Converted attr range to use RangeMap BTree (#41)

* Converted attr range to use RangeMap BTree

* Change get_span() to use First index instead of range.

* update doc comment
This commit is contained in:
Andrew Wheeler(Genusis) 2022-11-14 13:05:34 -05:00 committed by GitHub
parent b253800383
commit 271ca5cf7a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 43 additions and 98 deletions

View file

@ -20,6 +20,7 @@ sys-locale = { version = "0.2", optional = true }
unicode-linebreak = "0.1" unicode-linebreak = "0.1"
unicode-script = "0.5" unicode-script = "0.5"
unicode-segmentation = "1.7" unicode-segmentation = "1.7"
rangemap = "1.1.0"
[dependencies.unicode-bidi] [dependencies.unicode-bidi]
version = "0.3" version = "0.3"

View file

@ -8,6 +8,7 @@ use alloc::{
use core::ops::Range; use core::ops::Range;
pub use fontdb::{Family, Stretch, Style, Weight}; pub use fontdb::{Family, Stretch, Style, Weight};
use rangemap::RangeMap;
/// Text color /// Text color
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
@ -215,7 +216,7 @@ impl AttrsOwned {
#[derive(Eq, PartialEq)] #[derive(Eq, PartialEq)]
pub struct AttrsList { pub struct AttrsList {
defaults: AttrsOwned, defaults: AttrsOwned,
spans: Vec<(Range<usize>, AttrsOwned)>, spans: RangeMap<usize, AttrsOwned>,
} }
impl AttrsList { impl AttrsList {
@ -223,7 +224,7 @@ impl AttrsList {
pub fn new(defaults: Attrs) -> Self { pub fn new(defaults: Attrs) -> Self {
Self { Self {
defaults: AttrsOwned::new(defaults), defaults: AttrsOwned::new(defaults),
spans: Vec::new(), spans: RangeMap::new(),
} }
} }
@ -233,13 +234,14 @@ impl AttrsList {
} }
/// Get the current attribute spans /// Get the current attribute spans
pub fn spans(&self) -> &Vec<(Range<usize>, AttrsOwned)> { pub fn spans(&self) -> Vec<(&Range<usize>, &AttrsOwned)> {
&self.spans self.spans.iter().collect()
} }
/// Clear the current attribute spans /// Clear the current attribute spans
pub fn clear_spans(&mut self) { pub fn clear_spans(&mut self) {
self.spans.clear(); //Todo: Once clear is added Change this back to clear.
self.spans = RangeMap::new();
} }
/// Add an attribute span, removes any previous matching parts of spans /// Add an attribute span, removes any previous matching parts of spans
@ -249,104 +251,47 @@ impl AttrsList {
return; return;
} }
let mut rework_spans = Vec::with_capacity(3); self.spans.insert(range, AttrsOwned::new(attrs));
let mut i = 0;
//Grab intersecting parts that are not fully intersected. remove those that are.
//This clips or splits the parts that are outside of the range.
while i < self.spans.len() {
if self.spans[i].0.end <= range.end && self.spans[i].0.start >= range.start {
let _ = self.spans.remove(i);
} else if self.spans[i].0.end > range.end && self.spans[i].0.start >= range.start && self.spans[i].0.start <= range.end {
let rework = self.spans.remove(i);
rework_spans.push((range.end..rework.0.end, rework.1))
} else if self.spans[i].0.end <= range.end && self.spans[i].0.end >= range.start && self.spans[i].0.start < range.start {
let rework = self.spans.remove(i);
rework_spans.push((rework.0.start..range.start, rework.1))
} else if self.spans[i].0.end > range.end && self.spans[i].0.start < range.start {
let rework = self.spans.remove(i);
rework_spans.push((rework.0.start..range.start, rework.1.clone()));
rework_spans.push((range.end..rework.0.end, rework.1));
} else if self.spans[i].0.start > range.end {
break;
} else {
i += 1;
}
}
// Readd reworked arrays back.
for reworked in rework_spans {
self.spans.push(reworked);
}
// Combine span if possible
let mut combined = false;
for span in self.spans.iter_mut() {
if span.1.as_attrs() != attrs {
// Ignore not matching attrs
continue;
}
if span.0.end == range.start {
// Extend span with range at end
span.0.end = range.end;
combined = true;
break;
}
if span.0.start == range.end {
// Extend span with range at start
span.0.start = range.start;
combined = true;
break;
}
}
if ! combined {
//Finally lets add the new span. it should fit now.
self.spans.push((range, AttrsOwned::new(attrs)));
}
//sort by start to speed up further additions
self.spans.sort_by(|a, b| a.0.start.partial_cmp(&b.0.start).unwrap());
} }
/// Get the highest priority attribute span for a range /// Get the attribute span for an index
/// ///
/// This returns the first span that contains the range /// This returns a span that contains the index
pub fn get_span(&self, range: Range<usize>) -> Attrs { pub fn get_span(&self, index: usize) -> Attrs {
for span in self.spans.iter() { self.spans.get(&index).map(|v| v.as_attrs()).unwrap_or(self.defaults.as_attrs())
if range.start >= span.0.start && range.end <= span.0.end {
return span.1.as_attrs();
}
}
self.defaults.as_attrs()
} }
/// Split attributes list at an offset /// Split attributes list at an offset
pub fn split_off(&mut self, index: usize) -> Self { pub fn split_off(&mut self, index: usize) -> Self {
let mut new = Self::new(self.defaults.as_attrs()); let mut new = Self::new(self.defaults.as_attrs());
let mut i = 0; let mut removes = Vec::new();
while i < self.spans.len() {
if self.spans[i].0.end <= index { //get the keys we need to remove or fix.
// Leave this in the previous attributes list for span in self.spans.iter() {
i += 1; if span.0.end <= index {
} else if self.spans[i].0.start >= index { continue;
// Move this to the new attributes list } else if span.0.start >= index {
let (range, attrs) = self.spans.remove(i); removes.push((span.0.clone(), false));
new.spans.push(( } else {
removes.push((span.0.clone(), true));
}
}
for (key, resize) in removes {
let (range, attrs) = self.spans.get_key_value(&key.start).map(|v| (v.0.clone(), v.1.clone())).unwrap();
self.spans.remove(key);
if resize {
new.spans.insert(
0..range.end - index,
attrs.clone()
);
self.spans.insert(range.start..index, attrs);
} else {
new.spans.insert(
range.start - index..range.end - index, range.start - index..range.end - index,
attrs attrs
)); );
} else {
// New span has index..end
new.spans.push((
0..self.spans[i].0.end - index,
self.spans[i].1.clone()
));
// Old span has start..index
self.spans[i].0.end = index;
i += 1;
} }
} }
new new

View file

@ -97,7 +97,7 @@ fn shape_fallback(
// Set color // Set color
//TODO: these attributes should not be related to shaping //TODO: these attributes should not be related to shaping
for glyph in glyphs.iter_mut() { for glyph in glyphs.iter_mut() {
let attrs = attrs_list.get_span(glyph.start..glyph.end); let attrs = attrs_list.get_span(glyph.start);
glyph.color_opt = attrs.color_opt; glyph.color_opt = attrs.color_opt;
} }
@ -132,7 +132,7 @@ fn shape_run<'a>(
&line[start_run..end_run], &line[start_run..end_run],
); );
let attrs = attrs_list.get_span(start_run..end_run); let attrs = attrs_list.get_span(start_run);
let font_matches = font_system.get_font_matches(attrs); let font_matches = font_system.get_font_matches(attrs);
@ -304,10 +304,9 @@ impl ShapeWord {
let mut start_run = start_word; let mut start_run = start_word;
let mut attrs = attrs_list.defaults(); let mut attrs = attrs_list.defaults();
for (egc_i, egc) in word.grapheme_indices(true) { for (egc_i, _egc) in word.grapheme_indices(true) {
let start_egc = start_word + egc_i; let start_egc = start_word + egc_i;
let end_egc = start_egc + egc.len(); let attrs_egc = attrs_list.get_span(start_egc);
let attrs_egc = attrs_list.get_span(start_egc..end_egc);
if ! attrs.compatible(&attrs_egc) { if ! attrs.compatible(&attrs_egc) {
//TODO: more efficient //TODO: more efficient
glyphs.append(&mut shape_run( glyphs.append(&mut shape_run(