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:
parent
b253800383
commit
271ca5cf7a
3 changed files with 43 additions and 98 deletions
|
|
@ -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"
|
||||||
|
|
|
||||||
131
src/attrs.rs
131
src/attrs.rs
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue