Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement `word-break: keep-all` (#9673) #13414

Merged
merged 4 commits into from Sep 30, 2016
Merged
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

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

  • Loading branch information
flacerdk committed Sep 27, 2016
commit e0a48fe596a64bcf62671be2c34b867a937737ea
@@ -148,6 +148,8 @@ bitflags! {
const DISABLE_KERNING_SHAPING_FLAG = 0x04,
#[doc = "Text direction is right-to-left."]
const RTL_FLAG = 0x08,
#[doc = "Set if word-break is set to keep-all."]
const KEEP_ALL_FLAG = 0x10,
}
}

@@ -3,8 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use app_units::Au;
use font::{Font, FontHandleMethods, FontMetrics, IS_WHITESPACE_SHAPING_FLAG, RunMetrics};
use font::ShapingOptions;
use font::{Font, FontHandleMethods, FontMetrics, IS_WHITESPACE_SHAPING_FLAG, KEEP_ALL_FLAG};
use font::{RunMetrics, ShapingOptions};
use platform::font_template::FontTemplateData;
use range::Range;
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> {
text: &'a str,
glyph_run: Option<&'a GlyphRun>,
@@ -256,8 +209,9 @@ impl<'a> TextRun {
.take_while(|&(_, c)| char_is_whitespace(c)).last() {
whitespace.start = slice.start + i;
slice.end = whitespace.start;
} else if idx != text.len() {
// If there's no whitespace, try increasing the slice.
} else if idx != text.len() && options.flags.contains(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 {
@@ -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
/// characters in the given range.
pub fn character_slices_in_range(&'a self, range: &Range<ByteIndex>)
@@ -1640,7 +1640,7 @@ impl Fragment {
word_break::T::normal => {
// Break at normal word boundaries, allowing for soft wrap opportunities.
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(
soft_wrap_breaking_strategy,
max_inline_size,
@@ -10,7 +10,7 @@ use app_units::Au;
use fragment::{Fragment, REQUIRES_LINE_BREAK_AFTERWARD_IF_WRAPPING_ON_NEWLINES, ScannedTextFlags};
use fragment::{SELECTED, ScannedTextFragmentInfo, SpecificFragmentInfo, UnscannedTextFragmentInfo};
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::text::glyph::ByteIndex;
use gfx::text::text_run::TextRun;
@@ -24,7 +24,7 @@ use std::collections::LinkedList;
use std::mem;
use std::sync::Arc;
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::properties::ServoComputedValues;
use style::properties::style_structs;
@@ -151,6 +151,7 @@ impl TextRunScanner {
let letter_spacing;
let word_spacing;
let text_rendering;
let word_break;
{
let in_fragment = self.clump.front().unwrap();
let font_style = in_fragment.style().get_font_arc();
@@ -169,6 +170,7 @@ impl TextRunScanner {
.map(|lop| lop.to_hash_key())
.unwrap_or((Au(0), NotNaN::new(0.0).unwrap()));
text_rendering = inherited_text_style.text_rendering;
word_break = inherited_text_style.word_break;
}

// First, transform/compress text of all the nodes.
@@ -289,6 +291,9 @@ impl TextRunScanner {
flags.insert(IGNORE_LIGATURES_SHAPING_FLAG);
flags.insert(DISABLE_KERNING_SHAPING_FLAG)
}
if word_break == word_break::T::keep_all {
flags.insert(KEEP_ALL_FLAG);
}
let options = ShapingOptions {
letter_spacing: letter_spacing,
word_spacing: word_spacing,
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.