diff options
Diffstat (limited to 'tiny_skia/src')
| -rw-r--r-- | tiny_skia/src/text.rs | 102 | 
1 files changed, 64 insertions, 38 deletions
diff --git a/tiny_skia/src/text.rs b/tiny_skia/src/text.rs index 4f89ef52..22c17507 100644 --- a/tiny_skia/src/text.rs +++ b/tiny_skia/src/text.rs @@ -66,17 +66,10 @@ impl Pipeline {              shaping,          }; -        let (_, buffer) = self.cache.get_mut().allocate(font_system, key); +        let (_, entry) = self.cache.get_mut().allocate(font_system, key); -        let (total_lines, max_width) = buffer -            .layout_runs() -            .enumerate() -            .fold((0, 0.0), |(_, max), (i, buffer)| { -                (i + 1, buffer.line_w.max(max)) -            }); - -        let total_height = total_lines as f32 * line_height * scale_factor; -        let max_width = max_width * scale_factor; +        let max_width = entry.bounds.width * scale_factor; +        let total_height = entry.bounds.height * scale_factor;          let bounds = bounds * scale_factor; @@ -94,7 +87,7 @@ impl Pipeline {          let mut swash = cosmic_text::SwashCache::new(); -        for run in buffer.layout_runs() { +        for run in entry.buffer.layout_runs() {              for glyph in run.glyphs {                  let physical_glyph = glyph.physical((x, y), scale_factor); @@ -143,7 +136,7 @@ impl Pipeline {          let line_height = f32::from(line_height.to_absolute(Pixels(size))); -        let (_, paragraph) = measurement_cache.allocate( +        let (_, entry) = measurement_cache.allocate(              &mut self.font_system.borrow_mut(),              Key {                  content, @@ -155,14 +148,7 @@ impl Pipeline {              },          ); -        let (total_lines, max_width) = paragraph -            .layout_runs() -            .enumerate() -            .fold((0, 0.0), |(_, max), (i, buffer)| { -                (i + 1, buffer.line_w.max(max)) -            }); - -        Size::new(max_width, line_height * total_lines as f32) +        entry.bounds      }      pub fn hit_test( @@ -180,7 +166,7 @@ impl Pipeline {          let line_height = f32::from(line_height.to_absolute(Pixels(size))); -        let (_, paragraph) = measurement_cache.allocate( +        let (_, entry) = measurement_cache.allocate(              &mut self.font_system.borrow_mut(),              Key {                  content, @@ -192,12 +178,22 @@ impl Pipeline {              },          ); -        let cursor = paragraph.hit(point.x, point.y)?; +        let cursor = entry.buffer.hit(point.x, point.y)?;          Some(Hit::CharOffset(cursor.index))      }  } +fn measure(buffer: &cosmic_text::Buffer) -> Size { +    let (width, total_lines) = buffer +        .layout_runs() +        .fold((0.0, 0usize), |(width, total_lines), run| { +            (run.line_w.max(width), total_lines + 1) +        }); + +    Size::new(width, total_lines as f32 * buffer.metrics().line_height) +} +  fn to_family(family: font::Family) -> cosmic_text::Family<'static> {      match family {          font::Family::Name(name) => cosmic_text::Family::Name(name), @@ -354,12 +350,18 @@ impl GlyphCache {  }  struct Cache { -    entries: FxHashMap<KeyHash, cosmic_text::Buffer>, +    entries: FxHashMap<KeyHash, Entry>, +    measurements: FxHashMap<KeyHash, KeyHash>,      recently_used: FxHashSet<KeyHash>,      hasher: HashBuilder,      trim_count: usize,  } +struct Entry { +    buffer: cosmic_text::Buffer, +    bounds: Size, +} +  #[cfg(not(target_arch = "wasm32"))]  type HashBuilder = twox_hash::RandomXxHashBuilder64; @@ -372,6 +374,7 @@ impl Cache {      fn new() -> Self {          Self {              entries: FxHashMap::default(), +            measurements: FxHashMap::default(),              recently_used: FxHashSet::default(),              hasher: HashBuilder::default(),              trim_count: 0, @@ -382,20 +385,18 @@ impl Cache {          &mut self,          font_system: &mut cosmic_text::FontSystem,          key: Key<'_>, -    ) -> (KeyHash, &mut cosmic_text::Buffer) { -        let hash = { -            let mut hasher = self.hasher.build_hasher(); - -            key.content.hash(&mut hasher); -            key.size.to_bits().hash(&mut hasher); -            key.line_height.to_bits().hash(&mut hasher); -            key.font.hash(&mut hasher); -            key.bounds.width.to_bits().hash(&mut hasher); -            key.bounds.height.to_bits().hash(&mut hasher); -            key.shaping.hash(&mut hasher); - -            hasher.finish() -        }; +    ) -> (KeyHash, &mut Entry) { +        let hash = key.hash(self.hasher.build_hasher()); + +        if let Some(measured_hash) = self.measurements.get(&hash) { +            let _ = self.recently_used.insert(hash); +            let _ = self.recently_used.insert(*measured_hash); + +            return ( +                *measured_hash, +                self.entries.get_mut(&measured_hash).unwrap(), +            ); +        }          if let hash_map::Entry::Vacant(entry) = self.entries.entry(hash) {              let metrics = cosmic_text::Metrics::new(key.size, key.size * 1.2); @@ -416,7 +417,16 @@ impl Cache {                  to_shaping(key.shaping),              ); -            let _ = entry.insert(buffer); +            let bounds = measure(&buffer); + +            let _ = entry.insert(Entry { buffer, bounds }); + +            if key.bounds != bounds { +                let _ = self.measurements.insert( +                    Key { bounds, ..key }.hash(self.hasher.build_hasher()), +                    hash, +                ); +            }          }          let _ = self.recently_used.insert(hash); @@ -428,6 +438,8 @@ impl Cache {          if self.trim_count > Self::TRIM_INTERVAL {              self.entries                  .retain(|key, _| self.recently_used.contains(key)); +            self.measurements +                .retain(|key, _| self.recently_used.contains(key));              self.recently_used.clear(); @@ -448,4 +460,18 @@ struct Key<'a> {      shaping: Shaping,  } +impl Key<'_> { +    fn hash<H: Hasher>(self, mut hasher: H) -> KeyHash { +        self.content.hash(&mut hasher); +        self.size.to_bits().hash(&mut hasher); +        self.line_height.to_bits().hash(&mut hasher); +        self.font.hash(&mut hasher); +        self.bounds.width.to_bits().hash(&mut hasher); +        self.bounds.height.to_bits().hash(&mut hasher); +        self.shaping.hash(&mut hasher); + +        hasher.finish() +    } +} +  type KeyHash = u64;  | 
