-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
First of a series of TrueType hinting patches. This one models the TT "graphics state" which is essentially all of the data involving outlines, measurement and rounding. Includes a tiny math module that provides support for working with fixed point values as raw i32s. This is not ideal but exists from the initial port from FreeType and will require some time and attention to correct. This will need to be deferred to a later time.
- Loading branch information
Showing
8 changed files
with
1,336 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
//! Hinting error definitions. | ||
|
||
/// Errors that may occur when interpreting TrueType bytecode. | ||
#[derive(Clone, Debug)] | ||
pub enum HintErrorKind { | ||
UnexpectedEndOfBytecode, | ||
InvalidOpcode(u8), | ||
DefinitionInGlyphProgram, | ||
NestedDefinition, | ||
InvalidDefintionIndex(usize), | ||
ValueStackOverflow, | ||
ValueStackUnderflow, | ||
CallStackOverflow, | ||
CallStackUnderflow, | ||
InvalidStackValue(i32), | ||
InvalidPointIndex(usize), | ||
InvalidPointRange(usize, usize), | ||
InvalidContourIndex(usize), | ||
InvalidCvtIndex(usize), | ||
InvalidStorageIndex(usize), | ||
DivideByZero, | ||
InvalidZoneIndex(i32), | ||
NegativeLoopCounter, | ||
InvalidJump, | ||
} | ||
|
||
impl core::fmt::Display for HintErrorKind { | ||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
match self { | ||
Self::UnexpectedEndOfBytecode => write!(f, "unexpected end of bytecode"), | ||
Self::InvalidOpcode(opcode) => write!(f, "invalid instruction opcode {opcode}"), | ||
Self::DefinitionInGlyphProgram => { | ||
write!(f, "FDEF or IDEF instruction present in glyph program") | ||
} | ||
Self::NestedDefinition => write!( | ||
f, | ||
"FDEF or IDEF instruction present in another FDEF or IDEF block" | ||
), | ||
Self::InvalidDefintionIndex(index) => write!( | ||
f, | ||
"invalid function or instruction definition index {index}" | ||
), | ||
Self::ValueStackOverflow => write!(f, "value stack overflow"), | ||
Self::ValueStackUnderflow => write!(f, "value stack underflow"), | ||
Self::CallStackOverflow => write!(f, "call stack overflow"), | ||
Self::CallStackUnderflow => write!(f, "call stack underflow"), | ||
Self::InvalidStackValue(value) => write!( | ||
f, | ||
"stack value {value} was invalid for the current operation" | ||
), | ||
Self::InvalidPointIndex(index) => write!(f, "point index {index} was out of bounds"), | ||
Self::InvalidPointRange(start, end) => { | ||
write!(f, "point range {start}..{end} was out of bounds") | ||
} | ||
Self::InvalidContourIndex(index) => { | ||
write!(f, "contour index {index} was out of bounds") | ||
} | ||
Self::InvalidCvtIndex(index) => write!(f, "cvt index {index} was out of bounds"), | ||
Self::InvalidStorageIndex(index) => { | ||
write!(f, "storage area index {index} was out of bounds") | ||
} | ||
Self::DivideByZero => write!(f, "attempt to divide by 0"), | ||
Self::InvalidZoneIndex(index) => write!( | ||
f, | ||
"zone index {index} was invalid (only 0 or 1 are permitted)" | ||
), | ||
Self::NegativeLoopCounter => { | ||
write!(f, "attempt to set the loop counter to a negative value") | ||
} | ||
Self::InvalidJump => write!(f, "the target of a jump instruction was invalid"), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,211 @@ | ||
//! Graphics state for the TrueType interpreter. | ||
|
||
mod projection; | ||
mod round; | ||
mod zone; | ||
|
||
use core::ops::{Deref, DerefMut}; | ||
use read_fonts::types::Point; | ||
|
||
pub use { | ||
round::{RoundMode, RoundState}, | ||
zone::{Zone, ZonePointer}, | ||
}; | ||
|
||
/// Describes the axis to which a measurement or point movement operation | ||
/// applies. | ||
#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)] | ||
pub enum CoordAxis { | ||
#[default] | ||
Both, | ||
X, | ||
Y, | ||
} | ||
|
||
/// Context in which instructions are executed. | ||
/// | ||
/// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html> | ||
#[derive(Debug)] | ||
pub struct GraphicsState<'a> { | ||
/// Fields of the graphics state that persist between calls to the intepreter. | ||
pub retained: RetainedGraphicsState, | ||
/// A unit vector whose direction establishes an axis along which | ||
/// distances are measured. | ||
/// | ||
/// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#projection%20vector> | ||
pub proj_vector: Point<i32>, | ||
/// Current axis for the projection vector. | ||
pub proj_axis: CoordAxis, | ||
/// A second projection vector set to a line defined by the original | ||
/// outline location of two points. The dual projection vector is used | ||
/// when it is necessary to measure distances from the scaled outline | ||
/// before any instructions were executed. | ||
/// | ||
/// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#dual%20projection%20vector> | ||
pub dual_proj_vector: Point<i32>, | ||
/// Current axis for the dual projection vector. | ||
pub dual_proj_axis: CoordAxis, | ||
/// A unit vector that establishes an axis along which points can move. | ||
/// | ||
/// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#freedom%20vector> | ||
pub freedom_vector: Point<i32>, | ||
/// Current axis for point movement. | ||
pub freedom_axis: CoordAxis, | ||
/// Dot product of freedom and projection vectors. | ||
pub fdotp: i32, | ||
/// Determines the manner in which values are rounded. | ||
/// | ||
/// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#round%20state> | ||
pub round_state: RoundState, | ||
/// First reference point. | ||
/// | ||
/// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#rp0> | ||
pub rp0: usize, | ||
/// Second reference point. | ||
/// | ||
/// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#rp1> | ||
pub rp1: usize, | ||
/// Third reference point. | ||
/// | ||
/// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#rp1> | ||
pub rp2: usize, | ||
/// Makes it possible to repeat certain instructions a designated number of | ||
/// times. The default value of one assures that unless the value of loop | ||
/// is altered, these instructions will execute one time. | ||
/// | ||
/// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#loop> | ||
pub loop_counter: u32, | ||
/// First zone pointer. | ||
/// | ||
/// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#zp0> | ||
pub zp0: ZonePointer, | ||
/// Second zone pointer. | ||
/// | ||
/// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#zp1> | ||
pub zp1: ZonePointer, | ||
/// Third zone pointer. | ||
/// | ||
/// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#zp2> | ||
pub zp2: ZonePointer, | ||
/// Outline data for each zone. | ||
/// | ||
/// This array contains the twilight and glyph zones, in that order. | ||
pub zones: [Zone<'a>; 2], | ||
} | ||
|
||
impl Default for GraphicsState<'_> { | ||
fn default() -> Self { | ||
let vector = Point::new(0x4000, 0); | ||
Self { | ||
retained: RetainedGraphicsState::default(), | ||
proj_vector: vector, | ||
proj_axis: CoordAxis::Both, | ||
dual_proj_vector: vector, | ||
dual_proj_axis: CoordAxis::Both, | ||
freedom_vector: vector, | ||
freedom_axis: CoordAxis::Both, | ||
fdotp: 0x4000, | ||
round_state: RoundState::default(), | ||
rp0: 0, | ||
rp1: 0, | ||
rp2: 0, | ||
loop_counter: 1, | ||
zones: [Zone::default(), Zone::default()], | ||
zp0: ZonePointer::default(), | ||
zp1: ZonePointer::default(), | ||
zp2: ZonePointer::default(), | ||
} | ||
} | ||
} | ||
|
||
/// The persistent graphics state. | ||
/// | ||
/// Some of the graphics state is set by the control value program and | ||
/// persists between runs of the interpreter. This struct captures that | ||
/// state. | ||
/// | ||
/// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html> | ||
#[derive(Copy, Clone, Debug)] | ||
pub struct RetainedGraphicsState { | ||
/// Controls whether the sign of control value table entries will be | ||
/// changed to match the sign of the actual distance measurement with | ||
/// which it is compared. | ||
/// | ||
/// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#auto%20flip> | ||
pub auto_flip: bool, | ||
/// Limits the regularizing effects of control value table entries to | ||
/// cases where the difference between the table value and the measurement | ||
/// taken from the original outline is sufficiently small. | ||
/// | ||
/// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#control_value_cut-in> | ||
pub control_value_cutin: i32, | ||
/// Establishes the base value used to calculate the range of point sizes | ||
/// to which a given DELTAC[] or DELTAP[] instruction will apply. | ||
/// | ||
/// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#delta%20base> | ||
pub delta_base: u16, | ||
/// Determines the range of movement and smallest magnitude of movement | ||
/// (the step) in a DELTAC[] or DELTAP[] instruction. | ||
/// | ||
/// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#delta%20shift> | ||
pub delta_shift: u16, | ||
/// Makes it possible to turn off instructions under some circumstances. | ||
/// When set to TRUE, no instructions will be executed | ||
/// | ||
/// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#instruct%20control> | ||
pub instruct_control: u8, | ||
/// Establishes the smallest possible value to which a distance will be | ||
/// rounded. | ||
/// | ||
/// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#minimum%20distance> | ||
pub min_distance: i32, | ||
/// Determines whether the interpreter will activate dropout control for | ||
/// the current glyph. | ||
/// | ||
/// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#scan%20control> | ||
pub scan_control: bool, | ||
/// Type associated with `scan_control`. | ||
pub scan_type: i32, | ||
/// The distance difference below which the interpreter will replace a | ||
/// CVT distance or an actual distance in favor of the single width value. | ||
/// | ||
/// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#single_width_cut_in> | ||
pub single_width_cutin: i32, | ||
/// The value used in place of the control value table distance or the | ||
/// actual distance value when the difference between that distance and | ||
/// the single width value is less than the single width cut-in. | ||
/// | ||
/// See <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM04/Chap4.html#single_width_value> | ||
pub single_width: i32, | ||
} | ||
|
||
impl Default for RetainedGraphicsState { | ||
fn default() -> Self { | ||
Self { | ||
auto_flip: true, | ||
control_value_cutin: 68, | ||
delta_base: 9, | ||
delta_shift: 3, | ||
instruct_control: 0, | ||
min_distance: 64, | ||
scan_control: false, | ||
scan_type: 0, | ||
single_width_cutin: 0, | ||
single_width: 0, | ||
} | ||
} | ||
} | ||
|
||
impl Deref for GraphicsState<'_> { | ||
type Target = RetainedGraphicsState; | ||
|
||
fn deref(&self) -> &Self::Target { | ||
&self.retained | ||
} | ||
} | ||
|
||
impl DerefMut for GraphicsState<'_> { | ||
fn deref_mut(&mut self) -> &mut Self::Target { | ||
&mut self.retained | ||
} | ||
} |
Oops, something went wrong.