aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/gfx/text/glyph.rs257
-rw-r--r--components/gfx/text/mod.rs1
-rw-r--r--components/gfx/text/shaping/harfbuzz.rs226
-rw-r--r--components/gfx/text/shaping/mod.rs1
-rw-r--r--components/gfx/text/text_run.rs162
-rw-r--r--components/gfx/text/util.rs39
6 files changed, 420 insertions, 266 deletions
diff --git a/components/gfx/text/glyph.rs b/components/gfx/text/glyph.rs
index 78f02881058..8e4c56e309b 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<DetailedGlyphRecord> = vec!();
+ let mut unsorted_records: Vec<DetailedGlyphRecord> = vec![];
mem::swap(&mut self.detail_lookup, &mut unsorted_records);
let mut mut_records: Vec<DetailedGlyphRecord> = 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<Point2D<Au>>,
- cluster_start: bool,
- ligature_start: bool)
- -> GlyphData {
+ pub fn new(
+ id: GlyphId,
+ advance: Au,
+ offset: Option<Point2D<Au>>,
+ 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<Point2D<Au>> {
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<DetailedGlyph> = (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<DetailedGlyph> = (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<ByteIndex>, advance: Au, extra_word_spacing: Au) -> (usize, Au) {
+ pub fn range_index_of_advance(
+ &self,
+ range: &Range<ByteIndex>,
+ 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<ByteIndex>, extra_word_spacing: Au) -> Au {
+ pub fn advance_for_byte_range_slow_path(
+ &self,
+ range: &Range<ByteIndex>,
+ 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<ByteIndex>, extra_word_spacing: Au) -> Au {
+ fn advance_for_byte_range_simple_glyphs(
+ &self,
+ range: &Range<ByteIndex>,
+ 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<ByteIndex>, 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<ByteIndex>,
+ 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<GlyphInfo<'a>> {
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<GlyphInfo<'a>> {
- 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<GlyphInfo<'a>> {
// 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 5aae0876428..24c434e2e69 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 a07003b6ec3..eb6b7b8cd4a 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 79e5452db06..97d96980596 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 62126ab838a..39b96a934e6 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<LineBreakLeafIter>) -> (TextRun, bool) {
+ pub fn new(
+ font: &mut Font,
+ text: String,
+ options: &ShapingOptions,
+ bidi_level: bidi::Level,
+ breaker: &mut Option<LineBreakLeafIter>,
+ ) -> (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<LineBreakLeafIter>) -> (Vec<GlyphRun>, bool) {
- let mut glyphs = vec!();
+ pub fn break_and_shape(
+ font: &mut Font,
+ text: &str,
+ options: &ShapingOptions,
+ breaker: &mut Option<LineBreakLeafIter>,
+ ) -> (Vec<GlyphRun>, 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<ByteIndex>) -> 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<ByteIndex>) -> 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<ByteIndex>)
- -> 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<ByteIndex>,
+ ) -> 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<ByteIndex>) -> 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<ByteIndex>) -> 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<ByteIndex>)
- -> NaturalWordSliceIterator<'a> {
+ pub fn natural_word_slices_in_range(
+ &'a self,
+ range: &Range<ByteIndex>,
+ ) -> 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<ByteIndex>)
- -> NaturalWordSliceIterator<'a> {
+ pub fn natural_word_slices_in_visual_order(
+ &'a self,
+ range: &Range<ByteIndex>,
+ ) -> 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<ByteIndex>)
- -> CharacterSliceIterator<'a> {
+ pub fn character_slices_in_range(
+ &'a self,
+ range: &Range<ByteIndex>,
+ ) -> 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 f740c4a54e6..b1bf25724ba 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
}