Fix newline in text in math

Fixes #1948
This commit is contained in:
Laurenz 2023-09-13 13:45:05 +02:00
parent 8fb225feb4
commit 68b365b351
4 changed files with 59 additions and 31 deletions

View File

@ -2,6 +2,7 @@ use ttf_parser::gsub::SubstitutionSubtable;
use ttf_parser::math::MathValue; use ttf_parser::math::MathValue;
use typst::font::{FontStyle, FontWeight}; use typst::font::{FontStyle, FontWeight};
use typst::model::realize; use typst::model::realize;
use typst::syntax::is_newline;
use unicode_segmentation::UnicodeSegmentation; use unicode_segmentation::UnicodeSegmentation;
use super::*; use super::*;
@ -207,41 +208,64 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> {
FrameFragment::new(self, frame).into() FrameFragment::new(self, frame).into()
} else { } else {
// Anything else is handled by Typst's standard text layout. // Anything else is handled by Typst's standard text layout.
let spaced = text.graphemes(true).nth(1).is_some();
let mut style = self.style; let mut style = self.style;
if self.style.italic == Smart::Auto { if self.style.italic == Smart::Auto {
style = style.with_italic(false); style = style.with_italic(false);
} }
let text: EcoString = text.chars().map(|c| style.styled_char(c)).collect(); let text: EcoString = text.chars().map(|c| style.styled_char(c)).collect();
let text = TextElem::packed(text) if text.contains(is_newline) {
.styled(TextElem::set_top_edge(TopEdge::Metric(TopEdgeMetric::Bounds))) let mut fragments = vec![];
.styled(TextElem::set_bottom_edge(BottomEdge::Metric( for (i, piece) in text.split(is_newline).enumerate() {
BottomEdgeMetric::Bounds, if i != 0 {
))) fragments.push(MathFragment::Linebreak);
.spanned(span); }
let par = ParElem::new(vec![text]); if !piece.is_empty() {
fragments.push(self.layout_complex_text(piece, span)?.into());
// There isn't a natural width for a paragraph in a math environment; }
// because it will be placed somewhere probably not at the left margin }
// it will overflow. So emulate an `hbox` instead and allow the paragraph let mut frame = MathRow::new(fragments).into_frame(self);
// to extend as far as needed. let axis = scaled!(self, axis_height);
let frame = par frame.set_baseline(frame.height() / 2.0 + axis);
.layout( FrameFragment::new(self, frame).into()
self.vt, } else {
self.outer.chain(&self.local), self.layout_complex_text(&text, span)?.into()
false, }
Size::splat(Abs::inf()),
false,
)?
.into_frame();
FrameFragment::new(self, frame)
.with_class(MathClass::Alphabetic)
.with_spaced(spaced)
.into()
}; };
Ok(fragment) Ok(fragment)
} }
pub fn layout_complex_text(
&mut self,
text: &str,
span: Span,
) -> SourceResult<FrameFragment> {
let spaced = text.graphemes(true).nth(1).is_some();
let elem = TextElem::packed(text)
.styled(TextElem::set_top_edge(TopEdge::Metric(TopEdgeMetric::Bounds)))
.styled(TextElem::set_bottom_edge(BottomEdge::Metric(
BottomEdgeMetric::Bounds,
)))
.spanned(span);
// There isn't a natural width for a paragraph in a math environment;
// because it will be placed somewhere probably not at the left margin
// it will overflow. So emulate an `hbox` instead and allow the paragraph
// to extend as far as needed.
let frame = ParElem::new(vec![elem])
.layout(
self.vt,
self.outer.chain(&self.local),
false,
Size::splat(Abs::inf()),
false,
)?
.into_frame();
Ok(FrameFragment::new(self, frame)
.with_class(MathClass::Alphabetic)
.with_spaced(spaced))
}
pub fn styles(&self) -> StyleChain { pub fn styles(&self) -> StyleChain {
self.outer.chain(&self.local) self.outer.chain(&self.local)
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 900 B

View File

@ -0,0 +1,4 @@
// Test text with linebreaks in math.
---
$ x := "a\nb\nc\nd\ne" $

View File

@ -21,11 +21,11 @@ $#here[f] := #here[Hi there]$.
--- ---
// Test boxes without a baseline act as if the baseline is at the base // Test boxes without a baseline act as if the baseline is at the base
#{ #{
box(stroke: 0.2pt, $a #box(stroke: 0.2pt, $a$)$) box(stroke: 0.2pt, $a #box(stroke: 0.2pt, $a$)$)
h(12pt) h(12pt)
box(stroke: 0.2pt, $a #box(stroke: 0.2pt, $g$)$) box(stroke: 0.2pt, $a #box(stroke: 0.2pt, $g$)$)
h(12pt) h(12pt)
box(stroke: 0.2pt, $g #box(stroke: 0.2pt, $g$)$) box(stroke: 0.2pt, $g #box(stroke: 0.2pt, $g$)$)
} }
--- ---