diff options
Diffstat (limited to 'dom/base/FragmentOrElement.cpp')
-rw-r--r-- | dom/base/FragmentOrElement.cpp | 207 |
1 files changed, 124 insertions, 83 deletions
diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp index 526c3c9d4..6fbe04d25 100644 --- a/dom/base/FragmentOrElement.cpp +++ b/dom/base/FragmentOrElement.cpp @@ -123,6 +123,7 @@ #include "mozilla/CORSMode.h" #include "mozilla/dom/ShadowRoot.h" +#include "mozilla/dom/HTMLSlotElement.h" #include "mozilla/dom/HTMLTemplateElement.h" #include "nsStyledElement.h" @@ -151,8 +152,56 @@ nsIContent::FindFirstNonChromeOnlyAccessContent() const return nullptr; } +// https://dom.spec.whatwg.org/#dom-slotable-assignedslot +HTMLSlotElement* +nsIContent::GetAssignedSlotByMode() const +{ + /** + * Get slotable's assigned slot for the result of + * find a slot with open flag UNSET [1]. + * + * [1] https://dom.spec.whatwg.org/#assign-a-slot + */ + HTMLSlotElement* slot = GetAssignedSlot(); + if (!slot) { + return nullptr; + } + + MOZ_ASSERT(GetParent()); + MOZ_ASSERT(GetParent()->GetShadowRoot()); + + /** + * Additional check for open flag SET: + * If slotable’s parent’s shadow root's mode is not "open", + * then return null. + */ + if (GetParent()->GetShadowRoot()->IsClosed()) { + return nullptr; + } + + return slot; +} + +nsINode* +nsIContent::GetFlattenedTreeParentForMaybeAssignedNode() const +{ + if (HTMLSlotElement* assignedSlot = GetAssignedSlot()) { + return assignedSlot; + } + + HTMLSlotElement* parentSlot = HTMLSlotElement::FromContent(GetParent()); + if (!parentSlot) { + return nullptr; + } + + // If this is not an unassigned node, then it must be a fallback content. + MOZ_ASSERT(parentSlot->AssignedNodes().IsEmpty()); + + return parentSlot; +} + nsINode* -nsIContent::GetFlattenedTreeParentNodeInternal() const +nsIContent::GetFlattenedTreeParentNodeInternal(FlattenedParentType aType) const { nsINode* parentNode = GetParentNode(); if (!parentNode || !parentNode->IsContent()) { @@ -161,18 +210,51 @@ nsIContent::GetFlattenedTreeParentNodeInternal() const } nsIContent* parent = parentNode->AsContent(); + if (aType == eForStyle && + IsRootOfNativeAnonymousSubtree() && + OwnerDoc()->GetRootElement() == parent) { + // When getting the flattened tree parent for style, we return null + // for any "document level" native anonymous content subtree root. + // This is NAC generated by an ancestor frame of the document element's + // primary frame, and includes scrollbar elements created by the root + // scroll frame, and the "custom content container" and accessible caret + // generated by the nsCanvasFrame. We distinguish document level NAC + // from NAC generated by the root element's primary frame below. + nsIFrame* parentFrame = parent->GetPrimaryFrame(); + if (!parentFrame) { + // If the root element has no primary frame, it means it can't have + // generated any NAC itself. Thus any NAC we have here must have + // been generated by an ancestor frame. + // + // If we are in here, then either the root element is display:none, or + // we are in the middle of constructing the root of the frame tree and + // we are trying to eagerly restyle document level NAC in + // nsCSSFrameConstructor::GetAnonymousContent before the root + // element's frame has been constructed. + return nullptr; + } + nsIAnonymousContentCreator* creator = do_QueryFrame(parentFrame); + if (!creator) { + // If the root element does have a frame, but does not implement + // nsIAnonymousContentCreator, then this must be document level NAC. + return nullptr; + } + AutoTArray<nsIContent*, 8> elements; + creator->AppendAnonymousContentTo(elements, 0); + if (!elements.Contains(this)) { + // If the root element does have a frame, and also does implement + // nsIAnonymousContentCreator, but didn't create this node, then + // it must be document level NAC. + return nullptr; + } + } + if (parent && nsContentUtils::HasDistributedChildren(parent) && nsContentUtils::IsInSameAnonymousTree(parent, this)) { - // This node is distributed to insertion points, thus we - // need to consult the destination insertion points list to - // figure out where this node was inserted in the flattened tree. - // It may be the case that |parent| distributes its children - // but the child does not match any insertion points, thus - // the flattened tree parent is nullptr. - nsTArray<nsIContent*>* destInsertionPoints = GetExistingDestInsertionPoints(); - parent = destInsertionPoints && !destInsertionPoints->IsEmpty() ? - destInsertionPoints->LastElement()->GetParent() : nullptr; - } else if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) { + return GetFlattenedTreeParentForMaybeAssignedNode(); + } + + if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) { nsIContent* insertionParent = GetXBLInsertionParent(); if (insertionParent) { parent = insertionParent; @@ -575,6 +657,9 @@ FragmentOrElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb) NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mContainingShadow"); cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mExtendedSlots->mContainingShadow)); + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mAssignedSlot"); + cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mExtendedSlots->mAssignedSlot.get())); + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mXBLBinding"); cb.NoteNativeChild(mExtendedSlots->mXBLBinding, NS_CYCLE_COLLECTION_PARTICIPANT(nsXBLBinding)); @@ -618,6 +703,7 @@ FragmentOrElement::nsDOMSlots::Unlink() mExtendedSlots->mLabelsList = nullptr; mExtendedSlots->mShadowRoot = nullptr; mExtendedSlots->mContainingShadow = nullptr; + mExtendedSlots->mAssignedSlot = nullptr; MOZ_ASSERT(!(mExtendedSlots->mXBLBinding)); mExtendedSlots->mXBLInsertionParent = nullptr; if (mExtendedSlots->mCustomElementData) { @@ -718,7 +804,7 @@ FindChromeAccessOnlySubtreeOwner(nsIContent* aContent) } nsresult -nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor) +nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor) { //FIXME! Document how this event retargeting works, Bug 329124. aVisitor.mCanHandle = true; @@ -727,6 +813,7 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor) // Don't propagate mouseover and mouseout events when mouse is moving // inside chrome access only content. bool isAnonForEvents = IsRootOfChromeAccessOnlySubtree(); + aVisitor.mRootOfClosedTree = isAnonForEvents; if ((aVisitor.mEvent->mMessage == eMouseOver || aVisitor.mEvent->mMessage == eMouseOut || aVisitor.mEvent->mMessage == ePointerOver || @@ -738,7 +825,7 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor) ((this == aVisitor.mEvent->mOriginalTarget && !ChromeOnlyAccess()) || isAnonForEvents || GetShadowRoot())) { nsCOMPtr<nsIContent> relatedTarget = - do_QueryInterface(aVisitor.mEvent->AsMouseEvent()->relatedTarget); + do_QueryInterface(aVisitor.mEvent->AsMouseEvent()->mRelatedTarget); if (relatedTarget && relatedTarget->OwnerDoc() == OwnerDoc()) { @@ -748,7 +835,7 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor) nsIContent* adjustedTarget = Event::GetShadowRelatedTarget(this, relatedTarget); if (this == adjustedTarget) { - aVisitor.mParentTarget = nullptr; + aVisitor.SetParentTarget(nullptr, false); aVisitor.mCanHandle = false; return NS_OK; } @@ -805,7 +892,7 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor) originalTarget->FindFirstNonChromeOnlyAccessContent()) ? "" : "Wrong event propagation!?!\n"); #endif - aVisitor.mParentTarget = nullptr; + aVisitor.SetParentTarget(nullptr, false); // Event should not propagate to non-anon content. aVisitor.mCanHandle = isAnonForEvents; return NS_OK; @@ -816,58 +903,10 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor) } } - nsIContent* parent = GetParent(); - - // Web components have a special event chain that need to account - // for destination insertion points where nodes have been distributed. - nsTArray<nsIContent*>* destPoints = GetExistingDestInsertionPoints(); - if (destPoints && !destPoints->IsEmpty()) { - // Push destination insertion points to aVisitor.mDestInsertionPoints - // excluding shadow insertion points. - bool didPushNonShadowInsertionPoint = false; - for (uint32_t i = 0; i < destPoints->Length(); i++) { - nsIContent* point = destPoints->ElementAt(i); - if (!ShadowRoot::IsShadowInsertionPoint(point)) { - aVisitor.mDestInsertionPoints.AppendElement(point); - didPushNonShadowInsertionPoint = true; - } - } - - // Next node in the event path is the final destination - // (non-shadow) insertion point that was pushed. - if (didPushNonShadowInsertionPoint) { - parent = aVisitor.mDestInsertionPoints.LastElement(); - aVisitor.mDestInsertionPoints.SetLength( - aVisitor.mDestInsertionPoints.Length() - 1); - } - } - - ShadowRoot* thisShadowRoot = ShadowRoot::FromNode(this); - if (thisShadowRoot) { - if (!aVisitor.mEvent->mFlags.mComposed) { - // If we do stop propagation, we still want to propagate - // the event to chrome (nsPIDOMWindow::GetParentTarget()). - // The load event is special in that we don't ever propagate it - // to chrome. - nsCOMPtr<nsPIDOMWindowOuter> win = OwnerDoc()->GetWindow(); - EventTarget* parentTarget = win && aVisitor.mEvent->mMessage != eLoad - ? win->GetParentTarget() : nullptr; - - aVisitor.mParentTarget = parentTarget; - return NS_OK; - } - - if (!aVisitor.mDestInsertionPoints.IsEmpty()) { - parent = aVisitor.mDestInsertionPoints.LastElement(); - aVisitor.mDestInsertionPoints.SetLength( - aVisitor.mDestInsertionPoints.Length() - 1); - } else { - // The pool host for the youngest shadow root is shadow DOM host, - // for older shadow roots, it is the shadow insertion point - // where the shadow root is projected, nullptr if none exists. - parent = thisShadowRoot->GetPoolHost(); - } - } + // Event parent is the assigned slot, if node is assigned, or node's parent + // otherwise. + HTMLSlotElement* slot = GetAssignedSlot(); + nsIContent* parent = slot ? slot : GetParent(); // Event may need to be retargeted if this is the root of a native // anonymous content subtree or event is dispatched somewhere inside XBL. @@ -905,11 +944,17 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor) if (!aVisitor.mEvent->mFlags.mComposedInNativeAnonymousContent && IsRootOfNativeAnonymousSubtree() && OwnerDoc() && OwnerDoc()->GetWindow()) { - aVisitor.mParentTarget = OwnerDoc()->GetWindow()->GetParentTarget(); + aVisitor.SetParentTarget(OwnerDoc()->GetWindow()->GetParentTarget(), true); } else if (parent) { - aVisitor.mParentTarget = parent; + aVisitor.SetParentTarget(parent, false); + if (slot) { + ShadowRoot* root = slot->GetContainingShadow(); + if (root && root->IsClosed()) { + aVisitor.mParentIsSlotInClosedTree = true; + } + } } else { - aVisitor.mParentTarget = GetComposedDoc(); + aVisitor.SetParentTarget(GetComposedDoc(), false); } return NS_OK; } @@ -1086,21 +1131,18 @@ FragmentOrElement::SetShadowRoot(ShadowRoot* aShadowRoot) slots->mShadowRoot = aShadowRoot; } -nsTArray<nsIContent*>& -FragmentOrElement::DestInsertionPoints() +HTMLSlotElement* +FragmentOrElement::GetAssignedSlot() const { - nsExtendedDOMSlots* slots = ExtendedDOMSlots(); - return slots->mDestInsertionPoints; + nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots(); + return slots ? slots->mAssignedSlot.get() : nullptr; } -nsTArray<nsIContent*>* -FragmentOrElement::GetExistingDestInsertionPoints() const +void +FragmentOrElement::SetAssignedSlot(HTMLSlotElement* aSlot) { - nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots(); - if (slots) { - return &slots->mDestInsertionPoints; - } - return nullptr; + nsExtendedDOMSlots* slots = ExtendedDOMSlots(); + slots->mAssignedSlot = aSlot; } void @@ -2368,9 +2410,8 @@ FragmentOrElement::SetIsElementInStyleScopeFlagOnShadowTree(bool aInStyleScope) NS_ASSERTION(IsElement(), "calling SetIsElementInStyleScopeFlagOnShadowTree " "on a non-Element is useless"); ShadowRoot* shadowRoot = GetShadowRoot(); - while (shadowRoot) { + if (shadowRoot) { shadowRoot->SetIsElementInStyleScopeFlagOnSubtree(aInStyleScope); - shadowRoot = shadowRoot->GetOlderShadowRoot(); } } |