Use word-break to decide how glyph runs should be created

This commit is contained in:
Felipe 2016-09-27 10:02:33 +02:00 committed by Felipe Lacerda
parent d5669ead29
commit e0a48fe596
4 changed files with 15 additions and 72 deletions

View file

@ -148,6 +148,8 @@ bitflags! {
const DISABLE_KERNING_SHAPING_FLAG = 0x04, const DISABLE_KERNING_SHAPING_FLAG = 0x04,
#[doc = "Text direction is right-to-left."] #[doc = "Text direction is right-to-left."]
const RTL_FLAG = 0x08, const RTL_FLAG = 0x08,
#[doc = "Set if word-break is set to keep-all."]
const KEEP_ALL_FLAG = 0x10,
} }
} }

View file

@ -3,8 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use app_units::Au; use app_units::Au;
use font::{Font, FontHandleMethods, FontMetrics, IS_WHITESPACE_SHAPING_FLAG, RunMetrics}; use font::{Font, FontHandleMethods, FontMetrics, IS_WHITESPACE_SHAPING_FLAG, KEEP_ALL_FLAG};
use font::ShapingOptions; use font::{RunMetrics, ShapingOptions};
use platform::font_template::FontTemplateData; use platform::font_template::FontTemplateData;
use range::Range; use range::Range;
use std::cell::Cell; use std::cell::Cell;
@ -135,53 +135,6 @@ impl<'a> Iterator for NaturalWordSliceIterator<'a> {
} }
} }
pub struct SoftWrapSliceIterator<'a> {
text: &'a str,
glyph_run: Option<&'a GlyphRun>,
glyph_run_iter: Iter<'a, GlyphRun>,
range: Range<ByteIndex>,
}
// This is like NaturalWordSliceIterator, except that soft-wrap opportunities
// are allowed. That is, word boundaries are defined solely by UAX#29,
// regardless of whether the sequence being broken into different slices is
// a sequence of alphanumeric characters. This shouldn't make a difference in
// the case of Latin text, but it does in ideographic characters, as well as
// scripts such as Thai.
impl<'a> Iterator for SoftWrapSliceIterator<'a> {
type Item = TextRunSlice<'a>;
#[inline(always)]
fn next(&mut self) -> Option<TextRunSlice<'a>> {
let glyph_run = match self.glyph_run {
None => return None,
Some(glyph_run) => glyph_run,
};
let text_start = self.range.begin();
let text = &self.text[text_start.to_usize()..glyph_run.range.end().to_usize()];
let slice_text = match LineBreakIterator::new(text).next() {
Some((idx, _)) => &text[0..idx],
None => unreachable!()
};
let slice_len = ByteIndex(slice_text.len() as isize);
self.range.adjust_by(slice_len, -slice_len);
if self.range.is_empty() {
self.glyph_run = None
} else if self.range.intersect(&glyph_run.range).is_empty() {
self.glyph_run = self.glyph_run_iter.next();
}
let index_within_glyph_run = text_start - glyph_run.range.begin();
Some(TextRunSlice {
glyphs: &*glyph_run.glyph_store,
offset: glyph_run.range.begin(),
range: Range::new(index_within_glyph_run, slice_len),
})
}
}
pub struct CharacterSliceIterator<'a> { pub struct CharacterSliceIterator<'a> {
text: &'a str, text: &'a str,
glyph_run: Option<&'a GlyphRun>, glyph_run: Option<&'a GlyphRun>,
@ -256,8 +209,9 @@ impl<'a> TextRun {
.take_while(|&(_, c)| char_is_whitespace(c)).last() { .take_while(|&(_, c)| char_is_whitespace(c)).last() {
whitespace.start = slice.start + i; whitespace.start = slice.start + i;
slice.end = whitespace.start; slice.end = whitespace.start;
} else if idx != text.len() { } else if idx != text.len() && options.flags.contains(KEEP_ALL_FLAG) {
// If there's no whitespace, try increasing the slice. // If there's no whitespace and word-break is set to
// keep-all, try increasing the slice.
continue; continue;
} }
if slice.len() > 0 { if slice.len() > 0 {
@ -392,24 +346,6 @@ impl<'a> TextRun {
} }
} }
/// Returns an iterator that will iterate over all slices of glyphs that represent natural
/// words in the given range, where soft wrap opportunities are taken into account.
pub fn soft_wrap_slices_in_range(&'a self, range: &Range<ByteIndex>)
-> SoftWrapSliceIterator<'a> {
let index = match self.index_of_first_glyph_run_containing(range.begin()) {
None => self.glyphs.len(),
Some(index) => index,
};
let mut glyph_run_iter = self.glyphs[index..].iter();
let first_glyph_run = glyph_run_iter.next();
SoftWrapSliceIterator {
text: &self.text,
glyph_run: first_glyph_run,
glyph_run_iter: glyph_run_iter,
range: *range,
}
}
/// Returns an iterator that will iterate over all slices of glyphs that represent individual /// Returns an iterator that will iterate over all slices of glyphs that represent individual
/// characters in the given range. /// characters in the given range.
pub fn character_slices_in_range(&'a self, range: &Range<ByteIndex>) pub fn character_slices_in_range(&'a self, range: &Range<ByteIndex>)

View file

@ -1640,7 +1640,7 @@ impl Fragment {
word_break::T::normal => { word_break::T::normal => {
// Break at normal word boundaries, allowing for soft wrap opportunities. // Break at normal word boundaries, allowing for soft wrap opportunities.
let soft_wrap_breaking_strategy = let soft_wrap_breaking_strategy =
text_fragment_info.run.soft_wrap_slices_in_range(&text_fragment_info.range); text_fragment_info.run.natural_word_slices_in_range(&text_fragment_info.range);
self.calculate_split_position_using_breaking_strategy( self.calculate_split_position_using_breaking_strategy(
soft_wrap_breaking_strategy, soft_wrap_breaking_strategy,
max_inline_size, max_inline_size,

View file

@ -10,7 +10,7 @@ use app_units::Au;
use fragment::{Fragment, REQUIRES_LINE_BREAK_AFTERWARD_IF_WRAPPING_ON_NEWLINES, ScannedTextFlags}; use fragment::{Fragment, REQUIRES_LINE_BREAK_AFTERWARD_IF_WRAPPING_ON_NEWLINES, ScannedTextFlags};
use fragment::{SELECTED, ScannedTextFragmentInfo, SpecificFragmentInfo, UnscannedTextFragmentInfo}; use fragment::{SELECTED, ScannedTextFragmentInfo, SpecificFragmentInfo, UnscannedTextFragmentInfo};
use gfx::font::{DISABLE_KERNING_SHAPING_FLAG, FontMetrics, IGNORE_LIGATURES_SHAPING_FLAG}; use gfx::font::{DISABLE_KERNING_SHAPING_FLAG, FontMetrics, IGNORE_LIGATURES_SHAPING_FLAG};
use gfx::font::{RTL_FLAG, RunMetrics, ShapingFlags, ShapingOptions}; use gfx::font::{KEEP_ALL_FLAG, RTL_FLAG, RunMetrics, ShapingFlags, ShapingOptions};
use gfx::font_context::FontContext; use gfx::font_context::FontContext;
use gfx::text::glyph::ByteIndex; use gfx::text::glyph::ByteIndex;
use gfx::text::text_run::TextRun; use gfx::text::text_run::TextRun;
@ -24,7 +24,7 @@ use std::collections::LinkedList;
use std::mem; use std::mem;
use std::sync::Arc; use std::sync::Arc;
use style::computed_values::{line_height, text_orientation, text_rendering, text_transform}; use style::computed_values::{line_height, text_orientation, text_rendering, text_transform};
use style::computed_values::white_space; use style::computed_values::{word_break, white_space};
use style::logical_geometry::{LogicalSize, WritingMode}; use style::logical_geometry::{LogicalSize, WritingMode};
use style::properties::ServoComputedValues; use style::properties::ServoComputedValues;
use style::properties::style_structs; use style::properties::style_structs;
@ -151,6 +151,7 @@ impl TextRunScanner {
let letter_spacing; let letter_spacing;
let word_spacing; let word_spacing;
let text_rendering; let text_rendering;
let word_break;
{ {
let in_fragment = self.clump.front().unwrap(); let in_fragment = self.clump.front().unwrap();
let font_style = in_fragment.style().get_font_arc(); let font_style = in_fragment.style().get_font_arc();
@ -169,6 +170,7 @@ impl TextRunScanner {
.map(|lop| lop.to_hash_key()) .map(|lop| lop.to_hash_key())
.unwrap_or((Au(0), NotNaN::new(0.0).unwrap())); .unwrap_or((Au(0), NotNaN::new(0.0).unwrap()));
text_rendering = inherited_text_style.text_rendering; text_rendering = inherited_text_style.text_rendering;
word_break = inherited_text_style.word_break;
} }
// First, transform/compress text of all the nodes. // First, transform/compress text of all the nodes.
@ -289,6 +291,9 @@ impl TextRunScanner {
flags.insert(IGNORE_LIGATURES_SHAPING_FLAG); flags.insert(IGNORE_LIGATURES_SHAPING_FLAG);
flags.insert(DISABLE_KERNING_SHAPING_FLAG) flags.insert(DISABLE_KERNING_SHAPING_FLAG)
} }
if word_break == word_break::T::keep_all {
flags.insert(KEEP_ALL_FLAG);
}
let options = ShapingOptions { let options = ShapingOptions {
letter_spacing: letter_spacing, letter_spacing: letter_spacing,
word_spacing: word_spacing, word_spacing: word_spacing,