1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 The base XUL element class and associates.
12 #ifndef nsXULElement_h__
13 #define nsXULElement_h__
17 #include "ErrorList.h"
18 #include "js/experimental/JSStencil.h"
19 #include "js/RootingAPI.h"
20 #include "js/SourceText.h"
21 #include "js/TracingAPI.h"
22 #include "js/TypeDecls.h"
23 #include "js/Utility.h" // JS::FreePolicy
24 #include "mozilla/AlreadyAddRefed.h"
25 #include "mozilla/Assertions.h"
26 #include "mozilla/Attributes.h"
27 #include "mozilla/BasicEvents.h"
28 #include "mozilla/RefPtr.h"
29 #include "mozilla/UniquePtr.h"
30 #include "mozilla/dom/DOMString.h"
31 #include "mozilla/dom/Element.h"
32 #include "mozilla/dom/FragmentOrElement.h"
33 #include "mozilla/dom/FromParser.h"
34 #include "mozilla/dom/NameSpaceConstants.h"
35 #include "mozilla/dom/NodeInfo.h"
37 #include "nsAttrName.h"
38 #include "nsAttrValue.h"
40 #include "nsCaseTreatment.h"
41 #include "nsChangeHint.h"
42 #include "nsCycleCollectionParticipant.h"
43 #include "nsGkAtoms.h"
44 #include "nsIContent.h"
46 #include "nsISupports.h"
47 #include "nsLiteralString.h"
49 #include "nsStyledElement.h"
51 #include "nsTLiteralString.h"
56 class nsIObjectInputStream
;
57 class nsIObjectOutputStream
;
58 class nsIOffThreadScriptReceiver
;
61 class nsXULPrototypeDocument
;
62 class nsXULPrototypeNode
;
65 using nsPrototypeArray
= nsTArray
<RefPtr
<nsXULPrototypeNode
>>;
73 class EventChainPreVisitor
;
74 class EventListenerManager
;
80 class HTMLIFrameElement
;
81 class PrototypeDocumentContentSink
;
82 enum class CallerType
: uint32_t;
84 } // namespace mozilla
86 ////////////////////////////////////////////////////////////////////////
88 #ifdef XUL_PROTOTYPE_ATTRIBUTE_METERING
89 # define XUL_PROTOTYPE_ATTRIBUTE_METER(counter) \
90 (nsXULPrototypeAttribute::counter++)
92 # define XUL_PROTOTYPE_ATTRIBUTE_METER(counter) ((void)0)
97 A prototype attribute for an nsXULPrototypeElement.
101 class nsXULPrototypeAttribute
{
103 nsXULPrototypeAttribute()
104 : mName(nsGkAtoms::id
) // XXX this is a hack, but names have to have a
107 XUL_PROTOTYPE_ATTRIBUTE_METER(gNumAttributes
);
108 MOZ_COUNT_CTOR(nsXULPrototypeAttribute
);
111 ~nsXULPrototypeAttribute();
116 #ifdef XUL_PROTOTYPE_ATTRIBUTE_METERING
117 static uint32_t gNumElements
;
118 static uint32_t gNumAttributes
;
119 static uint32_t gNumCacheTests
;
120 static uint32_t gNumCacheHits
;
121 static uint32_t gNumCacheSets
;
122 static uint32_t gNumCacheFills
;
123 #endif /* !XUL_PROTOTYPE_ATTRIBUTE_METERING */
128 A prototype content model element that holds the "primordial" values
129 that have been parsed from the original XUL document.
133 class nsXULPrototypeNode
{
135 enum Type
{ eType_Element
, eType_Script
, eType_Text
, eType_PI
};
139 virtual nsresult
Serialize(
140 nsIObjectOutputStream
* aStream
, nsXULPrototypeDocument
* aProtoDoc
,
141 const nsTArray
<RefPtr
<mozilla::dom::NodeInfo
>>* aNodeInfos
) = 0;
142 virtual nsresult
Deserialize(
143 nsIObjectInputStream
* aStream
, nsXULPrototypeDocument
* aProtoDoc
,
144 nsIURI
* aDocumentURI
,
145 const nsTArray
<RefPtr
<mozilla::dom::NodeInfo
>>* aNodeInfos
) = 0;
148 * The prototype document must call ReleaseSubtree when it is going
149 * away. This makes the parents through the tree stop owning their
150 * children, whether or not the parent's reference count is zero.
151 * Individual elements may still own individual prototypes, but
152 * those prototypes no longer remember their children to allow them
155 virtual void ReleaseSubtree() {}
157 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(nsXULPrototypeNode
)
158 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsXULPrototypeNode
)
161 explicit nsXULPrototypeNode(Type aType
) : mType(aType
) {}
162 virtual ~nsXULPrototypeNode() = default;
165 class nsXULPrototypeElement
: public nsXULPrototypeNode
{
167 explicit nsXULPrototypeElement(mozilla::dom::NodeInfo
* aNodeInfo
= nullptr)
168 : nsXULPrototypeNode(eType_Element
),
169 mNodeInfo(aNodeInfo
),
170 mHasIdAttribute(false),
171 mHasClassAttribute(false),
172 mHasStyleAttribute(false),
176 virtual ~nsXULPrototypeElement() { Unlink(); }
179 virtual void ReleaseSubtree() override
{
180 for (int32_t i
= mChildren
.Length() - 1; i
>= 0; i
--) {
181 if (mChildren
[i
].get()) mChildren
[i
]->ReleaseSubtree();
184 nsXULPrototypeNode::ReleaseSubtree();
187 virtual nsresult
Serialize(
188 nsIObjectOutputStream
* aStream
, nsXULPrototypeDocument
* aProtoDoc
,
189 const nsTArray
<RefPtr
<mozilla::dom::NodeInfo
>>* aNodeInfos
) override
;
190 virtual nsresult
Deserialize(
191 nsIObjectInputStream
* aStream
, nsXULPrototypeDocument
* aProtoDoc
,
192 nsIURI
* aDocumentURI
,
193 const nsTArray
<RefPtr
<mozilla::dom::NodeInfo
>>* aNodeInfos
) override
;
195 nsresult
SetAttrAt(uint32_t aPos
, const nsAString
& aValue
,
196 nsIURI
* aDocumentURI
);
200 nsPrototypeArray mChildren
;
202 RefPtr
<mozilla::dom::NodeInfo
> mNodeInfo
;
204 uint32_t mHasIdAttribute
: 1;
205 uint32_t mHasClassAttribute
: 1;
206 uint32_t mHasStyleAttribute
: 1;
207 nsTArray
<nsXULPrototypeAttribute
> mAttributes
; // [OWNER]
208 RefPtr
<nsAtom
> mIsAtom
;
211 class nsXULPrototypeScript
: public nsXULPrototypeNode
{
213 explicit nsXULPrototypeScript(uint32_t aLineNo
);
216 virtual ~nsXULPrototypeScript() = default;
218 void FillCompileOptions(JS::CompileOptions
& aOptions
, const char* aFilename
,
222 virtual nsresult
Serialize(
223 nsIObjectOutputStream
* aStream
, nsXULPrototypeDocument
* aProtoDoc
,
224 const nsTArray
<RefPtr
<mozilla::dom::NodeInfo
>>* aNodeInfos
) override
;
225 nsresult
SerializeOutOfLine(nsIObjectOutputStream
* aStream
,
226 nsXULPrototypeDocument
* aProtoDoc
);
227 virtual nsresult
Deserialize(
228 nsIObjectInputStream
* aStream
, nsXULPrototypeDocument
* aProtoDoc
,
229 nsIURI
* aDocumentURI
,
230 const nsTArray
<RefPtr
<mozilla::dom::NodeInfo
>>* aNodeInfos
) override
;
231 nsresult
DeserializeOutOfLine(nsIObjectInputStream
* aInput
,
232 nsXULPrototypeDocument
* aProtoDoc
);
234 // Compile given JS source text synchronously.
236 // This method doesn't take the ownership of aText, but borrows during the
239 // If successfully compiled, `HasStencil()` returns true.
240 nsresult
Compile(const char16_t
* aText
, size_t aTextLength
, nsIURI
* aURI
,
241 uint32_t aLineNo
, mozilla::dom::Document
* aDocument
);
243 // Compile given JS source text possibly in off-thread.
245 // This method takes the ownership of aText.
247 // If this doesn't use off-thread compilation and successfully compiled,
248 // `HasStencil()` returns true.
250 // If this uses off-thread compilation, `HasStencil()` returns false, and
251 // once the compilation finishes, aOffThreadReceiver gets notified with the
252 // compiled stencil. The callback is responsible for calling `Set()` with
254 nsresult
CompileMaybeOffThread(
255 mozilla::UniquePtr
<mozilla::Utf8Unit
[], JS::FreePolicy
>&& aText
,
256 size_t aTextLength
, nsIURI
* aURI
, uint32_t aLineNo
,
257 mozilla::dom::Document
* aDocument
,
258 nsIOffThreadScriptReceiver
* aOffThreadReceiver
);
260 void Set(JS::Stencil
* aStencil
);
262 bool HasStencil() { return mStencil
; }
264 JS::Stencil
* GetStencil() { return mStencil
.get(); }
266 nsresult
InstantiateScript(JSContext
* aCx
,
267 JS::MutableHandle
<JSScript
*> aScript
);
269 nsCOMPtr
<nsIURI
> mSrcURI
;
273 mozilla::dom::PrototypeDocumentContentSink
*
274 mSrcLoadWaiters
; // [OWNER] but not COMPtr
276 RefPtr
<JS::Stencil
> mStencil
;
279 class nsXULPrototypeText
: public nsXULPrototypeNode
{
281 nsXULPrototypeText() : nsXULPrototypeNode(eType_Text
) {}
284 virtual ~nsXULPrototypeText() = default;
287 virtual nsresult
Serialize(
288 nsIObjectOutputStream
* aStream
, nsXULPrototypeDocument
* aProtoDoc
,
289 const nsTArray
<RefPtr
<mozilla::dom::NodeInfo
>>* aNodeInfos
) override
;
290 virtual nsresult
Deserialize(
291 nsIObjectInputStream
* aStream
, nsXULPrototypeDocument
* aProtoDoc
,
292 nsIURI
* aDocumentURI
,
293 const nsTArray
<RefPtr
<mozilla::dom::NodeInfo
>>* aNodeInfos
) override
;
298 class nsXULPrototypePI
: public nsXULPrototypeNode
{
300 nsXULPrototypePI() : nsXULPrototypeNode(eType_PI
) {}
303 virtual ~nsXULPrototypePI() = default;
306 virtual nsresult
Serialize(
307 nsIObjectOutputStream
* aStream
, nsXULPrototypeDocument
* aProtoDoc
,
308 const nsTArray
<RefPtr
<mozilla::dom::NodeInfo
>>* aNodeInfos
) override
;
309 virtual nsresult
Deserialize(
310 nsIObjectInputStream
* aStream
, nsXULPrototypeDocument
* aProtoDoc
,
311 nsIURI
* aDocumentURI
,
312 const nsTArray
<RefPtr
<mozilla::dom::NodeInfo
>>* aNodeInfos
) override
;
318 ////////////////////////////////////////////////////////////////////////
326 #define XUL_ELEMENT_FLAG_BIT(n_) \
327 NODE_FLAG_BIT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + (n_))
329 // XUL element specific bits
331 XUL_ELEMENT_HAS_CONTENTMENU_LISTENER
= XUL_ELEMENT_FLAG_BIT(0),
332 XUL_ELEMENT_HAS_POPUP_LISTENER
= XUL_ELEMENT_FLAG_BIT(1)
335 ASSERT_NODE_FLAGS_SPACE(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET
+ 2);
337 #undef XUL_ELEMENT_FLAG_BIT
339 class nsXULElement
: public nsStyledElement
{
341 using Document
= mozilla::dom::Document
;
343 // Use Construct to construct elements instead of this constructor.
344 explicit nsXULElement(already_AddRefed
<mozilla::dom::NodeInfo
>&& aNodeInfo
);
348 using Element::Focus
;
350 static nsresult
CreateFromPrototype(nsXULPrototypeElement
* aPrototype
,
351 Document
* aDocument
, bool aIsScriptable
,
353 mozilla::dom::Element
** aResult
);
355 // This is the constructor for nsXULElements.
356 static nsXULElement
* Construct(
357 already_AddRefed
<mozilla::dom::NodeInfo
>&& aNodeInfo
);
359 NS_IMPL_FROMNODE(nsXULElement
, kNameSpaceID_XUL
)
362 NS_DECL_ISUPPORTS_INHERITED
363 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXULElement
, nsStyledElement
)
365 // This doesn't work on XUL elements! You probably want
366 // GetXULBoolAttr(nsGkAtoms::disabled) or so.
367 // TODO(emilio): Maybe we should unify HTML and XUL here.
368 bool IsDisabled() const = delete;
371 void GetEventTargetParent(mozilla::EventChainPreVisitor
& aVisitor
) override
;
372 MOZ_CAN_RUN_SCRIPT_BOUNDARY
373 virtual nsresult
PreHandleEvent(
374 mozilla::EventChainVisitor
& aVisitor
) override
;
376 virtual nsresult
BindToTree(BindContext
&, nsINode
& aParent
) override
;
377 virtual void UnbindFromTree(bool aNullParent
) override
;
378 virtual void DestroyContent() override
;
379 virtual void DoneAddingChildren(bool aHaveNotified
) override
;
382 virtual void List(FILE* out
, int32_t aIndent
) const override
;
383 virtual void DumpContent(FILE* out
, int32_t aIndent
,
384 bool aDumpAll
) const override
{}
387 MOZ_CAN_RUN_SCRIPT
bool HasMenu();
388 MOZ_CAN_RUN_SCRIPT
void OpenMenu(bool aOpenFlag
);
391 virtual mozilla::Result
<bool, nsresult
> PerformAccesskey(
392 bool aKeyCausesActivation
, bool aIsTrustedEvent
) override
;
393 MOZ_CAN_RUN_SCRIPT
void ClickWithInputSource(uint16_t aInputSource
,
394 bool aIsTrustedEvent
);
396 bool IsFocusableInternal(int32_t* aTabIndex
, bool aWithMouse
) override
;
398 NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom
* aAttribute
) const override
;
400 virtual nsresult
Clone(mozilla::dom::NodeInfo
*,
401 nsINode
** aResult
) const override
;
403 virtual bool IsEventAttributeNameInternal(nsAtom
* aName
) override
;
405 using DOMString
= mozilla::dom::DOMString
;
406 void GetXULAttr(nsAtom
* aName
, DOMString
& aResult
) const {
407 GetAttr(aName
, aResult
);
409 void SetXULAttr(nsAtom
* aName
, const nsAString
& aValue
,
410 mozilla::ErrorResult
& aError
) {
411 SetAttr(aName
, aValue
, aError
);
413 bool GetXULBoolAttr(nsAtom
* aName
) const {
414 return AttrValueIs(kNameSpaceID_None
, aName
, u
"true"_ns
, eCaseMatters
);
416 void SetXULBoolAttr(nsAtom
* aName
, bool aValue
,
417 mozilla::ErrorResult
& aError
) {
419 SetAttr(aName
, u
"true"_ns
, aError
);
421 UnsetAttr(aName
, aError
);
426 bool Autofocus() const { return BoolAttrIsTrue(nsGkAtoms::autofocus
); }
427 void SetAutofocus(bool aAutofocus
, ErrorResult
& aRv
) {
428 SetXULBoolAttr(nsGkAtoms::autofocus
, aAutofocus
, aRv
);
430 bool Hidden() const { return BoolAttrIsTrue(nsGkAtoms::hidden
); }
431 void SetHidden(bool aHidden
) {
432 SetXULBoolAttr(nsGkAtoms::hidden
, aHidden
, mozilla::IgnoreErrors());
434 bool Collapsed() const { return BoolAttrIsTrue(nsGkAtoms::collapsed
); }
435 void SetCollapsed(bool aCollapsed
) {
436 SetXULBoolAttr(nsGkAtoms::collapsed
, aCollapsed
, mozilla::IgnoreErrors());
438 void GetObserves(DOMString
& aValue
) const {
439 GetXULAttr(nsGkAtoms::observes
, aValue
);
441 void SetObserves(const nsAString
& aValue
, mozilla::ErrorResult
& rv
) {
442 SetXULAttr(nsGkAtoms::observes
, aValue
, rv
);
444 void GetMenu(DOMString
& aValue
) const { GetXULAttr(nsGkAtoms::menu
, aValue
); }
445 void SetMenu(const nsAString
& aValue
, mozilla::ErrorResult
& rv
) {
446 SetXULAttr(nsGkAtoms::menu
, aValue
, rv
);
448 void GetContextMenu(DOMString
& aValue
) {
449 GetXULAttr(nsGkAtoms::contextmenu
, aValue
);
451 void SetContextMenu(const nsAString
& aValue
, mozilla::ErrorResult
& rv
) {
452 SetXULAttr(nsGkAtoms::contextmenu
, aValue
, rv
);
454 void GetTooltip(DOMString
& aValue
) const {
455 GetXULAttr(nsGkAtoms::tooltip
, aValue
);
457 void SetTooltip(const nsAString
& aValue
, mozilla::ErrorResult
& rv
) {
458 SetXULAttr(nsGkAtoms::tooltip
, aValue
, rv
);
460 void GetTooltipText(DOMString
& aValue
) const {
461 GetXULAttr(nsGkAtoms::tooltiptext
, aValue
);
463 void SetTooltipText(const nsAString
& aValue
, mozilla::ErrorResult
& rv
) {
464 SetXULAttr(nsGkAtoms::tooltiptext
, aValue
, rv
);
466 void GetSrc(DOMString
& aValue
) const { GetXULAttr(nsGkAtoms::src
, aValue
); }
467 void SetSrc(const nsAString
& aValue
, mozilla::ErrorResult
& rv
) {
468 SetXULAttr(nsGkAtoms::src
, aValue
, rv
);
470 nsIControllers
* GetControllers(mozilla::ErrorResult
& rv
);
471 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
472 MOZ_CAN_RUN_SCRIPT_BOUNDARY
void Click(mozilla::dom::CallerType aCallerType
);
473 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
474 MOZ_CAN_RUN_SCRIPT_BOUNDARY
void DoCommand();
475 // Style() inherited from nsStyledElement
477 nsINode
* GetScopeChainParent() const override
{
478 // For XUL, the parent is the parent element, if any
479 Element
* parent
= GetParentElement();
480 return parent
? parent
: nsStyledElement::GetScopeChainParent();
483 bool IsInteractiveHTMLContent() const override
;
488 // This can be removed if EnsureContentsGenerated dies.
489 friend class nsNSElementTearoff
;
491 // Implementation methods
492 nsresult
EnsureContentsGenerated(void) const;
494 nsresult
AddPopupListener(nsAtom
* aName
);
497 * Abandon our prototype linkage, and copy all attributes locally
499 nsresult
MakeHeavyweight(nsXULPrototypeElement
* aPrototype
);
501 void BeforeSetAttr(int32_t aNamespaceID
, nsAtom
* aName
,
502 const nsAttrValue
* aValue
, bool aNotify
) override
;
503 void AfterSetAttr(int32_t aNamespaceID
, nsAtom
* aName
,
504 const nsAttrValue
* aValue
, const nsAttrValue
* aOldValue
,
505 nsIPrincipal
* aSubjectPrincipal
, bool aNotify
) override
;
507 void UpdateEditableState(bool aNotify
) override
;
509 bool ParseAttribute(int32_t aNamespaceID
, nsAtom
* aAttribute
,
510 const nsAString
& aValue
,
511 nsIPrincipal
* aMaybeScriptedPrincipal
,
512 nsAttrValue
& aResult
) override
;
514 mozilla::EventListenerManager
* GetEventListenerManagerForAttr(
515 nsAtom
* aAttrName
, bool* aDefer
) override
;
518 * Add a listener for the specified attribute, if appropriate.
520 void AddListenerForAttributeIfNeeded(const nsAttrName
& aName
);
521 void AddListenerForAttributeIfNeeded(nsAtom
* aLocalName
);
524 void AddTooltipSupport();
525 void RemoveTooltipSupport();
527 // Internal accessor. This shadows the 'Slots', and returns
528 // appropriate value.
529 nsIControllers
* Controllers() {
530 nsExtendedDOMSlots
* slots
= GetExistingExtendedDOMSlots();
531 return slots
? slots
->mControllers
.get() : nullptr;
534 bool SupportsAccessKey() const;
535 void RegUnRegAccessKey(bool aDoReg
) override
;
536 bool BoolAttrIsTrue(nsAtom
* aName
) const;
538 friend nsXULElement
* NS_NewBasicXULElement(
539 already_AddRefed
<mozilla::dom::NodeInfo
>&& aNodeInfo
);
541 friend nsresult
NS_NewXULElement(mozilla::dom::Element
** aResult
,
542 mozilla::dom::NodeInfo
* aNodeInfo
,
543 mozilla::dom::FromParser aFromParser
,
544 const nsAString
* aIs
);
545 friend void NS_TrustedNewXULElement(mozilla::dom::Element
** aResult
,
546 mozilla::dom::NodeInfo
* aNodeInfo
);
548 static already_AddRefed
<nsXULElement
> CreateFromPrototype(
549 nsXULPrototypeElement
* aPrototype
, mozilla::dom::NodeInfo
* aNodeInfo
,
550 bool aIsScriptable
, bool aIsRoot
);
552 JSObject
* WrapNode(JSContext
*, JS::Handle
<JSObject
*> aGivenProto
) override
;
554 bool IsEventStoppedFromAnonymousScrollbar(mozilla::EventMessage aMessage
);
557 nsresult
DispatchXULCommand(const mozilla::EventChainVisitor
& aVisitor
,
558 nsAutoString
& aCommand
);
561 #endif // nsXULElement_h__