Merge inbound and m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 24 Jun 2013 14:00:41 -0400
changeset 147747 fe684609e72a21a24d4ddc66d3fda7ea8a5d168f
parent 147743 19c05a3d7d3cc7a4395435b579d359af37a440be (current diff)
parent 147746 8a9410b02e6e31d8eedcaa82279e6fbfac055aa4 (diff)
child 147760 d839f8a7f95660fc071eac3cf9d859aeb4cb7532
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
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
Merge inbound and m-c.
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -963,20 +963,22 @@ static const char js_zeal_frequency_str[
 static const char js_typeinfer_str[]          = JS_OPTIONS_DOT_STR "typeinference";
 static const char js_pccounts_content_str[]   = JS_OPTIONS_DOT_STR "pccounts.content";
 static const char js_pccounts_chrome_str[]    = JS_OPTIONS_DOT_STR "pccounts.chrome";
 static const char js_jit_hardening_str[]      = JS_OPTIONS_DOT_STR "jit_hardening";
 static const char js_memlog_option_str[]      = JS_OPTIONS_DOT_STR "mem.log";
 static const char js_memnotify_option_str[]   = JS_OPTIONS_DOT_STR "mem.notify";
 static const char js_disable_explicit_compartment_gc[] =
   JS_OPTIONS_DOT_STR "mem.disable_explicit_compartment_gc";
+static const char js_asmjs_content_str[]      = JS_OPTIONS_DOT_STR "asmjs";
 static const char js_baselinejit_content_str[] = JS_OPTIONS_DOT_STR "baselinejit.content";
 static const char js_baselinejit_chrome_str[]  = JS_OPTIONS_DOT_STR "baselinejit.chrome";
+static const char js_baselinejit_eager_str[]  = JS_OPTIONS_DOT_STR "baselinejit.unsafe_eager_compilation";
 static const char js_ion_content_str[]        = JS_OPTIONS_DOT_STR "ion.content";
-static const char js_asmjs_content_str[]      = JS_OPTIONS_DOT_STR "asmjs";
+static const char js_ion_eager_str[]          = JS_OPTIONS_DOT_STR "ion.unsafe_eager_compilation";
 static const char js_ion_parallel_compilation_str[] = JS_OPTIONS_DOT_STR "ion.parallel_compilation";
 
 int
 nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
 {
   nsJSContext *context = reinterpret_cast<nsJSContext *>(data);
   uint32_t oldDefaultJSOptions = context->mDefaultJSOptions;
   uint32_t newDefaultJSOptions = oldDefaultJSOptions;
@@ -1005,29 +1007,33 @@ nsJSContext::JSOptionChangedCallback(con
   bool usePCCounts = Preferences::GetBool(chromeWindow || !contentWindow ?
                                             js_pccounts_chrome_str :
                                             js_pccounts_content_str);
   bool useTypeInference = !chromeWindow && contentWindow && Preferences::GetBool(js_typeinfer_str);
   bool useHardening = Preferences::GetBool(js_jit_hardening_str);
   bool useBaselineJIT = Preferences::GetBool(chromeWindow || !contentWindow ?
                                                js_baselinejit_chrome_str :
                                                js_baselinejit_content_str);
+  bool useBaselineJITEager = Preferences::GetBool(js_baselinejit_eager_str);
   bool useIon = Preferences::GetBool(js_ion_content_str);
+  bool useIonEager = Preferences::GetBool(js_ion_eager_str);
   bool useAsmJS = Preferences::GetBool(js_asmjs_content_str);
   bool parallelIonCompilation = Preferences::GetBool(js_ion_parallel_compilation_str);
   nsCOMPtr<nsIXULRuntime> xr = do_GetService(XULRUNTIME_SERVICE_CONTRACTID);
   if (xr) {
     bool safeMode = false;
     xr->GetInSafeMode(&safeMode);
     if (safeMode) {
       usePCCounts = false;
       useTypeInference = false;
       useHardening = false;
       useBaselineJIT = false;
+      useBaselineJITEager = false;
       useIon = false;
+      useIonEager = false;
       useAsmJS = false;
     }
   }
 
   if (usePCCounts)
     newDefaultJSOptions |= JSOPTION_PCCOUNT;
   else
     newDefaultJSOptions &= ~JSOPTION_PCCOUNT;
@@ -1067,16 +1073,22 @@ nsJSContext::JSOptionChangedCallback(con
     newDefaultJSOptions |= JSOPTION_WERROR;
   else
     newDefaultJSOptions &= ~JSOPTION_WERROR;
 
   ::JS_SetOptions(context->mContext, newDefaultJSOptions & JSOPTION_MASK);
 
   ::JS_SetParallelCompilationEnabled(context->mContext, parallelIonCompilation);
 
+  ::JS_SetGlobalCompilerOption(context->mContext, JSCOMPILER_BASELINE_USECOUNT_TRIGGER,
+                               (useBaselineJITEager ? 0 : -1));
+
+  ::JS_SetGlobalCompilerOption(context->mContext, JSCOMPILER_ION_USECOUNT_TRIGGER,
+                               (useIonEager ? 0 : -1));
+
   // Save the new defaults for the next page load (InitContext).
   context->mDefaultJSOptions = newDefaultJSOptions;
 
   JSRuntime *rt = JS_GetRuntime(context->mContext);
   JS_SetJitHardening(rt, useHardening);
 
 #ifdef JS_GC_ZEAL
   int32_t zeal = Preferences::GetInt(js_zeal_option_str, -1);
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -6988,16 +6988,43 @@ JS_ScheduleGC(JSContext *cx, uint32_t co
 JS_PUBLIC_API(void)
 JS_SetParallelCompilationEnabled(JSContext *cx, bool enabled)
 {
 #ifdef JS_ION
     ion::js_IonOptions.parallelCompilation = enabled;
 #endif
 }
 
+JS_PUBLIC_API(void)
+JS_SetGlobalCompilerOption(JSContext *cx, JSCompilerOption opt, uint32_t value)
+{
+#ifdef JS_ION
+    ion::IonOptions defaultValues;
+
+    switch (opt) {
+      case JSCOMPILER_BASELINE_USECOUNT_TRIGGER:
+        if (value == uint32_t(-1))
+            value = defaultValues.baselineUsesBeforeCompile;
+        ion::js_IonOptions.baselineUsesBeforeCompile = value;
+        break;
+      case JSCOMPILER_ION_USECOUNT_TRIGGER:
+        if (value == uint32_t(-1))
+            value = defaultValues.usesBeforeCompile;
+        ion::js_IonOptions.usesBeforeCompile = value;
+        ion::js_IonOptions.eagerCompilation = (value == 0);
+        break;
+      case JSCOMPILER_PJS_ENABLE:
+        if (value == uint32_t(-1))
+            value = uint32_t(defaultValues.parallelCompilation);
+        ion::js_IonOptions.parallelCompilation = bool(value);
+        break;
+    }
+#endif
+}
+
 /************************************************************************/
 
 #if !defined(STATIC_EXPORTABLE_JS_API) && !defined(STATIC_JS_API) && defined(XP_WIN)
 
 #include "jswin.h"
 
 /*
  * Initialization routine for the JS DLL.
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -4994,16 +4994,25 @@ JS_SetGCZeal(JSContext *cx, uint8_t zeal
 
 extern JS_PUBLIC_API(void)
 JS_ScheduleGC(JSContext *cx, uint32_t count);
 #endif
 
 extern JS_PUBLIC_API(void)
 JS_SetParallelCompilationEnabled(JSContext *cx, bool enabled);
 
+typedef enum JSCompilerOption {
+    JSCOMPILER_BASELINE_USECOUNT_TRIGGER,
+    JSCOMPILER_ION_USECOUNT_TRIGGER,
+    JSCOMPILER_PJS_ENABLE
+} JSCompilerOption;
+
+extern JS_PUBLIC_API(void)
+JS_SetGlobalCompilerOption(JSContext *cx, JSCompilerOption opt, uint32_t value);
+
 /*
  * Convert a uint32_t index into a jsid.
  */
 extern JS_PUBLIC_API(JSBool)
 JS_IndexToId(JSContext *cx, uint32_t index, jsid *id);
 
 /*
  * Convert chars into a jsid.
--- 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