From 8245b7b73667dcdd32b32f49729d39083d513817 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Tue, 30 Mar 2021 21:43:12 +0200 Subject: =?UTF-8?q?Baseline=20alignment=20=E2=8F=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/layout/stack.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/layout/stack.rs') diff --git a/src/layout/stack.rs b/src/layout/stack.rs index 79fde72d..b9de1bbc 100644 --- a/src/layout/stack.rs +++ b/src/layout/stack.rs @@ -119,7 +119,8 @@ impl StackLayouter { size.switch(self.main) }; - let mut output = Frame::new(full_size.switch(self.main).to_size()); + let mut output = Frame::new(full_size.switch(self.main).to_size(), Length::ZERO); + let mut baseline = None; for (before, frame, aligns) in std::mem::take(&mut self.frames) { let child_size = frame.size.switch(self.main); @@ -142,9 +143,14 @@ impl StackLayouter { }); let pos = Gen::new(main, cross).switch(self.main).to_point(); + baseline.get_or_insert(pos.y + frame.baseline); output.push_frame(pos, frame); } + if let Some(baseline) = baseline { + output.baseline = baseline; + } + self.finished.push(output); self.areas.next(); self.ruler = Align::Start; -- cgit v1.2.3 From d74c9378b81618419dc8c6315e391b6012955218 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Sat, 3 Apr 2021 17:36:33 +0200 Subject: =?UTF-8?q?New=20paragraph=20layout=20=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous paragraph layout algorithm had a couple of flaws: - It always produced line break opportunities between runs although on the textual level there might have been none. - It didn't handle trailing spacing correctly in some cases. - It wouldn't have been easily adaptable to Knuth-Plass style optimal line breaking because it was fundamentally structured first-fit run-by-run. The new paragraph layout algorithm fixes these flaws. It proceeds roughly in the following stages: 1. Collect all text in the paragraph. 2. Compute BiDi embedding levels. 3. Shape all runs, layout all children and store the resulting items in a reusable (possibly even cacheable) `ParLayout`. 3. Iterate over all line breaks in the concatenated text. 4. Construct lightweight `LineLayout` objects for full lines instead of runs. These mostly borrow from the `ParLayout` and only reshape the first and last run if necessary. The design allows to use Harfbuzz's UNSAFE_TO_BREAK mechanism to make reshaping more efficient. The size of a `LineLayout` can be measured without building the line's frame. 5. Build only the selected line's frames and stack them. --- src/layout/stack.rs | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) (limited to 'src/layout/stack.rs') diff --git a/src/layout/stack.rs b/src/layout/stack.rs index b9de1bbc..8e2249d2 100644 --- a/src/layout/stack.rs +++ b/src/layout/stack.rs @@ -116,39 +116,40 @@ impl StackLayouter { size = Size::new(width, width / aspect); } - size.switch(self.main) + size }; - let mut output = Frame::new(full_size.switch(self.main).to_size(), Length::ZERO); - let mut baseline = None; + let mut output = Frame::new(full_size, full_size.height); + let mut first = true; + let full_size = full_size.switch(self.main); for (before, frame, aligns) in std::mem::take(&mut self.frames) { let child_size = frame.size.switch(self.main); // Align along the main axis. - let main = aligns.main.resolve(if self.dirs.main.is_positive() { - let after_with_self = self.size.main - before; - before .. full_size.main - after_with_self - } else { - let before_with_self = before + child_size.main; - let after = self.size.main - (before + child_size.main); - full_size.main - before_with_self .. after - }); + let main = aligns.main.resolve( + self.dirs.main, + if self.dirs.main.is_positive() { + before .. before + full_size.main - self.size.main + } else { + self.size.main - (before + child_size.main) + .. full_size.main - (before + child_size.main) + }, + ); // Align along the cross axis. - let cross = aligns.cross.resolve(if self.dirs.cross.is_positive() { - Length::ZERO .. full_size.cross - child_size.cross - } else { - full_size.cross - child_size.cross .. Length::ZERO - }); + let cross = aligns.cross.resolve( + self.dirs.cross, + Length::ZERO .. full_size.cross - child_size.cross, + ); let pos = Gen::new(main, cross).switch(self.main).to_point(); - baseline.get_or_insert(pos.y + frame.baseline); - output.push_frame(pos, frame); - } + if first { + output.baseline = pos.y + frame.baseline; + first = false; + } - if let Some(baseline) = baseline { - output.baseline = baseline; + output.push_frame(pos, frame); } self.finished.push(output); -- cgit v1.2.3 From 9014e834785aeae4af264c4e8c2c2141ead4788a Mon Sep 17 00:00:00 2001 From: Laurenz Date: Sat, 3 Apr 2021 20:53:18 +0200 Subject: =?UTF-8?q?Fix=20multi-page=20paragraph=20bugs=20=F0=9F=90=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/layout/stack.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/layout/stack.rs') diff --git a/src/layout/stack.rs b/src/layout/stack.rs index 8e2249d2..b69936ba 100644 --- a/src/layout/stack.rs +++ b/src/layout/stack.rs @@ -28,7 +28,13 @@ impl Layout for StackNode { match *child { StackChild::Spacing(amount) => layouter.push_spacing(amount), StackChild::Any(ref node, aligns) => { - for frame in node.layout(ctx, &layouter.areas) { + let mut frames = node.layout(ctx, &layouter.areas).into_iter(); + if let Some(frame) = frames.next() { + layouter.push_frame(frame, aligns); + } + + for frame in frames { + layouter.finish_area(); layouter.push_frame(frame, aligns); } } -- cgit v1.2.3