diff --git a/Cargo.toml b/Cargo.toml index c2430db0d..ee945338e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,9 +11,6 @@ byteorder = "1" smallvec = "0.6.10" unicode-xid = "0.1.0" -[dev-dependencies] -regex = "1" - [[bin]] name = "typstc" path = "src/bin/main.rs" diff --git a/src/size.rs b/src/size.rs index fac316259..50b3ace56 100644 --- a/src/size.rs +++ b/src/size.rs @@ -116,6 +116,12 @@ impl Size2D { Size2D::default() } + /// Create a 2D-size with `x` and `y` set to the same value `s`. + #[inline] + pub fn with_all(s: Size) -> Size2D { + Size2D { x: s, y: s } + } + /// Create a new 2D-size with `x` set to a value and `y` zero. #[inline] pub fn with_x(x: Size) -> Size2D { @@ -179,6 +185,12 @@ impl SizeBox { pub fn zero() -> SizeBox { SizeBox::default() } + + /// Create a box with all four fields set to the same value `s`. + #[inline] + pub fn with_all(s: Size) -> SizeBox { + SizeBox { left: s, top: s, right: s, bottom: s } + } } /// The maximum of two sizes. diff --git a/src/style.rs b/src/style.rs index da190b46a..ae396852c 100644 --- a/src/style.rs +++ b/src/style.rs @@ -65,10 +65,10 @@ impl Default for TextStyle { TextStyle { classes: vec![Regular], fallback: vec![Serif], - font_size: Size::pt(11.0), + font_size: Size::pt(10.0), word_spacing: 0.25, line_spacing: 1.2, - paragraph_spacing: 1.5, + paragraph_spacing: 1.4, } } } diff --git a/tests/layouting.rs b/tests/layouting.rs index 933335cc4..77ec54ae1 100644 --- a/tests/layouting.rs +++ b/tests/layouting.rs @@ -1,14 +1,12 @@ use std::fs::{self, File}; use std::io::{BufWriter, Read, Write}; use std::process::Command; -#[cfg(not(debug_assertions))] -use std::time::Instant; - -use regex::{Regex, Captures}; use typst::export::pdf::PdfExporter; use typst::layout::LayoutAction; use typst::toddle::query::FileSystemFontProvider; +use typst::size::{Size, Size2D, SizeBox}; +use typst::style::PageStyle; use typst::Typesetter; const CACHE_DIR: &str = "tests/cache"; @@ -60,35 +58,45 @@ fn main() { fn test(name: &str, src: &str) { println!("Testing: {}.", name); - let src = preprocess(src); - let mut typesetter = Typesetter::new(); + + typesetter.set_page_style(PageStyle { + dimensions: Size2D::with_all(Size::pt(250.0)), + margins: SizeBox::with_all(Size::pt(10.0)), + }); + let provider = FileSystemFontProvider::from_listing("fonts/fonts.toml").unwrap(); typesetter.add_font_provider(provider.clone()); - // Make run warm. - #[cfg(not(debug_assertions))] let warmup_start = Instant::now(); - #[cfg(not(debug_assertions))] typesetter.typeset(&src).unwrap(); - #[cfg(not(debug_assertions))] let warmup_end = Instant::now(); + #[cfg(not(debug_assertions))] + let layouts = { + use std::time::Instant; - // Layout into box layout. - #[cfg(not(debug_assertions))] let start = Instant::now(); - let tree = typesetter.parse(&src).unwrap(); - #[cfg(not(debug_assertions))] let mid = Instant::now(); - let layouts = typesetter.layout(&tree).unwrap(); - #[cfg(not(debug_assertions))] let end = Instant::now(); + // Warmup. + let warmup_start = Instant::now(); + typesetter.typeset(&src).unwrap(); + let warmup_end = Instant::now(); + + let start = Instant::now(); + let tree = typesetter.parse(&src).unwrap(); + let mid = Instant::now(); + let layouts = typesetter.layout(&tree).unwrap(); + let end = Instant::now(); - // Print measurements. - #[cfg(not(debug_assertions))] { println!(" - cold start: {:?}", warmup_end - warmup_start); println!(" - warmed up: {:?}", end - start); println!(" - parsing: {:?}", mid - start); println!(" - layouting: {:?}", end - mid); println!(); - } + + layouts + }; + + #[cfg(debug_assertions)] + let layouts = typesetter.typeset(&src).unwrap(); // Write the serialed layout file. - let path = format!("{}/serialized/{}.lay", CACHE_DIR, name); + let path = format!("{}/serialized/{}.tld", CACHE_DIR, name); let mut file = File::create(path).unwrap(); // Find all used fonts and their filenames. @@ -128,54 +136,3 @@ fn test(name: &str, src: &str) { let exporter = PdfExporter::new(); exporter.export(&layouts, typesetter.loader(), file).unwrap(); } - -fn preprocess<'a>(src: &'a str) -> String { - let include_regex = Regex::new(r"\{include:((.|\.|\-)*)\}").unwrap(); - let lorem_regex = Regex::new(r"\{lorem:(\d*)\}").unwrap(); - - let mut preprocessed = src.to_string(); - - let mut changed = true; - while changed { - changed = false; - preprocessed = include_regex.replace_all(&preprocessed, |cap: &Captures| { - changed = true; - let filename = cap.get(1).unwrap().as_str(); - - let path = format!("tests/layouts/{}", filename); - let mut file = File::open(path).unwrap(); - let mut buf = String::new(); - file.read_to_string(&mut buf).unwrap(); - buf - }).to_string(); - } - - preprocessed= lorem_regex.replace_all(&preprocessed, |cap: &Captures| { - let num_str = cap.get(1).unwrap().as_str(); - let num_words = num_str.parse::().unwrap(); - - generate_lorem(num_words) - }).to_string(); - - preprocessed -} - -fn generate_lorem(num_words: usize) -> String { - const LOREM: [&str; 69] = [ - "Lorem", "ipsum", "dolor", "sit", "amet,", "consectetur", "adipiscing", "elit.", "Etiam", - "suscipit", "porta", "pretium.", "Donec", "eu", "lorem", "hendrerit,", "scelerisque", - "lectus", "at,", "consequat", "ligula.", "Nulla", "elementum", "massa", "et", "viverra", - "consectetur.", "Donec", "blandit", "metus", "ut", "ipsum", "commodo", "congue.", "Nullam", - "auctor,", "mi", "vel", "tristique", "venenatis,", "nisl", "nunc", "tristique", "diam,", - "aliquam", "pellentesque", "lorem", "massa", "vel", "neque.", "Sed", "malesuada", "ante", - "nisi,", "sit", "amet", "auctor", "risus", "fermentum", "in.", "Sed", "blandit", "mollis", - "mi,", "non", "tristique", "nisi", "fringilla", "at." - ]; - - let mut buf = String::new(); - for i in 0 .. num_words { - buf.push_str(LOREM[i % LOREM.len()]); - buf.push(' '); - } - buf -} diff --git a/tests/layouts/align.typ b/tests/layouts/align.typ deleted file mode 100644 index 9d6ab0033..000000000 --- a/tests/layouts/align.typ +++ /dev/null @@ -1,33 +0,0 @@ -[page.size: width=150pt, height=215pt] -[page.margins: 0pt] - -// ---------------------------------- // -// Without newline in between. -[align: left][Left: {lorem:20}] -[align: right][Right: {lorem:20}] - -// Over three pages. -[align: center][Center: {lorem:80}] - -// Over multiple pages after the pervious 3-page run. -[align: left][Left: {lorem:80}] - -[page.break] - -// ---------------------------------- // -// Context-modifying align. -[align: right] - -Context Right: {lorem:10} - -[align: left][In-between Left] - -Right Again: {lorem:10} - -// Reset context-modifier. -[align: left] - -[page.break] - -// ---------------------------------- // -All in one line: {lorem:25} [align: right] {lorem:50} [align: left] {lorem:15} diff --git a/tests/layouts/lines.typ b/tests/layouts/lines.typ new file mode 100644 index 000000000..705de6389 --- /dev/null +++ b/tests/layouts/lines.typ @@ -0,0 +1,14 @@ +[page.size: height=5cm] + +Line. + +[box][ + Lines with [box][two] [box][boxes]. + + Lines with two boxes. +] +[box][ + Lines without two boxes. + + Lines without two boxes. +] diff --git a/tests/layouts/pagebreaks.typ b/tests/layouts/pagebreaks.typ deleted file mode 100644 index 4d3c1843e..000000000 --- a/tests/layouts/pagebreaks.typ +++ /dev/null @@ -1,12 +0,0 @@ -[page.size: width=150pt, height=200pt] -[page.margins: 0pt] - -{lorem:100} - -[page.break] -[page.break] - -{lorem:20} -[page.break] - -{lorem:150} diff --git a/tests/layouts/shakespeare.tpl b/tests/layouts/shakespeare.tpl deleted file mode 100644 index e08393025..000000000 --- a/tests/layouts/shakespeare.tpl +++ /dev/null @@ -1,86 +0,0 @@ -[bold][Scene 5: _The Tower of London_] - -[italic][Enter Mortimer, brought in a chair, and Gaolers.] - -*Mortimer.* Kind keepers of my weak decaying age, - Let dying Mortimer here rest himself. - Even like a man new haled from the rack, - So fare my limbs with long imprisonment; - And these grey locks, the pursuivants of death, - Nestor-like aged in an age of care, - Argue the end of Edmund Mortimer. - These eyes, like lamps whose wasting oil is spent, - Wax dim, as drawing to their exigent; - Weak shoulders, overborne with burdening grief, - And pithless arms, like to a withered vine - That droops his sapless branches to the ground. - Yet are these feet, whose strengthless stay is numb, - Unable to support this lump of clay, - Swift-winged with desire to get a grave, - As witting I no other comfort have. - But tell me, keeper, will my nephew come? - -*First Keeper.* Richard Plantagenet, my lord, will come. - We sent unto the Temple, unto his chamber; - And answer was return'd that he will come. - -*Mortimer.* Enough; my soul shall then be satisfied. - Poor gentleman! his wrong doth equal mine. - Since Henry Monmouth first began to reign, - Before whose glory I was great in arms, - This loathsome sequestration have I had; - And even since then hath Richard been obscur'd, - Depriv'd of honour and inheritance. - But now the arbitrator of despairs, - Just Death, kind umpire of men's miseries, - With sweet enlargement doth dismiss me hence. - I would his troubles likewise were expir'd, - That so he might recover what was lost. - - -[italic][Enter Richard Plantagenet] - -*First Keeper.* My lord, your loving nephew now is come. - -*Mortimer.* Richard Plantagenet, my friend, is he come? - -*Plantagenet.* Ay, noble uncle, thus ignobly us'd, - Your nephew, late despised Richard, comes. - -*Mortimer.* Direct mine arms I may embrace his neck - And in his bosom spend my latter gasp. - O, tell me when my lips do touch his cheeks, - That I may kindly give one fainting kiss. - And now declare, sweet stem from York's great stock, - Why didst thou say of late thou wert despis'd? - -*Plantagenet.* First, lean thine aged back against mine arm; - And, in that ease, I'll tell thee my disease. - This day, in argument upon a case, - Some words there grew 'twixt Somerset and me; - Among which terms he us'd his lavish tongue - And did upbraid me with my father's death; - Which obloquy set bars before my tongue, - Else with the like I had requited him. - Therefore, good uncle, for my father's sake, - In honour of a true Plantagenet, - And for alliance sake, declare the cause - My father, Earl of Cambridge, lost his head. - -*Mortimer.* That cause, fair nephew, that imprison'd me - And hath detain'd me all my flow'ring youth - Within a loathsome dungeon, there to pine, - Was cursed instrument of his decease. - -*Plantagenet.* Discover more at large what cause that was, - For I am ignorant and cannot guess. - -*Mortimer.* I will, if that my fading breath permit - And death approach not ere my tale be done. - Henry the Fourth, grandfather to this king, - Depos'd his nephew Richard, Edward's son, - The first-begotten and the lawful heir - Of Edward king, the third of that descent; - During whose reign the Percies of the north, - Finding his usurpation most unjust, - Endeavour'd my advancement to the throne ... diff --git a/tests/layouts/shakespeare.typ b/tests/layouts/shakespeare.typ deleted file mode 100644 index 8cffb9304..000000000 --- a/tests/layouts/shakespeare.typ +++ /dev/null @@ -1,3 +0,0 @@ -[align: center][{include:shakespeare.tpl}] [page.break] -[align: left][{include:shakespeare.tpl}] [page.break] -[align: right][{include:shakespeare.tpl}] diff --git a/tests/layouts/styles.typ b/tests/layouts/styles.typ deleted file mode 100644 index 637450268..000000000 --- a/tests/layouts/styles.typ +++ /dev/null @@ -1,24 +0,0 @@ -[page.size: width=250pt, height=300pt] -[page.margins: 10pt] - -_Emoji:_ Hello World! 🌍 - -_Styles:_ This is made *bold*, that _italic_ and this one `monospace` using the -built-in syntax! - -_Styles with functions:_ This [bold][word] is made bold and [italic][that] italic -using the standard library functions `bold` and `italic`! - -[italic] -Styles can also be changed through context modification. -This works basically in the same way as the built-in syntax. -[italic] - -This is not italic anymore. 😀 - -[box][ - [italic] - Styles are scoped by boxes. -] - -Outside of the box: No effect. diff --git a/tests/render.py b/tests/render.py index 1c2cf7c4d..81dd6a4eb 100644 --- a/tests/render.py +++ b/tests/render.py @@ -7,14 +7,14 @@ from PIL import Image, ImageDraw, ImageFont BASE = os.path.dirname(__file__) -CACHE_DIR = os.path.join(BASE, "cache/"); +CACHE_DIR = os.path.join(BASE, "cache/") def main(): assert len(sys.argv) == 2, "usage: python render.py " name = sys.argv[1] - filename = os.path.join(CACHE_DIR, f"serialized/{name}.lay") + filename = os.path.join(CACHE_DIR, f"serialized/{name}.tld") with open(filename, encoding="utf-8") as file: lines = [line[:-1] for line in file.readlines()] @@ -99,17 +99,18 @@ class BoxRenderer: def __init__(self, fonts, width, height): self.fonts = fonts self.size = (pix(width), pix(height)) - self.img = Image.new("RGBA", self.size, (255, 255, 255, 255)) + + img = Image.new("RGBA", self.size, (255, 255, 255, 255)) + pixels = numpy.array(img) + for i in range(0, int(height)): + for j in range(0, int(width)): + if ((i // 2) % 2 == 0) == ((j // 2) % 2 == 0): + pixels[4*i:4*(i+1), 4*j:4*(j+1)] = (225, 225, 225, 255) + + self.img = Image.fromarray(pixels, "RGBA") self.draw = ImageDraw.Draw(self.img) self.cursor = (0, 0) - pixels = numpy.array(self.img) - for i in range(0, int(height)): - for j in range(0 if i % 2 == 0 else 1, int(width), 2): - pixels[4*i:4*(i+1), 4*j:4*(j+1)] = (200, 200, 200, 255) - - self.img = Image.fromarray(pixels) - self.colors = [ (176, 264, 158), (274, 173, 207), @@ -143,7 +144,7 @@ class BoxRenderer: elif cmd == 'b': x, y, w, h = (pix(float(s)) for s in parts) - rect = [x, y, x+w, y+h] + rect = [x, y, x+w-1, y+h-1] forbidden_colors = set() for other_rect, other_color in self.rects: