Refactor line reordering from callback to iterator

This commit is contained in:
Laurenz 2021-09-27 22:36:07 +02:00
parent ed0c804017
commit f1ab290572

View File

@ -1,6 +1,7 @@
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use std::rc::Rc; use std::rc::Rc;
use itertools::Either;
use unicode_bidi::{BidiInfo, Level}; use unicode_bidi::{BidiInfo, Level};
use xi_unicode::LineBreakIterator; use xi_unicode::LineBreakIterator;
@ -437,7 +438,7 @@ impl<'a> LineLayout<'a> {
let mut offset = Length::zero(); let mut offset = Length::zero();
let mut ruler = Align::Start; let mut ruler = Align::Start;
self.reordered(ctx, |ctx, item| { for item in self.reordered() {
let mut position = |frame: &Frame, align| { let mut position = |frame: &Frame, align| {
// FIXME: Ruler alignment for RTL. // FIXME: Ruler alignment for RTL.
ruler = ruler.max(align); ruler = ruler.max(align);
@ -468,21 +469,15 @@ impl<'a> LineLayout<'a> {
output.push_frame(pos, frame); output.push_frame(pos, frame);
} }
} }
}); }
output output
} }
/// Iterate through the line's items in visual order. /// Iterate through the line's items in visual order.
fn reordered<F>(&self, ctx: &LayoutContext, mut f: F) fn reordered(&self) -> impl Iterator<Item = &ParItem<'a>> {
where
F: FnMut(&LayoutContext, &ParItem<'a>),
{
// The bidi crate doesn't like empty lines. // The bidi crate doesn't like empty lines.
if self.line.is_empty() { let (levels, runs) = if !self.line.is_empty() {
return;
}
// Find the paragraph that contains the line. // Find the paragraph that contains the line.
let para = self let para = self
.bidi .bidi
@ -492,10 +487,13 @@ impl<'a> LineLayout<'a> {
.unwrap(); .unwrap();
// Compute the reordered ranges in visual order (left to right). // Compute the reordered ranges in visual order (left to right).
let (levels, runs) = self.bidi.visual_runs(para, self.line.clone()); self.bidi.visual_runs(para, self.line.clone())
} else {
<_>::default()
};
// Find the items for each run. runs.into_iter()
for run in runs { .flat_map(move |run| {
let first_idx = self.find(run.start).unwrap(); let first_idx = self.find(run.start).unwrap();
let last_idx = self.find(run.end - 1).unwrap(); let last_idx = self.find(run.end - 1).unwrap();
let range = first_idx ..= last_idx; let range = first_idx ..= last_idx;
@ -503,15 +501,12 @@ impl<'a> LineLayout<'a> {
// Provide the items forwards or backwards depending on the run's // Provide the items forwards or backwards depending on the run's
// direction. // direction.
if levels[run.start].is_ltr() { if levels[run.start].is_ltr() {
for item in range { Either::Left(range)
f(ctx, self.get(item).unwrap());
}
} else { } else {
for item in range.rev() { Either::Right(range.rev())
f(ctx, self.get(item).unwrap());
}
}
} }
})
.map(move |idx| self.get(idx).unwrap())
} }
/// Find the index of the item whose range contains the `text_offset`. /// Find the index of the item whose range contains the `text_offset`.