mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
Refactor line reordering from callback to iterator
This commit is contained in:
parent
ed0c804017
commit
f1ab290572
@ -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,50 +469,44 @@ 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.
|
||||||
}
|
let para = self
|
||||||
|
.bidi
|
||||||
|
.paragraphs
|
||||||
|
.iter()
|
||||||
|
.find(|para| para.range.contains(&self.line.start))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// Find the paragraph that contains the line.
|
// Compute the reordered ranges in visual order (left to right).
|
||||||
let para = self
|
self.bidi.visual_runs(para, self.line.clone())
|
||||||
.bidi
|
} else {
|
||||||
.paragraphs
|
<_>::default()
|
||||||
.iter()
|
};
|
||||||
.find(|para| para.range.contains(&self.line.start))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Compute the reordered ranges in visual order (left to right).
|
runs.into_iter()
|
||||||
let (levels, runs) = self.bidi.visual_runs(para, self.line.clone());
|
.flat_map(move |run| {
|
||||||
|
let first_idx = self.find(run.start).unwrap();
|
||||||
|
let last_idx = self.find(run.end - 1).unwrap();
|
||||||
|
let range = first_idx ..= last_idx;
|
||||||
|
|
||||||
// Find the items for each run.
|
// Provide the items forwards or backwards depending on the run's
|
||||||
for run in runs {
|
// direction.
|
||||||
let first_idx = self.find(run.start).unwrap();
|
if levels[run.start].is_ltr() {
|
||||||
let last_idx = self.find(run.end - 1).unwrap();
|
Either::Left(range)
|
||||||
let range = first_idx ..= last_idx;
|
} else {
|
||||||
|
Either::Right(range.rev())
|
||||||
// Provide the items forwards or backwards depending on the run's
|
|
||||||
// direction.
|
|
||||||
if levels[run.start].is_ltr() {
|
|
||||||
for item in range {
|
|
||||||
f(ctx, self.get(item).unwrap());
|
|
||||||
}
|
}
|
||||||
} else {
|
})
|
||||||
for item in range.rev() {
|
.map(move |idx| self.get(idx).unwrap())
|
||||||
f(ctx, self.get(item).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`.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user