From aa4a8eb88d1cb7a261f42384431aa8654343fd64 Mon Sep 17 00:00:00 2001 From: kingdido999 Date: Fri, 7 Sep 2018 10:49:07 +0800 Subject: [PATCH] Format gfx text #21373 --- components/gfx/text/glyph.rs | 257 +++++++++++++++--------- components/gfx/text/mod.rs | 1 - components/gfx/text/shaping/harfbuzz.rs | 226 ++++++++++++--------- components/gfx/text/shaping/mod.rs | 1 - components/gfx/text/text_run.rs | 162 +++++++++------ components/gfx/text/util.rs | 39 ++-- 6 files changed, 420 insertions(+), 266 deletions(-) diff --git a/components/gfx/text/glyph.rs b/components/gfx/text/glyph.rs index 78f02881058b..8e4c56e309b8 100644 --- a/components/gfx/text/glyph.rs +++ b/components/gfx/text/glyph.rs @@ -4,7 +4,10 @@ use app_units::Au; use euclid::Point2D; -#[cfg(all(feature = "unstable", any(target_feature = "sse2", target_feature = "neon")))] +#[cfg(all( + feature = "unstable", + any(target_feature = "sse2", target_feature = "neon") +))] use packed_simd::u32x4; use range::{self, EachIndex, Range, RangeIndex}; use std::{fmt, mem, u16}; @@ -28,9 +31,7 @@ pub struct GlyphEntry { impl GlyphEntry { fn new(value: u32) -> GlyphEntry { - GlyphEntry { - value: value, - } + GlyphEntry { value: value } } fn initial() -> GlyphEntry { @@ -54,11 +55,11 @@ impl GlyphEntry { fn complex(starts_cluster: bool, starts_ligature: bool, glyph_count: usize) -> GlyphEntry { assert!(glyph_count <= u16::MAX as usize); - debug!("creating complex glyph entry: starts_cluster={}, starts_ligature={}, \ - glyph_count={}", - starts_cluster, - starts_ligature, - glyph_count); + debug!( + "creating complex glyph entry: starts_cluster={}, starts_ligature={}, \ + glyph_count={}", + starts_cluster, starts_ligature, glyph_count + ); GlyphEntry::new(glyph_count as u32) } @@ -73,16 +74,16 @@ pub type GlyphId = u32; // TODO: make this more type-safe. -const FLAG_CHAR_IS_SPACE: u32 = 0x40000000; +const FLAG_CHAR_IS_SPACE: u32 = 0x40000000; #[cfg(feature = "unstable")] #[cfg(any(target_feature = "sse2", target_feature = "neon"))] const FLAG_CHAR_IS_SPACE_SHIFT: u32 = 30; -const FLAG_IS_SIMPLE_GLYPH: u32 = 0x80000000; +const FLAG_IS_SIMPLE_GLYPH: u32 = 0x80000000; // glyph advance; in Au's. -const GLYPH_ADVANCE_MASK: u32 = 0x3FFF0000; -const GLYPH_ADVANCE_SHIFT: u32 = 16; -const GLYPH_ID_MASK: u32 = 0x0000FFFF; +const GLYPH_ADVANCE_MASK: u32 = 0x3FFF0000; +const GLYPH_ADVANCE_SHIFT: u32 = 16; +const GLYPH_ID_MASK: u32 = 0x0000FFFF; // Non-simple glyphs (more than one glyph per char; missing glyph, // newline, tab, large advance, or nonzero x/y offsets) may have one @@ -91,7 +92,7 @@ const GLYPH_ID_MASK: u32 = 0x0000FFFF; // unicode char. // The number of detailed glyphs for this char. -const GLYPH_COUNT_MASK: u32 = 0x0000FFFF; +const GLYPH_COUNT_MASK: u32 = 0x0000FFFF; fn is_simple_glyph_id(id: GlyphId) -> bool { ((id as u32) & GLYPH_ID_MASK) == id @@ -205,8 +206,8 @@ struct DetailedGlyphStore { impl<'a> DetailedGlyphStore { fn new() -> DetailedGlyphStore { DetailedGlyphStore { - detail_buffer: vec!(), // TODO: default size? - detail_lookup: vec!(), + detail_buffer: vec![], // TODO: default size? + detail_lookup: vec![], lookup_is_sorted: false, } } @@ -217,7 +218,10 @@ impl<'a> DetailedGlyphStore { detail_offset: self.detail_buffer.len(), }; - debug!("Adding entry[off={:?}] for detailed glyphs: {:?}", entry_offset, glyphs); + debug!( + "Adding entry[off={:?}] for detailed glyphs: {:?}", + entry_offset, glyphs + ); /* TODO: don't actually assert this until asserts are compiled in/out based on severity, debug/release, etc. This assertion @@ -235,9 +239,15 @@ impl<'a> DetailedGlyphStore { self.lookup_is_sorted = false; } - fn detailed_glyphs_for_entry(&'a self, entry_offset: ByteIndex, count: u16) - -> &'a [DetailedGlyph] { - debug!("Requesting detailed glyphs[n={}] for entry[off={:?}]", count, entry_offset); + fn detailed_glyphs_for_entry( + &'a self, + entry_offset: ByteIndex, + count: u16, + ) -> &'a [DetailedGlyph] { + debug!( + "Requesting detailed glyphs[n={}] for entry[off={:?}]", + count, entry_offset + ); // FIXME: Is this right? --pcwalton // TODO: should fix this somewhere else @@ -253,18 +263,21 @@ impl<'a> DetailedGlyphStore { detail_offset: 0, // unused }; - let i = self.detail_lookup.binary_search(&key) + let i = self + .detail_lookup + .binary_search(&key) .expect("Invalid index not found in detailed glyph lookup table!"); let main_detail_offset = self.detail_lookup[i].detail_offset; assert!(main_detail_offset + (count as usize) <= self.detail_buffer.len()); // return a slice into the buffer - &self.detail_buffer[main_detail_offset .. main_detail_offset + count as usize] + &self.detail_buffer[main_detail_offset..main_detail_offset + count as usize] } - fn detailed_glyph_with_index(&'a self, - entry_offset: ByteIndex, - detail_offset: u16) - -> &'a DetailedGlyph { + fn detailed_glyph_with_index( + &'a self, + entry_offset: ByteIndex, + detail_offset: u16, + ) -> &'a DetailedGlyph { assert!((detail_offset as usize) <= self.detail_buffer.len()); assert!(self.lookup_is_sorted); @@ -273,7 +286,9 @@ impl<'a> DetailedGlyphStore { detail_offset: 0, // unused }; - let i = self.detail_lookup.binary_search(&key) + let i = self + .detail_lookup + .binary_search(&key) .expect("Invalid index not found in detailed glyph lookup table!"); let main_detail_offset = self.detail_lookup[i].detail_offset; assert!(main_detail_offset + (detail_offset as usize) < self.detail_buffer.len()); @@ -290,7 +305,7 @@ impl<'a> DetailedGlyphStore { // immutable locations thus don't play well with freezing. // Thar be dragons here. You have been warned. (Tips accepted.) - let mut unsorted_records: Vec = vec!(); + let mut unsorted_records: Vec = vec![]; mem::swap(&mut self.detail_lookup, &mut unsorted_records); let mut mut_records: Vec = unsorted_records; mut_records.sort_by(|a, b| { @@ -320,12 +335,13 @@ pub struct GlyphData { impl GlyphData { /// Creates a new entry for one glyph. - pub fn new(id: GlyphId, - advance: Au, - offset: Option>, - cluster_start: bool, - ligature_start: bool) - -> GlyphData { + pub fn new( + id: GlyphId, + advance: Au, + offset: Option>, + cluster_start: bool, + ligature_start: bool, + ) -> GlyphData { GlyphData { id: id, advance: advance, @@ -351,8 +367,11 @@ impl<'a> GlyphInfo<'a> { match self { GlyphInfo::Simple(store, entry_i) => store.entry_buffer[entry_i.to_usize()].id(), GlyphInfo::Detail(store, entry_i, detail_j) => { - store.detail_store.detailed_glyph_with_index(entry_i, detail_j).id - } + store + .detail_store + .detailed_glyph_with_index(entry_i, detail_j) + .id + }, } } @@ -362,8 +381,11 @@ impl<'a> GlyphInfo<'a> { match self { GlyphInfo::Simple(store, entry_i) => store.entry_buffer[entry_i.to_usize()].advance(), GlyphInfo::Detail(store, entry_i, detail_j) => { - store.detail_store.detailed_glyph_with_index(entry_i, detail_j).advance - } + store + .detail_store + .detailed_glyph_with_index(entry_i, detail_j) + .advance + }, } } @@ -371,9 +393,12 @@ impl<'a> GlyphInfo<'a> { pub fn offset(self) -> Option> { match self { GlyphInfo::Simple(_, _) => None, - GlyphInfo::Detail(store, entry_i, detail_j) => { - Some(store.detail_store.detailed_glyph_with_index(entry_i, detail_j).offset) - } + GlyphInfo::Detail(store, entry_i, detail_j) => Some( + store + .detail_store + .detailed_glyph_with_index(entry_i, detail_j) + .offset, + ), } } @@ -477,14 +502,11 @@ impl<'a> GlyphStore { } /// Adds a single glyph. - pub fn add_glyph_for_byte_index(&mut self, - i: ByteIndex, - character: char, - data: &GlyphData) { + pub fn add_glyph_for_byte_index(&mut self, i: ByteIndex, character: char, data: &GlyphData) { let glyph_is_compressible = is_simple_glyph_id(data.id) && is_simple_advance(data.advance) && - data.offset == Point2D::zero() && - data.cluster_start; // others are stored in detail buffer + data.offset == Point2D::zero() && + data.cluster_start; // others are stored in detail buffer debug_assert!(data.ligature_start); // can't compress ligature continuation glyphs. debug_assert!(i < self.len()); @@ -512,20 +534,29 @@ impl<'a> GlyphStore { let glyph_count = data_for_glyphs.len(); let first_glyph_data = data_for_glyphs[0]; - let glyphs_vec: Vec = (0..glyph_count).map(|i| { - DetailedGlyph::new(data_for_glyphs[i].id, - data_for_glyphs[i].advance, - data_for_glyphs[i].offset) - }).collect(); + let glyphs_vec: Vec = (0..glyph_count) + .map(|i| { + DetailedGlyph::new( + data_for_glyphs[i].id, + data_for_glyphs[i].advance, + data_for_glyphs[i].offset, + ) + }).collect(); self.has_detailed_glyphs = true; - self.detail_store.add_detailed_glyphs_for_entry(i, &glyphs_vec); + self.detail_store + .add_detailed_glyphs_for_entry(i, &glyphs_vec); - let entry = GlyphEntry::complex(first_glyph_data.cluster_start, - first_glyph_data.ligature_start, - glyph_count); + let entry = GlyphEntry::complex( + first_glyph_data.cluster_start, + first_glyph_data.ligature_start, + glyph_count, + ); - debug!("Adding multiple glyphs[idx={:?}, count={}]: {:?}", i, glyph_count, entry); + debug!( + "Adding multiple glyphs[idx={:?}, count={}]: {:?}", + i, glyph_count, entry + ); self.entry_buffer[i.to_usize()] = entry; } @@ -540,9 +571,13 @@ impl<'a> GlyphStore { } GlyphIterator { - store: self, - byte_index: if self.is_rtl { range.end() } else { range.begin() - ByteIndex(1) }, - byte_range: *range, + store: self, + byte_index: if self.is_rtl { + range.end() + } else { + range.begin() - ByteIndex(1) + }, + byte_range: *range, glyph_range: None, } } @@ -551,7 +586,12 @@ impl<'a> GlyphStore { // and advance of the glyph in the range at the given advance, if reached. Otherwise, returns the // the number of glyphs and the advance for the given range. #[inline] - pub fn range_index_of_advance(&self, range: &Range, advance: Au, extra_word_spacing: Au) -> (usize, Au) { + pub fn range_index_of_advance( + &self, + range: &Range, + advance: Au, + extra_word_spacing: Au, + ) -> (usize, Au) { let mut index = 0; let mut current_advance = Au(0); for glyph in self.iter_glyphs_for_byte_range(range) { @@ -580,7 +620,11 @@ impl<'a> GlyphStore { } #[inline] - pub fn advance_for_byte_range_slow_path(&self, range: &Range, extra_word_spacing: Au) -> Au { + pub fn advance_for_byte_range_slow_path( + &self, + range: &Range, + extra_word_spacing: Au, + ) -> Au { self.iter_glyphs_for_byte_range(range) .fold(Au(0), |advance, glyph| { if glyph.char_is_space() { @@ -594,7 +638,11 @@ impl<'a> GlyphStore { #[inline] #[cfg(feature = "unstable")] #[cfg(any(target_feature = "sse2", target_feature = "neon"))] - fn advance_for_byte_range_simple_glyphs(&self, range: &Range, extra_word_spacing: Au) -> Au { + fn advance_for_byte_range_simple_glyphs( + &self, + range: &Range, + extra_word_spacing: Au, + ) -> Au { let advance_mask = u32x4::splat(GLYPH_ADVANCE_MASK); let space_flag_mask = u32x4::splat(FLAG_CHAR_IS_SPACE); let mut simd_advance = u32x4::splat(0); @@ -614,16 +662,14 @@ impl<'a> GlyphStore { simd_spaces = simd_spaces + spaces; } - let advance = - (simd_advance.extract(0) + - simd_advance.extract(1) + - simd_advance.extract(2) + - simd_advance.extract(3)) as i32; - let spaces = - (simd_spaces.extract(0) + - simd_spaces.extract(1) + - simd_spaces.extract(2) + - simd_spaces.extract(3)) as i32; + let advance = (simd_advance.extract(0) + + simd_advance.extract(1) + + simd_advance.extract(2) + + simd_advance.extract(3)) as i32; + let spaces = (simd_spaces.extract(0) + + simd_spaces.extract(1) + + simd_spaces.extract(2) + + simd_spaces.extract(3)) as i32; let mut leftover_advance = Au(0); let mut leftover_spaces = 0; for i in leftover_entries..range.end().to_usize() { @@ -637,8 +683,15 @@ impl<'a> GlyphStore { /// When SIMD isn't available, fallback to the slow path. #[inline] - #[cfg(not(all(feature = "unstable", any(target_feature = "sse2", target_feature = "neon"))))] - fn advance_for_byte_range_simple_glyphs(&self, range: &Range, extra_word_spacing: Au) -> Au { + #[cfg(not(all( + feature = "unstable", + any(target_feature = "sse2", target_feature = "neon") + )))] + fn advance_for_byte_range_simple_glyphs( + &self, + range: &Range, + extra_word_spacing: Au, + ) -> Au { self.advance_for_byte_range_slow_path(range, extra_word_spacing) } @@ -676,23 +729,27 @@ impl fmt::Debug for GlyphStore { let mut detailed_buffer = self.detail_store.detail_buffer.iter(); for entry in self.entry_buffer.iter() { if entry.is_simple() { - write!(formatter, - " simple id={:?} advance={:?}\n", - entry.id(), - entry.advance())?; - continue + write!( + formatter, + " simple id={:?} advance={:?}\n", + entry.id(), + entry.advance() + )?; + continue; } if entry.is_initial() { - continue + continue; } write!(formatter, " complex...")?; if detailed_buffer.next().is_none() { - continue + continue; } - write!(formatter, - " detailed id={:?} advance={:?}\n", - entry.id(), - entry.advance())?; + write!( + formatter, + " detailed id={:?} advance={:?}\n", + entry.id(), + entry.advance() + )?; } Ok(()) } @@ -712,27 +769,37 @@ impl<'a> GlyphIterator<'a> { fn next_glyph_range(&mut self) -> Option> { match self.glyph_range.as_mut().unwrap().next() { Some(j) => { - Some(GlyphInfo::Detail(self.store, self.byte_index, j.get() as u16 /* ??? */)) - } + Some(GlyphInfo::Detail( + self.store, + self.byte_index, + j.get() as u16, /* ??? */ + )) + }, None => { // No more glyphs for current character. Try to get another. self.glyph_range = None; self.next() - } + }, } } // Slow path when there is a complex glyph. #[inline(never)] fn next_complex_glyph(&mut self, entry: &GlyphEntry, i: ByteIndex) -> Option> { - let glyphs = self.store.detail_store.detailed_glyphs_for_entry(i, entry.glyph_count()); - self.glyph_range = Some(range::each_index(ByteIndex(0), ByteIndex(glyphs.len() as isize))); + let glyphs = self + .store + .detail_store + .detailed_glyphs_for_entry(i, entry.glyph_count()); + self.glyph_range = Some(range::each_index( + ByteIndex(0), + ByteIndex(glyphs.len() as isize), + )); self.next() } } impl<'a> Iterator for GlyphIterator<'a> { - type Item = GlyphInfo<'a>; + type Item = GlyphInfo<'a>; // I tried to start with something simpler and apply FlatMap, but the // inability to store free variables in the FlatMap struct was problematic. @@ -744,7 +811,7 @@ impl<'a> Iterator for GlyphIterator<'a> { fn next(&mut self) -> Option> { // Would use 'match' here but it borrows contents in a way that interferes with mutation. if self.glyph_range.is_some() { - return self.next_glyph_range() + return self.next_glyph_range(); } // No glyph range. Look at next byte. @@ -755,7 +822,7 @@ impl<'a> Iterator for GlyphIterator<'a> { }; let i = self.byte_index; if !self.byte_range.contains(i) { - return None + return None; } debug_assert!(i < self.store.len()); let entry = self.store.entry_buffer[i.to_usize()]; diff --git a/components/gfx/text/mod.rs b/components/gfx/text/mod.rs index 5aae0876428f..24c434e2e699 100644 --- a/components/gfx/text/mod.rs +++ b/components/gfx/text/mod.rs @@ -9,4 +9,3 @@ pub mod glyph; pub mod shaping; pub mod text_run; pub mod util; - diff --git a/components/gfx/text/shaping/harfbuzz.rs b/components/gfx/text/shaping/harfbuzz.rs index a07003b6ec30..eb6b7b8cd4aa 100644 --- a/components/gfx/text/shaping/harfbuzz.rs +++ b/components/gfx/text/shaping/harfbuzz.rs @@ -147,10 +147,11 @@ impl Drop for Shaper { impl Shaper { pub fn new(font: *const Font) -> Shaper { unsafe { - let hb_face: *mut hb_face_t = - hb_face_create_for_tables(Some(font_table_func), - font as *const c_void as *mut c_void, - None); + let hb_face: *mut hb_face_t = hb_face_create_for_tables( + Some(font_table_func), + font as *const c_void as *mut c_void, + None, + ); let hb_font: *mut hb_font_t = hb_font_create(hb_face); // Set points-per-em. if zero, performs no hinting in that direction. @@ -158,12 +159,19 @@ impl Shaper { hb_font_set_ppem(hb_font, pt_size as c_uint, pt_size as c_uint); // Set scaling. Note that this takes 16.16 fixed point. - hb_font_set_scale(hb_font, - Shaper::float_to_fixed(pt_size) as c_int, - Shaper::float_to_fixed(pt_size) as c_int); + hb_font_set_scale( + hb_font, + Shaper::float_to_fixed(pt_size) as c_int, + Shaper::float_to_fixed(pt_size) as c_int, + ); // configure static function callbacks. - hb_font_set_funcs(hb_font, HB_FONT_FUNCS.0, font as *mut Font as *mut c_void, None); + hb_font_set_funcs( + hb_font, + HB_FONT_FUNCS.0, + font as *mut Font as *mut c_void, + None, + ); Shaper { hb_face: hb_face, @@ -188,22 +196,30 @@ impl ShaperMethods for Shaper { fn shape_text(&self, text: &str, options: &ShapingOptions, glyphs: &mut GlyphStore) { unsafe { let hb_buffer: *mut hb_buffer_t = hb_buffer_create(); - hb_buffer_set_direction(hb_buffer, if options.flags.contains(ShapingFlags::RTL_FLAG) { - HB_DIRECTION_RTL - } else { - HB_DIRECTION_LTR - }); + hb_buffer_set_direction( + hb_buffer, + if options.flags.contains(ShapingFlags::RTL_FLAG) { + HB_DIRECTION_RTL + } else { + HB_DIRECTION_LTR + }, + ); hb_buffer_set_script(hb_buffer, options.script.to_hb_script()); - hb_buffer_add_utf8(hb_buffer, - text.as_ptr() as *const c_char, - text.len() as c_int, - 0, - text.len() as c_int); + hb_buffer_add_utf8( + hb_buffer, + text.as_ptr() as *const c_char, + text.len() as c_int, + 0, + text.len() as c_int, + ); let mut features = Vec::new(); - if options.flags.contains(ShapingFlags::IGNORE_LIGATURES_SHAPING_FLAG) { + if options + .flags + .contains(ShapingFlags::IGNORE_LIGATURES_SHAPING_FLAG) + { features.push(hb_feature_t { tag: LIGA, value: 0, @@ -211,7 +227,10 @@ impl ShaperMethods for Shaper { end: hb_buffer_get_length(hb_buffer), }) } - if options.flags.contains(ShapingFlags::DISABLE_KERNING_SHAPING_FLAG) { + if options + .flags + .contains(ShapingFlags::DISABLE_KERNING_SHAPING_FLAG) + { features.push(hb_feature_t { tag: KERN, value: 0, @@ -220,7 +239,12 @@ impl ShaperMethods for Shaper { }) } - hb_shape(self.hb_font, hb_buffer, features.as_mut_ptr(), features.len() as u32); + hb_shape( + self.hb_font, + hb_buffer, + features.as_mut_ptr(), + features.len() as u32, + ); self.save_glyph_results(text, options, glyphs, hb_buffer); hb_buffer_destroy(hb_buffer); } @@ -228,18 +252,21 @@ impl ShaperMethods for Shaper { } impl Shaper { - fn save_glyph_results(&self, - text: &str, - options: &ShapingOptions, - glyphs: &mut GlyphStore, - buffer: *mut hb_buffer_t) { + fn save_glyph_results( + &self, + text: &str, + options: &ShapingOptions, + glyphs: &mut GlyphStore, + buffer: *mut hb_buffer_t, + ) { let glyph_data = ShapedGlyphData::new(buffer); let glyph_count = glyph_data.len(); let byte_max = text.len(); - debug!("Shaped text[byte count={}], got back {} glyph info records.", - byte_max, - glyph_count); + debug!( + "Shaped text[byte count={}], got back {} glyph info records.", + byte_max, glyph_count + ); // make map of what chars have glyphs let mut byte_to_glyph = vec![NO_GLYPH; byte_max]; @@ -250,9 +277,10 @@ impl Shaper { if loc < byte_max { byte_to_glyph[loc] = i as i32; } else { - debug!("ERROR: tried to set out of range byte_to_glyph: idx={}, glyph idx={}", - loc, - i); + debug!( + "ERROR: tried to set out of range byte_to_glyph: idx={}, glyph idx={}", + loc, i + ); } debug!("{} -> {}", i, loc); } @@ -296,10 +324,14 @@ impl Shaper { } // if there's just one glyph, then we don't need further checks. - if glyph_span.len() == 1 { break; } + if glyph_span.len() == 1 { + break; + } // if no glyphs were found yet, extend the char byte range more. - if glyph_span.len() == 0 { continue; } + if glyph_span.len() == 0 { + continue; + } // If byte_range now includes all the byte offsets found in glyph_span, then we // have found a contiguous "cluster" and can stop extending it. @@ -308,11 +340,11 @@ impl Shaper { let loc = glyph_data.byte_offset_of_glyph(j) as usize; if !(byte_range.start <= loc && loc < byte_range.end) { all_glyphs_are_within_cluster = false; - break + break; } } if all_glyphs_are_within_cluster { - break + break; } // Otherwise, the bytes we have seen so far correspond to a non-contiguous set of @@ -348,34 +380,29 @@ impl Shaper { const TAB_COLS: i32 = 8; let (space_glyph_id, space_advance) = glyph_space_advance(self.font); let advance = Au::from_f64_px(space_advance) * TAB_COLS; - let data = GlyphData::new(space_glyph_id, - advance, - Default::default(), - true, - true); + let data = + GlyphData::new(space_glyph_id, advance, Default::default(), true, true); glyphs.add_glyph_for_byte_index(byte_idx, character, &data); } else { let shape = glyph_data.entry_for_glyph(glyph_span.start, &mut y_pos); let advance = self.advance_for_shaped_glyph(shape.advance, character, options); - let data = GlyphData::new(shape.codepoint, - advance, - shape.offset, - true, - true); + let data = GlyphData::new(shape.codepoint, advance, shape.offset, true, true); glyphs.add_glyph_for_byte_index(byte_idx, character, &data); } } else { // collect all glyphs to be assigned to the first character. - let mut datas = vec!(); + let mut datas = vec![]; for glyph_i in glyph_span.clone() { let shape = glyph_data.entry_for_glyph(glyph_i, &mut y_pos); - datas.push(GlyphData::new(shape.codepoint, - shape.advance, - shape.offset, - true, // treat as cluster start - glyph_i > glyph_span.start)); - // all but first are ligature continuations + datas.push(GlyphData::new( + shape.codepoint, + shape.advance, + shape.offset, + true, // treat as cluster start + glyph_i > glyph_span.start, + )); + // all but first are ligature continuations } // now add the detailed glyph entry. glyphs.add_glyphs_for_byte_index(byte_idx, &datas); @@ -390,8 +417,12 @@ impl Shaper { glyphs.finalize_changes(); } - fn advance_for_shaped_glyph(&self, mut advance: Au, character: char, options: &ShapingOptions) - -> Au { + fn advance_for_shaped_glyph( + &self, + mut advance: Au, + character: char, + options: &ShapingOptions, + ) -> Au { if let Some(letter_spacing) = options.letter_spacing { advance = advance + letter_spacing; }; @@ -403,7 +434,8 @@ impl Shaper { if character == ' ' || character == '\u{a0}' { // https://drafts.csswg.org/css-text-3/#word-spacing-property let (length, percent) = options.word_spacing; - advance = (advance + length) + Au::new((advance.0 as f32 * percent.into_inner()) as i32); + advance = + (advance + length) + Au::new((advance.0 as f32 * percent.into_inner()) as i32); } advance @@ -420,20 +452,29 @@ lazy_static! { let hb_funcs = hb_font_funcs_create(); hb_font_funcs_set_nominal_glyph_func(hb_funcs, Some(glyph_func), ptr::null_mut(), None); hb_font_funcs_set_glyph_h_advance_func( - hb_funcs, Some(glyph_h_advance_func), ptr::null_mut(), None); + hb_funcs, + Some(glyph_h_advance_func), + ptr::null_mut(), + None, + ); hb_font_funcs_set_glyph_h_kerning_func( - hb_funcs, Some(glyph_h_kerning_func), ptr::null_mut(), None); + hb_funcs, + Some(glyph_h_kerning_func), + ptr::null_mut(), + None, + ); FontFuncs(hb_funcs) }; } -extern fn glyph_func(_: *mut hb_font_t, - font_data: *mut c_void, - unicode: hb_codepoint_t, - glyph: *mut hb_codepoint_t, - _: *mut c_void) - -> hb_bool_t { +extern "C" fn glyph_func( + _: *mut hb_font_t, + font_data: *mut c_void, + unicode: hb_codepoint_t, + glyph: *mut hb_codepoint_t, + _: *mut c_void, +) -> hb_bool_t { let font: *const Font = font_data as *const Font; assert!(!font.is_null()); @@ -442,17 +483,18 @@ extern fn glyph_func(_: *mut hb_font_t, Some(g) => { *glyph = g as hb_codepoint_t; true as hb_bool_t - } - None => false as hb_bool_t + }, + None => false as hb_bool_t, } } } -extern fn glyph_h_advance_func(_: *mut hb_font_t, - font_data: *mut c_void, - glyph: hb_codepoint_t, - _: *mut c_void) - -> hb_position_t { +extern "C" fn glyph_h_advance_func( + _: *mut hb_font_t, + font_data: *mut c_void, + glyph: hb_codepoint_t, + _: *mut c_void, +) -> hb_position_t { let font: *mut Font = font_data as *mut Font; assert!(!font.is_null()); @@ -468,19 +510,20 @@ fn glyph_space_advance(font: *const Font) -> (hb_codepoint_t, f64) { match unsafe { (*font).glyph_index(space_unicode) } { Some(g) => { space_glyph = g as hb_codepoint_t; - } - None => panic!("No space info") + }, + None => panic!("No space info"), } let space_advance = unsafe { (*font).glyph_h_advance(space_glyph as GlyphId) }; (space_glyph, space_advance) } -extern fn glyph_h_kerning_func(_: *mut hb_font_t, - font_data: *mut c_void, - first_glyph: hb_codepoint_t, - second_glyph: hb_codepoint_t, - _: *mut c_void) - -> hb_position_t { +extern "C" fn glyph_h_kerning_func( + _: *mut hb_font_t, + font_data: *mut c_void, + first_glyph: hb_codepoint_t, + second_glyph: hb_codepoint_t, + _: *mut c_void, +) -> hb_position_t { let font: *mut Font = font_data as *mut Font; assert!(!font.is_null()); @@ -491,10 +534,11 @@ extern fn glyph_h_kerning_func(_: *mut hb_font_t, } // Callback to get a font table out of a font. -extern fn font_table_func(_: *mut hb_face_t, - tag: hb_tag_t, - user_data: *mut c_void) - -> *mut hb_blob_t { +extern "C" fn font_table_func( + _: *mut hb_face_t, + tag: hb_tag_t, + user_data: *mut c_void, +) -> *mut hb_blob_t { unsafe { // NB: These asserts have security implications. let font = user_data as *const Font; @@ -511,20 +555,22 @@ extern fn font_table_func(_: *mut hb_face_t, let buf = (*font_table_ptr).buffer(); // HarfBuzz calls `destroy_blob_func` when the buffer is no longer needed. - let blob = hb_blob_create(buf.as_ptr() as *const c_char, - buf.len() as c_uint, - HB_MEMORY_MODE_READONLY, - font_table_ptr as *mut c_void, - Some(destroy_blob_func)); + let blob = hb_blob_create( + buf.as_ptr() as *const c_char, + buf.len() as c_uint, + HB_MEMORY_MODE_READONLY, + font_table_ptr as *mut c_void, + Some(destroy_blob_func), + ); assert!(!blob.is_null()); blob - } + }, } } } -extern fn destroy_blob_func(font_table_ptr: *mut c_void) { +extern "C" fn destroy_blob_func(font_table_ptr: *mut c_void) { unsafe { drop(Box::from_raw(font_table_ptr as *mut FontTable)); } diff --git a/components/gfx/text/shaping/mod.rs b/components/gfx/text/shaping/mod.rs index 79e5452db061..97d969805967 100644 --- a/components/gfx/text/shaping/mod.rs +++ b/components/gfx/text/shaping/mod.rs @@ -17,4 +17,3 @@ pub mod harfbuzz; pub trait ShaperMethods { fn shape_text(&self, text: &str, options: &ShapingOptions, glyphs: &mut GlyphStore); } - diff --git a/components/gfx/text/text_run.rs b/components/gfx/text/text_run.rs index 62126ab838a7..39b96a934e65 100644 --- a/components/gfx/text/text_run.rs +++ b/components/gfx/text/text_run.rs @@ -155,7 +155,7 @@ impl<'a> Iterator for CharacterSliceIterator<'a> { let byte_start = self.range.begin(); let byte_len = match self.text[byte_start.to_usize()..].chars().next() { Some(ch) => ByteIndex(ch.len_utf8() as isize), - None => unreachable!() // XXX refactor? + None => unreachable!(), // XXX refactor? }; self.range.adjust_by(byte_len, -byte_len); @@ -178,24 +178,36 @@ impl<'a> Iterator for CharacterSliceIterator<'a> { impl<'a> TextRun { /// Constructs a new text run. Also returns if there is a line break at the beginning - pub fn new(font: &mut Font, text: String, options: &ShapingOptions, - bidi_level: bidi::Level, breaker: &mut Option) -> (TextRun, bool) { + pub fn new( + font: &mut Font, + text: String, + options: &ShapingOptions, + bidi_level: bidi::Level, + breaker: &mut Option, + ) -> (TextRun, bool) { let (glyphs, break_at_zero) = TextRun::break_and_shape(font, &text, options, breaker); - (TextRun { - text: Arc::new(text), - font_metrics: font.metrics.clone(), - font_template: font.handle.template(), - font_key: font.font_key, - actual_pt_size: font.actual_pt_size, - glyphs: Arc::new(glyphs), - bidi_level: bidi_level, - extra_word_spacing: Au(0), - }, break_at_zero) + ( + TextRun { + text: Arc::new(text), + font_metrics: font.metrics.clone(), + font_template: font.handle.template(), + font_key: font.font_key, + actual_pt_size: font.actual_pt_size, + glyphs: Arc::new(glyphs), + bidi_level: bidi_level, + extra_word_spacing: Au(0), + }, + break_at_zero, + ) } - pub fn break_and_shape(font: &mut Font, text: &str, options: &ShapingOptions, - breaker: &mut Option) -> (Vec, bool) { - let mut glyphs = vec!(); + pub fn break_and_shape( + font: &mut Font, + text: &str, + options: &ShapingOptions, + breaker: &mut Option, + ) -> (Vec, bool) { + let mut glyphs = vec![]; let mut slice = 0..0; let mut finished = false; @@ -203,7 +215,7 @@ impl<'a> TextRun { if breaker.is_none() { if text.len() == 0 { - return (glyphs, true) + return (glyphs, true); } *breaker = Some(LineBreakLeafIter::new(&text, 0)); } @@ -225,29 +237,39 @@ impl<'a> TextRun { // Split off any trailing whitespace into a separate glyph run. let mut whitespace = slice.end..slice.end; - if let Some((i, _)) = word.char_indices().rev() - .take_while(|&(_, c)| char_is_whitespace(c)).last() { - whitespace.start = slice.start + i; - slice.end = whitespace.start; - } else if idx != text.len() && options.flags.contains(ShapingFlags::KEEP_ALL_FLAG) { - // If there's no whitespace and word-break is set to - // keep-all, try increasing the slice. - continue; - } + if let Some((i, _)) = word + .char_indices() + .rev() + .take_while(|&(_, c)| char_is_whitespace(c)) + .last() + { + whitespace.start = slice.start + i; + slice.end = whitespace.start; + } else if idx != text.len() && options.flags.contains(ShapingFlags::KEEP_ALL_FLAG) { + // If there's no whitespace and word-break is set to + // keep-all, try increasing the slice. + continue; + } if slice.len() > 0 { glyphs.push(GlyphRun { glyph_store: font.shape_text(&text[slice.clone()], options), - range: Range::new(ByteIndex(slice.start as isize), - ByteIndex(slice.len() as isize)), + range: Range::new( + ByteIndex(slice.start as isize), + ByteIndex(slice.len() as isize), + ), }); } if whitespace.len() > 0 { let mut options = options.clone(); - options.flags.insert(ShapingFlags::IS_WHITESPACE_SHAPING_FLAG); + options + .flags + .insert(ShapingFlags::IS_WHITESPACE_SHAPING_FLAG); glyphs.push(GlyphRun { glyph_store: font.shape_text(&text[whitespace.clone()], &options), - range: Range::new(ByteIndex(whitespace.start as isize), - ByteIndex(whitespace.len() as isize)), + range: Range::new( + ByteIndex(whitespace.start as isize), + ByteIndex(whitespace.len() as isize), + ), }); } slice.start = whitespace.end; @@ -265,36 +287,46 @@ impl<'a> TextRun { pub fn advance_for_range(&self, range: &Range) -> Au { if range.is_empty() { - return Au(0) + 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) .fold(Au(0), |advance, slice| { - advance + slice.glyphs.advance_for_byte_range(&slice.range, self.extra_word_spacing) + advance + slice + .glyphs + .advance_for_byte_range(&slice.range, self.extra_word_spacing) }) } pub fn metrics_for_range(&self, range: &Range) -> RunMetrics { - RunMetrics::new(self.advance_for_range(range), - self.font_metrics.ascent, - self.font_metrics.descent) + RunMetrics::new( + self.advance_for_range(range), + self.font_metrics.ascent, + self.font_metrics.descent, + ) } - pub fn metrics_for_slice(&self, glyphs: &GlyphStore, slice_range: &Range) - -> RunMetrics { - RunMetrics::new(glyphs.advance_for_byte_range(slice_range, self.extra_word_spacing), - self.font_metrics.ascent, - self.font_metrics.descent) + pub fn metrics_for_slice( + &self, + glyphs: &GlyphStore, + slice_range: &Range, + ) -> RunMetrics { + RunMetrics::new( + glyphs.advance_for_byte_range(slice_range, self.extra_word_spacing), + self.font_metrics.ascent, + self.font_metrics.descent, + ) } pub fn min_width_for_range(&self, range: &Range) -> Au { debug!("iterating outer range {:?}", range); - self.natural_word_slices_in_range(range).fold(Au(0), |max_piece_width, slice| { - debug!("iterated on {:?}[{:?}]", slice.offset, slice.range); - max(max_piece_width, self.advance_for_range(&slice.range)) - }) + self.natural_word_slices_in_range(range) + .fold(Au(0), |max_piece_width, slice| { + debug!("iterated on {:?}[{:?}]", slice.offset, slice.range); + max(max_piece_width, self.advance_for_range(&slice.range)) + }) } pub fn minimum_splittable_inline_size(&self, range: &Range) -> Au { @@ -309,13 +341,15 @@ impl<'a> TextRun { 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() { + index_of_first_glyph_run_cache.get() + { if last_text_run == self_ptr && last_index == index { - return Some(last_result) + return Some(last_result); } } - if let Ok(result) = (&**self.glyphs).binary_search_by(|current| current.compare(&index)) { + if let Ok(result) = (&**self.glyphs).binary_search_by(|current| current.compare(&index)) + { index_of_first_glyph_run_cache.set(Some((self_ptr, index, result))); Some(result) } else { @@ -339,18 +373,22 @@ impl<'a> TextRun { let mut remaining = advance; self.natural_word_slices_in_range(range) .map(|slice| { - let (slice_index, slice_advance) = - slice.glyphs.range_index_of_advance(&slice.range, remaining, self.extra_word_spacing); + let (slice_index, slice_advance) = slice.glyphs.range_index_of_advance( + &slice.range, + remaining, + self.extra_word_spacing, + ); remaining -= slice_advance; slice_index - }) - .sum() + }).sum() } /// Returns an iterator that will iterate over all slices of glyphs that represent natural /// words in the given range. - pub fn natural_word_slices_in_range(&'a self, range: &Range) - -> NaturalWordSliceIterator<'a> { + pub fn natural_word_slices_in_range( + &'a self, + range: &Range, + ) -> NaturalWordSliceIterator<'a> { let index = match self.index_of_first_glyph_run_containing(range.begin()) { None => self.glyphs.len(), Some(index) => index, @@ -365,20 +403,22 @@ impl<'a> TextRun { /// Returns an iterator that over natural word slices in visual order (left to right or /// right to left, depending on the bidirectional embedding level). - pub fn natural_word_slices_in_visual_order(&'a self, range: &Range) - -> NaturalWordSliceIterator<'a> { + pub fn natural_word_slices_in_visual_order( + &'a self, + range: &Range, + ) -> NaturalWordSliceIterator<'a> { // Iterate in reverse order if bidi level is RTL. let reverse = self.bidi_level.is_rtl(); let index = if reverse { match self.index_of_first_glyph_run_containing(range.end() - ByteIndex(1)) { Some(i) => i + 1, // In reverse mode, index points one past the next element. - None => 0 + None => 0, } } else { match self.index_of_first_glyph_run_containing(range.begin()) { Some(i) => i, - None => self.glyphs.len() + None => self.glyphs.len(), } }; NaturalWordSliceIterator { @@ -391,8 +431,10 @@ impl<'a> TextRun { /// Returns an iterator that will iterate over all slices of glyphs that represent individual /// characters in the given range. - pub fn character_slices_in_range(&'a self, range: &Range) - -> CharacterSliceIterator<'a> { + pub fn character_slices_in_range( + &'a self, + range: &Range, + ) -> CharacterSliceIterator<'a> { let index = match self.index_of_first_glyph_run_containing(range.begin()) { None => self.glyphs.len(), Some(index) => index, diff --git a/components/gfx/text/util.rs b/components/gfx/text/util.rs index f740c4a54e6c..b1bf25724ba5 100644 --- a/components/gfx/text/util.rs +++ b/components/gfx/text/util.rs @@ -9,7 +9,7 @@ pub enum CompressionMode { CompressNone, CompressWhitespace, CompressWhitespaceNewline, - DiscardNewline + DiscardNewline, } // ported from Gecko's nsTextFrameUtils::TransformText. @@ -22,11 +22,12 @@ pub enum CompressionMode { // * Issue #114: record skipped and kept chars for mapping original to new text // // * Untracked: various edge cases for bidi, CJK, etc. -pub fn transform_text(text: &str, - mode: CompressionMode, - incoming_whitespace: bool, - output_text: &mut String) - -> bool { +pub fn transform_text( + text: &str, + mode: CompressionMode, + incoming_whitespace: bool, + output_text: &mut String, +) -> bool { let out_whitespace = match mode { CompressionMode::CompressNone | CompressionMode::DiscardNewline => { for ch in text.chars() { @@ -53,12 +54,13 @@ pub fn transform_text(text: &str, if is_always_discardable_char(ch) { // revert whitespace setting, since this char was discarded next_in_whitespace = in_whitespace; - // TODO: record skipped char + // TODO: record skipped char } else { // TODO: record kept char output_text.push(ch); } - } else { /* next_in_whitespace; possibly add a space char */ + } else { + /* next_in_whitespace; possibly add a space char */ if in_whitespace { // TODO: record skipped char } else { @@ -70,17 +72,17 @@ pub fn transform_text(text: &str, in_whitespace = next_in_whitespace; } /* /for str::each_char */ in_whitespace - } + }, }; return out_whitespace; fn is_in_whitespace(ch: char, mode: CompressionMode) -> bool { match (ch, mode) { - (' ', _) => true, + (' ', _) => true, ('\t', _) => true, ('\n', CompressionMode::CompressWhitespaceNewline) => true, - (_, _) => false + (_, _) => false, } } @@ -89,8 +91,10 @@ pub fn transform_text(text: &str, return true; } match mode { - CompressionMode::DiscardNewline | CompressionMode::CompressWhitespaceNewline => ch == '\n', - _ => false + CompressionMode::DiscardNewline | CompressionMode::CompressWhitespaceNewline => { + ch == '\n' + }, + _ => false, } } @@ -113,7 +117,7 @@ pub fn is_bidi_control(c: char) -> bool { '\u{202A}'...'\u{202E}' => true, '\u{2066}'...'\u{2069}' => true, '\u{200E}' | '\u{200F}' | '\u{061C}' => true, - _ => false + _ => false, } } @@ -143,15 +147,12 @@ pub fn is_cjk(codepoint: char) -> bool { UnicodeBlock::CJKUnifiedIdeographs | UnicodeBlock::CJKCompatibilityIdeographs | UnicodeBlock::CJKCompatibilityForms | - UnicodeBlock::HalfwidthandFullwidthForms => { - return true - } + UnicodeBlock::HalfwidthandFullwidthForms => return true, - _ => {} + _ => {}, } } - // https://en.wikipedia.org/wiki/Plane_(Unicode)#Supplementary_Ideographic_Plane unicode_plane(codepoint) == 2 }