Bug 265894 - Part 4. Selectors should not cross use-element shadow tree boundary. draft
authorcku <cku@mozilla.com>
Thu, 08 Jun 2017 14:46:52 +0800
changeset 593194 a9f44072e5083c53f23535700ef3ec0a8eeda523
parent 593193 332645facff15586c6f761011ba8093c79097d85
child 593195 20c2da279ab4334fc2a9bcaeba87b1fee6bb77a7
push id63626
push userbmo:cku@mozilla.com
push dateTue, 13 Jun 2017 09:27:54 +0000
bugs265894
milestone55.0a1
Bug 265894 - Part 4. Selectors should not cross use-element shadow tree boundary. MozReview-Commit-ID: DVYGUba6FD9
dom/base/Element.h
dom/svg/nsSVGElement.cpp
dom/svg/nsSVGElement.h
layout/style/nsCSSRuleProcessor.cpp
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -1345,16 +1345,26 @@ public:
   void RegisterIntersectionObserver(DOMIntersectionObserver* aObserver);
   void UnregisterIntersectionObserver(DOMIntersectionObserver* aObserver);
   bool UpdateIntersectionObservation(DOMIntersectionObserver* aObserver, int32_t threshold);
 
   virtual nsIAtom* GetTagNameAtom() const {
     return mNodeInfo->NameAtom();
   }
 
+  /*
+   * Mostly, this function is equal to GetParent, except for the root element
+   * of a use-element shadow tree.
+   *
+   * (Referes to nsSVGElement::GetParentInShadowTree)
+   */
+  virtual nsIContent* GetParentInsideUseElementShadowTree() const {
+    return GetParent();
+  }
+
 protected:
   /*
    * Named-bools for use with SetAttrAndNotify to make call sites easier to
    * read.
    */
   static const bool kFireMutationEvent           = true;
   static const bool kDontFireMutationEvent       = false;
   static const bool kNotifyDocumentObservers     = true;
--- a/dom/svg/nsSVGElement.cpp
+++ b/dom/svg/nsSVGElement.cpp
@@ -1352,16 +1352,34 @@ nsSVGElement::UpdateContentDeclarationBl
 }
 
 const DeclarationBlock*
 nsSVGElement::GetContentDeclarationBlock() const
 {
   return mContentDeclarationBlock;
 }
 
+nsIContent* nsSVGElement::GetParentInsideUseElementShadowTree() const
+{
+  MOZ_ASSERT(IsAnonymousContentInSVGUseSubtree(),
+             "Used only if this element is inside of an use element tree.");
+
+  nsIContent* parent = GetParent();
+  if (!parent) {
+    return nullptr;
+  }
+
+  // Do not get parent cross the boundary of an use-element shadow tree .
+  Element* parentElement = parent->AsElement();
+  if (parentElement && parentElement->IsSVGElement(nsGkAtoms::use)) {
+    return nullptr;
+  }
+
+  return parent;
+}
 /**
  * Helper methods for the type-specific WillChangeXXX methods.
  *
  * This method sends out appropriate pre-change notifications so that selector
  * restyles (e.g. due to changes that cause |elem[attr="val"]| to start/stop
  * matching) work, and it returns an nsAttrValue that _may_ contain the
  * attribute's pre-change value.
  *
--- a/dom/svg/nsSVGElement.h
+++ b/dom/svg/nsSVGElement.h
@@ -330,16 +330,18 @@ public:
   already_AddRefed<mozilla::dom::SVGAnimatedString> ClassName();
 
   virtual bool IsSVGFocusable(bool* aIsFocusable, int32_t* aTabIndex);
   virtual bool IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse) override;
 
   void UpdateContentDeclarationBlock(mozilla::StyleBackendType aBackend);
   const mozilla::DeclarationBlock* GetContentDeclarationBlock() const;
 
+  virtual nsIContent* GetParentInsideUseElementShadowTree() const override;
+
 protected:
   virtual JSObject* WrapNode(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
 
 #ifdef DEBUG
   // We define BeforeSetAttr here and mark it final to ensure it is NOT used
   // by SVG elements.
   // This is because we're not currently passing the correct value for aValue to
   // BeforeSetAttr since it would involve allocating extra SVG value types.
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -2411,17 +2411,20 @@ SelectorMatchesTree(Element* aPrevElemen
           parent->SetFlags(NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS);
 
         element = prevElement->GetPreviousElementSibling();
       }
     }
     // for descendant combinators and child combinators, the element
     // to test against is the parent
     else {
-      nsIContent *content = prevElement->GetParent();
+      nsIContent *content =
+        prevElement->IsInAnonymousSubtree() && prevElement->IsAnonymousContentInSVGUseSubtree()
+          ? prevElement->GetParentInsideUseElementShadowTree()
+          : prevElement->GetParent();
       // GetParent could return a document fragment; we only want
       // element parents.
       if (content && content->IsElement()) {
         element = content->AsElement();
         if (aTreeMatchContext.mForScopedStyle) {
           // We are moving up to the parent element; tell the
           // TreeMatchContext, so that in case this element is the
           // style scope element, selector matching stops before we