Bug 1810815 - Properly account for cases where CSS units ch or ic are based on a different font than the first, due to character coverage. r=emilio

Differential Revision: https://phabricator.services.mozilla.com/D167070
This commit is contained in:
Jonathan Kew 2023-01-18 14:22:11 +00:00
Родитель 482a193c66
Коммит f956fb8c4d
3 изменённых файлов: 61 добавлений и 10 удалений

Просмотреть файл

@ -2284,7 +2284,7 @@ already_AddRefed<gfxFont> gfxFontGroup::GetDefaultFont() {
}
already_AddRefed<gfxFont> gfxFontGroup::GetFirstValidFont(
uint32_t aCh, StyleGenericFontFamily* aGeneric) {
uint32_t aCh, StyleGenericFontFamily* aGeneric, bool* aIsFirst) {
// Ensure cached font instances are valid.
CheckForUpdatedPlatformList();
@ -2319,6 +2319,9 @@ already_AddRefed<gfxFont> gfxFontGroup::GetFirstValidFont(
if (aGeneric) {
*aGeneric = ff.Generic();
}
if (aIsFirst) {
*aIsFirst = (i == 0);
}
return font.forget();
}
@ -2349,12 +2352,18 @@ already_AddRefed<gfxFont> gfxFontGroup::GetFirstValidFont(
if (aGeneric) {
*aGeneric = ff.Generic();
}
if (aIsFirst) {
*aIsFirst = (i == 0);
}
return font.forget();
}
}
if (aGeneric) {
*aGeneric = StyleGenericFontFamily::None;
}
if (aIsFirst) {
*aIsFirst = false;
}
return GetDefaultFont();
}
@ -3831,6 +3840,35 @@ already_AddRefed<gfxFont> gfxFontGroup::WhichSystemFontSupportsChar(
&visibility);
}
gfxFont::Metrics gfxFontGroup::GetMetricsForCSSUnits(
gfxFont::Orientation aOrientation) {
bool isFirst;
RefPtr<gfxFont> font = GetFirstValidFont(0x20, nullptr, &isFirst);
auto metrics = font->GetMetrics(aOrientation);
// If the font we used to get metrics was not the first in the list,
// or if it doesn't support the ZERO character, check for the font that
// does support ZERO and use its metrics for the 'ch' unit.
if (!isFirst || !font->HasCharacter('0')) {
RefPtr<gfxFont> zeroFont = GetFirstValidFont('0');
if (zeroFont != font) {
const auto& zeroMetrics = zeroFont->GetMetrics(aOrientation);
metrics.zeroWidth = zeroMetrics.zeroWidth;
}
}
// Likewise for the WATER ideograph character used as the basis for 'ic'.
if (!isFirst || !font->HasCharacter(0x6C34)) {
RefPtr<gfxFont> icFont = GetFirstValidFont(0x6C34);
if (icFont != font) {
const auto& icMetrics = icFont->GetMetrics(aOrientation);
metrics.ideographicWidth = icMetrics.ideographicWidth;
}
}
return metrics;
}
void gfxMissingFontRecorder::Flush() {
static bool mNotifiedFontsInitialized = false;
static uint32_t mNotifiedFonts[gfxMissingFontRecorder::kNumScriptBitsWords];

Просмотреть файл

@ -947,8 +947,10 @@ class gfxFontGroup final : public gfxTextRunFactory {
// Initiates userfont loads if userfont not loaded.
// aGeneric: if non-null, returns the CSS generic type that was mapped to
// this font
// aIsFirst: if non-null, returns whether the font was first in the list
already_AddRefed<gfxFont> GetFirstValidFont(
uint32_t aCh = 0x20, mozilla::StyleGenericFontFamily* aGeneric = nullptr);
uint32_t aCh = 0x20, mozilla::StyleGenericFontFamily* aGeneric = nullptr,
bool* aIsFirst = nullptr);
// Returns the first font in the font-group that has an OpenType MATH table,
// or null if no such font is available. The GetMathConstant methods may be
@ -1104,6 +1106,14 @@ class gfxFontGroup final : public gfxTextRunFactory {
nsAtom* Language() const { return mLanguage.get(); }
// Get font metrics to be used as the basis for CSS font-relative units.
// Note that these may be a "composite" of metrics from multiple fonts,
// because the 'ch' and 'ic' units depend on the font that would be used
// to render specific characters, not simply the "first available" font.
// https://drafts.csswg.org/css-values-4/#ch
// https://drafts.csswg.org/css-values-4/#ic
gfxFont::Metrics GetMetricsForCSSUnits(gfxFont::Orientation aOrientation);
protected:
friend class mozilla::PostTraversalTask;

Просмотреть файл

@ -1431,17 +1431,20 @@ GeckoFontMetrics Gecko_GetFontMetrics(const nsPresContext* aPresContext,
nsPresContext* presContext = const_cast<nsPresContext*>(aPresContext);
RefPtr<nsFontMetrics> fm = nsLayoutUtils::GetMetricsFor(
presContext, aIsVertical, aFont, aFontSize, aUseUserFontSet);
RefPtr<gfxFont> font = fm->GetThebesFontGroup()->GetFirstValidFont();
const auto& metrics = font->GetMetrics(fm->Orientation());
auto* fontGroup = fm->GetThebesFontGroup();
auto metrics = fontGroup->GetMetricsForCSSUnits(fm->Orientation());
float scriptPercentScaleDown = 0;
float scriptScriptPercentScaleDown = 0;
if (aRetrieveMathScales && font->TryGetMathTable()) {
scriptPercentScaleDown = static_cast<float>(
font->MathTable()->Constant(gfxMathTable::ScriptPercentScaleDown));
scriptScriptPercentScaleDown =
static_cast<float>(font->MathTable()->Constant(
gfxMathTable::ScriptScriptPercentScaleDown));
if (aRetrieveMathScales) {
RefPtr<gfxFont> font = fontGroup->GetFirstValidFont();
if (font->TryGetMathTable()) {
scriptPercentScaleDown = static_cast<float>(
font->MathTable()->Constant(gfxMathTable::ScriptPercentScaleDown));
scriptScriptPercentScaleDown =
static_cast<float>(font->MathTable()->Constant(
gfxMathTable::ScriptScriptPercentScaleDown));
}
}
int32_t d2a = aPresContext->AppUnitsPerDevPixel();