/src/mozilla-central/dom/base/nsIContent.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | #ifndef nsIContent_h___ |
7 | | #define nsIContent_h___ |
8 | | |
9 | | #include "mozilla/Attributes.h" |
10 | | #include "mozilla/dom/BorrowedAttrInfo.h" |
11 | | #include "nsCaseTreatment.h" // for enum, cannot be forward-declared |
12 | | #include "nsINode.h" |
13 | | #include "nsStringFwd.h" |
14 | | #include "nsISupportsImpl.h" |
15 | | |
16 | | // Forward declarations |
17 | | class nsAtom; |
18 | | class nsIURI; |
19 | | class nsAttrValue; |
20 | | class nsAttrName; |
21 | | class nsTextFragment; |
22 | | class nsIFrame; |
23 | | class nsXBLBinding; |
24 | | class nsITextControlElement; |
25 | | |
26 | | namespace mozilla { |
27 | | class EventChainPreVisitor; |
28 | | struct URLExtraData; |
29 | | namespace dom { |
30 | | class ShadowRoot; |
31 | | class HTMLSlotElement; |
32 | | } // namespace dom |
33 | | namespace widget { |
34 | | struct IMEState; |
35 | | } // namespace widget |
36 | | } // namespace mozilla |
37 | | |
38 | | enum nsLinkState { |
39 | | eLinkState_Unvisited = 1, |
40 | | eLinkState_Visited = 2, |
41 | | eLinkState_NotLink = 3 |
42 | | }; |
43 | | |
44 | | // IID for the nsIContent interface |
45 | | // Must be kept in sync with xpcom/rust/xpcom/src/interfaces/nonidl.rs |
46 | | #define NS_ICONTENT_IID \ |
47 | | { 0x8e1bab9d, 0x8815, 0x4d2c, \ |
48 | | { 0xa2, 0x4d, 0x7a, 0xba, 0x52, 0x39, 0xdc, 0x22 } } |
49 | | |
50 | | /** |
51 | | * A node of content in a document's content model. This interface |
52 | | * is supported by all content objects. |
53 | | */ |
54 | | class nsIContent : public nsINode { |
55 | | public: |
56 | | typedef mozilla::widget::IMEState IMEState; |
57 | | |
58 | | void ConstructUbiNode(void* storage) override; |
59 | | |
60 | | #ifdef MOZILLA_INTERNAL_API |
61 | | // If you're using the external API, the only thing you can know about |
62 | | // nsIContent is that it exists with an IID |
63 | | |
64 | | explicit nsIContent(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo) |
65 | | : nsINode(std::move(aNodeInfo)) |
66 | | { |
67 | | MOZ_ASSERT(mNodeInfo); |
68 | | SetNodeIsContent(); |
69 | | } |
70 | | #endif // MOZILLA_INTERNAL_API |
71 | | |
72 | | NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENT_IID) |
73 | | |
74 | | NS_DECL_CYCLE_COLLECTING_ISUPPORTS |
75 | | NS_DECL_CYCLE_COLLECTION_CLASS(nsIContent) |
76 | | |
77 | | NS_IMPL_FROMNODE_HELPER(nsIContent, IsContent()) |
78 | | |
79 | | /** |
80 | | * Bind this content node to a tree. If this method throws, the caller must |
81 | | * call UnbindFromTree() on the node. In the typical case of a node being |
82 | | * appended to a parent, this will be called after the node has been added to |
83 | | * the parent's child list and before nsIDocumentObserver notifications for |
84 | | * the addition are dispatched. |
85 | | * @param aDocument The new document for the content node. May not be null |
86 | | * if aParent is null. Must match the current document of |
87 | | * aParent, if aParent is not null (note that |
88 | | * aParent->GetUncomposedDoc() can be null, in which case |
89 | | * this must also be null). |
90 | | * @param aParent The new parent for the content node. May be null if the |
91 | | * node is being bound as a direct child of the document. |
92 | | * @param aBindingParent The new binding parent for the content node. |
93 | | * This is must either be non-null if a particular |
94 | | * binding parent is desired or match aParent's binding |
95 | | * parent. |
96 | | * @note either aDocument or aParent must be non-null. If both are null, |
97 | | * this method _will_ crash. |
98 | | * @note This method must not be called by consumers of nsIContent on a node |
99 | | * that is already bound to a tree. Call UnbindFromTree first. |
100 | | * @note This method will handle rebinding descendants appropriately (eg |
101 | | * changing their binding parent as needed). |
102 | | * @note This method does not add the content node to aParent's child list |
103 | | * @throws NS_ERROR_OUT_OF_MEMORY if that happens |
104 | | * |
105 | | * TODO(emilio): Should we move to nsIContent::BindToTree most of the |
106 | | * FragmentOrElement / CharacterData duplicated code? |
107 | | */ |
108 | | virtual nsresult BindToTree(nsIDocument* aDocument, |
109 | | nsIContent* aParent, |
110 | | nsIContent* aBindingParent) = 0; |
111 | | |
112 | | /** |
113 | | * Unbind this content node from a tree. This will set its current document |
114 | | * and binding parent to null. In the typical case of a node being removed |
115 | | * from a parent, this will be called after it has been removed from the |
116 | | * parent's child list and after the nsIDocumentObserver notifications for |
117 | | * the removal have been dispatched. |
118 | | * @param aDeep Whether to recursively unbind the entire subtree rooted at |
119 | | * this node. The only time false should be passed is when the |
120 | | * parent node of the content is being destroyed. |
121 | | * @param aNullParent Whether to null out the parent pointer as well. This |
122 | | * is usually desirable. This argument should only be false while |
123 | | * recursively calling UnbindFromTree when a subtree is detached. |
124 | | * @note This method is safe to call on nodes that are not bound to a tree. |
125 | | */ |
126 | | virtual void UnbindFromTree(bool aDeep = true, |
127 | | bool aNullParent = true) = 0; |
128 | | |
129 | | enum { |
130 | | /** |
131 | | * All XBL flattened tree children of the node, as well as :before and |
132 | | * :after anonymous content and native anonymous children. |
133 | | * |
134 | | * @note the result children order is |
135 | | * 1. :before generated node |
136 | | * 2. XBL flattened tree children of this node |
137 | | * 3. native anonymous nodes |
138 | | * 4. :after generated node |
139 | | */ |
140 | | eAllChildren = 0, |
141 | | |
142 | | /** |
143 | | * All XBL explicit children of the node (see |
144 | | * http://www.w3.org/TR/xbl/#explicit3 ), as well as :before and :after |
145 | | * anonymous content and native anonymous children. |
146 | | * |
147 | | * @note the result children order is |
148 | | * 1. :before generated node |
149 | | * 2. XBL explicit children of the node |
150 | | * 3. native anonymous nodes |
151 | | * 4. :after generated node |
152 | | */ |
153 | | eAllButXBL = 1, |
154 | | |
155 | | /** |
156 | | * Skip native anonymous content created for placeholder of HTML input, |
157 | | * used in conjunction with eAllChildren or eAllButXBL. |
158 | | */ |
159 | | eSkipPlaceholderContent = 2, |
160 | | |
161 | | /** |
162 | | * Skip native anonymous content created by ancestor frames of the root |
163 | | * element's primary frame, such as scrollbar elements created by the root |
164 | | * scroll frame. |
165 | | */ |
166 | | eSkipDocumentLevelNativeAnonymousContent = 4, |
167 | | }; |
168 | | |
169 | | /** |
170 | | * Return either the XBL explicit children of the node or the XBL flattened |
171 | | * tree children of the node, depending on the filter, as well as |
172 | | * native anonymous children. |
173 | | * |
174 | | * @note calling this method with eAllButXBL will return children that are |
175 | | * also in the eAllButXBL and eAllChildren child lists of other descendants |
176 | | * of this node in the tree, but those other nodes cannot be reached from the |
177 | | * eAllButXBL child list. |
178 | | */ |
179 | | virtual already_AddRefed<nsINodeList> GetChildren(uint32_t aFilter) = 0; |
180 | | |
181 | | /** |
182 | | * Get whether this content is C++-generated anonymous content |
183 | | * @see nsIAnonymousContentCreator |
184 | | * @return whether this content is anonymous |
185 | | */ |
186 | | bool IsRootOfNativeAnonymousSubtree() const |
187 | | { |
188 | | NS_ASSERTION(!HasFlag(NODE_IS_NATIVE_ANONYMOUS_ROOT) || |
189 | | (HasFlag(NODE_IS_ANONYMOUS_ROOT) && |
190 | | HasFlag(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE)), |
191 | | "Some flags seem to be missing!"); |
192 | | return HasFlag(NODE_IS_NATIVE_ANONYMOUS_ROOT); |
193 | | } |
194 | | |
195 | | bool IsRootOfChromeAccessOnlySubtree() const |
196 | | { |
197 | | return HasFlag(NODE_IS_NATIVE_ANONYMOUS_ROOT | |
198 | | NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS); |
199 | | } |
200 | | |
201 | | /** |
202 | | * Makes this content anonymous |
203 | | * @see nsIAnonymousContentCreator |
204 | | */ |
205 | | void SetIsNativeAnonymousRoot() |
206 | | { |
207 | | SetFlags(NODE_IS_ANONYMOUS_ROOT | NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE | |
208 | | NODE_IS_NATIVE_ANONYMOUS_ROOT); |
209 | | } |
210 | | |
211 | | /** |
212 | | * Returns |this| if it is not chrome-only/native anonymous, otherwise |
213 | | * first non chrome-only/native anonymous ancestor. |
214 | | */ |
215 | | nsIContent* FindFirstNonChromeOnlyAccessContent() const; |
216 | | |
217 | | /** |
218 | | * Returns true if and only if this node has a parent, but is not in |
219 | | * its parent's child list. |
220 | | */ |
221 | | bool IsRootOfAnonymousSubtree() const |
222 | | { |
223 | | NS_ASSERTION(!IsRootOfNativeAnonymousSubtree() || |
224 | | (GetParent() && GetBindingParent() == GetParent()), |
225 | | "root of native anonymous subtree must have parent equal " |
226 | | "to binding parent"); |
227 | | NS_ASSERTION(!GetParent() || |
228 | | ((GetBindingParent() == GetParent()) == |
229 | | HasFlag(NODE_IS_ANONYMOUS_ROOT)) || |
230 | | // Unfortunately default content for XBL insertion points is |
231 | | // anonymous content that is bound with the parent of the |
232 | | // insertion point as the parent but the bound element for the |
233 | | // binding as the binding parent. So we have to complicate |
234 | | // the assert a bit here. |
235 | | (GetBindingParent() && |
236 | | (GetBindingParent() == GetParent()->GetBindingParent()) == |
237 | | HasFlag(NODE_IS_ANONYMOUS_ROOT)), |
238 | | "For nodes with parent, flag and GetBindingParent() check " |
239 | | "should match"); |
240 | | return HasFlag(NODE_IS_ANONYMOUS_ROOT); |
241 | | } |
242 | | |
243 | | /** |
244 | | * Returns true if there is NOT a path through child lists |
245 | | * from the top of this node's parent chain back to this node or |
246 | | * if the node is in native anonymous subtree without a parent. |
247 | | */ |
248 | | inline bool IsInAnonymousSubtree() const; |
249 | | |
250 | | /** |
251 | | * Return true iff this node is in an HTML document (in the HTML5 sense of |
252 | | * the term, i.e. not in an XHTML/XML document). |
253 | | */ |
254 | | inline bool IsInHTMLDocument() const; |
255 | | |
256 | | |
257 | | /** |
258 | | * Returns true if in a chrome document |
259 | | */ |
260 | | inline bool IsInChromeDocument() const; |
261 | | |
262 | | /** |
263 | | * Get the namespace that this element's tag is defined in |
264 | | * @return the namespace |
265 | | */ |
266 | | inline int32_t GetNameSpaceID() const |
267 | | { |
268 | | return mNodeInfo->NamespaceID(); |
269 | | } |
270 | | |
271 | | inline bool IsHTMLElement() const |
272 | | { |
273 | | return IsInNamespace(kNameSpaceID_XHTML); |
274 | | } |
275 | | |
276 | | inline bool IsHTMLElement(nsAtom* aTag) const |
277 | | { |
278 | | return mNodeInfo->Equals(aTag, kNameSpaceID_XHTML); |
279 | | } |
280 | | |
281 | | template<typename First, typename... Args> |
282 | | inline bool IsAnyOfHTMLElements(First aFirst, Args... aArgs) const |
283 | 0 | { |
284 | 0 | return IsHTMLElement() && IsNodeInternal(aFirst, aArgs...); |
285 | 0 | } |
286 | | |
287 | | inline bool IsSVGElement() const |
288 | | { |
289 | | return IsInNamespace(kNameSpaceID_SVG); |
290 | | } |
291 | | |
292 | | inline bool IsSVGElement(nsAtom* aTag) const |
293 | | { |
294 | | return mNodeInfo->Equals(aTag, kNameSpaceID_SVG); |
295 | | } |
296 | | |
297 | | template<typename First, typename... Args> |
298 | | inline bool IsAnyOfSVGElements(First aFirst, Args... aArgs) const |
299 | | { |
300 | | return IsSVGElement() && IsNodeInternal(aFirst, aArgs...); |
301 | | } |
302 | | |
303 | | inline bool IsXULElement() const |
304 | | { |
305 | | return IsInNamespace(kNameSpaceID_XUL); |
306 | | } |
307 | | |
308 | | inline bool IsXULElement(nsAtom* aTag) const |
309 | | { |
310 | | return mNodeInfo->Equals(aTag, kNameSpaceID_XUL); |
311 | | } |
312 | | |
313 | | template<typename First, typename... Args> |
314 | | inline bool IsAnyOfXULElements(First aFirst, Args... aArgs) const |
315 | | { |
316 | | return IsXULElement() && IsNodeInternal(aFirst, aArgs...); |
317 | | } |
318 | | |
319 | | inline bool IsMathMLElement() const |
320 | | { |
321 | | return IsInNamespace(kNameSpaceID_MathML); |
322 | | } |
323 | | |
324 | | inline bool IsMathMLElement(nsAtom* aTag) const |
325 | | { |
326 | | return mNodeInfo->Equals(aTag, kNameSpaceID_MathML); |
327 | | } |
328 | | |
329 | | template<typename First, typename... Args> |
330 | | inline bool IsAnyOfMathMLElements(First aFirst, Args... aArgs) const |
331 | | { |
332 | | return IsMathMLElement() && IsNodeInternal(aFirst, aArgs...); |
333 | | } |
334 | | |
335 | | inline bool IsActiveChildrenElement() const; |
336 | | |
337 | | bool IsGeneratedContentContainerForBefore() const |
338 | | { |
339 | | return IsRootOfNativeAnonymousSubtree() && |
340 | | mNodeInfo->NameAtom() == nsGkAtoms::mozgeneratedcontentbefore; |
341 | | } |
342 | | |
343 | | bool IsGeneratedContentContainerForAfter() const |
344 | | { |
345 | | return IsRootOfNativeAnonymousSubtree() && |
346 | | mNodeInfo->NameAtom() == nsGkAtoms::mozgeneratedcontentafter; |
347 | | } |
348 | | |
349 | | /** |
350 | | * Get direct access (but read only) to the text in the text content. |
351 | | * NOTE: For elements this is *not* the concatenation of all text children, |
352 | | * it is simply null; |
353 | | */ |
354 | | virtual const nsTextFragment *GetText() = 0; |
355 | | |
356 | | /** |
357 | | * Get the length of the text content. |
358 | | * NOTE: This should not be called on elements. |
359 | | */ |
360 | | virtual uint32_t TextLength() const = 0; |
361 | | |
362 | | /** |
363 | | * Determines if an event attribute name (such as onclick) is valid for |
364 | | * a given element type. |
365 | | * @note calls nsContentUtils::IsEventAttributeName with right flag |
366 | | * @note *Internal is overridden by subclasses as needed |
367 | | * @param aName the event name to look up |
368 | | */ |
369 | | bool IsEventAttributeName(nsAtom* aName); |
370 | | |
371 | | virtual bool IsEventAttributeNameInternal(nsAtom* aName) |
372 | | { |
373 | | return false; |
374 | | } |
375 | | |
376 | | /** |
377 | | * Query method to see if the frame is nothing but whitespace |
378 | | * NOTE: Always returns false for elements |
379 | | */ |
380 | | virtual bool TextIsOnlyWhitespace() = 0; |
381 | | |
382 | | /** |
383 | | * Thread-safe version of TextIsOnlyWhitespace. |
384 | | */ |
385 | | virtual bool ThreadSafeTextIsOnlyWhitespace() const = 0; |
386 | | |
387 | | /** |
388 | | * Check if this content is focusable and in the current tab order. |
389 | | * Note: most callers should use nsIFrame::IsFocusable() instead as it |
390 | | * checks visibility and other layout factors as well. |
391 | | * Tabbable is indicated by a nonnegative tabindex & is a subset of focusable. |
392 | | * For example, only the selected radio button in a group is in the |
393 | | * tab order, unless the radio group has no selection in which case |
394 | | * all of the visible, non-disabled radio buttons in the group are |
395 | | * in the tab order. On the other hand, all of the visible, non-disabled |
396 | | * radio buttons are always focusable via clicking or script. |
397 | | * Also, depending on either the accessibility.tabfocus pref or |
398 | | * a system setting (nowadays: Full keyboard access, mac only) |
399 | | * some widgets may be focusable but removed from the tab order. |
400 | | * @param [inout, optional] aTabIndex the computed tab index |
401 | | * In: default tabindex for element (-1 nonfocusable, == 0 focusable) |
402 | | * Out: computed tabindex |
403 | | * @param [optional] aTabIndex the computed tab index |
404 | | * < 0 if not tabbable |
405 | | * == 0 if in normal tab order |
406 | | * > 0 can be tabbed to in the order specified by this value |
407 | | * @return whether the content is focusable via mouse, kbd or script. |
408 | | */ |
409 | | bool IsFocusable(int32_t* aTabIndex = nullptr, bool aWithMouse = false); |
410 | | virtual bool IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse); |
411 | | |
412 | | /** |
413 | | * The method focuses (or activates) element that accesskey is bound to. It is |
414 | | * called when accesskey is activated. |
415 | | * |
416 | | * @param aKeyCausesActivation - if true then element should be activated |
417 | | * @param aIsTrustedEvent - if true then event that is cause of accesskey |
418 | | * execution is trusted. |
419 | | * @return true if the focus was changed. |
420 | | */ |
421 | | virtual bool PerformAccesskey(bool aKeyCausesActivation, |
422 | | bool aIsTrustedEvent) |
423 | | { |
424 | | return false; |
425 | | } |
426 | | |
427 | | /* |
428 | | * Get desired IME state for the content. |
429 | | * |
430 | | * @return The desired IME status for the content. |
431 | | * This is a combination of an IME enabled value and |
432 | | * an IME open value of widget::IMEState. |
433 | | * If you return DISABLED, you should not set the OPEN and CLOSE |
434 | | * value. |
435 | | * PASSWORD should be returned only from password editor, this value |
436 | | * has a special meaning. It is used as alternative of DISABLED. |
437 | | * PLUGIN should be returned only when plug-in has focus. When a |
438 | | * plug-in is focused content, we should send native events directly. |
439 | | * Because we don't process some native events, but they may be needed |
440 | | * by the plug-in. |
441 | | */ |
442 | | virtual IMEState GetDesiredIMEState(); |
443 | | |
444 | | /** |
445 | | * Gets content node with the binding (or native code, possibly on the |
446 | | * frame) responsible for our construction (and existence). Used by |
447 | | * anonymous content (both XBL-generated and native-anonymous). |
448 | | * |
449 | | * null for all explicit content (i.e., content reachable from the top |
450 | | * of its GetParent() chain via child lists). |
451 | | * |
452 | | * @return the binding parent |
453 | | */ |
454 | | virtual nsIContent* GetBindingParent() const |
455 | | { |
456 | | const nsExtendedContentSlots* slots = GetExistingExtendedContentSlots(); |
457 | | return slots ? slots->mBindingParent.get() : nullptr; |
458 | | } |
459 | | |
460 | | /** |
461 | | * Gets the current XBL binding that is bound to this element. |
462 | | * |
463 | | * @return the current binding. |
464 | | */ |
465 | | nsXBLBinding* GetXBLBinding() const |
466 | | { |
467 | | if (!HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) { |
468 | | return nullptr; |
469 | | } |
470 | | |
471 | | return DoGetXBLBinding(); |
472 | | } |
473 | | |
474 | | virtual nsXBLBinding* DoGetXBLBinding() const = 0; |
475 | | |
476 | | /** |
477 | | * Gets the ShadowRoot binding for this element. |
478 | | * |
479 | | * @return The ShadowRoot currently bound to this element. |
480 | | */ |
481 | | inline mozilla::dom::ShadowRoot* GetShadowRoot() const; |
482 | | |
483 | | /** |
484 | | * Gets the root of the node tree for this content if it is in a shadow tree. |
485 | | * This method is called |GetContainingShadow| instead of |GetRootShadowRoot| |
486 | | * to avoid confusion with |GetShadowRoot|. |
487 | | * |
488 | | * @return The ShadowRoot that is the root of the node tree. |
489 | | */ |
490 | | mozilla::dom::ShadowRoot* GetContainingShadow() const |
491 | | { |
492 | | const nsExtendedContentSlots* slots = GetExistingExtendedContentSlots(); |
493 | | return slots ? slots->mContainingShadow.get() : nullptr; |
494 | | } |
495 | | |
496 | | /** |
497 | | * Gets the shadow host if this content is in a shadow tree. That is, the host |
498 | | * of |GetContainingShadow|, if its not null. |
499 | | * |
500 | | * @return The shadow host, if this is in shadow tree, or null. |
501 | | */ |
502 | | nsIContent* GetContainingShadowHost() const; |
503 | | |
504 | | /** |
505 | | * Gets the assigned slot associated with this content. |
506 | | * |
507 | | * @return The assigned slot element or null. |
508 | | */ |
509 | | mozilla::dom::HTMLSlotElement* GetAssignedSlot() const |
510 | | { |
511 | | const nsExtendedContentSlots* slots = GetExistingExtendedContentSlots(); |
512 | | return slots ? slots->mAssignedSlot.get() : nullptr; |
513 | | } |
514 | | |
515 | | /** |
516 | | * Sets the assigned slot associated with this content. |
517 | | * |
518 | | * @param aSlot The assigned slot. |
519 | | */ |
520 | | void SetAssignedSlot(mozilla::dom::HTMLSlotElement* aSlot); |
521 | | |
522 | | /** |
523 | | * Gets the assigned slot associated with this content based on parent's |
524 | | * shadow root mode. Returns null if parent's shadow root is "closed". |
525 | | * https://dom.spec.whatwg.org/#dom-slotable-assignedslot |
526 | | * |
527 | | * @return The assigned slot element or null. |
528 | | */ |
529 | | mozilla::dom::HTMLSlotElement* GetAssignedSlotByMode() const; |
530 | | |
531 | | nsIContent* GetXBLInsertionParent() const |
532 | | { |
533 | | nsIContent* ip = GetXBLInsertionPoint(); |
534 | | return ip ? ip->GetParent() : nullptr; |
535 | | } |
536 | | |
537 | | /** |
538 | | * Gets the insertion parent element of the XBL binding. |
539 | | * The insertion parent is our one true parent in the transformed DOM. |
540 | | * |
541 | | * @return the insertion parent element. |
542 | | */ |
543 | | nsIContent* GetXBLInsertionPoint() const |
544 | | { |
545 | | const nsExtendedContentSlots* slots = GetExistingExtendedContentSlots(); |
546 | | return slots ? slots->mXBLInsertionPoint.get() : nullptr; |
547 | | } |
548 | | |
549 | | /** |
550 | | * Sets the insertion parent element of the XBL binding. |
551 | | * |
552 | | * @param aContent The insertion parent element. |
553 | | */ |
554 | | void SetXBLInsertionPoint(nsIContent* aContent); |
555 | | |
556 | | /** |
557 | | * Same as GetFlattenedTreeParentNode, but returns null if the parent is |
558 | | * non-nsIContent. |
559 | | */ |
560 | | inline nsIContent* GetFlattenedTreeParent() const; |
561 | | |
562 | | /** |
563 | | * API to check if this is a link that's traversed in response to user input |
564 | | * (e.g. a click event). Specializations for HTML/SVG/generic XML allow for |
565 | | * different types of link in different types of content. |
566 | | * |
567 | | * @param aURI Required out param. If this content is a link, a new nsIURI |
568 | | * set to this link's URI will be passed out. |
569 | | * |
570 | | * @note The out param, aURI, is guaranteed to be set to a non-null pointer |
571 | | * when the return value is true. |
572 | | * |
573 | | * XXXjwatt: IMO IsInteractiveLink would be a better name. |
574 | | */ |
575 | | virtual bool IsLink(nsIURI** aURI) const = 0; |
576 | | |
577 | | /** |
578 | | * Get a pointer to the full href URI (fully resolved and canonicalized, |
579 | | * since it's an nsIURI object) for link elements. |
580 | | * |
581 | | * @return A pointer to the URI or null if the element is not a link or it |
582 | | * has no HREF attribute. |
583 | | */ |
584 | | virtual already_AddRefed<nsIURI> GetHrefURI() const |
585 | | { |
586 | | return nullptr; |
587 | | } |
588 | | |
589 | | /** |
590 | | * This method is called when the parser finishes creating the element. This |
591 | | * particularly means that it has done everything you would expect it to have |
592 | | * done after it encounters the > at the end of the tag (for HTML or XML). |
593 | | * This includes setting the attributes, setting the document / form, and |
594 | | * placing the element into the tree at its proper place. |
595 | | * |
596 | | * For container elements, this is called *before* any of the children are |
597 | | * created or added into the tree. |
598 | | * |
599 | | * NOTE: this is currently only called for input and button, in the HTML |
600 | | * content sink. If you want to call it on your element, modify the content |
601 | | * sink of your choice to do so. This is an efficiency measure. |
602 | | * |
603 | | * If you also need to determine whether the parser is the one creating your |
604 | | * element (through createElement() or cloneNode() generally) then add a |
605 | | * uint32_t aFromParser to the NS_NewXXX() constructor for your element and |
606 | | * have the parser pass the appropriate flags. See HTMLInputElement.cpp and |
607 | | * nsHTMLContentSink::MakeContentObject(). |
608 | | * |
609 | | * DO NOT USE THIS METHOD to get around the fact that it's hard to deal with |
610 | | * attributes dynamically. If you make attributes affect your element from |
611 | | * this method, it will only happen on initialization and JavaScript will not |
612 | | * be able to create elements (which requires them to first create the |
613 | | * element and then call setAttribute() directly, at which point |
614 | | * DoneCreatingElement() has already been called and is out of the picture). |
615 | | */ |
616 | | virtual void DoneCreatingElement() |
617 | | { |
618 | | } |
619 | | |
620 | | /** |
621 | | * This method is called when the parser finishes creating the element's children, |
622 | | * if any are present. |
623 | | * |
624 | | * NOTE: this is currently only called for textarea, select, and object |
625 | | * elements in the HTML content sink. If you want to call it on your element, |
626 | | * modify the content sink of your choice to do so. This is an efficiency |
627 | | * measure. |
628 | | * |
629 | | * If you also need to determine whether the parser is the one creating your |
630 | | * element (through createElement() or cloneNode() generally) then add a |
631 | | * boolean aFromParser to the NS_NewXXX() constructor for your element and |
632 | | * have the parser pass true. See HTMLInputElement.cpp and |
633 | | * nsHTMLContentSink::MakeContentObject(). |
634 | | * |
635 | | * @param aHaveNotified Whether there has been a |
636 | | * ContentInserted/ContentAppended notification for this content node |
637 | | * yet. |
638 | | */ |
639 | | virtual void DoneAddingChildren(bool aHaveNotified) |
640 | | { |
641 | | } |
642 | | |
643 | | /** |
644 | | * For HTML textarea, select, and object elements, returns true if all |
645 | | * children have been added OR if the element was not created by the parser. |
646 | | * Returns true for all other elements. |
647 | | * |
648 | | * @returns false if the element was created by the parser and |
649 | | * it is an HTML textarea, select, or object |
650 | | * element and not all children have been added. |
651 | | * |
652 | | * @returns true otherwise. |
653 | | */ |
654 | | virtual bool IsDoneAddingChildren() |
655 | | { |
656 | | return true; |
657 | | } |
658 | | |
659 | | /** |
660 | | * Get the ID of this content node (the atom corresponding to the |
661 | | * value of the id attribute). This may be null if there is no ID. |
662 | | */ |
663 | | nsAtom* GetID() const { |
664 | | if (HasID()) { |
665 | | return DoGetID(); |
666 | | } |
667 | | return nullptr; |
668 | | } |
669 | | |
670 | | /** |
671 | | * Should be called when the node can become editable or when it can stop |
672 | | * being editable (for example when its contentEditable attribute changes, |
673 | | * when it is moved into an editable parent, ...). If aNotify is true and |
674 | | * the node is an element, this will notify the state change. |
675 | | */ |
676 | | virtual void UpdateEditableState(bool aNotify); |
677 | | |
678 | | /** |
679 | | * Destroy this node and its children. Ideally this shouldn't be needed |
680 | | * but for now we need to do it to break cycles. |
681 | | */ |
682 | | virtual void DestroyContent() |
683 | | { |
684 | | } |
685 | | |
686 | | /** |
687 | | * Saves the form state of this node and its children. |
688 | | */ |
689 | | virtual void SaveSubtreeState() = 0; |
690 | | |
691 | | /** |
692 | | * Getter and setter for our primary frame pointer. This is the frame that |
693 | | * is most closely associated with the content. A frame is more closely |
694 | | * associated with the content than another frame if the one frame contains |
695 | | * directly or indirectly the other frame (e.g., when a frame is scrolled |
696 | | * there is a scroll frame that contains the frame being scrolled). This |
697 | | * frame is always the first continuation. |
698 | | * |
699 | | * In the case of absolutely positioned elements and floated elements, this |
700 | | * frame is the out of flow frame, not the placeholder. |
701 | | */ |
702 | | nsIFrame* GetPrimaryFrame() const |
703 | | { |
704 | | return (IsInUncomposedDoc() || IsInShadowTree()) ? mPrimaryFrame : nullptr; |
705 | | } |
706 | | |
707 | | // Defined in nsIContentInlines.h because it needs nsIFrame. |
708 | | inline void SetPrimaryFrame(nsIFrame* aFrame); |
709 | | |
710 | | nsresult LookupNamespaceURIInternal(const nsAString& aNamespacePrefix, |
711 | | nsAString& aNamespaceURI) const; |
712 | | |
713 | | /** |
714 | | * If this content has independent selection, e.g., if this is input field |
715 | | * or textarea, this return TRUE. Otherwise, false. |
716 | | */ |
717 | | bool HasIndependentSelection(); |
718 | | |
719 | | /** |
720 | | * If the content is a part of HTML editor, this returns editing |
721 | | * host content. When the content is in designMode, this returns its body |
722 | | * element. Also, when the content isn't editable, this returns null. |
723 | | */ |
724 | | mozilla::dom::Element* GetEditingHost(); |
725 | | |
726 | | bool SupportsLangAttr() const { |
727 | | return IsHTMLElement() || IsSVGElement() || IsXULElement(); |
728 | | } |
729 | | |
730 | | /** |
731 | | * Determining language. Look at the nearest ancestor element that has a lang |
732 | | * attribute in the XML namespace or is an HTML/SVG element and has a lang in |
733 | | * no namespace attribute. |
734 | | * |
735 | | * Returns null if no language was specified. Can return the empty atom. |
736 | | */ |
737 | | nsAtom* GetLang() const; |
738 | | |
739 | | bool GetLang(nsAString& aResult) const { |
740 | | if (auto* lang = GetLang()) { |
741 | | aResult.Assign(nsDependentAtomString(lang)); |
742 | | return true; |
743 | | } |
744 | | |
745 | | return false; |
746 | | } |
747 | | |
748 | | // Overloaded from nsINode |
749 | | virtual already_AddRefed<nsIURI> GetBaseURI(bool aTryUseXHRDocBaseURI = false) const override; |
750 | | |
751 | | // Returns base URI for style attribute. |
752 | | nsIURI* GetBaseURIForStyleAttr() const; |
753 | | |
754 | | // Returns the URL data for style attribute. |
755 | | // If aSubjectPrincipal is passed, it should be the scripted principal |
756 | | // responsible for generating the URL data. |
757 | | already_AddRefed<mozilla::URLExtraData> |
758 | | GetURLDataForStyleAttr(nsIPrincipal* aSubjectPrincipal = nullptr) const; |
759 | | |
760 | | void GetEventTargetParent(mozilla::EventChainPreVisitor& aVisitor) override; |
761 | | |
762 | | bool IsPurple() const |
763 | | { |
764 | | return mRefCnt.IsPurple(); |
765 | | } |
766 | | |
767 | | void RemovePurple() |
768 | | { |
769 | | mRefCnt.RemovePurple(); |
770 | | } |
771 | | |
772 | | bool OwnedOnlyByTheDOMTree() |
773 | | { |
774 | | uint32_t rc = mRefCnt.get(); |
775 | | if (GetParent()) { |
776 | | --rc; |
777 | | } |
778 | | rc -= GetChildCount(); |
779 | | return rc == 0; |
780 | | } |
781 | | |
782 | | protected: |
783 | | /** |
784 | | * Lazily allocated extended slots to avoid |
785 | | * that may only be instantiated when a content object is accessed |
786 | | * through the DOM. Rather than burn actual slots in the content |
787 | | * objects for each of these instance variables, we put them off |
788 | | * in a side structure that's only allocated when the content is |
789 | | * accessed through the DOM. |
790 | | */ |
791 | | class nsExtendedContentSlots |
792 | | { |
793 | | public: |
794 | | nsExtendedContentSlots(); |
795 | | virtual ~nsExtendedContentSlots(); |
796 | | |
797 | | virtual void TraverseExtendedSlots(nsCycleCollectionTraversalCallback&); |
798 | | virtual void UnlinkExtendedSlots(); |
799 | | |
800 | | virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; |
801 | | |
802 | | /** |
803 | | * The nearest enclosing content node with a binding that created us. |
804 | | * TODO(emilio): This should be an Element*. |
805 | | * |
806 | | * @see nsIContent::GetBindingParent |
807 | | */ |
808 | | nsCOMPtr<nsIContent> mBindingParent; |
809 | | |
810 | | /** |
811 | | * @see nsIContent::GetXBLInsertionPoint |
812 | | */ |
813 | | nsCOMPtr<nsIContent> mXBLInsertionPoint; |
814 | | |
815 | | /** |
816 | | * @see nsIContent::GetContainingShadow |
817 | | */ |
818 | | RefPtr<mozilla::dom::ShadowRoot> mContainingShadow; |
819 | | |
820 | | /** |
821 | | * @see nsIContent::GetAssignedSlot |
822 | | */ |
823 | | RefPtr<mozilla::dom::HTMLSlotElement> mAssignedSlot; |
824 | | }; |
825 | | |
826 | | class nsContentSlots : public nsINode::nsSlots |
827 | | { |
828 | | public: |
829 | | nsContentSlots() |
830 | | : nsINode::nsSlots() |
831 | | , mExtendedSlots(0) |
832 | | { |
833 | | } |
834 | | |
835 | | ~nsContentSlots() |
836 | | { |
837 | | if (!(mExtendedSlots & sNonOwningExtendedSlotsFlag)) { |
838 | | delete GetExtendedContentSlots(); |
839 | | } |
840 | | } |
841 | | |
842 | | void Traverse(nsCycleCollectionTraversalCallback& aCb) override |
843 | | { |
844 | | nsINode::nsSlots::Traverse(aCb); |
845 | | if (mExtendedSlots) { |
846 | | GetExtendedContentSlots()->TraverseExtendedSlots(aCb); |
847 | | } |
848 | | } |
849 | | |
850 | | void Unlink() override |
851 | | { |
852 | | nsINode::nsSlots::Unlink(); |
853 | | if (mExtendedSlots) { |
854 | | GetExtendedContentSlots()->UnlinkExtendedSlots(); |
855 | | } |
856 | | } |
857 | | |
858 | | void SetExtendedContentSlots(nsExtendedContentSlots* aSlots, bool aOwning) |
859 | | { |
860 | | mExtendedSlots = reinterpret_cast<uintptr_t>(aSlots); |
861 | | if (!aOwning) { |
862 | | mExtendedSlots |= sNonOwningExtendedSlotsFlag; |
863 | | } |
864 | | } |
865 | | |
866 | | // OwnsExtendedSlots returns true if we have no extended slots or if we |
867 | | // have extended slots and own them. |
868 | | bool OwnsExtendedSlots() const |
869 | | { |
870 | | return !(mExtendedSlots & sNonOwningExtendedSlotsFlag); |
871 | | } |
872 | | |
873 | | nsExtendedContentSlots* GetExtendedContentSlots() const |
874 | | { |
875 | | return reinterpret_cast<nsExtendedContentSlots*>( |
876 | | mExtendedSlots & ~sNonOwningExtendedSlotsFlag); |
877 | | } |
878 | | |
879 | | private: |
880 | | static const uintptr_t sNonOwningExtendedSlotsFlag = 1u; |
881 | | |
882 | | uintptr_t mExtendedSlots; |
883 | | }; |
884 | | |
885 | | // Override from nsINode |
886 | | nsContentSlots* CreateSlots() override |
887 | | { |
888 | | return new nsContentSlots(); |
889 | | } |
890 | | |
891 | | nsContentSlots* ContentSlots() |
892 | | { |
893 | | return static_cast<nsContentSlots*>(Slots()); |
894 | | } |
895 | | |
896 | | const nsContentSlots* GetExistingContentSlots() const |
897 | | { |
898 | | return static_cast<nsContentSlots*>(GetExistingSlots()); |
899 | | } |
900 | | |
901 | | nsContentSlots* GetExistingContentSlots() |
902 | | { |
903 | | return static_cast<nsContentSlots*>(GetExistingSlots()); |
904 | | } |
905 | | |
906 | | virtual nsExtendedContentSlots* CreateExtendedSlots() |
907 | | { |
908 | | return new nsExtendedContentSlots(); |
909 | | } |
910 | | |
911 | | const nsExtendedContentSlots* GetExistingExtendedContentSlots() const |
912 | | { |
913 | | const nsContentSlots* slots = GetExistingContentSlots(); |
914 | | return slots ? slots->GetExtendedContentSlots() : nullptr; |
915 | | } |
916 | | |
917 | | nsExtendedContentSlots* GetExistingExtendedContentSlots() |
918 | | { |
919 | | nsContentSlots* slots = GetExistingContentSlots(); |
920 | | return slots ? slots->GetExtendedContentSlots() : nullptr; |
921 | | } |
922 | | |
923 | | nsExtendedContentSlots* ExtendedContentSlots() |
924 | | { |
925 | | nsContentSlots* slots = ContentSlots(); |
926 | | if (!slots->GetExtendedContentSlots()) { |
927 | | slots->SetExtendedContentSlots(CreateExtendedSlots(), true); |
928 | | } |
929 | | return slots->GetExtendedContentSlots(); |
930 | | } |
931 | | |
932 | | /** |
933 | | * Hook for implementing GetID. This is guaranteed to only be |
934 | | * called if HasID() is true. |
935 | | */ |
936 | | nsAtom* DoGetID() const; |
937 | | |
938 | | ~nsIContent() {} |
939 | | |
940 | | public: |
941 | | #ifdef DEBUG |
942 | | /** |
943 | | * List the content (and anything it contains) out to the given |
944 | | * file stream. Use aIndent as the base indent during formatting. |
945 | | */ |
946 | | virtual void List(FILE* out = stdout, int32_t aIndent = 0) const = 0; |
947 | | |
948 | | /** |
949 | | * Dump the content (and anything it contains) out to the given |
950 | | * file stream. Use aIndent as the base indent during formatting. |
951 | | */ |
952 | | virtual void DumpContent(FILE* out = stdout, int32_t aIndent = 0, |
953 | | bool aDumpAll = true) const = 0; |
954 | | #endif |
955 | | |
956 | | enum ETabFocusType { |
957 | | eTabFocus_textControlsMask = (1<<0), // textboxes and lists always tabbable |
958 | | eTabFocus_formElementsMask = (1<<1), // non-text form elements |
959 | | eTabFocus_linksMask = (1<<2), // links |
960 | | eTabFocus_any = 1 + (1<<1) + (1<<2) // everything that can be focused |
961 | | }; |
962 | | |
963 | | // Tab focus model bit field: |
964 | | static int32_t sTabFocusModel; |
965 | | |
966 | | // accessibility.tabfocus_applies_to_xul pref - if it is set to true, |
967 | | // the tabfocus bit field applies to xul elements. |
968 | | static bool sTabFocusModelAppliesToXUL; |
969 | | }; |
970 | | |
971 | | NS_DEFINE_STATIC_IID_ACCESSOR(nsIContent, NS_ICONTENT_IID) |
972 | | |
973 | | inline nsIContent* nsINode::AsContent() |
974 | | { |
975 | | MOZ_ASSERT(IsContent()); |
976 | | return static_cast<nsIContent*>(this); |
977 | | } |
978 | | |
979 | | inline const nsIContent* nsINode::AsContent() const |
980 | | { |
981 | | return const_cast<nsINode*>(this)->AsContent(); |
982 | | } |
983 | | |
984 | | #endif /* nsIContent_h___ */ |