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 "mozilla/AlreadyAddRefed.h"
24 #include "mozilla/Assertions.h"
25 #include "mozilla/Attributes.h"
26 #include "mozilla/BasicEvents.h"
27 #include "mozilla/RefPtr.h"
28 #include "mozilla/dom/DOMString.h"
29 #include "mozilla/dom/Element.h"
30 #include "mozilla/dom/FragmentOrElement.h"
31 #include "mozilla/dom/FromParser.h"
32 #include "mozilla/dom/NameSpaceConstants.h"
33 #include "mozilla/dom/NodeInfo.h"
35 #include "nsAttrName.h"
36 #include "nsAttrValue.h"
38 #include "nsCaseTreatment.h"
39 #include "nsChangeHint.h"
40 #include "nsCycleCollectionParticipant.h"
41 #include "nsGkAtoms.h"
42 #include "nsIContent.h"
44 #include "nsISupports.h"
45 #include "nsLiteralString.h"
47 #include "nsStyledElement.h"
49 #include "nsTLiteralString.h"
54 class nsIObjectInputStream
;
55 class nsIObjectOutputStream
;
56 class nsIOffThreadScriptReceiver
;
59 class nsXULPrototypeDocument
;
60 class nsXULPrototypeNode
;
63 using nsPrototypeArray
= nsTArray
<RefPtr
<nsXULPrototypeNode
>>;
71 class EventChainPreVisitor
;
72 class EventListenerManager
;
78 class HTMLIFrameElement
;
79 class PrototypeDocumentContentSink
;
80 enum class CallerType
: uint32_t;
82 } // namespace mozilla
84 ////////////////////////////////////////////////////////////////////////
86 #ifdef XUL_PROTOTYPE_ATTRIBUTE_METERING
87 # define XUL_PROTOTYPE_ATTRIBUTE_METER(counter) \
88 (nsXULPrototypeAttribute::counter++)
90 # define XUL_PROTOTYPE_ATTRIBUTE_METER(counter) ((void)0)
95 A prototype attribute for an nsXULPrototypeElement.
99 class nsXULPrototypeAttribute
{
101 nsXULPrototypeAttribute()
102 : mName(nsGkAtoms::id
) // XXX this is a hack, but names have to have a
105 XUL_PROTOTYPE_ATTRIBUTE_METER(gNumAttributes
);
106 MOZ_COUNT_CTOR(nsXULPrototypeAttribute
);
109 ~nsXULPrototypeAttribute();
114 #ifdef XUL_PROTOTYPE_ATTRIBUTE_METERING
115 static uint32_t gNumElements
;
116 static uint32_t gNumAttributes
;
117 static uint32_t gNumCacheTests
;
118 static uint32_t gNumCacheHits
;
119 static uint32_t gNumCacheSets
;
120 static uint32_t gNumCacheFills
;
121 #endif /* !XUL_PROTOTYPE_ATTRIBUTE_METERING */
126 A prototype content model element that holds the "primordial" values
127 that have been parsed from the original XUL document.
131 class nsXULPrototypeNode
{
133 enum Type
{ eType_Element
, eType_Script
, eType_Text
, eType_PI
};
137 virtual nsresult
Serialize(
138 nsIObjectOutputStream
* aStream
, nsXULPrototypeDocument
* aProtoDoc
,
139 const nsTArray
<RefPtr
<mozilla::dom::NodeInfo
>>* aNodeInfos
) = 0;
140 virtual nsresult
Deserialize(
141 nsIObjectInputStream
* aStream
, nsXULPrototypeDocument
* aProtoDoc
,
142 nsIURI
* aDocumentURI
,
143 const nsTArray
<RefPtr
<mozilla::dom::NodeInfo
>>* aNodeInfos
) = 0;
146 * The prototype document must call ReleaseSubtree when it is going
147 * away. This makes the parents through the tree stop owning their
148 * children, whether or not the parent's reference count is zero.
149 * Individual elements may still own individual prototypes, but
150 * those prototypes no longer remember their children to allow them
153 virtual void ReleaseSubtree() {}
155 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(nsXULPrototypeNode
)
156 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsXULPrototypeNode
)
159 explicit nsXULPrototypeNode(Type aType
) : mType(aType
) {}
160 virtual ~nsXULPrototypeNode() = default;
163 class nsXULPrototypeElement
: public nsXULPrototypeNode
{
165 explicit nsXULPrototypeElement(mozilla::dom::NodeInfo
* aNodeInfo
= nullptr)
166 : nsXULPrototypeNode(eType_Element
),
167 mNodeInfo(aNodeInfo
),
168 mHasIdAttribute(false),
169 mHasClassAttribute(false),
170 mHasStyleAttribute(false),
174 virtual ~nsXULPrototypeElement() { Unlink(); }
177 virtual void ReleaseSubtree() override
{
178 for (int32_t i
= mChildren
.Length() - 1; i
>= 0; i
--) {
179 if (mChildren
[i
].get()) mChildren
[i
]->ReleaseSubtree();
182 nsXULPrototypeNode::ReleaseSubtree();
185 virtual nsresult
Serialize(
186 nsIObjectOutputStream
* aStream
, nsXULPrototypeDocument
* aProtoDoc
,
187 const nsTArray
<RefPtr
<mozilla::dom::NodeInfo
>>* aNodeInfos
) override
;
188 virtual nsresult
Deserialize(
189 nsIObjectInputStream
* aStream
, nsXULPrototypeDocument
* aProtoDoc
,
190 nsIURI
* aDocumentURI
,
191 const nsTArray
<RefPtr
<mozilla::dom::NodeInfo
>>* aNodeInfos
) override
;
193 nsresult
SetAttrAt(uint32_t aPos
, const nsAString
& aValue
,
194 nsIURI
* aDocumentURI
);
198 nsPrototypeArray mChildren
;
200 RefPtr
<mozilla::dom::NodeInfo
> mNodeInfo
;
202 uint32_t mHasIdAttribute
: 1;
203 uint32_t mHasClassAttribute
: 1;
204 uint32_t mHasStyleAttribute
: 1;
205 nsTArray
<nsXULPrototypeAttribute
> mAttributes
; // [OWNER]
206 RefPtr
<nsAtom
> mIsAtom
;
209 class nsXULPrototypeScript
: public nsXULPrototypeNode
{
211 explicit nsXULPrototypeScript(uint32_t aLineNo
);
214 virtual ~nsXULPrototypeScript() = default;
216 void FillCompileOptions(JS::CompileOptions
& options
);
219 virtual nsresult
Serialize(
220 nsIObjectOutputStream
* aStream
, nsXULPrototypeDocument
* aProtoDoc
,
221 const nsTArray
<RefPtr
<mozilla::dom::NodeInfo
>>* aNodeInfos
) override
;
222 nsresult
SerializeOutOfLine(nsIObjectOutputStream
* aStream
,
223 nsXULPrototypeDocument
* aProtoDoc
);
224 virtual nsresult
Deserialize(
225 nsIObjectInputStream
* aStream
, nsXULPrototypeDocument
* aProtoDoc
,
226 nsIURI
* aDocumentURI
,
227 const nsTArray
<RefPtr
<mozilla::dom::NodeInfo
>>* aNodeInfos
) override
;
228 nsresult
DeserializeOutOfLine(nsIObjectInputStream
* aInput
,
229 nsXULPrototypeDocument
* aProtoDoc
);
231 template <typename Unit
>
232 nsresult
Compile(const Unit
* aText
, size_t aTextLength
,
233 JS::SourceOwnership aOwnership
, nsIURI
* aURI
,
234 uint32_t aLineNo
, mozilla::dom::Document
* aDocument
,
235 nsIOffThreadScriptReceiver
* aOffThreadReceiver
= nullptr);
237 void Set(JS::Stencil
* aStencil
);
239 bool HasStencil() { return mStencil
; }
241 JS::Stencil
* GetStencil() { return mStencil
.get(); }
243 nsresult
InstantiateScript(JSContext
* aCx
,
244 JS::MutableHandle
<JSScript
*> aScript
);
246 nsCOMPtr
<nsIURI
> mSrcURI
;
250 mozilla::dom::PrototypeDocumentContentSink
*
251 mSrcLoadWaiters
; // [OWNER] but not COMPtr
253 RefPtr
<JS::Stencil
> mStencil
;
256 class nsXULPrototypeText
: public nsXULPrototypeNode
{
258 nsXULPrototypeText() : nsXULPrototypeNode(eType_Text
) {}
261 virtual ~nsXULPrototypeText() = default;
264 virtual nsresult
Serialize(
265 nsIObjectOutputStream
* aStream
, nsXULPrototypeDocument
* aProtoDoc
,
266 const nsTArray
<RefPtr
<mozilla::dom::NodeInfo
>>* aNodeInfos
) override
;
267 virtual nsresult
Deserialize(
268 nsIObjectInputStream
* aStream
, nsXULPrototypeDocument
* aProtoDoc
,
269 nsIURI
* aDocumentURI
,
270 const nsTArray
<RefPtr
<mozilla::dom::NodeInfo
>>* aNodeInfos
) override
;
275 class nsXULPrototypePI
: public nsXULPrototypeNode
{
277 nsXULPrototypePI() : nsXULPrototypeNode(eType_PI
) {}
280 virtual ~nsXULPrototypePI() = default;
283 virtual nsresult
Serialize(
284 nsIObjectOutputStream
* aStream
, nsXULPrototypeDocument
* aProtoDoc
,
285 const nsTArray
<RefPtr
<mozilla::dom::NodeInfo
>>* aNodeInfos
) override
;
286 virtual nsresult
Deserialize(
287 nsIObjectInputStream
* aStream
, nsXULPrototypeDocument
* aProtoDoc
,
288 nsIURI
* aDocumentURI
,
289 const nsTArray
<RefPtr
<mozilla::dom::NodeInfo
>>* aNodeInfos
) override
;
295 ////////////////////////////////////////////////////////////////////////
303 #define XUL_ELEMENT_FLAG_BIT(n_) \
304 NODE_FLAG_BIT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + (n_))
306 // XUL element specific bits
308 XUL_ELEMENT_HAS_CONTENTMENU_LISTENER
= XUL_ELEMENT_FLAG_BIT(0),
309 XUL_ELEMENT_HAS_POPUP_LISTENER
= XUL_ELEMENT_FLAG_BIT(1)
312 ASSERT_NODE_FLAGS_SPACE(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET
+ 2);
314 #undef XUL_ELEMENT_FLAG_BIT
316 class nsXULElement
: public nsStyledElement
{
318 using Document
= mozilla::dom::Document
;
320 // Use Construct to construct elements instead of this constructor.
321 explicit nsXULElement(already_AddRefed
<mozilla::dom::NodeInfo
>&& aNodeInfo
);
325 using Element::Focus
;
327 static nsresult
CreateFromPrototype(nsXULPrototypeElement
* aPrototype
,
328 Document
* aDocument
, bool aIsScriptable
,
330 mozilla::dom::Element
** aResult
);
332 // This is the constructor for nsXULElements.
333 static nsXULElement
* Construct(
334 already_AddRefed
<mozilla::dom::NodeInfo
>&& aNodeInfo
);
336 NS_IMPL_FROMNODE(nsXULElement
, kNameSpaceID_XUL
)
339 NS_DECL_ISUPPORTS_INHERITED
340 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXULElement
, nsStyledElement
)
342 // This doesn't work on XUL elements! You probably want
343 // GetXULBoolAttr(nsGkAtoms::disabled) or so.
344 // TODO(emilio): Maybe we should unify HTML and XUL here.
345 bool IsDisabled() const = delete;
348 void GetEventTargetParent(mozilla::EventChainPreVisitor
& aVisitor
) override
;
349 MOZ_CAN_RUN_SCRIPT_BOUNDARY
350 virtual nsresult
PreHandleEvent(
351 mozilla::EventChainVisitor
& aVisitor
) override
;
353 virtual nsresult
BindToTree(BindContext
&, nsINode
& aParent
) override
;
354 virtual void UnbindFromTree(bool aNullParent
) override
;
355 virtual void DestroyContent() override
;
356 virtual void DoneAddingChildren(bool aHaveNotified
) override
;
359 virtual void List(FILE* out
, int32_t aIndent
) const override
;
360 virtual void DumpContent(FILE* out
, int32_t aIndent
,
361 bool aDumpAll
) const override
{}
364 MOZ_CAN_RUN_SCRIPT
bool HasMenu();
365 MOZ_CAN_RUN_SCRIPT
void OpenMenu(bool aOpenFlag
);
368 virtual mozilla::Result
<bool, nsresult
> PerformAccesskey(
369 bool aKeyCausesActivation
, bool aIsTrustedEvent
) override
;
370 MOZ_CAN_RUN_SCRIPT
void ClickWithInputSource(uint16_t aInputSource
,
371 bool aIsTrustedEvent
);
373 bool IsFocusableInternal(int32_t* aTabIndex
, bool aWithMouse
) override
;
375 NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom
* aAttribute
) const override
;
377 virtual nsresult
Clone(mozilla::dom::NodeInfo
*,
378 nsINode
** aResult
) const override
;
380 virtual bool IsEventAttributeNameInternal(nsAtom
* aName
) override
;
382 using DOMString
= mozilla::dom::DOMString
;
383 void GetXULAttr(nsAtom
* aName
, DOMString
& aResult
) const {
384 GetAttr(aName
, aResult
);
386 void SetXULAttr(nsAtom
* aName
, const nsAString
& aValue
,
387 mozilla::ErrorResult
& aError
) {
388 SetAttr(aName
, aValue
, aError
);
390 bool GetXULBoolAttr(nsAtom
* aName
) const {
391 return AttrValueIs(kNameSpaceID_None
, aName
, u
"true"_ns
, eCaseMatters
);
393 void SetXULBoolAttr(nsAtom
* aName
, bool aValue
,
394 mozilla::ErrorResult
& aError
) {
396 SetAttr(aName
, u
"true"_ns
, aError
);
398 UnsetAttr(aName
, aError
);
403 bool Autofocus() const { return BoolAttrIsTrue(nsGkAtoms::autofocus
); }
404 void SetAutofocus(bool aAutofocus
, ErrorResult
& aRv
) {
405 SetXULBoolAttr(nsGkAtoms::autofocus
, aAutofocus
, aRv
);
407 bool Hidden() const { return BoolAttrIsTrue(nsGkAtoms::hidden
); }
408 void SetHidden(bool aHidden
) {
409 SetXULBoolAttr(nsGkAtoms::hidden
, aHidden
, mozilla::IgnoreErrors());
411 bool Collapsed() const { return BoolAttrIsTrue(nsGkAtoms::collapsed
); }
412 void SetCollapsed(bool aCollapsed
) {
413 SetXULBoolAttr(nsGkAtoms::collapsed
, aCollapsed
, mozilla::IgnoreErrors());
415 void GetObserves(DOMString
& aValue
) const {
416 GetXULAttr(nsGkAtoms::observes
, aValue
);
418 void SetObserves(const nsAString
& aValue
, mozilla::ErrorResult
& rv
) {
419 SetXULAttr(nsGkAtoms::observes
, aValue
, rv
);
421 void GetMenu(DOMString
& aValue
) const { GetXULAttr(nsGkAtoms::menu
, aValue
); }
422 void SetMenu(const nsAString
& aValue
, mozilla::ErrorResult
& rv
) {
423 SetXULAttr(nsGkAtoms::menu
, aValue
, rv
);
425 void GetContextMenu(DOMString
& aValue
) {
426 GetXULAttr(nsGkAtoms::contextmenu
, aValue
);
428 void SetContextMenu(const nsAString
& aValue
, mozilla::ErrorResult
& rv
) {
429 SetXULAttr(nsGkAtoms::contextmenu
, aValue
, rv
);
431 void GetTooltip(DOMString
& aValue
) const {
432 GetXULAttr(nsGkAtoms::tooltip
, aValue
);
434 void SetTooltip(const nsAString
& aValue
, mozilla::ErrorResult
& rv
) {
435 SetXULAttr(nsGkAtoms::tooltip
, aValue
, rv
);
437 void GetTooltipText(DOMString
& aValue
) const {
438 GetXULAttr(nsGkAtoms::tooltiptext
, aValue
);
440 void SetTooltipText(const nsAString
& aValue
, mozilla::ErrorResult
& rv
) {
441 SetXULAttr(nsGkAtoms::tooltiptext
, aValue
, rv
);
443 void GetSrc(DOMString
& aValue
) const { GetXULAttr(nsGkAtoms::src
, aValue
); }
444 void SetSrc(const nsAString
& aValue
, mozilla::ErrorResult
& rv
) {
445 SetXULAttr(nsGkAtoms::src
, aValue
, rv
);
447 nsIControllers
* GetControllers(mozilla::ErrorResult
& rv
);
448 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
449 MOZ_CAN_RUN_SCRIPT_BOUNDARY
void Click(mozilla::dom::CallerType aCallerType
);
450 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
451 MOZ_CAN_RUN_SCRIPT_BOUNDARY
void DoCommand();
452 // Style() inherited from nsStyledElement
454 nsINode
* GetScopeChainParent() const override
{
455 // For XUL, the parent is the parent element, if any
456 Element
* parent
= GetParentElement();
457 return parent
? parent
: nsStyledElement::GetScopeChainParent();
460 bool IsInteractiveHTMLContent() const override
;
465 // This can be removed if EnsureContentsGenerated dies.
466 friend class nsNSElementTearoff
;
468 // Implementation methods
469 nsresult
EnsureContentsGenerated(void) const;
471 nsresult
AddPopupListener(nsAtom
* aName
);
474 * Abandon our prototype linkage, and copy all attributes locally
476 nsresult
MakeHeavyweight(nsXULPrototypeElement
* aPrototype
);
478 void BeforeSetAttr(int32_t aNamespaceID
, nsAtom
* aName
,
479 const nsAttrValue
* aValue
, bool aNotify
) override
;
480 void AfterSetAttr(int32_t aNamespaceID
, nsAtom
* aName
,
481 const nsAttrValue
* aValue
, const nsAttrValue
* aOldValue
,
482 nsIPrincipal
* aSubjectPrincipal
, bool aNotify
) override
;
484 void UpdateEditableState(bool aNotify
) override
;
486 bool ParseAttribute(int32_t aNamespaceID
, nsAtom
* aAttribute
,
487 const nsAString
& aValue
,
488 nsIPrincipal
* aMaybeScriptedPrincipal
,
489 nsAttrValue
& aResult
) override
;
491 mozilla::EventListenerManager
* GetEventListenerManagerForAttr(
492 nsAtom
* aAttrName
, bool* aDefer
) override
;
495 * Add a listener for the specified attribute, if appropriate.
497 void AddListenerForAttributeIfNeeded(const nsAttrName
& aName
);
498 void AddListenerForAttributeIfNeeded(nsAtom
* aLocalName
);
501 void AddTooltipSupport();
502 void RemoveTooltipSupport();
504 // Internal accessor. This shadows the 'Slots', and returns
505 // appropriate value.
506 nsIControllers
* Controllers() {
507 nsExtendedDOMSlots
* slots
= GetExistingExtendedDOMSlots();
508 return slots
? slots
->mControllers
.get() : nullptr;
511 bool SupportsAccessKey() const;
512 void RegUnRegAccessKey(bool aDoReg
) override
;
513 bool BoolAttrIsTrue(nsAtom
* aName
) const;
515 friend nsXULElement
* NS_NewBasicXULElement(
516 already_AddRefed
<mozilla::dom::NodeInfo
>&& aNodeInfo
);
518 friend nsresult
NS_NewXULElement(mozilla::dom::Element
** aResult
,
519 mozilla::dom::NodeInfo
* aNodeInfo
,
520 mozilla::dom::FromParser aFromParser
,
521 const nsAString
* aIs
);
522 friend void NS_TrustedNewXULElement(mozilla::dom::Element
** aResult
,
523 mozilla::dom::NodeInfo
* aNodeInfo
);
525 static already_AddRefed
<nsXULElement
> CreateFromPrototype(
526 nsXULPrototypeElement
* aPrototype
, mozilla::dom::NodeInfo
* aNodeInfo
,
527 bool aIsScriptable
, bool aIsRoot
);
529 JSObject
* WrapNode(JSContext
*, JS::Handle
<JSObject
*> aGivenProto
) override
;
531 bool IsEventStoppedFromAnonymousScrollbar(mozilla::EventMessage aMessage
);
534 nsresult
DispatchXULCommand(const mozilla::EventChainVisitor
& aVisitor
,
535 nsAutoString
& aCommand
);
538 #endif // nsXULElement_h__