Commit bd39a388 authored by Alex Butler's avatar Alex Butler

Merge branch 'owned-ttf-parser' into 'master'

Use owned_ttf_parser crate

See merge request !154
parents efd3797f 57e5029b
Pipeline #7375 passed with stages
in 4 minutes and 32 seconds
## Unreleased
* Use crate owned_ttf_parser to provide `OwnedFont` eliminating direct unsafe usage in rusttype.
* Remove unused legacy trait `BoundingBox`.
* Add `ScaledGlyph::build_outline` & `PositionedGlyph::build_outline` methods.
## 0.9.0
* Major rework to use crates **ttf-parser** & **ab_glyph_rasterizer** to respectively read and render OpenType .oft format fonts.
* Remove dependencies **approx**, **stb_truetype** & **ordered-float** along with in-crate rasterization code.
......
......@@ -26,7 +26,7 @@ exclude = ["/dev/**"]
features = ["gpu_cache"]
[dependencies]
ttf-parser = { version = "0.5", default-features = false }
owned_ttf_parser = { version = "0.5.1", default-features = false }
ab_glyph_rasterizer = { version = "0.1.1", default-features = false }
libm = { version = "0.2.1", default-features = false, optional = true }
......@@ -46,7 +46,7 @@ approx = { version = "0.3", default-features = false }
[features]
default = ["std"]
# Activates usage of std.
std = ["has-atomics", "ttf-parser/default", "ab_glyph_rasterizer/default"]
std = ["has-atomics", "owned_ttf_parser/default", "ab_glyph_rasterizer/default"]
# Uses libm when not using std. This needs to be active in that case.
libm-math = ["libm", "ab_glyph_rasterizer/libm"]
# Some targets don't have atomics, this activates usage of Arc<T> instead of Rc<T>.
......
use crate::{Glyph, GlyphIter, IntoGlyphId, LayoutIter, Point, Scale, VMetrics};
use core::fmt;
#[cfg(not(feature = "has-atomics"))]
use alloc::rc::Rc as Arc;
#[cfg(feature = "has-atomics")]
use alloc::sync::Arc;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use core::fmt;
/// A single font. This may or may not own the font data.
///
......@@ -28,7 +29,7 @@ use alloc::sync::Arc;
/// ```
#[derive(Clone)]
pub enum Font<'a> {
Ref(Arc<ttf_parser::Font<'a>>),
Ref(Arc<owned_ttf_parser::Font<'a>>),
Owned(Arc<owned_ttf_parser::OwnedFont>),
}
......@@ -50,17 +51,33 @@ impl Font<'_> {
///
/// Returns `None` for invalid data.
pub fn try_from_bytes_and_index(bytes: &[u8], index: u32) -> Option<Font<'_>> {
let inner = Arc::new(ttf_parser::Font::from_data(bytes, index)?);
let inner = Arc::new(owned_ttf_parser::Font::from_data(bytes, index)?);
Some(Font::Ref(inner))
}
/// Creates a Font from owned font data.
///
/// Returns `None` for invalid data.
pub fn try_from_vec(data: Vec<u8>) -> Option<Font<'static>> {
Self::try_from_vec_and_index(data, 0)
}
/// Creates a Font from owned font data & a font collection `index`.
///
/// Returns `None` for invalid data.
pub fn try_from_vec_and_index(data: Vec<u8>, index: u32) -> Option<Font<'static>> {
let inner = Arc::new(owned_ttf_parser::OwnedFont::from_vec(data, index)?);
Some(Font::Owned(inner))
}
}
impl<'font> Font<'font> {
#[inline]
pub(crate) fn inner(&self) -> &ttf_parser::Font<'_> {
pub(crate) fn inner(&self) -> &owned_ttf_parser::Font<'_> {
use owned_ttf_parser::AsFontRef;
match self {
Self::Ref(f) => f,
Self::Owned(f) => f.inner_ref(),
Self::Owned(f) => f.as_font(),
}
}
......@@ -219,72 +236,3 @@ impl<'font> Font<'font> {
height / fheight
}
}
/// Functionality to allow owned font data using ttf-parser.
///
/// This requires _unsafe_ usage to implement pinned self referencing, as
/// ttf-parser does not currently support owned data directly.
mod owned_ttf_parser {
use super::{Arc, Font};
#[cfg(not(feature = "std"))]
use alloc::{boxed::Box, vec::Vec};
use core::marker::PhantomPinned;
use core::pin::Pin;
use core::slice;
pub type OwnedFont = Pin<Box<VecFont>>;
impl Font<'_> {
/// Creates a Font from owned font data.
///
/// Returns `None` for invalid data.
pub fn try_from_vec(data: Vec<u8>) -> Option<Font<'static>> {
Self::try_from_vec_and_index(data, 0)
}
/// Creates a Font from owned font data & a font collection `index`.
///
/// Returns `None` for invalid data.
pub fn try_from_vec_and_index(data: Vec<u8>, index: u32) -> Option<Font<'static>> {
let inner = VecFont::try_from_vec(data, index)?;
Some(Font::Owned(inner))
}
}
pub struct VecFont {
data: Vec<u8>,
font: Option<ttf_parser::Font<'static>>,
_pin: PhantomPinned,
}
impl VecFont {
/// Creates an underlying font object from owned data.
pub fn try_from_vec(data: Vec<u8>, index: u32) -> Option<Arc<Pin<Box<Self>>>> {
let font = Self {
data,
font: None,
_pin: PhantomPinned,
};
let mut b = Box::pin(font);
unsafe {
// 'static lifetime is a lie, this data is owned, it has pseudo-self lifetime.
let slice: &'static [u8] = slice::from_raw_parts(b.data.as_ptr(), b.data.len());
let mut_ref: Pin<&mut Self> = Pin::as_mut(&mut b);
let mut_inner = mut_ref.get_unchecked_mut();
mut_inner.font = Some(ttf_parser::Font::from_data(slice, index)?);
}
Some(Arc::new(b))
}
// Must not leak the fake 'static lifetime that we lied about earlier to the
// compiler. Since the lifetime 'a will not outlive our owned data it's
// safe to provide Font<'a>
#[inline]
pub fn inner_ref<'a>(self: &'a Pin<Box<Self>>) -> &'a ttf_parser::Font<'a> {
match self.font.as_ref() {
Some(f) => f,
None => unsafe { core::hint::unreachable_unchecked() },
}
}
}
}
......@@ -156,16 +156,3 @@ impl<N: ops::Sub<Output = N> + Copy> Rect<N> {
self.max.y - self.min.y
}
}
pub trait BoundingBox<N> {
fn bounding_box(&self) -> Rect<N> {
let (min_x, max_x) = self.x_bounds();
let (min_y, max_y) = self.y_bounds();
Rect {
min: point(min_x, min_y),
max: point(max_x, max_y),
}
}
fn x_bounds(&self) -> (N, N);
fn y_bounds(&self) -> (N, N);
}
......@@ -115,17 +115,17 @@ use core::fmt;
#[cfg(all(feature = "libm-math", not(feature = "std")))]
use crate::nostd_float::FloatExt;
pub use ttf_parser::OutlineBuilder;
pub use owned_ttf_parser::OutlineBuilder;
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct GlyphId(pub u16);
impl From<ttf_parser::GlyphId> for GlyphId {
fn from(id: ttf_parser::GlyphId) -> Self {
impl From<owned_ttf_parser::GlyphId> for GlyphId {
fn from(id: owned_ttf_parser::GlyphId) -> Self {
Self(id.0)
}
}
impl From<GlyphId> for ttf_parser::GlyphId {
impl From<GlyphId> for owned_ttf_parser::GlyphId {
fn from(id: GlyphId) -> Self {
Self(id.0)
}
......@@ -244,8 +244,8 @@ impl<'font> ScaledGlyph<'font> {
&self.g
}
/// Builds the outline of the glyph with the builder specified. Returns `false` when the
/// outline is either malformed or empty.
/// Builds the outline of the glyph with the builder specified. Returns
/// `false` when the outline is either malformed or empty.
pub fn build_outline(&self, builder: &mut impl OutlineBuilder) -> bool {
let mut outliner =
crate::outliner::OutlineScaler::new(builder, vector(self.scale.x, -self.scale.y));
......@@ -290,7 +290,7 @@ impl<'font> ScaledGlyph<'font> {
/// `pixel_bounding_box`, the conservative pixel-boundary bounding box. The
/// coordinates are relative to the glyph's origin.
pub fn exact_bounding_box(&self) -> Option<Rect<f32>> {
let ttf_parser::Rect {
let owned_ttf_parser::Rect {
x_min,
y_min,
x_max,
......@@ -309,7 +309,7 @@ impl<'font> ScaledGlyph<'font> {
shift_x: f32,
shift_y: f32,
) -> Option<Rect<i32>> {
let ttf_parser::Rect {
let owned_ttf_parser::Rect {
x_min,
y_min,
x_max,
......@@ -400,8 +400,8 @@ impl<'font> PositionedGlyph<'font> {
self.position
}
/// Builds the outline of the glyph with the builder specified. Returns `false` when the
/// outline is either malformed or empty.
/// Builds the outline of the glyph with the builder specified. Returns
/// `false` when the outline is either malformed or empty.
pub fn build_outline(&self, builder: &mut impl OutlineBuilder) -> bool {
let bb = if let Some(bb) = self.bb.as_ref() {
bb
......@@ -516,7 +516,7 @@ impl IntoGlyphId for char {
fn into_glyph_id(self, font: &Font<'_>) -> GlyphId {
font.inner()
.glyph_index(self)
.unwrap_or(ttf_parser::GlyphId(0))
.unwrap_or(owned_ttf_parser::GlyphId(0))
.into()
}
}
......
use crate::{Point, Vector};
use ab_glyph_rasterizer::{point as ab_point, Point as AbPoint, Rasterizer};
use ttf_parser::OutlineBuilder;
use owned_ttf_parser::OutlineBuilder;
pub(crate) struct OutlineScaler<'b, T: ?Sized> {
inner: &'b mut T,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment