Compute and store line break information in the glyph storage when creating text runs.

This commit is contained in:
Brian J. Burg 2012-11-21 12:20:09 -08:00
parent 2ad1c1564c
commit 751901d39e
3 changed files with 52 additions and 7 deletions

View file

@ -375,6 +375,8 @@ pub trait FontMethods {
range: &Range, range: &Range,
baseline_origin: Point2D<Au>, baseline_origin: Point2D<Au>,
color: Color); color: Color);
// This calculates run metrics for the specified character range
// within the provided textrun.
fn measure_text(&TextRun, &const Range) -> RunMetrics; fn measure_text(&TextRun, &const Range) -> RunMetrics;
fn shape_text(@self, &str, &mut GlyphStore); fn shape_text(@self, &str, &mut GlyphStore);
fn get_descriptor() -> FontDescriptor; fn get_descriptor() -> FontDescriptor;
@ -448,12 +450,10 @@ pub impl Font : FontMethods {
} }
fn measure_text(run: &TextRun, range: &const Range) -> RunMetrics { fn measure_text(run: &TextRun, range: &const Range) -> RunMetrics {
assert range.is_valid_for_string(run.text);
// TODO(Issue #199): alter advance direction for RTL // TODO(Issue #199): alter advance direction for RTL
// TODO(Issue #98): using inter-char and inter-word spacing settings when measuring text // TODO(Issue #98): using inter-char and inter-word spacing settings when measuring text
let mut advance = Au(0); let mut advance = Au(0);
for run.glyphs.iter_glyphs_for_byte_range(range) |_i, glyph| { for run.glyphs.iter_glyphs_for_char_range(range) |_i, glyph| {
advance += glyph.advance(); advance += glyph.advance();
} }
let mut bounds = Rect(Point2D(Au(0), -self.metrics.ascent), let mut bounds = Rect(Point2D(Au(0), -self.metrics.ascent),

View file

@ -604,6 +604,7 @@ impl GlyphStore {
} }
pure fn iter_glyphs_for_byte_range(range: &const Range, cb: fn&(uint, GlyphInfo/&) -> bool) { pure fn iter_glyphs_for_byte_range(range: &const Range, cb: fn&(uint, GlyphInfo/&) -> bool) {
warn!("Using deprecated iter_glyphs_for_byte_range API!");
if range.begin() >= self.entry_buffer.len() { if range.begin() >= self.entry_buffer.len() {
error!("iter_glyphs_for_range: range.begin beyond length!"); error!("iter_glyphs_for_range: range.begin beyond length!");
return; return;
@ -613,9 +614,11 @@ impl GlyphStore {
return; return;
} }
// TODO: actually compute char indexes from byte indexes. self.iter_glyphs_for_char_range(range, cb)
let char_range = copy *range; }
for char_range.eachi |i| {
pure fn iter_glyphs_for_char_range(range: &const Range, cb: fn&(uint, GlyphInfo/&) -> bool) {
for range.eachi |i| {
if !self.iter_glyphs_for_char_index(i, cb) { break; } if !self.iter_glyphs_for_char_index(i, cb) { break; }
} }
} }

View file

@ -1,6 +1,9 @@
use font_context::FontContext; use font_context::FontContext;
use geometry::Au; use geometry::Au;
use glyph::GlyphStore; use glyph::{
BreakTypeNormal,
GlyphStore,
};
use servo_gfx_font::{Font, FontDescriptor, RunMetrics}; use servo_gfx_font::{Font, FontDescriptor, RunMetrics};
use servo_gfx_util::range::Range; use servo_gfx_util::range::Range;
@ -42,6 +45,7 @@ impl SendableTextRun {
impl TextRun { impl TextRun {
static fn new(font: @Font, text: ~str) -> TextRun { static fn new(font: @Font, text: ~str) -> TextRun {
let mut glyph_store = GlyphStore::new(str::char_len(text)); let mut glyph_store = GlyphStore::new(str::char_len(text));
TextRun::compute_potential_breaks(text, &mut glyph_store);
font.shape_text(text, &mut glyph_store); font.shape_text(text, &mut glyph_store);
let run = TextRun { let run = TextRun {
@ -52,6 +56,44 @@ impl TextRun {
return move run; return move run;
} }
static fn compute_potential_breaks(text: &str, glyphs: &mut GlyphStore) {
// TODO(Issue #230): do a better job. See Gecko's LineBreaker.
let mut i = 0u;
let mut prev_is_whitespace = false;
while i < text.len() {
let {ch, next} = str::char_range_at(text, i);
// set char properties.
match ch {
' ' => { glyphs.set_char_is_space(i); },
'\t' => { glyphs.set_char_is_tab(i); },
'\n' => { glyphs.set_char_is_newline(i); },
_ => {}
}
// set line break opportunities at whitespace/non-whitespace boundaries.
if prev_is_whitespace {
match ch {
' ' | '\t' | '\n' => {},
_ => {
glyphs.set_can_break_before(i, BreakTypeNormal);
prev_is_whitespace = false;
}
}
} else {
match ch {
' ' | '\t' | '\n' => {
glyphs.set_can_break_before(i, BreakTypeNormal);
prev_is_whitespace = true;
},
_ => { }
}
}
i = next;
}
}
pub fn serialize(&self) -> SendableTextRun { pub fn serialize(&self) -> SendableTextRun {
SendableTextRun { SendableTextRun {
text: copy self.text, text: copy self.text,