Implement 'rem' unit from css3-values. (Bug 472195) r+sr=dbaron

This commit is contained in:
Keith Rarick 2009-01-20 13:58:48 -08:00
parent 45688b5695
commit 01dca56c79
24 changed files with 195 additions and 12 deletions

View File

@ -761,6 +761,7 @@ 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")
@ -1416,7 +1417,6 @@ 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")

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -0,0 +1,7 @@
<style>
:root { font-size: 20px }
body { font-size: 25px }
div { font-size: 1.5rem }
</style>
<body><div>Inside</div></body>

View File

@ -0,0 +1,6 @@
<style>
:root { font-size: 10px }
body { font-size: 12px }
</style>
<body>Outside<iframe src=unit-rem-iframe-inside.html></body>

View File

@ -0,0 +1,7 @@
<style>
:root { font-size: 20px }
body { font-size: 25px }
div { font-size: 30px }
</style>
<body><div>Inside</div></body>

View File

@ -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>

View File

@ -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>

After

Width:  |  Height:  |  Size: 153 B

View File

@ -0,0 +1,7 @@
<style>
:root {
font-size: 1.5em;
}
</style>
<body>Hello</body>

View File

@ -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>

View File

@ -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>

View File

@ -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>

After

Width:  |  Height:  |  Size: 193 B

View File

@ -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>

After

Width:  |  Height:  |  Size: 324 B

View File

@ -0,0 +1,7 @@
<style>
:root {
font-size: 1.5rem;
}
</style>
<body>Hello</body>

View File

@ -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>

View File

@ -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>

After

Width:  |  Height:  |  Size: 189 B

View File

@ -41,6 +41,9 @@ 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

View File

@ -474,6 +474,7 @@ nsCSSDeclaration::AppendCSSValueToString(nsCSSProperty aProperty,
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;

View File

@ -4206,6 +4206,7 @@ const UnitInfo UnitData[] = {
{ 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 },

View File

@ -142,6 +142,7 @@ enum nsCSSUnit {
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

View File

@ -27,6 +27,7 @@
* 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"),
@ -166,11 +167,17 @@ static nsString& Unquote(nsString& aString)
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.
@ -199,8 +206,33 @@ static nscoord CalcLengthWith(const nsCSSValue& aValue,
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: {
@ -210,7 +242,7 @@ static nscoord CalcLengthWith(const nsCSSValue& aValue,
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;
@ -221,9 +253,8 @@ static nscoord CalcLengthWith(const nsCSSValue& aValue,
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");
@ -241,7 +272,7 @@ nsRuleNode::CalcLength(const nsCSSValue& aValue,
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. */
@ -261,7 +292,7 @@ nsRuleNode::CalcLengthWithInitialFont(nsPresContext* aPresContext,
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
@ -2289,6 +2320,7 @@ nsRuleNode::SetFontSize(nsPresContext* aPresContext,
nscoord aParentSize,
nscoord aScriptLevelAdjustedParentSize,
PRBool aUsedStartStruct,
PRBool aAtRoot,
PRBool& aInherited)
{
PRBool zoom = PR_FALSE;
@ -2344,7 +2376,7 @@ nsRuleNode::SetFontSize(nsPresContext* aPresContext,
// 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;
}
@ -2418,6 +2450,7 @@ nsRuleNode::SetFont(nsPresContext* aPresContext, nsStyleContext* aContext,
{
const nsFont* defaultVariableFont =
aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID);
PRBool atRoot = !aContext->GetParent();
// -moz-system-font: enum (never inherit!)
nsFont systemFont;
@ -2587,7 +2620,7 @@ nsRuleNode::SetFont(nsPresContext* aPresContext, nsStyleContext* aContext,
//
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
@ -2626,7 +2659,7 @@ nsRuleNode::SetFont(nsPresContext* aPresContext, nsStyleContext* aContext,
#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) {
@ -2641,7 +2674,7 @@ nsRuleNode::SetFont(nsPresContext* aPresContext, nsStyleContext* aContext,
&aFont->mScriptUnconstrainedSize, systemFont,
aParentFont->mScriptUnconstrainedSize,
scriptLevelAdjustedUnconstrainedParentSize,
aUsedStartStruct, aInherited);
aUsedStartStruct, atRoot, aInherited);
}
NS_ASSERTION(aFont->mScriptUnconstrainedSize <= aFont->mSize,
"scriptminsize should never be making things bigger");

View File

@ -622,6 +622,7 @@ protected:
nscoord aParentSize,
nscoord aScriptLevelAdjustedParentSize,
PRBool aUsedStartStruct,
PRBool aAtRoot,
PRBool& aInherited);
static NS_HIDDEN_(void) SetFont(nsPresContext* aPresContext,