зеркало из https://github.com/mozilla/pjs.git
Make nsRuleNode's use of font metrics for ch and ex units pass the correct language. (Bug 678671, patch 3) r=roc
This makes these users (which are exceptions within layout, although low-level enough that it won't matter for font inflation work) call through to GetMetricsFor explicitly with the correct language, rather than using the broken nsPresContext::GetMetricsFor and its charset-detected language. This improves the correctness of our behavior for 'ch' and 'ex' CSS units when the font selection (or defaults) are language-dependent. It should also reduce the number of unique sets of font metrics requested (which helps nsFontCache effectiveness).
This commit is contained in:
Родитель
4695681430
Коммит
0e94875a83
|
@ -184,6 +184,7 @@ static void EnsureBlockDisplay(PRUint8& display)
|
|||
static nscoord CalcLengthWith(const nsCSSValue& aValue,
|
||||
nscoord aFontSize,
|
||||
const nsStyleFont* aStyleFont,
|
||||
const nsStyleVisibility* aStyleVisibility,
|
||||
nsStyleContext* aStyleContext,
|
||||
nsPresContext* aPresContext,
|
||||
PRBool aUseProvidedRootEmSize,
|
||||
|
@ -196,6 +197,7 @@ struct CalcLengthCalcOps : public css::BasicCoordCalcOps,
|
|||
// All of the parameters to CalcLengthWith except aValue.
|
||||
const nscoord mFontSize;
|
||||
const nsStyleFont* const mStyleFont;
|
||||
const nsStyleVisibility* const mStyleVisibility;
|
||||
nsStyleContext* const mStyleContext;
|
||||
nsPresContext* const mPresContext;
|
||||
const PRBool mUseProvidedRootEmSize;
|
||||
|
@ -203,11 +205,13 @@ struct CalcLengthCalcOps : public css::BasicCoordCalcOps,
|
|||
PRBool& mCanStoreInRuleTree;
|
||||
|
||||
CalcLengthCalcOps(nscoord aFontSize, const nsStyleFont* aStyleFont,
|
||||
const nsStyleVisibility* aStyleVisibility,
|
||||
nsStyleContext* aStyleContext, nsPresContext* aPresContext,
|
||||
PRBool aUseProvidedRootEmSize, PRBool aUseUserFontSet,
|
||||
PRBool& aCanStoreInRuleTree)
|
||||
: mFontSize(aFontSize),
|
||||
mStyleFont(aStyleFont),
|
||||
mStyleVisibility(aStyleVisibility),
|
||||
mStyleContext(aStyleContext),
|
||||
mPresContext(aPresContext),
|
||||
mUseProvidedRootEmSize(aUseProvidedRootEmSize),
|
||||
|
@ -218,8 +222,8 @@ struct CalcLengthCalcOps : public css::BasicCoordCalcOps,
|
|||
|
||||
result_type ComputeLeafValue(const nsCSSValue& aValue)
|
||||
{
|
||||
return CalcLengthWith(aValue, mFontSize, mStyleFont, mStyleContext,
|
||||
mPresContext, mUseProvidedRootEmSize,
|
||||
return CalcLengthWith(aValue, mFontSize, mStyleFont, mStyleVisibility,
|
||||
mStyleContext, mPresContext, mUseProvidedRootEmSize,
|
||||
mUseUserFontSet, mCanStoreInRuleTree);
|
||||
}
|
||||
};
|
||||
|
@ -229,9 +233,34 @@ static inline nscoord ScaleCoord(const nsCSSValue &aValue, float factor)
|
|||
return NSToCoordRoundWithClamp(aValue.GetFloatValue() * factor);
|
||||
}
|
||||
|
||||
already_AddRefed<nsFontMetrics>
|
||||
GetMetricsFor(nsPresContext* aPresContext,
|
||||
nsStyleContext* aStyleContext,
|
||||
const nsStyleFont* aStyleFont,
|
||||
const nsStyleVisibility* aStyleVisibility,
|
||||
nscoord aFontSize, // overrides value from aStyleFont
|
||||
PRBool aUseUserFontSet)
|
||||
{
|
||||
nsFont font = aStyleFont->mFont;
|
||||
font.size = aFontSize;
|
||||
gfxUserFontSet *fs = nsnull;
|
||||
if (aUseUserFontSet) {
|
||||
fs = aPresContext->GetUserFontSet();
|
||||
}
|
||||
nsRefPtr<nsFontMetrics> fm;
|
||||
if (!aStyleVisibility) {
|
||||
aStyleVisibility = aStyleContext->GetStyleVisibility();
|
||||
}
|
||||
aPresContext->DeviceContext()->GetMetricsFor(font,
|
||||
aStyleVisibility->mLanguage,
|
||||
fs, *getter_AddRefs(fm));
|
||||
return fm.forget();
|
||||
}
|
||||
|
||||
static nscoord CalcLengthWith(const nsCSSValue& aValue,
|
||||
nscoord aFontSize,
|
||||
const nsStyleFont* aStyleFont,
|
||||
const nsStyleVisibility* aStyleVisibility,
|
||||
nsStyleContext* aStyleContext,
|
||||
nsPresContext* aPresContext,
|
||||
PRBool aUseProvidedRootEmSize,
|
||||
|
@ -243,8 +272,10 @@ static nscoord CalcLengthWith(const nsCSSValue& aValue,
|
|||
{
|
||||
NS_ASSERTION(aValue.IsLengthUnit() || aValue.IsCalcUnit(),
|
||||
"not a length or calc unit");
|
||||
NS_ASSERTION(aStyleFont || aStyleContext, "Must have style data");
|
||||
NS_ASSERTION(!aStyleFont || !aStyleContext, "Duplicate sources of data");
|
||||
NS_ASSERTION((aStyleFont && aStyleVisibility) || aStyleContext,
|
||||
"Must have style data");
|
||||
NS_ASSERTION((!aStyleFont && !aStyleVisibility) || !aStyleContext,
|
||||
"Duplicate sources of data");
|
||||
NS_ASSERTION(aPresContext, "Must have prescontext");
|
||||
|
||||
if (aValue.IsFixedLengthUnit()) {
|
||||
|
@ -305,17 +336,15 @@ static nscoord CalcLengthWith(const nsCSSValue& aValue,
|
|||
// XXX scale against font metrics height instead?
|
||||
}
|
||||
case eCSSUnit_XHeight: {
|
||||
nsFont font = styleFont->mFont;
|
||||
font.size = aFontSize;
|
||||
nsRefPtr<nsFontMetrics> fm =
|
||||
aPresContext->GetMetricsFor(font, aUseUserFontSet);
|
||||
GetMetricsFor(aPresContext, aStyleContext, styleFont,
|
||||
aStyleVisibility, aFontSize, aUseUserFontSet);
|
||||
return ScaleCoord(aValue, float(fm->XHeight()));
|
||||
}
|
||||
case eCSSUnit_Char: {
|
||||
nsFont font = styleFont->mFont;
|
||||
font.size = aFontSize;
|
||||
nsRefPtr<nsFontMetrics> fm =
|
||||
aPresContext->GetMetricsFor(font, aUseUserFontSet);
|
||||
GetMetricsFor(aPresContext, aStyleContext, styleFont,
|
||||
aStyleVisibility, aFontSize, aUseUserFontSet);
|
||||
gfxFloat zeroWidth = (fm->GetThebesFontGroup()->GetFontAt(0)
|
||||
->GetMetrics().zeroOrAveCharWidth);
|
||||
|
||||
|
@ -333,7 +362,8 @@ static nscoord CalcLengthWith(const nsCSSValue& aValue,
|
|||
case eCSSUnit_Calc_Times_L:
|
||||
case eCSSUnit_Calc_Times_R:
|
||||
case eCSSUnit_Calc_Divided: {
|
||||
CalcLengthCalcOps ops(aFontSize, aStyleFont, aStyleContext, aPresContext,
|
||||
CalcLengthCalcOps ops(aFontSize, aStyleFont, aStyleVisibility,
|
||||
aStyleContext, aPresContext,
|
||||
aUseProvidedRootEmSize, aUseUserFontSet,
|
||||
aCanStoreInRuleTree);
|
||||
return css::ComputeCalc(aValue, ops);
|
||||
|
@ -353,7 +383,8 @@ nsRuleNode::CalcLength(const nsCSSValue& aValue,
|
|||
{
|
||||
NS_ASSERTION(aStyleContext, "Must have style data");
|
||||
|
||||
return CalcLengthWith(aValue, -1, nsnull, aStyleContext, aPresContext,
|
||||
return CalcLengthWith(aValue, -1, nsnull, nsnull,
|
||||
aStyleContext, aPresContext,
|
||||
PR_FALSE, PR_TRUE, aCanStoreInRuleTree);
|
||||
}
|
||||
|
||||
|
@ -372,8 +403,10 @@ nsRuleNode::CalcLengthWithInitialFont(nsPresContext* aPresContext,
|
|||
const nsCSSValue& aValue)
|
||||
{
|
||||
nsStyleFont defaultFont(aPresContext);
|
||||
nsStyleVisibility defaultVisibility(aPresContext); // FIXME: best language?
|
||||
PRBool canStoreInRuleTree;
|
||||
return CalcLengthWith(aValue, -1, &defaultFont, nsnull, aPresContext,
|
||||
return CalcLengthWith(aValue, -1, &defaultFont, &defaultVisibility,
|
||||
nsnull, aPresContext,
|
||||
PR_TRUE, PR_FALSE, canStoreInRuleTree);
|
||||
}
|
||||
|
||||
|
@ -2442,15 +2475,18 @@ struct SetFontSizeCalcOps : public css::BasicCoordCalcOps,
|
|||
// The parameters beyond aValue that we need for CalcLengthWith.
|
||||
const nscoord mParentSize;
|
||||
const nsStyleFont* const mParentFont;
|
||||
const nsStyleVisibility* const mLanguageVisibility;
|
||||
nsPresContext* const mPresContext;
|
||||
const PRBool mAtRoot;
|
||||
PRBool& mCanStoreInRuleTree;
|
||||
|
||||
SetFontSizeCalcOps(nscoord aParentSize, const nsStyleFont* aParentFont,
|
||||
const nsStyleVisibility* aLanguageVisibility,
|
||||
nsPresContext* aPresContext, PRBool aAtRoot,
|
||||
PRBool& aCanStoreInRuleTree)
|
||||
: mParentSize(aParentSize),
|
||||
mParentFont(aParentFont),
|
||||
mLanguageVisibility(aLanguageVisibility),
|
||||
mPresContext(aPresContext),
|
||||
mAtRoot(aAtRoot),
|
||||
mCanStoreInRuleTree(aCanStoreInRuleTree)
|
||||
|
@ -2464,7 +2500,8 @@ struct SetFontSizeCalcOps : public css::BasicCoordCalcOps,
|
|||
// 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.
|
||||
size = CalcLengthWith(aValue, mParentSize, mParentFont,
|
||||
size = CalcLengthWith(aValue, mParentSize,
|
||||
mParentFont, mLanguageVisibility,
|
||||
nsnull, mPresContext, mAtRoot,
|
||||
PR_TRUE, mCanStoreInRuleTree);
|
||||
if (!aValue.IsRelativeLengthUnit()) {
|
||||
|
@ -2492,6 +2529,7 @@ nsRuleNode::SetFontSize(nsPresContext* aPresContext,
|
|||
const nsRuleData* aRuleData,
|
||||
const nsStyleFont* aFont,
|
||||
const nsStyleFont* aParentFont,
|
||||
const nsStyleVisibility* aLanguageVisibility,
|
||||
nscoord* aSize,
|
||||
const nsFont& aSystemFont,
|
||||
nscoord aParentSize,
|
||||
|
@ -2550,8 +2588,8 @@ nsRuleNode::SetFontSize(nsPresContext* aPresContext,
|
|||
else if (sizeValue->IsLengthUnit() ||
|
||||
sizeValue->GetUnit() == eCSSUnit_Percent ||
|
||||
sizeValue->IsCalcUnit()) {
|
||||
SetFontSizeCalcOps ops(aParentSize, aParentFont, aPresContext, aAtRoot,
|
||||
aCanStoreInRuleTree);
|
||||
SetFontSizeCalcOps ops(aParentSize, aParentFont, aLanguageVisibility,
|
||||
aPresContext, aAtRoot, aCanStoreInRuleTree);
|
||||
*aSize = css::ComputeCalc(*sizeValue, ops);
|
||||
if (*aSize < 0) {
|
||||
NS_ABORT_IF_FALSE(sizeValue->IsCalcUnit(),
|
||||
|
@ -2622,6 +2660,12 @@ nsRuleNode::SetFont(nsPresContext* aPresContext, nsStyleContext* aContext,
|
|||
const nsFont* defaultVariableFont =
|
||||
aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID);
|
||||
PRBool atRoot = !aContext->GetParent();
|
||||
// We get '%', 'em', 'ex', and 'ch' units from aParentFont. For 'ex'
|
||||
// and 'ch' units we use font metrics, which depend on language. It
|
||||
// makes sense to use the language from the same style context as
|
||||
// aParentFont.
|
||||
const nsStyleVisibility *languageVisibility =
|
||||
(atRoot ? aContext : aContext->GetParent())->GetStyleVisibility();
|
||||
|
||||
// -moz-system-font: enum (never inherit!)
|
||||
nsFont systemFont;
|
||||
|
@ -2810,7 +2854,8 @@ nsRuleNode::SetFont(nsPresContext* aPresContext, nsStyleContext* aContext,
|
|||
// to the parent font, or the size definitions are circular and we
|
||||
//
|
||||
aFont->mScriptMinSize =
|
||||
CalcLengthWith(*scriptMinSizeValue, aParentFont->mSize, aParentFont,
|
||||
CalcLengthWith(*scriptMinSizeValue, aParentFont->mSize,
|
||||
aParentFont, languageVisibility,
|
||||
nsnull, aPresContext, atRoot, PR_TRUE,
|
||||
aCanStoreInRuleTree);
|
||||
}
|
||||
|
@ -2878,7 +2923,8 @@ nsRuleNode::SetFont(nsPresContext* aPresContext, nsStyleContext* aContext,
|
|||
&scriptLevelAdjustedUnconstrainedParentSize);
|
||||
NS_ASSERTION(!aUsedStartStruct || aFont->mScriptUnconstrainedSize == aFont->mSize,
|
||||
"If we have a start struct, we should have reset everything coming in here");
|
||||
SetFontSize(aPresContext, aRuleData, aFont, aParentFont, &aFont->mSize,
|
||||
SetFontSize(aPresContext, aRuleData, aFont, aParentFont,
|
||||
languageVisibility, &aFont->mSize,
|
||||
systemFont, aParentFont->mSize, scriptLevelAdjustedParentSize,
|
||||
aUsedStartStruct, atRoot, aCanStoreInRuleTree);
|
||||
if (aParentFont->mSize == aParentFont->mScriptUnconstrainedSize &&
|
||||
|
@ -2891,8 +2937,8 @@ nsRuleNode::SetFont(nsPresContext* aPresContext, nsStyleContext* aContext,
|
|||
aFont->mScriptUnconstrainedSize = aFont->mSize;
|
||||
} else {
|
||||
SetFontSize(aPresContext, aRuleData, aFont, aParentFont,
|
||||
&aFont->mScriptUnconstrainedSize, systemFont,
|
||||
aParentFont->mScriptUnconstrainedSize,
|
||||
languageVisibility, &aFont->mScriptUnconstrainedSize,
|
||||
systemFont, aParentFont->mScriptUnconstrainedSize,
|
||||
scriptLevelAdjustedUnconstrainedParentSize,
|
||||
aUsedStartStruct, atRoot, aCanStoreInRuleTree);
|
||||
}
|
||||
|
@ -4556,6 +4602,10 @@ nsRuleNode::ComputeVisibilityData(void* aStartStruct,
|
|||
COMPUTE_START_INHERITED(Visibility, (mPresContext),
|
||||
visibility, parentVisibility)
|
||||
|
||||
// IMPORTANT: No properties in this struct have lengths in them. We
|
||||
// depend on this since CalcLengthWith can call GetStyleVisibility()
|
||||
// to get the language for resolving fonts!
|
||||
|
||||
// direction: enum, inherit, initial
|
||||
SetDiscrete(*aRuleData->ValueForDirection(), visibility->mDirection,
|
||||
canStoreInRuleTree,
|
||||
|
|
|
@ -600,6 +600,7 @@ protected:
|
|||
const nsRuleData* aRuleData,
|
||||
const nsStyleFont* aFont,
|
||||
const nsStyleFont* aParentFont,
|
||||
const nsStyleVisibility* aLanguageVisibility,
|
||||
nscoord* aSize,
|
||||
const nsFont& aSystemFont,
|
||||
nscoord aParentSize,
|
||||
|
|
|
@ -133,6 +133,7 @@ _TEST_FILES = test_acid3_test46.html \
|
|||
file_bug645998-1.css \
|
||||
file_bug645998-2.css \
|
||||
test_cascade.html \
|
||||
test_ch_ex_no_infloops.html \
|
||||
test_compute_data_with_start_struct.html \
|
||||
test_computed_style.html \
|
||||
test_computed_style_no_pseudo.html \
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=678671
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 678671</title>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="property_database.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=678671">Mozilla Bug 678671</a>
|
||||
<p id="display"></p>
|
||||
<div id="content"></div>
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 678671 **/
|
||||
|
||||
/**
|
||||
* Test 'ex' and 'ch' units in every place we possible can to make
|
||||
* sure they don't cause an infinite loop.
|
||||
*/
|
||||
|
||||
var content = document.getElementById("content");
|
||||
var cs = getComputedStyle(content, "");
|
||||
|
||||
for (var prop in gCSSProperties) {
|
||||
var info = gCSSProperties[prop];
|
||||
if (info.backend_only) {
|
||||
continue;
|
||||
}
|
||||
function test_val(v) {
|
||||
content.style.setProperty(prop, v, "");
|
||||
isnot(get_computed_value(cs, prop), "",
|
||||
"Setting '" + prop + "' to '" + v + "' should not cause infinite loop");
|
||||
}
|
||||
test_val('3ex');
|
||||
test_val('2ch');
|
||||
function test_replaced_values(value_list) {
|
||||
// For each item in value_list, if it looks like it has a dimension
|
||||
// in it, replace those dimensions with 3ex and 2ch and test it.
|
||||
for (var i = 0; i < value_list.length; ++i) {
|
||||
var value = value_list[i];
|
||||
function try_replace(withval) {
|
||||
var rep = value.replace(/[0-9.]+[a-zA-Z]+/g, withval)
|
||||
if (rep != value) {
|
||||
test_val(rep);
|
||||
}
|
||||
}
|
||||
try_replace('3ex');
|
||||
try_replace('2ch');
|
||||
}
|
||||
}
|
||||
test_replaced_values(info.initial_values);
|
||||
test_replaced_values(info.other_values);
|
||||
content.style.removeProperty(prop);
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче