Skip to content

Commit 2763574

Browse files
kbhomesemilio
authored andcommitted
Bug 1740584 - Implement relative root font lengths rcap, rch, rex, ric. r=emilio,firefox-style-system-reviewers,layout-reviewers
Differential Revision: https://phabricator.services.mozilla.com/D274527
1 parent 41c8409 commit 2763574

File tree

25 files changed

+535
-201
lines changed

25 files changed

+535
-201
lines changed

layout/base/nsPresContext.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2149,8 +2149,10 @@ void nsPresContext::UserFontSetUpdated(gfxUserFontEntry* aUpdatedFont) {
21492149
// TODO(emilio): We could be more granular if we knew which families have
21502150
// potentially changed.
21512151
if (!aUpdatedFont) {
2152-
auto hint = StyleSet()->UsesFontMetrics() ? RestyleHint::RecascadeSubtree()
2153-
: RestyleHint{0};
2152+
auto hint =
2153+
(StyleSet()->UsesFontMetrics() || StyleSet()->UsesRootFontMetrics())
2154+
? RestyleHint::RecascadeSubtree()
2155+
: RestyleHint{0};
21542156
PostRebuildAllStyleDataEvent(NS_STYLE_HINT_REFLOW, hint);
21552157
return;
21562158
}

layout/style/ServoStyleSet.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,6 +1186,10 @@ bool ServoStyleSet::UsesFontMetrics() const {
11861186
return Servo_StyleSet_UsesFontMetrics(mRawData.get());
11871187
}
11881188

1189+
bool ServoStyleSet::UsesRootFontMetrics() const {
1190+
return Servo_StyleSet_UsesRootFontMetrics(mRawData.get());
1191+
}
1192+
11891193
bool ServoStyleSet::EnsureUniqueInnerOnCSSSheets() {
11901194
using SheetOwner = Variant<ServoStyleSet*, ShadowRoot*>;
11911195

layout/style/ServoStyleSet.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ class ServoStyleSet {
166166

167167
bool UsesFontMetrics() const;
168168

169+
bool UsesRootFontMetrics() const;
170+
169171
void SetAuthorStyleDisabled(bool aStyleDisabled);
170172

171173
// Get a CopmutedStyle for a text node (which no rules will match).

layout/style/nsFontFaceUtils.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ void nsFontFaceUtils::MarkDirtyForFontChange(nsIFrame* aSubtreeRoot,
172172
PresShell* presShell = pc->PresShell();
173173

174174
const bool usesMetricsFromStyle = pc->StyleSet()->UsesFontMetrics();
175+
const bool usesRootMetricsFromStyle = pc->StyleSet()->UsesRootFontMetrics();
175176

176177
// StyleSingleFontFamily::IsNamedFamily expects a UTF-16 string. Convert it
177178
// once here rather than on each call.
@@ -201,7 +202,18 @@ void nsFontFaceUtils::MarkDirtyForFontChange(nsIFrame* aSubtreeRoot,
201202
ScheduleReflow(presShell, f);
202203
alreadyScheduled = ReflowAlreadyScheduled::Yes;
203204
}
204-
if (kind & FontUsageKind::FontMetrics) {
205+
206+
// If the updated font is used for font metrics, then styles need to be
207+
// recomputed. This can occur if the current frame directly uses the
208+
// font's metrics (ex/ch/...). However, if there are any elements in the
209+
// document using root element relative font metrics (rex/rch/...) and
210+
// the root element itself used the updated font, then the entire
211+
// subtree needs to be restyled.
212+
const bool shouldRestyleForFontMetrics =
213+
(kind & FontUsageKind::FontMetrics) ||
214+
(usesRootMetricsFromStyle && f->Style()->IsRootElementStyle());
215+
216+
if (shouldRestyleForFontMetrics) {
205217
MOZ_ASSERT(f->GetContent() && f->GetContent()->IsElement(),
206218
"How could we target a non-element with selectors?");
207219
f->PresContext()->RestyleManager()->PostRestyleEvent(

servo/components/style/custom_properties.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,12 @@ impl NonCustomReferences {
415415
if value.eq_ignore_ascii_case(FontRelativeLength::RLH) {
416416
return Self::ROOT_FONT_UNITS | Self::ROOT_LH_UNITS;
417417
}
418-
if value.eq_ignore_ascii_case(FontRelativeLength::REM) {
418+
if value.eq_ignore_ascii_case(FontRelativeLength::REM)
419+
|| value.eq_ignore_ascii_case(FontRelativeLength::REX)
420+
|| value.eq_ignore_ascii_case(FontRelativeLength::RCH)
421+
|| value.eq_ignore_ascii_case(FontRelativeLength::RCAP)
422+
|| value.eq_ignore_ascii_case(FontRelativeLength::RIC)
423+
{
419424
return Self::ROOT_FONT_UNITS;
420425
}
421426
Self::empty()

servo/components/style/font_metrics.rs

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
77
#![deny(missing_docs)]
88

9-
use crate::values::computed::Length;
9+
use crate::values::computed::{FontSize, Length};
1010

1111
/// Represents the font metrics that style needs from a font to compute the
1212
/// value of certain CSS units like `ex`.
@@ -44,6 +44,74 @@ impl Default for FontMetrics {
4444
}
4545
}
4646

47+
impl FontMetrics {
48+
/// Returns the x-height, computing a fallback value if not present
49+
pub fn x_height_or_default(&self, reference_font_size: &FontSize) -> Length {
50+
// https://drafts.csswg.org/css-values/#ex
51+
//
52+
// In the cases where it is impossible or impractical to
53+
// determine the x-height, a value of 0.5em must be
54+
// assumed.
55+
//
56+
// (But note we use 0.5em of the used, not computed
57+
// font-size)
58+
self.x_height
59+
.unwrap_or_else(|| reference_font_size.used_size() * 0.5)
60+
}
61+
62+
/// Returns the zero advance measure, computing a fallback value if not present
63+
pub fn zero_advance_measure_or_default(
64+
&self,
65+
reference_font_size: &FontSize,
66+
upright: bool,
67+
) -> Length {
68+
// https://drafts.csswg.org/css-values/#ch
69+
//
70+
// In the cases where it is impossible or impractical to
71+
// determine the measure of the “0” glyph, it must be
72+
// assumed to be 0.5em wide by 1em tall. Thus, the ch
73+
// unit falls back to 0.5em in the general case, and to
74+
// 1em when it would be typeset upright (i.e.
75+
// writing-mode is vertical-rl or vertical-lr and
76+
// text-orientation is upright).
77+
//
78+
// Same caveat about computed vs. used font-size applies
79+
// above.
80+
self.zero_advance_measure.unwrap_or_else(|| {
81+
if upright {
82+
reference_font_size.used_size()
83+
} else {
84+
reference_font_size.used_size() * 0.5
85+
}
86+
})
87+
}
88+
89+
/// Returns the cap-height, computing a fallback value if not present
90+
pub fn cap_height_or_default(&self) -> Length {
91+
// https://drafts.csswg.org/css-values/#cap
92+
//
93+
// In the cases where it is impossible or impractical to
94+
// determine the cap-height, the font’s ascent must be
95+
// used.
96+
//
97+
self.cap_height.unwrap_or_else(|| self.ascent)
98+
}
99+
100+
/// Returns the ideographic advance measure, computing a fallback value if not present
101+
pub fn ic_width_or_default(&self, reference_font_size: &FontSize) -> Length {
102+
// https://drafts.csswg.org/css-values/#ic
103+
//
104+
// In the cases where it is impossible or impractical to
105+
// determine the ideographic advance measure, it must be
106+
// assumed to be 1em.
107+
//
108+
// Same caveat about computed vs. used as for other
109+
// metric-dependent units.
110+
self.ic_width
111+
.unwrap_or_else(|| reference_font_size.used_size())
112+
}
113+
}
114+
47115
/// Type of font metrics to retrieve.
48116
#[derive(Clone, Debug, PartialEq)]
49117
pub enum FontMetricsOrientation {

servo/components/style/gecko/media_queries.rs

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ use crate::values::computed::font::GenericFontFamily;
1919
use crate::values::computed::{ColorScheme, Length, NonNegativeLength};
2020
use crate::values::specified::color::{ColorSchemeFlags, ForcedColors, SystemColor};
2121
use crate::values::specified::font::{
22-
QueryFontMetricsFlags, FONT_MEDIUM_LINE_HEIGHT_PX, FONT_MEDIUM_PX,
22+
QueryFontMetricsFlags, FONT_MEDIUM_CAP_PX, FONT_MEDIUM_CH_PX, FONT_MEDIUM_EX_PX,
23+
FONT_MEDIUM_IC_PX, FONT_MEDIUM_LINE_HEIGHT_PX, FONT_MEDIUM_PX,
2324
};
2425
use crate::values::specified::ViewportVariant;
2526
use crate::values::{CustomIdent, KeyframesName};
@@ -50,6 +51,14 @@ pub struct Device {
5051
root_font_size: AtomicU32,
5152
/// Line height of the root element, used for rlh units in other elements.
5253
root_line_height: AtomicU32,
54+
/// X-height of the root element, used for rex units in other elements.
55+
root_font_metrics_ex: AtomicU32,
56+
/// Cap-height of the root element, used for rcap units in other elements.
57+
root_font_metrics_cap: AtomicU32,
58+
/// Advance measure (ch) of the root element, used for rch units in other elements.
59+
root_font_metrics_ch: AtomicU32,
60+
/// Ideographic advance measure of the root element, used for ric units in other elements.
61+
root_font_metrics_ic: AtomicU32,
5362
/// The body text color, stored as an `nscolor`, used for the "tables
5463
/// inherit from body" quirk.
5564
///
@@ -61,6 +70,9 @@ pub struct Device {
6170
/// Whether any styles computed in the document relied on the root line-height
6271
/// by using rlh units.
6372
used_root_line_height: AtomicBool,
73+
/// Whether any styles computed in the document relied on the root font metrics
74+
/// by using rcap, rch, rex, or ric units.
75+
used_root_font_metrics: AtomicBool,
6476
/// Whether any styles computed in the document relied on font metrics.
6577
used_font_metrics: AtomicBool,
6678
/// Whether any styles computed in the document relied on the viewport size
@@ -103,11 +115,17 @@ impl Device {
103115
default_values: ComputedValues::default_values(doc),
104116
root_font_size: AtomicU32::new(FONT_MEDIUM_PX.to_bits()),
105117
root_line_height: AtomicU32::new(FONT_MEDIUM_LINE_HEIGHT_PX.to_bits()),
118+
root_font_metrics_ex: AtomicU32::new(FONT_MEDIUM_EX_PX.to_bits()),
119+
root_font_metrics_cap: AtomicU32::new(FONT_MEDIUM_CAP_PX.to_bits()),
120+
root_font_metrics_ch: AtomicU32::new(FONT_MEDIUM_CH_PX.to_bits()),
121+
root_font_metrics_ic: AtomicU32::new(FONT_MEDIUM_IC_PX.to_bits()),
122+
106123
// This gets updated when we see the <body>, so it doesn't really
107124
// matter which color-scheme we look at here.
108125
body_text_color: AtomicUsize::new(prefs.mLightColors.mDefault as usize),
109126
used_root_font_size: AtomicBool::new(false),
110127
used_root_line_height: AtomicBool::new(false),
128+
used_root_font_metrics: AtomicBool::new(false),
111129
used_font_metrics: AtomicBool::new(false),
112130
used_viewport_size: AtomicBool::new(false),
113131
used_dynamic_viewport_size: AtomicBool::new(false),
@@ -193,6 +211,66 @@ impl Device {
193211
.store(size.to_bits(), Ordering::Relaxed);
194212
}
195213

214+
/// Get the x-height of the root element (for rex)
215+
pub fn root_font_metrics_ex(&self) -> Length {
216+
self.used_root_font_metrics.store(true, Ordering::Relaxed);
217+
Length::new(f32::from_bits(
218+
self.root_font_metrics_ex.load(Ordering::Relaxed),
219+
))
220+
}
221+
222+
/// Set the x-height of the root element (for rex), in zoom-independent CSS pixels.
223+
pub fn set_root_font_metrics_ex(&self, size: f32) -> bool {
224+
let size = size.to_bits();
225+
let previous = self.root_font_metrics_ex.swap(size, Ordering::Relaxed);
226+
previous != size
227+
}
228+
229+
/// Get the cap-height of the root element (for rcap)
230+
pub fn root_font_metrics_cap(&self) -> Length {
231+
self.used_root_font_metrics.store(true, Ordering::Relaxed);
232+
Length::new(f32::from_bits(
233+
self.root_font_metrics_cap.load(Ordering::Relaxed),
234+
))
235+
}
236+
237+
/// Set the cap-height of the root element (for rcap), in zoom-independent CSS pixels.
238+
pub fn set_root_font_metrics_cap(&self, size: f32) -> bool {
239+
let size = size.to_bits();
240+
let previous = self.root_font_metrics_cap.swap(size, Ordering::Relaxed);
241+
previous != size
242+
}
243+
244+
/// Get the advance measure of the root element (for rch)
245+
pub fn root_font_metrics_ch(&self) -> Length {
246+
self.used_root_font_metrics.store(true, Ordering::Relaxed);
247+
Length::new(f32::from_bits(
248+
self.root_font_metrics_ch.load(Ordering::Relaxed),
249+
))
250+
}
251+
252+
/// Set the advance measure of the root element (for rch), in zoom-independent CSS pixels.
253+
pub fn set_root_font_metrics_ch(&self, size: f32) -> bool {
254+
let size = size.to_bits();
255+
let previous = self.root_font_metrics_ch.swap(size, Ordering::Relaxed);
256+
previous != size
257+
}
258+
259+
/// Get the ideographic advance measure of the root element (for ric)
260+
pub fn root_font_metrics_ic(&self) -> Length {
261+
self.used_root_font_metrics.store(true, Ordering::Relaxed);
262+
Length::new(f32::from_bits(
263+
self.root_font_metrics_ic.load(Ordering::Relaxed),
264+
))
265+
}
266+
267+
/// Set the ideographic advance measure of the root element (for ric), in zoom-independent CSS pixels.
268+
pub fn set_root_font_metrics_ic(&self, size: f32) -> bool {
269+
let size = size.to_bits();
270+
let previous = self.root_font_metrics_ic.swap(size, Ordering::Relaxed);
271+
previous != size
272+
}
273+
196274
/// The quirks mode of the document.
197275
pub fn quirks_mode(&self) -> QuirksMode {
198276
self.document().mCompatMode.into()
@@ -230,8 +308,11 @@ impl Device {
230308
font: &crate::properties::style_structs::Font,
231309
base_size: Length,
232310
flags: QueryFontMetricsFlags,
311+
track_usage: bool,
233312
) -> FontMetrics {
234-
self.used_font_metrics.store(true, Ordering::Relaxed);
313+
if track_usage {
314+
self.used_font_metrics.store(true, Ordering::Relaxed);
315+
}
235316
let pc = match self.pres_context() {
236317
Some(pc) => pc,
237318
None => return Default::default(),
@@ -309,6 +390,7 @@ impl Device {
309390
self.reset_computed_values();
310391
self.used_root_font_size.store(false, Ordering::Relaxed);
311392
self.used_root_line_height.store(false, Ordering::Relaxed);
393+
self.used_root_font_metrics.store(false, Ordering::Relaxed);
312394
self.used_font_metrics.store(false, Ordering::Relaxed);
313395
self.used_viewport_size.store(false, Ordering::Relaxed);
314396
self.used_dynamic_viewport_size
@@ -325,6 +407,11 @@ impl Device {
325407
self.used_root_line_height.load(Ordering::Relaxed)
326408
}
327409

410+
/// Returns whether we ever looked up the root font metrics of the device.
411+
pub fn used_root_font_metrics(&self) -> bool {
412+
self.used_root_font_metrics.load(Ordering::Relaxed)
413+
}
414+
328415
/// Recreates all the temporary state that the `Device` stores.
329416
///
330417
/// This includes the viewport override from `@viewport` rules, and also the

0 commit comments

Comments
 (0)