mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 11:25:00 +00:00
Bug 1702924 - Add support for the 'cap' font-relative unit. r=emilio
Differential Revision: https://phabricator.services.mozilla.com/D133101
This commit is contained in:
parent
dad1574a74
commit
719dd66863
@ -214,8 +214,9 @@ void nsPresContext::ForceReflowForFontInfoUpdate(bool aNeedsReframe) {
|
||||
|
||||
// We also need to trigger restyling for ex/ch units changes to take effect,
|
||||
// if needed.
|
||||
auto restyleHint =
|
||||
UsesExChUnits() ? RestyleHint::RecascadeSubtree() : RestyleHint{0};
|
||||
auto restyleHint = UsesFontMetricDependentFontUnits()
|
||||
? RestyleHint::RecascadeSubtree()
|
||||
: RestyleHint{0};
|
||||
|
||||
RebuildAllStyleData(changeHint, restyleHint);
|
||||
}
|
||||
@ -271,7 +272,7 @@ nsPresContext::nsPresContext(dom::Document* aDocument, nsPresContextType aType)
|
||||
mPendingUIResolutionChanged(false),
|
||||
mPendingFontInfoUpdateReflowFromStyle(false),
|
||||
mIsGlyph(false),
|
||||
mUsesExChUnits(false),
|
||||
mUsesFontMetricDependentFontUnits(false),
|
||||
mCounterStylesDirty(true),
|
||||
mFontFeatureValuesDirty(true),
|
||||
mSuppressResizeReflow(false),
|
||||
@ -658,7 +659,7 @@ void nsPresContext::PreferenceChanged(const char* aPrefName) {
|
||||
// Changes to font_rendering prefs need to trigger a reflow
|
||||
StringBeginsWith(prefName, "gfx.font_rendering."_ns)) {
|
||||
changeHint |= NS_STYLE_HINT_REFLOW;
|
||||
if (UsesExChUnits()) {
|
||||
if (UsesFontMetricDependentFontUnits()) {
|
||||
restyleHint |= RestyleHint::RecascadeSubtree();
|
||||
}
|
||||
}
|
||||
@ -1772,7 +1773,7 @@ void nsPresContext::PostRebuildAllStyleDataEvent(
|
||||
return;
|
||||
}
|
||||
if (aRestyleHint.DefinitelyRecascadesAllSubtree()) {
|
||||
mUsesExChUnits = false;
|
||||
mUsesFontMetricDependentFontUnits = false;
|
||||
}
|
||||
RestyleManager()->RebuildAllStyleData(aExtraHint, aRestyleHint);
|
||||
}
|
||||
@ -1970,8 +1971,9 @@ void nsPresContext::UserFontSetUpdated(gfxUserFontEntry* aUpdatedFont) {
|
||||
// TODO(emilio): We could be more granular if we knew which families have
|
||||
// potentially changed.
|
||||
if (!aUpdatedFont) {
|
||||
auto hint =
|
||||
UsesExChUnits() ? RestyleHint::RecascadeSubtree() : RestyleHint{0};
|
||||
auto hint = UsesFontMetricDependentFontUnits()
|
||||
? RestyleHint::RecascadeSubtree()
|
||||
: RestyleHint{0};
|
||||
PostRebuildAllStyleDataEvent(NS_STYLE_HINT_REFLOW, hint);
|
||||
return;
|
||||
}
|
||||
|
@ -1051,9 +1051,13 @@ class nsPresContext : public nsISupports, public mozilla::SupportsWeakPtr {
|
||||
bool HasEverBuiltInvisibleText() const { return mHasEverBuiltInvisibleText; }
|
||||
void SetBuiltInvisibleText() { mHasEverBuiltInvisibleText = true; }
|
||||
|
||||
bool UsesExChUnits() const { return mUsesExChUnits; }
|
||||
bool UsesFontMetricDependentFontUnits() const {
|
||||
return mUsesFontMetricDependentFontUnits;
|
||||
}
|
||||
|
||||
void SetUsesExChUnits(bool aValue) { mUsesExChUnits = aValue; }
|
||||
void SetUsesFontMetricDependentFontUnits(bool aValue) {
|
||||
mUsesFontMetricDependentFontUnits = aValue;
|
||||
}
|
||||
|
||||
bool IsDeviceSizePageSize();
|
||||
|
||||
@ -1330,7 +1334,7 @@ class nsPresContext : public nsISupports, public mozilla::SupportsWeakPtr {
|
||||
//
|
||||
// TODO(emilio): It's a bit weird that this lives here but all the other
|
||||
// relevant bits live in Device on the rust side.
|
||||
unsigned mUsesExChUnits : 1;
|
||||
unsigned mUsesFontMetricDependentFontUnits : 1;
|
||||
|
||||
// Is the current mCounterStyleManager valid?
|
||||
unsigned mCounterStylesDirty : 1;
|
||||
|
@ -199,7 +199,7 @@ nscoord nsMathMLFrame::CalcLength(nsPresContext* aPresContext,
|
||||
}
|
||||
|
||||
if (eCSSUnit_XHeight == unit) {
|
||||
aPresContext->SetUsesExChUnits(true);
|
||||
aPresContext->SetUsesFontMetricDependentFontUnits(true);
|
||||
RefPtr<nsFontMetrics> fm = nsLayoutUtils::GetFontMetricsForComputedStyle(
|
||||
aComputedStyle, aPresContext, aFontSizeInflation);
|
||||
nscoord xHeight = fm->XHeight();
|
||||
|
@ -1426,7 +1426,7 @@ GeckoFontMetrics Gecko_GetFontMetrics(const nsPresContext* aPresContext,
|
||||
// ArrayBuffer-backed FontFace objects are handled synchronously.
|
||||
|
||||
nsPresContext* presContext = const_cast<nsPresContext*>(aPresContext);
|
||||
presContext->SetUsesExChUnits(true);
|
||||
presContext->SetUsesFontMetricDependentFontUnits(true);
|
||||
|
||||
RefPtr<nsFontMetrics> fm = nsLayoutUtils::GetMetricsFor(
|
||||
presContext, aIsVertical, aFont, aFontSize, aUseUserFontSet);
|
||||
@ -1439,7 +1439,9 @@ GeckoFontMetrics Gecko_GetFontMetrics(const nsPresContext* aPresContext,
|
||||
return Length::FromPixels(CSSPixel::FromAppUnits(aLen));
|
||||
};
|
||||
return {ToLength(NS_round(metrics.xHeight * d2a)),
|
||||
ToLength(NS_round(metrics.zeroWidth * d2a))};
|
||||
ToLength(NS_round(metrics.zeroWidth * d2a)),
|
||||
ToLength(NS_round(metrics.capHeight * d2a)),
|
||||
ToLength(NS_round(metrics.maxAscent * d2a))};
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_FFI_REFCOUNTING(SheetLoadDataHolder, SheetLoadDataHolder);
|
||||
|
@ -483,7 +483,9 @@ mozilla::StyleDefaultFontSizes Gecko_GetBaseSize(nsAtom* lang);
|
||||
|
||||
struct GeckoFontMetrics {
|
||||
mozilla::Length mXSize;
|
||||
mozilla::Length mChSize; // negatives indicate not found.
|
||||
mozilla::Length mChSize; // negatives indicate not found.
|
||||
mozilla::Length mCapHeight; // negatives indicate not found.
|
||||
mozilla::Length mAscent;
|
||||
};
|
||||
|
||||
GeckoFontMetrics Gecko_GetFontMetrics(const nsPresContext*, bool is_vertical,
|
||||
|
@ -210,7 +210,7 @@ void nsFontFaceUtils::MarkDirtyForFontChange(nsIFrame* aSubtreeRoot,
|
||||
}
|
||||
|
||||
if (alreadyScheduled == ReflowAlreadyScheduled::No ||
|
||||
pc->UsesExChUnits()) {
|
||||
pc->UsesFontMetricDependentFontUnits()) {
|
||||
if (f->IsPlaceholderFrame()) {
|
||||
nsIFrame* oof = nsPlaceholderFrame::GetRealFrameForPlaceholder(f);
|
||||
if (!nsLayoutUtils::IsProperAncestorFrame(subtreeRoot, oof)) {
|
||||
|
@ -12,20 +12,38 @@ use crate::Atom;
|
||||
|
||||
/// Represents the font metrics that style needs from a font to compute the
|
||||
/// value of certain CSS units like `ex`.
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct FontMetrics {
|
||||
/// The x-height of the font.
|
||||
pub x_height: Option<Length>,
|
||||
/// The zero advance. This is usually writing mode dependent
|
||||
pub zero_advance_measure: Option<Length>,
|
||||
/// The cap-height of the font.
|
||||
pub cap_height: Option<Length>,
|
||||
/// The ascent of the font (a value is always available for this).
|
||||
pub ascent: Length,
|
||||
}
|
||||
|
||||
impl Default for FontMetrics {
|
||||
fn default() -> Self {
|
||||
FontMetrics {
|
||||
x_height: None,
|
||||
zero_advance_measure: None,
|
||||
cap_height: None,
|
||||
ascent: Length::new(0.0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Type of font metrics to retrieve.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum FontMetricsOrientation {
|
||||
/// Get metrics for horizontal or vertical according to the Context's
|
||||
/// writing mode.
|
||||
MatchContext,
|
||||
/// writing mode, using horizontal metrics for vertical/mixed
|
||||
MatchContextPreferHorizontal,
|
||||
/// Get metrics for horizontal or vertical according to the Context's
|
||||
/// writing mode, using vertical metrics for vertical/mixed
|
||||
MatchContextPreferVertical,
|
||||
/// Force getting horizontal metrics.
|
||||
Horizontal,
|
||||
}
|
||||
|
@ -991,7 +991,8 @@ impl FontMetricsProvider for GeckoFontMetricsProvider {
|
||||
};
|
||||
|
||||
let vertical_metrics = match orientation {
|
||||
FontMetricsOrientation::MatchContext => wm.is_vertical() && wm.is_upright(),
|
||||
FontMetricsOrientation::MatchContextPreferHorizontal => wm.is_vertical() && wm.is_upright(),
|
||||
FontMetricsOrientation::MatchContextPreferVertical => wm.is_vertical() && !wm.is_sideways(),
|
||||
FontMetricsOrientation::Horizontal => false,
|
||||
};
|
||||
let gecko_metrics = unsafe {
|
||||
@ -1011,6 +1012,12 @@ impl FontMetricsProvider for GeckoFontMetricsProvider {
|
||||
} else {
|
||||
None
|
||||
},
|
||||
cap_height: if gecko_metrics.mCapHeight.px() >= 0. {
|
||||
Some(gecko_metrics.mCapHeight)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
ascent: gecko_metrics.mAscent,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ pub enum MinMaxOp {
|
||||
pub enum SortKey {
|
||||
Number,
|
||||
Percentage,
|
||||
Cap,
|
||||
Ch,
|
||||
Deg,
|
||||
Em,
|
||||
|
@ -184,6 +184,7 @@ impl generic::CalcNodeLeaf for Leaf {
|
||||
FontRelativeLength::Ch(..) => SortKey::Ch,
|
||||
FontRelativeLength::Em(..) => SortKey::Em,
|
||||
FontRelativeLength::Ex(..) => SortKey::Ex,
|
||||
FontRelativeLength::Cap(..) => SortKey::Cap,
|
||||
FontRelativeLength::Rem(..) => SortKey::Rem,
|
||||
},
|
||||
NoCalcLength::ViewportPercentage(ref vp) => match *vp {
|
||||
|
@ -59,6 +59,9 @@ pub enum FontRelativeLength {
|
||||
/// A "ch" value: https://drafts.csswg.org/css-values/#ch
|
||||
#[css(dimension)]
|
||||
Ch(CSSFloat),
|
||||
/// A "cap" value: https://drafts.csswg.org/css-values/#cap
|
||||
#[css(dimension)]
|
||||
Cap(CSSFloat),
|
||||
/// A "rem" value: https://drafts.csswg.org/css-values/#rem
|
||||
#[css(dimension)]
|
||||
Rem(CSSFloat),
|
||||
@ -92,6 +95,7 @@ impl FontRelativeLength {
|
||||
FontRelativeLength::Em(v) |
|
||||
FontRelativeLength::Ex(v) |
|
||||
FontRelativeLength::Ch(v) |
|
||||
FontRelativeLength::Cap(v) |
|
||||
FontRelativeLength::Rem(v) => v == 0.,
|
||||
}
|
||||
}
|
||||
@ -101,6 +105,7 @@ impl FontRelativeLength {
|
||||
FontRelativeLength::Em(v) |
|
||||
FontRelativeLength::Ex(v) |
|
||||
FontRelativeLength::Ch(v) |
|
||||
FontRelativeLength::Cap(v) |
|
||||
FontRelativeLength::Rem(v) => v < 0.,
|
||||
}
|
||||
}
|
||||
@ -116,12 +121,13 @@ impl FontRelativeLength {
|
||||
(&Em(one), &Em(other)) => Em(one + other),
|
||||
(&Ex(one), &Ex(other)) => Ex(one + other),
|
||||
(&Ch(one), &Ch(other)) => Ch(one + other),
|
||||
(&Cap(one), &Cap(other)) => Cap(one + other),
|
||||
(&Rem(one), &Rem(other)) => Rem(one + other),
|
||||
// See https://github.com/rust-lang/rust/issues/68867. rustc isn't
|
||||
// able to figure it own on its own so we help.
|
||||
_ => unsafe {
|
||||
match *self {
|
||||
Em(..) | Ex(..) | Ch(..) | Rem(..) => {},
|
||||
Em(..) | Ex(..) | Ch(..) | Cap(..) | Rem(..) => {},
|
||||
}
|
||||
debug_unreachable!("Forgot to handle unit in try_sum()")
|
||||
},
|
||||
@ -210,7 +216,7 @@ impl FontRelativeLength {
|
||||
// whichever is in the inline axis of the element.)
|
||||
//
|
||||
let metrics =
|
||||
query_font_metrics(context, base_size, FontMetricsOrientation::MatchContext);
|
||||
query_font_metrics(context, base_size, FontMetricsOrientation::MatchContextPreferHorizontal);
|
||||
let reference_size = metrics.zero_advance_measure.unwrap_or_else(|| {
|
||||
// https://drafts.csswg.org/css-values/#ch
|
||||
//
|
||||
@ -231,6 +237,23 @@ impl FontRelativeLength {
|
||||
});
|
||||
(reference_size, length)
|
||||
},
|
||||
FontRelativeLength::Cap(length) => {
|
||||
if context.for_non_inherited_property.is_some() {
|
||||
context.rule_cache_conditions.borrow_mut().set_uncacheable();
|
||||
}
|
||||
context.builder.add_flags(font_metrics_flag);
|
||||
let metrics =
|
||||
query_font_metrics(context, base_size, FontMetricsOrientation::Horizontal);
|
||||
let reference_size = metrics.cap_height.unwrap_or_else(|| {
|
||||
// https://drafts.csswg.org/css-values/#cap
|
||||
//
|
||||
// In the cases where it is impossible or impractical to
|
||||
// determine the cap-height, the font’s ascent must be used.
|
||||
//
|
||||
metrics.ascent
|
||||
});
|
||||
(reference_size, length)
|
||||
},
|
||||
FontRelativeLength::Rem(length) => {
|
||||
// https://drafts.csswg.org/css-values/#rem:
|
||||
//
|
||||
@ -542,6 +565,7 @@ impl NoCalcLength {
|
||||
"em" => NoCalcLength::FontRelative(FontRelativeLength::Em(value)),
|
||||
"ex" => NoCalcLength::FontRelative(FontRelativeLength::Ex(value)),
|
||||
"ch" => NoCalcLength::FontRelative(FontRelativeLength::Ch(value)),
|
||||
"cap" => NoCalcLength::FontRelative(FontRelativeLength::Cap(value)),
|
||||
"rem" => NoCalcLength::FontRelative(FontRelativeLength::Rem(value)),
|
||||
// viewport percentages
|
||||
"vw" if !context.in_page_rule() => {
|
||||
@ -701,12 +725,13 @@ impl PartialOrd for FontRelativeLength {
|
||||
(&Em(ref one), &Em(ref other)) => one.partial_cmp(other),
|
||||
(&Ex(ref one), &Ex(ref other)) => one.partial_cmp(other),
|
||||
(&Ch(ref one), &Ch(ref other)) => one.partial_cmp(other),
|
||||
(&Cap(ref one), &Cap(ref other)) => one.partial_cmp(other),
|
||||
(&Rem(ref one), &Rem(ref other)) => one.partial_cmp(other),
|
||||
// See https://github.com/rust-lang/rust/issues/68867. rustc isn't
|
||||
// able to figure it own on its own so we help.
|
||||
_ => unsafe {
|
||||
match *self {
|
||||
Em(..) | Ex(..) | Ch(..) | Rem(..) => {},
|
||||
Em(..) | Ex(..) | Ch(..) | Cap(..) | Rem(..) => {},
|
||||
}
|
||||
debug_unreachable!("Forgot an arm in partial_cmp?")
|
||||
},
|
||||
@ -723,6 +748,7 @@ impl Mul<CSSFloat> for FontRelativeLength {
|
||||
FontRelativeLength::Em(v) => FontRelativeLength::Em(v * scalar),
|
||||
FontRelativeLength::Ex(v) => FontRelativeLength::Ex(v * scalar),
|
||||
FontRelativeLength::Ch(v) => FontRelativeLength::Ch(v * scalar),
|
||||
FontRelativeLength::Cap(v) => FontRelativeLength::Cap(v * scalar),
|
||||
FontRelativeLength::Rem(v) => FontRelativeLength::Rem(v * scalar),
|
||||
}
|
||||
}
|
||||
|
32
testing/web-platform/tests/css/css-values/cap-unit-001.html
Normal file
32
testing/web-platform/tests/css/css-values/cap-unit-001.html
Normal file
@ -0,0 +1,32 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Values and Units Test: support for the cap unit</title>
|
||||
<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-values-4/#font-relative-lengths">
|
||||
<link rel="match" href="reference/cap-unit-001-ref.html">
|
||||
<meta name="assert" content="The cap unit is equal to the used cap-height of the first available font.">
|
||||
<link rel="stylesheet" type="text/css" href="/fonts/ahem.css">
|
||||
<style>
|
||||
span {
|
||||
background: green;
|
||||
color: green;
|
||||
position: absolute;
|
||||
}
|
||||
div {
|
||||
font: 50px Ahem; /* cap-height of Ahem is 0.8em */
|
||||
background: red;
|
||||
position: relative;
|
||||
height: 180px;
|
||||
height: calc(180px - 2cap); /* reduce to 100px if cap correctly supported */
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
div span {
|
||||
width: 2.5cap;
|
||||
height: 100px;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p>
|
||||
<div><span></span></div>
|
||||
</body>
|
@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Values and Units reference: support for the cap unit</title>
|
||||
<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com">
|
||||
<style>
|
||||
div {
|
||||
background: green;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p>
|
||||
<div></div>
|
||||
</body>
|
Loading…
Reference in New Issue
Block a user