From 520c561d3d70dfeacd4b7b0f0a580e37f0702e35 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Tue, 15 Dec 2015 11:23:14 -0800 Subject: [PATCH] gfx: Cache the last result of `TextRun::index_of_first_glyph_run_containing` in TLS. This achieves a 40% or so hit rate on Wikipedia. --- components/gfx/text/text_run.rs | 39 ++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/components/gfx/text/text_run.rs b/components/gfx/text/text_run.rs index 7d4023a58e0..5b8acb5e1c5 100644 --- a/components/gfx/text/text_run.rs +++ b/components/gfx/text/text_run.rs @@ -6,6 +6,7 @@ use app_units::Au; use font::{Font, FontHandleMethods, FontMetrics, IS_WHITESPACE_SHAPING_FLAG, RunMetrics}; use font::{ShapingOptions}; use platform::font_template::FontTemplateData; +use std::cell::Cell; use std::cmp::{Ordering, max}; use std::slice::Iter; use std::sync::Arc; @@ -13,6 +14,11 @@ use text::glyph::{CharIndex, GlyphStore}; use util::range::Range; use util::vec::{Comparator, FullBinarySearchMethods}; +thread_local! { + static INDEX_OF_FIRST_GLYPH_RUN_CACHE: Cell> = + Cell::new(None) +} + /// A single "paragraph" of text in one font size and style. #[derive(Clone, Deserialize, Serialize)] pub struct TextRun { @@ -26,6 +32,19 @@ pub struct TextRun { pub bidi_level: u8, } +impl Drop for TextRun { + fn drop(&mut self) { + // Invalidate the glyph run cache if it was our text run that got freed. + INDEX_OF_FIRST_GLYPH_RUN_CACHE.with(|index_of_first_glyph_run_cache| { + if let Some((text_run_ptr, _, _)) = index_of_first_glyph_run_cache.get() { + if text_run_ptr == (self as *const TextRun) { + index_of_first_glyph_run_cache.set(None); + } + } + }) + } +} + /// A single series of glyphs within a text run. #[derive(Clone, Deserialize, Serialize)] pub struct GlyphRun { @@ -248,6 +267,10 @@ impl<'a> TextRun { } pub fn advance_for_range(&self, range: &Range) -> Au { + if range.is_empty() { + return Au(0) + } + // TODO(Issue #199): alter advance direction for RTL // TODO(Issue #98): using inter-char and inter-word spacing settings when measuring text self.natural_word_slices_in_range(range) @@ -279,7 +302,21 @@ impl<'a> TextRun { /// Returns the index of the first glyph run containing the given character index. fn index_of_first_glyph_run_containing(&self, index: CharIndex) -> Option { - (&**self.glyphs).binary_search_index_by(&index, CharIndexComparator) + let self_ptr = self as *const TextRun; + INDEX_OF_FIRST_GLYPH_RUN_CACHE.with(|index_of_first_glyph_run_cache| { + if let Some((last_text_run, last_index, last_result)) = + index_of_first_glyph_run_cache.get() { + if last_text_run == self_ptr && last_index == index { + return Some(last_result) + } + } + + let result = (&**self.glyphs).binary_search_index_by(&index, CharIndexComparator); + if let Some(result) = result { + index_of_first_glyph_run_cache.set(Some((self_ptr, index, result))); + } + result + }) } /// Returns an iterator that will iterate over all slices of glyphs that represent natural