diff options
| author | Laurenz <laurmaedje@gmail.com> | 2024-04-13 10:39:45 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-04-13 08:39:45 +0000 |
| commit | 020294fca9a7065d4b9cf4e677f606ebaaa29b00 (patch) | |
| tree | c0027ad22046e2726c22298461327823d6b88d53 /tests/suite/visualize | |
| parent | 72dd79210602ecc799726fc096b078afbb47f299 (diff) | |
Better test runner (#3922)
Diffstat (limited to 'tests/suite/visualize')
| -rw-r--r-- | tests/suite/visualize/circle.typ | 69 | ||||
| -rw-r--r-- | tests/suite/visualize/color.typ | 331 | ||||
| -rw-r--r-- | tests/suite/visualize/ellipse.typ | 31 | ||||
| -rw-r--r-- | tests/suite/visualize/gradient.typ | 631 | ||||
| -rw-r--r-- | tests/suite/visualize/image.typ | 122 | ||||
| -rw-r--r-- | tests/suite/visualize/line.typ | 92 | ||||
| -rw-r--r-- | tests/suite/visualize/path.typ | 52 | ||||
| -rw-r--r-- | tests/suite/visualize/pattern.typ | 131 | ||||
| -rw-r--r-- | tests/suite/visualize/polygon.typ | 51 | ||||
| -rw-r--r-- | tests/suite/visualize/rect.typ | 107 | ||||
| -rw-r--r-- | tests/suite/visualize/square.typ | 146 | ||||
| -rw-r--r-- | tests/suite/visualize/stroke.typ | 171 |
12 files changed, 1934 insertions, 0 deletions
diff --git a/tests/suite/visualize/circle.typ b/tests/suite/visualize/circle.typ new file mode 100644 index 00000000..43459eb5 --- /dev/null +++ b/tests/suite/visualize/circle.typ @@ -0,0 +1,69 @@ +// Test the `circle` function. + +--- circle --- +// Default circle. +#box(circle()) +#box(circle[Hey]) + +--- circle-auto-sizing --- +// Test auto sizing. +#set circle(inset: 0pt) + +Auto-sized circle. +#circle(fill: rgb("eb5278"), stroke: 2pt + black, + align(center + horizon)[But, soft!] +) + +Center-aligned rect in auto-sized circle. +#circle(fill: forest, stroke: conifer, + align(center + horizon, + rect(fill: conifer, inset: 5pt)[But, soft!] + ) +) + +Rect in auto-sized circle. +#circle(fill: forest, + rect(fill: conifer, stroke: white, inset: 4pt)[ + #set text(8pt) + But, soft! what light through yonder window breaks? + ] +) + +Expanded by height. +#circle(stroke: black, align(center)[A \ B \ C]) + +--- circle-directly-in-rect --- +// Ensure circle directly in rect works. +#rect(width: 40pt, height: 30pt, fill: forest, + circle(fill: conifer)) + +--- circle-relative-sizing --- +// Test relative sizing. +#set text(fill: white) +#show: rect.with(width: 100pt, height: 50pt, inset: 0pt, fill: rgb("aaa")) +#set align(center + horizon) +#stack( + dir: ltr, + spacing: 1fr, + 1fr, + circle(radius: 10pt, fill: eastern, [A]), // D=20pt + circle(height: 60%, fill: eastern, [B]), // D=30pt + circle(width: 20% + 20pt, fill: eastern, [C]), // D=40pt + 1fr, +) + +--- circle-radius-width-and-height --- +// Radius wins over width and height. +// Error: 23-34 unexpected argument: width +#circle(radius: 10pt, width: 50pt, height: 100pt, fill: eastern) + +--- circle-sizing-options --- +// Test different ways of sizing. +#set page(width: 120pt, height: 40pt) +#stack( + dir: ltr, + spacing: 2pt, + circle(radius: 5pt), + circle(width: 10%), + circle(height: 50%), +) diff --git a/tests/suite/visualize/color.typ b/tests/suite/visualize/color.typ new file mode 100644 index 00000000..6cf887a4 --- /dev/null +++ b/tests/suite/visualize/color.typ @@ -0,0 +1,331 @@ +// Test color modification methods. + +--- color-mix --- +// Compare both ways. +#test-repr(rgb(0%, 30.2%, 70.2%), rgb("004db3")) + +// Alpha channel. +#test(rgb(255, 0, 0, 50%), rgb("ff000080")) + +// Test color modification methods. +#test(rgb(25, 35, 45).lighten(10%), rgb(48, 57, 66)) +#test(rgb(40, 30, 20).darken(10%), rgb(36, 27, 18)) +#test(rgb("#133337").negate(space: rgb), rgb(236, 204, 200)) +#test(white.lighten(100%), white) + +// Color mixing, in Oklab space by default. +#test(rgb(color.mix(rgb("#ff0000"), rgb("#00ff00"))), rgb("#d0a800")) +#test(rgb(color.mix(rgb("#ff0000"), rgb("#00ff00"), space: oklab)), rgb("#d0a800")) +#test(rgb(color.mix(rgb("#ff0000"), rgb("#00ff00"), space: rgb)), rgb("#808000")) + +#test(rgb(color.mix(red, green, blue)), rgb("#909282")) +#test(rgb(color.mix(red, blue, green)), rgb("#909282")) +#test(rgb(color.mix(blue, red, green)), rgb("#909282")) + +// Mix with weights. +#test(rgb(color.mix((red, 50%), (green, 50%))), rgb("#c0983b")) +#test(rgb(color.mix((red, 0.5), (green, 0.5))), rgb("#c0983b")) +#test(rgb(color.mix((red, 5), (green, 5))), rgb("#c0983b")) +#test(rgb(color.mix((green, 5), (white, 0), (red, 5))), rgb("#c0983b")) +#test(color.mix((rgb("#aaff00"), 25%), (rgb("#aa00ff"), 75%), space: rgb), rgb("#aa40bf")) +#test(color.mix((rgb("#aaff00"), 50%), (rgb("#aa00ff"), 50%), space: rgb), rgb("#aa8080")) +#test(color.mix((rgb("#aaff00"), 75%), (rgb("#aa00ff"), 25%), space: rgb), rgb("#aabf40")) + +// Mix in hue-based space. +#test(rgb(color.mix(red, blue, space: color.hsl)), rgb("#c408ff")) +#test(rgb(color.mix((red, 50%), (blue, 100%), space: color.hsl)), rgb("#5100f8")) +// Error: 6-51 cannot mix more than two colors in a hue-based space +#rgb(color.mix(red, blue, white, space: color.hsl)) + +--- color-conversion --- +// Test color conversion method kinds +#test(rgb(rgb(10, 20, 30)).space(), rgb) +#test(color.linear-rgb(rgb(10, 20, 30)).space(), color.linear-rgb) +#test(oklab(rgb(10, 20, 30)).space(), oklab) +#test(oklch(rgb(10, 20, 30)).space(), oklch) +#test(color.hsl(rgb(10, 20, 30)).space(), color.hsl) +#test(color.hsv(rgb(10, 20, 30)).space(), color.hsv) +#test(cmyk(rgb(10, 20, 30)).space(), cmyk) +#test(luma(rgb(10, 20, 30)).space(), luma) + +#test(rgb(color.linear-rgb(10, 20, 30)).space(), rgb) +#test(color.linear-rgb(color.linear-rgb(10, 20, 30)).space(), color.linear-rgb) +#test(oklab(color.linear-rgb(10, 20, 30)).space(), oklab) +#test(oklch(color.linear-rgb(10, 20, 30)).space(), oklch) +#test(color.hsl(color.linear-rgb(10, 20, 30)).space(), color.hsl) +#test(color.hsv(color.linear-rgb(10, 20, 30)).space(), color.hsv) +#test(cmyk(color.linear-rgb(10, 20, 30)).space(), cmyk) +#test(luma(color.linear-rgb(10, 20, 30)).space(), luma) + +#test(rgb(oklab(10%, 20%, 30%)).space(), rgb) +#test(color.linear-rgb(oklab(10%, 20%, 30%)).space(), color.linear-rgb) +#test(oklab(oklab(10%, 20%, 30%)).space(), oklab) +#test(oklch(oklab(10%, 20%, 30%)).space(), oklch) +#test(color.hsl(oklab(10%, 20%, 30%)).space(), color.hsl) +#test(color.hsv(oklab(10%, 20%, 30%)).space(), color.hsv) +#test(cmyk(oklab(10%, 20%, 30%)).space(), cmyk) +#test(luma(oklab(10%, 20%, 30%)).space(), luma) + +#test(rgb(oklch(60%, 40%, 0deg)).space(), rgb) +#test(color.linear-rgb(oklch(60%, 40%, 0deg)).space(), color.linear-rgb) +#test(oklab(oklch(60%, 40%, 0deg)).space(), oklab) +#test(oklch(oklch(60%, 40%, 0deg)).space(), oklch) +#test(color.hsl(oklch(60%, 40%, 0deg)).space(), color.hsl) +#test(color.hsv(oklch(60%, 40%, 0deg)).space(), color.hsv) +#test(cmyk(oklch(60%, 40%, 0deg)).space(), cmyk) +#test(luma(oklch(60%, 40%, 0deg)).space(), luma) + +#test(rgb(color.hsl(10deg, 20%, 30%)).space(), rgb) +#test(color.linear-rgb(color.hsl(10deg, 20%, 30%)).space(), color.linear-rgb) +#test(oklab(color.hsl(10deg, 20%, 30%)).space(), oklab) +#test(oklch(color.hsl(10deg, 20%, 30%)).space(), oklch) +#test(color.hsl(color.hsl(10deg, 20%, 30%)).space(), color.hsl) +#test(color.hsv(color.hsl(10deg, 20%, 30%)).space(), color.hsv) +#test(cmyk(color.hsl(10deg, 20%, 30%)).space(), cmyk) +#test(luma(color.hsl(10deg, 20%, 30%)).space(), luma) + +#test(rgb(color.hsv(10deg, 20%, 30%)).space(), rgb) +#test(color.linear-rgb(color.hsv(10deg, 20%, 30%)).space(), color.linear-rgb) +#test(oklab(color.hsv(10deg, 20%, 30%)).space(), oklab) +#test(oklch(color.hsv(10deg, 20%, 30%)).space(), oklch) +#test(color.hsl(color.hsv(10deg, 20%, 30%)).space(), color.hsl) +#test(color.hsv(color.hsv(10deg, 20%, 30%)).space(), color.hsv) +#test(cmyk(color.hsv(10deg, 20%, 30%)).space(), cmyk) +#test(luma(color.hsv(10deg, 20%, 30%)).space(), luma) + +#test(rgb(cmyk(10%, 20%, 30%, 40%)).space(), rgb) +#test(color.linear-rgb(cmyk(10%, 20%, 30%, 40%)).space(), color.linear-rgb) +#test(oklab(cmyk(10%, 20%, 30%, 40%)).space(), oklab) +#test(oklch(cmyk(10%, 20%, 30%, 40%)).space(), oklch) +#test(color.hsl(cmyk(10%, 20%, 30%, 40%)).space(), color.hsl) +#test(color.hsv(cmyk(10%, 20%, 30%, 40%)).space(), color.hsv) +#test(cmyk(cmyk(10%, 20%, 30%, 40%)).space(), cmyk) +#test(luma(cmyk(10%, 20%, 30%, 40%)).space(), luma) + +#test(rgb(luma(10%)).space(), rgb) +#test(color.linear-rgb(luma(10%)).space(), color.linear-rgb) +#test(oklab(luma(10%)).space(), oklab) +#test(oklch(luma(10%)).space(), oklch) +#test(color.hsl(luma(10%)).space(), color.hsl) +#test(color.hsv(luma(10%)).space(), color.hsv) +#test(cmyk(luma(10%)).space(), cmyk) +#test(luma(luma(10%)).space(), luma) + +#test(rgb(1, 2, 3).to-hex(), "#010203") +#test(rgb(1, 2, 3, 4).to-hex(), "#01020304") +#test(luma(40).to-hex(), "#282828") +#test-repr(cmyk(4%, 5%, 6%, 7%).to-hex(), "#e0dcda") +#test-repr(rgb(cmyk(4%, 5%, 6%, 7%)), rgb(87.84%, 86.27%, 85.49%, 100%)) +#test-repr(rgb(luma(40%)), rgb(40%, 40%, 40%)) +#test-repr(cmyk(luma(40)), cmyk(11.76%, 10.67%, 10.51%, 14.12%)) +#test-repr(cmyk(rgb(1, 2, 3)), cmyk(66.67%, 33.33%, 0%, 98.82%)) +#test-repr(luma(rgb(1, 2, 3)), luma(0.73%)) +#test-repr(color.hsl(luma(40)), color.hsl(0deg, 0%, 15.69%)) +#test-repr(color.hsv(luma(40)), color.hsv(0deg, 0%, 15.69%)) +#test-repr(color.linear-rgb(luma(40)), color.linear-rgb(2.12%, 2.12%, 2.12%)) +#test-repr(color.linear-rgb(rgb(1, 2, 3)), color.linear-rgb(0.03%, 0.06%, 0.09%)) +#test-repr(color.hsl(rgb(1, 2, 3)), color.hsl(-150deg, 50%, 0.78%)) +#test-repr(color.hsv(rgb(1, 2, 3)), color.hsv(-150deg, 66.67%, 1.18%)) +#test-repr(oklab(luma(40)), oklab(27.68%, 0.0, 0.0, 100%)) +#test-repr(oklab(rgb(1, 2, 3)), oklab(8.23%, -0.004, -0.007, 100%)) +#test-repr(oklch(oklab(40%, 0.2, 0.2)), oklch(40%, 0.283, 45deg, 100%)) +#test-repr(oklch(luma(40)), oklch(27.68%, 0.0, 72.49deg, 100%)) +#test-repr(oklch(rgb(1, 2, 3)), oklch(8.23%, 0.008, 240.75deg, 100%)) + +--- color-spaces --- +// The the different color spaces +#let col = rgb(50%, 64%, 16%) +#box(square(size: 9pt, fill: col)) +#box(square(size: 9pt, fill: rgb(col))) +#box(square(size: 9pt, fill: oklab(col))) +#box(square(size: 9pt, fill: oklch(col))) +#box(square(size: 9pt, fill: luma(col))) +#box(square(size: 9pt, fill: cmyk(col))) +#box(square(size: 9pt, fill: color.linear-rgb(col))) +#box(square(size: 9pt, fill: color.hsl(col))) +#box(square(size: 9pt, fill: color.hsv(col))) + +--- color-space --- +// Test color kind method. +#test(rgb(1, 2, 3, 4).space(), rgb) +#test(cmyk(4%, 5%, 6%, 7%).space(), cmyk) +#test(luma(40).space(), luma) +#test(rgb(1, 2, 3, 4).space() != luma, true) + +--- color-components --- +// Test color '.components()' without conversions + +#let test-components(col, ref, has-alpha: true) = { + // Perform an approximate scalar comparison. + let are-equal((a, b)) = { + let to-float(x) = if type(x) == angle { x.rad() } else { float(x) } + let epsilon = 1e-4 // The maximum error between both numbers + assert.eq(type(a), type(b)) + calc.abs(to-float(a) - to-float(b)) < epsilon + } + + let ref-without-alpha = if has-alpha { ref.slice(0, -1) } else { ref } + assert.eq(col.components().len(), ref.len()) + assert(col.components().zip(ref).all(are-equal)) + assert(col.components(alpha: false).zip(ref-without-alpha).all(are-equal)) +} +#test-components(rgb(1, 2, 3, 4), (0.39%, 0.78%, 1.18%, 1.57%)) +#test-components(luma(40), (15.69%, 100%)) +#test-components(luma(40, 50%), (15.69%, 50%)) +#test-components(cmyk(4%, 5%, 6%, 7%), (4%, 5%, 6%, 7%), has-alpha: false) +#test-components(oklab(10%, 0.2, 0.4), (10%, 0.2, 0.4, 100%)) +#test-components(oklch(10%, 0.2, 90deg), (10%, 0.2, 90deg, 100%)) +#test-components(oklab(10%, 50%, 200%), (10%, 0.2, 0.8, 100%)) +#test-components(oklch(10%, 50%, 90deg), (10%, 0.2, 90deg, 100%)) +#test-components(color.linear-rgb(10%, 20%, 30%), (10%, 20%, 30%, 100%)) +#test-components(color.hsv(10deg, 20%, 30%), (10deg, 20%, 30%, 100%)) +#test-components(color.hsl(10deg, 20%, 30%), (10deg, 20%, 30%, 100%)) + +--- color-luma --- +// Test gray color conversion. +#stack(dir: ltr, rect(fill: luma(0)), rect(fill: luma(80%))) + +--- color-rgb-out-of-range --- +// Error for values that are out of range. +// Error: 11-14 number must be between 0 and 255 +#test(rgb(-30, 15, 50)) + +--- color-rgb-bad-string --- +// Error: 6-11 color string contains non-hexadecimal letters +#rgb("lol") + +--- color-rgb-missing-argument-red --- +// Error: 2-7 missing argument: red component +#rgb() + +--- color-rgb-missing-argument-blue --- +// Error: 2-11 missing argument: blue component +#rgb(0, 1) + +--- color-rgb-bad-type --- +// Error: 21-26 expected integer or ratio, found boolean +#rgb(10%, 20%, 30%, false) + +--- color-luma-unexpected-argument --- +// Error: 10-20 unexpected argument: key +#luma(1, key: "val") + +--- color-mix-bad-amount-type --- +// Error: 12-24 expected float or ratio, found string +// Error: 26-39 expected float or ratio, found string +#color.mix((red, "yes"), (green, "no"), (green, 10%)) + +--- color-mix-bad-value --- +// Error: 12-23 expected a color or color-weight pair +#color.mix((red, 1, 2)) + +--- color-mix-bad-space-type --- +// Error: 31-38 expected `rgb`, `luma`, `cmyk`, `oklab`, `oklch`, `color.linear-rgb`, `color.hsl`, or `color.hsv`, found string +#color.mix(red, green, space: "cyber") + +--- color-mix-bad-space-value-1 --- +// Error: 31-36 expected `rgb`, `luma`, `cmyk`, `oklab`, `oklch`, `color.linear-rgb`, `color.hsl`, or `color.hsv` +#color.mix(red, green, space: image) + +--- color-mix-bad-space-value-2 --- +// Error: 31-41 expected `rgb`, `luma`, `cmyk`, `oklab`, `oklch`, `color.linear-rgb`, `color.hsl`, or `color.hsv` +#color.mix(red, green, space: calc.round) + +--- color-cmyk-ops --- +// Test CMYK color conversion. +#let c = cmyk(50%, 64%, 16%, 17%) +#stack( + dir: ltr, + spacing: 1fr, + rect(width: 1cm, fill: cmyk(69%, 11%, 69%, 41%)), + rect(width: 1cm, fill: c), + rect(width: 1cm, fill: c.negate(space: cmyk)), +) + +#for x in range(0, 11) { + box(square(size: 9pt, fill: c.lighten(x * 10%))) +} +#for x in range(0, 11) { + box(square(size: 9pt, fill: c.darken(x * 10%))) +} + +--- color-outside-srgb-gamut --- +// Colors outside the sRGB gamut. +#box(square(size: 9pt, fill: oklab(90%, -0.2, -0.1))) +#box(square(size: 9pt, fill: oklch(50%, 0.5, 0deg))) + +--- color-rotate-hue --- +// Test hue rotation +#let col = rgb(50%, 64%, 16%) + +// Oklch +#for x in range(0, 11) { + box(square(size: 9pt, fill: rgb(col).rotate(x * 36deg))) +} + +// HSL +#for x in range(0, 11) { + box(square(size: 9pt, fill: rgb(col).rotate(x * 36deg, space: color.hsl))) +} + +// HSV +#for x in range(0, 11) { + box(square(size: 9pt, fill: rgb(col).rotate(x * 36deg, space: color.hsv))) +} + +--- color-saturation --- +// Test saturation +#let col = color.hsl(180deg, 0%, 50%) +#for x in range(0, 11) { + box(square(size: 9pt, fill: col.saturate(x * 10%))) +} + +#let col = color.hsl(180deg, 100%, 50%) +#for x in range(0, 11) { + box(square(size: 9pt, fill: col.desaturate(x * 10%))) +} + +#let col = color.hsv(180deg, 0%, 50%) +#for x in range(0, 11) { + box(square(size: 9pt, fill: col.saturate(x * 10%))) +} + +#let col = color.hsv(180deg, 100%, 50%) +#for x in range(0, 11) { + box(square(size: 9pt, fill: col.desaturate(x * 10%))) +} + +--- color-luma-ops --- +// Test gray color modification. +#test-repr(luma(20%).lighten(50%), luma(60%)) +#test-repr(luma(80%).darken(20%), luma(64%)) +#test-repr(luma(80%).negate(space: luma), luma(20%)) + +--- color-transparentize --- +// Test alpha modification. +#test-repr(luma(100%, 100%).transparentize(50%), luma(100%, 50%)) +#test-repr(luma(100%, 100%).transparentize(75%), luma(100%, 25%)) +#test-repr(luma(100%, 50%).transparentize(50%), luma(100%, 25%)) +#test-repr(luma(100%, 10%).transparentize(250%), luma(100%, 0%)) +#test-repr(luma(100%, 40%).transparentize(-50%), luma(100%, 70%)) +#test-repr(luma(100%, 0%).transparentize(-100%), luma(100%, 100%)) + +--- color-opacify --- +#test-repr(luma(100%, 50%).opacify(50%), luma(100%, 75%)) +#test-repr(luma(100%, 20%).opacify(100%), luma(100%, 100%)) +#test-repr(luma(100%, 100%).opacify(250%), luma(100%, 100%)) +#test-repr(luma(100%, 50%).opacify(-50%), luma(100%, 25%)) +#test-repr(luma(100%, 0%).opacify(0%), luma(100%, 0%)) + +--- repr-color --- +// Colors +#set page(width: 400pt) +#set text(0.8em) +#blue \ +#color.linear-rgb(blue) \ +#oklab(blue) \ +#oklch(blue) \ +#cmyk(blue) \ +#color.hsl(blue) \ +#color.hsv(blue) \ +#luma(blue) diff --git a/tests/suite/visualize/ellipse.typ b/tests/suite/visualize/ellipse.typ new file mode 100644 index 00000000..970a795e --- /dev/null +++ b/tests/suite/visualize/ellipse.typ @@ -0,0 +1,31 @@ +// Test the `ellipse` function. + +--- ellipse --- +// Default ellipse. +#ellipse() + +--- ellipse-auto-sizing --- +#set rect(inset: 0pt) +#set ellipse(inset: 0pt) + +Rect in ellipse in fixed rect. +#rect(width: 3cm, height: 2cm, fill: rgb("2a631a"), + ellipse(fill: forest, width: 100%, height: 100%, + rect(fill: conifer, width: 100%, height: 100%, + align(center + horizon)[ + Stuff inside an ellipse! + ] + ) + ) +) + +Auto-sized ellipse. +#ellipse(fill: conifer, stroke: 3pt + forest, inset: 3pt)[ + #set text(8pt) + But, soft! what light through yonder window breaks? +] + + +An inline +#box(ellipse(width: 8pt, height: 6pt, outset: (top: 3pt, rest: 5.5pt))) +ellipse. diff --git a/tests/suite/visualize/gradient.typ b/tests/suite/visualize/gradient.typ new file mode 100644 index 00000000..1ee5489a --- /dev/null +++ b/tests/suite/visualize/gradient.typ @@ -0,0 +1,631 @@ +--- gradient-linear-angled --- +// Test gradients with direction. +#set page(width: 90pt) +#grid( + gutter: 3pt, + columns: 4, + ..range(0, 360, step: 15).map(i => box( + height: 15pt, + width: 15pt, + fill: gradient.linear(angle: i * 1deg, (red, 0%), (blue, 100%)), + )) +) + + +--- gradient-linear-oklab --- +// The tests below test whether hue rotation works correctly. +// Here we test in Oklab space for reference. +#set page( + width: 100pt, + height: 30pt, + fill: gradient.linear(red, purple, space: oklab) +) + +--- gradient-linear-oklch --- +// Test in OkLCH space. +#set page( + width: 100pt, + height: 30pt, + fill: gradient.linear(red, purple, space: oklch) +) + +--- gradient-linear-hsv --- +// Test in HSV space. +#set page( + width: 100pt, + height: 30pt, + fill: gradient.linear(red, purple, space: color.hsv) +) + +--- gradient-linear-hsl --- +// Test in HSL space. +#set page( + width: 100pt, + height: 30pt, + fill: gradient.linear(red, purple, space: color.hsl) +) + + +--- gradient-linear-relative-parent --- +// The image should look as if there is a single gradient that is being used for +// both the page and the rectangles. +#let grad = gradient.linear(red, blue, green, purple, relative: "parent"); +#let my-rect = rect(width: 50%, height: 50%, fill: grad) +#set page( + height: 50pt, + width: 50pt, + margin: 2.5pt, + fill: grad, + background: place(top + left, my-rect), +) +#place(top + right, my-rect) +#place(bottom + center, rotate(45deg, my-rect)) + +--- gradient-linear-relative-self --- +// The image should look as if there are multiple gradients, one for each +// rectangle. +#let grad = gradient.linear(red, blue, green, purple, relative: "self"); +#let my-rect = rect(width: 50%, height: 50%, fill: grad) +#set page( + height: 50pt, + width: 50pt, + margin: 2.5pt, + fill: grad, + background: place(top + left, my-rect), +) +#place(top + right, my-rect) +#place(bottom + center, rotate(45deg, my-rect)) + +--- gradient-linear-repeat-and-mirror-1 --- +// Test repeated gradients. +#rect( + height: 40pt, + width: 100%, + fill: gradient.linear(..color.map.inferno).repeat(2, mirror: true) +) + +--- gradient-linear-repeat-and-mirror-2 --- +#rect( + height: 40pt, + width: 100%, + fill: gradient.linear(..color.map.rainbow).repeat(2, mirror: true), +) + +--- gradient-linear-repeat-and-mirror-3 --- +#rect( + height: 40pt, + width: 100%, + fill: gradient.linear(..color.map.rainbow).repeat(5, mirror: true) +) + +--- gradient-linear-sharp-and-repeat --- +#rect( + height: 40pt, + width: 100%, + fill: gradient.linear(..color.map.rainbow).sharp(10).repeat(5, mirror: false) +) + +--- gradient-linear-sharp-repeat-and-mirror --- +#rect( + height: 40pt, + width: 100%, + fill: gradient.linear(..color.map.rainbow).sharp(10).repeat(5, mirror: true) +) + +--- gradient-linear-sharp --- +#square( + size: 100pt, + fill: gradient.linear(..color.map.rainbow, space: color.hsl).sharp(10), +) +#square( + size: 100pt, + fill: gradient.radial(..color.map.rainbow, space: color.hsl).sharp(10), +) +#square( + size: 100pt, + fill: gradient.conic(..color.map.rainbow, space: color.hsl).sharp(10), +) + +--- gradient-linear-sharp-and-smooth --- +#square( + size: 100pt, + fill: gradient.linear(..color.map.rainbow, space: color.hsl).sharp(10, smoothness: 40%), +) +#square( + size: 100pt, + fill: gradient.radial(..color.map.rainbow, space: color.hsl).sharp(10, smoothness: 40%), +) +#square( + size: 100pt, + fill: gradient.conic(..color.map.rainbow, space: color.hsl).sharp(10, smoothness: 40%), +) + +--- gradient-linear-stroke --- +#align(center + top, square(size: 50pt, fill: black, stroke: 5pt + gradient.linear(red, blue))) + +--- gradient-fill-and-stroke --- +#align( + center + bottom, + square( + size: 50pt, + fill: gradient.radial(red, blue, radius: 70.7%, focal-center: (10%, 10%)), + stroke: 10pt + gradient.radial(red, blue, radius: 70.7%, focal-center: (10%, 10%)) + ) +) + +--- gradient-linear-line --- +// Test gradient on lines +#set page(width: 100pt, height: 100pt) +#line(length: 100%, stroke: 1pt + gradient.linear(red, blue)) +#line(length: 100%, angle: 10deg, stroke: 1pt + gradient.linear(red, blue)) +#line(length: 100%, angle: 10deg, stroke: 1pt + gradient.linear(red, blue, relative: "parent")) + +--- gradient-radial-hsl --- +#square( + size: 100pt, + fill: gradient.radial(..color.map.rainbow, space: color.hsl), +) + +--- gradient-radial-center --- +#grid( + columns: 2, + square( + size: 50pt, + fill: gradient.radial(..color.map.rainbow, space: color.hsl, center: (0%, 0%)), + ), + square( + size: 50pt, + fill: gradient.radial(..color.map.rainbow, space: color.hsl, center: (0%, 100%)), + ), + square( + size: 50pt, + fill: gradient.radial(..color.map.rainbow, space: color.hsl, center: (100%, 0%)), + ), + square( + size: 50pt, + fill: gradient.radial(..color.map.rainbow, space: color.hsl, center: (100%, 100%)), + ), +) + +--- gradient-radial-radius --- +#square( + size: 50pt, + fill: gradient.radial(..color.map.rainbow, space: color.hsl, radius: 10%), +) +#square( + size: 50pt, + fill: gradient.radial(..color.map.rainbow, space: color.hsl, radius: 72%), +) + +--- gradient-radial-focal-center-and-radius --- +#circle( + radius: 25pt, + fill: gradient.radial(white, rgb("#8fbc8f"), focal-center: (35%, 35%), focal-radius: 5%), +) +#circle( + radius: 25pt, + fill: gradient.radial(white, rgb("#8fbc8f"), focal-center: (75%, 35%), focal-radius: 5%), +) + +--- gradient-radial-relative-parent --- +// The image should look as if there is a single gradient that is being used for +// both the page and the rectangles. +#let grad = gradient.radial(red, blue, green, purple, relative: "parent"); +#let my-rect = rect(width: 50%, height: 50%, fill: grad) +#set page( + height: 50pt, + width: 50pt, + margin: 2.5pt, + fill: grad, + background: place(top + left, my-rect), +) +#place(top + right, my-rect) +#place(bottom + center, rotate(45deg, my-rect)) + +--- gradient-radial-relative-self --- +// The image should look as if there are multiple gradients, one for each +// rectangle. +#let grad = gradient.radial(red, blue, green, purple, relative: "self"); +#let my-rect = rect(width: 50%, height: 50%, fill: grad) +#set page( + height: 50pt, + width: 50pt, + margin: 2.5pt, + fill: grad, + background: place(top + left, my-rect), +) +#place(top + right, my-rect) +#place(bottom + center, rotate(45deg, my-rect)) + +--- gradient-radial-text --- +// Test that gradient fills on text. +// The solid bar gradients are used to make sure that all transforms are +// correct: if you can see the text through the bar, then the gradient is +// misaligned to its reference container. +#set page(width: 200pt, height: auto, margin: 10pt) +#set par(justify: true) +#set text(fill: gradient.radial(red, blue)) +#lorem(30) + +--- gradient-conic --- +#square( + size: 50pt, + fill: gradient.conic(..color.map.rainbow, space: color.hsv), +) + +--- gradient-conic-center-shifted-1 --- +#square( + size: 50pt, + fill: gradient.conic(..color.map.rainbow, space: color.hsv, center: (10%, 10%)), +) + +--- gradient-conic-center-shifted-2 --- +#square( + size: 50pt, + fill: gradient.conic(..color.map.rainbow, space: color.hsv, center: (90%, 90%)), +) + +--- gradient-conic-angled --- +#square( + size: 50pt, + fill: gradient.conic(..color.map.rainbow, space: color.hsv, angle: 90deg), +) + +--- gradient-conic-oklab --- +// Test in Oklab space for reference. +#set page( + width: 100pt, + height: 100pt, + fill: gradient.conic(red, purple, space: oklab) +) + +--- gradient-conic-oklch --- +// Test in OkLCH space. +#set page( + width: 100pt, + height: 100pt, + fill: gradient.conic(red, purple, space: oklch) +) + +--- gradient-conic-hsv --- +// Test in HSV space. +#set page( + width: 100pt, + height: 100pt, + fill: gradient.conic(red, purple, space: color.hsv) +) + +--- gradient-conic-hsl --- +// Test in HSL space. +#set page( + width: 100pt, + height: 100pt, + fill: gradient.conic(red, purple, space: color.hsl) +) + +--- gradient-conic-relative-parent --- +// The image should look as if there is a single gradient that is being used for +// both the page and the rectangles. +#let grad = gradient.conic(red, blue, green, purple, relative: "parent"); +#let my-rect = rect(width: 50%, height: 50%, fill: grad) +#set page( + height: 50pt, + width: 50pt, + margin: 2.5pt, + fill: grad, + background: place(top + left, my-rect), +) +#place(top + right, my-rect) +#place(bottom + center, rotate(45deg, my-rect)) + +--- gradient-conic-relative-self --- +// The image should look as if there are multiple gradients, one for each +// rectangle. +#let grad = gradient.conic(red, blue, green, purple, relative: "self"); +#let my-rect = rect(width: 50%, height: 50%, fill: grad) +#set page( + height: 50pt, + width: 50pt, + margin: 2.5pt, + fill: grad, + background: place(top + left, my-rect), +) +#place(top + right, my-rect) +#place(bottom + center, rotate(45deg, my-rect)) + +--- gradient-conic-stroke --- +#align( + center + bottom, + square( + size: 50pt, + fill: black, + stroke: 10pt + gradient.conic(red, blue) + ) +) + +--- gradient-conic-text --- +#set page(width: 200pt, height: auto, margin: 10pt) +#set par(justify: true) +#set text(fill: gradient.conic(red, blue, angle: 45deg)) +#lorem(30) + +--- gradient-text-bad-relative --- +// Make sure they don't work when `relative: "self"`. +// Hint: 17-61 make sure to set `relative: auto` on your text fill +// Error: 17-61 gradients and patterns on text must be relative to the parent +#set text(fill: gradient.linear(red, blue, relative: "self")) + +--- gradient-text-global --- +// Test that gradient fills on text work for globally defined gradients. +#set page(width: 200pt, height: auto, margin: 10pt, background: { + rect(width: 100%, height: 30pt, fill: gradient.linear(red, blue)) +}) +#set par(justify: true) +#set text(fill: gradient.linear(red, blue)) +#lorem(30) + +--- gradient-text-dir --- +// Sanity check that the direction works on text. +#set page(width: 200pt, height: auto, margin: 10pt, background: { + rect(height: 100%, width: 30pt, fill: gradient.linear(dir: btt, red, blue)) +}) +#set par(justify: true) +#set text(fill: gradient.linear(dir: btt, red, blue)) +#lorem(30) + +--- gradient-text-in-container --- +// Test that gradient fills on text work for locally defined gradients. +#set page(width: auto, height: auto, margin: 10pt) +#show box: set text(fill: gradient.linear(..color.map.rainbow)) +Hello, #box[World]! + +--- gradient-text-rotate --- +// Test that gradients fills on text work with transforms. +#set page(width: auto, height: auto, margin: 10pt) +#show box: set text(fill: gradient.linear(..color.map.rainbow)) +#rotate(45deg, box[World]) + +--- gradient-text-decoration --- +#set text(fill: gradient.linear(red, blue)) + +Hello #underline[World]! \ +Hello #overline[World]! \ +Hello #strike[World]! \ + +--- gradient-transformed --- +// Test whether gradients work well when they are contained within a transform. +#let grad = gradient.linear(red, blue, green, purple, relative: "parent"); +#let my-rect = rect(width: 50pt, height: 50pt, fill: grad) +#set page( + height: 50pt, + width: 50pt, + margin: 2.5pt, +) +#place(top + right, scale(x: 200%, y: 130%, my-rect)) +#place(bottom + center, rotate(45deg, my-rect)) +#place(horizon + center, scale(x: 200%, y: 130%, rotate(45deg, my-rect))) + +--- gradient-presets --- +// Test all gradient presets. +#set page(width: 100pt, height: auto, margin: 0pt) +#set text(fill: white, size: 18pt) +#set text(top-edge: "bounds", bottom-edge: "bounds") + +#let presets = ( + ("turbo", color.map.turbo), + ("cividis", color.map.cividis), + ("rainbow", color.map.rainbow), + ("spectral", color.map.spectral), + ("viridis", color.map.viridis), + ("inferno", color.map.inferno), + ("magma", color.map.magma), + ("plasma", color.map.plasma), + ("rocket", color.map.rocket), + ("mako", color.map.mako), + ("vlag", color.map.vlag), + ("icefire", color.map.icefire), + ("flare", color.map.flare), + ("crest", color.map.crest), +) + +#stack( + spacing: 3pt, + ..presets.map(((name, preset)) => block( + width: 100%, + height: 20pt, + fill: gradient.linear(..preset), + align(center + horizon, smallcaps(name)), + )) +) + +// Test that gradients are applied correctly on equations. + +--- gradient-math-cancel --- +// Test on cancel +#show math.equation: set text(fill: gradient.linear(..color.map.rainbow)) +#show math.equation: box + +$ a dot cancel(5) = cancel(25) 5 x + cancel(5) 1 $ + +--- gradient-math-frac --- +// Test on frac +#show math.equation: set text(fill: gradient.linear(..color.map.rainbow)) +#show math.equation: box + +$ nabla dot bold(E) = frac(rho, epsilon_0) $ + +--- gradient-math-root --- +// Test on root +#show math.equation: set text(fill: gradient.linear(..color.map.rainbow)) +#show math.equation: box + +$ x_"1,2" = frac(-b +- sqrt(b^2 - 4 a c), 2 a) $ + +--- gradient-math-mat --- +// Test on matrix +#show math.equation: set text(fill: gradient.linear(..color.map.rainbow)) +#show math.equation: box + +$ A = mat( + 1, 2, 3; + 4, 5, 6; + 7, 8, 9 +) $ + +--- gradient-math-underover --- +// Test on underover +#show math.equation: set text(fill: gradient.linear(..color.map.rainbow)) +#show math.equation: box + +$ underline(X^2) $ +$ overline("hello, world!") $ + +--- gradient-math-dir --- +// Test a different direction +#show math.equation: set text(fill: gradient.linear(..color.map.rainbow, dir: ttb)) +#show math.equation: box + +$ A = mat( + 1, 2, 3; + 4, 5, 6; + 7, 8, 9 +) $ + +$ x_"1,2" = frac(-b +- sqrt(b^2 - 4 a c), 2 a) $ + +--- gradient-math-misc --- +// Test miscellaneous +#show math.equation: set text(fill: gradient.linear(..color.map.rainbow)) +#show math.equation: box + +$ hat(x) = bar x bar = vec(x, y, z) = tilde(x) = dot(x) $ +$ x prime = vec(1, 2, delim: "[") $ +$ sum_(i in NN) 1 + i $ +$ attach( + Pi, t: alpha, b: beta, + tl: 1, tr: 2+3, bl: 4+5, br: 6, +) $ + +--- gradient-math-radial --- +// Test radial gradient +#show math.equation: set text(fill: gradient.radial(..color.map.rainbow, center: (30%, 30%))) +#show math.equation: box + +$ A = mat( + 1, 2, 3; + 4, 5, 6; + 7, 8, 9 +) $ + +--- gradient-math-conic --- +// Test conic gradient +#show math.equation: set text(fill: gradient.conic(red, blue, angle: 45deg)) +#show math.equation: box + +$ A = mat( + 1, 2, 3; + 4, 5, 6; + 7, 8, 9 +) $ + + +--- gradient-kind --- +// Test gradient functions. +#test(gradient.linear(red, green, blue).kind(), gradient.linear) + +--- gradient-stops --- +#test(gradient.linear(red, green, blue).stops(), ((red, 0%), (green, 50%), (blue, 100%))) + +--- gradient-sample --- +#test(gradient.linear(red, green, blue, space: rgb).sample(0%), red) +#test(gradient.linear(red, green, blue, space: rgb).sample(25%), rgb("#97873b")) +#test(gradient.linear(red, green, blue, space: rgb).sample(50%), green) +#test(gradient.linear(red, green, blue, space: rgb).sample(75%), rgb("#17a08c")) +#test(gradient.linear(red, green, blue, space: rgb).sample(100%), blue) + +--- gradient-space --- +#test(gradient.linear(red, green, space: rgb).space(), rgb) +#test(gradient.linear(red, green, space: oklab).space(), oklab) +#test(gradient.linear(red, green, space: oklch).space(), oklch) +#test(gradient.linear(red, green, space: cmyk).space(), cmyk) +#test(gradient.linear(red, green, space: luma).space(), luma) +#test(gradient.linear(red, green, space: color.linear-rgb).space(), color.linear-rgb) +#test(gradient.linear(red, green, space: color.hsl).space(), color.hsl) +#test(gradient.linear(red, green, space: color.hsv).space(), color.hsv) + +--- gradient-relative --- +#test(gradient.linear(red, green, relative: "self").relative(), "self") +#test(gradient.linear(red, green, relative: "parent").relative(), "parent") +#test(gradient.linear(red, green).relative(), auto) + +--- gradient-angle --- +#test(gradient.linear(red, green).angle(), 0deg) +#test(gradient.linear(red, green, dir: ltr).angle(), 0deg) +#test(gradient.linear(red, green, dir: rtl).angle(), 180deg) +#test(gradient.linear(red, green, dir: ttb).angle(), 90deg) +#test(gradient.linear(red, green, dir: btt).angle(), 270deg) + +--- gradient-repeat --- +#test( + gradient.linear(red, green, blue).repeat(2).stops(), + ((red, 0%), (green, 25%), (blue, 50%), (red, 50%), (green, 75%), (blue, 100%)) +) +#test( + gradient.linear(red, green, blue).repeat(2, mirror: true).stops(), + ((red, 0%), (green, 25%), (blue, 50%), (green, 75%), (red, 100%)) +) + +--- gradient-repr --- +// Gradients +#set page(width: 400pt) +#set text(0.8em) +#gradient.linear(blue, red) \ +#gradient.linear(blue, red, dir: ttb) \ +#gradient.linear(blue, red, angle: 45deg, relative: "self") \ +#gradient.linear(blue, red, angle: 45deg, space: rgb) + +--- issue-2902-gradient-oklch-panic --- +// Minimal reproduction of #2902 +#set page(width: 15cm, height: auto, margin: 1em) +#set block(width: 100%, height: 1cm, above: 2pt) + +// Oklch +#block(fill: gradient.linear(red, purple, space: oklch)) +#block(fill: gradient.linear(..color.map.rainbow, space: oklch)) +#block(fill: gradient.linear(..color.map.plasma, space: oklch)) + +--- issue-2902-gradient-oklab-panic --- +#set page(width: 15cm, height: auto, margin: 1em) +#set block(width: 100%, height: 1cm, above: 2pt) + +// Oklab +#block(fill: gradient.linear(red, purple, space: oklab)) +#block(fill: gradient.linear(..color.map.rainbow, space: oklab)) +#block(fill: gradient.linear(..color.map.plasma, space: oklab)) + +--- issue-gradient-cmyk-encode --- +// Test that CMYK works on gradients +#set page(margin: 0pt, width: 100pt, height: auto) + +#let violet = cmyk(75%, 80%, 0%, 0%) +#let blue = cmyk(75%, 30%, 0%, 0%) + +#rect( + width: 100%, + height: 10pt, + fill: gradient.linear(violet, blue) +) + +#rect( + width: 100%, + height: 10pt, + fill: gradient.linear(rgb(violet), rgb(blue)) +) + +// In PDF format, this gradient can look different from the others. +// This is because PDF readers do weird things with CMYK. +#rect( + width: 100%, + height: 10pt, + fill: gradient.linear(violet, blue, space: cmyk) +) diff --git a/tests/suite/visualize/image.typ b/tests/suite/visualize/image.typ new file mode 100644 index 00000000..ac2d5af9 --- /dev/null +++ b/tests/suite/visualize/image.typ @@ -0,0 +1,122 @@ +// Test the `image` function. + +--- image-rgba-png-and-jpeg --- +// Test loading different image formats. + +// Load an RGBA PNG image. +#image("/assets/images/rhino.png") + +// Load an RGB JPEG image. +#set page(height: 60pt) +#image("/assets/images/tiger.jpg") + +--- image-sizing --- +// Test configuring the size and fitting behaviour of images. + +// Set width and height explicitly. +#box(image("/assets/images/rhino.png", width: 30pt)) +#box(image("/assets/images/rhino.png", height: 30pt)) + +// Set width and height explicitly and force stretching. +#image("/assets/images/monkey.svg", width: 100%, height: 20pt, fit: "stretch") + +// Make sure the bounding-box of the image is correct. +#align(bottom + right, image("/assets/images/tiger.jpg", width: 40pt, alt: "A tiger")) + +--- image-fit --- +// Test all three fit modes. +#set page(height: 50pt, margin: 0pt) +#grid( + columns: (1fr, 1fr, 1fr), + rows: 100%, + gutter: 3pt, + image("/assets/images/tiger.jpg", width: 100%, height: 100%, fit: "contain"), + image("/assets/images/tiger.jpg", width: 100%, height: 100%, fit: "cover"), + image("/assets/images/monkey.svg", width: 100%, height: 100%, fit: "stretch"), +) + +--- image-jump-to-next-page --- +// Does not fit to remaining height of page. +#set page(height: 60pt) +Stuff +#image("/assets/images/rhino.png") + +--- image-baseline-with-box --- +// Test baseline. +A #box(image("/assets/images/tiger.jpg", height: 1cm, width: 80%)) B + +--- image-svg-complex --- +// Test advanced SVG features. +#image("/assets/images/pattern.svg") + +--- image-svg-text --- +#set page(width: 250pt) + +#figure( + image("/assets/images/diagram.svg"), + caption: [A textful diagram], +) + +--- image-svg-text-font --- +#set page(width: 250pt) +#show image: set text(font: ("Roboto", "Noto Serif CJK SC")) + +#figure( + image("/assets/images/chinese.svg"), + caption: [Bilingual text] +) + +--- image-natural-dpi-sizing --- +// Test that images aren't upscaled. +// Image is just 48x80 at 220dpi. It should not be scaled to fit the page +// width, but rather max out at its natural size. +#image("/assets/images/f2t.jpg") + +--- image-file-not-found --- +// Error: 8-29 file not found (searched at tests/suite/visualize/path/does/not/exist) +#image("path/does/not/exist") + +--- image-bad-format --- +// Error: 2-22 unknown image format +#image("./image.typ") + +--- image-bad-svg --- +// Error: 2-33 failed to parse SVG (found closing tag 'g' instead of 'style' in line 4) +#image("/assets/images/bad.svg") + +--- image-decode-svg --- +// Test parsing from svg data +#image.decode(`<svg xmlns="http://www.w3.org/2000/svg" height="140" width="500"><ellipse cx="200" cy="80" rx="100" ry="50" style="fill:yellow;stroke:purple;stroke-width:2" /></svg>`.text, format: "svg") + +--- image-decode-bad-svg --- +// Error: 2-168 failed to parse SVG (missing root node) +#image.decode(`<svg height="140" width="500"><ellipse cx="200" cy="80" rx="100" ry="50" style="fill:yellow;stroke:purple;stroke-width:2" /></svg>`.text, format: "svg") + +--- image-decode-detect-format --- +// Test format auto detect +#image.decode(read("/assets/images/tiger.jpg", encoding: none), width: 80%) + +--- image-decode-specify-format --- +// Test format manual +#image.decode(read("/assets/images/tiger.jpg", encoding: none), format: "jpg", width: 80%) + +--- image-decode-specify-wrong-format --- +// Error: 2-91 failed to decode image (Format error decoding Png: Invalid PNG signature.) +#image.decode(read("/assets/images/tiger.jpg", encoding: none), format: "png", width: 80%) + +--- issue-870-image-rotation --- +// Ensure that EXIF rotation is applied. +// https://github.com/image-rs/image/issues/1045 +// File is from https://magnushoff.com/articles/jpeg-orientation/ +#image("/assets/images/f2t.jpg", width: 10pt) + +--- issue-measure-image --- +// Test that image measurement doesn't turn `inf / some-value` into 0pt. +#context { + let size = measure(image("/assets/images/tiger.jpg")) + test(size, (width: 1024pt, height: 670pt)) +} + +--- issue-2051-new-cm-svg --- +#set text(font: "New Computer Modern") +#image("/assets/images/diagram.svg") diff --git a/tests/suite/visualize/line.typ b/tests/suite/visualize/line.typ new file mode 100644 index 00000000..7259f72b --- /dev/null +++ b/tests/suite/visualize/line.typ @@ -0,0 +1,92 @@ +// Test lines. + +--- line-basic --- +#set page(height: 60pt) +#box({ + set line(stroke: 0.75pt) + place(line(end: (0.4em, 0pt))) + place(line(start: (0pt, 0.4em), end: (0pt, 0pt))) + line(end: (0.6em, 0.6em)) +}) Hello #box(line(length: 1cm))! + +#line(end: (70%, 50%)) + +--- line-positioning --- +// Test the angle argument and positioning. + +#set page(fill: rgb("0B1026")) +#set line(stroke: white) + +#let star(size, ..args) = box(width: size, height: size)[ + #set text(spacing: 0%) + #set line(..args) + #set align(left) + #v(30%) + #place(line(length: +30%, start: (09.0%, 02%))) + #place(line(length: +30%, start: (38.7%, 02%), angle: -72deg)) + #place(line(length: +30%, start: (57.5%, 02%), angle: 252deg)) + #place(line(length: +30%, start: (57.3%, 02%))) + #place(line(length: -30%, start: (88.0%, 02%), angle: -36deg)) + #place(line(length: +30%, start: (73.3%, 48%), angle: 252deg)) + #place(line(length: -30%, start: (73.5%, 48%), angle: 36deg)) + #place(line(length: +30%, start: (25.4%, 48%), angle: -36deg)) + #place(line(length: +30%, start: (25.6%, 48%), angle: -72deg)) + #place(line(length: +32%, start: (8.50%, 02%), angle: 34deg)) +] + +#align(center, grid( + columns: 3, + column-gutter: 10pt, + ..((star(20pt, stroke: 0.5pt),) * 9) +)) + +--- line-stroke --- +// Some simple test lines +#line(length: 60pt, stroke: red) +#v(3pt) +#line(length: 60pt, stroke: 2pt) +#v(3pt) +#line(length: 60pt, stroke: blue + 1.5pt) +#v(3pt) +#line(length: 60pt, stroke: (paint: red, thickness: 1pt, dash: "dashed")) +#v(3pt) +#line(length: 60pt, stroke: (paint: red, thickness: 4pt, cap: "round")) + +--- line-stroke-set --- +// Set rules with stroke +#set line(stroke: (paint: red, thickness: 1pt, cap: "butt", dash: "dash-dotted")) +#line(length: 60pt) +#v(3pt) +#line(length: 60pt, stroke: blue) +#v(3pt) +#line(length: 60pt, stroke: (dash: none)) + +--- line-stroke-dash --- +// Dashing +#line(length: 60pt, stroke: (paint: red, thickness: 1pt, dash: ("dot", 1pt))) +#v(3pt) +#line(length: 60pt, stroke: (paint: red, thickness: 1pt, dash: ("dot", 1pt, 4pt, 2pt))) +#v(3pt) +#line(length: 60pt, stroke: (paint: red, thickness: 1pt, dash: (array: ("dot", 1pt, 4pt, 2pt), phase: 5pt))) +#v(3pt) +#line(length: 60pt, stroke: (paint: red, thickness: 1pt, dash: ())) +#v(3pt) +#line(length: 60pt, stroke: (paint: red, thickness: 1pt, dash: (1pt, 3pt, 9pt))) + +--- line-stroke-field-typo --- +// Error: 29-56 unexpected key "thicknes", valid keys are "paint", "thickness", "cap", "join", "dash", and "miter-limit" +#line(length: 60pt, stroke: (paint: red, thicknes: 1pt)) + +--- line-stroke-bad-dash-kind --- +// Error: 29-55 expected "solid", "dotted", "densely-dotted", "loosely-dotted", "dashed", "densely-dashed", "loosely-dashed", "dash-dotted", "densely-dash-dotted", "loosely-dash-dotted", array, dictionary, none, or auto +#line(length: 60pt, stroke: (paint: red, dash: "dash")) + +--- line-bad-point-array --- +// Test errors. + +// Error: 12-19 point array must contain exactly two entries +#line(end: (50pt,)) + +--- line-bad-point-component-type --- +// Error: 14-26 expected relative length, found angle +#line(start: (3deg, 10pt), length: 5cm) diff --git a/tests/suite/visualize/path.typ b/tests/suite/visualize/path.typ new file mode 100644 index 00000000..10955f14 --- /dev/null +++ b/tests/suite/visualize/path.typ @@ -0,0 +1,52 @@ +// Test paths. + +--- path --- +#set page(height: 200pt, width: 200pt) +#table( + columns: (1fr, 1fr), + rows: (1fr, 1fr), + align: center + horizon, + path( + fill: red, + closed: true, + ((0%, 0%), (4%, -4%)), + ((50%, 50%), (4%, -4%)), + ((0%, 50%), (4%, 4%)), + ((50%, 0%), (4%, 4%)), + ), + path( + fill: purple, + stroke: 1pt, + (0pt, 0pt), + (30pt, 30pt), + (0pt, 30pt), + (30pt, 0pt), + ), + path( + fill: blue, + stroke: 1pt, + closed: true, + ((30%, 0%), (35%, 30%), (-20%, 0%)), + ((30%, 60%), (-20%, 0%), (0%, 0%)), + ((50%, 30%), (60%, -30%), (60%, 0%)), + ), + path( + stroke: 5pt, + closed: true, + (0pt, 30pt), + (30pt, 30pt), + (15pt, 0pt), + ), +) + +--- path-bad-vertex --- +// Error: 7-9 path vertex must have 1, 2, or 3 points +#path(()) + +--- path-bad-point-count --- +// Error: 7-47 path vertex must have 1, 2, or 3 points +#path(((0%, 0%), (0%, 0%), (0%, 0%), (0%, 0%))) + +--- path-bad-point-array --- +// Error: 7-31 point array must contain exactly two entries +#path(((0%, 0%), (0%, 0%, 0%))) diff --git a/tests/suite/visualize/pattern.typ b/tests/suite/visualize/pattern.typ new file mode 100644 index 00000000..08051ed2 --- /dev/null +++ b/tests/suite/visualize/pattern.typ @@ -0,0 +1,131 @@ +// Test patterns. + +--- pattern-line --- +// Tests that simple patterns work. +#set page(width: auto, height: auto, margin: 0pt) +#let pat = pattern(size: (10pt, 10pt), line(stroke: 4pt, start: (0%, 0%), end: (100%, 100%))) +#rect(width: 50pt, height: 50pt, fill: pat) + +--- pattern-lines --- +#set page(width: auto, height: auto, margin: 0pt) + +#let pat = pattern(size: (10pt, 10pt), { + place(line(stroke: 4pt, start: (0%, 0%), end: (100%, 100%))) + place(line(stroke: 4pt, start: (100%,0%), end: (200%, 100%))) + place(line(stroke: 4pt, start: (0%,100%), end: (100%, 200%))) + place(line(stroke: 4pt, start: (-100%,0%), end: (0%, 100%))) + place(line(stroke: 4pt, start: (0%,-100%), end: (100%, 0%))) +}) +#rect(width: 50pt, height: 50pt, fill: pat) + +--- pattern-relative-self --- +// Test with relative set to `"self"` +#let pat(..args) = pattern(size: (30pt, 30pt), ..args)[ + #place(top + left, line(start: (0%, 0%), end: (100%, 100%), stroke: 1pt)) + #place(top + left, line(start: (0%, 100%), end: (100%, 0%), stroke: 1pt)) +] + +#set page(fill: pat(), width: 100pt, height: 100pt) + +#rect(fill: pat(relative: "self"), width: 100%, height: 100%, stroke: 1pt) + +--- pattern-relative-parent --- +// Test with relative set to `"parent"` +#let pat(..args) = pattern(size: (30pt, 30pt), ..args)[ + #place(top + left, line(start: (0%, 0%), end: (100%, 100%), stroke: 1pt)) + #place(top + left, line(start: (0%, 100%), end: (100%, 0%), stroke: 1pt)) +] + +#set page(fill: pat(), width: 100pt, height: 100pt) + +#rect(fill: pat(relative: "parent"), width: 100%, height: 100%, stroke: 1pt) + +--- pattern-small --- +// Tests small patterns for pixel accuracy. +#box( + width: 8pt, + height: 1pt, + fill: pattern(size: (1pt, 1pt), square(size: 1pt, fill: black)) +) +#v(-1em) +#box( + width: 8pt, + height: 1pt, + fill: pattern(size: (2pt, 1pt), square(size: 1pt, fill: black)) +) + +--- pattern-zero-sized --- +// Error: 15-52 pattern tile size must be non-zero +// Hint: 15-52 try setting the size manually +#line(stroke: pattern(path((0pt, 0pt), (1em, 0pt)))) + +--- pattern-spacing-negative --- +// Test with spacing set to `(-10pt, -10pt)` +#let pat(..args) = pattern(size: (30pt, 30pt), ..args)[ + #square(width: 100%, height: 100%, stroke: 1pt, fill: blue) +] + +#set page(width: 100pt, height: 100pt) + +#rect(fill: pat(spacing: (-10pt, -10pt)), width: 100%, height: 100%, stroke: 1pt) + +--- pattern-spacing-zero --- +// Test with spacing set to `(0pt, 0pt)` +#let pat(..args) = pattern(size: (30pt, 30pt), ..args)[ + #square(width: 100%, height: 100%, stroke: 1pt, fill: blue) +] + +#set page(width: 100pt, height: 100pt) + +#rect(fill: pat(spacing: (0pt, 0pt)), width: 100%, height: 100%, stroke: 1pt) + +--- pattern-spacing-positive --- +// Test with spacing set to `(10pt, 10pt)` +#let pat(..args) = pattern(size: (30pt, 30pt), ..args)[ + #square(width: 100%, height: 100%, stroke: 1pt, fill: blue) +] + +#set page(width: 100pt, height: 100pt) + +#rect(fill: pat(spacing: (10pt, 10pt,)), width: 100%, height: 100%, stroke: 1pt) + +--- pattern-stroke --- +// Test pattern on strokes +#align( + center + top, + square( + size: 50pt, + stroke: 5pt + pattern( + size: (5pt, 5pt), + align(horizon + center, circle(fill: blue, radius: 2.5pt)) + ) + ) +) + +--- pattern-text --- +// Test a pattern on some text +// You shouldn't be able to see the text, if you can then +// that means that the transform matrices are not being +// applied to the text correctly. +#let pat = pattern( + size: (30pt, 30pt), + relative: "parent", + square(size: 30pt, fill: gradient.conic(..color.map.rainbow)) +); + +#set page( + width: 140pt, + height: 140pt, + fill: pat +) + +#rotate(45deg, scale(x: 50%, y: 70%, rect( + width: 100%, + height: 100%, + stroke: 1pt, +)[ + #lorem(10) + + #set text(fill: pat) + #lorem(10) +])) diff --git a/tests/suite/visualize/polygon.typ b/tests/suite/visualize/polygon.typ new file mode 100644 index 00000000..a3f4c8ef --- /dev/null +++ b/tests/suite/visualize/polygon.typ @@ -0,0 +1,51 @@ +// Test polygons. + +--- polygon --- +#set page(width: 50pt) +#set polygon(stroke: 0.75pt, fill: blue) + +// These are not visible, but should also not give an error +#polygon() +#polygon((0em, 0pt)) +#polygon((0pt, 0pt), (10pt, 0pt)) +#polygon.regular(size: 0pt, vertices: 9) + +#polygon((5pt, 0pt), (0pt, 10pt), (10pt, 10pt)) +#polygon( + (0pt, 0pt), (5pt, 5pt), (10pt, 0pt), + (15pt, 5pt), + (5pt, 10pt) +) +#polygon(stroke: none, (5pt, 0pt), (0pt, 10pt), (10pt, 10pt)) +#polygon(stroke: 3pt, fill: none, (5pt, 0pt), (0pt, 10pt), (10pt, 10pt)) + +// Relative size +#polygon((0pt, 0pt), (100%, 5pt), (50%, 10pt)) + +// Antiparallelogram +#polygon((0pt, 5pt), (5pt, 0pt), (0pt, 10pt), (5pt, 15pt)) + +// Self-intersections +#polygon((0pt, 10pt), (30pt, 20pt), (0pt, 30pt), (20pt, 0pt), (20pt, 35pt)) + +// Regular polygon; should have equal side lengths +#for k in range(3, 9) {polygon.regular(size: 30pt, vertices: k,)} + +--- polygon-line-join --- +// Line joins +#stack( + dir: ltr, + spacing: 1em, + polygon(stroke: (thickness: 4pt, paint: blue, join: "round"), + (0pt, 20pt), (15pt, 0pt), (0pt, 40pt), (15pt, 45pt)), + polygon(stroke: (thickness: 4pt, paint: blue, join: "bevel"), + (0pt, 20pt), (15pt, 0pt), (0pt, 40pt), (15pt, 45pt)), + polygon(stroke: (thickness: 4pt, paint: blue, join: "miter"), + (0pt, 20pt), (15pt, 0pt), (0pt, 40pt), (15pt, 45pt)), + polygon(stroke: (thickness: 4pt, paint: blue, join: "miter", miter-limit: 20.0), + (0pt, 20pt), (15pt, 0pt), (0pt, 40pt), (15pt, 45pt)), +) + +--- polygon-bad-point-array --- +// Error: 10-17 point array must contain exactly two entries +#polygon((50pt,)) diff --git a/tests/suite/visualize/rect.typ b/tests/suite/visualize/rect.typ new file mode 100644 index 00000000..f84fafcb --- /dev/null +++ b/tests/suite/visualize/rect.typ @@ -0,0 +1,107 @@ +// Test the `rect` function. + +--- rect --- +// Default rectangle. +#rect() + +--- rect-customization --- +#set page(width: 150pt) + +// Fit to text. +#rect(fill: conifer)[Textbox] + +// Empty with fixed width and height. +#block(rect( + height: 15pt, + fill: rgb("46b3c2"), + stroke: 2pt + rgb("234994"), +)) + +// Fixed width, text height. +#rect(width: 2cm, fill: rgb("9650d6"))[Fixed and padded] + +// Page width, fixed height. +#rect(height: 1cm, width: 100%, fill: rgb("734ced"))[Topleft] + +// These are inline with text. +{#box(rect(width: 0.5in, height: 7pt, fill: rgb("d6cd67"))) + #box(rect(width: 0.5in, height: 7pt, fill: rgb("edd466"))) + #box(rect(width: 0.5in, height: 7pt, fill: rgb("e3be62")))} + +// Rounded corners. +#stack( + dir: ltr, + spacing: 1fr, + rect(width: 2cm, radius: 30%), + rect(width: 1cm, radius: (left: 10pt, right: 5pt)), + rect(width: 1.25cm, radius: ( + top-left: 2pt, + top-right: 5pt, + bottom-right: 8pt, + bottom-left: 11pt + )), +) + +// Different strokes. +#set rect(stroke: (right: red)) +#rect(width: 100%, fill: lime, stroke: (x: 5pt, y: 1pt)) + +--- rect-stroke --- +// Rectangle strokes +#rect(width: 20pt, height: 20pt, stroke: red) +#v(3pt) +#rect(width: 20pt, height: 20pt, stroke: (rest: red, top: (paint: blue, dash: "dashed"))) +#v(3pt) +#rect(width: 20pt, height: 20pt, stroke: (thickness: 5pt, join: "round")) + +--- red-stroke-bad-type --- +// Error: 15-21 expected length, color, gradient, pattern, dictionary, stroke, none, or auto, found array +#rect(stroke: (1, 2)) + +--- rect-fill-stroke --- +#let variant = rect.with(width: 20pt, height: 10pt) +#let items = for (i, item) in ( + variant(stroke: none), + variant(), + variant(fill: none), + variant(stroke: 2pt), + variant(stroke: eastern), + variant(stroke: eastern + 2pt), + variant(fill: eastern), + variant(fill: eastern, stroke: none), + variant(fill: forest, stroke: none), + variant(fill: forest, stroke: conifer), + variant(fill: forest, stroke: black + 2pt), + variant(fill: forest, stroke: conifer + 2pt), +).enumerate() { + (align(horizon)[#(i + 1).], item, []) +} + +#grid( + columns: (auto, auto, 1fr, auto, auto, 0fr), + gutter: 5pt, + ..items, +) + +--- rect-radius-bad-key --- +// Error: 15-38 unexpected key "cake", valid keys are "top-left", "top-right", "bottom-right", "bottom-left", "left", "top", "right", "bottom", and "rest" +#rect(radius: (left: 10pt, cake: 5pt)) + +--- issue-1825-rect-overflow --- +#set page(width: 17.8cm) +#set par(justify: true) +#rect(lorem(70)) + +--- issue-3264-rect-negative-dimensions --- +// Negative dimensions +#rect(width: -1cm, fill: gradient.linear(red, blue))[Reverse left] + +#rect(width: 1cm, fill: gradient.linear(red, blue))[Left] + +#align(center, rect(width: -1cm, fill: gradient.linear(red, blue))[Reverse center]) + +#align(center, rect(width: 1cm, fill: gradient.linear(red, blue))[Center]) + +#align(right, rect(width: -1cm, fill: gradient.linear(red, blue))[Reverse right]) + +#align(right, rect(width: 1cm, fill: gradient.linear(red, blue))[Right]) diff --git a/tests/suite/visualize/square.typ b/tests/suite/visualize/square.typ new file mode 100644 index 00000000..caa1fc21 --- /dev/null +++ b/tests/suite/visualize/square.typ @@ -0,0 +1,146 @@ +// Test the `square` function. + +--- square --- +// Default square. +#box(square()) +#box(square[hey!]) + +--- square-auto-sized --- +// Test auto-sized square. +#square(fill: eastern)[ + #set text(fill: white, weight: "bold") + Typst +] + +--- square-relatively-sized-child --- +// Test relative-sized child. +#square(fill: eastern)[ + #rect(width: 10pt, height: 5pt, fill: conifer) + #rect(width: 40%, height: 5pt, stroke: conifer) +] + +--- square-contents-overflow --- +// Test text overflowing height. +#set page(width: 75pt, height: 100pt) +#square(fill: conifer)[ + But, soft! what light through yonder window breaks? +] + +--- square-height-limited --- +// Test that square does not overflow page. +#set page(width: 100pt, height: 75pt) +#square(fill: conifer)[ + But, soft! what light through yonder window breaks? +] + +--- square-size-width-and-height --- +// Size wins over width and height. +// Error: 09-20 unexpected argument: width +#square(width: 10cm, height: 20cm, size: 1cm, fill: rgb("eb5278")) + +--- square-relative-size --- +// Test relative width and height and size that is smaller +// than default size. +#set page(width: 120pt, height: 70pt) +#set align(bottom) +#let centered = align.with(center + horizon) +#stack( + dir: ltr, + spacing: 1fr, + square(width: 50%, centered[A]), + square(height: 50%), + stack( + square(size: 10pt), + square(size: 20pt, centered[B]) + ), +) + +--- square-circle-alignment --- +// Test alignment in automatically sized square and circle. +#set text(8pt) +#box(square(inset: 4pt)[ + Hey there, #align(center + bottom, rotate(180deg, [you!])) +]) +#box(circle(align(center + horizon, [Hey.]))) + +--- square-circle-overspecified --- +// Test that minimum wins if both width and height are given. +#stack( + dir: ltr, + spacing: 2pt, + square(width: 20pt, height: 40pt), + circle(width: 20%, height: 100pt), +) + +--- square-height-limited-stack --- +// Test square that is limited by region size. +#set page(width: 20pt, height: 10pt, margin: 0pt) +#stack(dir: ltr, square(fill: forest), square(fill: conifer)) + +--- square-overflow --- +// Test that square doesn't overflow due to its aspect ratio. +#set page(width: 40pt, height: 25pt, margin: 5pt) +#square(width: 100%) +#square(width: 100%)[Hello there] + +--- square-size-relative-invalid --- +// Size cannot be relative because we wouldn't know +// relative to which axis. +// Error: 15-18 expected length or auto, found ratio +#square(size: 50%) + +--- square-rect-rounded --- +#set square(size: 20pt, stroke: 4pt) + +// no radius for non-rounded corners +#stack( + dir: ltr, + square(), + h(10pt), + square(radius: 0pt), + h(10pt), + square(radius: -10pt), +) + +#stack( + dir: ltr, + square(), + h(10pt), + square(radius: 0%), + h(10pt), + square(radius: -10%), +) + +// small values for small radius +#stack( + dir: ltr, + square(radius: 1pt), + h(10pt), + square(radius: 5%), + h(10pt), + square(radius: 2pt), +) + +// large values for large radius or circle +#stack( + dir: ltr, + square(radius: 8pt), + h(10pt), + square(radius: 10pt), + h(10pt), + square(radius: 12pt), +) + +#stack( + dir: ltr, + square(radius: 45%), + h(10pt), + square(radius: 50%), + h(10pt), + square(radius: 55%), +) + +--- square-base --- +// Test that square sets correct base for its content. +#set page(height: 80pt) +#square(width: 40%, rect(width: 60%, height: 80%)) diff --git a/tests/suite/visualize/stroke.typ b/tests/suite/visualize/stroke.typ new file mode 100644 index 00000000..b03c96c5 --- /dev/null +++ b/tests/suite/visualize/stroke.typ @@ -0,0 +1,171 @@ +// Test lines. + +--- stroke-constructor --- +// Converting to stroke +#assert.eq(stroke(red).paint, red) +#assert.eq(stroke(red).thickness, auto) +#assert.eq(stroke(2pt).paint, auto) +#assert.eq(stroke((cap: "round", paint: blue)).cap, "round") +#assert.eq(stroke((cap: auto, paint: blue)).cap, auto) +#assert.eq(stroke((cap: auto, paint: blue)).thickness, auto) + +// Constructing with named arguments +#assert.eq(stroke(paint: blue, thickness: 8pt), 8pt + blue) +#assert.eq(stroke(thickness: 2pt), stroke(2pt)) +#assert.eq(stroke(cap: "round").thickness, auto) +#assert.eq(stroke(cap: "round", thickness: auto).thickness, auto) + +--- stroke-constructor-unknown-key --- +// Error: 9-21 unexpected key "foo", valid keys are "paint", "thickness", "cap", "join", "dash", and "miter-limit" +#stroke((foo: "bar")) + +--- stroke-fields-simple --- +// Test stroke fields for simple strokes. +#test((1em + blue).paint, blue) +#test((1em + blue).thickness, 1em) +#test((1em + blue).cap, auto) +#test((1em + blue).join, auto) +#test((1em + blue).dash, auto) +#test((1em + blue).miter-limit, auto) + +--- stroke-fields-complex --- +// Test complex stroke fields. +#let r1 = rect(stroke: (paint: cmyk(1%, 2%, 3%, 4%), thickness: 4em + 2pt, cap: "round", join: "bevel", miter-limit: 5.0, dash: none)) +#let r2 = rect(stroke: (paint: cmyk(1%, 2%, 3%, 4%), thickness: 4em + 2pt, cap: "round", join: "bevel", miter-limit: 5.0, dash: (3pt, "dot", 4em))) +#let r3 = rect(stroke: (paint: cmyk(1%, 2%, 3%, 4%), thickness: 4em + 2pt, cap: "round", join: "bevel", dash: (array: (3pt, "dot", 4em), phase: 5em))) +#let s1 = r1.stroke +#let s2 = r2.stroke +#let s3 = r3.stroke +#test(s1.paint, cmyk(1%, 2%, 3%, 4%)) +#test(s1.thickness, 4em + 2pt) +#test(s1.cap, "round") +#test(s1.join, "bevel") +#test(s1.miter-limit, 5.0) +#test(s3.miter-limit, auto) +#test(s1.dash, none) +#test(s2.dash, (array: (3pt, "dot", 4em), phase: 0pt)) +#test(s3.dash, (array: (3pt, "dot", 4em), phase: 5em)) + +--- stroke-zero-thickness --- +// 0pt strokes must function exactly like 'none' strokes and not draw anything +#rect(width: 10pt, height: 10pt, stroke: none) +#rect(width: 10pt, height: 10pt, stroke: 0pt) +#rect(width: 10pt, height: 10pt, stroke: none, fill: blue) +#rect(width: 10pt, height: 10pt, stroke: 0pt + red, fill: blue) + +#line(length: 30pt, stroke: 0pt) +#line(length: 30pt, stroke: (paint: red, thickness: 0pt, dash: ("dot", 1pt))) + +#table(columns: 2, stroke: none)[A][B] +#table(columns: 2, stroke: 0pt)[A][B] + +#path( + fill: red, + stroke: none, + closed: true, + ((0%, 0%), (4%, -4%)), + ((50%, 50%), (4%, -4%)), + ((0%, 50%), (4%, 4%)), + ((50%, 0%), (4%, 4%)), +) + +#path( + fill: red, + stroke: 0pt, + closed: true, + ((0%, 0%), (4%, -4%)), + ((50%, 50%), (4%, -4%)), + ((0%, 50%), (4%, 4%)), + ((50%, 0%), (4%, 4%)), +) + +--- stroke-text --- +#set text(size: 20pt) +#set page(width: auto) +#let v = [测试字体Test] + +#text(stroke: 0.3pt + red, v) + +#text(stroke: 0.7pt + red, v) + +#text(stroke: 7pt + red, v) + +#text(stroke: (paint: blue, thickness: 1pt, dash: "dashed"), v) + +#text(stroke: 1pt + gradient.linear(..color.map.rainbow), v) + +--- stroke-folding --- +// Test stroke folding. +#let sq(..args) = box(square(size: 10pt, ..args)) + +#set square(stroke: none) +#sq() +#set square(stroke: auto) +#sq() +#sq(fill: teal) +#sq(stroke: 2pt) +#sq(stroke: blue) +#sq(fill: teal, stroke: blue) +#sq(fill: teal, stroke: 2pt + blue) + +--- stroke-composition --- +// Test stroke composition. +#set square(stroke: 4pt) +#set text(font: "Roboto") +#stack( + dir: ltr, + square( + stroke: (left: red, top: yellow, right: green, bottom: blue), + radius: 50%, align(center+horizon)[*G*], + inset: 8pt + ), + h(0.5cm), + square( + stroke: (left: red, top: yellow + 8pt, right: green, bottom: blue + 2pt), + radius: 50%, align(center+horizon)[*G*], + inset: 8pt + ), + h(0.5cm), + square( + stroke: (left: red, top: yellow, right: green, bottom: blue), + radius: 100%, align(center+horizon)[*G*], + inset: 8pt + ), +) + +// Join between different solid strokes +#set square(size: 20pt, stroke: 2pt) +#set square(stroke: (left: green + 4pt, top: black + 2pt, right: blue, bottom: black + 2pt)) +#stack( + dir: ltr, + square(), + h(0.2cm), + square(radius: (top-left: 0pt, rest: 1pt)), + h(0.2cm), + square(radius: (top-left: 0pt, rest: 8pt)), + h(0.2cm), + square(radius: (top-left: 0pt, rest: 100pt)), +) + +// Join between solid and dotted strokes +#set square(stroke: (left: green + 4pt, top: black + 2pt, right: (paint: blue, dash: "dotted"), bottom: (paint: black, dash: "dotted"))) +#stack( + dir: ltr, + square(), + h(0.2cm), + square(radius: (top-left: 0pt, rest: 1pt)), + h(0.2cm), + square(radius: (top-left: 0pt, rest: 8pt)), + h(0.2cm), + square(radius: (top-left: 0pt, rest: 100pt)), +) + +--- issue-3700-deformed-stroke --- +// Test shape fill & stroke for specific values that used to make the stroke +// deformed. +#rect( + radius: 1mm, + width: 100%, + height: 10pt, + stroke: (left: rgb("46b3c2") + 16.0mm), +) |
