mirror of
https://github.com/servo/servo.git
synced 2025-06-22 16:18:59 +01:00
Add RangeIndex trait and iterator
This will allow for the definition of typesafe range units in the future, for example for glyph indices. This also adds a macro that allows for the easy implementation of new range index types.
This commit is contained in:
parent
68f9aad883
commit
49df943649
5 changed files with 152 additions and 49 deletions
|
@ -3,7 +3,8 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use servo_util::vec::*;
|
use servo_util::vec::*;
|
||||||
use servo_util::range::Range;
|
use servo_util::range;
|
||||||
|
use servo_util::range::{Range, EachIndex};
|
||||||
use servo_util::geometry::Au;
|
use servo_util::geometry::Au;
|
||||||
|
|
||||||
use std::cmp::{Ord, Eq};
|
use std::cmp::{Ord, Eq};
|
||||||
|
@ -11,7 +12,6 @@ use std::num::{NumCast, Zero};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::u16;
|
use std::u16;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use std::iter;
|
|
||||||
use geom::point::Point2D;
|
use geom::point::Point2D;
|
||||||
|
|
||||||
/// GlyphEntry is a port of Gecko's CompressedGlyph scheme for storing glyph data compactly.
|
/// GlyphEntry is a port of Gecko's CompressedGlyph scheme for storing glyph data compactly.
|
||||||
|
@ -609,7 +609,7 @@ impl<'a> GlyphStore {
|
||||||
GlyphIterator {
|
GlyphIterator {
|
||||||
store: self,
|
store: self,
|
||||||
char_index: rang.begin(),
|
char_index: rang.begin(),
|
||||||
char_range: rang.eachi(),
|
char_range: rang.each_index(),
|
||||||
glyph_range: None
|
glyph_range: None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -674,8 +674,8 @@ impl<'a> GlyphStore {
|
||||||
pub struct GlyphIterator<'a> {
|
pub struct GlyphIterator<'a> {
|
||||||
store: &'a GlyphStore,
|
store: &'a GlyphStore,
|
||||||
char_index: int,
|
char_index: int,
|
||||||
char_range: iter::Range<int>,
|
char_range: EachIndex<int, int>,
|
||||||
glyph_range: Option<iter::Range<int>>,
|
glyph_range: Option<EachIndex<int, int>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> GlyphIterator<'a> {
|
impl<'a> GlyphIterator<'a> {
|
||||||
|
@ -698,7 +698,7 @@ impl<'a> GlyphIterator<'a> {
|
||||||
fn next_complex_glyph(&mut self, entry: &GlyphEntry, i: int)
|
fn next_complex_glyph(&mut self, entry: &GlyphEntry, i: int)
|
||||||
-> Option<(int, GlyphInfo<'a>)> {
|
-> Option<(int, 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(0, glyphs.len() as int));
|
self.glyph_range = Some(range::each_index(0, glyphs.len() as int));
|
||||||
self.next()
|
self.next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -316,7 +316,7 @@ impl Shaper {
|
||||||
// extend glyph range to max glyph index covered by char_span,
|
// extend glyph range to max glyph index covered by char_span,
|
||||||
// in cases where one char made several glyphs and left some unassociated chars.
|
// in cases where one char made several glyphs and left some unassociated chars.
|
||||||
let mut max_glyph_idx = glyph_span.end();
|
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 {
|
if byteToGlyph[i as uint] > NO_GLYPH {
|
||||||
max_glyph_idx = cmp::max(byteToGlyph[i as uint] as int + 1, max_glyph_idx);
|
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.");
|
probably doesn't work.");
|
||||||
|
|
||||||
let mut all_glyphs_are_within_cluster: bool = true;
|
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);
|
let loc = glyph_data.byte_offset_of_glyph(j);
|
||||||
if !char_byte_span.contains(loc) {
|
if !char_byte_span.contains(loc) {
|
||||||
all_glyphs_are_within_cluster = false;
|
all_glyphs_are_within_cluster = false;
|
||||||
|
@ -414,7 +414,7 @@ impl Shaper {
|
||||||
// collect all glyphs to be assigned to the first character.
|
// collect all glyphs to be assigned to the first character.
|
||||||
let mut datas = vec!();
|
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);
|
let shape = glyph_data.get_entry_for_glyph(glyph_i, &mut y_pos);
|
||||||
datas.push(GlyphData::new(shape.codepoint,
|
datas.push(GlyphData::new(shape.codepoint,
|
||||||
shape.advance,
|
shape.advance,
|
||||||
|
|
|
@ -713,7 +713,7 @@ impl InlineFlow {
|
||||||
text_align::right => slack_width,
|
text_align::right => slack_width,
|
||||||
};
|
};
|
||||||
|
|
||||||
for i in line.range.eachi() {
|
for i in line.range.each_index() {
|
||||||
let box_ = boxes.get_mut(i as uint);
|
let box_ = boxes.get_mut(i as uint);
|
||||||
let size = box_.border_box.size;
|
let size = box_.border_box.size;
|
||||||
box_.border_box = Rect(Point2D(offset_x, box_.border_box.origin.y), size);
|
box_.border_box = Rect(Point2D(offset_x, box_.border_box.origin.y), size);
|
||||||
|
@ -844,7 +844,7 @@ impl Flow for InlineFlow {
|
||||||
let (mut largest_height_for_top_fragments, mut largest_height_for_bottom_fragments) =
|
let (mut largest_height_for_top_fragments, mut largest_height_for_bottom_fragments) =
|
||||||
(Au(0), Au(0));
|
(Au(0), Au(0));
|
||||||
|
|
||||||
for box_i in line.range.eachi() {
|
for box_i in line.range.each_index() {
|
||||||
let fragment = self.boxes.boxes.get_mut(box_i as uint);
|
let fragment = self.boxes.boxes.get_mut(box_i as uint);
|
||||||
|
|
||||||
let InlineMetrics {
|
let InlineMetrics {
|
||||||
|
@ -920,7 +920,7 @@ impl Flow for InlineFlow {
|
||||||
|
|
||||||
// Compute the final positions in the block direction of each fragment. Recall that
|
// 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.
|
// `fragment.border_box.origin.y` was set to the distance from the baseline above.
|
||||||
for box_i in line.range.eachi() {
|
for box_i in line.range.each_index() {
|
||||||
let fragment = self.boxes.get_mut(box_i as uint);
|
let fragment = self.boxes.get_mut(box_i as uint);
|
||||||
match fragment.vertical_align() {
|
match fragment.vertical_align() {
|
||||||
vertical_align::top => {
|
vertical_align::top => {
|
||||||
|
|
|
@ -232,7 +232,7 @@ impl TextRunScanner {
|
||||||
|
|
||||||
// Make new boxes with the run and adjusted text indices.
|
// Make new boxes with the run and adjusted text indices.
|
||||||
debug!("TextRunScanner: pushing box(es) in range: {}", self.clump);
|
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 logical_offset = i - self.clump.begin();
|
||||||
let range = new_ranges.get(logical_offset as uint);
|
let range = new_ranges.get(logical_offset as uint);
|
||||||
if range.length() == 0 {
|
if range.length() == 0 {
|
||||||
|
|
|
@ -6,12 +6,85 @@ use std::cmp::{max, min};
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::num;
|
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)]
|
#[deriving(Show)]
|
||||||
pub enum RangeRelation<T> {
|
pub enum RangeRelation<I> {
|
||||||
OverlapsBegin(/* overlap */ T),
|
OverlapsBegin(/* overlap */ I),
|
||||||
OverlapsEnd(/* overlap */ T),
|
OverlapsEnd(/* overlap */ I),
|
||||||
ContainedBy,
|
ContainedBy,
|
||||||
Contains,
|
Contains,
|
||||||
Coincides,
|
Coincides,
|
||||||
|
@ -19,59 +92,88 @@ pub enum RangeRelation<T> {
|
||||||
EntirelyAfter
|
EntirelyAfter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A range of indices
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
pub struct Range<T> {
|
pub struct Range<I> {
|
||||||
off: T,
|
off: I,
|
||||||
len: T,
|
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 {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f.buf, "[{} .. {})", self.begin(), self.end())
|
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]
|
#[inline]
|
||||||
pub fn new(off: T, len: T) -> Range<T> {
|
fn next(&mut self) -> Option<I> {
|
||||||
Range {
|
self.it.next().map(|i| RangeIndex::new(i))
|
||||||
off: off,
|
|
||||||
len: len,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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())
|
Range::new(num::zero(), num::zero())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn begin(&self) -> T { self.off }
|
pub fn begin(&self) -> I { self.off }
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn length(&self) -> T { self.len }
|
pub fn length(&self) -> I { self.len }
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn end(&self) -> T { self.off + self.len }
|
pub fn end(&self) -> I { self.off + self.len }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn eachi(&self) -> iter::Range<T> {
|
pub fn each_index(&self) -> EachIndex<T, I> {
|
||||||
range(self.off, self.off + self.len)
|
each_index(self.off, self.off + self.len)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn contains(&self, i: T) -> bool {
|
pub fn contains(&self, i: I) -> bool {
|
||||||
i >= self.begin() && i < self.end()
|
i >= self.begin() && i < self.end()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_valid_for_string(&self, s: &str) -> bool {
|
pub fn is_valid_for_string(&self, s: &str) -> bool {
|
||||||
let s_len = s.len();
|
let s_len = s.len();
|
||||||
match num::cast(s_len) {
|
match num::cast::<uint, T>(s_len) {
|
||||||
Some(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 => {
|
None => {
|
||||||
debug!("Range<T>::is_valid_for_string: string length (len={}) is longer than the max \
|
debug!("Range<T>::is_valid_for_string: string length (len={}) is longer than the \
|
||||||
value for T (max={})", s_len, { let val: T = Bounded::max_value(); val });
|
max value for the range index (max={})", s_len,
|
||||||
|
{
|
||||||
|
let max: T = Bounded::max_value();
|
||||||
|
let val: I = RangeIndex::new(max);
|
||||||
|
val
|
||||||
|
});
|
||||||
false
|
false
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -83,34 +185,34 @@ impl<T: Int + TotalOrd + Signed> Range<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn shift_by(&mut self, i: T) {
|
pub fn shift_by(&mut self, i: I) {
|
||||||
self.off = self.off + i;
|
self.off = self.off + i;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn extend_by(&mut self, i: T) {
|
pub fn extend_by(&mut self, i: I) {
|
||||||
self.len = self.len + i;
|
self.len = self.len + i;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn extend_to(&mut self, i: T) {
|
pub fn extend_to(&mut self, i: I) {
|
||||||
self.len = i - self.off;
|
self.len = i - self.off;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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.off = self.off + off_i;
|
||||||
self.len = self.len + len_i;
|
self.len = self.len + len_i;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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.off = off_i;
|
||||||
self.len = len_i;
|
self.len = len_i;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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 begin = max(self.begin(), other.begin());
|
||||||
let end = min(self.end(), other.end());
|
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
|
/// from the point of view of `self`. So, 'EntirelyBefore' means
|
||||||
/// that the `self` range is entirely before `other` range.
|
/// that the `self` range is entirely before `other` range.
|
||||||
#[inline]
|
#[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() {
|
if other.begin() > self.end() {
|
||||||
return EntirelyBefore;
|
return EntirelyBefore;
|
||||||
}
|
}
|
||||||
|
@ -154,19 +256,20 @@ impl<T: Int + TotalOrd + Signed> Range<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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);
|
let relation = self.relation_to_range(other);
|
||||||
debug!("repair_after_coalesced_range: possibly repairing range {}", *self);
|
debug!("repair_after_coalesced_range: possibly repairing range {}", *self);
|
||||||
debug!("repair_after_coalesced_range: relation of original range and coalesced range {}: {}",
|
debug!("repair_after_coalesced_range: relation of original range and coalesced range {}: {}",
|
||||||
*other, relation);
|
*other, relation);
|
||||||
|
let _1: I = RangeIndex::new(num::one::<T>());
|
||||||
match relation {
|
match relation {
|
||||||
EntirelyBefore => {},
|
EntirelyBefore => {},
|
||||||
EntirelyAfter => { self.shift_by(-other.length()); },
|
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()); },
|
Contains => { self.extend_by(-other.length()); },
|
||||||
OverlapsBegin(overlap) => { self.extend_by(num::one::<T>() - overlap); },
|
OverlapsBegin(overlap) => { self.extend_by(_1 - overlap); },
|
||||||
OverlapsEnd(overlap) => {
|
OverlapsEnd(overlap) => {
|
||||||
let len = self.length() - overlap + num::one();
|
let len = self.length() - overlap + _1;
|
||||||
self.reset(other.begin(), len);
|
self.reset(other.begin(), len);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue