mirror of
https://github.com/servo/servo.git
synced 2025-09-09 06:28:22 +01:00
commit
9fe115192a
16 changed files with 450 additions and 292 deletions
|
@ -16,6 +16,7 @@
|
|||
|
||||
use color::Color;
|
||||
use render_context::RenderContext;
|
||||
use text::glyph::CharIndex;
|
||||
use text::TextRun;
|
||||
|
||||
use collections::deque::Deque;
|
||||
|
@ -395,7 +396,7 @@ pub struct TextDisplayItem {
|
|||
pub text_run: Arc<~TextRun>,
|
||||
|
||||
/// The range of text within the text run.
|
||||
pub range: Range<int>,
|
||||
pub range: Range<CharIndex>,
|
||||
|
||||
/// The color of the text.
|
||||
pub text_color: Color,
|
||||
|
|
|
@ -23,7 +23,7 @@ use servo_util::geometry::Au;
|
|||
use platform::font_context::FontContextHandle;
|
||||
use platform::font::{FontHandle, FontTable};
|
||||
use render_context::RenderContext;
|
||||
use text::glyph::{GlyphStore, GlyphIndex};
|
||||
use text::glyph::{CharIndex, GlyphStore, GlyphId};
|
||||
use text::shaping::ShaperMethods;
|
||||
use text::{Shaper, TextRun};
|
||||
|
||||
|
@ -45,8 +45,8 @@ pub trait FontHandleMethods {
|
|||
|
||||
fn clone_with_style(&self, fctx: &FontContextHandle, style: &UsedFontStyle)
|
||||
-> Result<FontHandle, ()>;
|
||||
fn glyph_index(&self, codepoint: char) -> Option<GlyphIndex>;
|
||||
fn glyph_h_advance(&self, GlyphIndex) -> Option<FractionalPixel>;
|
||||
fn glyph_index(&self, codepoint: char) -> Option<GlyphId>;
|
||||
fn glyph_h_advance(&self, GlyphId) -> Option<FractionalPixel>;
|
||||
fn get_metrics(&self) -> FontMetrics;
|
||||
fn get_table_for_tag(&self, FontTableTag) -> Option<FontTable>;
|
||||
}
|
||||
|
@ -330,7 +330,7 @@ impl Font {
|
|||
pub fn draw_text_into_context(&mut self,
|
||||
rctx: &RenderContext,
|
||||
run: &~TextRun,
|
||||
range: &Range<int>,
|
||||
range: &Range<CharIndex>,
|
||||
baseline_origin: Point2D<Au>,
|
||||
color: Color) {
|
||||
use libc::types::common::c99::{uint16_t, uint32_t};
|
||||
|
@ -353,7 +353,7 @@ impl Font {
|
|||
|
||||
let mut origin = baseline_origin.clone();
|
||||
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 (_i, glyph) in glyphs.iter_glyphs_for_char_range(&slice_range) {
|
||||
|
@ -361,7 +361,7 @@ impl Font {
|
|||
let glyph_offset = glyph.offset().unwrap_or(Zero::zero());
|
||||
|
||||
let azglyph = struct__AzGlyph {
|
||||
mIndex: glyph.index() as uint32_t,
|
||||
mIndex: glyph.id() as uint32_t,
|
||||
mPosition: struct__AzPoint {
|
||||
x: (origin.x + glyph_offset.x).to_nearest_px() as AzFloat,
|
||||
y: (origin.y + glyph_offset.y).to_nearest_px() as AzFloat
|
||||
|
@ -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 #98): using inter-char and inter-word spacing settings when measuring text
|
||||
let mut advance = Au(0);
|
||||
|
@ -405,7 +405,7 @@ impl Font {
|
|||
|
||||
pub fn measure_text_for_slice(&self,
|
||||
glyphs: &GlyphStore,
|
||||
slice_range: &Range<int>)
|
||||
slice_range: &Range<CharIndex>)
|
||||
-> RunMetrics {
|
||||
let mut advance = Au(0);
|
||||
for (_i, glyph) in glyphs.iter_glyphs_for_char_range(slice_range) {
|
||||
|
@ -430,11 +430,11 @@ impl Font {
|
|||
FontDescriptor::new(self.style.clone(), SelectorPlatformIdentifier(self.handle.face_identifier()))
|
||||
}
|
||||
|
||||
pub fn glyph_index(&self, codepoint: char) -> Option<GlyphIndex> {
|
||||
pub fn glyph_index(&self, codepoint: char) -> Option<GlyphId> {
|
||||
self.handle.glyph_index(codepoint)
|
||||
}
|
||||
|
||||
pub fn glyph_h_advance(&mut self, glyph: GlyphIndex) -> FractionalPixel {
|
||||
pub fn glyph_h_advance(&mut self, glyph: GlyphId) -> FractionalPixel {
|
||||
let handle = &self.handle;
|
||||
self.glyph_advance_cache.find_or_create(&glyph, |glyph| {
|
||||
match handle.glyph_h_advance(*glyph) {
|
||||
|
|
|
@ -23,6 +23,7 @@ extern crate png;
|
|||
#[phase(syntax)]
|
||||
extern crate servo_macros = "macros";
|
||||
extern crate servo_net = "net";
|
||||
#[phase(syntax, link)]
|
||||
extern crate servo_util = "util";
|
||||
extern crate servo_msg = "msg";
|
||||
extern crate style;
|
||||
|
|
|
@ -9,7 +9,7 @@ use font::{FontTableTag, FractionalPixel, SpecifiedFontStyle, UsedFontStyle};
|
|||
use servo_util::geometry::Au;
|
||||
use servo_util::geometry;
|
||||
use platform::font_context::FontContextHandle;
|
||||
use text::glyph::GlyphIndex;
|
||||
use text::glyph::GlyphId;
|
||||
use text::util::{float_to_fixed, fixed_to_float};
|
||||
use style::computed_values::font_weight;
|
||||
|
||||
|
@ -174,12 +174,12 @@ impl FontHandleMethods for FontHandle {
|
|||
}
|
||||
|
||||
fn glyph_index(&self,
|
||||
codepoint: char) -> Option<GlyphIndex> {
|
||||
codepoint: char) -> Option<GlyphId> {
|
||||
assert!(self.face.is_not_null());
|
||||
unsafe {
|
||||
let idx = FT_Get_Char_Index(self.face, codepoint as FT_ULong);
|
||||
return if idx != 0 as FT_UInt {
|
||||
Some(idx as GlyphIndex)
|
||||
Some(idx as GlyphId)
|
||||
} else {
|
||||
debug!("Invalid codepoint: {}", codepoint);
|
||||
None
|
||||
|
@ -188,7 +188,7 @@ impl FontHandleMethods for FontHandle {
|
|||
}
|
||||
|
||||
fn glyph_h_advance(&self,
|
||||
glyph: GlyphIndex) -> Option<FractionalPixel> {
|
||||
glyph: GlyphId) -> Option<FractionalPixel> {
|
||||
assert!(self.face.is_not_null());
|
||||
unsafe {
|
||||
let res = FT_Load_Glyph(self.face, glyph as FT_UInt, 0);
|
||||
|
|
|
@ -9,7 +9,7 @@ use font::{FontTableTag, FractionalPixel, SpecifiedFontStyle, UsedFontStyle};
|
|||
use servo_util::geometry::Au;
|
||||
use servo_util::geometry;
|
||||
use platform::font_context::FontContextHandle;
|
||||
use text::glyph::GlyphIndex;
|
||||
use text::glyph::GlyphId;
|
||||
use text::util::{float_to_fixed, fixed_to_float};
|
||||
use style::computed_values::font_weight;
|
||||
|
||||
|
@ -174,12 +174,12 @@ impl FontHandleMethods for FontHandle {
|
|||
}
|
||||
|
||||
fn glyph_index(&self,
|
||||
codepoint: char) -> Option<GlyphIndex> {
|
||||
codepoint: char) -> Option<GlyphId> {
|
||||
assert!(self.face.is_not_null());
|
||||
unsafe {
|
||||
let idx = FT_Get_Char_Index(self.face, codepoint as FT_ULong);
|
||||
return if idx != 0 as FT_UInt {
|
||||
Some(idx as GlyphIndex)
|
||||
Some(idx as GlyphId)
|
||||
} else {
|
||||
debug!("Invalid codepoint: {}", codepoint);
|
||||
None
|
||||
|
@ -188,7 +188,7 @@ impl FontHandleMethods for FontHandle {
|
|||
}
|
||||
|
||||
fn glyph_h_advance(&self,
|
||||
glyph: GlyphIndex) -> Option<FractionalPixel> {
|
||||
glyph: GlyphId) -> Option<FractionalPixel> {
|
||||
assert!(self.face.is_not_null());
|
||||
unsafe {
|
||||
let res = FT_Load_Glyph(self.face, glyph as FT_UInt, 0);
|
||||
|
|
|
@ -14,7 +14,7 @@ use font::{FractionalPixel, SpecifiedFontStyle};
|
|||
use servo_util::geometry::{Au, px_to_pt};
|
||||
use servo_util::geometry;
|
||||
use platform::macos::font_context::FontContextHandle;
|
||||
use text::glyph::GlyphIndex;
|
||||
use text::glyph::GlyphId;
|
||||
use style::computed_values::font_weight;
|
||||
|
||||
use core_foundation::base::CFIndex;
|
||||
|
@ -125,7 +125,7 @@ impl FontHandleMethods for FontHandle {
|
|||
return FontHandle::new_from_CTFont(fctx, new_font);
|
||||
}
|
||||
|
||||
fn glyph_index(&self, codepoint: char) -> Option<GlyphIndex> {
|
||||
fn glyph_index(&self, codepoint: char) -> Option<GlyphId> {
|
||||
let characters: [UniChar, ..1] = [codepoint as UniChar];
|
||||
let glyphs: [CGGlyph, ..1] = [0 as CGGlyph];
|
||||
let count: CFIndex = 1;
|
||||
|
@ -140,10 +140,10 @@ impl FontHandleMethods for FontHandle {
|
|||
}
|
||||
|
||||
assert!(glyphs[0] != 0); // FIXME: error handling
|
||||
return Some(glyphs[0] as GlyphIndex);
|
||||
return Some(glyphs[0] as GlyphId);
|
||||
}
|
||||
|
||||
fn glyph_h_advance(&self, glyph: GlyphIndex) -> Option<FractionalPixel> {
|
||||
fn glyph_h_advance(&self, glyph: GlyphId) -> Option<FractionalPixel> {
|
||||
let glyphs = [glyph as CGGlyph];
|
||||
let advance = self.ctfont.get_advances_for_glyphs(kCTFontDefaultOrientation,
|
||||
&glyphs[0],
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use servo_util::vec::*;
|
||||
use servo_util::range::Range;
|
||||
use servo_util::range;
|
||||
use servo_util::range::{Range, RangeIndex, EachIndex};
|
||||
use servo_util::geometry::Au;
|
||||
|
||||
use std::cmp::{Ord, Eq};
|
||||
|
@ -11,7 +12,6 @@ use std::num::{NumCast, Zero};
|
|||
use std::mem;
|
||||
use std::u16;
|
||||
use std::slice;
|
||||
use std::iter;
|
||||
use geom::point::Point2D;
|
||||
|
||||
/// GlyphEntry is a port of Gecko's CompressedGlyph scheme for storing glyph data compactly.
|
||||
|
@ -24,13 +24,13 @@ use geom::point::Point2D;
|
|||
/// in DetailedGlyphStore.
|
||||
#[deriving(Clone)]
|
||||
struct GlyphEntry {
|
||||
value: u32
|
||||
value: u32,
|
||||
}
|
||||
|
||||
impl GlyphEntry {
|
||||
fn new(value: u32) -> GlyphEntry {
|
||||
GlyphEntry {
|
||||
value: value
|
||||
value: value,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,15 +39,15 @@ impl GlyphEntry {
|
|||
}
|
||||
|
||||
// Creates a GlyphEntry for the common case
|
||||
fn simple(index: GlyphIndex, advance: Au) -> GlyphEntry {
|
||||
assert!(is_simple_glyph_id(index));
|
||||
fn simple(id: GlyphId, advance: Au) -> GlyphEntry {
|
||||
assert!(is_simple_glyph_id(id));
|
||||
assert!(is_simple_advance(advance));
|
||||
|
||||
let index_mask = index as u32;
|
||||
let id_mask = id as u32;
|
||||
let Au(advance) = advance;
|
||||
let advance_mask = (advance as u32) << GLYPH_ADVANCE_SHIFT;
|
||||
|
||||
GlyphEntry::new(index_mask | advance_mask | FLAG_IS_SIMPLE_GLYPH)
|
||||
GlyphEntry::new(id_mask | advance_mask | FLAG_IS_SIMPLE_GLYPH)
|
||||
}
|
||||
|
||||
// Create a GlyphEntry for uncommon case; should be accompanied by
|
||||
|
@ -83,15 +83,15 @@ impl GlyphEntry {
|
|||
}
|
||||
}
|
||||
|
||||
/// The index of a particular glyph within a font
|
||||
pub type GlyphIndex = u32;
|
||||
/// The id of a particular glyph within a font
|
||||
pub type GlyphId = u32;
|
||||
|
||||
// TODO: unify with bit flags?
|
||||
#[deriving(Eq)]
|
||||
pub enum BreakType {
|
||||
BreakTypeNone,
|
||||
BreakTypeNormal,
|
||||
BreakTypeHyphen
|
||||
BreakTypeHyphen,
|
||||
}
|
||||
|
||||
static BREAK_TYPE_NONE: u8 = 0x0;
|
||||
|
@ -100,12 +100,12 @@ static BREAK_TYPE_HYPHEN: u8 = 0x2;
|
|||
|
||||
fn break_flag_to_enum(flag: u8) -> BreakType {
|
||||
if (flag & BREAK_TYPE_NORMAL) != 0 {
|
||||
return BreakTypeNormal;
|
||||
BreakTypeNormal
|
||||
} else if (flag & BREAK_TYPE_HYPHEN) != 0 {
|
||||
BreakTypeHyphen
|
||||
} else {
|
||||
BreakTypeNone
|
||||
}
|
||||
if (flag & BREAK_TYPE_HYPHEN) != 0 {
|
||||
return BreakTypeHyphen;
|
||||
}
|
||||
BreakTypeNone
|
||||
}
|
||||
|
||||
fn break_enum_to_flag(e: BreakType) -> u8 {
|
||||
|
@ -151,8 +151,8 @@ static FLAG_CHAR_IS_NEWLINE: u32 = 0x00000010;
|
|||
//static FLAG_CHAR_IS_LOW_SURROGATE: u32 = 0x00000020;
|
||||
//static CHAR_IDENTITY_FLAGS_MASK: u32 = 0x00000038;
|
||||
|
||||
fn is_simple_glyph_id(glyphId: GlyphIndex) -> bool {
|
||||
((glyphId as u32) & GLYPH_ID_MASK) == glyphId
|
||||
fn is_simple_glyph_id(id: GlyphId) -> bool {
|
||||
((id as u32) & GLYPH_ID_MASK) == id
|
||||
}
|
||||
|
||||
fn is_simple_advance(advance: Au) -> bool {
|
||||
|
@ -171,7 +171,7 @@ impl GlyphEntry {
|
|||
NumCast::from((self.value & GLYPH_ADVANCE_MASK) >> GLYPH_ADVANCE_SHIFT).unwrap()
|
||||
}
|
||||
|
||||
fn index(&self) -> GlyphIndex {
|
||||
fn id(&self) -> GlyphId {
|
||||
self.value & GLYPH_ID_MASK
|
||||
}
|
||||
|
||||
|
@ -253,19 +253,19 @@ impl GlyphEntry {
|
|||
// correspond to one character, or the glyph's data couldn't be packed.
|
||||
#[deriving(Clone)]
|
||||
struct DetailedGlyph {
|
||||
index: GlyphIndex,
|
||||
id: GlyphId,
|
||||
// glyph's advance, in the text's direction (RTL or RTL)
|
||||
advance: Au,
|
||||
// glyph's offset from the font's em-box (from top-left)
|
||||
offset: Point2D<Au>
|
||||
offset: Point2D<Au>,
|
||||
}
|
||||
|
||||
impl DetailedGlyph {
|
||||
fn new(index: GlyphIndex, advance: Au, offset: Point2D<Au>) -> DetailedGlyph {
|
||||
fn new(id: GlyphId, advance: Au, offset: Point2D<Au>) -> DetailedGlyph {
|
||||
DetailedGlyph {
|
||||
index: index,
|
||||
id: id,
|
||||
advance: advance,
|
||||
offset: offset
|
||||
offset: offset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -273,9 +273,9 @@ impl DetailedGlyph {
|
|||
#[deriving(Eq, Clone)]
|
||||
struct DetailedGlyphRecord {
|
||||
// source string offset/GlyphEntry offset in the TextRun
|
||||
entry_offset: int,
|
||||
entry_offset: CharIndex,
|
||||
// offset into the detailed glyphs buffer
|
||||
detail_offset: int
|
||||
detail_offset: int,
|
||||
}
|
||||
|
||||
impl Ord for DetailedGlyphRecord {
|
||||
|
@ -312,14 +312,14 @@ impl<'a> DetailedGlyphStore {
|
|||
DetailedGlyphStore {
|
||||
detail_buffer: vec!(), // TODO: default size?
|
||||
detail_lookup: vec!(),
|
||||
lookup_is_sorted: false
|
||||
lookup_is_sorted: false,
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
entry_offset: entry_offset,
|
||||
detail_offset: self.detail_buffer.len() as int
|
||||
detail_offset: self.detail_buffer.len() as int,
|
||||
};
|
||||
|
||||
debug!("Adding entry[off={}] for detailed glyphs: {:?}", entry_offset, glyphs);
|
||||
|
@ -340,7 +340,7 @@ impl<'a> DetailedGlyphStore {
|
|||
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] {
|
||||
debug!("Requesting detailed glyphs[n={}] for entry[off={}]", count, entry_offset);
|
||||
|
||||
|
@ -355,7 +355,7 @@ impl<'a> DetailedGlyphStore {
|
|||
|
||||
let key = DetailedGlyphRecord {
|
||||
entry_offset: entry_offset,
|
||||
detail_offset: 0 // unused
|
||||
detail_offset: 0, // unused
|
||||
};
|
||||
|
||||
// FIXME: This is a workaround for borrow of self.detail_lookup not getting inferred.
|
||||
|
@ -371,7 +371,7 @@ impl<'a> DetailedGlyphStore {
|
|||
}
|
||||
|
||||
fn get_detailed_glyph_with_index(&'a self,
|
||||
entry_offset: int,
|
||||
entry_offset: CharIndex,
|
||||
detail_offset: u16)
|
||||
-> &'a DetailedGlyph {
|
||||
assert!((detail_offset as uint) <= self.detail_buffer.len());
|
||||
|
@ -379,7 +379,7 @@ impl<'a> DetailedGlyphStore {
|
|||
|
||||
let key = DetailedGlyphRecord {
|
||||
entry_offset: entry_offset,
|
||||
detail_offset: 0 // unused
|
||||
detail_offset: 0, // unused
|
||||
};
|
||||
|
||||
// FIXME: This is a workaround for borrow of self.detail_lookup not getting inferred.
|
||||
|
@ -423,7 +423,7 @@ impl<'a> DetailedGlyphStore {
|
|||
// This struct is used by GlyphStore clients to provide new glyph data.
|
||||
// It should be allocated on the stack and passed by reference to GlyphStore.
|
||||
pub struct GlyphData {
|
||||
index: GlyphIndex,
|
||||
id: GlyphId,
|
||||
advance: Au,
|
||||
offset: Point2D<Au>,
|
||||
is_missing: bool,
|
||||
|
@ -432,7 +432,7 @@ pub struct GlyphData {
|
|||
}
|
||||
|
||||
impl GlyphData {
|
||||
pub fn new(index: GlyphIndex,
|
||||
pub fn new(id: GlyphId,
|
||||
advance: Au,
|
||||
offset: Option<Point2D<Au>>,
|
||||
is_missing: bool,
|
||||
|
@ -441,11 +441,11 @@ impl GlyphData {
|
|||
-> GlyphData {
|
||||
let offset = match offset {
|
||||
None => Zero::zero(),
|
||||
Some(o) => o
|
||||
Some(o) => o,
|
||||
};
|
||||
|
||||
GlyphData {
|
||||
index: index,
|
||||
id: id,
|
||||
advance: advance,
|
||||
offset: offset,
|
||||
is_missing: is_missing,
|
||||
|
@ -460,16 +460,16 @@ impl GlyphData {
|
|||
// Rather than eagerly assembling and copying glyph data, it only retrieves
|
||||
// values as they are needed from the GlyphStore, using provided offsets.
|
||||
pub enum GlyphInfo<'a> {
|
||||
SimpleGlyphInfo(&'a GlyphStore, int),
|
||||
DetailGlyphInfo(&'a GlyphStore, int, u16)
|
||||
SimpleGlyphInfo(&'a GlyphStore, CharIndex),
|
||||
DetailGlyphInfo(&'a GlyphStore, CharIndex, u16),
|
||||
}
|
||||
|
||||
impl<'a> GlyphInfo<'a> {
|
||||
pub fn index(self) -> GlyphIndex {
|
||||
pub fn id(self) -> GlyphId {
|
||||
match self {
|
||||
SimpleGlyphInfo(store, entry_i) => store.entry_buffer.get(entry_i as uint).index(),
|
||||
SimpleGlyphInfo(store, entry_i) => store.entry_buffer.get(entry_i.to_uint()).id(),
|
||||
DetailGlyphInfo(store, entry_i, detail_j) => {
|
||||
store.detail_store.get_detailed_glyph_with_index(entry_i, detail_j).index
|
||||
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 _
|
||||
pub fn advance(self) -> Au {
|
||||
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) => {
|
||||
store.detail_store.get_detailed_glyph_with_index(entry_i, detail_j).advance
|
||||
}
|
||||
|
@ -495,17 +495,43 @@ impl<'a> GlyphInfo<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
// Public data structure and API for storing and retrieving glyph data
|
||||
/// Stores the glyph data belonging to a text run.
|
||||
///
|
||||
/// Simple glyphs are stored inline in the `entry_buffer`, detailed glyphs are
|
||||
/// stored as pointers into the `detail_store`.
|
||||
///
|
||||
/// ~~~
|
||||
/// +- GlyphStore --------------------------------+
|
||||
/// | +---+---+---+---+---+---+---+ |
|
||||
/// | entry_buffer: | | s | | s | | s | s | | d = detailed
|
||||
/// | +-|-+---+-|-+---+-|-+---+---+ | s = simple
|
||||
/// | | | | |
|
||||
/// | | +---+-------+ |
|
||||
/// | | | |
|
||||
/// | +-V-+-V-+ |
|
||||
/// | detail_store: | d | d | |
|
||||
/// | +---+---+ |
|
||||
/// +---------------------------------------------+
|
||||
/// ~~~
|
||||
pub struct GlyphStore {
|
||||
// TODO(pcwalton): Allocation of this buffer is expensive. Consider a small-vector
|
||||
// optimization.
|
||||
/// A buffer of glyphs within the text run, in the order in which they
|
||||
/// appear in the input text
|
||||
entry_buffer: Vec<GlyphEntry>,
|
||||
|
||||
/// A store of the detailed glyph data. Detailed glyphs contained in the
|
||||
/// `entry_buffer` point to locations in this data structure.
|
||||
detail_store: DetailedGlyphStore,
|
||||
|
||||
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 {
|
||||
// Initializes the glyph store, but doesn't actually shape anything.
|
||||
// Use the set_glyph, set_glyphs() methods to store glyph data.
|
||||
|
@ -519,8 +545,8 @@ impl<'a> GlyphStore {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn char_len(&self) -> int {
|
||||
self.entry_buffer.len() as int
|
||||
pub fn char_len(&self) -> CharIndex {
|
||||
CharIndex(self.entry_buffer.len() as int)
|
||||
}
|
||||
|
||||
pub fn is_whitespace(&self) -> bool {
|
||||
|
@ -531,32 +557,32 @@ impl<'a> GlyphStore {
|
|||
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 {
|
||||
is_simple_glyph_id(data.index)
|
||||
is_simple_glyph_id(data.id)
|
||||
&& is_simple_advance(data.advance)
|
||||
&& data.offset.is_zero()
|
||||
&& data.cluster_start // others are stored in detail buffer
|
||||
}
|
||||
|
||||
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)) {
|
||||
(true, _) => GlyphEntry::missing(1),
|
||||
(false, true) => GlyphEntry::simple(data.index, data.advance),
|
||||
(false, true) => GlyphEntry::simple(data.id, data.advance),
|
||||
(false, false) => {
|
||||
let glyph = [DetailedGlyph::new(data.index, data.advance, data.offset)];
|
||||
let glyph = [DetailedGlyph::new(data.id, data.advance, data.offset)];
|
||||
self.detail_store.add_detailed_glyphs_for_entry(i, glyph);
|
||||
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]) {
|
||||
assert!(i < self.entry_buffer.len() as int);
|
||||
pub fn add_glyphs_for_char_index(&mut self, i: CharIndex, data_for_glyphs: &[GlyphData]) {
|
||||
assert!(i < CharIndex(self.entry_buffer.len() as int));
|
||||
assert!(data_for_glyphs.len() > 0);
|
||||
|
||||
let glyph_count = data_for_glyphs.len() as int;
|
||||
|
@ -566,7 +592,7 @@ impl<'a> GlyphStore {
|
|||
true => GlyphEntry::missing(glyph_count),
|
||||
false => {
|
||||
let glyphs_vec = slice::from_fn(glyph_count as uint, |i| {
|
||||
DetailedGlyph::new(data_for_glyphs[i].index,
|
||||
DetailedGlyph::new(data_for_glyphs[i].id,
|
||||
data_for_glyphs[i].advance,
|
||||
data_for_glyphs[i].offset)
|
||||
});
|
||||
|
@ -576,115 +602,116 @@ impl<'a> GlyphStore {
|
|||
first_glyph_data.ligature_start,
|
||||
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);
|
||||
|
||||
*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.
|
||||
pub fn add_nonglyph_for_char_index(&mut self, i: int, cluster_start: bool, ligature_start: bool) {
|
||||
assert!(i < self.entry_buffer.len() as int);
|
||||
pub fn add_nonglyph_for_char_index(&mut self, i: CharIndex, cluster_start: bool, ligature_start: bool) {
|
||||
assert!(i < CharIndex(self.entry_buffer.len() as int));
|
||||
|
||||
let entry = GlyphEntry::complex(cluster_start, ligature_start, 0);
|
||||
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> {
|
||||
self.iter_glyphs_for_char_range(&Range::new(i as int, 1))
|
||||
pub fn iter_glyphs_for_char_index(&'a self, i: CharIndex) -> GlyphIterator<'a> {
|
||||
self.iter_glyphs_for_char_range(&Range::new(i, CharIndex(1)))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn iter_glyphs_for_char_range(&'a self, rang: &Range<int>) -> GlyphIterator<'a> {
|
||||
if rang.begin() >= self.entry_buffer.len() as int {
|
||||
pub fn iter_glyphs_for_char_range(&'a self, rang: &Range<CharIndex>) -> GlyphIterator<'a> {
|
||||
if rang.begin() >= CharIndex(self.entry_buffer.len() as int) {
|
||||
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!");
|
||||
}
|
||||
|
||||
GlyphIterator {
|
||||
store: self,
|
||||
char_index: rang.begin(),
|
||||
char_range: rang.eachi(),
|
||||
glyph_range: None
|
||||
char_range: rang.each_index(),
|
||||
glyph_range: None,
|
||||
}
|
||||
}
|
||||
|
||||
// getter methods
|
||||
pub fn char_is_space(&self, i: int) -> bool {
|
||||
assert!(i < self.entry_buffer.len() as int);
|
||||
self.entry_buffer.get(i as uint).char_is_space()
|
||||
pub fn char_is_space(&self, i: CharIndex) -> bool {
|
||||
assert!(i < CharIndex(self.entry_buffer.len() as int));
|
||||
self.entry_buffer.get(i.to_uint()).char_is_space()
|
||||
}
|
||||
|
||||
pub fn char_is_tab(&self, i: int) -> bool {
|
||||
assert!(i < self.entry_buffer.len() as int);
|
||||
self.entry_buffer.get(i as uint).char_is_tab()
|
||||
pub fn char_is_tab(&self, i: CharIndex) -> bool {
|
||||
assert!(i < CharIndex(self.entry_buffer.len() as int));
|
||||
self.entry_buffer.get(i.to_uint()).char_is_tab()
|
||||
}
|
||||
|
||||
pub fn char_is_newline(&self, i: int) -> bool {
|
||||
assert!(i < self.entry_buffer.len() as int);
|
||||
self.entry_buffer.get(i as uint).char_is_newline()
|
||||
pub fn char_is_newline(&self, i: CharIndex) -> bool {
|
||||
assert!(i < CharIndex(self.entry_buffer.len() as int));
|
||||
self.entry_buffer.get(i.to_uint()).char_is_newline()
|
||||
}
|
||||
|
||||
pub fn is_ligature_start(&self, i: int) -> bool {
|
||||
assert!(i < self.entry_buffer.len() as int);
|
||||
self.entry_buffer.get(i as uint).is_ligature_start()
|
||||
pub fn is_ligature_start(&self, i: CharIndex) -> bool {
|
||||
assert!(i < CharIndex(self.entry_buffer.len() as int));
|
||||
self.entry_buffer.get(i.to_uint()).is_ligature_start()
|
||||
}
|
||||
|
||||
pub fn is_cluster_start(&self, i: int) -> bool {
|
||||
assert!(i < self.entry_buffer.len() as int);
|
||||
self.entry_buffer.get(i as uint).is_cluster_start()
|
||||
pub fn is_cluster_start(&self, i: CharIndex) -> bool {
|
||||
assert!(i < CharIndex(self.entry_buffer.len() as int));
|
||||
self.entry_buffer.get(i.to_uint()).is_cluster_start()
|
||||
}
|
||||
|
||||
pub fn can_break_before(&self, i: int) -> BreakType {
|
||||
assert!(i < self.entry_buffer.len() as int);
|
||||
self.entry_buffer.get(i as uint).can_break_before()
|
||||
pub fn can_break_before(&self, i: CharIndex) -> BreakType {
|
||||
assert!(i < CharIndex(self.entry_buffer.len() as int));
|
||||
self.entry_buffer.get(i.to_uint()).can_break_before()
|
||||
}
|
||||
|
||||
// setter methods
|
||||
pub fn set_char_is_space(&mut self, i: int) {
|
||||
assert!(i < self.entry_buffer.len() as int);
|
||||
let entry = *self.entry_buffer.get(i as uint);
|
||||
*self.entry_buffer.get_mut(i as uint) = entry.set_char_is_space();
|
||||
pub fn set_char_is_space(&mut self, i: CharIndex) {
|
||||
assert!(i < CharIndex(self.entry_buffer.len() as int));
|
||||
let entry = *self.entry_buffer.get(i.to_uint());
|
||||
*self.entry_buffer.get_mut(i.to_uint()) = entry.set_char_is_space();
|
||||
}
|
||||
|
||||
pub fn set_char_is_tab(&mut self, i: int) {
|
||||
assert!(i < self.entry_buffer.len() as int);
|
||||
let entry = *self.entry_buffer.get(i as uint);
|
||||
*self.entry_buffer.get_mut(i as uint) = entry.set_char_is_tab();
|
||||
pub fn set_char_is_tab(&mut self, i: CharIndex) {
|
||||
assert!(i < CharIndex(self.entry_buffer.len() as int));
|
||||
let entry = *self.entry_buffer.get(i.to_uint());
|
||||
*self.entry_buffer.get_mut(i.to_uint()) = entry.set_char_is_tab();
|
||||
}
|
||||
|
||||
pub fn set_char_is_newline(&mut self, i: int) {
|
||||
assert!(i < self.entry_buffer.len() as int);
|
||||
let entry = *self.entry_buffer.get(i as uint);
|
||||
*self.entry_buffer.get_mut(i as uint) = entry.set_char_is_newline();
|
||||
pub fn set_char_is_newline(&mut self, i: CharIndex) {
|
||||
assert!(i < CharIndex(self.entry_buffer.len() as int));
|
||||
let entry = *self.entry_buffer.get(i.to_uint());
|
||||
*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) {
|
||||
assert!(i < self.entry_buffer.len() as int);
|
||||
let entry = *self.entry_buffer.get(i as uint);
|
||||
*self.entry_buffer.get_mut(i as uint) = entry.set_can_break_before(t);
|
||||
pub fn set_can_break_before(&mut self, i: CharIndex, t: BreakType) {
|
||||
assert!(i < CharIndex(self.entry_buffer.len() as int));
|
||||
let entry = *self.entry_buffer.get(i.to_uint());
|
||||
*self.entry_buffer.get_mut(i.to_uint()) = entry.set_can_break_before(t);
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over the glyphs in a character range in a `GlyphStore`.
|
||||
pub struct GlyphIterator<'a> {
|
||||
store: &'a GlyphStore,
|
||||
char_index: int,
|
||||
char_range: iter::Range<int>,
|
||||
glyph_range: Option<iter::Range<int>>,
|
||||
char_index: CharIndex,
|
||||
char_range: EachIndex<int, CharIndex>,
|
||||
glyph_range: Option<EachIndex<int, CharIndex>>,
|
||||
}
|
||||
|
||||
impl<'a> GlyphIterator<'a> {
|
||||
// Slow path when there is a glyph range.
|
||||
#[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() {
|
||||
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 => {
|
||||
// No more glyphs for current character. Try to get another.
|
||||
self.glyph_range = None;
|
||||
|
@ -695,15 +722,15 @@ impl<'a> GlyphIterator<'a> {
|
|||
|
||||
// Slow path when there is a complex glyph.
|
||||
#[inline(never)]
|
||||
fn next_complex_glyph(&mut self, entry: &GlyphEntry, i: int)
|
||||
-> Option<(int, GlyphInfo<'a>)> {
|
||||
fn next_complex_glyph(&mut self, entry: &GlyphEntry, i: CharIndex)
|
||||
-> Option<(CharIndex, GlyphInfo<'a>)> {
|
||||
let glyphs = self.store.detail_store.get_detailed_glyphs_for_entry(i, entry.glyph_count());
|
||||
self.glyph_range = Some(range(0, glyphs.len() as int));
|
||||
self.glyph_range = Some(range::each_index(CharIndex(0), CharIndex(glyphs.len() as int)));
|
||||
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
|
||||
// inability to store free variables in the FlatMap struct was problematic.
|
||||
//
|
||||
|
@ -711,7 +738,7 @@ impl<'a> Iterator<(int, GlyphInfo<'a>)> for GlyphIterator<'a> {
|
|||
// slow paths, which should not be inlined, are `next_glyph_range()` and
|
||||
// `next_complex_glyph()`.
|
||||
#[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
|
||||
// interferes with mutation.
|
||||
if self.glyph_range.is_some() {
|
||||
|
@ -721,8 +748,8 @@ impl<'a> Iterator<(int, GlyphInfo<'a>)> for GlyphIterator<'a> {
|
|||
match self.char_range.next() {
|
||||
Some(i) => {
|
||||
self.char_index = i;
|
||||
assert!(i < self.store.entry_buffer.len() as int);
|
||||
let entry = self.store.entry_buffer.get(i as uint);
|
||||
assert!(i < CharIndex(self.store.entry_buffer.len() as int));
|
||||
let entry = self.store.entry_buffer.get(i.to_uint());
|
||||
if entry.is_simple() {
|
||||
Some((self.char_index, SimpleGlyphInfo(self.store, i)))
|
||||
} else {
|
||||
|
|
|
@ -6,7 +6,7 @@ extern crate harfbuzz;
|
|||
|
||||
use font::{Font, FontHandleMethods, FontTableMethods, FontTableTag};
|
||||
use platform::font::FontTable;
|
||||
use text::glyph::{GlyphStore, GlyphIndex, GlyphData};
|
||||
use text::glyph::{CharIndex, GlyphStore, GlyphId, GlyphData};
|
||||
use text::shaping::ShaperMethods;
|
||||
use text::util::{float_to_fixed, fixed_to_float};
|
||||
|
||||
|
@ -55,7 +55,7 @@ pub struct ShapedGlyphData {
|
|||
|
||||
pub struct ShapedGlyphEntry {
|
||||
cluster: int,
|
||||
codepoint: GlyphIndex,
|
||||
codepoint: GlyphId,
|
||||
advance: Au,
|
||||
offset: Option<Point2D<Au>>,
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ impl ShapedGlyphData {
|
|||
|
||||
ShapedGlyphEntry {
|
||||
cluster: (*glyph_info_i).cluster as int,
|
||||
codepoint: (*glyph_info_i).codepoint as GlyphIndex,
|
||||
codepoint: (*glyph_info_i).codepoint as GlyphId,
|
||||
advance: x_advance,
|
||||
offset: offset,
|
||||
}
|
||||
|
@ -229,7 +229,7 @@ impl Shaper {
|
|||
|
||||
// GlyphStore records are indexed by character, not byte offset.
|
||||
// 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);
|
||||
|
||||
|
@ -316,7 +316,7 @@ impl Shaper {
|
|||
// extend glyph range to max glyph index covered by char_span,
|
||||
// in cases where one char made several glyphs and left some unassociated chars.
|
||||
let mut max_glyph_idx = glyph_span.end();
|
||||
for i in char_byte_span.eachi() {
|
||||
for i in char_byte_span.each_index() {
|
||||
if byteToGlyph[i as uint] > NO_GLYPH {
|
||||
max_glyph_idx = cmp::max(byteToGlyph[i as uint] as int + 1, max_glyph_idx);
|
||||
}
|
||||
|
@ -340,7 +340,7 @@ impl Shaper {
|
|||
probably doesn't work.");
|
||||
|
||||
let mut all_glyphs_are_within_cluster: bool = true;
|
||||
for j in glyph_span.eachi() {
|
||||
for j in glyph_span.each_index() {
|
||||
let loc = glyph_data.byte_offset_of_glyph(j);
|
||||
if !char_byte_span.contains(loc) {
|
||||
all_glyphs_are_within_cluster = false;
|
||||
|
@ -414,7 +414,7 @@ impl Shaper {
|
|||
// collect all glyphs to be assigned to the first character.
|
||||
let mut datas = vec!();
|
||||
|
||||
for glyph_i in glyph_span.eachi() {
|
||||
for glyph_i in glyph_span.each_index() {
|
||||
let shape = glyph_data.get_entry_for_glyph(glyph_i, &mut y_pos);
|
||||
datas.push(GlyphData::new(shape.codepoint,
|
||||
shape.advance,
|
||||
|
@ -435,7 +435,7 @@ impl Shaper {
|
|||
drop(range.ch);
|
||||
i = range.next as int;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -445,7 +445,7 @@ impl Shaper {
|
|||
glyph_span.reset(end, 0);
|
||||
let end = char_byte_span.end();; // FIXME: borrow checker workaround
|
||||
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
|
||||
|
@ -485,7 +485,7 @@ extern fn glyph_h_advance_func(_: *hb_font_t,
|
|||
assert!(font.is_not_null());
|
||||
|
||||
unsafe {
|
||||
let advance = (*font).glyph_h_advance(glyph as GlyphIndex);
|
||||
let advance = (*font).glyph_h_advance(glyph as GlyphId);
|
||||
Shaper::float_to_fixed(advance)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use servo_util::range::Range;
|
|||
use std::slice::Items;
|
||||
use style::computed_values::text_decoration;
|
||||
use sync::Arc;
|
||||
use text::glyph::GlyphStore;
|
||||
use text::glyph::{CharIndex, GlyphStore};
|
||||
|
||||
/// A text run.
|
||||
#[deriving(Clone)]
|
||||
|
@ -18,19 +18,20 @@ pub struct TextRun {
|
|||
pub font_metrics: FontMetrics,
|
||||
pub font_style: FontStyle,
|
||||
pub decoration: text_decoration::T,
|
||||
// An Arc pointing to a Vec of Arcs?! Wat.
|
||||
pub glyphs: Arc<Vec<Arc<GlyphStore>>>,
|
||||
}
|
||||
|
||||
pub struct SliceIterator<'a> {
|
||||
glyph_iter: Items<'a, Arc<GlyphStore>>,
|
||||
range: Range<int>,
|
||||
offset: int,
|
||||
range: Range<CharIndex>,
|
||||
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)]
|
||||
fn next(&mut self) -> Option<(&'a GlyphStore, int, Range<int>)> {
|
||||
fn next(&mut self) -> Option<(&'a GlyphStore, CharIndex, Range<CharIndex>)> {
|
||||
loop {
|
||||
let slice_glyphs = self.glyph_iter.next();
|
||||
if slice_glyphs.is_none() {
|
||||
|
@ -40,10 +41,10 @@ impl<'a> Iterator<(&'a GlyphStore, int, Range<int>)> for SliceIterator<'a> {
|
|||
|
||||
let slice_range = Range::new(self.offset, slice_glyphs.char_len());
|
||||
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;
|
||||
self.offset += slice_glyphs.char_len();
|
||||
self.offset = self.offset + slice_glyphs.char_len();
|
||||
if !char_range.is_empty() {
|
||||
return Some((&**slice_glyphs, old_offset, char_range))
|
||||
}
|
||||
|
@ -52,24 +53,24 @@ impl<'a> Iterator<(&'a GlyphStore, int, Range<int>)> for SliceIterator<'a> {
|
|||
}
|
||||
|
||||
pub struct LineIterator<'a> {
|
||||
range: Range<int>,
|
||||
clump: Option<Range<int>>,
|
||||
range: Range<CharIndex>,
|
||||
clump: Option<Range<CharIndex>>,
|
||||
slices: SliceIterator<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator<Range<int>> for LineIterator<'a> {
|
||||
fn next(&mut self) -> Option<Range<int>> {
|
||||
impl<'a> Iterator<Range<CharIndex>> for LineIterator<'a> {
|
||||
fn next(&mut self) -> Option<Range<CharIndex>> {
|
||||
// Loop until we hit whitespace and are in a clump.
|
||||
loop {
|
||||
match self.slices.next() {
|
||||
Some((glyphs, offset, slice_range)) => {
|
||||
match (glyphs.is_whitespace(), self.clump) {
|
||||
(false, Some(ref mut c)) => {
|
||||
c.extend_by(slice_range.length().to_int().unwrap());
|
||||
c.extend_by(slice_range.length());
|
||||
}
|
||||
(false, None) => {
|
||||
let mut c = slice_range;
|
||||
c.shift_by(offset.to_int().unwrap());
|
||||
c.shift_by(offset);
|
||||
self.clump = Some(c);
|
||||
}
|
||||
(true, None) => { /* chomp whitespace */ }
|
||||
|
@ -165,8 +166,8 @@ impl<'a> TextRun {
|
|||
glyphs
|
||||
}
|
||||
|
||||
pub fn char_len(&self) -> int {
|
||||
self.glyphs.iter().fold(0, |len, slice_glyphs| {
|
||||
pub fn char_len(&self) -> CharIndex {
|
||||
self.glyphs.iter().fold(CharIndex(0), |len, slice_glyphs| {
|
||||
len + slice_glyphs.char_len()
|
||||
})
|
||||
}
|
||||
|
@ -175,14 +176,14 @@ impl<'a> TextRun {
|
|||
&*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) {
|
||||
if !slice_glyphs.is_whitespace() { return false; }
|
||||
}
|
||||
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 #98): using inter-char and inter-word spacing settings when measuring text
|
||||
let mut advance = Au(0);
|
||||
|
@ -194,14 +195,14 @@ impl<'a> TextRun {
|
|||
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);
|
||||
for (_i, glyph) in glyphs.iter_glyphs_for_char_range(slice_range) {
|
||||
advance = advance + glyph.advance();
|
||||
}
|
||||
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);
|
||||
debug!("iterating outer range {:?}", range);
|
||||
for (_, offset, slice_range) in self.iter_slices_for_range(range) {
|
||||
|
@ -212,15 +213,15 @@ impl<'a> TextRun {
|
|||
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 {
|
||||
glyph_iter: self.glyphs.iter(),
|
||||
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 {
|
||||
range: *range,
|
||||
clump: None,
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
* 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/. */
|
||||
|
||||
use text::glyph::CharIndex;
|
||||
|
||||
#[deriving(Eq)]
|
||||
pub enum CompressionMode {
|
||||
CompressNone,
|
||||
|
@ -20,11 +22,13 @@ pub enum CompressionMode {
|
|||
// * Issue #114: record skipped and kept chars for mapping original to new text
|
||||
//
|
||||
// * 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 out_whitespace = match mode {
|
||||
CompressNone | DiscardNewline => {
|
||||
let mut new_line_index = 0;
|
||||
let mut new_line_index = CharIndex(0);
|
||||
for ch in text.chars() {
|
||||
if is_discardable_char(ch, mode) {
|
||||
// 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
|
||||
// This value is relative(not absolute)
|
||||
new_line_pos.push(new_line_index);
|
||||
new_line_index = 0;
|
||||
new_line_index = CharIndex(0);
|
||||
}
|
||||
|
||||
if ch != '\n' {
|
||||
new_line_index += 1;
|
||||
new_line_index = new_line_index + CharIndex(1);
|
||||
}
|
||||
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::{TextDecorations, TextDisplayItem, TextDisplayItemClass};
|
||||
use gfx::font::FontStyle;
|
||||
use gfx::text::glyph::CharIndex;
|
||||
use gfx::text::text_run::TextRun;
|
||||
use servo_msg::constellation_msg::{ConstellationChan, FrameRectMsg, PipelineId, SubpageId};
|
||||
use servo_net::image::holder::{ImageHolder, LocalImageCacheHandle};
|
||||
|
@ -95,7 +96,7 @@ pub struct Box {
|
|||
/// New-line chracter(\n)'s positions(relative, not absolute)
|
||||
///
|
||||
/// 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.
|
||||
|
@ -226,12 +227,12 @@ pub struct ScannedTextBoxInfo {
|
|||
pub run: Arc<~TextRun>,
|
||||
|
||||
/// The range within the above text run that this represents.
|
||||
pub range: Range<int>,
|
||||
pub range: Range<CharIndex>,
|
||||
}
|
||||
|
||||
impl ScannedTextBoxInfo {
|
||||
/// 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 {
|
||||
run: run,
|
||||
range: range,
|
||||
|
@ -1108,7 +1109,8 @@ impl Box {
|
|||
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 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.
|
||||
let left_box = {
|
||||
|
@ -1120,7 +1122,7 @@ impl Box {
|
|||
};
|
||||
|
||||
// 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_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));
|
||||
|
@ -1145,8 +1147,8 @@ impl Box {
|
|||
ScannedTextBox(ref text_box_info) => {
|
||||
let mut pieces_processed_count: uint = 0;
|
||||
let mut remaining_width: Au = max_width;
|
||||
let mut left_range = Range::new(text_box_info.range.begin(), 0);
|
||||
let mut right_range: Option<Range<int>> = None;
|
||||
let mut left_range = Range::new(text_box_info.range.begin(), CharIndex(0));
|
||||
let mut right_range: Option<Range<CharIndex>> = None;
|
||||
|
||||
debug!("split_to_width: splitting text box (strlen={:u}, range={}, \
|
||||
avail_width={})",
|
||||
|
@ -1171,11 +1173,11 @@ impl Box {
|
|||
|
||||
if starts_line && pieces_processed_count == 0 && glyphs.is_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 {
|
||||
debug!("split_to_width: case=enlarging span");
|
||||
remaining_width = remaining_width - advance;
|
||||
left_range.extend_by(slice_range.length() as int);
|
||||
left_range.extend_by(slice_range.length());
|
||||
}
|
||||
} else {
|
||||
// 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 mut new_metrics = new_text_box_info.run.metrics_for_range(&left_range);
|
||||
new_metrics.bounding_box.size.height = self.border_box.size.height;
|
||||
|
@ -1222,7 +1224,7 @@ impl Box {
|
|||
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(),
|
||||
range);
|
||||
let mut new_metrics = new_text_box_info.run.metrics_for_range(&range);
|
||||
|
|
|
@ -30,7 +30,7 @@ use layout::floats::FloatKind;
|
|||
use layout::flow::{Flow, ImmutableFlowUtils, MutableOwnedFlowUtils};
|
||||
use layout::flow::{Descendants, AbsDescendants};
|
||||
use layout::flow_list::{Rawlink};
|
||||
use layout::inline::{InlineBoxes, InlineFlow};
|
||||
use layout::inline::{FragmentIndex, InlineBoxes, InlineFlow};
|
||||
use layout::table_wrapper::TableWrapperFlow;
|
||||
use layout::table::TableFlow;
|
||||
use layout::table_caption::TableCaptionFlow;
|
||||
|
@ -189,7 +189,7 @@ impl InlineBoxAccumulator {
|
|||
|
||||
fn from_inline_node(node: &ThreadSafeLayoutNode) -> InlineBoxAccumulator {
|
||||
let mut boxes = InlineBoxes::new();
|
||||
boxes.map.push(node.style().clone(), Range::new(0, 0));
|
||||
boxes.map.push(node.style().clone(), Range::empty());
|
||||
InlineBoxAccumulator {
|
||||
boxes: boxes,
|
||||
has_enclosing_range: true,
|
||||
|
@ -203,8 +203,8 @@ impl InlineBoxAccumulator {
|
|||
} = self;
|
||||
|
||||
if has_enclosing_range {
|
||||
let len = boxes.len() as int;
|
||||
boxes.map.get_mut(0).range.extend_to(len);
|
||||
let len = FragmentIndex(boxes.len() as int);
|
||||
boxes.map.get_mut(FragmentIndex(0)).range.extend_to(len);
|
||||
}
|
||||
boxes
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ use gfx::font::FontMetrics;
|
|||
use gfx::font_context::FontContext;
|
||||
use servo_util::geometry::Au;
|
||||
use servo_util::geometry;
|
||||
use servo_util::range::Range;
|
||||
use servo_util::range::{Range, RangeIndex};
|
||||
use std::iter::Enumerate;
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
|
@ -56,11 +56,15 @@ use sync::Arc;
|
|||
/// left corner of the green zone is the same as that of the line, but
|
||||
/// the green zone can be taller and wider than the line itself.
|
||||
pub struct LineBox {
|
||||
pub range: Range<int>,
|
||||
pub range: Range<BoxIndex>,
|
||||
pub bounds: Rect<Au>,
|
||||
pub green_zone: Size2D<Au>
|
||||
}
|
||||
|
||||
range_index! {
|
||||
struct BoxIndex(int)
|
||||
}
|
||||
|
||||
struct LineboxScanner {
|
||||
pub floats: Floats,
|
||||
pub new_boxes: Vec<Box>,
|
||||
|
@ -99,7 +103,7 @@ impl LineboxScanner {
|
|||
}
|
||||
|
||||
fn reset_linebox(&mut self) {
|
||||
self.pending_line.range.reset(0,0);
|
||||
self.pending_line.range.reset(BoxIndex(0), BoxIndex(0));
|
||||
self.pending_line.bounds = Rect(Point2D(Au::new(0), self.cur_y), Size2D(Au::new(0), Au::new(0)));
|
||||
self.pending_line.green_zone = Size2D(Au::new(0), Au::new(0))
|
||||
}
|
||||
|
@ -146,7 +150,7 @@ impl LineboxScanner {
|
|||
}
|
||||
}
|
||||
|
||||
if self.pending_line.range.length() > 0 {
|
||||
if self.pending_line.range.length() > BoxIndex(0) {
|
||||
debug!("LineboxScanner: Partially full linebox {:u} left at end of scanning.",
|
||||
self.lines.len());
|
||||
self.flush_current_line();
|
||||
|
@ -193,7 +197,7 @@ impl LineboxScanner {
|
|||
let first_box_size = first_box.border_box.size;
|
||||
let splittable = first_box.can_split();
|
||||
debug!("LineboxScanner: box size: {}, splittable: {}", first_box_size, splittable);
|
||||
let line_is_empty: bool = self.pending_line.range.length() == 0;
|
||||
let line_is_empty: bool = self.pending_line.range.length() == BoxIndex(0);
|
||||
|
||||
// Initally, pretend a splittable box has 0 width.
|
||||
// We will move it later if it has nonzero width
|
||||
|
@ -349,7 +353,7 @@ impl LineboxScanner {
|
|||
/// Tries to append the given box to the line, splitting it if necessary. Returns false only if
|
||||
/// we should break the line.
|
||||
fn try_append_to_line(&mut self, in_box: Box, flow: &mut InlineFlow) -> bool {
|
||||
let line_is_empty = self.pending_line.range.length() == 0;
|
||||
let line_is_empty = self.pending_line.range.length() == BoxIndex(0);
|
||||
if line_is_empty {
|
||||
let (line_bounds, _) = self.initial_line_placement(&in_box, self.cur_y, flow);
|
||||
self.pending_line.bounds.origin = line_bounds.origin;
|
||||
|
@ -444,11 +448,11 @@ impl LineboxScanner {
|
|||
fn push_box_to_line(&mut self, box_: Box) {
|
||||
debug!("LineboxScanner: Pushing box {} to line {:u}", box_.debug_id(), self.lines.len());
|
||||
|
||||
if self.pending_line.range.length() == 0 {
|
||||
if self.pending_line.range.length() == BoxIndex(0) {
|
||||
assert!(self.new_boxes.len() <= (u16::MAX as uint));
|
||||
self.pending_line.range.reset(self.new_boxes.len() as int, 0);
|
||||
self.pending_line.range.reset(BoxIndex(self.new_boxes.len() as int), BoxIndex(0));
|
||||
}
|
||||
self.pending_line.range.extend_by(1);
|
||||
self.pending_line.range.extend_by(BoxIndex(1));
|
||||
self.pending_line.bounds.size.width = self.pending_line.bounds.size.width +
|
||||
box_.border_box.size.width;
|
||||
self.pending_line.bounds.size.height = Au::max(self.pending_line.bounds.size.height,
|
||||
|
@ -468,7 +472,10 @@ impl<'a> Iterator<(&'a Box, InlineFragmentContext<'a>)> for BoxIterator<'a> {
|
|||
fn next(&mut self) -> Option<(&'a Box, InlineFragmentContext<'a>)> {
|
||||
match self.iter.next() {
|
||||
None => None,
|
||||
Some((i, fragment)) => Some((fragment, InlineFragmentContext::new(self.map, i as int))),
|
||||
Some((i, fragment)) => Some((
|
||||
fragment,
|
||||
InlineFragmentContext::new(self.map, FragmentIndex(i as int)),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -484,7 +491,10 @@ impl<'a> Iterator<(&'a mut Box, InlineFragmentContext<'a>)> for MutBoxIterator<'
|
|||
fn next(&mut self) -> Option<(&'a mut Box, InlineFragmentContext<'a>)> {
|
||||
match self.iter.next() {
|
||||
None => None,
|
||||
Some((i, fragment)) => Some((fragment, InlineFragmentContext::new(self.map, i as int))),
|
||||
Some((i, fragment)) => Some((
|
||||
fragment,
|
||||
InlineFragmentContext::new(self.map, FragmentIndex(i as int)),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -518,7 +528,7 @@ impl InlineBoxes {
|
|||
|
||||
/// Pushes a new inline box.
|
||||
pub fn push(&mut self, fragment: Box, style: Arc<ComputedValues>) {
|
||||
self.map.push(style, Range::new(self.boxes.len() as int, 1));
|
||||
self.map.push(style, Range::new(FragmentIndex(self.boxes.len() as int), FragmentIndex(1)));
|
||||
self.boxes.push(fragment)
|
||||
}
|
||||
|
||||
|
@ -528,7 +538,7 @@ impl InlineBoxes {
|
|||
boxes: other_boxes,
|
||||
map: other_map
|
||||
} = other;
|
||||
let adjustment = self.boxes.len();
|
||||
let adjustment = FragmentIndex(self.boxes.len() as int);
|
||||
self.map.push_all(other_map, adjustment);
|
||||
self.boxes.push_all_move(other_boxes);
|
||||
}
|
||||
|
@ -713,8 +723,8 @@ impl InlineFlow {
|
|||
text_align::right => slack_width,
|
||||
};
|
||||
|
||||
for i in line.range.eachi() {
|
||||
let box_ = boxes.get_mut(i as uint);
|
||||
for i in line.range.each_index() {
|
||||
let box_ = boxes.get_mut(i.to_uint());
|
||||
let size = box_.border_box.size;
|
||||
box_.border_box = Rect(Point2D(offset_x, box_.border_box.origin.y), size);
|
||||
offset_x = offset_x + size.width;
|
||||
|
@ -844,8 +854,8 @@ impl Flow for InlineFlow {
|
|||
let (mut largest_height_for_top_fragments, mut largest_height_for_bottom_fragments) =
|
||||
(Au(0), Au(0));
|
||||
|
||||
for box_i in line.range.eachi() {
|
||||
let fragment = self.boxes.boxes.get_mut(box_i as uint);
|
||||
for box_i in line.range.each_index() {
|
||||
let fragment = self.boxes.boxes.get_mut(box_i.to_uint());
|
||||
|
||||
let InlineMetrics {
|
||||
height_above_baseline: mut height_above_baseline,
|
||||
|
@ -920,8 +930,8 @@ impl Flow for InlineFlow {
|
|||
|
||||
// Compute the final positions in the block direction of each fragment. Recall that
|
||||
// `fragment.border_box.origin.y` was set to the distance from the baseline above.
|
||||
for box_i in line.range.eachi() {
|
||||
let fragment = self.boxes.get_mut(box_i as uint);
|
||||
for box_i in line.range.each_index() {
|
||||
let fragment = self.boxes.get_mut(box_i.to_uint());
|
||||
match fragment.vertical_align() {
|
||||
vertical_align::top => {
|
||||
fragment.border_box.origin.y = fragment.border_box.origin.y +
|
||||
|
@ -971,18 +981,23 @@ impl fmt::Show for InlineFlow {
|
|||
}
|
||||
}
|
||||
|
||||
range_index! {
|
||||
#[doc = "The index of a DOM element into the flat list of fragments."]
|
||||
struct FragmentIndex(int)
|
||||
}
|
||||
|
||||
/// Information that inline flows keep about a single nested element. This is used to recover the
|
||||
/// DOM structure from the flat box list when it's needed.
|
||||
pub struct FragmentRange {
|
||||
/// The style of the DOM node that this range refers to.
|
||||
pub style: Arc<ComputedValues>,
|
||||
/// The range, in indices into the fragment list.
|
||||
pub range: Range<int>,
|
||||
pub range: Range<FragmentIndex>,
|
||||
}
|
||||
|
||||
impl FragmentRange {
|
||||
/// Creates a new fragment range from the given values.
|
||||
fn new(style: Arc<ComputedValues>, range: Range<int>) -> FragmentRange {
|
||||
fn new(style: Arc<ComputedValues>, range: Range<FragmentIndex>) -> FragmentRange {
|
||||
FragmentRange {
|
||||
style: style,
|
||||
range: range,
|
||||
|
@ -1003,14 +1018,14 @@ impl FragmentRange {
|
|||
|
||||
struct FragmentFixupWorkItem {
|
||||
style: Arc<ComputedValues>,
|
||||
new_start_index: int,
|
||||
old_end_index: int,
|
||||
new_start_index: FragmentIndex,
|
||||
old_end_index: FragmentIndex,
|
||||
}
|
||||
|
||||
/// The type of an iterator over fragment ranges in the fragment map.
|
||||
pub struct RangeIterator<'a> {
|
||||
iter: Items<'a,FragmentRange>,
|
||||
index: int,
|
||||
index: FragmentIndex,
|
||||
seen_first: bool,
|
||||
}
|
||||
|
||||
|
@ -1053,13 +1068,13 @@ impl FragmentMap {
|
|||
}
|
||||
|
||||
/// Adds the given node to the fragment map.
|
||||
pub fn push(&mut self, style: Arc<ComputedValues>, range: Range<int>) {
|
||||
pub fn push(&mut self, style: Arc<ComputedValues>, range: Range<FragmentIndex>) {
|
||||
self.list.push(FragmentRange::new(style, range))
|
||||
}
|
||||
|
||||
/// Pushes the ranges in another fragment map onto the end of this one, adjusting indices as
|
||||
/// necessary.
|
||||
fn push_all(&mut self, other: FragmentMap, adjustment: uint) {
|
||||
fn push_all(&mut self, other: FragmentMap, adjustment: FragmentIndex) {
|
||||
let FragmentMap {
|
||||
list: other_list
|
||||
} = other;
|
||||
|
@ -1070,19 +1085,19 @@ impl FragmentMap {
|
|||
range: mut other_range
|
||||
} = other_range;
|
||||
|
||||
other_range.shift_by(adjustment as int);
|
||||
other_range.shift_by(adjustment);
|
||||
self.push(other_style, other_range)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the range with the given index.
|
||||
pub fn get_mut<'a>(&'a mut self, index: int) -> &'a mut FragmentRange {
|
||||
&mut self.list.as_mut_slice()[index as uint]
|
||||
pub fn get_mut<'a>(&'a mut self, index: FragmentIndex) -> &'a mut FragmentRange {
|
||||
&mut self.list.as_mut_slice()[index.to_uint()]
|
||||
}
|
||||
|
||||
/// Iterates over all ranges that contain the box with the given index, outermost first.
|
||||
#[inline(always)]
|
||||
fn ranges_for_index<'a>(&'a self, index: int) -> RangeIterator<'a> {
|
||||
fn ranges_for_index<'a>(&'a self, index: FragmentIndex) -> RangeIterator<'a> {
|
||||
RangeIterator {
|
||||
iter: self.list.as_slice().iter(),
|
||||
index: index,
|
||||
|
@ -1108,12 +1123,13 @@ impl FragmentMap {
|
|||
|
||||
// FIXME(#2270, pcwalton): I don't think this will work if multiple old fragments
|
||||
// correspond to the same node.
|
||||
for (old_fragment_index, old_fragment) in old_fragments.iter().enumerate() {
|
||||
for (i, old_fragment) in old_fragments.iter().enumerate() {
|
||||
let old_fragment_index = FragmentIndex(i as int);
|
||||
// Find the start of the corresponding new fragment.
|
||||
let new_fragment_start = match new_fragments_iter.peek() {
|
||||
Some(&(index, new_fragment)) if new_fragment.node == old_fragment.node => {
|
||||
// We found the start of the corresponding new fragment.
|
||||
index as int
|
||||
FragmentIndex(index as int)
|
||||
}
|
||||
Some(_) | None => {
|
||||
// The old fragment got deleted entirely.
|
||||
|
@ -1136,7 +1152,7 @@ impl FragmentMap {
|
|||
match old_list_iter.peek() {
|
||||
None => break,
|
||||
Some(fragment_range) => {
|
||||
if fragment_range.range.begin() > old_fragment_index as int {
|
||||
if fragment_range.range.begin() > old_fragment_index {
|
||||
// We haven't gotten to the appropriate old fragment yet, so stop.
|
||||
break
|
||||
}
|
||||
|
@ -1163,7 +1179,7 @@ impl FragmentMap {
|
|||
match worklist.as_slice().last() {
|
||||
None => break,
|
||||
Some(last_work_item) => {
|
||||
if last_work_item.old_end_index > old_fragment_index as int + 1 {
|
||||
if last_work_item.old_end_index > old_fragment_index + FragmentIndex(1) {
|
||||
// Haven't gotten to it yet.
|
||||
break
|
||||
}
|
||||
|
@ -1173,10 +1189,12 @@ impl FragmentMap {
|
|||
let new_last_index = match new_fragments_iter.peek() {
|
||||
None => {
|
||||
// At the end.
|
||||
new_fragments.len()
|
||||
FragmentIndex(new_fragments.len() as int)
|
||||
}
|
||||
Some(&(index, _)) => index,
|
||||
} as int;
|
||||
Some(&(index, _)) => {
|
||||
FragmentIndex(index as int)
|
||||
},
|
||||
};
|
||||
|
||||
let FragmentFixupWorkItem {
|
||||
style,
|
||||
|
@ -1194,11 +1212,11 @@ impl FragmentMap {
|
|||
/// conveniently to various fragment functions.
|
||||
pub struct InlineFragmentContext<'a> {
|
||||
map: &'a FragmentMap,
|
||||
index: int,
|
||||
index: FragmentIndex,
|
||||
}
|
||||
|
||||
impl<'a> InlineFragmentContext<'a> {
|
||||
pub fn new<'a>(map: &'a FragmentMap, index: int) -> InlineFragmentContext<'a> {
|
||||
pub fn new<'a>(map: &'a FragmentMap, index: FragmentIndex) -> InlineFragmentContext<'a> {
|
||||
InlineFragmentContext {
|
||||
map: map,
|
||||
index: index,
|
||||
|
|
|
@ -10,6 +10,7 @@ use layout::inline::InlineBoxes;
|
|||
|
||||
use gfx::font::{FontMetrics, FontStyle};
|
||||
use gfx::font_context::FontContext;
|
||||
use gfx::text::glyph::CharIndex;
|
||||
use gfx::text::text_run::TextRun;
|
||||
use gfx::text::util::{CompressWhitespaceNewline, transform_text, CompressNone};
|
||||
use servo_util::geometry::Au;
|
||||
|
@ -20,7 +21,7 @@ use style::computed_values::{font_family, line_height, white_space};
|
|||
use sync::Arc;
|
||||
|
||||
struct NewLinePositions {
|
||||
new_line_pos: Vec<int>,
|
||||
new_line_pos: Vec<CharIndex>,
|
||||
}
|
||||
|
||||
// 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.
|
||||
pub struct TextRunScanner {
|
||||
pub clump: Range<int>,
|
||||
pub clump: Range<CharIndex>,
|
||||
}
|
||||
|
||||
impl TextRunScanner {
|
||||
|
@ -63,11 +64,11 @@ impl TextRunScanner {
|
|||
last_whitespace);
|
||||
}
|
||||
|
||||
self.clump.extend_by(1);
|
||||
self.clump.extend_by(CharIndex(1));
|
||||
}
|
||||
|
||||
// Handle remaining clumps.
|
||||
if self.clump.length() > 0 {
|
||||
if self.clump.length() > CharIndex(0) {
|
||||
drop(self.flush_clump_to_list(font_context,
|
||||
old_boxes.as_slice(),
|
||||
&mut new_boxes,
|
||||
|
@ -99,12 +100,12 @@ impl TextRunScanner {
|
|||
out_boxes: &mut Vec<Box>,
|
||||
last_whitespace: bool)
|
||||
-> bool {
|
||||
assert!(self.clump.length() > 0);
|
||||
assert!(self.clump.length() > CharIndex(0));
|
||||
|
||||
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,
|
||||
_ => false,
|
||||
};
|
||||
|
@ -117,11 +118,11 @@ impl TextRunScanner {
|
|||
(true, false) => {
|
||||
// FIXME(pcwalton): Stop cloning boxes, as above.
|
||||
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)
|
||||
},
|
||||
(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 {
|
||||
UnscannedTextBox(ref text_box_info) => &text_box_info.text,
|
||||
_ => fail!("Expected an unscanned text box!"),
|
||||
|
@ -156,11 +157,11 @@ impl TextRunScanner {
|
|||
debug!("TextRunScanner: pushing single text box in range: {} ({})",
|
||||
self.clump,
|
||||
*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_text_box_info = ScannedTextBoxInfo::new(Arc::new(run), range);
|
||||
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;
|
||||
out_boxes.push(new_box)
|
||||
}
|
||||
|
@ -169,7 +170,7 @@ impl TextRunScanner {
|
|||
// 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
|
||||
// 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 fontgroup = font_context.get_resolved_font_for_style(&font_style);
|
||||
let decoration = in_box.text_decoration();
|
||||
|
@ -184,12 +185,12 @@ impl TextRunScanner {
|
|||
|
||||
// First, transform/compress text of all the nodes.
|
||||
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
|
||||
// `transform_text`, so that boxes starting and/or ending with whitespace can
|
||||
// be compressed correctly with respect to the text run.
|
||||
let idx = i as int + self.clump.begin();
|
||||
let in_box = match in_boxes[idx as uint].specific {
|
||||
let idx = CharIndex(i as int) + self.clump.begin();
|
||||
let in_box = match in_boxes[idx.to_uint()].specific {
|
||||
UnscannedTextBox(ref text_box_info) => &text_box_info.text,
|
||||
_ => fail!("Expected an unscanned text box!"),
|
||||
};
|
||||
|
@ -210,20 +211,20 @@ impl TextRunScanner {
|
|||
// Next, concatenate all of the transformed strings together, saving the new
|
||||
// character indices.
|
||||
let mut run_str: ~str = "".to_owned();
|
||||
let mut new_ranges: Vec<Range<int>> = vec![];
|
||||
let mut char_total = 0;
|
||||
let mut new_ranges: Vec<Range<CharIndex>> = vec![];
|
||||
let mut char_total = CharIndex(0);
|
||||
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));
|
||||
run_str.push_str(*transformed_strs.get(i as uint));
|
||||
char_total += added_chars;
|
||||
char_total = char_total + added_chars;
|
||||
}
|
||||
|
||||
// Now create the run.
|
||||
// TextRuns contain a cycle which is usually resolved by the teardown
|
||||
// sequence. If no clump takes ownership, however, it will leak.
|
||||
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(),
|
||||
run_str.clone(), decoration)))
|
||||
} else {
|
||||
|
@ -232,27 +233,27 @@ impl TextRunScanner {
|
|||
|
||||
// Make new boxes with the run and adjusted text indices.
|
||||
debug!("TextRunScanner: pushing box(es) in range: {}", self.clump);
|
||||
for i in clump.eachi() {
|
||||
for i in clump.each_index() {
|
||||
let logical_offset = i - self.clump.begin();
|
||||
let range = new_ranges.get(logical_offset as uint);
|
||||
if range.length() == 0 {
|
||||
let range = new_ranges.get(logical_offset.to_uint());
|
||||
if range.length() == CharIndex(0) {
|
||||
debug!("Elided an `UnscannedTextbox` because it was zero-length after \
|
||||
compression; {}", in_boxes[i as uint]);
|
||||
compression; {}", in_boxes[i.to_uint()]);
|
||||
continue
|
||||
}
|
||||
|
||||
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 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));
|
||||
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)
|
||||
}
|
||||
}
|
||||
} // End of match.
|
||||
|
||||
let end = self.clump.end(); // FIXME: borrow checker workaround
|
||||
self.clump.reset(end, 0);
|
||||
self.clump.reset(end, CharIndex(0));
|
||||
|
||||
new_whitespace
|
||||
} // End of `flush_clump_to_list`.
|
||||
|
|
2
src/components/main/servo.rs
Executable file → Normal file
2
src/components/main/servo.rs
Executable file → Normal file
|
@ -8,7 +8,6 @@
|
|||
|
||||
#![feature(globs, macro_rules, phase, thread_local)]
|
||||
|
||||
#![feature(phase)]
|
||||
#[phase(syntax, link)]
|
||||
extern crate log;
|
||||
|
||||
|
@ -30,6 +29,7 @@ extern crate script;
|
|||
extern crate servo_macros = "macros";
|
||||
extern crate servo_net = "net";
|
||||
extern crate servo_msg = "msg";
|
||||
#[phase(syntax, link)]
|
||||
extern crate servo_util = "util";
|
||||
extern crate style;
|
||||
extern crate sharegl;
|
||||
|
|
|
@ -6,12 +6,85 @@ use std::cmp::{max, min};
|
|||
use std::iter;
|
||||
use std::fmt;
|
||||
use std::num;
|
||||
use std::num::Bounded;
|
||||
use std::num::{Bounded, Zero};
|
||||
|
||||
/// An index type to be used by a `Range`
|
||||
pub trait RangeIndex<T>: Eq + Ord
|
||||
+ Clone
|
||||
+ Copy
|
||||
+ Zero
|
||||
+ TotalEq
|
||||
+ TotalOrd
|
||||
+ Add<Self, Self>
|
||||
+ Sub<Self, Self>
|
||||
+ Neg<Self>
|
||||
+ fmt::Show {
|
||||
fn new(x: T) -> Self;
|
||||
fn get(self) -> T;
|
||||
}
|
||||
|
||||
impl RangeIndex<int> for int {
|
||||
#[inline]
|
||||
fn new(x: int) -> int { x }
|
||||
|
||||
#[inline]
|
||||
fn get(self) -> int { self }
|
||||
}
|
||||
|
||||
/// Implements a range index type with operator overloads
|
||||
#[macro_export]
|
||||
macro_rules! range_index {
|
||||
($(#[$attr:meta])* struct $Self:ident($T:ty)) => (
|
||||
#[deriving(Clone, Eq, Ord, TotalEq, TotalOrd, Show, Zero)]
|
||||
$(#[$attr])*
|
||||
pub struct $Self(pub $T);
|
||||
|
||||
impl $Self {
|
||||
#[inline]
|
||||
pub fn to_uint(self) -> uint {
|
||||
self.get() as uint
|
||||
}
|
||||
}
|
||||
|
||||
impl RangeIndex<$T> for $Self {
|
||||
#[inline]
|
||||
fn new(x: $T) -> $Self {
|
||||
$Self(x)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get(self) -> $T {
|
||||
match self { $Self(x) => x }
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<$Self, $Self> for $Self {
|
||||
#[inline]
|
||||
fn add(&self, other: &$Self) -> $Self {
|
||||
$Self(self.get() + other.get())
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<$Self, $Self> for $Self {
|
||||
#[inline]
|
||||
fn sub(&self, other: &$Self) -> $Self {
|
||||
$Self(self.get() - other.get())
|
||||
}
|
||||
}
|
||||
|
||||
impl Neg<$Self> for $Self {
|
||||
#[inline]
|
||||
fn neg(&self) -> $Self {
|
||||
$Self(-self.get())
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[deriving(Show)]
|
||||
pub enum RangeRelation<T> {
|
||||
OverlapsBegin(/* overlap */ T),
|
||||
OverlapsEnd(/* overlap */ T),
|
||||
pub enum RangeRelation<I> {
|
||||
OverlapsBegin(/* overlap */ I),
|
||||
OverlapsEnd(/* overlap */ I),
|
||||
ContainedBy,
|
||||
Contains,
|
||||
Coincides,
|
||||
|
@ -19,59 +92,88 @@ pub enum RangeRelation<T> {
|
|||
EntirelyAfter
|
||||
}
|
||||
|
||||
/// A range of indices
|
||||
#[deriving(Clone)]
|
||||
pub struct Range<T> {
|
||||
off: T,
|
||||
len: T,
|
||||
pub struct Range<I> {
|
||||
off: I,
|
||||
len: I,
|
||||
}
|
||||
|
||||
impl<T: Int + TotalOrd + Signed> fmt::Show for Range<T> {
|
||||
impl<T: Int, I: fmt::Show + RangeIndex<T>> fmt::Show for Range<I> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f.buf, "[{} .. {})", self.begin(), self.end())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Int + TotalOrd + Signed> Range<T> {
|
||||
/// An iterator over each index in a range
|
||||
pub struct EachIndex<T, I> {
|
||||
it: iter::Range<T>,
|
||||
}
|
||||
|
||||
pub fn each_index<T: Int, I: RangeIndex<T>>(start: I, stop: I) -> EachIndex<T, I> {
|
||||
EachIndex {
|
||||
it: iter::range(start.get(), stop.get())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Int, I: RangeIndex<T>> Iterator<I> for EachIndex<T, I> {
|
||||
#[inline]
|
||||
pub fn new(off: T, len: T) -> Range<T> {
|
||||
Range {
|
||||
off: off,
|
||||
len: len,
|
||||
}
|
||||
fn next(&mut self) -> Option<I> {
|
||||
self.it.next().map(|i| RangeIndex::new(i))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn empty() -> Range<T> {
|
||||
fn size_hint(&self) -> (uint, Option<uint>) {
|
||||
self.it.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Int, I: RangeIndex<T>> Range<I> {
|
||||
#[inline]
|
||||
pub fn new(off: I, len: I) -> Range<I> {
|
||||
Range { off: off, len: len }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn empty() -> Range<I> {
|
||||
Range::new(num::zero(), num::zero())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn begin(&self) -> T { self.off }
|
||||
pub fn begin(&self) -> I { self.off }
|
||||
#[inline]
|
||||
pub fn length(&self) -> T { self.len }
|
||||
pub fn length(&self) -> I { self.len }
|
||||
#[inline]
|
||||
pub fn end(&self) -> T { self.off + self.len }
|
||||
pub fn end(&self) -> I { self.off + self.len }
|
||||
|
||||
#[inline]
|
||||
pub fn eachi(&self) -> iter::Range<T> {
|
||||
range(self.off, self.off + self.len)
|
||||
pub fn each_index(&self) -> EachIndex<T, I> {
|
||||
each_index(self.off, self.off + self.len)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn contains(&self, i: T) -> bool {
|
||||
pub fn contains(&self, i: I) -> bool {
|
||||
i >= self.begin() && i < self.end()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_valid_for_string(&self, s: &str) -> bool {
|
||||
let s_len = s.len();
|
||||
match num::cast(s_len) {
|
||||
match num::cast::<uint, T>(s_len) {
|
||||
Some(len) => {
|
||||
self.begin() < len && self.end() <= len && self.length() <= len
|
||||
let len = RangeIndex::new(len);
|
||||
self.begin() < len
|
||||
&& self.end() <= len
|
||||
&& self.length() <= len
|
||||
},
|
||||
None => {
|
||||
debug!("Range<T>::is_valid_for_string: string length (len={}) is longer than the max \
|
||||
value for T (max={})", s_len, { let val: T = Bounded::max_value(); val });
|
||||
debug!("Range<T>::is_valid_for_string: string length (len={}) is longer than the \
|
||||
max value for the range index (max={})", s_len,
|
||||
{
|
||||
let max: T = Bounded::max_value();
|
||||
let val: I = RangeIndex::new(max);
|
||||
val
|
||||
});
|
||||
false
|
||||
},
|
||||
}
|
||||
|
@ -83,34 +185,34 @@ impl<T: Int + TotalOrd + Signed> Range<T> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn shift_by(&mut self, i: T) {
|
||||
pub fn shift_by(&mut self, i: I) {
|
||||
self.off = self.off + i;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn extend_by(&mut self, i: T) {
|
||||
pub fn extend_by(&mut self, i: I) {
|
||||
self.len = self.len + i;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn extend_to(&mut self, i: T) {
|
||||
pub fn extend_to(&mut self, i: I) {
|
||||
self.len = i - self.off;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn adjust_by(&mut self, off_i: T, len_i: T) {
|
||||
pub fn adjust_by(&mut self, off_i: I, len_i: I) {
|
||||
self.off = self.off + off_i;
|
||||
self.len = self.len + len_i;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn reset(&mut self, off_i: T, len_i: T) {
|
||||
pub fn reset(&mut self, off_i: I, len_i: I) {
|
||||
self.off = off_i;
|
||||
self.len = len_i;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn intersect(&self, other: &Range<T>) -> Range<T> {
|
||||
pub fn intersect(&self, other: &Range<I>) -> Range<I> {
|
||||
let begin = max(self.begin(), other.begin());
|
||||
let end = min(self.end(), other.end());
|
||||
|
||||
|
@ -125,7 +227,7 @@ impl<T: Int + TotalOrd + Signed> Range<T> {
|
|||
/// from the point of view of `self`. So, 'EntirelyBefore' means
|
||||
/// that the `self` range is entirely before `other` range.
|
||||
#[inline]
|
||||
pub fn relation_to_range(&self, other: &Range<T>) -> RangeRelation<T> {
|
||||
pub fn relation_to_range(&self, other: &Range<I>) -> RangeRelation<I> {
|
||||
if other.begin() > self.end() {
|
||||
return EntirelyBefore;
|
||||
}
|
||||
|
@ -154,19 +256,20 @@ impl<T: Int + TotalOrd + Signed> Range<T> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn repair_after_coalesced_range(&mut self, other: &Range<T>) {
|
||||
pub fn repair_after_coalesced_range(&mut self, other: &Range<I>) {
|
||||
let relation = self.relation_to_range(other);
|
||||
debug!("repair_after_coalesced_range: possibly repairing range {}", *self);
|
||||
debug!("repair_after_coalesced_range: relation of original range and coalesced range {}: {}",
|
||||
*other, relation);
|
||||
let _1: I = RangeIndex::new(num::one::<T>());
|
||||
match relation {
|
||||
EntirelyBefore => {},
|
||||
EntirelyAfter => { self.shift_by(-other.length()); },
|
||||
Coincides | ContainedBy => { self.reset(other.begin(), num::one()); },
|
||||
Coincides | ContainedBy => { self.reset(other.begin(), _1); },
|
||||
Contains => { self.extend_by(-other.length()); },
|
||||
OverlapsBegin(overlap) => { self.extend_by(num::one::<T>() - overlap); },
|
||||
OverlapsBegin(overlap) => { self.extend_by(_1 - overlap); },
|
||||
OverlapsEnd(overlap) => {
|
||||
let len = self.length() - overlap + num::one();
|
||||
let len = self.length() - overlap + _1;
|
||||
self.reset(other.begin(), len);
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue