Commit 9d339450 authored by Christopher Serr's avatar Christopher Serr
Browse files

Implement Support for building outlines

This brings back support for building outlines, which disappeared in
rusttype 0.9.
parent c8ab1842
......@@ -115,6 +115,8 @@ use core::fmt;
#[cfg(all(feature = "libm-math", not(feature = "std")))]
use crate::nostd_float::FloatExt;
pub use ttf_parser::OutlineBuilder;
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct GlyphId(pub u16);
......@@ -242,6 +244,18 @@ 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.
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));
self.font()
.inner()
.outline_glyph(self.id().into(), &mut outliner)
.is_some()
}
/// Augments this glyph with positioning information, making methods that
/// depend on the position of the glyph available.
pub fn positioned(self, p: Point<f32>) -> PositionedGlyph<'font> {
......@@ -316,7 +330,7 @@ impl<'font> ScaledGlyph<'font> {
#[inline]
fn pixel_bounds_at(&self, p: Point<f32>) -> Option<Rect<i32>> {
// Use subpixel fraction in floor/ceil rounding to elimate rounding error
// Use subpixel fraction in floor/ceil rounding to eliminate rounding error
// from identical subpixel positions
let (x_trunc, x_fract) = (p.x.trunc() as i32, p.x.fract());
let (y_trunc, y_fract) = (p.y.trunc() as i32, p.y.fract());
......@@ -386,6 +400,22 @@ 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.
pub fn build_outline(&self, builder: &mut impl OutlineBuilder) -> bool {
let bb = if let Some(bb) = self.bb.as_ref() {
bb
} else {
return false;
};
let offset = vector(bb.min.x as f32, bb.min.y as f32);
let mut outliner = crate::outliner::OutlineTranslator::new(builder, self.position - offset);
self.sg.build_outline(&mut outliner)
}
/// Rasterises this glyph. For each pixel in the rect given by
/// `pixel_bounding_box()`, `o` is called:
///
......@@ -416,18 +446,9 @@ impl<'font> PositionedGlyph<'font> {
let width = (bb.max.x - bb.min.x) as u32;
let height = (bb.max.y - bb.min.y) as u32;
let offset = vector(bb.min.x as f32, bb.min.y as f32);
let mut outliner = crate::outliner::OutlineRasterizer::new(
self.position - offset,
self.sg.scale,
width as _,
height as _,
);
let mut outliner = crate::outliner::OutlineRasterizer::new(width as _, height as _);
self.font()
.inner()
.outline_glyph(self.id().into(), &mut outliner);
self.build_outline(&mut outliner);
outliner.rasterizer.for_each_pixel_2d(o);
}
......@@ -459,7 +480,7 @@ impl fmt::Debug for PositionedGlyph<'_> {
}
/// Defines the size of a rendered face of a font, in pixels, horizontally and
/// vertically. A vertical scale of `y` pixels means that the distance betwen
/// vertically. A vertical scale of `y` pixels means that the distance between
/// the ascent and descent lines (see `VMetrics`) of the face will be `y`
/// pixels. If `x` and `y` are equal the scaling is uniform. Non-uniform scaling
/// by a factor *f* in the horizontal direction is achieved by setting `x` equal
......
use crate::{Point, Vector};
use ab_glyph_rasterizer::{point as ab_point, Point as AbPoint, Rasterizer};
use ttf_parser::OutlineBuilder;
pub(crate) struct OutlineScaler<'b, T: ?Sized> {
inner: &'b mut T,
scale: Vector<f32>,
}
impl<'b, T: ?Sized> OutlineScaler<'b, T> {
pub(crate) fn new(inner: &'b mut T, scale: Vector<f32>) -> Self {
Self { inner, scale }
}
}
impl<T: OutlineBuilder + ?Sized> OutlineBuilder for OutlineScaler<'_, T> {
fn move_to(&mut self, x: f32, y: f32) {
self.inner.move_to(x * self.scale.x, y * self.scale.y)
}
fn line_to(&mut self, x1: f32, y1: f32) {
self.inner.line_to(x1 * self.scale.x, y1 * self.scale.y)
}
fn quad_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32) {
self.inner.quad_to(
x1 * self.scale.x,
y1 * self.scale.y,
x2 * self.scale.x,
y2 * self.scale.y,
)
}
fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x3: f32, y3: f32) {
self.inner.curve_to(
x1 * self.scale.x,
y1 * self.scale.y,
x2 * self.scale.x,
y2 * self.scale.y,
x3 * self.scale.x,
y3 * self.scale.y,
)
}
fn close(&mut self) {
self.inner.close()
}
}
pub(crate) struct OutlineTranslator<'b, T: ?Sized> {
inner: &'b mut T,
translation: Point<f32>,
}
impl<'b, T: ?Sized> OutlineTranslator<'b, T> {
pub(crate) fn new(inner: &'b mut T, translation: Point<f32>) -> Self {
Self { inner, translation }
}
}
impl<T: OutlineBuilder + ?Sized> OutlineBuilder for OutlineTranslator<'_, T> {
fn move_to(&mut self, x: f32, y: f32) {
self.inner
.move_to(x + self.translation.x, y + self.translation.y)
}
fn line_to(&mut self, x1: f32, y1: f32) {
self.inner
.line_to(x1 + self.translation.x, y1 + self.translation.y)
}
fn quad_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32) {
self.inner.quad_to(
x1 + self.translation.x,
y1 + self.translation.y,
x2 + self.translation.x,
y2 + self.translation.y,
)
}
fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x3: f32, y3: f32) {
self.inner.curve_to(
x1 + self.translation.x,
y1 + self.translation.y,
x2 + self.translation.x,
y2 + self.translation.y,
x3 + self.translation.x,
y3 + self.translation.y,
)
}
fn close(&mut self) {
self.inner.close()
}
}
pub(crate) struct OutlineRasterizer {
pub(crate) rasterizer: Rasterizer,
last: AbPoint,
last_move: Option<AbPoint>,
position: AbPoint,
scale: Vector<f32>,
}
impl OutlineRasterizer {
pub(crate) fn new(
position: Point<f32>,
scale: Vector<f32>,
width: usize,
height: usize,
) -> Self {
pub(crate) fn new(width: usize, height: usize) -> Self {
Self {
rasterizer: Rasterizer::new(width, height),
last: ab_point(0.0, 0.0),
last_move: None,
position: ab_point(position.x, position.y),
scale,
}
}
}
impl ttf_parser::OutlineBuilder for OutlineRasterizer {
impl OutlineBuilder for OutlineRasterizer {
fn move_to(&mut self, x: f32, y: f32) {
self.last = AbPoint {
x: x as f32 * self.scale.x + self.position.x,
y: -y as f32 * self.scale.y + self.position.y,
};
self.last = AbPoint { x, y };
self.last_move = Some(self.last);
}
fn line_to(&mut self, x1: f32, y1: f32) {
let p1 = AbPoint {
x: x1 as f32 * self.scale.x + self.position.x,
y: -y1 as f32 * self.scale.y + self.position.y,
};
let p1 = AbPoint { x: x1, y: y1 };
self.rasterizer.draw_line(self.last, p1);
self.last = p1;
}
fn quad_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32) {
let p1 = AbPoint {
x: x1 as f32 * self.scale.x + self.position.x,
y: -y1 as f32 * self.scale.y + self.position.y,
};
let p2 = AbPoint {
x: x2 as f32 * self.scale.x + self.position.x,
y: -y2 as f32 * self.scale.y + self.position.y,
};
let p1 = AbPoint { x: x1, y: y1 };
let p2 = AbPoint { x: x2, y: y2 };
self.rasterizer.draw_quad(self.last, p1, p2);
self.last = p2;
}
fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x3: f32, y3: f32) {
let p1 = AbPoint {
x: x1 as f32 * self.scale.x + self.position.x,
y: -y1 as f32 * self.scale.y + self.position.y,
};
let p2 = AbPoint {
x: x2 as f32 * self.scale.x + self.position.x,
y: -y2 as f32 * self.scale.y + self.position.y,
};
let p3 = AbPoint {
x: x3 as f32 * self.scale.x + self.position.x,
y: -y3 as f32 * self.scale.y + self.position.y,
};
let p1 = AbPoint { x: x1, y: y1 };
let p2 = AbPoint { x: x2, y: y2 };
let p3 = AbPoint { x: x3, y: y3 };
self.rasterizer.draw_cubic(self.last, p1, p2, p3);
self.last = p3;
......
Supports Markdown
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