mirror of
https://github.com/servo/servo.git
synced 2025-08-04 21:20:23 +01:00
Add character index type
This is more self-documenting and may highlight errors in the future.
This commit is contained in:
parent
9df9f07cfd
commit
9dd533ce01
9 changed files with 161 additions and 146 deletions
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
use color::Color;
|
use color::Color;
|
||||||
use render_context::RenderContext;
|
use render_context::RenderContext;
|
||||||
|
use text::glyph::CharIndex;
|
||||||
use text::TextRun;
|
use text::TextRun;
|
||||||
|
|
||||||
use collections::deque::Deque;
|
use collections::deque::Deque;
|
||||||
|
@ -395,7 +396,7 @@ pub struct TextDisplayItem {
|
||||||
pub text_run: Arc<~TextRun>,
|
pub text_run: Arc<~TextRun>,
|
||||||
|
|
||||||
/// The range of text within the text run.
|
/// The range of text within the text run.
|
||||||
pub range: Range<int>,
|
pub range: Range<CharIndex>,
|
||||||
|
|
||||||
/// The color of the text.
|
/// The color of the text.
|
||||||
pub text_color: Color,
|
pub text_color: Color,
|
||||||
|
|
|
@ -23,7 +23,7 @@ use servo_util::geometry::Au;
|
||||||
use platform::font_context::FontContextHandle;
|
use platform::font_context::FontContextHandle;
|
||||||
use platform::font::{FontHandle, FontTable};
|
use platform::font::{FontHandle, FontTable};
|
||||||
use render_context::RenderContext;
|
use render_context::RenderContext;
|
||||||
use text::glyph::{GlyphStore, GlyphId};
|
use text::glyph::{CharIndex, GlyphStore, GlyphId};
|
||||||
use text::shaping::ShaperMethods;
|
use text::shaping::ShaperMethods;
|
||||||
use text::{Shaper, TextRun};
|
use text::{Shaper, TextRun};
|
||||||
|
|
||||||
|
@ -330,7 +330,7 @@ impl Font {
|
||||||
pub fn draw_text_into_context(&mut self,
|
pub fn draw_text_into_context(&mut self,
|
||||||
rctx: &RenderContext,
|
rctx: &RenderContext,
|
||||||
run: &~TextRun,
|
run: &~TextRun,
|
||||||
range: &Range<int>,
|
range: &Range<CharIndex>,
|
||||||
baseline_origin: Point2D<Au>,
|
baseline_origin: Point2D<Au>,
|
||||||
color: Color) {
|
color: Color) {
|
||||||
use libc::types::common::c99::{uint16_t, uint32_t};
|
use libc::types::common::c99::{uint16_t, uint32_t};
|
||||||
|
@ -353,7 +353,7 @@ impl Font {
|
||||||
|
|
||||||
let mut origin = baseline_origin.clone();
|
let mut origin = baseline_origin.clone();
|
||||||
let mut azglyphs = vec!();
|
let mut azglyphs = vec!();
|
||||||
azglyphs.reserve(range.length() as uint);
|
azglyphs.reserve(range.length().to_uint());
|
||||||
|
|
||||||
for (glyphs, _offset, slice_range) in run.iter_slices_for_range(range) {
|
for (glyphs, _offset, slice_range) in run.iter_slices_for_range(range) {
|
||||||
for (_i, glyph) in glyphs.iter_glyphs_for_char_range(&slice_range) {
|
for (_i, glyph) in glyphs.iter_glyphs_for_char_range(&slice_range) {
|
||||||
|
@ -391,7 +391,7 @@ impl Font {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn measure_text(&self, run: &TextRun, range: &Range<int>) -> RunMetrics {
|
pub fn measure_text(&self, run: &TextRun, range: &Range<CharIndex>) -> RunMetrics {
|
||||||
// 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);
|
||||||
|
@ -405,7 +405,7 @@ impl Font {
|
||||||
|
|
||||||
pub fn measure_text_for_slice(&self,
|
pub fn measure_text_for_slice(&self,
|
||||||
glyphs: &GlyphStore,
|
glyphs: &GlyphStore,
|
||||||
slice_range: &Range<int>)
|
slice_range: &Range<CharIndex>)
|
||||||
-> RunMetrics {
|
-> RunMetrics {
|
||||||
let mut advance = Au(0);
|
let mut advance = Au(0);
|
||||||
for (_i, glyph) in glyphs.iter_glyphs_for_char_range(slice_range) {
|
for (_i, glyph) in glyphs.iter_glyphs_for_char_range(slice_range) {
|
||||||
|
|
|
@ -23,6 +23,7 @@ extern crate png;
|
||||||
#[phase(syntax)]
|
#[phase(syntax)]
|
||||||
extern crate servo_macros = "macros";
|
extern crate servo_macros = "macros";
|
||||||
extern crate servo_net = "net";
|
extern crate servo_net = "net";
|
||||||
|
#[phase(syntax, link)]
|
||||||
extern crate servo_util = "util";
|
extern crate servo_util = "util";
|
||||||
extern crate servo_msg = "msg";
|
extern crate servo_msg = "msg";
|
||||||
extern crate style;
|
extern crate style;
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
use servo_util::vec::*;
|
use servo_util::vec::*;
|
||||||
use servo_util::range;
|
use servo_util::range;
|
||||||
use servo_util::range::{Range, EachIndex};
|
use servo_util::range::{Range, RangeIndex, EachIndex};
|
||||||
use servo_util::geometry::Au;
|
use servo_util::geometry::Au;
|
||||||
|
|
||||||
use std::cmp::{Ord, Eq};
|
use std::cmp::{Ord, Eq};
|
||||||
|
@ -273,7 +273,7 @@ impl DetailedGlyph {
|
||||||
#[deriving(Eq, Clone)]
|
#[deriving(Eq, Clone)]
|
||||||
struct DetailedGlyphRecord {
|
struct DetailedGlyphRecord {
|
||||||
// source string offset/GlyphEntry offset in the TextRun
|
// source string offset/GlyphEntry offset in the TextRun
|
||||||
entry_offset: int,
|
entry_offset: CharIndex,
|
||||||
// offset into the detailed glyphs buffer
|
// offset into the detailed glyphs buffer
|
||||||
detail_offset: int,
|
detail_offset: int,
|
||||||
}
|
}
|
||||||
|
@ -316,7 +316,7 @@ impl<'a> DetailedGlyphStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_detailed_glyphs_for_entry(&mut self, entry_offset: int, glyphs: &[DetailedGlyph]) {
|
fn add_detailed_glyphs_for_entry(&mut self, entry_offset: CharIndex, glyphs: &[DetailedGlyph]) {
|
||||||
let entry = DetailedGlyphRecord {
|
let entry = DetailedGlyphRecord {
|
||||||
entry_offset: entry_offset,
|
entry_offset: entry_offset,
|
||||||
detail_offset: self.detail_buffer.len() as int,
|
detail_offset: self.detail_buffer.len() as int,
|
||||||
|
@ -340,7 +340,7 @@ impl<'a> DetailedGlyphStore {
|
||||||
self.lookup_is_sorted = false;
|
self.lookup_is_sorted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_detailed_glyphs_for_entry(&'a self, entry_offset: int, count: u16)
|
fn get_detailed_glyphs_for_entry(&'a self, entry_offset: CharIndex, count: u16)
|
||||||
-> &'a [DetailedGlyph] {
|
-> &'a [DetailedGlyph] {
|
||||||
debug!("Requesting detailed glyphs[n={}] for entry[off={}]", count, entry_offset);
|
debug!("Requesting detailed glyphs[n={}] for entry[off={}]", count, entry_offset);
|
||||||
|
|
||||||
|
@ -371,7 +371,7 @@ impl<'a> DetailedGlyphStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_detailed_glyph_with_index(&'a self,
|
fn get_detailed_glyph_with_index(&'a self,
|
||||||
entry_offset: int,
|
entry_offset: CharIndex,
|
||||||
detail_offset: u16)
|
detail_offset: u16)
|
||||||
-> &'a DetailedGlyph {
|
-> &'a DetailedGlyph {
|
||||||
assert!((detail_offset as uint) <= self.detail_buffer.len());
|
assert!((detail_offset as uint) <= self.detail_buffer.len());
|
||||||
|
@ -460,14 +460,14 @@ impl GlyphData {
|
||||||
// Rather than eagerly assembling and copying glyph data, it only retrieves
|
// Rather than eagerly assembling and copying glyph data, it only retrieves
|
||||||
// values as they are needed from the GlyphStore, using provided offsets.
|
// values as they are needed from the GlyphStore, using provided offsets.
|
||||||
pub enum GlyphInfo<'a> {
|
pub enum GlyphInfo<'a> {
|
||||||
SimpleGlyphInfo(&'a GlyphStore, int),
|
SimpleGlyphInfo(&'a GlyphStore, CharIndex),
|
||||||
DetailGlyphInfo(&'a GlyphStore, int, u16),
|
DetailGlyphInfo(&'a GlyphStore, CharIndex, u16),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> GlyphInfo<'a> {
|
impl<'a> GlyphInfo<'a> {
|
||||||
pub fn id(self) -> GlyphId {
|
pub fn id(self) -> GlyphId {
|
||||||
match self {
|
match self {
|
||||||
SimpleGlyphInfo(store, entry_i) => store.entry_buffer.get(entry_i as uint).id(),
|
SimpleGlyphInfo(store, entry_i) => store.entry_buffer.get(entry_i.to_uint()).id(),
|
||||||
DetailGlyphInfo(store, entry_i, detail_j) => {
|
DetailGlyphInfo(store, entry_i, detail_j) => {
|
||||||
store.detail_store.get_detailed_glyph_with_index(entry_i, detail_j).id
|
store.detail_store.get_detailed_glyph_with_index(entry_i, detail_j).id
|
||||||
}
|
}
|
||||||
|
@ -478,7 +478,7 @@ impl<'a> GlyphInfo<'a> {
|
||||||
// FIXME: Resolution conflicts with IteratorUtil trait so adding trailing _
|
// FIXME: Resolution conflicts with IteratorUtil trait so adding trailing _
|
||||||
pub fn advance(self) -> Au {
|
pub fn advance(self) -> Au {
|
||||||
match self {
|
match self {
|
||||||
SimpleGlyphInfo(store, entry_i) => store.entry_buffer.get(entry_i as uint).advance(),
|
SimpleGlyphInfo(store, entry_i) => store.entry_buffer.get(entry_i.to_uint()).advance(),
|
||||||
DetailGlyphInfo(store, entry_i, detail_j) => {
|
DetailGlyphInfo(store, entry_i, detail_j) => {
|
||||||
store.detail_store.get_detailed_glyph_with_index(entry_i, detail_j).advance
|
store.detail_store.get_detailed_glyph_with_index(entry_i, detail_j).advance
|
||||||
}
|
}
|
||||||
|
@ -506,6 +506,12 @@ pub struct GlyphStore {
|
||||||
is_whitespace: bool,
|
is_whitespace: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
range_index! {
|
||||||
|
#[doc = "An index that refers to a character in a text run. This could \
|
||||||
|
point to the middle of a glyph."]
|
||||||
|
struct CharIndex(int)
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> GlyphStore {
|
impl<'a> GlyphStore {
|
||||||
// Initializes the glyph store, but doesn't actually shape anything.
|
// Initializes the glyph store, but doesn't actually shape anything.
|
||||||
// Use the set_glyph, set_glyphs() methods to store glyph data.
|
// Use the set_glyph, set_glyphs() methods to store glyph data.
|
||||||
|
@ -519,8 +525,8 @@ impl<'a> GlyphStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn char_len(&self) -> int {
|
pub fn char_len(&self) -> CharIndex {
|
||||||
self.entry_buffer.len() as int
|
CharIndex(self.entry_buffer.len() as int)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_whitespace(&self) -> bool {
|
pub fn is_whitespace(&self) -> bool {
|
||||||
|
@ -531,7 +537,7 @@ impl<'a> GlyphStore {
|
||||||
self.detail_store.ensure_sorted();
|
self.detail_store.ensure_sorted();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_glyph_for_char_index(&mut self, i: int, data: &GlyphData) {
|
pub fn add_glyph_for_char_index(&mut self, i: CharIndex, data: &GlyphData) {
|
||||||
fn glyph_is_compressible(data: &GlyphData) -> bool {
|
fn glyph_is_compressible(data: &GlyphData) -> bool {
|
||||||
is_simple_glyph_id(data.id)
|
is_simple_glyph_id(data.id)
|
||||||
&& is_simple_advance(data.advance)
|
&& is_simple_advance(data.advance)
|
||||||
|
@ -540,7 +546,7 @@ impl<'a> GlyphStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(data.ligature_start); // can't compress ligature continuation glyphs.
|
assert!(data.ligature_start); // can't compress ligature continuation glyphs.
|
||||||
assert!(i < self.entry_buffer.len() as int);
|
assert!(i < CharIndex(self.entry_buffer.len() as int));
|
||||||
|
|
||||||
let entry = match (data.is_missing, glyph_is_compressible(data)) {
|
let entry = match (data.is_missing, glyph_is_compressible(data)) {
|
||||||
(true, _) => GlyphEntry::missing(1),
|
(true, _) => GlyphEntry::missing(1),
|
||||||
|
@ -550,13 +556,13 @@ impl<'a> GlyphStore {
|
||||||
self.detail_store.add_detailed_glyphs_for_entry(i, glyph);
|
self.detail_store.add_detailed_glyphs_for_entry(i, glyph);
|
||||||
GlyphEntry::complex(data.cluster_start, data.ligature_start, 1)
|
GlyphEntry::complex(data.cluster_start, data.ligature_start, 1)
|
||||||
}
|
}
|
||||||
}.adapt_character_flags_of_entry(*self.entry_buffer.get(i as uint));
|
}.adapt_character_flags_of_entry(*self.entry_buffer.get(i.to_uint()));
|
||||||
|
|
||||||
*self.entry_buffer.get_mut(i as uint) = entry;
|
*self.entry_buffer.get_mut(i.to_uint()) = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_glyphs_for_char_index(&mut self, i: int, data_for_glyphs: &[GlyphData]) {
|
pub fn add_glyphs_for_char_index(&mut self, i: CharIndex, data_for_glyphs: &[GlyphData]) {
|
||||||
assert!(i < self.entry_buffer.len() as int);
|
assert!(i < CharIndex(self.entry_buffer.len() as int));
|
||||||
assert!(data_for_glyphs.len() > 0);
|
assert!(data_for_glyphs.len() > 0);
|
||||||
|
|
||||||
let glyph_count = data_for_glyphs.len() as int;
|
let glyph_count = data_for_glyphs.len() as int;
|
||||||
|
@ -576,33 +582,33 @@ impl<'a> GlyphStore {
|
||||||
first_glyph_data.ligature_start,
|
first_glyph_data.ligature_start,
|
||||||
glyph_count)
|
glyph_count)
|
||||||
}
|
}
|
||||||
}.adapt_character_flags_of_entry(*self.entry_buffer.get(i as uint));
|
}.adapt_character_flags_of_entry(*self.entry_buffer.get(i.to_uint()));
|
||||||
|
|
||||||
debug!("Adding multiple glyphs[idx={}, count={}]: {:?}", i, glyph_count, entry);
|
debug!("Adding multiple glyphs[idx={}, count={}]: {:?}", i, glyph_count, entry);
|
||||||
|
|
||||||
*self.entry_buffer.get_mut(i as uint) = entry;
|
*self.entry_buffer.get_mut(i.to_uint()) = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
// used when a character index has no associated glyph---for example, a ligature continuation.
|
// used when a character index has no associated glyph---for example, a ligature continuation.
|
||||||
pub fn add_nonglyph_for_char_index(&mut self, i: int, cluster_start: bool, ligature_start: bool) {
|
pub fn add_nonglyph_for_char_index(&mut self, i: CharIndex, cluster_start: bool, ligature_start: bool) {
|
||||||
assert!(i < self.entry_buffer.len() as int);
|
assert!(i < CharIndex(self.entry_buffer.len() as int));
|
||||||
|
|
||||||
let entry = GlyphEntry::complex(cluster_start, ligature_start, 0);
|
let entry = GlyphEntry::complex(cluster_start, ligature_start, 0);
|
||||||
debug!("adding spacer for chracter without associated glyph[idx={}]", i);
|
debug!("adding spacer for chracter without associated glyph[idx={}]", i);
|
||||||
|
|
||||||
*self.entry_buffer.get_mut(i as uint) = entry;
|
*self.entry_buffer.get_mut(i.to_uint()) = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_glyphs_for_char_index(&'a self, i: int) -> GlyphIterator<'a> {
|
pub fn iter_glyphs_for_char_index(&'a self, i: CharIndex) -> GlyphIterator<'a> {
|
||||||
self.iter_glyphs_for_char_range(&Range::new(i as int, 1))
|
self.iter_glyphs_for_char_range(&Range::new(i, CharIndex(1)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter_glyphs_for_char_range(&'a self, rang: &Range<int>) -> GlyphIterator<'a> {
|
pub fn iter_glyphs_for_char_range(&'a self, rang: &Range<CharIndex>) -> GlyphIterator<'a> {
|
||||||
if rang.begin() >= self.entry_buffer.len() as int {
|
if rang.begin() >= CharIndex(self.entry_buffer.len() as int) {
|
||||||
fail!("iter_glyphs_for_range: range.begin beyond length!");
|
fail!("iter_glyphs_for_range: range.begin beyond length!");
|
||||||
}
|
}
|
||||||
if rang.end() > self.entry_buffer.len() as int {
|
if rang.end() > CharIndex(self.entry_buffer.len() as int) {
|
||||||
fail!("iter_glyphs_for_range: range.end beyond length!");
|
fail!("iter_glyphs_for_range: range.end beyond length!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -615,76 +621,76 @@ impl<'a> GlyphStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
// getter methods
|
// getter methods
|
||||||
pub fn char_is_space(&self, i: int) -> bool {
|
pub fn char_is_space(&self, i: CharIndex) -> bool {
|
||||||
assert!(i < self.entry_buffer.len() as int);
|
assert!(i < CharIndex(self.entry_buffer.len() as int));
|
||||||
self.entry_buffer.get(i as uint).char_is_space()
|
self.entry_buffer.get(i.to_uint()).char_is_space()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn char_is_tab(&self, i: int) -> bool {
|
pub fn char_is_tab(&self, i: CharIndex) -> bool {
|
||||||
assert!(i < self.entry_buffer.len() as int);
|
assert!(i < CharIndex(self.entry_buffer.len() as int));
|
||||||
self.entry_buffer.get(i as uint).char_is_tab()
|
self.entry_buffer.get(i.to_uint()).char_is_tab()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn char_is_newline(&self, i: int) -> bool {
|
pub fn char_is_newline(&self, i: CharIndex) -> bool {
|
||||||
assert!(i < self.entry_buffer.len() as int);
|
assert!(i < CharIndex(self.entry_buffer.len() as int));
|
||||||
self.entry_buffer.get(i as uint).char_is_newline()
|
self.entry_buffer.get(i.to_uint()).char_is_newline()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_ligature_start(&self, i: int) -> bool {
|
pub fn is_ligature_start(&self, i: CharIndex) -> bool {
|
||||||
assert!(i < self.entry_buffer.len() as int);
|
assert!(i < CharIndex(self.entry_buffer.len() as int));
|
||||||
self.entry_buffer.get(i as uint).is_ligature_start()
|
self.entry_buffer.get(i.to_uint()).is_ligature_start()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_cluster_start(&self, i: int) -> bool {
|
pub fn is_cluster_start(&self, i: CharIndex) -> bool {
|
||||||
assert!(i < self.entry_buffer.len() as int);
|
assert!(i < CharIndex(self.entry_buffer.len() as int));
|
||||||
self.entry_buffer.get(i as uint).is_cluster_start()
|
self.entry_buffer.get(i.to_uint()).is_cluster_start()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn can_break_before(&self, i: int) -> BreakType {
|
pub fn can_break_before(&self, i: CharIndex) -> BreakType {
|
||||||
assert!(i < self.entry_buffer.len() as int);
|
assert!(i < CharIndex(self.entry_buffer.len() as int));
|
||||||
self.entry_buffer.get(i as uint).can_break_before()
|
self.entry_buffer.get(i.to_uint()).can_break_before()
|
||||||
}
|
}
|
||||||
|
|
||||||
// setter methods
|
// setter methods
|
||||||
pub fn set_char_is_space(&mut self, i: int) {
|
pub fn set_char_is_space(&mut self, i: CharIndex) {
|
||||||
assert!(i < self.entry_buffer.len() as int);
|
assert!(i < CharIndex(self.entry_buffer.len() as int));
|
||||||
let entry = *self.entry_buffer.get(i as uint);
|
let entry = *self.entry_buffer.get(i.to_uint());
|
||||||
*self.entry_buffer.get_mut(i as uint) = entry.set_char_is_space();
|
*self.entry_buffer.get_mut(i.to_uint()) = entry.set_char_is_space();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_char_is_tab(&mut self, i: int) {
|
pub fn set_char_is_tab(&mut self, i: CharIndex) {
|
||||||
assert!(i < self.entry_buffer.len() as int);
|
assert!(i < CharIndex(self.entry_buffer.len() as int));
|
||||||
let entry = *self.entry_buffer.get(i as uint);
|
let entry = *self.entry_buffer.get(i.to_uint());
|
||||||
*self.entry_buffer.get_mut(i as uint) = entry.set_char_is_tab();
|
*self.entry_buffer.get_mut(i.to_uint()) = entry.set_char_is_tab();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_char_is_newline(&mut self, i: int) {
|
pub fn set_char_is_newline(&mut self, i: CharIndex) {
|
||||||
assert!(i < self.entry_buffer.len() as int);
|
assert!(i < CharIndex(self.entry_buffer.len() as int));
|
||||||
let entry = *self.entry_buffer.get(i as uint);
|
let entry = *self.entry_buffer.get(i.to_uint());
|
||||||
*self.entry_buffer.get_mut(i as uint) = entry.set_char_is_newline();
|
*self.entry_buffer.get_mut(i.to_uint()) = entry.set_char_is_newline();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_can_break_before(&mut self, i: int, t: BreakType) {
|
pub fn set_can_break_before(&mut self, i: CharIndex, t: BreakType) {
|
||||||
assert!(i < self.entry_buffer.len() as int);
|
assert!(i < CharIndex(self.entry_buffer.len() as int));
|
||||||
let entry = *self.entry_buffer.get(i as uint);
|
let entry = *self.entry_buffer.get(i.to_uint());
|
||||||
*self.entry_buffer.get_mut(i as uint) = entry.set_can_break_before(t);
|
*self.entry_buffer.get_mut(i.to_uint()) = entry.set_can_break_before(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GlyphIterator<'a> {
|
pub struct GlyphIterator<'a> {
|
||||||
store: &'a GlyphStore,
|
store: &'a GlyphStore,
|
||||||
char_index: int,
|
char_index: CharIndex,
|
||||||
char_range: EachIndex<int, int>,
|
char_range: EachIndex<int, CharIndex>,
|
||||||
glyph_range: Option<EachIndex<int, int>>,
|
glyph_range: Option<EachIndex<int, CharIndex>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> GlyphIterator<'a> {
|
impl<'a> GlyphIterator<'a> {
|
||||||
// Slow path when there is a glyph range.
|
// Slow path when there is a glyph range.
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn next_glyph_range(&mut self) -> Option<(int, GlyphInfo<'a>)> {
|
fn next_glyph_range(&mut self) -> Option<(CharIndex, GlyphInfo<'a>)> {
|
||||||
match self.glyph_range.get_mut_ref().next() {
|
match self.glyph_range.get_mut_ref().next() {
|
||||||
Some(j) => Some((self.char_index,
|
Some(j) => Some((self.char_index,
|
||||||
DetailGlyphInfo(self.store, self.char_index, j as u16))),
|
DetailGlyphInfo(self.store, self.char_index, j.get() as u16 /* ??? */))),
|
||||||
None => {
|
None => {
|
||||||
// No more glyphs for current character. Try to get another.
|
// No more glyphs for current character. Try to get another.
|
||||||
self.glyph_range = None;
|
self.glyph_range = None;
|
||||||
|
@ -695,15 +701,15 @@ impl<'a> GlyphIterator<'a> {
|
||||||
|
|
||||||
// Slow path when there is a complex glyph.
|
// Slow path when there is a complex glyph.
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn next_complex_glyph(&mut self, entry: &GlyphEntry, i: int)
|
fn next_complex_glyph(&mut self, entry: &GlyphEntry, i: CharIndex)
|
||||||
-> Option<(int, GlyphInfo<'a>)> {
|
-> Option<(CharIndex, GlyphInfo<'a>)> {
|
||||||
let glyphs = self.store.detail_store.get_detailed_glyphs_for_entry(i, entry.glyph_count());
|
let glyphs = self.store.detail_store.get_detailed_glyphs_for_entry(i, entry.glyph_count());
|
||||||
self.glyph_range = Some(range::each_index(0, glyphs.len() as int));
|
self.glyph_range = Some(range::each_index(CharIndex(0), CharIndex(glyphs.len() as int)));
|
||||||
self.next()
|
self.next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator<(int, GlyphInfo<'a>)> for GlyphIterator<'a> {
|
impl<'a> Iterator<(CharIndex, GlyphInfo<'a>)> for GlyphIterator<'a> {
|
||||||
// I tried to start with something simpler and apply FlatMap, but the
|
// I tried to start with something simpler and apply FlatMap, but the
|
||||||
// inability to store free variables in the FlatMap struct was problematic.
|
// inability to store free variables in the FlatMap struct was problematic.
|
||||||
//
|
//
|
||||||
|
@ -711,7 +717,7 @@ impl<'a> Iterator<(int, GlyphInfo<'a>)> for GlyphIterator<'a> {
|
||||||
// slow paths, which should not be inlined, are `next_glyph_range()` and
|
// slow paths, which should not be inlined, are `next_glyph_range()` and
|
||||||
// `next_complex_glyph()`.
|
// `next_complex_glyph()`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn next(&mut self) -> Option<(int, GlyphInfo<'a>)> {
|
fn next(&mut self) -> Option<(CharIndex, GlyphInfo<'a>)> {
|
||||||
// Would use 'match' here but it borrows contents in a way that
|
// Would use 'match' here but it borrows contents in a way that
|
||||||
// interferes with mutation.
|
// interferes with mutation.
|
||||||
if self.glyph_range.is_some() {
|
if self.glyph_range.is_some() {
|
||||||
|
@ -721,8 +727,8 @@ impl<'a> Iterator<(int, GlyphInfo<'a>)> for GlyphIterator<'a> {
|
||||||
match self.char_range.next() {
|
match self.char_range.next() {
|
||||||
Some(i) => {
|
Some(i) => {
|
||||||
self.char_index = i;
|
self.char_index = i;
|
||||||
assert!(i < self.store.entry_buffer.len() as int);
|
assert!(i < CharIndex(self.store.entry_buffer.len() as int));
|
||||||
let entry = self.store.entry_buffer.get(i as uint);
|
let entry = self.store.entry_buffer.get(i.to_uint());
|
||||||
if entry.is_simple() {
|
if entry.is_simple() {
|
||||||
Some((self.char_index, SimpleGlyphInfo(self.store, i)))
|
Some((self.char_index, SimpleGlyphInfo(self.store, i)))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -6,7 +6,7 @@ extern crate harfbuzz;
|
||||||
|
|
||||||
use font::{Font, FontHandleMethods, FontTableMethods, FontTableTag};
|
use font::{Font, FontHandleMethods, FontTableMethods, FontTableTag};
|
||||||
use platform::font::FontTable;
|
use platform::font::FontTable;
|
||||||
use text::glyph::{GlyphStore, GlyphId, GlyphData};
|
use text::glyph::{CharIndex, GlyphStore, GlyphId, GlyphData};
|
||||||
use text::shaping::ShaperMethods;
|
use text::shaping::ShaperMethods;
|
||||||
use text::util::{float_to_fixed, fixed_to_float};
|
use text::util::{float_to_fixed, fixed_to_float};
|
||||||
|
|
||||||
|
@ -229,7 +229,7 @@ impl Shaper {
|
||||||
|
|
||||||
// GlyphStore records are indexed by character, not byte offset.
|
// GlyphStore records are indexed by character, not byte offset.
|
||||||
// so, we must be careful to increment this when saving glyph entries.
|
// so, we must be careful to increment this when saving glyph entries.
|
||||||
let mut char_idx = 0;
|
let mut char_idx = CharIndex(0);
|
||||||
|
|
||||||
assert!(glyph_count <= char_max);
|
assert!(glyph_count <= char_max);
|
||||||
|
|
||||||
|
@ -435,7 +435,7 @@ impl Shaper {
|
||||||
drop(range.ch);
|
drop(range.ch);
|
||||||
i = range.next as int;
|
i = range.next as int;
|
||||||
if i >= covered_byte_span.end() { break; }
|
if i >= covered_byte_span.end() { break; }
|
||||||
char_idx += 1;
|
char_idx = char_idx + CharIndex(1);
|
||||||
glyphs.add_nonglyph_for_char_index(char_idx, false, false);
|
glyphs.add_nonglyph_for_char_index(char_idx, false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -445,7 +445,7 @@ impl Shaper {
|
||||||
glyph_span.reset(end, 0);
|
glyph_span.reset(end, 0);
|
||||||
let end = char_byte_span.end();; // FIXME: borrow checker workaround
|
let end = char_byte_span.end();; // FIXME: borrow checker workaround
|
||||||
char_byte_span.reset(end, 0);
|
char_byte_span.reset(end, 0);
|
||||||
char_idx += 1;
|
char_idx = char_idx + CharIndex(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this must be called after adding all glyph data; it sorts the
|
// this must be called after adding all glyph data; it sorts the
|
||||||
|
|
|
@ -8,7 +8,7 @@ use servo_util::range::Range;
|
||||||
use std::slice::Items;
|
use std::slice::Items;
|
||||||
use style::computed_values::text_decoration;
|
use style::computed_values::text_decoration;
|
||||||
use sync::Arc;
|
use sync::Arc;
|
||||||
use text::glyph::GlyphStore;
|
use text::glyph::{CharIndex, GlyphStore};
|
||||||
|
|
||||||
/// A text run.
|
/// A text run.
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
|
@ -23,14 +23,14 @@ pub struct TextRun {
|
||||||
|
|
||||||
pub struct SliceIterator<'a> {
|
pub struct SliceIterator<'a> {
|
||||||
glyph_iter: Items<'a, Arc<GlyphStore>>,
|
glyph_iter: Items<'a, Arc<GlyphStore>>,
|
||||||
range: Range<int>,
|
range: Range<CharIndex>,
|
||||||
offset: int,
|
offset: CharIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator<(&'a GlyphStore, int, Range<int>)> for SliceIterator<'a> {
|
impl<'a> Iterator<(&'a GlyphStore, CharIndex, Range<CharIndex>)> for SliceIterator<'a> {
|
||||||
// inline(always) due to the inefficient rt failures messing up inline heuristics, I think.
|
// inline(always) due to the inefficient rt failures messing up inline heuristics, I think.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn next(&mut self) -> Option<(&'a GlyphStore, int, Range<int>)> {
|
fn next(&mut self) -> Option<(&'a GlyphStore, CharIndex, Range<CharIndex>)> {
|
||||||
loop {
|
loop {
|
||||||
let slice_glyphs = self.glyph_iter.next();
|
let slice_glyphs = self.glyph_iter.next();
|
||||||
if slice_glyphs.is_none() {
|
if slice_glyphs.is_none() {
|
||||||
|
@ -40,10 +40,10 @@ impl<'a> Iterator<(&'a GlyphStore, int, Range<int>)> for SliceIterator<'a> {
|
||||||
|
|
||||||
let slice_range = Range::new(self.offset, slice_glyphs.char_len());
|
let slice_range = Range::new(self.offset, slice_glyphs.char_len());
|
||||||
let mut char_range = self.range.intersect(&slice_range);
|
let mut char_range = self.range.intersect(&slice_range);
|
||||||
char_range.shift_by(-(self.offset.to_int().unwrap()));
|
char_range.shift_by(-self.offset);
|
||||||
|
|
||||||
let old_offset = self.offset;
|
let old_offset = self.offset;
|
||||||
self.offset += slice_glyphs.char_len();
|
self.offset = self.offset + slice_glyphs.char_len();
|
||||||
if !char_range.is_empty() {
|
if !char_range.is_empty() {
|
||||||
return Some((&**slice_glyphs, old_offset, char_range))
|
return Some((&**slice_glyphs, old_offset, char_range))
|
||||||
}
|
}
|
||||||
|
@ -52,24 +52,24 @@ impl<'a> Iterator<(&'a GlyphStore, int, Range<int>)> for SliceIterator<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LineIterator<'a> {
|
pub struct LineIterator<'a> {
|
||||||
range: Range<int>,
|
range: Range<CharIndex>,
|
||||||
clump: Option<Range<int>>,
|
clump: Option<Range<CharIndex>>,
|
||||||
slices: SliceIterator<'a>,
|
slices: SliceIterator<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator<Range<int>> for LineIterator<'a> {
|
impl<'a> Iterator<Range<CharIndex>> for LineIterator<'a> {
|
||||||
fn next(&mut self) -> Option<Range<int>> {
|
fn next(&mut self) -> Option<Range<CharIndex>> {
|
||||||
// Loop until we hit whitespace and are in a clump.
|
// Loop until we hit whitespace and are in a clump.
|
||||||
loop {
|
loop {
|
||||||
match self.slices.next() {
|
match self.slices.next() {
|
||||||
Some((glyphs, offset, slice_range)) => {
|
Some((glyphs, offset, slice_range)) => {
|
||||||
match (glyphs.is_whitespace(), self.clump) {
|
match (glyphs.is_whitespace(), self.clump) {
|
||||||
(false, Some(ref mut c)) => {
|
(false, Some(ref mut c)) => {
|
||||||
c.extend_by(slice_range.length().to_int().unwrap());
|
c.extend_by(slice_range.length());
|
||||||
}
|
}
|
||||||
(false, None) => {
|
(false, None) => {
|
||||||
let mut c = slice_range;
|
let mut c = slice_range;
|
||||||
c.shift_by(offset.to_int().unwrap());
|
c.shift_by(offset);
|
||||||
self.clump = Some(c);
|
self.clump = Some(c);
|
||||||
}
|
}
|
||||||
(true, None) => { /* chomp whitespace */ }
|
(true, None) => { /* chomp whitespace */ }
|
||||||
|
@ -165,8 +165,8 @@ impl<'a> TextRun {
|
||||||
glyphs
|
glyphs
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn char_len(&self) -> int {
|
pub fn char_len(&self) -> CharIndex {
|
||||||
self.glyphs.iter().fold(0, |len, slice_glyphs| {
|
self.glyphs.iter().fold(CharIndex(0), |len, slice_glyphs| {
|
||||||
len + slice_glyphs.char_len()
|
len + slice_glyphs.char_len()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -175,14 +175,14 @@ impl<'a> TextRun {
|
||||||
&*self.glyphs
|
&*self.glyphs
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn range_is_trimmable_whitespace(&self, range: &Range<int>) -> bool {
|
pub fn range_is_trimmable_whitespace(&self, range: &Range<CharIndex>) -> bool {
|
||||||
for (slice_glyphs, _, _) in self.iter_slices_for_range(range) {
|
for (slice_glyphs, _, _) in self.iter_slices_for_range(range) {
|
||||||
if !slice_glyphs.is_whitespace() { return false; }
|
if !slice_glyphs.is_whitespace() { return false; }
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn metrics_for_range(&self, range: &Range<int>) -> RunMetrics {
|
pub fn metrics_for_range(&self, range: &Range<CharIndex>) -> RunMetrics {
|
||||||
// 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);
|
||||||
|
@ -194,14 +194,14 @@ impl<'a> TextRun {
|
||||||
RunMetrics::new(advance, self.font_metrics.ascent, self.font_metrics.descent)
|
RunMetrics::new(advance, self.font_metrics.ascent, self.font_metrics.descent)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn metrics_for_slice(&self, glyphs: &GlyphStore, slice_range: &Range<int>) -> RunMetrics {
|
pub fn metrics_for_slice(&self, glyphs: &GlyphStore, slice_range: &Range<CharIndex>) -> RunMetrics {
|
||||||
let mut advance = Au(0);
|
let mut advance = Au(0);
|
||||||
for (_i, glyph) in glyphs.iter_glyphs_for_char_range(slice_range) {
|
for (_i, glyph) in glyphs.iter_glyphs_for_char_range(slice_range) {
|
||||||
advance = advance + glyph.advance();
|
advance = advance + glyph.advance();
|
||||||
}
|
}
|
||||||
RunMetrics::new(advance, self.font_metrics.ascent, self.font_metrics.descent)
|
RunMetrics::new(advance, self.font_metrics.ascent, self.font_metrics.descent)
|
||||||
}
|
}
|
||||||
pub fn min_width_for_range(&self, range: &Range<int>) -> Au {
|
pub fn min_width_for_range(&self, range: &Range<CharIndex>) -> Au {
|
||||||
let mut max_piece_width = Au(0);
|
let mut max_piece_width = Au(0);
|
||||||
debug!("iterating outer range {:?}", range);
|
debug!("iterating outer range {:?}", range);
|
||||||
for (_, offset, slice_range) in self.iter_slices_for_range(range) {
|
for (_, offset, slice_range) in self.iter_slices_for_range(range) {
|
||||||
|
@ -212,15 +212,15 @@ impl<'a> TextRun {
|
||||||
max_piece_width
|
max_piece_width
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_slices_for_range(&'a self, range: &Range<int>) -> SliceIterator<'a> {
|
pub fn iter_slices_for_range(&'a self, range: &Range<CharIndex>) -> SliceIterator<'a> {
|
||||||
SliceIterator {
|
SliceIterator {
|
||||||
glyph_iter: self.glyphs.iter(),
|
glyph_iter: self.glyphs.iter(),
|
||||||
range: *range,
|
range: *range,
|
||||||
offset: 0,
|
offset: CharIndex(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_natural_lines_for_range(&'a self, range: &Range<int>) -> LineIterator<'a> {
|
pub fn iter_natural_lines_for_range(&'a self, range: &Range<CharIndex>) -> LineIterator<'a> {
|
||||||
LineIterator {
|
LineIterator {
|
||||||
range: *range,
|
range: *range,
|
||||||
clump: None,
|
clump: None,
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* 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 text::glyph::CharIndex;
|
||||||
|
|
||||||
#[deriving(Eq)]
|
#[deriving(Eq)]
|
||||||
pub enum CompressionMode {
|
pub enum CompressionMode {
|
||||||
CompressNone,
|
CompressNone,
|
||||||
|
@ -20,11 +22,13 @@ pub enum CompressionMode {
|
||||||
// * Issue #114: record skipped and kept chars for mapping original to new text
|
// * Issue #114: record skipped and kept chars for mapping original to new text
|
||||||
//
|
//
|
||||||
// * Untracked: various edge cases for bidi, CJK, etc.
|
// * Untracked: various edge cases for bidi, CJK, etc.
|
||||||
pub fn transform_text(text: &str, mode: CompressionMode, incoming_whitespace: bool, new_line_pos: &mut Vec<int>) -> (~str, bool) {
|
pub fn transform_text(text: &str, mode: CompressionMode,
|
||||||
|
incoming_whitespace: bool,
|
||||||
|
new_line_pos: &mut Vec<CharIndex>) -> (~str, bool) {
|
||||||
let mut out_str: ~str = "".to_owned();
|
let mut out_str: ~str = "".to_owned();
|
||||||
let out_whitespace = match mode {
|
let out_whitespace = match mode {
|
||||||
CompressNone | DiscardNewline => {
|
CompressNone | DiscardNewline => {
|
||||||
let mut new_line_index = 0;
|
let mut new_line_index = CharIndex(0);
|
||||||
for ch in text.chars() {
|
for ch in text.chars() {
|
||||||
if is_discardable_char(ch, mode) {
|
if is_discardable_char(ch, mode) {
|
||||||
// TODO: record skipped char
|
// TODO: record skipped char
|
||||||
|
@ -36,11 +40,11 @@ pub fn transform_text(text: &str, mode: CompressionMode, incoming_whitespace: bo
|
||||||
// Save new-line's position for line-break
|
// Save new-line's position for line-break
|
||||||
// This value is relative(not absolute)
|
// This value is relative(not absolute)
|
||||||
new_line_pos.push(new_line_index);
|
new_line_pos.push(new_line_index);
|
||||||
new_line_index = 0;
|
new_line_index = CharIndex(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ch != '\n' {
|
if ch != '\n' {
|
||||||
new_line_index += 1;
|
new_line_index = new_line_index + CharIndex(1);
|
||||||
}
|
}
|
||||||
out_str.push_char(ch);
|
out_str.push_char(ch);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ use gfx::display_list::{LineDisplayItemClass, OpaqueNode, PseudoDisplayItemClass
|
||||||
use gfx::display_list::{SolidColorDisplayItem, SolidColorDisplayItemClass, StackingLevel};
|
use gfx::display_list::{SolidColorDisplayItem, SolidColorDisplayItemClass, StackingLevel};
|
||||||
use gfx::display_list::{TextDecorations, TextDisplayItem, TextDisplayItemClass};
|
use gfx::display_list::{TextDecorations, TextDisplayItem, TextDisplayItemClass};
|
||||||
use gfx::font::FontStyle;
|
use gfx::font::FontStyle;
|
||||||
|
use gfx::text::glyph::CharIndex;
|
||||||
use gfx::text::text_run::TextRun;
|
use gfx::text::text_run::TextRun;
|
||||||
use servo_msg::constellation_msg::{ConstellationChan, FrameRectMsg, PipelineId, SubpageId};
|
use servo_msg::constellation_msg::{ConstellationChan, FrameRectMsg, PipelineId, SubpageId};
|
||||||
use servo_net::image::holder::{ImageHolder, LocalImageCacheHandle};
|
use servo_net::image::holder::{ImageHolder, LocalImageCacheHandle};
|
||||||
|
@ -95,7 +96,7 @@ pub struct Box {
|
||||||
/// New-line chracter(\n)'s positions(relative, not absolute)
|
/// New-line chracter(\n)'s positions(relative, not absolute)
|
||||||
///
|
///
|
||||||
/// FIXME(#2260, pcwalton): This is very inefficient; remove.
|
/// FIXME(#2260, pcwalton): This is very inefficient; remove.
|
||||||
pub new_line_pos: Vec<int>,
|
pub new_line_pos: Vec<CharIndex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Info specific to the kind of box. Keep this enum small.
|
/// Info specific to the kind of box. Keep this enum small.
|
||||||
|
@ -226,12 +227,12 @@ pub struct ScannedTextBoxInfo {
|
||||||
pub run: Arc<~TextRun>,
|
pub run: Arc<~TextRun>,
|
||||||
|
|
||||||
/// The range within the above text run that this represents.
|
/// The range within the above text run that this represents.
|
||||||
pub range: Range<int>,
|
pub range: Range<CharIndex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScannedTextBoxInfo {
|
impl ScannedTextBoxInfo {
|
||||||
/// Creates the information specific to a scanned text box from a range and a text run.
|
/// Creates the information specific to a scanned text box from a range and a text run.
|
||||||
pub fn new(run: Arc<~TextRun>, range: Range<int>) -> ScannedTextBoxInfo {
|
pub fn new(run: Arc<~TextRun>, range: Range<CharIndex>) -> ScannedTextBoxInfo {
|
||||||
ScannedTextBoxInfo {
|
ScannedTextBoxInfo {
|
||||||
run: run,
|
run: run,
|
||||||
range: range,
|
range: range,
|
||||||
|
@ -1108,7 +1109,8 @@ impl Box {
|
||||||
let cur_new_line_pos = new_line_pos.shift().unwrap();
|
let cur_new_line_pos = new_line_pos.shift().unwrap();
|
||||||
|
|
||||||
let left_range = Range::new(text_box_info.range.begin(), cur_new_line_pos);
|
let left_range = Range::new(text_box_info.range.begin(), cur_new_line_pos);
|
||||||
let right_range = Range::new(text_box_info.range.begin() + cur_new_line_pos + 1, text_box_info.range.length() - (cur_new_line_pos + 1));
|
let right_range = Range::new(text_box_info.range.begin() + cur_new_line_pos + CharIndex(1),
|
||||||
|
text_box_info.range.length() - (cur_new_line_pos + CharIndex(1)));
|
||||||
|
|
||||||
// Left box is for left text of first founded new-line character.
|
// Left box is for left text of first founded new-line character.
|
||||||
let left_box = {
|
let left_box = {
|
||||||
|
@ -1120,7 +1122,7 @@ impl Box {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Right box is for right text of first founded new-line character.
|
// Right box is for right text of first founded new-line character.
|
||||||
let right_box = if right_range.length() > 0 {
|
let right_box = if right_range.length() > CharIndex(0) {
|
||||||
let new_text_box_info = ScannedTextBoxInfo::new(text_box_info.run.clone(), right_range);
|
let new_text_box_info = ScannedTextBoxInfo::new(text_box_info.run.clone(), right_range);
|
||||||
let new_metrics = new_text_box_info.run.metrics_for_range(&right_range);
|
let new_metrics = new_text_box_info.run.metrics_for_range(&right_range);
|
||||||
let mut new_box = self.transform(new_metrics.bounding_box.size, ScannedTextBox(new_text_box_info));
|
let mut new_box = self.transform(new_metrics.bounding_box.size, ScannedTextBox(new_text_box_info));
|
||||||
|
@ -1145,8 +1147,8 @@ impl Box {
|
||||||
ScannedTextBox(ref text_box_info) => {
|
ScannedTextBox(ref text_box_info) => {
|
||||||
let mut pieces_processed_count: uint = 0;
|
let mut pieces_processed_count: uint = 0;
|
||||||
let mut remaining_width: Au = max_width;
|
let mut remaining_width: Au = max_width;
|
||||||
let mut left_range = Range::new(text_box_info.range.begin(), 0);
|
let mut left_range = Range::new(text_box_info.range.begin(), CharIndex(0));
|
||||||
let mut right_range: Option<Range<int>> = None;
|
let mut right_range: Option<Range<CharIndex>> = None;
|
||||||
|
|
||||||
debug!("split_to_width: splitting text box (strlen={:u}, range={}, \
|
debug!("split_to_width: splitting text box (strlen={:u}, range={}, \
|
||||||
avail_width={})",
|
avail_width={})",
|
||||||
|
@ -1171,11 +1173,11 @@ impl Box {
|
||||||
|
|
||||||
if starts_line && pieces_processed_count == 0 && glyphs.is_whitespace() {
|
if starts_line && pieces_processed_count == 0 && glyphs.is_whitespace() {
|
||||||
debug!("split_to_width: case=skipping leading trimmable whitespace");
|
debug!("split_to_width: case=skipping leading trimmable whitespace");
|
||||||
left_range.shift_by(slice_range.length() as int);
|
left_range.shift_by(slice_range.length());
|
||||||
} else {
|
} else {
|
||||||
debug!("split_to_width: case=enlarging span");
|
debug!("split_to_width: case=enlarging span");
|
||||||
remaining_width = remaining_width - advance;
|
remaining_width = remaining_width - advance;
|
||||||
left_range.extend_by(slice_range.length() as int);
|
left_range.extend_by(slice_range.length());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// The advance is more than the remaining width.
|
// The advance is more than the remaining width.
|
||||||
|
@ -1212,7 +1214,7 @@ impl Box {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let left_box = if left_range.length() > 0 {
|
let left_box = if left_range.length() > CharIndex(0) {
|
||||||
let new_text_box_info = ScannedTextBoxInfo::new(text_box_info.run.clone(), left_range);
|
let new_text_box_info = ScannedTextBoxInfo::new(text_box_info.run.clone(), left_range);
|
||||||
let mut new_metrics = new_text_box_info.run.metrics_for_range(&left_range);
|
let mut new_metrics = new_text_box_info.run.metrics_for_range(&left_range);
|
||||||
new_metrics.bounding_box.size.height = self.border_box.size.height;
|
new_metrics.bounding_box.size.height = self.border_box.size.height;
|
||||||
|
@ -1222,7 +1224,7 @@ impl Box {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let right_box = right_range.map_or(None, |range: Range<int>| {
|
let right_box = right_range.map_or(None, |range: Range<CharIndex>| {
|
||||||
let new_text_box_info = ScannedTextBoxInfo::new(text_box_info.run.clone(),
|
let new_text_box_info = ScannedTextBoxInfo::new(text_box_info.run.clone(),
|
||||||
range);
|
range);
|
||||||
let mut new_metrics = new_text_box_info.run.metrics_for_range(&range);
|
let mut new_metrics = new_text_box_info.run.metrics_for_range(&range);
|
||||||
|
|
|
@ -10,6 +10,7 @@ use layout::inline::InlineBoxes;
|
||||||
|
|
||||||
use gfx::font::{FontMetrics, FontStyle};
|
use gfx::font::{FontMetrics, FontStyle};
|
||||||
use gfx::font_context::FontContext;
|
use gfx::font_context::FontContext;
|
||||||
|
use gfx::text::glyph::CharIndex;
|
||||||
use gfx::text::text_run::TextRun;
|
use gfx::text::text_run::TextRun;
|
||||||
use gfx::text::util::{CompressWhitespaceNewline, transform_text, CompressNone};
|
use gfx::text::util::{CompressWhitespaceNewline, transform_text, CompressNone};
|
||||||
use servo_util::geometry::Au;
|
use servo_util::geometry::Au;
|
||||||
|
@ -20,7 +21,7 @@ use style::computed_values::{font_family, line_height, white_space};
|
||||||
use sync::Arc;
|
use sync::Arc;
|
||||||
|
|
||||||
struct NewLinePositions {
|
struct NewLinePositions {
|
||||||
new_line_pos: Vec<int>,
|
new_line_pos: Vec<CharIndex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// A helper function.
|
// A helper function.
|
||||||
|
@ -31,7 +32,7 @@ fn can_coalesce_text_nodes(boxes: &[Box], left_i: uint, right_i: uint) -> bool {
|
||||||
|
|
||||||
/// A stack-allocated object for scanning an inline flow into `TextRun`-containing `TextBox`es.
|
/// A stack-allocated object for scanning an inline flow into `TextRun`-containing `TextBox`es.
|
||||||
pub struct TextRunScanner {
|
pub struct TextRunScanner {
|
||||||
pub clump: Range<int>,
|
pub clump: Range<CharIndex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextRunScanner {
|
impl TextRunScanner {
|
||||||
|
@ -63,11 +64,11 @@ impl TextRunScanner {
|
||||||
last_whitespace);
|
last_whitespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.clump.extend_by(1);
|
self.clump.extend_by(CharIndex(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle remaining clumps.
|
// Handle remaining clumps.
|
||||||
if self.clump.length() > 0 {
|
if self.clump.length() > CharIndex(0) {
|
||||||
drop(self.flush_clump_to_list(font_context,
|
drop(self.flush_clump_to_list(font_context,
|
||||||
old_boxes.as_slice(),
|
old_boxes.as_slice(),
|
||||||
&mut new_boxes,
|
&mut new_boxes,
|
||||||
|
@ -99,12 +100,12 @@ impl TextRunScanner {
|
||||||
out_boxes: &mut Vec<Box>,
|
out_boxes: &mut Vec<Box>,
|
||||||
last_whitespace: bool)
|
last_whitespace: bool)
|
||||||
-> bool {
|
-> bool {
|
||||||
assert!(self.clump.length() > 0);
|
assert!(self.clump.length() > CharIndex(0));
|
||||||
|
|
||||||
debug!("TextRunScanner: flushing boxes in range={}", self.clump);
|
debug!("TextRunScanner: flushing boxes in range={}", self.clump);
|
||||||
let is_singleton = self.clump.length() == 1;
|
let is_singleton = self.clump.length() == CharIndex(1);
|
||||||
|
|
||||||
let is_text_clump = match in_boxes[self.clump.begin() as uint].specific {
|
let is_text_clump = match in_boxes[self.clump.begin().to_uint()].specific {
|
||||||
UnscannedTextBox(_) => true,
|
UnscannedTextBox(_) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
@ -117,11 +118,11 @@ impl TextRunScanner {
|
||||||
(true, false) => {
|
(true, false) => {
|
||||||
// FIXME(pcwalton): Stop cloning boxes, as above.
|
// FIXME(pcwalton): Stop cloning boxes, as above.
|
||||||
debug!("TextRunScanner: pushing single non-text box in range: {}", self.clump);
|
debug!("TextRunScanner: pushing single non-text box in range: {}", self.clump);
|
||||||
let new_box = in_boxes[self.clump.begin() as uint].clone();
|
let new_box = in_boxes[self.clump.begin().to_uint()].clone();
|
||||||
out_boxes.push(new_box)
|
out_boxes.push(new_box)
|
||||||
},
|
},
|
||||||
(true, true) => {
|
(true, true) => {
|
||||||
let old_box = &in_boxes[self.clump.begin() as uint];
|
let old_box = &in_boxes[self.clump.begin().to_uint()];
|
||||||
let text = match old_box.specific {
|
let text = match old_box.specific {
|
||||||
UnscannedTextBox(ref text_box_info) => &text_box_info.text,
|
UnscannedTextBox(ref text_box_info) => &text_box_info.text,
|
||||||
_ => fail!("Expected an unscanned text box!"),
|
_ => fail!("Expected an unscanned text box!"),
|
||||||
|
@ -156,11 +157,11 @@ impl TextRunScanner {
|
||||||
debug!("TextRunScanner: pushing single text box in range: {} ({})",
|
debug!("TextRunScanner: pushing single text box in range: {} ({})",
|
||||||
self.clump,
|
self.clump,
|
||||||
*text);
|
*text);
|
||||||
let range = Range::new(0, run.char_len());
|
let range = Range::new(CharIndex(0), run.char_len());
|
||||||
let new_metrics = run.metrics_for_range(&range);
|
let new_metrics = run.metrics_for_range(&range);
|
||||||
let new_text_box_info = ScannedTextBoxInfo::new(Arc::new(run), range);
|
let new_text_box_info = ScannedTextBoxInfo::new(Arc::new(run), range);
|
||||||
let mut new_box = old_box.transform(new_metrics.bounding_box.size,
|
let mut new_box = old_box.transform(new_metrics.bounding_box.size,
|
||||||
ScannedTextBox(new_text_box_info));
|
ScannedTextBox(new_text_box_info));
|
||||||
new_box.new_line_pos = new_line_pos;
|
new_box.new_line_pos = new_line_pos;
|
||||||
out_boxes.push(new_box)
|
out_boxes.push(new_box)
|
||||||
}
|
}
|
||||||
|
@ -169,7 +170,7 @@ impl TextRunScanner {
|
||||||
// TODO(#177): Text run creation must account for the renderability of text by
|
// TODO(#177): Text run creation must account for the renderability of text by
|
||||||
// font group fonts. This is probably achieved by creating the font group above
|
// font group fonts. This is probably achieved by creating the font group above
|
||||||
// and then letting `FontGroup` decide which `Font` to stick into the text run.
|
// and then letting `FontGroup` decide which `Font` to stick into the text run.
|
||||||
let in_box = &in_boxes[self.clump.begin() as uint];
|
let in_box = &in_boxes[self.clump.begin().to_uint()];
|
||||||
let font_style = in_box.font_style();
|
let font_style = in_box.font_style();
|
||||||
let fontgroup = font_context.get_resolved_font_for_style(&font_style);
|
let fontgroup = font_context.get_resolved_font_for_style(&font_style);
|
||||||
let decoration = in_box.text_decoration();
|
let decoration = in_box.text_decoration();
|
||||||
|
@ -184,12 +185,12 @@ impl TextRunScanner {
|
||||||
|
|
||||||
// First, transform/compress text of all the nodes.
|
// First, transform/compress text of all the nodes.
|
||||||
let mut last_whitespace_in_clump = new_whitespace;
|
let mut last_whitespace_in_clump = new_whitespace;
|
||||||
let transformed_strs: Vec<~str> = Vec::from_fn(self.clump.length() as uint, |i| {
|
let transformed_strs: Vec<~str> = Vec::from_fn(self.clump.length().to_uint(), |i| {
|
||||||
// TODO(#113): We should be passing the compression context between calls to
|
// TODO(#113): We should be passing the compression context between calls to
|
||||||
// `transform_text`, so that boxes starting and/or ending with whitespace can
|
// `transform_text`, so that boxes starting and/or ending with whitespace can
|
||||||
// be compressed correctly with respect to the text run.
|
// be compressed correctly with respect to the text run.
|
||||||
let idx = i as int + self.clump.begin();
|
let idx = CharIndex(i as int) + self.clump.begin();
|
||||||
let in_box = match in_boxes[idx as uint].specific {
|
let in_box = match in_boxes[idx.to_uint()].specific {
|
||||||
UnscannedTextBox(ref text_box_info) => &text_box_info.text,
|
UnscannedTextBox(ref text_box_info) => &text_box_info.text,
|
||||||
_ => fail!("Expected an unscanned text box!"),
|
_ => fail!("Expected an unscanned text box!"),
|
||||||
};
|
};
|
||||||
|
@ -210,20 +211,20 @@ impl TextRunScanner {
|
||||||
// Next, concatenate all of the transformed strings together, saving the new
|
// Next, concatenate all of the transformed strings together, saving the new
|
||||||
// character indices.
|
// character indices.
|
||||||
let mut run_str: ~str = "".to_owned();
|
let mut run_str: ~str = "".to_owned();
|
||||||
let mut new_ranges: Vec<Range<int>> = vec![];
|
let mut new_ranges: Vec<Range<CharIndex>> = vec![];
|
||||||
let mut char_total = 0;
|
let mut char_total = CharIndex(0);
|
||||||
for i in range(0, transformed_strs.len() as int) {
|
for i in range(0, transformed_strs.len() as int) {
|
||||||
let added_chars = transformed_strs.get(i as uint).char_len() as int;
|
let added_chars = CharIndex(transformed_strs.get(i as uint).char_len() as int);
|
||||||
new_ranges.push(Range::new(char_total, added_chars));
|
new_ranges.push(Range::new(char_total, added_chars));
|
||||||
run_str.push_str(*transformed_strs.get(i as uint));
|
run_str.push_str(*transformed_strs.get(i as uint));
|
||||||
char_total += added_chars;
|
char_total = char_total + added_chars;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now create the run.
|
// Now create the run.
|
||||||
// TextRuns contain a cycle which is usually resolved by the teardown
|
// TextRuns contain a cycle which is usually resolved by the teardown
|
||||||
// sequence. If no clump takes ownership, however, it will leak.
|
// sequence. If no clump takes ownership, however, it will leak.
|
||||||
let clump = self.clump;
|
let clump = self.clump;
|
||||||
let run = if clump.length() != 0 && run_str.len() > 0 {
|
let run = if clump.length() != CharIndex(0) && run_str.len() > 0 {
|
||||||
Some(Arc::new(~TextRun::new(&mut *fontgroup.borrow().fonts.get(0).borrow_mut(),
|
Some(Arc::new(~TextRun::new(&mut *fontgroup.borrow().fonts.get(0).borrow_mut(),
|
||||||
run_str.clone(), decoration)))
|
run_str.clone(), decoration)))
|
||||||
} else {
|
} else {
|
||||||
|
@ -234,25 +235,25 @@ impl TextRunScanner {
|
||||||
debug!("TextRunScanner: pushing box(es) in range: {}", self.clump);
|
debug!("TextRunScanner: pushing box(es) in range: {}", self.clump);
|
||||||
for i in clump.each_index() {
|
for i in clump.each_index() {
|
||||||
let logical_offset = i - self.clump.begin();
|
let logical_offset = i - self.clump.begin();
|
||||||
let range = new_ranges.get(logical_offset as uint);
|
let range = new_ranges.get(logical_offset.to_uint());
|
||||||
if range.length() == 0 {
|
if range.length() == CharIndex(0) {
|
||||||
debug!("Elided an `UnscannedTextbox` because it was zero-length after \
|
debug!("Elided an `UnscannedTextbox` because it was zero-length after \
|
||||||
compression; {}", in_boxes[i as uint]);
|
compression; {}", in_boxes[i.to_uint()]);
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_text_box_info = ScannedTextBoxInfo::new(run.get_ref().clone(), *range);
|
let new_text_box_info = ScannedTextBoxInfo::new(run.get_ref().clone(), *range);
|
||||||
let new_metrics = new_text_box_info.run.metrics_for_range(range);
|
let new_metrics = new_text_box_info.run.metrics_for_range(range);
|
||||||
let mut new_box = in_boxes[i as uint].transform(new_metrics.bounding_box.size,
|
let mut new_box = in_boxes[i.to_uint()].transform(new_metrics.bounding_box.size,
|
||||||
ScannedTextBox(new_text_box_info));
|
ScannedTextBox(new_text_box_info));
|
||||||
new_box.new_line_pos = new_line_positions.get(logical_offset as uint).new_line_pos.clone();
|
new_box.new_line_pos = new_line_positions.get(logical_offset.to_uint()).new_line_pos.clone();
|
||||||
out_boxes.push(new_box)
|
out_boxes.push(new_box)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // End of match.
|
} // End of match.
|
||||||
|
|
||||||
let end = self.clump.end(); // FIXME: borrow checker workaround
|
let end = self.clump.end(); // FIXME: borrow checker workaround
|
||||||
self.clump.reset(end, 0);
|
self.clump.reset(end, CharIndex(0));
|
||||||
|
|
||||||
new_whitespace
|
new_whitespace
|
||||||
} // End of `flush_clump_to_list`.
|
} // End of `flush_clump_to_list`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue