render: preserve numeric font weights
This commit is contained in:
1 parent
d6be828d17
commit
20be62bca9
6 files changed
+266
-47
No files matched your search
@@ -495,11 +495,9 @@ fn apply_value(style: &mut LayoutStyle, name: &str, value: &str) {
|
||||
}
|
||||
"font" => apply_font_shorthand(style, value),
|
||||
"font-weight" => {
|
||||
// Normalize to "bold"/"normal" (consumers test for "bold"). Numeric
|
||||
// >= 600 and `bold`/`bolder` are bold; others normal.
|
||||
let v = value.trim().to_ascii_lowercase();
|
||||
let bold = v == "bold" || v == "bolder" || v.parse::<u32>().map(|n| n >= 600).unwrap_or(false);
|
||||
style.font_weight = Some(if bold { "bold".to_string() } else { "normal".to_string() });
|
||||
if let Some(weight) = specified_font_weight(value) {
|
||||
style.font_weight = Some(weight);
|
||||
}
|
||||
}
|
||||
"font-family" => {
|
||||
let v = value.trim().to_ascii_lowercase();
|
||||
@@ -2513,18 +2511,15 @@ fn apply_font_shorthand(style: &mut LayoutStyle, value: &str) {
|
||||
|
||||
// The shorthand resets every constituent before applying supplied values.
|
||||
style.font_style_italic = Some(false);
|
||||
style.font_weight = Some("normal".to_string());
|
||||
style.font_weight = Some("400".to_string());
|
||||
style.line_height = Some(crate::LineHeight::Normal);
|
||||
style.line_height_expression = None;
|
||||
for token in &tokens[..size_index] {
|
||||
let lower = token.to_ascii_lowercase();
|
||||
if lower == "italic" || lower.starts_with("oblique") {
|
||||
style.font_style_italic = Some(true);
|
||||
} else if lower == "bold"
|
||||
|| lower == "bolder"
|
||||
|| lower.parse::<u32>().map(|weight| weight >= 600).unwrap_or(false)
|
||||
{
|
||||
style.font_weight = Some("bold".to_string());
|
||||
} else if let Some(weight) = specified_font_weight(&lower) {
|
||||
style.font_weight = Some(weight);
|
||||
}
|
||||
}
|
||||
apply_font_size(style, size);
|
||||
@@ -2534,6 +2529,54 @@ fn apply_font_shorthand(style: &mut LayoutStyle, value: &str) {
|
||||
style.font_family = Some(tokens[family_index..].join(" ").to_ascii_lowercase());
|
||||
}
|
||||
|
||||
/// Normalize a specified CSS font weight while preserving relative keywords
|
||||
/// until the top-down inheritance pass can see the parent's computed weight.
|
||||
fn specified_font_weight(value: &str) -> Option<String> {
|
||||
let lower = value.trim().to_ascii_lowercase();
|
||||
match lower.as_str() {
|
||||
"normal" => Some("400".to_string()),
|
||||
"bold" => Some("700".to_string()),
|
||||
"bolder" | "lighter" => Some(lower),
|
||||
_ => lower
|
||||
.parse::<f32>()
|
||||
.ok()
|
||||
.filter(|weight| weight.is_finite() && (1.0..=1000.0).contains(weight))
|
||||
.map(|weight| weight.round().to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolve `font-weight` to the numeric computed value defined by CSS Fonts.
|
||||
/// Relative keywords use the inherited weight table rather than a binary
|
||||
/// normal/bold threshold.
|
||||
pub(crate) fn computed_font_weight(specified: Option<&str>, inherited: u16) -> u16 {
|
||||
match specified {
|
||||
None => inherited,
|
||||
Some("normal") => 400,
|
||||
Some("bold") => 700,
|
||||
Some("bolder") if inherited < 100 => 400,
|
||||
Some("bolder") if inherited < 350 => 400,
|
||||
Some("bolder") if inherited < 550 => 700,
|
||||
Some("bolder") if inherited < 900 => 900,
|
||||
Some("bolder") => inherited,
|
||||
Some("lighter") if inherited < 100 => inherited,
|
||||
Some("lighter") if inherited < 350 => 100,
|
||||
Some("lighter") if inherited < 550 => 100,
|
||||
Some("lighter") if inherited < 750 => 400,
|
||||
Some("lighter") if inherited < 900 => 700,
|
||||
Some("lighter") => 700,
|
||||
Some(weight) => weight
|
||||
.parse::<f32>()
|
||||
.ok()
|
||||
.filter(|weight| weight.is_finite())
|
||||
.map(|weight| weight.round().clamp(1.0, 1000.0) as u16)
|
||||
.unwrap_or(inherited),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn used_font_weight(style: &LayoutStyle) -> u16 {
|
||||
computed_font_weight(style.font_weight.as_deref(), 400)
|
||||
}
|
||||
|
||||
fn is_font_size_token(value: &str) -> bool {
|
||||
let lower = value.trim().to_ascii_lowercase();
|
||||
if lower == "0" || font_size_keyword(&lower).is_some() {
|
||||
@@ -3504,7 +3547,7 @@ mod tests {
|
||||
);
|
||||
assert_eq!(s.font_size, Some(64.0));
|
||||
assert_eq!(s.line_height, Some(crate::LineHeight::Px(60.0)));
|
||||
assert_eq!(s.font_weight.as_deref(), Some("normal"));
|
||||
assert_eq!(s.font_weight.as_deref(), Some("500"));
|
||||
assert_eq!(s.font_style_italic, Some(false));
|
||||
assert_eq!(s.font_family.as_deref(), Some("\"google sans\", sans-serif"));
|
||||
|
||||
@@ -3514,10 +3557,32 @@ mod tests {
|
||||
);
|
||||
assert_eq!(reset.font_size, Some(20.0));
|
||||
assert_eq!(reset.line_height, Some(crate::LineHeight::Normal));
|
||||
assert_eq!(reset.font_weight.as_deref(), Some("normal"));
|
||||
assert_eq!(reset.font_weight.as_deref(), Some("400"));
|
||||
assert_eq!(reset.font_style_italic, Some(false));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn font_weight_preserves_numeric_values_and_resolves_relative_keywords() {
|
||||
let medium = compute_style("div", Some("font-weight:500"));
|
||||
assert_eq!(medium.font_weight.as_deref(), Some("500"));
|
||||
let semibold = compute_style("div", Some("font-weight:600"));
|
||||
assert_eq!(semibold.font_weight.as_deref(), Some("600"));
|
||||
let normal = compute_style("strong", Some("font-weight:normal"));
|
||||
assert_eq!(normal.font_weight.as_deref(), Some("400"));
|
||||
|
||||
assert_eq!(computed_font_weight(Some("bolder"), 99), 400);
|
||||
assert_eq!(computed_font_weight(Some("bolder"), 349), 400);
|
||||
assert_eq!(computed_font_weight(Some("bolder"), 350), 700);
|
||||
assert_eq!(computed_font_weight(Some("bolder"), 550), 900);
|
||||
assert_eq!(computed_font_weight(Some("bolder"), 900), 900);
|
||||
assert_eq!(computed_font_weight(Some("lighter"), 99), 99);
|
||||
assert_eq!(computed_font_weight(Some("lighter"), 100), 100);
|
||||
assert_eq!(computed_font_weight(Some("lighter"), 350), 100);
|
||||
assert_eq!(computed_font_weight(Some("lighter"), 550), 400);
|
||||
assert_eq!(computed_font_weight(Some("lighter"), 750), 700);
|
||||
assert_eq!(computed_font_weight(Some("lighter"), 900), 700);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn containing_block_property_triggers_are_independent() {
|
||||
let s = compute_style("div", Some("transform:rotate(0deg);filter:none"));
|
||||
|
||||
Reference in new issue
Block a user