Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[skrifa] new hinting options type #1087

Merged
merged 9 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion skrifa/src/outline/autohint/hint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ mod tests {
super::{latin, metrics::Scale, style},
*,
};
use crate::MetadataProvider;
use crate::{attribute::Style, MetadataProvider};
use raw::{
types::{F2Dot14, GlyphId},
FontRef, TableProvider,
Expand Down Expand Up @@ -413,6 +413,7 @@ mod tests {
let scale = Scale::new(
size,
font.head().unwrap().units_per_em() as i32,
Style::Normal,
Default::default(),
);
latin::hint_outline(&mut outline, &metrics, &scale);
Expand Down
2 changes: 1 addition & 1 deletion skrifa/src/outline/autohint/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use raw::TableProvider;
/// Set of derived glyph styles that are used for automatic hinting.
///
/// These are invariant per font so can be precomputed and reused for multiple
/// instances when requesting automatic hinting.
/// instances when requesting automatic hinting with [`Engine::Auto`](super::super::hint::Engine::Auto).
#[derive(Clone, Debug)]
pub struct GlyphStyles(Arc<GlyphStyleMap>);

Expand Down
3 changes: 2 additions & 1 deletion skrifa/src/outline/autohint/latin/edges.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ mod tests {
},
*,
};
use crate::MetadataProvider;
use crate::{attribute::Style, MetadataProvider};
use raw::{types::GlyphId, FontRef, TableProvider};

#[test]
Expand All @@ -301,6 +301,7 @@ mod tests {
let scale = metrics::Scale::new(
16.0,
font.head().unwrap().units_per_em() as i32,
Style::Normal,
Default::default(),
);
let scaled_metrics = latin::metrics::scale_style_metrics(&unscaled_metrics, scale);
Expand Down
3 changes: 2 additions & 1 deletion skrifa/src/outline/autohint/latin/hint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@ mod tests {
},
*,
};
use crate::MetadataProvider;
use crate::{attribute::Style, MetadataProvider};
use raw::{types::GlyphId, FontRef, TableProvider};

#[test]
Expand All @@ -574,6 +574,7 @@ mod tests {
let scale = metrics::Scale::new(
16.0,
font.head().unwrap().units_per_em() as i32,
Style::Normal,
Default::default(),
);
let scaled_metrics = latin::metrics::scale_style_metrics(&unscaled_metrics, scale);
Expand Down
2 changes: 2 additions & 0 deletions skrifa/src/outline/autohint/latin/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ fn scale_axis_metrics(
#[cfg(test)]
mod tests {
use super::{super::super::style, *};
use crate::attribute::Style;
use raw::{FontRef, TableProvider};

#[test]
Expand All @@ -219,6 +220,7 @@ mod tests {
let scale = Scale::new(
16.0,
font.head().unwrap().units_per_em() as i32,
Style::Normal,
Default::default(),
);
let scaled_metrics = scale_style_metrics(&unscaled_metrics, scale);
Expand Down
30 changes: 11 additions & 19 deletions skrifa/src/outline/autohint/metrics.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
//! Autohinting specific metrics.

use super::{
super::{HintingMode, LcdLayout},
super::Target,
axis::Dimension,
style::{GlyphStyleMap, StyleClass},
};
use crate::{collections::SmallVec, FontRef};
use crate::{attribute::Style, collections::SmallVec, FontRef};
use alloc::vec::Vec;
use raw::types::{F2Dot14, Fixed, GlyphId};
#[cfg(feature = "std")]
Expand Down Expand Up @@ -218,40 +218,32 @@ pub(crate) struct Scale {
}

impl Scale {
/// Create initial scaling parameters from font size, units per em
/// and hinting mode.
pub fn new(size: f32, units_per_em: i32, mode: HintingMode) -> Self {
/// Create initial scaling parameters from metrics and hinting target.
pub fn new(size: f32, units_per_em: i32, font_style: Style, target: Target) -> Self {
let scale =
(Fixed::from_bits((size * 64.0) as i32) / Fixed::from_bits(units_per_em)).to_bits();
let is_mono = mode == HintingMode::Strong;
let lcd = match mode {
HintingMode::Smooth { lcd_subpixel, .. } => lcd_subpixel,
_ => None,
};
// TODO: handle light hinting mode and italic flag
let is_light = false;
let is_italic = false;
let is_lcd = lcd == Some(LcdLayout::Horizontal);
let is_lcd_v = lcd == Some(LcdLayout::Horizontal);
let mut flags = 0;
let is_italic = font_style != Style::Normal;
let is_mono = target == Target::Mono;
let is_light = target.is_light() || target.preserve_linear_metrics();
// Snap vertical stems for monochrome and horizontal LCD rendering.
if is_mono || is_lcd {
if is_mono || target.is_lcd() {
flags |= Self::HORIZONTAL_SNAP;
}
// Snap horizontal stems for monochrome and vertical LCD rendering.
if is_mono || is_lcd_v {
if is_mono || target.is_vertical_lcd() {
flags |= Self::VERTICAL_SNAP;
}
// Adjust stems to full pixels unless in LCD or light modes.
if !(is_lcd || is_light) {
if !(target.is_lcd() || is_light) {
flags |= Self::STEM_ADJUST;
}
if is_mono {
flags |= Self::MONO;
}
// Disable horizontal hinting completely for LCD, light hinting
// and italic fonts.
if is_lcd || is_light || is_italic {
if target.is_lcd() || is_light || is_italic {
flags |= Self::NO_HORIZONTAL;
}
Self {
Expand Down
4 changes: 2 additions & 2 deletions skrifa/src/outline/glyf/hint/engine/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ impl<'a> Engine<'a> {
self.graphics.reset_retained();
}
// Set backward compatibility mode
if self.graphics.mode.preserve_linear_metrics() {
if self.graphics.target.preserve_linear_metrics() {
self.graphics.backward_compatibility = true;
} else if self.graphics.mode.is_smooth() {
} else if self.graphics.target.is_smooth() {
self.graphics.backward_compatibility =
(self.graphics.instruct_control & 0x4) == 0;
} else {
Expand Down
2 changes: 1 addition & 1 deletion skrifa/src/outline/glyf/hint/engine/graphics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,7 @@ impl<'a> Engine<'a> {
}
// If preserving linear metrics, prevent modification of the backward
// compatibility flag.
if selector == 3 && self.graphics.mode.preserve_linear_metrics() {
if selector == 3 && self.graphics.target.preserve_linear_metrics() {
return Ok(());
}
match (self.program.initial, selector) {
Expand Down
29 changes: 16 additions & 13 deletions skrifa/src/outline/glyf/hint/engine/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,15 @@ impl<'a> Engine<'a> {
result |= FONT_VARIATIONS_RESULT_BIT;
}
// The following only apply for smooth hinting.
if self.graphics.mode.is_smooth() {
if self.graphics.target.is_smooth() {
// Subpixel hinting [cleartype enabled] (selector bit: 6, result bit: 13)
// (always enabled)
if (selector & SUBPIXEL_HINTING_SELECTOR_BIT) != 0 {
result |= SUBPIXEL_HINTING_RESULT_BIT;
}
// Vertical LCD subpixels? (selector bit: 8, result bit: 15)
if (selector & VERTICAL_LCD_SELECTOR_BIT) != 0 && self.graphics.mode.is_vertical_lcd() {
if (selector & VERTICAL_LCD_SELECTOR_BIT) != 0 && self.graphics.target.is_vertical_lcd()
{
result |= VERTICAL_LCD_RESULT_BIT;
}
// Subpixel positioned? (selector bit: 10, result bit: 17)
Expand All @@ -58,16 +59,17 @@ impl<'a> Engine<'a> {
result |= SUBPIXEL_POSITIONED_RESULT_BIT;
}
// Symmetrical smoothing (selector bit: 11, result bit: 18)
// Note: FreeType always enables this but we deviate when our own
// preserve linear metrics flag is enabled.
// Note: FreeType always enables this but we allow direct control
// with our own flag.
// See <https://github.com/googlefonts/fontations/issues/1080>
if (selector & SYMMETRICAL_SMOOTHING_SELECTOR_BIT) != 0
&& !self.graphics.mode.preserve_linear_metrics()
&& self.graphics.target.symmetric_rendering()
{
result |= SYMMETRICAL_SMOOTHING_RESULT_BIT;
}
// ClearType hinting and grayscale rendering (selector bit: 12, result bit: 19)
if (selector & GRAYSCALE_CLEARTYPE_SELECTOR_BIT) != 0
&& self.graphics.mode.is_grayscale_cleartype()
&& self.graphics.target.is_grayscale_cleartype()
{
result |= GRAYSCALE_CLEARTYPE_RESULT_BIT;
}
Expand Down Expand Up @@ -176,7 +178,7 @@ mod getinfo {
#[cfg(test)]
mod tests {
use super::super::{
super::{super::super::LcdLayout, HintingMode},
super::super::super::{SmoothMode, Target},
Engine, HintErrorKind, MockEngine,
};
use raw::types::F2Dot14;
Expand Down Expand Up @@ -210,7 +212,7 @@ mod tests {
engine.axis_count = 1;
engine.getinfo_test(FONT_VARIATIONS_SELECTOR_BIT, FONT_VARIATIONS_RESULT_BIT);
// in strong hinting mode, the following selectors are always disabled
engine.graphics.mode = HintingMode::Strong;
engine.graphics.target = Target::Mono;
for selector in [
SUBPIXEL_HINTING_SELECTOR_BIT,
VERTICAL_LCD_SELECTOR_BIT,
Expand All @@ -221,7 +223,7 @@ mod tests {
engine.getinfo_test(selector, 0);
}
// set back to smooth mode
engine.graphics.mode = HintingMode::default();
engine.graphics.target = Target::default();
for (selector, result) in [
// default smooth mode is grayscale cleartype
(
Expand All @@ -238,17 +240,18 @@ mod tests {
engine.getinfo_test(selector, result);
}
// vertical lcd
engine.graphics.mode = HintingMode::Smooth {
lcd_subpixel: Some(LcdLayout::Vertical),
engine.graphics.target = Target::Smooth {
mode: SmoothMode::VerticalLcd,
preserve_linear_metrics: true,
symmetric_rendering: false,
};
engine.getinfo_test(VERTICAL_LCD_SELECTOR_BIT, VERTICAL_LCD_RESULT_BIT);
// symmetical smoothing is disabled when preserving linear metrics
// symmetical smoothing is disabled
engine.getinfo_test(SYMMETRICAL_SMOOTHING_SELECTOR_BIT, 0);
// grayscale cleartype is disabled when lcd_subpixel is not None
engine.getinfo_test(GRAYSCALE_CLEARTYPE_SELECTOR_BIT, 0);
// reset to default to disable preserve linear metrics
engine.graphics.mode = HintingMode::default();
engine.graphics.target = Target::default();
// now symmetrical smoothing is enabled
engine.getinfo_test(
SYMMETRICAL_SMOOTHING_SELECTOR_BIT,
Expand Down
16 changes: 8 additions & 8 deletions skrifa/src/outline/glyf/hint/graphics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use super::{
round::RoundState,
zone::{Zone, ZonePointer},
F26Dot6, HintingMode, Point,
F26Dot6, Point, Target,
};
use core::ops::{Deref, DerefMut};

Expand Down Expand Up @@ -150,11 +150,11 @@ impl<'a> GraphicsState<'a> {
pub fn reset_retained(&mut self) {
let scale = self.scale;
let ppem = self.ppem;
let mode = self.mode;
let mode = self.target;
self.retained = RetainedGraphicsState {
scale,
ppem,
mode,
target: mode,
..Default::default()
}
}
Expand Down Expand Up @@ -251,8 +251,8 @@ pub struct RetainedGraphicsState {
///
/// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#single_width_value>
pub single_width: F26Dot6,
/// The user requested hinting mode.
pub mode: HintingMode,
/// The user requested hinting target.
pub target: Target,
/// The scale factor for the current instance. Conversion from font units
/// to 26.6 for current ppem.
pub scale: i32,
Expand All @@ -265,11 +265,11 @@ pub struct RetainedGraphicsState {
}

impl RetainedGraphicsState {
pub fn new(scale: i32, ppem: i32, mode: HintingMode) -> Self {
pub fn new(scale: i32, ppem: i32, target: Target) -> Self {
Self {
scale,
ppem,
mode,
target,
..Default::default()
}
}
Expand All @@ -292,7 +292,7 @@ impl Default for RetainedGraphicsState {
scan_type: 0,
single_width_cutin: F26Dot6::ZERO,
single_width: F26Dot6::ZERO,
mode: Default::default(),
target: Default::default(),
scale: 0,
ppem: 0,
is_rotated: false,
Expand Down
10 changes: 5 additions & 5 deletions skrifa/src/outline/glyf/hint/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use super::{
program::{Program, ProgramState},
value_stack::ValueStack,
zone::Zone,
HintOutline, HintingMode, PointFlags,
HintOutline, PointFlags, Target,
};
use alloc::vec::Vec;
use raw::{
Expand Down Expand Up @@ -38,7 +38,7 @@ impl HintInstance {
outlines: &Outlines,
scale: i32,
ppem: i32,
mode: HintingMode,
target: Target,
coords: &[F2Dot14],
) -> Result<(), HintError> {
self.setup(outlines, scale, coords);
Expand All @@ -53,7 +53,7 @@ impl HintInstance {
let glyph = Zone::default();
let mut stack_buf = vec![0; self.max_stack];
let value_stack = ValueStack::new(&mut stack_buf, false);
let graphics = RetainedGraphicsState::new(scale, ppem, mode);
let graphics = RetainedGraphicsState::new(scale, ppem, target);
let mut engine = Engine::new(
outlines,
ProgramState::new(outlines.fpgm, outlines.prep, &[], Program::Font),
Expand Down Expand Up @@ -92,9 +92,9 @@ impl HintInstance {
/// by the hinter settings or the `prep` table.
pub fn backward_compatibility(&self) -> bool {
// Set backward compatibility mode
if self.graphics.mode.preserve_linear_metrics() {
if self.graphics.target.preserve_linear_metrics() {
true
} else if self.graphics.mode.is_smooth() {
} else if self.graphics.target.is_smooth() {
(self.graphics.instruct_control & 0x4) == 0
} else {
false
Expand Down
41 changes: 1 addition & 40 deletions skrifa/src/outline/glyf/hint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ mod storage;
mod value_stack;
mod zone;

use super::super::{HintingMode, LcdLayout};
use super::super::Target;

use read_fonts::{
tables::glyf::PointFlags,
Expand Down Expand Up @@ -45,42 +45,3 @@ pub struct HintOutline<'a> {
pub is_composite: bool,
pub coords: &'a [F2Dot14],
}

// Helpers for deriving various flags from the mode which
// change the behavior of certain instructions.
// See <https://gitlab.freedesktop.org/freetype/freetype/-/blob/57617782464411201ce7bbc93b086c1b4d7d84a5/src/truetype/ttgload.c#L2222>
impl HintingMode {
fn is_smooth(&self) -> bool {
matches!(self, Self::Smooth { .. })
}

fn is_grayscale_cleartype(&self) -> bool {
matches!(
self,
Self::Smooth {
lcd_subpixel: None,
..
}
)
}

fn is_vertical_lcd(&self) -> bool {
matches!(
self,
Self::Smooth {
lcd_subpixel: Some(LcdLayout::Vertical),
..
}
)
}

fn preserve_linear_metrics(&self) -> bool {
matches!(
self,
Self::Smooth {
preserve_linear_metrics: true,
..
}
)
}
}
Loading