summaryrefslogtreecommitdiffstats
path: root/dom/base/FragmentOrElement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/base/FragmentOrElement.cpp')
-rw-r--r--dom/base/FragmentOrElement.cpp207
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();
}
}