diff --git a/src/exec/state.rs b/src/exec/state.rs index 22839c54d..416b5d085 100644 --- a/src/exec/state.rs +++ b/src/exec/state.rs @@ -93,7 +93,7 @@ impl Default for ParState { fn default() -> Self { Self { word_spacing: Relative::new(0.25).into(), - line_spacing: Relative::new(0.2).into(), + line_spacing: Linear::ZERO, par_spacing: Relative::new(0.5).into(), } } diff --git a/src/export/pdf.rs b/src/export/pdf.rs index 9f3552786..c30222b2b 100644 --- a/src/export/pdf.rs +++ b/src/export/pdf.rs @@ -195,7 +195,7 @@ impl<'a> PdfExporter<'a> { } let x = pos.x.to_pt() as f32; - let y = (page.size.height - pos.y - size).to_pt() as f32; + let y = (page.size.height - pos.y).to_pt() as f32; text.matrix(1.0, 0.0, 0.0, 1.0, x, y); text.show(&shaped.encode_glyphs_be()); } diff --git a/src/layout/par.rs b/src/layout/par.rs index 7d876fc17..45494decb 100644 --- a/src/layout/par.rs +++ b/src/layout/par.rs @@ -163,13 +163,17 @@ impl<'a> ParLayouter<'a> { output.push_frame(pos, frame); } + // Add line spacing, but only between lines. + if !self.lines.is_empty() { + self.lines_size.main += self.par.line_spacing; + *self.areas.current.get_mut(self.main) -= self.par.line_spacing; + } + // Update metrics of the whole paragraph. self.lines.push((self.lines_size.main, output, self.line_ruler)); self.lines_size.main += full_size.main; - self.lines_size.main += self.par.line_spacing; self.lines_size.cross = self.lines_size.cross.max(full_size.cross); *self.areas.current.get_mut(self.main) -= full_size.main; - *self.areas.current.get_mut(self.main) -= self.par.line_spacing; // Reset metrics for the single line. self.line_size = Gen::ZERO; diff --git a/src/shaping.rs b/src/shaping.rs index 722d103a4..a8d2b2bf1 100644 --- a/src/shaping.rs +++ b/src/shaping.rs @@ -70,6 +70,8 @@ pub fn shape( let mut frame = Frame::new(Size::new(Length::ZERO, font_size)); let mut shaped = Shaped::new(FaceId::MAX, font_size); let mut offset = Length::ZERO; + let mut ascender = Length::ZERO; + let mut descender = Length::ZERO; // Create an iterator with conditional direction. let mut forwards = text.chars(); @@ -84,47 +86,56 @@ pub fn shape( let query = FaceQuery { fallback: fallback.iter(), variant, c }; if let Some(id) = loader.query(query) { let face = loader.face(id).get(); - let (glyph, width) = match lookup_glyph(face, c, font_size) { + let (glyph, width) = match lookup_glyph(face, c) { Some(v) => v, None => continue, }; - // Flush the buffer if we change the font face. - if shaped.face != id && !shaped.text.is_empty() { - let pos = Point::new(frame.size.width, Length::ZERO); - frame.push(pos, Element::Text(shaped)); - frame.size.width += offset; - shaped = Shaped::new(FaceId::MAX, font_size); + let units_per_em = f64::from(face.units_per_em().unwrap_or(1000)); + let convert = |units| units / units_per_em * font_size; + + // Flush the buffer and reset the metrics if we use a new font face. + if shaped.face != id { + place(&mut frame, shaped, offset, ascender, descender); + + shaped = Shaped::new(id, font_size); offset = Length::ZERO; + ascender = convert(f64::from(face.ascender())); + descender = convert(f64::from(face.descender())); } - shaped.face = id; shaped.text.push(c); shaped.glyphs.push(glyph); shaped.offsets.push(offset); - offset += width; + offset += convert(f64::from(width)); } } // Flush the last buffered parts of the word. - if !shaped.text.is_empty() { - let pos = Point::new(frame.size.width, Length::ZERO); - frame.push(pos, Element::Text(shaped)); - frame.size.width += offset; - } + place(&mut frame, shaped, offset, ascender, descender); frame } -/// Looks up the glyph for `c` and returns its index alongside its width at the -/// given `size`. -fn lookup_glyph(face: &Face, c: char, size: Length) -> Option<(GlyphId, Length)> { +/// Look up the glyph for `c` and returns its index alongside its advance width. +fn lookup_glyph(face: &Face, c: char) -> Option<(GlyphId, u16)> { let glyph = face.glyph_index(c)?; - - // Determine the width of the char. - let units_per_em = face.units_per_em().unwrap_or(1000) as f64; - let width_units = face.glyph_hor_advance(glyph)? as f64; - let width = width_units / units_per_em * size; - + let width = face.glyph_hor_advance(glyph)?; Some((glyph, width)) } + +/// Place shaped text into a frame. +fn place( + frame: &mut Frame, + shaped: Shaped, + offset: Length, + ascender: Length, + descender: Length, +) { + if !shaped.text.is_empty() { + let pos = Point::new(frame.size.width, ascender); + frame.push(pos, Element::Text(shaped)); + frame.size.width += offset; + frame.size.height = frame.size.height.max(ascender - descender); + } +} diff --git a/tests/ref/comment.png b/tests/ref/comment.png index 9cee51b6e..1fad97fe8 100644 Binary files a/tests/ref/comment.png and b/tests/ref/comment.png differ diff --git a/tests/ref/control/for.png b/tests/ref/control/for.png index f0d4a5cda..d04ea62cf 100644 Binary files a/tests/ref/control/for.png and b/tests/ref/control/for.png differ diff --git a/tests/ref/control/if.png b/tests/ref/control/if.png index 04724e1f4..99bde49e0 100644 Binary files a/tests/ref/control/if.png and b/tests/ref/control/if.png differ diff --git a/tests/ref/control/invalid.png b/tests/ref/control/invalid.png index c9822eeb6..ff4c69875 100644 Binary files a/tests/ref/control/invalid.png and b/tests/ref/control/invalid.png differ diff --git a/tests/ref/control/let.png b/tests/ref/control/let.png index 693a8d4f1..5fb1c992f 100644 Binary files a/tests/ref/control/let.png and b/tests/ref/control/let.png differ diff --git a/tests/ref/control/while.png b/tests/ref/control/while.png index 55a6ed80b..890131f1b 100644 Binary files a/tests/ref/control/while.png and b/tests/ref/control/while.png differ diff --git a/tests/ref/expr/array.png b/tests/ref/expr/array.png index 44331d9fd..784553b3f 100644 Binary files a/tests/ref/expr/array.png and b/tests/ref/expr/array.png differ diff --git a/tests/ref/expr/block-invalid.png b/tests/ref/expr/block-invalid.png index 11899d863..b380defc9 100644 Binary files a/tests/ref/expr/block-invalid.png and b/tests/ref/expr/block-invalid.png differ diff --git a/tests/ref/expr/block.png b/tests/ref/expr/block.png index ffa595687..d5ad52ae9 100644 Binary files a/tests/ref/expr/block.png and b/tests/ref/expr/block.png differ diff --git a/tests/ref/expr/call-invalid.png b/tests/ref/expr/call-invalid.png index 0d3783a84..88f137804 100644 Binary files a/tests/ref/expr/call-invalid.png and b/tests/ref/expr/call-invalid.png differ diff --git a/tests/ref/expr/call.png b/tests/ref/expr/call.png index 39941778b..7197bb908 100644 Binary files a/tests/ref/expr/call.png and b/tests/ref/expr/call.png differ diff --git a/tests/ref/expr/dict.png b/tests/ref/expr/dict.png index 351e0498d..28a7cb3bc 100644 Binary files a/tests/ref/expr/dict.png and b/tests/ref/expr/dict.png differ diff --git a/tests/ref/expr/ops.png b/tests/ref/expr/ops.png index fb717dd02..95a24c0ed 100644 Binary files a/tests/ref/expr/ops.png and b/tests/ref/expr/ops.png differ diff --git a/tests/ref/full/coma.png b/tests/ref/full/coma.png index ed8494043..f5db682d5 100644 Binary files a/tests/ref/full/coma.png and b/tests/ref/full/coma.png differ diff --git a/tests/ref/library/box.png b/tests/ref/library/box.png index e8513d70d..2804f8e96 100644 Binary files a/tests/ref/library/box.png and b/tests/ref/library/box.png differ diff --git a/tests/ref/library/font.png b/tests/ref/library/font.png index 92b5b7fc2..8e611b16a 100644 Binary files a/tests/ref/library/font.png and b/tests/ref/library/font.png differ diff --git a/tests/ref/library/hv.png b/tests/ref/library/hv.png index 13a352a46..0842d4093 100644 Binary files a/tests/ref/library/hv.png and b/tests/ref/library/hv.png differ diff --git a/tests/ref/library/image.png b/tests/ref/library/image.png index 70f263e6e..af497c8d6 100644 Binary files a/tests/ref/library/image.png and b/tests/ref/library/image.png differ diff --git a/tests/ref/library/page.png b/tests/ref/library/page.png index 1ddeeb3d7..1537fad47 100644 Binary files a/tests/ref/library/page.png and b/tests/ref/library/page.png differ diff --git a/tests/ref/library/pagebreak.png b/tests/ref/library/pagebreak.png index dfb9dcaae..b1ee0eef2 100644 Binary files a/tests/ref/library/pagebreak.png and b/tests/ref/library/pagebreak.png differ diff --git a/tests/ref/markup/emph.png b/tests/ref/markup/emph.png index aec7fefbb..f002610e9 100644 Binary files a/tests/ref/markup/emph.png and b/tests/ref/markup/emph.png differ diff --git a/tests/ref/markup/escape.png b/tests/ref/markup/escape.png index 54e612012..3fa44c6dd 100644 Binary files a/tests/ref/markup/escape.png and b/tests/ref/markup/escape.png differ diff --git a/tests/ref/markup/heading.png b/tests/ref/markup/heading.png index b4aa1bbde..9f2ce6ece 100644 Binary files a/tests/ref/markup/heading.png and b/tests/ref/markup/heading.png differ diff --git a/tests/ref/markup/linebreak.png b/tests/ref/markup/linebreak.png index dda5efa68..fec65248d 100644 Binary files a/tests/ref/markup/linebreak.png and b/tests/ref/markup/linebreak.png differ diff --git a/tests/ref/markup/nbsp.png b/tests/ref/markup/nbsp.png index ad7591ac7..3e1f0ee74 100644 Binary files a/tests/ref/markup/nbsp.png and b/tests/ref/markup/nbsp.png differ diff --git a/tests/ref/markup/raw.png b/tests/ref/markup/raw.png index c0bf01608..ce8334284 100644 Binary files a/tests/ref/markup/raw.png and b/tests/ref/markup/raw.png differ diff --git a/tests/ref/markup/strong.png b/tests/ref/markup/strong.png index cd6d670de..ac38c4369 100644 Binary files a/tests/ref/markup/strong.png and b/tests/ref/markup/strong.png differ diff --git a/tests/ref/repr.png b/tests/ref/repr.png index 54a1d2409..21d7af278 100644 Binary files a/tests/ref/repr.png and b/tests/ref/repr.png differ diff --git a/tests/ref/spacing.png b/tests/ref/spacing.png index a8086177d..8bdc98850 100644 Binary files a/tests/ref/spacing.png and b/tests/ref/spacing.png differ diff --git a/tests/ref/text.png b/tests/ref/text.png index 31d0b45e8..38ae364d0 100644 Binary files a/tests/ref/text.png and b/tests/ref/text.png differ diff --git a/tests/typ/full/coma.typ b/tests/typ/full/coma.typ index 39404a35d..d324627f3 100644 --- a/tests/typ/full/coma.typ +++ b/tests/typ/full/coma.typ @@ -1,5 +1,5 @@ // Configuration with `page` and `font` functions. -#page(width: 450pt, height: 380pt, margins: 1cm) +#page(width: 450pt, margins: 1cm) // There are variables and they can take normal values like strings, ... #let city = "Berlin" diff --git a/tests/typ/library/box.typ b/tests/typ/library/box.typ index 10e2c93e9..7ce568592 100644 --- a/tests/typ/library/box.typ +++ b/tests/typ/library/box.typ @@ -1,15 +1,15 @@ // Test the box function. --- -#page("a7", flip: true) +#page("a8", flip: true) // Box with fixed width, should have text height. -#box(width: 2cm, color: #9650D6)[A] +#box(width: 2cm, color: #9650D6)[Legal] Sometimes there is no box. // Box with fixed height, should span line. -#box(height: 2cm, width: 100%, color: #734CED)[B] +#box(height: 1cm, width: 100%, color: #734CED)[B] // Empty box with fixed width and height. #box(width: 6cm, height: 12pt, color: #CB4CED) @@ -18,6 +18,6 @@ Sometimes there is no box. #box(width: 2in, color: #ff0000) // These are in a row! -#box(width: 1in, height: 10pt, color: #D6CD67) -#box(width: 1in, height: 10pt, color: #EDD466) -#box(width: 1in, height: 10pt, color: #E3BE62) +#box(width: 0.5in, height: 10pt, color: #D6CD67) +#box(width: 0.5in, height: 10pt, color: #EDD466) +#box(width: 0.5in, height: 10pt, color: #E3BE62) diff --git a/tests/typ/repr.typ b/tests/typ/repr.typ index 6eead75e0..96eb710ef 100644 --- a/tests/typ/repr.typ +++ b/tests/typ/repr.typ @@ -32,9 +32,8 @@ {12e1pt} \ {2.5rad} \ {45deg} \ - // Not in monospace via repr. -#repr(45deg) +#repr(45deg) \ --- // Colors. diff --git a/tests/typeset.rs b/tests/typeset.rs index c56655f51..232dfa5c1 100644 --- a/tests/typeset.rs +++ b/tests/typeset.rs @@ -393,7 +393,7 @@ fn draw_text(env: &Env, canvas: &mut Canvas, pos: Point, shaped: &Shaped) { let units_per_em = face.units_per_em().unwrap_or(1000); let x = (pos.x + offset).to_pt() as f32; - let y = (pos.y + shaped.font_size).to_pt() as f32; + let y = pos.y.to_pt() as f32; let scale = (shaped.font_size / units_per_em as f64).to_pt() as f32; let mut builder = WrappedPathBuilder(PathBuilder::new());