Bug 1664372 - Fix font loading invalidation to account for metrics coming from the parent style. r=jfkthame

We were only looking at the given frame's style, which is not
sufficient for this case.

Differential Revision: https://phabricator.services.mozilla.com/D96237
This commit is contained in:
Emilio Cobos Álvarez 2020-11-06 22:30:28 +00:00
Родитель 1a3ae2644d
Коммит 8bd419268c
5 изменённых файлов: 84 добавлений и 80 удалений

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

@ -152,10 +152,15 @@ class ComputedStyle {
// only set on ComputedStyles whose pseudo is nsCSSAnonBoxes::mozText().
bool IsTextCombined() const { return bool(Flags() & Flag::IS_TEXT_COMBINED); }
// Is this horizontal-in-vertical (tate-chu-yoko) text? This flag is
// only set on ComputedStyles whose pseudo is nsCSSAnonBoxes::mozText().
bool DependsOnFontMetrics() const {
return bool(Flags() & Flag::DEPENDS_ON_FONT_METRICS);
// Whether there's any font metric dependency coming directly from our style.
bool DependsOnSelfFontMetrics() const {
return bool(Flags() & Flag::DEPENDS_ON_SELF_FONT_METRICS);
}
// Whether there's any font metric dependency coming directly from our parent
// style.
bool DependsOnInheritedFontMetrics() const {
return bool(Flags() & Flag::DEPENDS_ON_INHERITED_FONT_METRICS);
}
// Does this ComputedStyle represent the style for a pseudo-element or

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

@ -24,40 +24,67 @@ enum class FontUsageKind {
None = 0,
// The frame uses the given font, but doesn't use font-metric-dependent units,
// which means that its style doesn't depend on this font.
Frame,
// The frame uses this font and also has some font-metric-dependent units.
Frame = 1 << 0,
// The frame uses has some font-metric-dependent units on this font.
// This means that its style depends on this font, and we need to restyle the
// element the frame came from.
FrameAndFontMetrics,
FontMetrics = 1 << 1,
Max = Frame | FontMetrics,
};
static FontUsageKind StyleFontUsage(ComputedStyle* aComputedStyle,
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(FontUsageKind);
static FontUsageKind StyleFontUsage(nsIFrame* aFrame, ComputedStyle* aStyle,
nsPresContext* aPresContext,
const gfxUserFontSet* aUserFontSet,
const gfxUserFontEntry* aFont,
const nsAString& aFamilyName) {
const nsAString& aFamilyName,
bool aIsExtraStyle) {
MOZ_ASSERT(NS_ConvertUTF8toUTF16(aFont->FamilyName()) == aFamilyName);
// first, check if the family name is in the fontlist
if (!aComputedStyle->StyleFont()->mFont.fontlist.Contains(aFamilyName)) {
return FontUsageKind::None;
auto FontIsUsed = [&aFont, &aPresContext,
&aFamilyName](ComputedStyle* aStyle) {
if (!aStyle->StyleFont()->mFont.fontlist.Contains(aFamilyName)) {
return false;
}
// family name is in the fontlist, check to see if the font group
// associated with the frame includes the specific userfont.
//
// TODO(emilio): Is this check really useful? I guess it's useful for
// different font faces of the same font?
RefPtr<nsFontMetrics> fm = nsLayoutUtils::GetFontMetricsForComputedStyle(
aStyle, aPresContext, 1.0f);
return fm->GetThebesFontGroup()->ContainsUserFont(aFont);
};
auto usage = FontUsageKind::None;
if (FontIsUsed(aStyle)) {
usage |= FontUsageKind::Frame;
if (aStyle->DependsOnSelfFontMetrics()) {
MOZ_ASSERT(aPresContext->UsesExChUnits());
usage |= FontUsageKind::FontMetrics;
}
}
// family name is in the fontlist, check to see if the font group
// associated with the frame includes the specific userfont
RefPtr<nsFontMetrics> fm = nsLayoutUtils::GetFontMetricsForComputedStyle(
aComputedStyle, aPresContext, 1.0f);
if (!fm->GetThebesFontGroup()->ContainsUserFont(aFont)) {
return FontUsageKind::None;
}
if (aComputedStyle->DependsOnFontMetrics()) {
if (aStyle->DependsOnInheritedFontMetrics() &&
!(usage & FontUsageKind::FontMetrics)) {
MOZ_ASSERT(aPresContext->UsesExChUnits());
return FontUsageKind::FrameAndFontMetrics;
ComputedStyle* parentStyle = nullptr;
if (aIsExtraStyle) {
parentStyle = aFrame->Style();
} else {
nsIFrame* provider = nullptr;
parentStyle = aFrame->GetParentComputedStyle(&provider);
}
if (parentStyle && FontIsUsed(parentStyle)) {
usage |= FontUsageKind::FontMetrics;
}
}
return FontUsageKind::Frame;
return usage;
}
static FontUsageKind FrameFontUsage(nsIFrame* aFrame,
@ -65,10 +92,9 @@ static FontUsageKind FrameFontUsage(nsIFrame* aFrame,
const gfxUserFontEntry* aFont,
const nsAString& aFamilyName) {
// check the style of the frame
gfxUserFontSet* ufs = aPresContext->GetUserFontSet();
FontUsageKind kind =
StyleFontUsage(aFrame->Style(), aPresContext, ufs, aFont, aFamilyName);
if (kind == FontUsageKind::FrameAndFontMetrics) {
FontUsageKind kind = StyleFontUsage(aFrame, aFrame->Style(), aPresContext,
aFont, aFamilyName, /* extra = */ false);
if (kind == FontUsageKind::Max) {
return kind;
}
@ -77,9 +103,9 @@ static FontUsageKind FrameFontUsage(nsIFrame* aFrame,
for (ComputedStyle* extraContext;
(extraContext = aFrame->GetAdditionalComputedStyle(contextIndex));
++contextIndex) {
kind = std::max(kind, StyleFontUsage(extraContext, aPresContext, ufs, aFont,
aFamilyName));
if (kind == FontUsageKind::FrameAndFontMetrics) {
kind |= StyleFontUsage(aFrame, extraContext, aPresContext, aFont,
aFamilyName, /* extra = */ true);
if (kind == FontUsageKind::Max) {
break;
}
}
@ -160,11 +186,12 @@ void nsFontFaceUtils::MarkDirtyForFontChange(nsIFrame* aSubtreeRoot,
// and skip checking its children
FontUsageKind kind = FrameFontUsage(f, pc, aFont, familyName);
if (kind != FontUsageKind::None) {
if (alreadyScheduled == ReflowAlreadyScheduled::No) {
if ((kind & FontUsageKind::Frame) &&
alreadyScheduled == ReflowAlreadyScheduled::No) {
ScheduleReflow(presShell, f);
alreadyScheduled = ReflowAlreadyScheduled::Yes;
}
if (kind == FontUsageKind::FrameAndFontMetrics) {
if (kind & FontUsageKind::FontMetrics) {
MOZ_ASSERT(f->GetContent() && f->GetContent()->IsElement(),
"How could we target a non-element with selectors?");
f->PresContext()->RestyleManager()->PostRestyleEvent(

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

@ -57,19 +57,24 @@ bitflags! {
/// Whether the child explicitly inherits any reset property.
const INHERITS_RESET_STYLE = 1 << 8;
/// Whether any value on our style is font-metric-dependent.
const DEPENDS_ON_FONT_METRICS = 1 << 9;
/// Whether any value on our style is font-metric-dependent on our
/// primary font.
const DEPENDS_ON_SELF_FONT_METRICS = 1 << 9;
/// Whether any value on our style is font-metric-dependent on the
/// primary font of our parent.
const DEPENDS_ON_INHERITED_FONT_METRICS = 1 << 10;
/// Whether the style or any of the ancestors has a multicol style.
///
/// Only used in Servo.
const CAN_BE_FRAGMENTED = 1 << 10;
const CAN_BE_FRAGMENTED = 1 << 11;
/// Whether this style is the style of the document element.
const IS_ROOT_ELEMENT_STYLE = 1 << 11;
const IS_ROOT_ELEMENT_STYLE = 1 << 12;
/// Whether this element is inside an `opacity: 0` subtree.
const IS_IN_OPACITY_ZERO_SUBTREE = 1 << 12;
const IS_IN_OPACITY_ZERO_SUBTREE = 1 << 13;
/// Whether there are author-specified rules for border-* properties
/// (except border-image-*), background-color, or background-image.
@ -77,13 +82,13 @@ bitflags! {
/// TODO(emilio): Maybe do include border-image, see:
///
/// https://github.com/w3c/csswg-drafts/issues/4777#issuecomment-604424845
const HAS_AUTHOR_SPECIFIED_BORDER_BACKGROUND = 1 << 13;
const HAS_AUTHOR_SPECIFIED_BORDER_BACKGROUND = 1 << 14;
/// Whether there are author-specified rules for padding-* properties.
///
/// FIXME(emilio): Try to merge this with BORDER_BACKGROUND, see
/// https://github.com/w3c/csswg-drafts/issues/4777
const HAS_AUTHOR_SPECIFIED_PADDING = 1 << 14;
const HAS_AUTHOR_SPECIFIED_PADDING = 1 << 15;
}
}

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

@ -161,6 +161,10 @@ impl FontRelativeLength {
}
let reference_font_size = base_size.resolve(context);
let font_metrics_flag = match base_size {
FontBaseSize::CurrentStyle => ComputedValueFlags::DEPENDS_ON_SELF_FONT_METRICS,
FontBaseSize::InheritedStyle => ComputedValueFlags::DEPENDS_ON_INHERITED_FONT_METRICS,
};
match *self {
FontRelativeLength::Em(length) => {
if context.for_non_inherited_property.is_some() {
@ -178,9 +182,7 @@ impl FontRelativeLength {
if context.for_non_inherited_property.is_some() {
context.rule_cache_conditions.borrow_mut().set_uncacheable();
}
context
.builder
.add_flags(ComputedValueFlags::DEPENDS_ON_FONT_METRICS);
context.builder.add_flags(font_metrics_flag);
// The x-height is an intrinsically horizontal metric.
let metrics =
query_font_metrics(context, base_size, FontMetricsOrientation::Horizontal);
@ -199,9 +201,7 @@ impl FontRelativeLength {
if context.for_non_inherited_property.is_some() {
context.rule_cache_conditions.borrow_mut().set_uncacheable();
}
context
.builder
.add_flags(ComputedValueFlags::DEPENDS_ON_FONT_METRICS);
context.builder.add_flags(font_metrics_flag);
// https://drafts.csswg.org/css-values/#ch:
//
// Equal to the used advance measure of the “0” (ZERO,

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

@ -1,33 +0,0 @@
[ch-pseudo-recalc-on-font-load.html]
[ch in pseudo-element ::marker should be recalculated after loading a web font]
expected:
if (os == "win") and webrender and not debug and not fission: ["PASS", "FAIL"]
if (os == "linux") and webrender and debug and not fission: ["PASS", "FAIL"]
if (os == "linux") and not webrender and (processor == "x86"): ["FAIL", "PASS"]
if (os == "linux") and not webrender and (processor == "x86_64"): ["PASS", "FAIL"]
if os == "mac": ["PASS", "FAIL"]
[ch in pseudo-element ::after should be recalculated after loading a web font]
expected:
if (os == "win") and webrender and not debug and not fission: ["PASS", "FAIL"]
if (os == "linux") and webrender and debug and not fission: ["PASS", "FAIL"]
if (os == "linux") and not webrender and (processor == "x86_64"): ["PASS", "FAIL"]
if (os == "linux") and not webrender and (processor == "x86"): ["FAIL", "PASS"]
if os == "mac": ["PASS", "FAIL"]
[ch in pseudo-element ::first-line should be recalculated after loading a web font]
expected:
if (os == "linux") and webrender and debug and not fission: ["PASS", "FAIL"]
if (os == "win") and webrender and not debug and not fission: ["PASS", "FAIL"]
if (os == "linux") and not webrender and (processor == "x86_64"): ["PASS", "FAIL"]
if (os == "linux") and not webrender and (processor == "x86"): ["FAIL", "PASS"]
if os == "mac": ["PASS", "FAIL"]
[ch in pseudo-element ::before should be recalculated after loading a web font]
expected:
if (os == "linux") and webrender and debug and not fission: ["PASS", "FAIL"]
if (os == "win") and webrender and not debug and not fission: ["PASS", "FAIL"]
if (os == "linux") and not webrender and (processor == "x86_64"): ["PASS", "FAIL"]
if (os == "linux") and not webrender and (processor == "x86"): ["FAIL", "PASS"]
if os == "mac": ["PASS", "FAIL"]