Commit 2fcad746 authored by Alex Butler's avatar Alex Butler

Merge branch 'glyph-set-position' into 'master'

Add fn `PositionedGlyph::set_position`

See merge request !137
parents 4a848761 2e9560b8
Pipeline #2781 passed with stages
in 12 minutes and 28 seconds
## master
## Unreleased
* Add fn `PositionedGlyph::set_position`
* gpu_cache: Update crossbeam-deque -> `0.7`, use `Injector` for minor rasterization performance boost.
## 0.7.3
* gpu_cache: Update crossbeam-utils -> `0.6`
......
......@@ -54,7 +54,7 @@ fn layout_paragraph<'a>(
if let Some(bb) = glyph.pixel_bounding_box() {
if bb.max.x > width as i32 {
caret = point(0.0, caret.y + advance_height);
glyph = glyph.into_unpositioned().positioned(caret);
glyph.set_position(caret);
last_glyph_id = None;
}
}
......
......@@ -36,7 +36,7 @@ fn layout_paragraph<'a>(
if let Some(bb) = glyph.pixel_bounding_box() {
if bb.max.x > width as i32 {
caret = point(0.0, caret.y + advance_height);
glyph = glyph.into_unpositioned().positioned(caret);
glyph.set_position(caret);
last_glyph_id = None;
}
}
......
......@@ -107,6 +107,7 @@ mod rasterizer;
pub mod gpu_cache;
pub use crate::geometry::{point, vector, Curve, Line, Point, Rect, Vector};
use approx::relative_eq;
use stb_truetype as tt;
use std::fmt;
use std::sync::Arc;
......@@ -609,12 +610,7 @@ impl<'a> Font<'a> {
/// })
/// # ;
/// ```
pub fn layout<'b>(
&self,
s: &'b str,
scale: Scale,
start: Point<f32>,
) -> LayoutIter<'_, 'b> {
pub fn layout<'b>(&self, s: &'b str, scale: Scale, start: Point<f32>) -> LayoutIter<'_, 'b> {
LayoutIter {
font: self,
chars: s.chars(),
......@@ -793,30 +789,7 @@ impl<'a> ScaledGlyph<'a> {
/// 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<'a> {
// Use subpixel fraction in floor/ceil rounding to elimate 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());
let bb = match self.g.inner {
GlyphInner::Proxy(ref font, id) => font
.info
.get_glyph_bitmap_box_subpixel(id, self.scale.x, self.scale.y, x_fract, y_fract)
.map(|bb| Rect {
min: point(x_trunc + bb.x0, y_trunc + bb.y0),
max: point(x_trunc + bb.x1, y_trunc + bb.y1),
}),
GlyphInner::Shared(ref data) => data.extents.map(|bb| Rect {
min: point(
(bb.min.x as f32 * self.scale.x + x_fract).floor() as i32 + x_trunc,
(bb.min.y as f32 * self.scale.y + y_fract).floor() as i32 + y_trunc,
),
max: point(
(bb.max.x as f32 * self.scale.x + x_fract).ceil() as i32 + x_trunc,
(bb.max.y as f32 * self.scale.y + y_fract).ceil() as i32 + y_trunc,
),
}),
};
let bb = self.pixel_bounds_at(p);
PositionedGlyph {
sg: self,
position: p,
......@@ -924,6 +897,34 @@ impl<'a> ScaledGlyph<'a> {
scale: self.scale,
}
}
#[inline]
fn pixel_bounds_at(&self, p: Point<f32>) -> Option<Rect<i32>> {
// Use subpixel fraction in floor/ceil rounding to elimate 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());
match self.g.inner {
GlyphInner::Proxy(ref font, id) => font
.info
.get_glyph_bitmap_box_subpixel(id, self.scale.x, self.scale.y, x_fract, y_fract)
.map(|bb| Rect {
min: point(x_trunc + bb.x0, y_trunc + bb.y0),
max: point(x_trunc + bb.x1, y_trunc + bb.y1),
}),
GlyphInner::Shared(ref data) => data.extents.map(|bb| Rect {
min: point(
(bb.min.x as f32 * self.scale.x + x_fract).floor() as i32 + x_trunc,
(bb.min.y as f32 * self.scale.y + y_fract).floor() as i32 + y_trunc,
),
max: point(
(bb.max.x as f32 * self.scale.x + x_fract).ceil() as i32 + x_trunc,
(bb.max.y as f32 * self.scale.y + y_fract).ceil() as i32 + y_trunc,
),
}),
}
}
}
impl<'a> PositionedGlyph<'a> {
......@@ -1039,6 +1040,21 @@ impl<'a> PositionedGlyph<'a> {
position: self.position,
}
}
/// Resets positioning information and recalculates the pixel bounding box
pub fn set_position(&mut self, p: Point<f32>) {
let p_diff = p - self.position;
if relative_eq!(p_diff.x.fract(), 0.0) && relative_eq!(p_diff.y.fract(), 0.0) {
if let Some(bb) = self.bb.as_mut() {
let rounded_diff = vector(p_diff.x.round() as i32, p_diff.y.round() as i32);
bb.min = bb.min + rounded_diff;
bb.max = bb.max + rounded_diff;
}
} else {
self.bb = self.sg.pixel_bounds_at(p);
}
self.position = p;
}
}
/// The type for errors returned by rusttype.
......
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