Bug 652991 - Part 3. Using FragmentOrURL to represent SVG maker url. draft
authorcku <cku@mozilla.com>
Fri, 24 Jun 2016 02:11:51 +0800
changeset 395498 d5e7a1efd379d8b85d5a347f5e778529de4492b7
parent 395497 46fd63b7849ce6ad93365b2c41941b4d1419d34e
child 395499 d73aaf717522406a38ac65f4d520e81b8f1dbda5
push id24801
push usercku@mozilla.com
push dateTue, 02 Aug 2016 14:45:11 +0000
bugs652991
milestone51.0a1
Bug 652991 - Part 3. Using FragmentOrURL to represent SVG maker url. MozReview-Commit-ID: IQDGL7j5p1q
layout/style/nsComputedDOMStyle.cpp
layout/style/nsRuleNode.cpp
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
layout/svg/nsSVGEffects.cpp
layout/svg/nsSVGEffects.h
layout/svg/nsSVGPathGeometryFrame.cpp
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -5598,51 +5598,51 @@ nsComputedDOMStyle::DoGetStroke()
 {
   return GetSVGPaintFor(false);
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetMarkerEnd()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-
-  const nsStyleSVG* svg = StyleSVG();
-
-  if (svg->mMarkerEnd)
-    val->SetURI(svg->mMarkerEnd);
+  // Bug 1288812 - we should only serialize fragment for local-ref URL.
+  nsCOMPtr<nsIURI> markerURI = StyleSVG()->mMarkerEnd.GetSourceURL();
+
+  if (markerURI)
+    val->SetURI(markerURI);
   else
     val->SetIdent(eCSSKeyword_none);
 
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetMarkerMid()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-
-  const nsStyleSVG* svg = StyleSVG();
-
-  if (svg->mMarkerMid)
-    val->SetURI(svg->mMarkerMid);
+  // Bug 1288812 - we should only serialize fragment for local-ref URL.
+  nsCOMPtr<nsIURI> markerURI = StyleSVG()->mMarkerMid.GetSourceURL();
+
+  if (markerURI)
+    val->SetURI(markerURI);
   else
     val->SetIdent(eCSSKeyword_none);
 
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetMarkerStart()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-
-  const nsStyleSVG* svg = StyleSVG();
-
-  if (svg->mMarkerStart)
-    val->SetURI(svg->mMarkerStart);
+  // Bug 1288812 - we should only serialize fragment for local-ref URL.
+  nsCOMPtr<nsIURI> markerURI = StyleSVG()->mMarkerStart.GetSourceURL();
+
+  if (markerURI)
+    val->SetURI(markerURI);
   else
     val->SetIdent(eCSSKeyword_none);
 
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetStrokeDasharray()
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -9362,46 +9362,46 @@ nsRuleNode::ComputeSVGData(void* aStartS
            svg->mFillRule, conditions,
            SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
            parentSVG->mFillRule,
            NS_STYLE_FILL_RULE_NONZERO);
 
   // marker-end: url, none, inherit
   const nsCSSValue* markerEndValue = aRuleData->ValueForMarkerEnd();
   if (eCSSUnit_URL == markerEndValue->GetUnit()) {
-    svg->mMarkerEnd = markerEndValue->GetURLValue();
+    svg->mMarkerEnd.SetValue(markerEndValue);
   } else if (eCSSUnit_None == markerEndValue->GetUnit() ||
              eCSSUnit_Initial == markerEndValue->GetUnit()) {
-    svg->mMarkerEnd = nullptr;
+    svg->mMarkerEnd.SetNull();
   } else if (eCSSUnit_Inherit == markerEndValue->GetUnit() ||
              eCSSUnit_Unset == markerEndValue->GetUnit()) {
     conditions.SetUncacheable();
     svg->mMarkerEnd = parentSVG->mMarkerEnd;
   }
 
   // marker-mid: url, none, inherit
   const nsCSSValue* markerMidValue = aRuleData->ValueForMarkerMid();
   if (eCSSUnit_URL == markerMidValue->GetUnit()) {
-    svg->mMarkerMid = markerMidValue->GetURLValue();
+    svg->mMarkerMid.SetValue(markerMidValue);
   } else if (eCSSUnit_None == markerMidValue->GetUnit() ||
              eCSSUnit_Initial == markerMidValue->GetUnit()) {
-    svg->mMarkerMid = nullptr;
+    svg->mMarkerMid.SetNull();
   } else if (eCSSUnit_Inherit == markerMidValue->GetUnit() ||
              eCSSUnit_Unset == markerMidValue->GetUnit()) {
     conditions.SetUncacheable();
     svg->mMarkerMid = parentSVG->mMarkerMid;
   }
 
   // marker-start: url, none, inherit
   const nsCSSValue* markerStartValue = aRuleData->ValueForMarkerStart();
   if (eCSSUnit_URL == markerStartValue->GetUnit()) {
-    svg->mMarkerStart = markerStartValue->GetURLValue();
+    svg->mMarkerStart.SetValue(markerStartValue);
   } else if (eCSSUnit_None == markerStartValue->GetUnit() ||
              eCSSUnit_Initial == markerStartValue->GetUnit()) {
-    svg->mMarkerStart = nullptr;
+    svg->mMarkerStart.SetNull();
   } else if (eCSSUnit_Inherit == markerStartValue->GetUnit() ||
              eCSSUnit_Unset == markerStartValue->GetUnit()) {
     conditions.SetUncacheable();
     svg->mMarkerStart = parentSVG->mMarkerStart;
   }
 
   // paint-order: enum (bit field), inherit, initial
   const nsCSSValue* paintOrderValue = aRuleData->ValueForPaintOrder();
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -916,19 +916,18 @@ PaintURIChanged(const nsStyleSVGPaint& a
     !EqualURIs(aPaint1.mPaint.mPaintServer, aPaint2.mPaint.mPaintServer);
 }
 
 nsChangeHint
 nsStyleSVG::CalcDifference(const nsStyleSVG& aNewData) const
 {
   nsChangeHint hint = nsChangeHint(0);
 
-  if (!EqualURIs(mMarkerEnd, aNewData.mMarkerEnd) ||
-      !EqualURIs(mMarkerMid, aNewData.mMarkerMid) ||
-      !EqualURIs(mMarkerStart, aNewData.mMarkerStart)) {
+  if (mMarkerEnd != aNewData.mMarkerEnd || mMarkerMid != aNewData.mMarkerMid ||
+      mMarkerStart != aNewData.mMarkerStart) {
     // Markers currently contribute to nsSVGPathGeometryFrame::mRect,
     // so we need a reflow as well as a repaint. No intrinsic sizes need
     // to change, so nsChangeHint_NeedReflow is sufficient.
     return nsChangeHint_UpdateEffects |
            nsChangeHint_NeedReflow |
            nsChangeHint_NeedDirtyReflow | // XXX remove me: bug 876085
            nsChangeHint_RepaintFrame;
   }
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -3306,19 +3306,19 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
     // CalcDifference never returns nsChangeHint_NeedReflow as a hint
     // not handled for descendants, and never returns
     // nsChangeHint_ClearAncestorIntrinsics at all.
     return nsChangeHint_NeedReflow;
   }
 
   nsStyleSVGPaint  mFill;             // [inherited]
   nsStyleSVGPaint  mStroke;           // [inherited]
-  nsCOMPtr<nsIURI> mMarkerEnd;        // [inherited]
-  nsCOMPtr<nsIURI> mMarkerMid;        // [inherited]
-  nsCOMPtr<nsIURI> mMarkerStart;      // [inherited]
+  FragmentOrURL    mMarkerEnd;        // [inherited]
+  FragmentOrURL    mMarkerMid;        // [inherited]
+  FragmentOrURL    mMarkerStart;      // [inherited]
   nsTArray<nsStyleCoord> mStrokeDasharray;  // [inherited] coord, percent, factor
 
   nsStyleCoord     mStrokeDashoffset; // [inherited] coord, percent, factor
   nsStyleCoord     mStrokeWidth;      // [inherited] coord, percent, factor
 
   float            mFillOpacity;      // [inherited]
   float            mStrokeMiterlimit; // [inherited]
   float            mStrokeOpacity;    // [inherited]
@@ -3370,17 +3370,18 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
                     (aValue ? STROKE_DASHOFFSET_CONTEXT : 0);
   }
   void SetStrokeWidthFromObject(bool aValue) {
     mContextFlags = (mContextFlags & ~STROKE_WIDTH_CONTEXT) |
                     (aValue ? STROKE_WIDTH_CONTEXT : 0);
   }
 
   bool HasMarker() const {
-    return mMarkerStart || mMarkerMid || mMarkerEnd;
+    return mMarkerStart.GetSourceURL() || mMarkerMid.GetSourceURL() ||
+           mMarkerEnd.GetSourceURL();
   }
 
   /**
    * Returns true if the stroke is not "none" and the stroke-opacity is greater
    * than zero. This ignores stroke-widths as that depends on the context.
    */
   bool HasStroke() const {
     return mStroke.mType != eStyleSVGPaintType_None && mStrokeOpacity > 0;
--- a/layout/svg/nsSVGEffects.cpp
+++ b/layout/svg/nsSVGEffects.cpp
@@ -13,16 +13,17 @@
 #include "nsISupportsImpl.h"
 #include "nsSVGClipPathFrame.h"
 #include "nsSVGPaintServerFrame.h"
 #include "nsSVGPathGeometryElement.h"
 #include "nsSVGFilterFrame.h"
 #include "nsSVGMaskFrame.h"
 #include "nsIReflowCallback.h"
 #include "nsCycleCollectionParticipant.h"
+#include "SVGUseElement.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 void
 nsSVGRenderingObserver::StartListening()
 {
   Element* target = GetTarget();
@@ -689,20 +690,23 @@ nsSVGEffects::UpdateEffects(nsIFrame *aF
 
   // Ensure that the filter is repainted correctly
   // We can't do that in DoUpdate as the referenced frame may not be valid
   GetOrCreateFilterProperty(aFrame);
 
   if (aFrame->GetType() == nsGkAtoms::svgPathGeometryFrame &&
       static_cast<nsSVGPathGeometryElement*>(aFrame->GetContent())->IsMarkable()) {
     // Set marker properties here to avoid reference loops
-    const nsStyleSVG *style = aFrame->StyleSVG();
-    GetMarkerProperty(style->mMarkerStart, aFrame, MarkerBeginProperty());
-    GetMarkerProperty(style->mMarkerMid, aFrame, MarkerMiddleProperty());
-    GetMarkerProperty(style->mMarkerEnd, aFrame, MarkerEndProperty());
+    nsCOMPtr<nsIURI> markerURL =
+      nsSVGEffects::GetMarkerURI(aFrame, &nsStyleSVG::mMarkerStart);
+    GetMarkerProperty(markerURL, aFrame, MarkerBeginProperty());
+    markerURL = nsSVGEffects::GetMarkerURI(aFrame, &nsStyleSVG::mMarkerMid);
+    GetMarkerProperty(markerURL, aFrame, MarkerMiddleProperty());
+    markerURL = nsSVGEffects::GetMarkerURI(aFrame, &nsStyleSVG::mMarkerEnd);
+    GetMarkerProperty(markerURL, aFrame, MarkerEndProperty());
   }
 }
 
 nsSVGFilterProperty *
 nsSVGEffects::GetFilterProperty(nsIFrame *aFrame)
 {
   NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
 
@@ -864,8 +868,45 @@ nsSVGEffects::InvalidateDirectRenderingO
 void
 nsSVGEffects::InvalidateDirectRenderingObservers(nsIFrame *aFrame, uint32_t aFlags /* = 0 */)
 {
   nsIContent* content = aFrame->GetContent();
   if (content && content->IsElement()) {
     InvalidateDirectRenderingObservers(content->AsElement(), aFlags);
   }
 }
+
+static already_AddRefed<nsIURI>
+ResolveFragmentOrURL(nsIFrame* aFrame, const FragmentOrURL* aFragmentOrURL)
+{
+  MOZ_ASSERT(aFrame);
+
+  if (!aFragmentOrURL) {
+    return nullptr;
+  }
+
+  // Non-local-reference URL.
+  if (!aFragmentOrURL->IsLocalRef()) {
+    nsCOMPtr<nsIURI> result = aFragmentOrURL->GetSourceURL();
+    return result.forget();
+  }
+
+  nsIContent* content = aFrame->GetContent();
+  nsCOMPtr<nsIURI> baseURI = content->GetBaseURI();
+
+  if (content->IsInAnonymousSubtree()) {
+    // content is in a shadow tree.
+    // Depending on where this url comes from, choose either the baseURI of the
+    // original document of content or the root document of the shadow tree
+    // to resolve URI.
+    if (!aFragmentOrURL->EqualsExceptRef(baseURI))
+      baseURI = content->OwnerDoc()->GetBaseURI();
+  }
+
+  return aFragmentOrURL->Resolve(baseURI);
+}
+
+already_AddRefed<nsIURI>
+nsSVGEffects::GetMarkerURI(nsIFrame* aFrame,
+                           FragmentOrURL nsStyleSVG::* aMarker)
+{
+  return ResolveFragmentOrURL(aFrame, &(aFrame->StyleSVG()->*aMarker));
+}
--- a/layout/svg/nsSVGEffects.h
+++ b/layout/svg/nsSVGEffects.h
@@ -587,11 +587,17 @@ public:
       const mozilla::FramePropertyDescriptor<nsSVGPaintingProperty>* aProperty);
   /**
    * Get an nsSVGPaintingProperty for the frame for that URI, creating a fresh
    * one if necessary
    */
   static nsSVGPaintingProperty *
   GetPaintingPropertyForURI(nsIURI *aURI, nsIFrame *aFrame,
                             URIObserverHashtablePropertyDescriptor aProp);
+
+  /**
+   * A helper function to resolve marker's URL.
+   */
+  static already_AddRefed<nsIURI>
+  GetMarkerURI(nsIFrame* aFrame, FragmentOrURL nsStyleSVG::* aMarker);
 };
 
 #endif /*NSSVGEFFECTS_H_*/
--- a/layout/svg/nsSVGPathGeometryFrame.cpp
+++ b/layout/svg/nsSVGPathGeometryFrame.cpp
@@ -709,25 +709,30 @@ nsSVGPathGeometryFrame::GetCanvasTM()
 }
 
 nsSVGPathGeometryFrame::MarkerProperties
 nsSVGPathGeometryFrame::GetMarkerProperties(nsSVGPathGeometryFrame *aFrame)
 {
   NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
 
   MarkerProperties result;
-  const nsStyleSVG *style = aFrame->StyleSVG();
+  nsCOMPtr<nsIURI> markerURL =
+    nsSVGEffects::GetMarkerURI(aFrame, &nsStyleSVG::mMarkerStart);
   result.mMarkerStart =
-    nsSVGEffects::GetMarkerProperty(style->mMarkerStart, aFrame,
+    nsSVGEffects::GetMarkerProperty(markerURL, aFrame,
                                     nsSVGEffects::MarkerBeginProperty());
+
+  markerURL = nsSVGEffects::GetMarkerURI(aFrame, &nsStyleSVG::mMarkerMid);
   result.mMarkerMid =
-    nsSVGEffects::GetMarkerProperty(style->mMarkerMid, aFrame,
+    nsSVGEffects::GetMarkerProperty(markerURL, aFrame,
                                     nsSVGEffects::MarkerMiddleProperty());
+
+  markerURL = nsSVGEffects::GetMarkerURI(aFrame, &nsStyleSVG::mMarkerEnd);
   result.mMarkerEnd =
-    nsSVGEffects::GetMarkerProperty(style->mMarkerEnd, aFrame,
+    nsSVGEffects::GetMarkerProperty(markerURL, aFrame,
                                     nsSVGEffects::MarkerEndProperty());
   return result;
 }
 
 nsSVGMarkerFrame *
 nsSVGPathGeometryFrame::MarkerProperties::GetMarkerStartFrame()
 {
   if (!mMarkerStart)