Bug 865901 - make nsSVGTextFrame2::mPositioningDirty and mPositioningUsesPercentages SVG frame state bits. r=cam
authorRobert Longson <longsonr@gmail.com>
Mon, 24 Jun 2013 12:20:38 +0100
changeset 136253 d53ba2cc53370cebabb8d87bda8d894454212476
parent 136224 7edda78eca8bc23c99cebfcab24ccd8838d09f16
child 136254 08c202fef05914597a34500ae2cf03cbaf924560
push id24875
push userryanvm@gmail.com
push dateMon, 24 Jun 2013 18:01:46 +0000
treeherdermozilla-central@d839f8a7f956 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscam
bugs865901
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 865901 - make nsSVGTextFrame2::mPositioningDirty and mPositioningUsesPercentages SVG frame state bits. r=cam
layout/svg/nsSVGTextFrame.cpp
layout/svg/nsSVGTextFrame.h
layout/svg/nsSVGTextFrame2.cpp
layout/svg/nsSVGTextFrame2.h
layout/svg/nsSVGUtils.h
--- a/layout/svg/nsSVGTextFrame.cpp
+++ b/layout/svg/nsSVGTextFrame.cpp
@@ -233,24 +233,24 @@ nsSVGTextFrame::ReflowSVG()
 {
   NS_ASSERTION(nsSVGUtils::OuterSVGIsCallingReflowSVG(this),
                "This call is probably a wasteful mistake");
 
   NS_ABORT_IF_FALSE(!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD),
                     "ReflowSVG mechanism not designed for this");
 
   if (!nsSVGUtils::NeedsReflowSVG(this)) {
-    NS_ASSERTION(!mPositioningDirty, "How did this happen?");
+    NS_ASSERTION(!(mState & NS_STATE_SVG_POSITIONING_DIRTY), "How did this happen?");
     return;
   }
 
-  // UpdateGlyphPositioning may have been called under DOM calls and set
-  // mPositioningDirty to false. We may now have better positioning, though, so
+  // UpdateGlyphPositioning may have been called under DOM calls and cleared
+  // NS_STATE_SVG_POSITIONING_DIRTY. We may now have better positioning, though, so
   // set it to true so that UpdateGlyphPositioning will do its work.
-  mPositioningDirty = true;
+  AddStateBits(NS_STATE_SVG_POSITIONING_DIRTY);
 
   UpdateGlyphPositioning(false);
 
   // We leave it up to nsSVGTextFrameBase::ReflowSVG to invalidate. XXXSDL
   // With glyph positions updated, our descendants can invalidate their new
   // areas correctly:
   nsSVGTextFrameBase::ReflowSVG();
 }
@@ -321,17 +321,17 @@ nsSVGTextFrame::NotifyGlyphMetricsChange
 {
   // NotifySVGChanged isn't appropriate here, so we just mark our descendants
   // as fully dirty to get ReflowSVG() called on them:
   MarkDirtyBitsOnDescendants(this);
 
   nsSVGEffects::InvalidateRenderingObservers(this);
   nsSVGUtils::ScheduleReflowSVG(this);
 
-  mPositioningDirty = true;
+  AddStateBits(NS_STATE_SVG_POSITIONING_DIRTY);
 }
 
 void
 nsSVGTextFrame::SetWhitespaceHandling(nsSVGGlyphFrame *aFrame)
 {
   SetWhitespaceCompression();
 
   nsSVGGlyphFrame* firstFrame = aFrame;
@@ -369,20 +369,20 @@ nsSVGTextFrame::SetWhitespaceHandling(ns
     aFrame->SetTrimTrailingWhitespace(true);
     aFrame = aFrame->GetNextGlyphFrame();
   }
 }
 
 void
 nsSVGTextFrame::UpdateGlyphPositioning(bool aForceGlobalTransform)
 {
-  if (!mPositioningDirty)
+  if (!(mState & NS_STATE_SVG_POSITIONING_DIRTY))
     return;
 
-  mPositioningDirty = false;
+  RemoveStateBits(NS_STATE_SVG_POSITIONING_DIRTY);
 
   nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode();
   if (!node)
     return;
 
   nsSVGGlyphFrame *frame, *firstFrame;
 
   firstFrame = node->GetFirstGlyphFrame();
--- a/layout/svg/nsSVGTextFrame.h
+++ b/layout/svg/nsSVGTextFrame.h
@@ -21,19 +21,20 @@ class SVGIRect;
 }
 }
 
 class nsSVGTextFrame : public nsSVGTextFrameBase
 {
   friend nsIFrame*
   NS_NewSVGTextFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
-  nsSVGTextFrame(nsStyleContext* aContext)
-    : nsSVGTextFrameBase(aContext),
-      mPositioningDirty(true) {}
+  nsSVGTextFrame(nsStyleContext* aContext) : nsSVGTextFrameBase(aContext)
+  {
+    AddStateBits(NS_STATE_SVG_POSITIONING_DIRTY);
+  }
 
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   // nsIFrame:
 #ifdef DEBUG
   virtual void Init(nsIContent*      aContent,
                     nsIFrame*        aParent,
@@ -96,13 +97,11 @@ private:
    * control whether they should use the global transform even when
    * NS_STATE_NONDISPLAY_CHILD
    */
   void UpdateGlyphPositioning(bool aForceGlobalTransform);
 
   void SetWhitespaceHandling(nsSVGGlyphFrame *aFrame);
 
   nsAutoPtr<gfxMatrix> mCanvasTM;
-
-  bool mPositioningDirty;
 };
 
 #endif
--- a/layout/svg/nsSVGTextFrame2.cpp
+++ b/layout/svg/nsSVGTextFrame2.cpp
@@ -3256,17 +3256,18 @@ nsSVGTextFrame2::NotifySVGChanged(uint32
 {
   NS_ABORT_IF_FALSE(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED),
                     "Invalidation logic may need adjusting");
 
   bool needNewBounds = false;
   bool needGlyphMetricsUpdate = false;
   bool needNewCanvasTM = false;
 
-  if ((aFlags & COORD_CONTEXT_CHANGED) && mPositioningMayUsePercentages) {
+  if ((aFlags & COORD_CONTEXT_CHANGED) &&
+      (mState & NS_STATE_SVG_POSITIONING_MAY_USE_PERCENTAGES)) {
     needGlyphMetricsUpdate = true;
   }
 
   if (aFlags & TRANSFORM_CHANGED) {
     needNewCanvasTM = true;
     if (mCanvasTM && mCanvasTM->IsSingular()) {
       // We won't have calculated the glyph positions correctly.
       needNewBounds = true;
@@ -3528,17 +3529,17 @@ nsSVGTextFrame2::ReflowSVG()
 {
   NS_ASSERTION(nsSVGUtils::OuterSVGIsCallingReflowSVG(this),
                "This call is probaby a wasteful mistake");
 
   NS_ABORT_IF_FALSE(!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD),
                     "ReflowSVG mechanism not designed for this");
 
   if (!nsSVGUtils::NeedsReflowSVG(this)) {
-    NS_ASSERTION(!mPositioningDirty, "How did this happen?");
+    NS_ASSERTION(!(mState & NS_STATE_SVG_POSITIONING_DIRTY), "How did this happen?");
     return;
   }
 
   MaybeReflowAnonymousBlockChild();
   UpdateGlyphPositioning();
 
   nsPresContext* presContext = PresContext();
 
@@ -4139,17 +4140,17 @@ nsSVGTextFrame2::ResolvePositions(nsICon
     const SVGNumberList* rotate = nullptr;
     SVGAnimatedNumberList* animatedRotate =
       element->GetAnimatedNumberList(nsGkAtoms::rotate);
     if (animatedRotate) {
       rotate = &animatedRotate->GetAnimValue();
     }
 
     uint32_t count = GetTextContentLength(aContent);
-    bool& percentages = mPositioningMayUsePercentages;
+    bool percentages = false;
 
     // New text anchoring chunks start at each character assigned a position
     // with x="" or y="", or if we forced one with aForceStartOfChunk due to
     // being just after a <textPath>.
     uint32_t newChunkCount = std::max(x.Length(), y.Length());
     if (!newChunkCount && aForceStartOfChunk) {
       newChunkCount = 1;
     }
@@ -4207,16 +4208,20 @@ nsSVGTextFrame2::ResolvePositions(nsICon
         j++;
       }
       // Propagate final rotate="" value to the end of this element.
       while (j < count) {
         mPositions[aIndex + j].mAngle = mPositions[aIndex + j - 1].mAngle;
         j++;
       }
     }
+
+    if (percentages) {
+      AddStateBits(NS_STATE_SVG_POSITIONING_MAY_USE_PERCENTAGES);
+    }
   }
 
   // Recurse to children.
   bool inTextPath = aInTextPath || aContent->Tag() == nsGkAtoms::textPath;
   for (nsIContent* child = aContent->GetFirstChild();
        child;
        child = child->GetNextSibling()) {
     aIndex = ResolvePositions(child, aIndex, inTextPath, aForceStartOfChunk,
@@ -4230,17 +4235,17 @@ nsSVGTextFrame2::ResolvePositions(nsICon
 
   return aIndex;
 }
 
 bool
 nsSVGTextFrame2::ResolvePositions(nsTArray<gfxPoint>& aDeltas)
 {
   NS_ASSERTION(mPositions.IsEmpty(), "expected mPositions to be empty");
-  mPositioningMayUsePercentages = false;
+  RemoveStateBits(NS_STATE_SVG_POSITIONING_MAY_USE_PERCENTAGES);
 
   CharIterator it(this, CharIterator::eOriginal);
   if (it.AtEnd()) {
     return false;
   }
 
   // We assume the first character position is (0,0) unless we later see
   // otherwise, and note it as unaddressable if it is.
@@ -4664,17 +4669,17 @@ nsSVGTextFrame2::DoAnchoring()
     start = it.TextElementCharIndex();
   }
 }
 
 void
 nsSVGTextFrame2::DoGlyphPositioning()
 {
   mPositions.Clear();
-  mPositioningDirty = false;
+  RemoveStateBits(NS_STATE_SVG_POSITIONING_DIRTY);
 
   // Determine the positions of each character in app units.
   nsTArray<nsPoint> charPositions;
   DetermineCharPositions(charPositions);
 
   if (charPositions.IsEmpty()) {
     // No characters, so nothing to do.
     return;
@@ -4815,30 +4820,30 @@ nsSVGTextFrame2::ScheduleReflowSVG()
   } else {
     nsSVGUtils::ScheduleReflowSVG(this);
   }
 }
 
 void
 nsSVGTextFrame2::NotifyGlyphMetricsChange()
 {
-  mPositioningDirty = true;
+  AddStateBits(NS_STATE_SVG_POSITIONING_DIRTY);
   nsSVGEffects::InvalidateRenderingObservers(this);
   ScheduleReflowSVG();
 }
 
 void
 nsSVGTextFrame2::UpdateGlyphPositioning()
 {
   nsIFrame* kid = GetFirstPrincipalChild();
   if (!kid) {
     return;
   }
 
-  if (mPositioningDirty) {
+  if (mState & NS_STATE_SVG_POSITIONING_DIRTY) {
     MOZ_ASSERT(!NS_SUBTREE_DIRTY(kid), "should have already reflowed the kid");
     DoGlyphPositioning();
   }
 }
 
 void
 nsSVGTextFrame2::MaybeReflowAnonymousBlockChild()
 {
@@ -4864,17 +4869,17 @@ nsSVGTextFrame2::MaybeReflowAnonymousBlo
   }
 }
 
 void
 nsSVGTextFrame2::DoReflow()
 {
   // Since we are going to reflow the anonymous block frame, we will
   // need to update mPositions.
-  mPositioningDirty = true;
+  AddStateBits(NS_STATE_SVG_POSITIONING_DIRTY);
 
   if (mState & NS_STATE_SVG_NONDISPLAY_CHILD) {
     // Normally, these dirty flags would be cleared in ReflowSVG(), but that
     // doesn't get called for non-display frames. We don't want to reflow our
     // descendants every time nsSVGTextFrame2::PaintSVG makes sure that we have
     // valid positions by calling UpdateGlyphPositioning(), so we need to clear
     // these dirty bits. Note that this also breaks an invalidation loop where
     // our descendants invalidate as they reflow, which invalidates rendering
--- a/layout/svg/nsSVGTextFrame2.h
+++ b/layout/svg/nsSVGTextFrame2.h
@@ -183,20 +183,19 @@ class nsSVGTextFrame2 : public nsSVGText
   friend class AutoCanvasTMForMarker;
   friend class MutationObserver;
   friend class nsDisplaySVGText;
 
 protected:
   nsSVGTextFrame2(nsStyleContext* aContext)
     : nsSVGTextFrame2Base(aContext),
       mFontSizeScaleFactor(1.0f),
-      mGetCanvasTMForFlag(FOR_OUTERSVG_TM),
-      mPositioningDirty(true),
-      mPositioningMayUsePercentages(false)
+      mGetCanvasTMForFlag(FOR_OUTERSVG_TM)
   {
+    AddStateBits(NS_STATE_SVG_POSITIONING_DIRTY);
   }
 
 public:
   NS_DECL_QUERYFRAME_TARGET(nsSVGTextFrame2)
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
 
   // nsIFrame:
@@ -645,47 +644,11 @@ private:
    * This flag is also used to determine whether in UpdateFontSizeScaleFactor
    * GetCanvasTM should be called at all.  When the nsSVGTextFrame2 is a
    * non-display child, and we are not painting or hit testing, there is
    * no sensible CTM stack to use.  Additionally, when inside a <marker>,
    * calling GetCanvasTM on the nsSVGMarkerFrame would crash due to not
    * having a current mMarkedFrame.
    */
   uint32_t mGetCanvasTMForFlag;
-
-  /**
-   * The NS_FRAME_IS_DIRTY and NS_FRAME_HAS_DIRTY_CHILDREN bits indicate
-   * that our anonymous block child needs to be reflowed, and that mPositions
-   * will likely need to be updated as a consequence. These are set, for
-   * example, when the font-family changes. Sometimes we only need to
-   * update mPositions though. For example if the x/y attributes change.
-   * mPositioningDirty is used to indicate this latter "things are dirty" case
-   * to allow us to avoid reflowing the anonymous block when it is not
-   * necessary.
-   */
-  bool mPositioningDirty;
-
-  /**
-   * Whether the values from x/y/dx/dy attributes have any percentage values
-   * that are used in determining the positions of glyphs.  The value will
-   * be true even if a positioning value is overridden by a descendant element's
-   * attribute with a non-percentage length.  For example,
-   * mPositioningMayUsePercentages would be true for:
-   *
-   *   <text x="10%"><tspan x="0">abc</tspan></text>
-   *
-   * Percentage values beyond the number of addressable characters, however, do
-   * not influence mPositioningMayUsePercentages.  For example,
-   * mPositioningMayUsePercentages would be false for:
-   *
-   *   <text x="10 20 30 40%">abc</text>
-   *
-   * mPositioningMayUsePercentages is used to determine whether to recompute
-   * mPositions when the viewport size changes.  So although the first example
-   * above shows that mPositioningMayUsePercentages can be true even if a viewport
-   * size change will not affect mPositions, determining a completley accurate
-   * value for mPositioningMayUsePercentages would require extra work that is
-   * probably not worth it.
-   */
-  bool mPositioningMayUsePercentages;
 };
 
 #endif
--- a/layout/svg/nsSVGUtils.h
+++ b/layout/svg/nsSVGUtils.h
@@ -59,20 +59,57 @@ namespace dom {
 class Element;
 } // namespace dom
 } // namespace mozilla
 
 // SVG Frame state bits
 #define NS_STATE_IS_OUTER_SVG                    NS_FRAME_STATE_BIT(20)
 
 /* are we the child of a non-display container? */
-#define NS_STATE_SVG_NONDISPLAY_CHILD            NS_FRAME_STATE_BIT(22)
+#define NS_STATE_SVG_NONDISPLAY_CHILD            NS_FRAME_STATE_BIT(21)
 
 // If this bit is set, we are a <clipPath> element or descendant.
-#define NS_STATE_SVG_CLIPPATH_CHILD              NS_FRAME_STATE_BIT(23)
+#define NS_STATE_SVG_CLIPPATH_CHILD              NS_FRAME_STATE_BIT(22)
+
+/**
+ * For text, the NS_FRAME_IS_DIRTY and NS_FRAME_HAS_DIRTY_CHILDREN bits indicate
+ * that our anonymous block child needs to be reflowed, and that mPositions
+ * will likely need to be updated as a consequence. These are set, for
+ * example, when the font-family changes. Sometimes we only need to
+ * update mPositions though. For example if the x/y attributes change.
+ * mPositioningDirty is used to indicate this latter "things are dirty" case
+ * to allow us to avoid reflowing the anonymous block when it is not
+ * necessary.
+ */
+#define NS_STATE_SVG_POSITIONING_DIRTY           NS_FRAME_STATE_BIT(23)
+
+/**
+ * For text, whether the values from x/y/dx/dy attributes have any percentage values
+ * that are used in determining the positions of glyphs.  The value will
+ * be true even if a positioning value is overridden by a descendant element's
+ * attribute with a non-percentage length.  For example,
+ * NS_STATE_SVG_POSITIONING_MAY_USE_PERCENTAGES would be set for:
+ *
+ *   <text x="10%"><tspan x="0">abc</tspan></text>
+ *
+ * Percentage values beyond the number of addressable characters, however, do
+ * not influence NS_STATE_SVG_POSITIONING_MAY_USE_PERCENTAGES.  For example,
+ * NS_STATE_SVG_POSITIONING_MAY_USE_PERCENTAGES would be false for:
+ *
+ *   <text x="10 20 30 40%">abc</text>
+ *
+ * NS_STATE_SVG_POSITIONING_MAY_USE_PERCENTAGES is used to determine whether
+ * to recompute mPositions when the viewport size changes.  So although the 
+ * first example above shows that NS_STATE_SVG_POSITIONING_MAY_USE_PERCENTAGES
+ * can be true even if a viewport size change will not affect mPositions,
+ * determining a completley accurate value for
+ * NS_STATE_SVG_POSITIONING_MAY_USE_PERCENTAGES would require extra work that is
+ * probably not worth it.
+ */
+#define NS_STATE_SVG_POSITIONING_MAY_USE_PERCENTAGES NS_FRAME_STATE_BIT(24)
 
 /**
  * Byte offsets of channels in a native packed gfxColor or cairo image surface.
  */
 #ifdef IS_BIG_ENDIAN
 #define GFX_ARGB32_OFFSET_A 0
 #define GFX_ARGB32_OFFSET_R 1
 #define GFX_ARGB32_OFFSET_G 2