mirror of
https://github.com/servo/servo.git
synced 2025-09-29 16:19:14 +01:00
This change adds support for variable fonts via the [`font-variation-settings`](https://developer.mozilla.org/en-US/docs/Web/CSS/font-variation-settings) property. There are three areas where we need to set the variation values: * Webrender (`compositor.rs`), for drawing the glyphs * Harfbuzz (`shaper.rs`), for most shaping tasks * PlatformFont (`fonts/platform/`), for horizontal advances and kerning For now, freetype is the only platform shaper that supports variable fonts. I can't easily test the fonts with non-freetype shapers. Thats why variable fonts are behind the `layout_variable_fonts_enabled` pref, which is disabled by default. <img width="1250" height="710" alt="image" src="https://github.com/user-attachments/assets/1aee1407-f3a2-42f6-a106-af0443fcd588" /> <details><summary>HTML test file</summary> ```html <style> @font-face { font-family: "Amstelvar VF"; src: url("https://mdn.github.io/shared-assets/fonts/variable-fonts/AmstelvarAlpha-VF.woff2") format("woff2-variations"); font-weight: 300 900; font-stretch: 35% 100%; font-style: normal; font-display: swap; } p { font: 1.2em "Amstelvar VF", Georgia, serif; font-size: 4rem; margin: 1rem; display: inline-block; } .p1 { font-variation-settings: "wght" 300; } .p2 { font-variation-settings: "wght" 625; } .p3 { font-variation-settings: "wght" 900; } </style> <div> <p class="p1">Weight</p> <span>(font-variation-settings: "wght" 300)</span> </div> <div> <p class="p2">Weight</p> <span>(font-variation-settings: "wght" 625)</span> </div> <div> <p class="p3">Weight</p> <span>(font-variation-settings: "wght" 900)</span> </div> </div> ``` </details> https://github.com/user-attachments/assets/9e21101a-796a-49fe-b82c-8999d8fa9ee1 Testing: Needs decision on whether we want to enable the pref in CI Works towards https://github.com/servo/servo/issues/37236 Depends on https://github.com/servo/stylo/pull/230 --------- Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
105 lines
3.4 KiB
Rust
105 lines
3.4 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
use std::fs::File;
|
|
use std::io::Read;
|
|
use std::path::PathBuf;
|
|
|
|
use app_units::Au;
|
|
use euclid::num::Zero;
|
|
use fonts::platform::font::PlatformFont;
|
|
use fonts::{
|
|
Font, FontData, FontDescriptor, FontIdentifier, FontTemplate, FontTemplateRef,
|
|
PlatformFontMethods, ShapingFlags, ShapingOptions,
|
|
};
|
|
use servo_url::ServoUrl;
|
|
use style::properties::longhands::font_variant_caps::computed_value::T as FontVariantCaps;
|
|
use style::values::computed::{FontStretch, FontStyle, FontWeight};
|
|
use unicode_script::Script;
|
|
|
|
fn make_font(path: PathBuf) -> Font {
|
|
let mut bytes = Vec::new();
|
|
File::open(path.clone())
|
|
.expect("Couldn't open font file!")
|
|
.read_to_end(&mut bytes)
|
|
.unwrap();
|
|
let data = FontData::from_bytes(&bytes);
|
|
|
|
let identifier = FontIdentifier::Web(ServoUrl::from_file_path(path).unwrap());
|
|
let platform_font = PlatformFont::new_from_data(identifier.clone(), &data, None, &[]).unwrap();
|
|
|
|
let template = FontTemplate {
|
|
identifier,
|
|
descriptor: platform_font.descriptor(),
|
|
stylesheet: None,
|
|
};
|
|
let descriptor = FontDescriptor {
|
|
weight: FontWeight::normal(),
|
|
stretch: FontStretch::hundred(),
|
|
style: FontStyle::normal(),
|
|
variant: FontVariantCaps::Normal,
|
|
pt_size: Au::from_px(24),
|
|
variation_settings: vec![],
|
|
};
|
|
Font::new(FontTemplateRef::new(template), descriptor, Some(data), None).unwrap()
|
|
}
|
|
|
|
#[test]
|
|
fn test_font_can_do_fast_shaping() {
|
|
let dejavu_sans = make_font(
|
|
[
|
|
env!("CARGO_MANIFEST_DIR"),
|
|
"tests",
|
|
"support",
|
|
"dejavu-fonts-ttf-2.37",
|
|
"ttf",
|
|
"DejaVuSans.ttf",
|
|
]
|
|
.iter()
|
|
.collect(),
|
|
);
|
|
|
|
let dejavu_sans_fast_shapeable = make_font(
|
|
[
|
|
env!("CARGO_MANIFEST_DIR"),
|
|
"tests",
|
|
"support",
|
|
"dejavu-fonts-ttf-2.37",
|
|
"ttf",
|
|
"DejaVuSansNoGSUBNoGPOS.ttf",
|
|
]
|
|
.iter()
|
|
.collect(),
|
|
);
|
|
|
|
// Fast shaping requires a font with a kern table and no GPOS or GSUB tables.
|
|
let shaping_options = ShapingOptions {
|
|
letter_spacing: None,
|
|
word_spacing: Au::zero(),
|
|
script: Script::Latin,
|
|
flags: ShapingFlags::empty(),
|
|
};
|
|
assert!(!dejavu_sans.can_do_fast_shaping("WAVE", &shaping_options));
|
|
assert!(dejavu_sans_fast_shapeable.can_do_fast_shaping("WAVE", &shaping_options));
|
|
|
|
// Non-Latin script should never have fast shaping.
|
|
let shaping_options = ShapingOptions {
|
|
letter_spacing: None,
|
|
word_spacing: Au::zero(),
|
|
script: Script::Cherokee,
|
|
flags: ShapingFlags::empty(),
|
|
};
|
|
assert!(!dejavu_sans.can_do_fast_shaping("WAVE", &shaping_options));
|
|
assert!(!dejavu_sans_fast_shapeable.can_do_fast_shaping("WAVE", &shaping_options));
|
|
|
|
// Right-to-left text should never use fast shaping.
|
|
let shaping_options = ShapingOptions {
|
|
letter_spacing: None,
|
|
word_spacing: Au::zero(),
|
|
script: Script::Latin,
|
|
flags: ShapingFlags::RTL_FLAG,
|
|
};
|
|
assert!(!dejavu_sans.can_do_fast_shaping("WAVE", &shaping_options));
|
|
assert!(!dejavu_sans_fast_shapeable.can_do_fast_shaping("WAVE", &shaping_options));
|
|
}
|