Vendor things

This commit is contained in:
John Doty 2024-03-08 11:03:01 -08:00
parent 5deceec006
commit 977e3c17e5
19434 changed files with 10682014 additions and 0 deletions

View file

@ -0,0 +1,24 @@
use crate::GlyphId;
use alloc::boxed::Box;
use core::{fmt, iter};
pub struct CodepointIdIter<'a> {
pub(crate) inner: Box<dyn Iterator<Item = (GlyphId, char)> + 'a>,
}
impl<'a> Iterator for CodepointIdIter<'a> {
type Item = (GlyphId, char);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}
impl iter::FusedIterator for CodepointIdIter<'_> {}
impl fmt::Debug for CodepointIdIter<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "CodepointIdIter")
}
}

14
third-party/vendor/ab_glyph/src/err.rs vendored Normal file
View file

@ -0,0 +1,14 @@
use core::fmt;
/// Invalid font data error.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct InvalidFont;
impl fmt::Display for InvalidFont {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "InvalidFont")
}
}
#[cfg(feature = "std")]
impl std::error::Error for InvalidFont {}

318
third-party/vendor/ab_glyph/src/font.rs vendored Normal file
View file

@ -0,0 +1,318 @@
use crate::{
point, v2, Glyph, GlyphId, Outline, OutlinedGlyph, PxScale, PxScaleFont, Rect, ScaleFont,
};
/// Functionality required from font data.
///
/// See also [`FontArc`](struct.FontArc.html), [`FontRef`](struct.FontRef.html)
/// and [`FontVec`](struct.FontVec.html).
///
/// ## Units
///
/// Units of unscaled accessors are "font units", which is an arbitrary unit
/// defined by the font. See [`Font::units_per_em`].
///
/// ab_glyph uses a non-standard scale [`PxScale`] which is the pixel height
/// of the text. See [`Font::pt_to_px_scale`] to convert standard point sizes.
pub trait Font {
/// Get the size of the font unit
///
/// This returns "font units per em", where 1em is a base unit of font scale
/// (typically the width of a capital 'M').
///
/// Returns `None` in case the font unit size exceeds the expected range.
/// See [`Face::units_per_em`](https://docs.rs/ttf-parser/latest/ttf_parser/struct.Face.html#method.units_per_em).
///
/// May be used to calculate [`PxScale`] from pt size, see [`Font::pt_to_px_scale`].
fn units_per_em(&self) -> Option<f32>;
/// Converts pt units into [`PxScale`].
///
/// Note: To handle a screen scale factor multiply it to the `pt_size` argument.
///
/// Returns `None` in case the [`Font::units_per_em`] unit size exceeds the expected range.
///
/// ## Point size (pt)
///
/// Font sizes are typically specified in "points". According to the modern
/// standard, 1pt = 1/72in. The "point size" of a font is the number of points
/// per em.
///
/// The DPI (dots-per-inch) of a screen depends on the screen in question;
/// 96 DPI is often considered the "standard". For high-DPI displays the
/// DPI may be specified directly or one may multiply 96 by a scale-factor.
///
/// Thus, for example, a 10pt font on a 96 pixels-per-inch display has
/// 10 / 72 * 96 = 13.333... pixels-per-em. If we divide this number by
/// `units_per_em` we then get a scaling factor: pixels-per-font-unit.
///
/// Note however that since [`PxScale`] values are relative to the text height,
/// one further step is needed: multiply by [`Font::height_unscaled`].
fn pt_to_px_scale(&self, pt_size: f32) -> Option<PxScale> {
let px_per_em = pt_size * (96.0 / 72.0);
let units_per_em = self.units_per_em()?;
let height = self.height_unscaled();
Some(PxScale::from(px_per_em * height / units_per_em))
}
/// Unscaled glyph ascent.
///
/// Scaling can be done with [as_scaled](trait.Font.html#method.as_scaled).
fn ascent_unscaled(&self) -> f32;
/// Unscaled glyph descent.
///
/// Scaling can be done with [as_scaled](trait.Font.html#method.as_scaled).
fn descent_unscaled(&self) -> f32;
/// Unscaled height `ascent - descent`.
///
/// Scaling can be done with [as_scaled](trait.Font.html#method.as_scaled).
#[inline]
fn height_unscaled(&self) -> f32 {
self.ascent_unscaled() - self.descent_unscaled()
}
/// Unscaled line gap.
///
/// Scaling can be done with [as_scaled](trait.Font.html#method.as_scaled).
fn line_gap_unscaled(&self) -> f32;
/// Lookup a `GlyphId` matching a given `char`.
///
/// Scaling can be done with [as_scaled](trait.Font.html#method.as_scaled).
fn glyph_id(&self, c: char) -> GlyphId;
/// Unscaled horizontal advance for a given glyph id.
///
/// Returns `0.0` if the font does not define this value.
///
/// Scaling can be done with [as_scaled](trait.Font.html#method.as_scaled).
fn h_advance_unscaled(&self, id: GlyphId) -> f32;
/// Unscaled horizontal side bearing for a given glyph id.
///
/// Returns `0.0` if the font does not define this value.
///
/// Scaling can be done with [as_scaled](trait.Font.html#method.as_scaled).
fn h_side_bearing_unscaled(&self, id: GlyphId) -> f32;
/// Unscaled vertical advance for a given glyph id.
///
/// Returns `0.0` if the font does not define this value.
///
/// Scaling can be done with [as_scaled](trait.Font.html#method.as_scaled).
fn v_advance_unscaled(&self, id: GlyphId) -> f32;
/// Unscaled vertical side bearing for a given glyph id.
///
/// Returns `0.0` if the font does not define this value.
///
/// Scaling can be done with [as_scaled](trait.Font.html#method.as_scaled).
fn v_side_bearing_unscaled(&self, id: GlyphId) -> f32;
/// Returns additional unscaled kerning to apply for a particular pair of glyph ids.
///
/// Scaling can be done with [as_scaled](trait.Font.html#method.as_scaled).
fn kern_unscaled(&self, first: GlyphId, second: GlyphId) -> f32;
/// Compute unscaled glyph outline curves & bounding box.
fn outline(&self, id: GlyphId) -> Option<Outline>;
/// The number of glyphs present in this font. Glyph identifiers for this
/// font will always be in the range `0..self.glyph_count()`
fn glyph_count(&self) -> usize;
/// Returns an iterator of all distinct `(GlyphId, char)` pairs. Not ordered.
///
/// # Example
/// ```
/// # use ab_glyph::{Font, FontRef, GlyphId};
/// # use std::collections::HashMap;
/// # fn main() -> Result<(), ab_glyph::InvalidFont> {
/// let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf"))?;
///
/// // Iterate over pairs, each id will appear at most once.
/// let mut codepoint_ids = font.codepoint_ids();
/// assert_eq!(codepoint_ids.next(), Some((GlyphId(408), '\r')));
/// assert_eq!(codepoint_ids.next(), Some((GlyphId(1), ' ')));
/// assert_eq!(codepoint_ids.next(), Some((GlyphId(75), '!')));
///
/// // Build a lookup map for all ids
/// let map: HashMap<_, _> = font.codepoint_ids().collect();
/// assert_eq!(map.get(&GlyphId(75)), Some(&'!'));
/// # assert_eq!(map.len(), 908);
/// # Ok(()) }
/// ```
fn codepoint_ids(&self) -> crate::CodepointIdIter<'_>;
/// Returns a pre-rendered image of the glyph.
///
/// This is normally only present when an outline is not sufficient to describe the glyph, such
/// as emojis (particularly color ones). The `pixel_size` parameter is in pixels per em, and will be
/// used to select between multiple possible images (if present); the returned image will
/// likely not match this value, requiring you to scale it to match the target resolution.
/// To get the largest image use `u16::MAX`.
#[allow(deprecated)]
#[deprecated(
since = "0.2.22",
note = "Deprecated in favor of `glyph_raster_image2`"
)]
fn glyph_raster_image(&self, id: GlyphId, pixel_size: u16) -> Option<crate::GlyphImage> {
self.glyph_raster_image2(id, pixel_size)
.map(|i| crate::GlyphImage {
origin: i.origin,
scale: i.pixels_per_em.into(),
data: i.data,
format: i.format,
})
}
/// Returns a pre-rendered image of the glyph.
///
/// This is normally only present when an outline is not sufficient to describe the glyph, such
/// as emojis (particularly color ones). The `pixel_size` parameter is in pixels per em, and will be
/// used to select between multiple possible images (if present); the returned image will
/// likely not match this value, requiring you to scale it to match the target resolution.
/// To get the largest image use `u16::MAX`.
fn glyph_raster_image2(&self, id: GlyphId, pixel_size: u16) -> Option<v2::GlyphImage>;
/// Returns the layout bounds of this glyph. These are different to the outline `px_bounds()`.
///
/// Horizontally: Glyph position +/- h_advance/h_side_bearing.
/// Vertically: Glyph position +/- ascent/descent.
#[inline]
fn glyph_bounds(&self, glyph: &Glyph) -> Rect
where
Self: Sized,
{
let sf = self.as_scaled(glyph.scale);
let pos = glyph.position;
Rect {
min: point(pos.x - sf.h_side_bearing(glyph.id), pos.y - sf.ascent()),
max: point(pos.x + sf.h_advance(glyph.id), pos.y - sf.descent()),
}
}
/// Compute glyph outline ready for drawing.
#[inline]
fn outline_glyph(&self, glyph: Glyph) -> Option<OutlinedGlyph>
where
Self: Sized,
{
let outline = self.outline(glyph.id)?;
let scale_factor = self.as_scaled(glyph.scale).scale_factor();
Some(OutlinedGlyph::new(glyph, outline, scale_factor))
}
/// Construct a [`PxScaleFontRef`](struct.PxScaleFontRef.html) by associating with the
/// given pixel `scale`.
///
/// # Example
/// ```
/// # use ab_glyph::{Font, FontRef, PxScale, ScaleFont};
/// # fn main() -> Result<(), ab_glyph::InvalidFont> {
/// let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf"))?;
///
/// assert_eq!(font.descent_unscaled(), -201.0);
///
/// assert_eq!(font.as_scaled(24.0).descent(), -4.02);
/// assert_eq!(font.as_scaled(50.0).descent(), -8.375);
/// # Ok(()) }
/// ```
#[inline]
fn as_scaled<S: Into<PxScale>>(&self, scale: S) -> PxScaleFont<&'_ Self>
where
Self: Sized,
{
PxScaleFont {
font: self,
scale: scale.into(),
}
}
/// Move into a [`PxScaleFont`](struct.PxScaleFont.html) associated with the
/// given pixel `scale`.
#[inline]
fn into_scaled<S: Into<PxScale>>(self, scale: S) -> PxScaleFont<Self>
where
Self: core::marker::Sized,
{
PxScaleFont {
font: self,
scale: scale.into(),
}
}
}
impl<F: Font> Font for &F {
#[inline]
fn units_per_em(&self) -> Option<f32> {
(*self).units_per_em()
}
#[inline]
fn ascent_unscaled(&self) -> f32 {
(*self).ascent_unscaled()
}
#[inline]
fn descent_unscaled(&self) -> f32 {
(*self).descent_unscaled()
}
#[inline]
fn line_gap_unscaled(&self) -> f32 {
(*self).line_gap_unscaled()
}
#[inline]
fn glyph_id(&self, c: char) -> GlyphId {
(*self).glyph_id(c)
}
#[inline]
fn h_advance_unscaled(&self, id: GlyphId) -> f32 {
(*self).h_advance_unscaled(id)
}
#[inline]
fn h_side_bearing_unscaled(&self, id: GlyphId) -> f32 {
(*self).h_side_bearing_unscaled(id)
}
#[inline]
fn v_advance_unscaled(&self, id: GlyphId) -> f32 {
(*self).v_advance_unscaled(id)
}
#[inline]
fn v_side_bearing_unscaled(&self, id: GlyphId) -> f32 {
(*self).v_side_bearing_unscaled(id)
}
#[inline]
fn kern_unscaled(&self, first: GlyphId, second: GlyphId) -> f32 {
(*self).kern_unscaled(first, second)
}
#[inline]
fn outline(&self, glyph: GlyphId) -> Option<Outline> {
(*self).outline(glyph)
}
#[inline]
fn glyph_count(&self) -> usize {
(*self).glyph_count()
}
#[inline]
fn codepoint_ids(&self) -> crate::CodepointIdIter<'_> {
(*self).codepoint_ids()
}
#[inline]
fn glyph_raster_image2(&self, id: GlyphId, size: u16) -> Option<v2::GlyphImage> {
(*self).glyph_raster_image2(id, size)
}
}

View file

@ -0,0 +1,162 @@
use crate::{v2, Font, FontRef, FontVec, GlyphId, InvalidFont, Outline};
use alloc::sync::Arc;
use core::fmt;
/// `Font` implementor that wraps another concrete `Font + 'static` type storing in an `Arc`.
///
/// Provides convenient type erasure & cheap clones (particularly for `FontVec`).
///
/// # Example
/// ```
/// use ab_glyph::{Font, FontArc};
///
/// # fn main() -> Result<(), ab_glyph::InvalidFont> {
/// let font = FontArc::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf"))?;
///
/// assert_eq!(font.glyph_id('s'), ab_glyph::GlyphId(56));
/// # Ok(()) }
/// ```
#[derive(Clone)]
pub struct FontArc(Arc<dyn Font + Send + Sync + 'static>);
impl FontArc {
/// # Example
/// ```
/// # use ab_glyph::*;
/// # fn main() -> Result<(), ab_glyph::InvalidFont> {
/// # let font_data = include_bytes!("../../dev/fonts/Exo2-Light.otf").to_vec();
/// # let font_vec = FontVec::try_from_vec(font_data)?;
/// let font_arc = FontArc::new(font_vec);
/// # Ok(()) }
/// ```
#[inline]
pub fn new<F: Font + Send + Sync + 'static>(font: F) -> Self {
Self(Arc::new(font))
}
/// Creates an `FontArc` from owned data.
///
/// # Example
/// ```
/// # use ab_glyph::*;
/// # fn main() -> Result<(), InvalidFont> {
/// # let owned_font_data = include_bytes!("../../dev/fonts/Exo2-Light.otf").to_vec();
/// let font = FontArc::try_from_vec(owned_font_data)?;
/// # Ok(()) }
/// ```
#[inline]
pub fn try_from_vec(data: Vec<u8>) -> Result<Self, InvalidFont> {
Ok(FontVec::try_from_vec(data)?.into())
}
/// Creates an `FontArc` from a byte-slice.
///
/// # Example
/// ```
/// # use ab_glyph::*;
/// # fn main() -> Result<(), InvalidFont> {
/// let font = FontArc::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf"))?;
/// # Ok(()) }
/// ```
#[inline]
pub fn try_from_slice(data: &'static [u8]) -> Result<Self, InvalidFont> {
Ok(FontRef::try_from_slice(data)?.into())
}
}
impl fmt::Debug for FontArc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "FontArc")
}
}
impl Font for FontArc {
#[inline]
fn units_per_em(&self) -> Option<f32> {
self.0.units_per_em()
}
#[inline]
fn ascent_unscaled(&self) -> f32 {
self.0.ascent_unscaled()
}
#[inline]
fn descent_unscaled(&self) -> f32 {
self.0.descent_unscaled()
}
#[inline]
fn line_gap_unscaled(&self) -> f32 {
self.0.line_gap_unscaled()
}
#[inline]
fn glyph_id(&self, c: char) -> GlyphId {
self.0.glyph_id(c)
}
#[inline]
fn h_advance_unscaled(&self, id: GlyphId) -> f32 {
self.0.h_advance_unscaled(id)
}
#[inline]
fn h_side_bearing_unscaled(&self, id: GlyphId) -> f32 {
self.0.h_side_bearing_unscaled(id)
}
#[inline]
fn v_advance_unscaled(&self, id: GlyphId) -> f32 {
self.0.v_advance_unscaled(id)
}
#[inline]
fn v_side_bearing_unscaled(&self, id: GlyphId) -> f32 {
self.0.v_side_bearing_unscaled(id)
}
#[inline]
fn kern_unscaled(&self, first: GlyphId, second: GlyphId) -> f32 {
self.0.kern_unscaled(first, second)
}
#[inline]
fn outline(&self, glyph: GlyphId) -> Option<Outline> {
self.0.outline(glyph)
}
#[inline]
fn glyph_count(&self) -> usize {
self.0.glyph_count()
}
#[inline]
fn codepoint_ids(&self) -> crate::CodepointIdIter<'_> {
self.0.codepoint_ids()
}
#[inline]
fn glyph_raster_image2(&self, id: GlyphId, size: u16) -> Option<v2::GlyphImage> {
self.0.glyph_raster_image2(id, size)
}
}
impl From<FontVec> for FontArc {
#[inline]
fn from(font: FontVec) -> Self {
Self::new(font)
}
}
impl From<FontRef<'static>> for FontArc {
#[inline]
fn from(font: FontRef<'static>) -> Self {
Self::new(font)
}
}
impl From<Arc<dyn Font + Send + Sync + 'static>> for FontArc {
#[inline]
fn from(font: Arc<dyn Font + Send + Sync + 'static>) -> Self {
Self(font)
}
}

171
third-party/vendor/ab_glyph/src/glyph.rs vendored Normal file
View file

@ -0,0 +1,171 @@
use crate::{Point, PxScale};
/// Glyph id.
///
/// # Example
/// ```
/// use ab_glyph::{Font, FontRef, GlyphId};
/// # fn main() -> Result<(), ab_glyph::InvalidFont> {
/// let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf"))?;
///
/// let q_id: GlyphId = font.glyph_id('q');
/// # Ok(()) }
/// ```
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct GlyphId(pub u16);
impl GlyphId {
/// Construct a `Glyph` with given scale & position.
///
/// # Example
/// ```
/// # use ab_glyph::*;
/// # let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf")).unwrap();
/// let glyph = font.glyph_id('z').with_scale_and_position(24.0, point(100.0, 0.0));
/// ```
#[inline]
pub fn with_scale_and_position<S: Into<PxScale>, P: Into<Point>>(
self,
scale: S,
position: P,
) -> Glyph {
Glyph {
id: self,
scale: scale.into(),
position: position.into(),
}
}
/// Construct a `Glyph` with given scale and position `point(0.0, 0.0)`.
///
/// # Example
/// ```
/// # use ab_glyph::*;
/// # let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf")).unwrap();
/// let glyph = font.glyph_id('w').with_scale(48.0);
/// ```
#[inline]
pub fn with_scale<S: Into<PxScale>>(self, scale: S) -> Glyph {
self.with_scale_and_position(scale, Point::default())
}
}
/// A glyph with pixel scale & position.
#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct Glyph {
/// Glyph id.
pub id: GlyphId,
/// Pixel scale of this glyph.
pub scale: PxScale,
/// Position of this glyph.
pub position: Point,
}
/// Old version of [`v2::GlyphImage`].
#[deprecated(since = "0.2.22", note = "Deprecated in favor of `v2::GlyphImage`")]
#[derive(Debug, Clone)]
pub struct GlyphImage<'a> {
/// Offset of the image from the normal origin (top at the baseline plus
/// ascent), measured in pixels at the image's current scale.
pub origin: Point,
/// Current scale of the image in pixels per em.
pub scale: f32,
/// Raw image data, not a bitmap in the case of [`GlyphImageFormat::Png`] format.
pub data: &'a [u8],
/// Format of the raw data.
pub format: GlyphImageFormat,
}
pub mod v2 {
use crate::{GlyphImageFormat, Point};
/// A pre-rendered image of a glyph, usually used for emojis or other glyphs
/// that can't be represented only using an outline.
#[non_exhaustive]
#[derive(Debug, Clone)]
pub struct GlyphImage<'a> {
/// Offset of the image from the normal origin (top at the baseline plus
/// ascent), measured in pixels at the image's current scale.
pub origin: Point,
/// Image width.
///
/// It doesn't guarantee that this value is the same as set in the `data` in the case of
/// [`GlyphImageFormat::Png`] format.
pub width: u16,
/// Image height.
///
/// It doesn't guarantee that this value is the same as set in the `data` in the case of
/// [`GlyphImageFormat::Png`] format.
pub height: u16,
/// Pixels per em of the selected strike.
pub pixels_per_em: u16,
/// Raw image data, see [`format`](GlyphImageFormat).
pub data: &'a [u8],
/// Format of the raw [`data`](Self::data).
pub format: GlyphImageFormat,
}
}
/// Valid formats for a [`GlyphImage`].
// Possible future formats: SVG, JPEG, TIFF
#[non_exhaustive]
#[derive(Debug, Clone)]
pub enum GlyphImageFormat {
Png,
/// A monochrome bitmap.
///
/// The most significant bit of the first byte corresponds to the top-left pixel, proceeding
/// through succeeding bits moving left to right. The data for each row is padded to a byte
/// boundary, so the next row begins with the most significant bit of a new byte. 1 corresponds
/// to black, and 0 to white.
BitmapMono,
/// A packed monochrome bitmap.
///
/// The most significant bit of the first byte corresponds to the top-left pixel, proceeding
/// through succeeding bits moving left to right. Data is tightly packed with no padding. 1
/// corresponds to black, and 0 to white.
BitmapMonoPacked,
/// A grayscale bitmap with 2 bits per pixel.
///
/// The most significant bits of the first byte corresponds to the top-left pixel, proceeding
/// through succeeding bits moving left to right. The data for each row is padded to a byte
/// boundary, so the next row begins with the most significant bit of a new byte.
BitmapGray2,
/// A packed grayscale bitmap with 2 bits per pixel.
///
/// The most significant bits of the first byte corresponds to the top-left pixel, proceeding
/// through succeeding bits moving left to right. Data is tightly packed with no padding.
BitmapGray2Packed,
/// A grayscale bitmap with 4 bits per pixel.
///
/// The most significant bits of the first byte corresponds to the top-left pixel, proceeding
/// through succeeding bits moving left to right. The data for each row is padded to a byte
/// boundary, so the next row begins with the most significant bit of a new byte.
BitmapGray4,
/// A packed grayscale bitmap with 4 bits per pixel.
///
/// The most significant bits of the first byte corresponds to the top-left pixel, proceeding
/// through succeeding bits moving left to right. Data is tightly packed with no padding.
BitmapGray4Packed,
/// A grayscale bitmap with 8 bits per pixel.
///
/// The first byte corresponds to the top-left pixel, proceeding through succeeding bytes
/// moving left to right.
BitmapGray8,
/// A color bitmap with 32 bits per pixel.
///
/// The first group of four bytes corresponds to the top-left pixel, proceeding through
/// succeeding pixels moving left to right. Each byte corresponds to a color channel and the
/// channels within a pixel are in blue, green, red, alpha order. Color values are
/// pre-multiplied by the alpha. For example, the color "full-green with half translucency"
/// is encoded as `\x00\x80\x00\x80`, and not `\x00\xFF\x00\x80`.
BitmapPremulBgra32,
}

54
third-party/vendor/ab_glyph/src/lib.rs vendored Normal file
View file

@ -0,0 +1,54 @@
//! API for loading, scaling, positioning and rasterizing OpenType font glyphs.
//!
//! # Example
//! ```
//! use ab_glyph::{point, Font, FontRef, Glyph};
//!
//! # fn main() -> Result<(), ab_glyph::InvalidFont> {
//! let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf"))?;
//!
//! // Get a glyph for 'q' with a scale & position.
//! let q_glyph: Glyph = font
//! .glyph_id('q')
//! .with_scale_and_position(24.0, point(100.0, 0.0));
//!
//! // Draw it.
//! if let Some(q) = font.outline_glyph(q_glyph) {
//! q.draw(|x, y, c| { /* draw pixel `(x, y)` with coverage: `c` */ });
//! }
//! # Ok(()) }
//! ```
#![warn(missing_debug_implementations)]
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
mod codepoint_ids;
mod err;
mod font;
#[cfg(feature = "std")]
mod font_arc;
mod glyph;
#[cfg(all(feature = "libm", not(feature = "std")))]
mod nostd_float;
mod outlined;
mod scale;
mod ttfp;
#[cfg(feature = "variable-fonts")]
mod variable;
#[cfg(feature = "std")]
pub use crate::font_arc::*;
#[allow(deprecated)]
pub use crate::{
codepoint_ids::*,
err::*,
font::*,
glyph::*,
outlined::*,
scale::*,
ttfp::{FontRef, FontVec},
};
pub use ab_glyph_rasterizer::{point, Point};
#[cfg(feature = "variable-fonts")]
pub use variable::*;

View file

@ -0,0 +1,41 @@
/// Basic required float operations.
pub(crate) trait FloatExt {
fn floor(self) -> Self;
fn ceil(self) -> Self;
fn sqrt(self) -> Self;
fn round(self) -> Self;
fn abs(self) -> Self;
fn trunc(self) -> Self;
fn fract(self) -> Self;
}
impl FloatExt for f32 {
#[inline]
fn floor(self) -> Self {
libm::floorf(self)
}
#[inline]
fn ceil(self) -> Self {
libm::ceilf(self)
}
#[inline]
fn sqrt(self) -> Self {
libm::sqrtf(self)
}
#[inline]
fn round(self) -> Self {
libm::roundf(self)
}
#[inline]
fn abs(self) -> Self {
libm::fabsf(self)
}
#[inline]
fn trunc(self) -> Self {
libm::truncf(self)
}
#[inline]
fn fract(self) -> Self {
self - self.trunc()
}
}

View file

@ -0,0 +1,176 @@
#[cfg(all(feature = "libm", not(feature = "std")))]
use crate::nostd_float::FloatExt;
use crate::{point, Glyph, Point, PxScaleFactor};
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
/// A "raw" collection of outline curves for a glyph, unscaled & unpositioned.
#[derive(Clone, Debug)]
pub struct Outline {
/// Unscaled bounding box.
pub bounds: Rect,
/// Unscaled & unpositioned outline curves.
pub curves: Vec<OutlineCurve>,
}
impl Outline {
/// Convert unscaled bounds into pixel bounds at a given scale & position.
pub fn px_bounds(&self, scale_factor: PxScaleFactor, position: Point) -> Rect {
let Rect { min, max } = self.bounds;
// Use subpixel fraction in floor/ceil rounding to elimate rounding error
// from identical subpixel positions
let (x_trunc, x_fract) = (position.x.trunc(), position.x.fract());
let (y_trunc, y_fract) = (position.y.trunc(), position.y.fract());
Rect {
min: point(
(min.x * scale_factor.horizontal + x_fract).floor() + x_trunc,
(min.y * -scale_factor.vertical + y_fract).floor() + y_trunc,
),
max: point(
(max.x * scale_factor.horizontal + x_fract).ceil() + x_trunc,
(max.y * -scale_factor.vertical + y_fract).ceil() + y_trunc,
),
}
}
}
/// A glyph that has been outlined at a scale & position.
#[derive(Clone, Debug)]
pub struct OutlinedGlyph {
glyph: Glyph,
// Pixel scale bounds.
px_bounds: Rect,
// Scale factor
scale_factor: PxScaleFactor,
// Raw outline
outline: Outline,
}
impl OutlinedGlyph {
/// Constructs an `OutlinedGlyph` from the source `Glyph`, pixel bounds
/// & relatively positioned outline curves.
#[inline]
pub fn new(glyph: Glyph, outline: Outline, scale_factor: PxScaleFactor) -> Self {
// work this out now as it'll usually be used more than once
let px_bounds = outline.px_bounds(scale_factor, glyph.position);
Self {
glyph,
px_bounds,
scale_factor,
outline,
}
}
/// Glyph info.
#[inline]
pub fn glyph(&self) -> &Glyph {
&self.glyph
}
#[deprecated = "Renamed to `px_bounds`"]
#[doc(hidden)]
pub fn bounds(&self) -> Rect {
self.px_bounds()
}
/// Conservative whole number pixel bounding box for this glyph.
#[inline]
pub fn px_bounds(&self) -> Rect {
self.px_bounds
}
/// Draw this glyph outline using a pixel & coverage handling function.
///
/// The callback will be called for each `(x, y)` pixel coordinate inside the bounds
/// with a coverage value indicating how much the glyph covered that pixel.
///
/// A coverage value of `0.0` means the pixel is totally uncoverred by the glyph.
/// A value of `1.0` or greater means fully coverred.
pub fn draw<O: FnMut(u32, u32, f32)>(&self, o: O) {
use ab_glyph_rasterizer::Rasterizer;
let h_factor = self.scale_factor.horizontal;
let v_factor = -self.scale_factor.vertical;
let offset = self.glyph.position - self.px_bounds.min;
let (w, h) = (
self.px_bounds.width() as usize,
self.px_bounds.height() as usize,
);
let scale_up = |&Point { x, y }| point(x * h_factor, y * v_factor);
self.outline
.curves
.iter()
.fold(Rasterizer::new(w, h), |mut rasterizer, curve| match curve {
OutlineCurve::Line(p0, p1) => {
// eprintln!("r.draw_line({:?}, {:?});",
// scale_up(p0) + offset, scale_up(p1) + offset);
rasterizer.draw_line(scale_up(p0) + offset, scale_up(p1) + offset);
rasterizer
}
OutlineCurve::Quad(p0, p1, p2) => {
// eprintln!("r.draw_quad({:?}, {:?}, {:?});",
// scale_up(p0) + offset, scale_up(p1) + offset, scale_up(p2) + offset);
rasterizer.draw_quad(
scale_up(p0) + offset,
scale_up(p1) + offset,
scale_up(p2) + offset,
);
rasterizer
}
OutlineCurve::Cubic(p0, p1, p2, p3) => {
// eprintln!("r.draw_cubic({:?}, {:?}, {:?}, {:?});",
// scale_up(p0) + offset, scale_up(p1) + offset, scale_up(p2) + offset, scale_up(p3) + offset);
rasterizer.draw_cubic(
scale_up(p0) + offset,
scale_up(p1) + offset,
scale_up(p2) + offset,
scale_up(p3) + offset,
);
rasterizer
}
})
.for_each_pixel_2d(o);
}
}
impl AsRef<Glyph> for OutlinedGlyph {
#[inline]
fn as_ref(&self) -> &Glyph {
self.glyph()
}
}
/// Glyph outline primitives.
#[derive(Clone, Debug)]
pub enum OutlineCurve {
/// Straight line from `.0` to `.1`.
Line(Point, Point),
/// Quadratic Bézier curve from `.0` to `.2` using `.1` as the control.
Quad(Point, Point, Point),
/// Cubic Bézier curve from `.0` to `.3` using `.1` as the control at the beginning of the
/// curve and `.2` at the end of the curve.
Cubic(Point, Point, Point, Point),
}
/// A rectangle, with top-left corner at `min`, and bottom-right corner at `max`.
#[derive(Copy, Clone, Debug, Default, PartialEq, PartialOrd)]
pub struct Rect {
pub min: Point,
pub max: Point,
}
impl Rect {
#[inline]
pub fn width(&self) -> f32 {
self.max.x - self.min.x
}
#[inline]
pub fn height(&self) -> f32 {
self.max.y - self.min.y
}
}

270
third-party/vendor/ab_glyph/src/scale.rs vendored Normal file
View file

@ -0,0 +1,270 @@
#[cfg(all(feature = "libm", not(feature = "std")))]
use crate::nostd_float::FloatExt;
use crate::{Font, Glyph, GlyphId, OutlinedGlyph, Rect};
/// Pixel scale.
///
/// This is the pixel-height of text.
///
/// Usually one uses `x == y`, but one may use a different ratio to stretch a
/// font horizontally or vertically.
///
/// To convert pt size into pixel-scale see [`Font::pt_to_px_scale`].
///
/// # Example
/// ```
/// use ab_glyph::PxScale;
///
/// let uniform_scale_24px = PxScale::from(24.0);
/// ```
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct PxScale {
/// Horizontal scale in pixels.
pub x: f32,
/// Vertical scale in pixels.
///
/// By definition, this is the pixel-height of a font.
pub y: f32,
}
impl PxScale {
/// Returns a `PxScale` with both x & y scale values set to the nearest integer.
#[inline]
pub fn round(self) -> Self {
Self {
x: self.x.round(),
y: self.y.round(),
}
}
}
impl From<f32> for PxScale {
/// Uniform scaling where x & y are the same.
#[inline]
fn from(s: f32) -> Self {
PxScale { x: s, y: s }
}
}
/// 2D scale factors for use with unscaled metrics.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct PxScaleFactor {
pub horizontal: f32,
pub vertical: f32,
}
/// A [`Font`](trait.Font.html) with an associated pixel scale. This can be used to provide
/// pixel scale values for glyph advances, heights etc.
///
/// # Example
/// ```
/// use ab_glyph::{Font, FontRef, PxScale, ScaleFont};
///
/// # fn main() -> Result<(), ab_glyph::InvalidFont> {
/// let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf"))?;
///
/// // Associate the font with a scale of 45px
/// let scaled_font = font.as_scaled(PxScale::from(45.0));
///
/// assert_eq!(scaled_font.height(), 45.0);
/// assert_eq!(scaled_font.h_advance(scaled_font.glyph_id('b')), 21.225);
///
/// // Replace associated scale with another
/// let scaled_font = scaled_font.with_scale(180.0);
///
/// assert_eq!(scaled_font.height(), 180.0);
/// assert_eq!(scaled_font.h_advance(scaled_font.glyph_id('b')), 84.9);
/// # Ok(()) }
/// ```
pub trait ScaleFont<F: Font> {
/// Returns the pixel scale associated with this font.
fn scale(&self) -> PxScale;
/// Returns a font reference.
fn font(&self) -> &F;
/// Scale factor for unscaled font horizontal values.
#[inline]
fn h_scale_factor(&self) -> f32 {
self.scale().x / self.font().height_unscaled()
}
/// Scale factor for unscaled font vertical values.
#[inline]
fn v_scale_factor(&self) -> f32 {
self.scale().y / self.font().height_unscaled()
}
#[inline]
fn scale_factor(&self) -> PxScaleFactor {
PxScaleFactor {
horizontal: self.h_scale_factor(),
vertical: self.v_scale_factor(),
}
}
/// Pixel scaled glyph ascent.
#[inline]
fn ascent(&self) -> f32 {
self.v_scale_factor() * self.font().ascent_unscaled()
}
/// Pixel scaled glyph descent.
#[inline]
fn descent(&self) -> f32 {
self.v_scale_factor() * self.font().descent_unscaled()
}
/// Pixel scaled height `ascent - descent`.
///
/// By definition of [`PxScale`], this is `self.scale().y`.
#[inline]
fn height(&self) -> f32 {
self.scale().y
}
/// Pixel scaled line gap.
#[inline]
fn line_gap(&self) -> f32 {
self.v_scale_factor() * self.font().line_gap_unscaled()
}
/// Lookup a `GlyphId` matching a given `char`.
#[inline]
fn glyph_id(&self, c: char) -> GlyphId {
self.font().glyph_id(c)
}
/// Construct a [`Glyph`](struct.Glyph.html) with the font's pixel scale at
/// position `point(0.0, 0.0)`.
///
/// # Example
/// ```
/// # use ab_glyph::*;
/// # let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf")).unwrap();
/// let scaled_font = font.as_scaled(50.0);
///
/// let a1 = scaled_font.scaled_glyph('a');
/// let a2 = font.glyph_id('a').with_scale(50.0); // equivalent
///
/// # assert_eq!(a1.id, a2.id);
/// assert_eq!(a1.scale, PxScale::from(50.0));
/// assert_eq!(a1.position, point(0.0, 0.0));
/// ```
#[inline]
fn scaled_glyph(&self, c: char) -> Glyph {
self.font().glyph_id(c).with_scale(self.scale())
}
/// Pixel scaled horizontal advance for a given glyph.
#[inline]
fn h_advance(&self, id: GlyphId) -> f32 {
self.h_scale_factor() * self.font().h_advance_unscaled(id)
}
/// Pixel scaled horizontal side bearing for a given glyph.
#[inline]
fn h_side_bearing(&self, id: GlyphId) -> f32 {
self.h_scale_factor() * self.font().h_side_bearing_unscaled(id)
}
/// Pixel scaled vertical advance for a given glyph.
#[inline]
fn v_advance(&self, id: GlyphId) -> f32 {
self.v_scale_factor() * self.font().v_advance_unscaled(id)
}
/// Pixel scaled vertical side bearing for a given glyph.
#[inline]
fn v_side_bearing(&self, id: GlyphId) -> f32 {
self.v_scale_factor() * self.font().v_side_bearing_unscaled(id)
}
/// Returns additional pixel scaled kerning to apply for a particular pair of glyphs.
#[inline]
fn kern(&self, first: GlyphId, second: GlyphId) -> f32 {
self.h_scale_factor() * self.font().kern_unscaled(first, second)
}
/// Returns the layout bounds of this glyph. These are different to the outline `px_bounds()`.
///
/// Horizontally: Glyph position +/- h_advance/h_side_bearing.
/// Vertically: Glyph position +/- ascent/descent.
///
/// Note this method does not make use of the associated scale, as `Glyph`
/// already includes one of it's own.
#[inline]
fn glyph_bounds(&self, glyph: &Glyph) -> Rect {
self.font().glyph_bounds(glyph)
}
/// The number of glyphs present in this font. Glyph identifiers for this
/// font will always be in the range `0..self.glyph_count()`
#[inline]
fn glyph_count(&self) -> usize {
self.font().glyph_count()
}
/// Returns an iterator of all distinct `(GlyphId, char)` pairs. Not ordered.
///
/// Same as [`Font::codepoint_ids`](trait.Font.html#tymethod.codepoint_ids).
fn codepoint_ids(&self) -> crate::CodepointIdIter<'_>;
/// Compute glyph outline ready for drawing.
///
/// Note this method does not make use of the associated scale, as `Glyph`
/// already includes one of it's own.
#[inline]
fn outline_glyph(&self, glyph: Glyph) -> Option<OutlinedGlyph> {
self.font().outline_glyph(glyph)
}
}
impl<F: Font, SF: ScaleFont<F>> ScaleFont<F> for &SF {
#[inline]
fn scale(&self) -> PxScale {
(*self).scale()
}
#[inline]
fn font(&self) -> &F {
(*self).font()
}
#[inline]
fn codepoint_ids(&self) -> crate::CodepointIdIter<'_> {
(*self).codepoint_ids()
}
}
/// A [`Font`](trait.Font.html) and an associated pixel scale.
#[derive(Clone, Copy, Debug)]
pub struct PxScaleFont<F> {
pub font: F,
pub scale: PxScale,
}
impl<F> PxScaleFont<F> {
#[inline]
pub fn with_scale<S: Into<PxScale>>(mut self, scale: S) -> Self {
self.scale = scale.into();
self
}
}
impl<F: Font> ScaleFont<F> for PxScaleFont<F> {
#[inline]
fn scale(&self) -> PxScale {
self.scale
}
#[inline]
fn font(&self) -> &F {
&self.font
}
#[inline]
fn codepoint_ids(&self) -> crate::CodepointIdIter<'_> {
self.font.codepoint_ids()
}
}

349
third-party/vendor/ab_glyph/src/ttfp.rs vendored Normal file
View file

@ -0,0 +1,349 @@
//! ttf-parser crate specific code. ttf-parser types should not be leaked publicly.
mod outliner;
#[cfg(feature = "variable-fonts")]
mod variable;
use crate::{point, v2, Font, GlyphId, GlyphImageFormat, InvalidFont, Outline, Rect};
use alloc::boxed::Box;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use core::fmt;
use owned_ttf_parser::{self as ttfp, AsFaceRef};
impl From<GlyphId> for ttfp::GlyphId {
#[inline]
fn from(id: GlyphId) -> Self {
Self(id.0)
}
}
/// Font data handle stored as a `&[u8]` + parsed data.
/// See [`Font`](trait.Font.html) for more methods.
///
/// Also see the owned version [`FontVec`](struct.FontVec.html).
///
/// # Example
/// ```
/// use ab_glyph::{Font, FontRef};
///
/// # fn main() -> Result<(), ab_glyph::InvalidFont> {
/// let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf"))?;
///
/// assert_eq!(font.glyph_id('s'), ab_glyph::GlyphId(56));
/// # Ok(()) }
/// ```
#[derive(Clone)]
pub struct FontRef<'font>(ttfp::PreParsedSubtables<'font, ttfp::Face<'font>>);
impl fmt::Debug for FontRef<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "FontRef")
}
}
impl<'font> FontRef<'font> {
/// Creates an `FontRef` from a byte-slice.
///
/// For font collections see
/// [`FontRef::try_from_slice_and_index`](#method.try_from_slice_and_index).
///
/// # Example
/// ```
/// # use ab_glyph::*;
/// # fn main() -> Result<(), InvalidFont> {
/// let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf"))?;
/// # Ok(()) }
/// ```
#[inline]
pub fn try_from_slice(data: &'font [u8]) -> Result<Self, InvalidFont> {
Self::try_from_slice_and_index(data, 0)
}
/// Creates an `FontRef` from byte-slice.
///
/// You can set index for font collections. For simple fonts use `0` or
/// [`FontRef::try_from_slice`](#method.try_from_slice).
///
/// # Example
/// ```
/// # use ab_glyph::*;
/// # fn main() -> Result<(), InvalidFont> {
/// let font =
/// FontRef::try_from_slice_and_index(include_bytes!("../../dev/fonts/Exo2-Light.otf"), 0)?;
/// # Ok(()) }
/// ```
#[inline]
pub fn try_from_slice_and_index(data: &'font [u8], index: u32) -> Result<Self, InvalidFont> {
Ok(Self(ttfp::PreParsedSubtables::from(
ttfp::Face::parse(data, index).map_err(|_| InvalidFont)?,
)))
}
}
/// Font data handle stored in a `Vec<u8>` + parsed data.
/// See [`Font`](trait.Font.html) for more methods.
///
/// Also see [`FontRef`](struct.FontRef.html).
///
/// # Example
/// ```
/// use ab_glyph::{Font, FontVec};
///
/// # fn main() -> Result<(), ab_glyph::InvalidFont> {
/// # let owned_font_data = include_bytes!("../../dev/fonts/Exo2-Light.otf").to_vec();
/// let font = FontVec::try_from_vec_and_index(owned_font_data, 0)?;
///
/// assert_eq!(font.glyph_id('s'), ab_glyph::GlyphId(56));
/// # Ok(()) }
/// ```
pub struct FontVec(ttfp::PreParsedSubtables<'static, ttfp::OwnedFace>);
impl fmt::Debug for FontVec {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "FontVec")
}
}
impl FontVec {
/// Creates an `FontVec` from owned data.
///
/// For font collections see
/// [`FontVec::try_from_vec_and_index`](#method.try_from_vec_and_index).
///
/// # Example
/// ```
/// # use ab_glyph::*;
/// # fn main() -> Result<(), InvalidFont> {
/// # let owned_font_data = include_bytes!("../../dev/fonts/Exo2-Light.otf").to_vec();
/// let font = FontVec::try_from_vec(owned_font_data)?;
/// # Ok(()) }
/// ```
#[inline]
pub fn try_from_vec(data: Vec<u8>) -> Result<Self, InvalidFont> {
Self::try_from_vec_and_index(data, 0)
}
/// Creates an `FontVec` from owned data.
///
/// You can set index for font collections. For simple fonts use `0` or
/// [`FontVec::try_from_vec`](#method.try_from_vec).
///
/// # Example
/// ```
/// # use ab_glyph::*;
/// # fn main() -> Result<(), InvalidFont> {
/// # let owned_font_data = include_bytes!("../../dev/fonts/Exo2-Light.otf").to_vec();
/// let font = FontVec::try_from_vec_and_index(owned_font_data, 0)?;
/// # Ok(()) }
/// ```
#[inline]
pub fn try_from_vec_and_index(data: Vec<u8>, index: u32) -> Result<Self, InvalidFont> {
Ok(Self(ttfp::PreParsedSubtables::from(
ttfp::OwnedFace::from_vec(data, index).map_err(|_| InvalidFont)?,
)))
}
/// Extracts a slice containing the data passed into e.g. [`FontVec::try_from_vec`].
///
/// # Example
/// ```
/// # use ab_glyph::*;
/// # fn main() -> Result<(), InvalidFont> {
/// # let owned_font_data = include_bytes!("../../dev/fonts/Exo2-Light.otf").to_vec();
/// let font_data_clone = owned_font_data.clone();
/// let font = FontVec::try_from_vec(owned_font_data)?;
/// assert_eq!(font.as_slice(), font_data_clone);
/// # Ok(()) }
/// ```
#[inline]
pub fn as_slice(&self) -> &[u8] {
self.0.face.as_slice()
}
/// Unwraps the data passed into e.g. [`FontVec::try_from_vec`].
///
/// # Example
/// ```
/// # use ab_glyph::*;
/// # fn main() -> Result<(), InvalidFont> {
/// # let owned_font_data = include_bytes!("../../dev/fonts/Exo2-Light.otf").to_vec();
/// let font_data_clone = owned_font_data.clone();
/// let font = FontVec::try_from_vec(owned_font_data)?;
/// assert_eq!(font.into_vec(), font_data_clone);
/// # Ok(()) }
/// ```
pub fn into_vec(self) -> Vec<u8> {
self.0.face.into_vec()
}
}
/// Implement `Font` for `Self(AsFontRef)` types.
macro_rules! impl_font {
($font:ty) => {
impl Font for $font {
#[inline]
fn units_per_em(&self) -> Option<f32> {
// TODO unwrap signature when making next breaking change
Some(self.0.as_face_ref().units_per_em().into())
}
#[inline]
fn ascent_unscaled(&self) -> f32 {
self.0.as_face_ref().ascender().into()
}
#[inline]
fn descent_unscaled(&self) -> f32 {
self.0.as_face_ref().descender().into()
}
#[inline]
fn line_gap_unscaled(&self) -> f32 {
self.0.as_face_ref().line_gap().into()
}
#[inline]
fn glyph_id(&self, c: char) -> GlyphId {
// Note: Using `PreParsedSubtables` method for better performance.
let index = self.0.glyph_index(c).map(|id| id.0).unwrap_or(0);
GlyphId(index)
}
#[inline]
fn h_advance_unscaled(&self, id: GlyphId) -> f32 {
self.0
.as_face_ref()
.glyph_hor_advance(id.into())
.unwrap_or_default()
.into()
}
#[inline]
fn h_side_bearing_unscaled(&self, id: GlyphId) -> f32 {
self.0
.as_face_ref()
.glyph_hor_side_bearing(id.into())
.unwrap_or_default()
.into()
}
#[inline]
fn v_advance_unscaled(&self, id: GlyphId) -> f32 {
self.0
.as_face_ref()
.glyph_ver_advance(id.into())
.unwrap_or_default()
.into()
}
#[inline]
fn v_side_bearing_unscaled(&self, id: GlyphId) -> f32 {
self.0
.as_face_ref()
.glyph_ver_side_bearing(id.into())
.unwrap_or_default()
.into()
}
#[inline]
fn kern_unscaled(&self, first: GlyphId, second: GlyphId) -> f32 {
// Note: Using `PreParsedSubtables` method for better performance.
self.0
.glyphs_hor_kerning(first.into(), second.into())
.map(f32::from)
.unwrap_or_default()
}
fn outline(&self, id: GlyphId) -> Option<Outline> {
let mut outliner = outliner::OutlineCurveBuilder::default();
let ttfp::Rect {
x_min,
x_max,
y_min,
y_max,
} = self
.0
.as_face_ref()
.outline_glyph(id.into(), &mut outliner)
// invalid bounds are treated as having no outline
.filter(|b| b.x_min < b.x_max && b.y_min < b.y_max)?;
let curves = outliner.take_outline();
let bounds = Rect {
min: point(x_min.into(), y_max.into()),
max: point(x_max.into(), y_min.into()),
};
Some(Outline { bounds, curves })
}
#[inline]
fn glyph_count(&self) -> usize {
self.0.as_face_ref().number_of_glyphs() as _
}
fn codepoint_ids(&self) -> crate::CodepointIdIter<'_> {
let face_ref = self.0.as_face_ref();
#[cfg(feature = "std")]
let mut used_indices =
std::collections::HashSet::with_capacity(face_ref.number_of_glyphs() as _);
#[cfg(not(feature = "std"))]
let mut used_indices = alloc::collections::BTreeSet::new();
let inner = Box::new(
face_ref
.tables()
.cmap
.iter()
.flat_map(|c| c.subtables)
.filter(|s| s.is_unicode())
.flat_map(move |subtable| {
let mut pairs = Vec::new();
subtable.codepoints(|c| {
if let Ok(ch) = char::try_from(c) {
if let Some(idx) = subtable.glyph_index(c).filter(|i| i.0 > 0) {
if used_indices.insert(idx.0) {
pairs.push((GlyphId(idx.0), ch));
}
}
}
});
pairs
}),
);
crate::CodepointIdIter { inner }
}
fn glyph_raster_image2(&self, id: GlyphId, size: u16) -> Option<v2::GlyphImage> {
use GlyphImageFormat::*;
let img = self.0.as_face_ref().glyph_raster_image(id.into(), size)?;
Some(v2::GlyphImage {
origin: point(img.x.into(), img.y.into()),
width: img.width,
height: img.height,
pixels_per_em: img.pixels_per_em,
data: img.data,
format: match img.format {
ttfp::RasterImageFormat::PNG => Png,
ttfp::RasterImageFormat::BitmapMono => BitmapMono,
ttfp::RasterImageFormat::BitmapMonoPacked => BitmapMonoPacked,
ttfp::RasterImageFormat::BitmapGray2 => BitmapGray2,
ttfp::RasterImageFormat::BitmapGray2Packed => BitmapGray2Packed,
ttfp::RasterImageFormat::BitmapGray4 => BitmapGray4,
ttfp::RasterImageFormat::BitmapGray4Packed => BitmapGray4Packed,
ttfp::RasterImageFormat::BitmapGray8 => BitmapGray8,
ttfp::RasterImageFormat::BitmapPremulBgra32 => BitmapPremulBgra32,
},
})
}
}
};
}
impl_font!(FontRef<'_>);
impl_font!(FontVec);

View file

@ -0,0 +1,65 @@
use crate::{point, OutlineCurve, Point};
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
#[derive(Debug, Default)]
pub(crate) struct OutlineCurveBuilder {
last: Point,
last_move: Option<Point>,
outline: Vec<OutlineCurve>,
}
impl OutlineCurveBuilder {
#[inline]
pub(crate) fn take_outline(mut self) -> Vec<OutlineCurve> {
// some font glyphs implicitly close, e.g. Cantarell-VF.otf
owned_ttf_parser::OutlineBuilder::close(&mut self);
self.outline
}
}
impl owned_ttf_parser::OutlineBuilder for OutlineCurveBuilder {
#[inline]
fn move_to(&mut self, x: f32, y: f32) {
// eprintln!("M {x} {y}");
self.last = point(x, y);
self.last_move = Some(self.last);
}
#[inline]
fn line_to(&mut self, x1: f32, y1: f32) {
// eprintln!("L {x1} {y1}");
let p1 = point(x1, y1);
self.outline.push(OutlineCurve::Line(self.last, p1));
self.last = p1;
}
#[inline]
fn quad_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32) {
// eprintln!("Q {x1} {y1}");
let p1 = point(x1, y1);
let p2 = point(x2, y2);
self.outline.push(OutlineCurve::Quad(self.last, p1, p2));
self.last = p2;
}
#[inline]
fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x3: f32, y3: f32) {
// eprintln!("C {x1} {y1} {x3} {y3}");
let p1 = point(x1, y1);
let p2 = point(x2, y2);
let p3 = point(x3, y3);
self.outline
.push(OutlineCurve::Cubic(self.last, p1, p2, p3));
self.last = p3;
}
#[inline]
fn close(&mut self) {
// eprintln!("Z");
if let Some(m) = self.last_move.take() {
self.outline.push(OutlineCurve::Line(self.last, m));
}
}
}

View file

@ -0,0 +1,63 @@
use crate::{FontRef, FontVec, VariableFont, VariationAxis};
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use owned_ttf_parser::{self as ttfp, AsFaceRef, FaceMut};
impl VariableFont for FontRef<'_> {
fn set_variation(&mut self, axis: &[u8; 4], value: f32) -> bool {
let tag = ttfp::Tag::from_bytes(axis);
// TODO remove existence check in next breaking version
let exists = self
.0
.as_face_ref()
.variation_axes()
.into_iter()
.any(|axis| axis.tag == tag);
if exists {
self.0.set_variation(tag, value);
}
exists
}
fn variations(&self) -> Vec<VariationAxis> {
variations(self.0.as_face_ref())
}
}
impl VariableFont for FontVec {
fn set_variation(&mut self, axis: &[u8; 4], value: f32) -> bool {
self.0
.set_variation(ttfp::Tag::from_bytes(axis), value)
.is_some()
}
fn variations(&self) -> Vec<VariationAxis> {
variations(self.0.as_face_ref())
}
}
fn variations(face: &ttfp::Face<'_>) -> Vec<VariationAxis> {
face.variation_axes()
.into_iter()
.map(|axis| {
#[cfg(feature = "std")]
let name = face.names().into_iter().find_map(|n| {
if n.name_id == axis.name_id {
n.to_string()
} else {
None
}
});
#[cfg(not(feature = "std"))]
let name = None;
VariationAxis {
tag: axis.tag.to_bytes(),
name,
min_value: axis.min_value,
default_value: axis.def_value,
max_value: axis.max_value,
hidden: axis.hidden,
}
})
.collect()
}

View file

@ -0,0 +1,67 @@
#[cfg(not(feature = "std"))]
use alloc::string::String;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
/// Logic for variable fonts.
///
/// Requires feature `variable-fonts` (enabled by default).
pub trait VariableFont {
/// Sets a variation axis coordinate value by it's tag.
///
/// Returns false if there is no such axis tag.
///
/// # Example
/// ```
/// use ab_glyph::{FontRef, VariableFont};
///
/// # fn main() -> Result<(), ab_glyph::InvalidFont> {
/// let mut font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Cantarell-VF.otf"))?;
///
/// // set weight to 600
/// assert!(font.set_variation(b"wght", 600.0));
///
/// // no such variation tag "foob" so return false
/// assert!(!font.set_variation(b"foob", 200.0));
/// # Ok(()) }
/// ```
fn set_variation(&mut self, tag: &[u8; 4], value: f32) -> bool;
/// Returns variation axes.
///
/// # Example
/// ```
/// use ab_glyph::{FontRef, VariableFont};
///
/// # fn main() -> Result<(), ab_glyph::InvalidFont> {
/// let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Cantarell-VF.otf"))?;
/// let var = &font.variations()[0];
/// # eprintln!("{var:#?}");
///
/// assert_eq!(var.tag, *b"wght");
/// assert_eq!(var.name.as_deref(), Some("Weight"));
/// assert!((var.min_value - 100.0).abs() < f32::EPSILON);
/// assert!((var.default_value - 400.0).abs() < f32::EPSILON);
/// assert!((var.max_value - 800.0).abs() < f32::EPSILON);
/// assert!(!var.hidden);
/// # Ok(()) }
/// ```
fn variations(&self) -> Vec<VariationAxis>;
}
#[non_exhaustive]
#[derive(Debug, Clone)]
pub struct VariationAxis {
/// Tag identifying the design variation for the axis.
pub tag: [u8; 4],
/// Unicode name.
pub name: Option<String>,
/// The minimum coordinate value for the axis.
pub min_value: f32,
/// The default coordinate value for the axis.
pub default_value: f32,
/// The maximum coordinate value for the axis.
pub max_value: f32,
/// Whether the axis should be exposed directly in user interfaces.
pub hidden: bool,
}