fonts: Implement CSS font-variation-settings property for FreeType platforms (#38642)

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>
This commit is contained in:
Simon Wülker 2025-08-18 18:30:14 +02:00 committed by GitHub
parent ce16fbce75
commit 7471ad7730
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 274 additions and 79 deletions

View file

@ -43,9 +43,9 @@ use webrender_api::units::{
use webrender_api::{
self, BuiltDisplayList, DirtyRect, DisplayListPayload, DocumentId, Epoch as WebRenderEpoch,
ExternalScrollId, FontInstanceFlags, FontInstanceKey, FontInstanceOptions, FontKey,
HitTestFlags, PipelineId as WebRenderPipelineId, PropertyBinding, ReferenceFrameKind,
RenderReasons, SampledScrollOffset, ScrollLocation, SpaceAndClipInfo, SpatialId,
SpatialTreeItemKey, TransformStyle,
FontVariation, HitTestFlags, PipelineId as WebRenderPipelineId, PropertyBinding,
ReferenceFrameKind, RenderReasons, SampledScrollOffset, ScrollLocation, SpaceAndClipInfo,
SpatialId, SpatialTreeItemKey, TransformStyle,
};
use crate::InitialCompositorState;
@ -713,8 +713,14 @@ impl IOCompositor {
self.global.borrow_mut().send_transaction(transaction);
},
CompositorMsg::AddFontInstance(font_instance_key, font_key, size, flags) => {
self.add_font_instance(font_instance_key, font_key, size, flags);
CompositorMsg::AddFontInstance(
font_instance_key,
font_key,
size,
flags,
variations,
) => {
self.add_font_instance(font_instance_key, font_key, size, flags, variations);
},
CompositorMsg::RemoveFonts(keys, instance_keys) => {
@ -1506,7 +1512,14 @@ impl IOCompositor {
font_key: FontKey,
size: f32,
flags: FontInstanceFlags,
variations: Vec<FontVariation>,
) {
let variations = if pref!(layout_variable_fonts_enabled) {
variations
} else {
vec![]
};
let mut transaction = Transaction::new();
let font_instance_options = FontInstanceOptions {
@ -1519,7 +1532,7 @@ impl IOCompositor {
size,
Some(font_instance_options),
None,
Vec::new(),
variations,
);
self.global.borrow_mut().send_transaction(transaction);