Implement 'rem' unit from css3-values. (Bug 472195) r+sr=dbaron
authorKeith Rarick <kr@xph.us>
Tue, 20 Jan 2009 13:58:48 -0800
changeset 23981 23d1cadf9e8d
parent 23980 2a1f13246939
child 23982 adf44ec71ce9
push id4824
push userdbaron@mozilla.com
push date2009-01-20 21:59 +0000
treeherdermozilla-central@adf44ec71ce9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs472195
milestone1.9.2a1pre
Implement 'rem' unit from css3-values. (Bug 472195) r+sr=dbaron
content/base/src/nsGkAtomList.h
layout/reftests/css-valuesandunits/reftest.list
layout/reftests/css-valuesandunits/unit-rem-div-fontsize.html
layout/reftests/css-valuesandunits/unit-rem-div-width-inner.html
layout/reftests/css-valuesandunits/unit-rem-div-width-outer.html
layout/reftests/css-valuesandunits/unit-rem-iframe-inside.html
layout/reftests/css-valuesandunits/unit-rem-iframe.html
layout/reftests/css-valuesandunits/unit-rem-ref-iframe-inside.html
layout/reftests/css-valuesandunits/unit-rem-ref-iframe.html
layout/reftests/css-valuesandunits/unit-rem-ref-resource.svg
layout/reftests/css-valuesandunits/unit-rem-ref-root-fontsize.html
layout/reftests/css-valuesandunits/unit-rem-ref-root-width.html
layout/reftests/css-valuesandunits/unit-rem-ref.html
layout/reftests/css-valuesandunits/unit-rem-ref.svg
layout/reftests/css-valuesandunits/unit-rem-resource.svg
layout/reftests/css-valuesandunits/unit-rem-root-fontsize.html
layout/reftests/css-valuesandunits/unit-rem-root-width.html
layout/reftests/css-valuesandunits/unit-rem.svg
layout/reftests/reftest.list
layout/style/nsCSSDeclaration.cpp
layout/style/nsCSSParser.cpp
layout/style/nsCSSValue.h
layout/style/nsRuleNode.cpp
layout/style/nsRuleNode.h
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -756,16 +756,17 @@ GK_ATOM(querytype, "querytype")
 GK_ATOM(radio, "radio")
 GK_ATOM(radiogroup, "radiogroup")
 GK_ATOM(readonly, "readonly")
 GK_ATOM(rect, "rect")
 GK_ATOM(rectangle, "rectangle")
 GK_ATOM(ref, "ref")
 GK_ATOM(refresh, "refresh")
 GK_ATOM(rel, "rel")
+GK_ATOM(rem, "rem")
 GK_ATOM(removeelement, "removeelement")
 GK_ATOM(repeat, "repeat")
 GK_ATOM(replace, "replace")
 GK_ATOM(reset, "reset")
 GK_ATOM(resizeafter, "resizeafter")
 GK_ATOM(resizebefore, "resizebefore")
 GK_ATOM(resizer, "resizer")
 GK_ATOM(resolution, "resolution")
@@ -1411,17 +1412,16 @@ GK_ATOM(numalign_, "numalign")
 GK_ATOM(other_, "other")
 GK_ATOM(partialdiff_, "partialdiff")
 GK_ATOM(plus_, "plus")
 GK_ATOM(power_, "power")
 GK_ATOM(product_, "product")
 GK_ATOM(prsubset_, "prsubset")
 GK_ATOM(quotient_, "quotient")
 GK_ATOM(reln_, "reln")
-GK_ATOM(rem_, "rem")
 GK_ATOM(root_, "root")
 GK_ATOM(rowalign_, "rowalign")
 GK_ATOM(rowlines_, "rowlines")
 GK_ATOM(rowspacing_, "rowspacing")
 GK_ATOM(rquote_, "rquote")
 GK_ATOM(rspace_, "rspace")
 GK_ATOM(scriptlevel_, "scriptlevel")
 GK_ATOM(scriptminsize_, "scriptminsize")
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valuesandunits/reftest.list
@@ -0,0 +1,7 @@
+== unit-rem-div-fontsize.html unit-rem-ref.html
+== unit-rem-div-width-inner.html unit-rem-ref.html
+== unit-rem-div-width-outer.html unit-rem-ref.html
+== unit-rem-iframe.html unit-rem-ref-iframe.html
+== unit-rem-root-fontsize.html unit-rem-ref-root-fontsize.html
+== unit-rem-root-width.html unit-rem-ref-root-width.html
+== unit-rem.svg unit-rem-ref.svg
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valuesandunits/unit-rem-div-fontsize.html
@@ -0,0 +1,13 @@
+<style>
+:root { font-size: 20px }
+body { font-size: 25px }
+div {
+  font-size: 1.5rem;
+  width: 300px;
+}
+#a {
+  border-bottom: 1px solid #f00;
+}
+</style>
+
+<body>Level 1<div id=a>Level 2<div id=b>Level 3</div></div></body>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valuesandunits/unit-rem-div-width-inner.html
@@ -0,0 +1,13 @@
+<style>
+:root { font-size: 20px }
+body { font-size: 25px }
+div {
+  font-size: 30px;
+  width: 15rem;
+}
+#b {
+  border-bottom: 1px solid #f00;
+}
+</style>
+
+<body>Level 1<div id=a>Level 2<div id=b>Level 3</div></div></body>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valuesandunits/unit-rem-div-width-outer.html
@@ -0,0 +1,13 @@
+<style>
+:root { font-size: 20px }
+body { font-size: 25px }
+div {
+  font-size: 30px;
+  width: 15rem;
+}
+#a {
+  border-bottom: 1px solid #f00;
+}
+</style>
+
+<body>Level 1<div id=a>Level 2<div id=b>Level 3</div></div></body>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valuesandunits/unit-rem-iframe-inside.html
@@ -0,0 +1,7 @@
+<style>
+:root { font-size: 20px }
+body { font-size: 25px }
+div { font-size: 1.5rem }
+</style>
+
+<body><div>Inside</div></body>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valuesandunits/unit-rem-iframe.html
@@ -0,0 +1,6 @@
+<style>
+:root { font-size: 10px }
+body { font-size: 12px }
+</style>
+
+<body>Outside<iframe src=unit-rem-iframe-inside.html></body>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valuesandunits/unit-rem-ref-iframe-inside.html
@@ -0,0 +1,7 @@
+<style>
+:root { font-size: 20px }
+body { font-size: 25px }
+div { font-size: 30px }
+</style>
+
+<body><div>Inside</div></body>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valuesandunits/unit-rem-ref-iframe.html
@@ -0,0 +1,6 @@
+<style>
+:root { font-size: 10px }
+body { font-size: 12px }
+</style>
+
+<body>Outside<iframe src=unit-rem-ref-iframe-inside.html></body>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valuesandunits/unit-rem-ref-resource.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
+     style="font-size: 30px">
+  <rect id="rect" fill="green" width="200px" height="50px" />
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valuesandunits/unit-rem-ref-root-fontsize.html
@@ -0,0 +1,7 @@
+<style>
+:root {
+  font-size: 1.5em;
+}
+</style>
+
+<body>Hello</body>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valuesandunits/unit-rem-ref-root-width.html
@@ -0,0 +1,12 @@
+<style>
+:root {
+  font-size: 30px;
+  width: 300px;
+  border-bottom: 1px solid #f00;
+}
+body {
+  font-size: 25px;
+}
+</style>
+
+<body>Level 1</body>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valuesandunits/unit-rem-ref.html
@@ -0,0 +1,13 @@
+<style>
+:root { font-size: 20px }
+body { font-size: 25px }
+div {
+  font-size: 30px;
+  width: 300px;
+}
+#a {
+  border-bottom: 1px solid #f00;
+}
+</style>
+
+<body>Level 1<div id=a>Level 2<div id=b>Level 3</div></div></body>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valuesandunits/unit-rem-ref.svg
@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
+     xmlns:xlink="http://www.w3.org/1999/xlink"
+     style="font-size: 20px">
+  <use xlink:href="unit-rem-ref-resource.svg#rect" />
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valuesandunits/unit-rem-resource.svg
@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
+     style="font-size: 30px">
+  <!-- We don't support 'rem' in the width attribute because that's nsSVGLength
+       code, so we use indirection through 'em' and 'font-size'. -->
+  <rect id="rect" fill="green" style="font-size: 2rem" width="5em" height="50px" />
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valuesandunits/unit-rem-root-fontsize.html
@@ -0,0 +1,7 @@
+<style>
+:root {
+  font-size: 1.5rem;
+}
+</style>
+
+<body>Hello</body>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valuesandunits/unit-rem-root-width.html
@@ -0,0 +1,12 @@
+<style>
+:root {
+  font-size: 30px;
+  width: 10rem;
+  border-bottom: 1px solid #f00;
+}
+body {
+  font-size: 25px;
+}
+</style>
+
+<body>Level 1</body>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valuesandunits/unit-rem.svg
@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
+     xmlns:xlink="http://www.w3.org/1999/xlink"
+     style="font-size: 20px">
+  <use xlink:href="unit-rem-resource.svg#rect" />
+</svg>
--- a/layout/reftests/reftest.list
+++ b/layout/reftests/reftest.list
@@ -36,16 +36,19 @@ include canvas/reftest.list
 include css-import/reftest.list
 
 # css character encoding tests
 include css-charset/reftest.list
 
 # css media queries (tests for print mode)
 include css-mediaqueries/reftest.list
 
+# css values and units
+include css-valuesandunits/reftest.list
+
 # columns/
 include columns/reftest.list
 
 # content/
 include ../../content/test/reftest/reftest.list
 
 # counters/
 include counters/reftest.list
--- a/layout/style/nsCSSDeclaration.cpp
+++ b/layout/style/nsCSSDeclaration.cpp
@@ -469,16 +469,17 @@ nsCSSDeclaration::AppendCSSValueToString
     case eCSSUnit_Point:        aResult.AppendLiteral("pt");   break;
     case eCSSUnit_Pica:         aResult.AppendLiteral("pc");   break;
     case eCSSUnit_Didot:        aResult.AppendLiteral("dt");   break;
     case eCSSUnit_Cicero:       aResult.AppendLiteral("cc");   break;
 
     case eCSSUnit_EM:           aResult.AppendLiteral("em");   break;
     case eCSSUnit_XHeight:      aResult.AppendLiteral("ex");   break;
     case eCSSUnit_Char:         aResult.AppendLiteral("ch");   break;
+    case eCSSUnit_RootEM:       aResult.AppendLiteral("rem");  break;
 
     case eCSSUnit_Pixel:        aResult.AppendLiteral("px");   break;
 
     case eCSSUnit_Degree:       aResult.AppendLiteral("deg");  break;
     case eCSSUnit_Grad:         aResult.AppendLiteral("grad"); break;
     case eCSSUnit_Radian:       aResult.AppendLiteral("rad");  break;
 
     case eCSSUnit_Hertz:        aResult.AppendLiteral("Hz");   break;
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -4201,16 +4201,17 @@ struct UnitInfo {
 const UnitInfo UnitData[] = {
   { STR_WITH_LEN("px"), eCSSUnit_Pixel, VARIANT_LENGTH },
   { STR_WITH_LEN("em"), eCSSUnit_EM, VARIANT_LENGTH },
   { STR_WITH_LEN("ex"), eCSSUnit_XHeight, VARIANT_LENGTH },
   { STR_WITH_LEN("pt"), eCSSUnit_Point, VARIANT_LENGTH },
   { STR_WITH_LEN("in"), eCSSUnit_Inch, VARIANT_LENGTH },
   { STR_WITH_LEN("cm"), eCSSUnit_Centimeter, VARIANT_LENGTH },
   { STR_WITH_LEN("ch"), eCSSUnit_Char, VARIANT_LENGTH },
+  { STR_WITH_LEN("rem"), eCSSUnit_RootEM, VARIANT_LENGTH },
   { STR_WITH_LEN("mm"), eCSSUnit_Millimeter, VARIANT_LENGTH },
   { STR_WITH_LEN("pc"), eCSSUnit_Pica, VARIANT_LENGTH },
   { STR_WITH_LEN("deg"), eCSSUnit_Degree, VARIANT_ANGLE },
   { STR_WITH_LEN("grad"), eCSSUnit_Grad, VARIANT_ANGLE },
   { STR_WITH_LEN("rad"), eCSSUnit_Radian, VARIANT_ANGLE },
   { STR_WITH_LEN("hz"), eCSSUnit_Hertz, VARIANT_FREQUENCY },
   { STR_WITH_LEN("khz"), eCSSUnit_Kilohertz, VARIANT_FREQUENCY },
   { STR_WITH_LEN("s"), eCSSUnit_Seconds, VARIANT_TIME },
--- a/layout/style/nsCSSValue.h
+++ b/layout/style/nsCSSValue.h
@@ -137,16 +137,17 @@ enum nsCSSUnit {
   eCSSUnit_Didot        = 400,    // (float) 15 didots == 16 points
   eCSSUnit_Cicero       = 401,    // (float) 12 didots
 
   // Length units - relative
   // Font relative measure
   eCSSUnit_EM           = 800,    // (float) == current font size
   eCSSUnit_XHeight      = 801,    // (float) distance from top of lower case x to baseline
   eCSSUnit_Char         = 802,    // (float) number of characters, used for width with monospace font
+  eCSSUnit_RootEM       = 803,    // (float) == root element font size
 
   // Screen relative measure
   eCSSUnit_Pixel        = 900,    // (float) CSS pixel unit
 
   // Angular units
   eCSSUnit_Degree       = 1000,    // (float) 360 per circle
   eCSSUnit_Grad         = 1001,    // (float) 400 per circle
   eCSSUnit_Radian       = 1002,    // (float) 2*pi per circle
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -22,16 +22,17 @@
  * Contributor(s):
  *   Original Author: David W. Hyatt (hyatt@netscape.com)
  *   Daniel Glazman <glazman@netscape.com>
  *   Roger B. Sidje <rbs@maths.uq.edu.au>
  *   Mats Palmgren <mats.palmgren@bredband.net>
  *   L. David Baron <dbaron@dbaron.org>
  *   Christian Biesinger <cbiesinger@web.de>
  *   Michael Ventnor <m.ventnor@gmail.com>
+ *   Keith Rarick <kr@xph.us>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -161,21 +162,27 @@ static nsString& Unquote(nsString& aStri
        (start == PRUnichar('\'')))) {
     PRInt32 length = aString.Length();
     aString.Truncate(length - 1);
     aString.Cut(0, 1);
   }
   return aString;
 }
 
+static inline nscoord ScaleCoord(const nsCSSValue &aValue, float factor)
+{
+  return NSToCoordRoundWithClamp(aValue.GetFloatValue() * factor);
+}
+
 static nscoord CalcLengthWith(const nsCSSValue& aValue,
                               nscoord aFontSize,
                               const nsStyleFont* aStyleFont,
                               nsStyleContext* aStyleContext,
                               nsPresContext* aPresContext,
+                              PRBool aUseProvidedRootEmSize,
                               // aUseUserFontSet should always be PR_TRUE
                               // except when called from
                               // CalcLengthWithInitialFont.
                               PRBool aUseUserFontSet,
                               PRBool& aInherited)
 {
   NS_ASSERTION(aValue.IsLengthUnit(), "not a length unit");
   NS_ASSERTION(aStyleFont || aStyleContext, "Must have style data");
@@ -194,41 +201,65 @@ static nscoord CalcLengthWith(const nsCS
     aStyleFont = aStyleContext->GetStyleFont();
   }
   if (aFontSize == -1) {
     // XXX Should this be aStyleFont->mSize instead to avoid taking minfontsize
     // prefs into account?
     aFontSize = aStyleFont->mFont.size;
   }
   switch (unit) {
+    case eCSSUnit_RootEM: {
+      nscoord rootFontSize;
+
+      if (aUseProvidedRootEmSize) {
+        // We should use the provided aFontSize as the reference length to
+        // scale. This only happens when we are calculating something on the
+        // root element, in which case aFontSize is already the value we want.
+        rootFontSize = aFontSize;
+      } else {
+        // This is not the root element or we are calculating something other
+        // than font size, so rem is relative to the root element's font size.
+        nsRefPtr<nsStyleContext> rootStyle;
+        const nsStyleFont *rootStyleFont = aStyleFont;
+        nsIContent* docElement = aPresContext->Document()->GetRootContent();
+
+        rootStyle = aPresContext->StyleSet()->ResolveStyleFor(docElement,
+                                                              nsnull);
+        if (rootStyle) {
+          rootStyleFont = rootStyle->GetStyleFont();
+          rootFontSize = rootStyleFont->mFont.size;
+        }
+      }
+
+      return ScaleCoord(aValue, float(rootFontSize));
+    }
     case eCSSUnit_EM: {
-      return NSToCoordRoundWithClamp(aValue.GetFloatValue() * float(aFontSize));
+      return ScaleCoord(aValue, float(aFontSize));
       // XXX scale against font metrics height instead?
     }
     case eCSSUnit_XHeight: {
       nsFont font = aStyleFont->mFont;
       font.size = aFontSize;
       nsCOMPtr<nsIFontMetrics> fm =
         aPresContext->GetMetricsFor(font, aUseUserFontSet);
       nscoord xHeight;
       fm->GetXHeight(xHeight);
-      return NSToCoordRoundWithClamp(aValue.GetFloatValue() * float(xHeight));
+      return ScaleCoord(aValue, float(xHeight));
     }
     case eCSSUnit_Char: {
       nsFont font = aStyleFont->mFont;
       font.size = aFontSize;
       nsCOMPtr<nsIFontMetrics> fm =
         aPresContext->GetMetricsFor(font, aUseUserFontSet);
       nsCOMPtr<nsIThebesFontMetrics> tfm(do_QueryInterface(fm));
       gfxFloat zeroWidth = (tfm->GetThebesFontGroup()->GetFontAt(0)
                             ->GetMetrics().zeroOrAveCharWidth);
 
-      return NSToCoordRoundWithClamp(aValue.GetFloatValue() *
-                            NS_ceil(aPresContext->AppUnitsPerDevPixel() *
-                                    zeroWidth));
+      return ScaleCoord(aValue, NS_ceil(aPresContext->AppUnitsPerDevPixel() *
+                                        zeroWidth));
     }
     default:
       NS_NOTREACHED("unexpected unit");
       break;
   }
   return 0;
 }
 
@@ -236,17 +267,17 @@ static nscoord CalcLengthWith(const nsCS
 nsRuleNode::CalcLength(const nsCSSValue& aValue,
                        nsStyleContext* aStyleContext,
                        nsPresContext* aPresContext,
                        PRBool& aInherited)
 {
   NS_ASSERTION(aStyleContext, "Must have style data");
 
   return CalcLengthWith(aValue, -1, nsnull, aStyleContext, aPresContext,
-                        PR_TRUE, aInherited);
+                        PR_FALSE, PR_TRUE, aInherited);
 }
 
 /* Inline helper function to redirect requests to CalcLength. */
 static inline nscoord CalcLength(const nsCSSValue& aValue,
                                  nsStyleContext* aStyleContext,
                                  nsPresContext* aPresContext,
                                  PRBool& aInherited)
 {
@@ -256,17 +287,17 @@ static inline nscoord CalcLength(const n
 
 /* static */ nscoord
 nsRuleNode::CalcLengthWithInitialFont(nsPresContext* aPresContext,
                                       const nsCSSValue& aValue)
 {
   nsStyleFont defaultFont(aPresContext);
   PRBool inherited;
   return CalcLengthWith(aValue, -1, &defaultFont, nsnull, aPresContext,
-                        PR_FALSE, inherited);
+                        PR_TRUE, PR_FALSE, inherited);
 }
 
 #define SETCOORD_NORMAL                 0x01   // N
 #define SETCOORD_AUTO                   0x02   // A
 #define SETCOORD_INHERIT                0x04   // H
 #define SETCOORD_PERCENT                0x08   // P
 #define SETCOORD_FACTOR                 0x10   // F
 #define SETCOORD_LENGTH                 0x20   // L
@@ -2284,16 +2315,17 @@ nsRuleNode::SetFontSize(nsPresContext* a
                         const nsRuleDataFont& aFontData,
                         const nsStyleFont* aFont,
                         const nsStyleFont* aParentFont,
                         nscoord* aSize,
                         const nsFont& aSystemFont,
                         nscoord aParentSize,
                         nscoord aScriptLevelAdjustedParentSize,
                         PRBool aUsedStartStruct,
+                        PRBool aAtRoot,
                         PRBool& aInherited)
 {
   PRBool zoom = PR_FALSE;
   PRInt32 baseSize = (PRInt32) aPresContext->
     GetDefaultFont(aFont->mGenericID)->size;
   if (eCSSUnit_Enumerated == aFontData.mSize.GetUnit()) {
     PRInt32 value = aFontData.mSize.GetIntValue();
     PRInt32 scaler = aPresContext->FontScaler();
@@ -2339,17 +2371,17 @@ nsRuleNode::SetFontSize(nsPresContext* a
       NS_NOTREACHED("unexpected value");
     }
   }
   else if (aFontData.mSize.IsLengthUnit()) {
     // Note that font-based length units use the parent's size unadjusted
     // for scriptlevel changes. A scriptlevel change between us and the parent
     // is simply ignored.
     *aSize = CalcLengthWith(aFontData.mSize, aParentSize, aParentFont, nsnull,
-                            aPresContext, PR_TRUE, aInherited);
+                            aPresContext, aAtRoot, PR_TRUE, aInherited);
     zoom = aFontData.mSize.IsFixedLengthUnit() ||
            aFontData.mSize.GetUnit() == eCSSUnit_Pixel;
   }
   else if (eCSSUnit_Percent == aFontData.mSize.GetUnit()) {
     aInherited = PR_TRUE;
     // Note that % units use the parent's size unadjusted for scriptlevel
     // changes. A scriptlevel change between us and the parent is simply
     // ignored.
@@ -2413,16 +2445,17 @@ nsRuleNode::SetFont(nsPresContext* aPres
                     nscoord aMinFontSize,
                     PRUint8 aGenericFontID, const nsRuleDataFont& aFontData,
                     const nsStyleFont* aParentFont,
                     nsStyleFont* aFont, PRBool aUsedStartStruct,
                     PRBool& aInherited)
 {
   const nsFont* defaultVariableFont =
     aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID);
+  PRBool atRoot = !aContext->GetParent();
 
   // -moz-system-font: enum (never inherit!)
   nsFont systemFont;
   if (eCSSUnit_Enumerated == aFontData.mSystemFont.GetUnit()) {
     nsSystemFontID sysID;
     switch (aFontData.mSystemFont.GetIntValue()) {
       case NS_STYLE_FONT_CAPTION:       sysID = eSystemFont_Caption;      break;    // css2
       case NS_STYLE_FONT_ICON:          sysID = eSystemFont_Icon;         break;
@@ -2582,17 +2615,17 @@ nsRuleNode::SetFont(nsPresContext* aPres
 
   // -moz-script-min-size: length
   if (aFontData.mScriptMinSize.IsLengthUnit()) {
     // scriptminsize in font units (em, ex) has to be interpreted relative
     // to the parent font, or the size definitions are circular and we
     // 
     aFont->mScriptMinSize =
       CalcLengthWith(aFontData.mScriptMinSize, aParentFont->mSize, aParentFont,
-                     nsnull, aPresContext, PR_TRUE, aInherited);
+                     nsnull, aPresContext, atRoot, PR_TRUE, aInherited);
   }
 
   // -moz-script-size-multiplier: factor, inherit, initial
   SetFactor(aFontData.mScriptSizeMultiplier, aFont->mScriptSizeMultiplier,
             aInherited, aParentFont->mScriptSizeMultiplier,
             NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER,
             SETFCT_POSITIVE);
   
@@ -2621,32 +2654,32 @@ nsRuleNode::SetFont(nsPresContext* aPres
   scriptLevelAdjustedParentSize =
     ComputeScriptLevelSize(aFont, aParentFont, aPresContext,
                            &scriptLevelAdjustedUnconstrainedParentSize);
   NS_ASSERTION(!aUsedStartStruct || aFont->mScriptUnconstrainedSize == aFont->mSize,
                "If we have a start struct, we should have reset everything coming in here");
 #endif
   SetFontSize(aPresContext, aFontData, aFont, aParentFont, &aFont->mSize,
               systemFont, aParentFont->mSize, scriptLevelAdjustedParentSize,
-              aUsedStartStruct, aInherited);
+              aUsedStartStruct, atRoot, aInherited);
 #ifdef MOZ_MATHML
   if (aParentFont->mSize == aParentFont->mScriptUnconstrainedSize &&
       scriptLevelAdjustedParentSize == scriptLevelAdjustedUnconstrainedParentSize) {
     // Fast path: we have not been affected by scriptminsize so we don't
     // need to call SetFontSize again to compute the
     // scriptminsize-unconstrained size. This is OK even if we have a
     // start struct, because if we have a start struct then 'font-size'
     // was specified and so scriptminsize has no effect.
     aFont->mScriptUnconstrainedSize = aFont->mSize;
   } else {
     SetFontSize(aPresContext, aFontData, aFont, aParentFont,
                 &aFont->mScriptUnconstrainedSize, systemFont,
                 aParentFont->mScriptUnconstrainedSize,
                 scriptLevelAdjustedUnconstrainedParentSize,
-                aUsedStartStruct, aInherited);
+                aUsedStartStruct, atRoot, aInherited);
   }
   NS_ASSERTION(aFont->mScriptUnconstrainedSize <= aFont->mSize,
                "scriptminsize should never be making things bigger");
 #endif
 
   // enforce the user' specified minimum font-size on the value that we expose
   // (but don't change font-size:0)
   if (0 < aFont->mSize && aFont->mSize < aMinFontSize)
--- a/layout/style/nsRuleNode.h
+++ b/layout/style/nsRuleNode.h
@@ -617,16 +617,17 @@ protected:
                                       const nsRuleDataFont& aFontData,
                                       const nsStyleFont* aFont,
                                       const nsStyleFont* aParentFont,
                                       nscoord* aSize,
                                       const nsFont& aSystemFont,
                                       nscoord aParentSize,
                                       nscoord aScriptLevelAdjustedParentSize,
                                       PRBool aUsedStartStruct,
+                                      PRBool aAtRoot,
                                       PRBool& aInherited);
 
   static NS_HIDDEN_(void) SetFont(nsPresContext* aPresContext,
                                   nsStyleContext* aContext,
                                   nscoord aMinFontSize,
                                   PRUint8 aGenericFontID,
                                   const nsRuleDataFont& aFontData,
                                   const nsStyleFont* aParentFont,