Skip to content

Commit

Permalink
Merge pull request #65 from alexheretic/glyph-lifetime
Browse files Browse the repository at this point in the history
Fix font.glyph lifetimes allow proxy glyphs in cache
  • Loading branch information
jackpot51 committed Oct 30, 2017
2 parents 4d5c601 + 2c308ce commit a035670
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 25 deletions.
24 changes: 14 additions & 10 deletions src/gpu_cache.rs
Expand Up @@ -145,15 +145,15 @@ struct Row {
}

/// An implementation of a dynamic GPU glyph cache. See the module documentation for more information.
pub struct Cache {
pub struct Cache<'font> {
scale_tolerance: f32,
position_tolerance: f32,
width: u32,
height: u32,
rows: LinkedHashMap<u32, Row>,
space_start_for_end: HashMap<u32, u32>,
space_end_for_start: HashMap<u32, u32>,
queue: Vec<(usize, PositionedGlyph<'static>)>,
queue: Vec<(usize, PositionedGlyph<'font>)>,
queue_retry: bool,
all_glyphs: BTreeMap<PGlyphSpec, (u32, u32)>
}
Expand Down Expand Up @@ -187,7 +187,7 @@ fn normalise_pixel_offset(mut offset: Vector<f32>) -> Vector<f32> {
offset
}

impl Cache {
impl<'font> Cache<'font> {
/// Constructs a new cache. Note that this is just the CPU side of the cache. The GPU texture is managed
/// by the user.
///
Expand All @@ -209,8 +209,12 @@ impl Cache {
/// # Panics
///
/// `scale_tolerance` or `position_tolerance` are less than or equal to zero.
pub fn new(width: u32, height: u32,
scale_tolerance: f32, position_tolerance: f32) -> Cache {
pub fn new<'a>(
width: u32,
height: u32,
scale_tolerance: f32,
position_tolerance: f32,
) -> Cache<'a> {
assert!(scale_tolerance >= 0.0);
assert!(position_tolerance >= 0.0);
let scale_tolerance = scale_tolerance.max(0.001);
Expand Down Expand Up @@ -265,9 +269,9 @@ impl Cache {
/// Queue a glyph for caching by the next call to `cache_queued`. `font_id` is used to
/// disambiguate glyphs from different fonts. The user should ensure that `font_id` is unique to the
/// font the glyph is from.
pub fn queue_glyph(&mut self, font_id: usize, glyph: PositionedGlyph) {
pub fn queue_glyph(&mut self, font_id: usize, glyph: PositionedGlyph<'font>) {
if glyph.pixel_bounding_box().is_some() {
self.queue.push((font_id, glyph.standalone()));
self.queue.push((font_id, glyph));
}
}
/// Clears the cache. Does not affect the glyph queue.
Expand Down Expand Up @@ -615,9 +619,9 @@ fn cache_test() {
use ::FontCollection;
use ::Scale;
use ::point;
let mut cache = Cache::new(32, 32, 0.1, 0.1);
let font_data = include_bytes!("../fonts/wqy-microhei/WenQuanYiMicroHei.ttf");
let font = FontCollection::from_bytes(font_data as &[u8]).into_font().unwrap();
let mut cache = Cache::new(32, 32, 0.1, 0.1);
let strings = [
("Hello World!", 15.0),
("Hello World!", 14.0),
Expand Down Expand Up @@ -726,13 +730,13 @@ mod cache_bench_tests {
// Cache settings also affect this, it occurs when position_tolerance is < 1.0
for scale in &[25_f32, 24.5, 25.01, 24.7, 24.99] {
for glyph in layout_paragraph(&font, Scale::uniform(*scale), 500, TEST_STR) {
glyphs.push(glyph.standalone());
glyphs.push(glyph);
}
}
glyphs
}

fn layout_paragraph<'a>(font: &'a Font,
fn layout_paragraph<'a>(font: &Font<'a>,
scale: Scale,
width: u32,
text: &str) -> Vec<PositionedGlyph<'a>> {
Expand Down
29 changes: 14 additions & 15 deletions src/lib.rs
Expand Up @@ -181,7 +181,7 @@ pub struct Glyph<'a> {

#[derive(Clone)]
enum GlyphInner<'a> {
Proxy(&'a Font<'a>, u32),
Proxy(Font<'a>, u32),
Shared(Arc<SharedGlyphData>)
}

Expand Down Expand Up @@ -342,12 +342,13 @@ impl<'a> Font<'a> {
/// otherwise `None` is returned.
///
/// Note that code points without corresponding glyphs in this font map to the "undef" glyph, glyph 0.
pub fn glyph<C: Into<CodepointOrGlyphId>>(&self, id: C) -> Option<Glyph> {
pub fn glyph<C: Into<CodepointOrGlyphId>>(&self, id: C) -> Option<Glyph<'a>> {
let gid = match id.into() {
CodepointOrGlyphId::Codepoint(Codepoint(c)) => self.info.find_glyph_index(c),
CodepointOrGlyphId::GlyphId(GlyphId(gid)) => gid
};
Some(Glyph::new(GlyphInner::Proxy(self, gid)))
// font clone either a reference clone, or arc clone
Some(Glyph::new(GlyphInner::Proxy(self.clone(), gid)))
}
/// A convenience function.
///
Expand Down Expand Up @@ -456,17 +457,15 @@ impl<'a, 'b> Iterator for LayoutIter<'a, 'b> {
}
}
impl<'a> Glyph<'a> {
fn new(inner: GlyphInner) -> Glyph {
Glyph {
inner: inner
}
fn new(inner: GlyphInner<'a>) -> Glyph<'a> {
Glyph { inner }
}
/// The font to which this glyph belongs. If the glyph is a standalone glyph that owns its resources,
/// it no longer has a reference to the font which it was created from (using `standalone()`). In which
/// case, `None` is returned.
pub fn font(&self) -> Option<&Font<'a>> {
match self.inner {
GlyphInner::Proxy(f, _) => Some(f),
GlyphInner::Proxy(ref f, _) => Some(f),
GlyphInner::Shared(_) => None
}
}
Expand All @@ -481,7 +480,7 @@ impl<'a> Glyph<'a> {
/// available.
pub fn scaled(self, scale: Scale) -> ScaledGlyph<'a> {
let (scale_x, scale_y) = match self.inner {
GlyphInner::Proxy(font, _) => {
GlyphInner::Proxy(ref font, _) => {
let scale_y = font.info.scale_for_pixel_height(scale.y);
let scale_x = scale_y * scale.x / scale.y;
(scale_x, scale_y)
Expand All @@ -504,7 +503,7 @@ impl<'a> Glyph<'a> {
/// Calling `standalone()` on a standalone glyph shares the resources, and is equivalent to `clone()`.
pub fn standalone(&self) -> Glyph<'static> {
match self.inner {
GlyphInner::Proxy(font, id) => Glyph::new(GlyphInner::Shared(Arc::new(SharedGlyphData {
GlyphInner::Proxy(ref font, id) => Glyph::new(GlyphInner::Shared(Arc::new(SharedGlyphData {
id: id,
scale_for_1_pixel: font.info.scale_for_pixel_height(1.0),
unit_h_metrics: {
Expand Down Expand Up @@ -558,7 +557,7 @@ impl<'a> ScaledGlyph<'a> {
/// glyph available.
pub fn positioned(self, p: Point<f32>) -> PositionedGlyph<'a> {
let bb = match self.g.inner {
GlyphInner::Proxy(font, id) => {
GlyphInner::Proxy(ref font, id) => {
font.info.get_glyph_bitmap_box_subpixel(id,
self.scale.x, self.scale.y,
p.x, p.y)
Expand Down Expand Up @@ -588,7 +587,7 @@ impl<'a> ScaledGlyph<'a> {
/// Retrieves the "horizontal metrics" of this glyph. See `HMetrics` for more detail.
pub fn h_metrics(&self) -> HMetrics {
match self.g.inner {
GlyphInner::Proxy(font, id) => {
GlyphInner::Proxy(ref font, id) => {
let hm = font.info.get_glyph_h_metrics(id);
HMetrics {
advance_width: hm.advance_width as f32 * self.scale.x,
Expand All @@ -607,7 +606,7 @@ impl<'a> ScaledGlyph<'a> {
use stb_truetype::VertexType;
use std::mem::replace;
match self.g.inner {
GlyphInner::Proxy(font, id) => font.info.get_glyph_shape(id),
GlyphInner::Proxy(ref font, id) => font.info.get_glyph_shape(id),
GlyphInner::Shared(ref data) => data.shape.clone()
}.map(|shape| {
let mut result = Vec::new();
Expand Down Expand Up @@ -657,7 +656,7 @@ impl<'a> ScaledGlyph<'a> {
/// conservative pixel-boundary bounding box. The coordinates are relative to the glyph's origin.
pub fn exact_bounding_box(&self) -> Option<Rect<f32>> {
match self.g.inner {
GlyphInner::Proxy(font, id) => font.info.get_glyph_box(id).map(|bb| {
GlyphInner::Proxy(ref font, id) => font.info.get_glyph_box(id).map(|bb| {
Rect {
min: point(bb.x0 as f32 * self.scale.x, -bb.y1 as f32 * self.scale.y),
max: point(bb.x1 as f32 * self.scale.x, -bb.y0 as f32 * self.scale.y)
Expand Down Expand Up @@ -736,7 +735,7 @@ impl<'a> PositionedGlyph<'a> {
use geometry::{Line, Curve};
use stb_truetype::VertexType;
let shape = match self.sg.g.inner {
GlyphInner::Proxy(font, id) => font.info.get_glyph_shape(id).unwrap_or_else(|| Vec::new()),
GlyphInner::Proxy(ref font, id) => font.info.get_glyph_shape(id).unwrap_or_else(|| Vec::new()),
GlyphInner::Shared(ref data) => data.shape.clone().unwrap_or_else(|| Vec::new())
};
let bb = if let Some(bb) = self.bb.as_ref() {
Expand Down

0 comments on commit a035670

Please sign in to comment.