summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2020-12-17 00:20:27 +0100
committerLaurenz <laurmaedje@gmail.com>2020-12-17 00:20:27 +0100
commit81e80ecfba80f5bffab45719c1f2aba4f9b91b4f (patch)
tree03452a7ef0361f24159a60c93fb543263afb91e3
parent2336aeb4c32864f53a4d4e0f72e54a174df47a60 (diff)
Test [page] function 📕
- Make page break behaviour more consistent - Allow skipping reference image testing for single tests with `// compare-ref: false` (useful for tests which only check error messages)
-rw-r--r--bench/Cargo.toml4
-rw-r--r--src/eval/mod.rs39
-rw-r--r--src/layout/spacing.rs26
-rw-r--r--src/library/layout.rs28
-rw-r--r--tests/ref/image-error.pngbin120 -> 0 bytes
-rw-r--r--tests/ref/image-formats.pngbin0 -> 107778 bytes
-rw-r--r--tests/ref/image-jpeg.pngbin69754 -> 0 bytes
-rw-r--r--tests/ref/image-png.pngbin37986 -> 0 bytes
-rw-r--r--tests/ref/page-body.pngbin0 -> 2974 bytes
-rw-r--r--tests/ref/page-dirs.pngbin0 -> 1030 bytes
-rw-r--r--tests/ref/page-metrics.pngbin0 -> 5092 bytes
-rw-r--r--tests/typ/example-coma.typ2
-rw-r--r--tests/typ/image-error.typ5
-rw-r--r--tests/typ/image-fit.typ2
-rw-r--r--tests/typ/image-formats.typ8
-rw-r--r--tests/typ/image-jpeg.typ2
-rw-r--r--tests/typ/image-png.typ2
-rw-r--r--tests/typ/page-body.typ11
-rw-r--r--tests/typ/page-dirs.typ5
-rw-r--r--tests/typ/page-error.typ11
-rw-r--r--tests/typ/page-metrics.typ25
-rw-r--r--tests/typeset.rs24
22 files changed, 137 insertions, 57 deletions
diff --git a/bench/Cargo.toml b/bench/Cargo.toml
index 25a112a1..36f40b8c 100644
--- a/bench/Cargo.toml
+++ b/bench/Cargo.toml
@@ -5,10 +5,10 @@ authors = ["The Typst Project Developers"]
edition = "2018"
publish = false
-[dependencies]
+[dev-dependencies]
+criterion = "0.3"
fontdock = { path = "../../fontdock" }
typst = { path = ".." }
-criterion = "0.3"
[[bench]]
name = "typst"
diff --git a/src/eval/mod.rs b/src/eval/mod.rs
index 6d8f66ca..bab93a05 100644
--- a/src/eval/mod.rs
+++ b/src/eval/mod.rs
@@ -25,7 +25,7 @@ use crate::diag::{Deco, Feedback, Pass};
use crate::env::SharedEnv;
use crate::geom::{BoxAlign, Dir, Flow, Gen, Length, Linear, Relative, Sides, Size};
use crate::layout::{
- Document, Expansion, LayoutNode, Pad, Pages, Par, Softness, Spacing, Stack, Text,
+ Document, Expansion, LayoutNode, Pad, Pages, Par, Spacing, Stack, Text,
};
use crate::syntax::*;
@@ -35,9 +35,9 @@ use crate::syntax::*;
/// evaluation.
pub fn eval(tree: &SynTree, env: SharedEnv, state: State) -> Pass<Document> {
let mut ctx = EvalContext::new(env, state);
- ctx.start_page_group(false);
+ ctx.start_page_group(Softness::Hard);
tree.eval(&mut ctx);
- ctx.end_page_group(true);
+ ctx.end_page_group(|s| s == Softness::Hard);
ctx.finish()
}
@@ -117,28 +117,35 @@ impl EvalContext {
/// Start a page group based on the active page state.
///
- /// If both this `hard` and the one in the matching call to `end_page_group`
- /// are false, empty page runs will be omitted from the output.
+ /// The `softness` is a hint on whether empty pages should be kept in the
+ /// output.
///
/// This also starts an inner paragraph.
- pub fn start_page_group(&mut self, hard: bool) {
+ pub fn start_page_group(&mut self, softness: Softness) {
self.start_group(PageGroup {
size: self.state.page.size,
padding: self.state.page.margins(),
flow: self.state.flow,
align: self.state.align,
- hard,
+ softness,
});
self.start_par_group();
}
- /// End a page group and push it to the finished page runs.
+ /// End a page group, returning its [`Softness`].
+ ///
+ /// Whether the page is kept when it's empty is decided by `keep_empty`
+ /// based on its softness. If kept, the page is pushed to the finished page
+ /// runs.
///
/// This also ends an inner paragraph.
- pub fn end_page_group(&mut self, hard: bool) {
+ pub fn end_page_group(
+ &mut self,
+ keep_empty: impl FnOnce(Softness) -> bool,
+ ) -> Softness {
self.end_par_group();
let (group, children) = self.end_group::<PageGroup>();
- if hard || group.hard || !children.is_empty() {
+ if !children.is_empty() || keep_empty(group.softness) {
self.runs.push(Pages {
size: group.size,
child: LayoutNode::dynamic(Pad {
@@ -152,6 +159,7 @@ impl EvalContext {
}),
})
}
+ group.softness
}
/// Start a content group.
@@ -273,7 +281,7 @@ struct PageGroup {
padding: Sides<Linear>,
flow: Flow,
align: BoxAlign,
- hard: bool,
+ softness: Softness,
}
/// A group for generic content.
@@ -286,6 +294,15 @@ struct ParGroup {
line_spacing: Length,
}
+/// Defines how items interact with surrounding items.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
+pub enum Softness {
+ /// Soft items can be skipped in some circumstances.
+ Soft,
+ /// Hard items are always retained.
+ Hard,
+}
+
/// Evaluate an item.
///
/// _Note_: Evaluation is not necessarily pure, it may change the active state.
diff --git a/src/layout/spacing.rs b/src/layout/spacing.rs
index 1ba3b54a..c9a9c233 100644
--- a/src/layout/spacing.rs
+++ b/src/layout/spacing.rs
@@ -1,14 +1,21 @@
use std::fmt::{self, Debug, Formatter};
use super::*;
+use crate::eval::Softness;
/// A spacing node.
#[derive(Copy, Clone, PartialEq)]
pub struct Spacing {
/// The amount of spacing to insert.
pub amount: Length,
- /// Spacing interaction, see [`Softness`]'s documentation for more
- /// information.
+ /// Defines how spacing interacts with surrounding spacing.
+ ///
+ /// Hard spacing assures that a fixed amount of spacing will always be
+ /// inserted. Soft spacing will be consumed by previous soft spacing or
+ /// neighbouring hard spacing and can be used to insert overridable spacing,
+ /// e.g. between words or paragraphs.
+ ///
+ /// This field is only used in evaluation, not in layouting.
pub softness: Softness,
}
@@ -32,18 +39,3 @@ impl From<Spacing> for LayoutNode {
Self::Spacing(spacing)
}
}
-
-/// Defines how spacing interacts with surrounding spacing.
-///
-/// Hard spacing assures that a fixed amount of spacing will always be inserted.
-/// Soft spacing will be consumed by previous soft spacing or neighbouring hard
-/// spacing and can be used to insert overridable spacing, e.g. between words or
-/// paragraphs.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
-pub enum Softness {
- /// Soft spacing is not laid out if it directly follows other soft spacing
- /// or if it touches hard spacing.
- Soft,
- /// Hard spacing is always laid out and consumes surrounding soft spacing.
- Hard,
-}
diff --git a/src/library/layout.rs b/src/library/layout.rs
index 4a787f1e..36a20821 100644
--- a/src/library/layout.rs
+++ b/src/library/layout.rs
@@ -1,7 +1,8 @@
use std::fmt::{self, Display, Formatter};
+use crate::eval::Softness;
use crate::geom::{Length, Linear};
-use crate::layout::{Expansion, Fixed, Softness, Spacing, Stack};
+use crate::layout::{Expansion, Fixed, Spacing, Stack};
use crate::paper::{Paper, PaperClass};
use crate::prelude::*;
@@ -184,8 +185,8 @@ pub fn boxed(mut args: Args, ctx: &mut EvalContext) -> Value {
let body = args.find::<SynTree>().unwrap_or_default();
let width = args.get::<_, Linear>(ctx, "width");
let height = args.get::<_, Linear>(ctx, "height");
- let main = args.get::<_, Spanned<Dir>>(ctx, "main");
- let cross = args.get::<_, Spanned<Dir>>(ctx, "cross");
+ let main = args.get::<_, Spanned<Dir>>(ctx, "main-dir");
+ let cross = args.get::<_, Spanned<Dir>>(ctx, "cross-dir");
ctx.set_flow(Gen::new(main, cross));
args.done(ctx);
@@ -269,7 +270,7 @@ pub fn page(mut args: Args, ctx: &mut EvalContext) -> Value {
let snapshot = ctx.state.clone();
let body = args.find::<SynTree>();
- if let Some(paper) = args.find::<Paper>() {
+ if let Some(paper) = args.get::<_, Paper>(ctx, 0) {
ctx.state.page.class = paper.class;
ctx.state.page.size = paper.size();
}
@@ -309,21 +310,24 @@ pub fn page(mut args: Args, ctx: &mut EvalContext) -> Value {
std::mem::swap(&mut size.width, &mut size.height);
}
- let main = args.get::<_, Spanned<Dir>>(ctx, "main");
- let cross = args.get::<_, Spanned<Dir>>(ctx, "cross");
+ let main = args.get::<_, Spanned<Dir>>(ctx, "main-dir");
+ let cross = args.get::<_, Spanned<Dir>>(ctx, "cross-dir");
ctx.set_flow(Gen::new(main, cross));
args.done(ctx);
+ let mut softness = ctx.end_page_group(|_| false);
+
if let Some(body) = body {
- ctx.end_page_group(false);
- ctx.start_page_group(true);
+ // TODO: Restrict body to a single page?
+ ctx.start_page_group(Softness::Hard);
body.eval(ctx);
+ ctx.end_page_group(|s| s == Softness::Hard);
ctx.state = snapshot;
+ softness = Softness::Soft;
}
- ctx.end_page_group(false);
- ctx.start_page_group(false);
+ ctx.start_page_group(softness);
Value::None
}
@@ -331,7 +335,7 @@ pub fn page(mut args: Args, ctx: &mut EvalContext) -> Value {
/// `pagebreak`: Start a new page.
pub fn pagebreak(args: Args, ctx: &mut EvalContext) -> Value {
args.done(ctx);
- ctx.end_page_group(false);
- ctx.start_page_group(true);
+ ctx.end_page_group(|_| true);
+ ctx.start_page_group(Softness::Hard);
Value::None
}
diff --git a/tests/ref/image-error.png b/tests/ref/image-error.png
deleted file mode 100644
index 812a3758..00000000
--- a/tests/ref/image-error.png
+++ /dev/null
Binary files differ
diff --git a/tests/ref/image-formats.png b/tests/ref/image-formats.png
new file mode 100644
index 00000000..45b23276
--- /dev/null
+++ b/tests/ref/image-formats.png
Binary files differ
diff --git a/tests/ref/image-jpeg.png b/tests/ref/image-jpeg.png
deleted file mode 100644
index ef9e74cb..00000000
--- a/tests/ref/image-jpeg.png
+++ /dev/null
Binary files differ
diff --git a/tests/ref/image-png.png b/tests/ref/image-png.png
deleted file mode 100644
index 4e0818d2..00000000
--- a/tests/ref/image-png.png
+++ /dev/null
Binary files differ
diff --git a/tests/ref/page-body.png b/tests/ref/page-body.png
new file mode 100644
index 00000000..a3b3d726
--- /dev/null
+++ b/tests/ref/page-body.png
Binary files differ
diff --git a/tests/ref/page-dirs.png b/tests/ref/page-dirs.png
new file mode 100644
index 00000000..2bf23ebc
--- /dev/null
+++ b/tests/ref/page-dirs.png
Binary files differ
diff --git a/tests/ref/page-metrics.png b/tests/ref/page-metrics.png
new file mode 100644
index 00000000..2e8d626d
--- /dev/null
+++ b/tests/ref/page-metrics.png
Binary files differ
diff --git a/tests/typ/example-coma.typ b/tests/typ/example-coma.typ
index f841a122..d41032c1 100644
--- a/tests/typ/example-coma.typ
+++ b/tests/typ/example-coma.typ
@@ -1,4 +1,4 @@
-// Small integration test of syntax, page setup, box layout and alignment.
+// Test integration of syntax, page setup, box layout and alignment.
[page: width=450pt, height=300pt, margins=1cm]
diff --git a/tests/typ/image-error.typ b/tests/typ/image-error.typ
index 4fde4ab2..9a7f2c40 100644
--- a/tests/typ/image-error.typ
+++ b/tests/typ/image-error.typ
@@ -1,5 +1,8 @@
-// error: 5:9-5:30 failed to load image
+// Test error cases of the `image` function.
+
+// compare-ref: false
// error: 8:9-8:30 failed to load image
+// error: 11:9-11:30 failed to load image
// File does not exist.
[image: "path/does/not/exist"]
diff --git a/tests/typ/image-fit.typ b/tests/typ/image-fit.typ
index b735f058..eca7c1e4 100644
--- a/tests/typ/image-fit.typ
+++ b/tests/typ/image-fit.typ
@@ -1,3 +1,5 @@
+// Test configuring the size and fitting behaviour of images.
+
// Fit to width of page.
[image: "res/rhino.png"]
diff --git a/tests/typ/image-formats.typ b/tests/typ/image-formats.typ
new file mode 100644
index 00000000..36b991d0
--- /dev/null
+++ b/tests/typ/image-formats.typ
@@ -0,0 +1,8 @@
+// Test loading different image formats.
+
+// Load an RGBA PNG image.
+[image: "res/rhino.png"]
+[pagebreak]
+
+// Load an RGB JPEG image.
+[image: "res/tiger.jpg"]
diff --git a/tests/typ/image-jpeg.typ b/tests/typ/image-jpeg.typ
deleted file mode 100644
index 48cf1a0d..00000000
--- a/tests/typ/image-jpeg.typ
+++ /dev/null
@@ -1,2 +0,0 @@
-// Load an RGB JPEG image.
-[image: "res/tiger.jpg"]
diff --git a/tests/typ/image-png.typ b/tests/typ/image-png.typ
deleted file mode 100644
index 482591e9..00000000
--- a/tests/typ/image-png.typ
+++ /dev/null
@@ -1,2 +0,0 @@
-// Load an RGBA PNG image.
-[image: "res/rhino.png"]
diff --git a/tests/typ/page-body.typ b/tests/typ/page-body.typ
new file mode 100644
index 00000000..6067dcfe
--- /dev/null
+++ b/tests/typ/page-body.typ
@@ -0,0 +1,11 @@
+// Test a combination of pages with bodies and normal content.
+
+[page: height=50pt]
+
+[page][First]
+[page][Second]
+[pagebreak]
+Fourth
+[page][Fifth]
+Sixth
+[page][Seventh and last]
diff --git a/tests/typ/page-dirs.typ b/tests/typ/page-dirs.typ
new file mode 100644
index 00000000..09ba4e9e
--- /dev/null
+++ b/tests/typ/page-dirs.typ
@@ -0,0 +1,5 @@
+// Test changing the layouting directions of pages.
+
+[page: main-dir=btt, cross-dir=rtl]
+
+Right to left!
diff --git a/tests/typ/page-error.typ b/tests/typ/page-error.typ
new file mode 100644
index 00000000..dee5c449
--- /dev/null
+++ b/tests/typ/page-error.typ
@@ -0,0 +1,11 @@
+// Test error cases of the `page` function.
+
+// compare-ref: false
+// error: 8:8-8:19 invalid paper
+// error: 11:17-11:20 aligned axis
+
+// Invalid paper.
+[page: nonexistant]
+
+// Aligned axes.
+[page: main-dir=ltr]
diff --git a/tests/typ/page-metrics.typ b/tests/typ/page-metrics.typ
new file mode 100644
index 00000000..6c7bd461
--- /dev/null
+++ b/tests/typ/page-metrics.typ
@@ -0,0 +1,25 @@
+// Test configuring page sizes and margins.
+
+// Set width.
+[page: width=50pt][High]
+
+// Set height.
+[page: height=50pt][Wide]
+
+// Set all margins at once.
+[page: margins=40pt][
+ [align: top, left][TL]
+ [align: bottom, right][BR]
+]
+
+// Set individual margins.
+[page: left=0pt >> align: left][Left]
+[page: right=0pt >> align: right][Right]
+[page: top=0pt >> align: top][Top]
+[page: bottom=0pt >> align: bottom][Bottom]
+
+// Ensure that specific margins override general margins.
+[page: margins=0pt, left=40pt][Overriden]
+
+// Flip the page.
+[page: a10, flip=true][Flipped]
diff --git a/tests/typeset.rs b/tests/typeset.rs
index 012aff63..5f108585 100644
--- a/tests/typeset.rs
+++ b/tests/typeset.rs
@@ -127,7 +127,7 @@ fn test(
let src = fs::read_to_string(src_path).unwrap();
let map = LineMap::new(&src);
- let ref_diags = parse_diags(&src, &map);
+ let (ref_diags, compare_ref) = parse_metadata(&src, &map);
let mut state = State::default();
state.page.size = Size::uniform(Length::pt(120.0));
@@ -167,14 +167,16 @@ fn test(
}
}
- if let Ok(ref_pixmap) = Pixmap::load_png(&ref_path) {
- if canvas.pixmap != ref_pixmap {
- println!(" Does not match reference image. ❌");
+ if compare_ref {
+ if let Ok(ref_pixmap) = Pixmap::load_png(&ref_path) {
+ if canvas.pixmap != ref_pixmap {
+ println!(" Does not match reference image. ❌");
+ ok = false;
+ }
+ } else {
+ println!(" Failed to open reference image. ❌");
ok = false;
}
- } else {
- println!(" Failed to open reference image. ❌");
- ok = false;
}
if ok {
@@ -184,10 +186,13 @@ fn test(
ok
}
-fn parse_diags(src: &str, map: &LineMap) -> SpanVec<Diag> {
+fn parse_metadata(src: &str, map: &LineMap) -> (SpanVec<Diag>, bool) {
let mut diags = vec![];
+ let mut compare_ref = true;
for line in src.lines() {
+ compare_ref &= !line.starts_with("// compare-ref: false");
+
let (level, rest) = if let Some(rest) = line.strip_prefix("// error: ") {
(Level::Error, rest)
} else if let Some(rest) = line.strip_prefix("// warning: ") {
@@ -211,7 +216,8 @@ fn parse_diags(src: &str, map: &LineMap) -> SpanVec<Diag> {
}
diags.sort();
- diags
+
+ (diags, compare_ref)
}
fn print_diag(diag: &Spanned<Diag>, map: &LineMap) {