Resolve variations on fallback faces

This commit is contained in:
SGavrl committed 2026-07-30 23:47:44 +00:00
1 parent 3dc4014589
commit 178102799d
4 files changed
+398 -89

No files matched your search

+38
View File
@@ -331,6 +331,14 @@ pub struct Attrs<'a> {
/// A specific database face selected by the caller. Font fallback remains
/// available when that face does not contain a requested glyph.
pub font_id_opt: Option<fontdb::ID>,
/// High-level CSS `font-weight` coordinate, applied only when the actual
/// shaped face provides a `wght` axis.
pub font_weight_axis_opt: Option<VariationValue>,
/// Automatic optical-size coordinate derived from the used font size.
/// `None` represents `font-optical-sizing: none`.
pub font_optical_size_opt: Option<VariationValue>,
/// Whether high-level font style requests an italic variable instance.
pub font_italic_axis: bool,
pub stretch: Stretch,
pub style: Style,
pub weight: Weight,
@@ -352,6 +360,9 @@ impl<'a> Attrs<'a> {
color_opt: None,
family: Family::SansSerif,
font_id_opt: None,
font_weight_axis_opt: None,
font_optical_size_opt: None,
font_italic_axis: false,
stretch: Stretch::Normal,
style: Style::Normal,
weight: Weight::NORMAL,
@@ -382,6 +393,21 @@ impl<'a> Attrs<'a> {
self
}
pub fn font_weight_axis(mut self, value: f32) -> Self {
self.font_weight_axis_opt = Some(VariationValue(value));
self
}
pub fn font_optical_size(mut self, value: f32) -> Self {
self.font_optical_size_opt = Some(VariationValue(value));
self
}
pub fn font_italic_axis(mut self, italic: bool) -> Self {
self.font_italic_axis = italic;
self
}
/// Set [Stretch]
pub fn stretch(mut self, stretch: Stretch) -> Self {
self.stretch = stretch;
@@ -453,6 +479,9 @@ impl<'a> Attrs<'a> {
pub fn compatible(&self, other: &Self) -> bool {
self.family == other.family
&& self.font_id_opt == other.font_id_opt
&& self.font_weight_axis_opt == other.font_weight_axis_opt
&& self.font_optical_size_opt == other.font_optical_size_opt
&& self.font_italic_axis == other.font_italic_axis
&& self.stretch == other.stretch
&& self.style == other.style
&& self.weight == other.weight
@@ -487,6 +516,9 @@ pub struct AttrsOwned {
pub color_opt: Option<Color>,
pub family_owned: FamilyOwned,
pub font_id_opt: Option<fontdb::ID>,
pub font_weight_axis_opt: Option<VariationValue>,
pub font_optical_size_opt: Option<VariationValue>,
pub font_italic_axis: bool,
pub stretch: Stretch,
pub style: Style,
pub weight: Weight,
@@ -505,6 +537,9 @@ impl AttrsOwned {
color_opt: attrs.color_opt,
family_owned: FamilyOwned::new(attrs.family),
font_id_opt: attrs.font_id_opt,
font_weight_axis_opt: attrs.font_weight_axis_opt,
font_optical_size_opt: attrs.font_optical_size_opt,
font_italic_axis: attrs.font_italic_axis,
stretch: attrs.stretch,
style: attrs.style,
weight: attrs.weight,
@@ -522,6 +557,9 @@ impl AttrsOwned {
color_opt: self.color_opt,
family: self.family_owned.as_family(),
font_id_opt: self.font_id_opt,
font_weight_axis_opt: self.font_weight_axis_opt,
font_optical_size_opt: self.font_optical_size_opt,
font_italic_axis: self.font_italic_axis,
stretch: self.stretch,
style: self.style,
weight: self.weight,
+8
View File
@@ -22,6 +22,14 @@ pub struct LayoutGlyph {
pub font_id: fontdb::ID,
/// Font id of the glyph
pub glyph_id: u16,
/// Whether the selected font face has variation axes.
pub font_is_variable: bool,
/// Automatic `wght` axis value requested by the span.
pub font_weight_axis_opt: Option<f32>,
/// Automatic `opsz` axis value requested by the span.
pub font_optical_size_opt: Option<f32>,
/// Whether the span requests an italic variation axis.
pub font_italic_axis: bool,
/// X offset of hitbox
pub x: f32,
/// Y offset of hitbox
+49 -1
View File
@@ -144,10 +144,41 @@ fn shape_fallback(
// requests non-default variation coordinates, then use the varied face for
// metrics, plan construction, and shaping so advances and glyph selection
// are derived from the same instance.
let varied_face = if attrs.font_variations.is_empty() {
let varied_face = if !font.rustybuzz().is_variable()
|| (attrs.font_variations.is_empty()
&& attrs.font_weight_axis_opt.is_none()
&& attrs.font_optical_size_opt.is_none()
&& !attrs.font_italic_axis)
{
None
} else {
let mut face = font.rustybuzz().clone();
if let Some(value) = attrs
.font_weight_axis_opt
.map(|value| value.0)
.filter(|value| value.is_finite())
{
let _ = face.set_variation(rustybuzz::ttf_parser::Tag::from_bytes(b"wght"), value);
}
if let Some(value) = attrs
.font_optical_size_opt
.map(|value| value.0)
.filter(|value| value.is_finite())
{
let _ = face.set_variation(rustybuzz::ttf_parser::Tag::from_bytes(b"opsz"), value);
}
if attrs.font_italic_axis {
let italic = rustybuzz::ttf_parser::Tag::from_bytes(b"ital");
if face
.variation_axes()
.into_iter()
.any(|axis| axis.tag == italic)
{
let _ = face.set_variation(italic, 1.0);
} else {
let _ = face.set_variation(rustybuzz::ttf_parser::Tag::from_bytes(b"slnt"), -14.0);
}
}
for variation in attrs
.font_variations
.iter()
@@ -257,6 +288,10 @@ fn shape_fallback(
font_monospace_em_width: font.monospace_em_width(),
font_id: font.id(),
glyph_id: info.glyph_id.try_into().expect("failed to cast glyph ID"),
font_is_variable: face.is_variable(),
font_weight_axis_opt: attrs.font_weight_axis_opt.map(|value| value.0),
font_optical_size_opt: attrs.font_optical_size_opt.map(|value| value.0),
font_italic_axis: attrs.font_italic_axis,
//TODO: color should not be related to shaping
color_opt: attrs.color_opt,
metadata: attrs.metadata,
@@ -539,6 +574,7 @@ fn shape_skip(
.expect("no default font found");
let font_id = font.id();
let font_monospace_em_width = font.monospace_em_width();
let font_is_variable = font.rustybuzz().is_variable();
let font = font.as_swash();
let charmap = font.charmap();
@@ -569,6 +605,10 @@ fn shape_skip(
font_monospace_em_width,
font_id,
glyph_id,
font_is_variable,
font_weight_axis_opt: attrs.font_weight_axis_opt.map(|value| value.0),
font_optical_size_opt: attrs.font_optical_size_opt.map(|value| value.0),
font_italic_axis: attrs.font_italic_axis,
color_opt: attrs.color_opt,
metadata: attrs.metadata,
cache_key_flags: attrs.cache_key_flags,
@@ -592,6 +632,10 @@ pub struct ShapeGlyph {
pub font_monospace_em_width: Option<f32>,
pub font_id: fontdb::ID,
pub glyph_id: u16,
pub font_is_variable: bool,
pub font_weight_axis_opt: Option<f32>,
pub font_optical_size_opt: Option<f32>,
pub font_italic_axis: bool,
pub color_opt: Option<Color>,
pub metadata: usize,
pub cache_key_flags: CacheKeyFlags,
@@ -615,6 +659,10 @@ impl ShapeGlyph {
line_height_opt,
font_id: self.font_id,
glyph_id: self.glyph_id,
font_is_variable: self.font_is_variable,
font_weight_axis_opt: self.font_weight_axis_opt,
font_optical_size_opt: self.font_optical_size_opt,
font_italic_axis: self.font_italic_axis,
x,
y,
w,