mirror of
https://github.com/lexmount/moli.git
synced 2026-10-30 16:07:24 +00:00
fix(cssom): serialize computed font from native longhands
Serialize computed font from the retained style read and Stylo font longhand metadata. Reuse the native font serializer for CSS2 variant/stretch constraints, reset-only longhands and omission of initial components. Resolve font size, weight and line height through the shared CSSOM path. Keep computed Typed OM font values opaque, property-associated and immutable while retained maps observe new styles. Cover relative and inherited sizes, numeric line height, snapshots and supported unrepresentable longhands.
This commit is contained in:
+4
@@ -1,6 +1,7 @@
|
||||
use super::*;
|
||||
|
||||
mod background;
|
||||
mod font;
|
||||
|
||||
pub(in crate::native_bridge::element::styles) fn style_property_value_with_context(
|
||||
runtime: &JsContextHost,
|
||||
@@ -104,6 +105,9 @@ pub(super) fn computed_style_property_value_after_style_update(
|
||||
if property == "text-emphasis" {
|
||||
return computed_text_emphasis_shorthand_value(runtime, handle, context);
|
||||
}
|
||||
if property == "font" {
|
||||
return font::computed_shorthand(runtime, handle, resolution);
|
||||
}
|
||||
if property == "font-variant" {
|
||||
return computed_font_variant_shorthand_value(runtime, handle, resolution);
|
||||
}
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
use super::*;
|
||||
|
||||
pub(super) fn computed_shorthand(
|
||||
runtime: &JsContextHost,
|
||||
handle: DomHandle,
|
||||
resolution: StyleResolutionContext<'_>,
|
||||
) -> String {
|
||||
// Servo's font schema excludes this compatibility longhand. It is reset
|
||||
// by font, but a non-initial value cannot be expressed by the shorthand.
|
||||
if resolution.computed_property(runtime, handle, "font-size-adjust") != "none" {
|
||||
return String::new();
|
||||
}
|
||||
let mut block = moli_css_parse::CssDeclarationBlock::default();
|
||||
for longhand in style::properties::ShorthandId::Font.longhands() {
|
||||
let property = longhand.name();
|
||||
let value = resolution.computed_property(runtime, handle, property);
|
||||
if value.is_empty()
|
||||
|| block.set_property(property, &value, false)
|
||||
== moli_css_parse::CssSetResult::ParseError
|
||||
{
|
||||
return String::new();
|
||||
}
|
||||
}
|
||||
// The native serializer handles CSS2 variant/stretch restrictions,
|
||||
// reset-only longhands and omission of initial components.
|
||||
block.property_value("font").unwrap_or_default()
|
||||
}
|
||||
@@ -59,6 +59,7 @@ mod computed_style_access;
|
||||
mod content_and_invalidation;
|
||||
mod cross_document_and_animations;
|
||||
mod css_computed_background;
|
||||
mod css_computed_font;
|
||||
mod css_computed_map_enumeration;
|
||||
mod css_variable_fonts;
|
||||
mod nested_document_invalidation;
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
(() => {
|
||||
const check = (ok, message) => {if (!ok) throw new Error(message);};
|
||||
const cases = [
|
||||
['font:16px serif', '16px serif'],
|
||||
['font:italic bold 20px / 1.5 monospace', 'italic 700 20px / 30px monospace'],
|
||||
['font:small-caps bold condensed 24px / 2 serif', 'small-caps 700 condensed 24px / 48px serif'],
|
||||
['font:oblique 20deg 20px serif', 'oblique 20deg 20px serif'],
|
||||
['font-size:24px;font-family:serif;font-weight:700;line-height:1.25', '700 24px / 30px serif'],
|
||||
];
|
||||
for (const [text, expected] of cases) {
|
||||
const element = document.createElement('div');
|
||||
element.style.cssText = text;
|
||||
document.body.append(element);
|
||||
const computed = getComputedStyle(element);
|
||||
const value = computed.font;
|
||||
check(getComputedStyle(element).font === expected, text + ': ' + getComputedStyle(element).font);
|
||||
check(value === expected, text + ': serialized value');
|
||||
element.style.font = '12px sans-serif';
|
||||
check(value === expected, 'retained font string');
|
||||
check(computed.font === '12px sans-serif', 'live computed declaration');
|
||||
element.remove();
|
||||
}
|
||||
const element = document.createElement('div');
|
||||
document.body.append(element);
|
||||
for (const [property, value] of [
|
||||
['font-variant-ligatures', 'none'],
|
||||
['font-variant-east-asian', 'full-width'],
|
||||
['font-kerning', 'normal'],
|
||||
]) {
|
||||
element.style.cssText = 'font:16px serif';
|
||||
element.style.setProperty(property, value);
|
||||
check(element.style.font === '', property + ': specified font cannot represent value');
|
||||
check(getComputedStyle(element).font === '', property + ': computed font cannot represent value');
|
||||
}
|
||||
const parent = document.createElement('div');
|
||||
parent.style.font = 'bold 20px / 1.5 monospace';
|
||||
parent.append(element); document.body.append(parent);
|
||||
element.style.cssText = 'font-size:2em';
|
||||
check(getComputedStyle(element).font === '700 40px / 60px monospace', 'inherited computed longhands');
|
||||
parent.remove();
|
||||
return true;
|
||||
})()
|
||||
@@ -0,0 +1,10 @@
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn css_computed_font_serializes_resolved_longhands_and_retains_values() {
|
||||
let mut vm = new_parsed_test_vm("https://computed-font.test/", "<!doctype html><body>");
|
||||
assert_eq!(
|
||||
vm.eval(include_str!("css_computed_font.js")).unwrap(),
|
||||
"true"
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user