From 5991afafa412cf1b36bf1d375fc8304328042496 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Tue, 17 May 2016 09:58:55 -0700 Subject: Add a fast path for shaping ASCII text --- components/gfx/text/shaping/harfbuzz.rs | 52 ++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) (limited to 'components/gfx/text') diff --git a/components/gfx/text/shaping/harfbuzz.rs b/components/gfx/text/shaping/harfbuzz.rs index a1457e4ffd0..79d36f9b6e0 100644 --- a/components/gfx/text/shaping/harfbuzz.rs +++ b/components/gfx/text/shaping/harfbuzz.rs @@ -4,7 +4,7 @@ use app_units::Au; use euclid::Point2D; -use font::{DISABLE_KERNING_SHAPING_FLAG, Font, FontTableMethods, FontTableTag}; +use font::{DISABLE_KERNING_SHAPING_FLAG, Font, FontHandleMethods, FontTableMethods, FontTableTag}; use font::{IGNORE_LIGATURES_SHAPING_FLAG, KERN, RTL_FLAG, ShapingOptions}; use harfbuzz::{HB_DIRECTION_LTR, HB_DIRECTION_RTL, HB_MEMORY_MODE_READONLY}; use harfbuzz::{hb_blob_create, hb_face_create_for_tables}; @@ -34,10 +34,12 @@ use harfbuzz::{hb_glyph_position_t}; use harfbuzz::{hb_position_t, hb_tag_t}; use libc::{c_char, c_int, c_uint, c_void}; use platform::font::FontTable; +use std::ascii::AsciiExt; use std::{char, cmp, ptr}; use text::glyph::{ByteIndex, GlyphData, GlyphId, GlyphStore}; use text::shaping::ShaperMethods; use text::util::{fixed_to_float, float_to_fixed, is_bidi_control}; +use unicode_script::Script; const NO_GLYPH: i32 = -1; const LIGA: u32 = ot_tag!('l', 'i', 'g', 'a'); @@ -199,7 +201,14 @@ impl ShaperMethods for Shaper { /// Calculate the layout metrics associated with the given text when painted in a specific /// font. fn shape_text(&self, text: &str, options: &ShapingOptions, glyphs: &mut GlyphStore) { + if self.can_use_fast_path(text, options) { + debug!("shape_text: Using ASCII fast path."); + self.shape_text_fast(text, options, glyphs); + return; + } unsafe { + debug!("shape_text: Using Harfbuzz."); + let hb_buffer: *mut hb_buffer_t = hb_buffer_create(); hb_buffer_set_direction(hb_buffer, if options.flags.contains(RTL_FLAG) { HB_DIRECTION_RTL @@ -241,6 +250,47 @@ impl ShaperMethods for Shaper { } impl Shaper { + fn can_use_fast_path(&self, text: &str, options: &ShapingOptions) -> bool { + let font = self.font_and_shaping_options.font; + + options.script == Script::Latin && + !options.flags.contains(RTL_FLAG) && + unsafe { (*font).handle.can_do_fast_shaping() } && + text.is_ascii() + } + + /// Fast path for ASCII text that only needs simple horizontal LTR kerning. + fn shape_text_fast(&self, text: &str, options: &ShapingOptions, glyphs: &mut GlyphStore) { + let font = unsafe { &mut *self.font_and_shaping_options.font }; + + let mut prev_glyph_id = None; + for (i, byte) in text.bytes().enumerate() { + let character = byte as char; + let glyph_id = match font.glyph_index(character) { + Some(id) => id, + None => continue, + }; + + let mut advance = Au::from_f64_px(font.glyph_h_advance(glyph_id)); + if character == ' ' { + advance += options.word_spacing; + } + if let Some(letter_spacing) = options.letter_spacing { + advance += letter_spacing; + } + let offset = prev_glyph_id.map(|prev| { + let h_kerning = Au::from_f64_px(font.glyph_h_kerning(prev, glyph_id)); + advance += h_kerning; + Point2D::new(h_kerning, Au(0)) + }); + + let glyph = GlyphData::new(glyph_id, advance, offset, true, true); + glyphs.add_glyph_for_byte_index(ByteIndex(i as isize), character, &glyph); + prev_glyph_id = Some(glyph_id); + } + glyphs.finalize_changes(); + } + fn save_glyph_results(&self, text: &str, options: &ShapingOptions, -- cgit v1.2.3