1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 use app_units::Au;
6 use font::{Font, FontHandleMethods, FontMetrics, ShapingFlags};
7 use font::{RunMetrics, ShapingOptions};
8 use platform::font_template::FontTemplateData;
9 use range::Range;
10 use std::cell::Cell;
11 use std::cmp::{Ordering, max};
12 use std::slice::Iter;
13 use std::sync::Arc;
14 use style::str::char_is_whitespace;
15 use text::glyph::{ByteIndex, GlyphStore};
16 use unicode_bidi as bidi;
17 use webrender_api;
18 use xi_unicode::LineBreakLeafIter;
19 
20 thread_local! {
21     static INDEX_OF_FIRST_GLYPH_RUN_CACHE: Cell<Option<(*const TextRun, ByteIndex, usize)>> =
22         Cell::new(None)
23 }
24 
25 /// A single "paragraph" of text in one font size and style.
26 #[derive(Clone, Deserialize, Serialize)]
27 pub struct TextRun {
28     /// The UTF-8 string represented by this text run.
29     pub text: Arc<String>,
30     pub font_template: Arc<FontTemplateData>,
31     pub actual_pt_size: Au,
32     pub font_metrics: FontMetrics,
33     pub font_key: webrender_api::FontInstanceKey,
34     /// The glyph runs that make up this text run.
35     pub glyphs: Arc<Vec<GlyphRun>>,
36     pub bidi_level: bidi::Level,
37     pub extra_word_spacing: Au,
38 }
39 
40 impl Drop for TextRun {
drop(&mut self)41     fn drop(&mut self) {
42         // Invalidate the glyph run cache if it was our text run that got freed.
43         INDEX_OF_FIRST_GLYPH_RUN_CACHE.with(|index_of_first_glyph_run_cache| {
44             if let Some((text_run_ptr, _, _)) = index_of_first_glyph_run_cache.get() {
45                 if text_run_ptr == (self as *const TextRun) {
46                     index_of_first_glyph_run_cache.set(None);
47                 }
48             }
49         })
50     }
51 }
52 
53 /// A single series of glyphs within a text run.
54 #[derive(Clone, Deserialize, Serialize)]
55 pub struct GlyphRun {
56     /// The glyphs.
57     pub glyph_store: Arc<GlyphStore>,
58     /// The byte range of characters in the containing run.
59     pub range: Range<ByteIndex>,
60 }
61 
62 pub struct NaturalWordSliceIterator<'a> {
63     glyphs: &'a [GlyphRun],
64     index: usize,
65     range: Range<ByteIndex>,
66     reverse: bool,
67 }
68 
69 impl GlyphRun {
compare(&self, key: &ByteIndex) -> Ordering70     fn compare(&self, key: &ByteIndex) -> Ordering {
71         if *key < self.range.begin() {
72             Ordering::Greater
73         } else if *key >= self.range.end() {
74             Ordering::Less
75         } else {
76             Ordering::Equal
77         }
78     }
79 }
80 
81 /// A "slice" of a text run is a series of contiguous glyphs that all belong to the same glyph
82 /// store. Line breaking strategies yield these.
83 pub struct TextRunSlice<'a> {
84     /// The glyph store that the glyphs in this slice belong to.
85     pub glyphs: &'a GlyphStore,
86     /// The byte index that this slice begins at, relative to the start of the *text run*.
87     pub offset: ByteIndex,
88     /// The range that these glyphs encompass, relative to the start of the *glyph store*.
89     pub range: Range<ByteIndex>,
90 }
91 
92 impl<'a> TextRunSlice<'a> {
93     /// Returns the range that these glyphs encompass, relative to the start of the *text run*.
94     #[inline]
text_run_range(&self) -> Range<ByteIndex>95     pub fn text_run_range(&self) -> Range<ByteIndex> {
96         let mut range = self.range;
97         range.shift_by(self.offset);
98         range
99     }
100 }
101 
102 impl<'a> Iterator for NaturalWordSliceIterator<'a> {
103     type Item = TextRunSlice<'a>;
104 
105     // inline(always) due to the inefficient rt failures messing up inline heuristics, I think.
106     #[inline(always)]
next(&mut self) -> Option<TextRunSlice<'a>>107     fn next(&mut self) -> Option<TextRunSlice<'a>> {
108         let slice_glyphs;
109         if self.reverse {
110             if self.index == 0 {
111                 return None;
112             }
113             self.index -= 1;
114             slice_glyphs = &self.glyphs[self.index];
115         } else {
116             if self.index >= self.glyphs.len() {
117                 return None;
118             }
119             slice_glyphs = &self.glyphs[self.index];
120             self.index += 1;
121         }
122 
123         let mut byte_range = self.range.intersect(&slice_glyphs.range);
124         let slice_range_begin = slice_glyphs.range.begin();
125         byte_range.shift_by(-slice_range_begin);
126 
127         if !byte_range.is_empty() {
128             Some(TextRunSlice {
129                 glyphs: &*slice_glyphs.glyph_store,
130                 offset: slice_range_begin,
131                 range: byte_range,
132             })
133         } else {
134             None
135         }
136     }
137 }
138 
139 pub struct CharacterSliceIterator<'a> {
140     text: &'a str,
141     glyph_run: Option<&'a GlyphRun>,
142     glyph_run_iter: Iter<'a, GlyphRun>,
143     range: Range<ByteIndex>,
144 }
145 
146 impl<'a> Iterator for CharacterSliceIterator<'a> {
147     type Item = TextRunSlice<'a>;
148 
149     // inline(always) due to the inefficient rt failures messing up inline heuristics, I think.
150     #[inline(always)]
next(&mut self) -> Option<TextRunSlice<'a>>151     fn next(&mut self) -> Option<TextRunSlice<'a>> {
152         let glyph_run = self.glyph_run?;
153 
154         debug_assert!(!self.range.is_empty());
155         let byte_start = self.range.begin();
156         let byte_len = match self.text[byte_start.to_usize()..].chars().next() {
157             Some(ch) => ByteIndex(ch.len_utf8() as isize),
158             None => unreachable!() // XXX refactor?
159         };
160 
161         self.range.adjust_by(byte_len, -byte_len);
162         if self.range.is_empty() {
163             // We're done.
164             self.glyph_run = None
165         } else if self.range.intersect(&glyph_run.range).is_empty() {
166             // Move on to the next glyph run.
167             self.glyph_run = self.glyph_run_iter.next();
168         }
169 
170         let index_within_glyph_run = byte_start - glyph_run.range.begin();
171         Some(TextRunSlice {
172             glyphs: &*glyph_run.glyph_store,
173             offset: glyph_run.range.begin(),
174             range: Range::new(index_within_glyph_run, byte_len),
175         })
176     }
177 }
178 
179 impl<'a> TextRun {
180     /// Constructs a new text run. Also returns if there is a line break at the beginning
new(font: &mut Font, text: String, options: &ShapingOptions, bidi_level: bidi::Level, breaker: &mut Option<LineBreakLeafIter>) -> (TextRun, bool)181     pub fn new(font: &mut Font, text: String, options: &ShapingOptions,
182                bidi_level: bidi::Level, breaker: &mut Option<LineBreakLeafIter>) -> (TextRun, bool) {
183         let (glyphs, break_at_zero) = TextRun::break_and_shape(font, &text, options, breaker);
184         (TextRun {
185             text: Arc::new(text),
186             font_metrics: font.metrics.clone(),
187             font_template: font.handle.template(),
188             font_key: font.font_key,
189             actual_pt_size: font.actual_pt_size,
190             glyphs: Arc::new(glyphs),
191             bidi_level: bidi_level,
192             extra_word_spacing: Au(0),
193         }, break_at_zero)
194     }
195 
break_and_shape(font: &mut Font, text: &str, options: &ShapingOptions, breaker: &mut Option<LineBreakLeafIter>) -> (Vec<GlyphRun>, bool)196     pub fn break_and_shape(font: &mut Font, text: &str, options: &ShapingOptions,
197                            breaker: &mut Option<LineBreakLeafIter>) -> (Vec<GlyphRun>, bool) {
198         let mut glyphs = vec!();
199         let mut slice = 0..0;
200 
201         let mut finished = false;
202         let mut break_at_zero = false;
203 
204         if breaker.is_none() {
205             if text.len() == 0 {
206                 return (glyphs, true)
207             }
208             *breaker = Some(LineBreakLeafIter::new(&text, 0));
209         }
210 
211         let breaker = breaker.as_mut().unwrap();
212 
213         while !finished {
214             let (idx, _is_hard_break) = breaker.next(text);
215             if idx == text.len() {
216                 finished = true;
217             }
218             if idx == 0 {
219                 break_at_zero = true;
220             }
221 
222             // Extend the slice to the next UAX#14 line break opportunity.
223             slice.end = idx;
224             let word = &text[slice.clone()];
225 
226             // Split off any trailing whitespace into a separate glyph run.
227             let mut whitespace = slice.end..slice.end;
228             if let Some((i, _)) = word.char_indices().rev()
229                 .take_while(|&(_, c)| char_is_whitespace(c)).last() {
230                     whitespace.start = slice.start + i;
231                     slice.end = whitespace.start;
232                 } else if idx != text.len() && options.flags.contains(ShapingFlags::KEEP_ALL_FLAG) {
233                     // If there's no whitespace and word-break is set to
234                     // keep-all, try increasing the slice.
235                     continue;
236                 }
237             if slice.len() > 0 {
238                 glyphs.push(GlyphRun {
239                     glyph_store: font.shape_text(&text[slice.clone()], options),
240                     range: Range::new(ByteIndex(slice.start as isize),
241                                       ByteIndex(slice.len() as isize)),
242                 });
243             }
244             if whitespace.len() > 0 {
245                 let mut options = options.clone();
246                 options.flags.insert(ShapingFlags::IS_WHITESPACE_SHAPING_FLAG);
247                 glyphs.push(GlyphRun {
248                     glyph_store: font.shape_text(&text[whitespace.clone()], &options),
249                     range: Range::new(ByteIndex(whitespace.start as isize),
250                                       ByteIndex(whitespace.len() as isize)),
251                 });
252             }
253             slice.start = whitespace.end;
254         }
255         (glyphs, break_at_zero)
256     }
257 
ascent(&self) -> Au258     pub fn ascent(&self) -> Au {
259         self.font_metrics.ascent
260     }
261 
descent(&self) -> Au262     pub fn descent(&self) -> Au {
263         self.font_metrics.descent
264     }
265 
advance_for_range(&self, range: &Range<ByteIndex>) -> Au266     pub fn advance_for_range(&self, range: &Range<ByteIndex>) -> Au {
267         if range.is_empty() {
268             return Au(0)
269         }
270 
271         // TODO(Issue #199): alter advance direction for RTL
272         // TODO(Issue #98): using inter-char and inter-word spacing settings when measuring text
273         self.natural_word_slices_in_range(range)
274             .fold(Au(0), |advance, slice| {
275                 advance + slice.glyphs.advance_for_byte_range(&slice.range, self.extra_word_spacing)
276             })
277     }
278 
metrics_for_range(&self, range: &Range<ByteIndex>) -> RunMetrics279     pub fn metrics_for_range(&self, range: &Range<ByteIndex>) -> RunMetrics {
280         RunMetrics::new(self.advance_for_range(range),
281                         self.font_metrics.ascent,
282                         self.font_metrics.descent)
283     }
284 
metrics_for_slice(&self, glyphs: &GlyphStore, slice_range: &Range<ByteIndex>) -> RunMetrics285     pub fn metrics_for_slice(&self, glyphs: &GlyphStore, slice_range: &Range<ByteIndex>)
286                              -> RunMetrics {
287         RunMetrics::new(glyphs.advance_for_byte_range(slice_range, self.extra_word_spacing),
288                         self.font_metrics.ascent,
289                         self.font_metrics.descent)
290     }
291 
min_width_for_range(&self, range: &Range<ByteIndex>) -> Au292     pub fn min_width_for_range(&self, range: &Range<ByteIndex>) -> Au {
293         debug!("iterating outer range {:?}", range);
294         self.natural_word_slices_in_range(range).fold(Au(0), |max_piece_width, slice| {
295             debug!("iterated on {:?}[{:?}]", slice.offset, slice.range);
296             max(max_piece_width, self.advance_for_range(&slice.range))
297         })
298     }
299 
minimum_splittable_inline_size(&self, range: &Range<ByteIndex>) -> Au300     pub fn minimum_splittable_inline_size(&self, range: &Range<ByteIndex>) -> Au {
301         match self.natural_word_slices_in_range(range).next() {
302             None => Au(0),
303             Some(slice) => self.advance_for_range(&slice.range),
304         }
305     }
306 
307     /// Returns the index of the first glyph run containing the given character index.
index_of_first_glyph_run_containing(&self, index: ByteIndex) -> Option<usize>308     fn index_of_first_glyph_run_containing(&self, index: ByteIndex) -> Option<usize> {
309         let self_ptr = self as *const TextRun;
310         INDEX_OF_FIRST_GLYPH_RUN_CACHE.with(|index_of_first_glyph_run_cache| {
311             if let Some((last_text_run, last_index, last_result)) =
312                     index_of_first_glyph_run_cache.get() {
313                 if last_text_run == self_ptr && last_index == index {
314                     return Some(last_result)
315                 }
316             }
317 
318             if let Ok(result) = (&**self.glyphs).binary_search_by(|current| current.compare(&index)) {
319                 index_of_first_glyph_run_cache.set(Some((self_ptr, index, result)));
320                 Some(result)
321             } else {
322                 None
323             }
324         })
325     }
326 
on_glyph_run_boundary(&self, index: ByteIndex) -> bool327     pub fn on_glyph_run_boundary(&self, index: ByteIndex) -> bool {
328         if let Some(glyph_index) = self.index_of_first_glyph_run_containing(index) {
329             self.glyphs[glyph_index].range.begin() == index
330         } else {
331             true
332         }
333     }
334 
335     /// Returns the index in the range of the first glyph advancing over given advance
range_index_of_advance(&self, range: &Range<ByteIndex>, advance: Au) -> usize336     pub fn range_index_of_advance(&self, range: &Range<ByteIndex>, advance: Au) -> usize {
337         // TODO(Issue #199): alter advance direction for RTL
338         // TODO(Issue #98): using inter-char and inter-word spacing settings when measuring text
339         let mut remaining = advance;
340         self.natural_word_slices_in_range(range)
341             .map(|slice| {
342                 let (slice_index, slice_advance) =
343                     slice.glyphs.range_index_of_advance(&slice.range, remaining, self.extra_word_spacing);
344                 remaining -= slice_advance;
345                 slice_index
346             })
347             .sum()
348     }
349 
350     /// Returns an iterator that will iterate over all slices of glyphs that represent natural
351     /// words in the given range.
natural_word_slices_in_range(&'a self, range: &Range<ByteIndex>) -> NaturalWordSliceIterator<'a>352     pub fn natural_word_slices_in_range(&'a self, range: &Range<ByteIndex>)
353                                         -> NaturalWordSliceIterator<'a> {
354         let index = match self.index_of_first_glyph_run_containing(range.begin()) {
355             None => self.glyphs.len(),
356             Some(index) => index,
357         };
358         NaturalWordSliceIterator {
359             glyphs: &self.glyphs[..],
360             index: index,
361             range: *range,
362             reverse: false,
363         }
364     }
365 
366     /// Returns an iterator that over natural word slices in visual order (left to right or
367     /// right to left, depending on the bidirectional embedding level).
natural_word_slices_in_visual_order(&'a self, range: &Range<ByteIndex>) -> NaturalWordSliceIterator<'a>368     pub fn natural_word_slices_in_visual_order(&'a self, range: &Range<ByteIndex>)
369                                         -> NaturalWordSliceIterator<'a> {
370         // Iterate in reverse order if bidi level is RTL.
371         let reverse = self.bidi_level.is_rtl();
372 
373         let index = if reverse {
374             match self.index_of_first_glyph_run_containing(range.end() - ByteIndex(1)) {
375                 Some(i) => i + 1, // In reverse mode, index points one past the next element.
376                 None => 0
377             }
378         } else {
379             match self.index_of_first_glyph_run_containing(range.begin()) {
380                 Some(i) => i,
381                 None => self.glyphs.len()
382             }
383         };
384         NaturalWordSliceIterator {
385             glyphs: &self.glyphs[..],
386             index: index,
387             range: *range,
388             reverse: reverse,
389         }
390     }
391 
392     /// Returns an iterator that will iterate over all slices of glyphs that represent individual
393     /// characters in the given range.
character_slices_in_range(&'a self, range: &Range<ByteIndex>) -> CharacterSliceIterator<'a>394     pub fn character_slices_in_range(&'a self, range: &Range<ByteIndex>)
395                                      -> CharacterSliceIterator<'a> {
396         let index = match self.index_of_first_glyph_run_containing(range.begin()) {
397             None => self.glyphs.len(),
398             Some(index) => index,
399         };
400         let mut glyph_run_iter = self.glyphs[index..].iter();
401         let first_glyph_run = glyph_run_iter.next();
402         CharacterSliceIterator {
403             text: &self.text,
404             glyph_run: first_glyph_run,
405             glyph_run_iter: glyph_run_iter,
406             range: *range,
407         }
408     }
409 }
410