Bug 265894 - Part 2. A cloned symbol element instance should not match rules of svg tag. draft
authorcku <cku@mozilla.com>
Wed, 07 Jun 2017 17:24:29 +0800
changeset 593192 edd913d0ca7b8f71094f77079d1a46c0e8b214bd
parent 593185 be0da3b45640edcb27bf73c962e177e25d5b88dd
child 593193 332645facff15586c6f761011ba8093c79097d85
push id63626
push userbmo:cku@mozilla.com
push dateTue, 13 Jun 2017 09:27:54 +0000
bugs265894
milestone55.0a1
Bug 265894 - Part 2. A cloned symbol element instance should not match rules of svg tag. Gecko did not implement SymbolFrame for layouting and rendering a cloned symbol element instance. Instead, we leverage SVGSVGElement and nsSVGInnerFrame to render a symbol element. As a result, when we match rules for a svg element, we need to tell whether this svg element is indeed an svg element, or it a bogus one, used to represent a symbol one. In this patch, we used SVGSVGElement::mCloneFromSymbol flag to tell whether an SVG element is truely an SVG element. MozReview-Commit-ID: Hx2dtWhVEEu
dom/base/Element.h
dom/svg/SVGSVGElement.cpp
dom/svg/SVGSVGElement.h
layout/style/nsCSSRuleProcessor.cpp
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -1341,16 +1341,20 @@ public:
   // Callback for destructor of dataset to ensure to null out our weak pointer
   // to it.
   void ClearDataset();
 
   void RegisterIntersectionObserver(DOMIntersectionObserver* aObserver);
   void UnregisterIntersectionObserver(DOMIntersectionObserver* aObserver);
   bool UpdateIntersectionObservation(DOMIntersectionObserver* aObserver, int32_t threshold);
 
+  virtual nsIAtom* GetTagNameAtom() const {
+    return mNodeInfo->NameAtom();
+  }
+
 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/SVGSVGElement.cpp
+++ b/dom/svg/SVGSVGElement.cpp
@@ -178,17 +178,18 @@ SVGSVGElement::SVGSVGElement(already_Add
     mCurrentTranslate(0.0f, 0.0f),
     mCurrentScale(1.0f),
     mPreviousTranslate(0.0f, 0.0f),
     mPreviousScale(1.0f),
     mStartAnimationOnBindToTree(aFromParser == NOT_FROM_PARSER ||
                                 aFromParser == FROM_PARSER_FRAGMENT ||
                                 aFromParser == FROM_PARSER_XSLT),
     mImageNeedsTransformInvalidation(false),
-    mHasChildrenOnlyTransform(false)
+    mHasChildrenOnlyTransform(false),
+    mCloneFromSymbol(false)
 {
 }
 
 //----------------------------------------------------------------------
 // nsIDOMNode methods
 
 // From NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGSVGElement)
 nsresult
@@ -1234,13 +1235,15 @@ SVGSVGElement::CloneFromSymbol(Element* 
   // move the children over
   uint32_t num = aSymbol->GetChildCount();
   for (i = 0; i < num; i++) {
     nsCOMPtr<nsIContent> child = aSymbol->GetFirstChild();
     aSymbol->RemoveChildAt(0, false);
     svgNode->InsertChildAt(child, i, true);
   }
 
+  static_cast<SVGSVGElement*>(svgNode.get())->mCloneFromSymbol = true;
+
   return svgNode.forget();
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/svg/SVGSVGElement.h
+++ b/dom/svg/SVGSVGElement.h
@@ -254,16 +254,21 @@ public:
 
   void SetViewportSize(const svgFloatSize& aSize) {
     mViewportWidth  = aSize.width;
     mViewportHeight = aSize.height;
   }
 
   static already_AddRefed<nsIContent> CloneFromSymbol(Element* aShadowHost,
                                                       nsIContent* aSymbol);
+
+  virtual nsIAtom* GetTagNameAtom() const {
+    return mCloneFromSymbol ? nsGkAtoms::symbol
+                            : mNodeInfo->NameAtom();
+  }
   // WebIDL
   already_AddRefed<SVGAnimatedLength> X();
   already_AddRefed<SVGAnimatedLength> Y();
   already_AddRefed<SVGAnimatedLength> Width();
   already_AddRefed<SVGAnimatedLength> Height();
   float PixelUnitToMillimeterX();
   float PixelUnitToMillimeterY();
   float ScreenPixelToMillimeterX();
@@ -419,16 +424,21 @@ private:
 
   // For outermost <svg> elements created from parsing, animation is started by
   // the onload event in accordance with the SVG spec, but for <svg> elements
   // created by script or promoted from inner <svg> to outermost <svg> we need
   // to manually kick off animation when they are bound to the tree.
   bool     mStartAnimationOnBindToTree;
   bool     mImageNeedsTransformInvalidation;
   bool     mHasChildrenOnlyTransform;
+  // A flag to indicate this svg element is cloned from a symbol element and
+  // is used to represent a symbol element as a element instance inside an
+  // use-element shadow tree. We did this because the behavior of a cloned
+  // symbol is pretty much the same with an svg element.
+  bool     mCloneFromSymbol;
 };
 
 } // namespace dom
 
 class MOZ_RAII AutoPreserveAspectRatioOverride
 {
 public:
   AutoPreserveAspectRatioOverride(const Maybe<SVGImageContext>& aSVGContext,
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -607,17 +607,17 @@ static inline
 void ContentEnumFunc(const RuleValue &value, nsCSSSelector* selector,
                      ElementDependentRuleProcessorData* data, NodeMatchContext& nodeContext,
                      AncestorFilter *ancestorFilter);
 
 void RuleHash::EnumerateAllRules(Element* aElement, ElementDependentRuleProcessorData* aData,
                                  NodeMatchContext& aNodeContext)
 {
   int32_t nameSpace = aElement->GetNameSpaceID();
-  nsIAtom* tag = aElement->NodeInfo()->NameAtom();
+  nsIAtom* tag = aElement->GetTagNameAtom();
   nsIAtom* id = aElement->GetID();
   const nsAttrValue* classList = aElement->GetClasses();
 
   MOZ_ASSERT(tag, "How could we not have a tag?");
 
   int32_t classCount = classList ? classList->GetAtomCount() : 0;
 
   // assume 1 universal, tag, id, and namespace, rather than wasting
@@ -1871,17 +1871,17 @@ static bool SelectorMatches(Element* aEl
   if ((kNameSpaceID_Unknown != aSelector->mNameSpace &&
        aElement->GetNameSpaceID() != aSelector->mNameSpace))
     return false;
 
   if (aSelector->mLowercaseTag) {
     nsIAtom* selectorTag =
       (aTreeMatchContext.mIsHTMLDocument && aElement->IsHTMLElement()) ?
         aSelector->mLowercaseTag : aSelector->mCasedTag;
-    if (selectorTag != aElement->NodeInfo()->NameAtom()) {
+    if (selectorTag != aElement->GetTagNameAtom()) {
       return false;
     }
   }
 
   nsAtomList* IDList = aSelector->mIDList;
   if (IDList) {
     nsIAtom* id = aElement->GetID();
     if (id) {