Bug 1857841 - pt 3. Add a new page kind named "fresh" r=glandium
[gecko.git] / dom / xul / nsXULElement.h
blob2681a14a9a2271f9fba77df46f981879ecf27d60
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/. */
6 /*
8 The base XUL element class and associates.
12 #ifndef nsXULElement_h__
13 #define nsXULElement_h__
15 #include <stdint.h>
16 #include <stdio.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"
36 #include "nsAtom.h"
37 #include "nsAttrName.h"
38 #include "nsAttrValue.h"
39 #include "nsCOMPtr.h"
40 #include "nsCaseTreatment.h"
41 #include "nsChangeHint.h"
42 #include "nsCycleCollectionParticipant.h"
43 #include "nsGkAtoms.h"
44 #include "nsIContent.h"
45 #include "nsINode.h"
46 #include "nsISupports.h"
47 #include "nsLiteralString.h"
48 #include "nsString.h"
49 #include "nsStyledElement.h"
50 #include "nsTArray.h"
51 #include "nsTLiteralString.h"
52 #include "nscore.h"
54 class JSObject;
55 class nsIControllers;
56 class nsIObjectInputStream;
57 class nsIObjectOutputStream;
58 class nsIOffThreadScriptReceiver;
59 class nsIPrincipal;
60 class nsIURI;
61 class nsXULPrototypeDocument;
62 class nsXULPrototypeNode;
63 struct JSContext;
65 using nsPrototypeArray = nsTArray<RefPtr<nsXULPrototypeNode>>;
67 namespace JS {
68 class CompileOptions;
71 namespace mozilla {
72 class ErrorResult;
73 class EventChainPreVisitor;
74 class EventListenerManager;
75 namespace css {
76 class StyleRule;
77 } // namespace css
78 namespace dom {
79 class Document;
80 class HTMLIFrameElement;
81 class PrototypeDocumentContentSink;
82 enum class CallerType : uint32_t;
83 } // namespace dom
84 } // namespace mozilla
86 ////////////////////////////////////////////////////////////////////////
88 #ifdef XUL_PROTOTYPE_ATTRIBUTE_METERING
89 # define XUL_PROTOTYPE_ATTRIBUTE_METER(counter) \
90 (nsXULPrototypeAttribute::counter++)
91 #else
92 # define XUL_PROTOTYPE_ATTRIBUTE_METER(counter) ((void)0)
93 #endif
95 /**
97 A prototype attribute for an nsXULPrototypeElement.
101 class nsXULPrototypeAttribute {
102 public:
103 nsXULPrototypeAttribute()
104 : mName(nsGkAtoms::id) // XXX this is a hack, but names have to have a
105 // value
107 XUL_PROTOTYPE_ATTRIBUTE_METER(gNumAttributes);
108 MOZ_COUNT_CTOR(nsXULPrototypeAttribute);
111 ~nsXULPrototypeAttribute();
113 nsAttrName mName;
114 nsAttrValue mValue;
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 {
134 public:
135 enum Type { eType_Element, eType_Script, eType_Text, eType_PI };
137 Type mType;
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
153 * to be constructed.
155 virtual void ReleaseSubtree() {}
157 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(nsXULPrototypeNode)
158 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsXULPrototypeNode)
160 protected:
161 explicit nsXULPrototypeNode(Type aType) : mType(aType) {}
162 virtual ~nsXULPrototypeNode() = default;
165 class nsXULPrototypeElement : public nsXULPrototypeNode {
166 public:
167 explicit nsXULPrototypeElement(mozilla::dom::NodeInfo* aNodeInfo = nullptr)
168 : nsXULPrototypeNode(eType_Element),
169 mNodeInfo(aNodeInfo),
170 mHasIdAttribute(false),
171 mHasClassAttribute(false),
172 mHasStyleAttribute(false),
173 mIsAtom(nullptr) {}
175 private:
176 virtual ~nsXULPrototypeElement() { Unlink(); }
178 public:
179 virtual void ReleaseSubtree() override {
180 for (int32_t i = mChildren.Length() - 1; i >= 0; i--) {
181 if (mChildren[i].get()) mChildren[i]->ReleaseSubtree();
183 mChildren.Clear();
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);
198 void Unlink();
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 {
212 public:
213 explicit nsXULPrototypeScript(uint32_t aLineNo);
215 private:
216 virtual ~nsXULPrototypeScript() = default;
218 void FillCompileOptions(JS::CompileOptions& aOptions, const char* aFilename,
219 uint32_t aLineNo);
221 public:
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
237 // compilation.
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
253 // the stencil.
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;
270 uint32_t mLineNo;
271 bool mSrcLoading;
272 bool mOutOfLine;
273 mozilla::dom::PrototypeDocumentContentSink*
274 mSrcLoadWaiters; // [OWNER] but not COMPtr
275 private:
276 RefPtr<JS::Stencil> mStencil;
279 class nsXULPrototypeText : public nsXULPrototypeNode {
280 public:
281 nsXULPrototypeText() : nsXULPrototypeNode(eType_Text) {}
283 private:
284 virtual ~nsXULPrototypeText() = default;
286 public:
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;
295 nsString mValue;
298 class nsXULPrototypePI : public nsXULPrototypeNode {
299 public:
300 nsXULPrototypePI() : nsXULPrototypeNode(eType_PI) {}
302 private:
303 virtual ~nsXULPrototypePI() = default;
305 public:
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;
314 nsString mTarget;
315 nsString mData;
318 ////////////////////////////////////////////////////////////////////////
322 The XUL element.
326 #define XUL_ELEMENT_FLAG_BIT(n_) \
327 NODE_FLAG_BIT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + (n_))
329 // XUL element specific bits
330 enum {
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 {
340 protected:
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);
346 public:
347 using Element::Blur;
348 using Element::Focus;
350 static nsresult CreateFromPrototype(nsXULPrototypeElement* aPrototype,
351 Document* aDocument, bool aIsScriptable,
352 bool aIsRoot,
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)
361 // nsISupports
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;
370 // nsINode
371 void GetEventTargetParent(mozilla::EventChainPreVisitor& aVisitor) override;
372 MOZ_CAN_RUN_SCRIPT_BOUNDARY
373 virtual nsresult PreHandleEvent(
374 mozilla::EventChainVisitor& aVisitor) override;
375 // nsIContent
376 virtual nsresult BindToTree(BindContext&, nsINode& aParent) override;
377 virtual void UnbindFromTree(UnbindContext&) override;
378 virtual void DestroyContent() override;
379 virtual void DoneAddingChildren(bool aHaveNotified) override;
381 #ifdef MOZ_DOM_LIST
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 {}
385 #endif
387 MOZ_CAN_RUN_SCRIPT bool HasMenu();
388 MOZ_CAN_RUN_SCRIPT void OpenMenu(bool aOpenFlag);
390 MOZ_CAN_RUN_SCRIPT
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);
395 struct XULFocusability {
396 bool mDefaultFocusable = false;
397 mozilla::Maybe<bool> mForcedFocusable;
398 mozilla::Maybe<int32_t> mForcedTabIndexIfFocusable;
400 static XULFocusability NeverFocusable() {
401 return {false, mozilla::Some(false), mozilla::Some(-1)};
404 XULFocusability GetXULFocusability(bool aWithMouse);
405 Focusable IsFocusableWithoutStyle(bool aWithMouse) override;
407 NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override;
409 virtual nsresult Clone(mozilla::dom::NodeInfo*,
410 nsINode** aResult) const override;
412 virtual bool IsEventAttributeNameInternal(nsAtom* aName) override;
414 using DOMString = mozilla::dom::DOMString;
415 void GetXULAttr(nsAtom* aName, DOMString& aResult) const {
416 GetAttr(aName, aResult);
418 void SetXULAttr(nsAtom* aName, const nsAString& aValue,
419 mozilla::ErrorResult& aError) {
420 SetAttr(aName, aValue, aError);
422 bool GetXULBoolAttr(nsAtom* aName) const {
423 return AttrValueIs(kNameSpaceID_None, aName, u"true"_ns, eCaseMatters);
425 void SetXULBoolAttr(nsAtom* aName, bool aValue,
426 mozilla::ErrorResult& aError) {
427 if (aValue) {
428 SetAttr(aName, u"true"_ns, aError);
429 } else {
430 UnsetAttr(aName, aError);
434 // WebIDL API
435 bool Autofocus() const { return BoolAttrIsTrue(nsGkAtoms::autofocus); }
436 void SetAutofocus(bool aAutofocus, ErrorResult& aRv) {
437 SetXULBoolAttr(nsGkAtoms::autofocus, aAutofocus, aRv);
439 bool Hidden() const { return BoolAttrIsTrue(nsGkAtoms::hidden); }
440 void SetHidden(bool aHidden) {
441 SetXULBoolAttr(nsGkAtoms::hidden, aHidden, mozilla::IgnoreErrors());
443 bool Collapsed() const { return BoolAttrIsTrue(nsGkAtoms::collapsed); }
444 void SetCollapsed(bool aCollapsed) {
445 SetXULBoolAttr(nsGkAtoms::collapsed, aCollapsed, mozilla::IgnoreErrors());
447 void GetObserves(DOMString& aValue) const {
448 GetXULAttr(nsGkAtoms::observes, aValue);
450 void SetObserves(const nsAString& aValue, mozilla::ErrorResult& rv) {
451 SetXULAttr(nsGkAtoms::observes, aValue, rv);
453 void GetMenu(DOMString& aValue) const { GetXULAttr(nsGkAtoms::menu, aValue); }
454 void SetMenu(const nsAString& aValue, mozilla::ErrorResult& rv) {
455 SetXULAttr(nsGkAtoms::menu, aValue, rv);
457 void GetContextMenu(DOMString& aValue) {
458 GetXULAttr(nsGkAtoms::contextmenu, aValue);
460 void SetContextMenu(const nsAString& aValue, mozilla::ErrorResult& rv) {
461 SetXULAttr(nsGkAtoms::contextmenu, aValue, rv);
463 void GetTooltip(DOMString& aValue) const {
464 GetXULAttr(nsGkAtoms::tooltip, aValue);
466 void SetTooltip(const nsAString& aValue, mozilla::ErrorResult& rv) {
467 SetXULAttr(nsGkAtoms::tooltip, aValue, rv);
469 void GetTooltipText(DOMString& aValue) const {
470 GetXULAttr(nsGkAtoms::tooltiptext, aValue);
472 void SetTooltipText(const nsAString& aValue, mozilla::ErrorResult& rv) {
473 SetXULAttr(nsGkAtoms::tooltiptext, aValue, rv);
475 void GetSrc(DOMString& aValue) const { GetXULAttr(nsGkAtoms::src, aValue); }
476 void SetSrc(const nsAString& aValue, mozilla::ErrorResult& rv) {
477 SetXULAttr(nsGkAtoms::src, aValue, rv);
479 nsIControllers* GetControllers(mozilla::ErrorResult& rv);
480 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
481 MOZ_CAN_RUN_SCRIPT_BOUNDARY void Click(mozilla::dom::CallerType aCallerType);
482 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
483 MOZ_CAN_RUN_SCRIPT_BOUNDARY void DoCommand();
484 // Style() inherited from nsStyledElement
486 nsINode* GetScopeChainParent() const override {
487 // For XUL, the parent is the parent element, if any
488 Element* parent = GetParentElement();
489 return parent ? parent : nsStyledElement::GetScopeChainParent();
492 bool IsInteractiveHTMLContent() const override;
494 protected:
495 ~nsXULElement();
497 // This can be removed if EnsureContentsGenerated dies.
498 friend class nsNSElementTearoff;
500 // Implementation methods
501 nsresult EnsureContentsGenerated(void) const;
503 nsresult AddPopupListener(nsAtom* aName);
506 * Abandon our prototype linkage, and copy all attributes locally
508 nsresult MakeHeavyweight(nsXULPrototypeElement* aPrototype);
510 void BeforeSetAttr(int32_t aNamespaceID, nsAtom* aName,
511 const nsAttrValue* aValue, bool aNotify) override;
512 void AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
513 const nsAttrValue* aValue, const nsAttrValue* aOldValue,
514 nsIPrincipal* aSubjectPrincipal, bool aNotify) override;
516 bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
517 const nsAString& aValue,
518 nsIPrincipal* aMaybeScriptedPrincipal,
519 nsAttrValue& aResult) override;
521 mozilla::EventListenerManager* GetEventListenerManagerForAttr(
522 nsAtom* aAttrName, bool* aDefer) override;
525 * Add a listener for the specified attribute, if appropriate.
527 void AddListenerForAttributeIfNeeded(const nsAttrName& aName);
528 void AddListenerForAttributeIfNeeded(nsAtom* aLocalName);
530 protected:
531 void AddTooltipSupport();
532 void RemoveTooltipSupport();
534 // Internal accessor. This shadows the 'Slots', and returns
535 // appropriate value.
536 nsIControllers* Controllers() {
537 nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
538 return slots ? slots->mControllers.get() : nullptr;
541 bool SupportsAccessKey() const;
542 void RegUnRegAccessKey(bool aDoReg) override;
543 bool BoolAttrIsTrue(nsAtom* aName) const;
545 friend nsXULElement* NS_NewBasicXULElement(
546 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
548 friend nsresult NS_NewXULElement(mozilla::dom::Element** aResult,
549 mozilla::dom::NodeInfo* aNodeInfo,
550 mozilla::dom::FromParser aFromParser,
551 const nsAString* aIs);
552 friend void NS_TrustedNewXULElement(mozilla::dom::Element** aResult,
553 mozilla::dom::NodeInfo* aNodeInfo);
555 static already_AddRefed<nsXULElement> CreateFromPrototype(
556 nsXULPrototypeElement* aPrototype, mozilla::dom::NodeInfo* aNodeInfo,
557 bool aIsScriptable, bool aIsRoot);
559 JSObject* WrapNode(JSContext*, JS::Handle<JSObject*> aGivenProto) override;
561 bool IsEventStoppedFromAnonymousScrollbar(mozilla::EventMessage aMessage);
563 MOZ_CAN_RUN_SCRIPT
564 nsresult DispatchXULCommand(const mozilla::EventChainVisitor& aVisitor,
565 nsAutoString& aCommand);
568 #endif // nsXULElement_h__