diff --git a/.github/workflows/check-generated-fbs.yml b/.github/workflows/check-generated-fbs.yml
new file mode 100644
index 0000000000..348581ab8f
--- /dev/null
+++ b/.github/workflows/check-generated-fbs.yml
@@ -0,0 +1,62 @@
+# -----------------------------------------------------------------
+# Freshness check for committed FlatBuffers bindings
+# -----------------------------------------------------------------
+#
+# Why this exists
+# ---------------
+# The Rust FlatBuffers bindings (`crates/grida-canvas/src/io/generated/grida.rs`)
+# are committed to git so that `cargo build` works from a clean checkout without
+# requiring `flatc`. However, because the file is generated from `format/grida.fbs`,
+# it can become stale if someone edits the schema but forgets to regenerate.
+#
+# This workflow re-runs codegen and asserts that the committed file is identical
+# to what `flatc` would produce. If it differs, the check fails with a clear
+# error message telling the contributor how to fix it.
+#
+# When does it run
+# ----------------
+# Only on PRs / pushes that touch the schema, the generated output, the codegen
+# tooling, or the TS format package (which shares the same schema source).
+#
+# How to fix a failure
+# --------------------
+# pnpm --filter @crates/grida-canvas generate
+# git add crates/grida-canvas/src/io/generated/grida.rs
+# git commit
+# -----------------------------------------------------------------
+
+name: check generated flatbuffers
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+ paths:
+ - "format/grida.fbs"
+ - "crates/grida-canvas/src/io/generated/**"
+ - "packages/grida-format/src/**"
+ - "bin/activate-flatc"
+
+jobs:
+ rust-bindings:
+ name: rust fbs freshness
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Regenerate Rust FlatBuffers bindings
+ run: |
+ python3 bin/activate-flatc -- --rust \
+ -o crates/grida-canvas/src/io/generated \
+ format/grida.fbs
+ mv crates/grida-canvas/src/io/generated/grida_generated.rs \
+ crates/grida-canvas/src/io/generated/grida.rs
+
+ - name: Check for uncommitted changes
+ run: |
+ if ! git diff --exit-code crates/grida-canvas/src/io/generated/grida.rs; then
+ echo "::error::Generated Rust FlatBuffers bindings are stale. Run 'pnpm --filter @crates/grida-canvas generate' and commit the result."
+ exit 1
+ fi
diff --git a/Cargo.lock b/Cargo.lock
index 6ba92a5f52..70e92a7cf6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -495,6 +495,7 @@ dependencies = [
"clap",
"criterion",
"figma-api",
+ "flatbuffers",
"futures",
"gl",
"glutin",
@@ -730,9 +731,9 @@ dependencies = [
[[package]]
name = "crc32fast"
-version = "1.4.2"
+version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
+checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
dependencies = [
"cfg-if",
]
@@ -1172,6 +1173,16 @@ dependencies = [
"typenum",
]
+[[package]]
+name = "flatbuffers"
+version = "25.12.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35f6839d7b3b98adde531effaf34f0c2badc6f4735d26fe74709d8e513a96ef3"
+dependencies = [
+ "bitflags 2.9.1",
+ "rustc_version",
+]
+
[[package]]
name = "flate2"
version = "1.1.1"
@@ -1574,6 +1585,7 @@ dependencies = [
"tokio",
"toml 0.9.8",
"winit",
+ "zip",
]
[[package]]
@@ -3653,6 +3665,15 @@ version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
+[[package]]
+name = "rustc_version"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
+dependencies = [
+ "semver",
+]
+
[[package]]
name = "rustix"
version = "0.38.44"
@@ -3836,6 +3857,12 @@ dependencies = [
"to_shmem_derive",
]
+[[package]]
+name = "semver"
+version = "1.0.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
+
[[package]]
name = "serde"
version = "1.0.226"
@@ -4829,6 +4856,12 @@ dependencies = [
"core_maths",
]
+[[package]]
+name = "typed-path"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e28f89b80c87b8fb0cf04ab448d5dd0dd0ade2f8891bae878de66a75a28600e"
+
[[package]]
name = "typenum"
version = "1.18.0"
@@ -5884,6 +5917,19 @@ dependencies = [
"syn 2.0.101",
]
+[[package]]
+name = "zip"
+version = "8.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b680f2a0cd479b4cff6e1233c483fdead418106eae419dc60200ae9850f6d004"
+dependencies = [
+ "crc32fast",
+ "flate2",
+ "indexmap 2.11.4",
+ "memchr",
+ "typed-path",
+]
+
[[package]]
name = "zune-core"
version = "0.4.12"
diff --git a/bin/activate-flatc b/bin/activate-flatc
index 74debc074b..4ee37f9fec 100644
--- a/bin/activate-flatc
+++ b/bin/activate-flatc
@@ -5,9 +5,10 @@ Grida: FlatBuffers compiler (flatc) bootstrapper
Why this exists
---------------
-We intentionally do NOT commit generated FlatBuffers bindings to git (see
-`packages/grida-format/.gitignore`). The package build step runs `flatc` (see
-`packages/grida-format/package.json`), so CI and Vercel builds must have a
+Generated FlatBuffers bindings are committed for the Rust crate
+(`crates/grida-canvas/src/io/generated/grida.rs`) so that `cargo build` works
+from a clean checkout. The TypeScript package (`packages/grida-format`)
+regenerates at build time. In both cases CI and Vercel builds need a
deterministic way to obtain `flatc`.
FlatBuffers does not ship `flatc` via npm, so this script installs a prebuilt
diff --git a/crates/grida-canvas-wasm/example/demo.grida1 b/crates/grida-canvas-wasm/example/demo.grida1
index 9cc296743c..42877cfdf8 100644
--- a/crates/grida-canvas-wasm/example/demo.grida1
+++ b/crates/grida-canvas-wasm/example/demo.grida1
@@ -9889,5 +9889,5 @@
"main"
]
},
- "version": "0.90.0-beta+20260108"
+ "version": "0.91.0-beta+20260311"
}
\ No newline at end of file
diff --git a/crates/grida-canvas-wasm/example/gradient.grida1 b/crates/grida-canvas-wasm/example/gradient.grida1
index dd00e65a6c..f336470f86 100644
--- a/crates/grida-canvas-wasm/example/gradient.grida1
+++ b/crates/grida-canvas-wasm/example/gradient.grida1
@@ -1,5 +1,5 @@
{
- "version": "0.90.0-beta+20260108",
+ "version": "0.91.0-beta+20260311",
"document": {
"nodes": {
"gradient-rect": {
diff --git a/crates/grida-canvas-wasm/example/rectangle.grida1 b/crates/grida-canvas-wasm/example/rectangle.grida1
index 2d4507033b..e084bb2848 100644
--- a/crates/grida-canvas-wasm/example/rectangle.grida1
+++ b/crates/grida-canvas-wasm/example/rectangle.grida1
@@ -1,5 +1,5 @@
{
- "version": "0.90.0-beta+20260108",
+ "version": "0.91.0-beta+20260311",
"document": {
"nodes": {
"rectangle": {
diff --git a/crates/grida-canvas-wasm/lib/__test__/environment-node-raster-export.test.ts b/crates/grida-canvas-wasm/lib/__test__/environment-node-raster-export.test.ts
index 051095d2ad..da5d34bb29 100644
--- a/crates/grida-canvas-wasm/lib/__test__/environment-node-raster-export.test.ts
+++ b/crates/grida-canvas-wasm/lib/__test__/environment-node-raster-export.test.ts
@@ -76,7 +76,7 @@ describe("raster export (node)", () => {
const imageBytes = new Uint8Array(readFileSync(imagePath));
const doc = {
- version: "0.90.0-beta+20260108",
+ version: "0.91.0-beta+20260311",
document: {
nodes: {
"image-rect": {
diff --git a/crates/grida-canvas/AGENTS.md b/crates/grida-canvas/AGENTS.md
index f0116bd093..efc8bc1e22 100644
--- a/crates/grida-canvas/AGENTS.md
+++ b/crates/grida-canvas/AGENTS.md
@@ -75,6 +75,5 @@ See [examples/tool_io_grida.rs](./examples/tool_io_grida.rs) for full documentat
## Package Docs
```sh
-# skia-safe
-cargo doc --package skia-safe --open --no-deps
+cargo doc --package cg --open --no-deps
```
diff --git a/crates/grida-canvas/Cargo.toml b/crates/grida-canvas/Cargo.toml
index 190fbce774..7f73b2d34c 100644
--- a/crates/grida-canvas/Cargo.toml
+++ b/crates/grida-canvas/Cargo.toml
@@ -22,6 +22,7 @@ gl = "0.14.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
json-patch = "4.1.0"
+flatbuffers = "25.12.19"
# text editing
grida-text-edit = { path = "../grida-text-edit" }
diff --git a/crates/grida-canvas/README.md b/crates/grida-canvas/README.md
index 03bcccea8f..ce4705d27a 100644
--- a/crates/grida-canvas/README.md
+++ b/crates/grida-canvas/README.md
@@ -2,52 +2,116 @@
-Grida Canvas core graphics implements High-level Node & Property based Graphics API that supports mordern design techniques.
+Grida Canvas is a **safe, high-performance 2D real-time rendering engine** for the Grida design tool. It provides a node- and property-based graphics API with support for modern design techniques.
-## Rendering
+- **Rendering**: [`skia-safe`](https://rust-skia.github.io/doc/skia_safe/) for painting
+- **Geometry & math**: [`math2`](../math2/README.md) for transforms, rects, and common operations
-**2D Nodes**
+## Capabilities
-- [ ] TextSpan
-- [ ] Text (Text with mixed styles)
-- [ ] Image
-- [ ] Bitmap (for bitmap drawing)
-- [ ] Group
-- [ ] Container (Frame)
-- [ ] Rectangle
-- [ ] Ellipse
-- [ ] Polygon
-- [ ] RegularPolygon
-- [ ] RegularStarPolygon
-- [ ] Path (SVG Path)
-- [ ] Vector (Vector Network)
-- [ ] Line
+### 2D nodes
-**Meta**
+| Node | Status |
+| ------------------------------------------- | ------ |
+| Container (Frame) | ✅ |
+| Group | ✅ |
+| Rectangle | ✅ |
+| Ellipse (incl. arc, ring, sector) | ✅ |
+| Polygon, RegularPolygon, RegularStarPolygon | ✅ |
+| Line | ✅ |
+| Path (SVG path) | ✅ |
+| Vector (vector network) | ✅ |
+| BooleanOperation | ✅ |
+| TextSpan | ✅ |
+| Image | ✅ |
+| InitialContainer, Error | ✅ |
-- [ ] Mask
-- [ ] Clip
+### Paints & effects
-**Styles & Effects**
+- **Fills**: Solid, LinearGradient, RadialGradient, SweepGradient, Image (with fit and image filters)
+- **Strokes**: Stroke width (uniform/variable), dash array, caps/joins, stroke alignment, rect-specific stroke widths, markers
+- **Effects**: Layer blur, backdrop blur, drop/inner shadow, liquid glass, noise
+- **Blend modes** on layers and paints
-- [ ] SolidPaint
-- [ ] LinearGradientPaint
-- [ ] RadialGradientPaint
-- [ ] DropShadow
-- [ ] BoxShadow
-- [ ] BlendMode
+### Layout
-## API
+- **Taffy**-based layout: flex (direction, alignment, gap, padding), positioning (inset, width/height), transform
-**Camera**
+### Meta
-- [ ] 2D Camera
+- **Masks** (layer and vector masks)
-**Pipeline & API**
+### Pipeline & runtime
-- [ ] load font
-- [ ] load image
+- **Camera**: 2D camera (pan, zoom, viewport)
+- **Resources**: Font loading (`FontRepository`), image loading (`ImageRepository`), embedded fonts (e.g. Geist, Geist Mono)
+- **Export**: PNG, JPEG, WEBP, BMP, PDF, SVG
-## Interactivity
+### Interactivity
-- [ ] Hit testing
+- **Hit testing**: `HitTester` for point-in-node and hit-test queries
+
+## I/O
+
+| Module | Description |
+| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `io::io_grida_fbs` | Encode/decode `.grida` FlatBuffers binaries. Bindings are generated from `format/grida.fbs` via `flatc --rust` (see repo root and `format/README.md`). |
+| `io::io_grida` | Decode Grida JSON documents into a `Scene`. |
+| `io::io_grida_patch` | Apply JSON Patch to a decoded scene. |
+| `io::io_figma` | Decode Figma API JSON into a `Scene` (feature-gated: `--features figma`). |
+| `io::io_svg`, `io::io_css`, `io::io_markdown` | Additional import/parsing helpers. |
+
+### Test fixtures
+
+Raw FlatBuffers test fixtures live in [`fixtures/test-grida/`](../../fixtures/test-grida/) at the repo root. In-memory round-trip tests are in `cargo test --package cg --test fbs_roundtrip`. See the fixtures directory README for format and version details.
+
+## NodeID system
+
+The canvas uses a dual-ID system:
+
+- **NodeId** (`u64`): Internal counter-based IDs for high-performance operations. Ephemeral and not serialized.
+- **UserNodeId** (`String`): External user-provided IDs for public APIs. Stable and serialized in `.grida` files.
+
+See [AGENTS.md](./AGENTS.md#nodeid-system) for details and migration notes.
+
+## Testing & development
+
+```sh
+# run tests
+cargo test
+
+# run fmt
+cargo fmt
+
+# run check
+cargo check
+cargo check --all-targets --all-features
+
+# run clippy (no deps — skips re-checking skia etc.)
+cargo clippy --no-deps --all-targets --all-features
+
+# run build
+cargo build
+
+# run examples (many require window/GPU; headless_gpu requires native-gl-context)
+cargo run --example
+cargo run --example headless_gpu --features native-gl-context
+```
+
+## Tools
+
+### `tool_io_grida` — Grida file validator
+
+CLI for validating `.grida` files and debugging parsing.
+
+```sh
+cargo run --example tool_io_grida
+```
+
+Validates file structure, reports node counts and types, and surfaces decode errors. See [examples/tool_io_grida.rs](./examples/tool_io_grida.rs) for full documentation.
+
+## Package docs
+
+```sh
+cargo doc --package cg --open --no-deps
+```
diff --git a/crates/grida-canvas/examples/fixtures/README.md b/crates/grida-canvas/examples/fixtures/README.md
new file mode 100644
index 0000000000..5d9ae9ea97
--- /dev/null
+++ b/crates/grida-canvas/examples/fixtures/README.md
@@ -0,0 +1,382 @@
+# `.grida` Test Fixtures
+
+Generated by the fixture generator tool:
+
+```sh
+cargo run --package cg --example tool_gen_fixtures
+```
+
+Each fixture is a self-contained `.grida` file focusing on a single feature area.
+The naming convention is `L0-.grida` where `L0` indicates baseline coverage.
+
+---
+
+## L0-shapes
+
+One of each basic shape type with a plain solid fill. No effects, no strokes (except line), no layout tricks.
+
+```text
+scene "L0 Shapes"
+├─ rectangle 200×100 red solid
+├─ ellipse 100×80 blue solid
+├─ regular_polygon 100×100 hexagon (6 sides), green solid, corner_radius=5
+├─ regular_star 120×120 5-point star, inner_radius=0.4, gold solid
+├─ line 200px black stroke 2px
+├─ text_span "Hello, Grida!" Inter 20px, black solid
+└─ vector 100×100 closed bezier quad (4 segments), purple fill + black stroke 1px
+```
+
+**Exercises:** all 7 leaf node types that the encoder supports.
+
+---
+
+## L0-shape-arc
+
+Ellipse arcs demonstrating inner_radius, start_angle, sweep angle, and corner_radius.
+
+```text
+scene "L0 Shape Arc"
+├─ ellipse full circle (defaults)
+├─ ellipse semicircle (angle=180°)
+├─ ellipse donut (inner_radius=0.5)
+├─ ellipse pie wedge (start_angle=45°, angle=90°)
+└─ ellipse rounded arc (inner_radius=0.6, angle=270°, corner_radius=8)
+```
+
+**Exercises:** EllipseNodeRec arc fields: inner_radius, start_angle, angle, corner_radius.
+
+---
+
+## L0-shape-polygon
+
+Regular polygons and star polygons with varying point counts and parameters.
+
+```text
+scene "L0 Shape Polygon"
+├─ regular_polygon triangle (3 sides)
+├─ regular_polygon pentagon (5, corner_radius=10)
+├─ regular_polygon hexagon (6, corner_radius=5)
+├─ regular_polygon octagon (8)
+├─ regular_star 4-point star (inner_radius=0.3, sharp)
+├─ regular_star 5-point star (inner_radius=0.4, corner_radius=3)
+├─ regular_star 6-point star (inner_radius=0.5)
+└─ regular_star 8-point star (inner_radius=0.7, corner_radius=6)
+```
+
+**Exercises:** RegularPolygonNodeRec (point_count, corner_radius), RegularStarPolygonNodeRec (inner_radius, corner_radius).
+
+---
+
+## L0-vector
+
+Vector network nodes: closed shapes, open paths, region fills, variable-width strokes.
+
+```text
+scene "L0 Vector"
+├─ vector closed bezier quad (4 curved segments, EvenOdd region, blue fill)
+├─ vector open path (3 vertices, 2 segments, no region, markers)
+├─ vector triangle with explicit region fill + dashed stroke (NonZero)
+└─ vector open path with variable-width stroke profile (3 stops)
+```
+
+**Exercises:** VectorNetwork (segments, loops, regions), FillRule (EvenOdd, NonZero), region fills, VarWidthProfile, markers on vectors.
+
+---
+
+## L0-paints
+
+One rectangle per paint type. Each rectangle uses exactly one fill to isolate the paint variant.
+
+```text
+scene "L0 Paints"
+├─ rectangle solid (red, full opacity)
+├─ rectangle linear gradient (red→blue, left→right)
+├─ rectangle radial gradient (yellow center→green edge, 80% opacity)
+├─ rectangle sweep gradient (cyan→magenta→yellow, 3 stops)
+└─ rectangle image paint (HASH ref, BoxFit::Cover)
+```
+
+**Exercises:** Solid, LinearGradient, RadialGradient, SweepGradient, ImagePaint.
+
+---
+
+## L0-paints-stack
+
+A single rectangle with multiple fills stacked bottom-to-top, demonstrating paint compositing.
+
+```text
+scene "L0 Paints Stack"
+└─ rectangle 200×200
+ fill[0]: solid white (base)
+ fill[1]: linear gradient (red→transparent, left→right)
+ fill[2]: radial gradient (yellow center→transparent edge)
+ fill[3]: sweep gradient (cyan→magenta→transparent)
+ fill[4]: image paint (HASH ref, 50% opacity)
+```
+
+**Exercises:** multiple fills on one node, paint opacity, compositing order.
+
+---
+
+## L0-strokes
+
+Stroke options on basic shapes: alignment, cap, join, dash array, markers.
+
+```text
+scene "L0 Strokes"
+├─ rectangle stroke_align=Center, cap=Butt, join=Miter, 2px black
+├─ rectangle stroke_align=Inside, cap=Round, join=Round, 3px blue
+├─ rectangle stroke_align=Outside, cap=Square, join=Bevel, 4px green
+├─ rectangle dashed stroke [10, 5], cap=Round, 2px black
+├─ line marker_start=Circle, marker_end=EquilateralTriangle, 2px
+└─ line marker_start=Diamond, marker_end=VerticalBar, 2px
+```
+
+**Exercises:** StrokeAlign (3), StrokeCap (3), StrokeJoin (3), StrokeDashArray, StrokeMarkerPreset (5 of 7).
+
+---
+
+## L0-strokes-rect
+
+Container-specific rectangular (per-side) stroke widths and per-side corner radii.
+
+```text
+scene "L0 Strokes Rect"
+├─ container 300×200 rectangular stroke (top=1, right=2, bottom=3, left=4), black
+└─ container 300×200 uniform stroke 2px + per-side corner radii (tl=0, tr=8, bl=16, br=24)
+```
+
+**Exercises:** StrokeWidth::Rectangular, per-side RectangularCornerRadius with varying radii.
+
+---
+
+## L0-image
+
+Image paint-specific properties: fit modes, resource references, quarter turns, alignment.
+
+```text
+scene "L0 Image"
+├─ rectangle ImagePaint, HASH ref, BoxFit::Cover, alignment=CENTER
+├─ rectangle ImagePaint, RID ref, BoxFit::Contain, alignment=CENTER
+├─ rectangle ImagePaint, Transform fit (scale=0.5, translate 10,20)
+└─ rectangle ImagePaint, quarter_turns=2, alignment=BOTTOM_RIGHT, Screen blend
+```
+
+**Exercises:** ResourceRef (HASH, RID), ImagePaintFit (Fit/Cover, Fit/Contain, Transform), quarter_turns, Alignment, paint-level blend_mode.
+
+---
+
+## L0-image-filters
+
+Image paint with non-default ImageFilters: exposure, contrast, saturation, temperature, tint, highlights, shadows.
+
+```text
+scene "L0 Image Filters"
+├─ rectangle bright + warm (exposure=0.5, temperature=0.4)
+├─ rectangle high contrast + desaturated (contrast=0.25, saturation=-0.8)
+├─ rectangle cool tint + shadow lift (temperature=-0.6, tint=-0.3, shadows=0.5)
+└─ rectangle all 7 filter channels non-zero
+```
+
+**Exercises:** ImageFilters (exposure, contrast, saturation, temperature, tint, highlights, shadows).
+
+---
+
+## L0-effects
+
+Each effect type on its own rectangle, one per node. Solid grey fill so the effect is visible.
+
+```text
+scene "L0 Effects"
+├─ rectangle blur: gaussian, radius=5
+├─ rectangle backdrop_blur: gaussian, radius=8
+├─ rectangle drop_shadow: dx=2, dy=2, blur=4, spread=0, black
+├─ rectangle inner_shadow: dx=1, dy=1, blur=3, spread=0, grey
+└─ rectangle noise: mono coloring, intensity=0.3
+```
+
+**Exercises:** FeLayerBlur, FeBackdropBlur, FeShadow (DropShadow), FeShadow (InnerShadow), FeNoiseEffect.
+
+---
+
+## L0-effects-glass
+
+Liquid glass effect centered over alternating black/white stripes with even
+padding (matching the golden reference pattern). The 380×380 stripe background
+is drawn first; the 300×300 glass panel sits centered with 40 px padding on
+every side.
+
+```text
+scene "L0 Effects Glass"
+├─ rectangle 380×380 fill: white (background)
+├─ 10× rectangle 20×380 fill: black (even stripes over white bg)
+└─ rectangle 300×300 corner_radius=60 glass: refraction=1.0, depth=100,
+ dispersion=1.0, blur_radius=0, light_intensity=0.7
+```
+
+**Exercises:** FeLiquidGlass with maximum refraction and chromatic aberration
+over a stripe pattern (same approach as `golden_liquid_glass.rs`).
+
+---
+
+## L0-type
+
+Core typography: font sizes, weights, alignment, decoration, spacing, transforms, stroke, effects.
+
+```text
+scene "L0 Type"
+├─ text_span "Regular 16px" Inter 16px, weight=400, Left/Top
+├─ text_span "Bold 24px" Inter 24px, weight=700, Center/Center
+├─ text_span "Right Aligned" Inter 16px, Right/Bottom
+├─ text_span "Justified Text..." Inter 14px, Justify/Top, width=200
+├─ text_span "With Stroke" Inter 20px, red stroke 1px Outside
+├─ text_span "Drop Shadow" Inter 20px, drop shadow
+├─ text_span "Max 2 Lines..." Inter 14px, max_lines=2, ellipsis="…"
+├─ text_span "Tracked + Tall..." Inter 16px, letter_spacing=4, line_height=2×
+├─ text_span "Underlined Text" Inter 18px, underline red 2px, skip_ink
+└─ text_span "uppercase transform" Inter 16px, TextTransform::Uppercase
+```
+
+**Exercises:** TextAlign (Left, Center, Right, Justify), TextAlignVertical (Top, Center, Bottom), text stroke + stroke_align, drop shadow, max_lines, ellipsis, letter_spacing, line_height, TextDecorationRec (underline, color, style, skip_ink, thickness), TextTransform.
+
+---
+
+## L0-type-fvar
+
+Variable font axes: weight, width, optical sizing, custom fvar axes, italic.
+
+```text
+scene "L0 Type fvar"
+├─ text_span "Thin 100" Inter weight=100
+├─ text_span "Light 300" Inter weight=300
+├─ text_span "Regular 400" Inter weight=400
+├─ text_span "Bold 700" Inter weight=700
+├─ text_span "Black 900" Inter weight=900
+├─ text_span "Condensed (width=75)" Inter font_width=75
+├─ text_span "Optical Size Fixed(48)" Inter font_optical_sizing=Fixed(48)
+├─ text_span "Custom Axes..." Roboto Flex, wght=600 wdth=80 GRAD=50
+└─ text_span "Italic Style" Inter italic=true
+```
+
+**Exercises:** FontWeight (100–900), font_width, FontOpticalSizing (Auto, Fixed), FontVariation (custom axes), font_style_italic.
+
+---
+
+## L0-type-features
+
+OpenType font features: ligatures, small caps, stylistic sets, tabular numbers, kerning.
+
+```text
+scene "L0 Type Features"
+├─ text_span "ffi ffl — liga off" Inter, liga=false
+├─ text_span "ffi ffl — liga on" Inter, liga=true
+├─ text_span "Small Caps Text — smcp" Inter, smcp=true
+├─ text_span "Stylistic Set 01 — ss01" Inter, ss01=true
+├─ text_span "0123456789 — tnum + zero" Inter, tnum=true zero=true
+└─ text_span "AVAW Typography — kern off" Inter, font_kerning=false
+```
+
+**Exercises:** FontFeature (liga, smcp, ss01, tnum, zero), font_kerning toggle.
+
+---
+
+## L0-masks
+
+Mask composition with each mask type. Each mask + its target are inside a dedicated group to avoid masking unrelated siblings.
+
+```text
+scene "L0 Masks"
+├─ group (image mask demo)
+│ ├─ rectangle 100×100 red solid (content)
+│ └─ rectangle 100×100 white solid (mask: Image/Alpha)
+└─ group (geometry mask demo)
+ ├─ rectangle 100×100 blue solid (content)
+ └─ ellipse 80×80 black solid (mask: Geometry)
+```
+
+**Exercises:** LayerMaskType::Image(Alpha), LayerMaskType::Geometry, mask scoping via group.
+
+---
+
+## L0-boolean-operation
+
+All four boolean path operations, each with two overlapping child rectangles.
+
+```text
+scene "L0 Boolean Operation"
+├─ boolean_op Union (red, 2 overlapping rects)
+├─ boolean_op Intersection (blue, 2 overlapping rects)
+├─ boolean_op Difference (green, 2 overlapping rects)
+└─ boolean_op Xor (yellow, 2 overlapping rects)
+```
+
+**Exercises:** BooleanPathOperation (Union, Intersection, Difference, Xor), BooleanPathOperationNodeRec with child shapes.
+
+---
+
+## L0-layout-position
+
+Positioning modes for shapes within a container. No flex — uses Normal layout mode.
+
+```text
+scene "L0 Layout Position"
+└─ container 400×300 Normal layout, light grey fill
+ ├─ rectangle 80×60 Cartesian position (x=20, y=20)
+ ├─ rectangle 80×60 Inset position (top=50, left=150)
+ └─ rectangle 80×60 Absolute positioning (layout_child, inset top=150, left=20)
+```
+
+**Exercises:** LayoutPositioningBasis::Cartesian, LayoutPositioningBasis::Inset, LayoutPositioning::Absolute.
+
+---
+
+## L0-layout-flex
+
+Flex layout demonstration with two containers showing different configurations.
+
+```text
+scene "L0 Layout Flex"
+├─ container 500×80 horizontal flex, gap=10, main=SpaceBetween, cross=Center
+│ ├─ rectangle 100×50 (auto)
+│ ├─ rectangle 100×50 (auto)
+│ └─ rectangle fill×50 (flex_grow=1)
+└─ container 200×300 vertical flex, main=Center, cross=Stretch, padding=16, gap=8
+ ├─ rectangle auto×40
+ └─ rectangle auto×40
+```
+
+**Exercises:** LayoutMode::Flex, Axis (Horizontal, Vertical), MainAxisAlignment::SpaceBetween, MainAxisAlignment::Center, CrossAxisAlignment::Center, CrossAxisAlignment::Stretch, layout_grow, LayoutGap, padding.
+
+---
+
+## L0-layout-transform
+
+Rotation and affine transforms on containers and shapes.
+
+```text
+scene "L0 Layout Transform"
+├─ container 200×150 rotated 90°, Cartesian at (300, 50), blue fill
+├─ rectangle 120×80 rotated 45°, at (50, 50), red fill
+└─ line 200px rotated 45°, at (400, 200), black stroke 2px
+```
+
+**Exercises:** Container rotation, shape rotation via AffineTransform, line rotation.
+
+---
+
+## Not included (rationale)
+
+| Topic | Reason |
+| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| Blend modes | All 16 + PassThrough are exhaustively covered by the `gen_all_blend_modes` in-memory test. A fixture file would be 17 identical rectangles — low visual value. |
+| Deep nesting | Covered by `gen_deep_nesting` (4 levels). Nesting is structural, not visual. |
+| Inactive / edge cases | Covered by `gen_inactive_node`. An invisible node in a visual fixture adds nothing. |
+
+---
+
+## Regenerating
+
+```sh
+# regenerate L0.grida (all scenes)
+cargo run --package cg --example tool_gen_fixtures
+```
diff --git a/crates/grida-canvas/examples/fixtures/l0_boolean_operation.rs b/crates/grida-canvas/examples/fixtures/l0_boolean_operation.rs
new file mode 100644
index 0000000000..09555fd66c
--- /dev/null
+++ b/crates/grida-canvas/examples/fixtures/l0_boolean_operation.rs
@@ -0,0 +1,88 @@
+use super::*;
+use cg::cg::stroke_width::SingularStrokeWidth;
+use math2::transform::AffineTransform;
+use std::collections::HashMap;
+
+/// All four boolean operations, each with two overlapping child rectangles.
+pub fn build() -> Scene {
+ let ops = [
+ (BooleanPathOperation::Union, solid(220, 59, 59, 255)),
+ (BooleanPathOperation::Intersection, solid(59, 100, 220, 255)),
+ (BooleanPathOperation::Difference, solid(59, 180, 75, 255)),
+ (BooleanPathOperation::Xor, solid(255, 200, 40, 255)),
+ ];
+
+ let gap = 160.0;
+ let mut nodes: Vec<(u64, Node)> = Vec::new();
+ let mut links: HashMap> = HashMap::new();
+ let mut roots: Vec = Vec::new();
+ let mut next_id = 1u64;
+
+ for (i, (op, fill)) in ops.iter().enumerate() {
+ let x = (i as f32) * gap;
+ let bool_id = next_id;
+ next_id += 1;
+
+ let bool_node = Node::BooleanOperation(BooleanPathOperationNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ transform: Some(AffineTransform::from_box_center(x, 0.0, 0.0, 0.0, 0.0)),
+ op: *op,
+ corner_radius: None,
+ fills: Paints::new(vec![fill.clone()]),
+ strokes: Paints::new(vec![solid(0, 0, 0, 255)]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: SingularStrokeWidth(Some(1.0)),
+ });
+
+ // Two overlapping rectangles as children
+ let child_a_id = next_id;
+ next_id += 1;
+ let child_a = Node::Rectangle(RectangleNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ transform: AffineTransform::from_box_center(0.0, 0.0, 80.0, 80.0, 0.0),
+ size: Size { width: 80.0, height: 80.0 },
+ corner_radius: RectangularCornerRadius::default(),
+ corner_smoothing: CornerSmoothing(0.0),
+ fills: Paints::new(vec![]),
+ strokes: Paints::new(vec![]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: StrokeWidth::None,
+ effects: LayerEffects::default(),
+ layout_child: None,
+ });
+
+ let child_b_id = next_id;
+ next_id += 1;
+ let child_b = Node::Rectangle(RectangleNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ transform: AffineTransform::from_box_center(40.0, 40.0, 80.0, 80.0, 0.0),
+ size: Size { width: 80.0, height: 80.0 },
+ corner_radius: RectangularCornerRadius::default(),
+ corner_smoothing: CornerSmoothing(0.0),
+ fills: Paints::new(vec![]),
+ strokes: Paints::new(vec![]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: StrokeWidth::None,
+ effects: LayerEffects::default(),
+ layout_child: None,
+ });
+
+ nodes.push((bool_id, bool_node));
+ nodes.push((child_a_id, child_a));
+ nodes.push((child_b_id, child_b));
+ links.insert(bool_id, vec![child_a_id, child_b_id]);
+ roots.push(bool_id);
+ }
+
+ build_scene("L0 Boolean Operation", None, nodes, links, roots)
+}
diff --git a/crates/grida-canvas/examples/fixtures/l0_container.rs b/crates/grida-canvas/examples/fixtures/l0_container.rs
new file mode 100644
index 0000000000..7836a533e5
--- /dev/null
+++ b/crates/grida-canvas/examples/fixtures/l0_container.rs
@@ -0,0 +1,190 @@
+use super::*;
+use std::collections::HashMap;
+
+/// Container-specific features: clip on/off, nesting, InitialContainer.
+pub fn build() -> Scene {
+ // ── [1] Outer container (clip=true) ─────────────────────────────────
+ // Child rectangle intentionally overflows to demonstrate clipping.
+ let clip_on = Node::Container(ContainerNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ rotation: 0.0,
+ position: LayoutPositioningBasis::Inset(EdgeInsets {
+ top: 0.0, right: 0.0, bottom: 0.0, left: 0.0,
+ }),
+ layout_container: LayoutContainerStyle::default(),
+ layout_dimensions: LayoutDimensionStyle {
+ layout_target_width: Some(200.0),
+ layout_target_height: Some(150.0),
+ layout_min_width: None, layout_max_width: None,
+ layout_min_height: None, layout_max_height: None,
+ layout_target_aspect_ratio: None,
+ },
+ layout_child: None,
+ corner_radius: {
+ use cg::cg::types::Radius;
+ let r = Radius::circular(12.0);
+ RectangularCornerRadius { tl: r, tr: r, bl: r, br: r }
+ },
+ corner_smoothing: CornerSmoothing(0.0),
+ fills: Paints::new(vec![solid(235, 240, 255, 255)]),
+ strokes: Paints::new(vec![solid(100, 120, 200, 255)]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: StrokeWidth::Uniform(1.0),
+ effects: LayerEffects::default(),
+ clip: true,
+ });
+
+ // Overflowing child — should be clipped by parent
+ let overflow_rect = rect(60.0, 80.0, 200.0, 120.0, solid(220, 59, 59, 200));
+
+ // ── [3] Same container but clip=false ───────────────────────────────
+ let clip_off = Node::Container(ContainerNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ rotation: 0.0,
+ position: LayoutPositioningBasis::Inset(EdgeInsets {
+ top: 0.0, right: 0.0, bottom: 0.0, left: 240.0,
+ }),
+ layout_container: LayoutContainerStyle::default(),
+ layout_dimensions: LayoutDimensionStyle {
+ layout_target_width: Some(200.0),
+ layout_target_height: Some(150.0),
+ layout_min_width: None, layout_max_width: None,
+ layout_min_height: None, layout_max_height: None,
+ layout_target_aspect_ratio: None,
+ },
+ layout_child: None,
+ corner_radius: {
+ use cg::cg::types::Radius;
+ let r = Radius::circular(12.0);
+ RectangularCornerRadius { tl: r, tr: r, bl: r, br: r }
+ },
+ corner_smoothing: CornerSmoothing(0.0),
+ fills: Paints::new(vec![solid(235, 255, 240, 255)]),
+ strokes: Paints::new(vec![solid(100, 200, 120, 255)]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: StrokeWidth::Uniform(1.0),
+ effects: LayerEffects::default(),
+ clip: false,
+ });
+
+ // Same overflowing child — should be visible beyond parent bounds
+ let overflow_rect2 = rect(60.0, 80.0, 200.0, 120.0, solid(59, 180, 75, 200));
+
+ // ── [5] Nested containers (3 levels deep) ──────────────────────────
+ let outer = Node::Container(ContainerNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ rotation: 0.0,
+ position: LayoutPositioningBasis::Inset(EdgeInsets {
+ top: 180.0, right: 0.0, bottom: 0.0, left: 0.0,
+ }),
+ layout_container: LayoutContainerStyle::default(),
+ layout_dimensions: LayoutDimensionStyle {
+ layout_target_width: Some(400.0),
+ layout_target_height: Some(250.0),
+ layout_min_width: None, layout_max_width: None,
+ layout_min_height: None, layout_max_height: None,
+ layout_target_aspect_ratio: None,
+ },
+ layout_child: None,
+ corner_radius: RectangularCornerRadius::default(),
+ corner_smoothing: CornerSmoothing(0.0),
+ fills: Paints::new(vec![solid(245, 245, 245, 255)]),
+ strokes: Paints::new(vec![solid(180, 180, 180, 255)]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: StrokeWidth::Uniform(1.0),
+ effects: LayerEffects::default(),
+ clip: false,
+ });
+
+ let middle = Node::Container(ContainerNodeRec {
+ active: true,
+ opacity: 0.9,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ rotation: 0.0,
+ position: LayoutPositioningBasis::Inset(EdgeInsets {
+ top: 20.0, right: 0.0, bottom: 0.0, left: 20.0,
+ }),
+ layout_container: LayoutContainerStyle::default(),
+ layout_dimensions: LayoutDimensionStyle {
+ layout_target_width: Some(300.0),
+ layout_target_height: Some(180.0),
+ layout_min_width: None, layout_max_width: None,
+ layout_min_height: None, layout_max_height: None,
+ layout_target_aspect_ratio: None,
+ },
+ layout_child: None,
+ corner_radius: {
+ use cg::cg::types::Radius;
+ let r = Radius::circular(8.0);
+ RectangularCornerRadius { tl: r, tr: r, bl: r, br: r }
+ },
+ corner_smoothing: CornerSmoothing(0.0),
+ fills: Paints::new(vec![solid(220, 230, 255, 255)]),
+ strokes: Paints::new(vec![solid(150, 170, 220, 255)]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: StrokeWidth::Uniform(1.0),
+ effects: LayerEffects::default(),
+ clip: true,
+ });
+
+ let inner = Node::Container(ContainerNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ rotation: 0.0,
+ position: LayoutPositioningBasis::Inset(EdgeInsets {
+ top: 15.0, right: 0.0, bottom: 0.0, left: 15.0,
+ }),
+ layout_container: LayoutContainerStyle::default(),
+ layout_dimensions: LayoutDimensionStyle {
+ layout_target_width: Some(200.0),
+ layout_target_height: Some(120.0),
+ layout_min_width: None, layout_max_width: None,
+ layout_min_height: None, layout_max_height: None,
+ layout_target_aspect_ratio: None,
+ },
+ layout_child: None,
+ corner_radius: RectangularCornerRadius::default(),
+ corner_smoothing: CornerSmoothing(0.0),
+ fills: Paints::new(vec![solid(255, 240, 230, 255)]),
+ strokes: Paints::new(vec![solid(220, 180, 150, 255)]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: StrokeWidth::Uniform(1.0),
+ effects: LayerEffects::default(),
+ clip: false,
+ });
+
+ // Leaf inside the innermost container
+ let leaf = rect(10.0, 10.0, 80.0, 60.0, solid(128, 60, 200, 255));
+
+ // ── Tree ────────────────────────────────────────────────────────────
+ let mut links = HashMap::new();
+ links.insert(1u64, vec![2u64]); // clip_on → overflow_rect
+ links.insert(3u64, vec![4u64]); // clip_off → overflow_rect2
+ links.insert(5u64, vec![6u64]); // outer → middle
+ links.insert(6u64, vec![7u64]); // middle → inner
+ links.insert(7u64, vec![8u64]); // inner → leaf
+
+ build_scene(
+ "L0 Container",
+ None,
+ vec![
+ (1, clip_on), (2, overflow_rect),
+ (3, clip_off), (4, overflow_rect2),
+ (5, outer), (6, middle), (7, inner), (8, leaf),
+ ],
+ links,
+ vec![1, 3, 5],
+ )
+}
diff --git a/crates/grida-canvas/examples/fixtures/l0_effects.rs b/crates/grida-canvas/examples/fixtures/l0_effects.rs
new file mode 100644
index 0000000000..0ca9c3c534
--- /dev/null
+++ b/crates/grida-canvas/examples/fixtures/l0_effects.rs
@@ -0,0 +1,77 @@
+use super::*;
+use cg::cg::color::CGColor;
+use cg::cg::fe::*;
+
+fn effect_rect(x: f32, effects: LayerEffects) -> Node {
+ Node::Rectangle(RectangleNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ transform: AffineTransform::from_box_center(x, 0.0, 150.0, 150.0, 0.0),
+ size: Size { width: 150.0, height: 150.0 },
+ corner_radius: RectangularCornerRadius::default(),
+ corner_smoothing: CornerSmoothing(0.0),
+ fills: Paints::new(vec![solid(180, 180, 180, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: StrokeWidth::None,
+ effects,
+ layout_child: None,
+ })
+}
+
+pub fn build() -> Scene {
+ let gap = 170.0;
+
+ let blur = effect_rect(0.0, LayerEffects {
+ blur: Some(FeLayerBlur {
+ active: true,
+ blur: FeBlur::Gaussian(FeGaussianBlur { radius: 5.0 }),
+ }),
+ ..LayerEffects::default()
+ });
+
+ let backdrop = effect_rect(gap, LayerEffects {
+ backdrop_blur: Some(FeBackdropBlur {
+ active: true,
+ blur: FeBlur::Gaussian(FeGaussianBlur { radius: 8.0 }),
+ }),
+ ..LayerEffects::default()
+ });
+
+ let drop_shadow = effect_rect(gap * 2.0, LayerEffects {
+ shadows: vec![FilterShadowEffect::DropShadow(FeShadow {
+ dx: 2.0, dy: 2.0, blur: 4.0, spread: 0.0,
+ color: CGColor { r: 0, g: 0, b: 0, a: 255 },
+ active: true,
+ })],
+ ..LayerEffects::default()
+ });
+
+ let inner_shadow = effect_rect(gap * 3.0, LayerEffects {
+ shadows: vec![FilterShadowEffect::InnerShadow(FeShadow {
+ dx: 1.0, dy: 1.0, blur: 3.0, spread: 0.0,
+ color: CGColor { r: 128, g: 128, b: 128, a: 200 },
+ active: true,
+ })],
+ ..LayerEffects::default()
+ });
+
+ let noise = effect_rect(gap * 4.0, LayerEffects {
+ noises: vec![FeNoiseEffect {
+ active: true,
+ noise_size: 1.0,
+ density: 0.3,
+ num_octaves: 4,
+ seed: 42.0,
+ coloring: NoiseEffectColors::Mono {
+ color: CGColor { r: 0, g: 0, b: 0, a: 64 },
+ },
+ blend_mode: BlendMode::Normal,
+ }],
+ ..LayerEffects::default()
+ });
+
+ flat_scene("L0 Effects", vec![blur, backdrop, drop_shadow, inner_shadow, noise])
+}
diff --git a/crates/grida-canvas/examples/fixtures/l0_effects_glass.rs b/crates/grida-canvas/examples/fixtures/l0_effects_glass.rs
new file mode 100644
index 0000000000..5a82b05e3a
--- /dev/null
+++ b/crates/grida-canvas/examples/fixtures/l0_effects_glass.rs
@@ -0,0 +1,65 @@
+use super::*;
+use cg::cg::fe::*;
+
+pub fn build() -> Scene {
+ // Note: rect(x, y, w, h, ..) uses from_box_center which, at 0° rotation,
+ // places the rect's top-left at (x, y).
+
+ let glass_size = 300.0;
+ let padding = 40.0;
+ let total = glass_size + padding * 2.0; // 380
+
+ // ── Background ─────────────────────────────────────────────────────
+ // White base + black stripes → alternating black/white pattern.
+ // Top-left at (0, 0), spans [0 .. total] in both axes.
+ let bg = rect(0.0, 0.0, total, total, solid(255, 255, 255, 255));
+
+ let stripe_w = 10.0;
+ let n_stripes = (total / stripe_w).ceil() as i32;
+ let mut nodes: Vec = vec![bg];
+ for i in 0..n_stripes {
+ if i % 2 != 0 {
+ continue; // white gap covered by bg
+ }
+ let x = i as f32 * stripe_w; // top-left x within [0 .. total]
+ nodes.push(rect(x, 0.0, stripe_w, total, solid(0, 0, 0, 255)));
+ }
+
+ // ── Glass panel ────────────────────────────────────────────────────
+ // Inset by `padding` on every side → top-left at (padding, padding),
+ // centered within the stripe background.
+ // Parameters match the golden reference (golden_liquid_glass.rs).
+ let glass_rect = Node::Rectangle(RectangleNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ transform: AffineTransform::from_box_center(
+ padding, padding, glass_size, glass_size, 0.0,
+ ),
+ size: Size { width: glass_size, height: glass_size },
+ corner_radius: RectangularCornerRadius::circular(60.0),
+ corner_smoothing: CornerSmoothing(0.0),
+ fills: Paints::new(vec![]),
+ strokes: Paints::new(vec![]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: StrokeWidth::None,
+ effects: LayerEffects {
+ glass: Some(FeLiquidGlass {
+ active: true,
+ light_intensity: 0.7,
+ light_angle: 45.0,
+ refraction: 1.0,
+ depth: 100.0,
+ blur_radius: 0.0,
+ dispersion: 1.0,
+ }),
+ ..LayerEffects::default()
+ },
+ layout_child: None,
+ });
+
+ nodes.push(glass_rect);
+
+ flat_scene("L0 Effects Glass", nodes)
+}
diff --git a/crates/grida-canvas/examples/fixtures/l0_group.rs b/crates/grida-canvas/examples/fixtures/l0_group.rs
new file mode 100644
index 0000000000..185150bc9c
--- /dev/null
+++ b/crates/grida-canvas/examples/fixtures/l0_group.rs
@@ -0,0 +1,83 @@
+use super::*;
+use math2::transform::AffineTransform;
+use std::collections::HashMap;
+
+/// Group node features: grouping children, opacity inheritance, blend modes, nesting.
+pub fn build() -> Scene {
+ // ── [1] Simple group with two children ──────────────────────────────
+ let g1 = Node::Group(GroupNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ transform: Some(AffineTransform::from_box_center(0.0, 0.0, 0.0, 0.0, 0.0)),
+ });
+ let g1_a = rect(0.0, 0.0, 80.0, 80.0, solid(220, 59, 59, 255));
+ let g1_b = rect(40.0, 40.0, 80.0, 80.0, solid(59, 100, 220, 200));
+
+ // ── [4] Group with reduced opacity (children inherit) ───────────────
+ let g2 = Node::Group(GroupNodeRec {
+ active: true,
+ opacity: 0.4,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ transform: Some(AffineTransform::from_box_center(200.0, 0.0, 0.0, 0.0, 0.0)),
+ });
+ let g2_a = rect(0.0, 0.0, 80.0, 80.0, solid(220, 59, 59, 255));
+ let g2_b = rect(40.0, 40.0, 80.0, 80.0, solid(59, 100, 220, 255));
+
+ // ── [7] Group with blend mode ───────────────────────────────────────
+ let g3 = Node::Group(GroupNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::Blend(BlendMode::Multiply),
+ mask: None,
+ transform: Some(AffineTransform::from_box_center(400.0, 0.0, 0.0, 0.0, 0.0)),
+ });
+ let g3_a = rect(0.0, 0.0, 100.0, 100.0, solid(255, 200, 40, 255));
+ let g3_b = rect(30.0, 30.0, 100.0, 100.0, solid(59, 100, 220, 255));
+
+ // ── [10] Nested groups ──────────────────────────────────────────────
+ let g_outer = Node::Group(GroupNodeRec {
+ active: true,
+ opacity: 0.8,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ transform: Some(AffineTransform::from_box_center(0.0, 160.0, 0.0, 0.0, 0.0)),
+ });
+
+ let g_inner = Node::Group(GroupNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::Blend(BlendMode::Screen),
+ mask: None,
+ transform: Some(AffineTransform::from_box_center(20.0, 20.0, 0.0, 0.0, 0.0)),
+ });
+
+ let leaf1 = rect(0.0, 0.0, 60.0, 60.0, solid(59, 180, 75, 255));
+ let leaf2 = rect(30.0, 30.0, 60.0, 60.0, solid(128, 60, 200, 255));
+
+ // Sibling of g_inner inside g_outer
+ let sibling = ellipse(150.0, 20.0, 80.0, 80.0, solid(220, 120, 60, 255));
+
+ // ── Tree ────────────────────────────────────────────────────────────
+ let mut links = HashMap::new();
+ links.insert(1u64, vec![2, 3]); // g1 → children
+ links.insert(4u64, vec![5, 6]); // g2 → children
+ links.insert(7u64, vec![8, 9]); // g3 → children
+ links.insert(10u64, vec![11, 14]); // g_outer → g_inner + sibling
+ links.insert(11u64, vec![12, 13]); // g_inner → leaves
+
+ build_scene(
+ "L0 Group",
+ None,
+ vec![
+ (1, g1), (2, g1_a), (3, g1_b),
+ (4, g2), (5, g2_a), (6, g2_b),
+ (7, g3), (8, g3_a), (9, g3_b),
+ (10, g_outer), (11, g_inner), (12, leaf1), (13, leaf2), (14, sibling),
+ ],
+ links,
+ vec![1, 4, 7, 10],
+ )
+}
diff --git a/crates/grida-canvas/examples/fixtures/l0_image.rs b/crates/grida-canvas/examples/fixtures/l0_image.rs
new file mode 100644
index 0000000000..439cf6848f
--- /dev/null
+++ b/crates/grida-canvas/examples/fixtures/l0_image.rs
@@ -0,0 +1,37 @@
+use super::*;
+use cg::cg::alignment::Alignment;
+use math2::box_fit::BoxFit;
+use math2::transform::AffineTransform;
+
+pub fn build() -> Scene {
+ let s = 150.0;
+ let gap = 170.0;
+ let img = || ResourceRef::HASH(SYSTEM_IMAGE.to_owned());
+
+ // Cover fit
+ let r1 = rect(0.0, 0.0, s, s,
+ image_paint_with(img(), ImagePaintFit::Fit(BoxFit::Cover)));
+
+ // Contain fit
+ let r2 = rect(gap, 0.0, s, s,
+ image_paint_with(img(), ImagePaintFit::Fit(BoxFit::Contain)));
+
+ // Transform fit (scale + offset)
+ let r3 = rect(gap * 2.0, 0.0, s, s,
+ image_paint_with(img(), ImagePaintFit::Transform(AffineTransform::new(10.0, 20.0, 0.0))));
+
+ // Quarter turns + alignment + Screen blend
+ let r4 = rect(gap * 3.0, 0.0, s, s,
+ Paint::Image(ImagePaint {
+ active: true,
+ image: img(),
+ fit: ImagePaintFit::Fit(BoxFit::Cover),
+ filters: ImageFilters::default(),
+ opacity: 1.0,
+ blend_mode: BlendMode::Screen,
+ quarter_turns: 2,
+ alignement: Alignment::BOTTOM_RIGHT,
+ }));
+
+ flat_scene("L0 Image", vec![r1, r2, r3, r4])
+}
diff --git a/crates/grida-canvas/examples/fixtures/l0_image_filters.rs b/crates/grida-canvas/examples/fixtures/l0_image_filters.rs
new file mode 100644
index 0000000000..5912556953
--- /dev/null
+++ b/crates/grida-canvas/examples/fixtures/l0_image_filters.rs
@@ -0,0 +1,80 @@
+use super::*;
+use cg::cg::alignment::Alignment;
+use math2::box_fit::BoxFit;
+
+/// Image paint with non-default filter values: exposure, contrast, saturation, etc.
+pub fn build() -> Scene {
+ let s = 150.0;
+ let gap = 170.0;
+
+ // Bright + warm
+ let bright_warm = rect(0.0, 0.0, s, s, Paint::Image(ImagePaint {
+ active: true,
+ image: ResourceRef::HASH(SYSTEM_IMAGE.to_owned()),
+ fit: ImagePaintFit::Fit(BoxFit::Cover),
+ filters: ImageFilters {
+ exposure: 0.5,
+ temperature: 0.4,
+ ..ImageFilters::default()
+ },
+ opacity: 1.0,
+ blend_mode: BlendMode::Normal,
+ quarter_turns: 0,
+ alignement: Alignment::CENTER,
+ }));
+
+ // High contrast + desaturated
+ let contrast_desat = rect(gap, 0.0, s, s, Paint::Image(ImagePaint {
+ active: true,
+ image: ResourceRef::HASH(SYSTEM_IMAGE.to_owned()),
+ fit: ImagePaintFit::Fit(BoxFit::Cover),
+ filters: ImageFilters {
+ contrast: 0.25,
+ saturation: -0.8,
+ ..ImageFilters::default()
+ },
+ opacity: 1.0,
+ blend_mode: BlendMode::Normal,
+ quarter_turns: 0,
+ alignement: Alignment::CENTER,
+ }));
+
+ // Cool tint + shadow lift
+ let cool_shadow = rect(gap * 2.0, 0.0, s, s, Paint::Image(ImagePaint {
+ active: true,
+ image: ResourceRef::HASH(SYSTEM_IMAGE.to_owned()),
+ fit: ImagePaintFit::Fit(BoxFit::Cover),
+ filters: ImageFilters {
+ temperature: -0.6,
+ tint: -0.3,
+ shadows: 0.5,
+ ..ImageFilters::default()
+ },
+ opacity: 1.0,
+ blend_mode: BlendMode::Normal,
+ quarter_turns: 0,
+ alignement: Alignment::CENTER,
+ }));
+
+ // All filters non-zero
+ let all_filters = rect(gap * 3.0, 0.0, s, s, Paint::Image(ImagePaint {
+ active: true,
+ image: ResourceRef::HASH(SYSTEM_IMAGE.to_owned()),
+ fit: ImagePaintFit::Fit(BoxFit::Cover),
+ filters: ImageFilters {
+ exposure: 0.2,
+ contrast: 0.1,
+ saturation: 0.3,
+ temperature: -0.2,
+ tint: 0.15,
+ highlights: -0.4,
+ shadows: 0.3,
+ },
+ opacity: 1.0,
+ blend_mode: BlendMode::Normal,
+ quarter_turns: 0,
+ alignement: Alignment::CENTER,
+ }));
+
+ flat_scene("L0 Image Filters", vec![bright_warm, contrast_desat, cool_shadow, all_filters])
+}
diff --git a/crates/grida-canvas/examples/fixtures/l0_layout_flex.rs b/crates/grida-canvas/examples/fixtures/l0_layout_flex.rs
new file mode 100644
index 0000000000..185d531916
--- /dev/null
+++ b/crates/grida-canvas/examples/fixtures/l0_layout_flex.rs
@@ -0,0 +1,121 @@
+use super::*;
+use std::collections::HashMap;
+
+pub fn build() -> Scene {
+ // Horizontal flex container: SpaceBetween, Center
+ let h_container = Node::Container(ContainerNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ rotation: 0.0,
+ position: LayoutPositioningBasis::Inset(EdgeInsets {
+ top: 0.0, right: 0.0, bottom: 0.0, left: 0.0,
+ }),
+ layout_container: LayoutContainerStyle {
+ layout_mode: LayoutMode::Flex,
+ layout_direction: Axis::Horizontal,
+ layout_wrap: Some(LayoutWrap::NoWrap),
+ layout_main_axis_alignment: Some(MainAxisAlignment::SpaceBetween),
+ layout_cross_axis_alignment: Some(CrossAxisAlignment::Center),
+ layout_padding: None,
+ layout_gap: Some(LayoutGap { main_axis_gap: 10.0, cross_axis_gap: 0.0 }),
+ },
+ layout_dimensions: LayoutDimensionStyle {
+ layout_target_width: Some(500.0),
+ layout_target_height: Some(80.0),
+ layout_min_width: None, layout_max_width: None,
+ layout_min_height: None, layout_max_height: None,
+ layout_target_aspect_ratio: None,
+ },
+ layout_child: None,
+ corner_radius: RectangularCornerRadius::default(),
+ corner_smoothing: CornerSmoothing(0.0),
+ fills: Paints::new(vec![solid(240, 240, 245, 255)]),
+ strokes: Paints::new(vec![solid(200, 200, 210, 255)]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: StrokeWidth::Uniform(1.0),
+ effects: LayerEffects::default(),
+ clip: false,
+ });
+
+ let h1 = rect(0.0, 0.0, 100.0, 50.0, solid(220, 59, 59, 255));
+ let h2 = rect(0.0, 0.0, 100.0, 50.0, solid(59, 100, 220, 255));
+ // flex_grow=1
+ let h3 = Node::Rectangle(RectangleNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ transform: AffineTransform::from_box_center(0.0, 0.0, 100.0, 50.0, 0.0),
+ size: Size { width: 100.0, height: 50.0 },
+ corner_radius: RectangularCornerRadius::default(),
+ corner_smoothing: CornerSmoothing(0.0),
+ fills: Paints::new(vec![solid(59, 180, 75, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: StrokeWidth::None,
+ effects: LayerEffects::default(),
+ layout_child: Some(LayoutChildStyle {
+ layout_grow: 1.0,
+ layout_positioning: LayoutPositioning::Auto,
+ }),
+ });
+
+ // Vertical flex container: Center, Stretch
+ let v_container = Node::Container(ContainerNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ rotation: 0.0,
+ position: LayoutPositioningBasis::Inset(EdgeInsets {
+ top: 100.0, right: 0.0, bottom: 0.0, left: 0.0,
+ }),
+ layout_container: LayoutContainerStyle {
+ layout_mode: LayoutMode::Flex,
+ layout_direction: Axis::Vertical,
+ layout_wrap: Some(LayoutWrap::NoWrap),
+ layout_main_axis_alignment: Some(MainAxisAlignment::Center),
+ layout_cross_axis_alignment: Some(CrossAxisAlignment::Stretch),
+ layout_padding: Some(EdgeInsets {
+ top: 16.0, right: 16.0, bottom: 16.0, left: 16.0,
+ }),
+ layout_gap: Some(LayoutGap { main_axis_gap: 8.0, cross_axis_gap: 0.0 }),
+ },
+ layout_dimensions: LayoutDimensionStyle {
+ layout_target_width: Some(200.0),
+ layout_target_height: Some(200.0),
+ layout_min_width: None, layout_max_width: None,
+ layout_min_height: None, layout_max_height: None,
+ layout_target_aspect_ratio: None,
+ },
+ layout_child: None,
+ corner_radius: RectangularCornerRadius::default(),
+ corner_smoothing: CornerSmoothing(0.0),
+ fills: Paints::new(vec![solid(245, 240, 240, 255)]),
+ strokes: Paints::new(vec![solid(210, 200, 200, 255)]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: StrokeWidth::Uniform(1.0),
+ effects: LayerEffects::default(),
+ clip: false,
+ });
+
+ let v1 = rect(0.0, 0.0, 80.0, 40.0, solid(255, 200, 40, 255));
+ let v2 = rect(0.0, 0.0, 80.0, 40.0, solid(128, 60, 200, 255));
+
+ let mut links = HashMap::new();
+ links.insert(1u64, vec![2u64, 3u64, 4u64]);
+ links.insert(5u64, vec![6u64, 7u64]);
+
+ build_scene(
+ "L0 Layout Flex",
+ None,
+ vec![
+ (1, h_container), (2, h1), (3, h2), (4, h3),
+ (5, v_container), (6, v1), (7, v2),
+ ],
+ links,
+ vec![1, 5],
+ )
+}
diff --git a/crates/grida-canvas/examples/fixtures/l0_layout_position.rs b/crates/grida-canvas/examples/fixtures/l0_layout_position.rs
new file mode 100644
index 0000000000..121e2c10c0
--- /dev/null
+++ b/crates/grida-canvas/examples/fixtures/l0_layout_position.rs
@@ -0,0 +1,70 @@
+use super::*;
+use std::collections::HashMap;
+
+pub fn build() -> Scene {
+ let container = Node::Container(ContainerNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ rotation: 0.0,
+ position: LayoutPositioningBasis::Inset(EdgeInsets {
+ top: 0.0, right: 0.0, bottom: 0.0, left: 0.0,
+ }),
+ layout_container: LayoutContainerStyle::default(), // Normal mode
+ layout_dimensions: LayoutDimensionStyle {
+ layout_target_width: Some(400.0),
+ layout_target_height: Some(300.0),
+ layout_min_width: None, layout_max_width: None,
+ layout_min_height: None, layout_max_height: None,
+ layout_target_aspect_ratio: None,
+ },
+ layout_child: None,
+ corner_radius: RectangularCornerRadius::default(),
+ corner_smoothing: CornerSmoothing(0.0),
+ fills: Paints::new(vec![solid(245, 245, 245, 255)]),
+ strokes: Paints::new(vec![solid(200, 200, 200, 255)]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: StrokeWidth::Uniform(1.0),
+ effects: LayerEffects::default(),
+ clip: false,
+ });
+
+ // Child at Cartesian (20, 20)
+ let c1 = rect(20.0, 20.0, 80.0, 60.0, solid(220, 59, 59, 255));
+
+ // Child at Inset (top=50, left=150) — same x,y via inset
+ let c2 = rect(150.0, 50.0, 80.0, 60.0, solid(59, 100, 220, 255));
+
+ // Child with layout_child Absolute positioning
+ let c3 = Node::Rectangle(RectangleNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ transform: AffineTransform::from_box_center(20.0, 150.0, 80.0, 60.0, 0.0),
+ size: Size { width: 80.0, height: 60.0 },
+ corner_radius: RectangularCornerRadius::default(),
+ corner_smoothing: CornerSmoothing(0.0),
+ fills: Paints::new(vec![solid(59, 180, 75, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: StrokeWidth::None,
+ effects: LayerEffects::default(),
+ layout_child: Some(LayoutChildStyle {
+ layout_grow: 0.0,
+ layout_positioning: LayoutPositioning::Absolute,
+ }),
+ });
+
+ let mut links = HashMap::new();
+ links.insert(1u64, vec![2u64, 3u64, 4u64]);
+
+ build_scene(
+ "L0 Layout Position",
+ None,
+ vec![(1, container), (2, c1), (3, c2), (4, c3)],
+ links,
+ vec![1],
+ )
+}
diff --git a/crates/grida-canvas/examples/fixtures/l0_layout_transform.rs b/crates/grida-canvas/examples/fixtures/l0_layout_transform.rs
new file mode 100644
index 0000000000..8aee256c0a
--- /dev/null
+++ b/crates/grida-canvas/examples/fixtures/l0_layout_transform.rs
@@ -0,0 +1,38 @@
+use super::*;
+
+pub fn build() -> Scene {
+ // Container rotated 90°, Cartesian position
+ let rotated_container = Node::Container(ContainerNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ rotation: 90.0,
+ position: LayoutPositioningBasis::Cartesian(CGPoint::new(300.0, 50.0)),
+ layout_container: LayoutContainerStyle::default(),
+ layout_dimensions: LayoutDimensionStyle {
+ layout_target_width: Some(200.0),
+ layout_target_height: Some(150.0),
+ layout_min_width: None, layout_max_width: None,
+ layout_min_height: None, layout_max_height: None,
+ layout_target_aspect_ratio: None,
+ },
+ layout_child: None,
+ corner_radius: RectangularCornerRadius::default(),
+ corner_smoothing: CornerSmoothing(0.0),
+ fills: Paints::new(vec![solid(59, 100, 220, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: StrokeWidth::None,
+ effects: LayerEffects::default(),
+ clip: false,
+ });
+
+ // Rectangle rotated 45°
+ let rotated_rect = rect_rotated(50.0, 50.0, 120.0, 80.0, 45.0, solid(220, 59, 59, 255));
+
+ // Line rotated 45°
+ let rotated_line = line(400.0, 200.0, 200.0, 45.0, 2.0);
+
+ flat_scene("L0 Layout Transform", vec![rotated_container, rotated_rect, rotated_line])
+}
diff --git a/crates/grida-canvas/examples/fixtures/l0_masks.rs b/crates/grida-canvas/examples/fixtures/l0_masks.rs
new file mode 100644
index 0000000000..b4d64aa926
--- /dev/null
+++ b/crates/grida-canvas/examples/fixtures/l0_masks.rs
@@ -0,0 +1,75 @@
+use super::*;
+use cg::cg::stroke_width::SingularStrokeWidth;
+use math2::transform::AffineTransform;
+use std::collections::HashMap;
+
+pub fn build() -> Scene {
+ // Group 1: image mask (alpha)
+ let group_img = Node::Group(GroupNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ transform: Some(AffineTransform::from_box_center(0.0, 0.0, 0.0, 0.0, 0.0)),
+ });
+ let content_img = rect(0.0, 0.0, 100.0, 100.0, solid(220, 59, 59, 255));
+ let mask_img = Node::Rectangle(RectangleNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: Some(LayerMaskType::Image(ImageMaskType::Alpha)),
+ transform: AffineTransform::from_box_center(0.0, 0.0, 100.0, 100.0, 0.0),
+ size: Size { width: 100.0, height: 100.0 },
+ corner_radius: RectangularCornerRadius::default(),
+ corner_smoothing: CornerSmoothing(0.0),
+ fills: Paints::new(vec![solid(255, 255, 255, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: StrokeWidth::None,
+ effects: LayerEffects::default(),
+ layout_child: None,
+ });
+
+ // Group 2: geometry mask
+ let group_geo = Node::Group(GroupNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ transform: Some(AffineTransform::from_box_center(150.0, 0.0, 0.0, 0.0, 0.0)),
+ });
+ let content_geo = rect(0.0, 0.0, 100.0, 100.0, solid(59, 100, 220, 255));
+ let mask_geo = Node::Ellipse(EllipseNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: Some(LayerMaskType::Geometry),
+ transform: AffineTransform::from_box_center(10.0, 10.0, 80.0, 80.0, 0.0),
+ size: Size { width: 80.0, height: 80.0 },
+ fills: Paints::new(vec![solid(0, 0, 0, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: SingularStrokeWidth(None),
+ inner_radius: None,
+ start_angle: 0.0,
+ angle: None,
+ corner_radius: None,
+ effects: LayerEffects::default(),
+ layout_child: None,
+ });
+
+ let mut links = HashMap::new();
+ links.insert(1u64, vec![2u64, 3u64]);
+ links.insert(4u64, vec![5u64, 6u64]);
+
+ build_scene(
+ "L0 Masks",
+ None,
+ vec![
+ (1, group_img), (2, content_img), (3, mask_img),
+ (4, group_geo), (5, content_geo), (6, mask_geo),
+ ],
+ links,
+ vec![1, 4],
+ )
+}
diff --git a/crates/grida-canvas/examples/fixtures/l0_paints.rs b/crates/grida-canvas/examples/fixtures/l0_paints.rs
new file mode 100644
index 0000000000..4c54a0d563
--- /dev/null
+++ b/crates/grida-canvas/examples/fixtures/l0_paints.rs
@@ -0,0 +1,14 @@
+use super::*;
+
+pub fn build() -> Scene {
+ let s = 150.0;
+ let gap = 170.0;
+
+ let solid_rect = rect(0.0, 0.0, s, s, solid(220, 59, 59, 255));
+ let linear_rect = rect(gap, 0.0, s, s, linear_gradient());
+ let radial_rect = rect(gap * 2.0, 0.0, s, s, radial_gradient());
+ let sweep_rect = rect(gap * 3.0, 0.0, s, s, sweep_gradient());
+ let image_rect = rect(gap * 4.0, 0.0, s, s, image_paint());
+
+ flat_scene("L0 Paints", vec![solid_rect, linear_rect, radial_rect, sweep_rect, image_rect])
+}
diff --git a/crates/grida-canvas/examples/fixtures/l0_paints_stack.rs b/crates/grida-canvas/examples/fixtures/l0_paints_stack.rs
new file mode 100644
index 0000000000..1929dea919
--- /dev/null
+++ b/crates/grida-canvas/examples/fixtures/l0_paints_stack.rs
@@ -0,0 +1,70 @@
+use super::*;
+use cg::cg::alignment::Alignment;
+use cg::cg::color::CGColor;
+use cg::cg::tilemode::TileMode;
+use math2::box_fit::BoxFit;
+use math2::transform::AffineTransform;
+
+pub fn build() -> Scene {
+ // Single rectangle with 5 stacked fills
+ let stacked = Node::Rectangle(RectangleNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ transform: AffineTransform::from_box_center(0.0, 0.0, 200.0, 200.0, 0.0),
+ size: Size { width: 200.0, height: 200.0 },
+ corner_radius: RectangularCornerRadius::default(),
+ corner_smoothing: CornerSmoothing(0.0),
+ fills: Paints::new(vec![
+ // [0] solid white base
+ solid(255, 255, 255, 255),
+ // [1] linear gradient red→transparent
+ Paint::LinearGradient(LinearGradientPaint {
+ active: true,
+ xy1: Alignment::CENTER_LEFT,
+ xy2: Alignment::CENTER_RIGHT,
+ tile_mode: TileMode::default(),
+ transform: AffineTransform::default(),
+ stops: vec![
+ GradientStop { offset: 0.0, color: CGColor { r: 255, g: 0, b: 0, a: 255 } },
+ GradientStop { offset: 1.0, color: CGColor { r: 255, g: 0, b: 0, a: 0 } },
+ ],
+ opacity: 1.0,
+ blend_mode: BlendMode::Normal,
+ }),
+ // [2] radial gradient yellow center→transparent
+ Paint::RadialGradient(RadialGradientPaint {
+ active: true,
+ transform: AffineTransform::default(),
+ stops: vec![
+ GradientStop { offset: 0.0, color: CGColor { r: 255, g: 255, b: 0, a: 255 } },
+ GradientStop { offset: 1.0, color: CGColor { r: 255, g: 255, b: 0, a: 0 } },
+ ],
+ opacity: 1.0,
+ blend_mode: BlendMode::Normal,
+ tile_mode: TileMode::default(),
+ }),
+ // [3] sweep gradient
+ sweep_gradient(),
+ // [4] image paint at 50% opacity
+ Paint::Image(ImagePaint {
+ active: true,
+ image: ResourceRef::HASH(SYSTEM_IMAGE.to_owned()),
+ fit: ImagePaintFit::Fit(BoxFit::Cover),
+ filters: ImageFilters::default(),
+ opacity: 0.5,
+ blend_mode: BlendMode::Normal,
+ quarter_turns: 0,
+ alignement: Alignment::CENTER,
+ }),
+ ]),
+ strokes: Paints::new(vec![]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: StrokeWidth::None,
+ effects: LayerEffects::default(),
+ layout_child: None,
+ });
+
+ flat_scene("L0 Paints Stack", vec![stacked])
+}
diff --git a/crates/grida-canvas/examples/fixtures/l0_shape_arc.rs b/crates/grida-canvas/examples/fixtures/l0_shape_arc.rs
new file mode 100644
index 0000000000..b978e50d19
--- /dev/null
+++ b/crates/grida-canvas/examples/fixtures/l0_shape_arc.rs
@@ -0,0 +1,111 @@
+use super::*;
+use cg::cg::stroke_width::SingularStrokeWidth;
+use math2::transform::AffineTransform;
+
+/// Ellipse arc variants: full, semicircle, donut, pie wedge, rounded arc.
+pub fn build() -> Scene {
+ let s = 120.0;
+ let gap = 140.0;
+
+ // Full ellipse (defaults — no arc)
+ let full = Node::Ellipse(EllipseNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ transform: AffineTransform::from_box_center(0.0, 0.0, s, s, 0.0),
+ size: Size { width: s, height: s },
+ fills: Paints::new(vec![solid(59, 100, 220, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: SingularStrokeWidth(None),
+ inner_radius: None,
+ start_angle: 0.0,
+ angle: None,
+ corner_radius: None,
+ effects: LayerEffects::default(),
+ layout_child: None,
+ });
+
+ // Semicircle (180° sweep)
+ let semi = Node::Ellipse(EllipseNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ transform: AffineTransform::from_box_center(gap, 0.0, s, s, 0.0),
+ size: Size { width: s, height: s },
+ fills: Paints::new(vec![solid(220, 59, 59, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: SingularStrokeWidth(None),
+ inner_radius: None,
+ start_angle: 0.0,
+ angle: Some(180.0),
+ corner_radius: None,
+ effects: LayerEffects::default(),
+ layout_child: None,
+ });
+
+ // Donut (inner_radius = 0.5)
+ let donut = Node::Ellipse(EllipseNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ transform: AffineTransform::from_box_center(gap * 2.0, 0.0, s, s, 0.0),
+ size: Size { width: s, height: s },
+ fills: Paints::new(vec![solid(59, 180, 75, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: SingularStrokeWidth(None),
+ inner_radius: Some(0.5),
+ start_angle: 0.0,
+ angle: None,
+ corner_radius: None,
+ effects: LayerEffects::default(),
+ layout_child: None,
+ });
+
+ // Pie wedge (90° sweep, start at 45°)
+ let pie = Node::Ellipse(EllipseNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ transform: AffineTransform::from_box_center(gap * 3.0, 0.0, s, s, 0.0),
+ size: Size { width: s, height: s },
+ fills: Paints::new(vec![solid(255, 200, 40, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: SingularStrokeWidth(None),
+ inner_radius: None,
+ start_angle: 45.0,
+ angle: Some(90.0),
+ corner_radius: None,
+ effects: LayerEffects::default(),
+ layout_child: None,
+ });
+
+ // Rounded arc (270° sweep, inner_radius 0.6, corner_radius 8)
+ let rounded_arc = Node::Ellipse(EllipseNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ transform: AffineTransform::from_box_center(gap * 4.0, 0.0, s, s, 0.0),
+ size: Size { width: s, height: s },
+ fills: Paints::new(vec![solid(128, 60, 200, 255)]),
+ strokes: Paints::new(vec![solid(0, 0, 0, 255)]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: SingularStrokeWidth(Some(2.0)),
+ inner_radius: Some(0.6),
+ start_angle: 0.0,
+ angle: Some(270.0),
+ corner_radius: Some(8.0),
+ effects: LayerEffects::default(),
+ layout_child: None,
+ });
+
+ flat_scene("L0 Shape Arc", vec![full, semi, donut, pie, rounded_arc])
+}
diff --git a/crates/grida-canvas/examples/fixtures/l0_shape_polygon.rs b/crates/grida-canvas/examples/fixtures/l0_shape_polygon.rs
new file mode 100644
index 0000000000..75f5fd30ed
--- /dev/null
+++ b/crates/grida-canvas/examples/fixtures/l0_shape_polygon.rs
@@ -0,0 +1,162 @@
+use super::*;
+use cg::cg::stroke_width::SingularStrokeWidth;
+use math2::transform::AffineTransform;
+
+/// Regular polygons and star polygons with varying point counts and parameters.
+pub fn build() -> Scene {
+ let s = 120.0;
+ let gap = 140.0;
+
+ // Triangle (3 sides)
+ let tri = Node::RegularPolygon(RegularPolygonNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ transform: AffineTransform::from_box_center(0.0, 0.0, s, s, 0.0),
+ size: Size { width: s, height: s },
+ point_count: 3,
+ corner_radius: 0.0,
+ fills: Paints::new(vec![solid(220, 59, 59, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: SingularStrokeWidth(None),
+ layout_child: None,
+ });
+
+ // Pentagon (5 sides, rounded corners)
+ let pent = Node::RegularPolygon(RegularPolygonNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ transform: AffineTransform::from_box_center(gap, 0.0, s, s, 0.0),
+ size: Size { width: s, height: s },
+ point_count: 5,
+ corner_radius: 10.0,
+ fills: Paints::new(vec![solid(59, 100, 220, 255)]),
+ strokes: Paints::new(vec![solid(0, 0, 0, 255)]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: SingularStrokeWidth(Some(1.5)),
+ layout_child: None,
+ });
+
+ // Hexagon (6 sides)
+ let hex = Node::RegularPolygon(RegularPolygonNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ transform: AffineTransform::from_box_center(gap * 2.0, 0.0, s, s, 0.0),
+ size: Size { width: s, height: s },
+ point_count: 6,
+ corner_radius: 5.0,
+ fills: Paints::new(vec![solid(59, 180, 75, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: SingularStrokeWidth(None),
+ layout_child: None,
+ });
+
+ // Octagon (8 sides)
+ let oct = Node::RegularPolygon(RegularPolygonNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ transform: AffineTransform::from_box_center(gap * 3.0, 0.0, s, s, 0.0),
+ size: Size { width: s, height: s },
+ point_count: 8,
+ corner_radius: 0.0,
+ fills: Paints::new(vec![solid(255, 200, 40, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: SingularStrokeWidth(None),
+ layout_child: None,
+ });
+
+ // 4-point star (sharp)
+ let star4 = Node::RegularStarPolygon(RegularStarPolygonNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ transform: AffineTransform::from_box_center(0.0, gap, s, s, 0.0),
+ size: Size { width: s, height: s },
+ point_count: 4,
+ inner_radius: 0.3,
+ corner_radius: 0.0,
+ fills: Paints::new(vec![solid(128, 60, 200, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: SingularStrokeWidth(None),
+ layout_child: None,
+ });
+
+ // 5-point star (classic)
+ let star5 = Node::RegularStarPolygon(RegularStarPolygonNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ transform: AffineTransform::from_box_center(gap, gap, s, s, 0.0),
+ size: Size { width: s, height: s },
+ point_count: 5,
+ inner_radius: 0.4,
+ corner_radius: 3.0,
+ fills: Paints::new(vec![solid(255, 215, 0, 255)]),
+ strokes: Paints::new(vec![solid(0, 0, 0, 255)]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: SingularStrokeWidth(Some(1.0)),
+ layout_child: None,
+ });
+
+ // 6-point star (Star of David shape)
+ let star6 = Node::RegularStarPolygon(RegularStarPolygonNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ transform: AffineTransform::from_box_center(gap * 2.0, gap, s, s, 0.0),
+ size: Size { width: s, height: s },
+ point_count: 6,
+ inner_radius: 0.5,
+ corner_radius: 0.0,
+ fills: Paints::new(vec![solid(59, 180, 180, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: SingularStrokeWidth(None),
+ layout_child: None,
+ });
+
+ // 8-point star (rounded)
+ let star8 = Node::RegularStarPolygon(RegularStarPolygonNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ transform: AffineTransform::from_box_center(gap * 3.0, gap, s, s, 0.0),
+ size: Size { width: s, height: s },
+ point_count: 8,
+ inner_radius: 0.7,
+ corner_radius: 6.0,
+ fills: Paints::new(vec![solid(220, 120, 60, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: SingularStrokeWidth(None),
+ layout_child: None,
+ });
+
+ flat_scene(
+ "L0 Shape Polygon",
+ vec![tri, pent, hex, oct, star4, star5, star6, star8],
+ )
+}
diff --git a/crates/grida-canvas/examples/fixtures/l0_shapes.rs b/crates/grida-canvas/examples/fixtures/l0_shapes.rs
new file mode 100644
index 0000000000..444289ca52
--- /dev/null
+++ b/crates/grida-canvas/examples/fixtures/l0_shapes.rs
@@ -0,0 +1,86 @@
+use super::*;
+use cg::vectornetwork::*;
+use math2::transform::AffineTransform;
+
+pub fn build() -> Scene {
+ let rectangle = rect(0.0, 0.0, 200.0, 100.0, solid(220, 59, 59, 255));
+
+ let ell = ellipse(220.0, 10.0, 100.0, 80.0, solid(59, 100, 220, 255));
+
+ let polygon = Node::RegularPolygon(RegularPolygonNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ transform: AffineTransform::from_box_center(340.0, 0.0, 100.0, 100.0, 0.0),
+ size: Size { width: 100.0, height: 100.0 },
+ point_count: 6,
+ corner_radius: 5.0,
+ fills: Paints::new(vec![solid(59, 180, 75, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: SingularStrokeWidth(None),
+ layout_child: None,
+ });
+
+ let star = Node::RegularStarPolygon(RegularStarPolygonNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ transform: AffineTransform::from_box_center(460.0, 0.0, 120.0, 120.0, 0.0),
+ size: Size { width: 120.0, height: 120.0 },
+ point_count: 5,
+ inner_radius: 0.4,
+ corner_radius: 3.0,
+ fills: Paints::new(vec![solid(255, 200, 40, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: SingularStrokeWidth(None),
+ layout_child: None,
+ });
+
+ let ln = line(0.0, 140.0, 200.0, 0.0, 2.0);
+
+ let txt = text(220.0, 130.0, "Hello, Grida!", 20.0, 400);
+
+ let vector = Node::Vector(VectorNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ transform: AffineTransform::from_box_center(460.0, 130.0, 100.0, 100.0, 0.0),
+ network: VectorNetwork {
+ vertices: vec![(0.0, 0.0), (100.0, 0.0), (100.0, 100.0), (0.0, 100.0)],
+ segments: vec![
+ VectorNetworkSegment { a: 0, b: 1, ta: (30.0, 0.0), tb: (-30.0, 0.0) },
+ VectorNetworkSegment { a: 1, b: 2, ta: (0.0, 30.0), tb: (0.0, -30.0) },
+ VectorNetworkSegment { a: 2, b: 3, ta: (-30.0, 0.0), tb: (30.0, 0.0) },
+ VectorNetworkSegment { a: 3, b: 0, ta: (0.0, -30.0), tb: (0.0, 30.0) },
+ ],
+ regions: vec![VectorNetworkRegion {
+ loops: vec![VectorNetworkLoop(vec![0, 1, 2, 3])],
+ fill_rule: FillRule::EvenOdd,
+ fills: None,
+ }],
+ },
+ corner_radius: 0.0,
+ fills: Paints::new(vec![solid(128, 60, 200, 255)]),
+ strokes: Paints::new(vec![solid(0, 0, 0, 255)]),
+ stroke_width: 1.0,
+ stroke_width_profile: None,
+ stroke_align: StrokeAlign::Center,
+ stroke_cap: StrokeCap::Butt,
+ stroke_join: StrokeJoin::Miter,
+ stroke_miter_limit: StrokeMiterLimit(4.0),
+ stroke_dash_array: None,
+ marker_start_shape: StrokeMarkerPreset::None,
+ marker_end_shape: StrokeMarkerPreset::None,
+ layout_child: None,
+ });
+
+ flat_scene("L0 Shapes", vec![rectangle, ell, polygon, star, ln, txt, vector])
+}
diff --git a/crates/grida-canvas/examples/fixtures/l0_strokes.rs b/crates/grida-canvas/examples/fixtures/l0_strokes.rs
new file mode 100644
index 0000000000..0e4853ece9
--- /dev/null
+++ b/crates/grida-canvas/examples/fixtures/l0_strokes.rs
@@ -0,0 +1,81 @@
+use super::*;
+use cg::cg::stroke_dasharray::StrokeDashArray;
+use math2::transform::AffineTransform;
+
+fn stroked_rect(
+ x: f32, y: f32,
+ align: StrokeAlign, cap: StrokeCap, join: StrokeJoin,
+ width: f32, color: Paint, dash: Option,
+) -> Node {
+ Node::Rectangle(RectangleNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ transform: AffineTransform::from_box_center(x, y, 120.0, 80.0, 0.0),
+ size: Size { width: 120.0, height: 80.0 },
+ corner_radius: RectangularCornerRadius::default(),
+ corner_smoothing: CornerSmoothing(0.0),
+ fills: Paints::new(vec![solid(240, 240, 240, 255)]),
+ strokes: Paints::new(vec![color]),
+ stroke_style: StrokeStyle {
+ stroke_align: align,
+ stroke_cap: cap,
+ stroke_join: join,
+ stroke_miter_limit: StrokeMiterLimit(4.0),
+ stroke_dash_array: dash,
+ },
+ stroke_width: StrokeWidth::Uniform(width),
+ effects: LayerEffects::default(),
+ layout_child: None,
+ })
+}
+
+fn marker_line(
+ x: f32, y: f32,
+ start: StrokeMarkerPreset, end: StrokeMarkerPreset,
+) -> Node {
+ Node::Line(LineNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ transform: AffineTransform::new(x, y, 0.0),
+ size: Size { width: 150.0, height: 0.0 },
+ strokes: Paints::new(vec![solid(0, 0, 0, 255)]),
+ stroke_width: 2.0,
+ stroke_cap: StrokeCap::Round,
+ stroke_miter_limit: StrokeMiterLimit(4.0),
+ stroke_dash_array: None,
+ _data_stroke_align: StrokeAlign::Center,
+ marker_start_shape: start,
+ marker_end_shape: end,
+ layout_child: None,
+ })
+}
+
+pub fn build() -> Scene {
+ let gap = 140.0;
+
+ let r1 = stroked_rect(0.0, 0.0,
+ StrokeAlign::Center, StrokeCap::Butt, StrokeJoin::Miter,
+ 2.0, solid(0, 0, 0, 255), None);
+ let r2 = stroked_rect(gap, 0.0,
+ StrokeAlign::Inside, StrokeCap::Round, StrokeJoin::Round,
+ 3.0, solid(59, 100, 220, 255), None);
+ let r3 = stroked_rect(gap * 2.0, 0.0,
+ StrokeAlign::Outside, StrokeCap::Square, StrokeJoin::Bevel,
+ 4.0, solid(59, 180, 75, 255), None);
+ let r4 = stroked_rect(gap * 3.0, 0.0,
+ StrokeAlign::Center, StrokeCap::Round, StrokeJoin::Miter,
+ 2.0, solid(0, 0, 0, 255),
+ Some(StrokeDashArray(vec![10.0, 5.0])));
+
+ let l1 = marker_line(0.0, 120.0,
+ StrokeMarkerPreset::Circle, StrokeMarkerPreset::EquilateralTriangle);
+ let l2 = marker_line(200.0, 120.0,
+ StrokeMarkerPreset::Diamond, StrokeMarkerPreset::VerticalBar);
+
+ flat_scene("L0 Strokes", vec![r1, r2, r3, r4, l1, l2])
+}
diff --git a/crates/grida-canvas/examples/fixtures/l0_strokes_rect.rs b/crates/grida-canvas/examples/fixtures/l0_strokes_rect.rs
new file mode 100644
index 0000000000..4af15eef9b
--- /dev/null
+++ b/crates/grida-canvas/examples/fixtures/l0_strokes_rect.rs
@@ -0,0 +1,157 @@
+use super::*;
+use cg::cg::stroke_width::RectangularStrokeWidth;
+
+pub fn build() -> Scene {
+ // Container with per-side stroke widths
+ let c1 = Node::Container(ContainerNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ rotation: 0.0,
+ position: LayoutPositioningBasis::Inset(EdgeInsets {
+ top: 0.0, right: 0.0, bottom: 0.0, left: 0.0,
+ }),
+ layout_container: LayoutContainerStyle::default(),
+ layout_dimensions: LayoutDimensionStyle {
+ layout_target_width: Some(300.0),
+ layout_target_height: Some(200.0),
+ layout_min_width: None, layout_max_width: None,
+ layout_min_height: None, layout_max_height: None,
+ layout_target_aspect_ratio: None,
+ },
+ layout_child: None,
+ corner_radius: RectangularCornerRadius::default(),
+ corner_smoothing: CornerSmoothing(0.0),
+ fills: Paints::new(vec![solid(250, 250, 250, 255)]),
+ strokes: Paints::new(vec![solid(0, 0, 0, 255)]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: StrokeWidth::Rectangular(RectangularStrokeWidth {
+ stroke_top_width: 1.0, stroke_right_width: 2.0, stroke_bottom_width: 3.0, stroke_left_width: 4.0,
+ }),
+ effects: LayerEffects::default(),
+ clip: false,
+ });
+
+ // Container with uniform stroke + per-side corner radii
+ let c2 = Node::Container(ContainerNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ rotation: 0.0,
+ position: LayoutPositioningBasis::Inset(EdgeInsets {
+ top: 0.0, right: 0.0, bottom: 0.0, left: 320.0,
+ }),
+ layout_container: LayoutContainerStyle::default(),
+ layout_dimensions: LayoutDimensionStyle {
+ layout_target_width: Some(300.0),
+ layout_target_height: Some(200.0),
+ layout_min_width: None, layout_max_width: None,
+ layout_min_height: None, layout_max_height: None,
+ layout_target_aspect_ratio: None,
+ },
+ layout_child: None,
+ corner_radius: {
+ use cg::cg::types::Radius;
+ RectangularCornerRadius {
+ tl: Radius::circular(0.0),
+ tr: Radius::circular(8.0),
+ bl: Radius::circular(16.0),
+ br: Radius::circular(24.0),
+ }
+ },
+ corner_smoothing: CornerSmoothing(0.0),
+ fills: Paints::new(vec![solid(250, 250, 250, 255)]),
+ strokes: Paints::new(vec![solid(0, 0, 0, 255)]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: StrokeWidth::Uniform(2.0),
+ effects: LayerEffects::default(),
+ clip: false,
+ });
+
+ // Container with varying per-side stroke widths + dashed pattern
+ let c3 = Node::Container(ContainerNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ rotation: 0.0,
+ position: LayoutPositioningBasis::Inset(EdgeInsets {
+ top: 220.0, right: 0.0, bottom: 0.0, left: 0.0,
+ }),
+ layout_container: LayoutContainerStyle::default(),
+ layout_dimensions: LayoutDimensionStyle {
+ layout_target_width: Some(300.0),
+ layout_target_height: Some(200.0),
+ layout_min_width: None, layout_max_width: None,
+ layout_min_height: None, layout_max_height: None,
+ layout_target_aspect_ratio: None,
+ },
+ layout_child: None,
+ corner_radius: RectangularCornerRadius::default(),
+ corner_smoothing: CornerSmoothing(0.0),
+ fills: Paints::new(vec![solid(250, 250, 250, 255)]),
+ strokes: Paints::new(vec![solid(220, 59, 59, 255)]),
+ stroke_style: StrokeStyle {
+ stroke_align: StrokeAlign::Inside,
+ stroke_cap: StrokeCap::Round,
+ stroke_join: StrokeJoin::Round,
+ stroke_miter_limit: StrokeMiterLimit(4.0),
+ stroke_dash_array: Some(cg::cg::stroke_dasharray::StrokeDashArray(vec![12.0, 6.0, 4.0, 6.0])),
+ },
+ stroke_width: StrokeWidth::Rectangular(RectangularStrokeWidth {
+ stroke_top_width: 2.0, stroke_right_width: 4.0, stroke_bottom_width: 6.0, stroke_left_width: 8.0,
+ }),
+ effects: LayerEffects::default(),
+ clip: false,
+ });
+
+ // Container with per-side corners + per-side stroke widths + dashed pattern
+ let c4 = Node::Container(ContainerNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ rotation: 0.0,
+ position: LayoutPositioningBasis::Inset(EdgeInsets {
+ top: 220.0, right: 0.0, bottom: 0.0, left: 320.0,
+ }),
+ layout_container: LayoutContainerStyle::default(),
+ layout_dimensions: LayoutDimensionStyle {
+ layout_target_width: Some(300.0),
+ layout_target_height: Some(200.0),
+ layout_min_width: None, layout_max_width: None,
+ layout_min_height: None, layout_max_height: None,
+ layout_target_aspect_ratio: None,
+ },
+ layout_child: None,
+ corner_radius: {
+ use cg::cg::types::Radius;
+ RectangularCornerRadius {
+ tl: Radius::circular(12.0),
+ tr: Radius::circular(0.0),
+ bl: Radius::circular(0.0),
+ br: Radius::circular(12.0),
+ }
+ },
+ corner_smoothing: CornerSmoothing(0.0),
+ fills: Paints::new(vec![solid(250, 250, 250, 255)]),
+ strokes: Paints::new(vec![solid(59, 100, 220, 255)]),
+ stroke_style: StrokeStyle {
+ stroke_align: StrokeAlign::Center,
+ stroke_cap: StrokeCap::Butt,
+ stroke_join: StrokeJoin::Miter,
+ stroke_miter_limit: StrokeMiterLimit(4.0),
+ stroke_dash_array: Some(cg::cg::stroke_dasharray::StrokeDashArray(vec![8.0, 4.0])),
+ },
+ stroke_width: StrokeWidth::Rectangular(RectangularStrokeWidth {
+ stroke_top_width: 1.0, stroke_right_width: 3.0, stroke_bottom_width: 5.0, stroke_left_width: 3.0,
+ }),
+ effects: LayerEffects::default(),
+ clip: false,
+ });
+
+ let pairs = vec![(1u64, c1), (2u64, c2), (3u64, c3), (4u64, c4)];
+ build_scene("L0 Strokes Rect", None, pairs, HashMap::new(), vec![1, 2, 3, 4])
+}
diff --git a/crates/grida-canvas/examples/fixtures/l0_type.rs b/crates/grida-canvas/examples/fixtures/l0_type.rs
new file mode 100644
index 0000000000..5d0a6609e0
--- /dev/null
+++ b/crates/grida-canvas/examples/fixtures/l0_type.rs
@@ -0,0 +1,246 @@
+use super::*;
+use cg::cg::color::CGColor;
+use cg::cg::fe::*;
+
+fn tspan(
+ x: f32, y: f32,
+ content: &str,
+ font_size: f32,
+ font_weight: u32,
+ h_align: TextAlign,
+ v_align: TextAlignVertical,
+ width: Option,
+ height: Option,
+) -> Node {
+ Node::TextSpan(TextSpanNodeRec {
+ active: true,
+ transform: AffineTransform::new(x, y, 0.0),
+ width,
+ height,
+ layout_child: None,
+ text: content.to_owned(),
+ text_style: {
+ let mut ts = TextStyleRec::from_font("Inter", font_size);
+ ts.font_weight = FontWeight(font_weight);
+ ts
+ },
+ text_align: h_align,
+ text_align_vertical: v_align,
+ max_lines: None,
+ ellipsis: None,
+ fills: Paints::new(vec![solid(0, 0, 0, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_width: 0.0,
+ stroke_align: StrokeAlign::Center,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ })
+}
+
+pub fn build() -> Scene {
+ let y_gap = 50.0;
+
+ // Regular 16px, Left/Top
+ let t1 = tspan(0.0, 0.0,
+ "Regular 16px", 16.0, 400,
+ TextAlign::Left, TextAlignVertical::Top, None, None);
+
+ // Bold 24px, Center/Center
+ let t2 = tspan(0.0, y_gap,
+ "Bold 24px", 24.0, 700,
+ TextAlign::Center, TextAlignVertical::Center,
+ Some(300.0), Some(40.0));
+
+ // Right aligned
+ let t3 = tspan(0.0, y_gap * 2.0,
+ "Right Aligned", 16.0, 400,
+ TextAlign::Right, TextAlignVertical::Bottom,
+ Some(300.0), Some(30.0));
+
+ // Justified text
+ let t4 = tspan(0.0, y_gap * 3.0,
+ "Justified Text with enough words to wrap across multiple lines for demonstration.",
+ 14.0, 400,
+ TextAlign::Justify, TextAlignVertical::Top,
+ Some(200.0), None);
+
+ // Text with stroke
+ let t5 = Node::TextSpan(TextSpanNodeRec {
+ active: true,
+ transform: AffineTransform::new(0.0, y_gap * 5.0, 0.0),
+ width: None,
+ height: None,
+ layout_child: None,
+ text: "With Stroke".to_owned(),
+ text_style: {
+ let mut ts = TextStyleRec::from_font("Inter", 20.0);
+ ts.font_weight = FontWeight(400);
+ ts
+ },
+ text_align: TextAlign::Left,
+ text_align_vertical: TextAlignVertical::Top,
+ max_lines: None,
+ ellipsis: None,
+ fills: Paints::new(vec![solid(0, 0, 0, 255)]),
+ strokes: Paints::new(vec![solid(220, 59, 59, 255)]),
+ stroke_width: 1.0,
+ stroke_align: StrokeAlign::Outside,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ });
+
+ // Text with drop shadow
+ let t6 = Node::TextSpan(TextSpanNodeRec {
+ active: true,
+ transform: AffineTransform::new(0.0, y_gap * 6.0, 0.0),
+ width: None,
+ height: None,
+ layout_child: None,
+ text: "Drop Shadow".to_owned(),
+ text_style: {
+ let mut ts = TextStyleRec::from_font("Inter", 20.0);
+ ts.font_weight = FontWeight(400);
+ ts
+ },
+ text_align: TextAlign::Left,
+ text_align_vertical: TextAlignVertical::Top,
+ max_lines: None,
+ ellipsis: None,
+ fills: Paints::new(vec![solid(0, 0, 0, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_width: 0.0,
+ stroke_align: StrokeAlign::Center,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects {
+ shadows: vec![FilterShadowEffect::DropShadow(FeShadow {
+ dx: 2.0, dy: 2.0, blur: 4.0, spread: 0.0,
+ color: CGColor { r: 0, g: 0, b: 0, a: 153 },
+ active: true,
+ })],
+ ..LayerEffects::default()
+ },
+ });
+
+ // Max lines + ellipsis
+ let t7 = Node::TextSpan(TextSpanNodeRec {
+ active: true,
+ transform: AffineTransform::new(0.0, y_gap * 7.0, 0.0),
+ width: Some(120.0),
+ height: None,
+ layout_child: None,
+ text: "Max 2 Lines with truncation and ellipsis at the end".to_owned(),
+ text_style: {
+ let mut ts = TextStyleRec::from_font("Inter", 14.0);
+ ts.font_weight = FontWeight(400);
+ ts
+ },
+ text_align: TextAlign::Left,
+ text_align_vertical: TextAlignVertical::Top,
+ max_lines: Some(2),
+ ellipsis: Some("\u{2026}".to_owned()),
+ fills: Paints::new(vec![solid(0, 0, 0, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_width: 0.0,
+ stroke_align: StrokeAlign::Center,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ });
+
+ // Letter spacing + line height
+ let t8 = Node::TextSpan(TextSpanNodeRec {
+ active: true,
+ transform: AffineTransform::new(0.0, y_gap * 8.5, 0.0),
+ width: Some(300.0),
+ height: None,
+ layout_child: None,
+ text: "Tracked + Tall Line Height".to_owned(),
+ text_style: {
+ let mut ts = TextStyleRec::from_font("Inter", 16.0);
+ ts.letter_spacing = TextLetterSpacing::Fixed(4.0);
+ ts.line_height = TextLineHeight::Factor(2.0);
+ ts
+ },
+ text_align: TextAlign::Left,
+ text_align_vertical: TextAlignVertical::Top,
+ max_lines: None,
+ ellipsis: None,
+ fills: Paints::new(vec![solid(0, 0, 0, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_width: 0.0,
+ stroke_align: StrokeAlign::Center,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ });
+
+ // Underline decoration (red, 2px thick)
+ let t9 = Node::TextSpan(TextSpanNodeRec {
+ active: true,
+ transform: AffineTransform::new(0.0, y_gap * 10.0, 0.0),
+ width: None,
+ height: None,
+ layout_child: None,
+ text: "Underlined Text".to_owned(),
+ text_style: {
+ let mut ts = TextStyleRec::from_font("Inter", 18.0);
+ ts.text_decoration = Some(TextDecorationRec {
+ text_decoration_line: TextDecorationLine::Underline,
+ text_decoration_color: Some(CGColor { r: 220, g: 59, b: 59, a: 255 }),
+ text_decoration_style: Some(TextDecorationStyle::Solid),
+ text_decoration_skip_ink: Some(true),
+ text_decoration_thickness: Some(2.0),
+ });
+ ts
+ },
+ text_align: TextAlign::Left,
+ text_align_vertical: TextAlignVertical::Top,
+ max_lines: None,
+ ellipsis: None,
+ fills: Paints::new(vec![solid(0, 0, 0, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_width: 0.0,
+ stroke_align: StrokeAlign::Center,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ });
+
+ // UPPERCASE transform
+ let t10 = Node::TextSpan(TextSpanNodeRec {
+ active: true,
+ transform: AffineTransform::new(0.0, y_gap * 11.0, 0.0),
+ width: None,
+ height: None,
+ layout_child: None,
+ text: "uppercase transform".to_owned(),
+ text_style: {
+ let mut ts = TextStyleRec::from_font("Inter", 16.0);
+ ts.text_transform = TextTransform::Uppercase;
+ ts
+ },
+ text_align: TextAlign::Left,
+ text_align_vertical: TextAlignVertical::Top,
+ max_lines: None,
+ ellipsis: None,
+ fills: Paints::new(vec![solid(0, 0, 0, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_width: 0.0,
+ stroke_align: StrokeAlign::Center,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ });
+
+ flat_scene("L0 Type", vec![t1, t2, t3, t4, t5, t6, t7, t8, t9, t10])
+}
diff --git a/crates/grida-canvas/examples/fixtures/l0_type_features.rs b/crates/grida-canvas/examples/fixtures/l0_type_features.rs
new file mode 100644
index 0000000000..cc8cbde935
--- /dev/null
+++ b/crates/grida-canvas/examples/fixtures/l0_type_features.rs
@@ -0,0 +1,181 @@
+use super::*;
+
+/// OpenType font features: ligatures, small caps, stylistic sets, etc.
+pub fn build() -> Scene {
+ let y_gap = 50.0;
+
+ // Ligatures disabled
+ let t1 = Node::TextSpan(TextSpanNodeRec {
+ active: true,
+ transform: AffineTransform::new(0.0, 0.0, 0.0),
+ width: None,
+ height: None,
+ layout_child: None,
+ text: "ffi ffl — liga off".to_owned(),
+ text_style: {
+ let mut ts = TextStyleRec::from_font("Inter", 20.0);
+ ts.font_features = Some(vec![
+ FontFeature { tag: "liga".to_owned(), value: false },
+ ]);
+ ts
+ },
+ text_align: TextAlign::Left,
+ text_align_vertical: TextAlignVertical::Top,
+ max_lines: None,
+ ellipsis: None,
+ fills: Paints::new(vec![solid(0, 0, 0, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_width: 0.0,
+ stroke_align: StrokeAlign::Center,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ });
+
+ // Ligatures enabled (default, explicit)
+ let t2 = Node::TextSpan(TextSpanNodeRec {
+ active: true,
+ transform: AffineTransform::new(0.0, y_gap, 0.0),
+ width: None,
+ height: None,
+ layout_child: None,
+ text: "ffi ffl — liga on".to_owned(),
+ text_style: {
+ let mut ts = TextStyleRec::from_font("Inter", 20.0);
+ ts.font_features = Some(vec![
+ FontFeature { tag: "liga".to_owned(), value: true },
+ ]);
+ ts
+ },
+ text_align: TextAlign::Left,
+ text_align_vertical: TextAlignVertical::Top,
+ max_lines: None,
+ ellipsis: None,
+ fills: Paints::new(vec![solid(0, 0, 0, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_width: 0.0,
+ stroke_align: StrokeAlign::Center,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ });
+
+ // Small caps
+ let t3 = Node::TextSpan(TextSpanNodeRec {
+ active: true,
+ transform: AffineTransform::new(0.0, y_gap * 2.0, 0.0),
+ width: None,
+ height: None,
+ layout_child: None,
+ text: "Small Caps Text — smcp".to_owned(),
+ text_style: {
+ let mut ts = TextStyleRec::from_font("Inter", 20.0);
+ ts.font_features = Some(vec![
+ FontFeature { tag: "smcp".to_owned(), value: true },
+ ]);
+ ts
+ },
+ text_align: TextAlign::Left,
+ text_align_vertical: TextAlignVertical::Top,
+ max_lines: None,
+ ellipsis: None,
+ fills: Paints::new(vec![solid(0, 0, 0, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_width: 0.0,
+ stroke_align: StrokeAlign::Center,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ });
+
+ // Stylistic set 01
+ let t4 = Node::TextSpan(TextSpanNodeRec {
+ active: true,
+ transform: AffineTransform::new(0.0, y_gap * 3.0, 0.0),
+ width: None,
+ height: None,
+ layout_child: None,
+ text: "Stylistic Set 01 — ss01".to_owned(),
+ text_style: {
+ let mut ts = TextStyleRec::from_font("Inter", 20.0);
+ ts.font_features = Some(vec![
+ FontFeature { tag: "ss01".to_owned(), value: true },
+ ]);
+ ts
+ },
+ text_align: TextAlign::Left,
+ text_align_vertical: TextAlignVertical::Top,
+ max_lines: None,
+ ellipsis: None,
+ fills: Paints::new(vec![solid(0, 0, 0, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_width: 0.0,
+ stroke_align: StrokeAlign::Center,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ });
+
+ // Tabular numbers + slashed zero
+ let t5 = Node::TextSpan(TextSpanNodeRec {
+ active: true,
+ transform: AffineTransform::new(0.0, y_gap * 4.0, 0.0),
+ width: None,
+ height: None,
+ layout_child: None,
+ text: "0123456789 — tnum + zero".to_owned(),
+ text_style: {
+ let mut ts = TextStyleRec::from_font("Inter", 20.0);
+ ts.font_features = Some(vec![
+ FontFeature { tag: "tnum".to_owned(), value: true },
+ FontFeature { tag: "zero".to_owned(), value: true },
+ ]);
+ ts
+ },
+ text_align: TextAlign::Left,
+ text_align_vertical: TextAlignVertical::Top,
+ max_lines: None,
+ ellipsis: None,
+ fills: Paints::new(vec![solid(0, 0, 0, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_width: 0.0,
+ stroke_align: StrokeAlign::Center,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ });
+
+ // Kerning off
+ let t6 = Node::TextSpan(TextSpanNodeRec {
+ active: true,
+ transform: AffineTransform::new(0.0, y_gap * 5.0, 0.0),
+ width: None,
+ height: None,
+ layout_child: None,
+ text: "AVAW Typography — kern off".to_owned(),
+ text_style: {
+ let mut ts = TextStyleRec::from_font("Inter", 20.0);
+ ts.font_kerning = false;
+ ts
+ },
+ text_align: TextAlign::Left,
+ text_align_vertical: TextAlignVertical::Top,
+ max_lines: None,
+ ellipsis: None,
+ fills: Paints::new(vec![solid(0, 0, 0, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_width: 0.0,
+ stroke_align: StrokeAlign::Center,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ });
+
+ flat_scene("L0 Type Features", vec![t1, t2, t3, t4, t5, t6])
+}
diff --git a/crates/grida-canvas/examples/fixtures/l0_type_fvar.rs b/crates/grida-canvas/examples/fixtures/l0_type_fvar.rs
new file mode 100644
index 0000000000..0652f3b7d3
--- /dev/null
+++ b/crates/grida-canvas/examples/fixtures/l0_type_fvar.rs
@@ -0,0 +1,161 @@
+use super::*;
+
+/// Variable font axes: weight, width, optical sizing, and custom fvar axes.
+pub fn build() -> Scene {
+ let y_gap = 50.0;
+
+ // Weight axis via font_weight (100..900)
+ let weights = [
+ (100, "Thin 100"),
+ (300, "Light 300"),
+ (400, "Regular 400"),
+ (700, "Bold 700"),
+ (900, "Black 900"),
+ ];
+
+ let mut nodes: Vec = Vec::new();
+
+ for (i, (w, label)) in weights.iter().enumerate() {
+ nodes.push(Node::TextSpan(TextSpanNodeRec {
+ active: true,
+ transform: AffineTransform::new(0.0, (i as f32) * y_gap, 0.0),
+ width: None,
+ height: None,
+ layout_child: None,
+ text: label.to_string(),
+ text_style: {
+ let mut ts = TextStyleRec::from_font("Inter", 20.0);
+ ts.font_weight = FontWeight(*w);
+ ts
+ },
+ text_align: TextAlign::Left,
+ text_align_vertical: TextAlignVertical::Top,
+ max_lines: None,
+ ellipsis: None,
+ fills: Paints::new(vec![solid(0, 0, 0, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_width: 0.0,
+ stroke_align: StrokeAlign::Center,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ }));
+ }
+
+ let base_y = (weights.len() as f32) * y_gap;
+
+ // Width axis (font_width field — high-level wdth exposure)
+ nodes.push(Node::TextSpan(TextSpanNodeRec {
+ active: true,
+ transform: AffineTransform::new(0.0, base_y, 0.0),
+ width: None,
+ height: None,
+ layout_child: None,
+ text: "Condensed (width=75)".to_owned(),
+ text_style: {
+ let mut ts = TextStyleRec::from_font("Inter", 20.0);
+ ts.font_width = Some(75.0);
+ ts
+ },
+ text_align: TextAlign::Left,
+ text_align_vertical: TextAlignVertical::Top,
+ max_lines: None,
+ ellipsis: None,
+ fills: Paints::new(vec![solid(0, 0, 0, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_width: 0.0,
+ stroke_align: StrokeAlign::Center,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ }));
+
+ // Optical sizing
+ nodes.push(Node::TextSpan(TextSpanNodeRec {
+ active: true,
+ transform: AffineTransform::new(0.0, base_y + y_gap, 0.0),
+ width: None,
+ height: None,
+ layout_child: None,
+ text: "Optical Size Fixed(48)".to_owned(),
+ text_style: {
+ let mut ts = TextStyleRec::from_font("Inter", 20.0);
+ ts.font_optical_sizing = FontOpticalSizing::Fixed(48.0);
+ ts
+ },
+ text_align: TextAlign::Left,
+ text_align_vertical: TextAlignVertical::Top,
+ max_lines: None,
+ ellipsis: None,
+ fills: Paints::new(vec![solid(0, 0, 0, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_width: 0.0,
+ stroke_align: StrokeAlign::Center,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ }));
+
+ // Custom fvar axes via font_variations
+ nodes.push(Node::TextSpan(TextSpanNodeRec {
+ active: true,
+ transform: AffineTransform::new(0.0, base_y + y_gap * 2.0, 0.0),
+ width: None,
+ height: None,
+ layout_child: None,
+ text: "Custom Axes: wght=600 wdth=80 GRAD=50".to_owned(),
+ text_style: {
+ let mut ts = TextStyleRec::from_font("Roboto Flex", 20.0);
+ ts.font_variations = Some(vec![
+ FontVariation { axis: "wght".to_owned(), value: 600.0 },
+ FontVariation { axis: "wdth".to_owned(), value: 80.0 },
+ FontVariation { axis: "GRAD".to_owned(), value: 50.0 },
+ ]);
+ ts
+ },
+ text_align: TextAlign::Left,
+ text_align_vertical: TextAlignVertical::Top,
+ max_lines: None,
+ ellipsis: None,
+ fills: Paints::new(vec![solid(0, 0, 0, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_width: 0.0,
+ stroke_align: StrokeAlign::Center,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ }));
+
+ // Italic style
+ nodes.push(Node::TextSpan(TextSpanNodeRec {
+ active: true,
+ transform: AffineTransform::new(0.0, base_y + y_gap * 3.0, 0.0),
+ width: None,
+ height: None,
+ layout_child: None,
+ text: "Italic Style".to_owned(),
+ text_style: {
+ let mut ts = TextStyleRec::from_font("Inter", 20.0);
+ ts.font_style_italic = true;
+ ts
+ },
+ text_align: TextAlign::Left,
+ text_align_vertical: TextAlignVertical::Top,
+ max_lines: None,
+ ellipsis: None,
+ fills: Paints::new(vec![solid(0, 0, 0, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_width: 0.0,
+ stroke_align: StrokeAlign::Center,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ }));
+
+ flat_scene("L0 Type fvar", nodes)
+}
diff --git a/crates/grida-canvas/examples/fixtures/l0_vector.rs b/crates/grida-canvas/examples/fixtures/l0_vector.rs
new file mode 100644
index 0000000000..a6e47ef10c
--- /dev/null
+++ b/crates/grida-canvas/examples/fixtures/l0_vector.rs
@@ -0,0 +1,152 @@
+use super::*;
+use cg::cg::stroke_dasharray::StrokeDashArray;
+use cg::vectornetwork::*;
+use math2::transform::AffineTransform;
+
+/// Vector network nodes: closed shape, open path, multi-region, variable-width stroke.
+pub fn build() -> Scene {
+ // Closed bezier quad (4 curved segments forming a rounded square)
+ let closed = Node::Vector(VectorNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ transform: AffineTransform::from_box_center(0.0, 0.0, 100.0, 100.0, 0.0),
+ network: VectorNetwork {
+ vertices: vec![(0.0, 0.0), (100.0, 0.0), (100.0, 100.0), (0.0, 100.0)],
+ segments: vec![
+ VectorNetworkSegment { a: 0, b: 1, ta: (30.0, 0.0), tb: (-30.0, 0.0) },
+ VectorNetworkSegment { a: 1, b: 2, ta: (0.0, 30.0), tb: (0.0, -30.0) },
+ VectorNetworkSegment { a: 2, b: 3, ta: (-30.0, 0.0), tb: (30.0, 0.0) },
+ VectorNetworkSegment { a: 3, b: 0, ta: (0.0, -30.0), tb: (0.0, 30.0) },
+ ],
+ regions: vec![VectorNetworkRegion {
+ loops: vec![VectorNetworkLoop(vec![0, 1, 2, 3])],
+ fill_rule: FillRule::EvenOdd,
+ fills: None,
+ }],
+ },
+ corner_radius: 0.0,
+ fills: Paints::new(vec![solid(59, 100, 220, 255)]),
+ strokes: Paints::new(vec![solid(0, 0, 0, 255)]),
+ stroke_width: 1.5,
+ stroke_width_profile: None,
+ stroke_align: StrokeAlign::Center,
+ stroke_cap: StrokeCap::Butt,
+ stroke_join: StrokeJoin::Miter,
+ stroke_miter_limit: StrokeMiterLimit(4.0),
+ stroke_dash_array: None,
+ marker_start_shape: StrokeMarkerPreset::None,
+ marker_end_shape: StrokeMarkerPreset::None,
+ layout_child: None,
+ });
+
+ // Open path (3 vertices, 2 segments, no region)
+ let open = Node::Vector(VectorNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ transform: AffineTransform::from_box_center(140.0, 0.0, 120.0, 80.0, 0.0),
+ network: VectorNetwork {
+ vertices: vec![(0.0, 80.0), (60.0, 0.0), (120.0, 80.0)],
+ segments: vec![
+ VectorNetworkSegment { a: 0, b: 1, ta: (20.0, -30.0), tb: (-20.0, 10.0) },
+ VectorNetworkSegment { a: 1, b: 2, ta: (20.0, 10.0), tb: (-20.0, -30.0) },
+ ],
+ regions: vec![],
+ },
+ corner_radius: 0.0,
+ fills: Paints::new(vec![]),
+ strokes: Paints::new(vec![solid(220, 59, 59, 255)]),
+ stroke_width: 3.0,
+ stroke_width_profile: None,
+ stroke_align: StrokeAlign::Center,
+ stroke_cap: StrokeCap::Round,
+ stroke_join: StrokeJoin::Round,
+ stroke_miter_limit: StrokeMiterLimit(4.0),
+ stroke_dash_array: None,
+ marker_start_shape: StrokeMarkerPreset::Circle,
+ marker_end_shape: StrokeMarkerPreset::EquilateralTriangle,
+ layout_child: None,
+ });
+
+ // Region with explicit fill + dashed stroke
+ let region_fill = Node::Vector(VectorNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ transform: AffineTransform::from_box_center(0.0, 140.0, 100.0, 100.0, 0.0),
+ network: VectorNetwork {
+ vertices: vec![(50.0, 0.0), (100.0, 100.0), (0.0, 100.0)],
+ segments: vec![
+ VectorNetworkSegment { a: 0, b: 1, ta: (0.0, 0.0), tb: (0.0, 0.0) },
+ VectorNetworkSegment { a: 1, b: 2, ta: (0.0, 0.0), tb: (0.0, 0.0) },
+ VectorNetworkSegment { a: 2, b: 0, ta: (0.0, 0.0), tb: (0.0, 0.0) },
+ ],
+ regions: vec![VectorNetworkRegion {
+ loops: vec![VectorNetworkLoop(vec![0, 1, 2])],
+ fill_rule: FillRule::NonZero,
+ fills: Some(Paints::new(vec![solid(255, 200, 40, 255)])),
+ }],
+ },
+ corner_radius: 0.0,
+ fills: Paints::new(vec![solid(59, 180, 75, 255)]),
+ strokes: Paints::new(vec![solid(0, 0, 0, 255)]),
+ stroke_width: 2.0,
+ stroke_width_profile: None,
+ stroke_align: StrokeAlign::Center,
+ stroke_cap: StrokeCap::Butt,
+ stroke_join: StrokeJoin::Miter,
+ stroke_miter_limit: StrokeMiterLimit(4.0),
+ stroke_dash_array: Some(StrokeDashArray(vec![8.0, 4.0])),
+ marker_start_shape: StrokeMarkerPreset::None,
+ marker_end_shape: StrokeMarkerPreset::None,
+ layout_child: None,
+ });
+
+ // Variable-width stroke profile
+ let varwidth = Node::Vector(VectorNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ transform: AffineTransform::from_box_center(140.0, 140.0, 120.0, 80.0, 0.0),
+ network: VectorNetwork {
+ vertices: vec![(0.0, 40.0), (60.0, 0.0), (120.0, 40.0), (60.0, 80.0)],
+ segments: vec![
+ VectorNetworkSegment { a: 0, b: 1, ta: (20.0, -20.0), tb: (-20.0, 10.0) },
+ VectorNetworkSegment { a: 1, b: 2, ta: (20.0, 10.0), tb: (-20.0, -20.0) },
+ VectorNetworkSegment { a: 2, b: 3, ta: (-20.0, 20.0), tb: (20.0, -10.0) },
+ ],
+ regions: vec![],
+ },
+ corner_radius: 0.0,
+ fills: Paints::new(vec![]),
+ strokes: Paints::new(vec![solid(128, 60, 200, 255)]),
+ stroke_width: 4.0,
+ stroke_width_profile: Some(cg::cg::varwidth::VarWidthProfile {
+ base: 2.0,
+ stops: vec![
+ cg::cg::varwidth::WidthStop { u: 0.0, r: 1.0 },
+ cg::cg::varwidth::WidthStop { u: 0.5, r: 6.0 },
+ cg::cg::varwidth::WidthStop { u: 1.0, r: 1.0 },
+ ],
+ }),
+ stroke_align: StrokeAlign::Center,
+ stroke_cap: StrokeCap::Round,
+ stroke_join: StrokeJoin::Round,
+ stroke_miter_limit: StrokeMiterLimit(4.0),
+ stroke_dash_array: None,
+ marker_start_shape: StrokeMarkerPreset::None,
+ marker_end_shape: StrokeMarkerPreset::None,
+ layout_child: None,
+ });
+
+ flat_scene("L0 Vector", vec![closed, open, region_fill, varwidth])
+}
diff --git a/crates/grida-canvas/examples/fixtures/mod.rs b/crates/grida-canvas/examples/fixtures/mod.rs
new file mode 100644
index 0000000000..2eeba87043
--- /dev/null
+++ b/crates/grida-canvas/examples/fixtures/mod.rs
@@ -0,0 +1,363 @@
+//! Shared helpers for L0 fixture generators.
+
+use std::collections::HashMap;
+
+use cg::cg::alignment::Alignment;
+use cg::cg::color::CGColor;
+use cg::cg::stroke_width::{SingularStrokeWidth, StrokeWidth};
+use cg::cg::tilemode::TileMode;
+use cg::cg::types::*;
+use math2::box_fit::BoxFit;
+use cg::io::io_grida_fbs;
+use cg::node::scene_graph::SceneGraph;
+use cg::node::schema::*;
+use math2::transform::AffineTransform;
+
+pub mod l0_boolean_operation;
+pub mod l0_container;
+pub mod l0_effects;
+pub mod l0_group;
+pub mod l0_effects_glass;
+pub mod l0_image;
+pub mod l0_image_filters;
+pub mod l0_layout_flex;
+pub mod l0_layout_position;
+pub mod l0_layout_transform;
+pub mod l0_masks;
+pub mod l0_paints;
+pub mod l0_paints_stack;
+pub mod l0_shape_arc;
+pub mod l0_shape_polygon;
+pub mod l0_shapes;
+pub mod l0_strokes;
+pub mod l0_strokes_rect;
+pub mod l0_type;
+pub mod l0_type_features;
+pub mod l0_type_fvar;
+pub mod l0_vector;
+
+// ═════════════════════════════════════════════════════════════════════════════
+// Scene building
+// ═════════════════════════════════════════════════════════════════════════════
+
+/// Build a `Scene` from `(id, node)` pairs, parent→children links, and root ids.
+pub fn build_scene(
+ name: &str,
+ bg: Option,
+ nodes: Vec<(NodeId, Node)>,
+ links: HashMap>,
+ roots: Vec,
+) -> Scene {
+ let graph = SceneGraph::new_from_snapshot(nodes, links, roots);
+ Scene {
+ name: name.to_owned(),
+ graph,
+ background_color: bg,
+ }
+}
+
+/// Build id_map and position_map with a prefix to avoid collisions in multi-scene files. every node ID to avoid collisions in multi-scene files.
+pub fn build_maps_prefixed(
+ scene: &Scene,
+ id_map: &mut HashMap,
+ position_map: &mut HashMap,
+ prefix: &str,
+) {
+ fn walk(
+ graph: &SceneGraph,
+ nid: &NodeId,
+ counter: &mut usize,
+ id_map: &mut HashMap,
+ position_map: &mut HashMap,
+ prefix: &str,
+ ) {
+ id_map.entry(*nid).or_insert_with(|| format!("{prefix}n{nid}"));
+ if let Some(children) = graph.get_children(nid) {
+ for (i, child) in children.clone().iter().enumerate() {
+ let pos = format!("a{i:04}");
+ position_map.insert(*child, pos);
+ walk(graph, child, counter, id_map, position_map, prefix);
+ }
+ }
+ *counter += 1;
+ }
+ let mut counter = 0usize;
+ for root in scene.graph.roots() {
+ walk(&scene.graph, &root, &mut counter, id_map, position_map, prefix);
+ }
+}
+
+fn fixtures_dir() -> std::path::PathBuf {
+ let manifest = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
+ manifest.join("../../fixtures/test-grida")
+}
+
+/// Encode multiple scenes into a single `.grida` file and write to disk.
+/// Each entry is `(scene_id_suffix, scene)`. The scene_id is derived from the scene name.
+pub fn write_multi_fixture(scenes: &[(&str, Scene)], name: &str) {
+ let mut entries_data: Vec<(
+ String,
+ HashMap,
+ HashMap,
+ )> = Vec::new();
+
+ for (i, (key, scene)) in scenes.iter().enumerate() {
+ let scene_id = key.to_string();
+ let mut id_map = HashMap::new();
+ let mut position_map = HashMap::new();
+ // Prefix node IDs with scene index to avoid collisions across scenes
+ // in the shared flat node list.
+ build_maps_prefixed(scene, &mut id_map, &mut position_map, &format!("s{}_", i));
+ entries_data.push((scene_id, id_map, position_map));
+ }
+
+ let entries: Vec<(
+ &str,
+ &Scene,
+ &HashMap,
+ &HashMap,
+ )> = scenes
+ .iter()
+ .zip(entries_data.iter())
+ .map(|((_, scene), (scene_id, id_map, position_map))| {
+ (scene_id.as_str(), scene, id_map, position_map)
+ })
+ .collect();
+
+ let bytes = io_grida_fbs::encode_multi(&entries);
+ assert!(!bytes.is_empty(), "{name}: encoded bytes empty");
+
+ // Verify decode: all scenes should be recoverable
+ let decoded = io_grida_fbs::decode_all(&bytes)
+ .unwrap_or_else(|e| panic!("{name}: decode failed: {e}"));
+ assert_eq!(
+ decoded.len(),
+ scenes.len(),
+ "{name}: expected {} scenes, got {}",
+ scenes.len(),
+ decoded.len()
+ );
+ for (i, ((_, original), decoded_scene)) in scenes.iter().zip(decoded.iter()).enumerate() {
+ assert_eq!(
+ original.name, decoded_scene.name,
+ "{name}: scene[{i}] name mismatch"
+ );
+ }
+
+ let dir = fixtures_dir();
+ std::fs::create_dir_all(&dir).unwrap();
+ let path = dir.join(format!("{name}.grida"));
+ std::fs::write(&path, &bytes).unwrap();
+ eprintln!(
+ "Wrote {} bytes ({} scenes) to {}",
+ bytes.len(),
+ scenes.len(),
+ path.display()
+ );
+}
+
+// ═════════════════════════════════════════════════════════════════════════════
+// Paint builders
+// ═════════════════════════════════════════════════════════════════════════════
+
+pub fn solid(r: u8, g: u8, b: u8, a: u8) -> Paint {
+ Paint::Solid(SolidPaint {
+ active: true,
+ color: CGColor { r, g, b, a },
+ blend_mode: BlendMode::Normal,
+ })
+}
+
+pub fn linear_gradient() -> Paint {
+ Paint::LinearGradient(LinearGradientPaint {
+ active: true,
+ xy1: Alignment::CENTER_LEFT,
+ xy2: Alignment::CENTER_RIGHT,
+ tile_mode: TileMode::default(),
+ transform: AffineTransform::default(),
+ stops: vec![
+ GradientStop { offset: 0.0, color: CGColor { r: 255, g: 0, b: 0, a: 255 } },
+ GradientStop { offset: 1.0, color: CGColor { r: 0, g: 0, b: 255, a: 255 } },
+ ],
+ opacity: 1.0,
+ blend_mode: BlendMode::Normal,
+ })
+}
+
+pub fn radial_gradient() -> Paint {
+ Paint::RadialGradient(RadialGradientPaint {
+ active: true,
+ transform: AffineTransform::default(),
+ stops: vec![
+ GradientStop { offset: 0.0, color: CGColor { r: 255, g: 255, b: 0, a: 255 } },
+ GradientStop { offset: 1.0, color: CGColor { r: 0, g: 128, b: 0, a: 200 } },
+ ],
+ opacity: 0.8,
+ blend_mode: BlendMode::Normal,
+ tile_mode: TileMode::default(),
+ })
+}
+
+pub fn sweep_gradient() -> Paint {
+ Paint::SweepGradient(SweepGradientPaint {
+ active: true,
+ transform: AffineTransform::default(),
+ stops: vec![
+ GradientStop { offset: 0.0, color: CGColor { r: 0, g: 255, b: 255, a: 255 } },
+ GradientStop { offset: 0.5, color: CGColor { r: 255, g: 0, b: 255, a: 255 } },
+ GradientStop { offset: 1.0, color: CGColor { r: 255, g: 255, b: 0, a: 255 } },
+ ],
+ opacity: 1.0,
+ blend_mode: BlendMode::Normal,
+ })
+}
+
+/// The system checker image bundled in the renderer. Use this for all fixture
+/// image paints so they actually render in the native demo.
+pub const SYSTEM_IMAGE: &str = "system://images/checker-16-strip-L98L92.png";
+
+pub fn image_paint() -> Paint {
+ image_paint_with(ResourceRef::HASH(SYSTEM_IMAGE.to_owned()), ImagePaintFit::Fit(BoxFit::Cover))
+}
+
+pub fn image_paint_with(image: ResourceRef, fit: ImagePaintFit) -> Paint {
+ Paint::Image(ImagePaint {
+ active: true,
+ image,
+ fit,
+ filters: ImageFilters::default(),
+ opacity: 1.0,
+ blend_mode: BlendMode::Normal,
+ quarter_turns: 0,
+ alignement: Alignment::CENTER,
+ })
+}
+
+// ═════════════════════════════════════════════════════════════════════════════
+// Node builders
+// ═════════════════════════════════════════════════════════════════════════════
+
+/// Simple rectangle with one fill.
+pub fn rect(x: f32, y: f32, w: f32, h: f32, fill: Paint) -> Node {
+ Node::Rectangle(RectangleNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ transform: AffineTransform::from_box_center(x, y, w, h, 0.0),
+ size: Size { width: w, height: h },
+ corner_radius: RectangularCornerRadius::default(),
+ corner_smoothing: CornerSmoothing(0.0),
+ fills: Paints::new(vec![fill]),
+ strokes: Paints::new(vec![]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: StrokeWidth::None,
+ effects: LayerEffects::default(),
+ layout_child: None,
+ })
+}
+
+/// Rectangle with rotation.
+pub fn rect_rotated(x: f32, y: f32, w: f32, h: f32, rotation: f32, fill: Paint) -> Node {
+ Node::Rectangle(RectangleNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ transform: AffineTransform::from_box_center(x, y, w, h, rotation),
+ size: Size { width: w, height: h },
+ corner_radius: RectangularCornerRadius::default(),
+ corner_smoothing: CornerSmoothing(0.0),
+ fills: Paints::new(vec![fill]),
+ strokes: Paints::new(vec![]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: StrokeWidth::None,
+ effects: LayerEffects::default(),
+ layout_child: None,
+ })
+}
+
+/// Simple ellipse with one fill.
+pub fn ellipse(x: f32, y: f32, w: f32, h: f32, fill: Paint) -> Node {
+ Node::Ellipse(EllipseNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ transform: AffineTransform::from_box_center(x, y, w, h, 0.0),
+ size: Size { width: w, height: h },
+ fills: Paints::new(vec![fill]),
+ strokes: Paints::new(vec![]),
+ stroke_style: StrokeStyle::default(),
+ stroke_width: SingularStrokeWidth(None),
+ inner_radius: None,
+ start_angle: 0.0,
+ angle: None,
+ corner_radius: None,
+ effects: LayerEffects::default(),
+ layout_child: None,
+ })
+}
+
+/// Simple line.
+pub fn line(x: f32, y: f32, length: f32, rotation: f32, stroke_width: f32) -> Node {
+ Node::Line(LineNodeRec {
+ active: true,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ transform: AffineTransform::new(x, y, rotation),
+ size: Size { width: length, height: 0.0 },
+ strokes: Paints::new(vec![solid(0, 0, 0, 255)]),
+ stroke_width,
+ stroke_cap: StrokeCap::Butt,
+ stroke_miter_limit: StrokeMiterLimit(4.0),
+ stroke_dash_array: None,
+ _data_stroke_align: StrokeAlign::Center,
+ marker_start_shape: StrokeMarkerPreset::None,
+ marker_end_shape: StrokeMarkerPreset::None,
+ layout_child: None,
+ })
+}
+
+/// Simple text span.
+pub fn text(x: f32, y: f32, content: &str, font_size: f32, font_weight: u32) -> Node {
+ Node::TextSpan(TextSpanNodeRec {
+ active: true,
+ transform: AffineTransform::new(x, y, 0.0),
+ width: None,
+ height: None,
+ layout_child: None,
+ text: content.to_owned(),
+ text_style: {
+ let mut ts = TextStyleRec::from_font("Inter", font_size);
+ ts.font_weight = FontWeight(font_weight);
+ ts
+ },
+ text_align: TextAlign::Left,
+ text_align_vertical: TextAlignVertical::Top,
+ max_lines: None,
+ ellipsis: None,
+ fills: Paints::new(vec![solid(0, 0, 0, 255)]),
+ strokes: Paints::new(vec![]),
+ stroke_width: 0.0,
+ stroke_align: StrokeAlign::Center,
+ opacity: 1.0,
+ blend_mode: LayerBlendMode::PassThrough,
+ mask: None,
+ effects: LayerEffects::default(),
+ })
+}
+
+/// Simple flat scene: all nodes at the root level, auto-assigned positions.
+pub fn flat_scene(name: &str, nodes: Vec) -> Scene {
+ let mut pairs = Vec::new();
+ for (i, node) in nodes.into_iter().enumerate() {
+ pairs.push(((i + 1) as u64, node));
+ }
+ let roots: Vec = pairs.iter().map(|(id, _)| *id).collect();
+ build_scene(name, None, pairs, HashMap::new(), roots)
+}
+
+
diff --git a/crates/grida-canvas/examples/golden_type_decoration.rs b/crates/grida-canvas/examples/golden_type_decoration.rs
index 00f0af156d..f13de23ee4 100644
--- a/crates/grida-canvas/examples/golden_type_decoration.rs
+++ b/crates/grida-canvas/examples/golden_type_decoration.rs
@@ -99,7 +99,7 @@ fn main() {
text_decoration_color: Some(CGColor::RED),
text_decoration_style: None,
text_decoration_skip_ink: None,
- text_decoration_thinkness: None,
+ text_decoration_thickness: None,
}),
font_family: "Geist".to_string(),
font_size: font_size,
@@ -153,7 +153,7 @@ fn main() {
text_decoration_color: Some(CGColor::BLACK),
text_decoration_style: Some(*style),
text_decoration_skip_ink: None,
- text_decoration_thinkness: None,
+ text_decoration_thickness: None,
}),
font_family: "Geist".to_string(),
font_size: font_size,
@@ -207,7 +207,7 @@ fn main() {
text_decoration_color: Some(*color),
text_decoration_style: None,
text_decoration_skip_ink: None,
- text_decoration_thinkness: None,
+ text_decoration_thickness: None,
}),
font_family: "Geist".to_string(),
font_size: font_size,
@@ -265,7 +265,7 @@ fn main() {
text_decoration_color: Some(CGColor::BLACK),
text_decoration_style: None,
text_decoration_skip_ink: None,
- text_decoration_thinkness: Some(*thickness),
+ text_decoration_thickness: Some(*thickness),
}),
font_family: "Geist".to_string(),
font_size: font_size,
@@ -317,7 +317,7 @@ fn main() {
text_decoration_color: Some(CGColor::from_rgba(255, 0, 0, 255)),
text_decoration_style: None,
text_decoration_skip_ink: Some(*skip_ink),
- text_decoration_thinkness: None,
+ text_decoration_thickness: None,
}),
font_family: "Geist".to_string(),
font_size: font_size,
@@ -388,7 +388,7 @@ fn main() {
text_decoration_color: *color,
text_decoration_style: *style,
text_decoration_skip_ink: None,
- text_decoration_thinkness: *thickness,
+ text_decoration_thickness: *thickness,
}),
font_family: "Geist".to_string(),
font_size: font_size,
@@ -445,7 +445,7 @@ fn main() {
text_decoration_color: Some(CGColor::from_rgba(100, 100, 100, 255)),
text_decoration_style: Some(TextDecorationStyle::Solid),
text_decoration_skip_ink: None,
- text_decoration_thinkness: Some(1.5),
+ text_decoration_thickness: Some(1.5),
}),
font_family: "Geist".to_string(),
font_size: font_size,
diff --git a/crates/grida-canvas/examples/golden_type_decoration_color.rs b/crates/grida-canvas/examples/golden_type_decoration_color.rs
index f11251c965..04b2b5d3de 100644
--- a/crates/grida-canvas/examples/golden_type_decoration_color.rs
+++ b/crates/grida-canvas/examples/golden_type_decoration_color.rs
@@ -90,7 +90,7 @@ fn main() {
text_decoration_color: Some(*color),
text_decoration_style: None,
text_decoration_skip_ink: None,
- text_decoration_thinkness: Some(1.5),
+ text_decoration_thickness: Some(1.5),
}),
font_family: "Geist".to_string(),
font_size: font_size,
diff --git a/crates/grida-canvas/examples/golden_type_emoji_placeholder.rs b/crates/grida-canvas/examples/golden_type_emoji_placeholder.rs
index 69482d4a8b..d6f21d6da1 100644
--- a/crates/grida-canvas/examples/golden_type_emoji_placeholder.rs
+++ b/crates/grida-canvas/examples/golden_type_emoji_placeholder.rs
@@ -108,7 +108,7 @@ fn main() {
text_decoration_color: Some(CGColor::BLUE),
text_decoration_style: None,
text_decoration_skip_ink: None,
- text_decoration_thinkness: None,
+ text_decoration_thickness: None,
});
let mut ts = textstyle(&style, &None);
ts.set_foreground_paint(&paint);
diff --git a/crates/grida-canvas/examples/tool_gen_fixtures.rs b/crates/grida-canvas/examples/tool_gen_fixtures.rs
new file mode 100644
index 0000000000..40f73a9519
--- /dev/null
+++ b/crates/grida-canvas/examples/tool_gen_fixtures.rs
@@ -0,0 +1,44 @@
+//! Fixture Generator Tool
+//!
+//! Packs all L0 scene builders into a single `L0.grida` file and writes it to
+//! `fixtures/test-grida/`.
+//!
+//! ## Usage
+//!
+//! ```bash
+//! cargo run --package cg --example tool_gen_fixtures
+//! ```
+//!
+//! ## Output
+//!
+//! On success the tool prints the byte count, scene count, and output path.
+
+mod fixtures;
+
+fn main() {
+ let scenes: Vec<(&str, _)> = vec![
+ ("L0-shapes", fixtures::l0_shapes::build()),
+ ("L0-shape-arc", fixtures::l0_shape_arc::build()),
+ ("L0-shape-polygon", fixtures::l0_shape_polygon::build()),
+ ("L0-vector", fixtures::l0_vector::build()),
+ ("L0-paints", fixtures::l0_paints::build()),
+ ("L0-paints-stack", fixtures::l0_paints_stack::build()),
+ ("L0-strokes", fixtures::l0_strokes::build()),
+ ("L0-strokes-rect", fixtures::l0_strokes_rect::build()),
+ ("L0-image", fixtures::l0_image::build()),
+ ("L0-image-filters", fixtures::l0_image_filters::build()),
+ ("L0-effects", fixtures::l0_effects::build()),
+ ("L0-effects-glass", fixtures::l0_effects_glass::build()),
+ ("L0-type", fixtures::l0_type::build()),
+ ("L0-type-fvar", fixtures::l0_type_fvar::build()),
+ ("L0-type-features", fixtures::l0_type_features::build()),
+ ("L0-masks", fixtures::l0_masks::build()),
+ ("L0-boolean-operation", fixtures::l0_boolean_operation::build()),
+ ("L0-container", fixtures::l0_container::build()),
+ ("L0-group", fixtures::l0_group::build()),
+ ("L0-layout-position", fixtures::l0_layout_position::build()),
+ ("L0-layout-flex", fixtures::l0_layout_flex::build()),
+ ("L0-layout-transform", fixtures::l0_layout_transform::build()),
+ ];
+ fixtures::write_multi_fixture(&scenes, "L0");
+}
diff --git a/crates/grida-canvas/package.json b/crates/grida-canvas/package.json
index a3d97ea174..9cde75502d 100644
--- a/crates/grida-canvas/package.json
+++ b/crates/grida-canvas/package.json
@@ -4,6 +4,10 @@
"description": "turbo ci rust wrapper",
"scripts": {
"build": "cargo build --release",
+ "flatc:clean": "rm -f src/io/generated/grida.rs",
+ "flatc:generate": "pnpm flatc:clean && python3 ../../bin/activate-flatc -- --rust -o src/io/generated ../../format/grida.fbs && mv src/io/generated/grida_generated.rs src/io/generated/grida.rs",
+ "generate": "pnpm flatc:generate",
+ "prebuild": "pnpm flatc:generate",
"test": "cargo test"
}
}
diff --git a/crates/grida-canvas/src/cg/types.rs b/crates/grida-canvas/src/cg/types.rs
index ca1273fc58..6ae4b93426 100644
--- a/crates/grida-canvas/src/cg/types.rs
+++ b/crates/grida-canvas/src/cg/types.rs
@@ -1407,7 +1407,7 @@ pub struct TextDecorationRec {
pub text_decoration_skip_ink: Option,
/// The thickness of the decoration stroke as a multiplier of the thickness defined by the font.
- pub text_decoration_thinkness: Option,
+ pub text_decoration_thickness: Option,
}
impl TextDecorationRec {
@@ -1417,7 +1417,7 @@ impl TextDecorationRec {
text_decoration_color: None,
text_decoration_style: None,
text_decoration_skip_ink: None,
- text_decoration_thinkness: None,
+ text_decoration_thickness: None,
}
}
@@ -1427,7 +1427,7 @@ impl TextDecorationRec {
text_decoration_color: None,
text_decoration_style: None,
text_decoration_skip_ink: None,
- text_decoration_thinkness: None,
+ text_decoration_thickness: None,
}
}
@@ -1437,7 +1437,7 @@ impl TextDecorationRec {
text_decoration_color: None,
text_decoration_style: None,
text_decoration_skip_ink: None,
- text_decoration_thinkness: None,
+ text_decoration_thickness: None,
}
}
}
@@ -1454,7 +1454,7 @@ pub struct TextDecoration {
pub text_decoration_color: CGColor,
pub text_decoration_style: TextDecorationStyle,
pub text_decoration_skip_ink: bool,
- pub text_decoration_thinkness: f32,
+ pub text_decoration_thickness: f32,
}
impl Default for TextDecoration {
@@ -1464,7 +1464,7 @@ impl Default for TextDecoration {
text_decoration_color: CGColor::TRANSPARENT,
text_decoration_style: TextDecorationStyle::Solid,
text_decoration_skip_ink: true,
- text_decoration_thinkness: 1.0,
+ text_decoration_thickness: 1.0,
}
}
}
@@ -1476,14 +1476,14 @@ impl FromWithContext for TextDecor
.text_decoration_style
.unwrap_or(TextDecorationStyle::default());
let text_decoration_skip_ink = value.text_decoration_skip_ink.unwrap_or(true);
- let text_decoration_thinkness = value.text_decoration_thinkness.unwrap_or(1.0);
+ let text_decoration_thickness = value.text_decoration_thickness.unwrap_or(1.0);
Self {
text_decoration_line: value.text_decoration_line,
text_decoration_color: text_decoration_color,
text_decoration_style: text_decoration_style,
text_decoration_skip_ink: text_decoration_skip_ink,
- text_decoration_thinkness: text_decoration_thinkness,
+ text_decoration_thickness: text_decoration_thickness,
}
}
}
diff --git a/crates/grida-canvas/src/io/generated/.gitattributes b/crates/grida-canvas/src/io/generated/.gitattributes
new file mode 100644
index 0000000000..2c1875e3d1
--- /dev/null
+++ b/crates/grida-canvas/src/io/generated/.gitattributes
@@ -0,0 +1 @@
+grida.rs linguist-generated=true
diff --git a/crates/grida-canvas/src/io/generated/grida.rs b/crates/grida-canvas/src/io/generated/grida.rs
new file mode 100644
index 0000000000..8cae8f9d85
--- /dev/null
+++ b/crates/grida-canvas/src/io/generated/grida.rs
@@ -0,0 +1,18899 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+// @generated
+extern crate alloc;
+
+
+#[allow(unused_imports, dead_code)]
+pub mod grida {
+
+
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_NODE_TYPE: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_NODE_TYPE: u8 = 14;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_NODE_TYPE: [NodeType; 15] = [
+ NodeType::Exception,
+ NodeType::Scene,
+ NodeType::Group,
+ NodeType::InitialContainer,
+ NodeType::Container,
+ NodeType::BooleanOperation,
+ NodeType::Rectangle,
+ NodeType::Ellipse,
+ NodeType::Polygon,
+ NodeType::RegularPolygon,
+ NodeType::RegularStarPolygon,
+ NodeType::Path,
+ NodeType::Line,
+ NodeType::Vector,
+ NodeType::TextSpan,
+];
+
+/// node type
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct NodeType(pub u8);
+#[allow(non_upper_case_globals)]
+impl NodeType {
+ pub const Exception: Self = Self(0);
+ pub const Scene: Self = Self(1);
+ pub const Group: Self = Self(2);
+ pub const InitialContainer: Self = Self(3);
+ pub const Container: Self = Self(4);
+ pub const BooleanOperation: Self = Self(5);
+ pub const Rectangle: Self = Self(6);
+ pub const Ellipse: Self = Self(7);
+ pub const Polygon: Self = Self(8);
+ pub const RegularPolygon: Self = Self(9);
+ pub const RegularStarPolygon: Self = Self(10);
+ pub const Path: Self = Self(11);
+ pub const Line: Self = Self(12);
+ pub const Vector: Self = Self(13);
+ pub const TextSpan: Self = Self(14);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 14;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::Exception,
+ Self::Scene,
+ Self::Group,
+ Self::InitialContainer,
+ Self::Container,
+ Self::BooleanOperation,
+ Self::Rectangle,
+ Self::Ellipse,
+ Self::Polygon,
+ Self::RegularPolygon,
+ Self::RegularStarPolygon,
+ Self::Path,
+ Self::Line,
+ Self::Vector,
+ Self::TextSpan,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::Exception => Some("Exception"),
+ Self::Scene => Some("Scene"),
+ Self::Group => Some("Group"),
+ Self::InitialContainer => Some("InitialContainer"),
+ Self::Container => Some("Container"),
+ Self::BooleanOperation => Some("BooleanOperation"),
+ Self::Rectangle => Some("Rectangle"),
+ Self::Ellipse => Some("Ellipse"),
+ Self::Polygon => Some("Polygon"),
+ Self::RegularPolygon => Some("RegularPolygon"),
+ Self::RegularStarPolygon => Some("RegularStarPolygon"),
+ Self::Path => Some("Path"),
+ Self::Line => Some("Line"),
+ Self::Vector => Some("Vector"),
+ Self::TextSpan => Some("TextSpan"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for NodeType {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for NodeType {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for NodeType {
+ type Output = NodeType;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for NodeType {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for NodeType {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for NodeType {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_BASIC_SHAPE_NODE_TYPE: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_BASIC_SHAPE_NODE_TYPE: u8 = 5;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_BASIC_SHAPE_NODE_TYPE: [BasicShapeNodeType; 6] = [
+ BasicShapeNodeType::Rectangle,
+ BasicShapeNodeType::Ellipse,
+ BasicShapeNodeType::Polygon,
+ BasicShapeNodeType::RegularPolygon,
+ BasicShapeNodeType::RegularStarPolygon,
+ BasicShapeNodeType::Path,
+];
+
+/// shape node type (flag within BasicShapeNode)
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct BasicShapeNodeType(pub u8);
+#[allow(non_upper_case_globals)]
+impl BasicShapeNodeType {
+ pub const Rectangle: Self = Self(0);
+ pub const Ellipse: Self = Self(1);
+ pub const Polygon: Self = Self(2);
+ pub const RegularPolygon: Self = Self(3);
+ pub const RegularStarPolygon: Self = Self(4);
+ pub const Path: Self = Self(5);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 5;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::Rectangle,
+ Self::Ellipse,
+ Self::Polygon,
+ Self::RegularPolygon,
+ Self::RegularStarPolygon,
+ Self::Path,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::Rectangle => Some("Rectangle"),
+ Self::Ellipse => Some("Ellipse"),
+ Self::Polygon => Some("Polygon"),
+ Self::RegularPolygon => Some("RegularPolygon"),
+ Self::RegularStarPolygon => Some("RegularStarPolygon"),
+ Self::Path => Some("Path"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for BasicShapeNodeType {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for BasicShapeNodeType {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for BasicShapeNodeType {
+ type Output = BasicShapeNodeType;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for BasicShapeNodeType {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for BasicShapeNodeType {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for BasicShapeNodeType {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_BLEND_MODE: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_BLEND_MODE: u8 = 15;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_BLEND_MODE: [BlendMode; 16] = [
+ BlendMode::Normal,
+ BlendMode::Multiply,
+ BlendMode::Screen,
+ BlendMode::Overlay,
+ BlendMode::Darken,
+ BlendMode::Lighten,
+ BlendMode::ColorDodge,
+ BlendMode::ColorBurn,
+ BlendMode::HardLight,
+ BlendMode::SoftLight,
+ BlendMode::Difference,
+ BlendMode::Exclusion,
+ BlendMode::Hue,
+ BlendMode::Saturation,
+ BlendMode::Color,
+ BlendMode::Luminosity,
+];
+
+/// Rust: `BlendMode` (does not include pass-through)
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct BlendMode(pub u8);
+#[allow(non_upper_case_globals)]
+impl BlendMode {
+ pub const Normal: Self = Self(0);
+ pub const Multiply: Self = Self(1);
+ pub const Screen: Self = Self(2);
+ pub const Overlay: Self = Self(3);
+ pub const Darken: Self = Self(4);
+ pub const Lighten: Self = Self(5);
+ pub const ColorDodge: Self = Self(6);
+ pub const ColorBurn: Self = Self(7);
+ pub const HardLight: Self = Self(8);
+ pub const SoftLight: Self = Self(9);
+ pub const Difference: Self = Self(10);
+ pub const Exclusion: Self = Self(11);
+ pub const Hue: Self = Self(12);
+ pub const Saturation: Self = Self(13);
+ pub const Color: Self = Self(14);
+ pub const Luminosity: Self = Self(15);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 15;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::Normal,
+ Self::Multiply,
+ Self::Screen,
+ Self::Overlay,
+ Self::Darken,
+ Self::Lighten,
+ Self::ColorDodge,
+ Self::ColorBurn,
+ Self::HardLight,
+ Self::SoftLight,
+ Self::Difference,
+ Self::Exclusion,
+ Self::Hue,
+ Self::Saturation,
+ Self::Color,
+ Self::Luminosity,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::Normal => Some("Normal"),
+ Self::Multiply => Some("Multiply"),
+ Self::Screen => Some("Screen"),
+ Self::Overlay => Some("Overlay"),
+ Self::Darken => Some("Darken"),
+ Self::Lighten => Some("Lighten"),
+ Self::ColorDodge => Some("ColorDodge"),
+ Self::ColorBurn => Some("ColorBurn"),
+ Self::HardLight => Some("HardLight"),
+ Self::SoftLight => Some("SoftLight"),
+ Self::Difference => Some("Difference"),
+ Self::Exclusion => Some("Exclusion"),
+ Self::Hue => Some("Hue"),
+ Self::Saturation => Some("Saturation"),
+ Self::Color => Some("Color"),
+ Self::Luminosity => Some("Luminosity"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for BlendMode {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for BlendMode {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for BlendMode {
+ type Output = BlendMode;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for BlendMode {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for BlendMode {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for BlendMode {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_LAYER_BLEND_MODE: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_LAYER_BLEND_MODE: u8 = 100;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_LAYER_BLEND_MODE: [LayerBlendMode; 17] = [
+ LayerBlendMode::Normal,
+ LayerBlendMode::Multiply,
+ LayerBlendMode::Screen,
+ LayerBlendMode::Overlay,
+ LayerBlendMode::Darken,
+ LayerBlendMode::Lighten,
+ LayerBlendMode::ColorDodge,
+ LayerBlendMode::ColorBurn,
+ LayerBlendMode::HardLight,
+ LayerBlendMode::SoftLight,
+ LayerBlendMode::Difference,
+ LayerBlendMode::Exclusion,
+ LayerBlendMode::Hue,
+ LayerBlendMode::Saturation,
+ LayerBlendMode::Color,
+ LayerBlendMode::Luminosity,
+ LayerBlendMode::PassThrough,
+];
+
+/// Archive model: flattened blend mode with pass-through included.
+///
+/// This duplicates `BlendMode` variants and adds `pass_through`, avoiding a union/table wrapper.
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct LayerBlendMode(pub u8);
+#[allow(non_upper_case_globals)]
+impl LayerBlendMode {
+ pub const Normal: Self = Self(0);
+ pub const Multiply: Self = Self(1);
+ pub const Screen: Self = Self(2);
+ pub const Overlay: Self = Self(3);
+ pub const Darken: Self = Self(4);
+ pub const Lighten: Self = Self(5);
+ pub const ColorDodge: Self = Self(6);
+ pub const ColorBurn: Self = Self(7);
+ pub const HardLight: Self = Self(8);
+ pub const SoftLight: Self = Self(9);
+ pub const Difference: Self = Self(10);
+ pub const Exclusion: Self = Self(11);
+ pub const Hue: Self = Self(12);
+ pub const Saturation: Self = Self(13);
+ pub const Color: Self = Self(14);
+ pub const Luminosity: Self = Self(15);
+ /// Archive-only sentinel: corresponds to Rust `LayerBlendMode::PassThrough`.
+ /// Set to 100 to avoid confusing it with `BlendMode` ids.
+ pub const PassThrough: Self = Self(100);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 100;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::Normal,
+ Self::Multiply,
+ Self::Screen,
+ Self::Overlay,
+ Self::Darken,
+ Self::Lighten,
+ Self::ColorDodge,
+ Self::ColorBurn,
+ Self::HardLight,
+ Self::SoftLight,
+ Self::Difference,
+ Self::Exclusion,
+ Self::Hue,
+ Self::Saturation,
+ Self::Color,
+ Self::Luminosity,
+ Self::PassThrough,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::Normal => Some("Normal"),
+ Self::Multiply => Some("Multiply"),
+ Self::Screen => Some("Screen"),
+ Self::Overlay => Some("Overlay"),
+ Self::Darken => Some("Darken"),
+ Self::Lighten => Some("Lighten"),
+ Self::ColorDodge => Some("ColorDodge"),
+ Self::ColorBurn => Some("ColorBurn"),
+ Self::HardLight => Some("HardLight"),
+ Self::SoftLight => Some("SoftLight"),
+ Self::Difference => Some("Difference"),
+ Self::Exclusion => Some("Exclusion"),
+ Self::Hue => Some("Hue"),
+ Self::Saturation => Some("Saturation"),
+ Self::Color => Some("Color"),
+ Self::Luminosity => Some("Luminosity"),
+ Self::PassThrough => Some("PassThrough"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for LayerBlendMode {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for LayerBlendMode {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for LayerBlendMode {
+ type Output = LayerBlendMode;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for LayerBlendMode {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for LayerBlendMode {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for LayerBlendMode {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_AXIS: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_AXIS: u8 = 1;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_AXIS: [Axis; 2] = [
+ Axis::Horizontal,
+ Axis::Vertical,
+];
+
+/// Rust: `Axis`
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct Axis(pub u8);
+#[allow(non_upper_case_globals)]
+impl Axis {
+ pub const Horizontal: Self = Self(0);
+ pub const Vertical: Self = Self(1);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 1;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::Horizontal,
+ Self::Vertical,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::Horizontal => Some("Horizontal"),
+ Self::Vertical => Some("Vertical"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for Axis {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for Axis {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for Axis {
+ type Output = Axis;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for Axis {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for Axis {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for Axis {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_TILE_MODE: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_TILE_MODE: u8 = 3;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_TILE_MODE: [TileMode; 4] = [
+ TileMode::Clamp,
+ TileMode::Repeated,
+ TileMode::Mirror,
+ TileMode::Decal,
+];
+
+/// Rust: `TileMode`
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct TileMode(pub u8);
+#[allow(non_upper_case_globals)]
+impl TileMode {
+ pub const Clamp: Self = Self(0);
+ pub const Repeated: Self = Self(1);
+ pub const Mirror: Self = Self(2);
+ pub const Decal: Self = Self(3);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 3;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::Clamp,
+ Self::Repeated,
+ Self::Mirror,
+ Self::Decal,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::Clamp => Some("Clamp"),
+ Self::Repeated => Some("Repeated"),
+ Self::Mirror => Some("Mirror"),
+ Self::Decal => Some("Decal"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for TileMode {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for TileMode {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for TileMode {
+ type Output = TileMode;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for TileMode {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for TileMode {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for TileMode {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_BOX_FIT: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_BOX_FIT: u8 = 3;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_BOX_FIT: [BoxFit; 4] = [
+ BoxFit::Contain,
+ BoxFit::Cover,
+ BoxFit::Fill,
+ BoxFit::None,
+];
+
+/// Rust: `math2::box_fit::BoxFit`
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct BoxFit(pub u8);
+#[allow(non_upper_case_globals)]
+impl BoxFit {
+ pub const Contain: Self = Self(0);
+ pub const Cover: Self = Self(1);
+ pub const Fill: Self = Self(2);
+ pub const None: Self = Self(3);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 3;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::Contain,
+ Self::Cover,
+ Self::Fill,
+ Self::None,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::Contain => Some("Contain"),
+ Self::Cover => Some("Cover"),
+ Self::Fill => Some("Fill"),
+ Self::None => Some("None"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for BoxFit {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for BoxFit {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for BoxFit {
+ type Output = BoxFit;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for BoxFit {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for BoxFit {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for BoxFit {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_IMAGE_REPEAT: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_IMAGE_REPEAT: u8 = 2;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_IMAGE_REPEAT: [ImageRepeat; 3] = [
+ ImageRepeat::RepeatX,
+ ImageRepeat::RepeatY,
+ ImageRepeat::Repeat,
+];
+
+/// Rust: `ImageRepeat`
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct ImageRepeat(pub u8);
+#[allow(non_upper_case_globals)]
+impl ImageRepeat {
+ pub const RepeatX: Self = Self(0);
+ pub const RepeatY: Self = Self(1);
+ pub const Repeat: Self = Self(2);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 2;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::RepeatX,
+ Self::RepeatY,
+ Self::Repeat,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::RepeatX => Some("RepeatX"),
+ Self::RepeatY => Some("RepeatY"),
+ Self::Repeat => Some("Repeat"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for ImageRepeat {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for ImageRepeat {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for ImageRepeat {
+ type Output = ImageRepeat;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for ImageRepeat {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for ImageRepeat {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for ImageRepeat {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_LAYOUT_MODE: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_LAYOUT_MODE: u8 = 1;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_LAYOUT_MODE: [LayoutMode; 2] = [
+ LayoutMode::Normal,
+ LayoutMode::Flex,
+];
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct LayoutMode(pub u8);
+#[allow(non_upper_case_globals)]
+impl LayoutMode {
+ pub const Normal: Self = Self(0);
+ pub const Flex: Self = Self(1);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 1;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::Normal,
+ Self::Flex,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::Normal => Some("Normal"),
+ Self::Flex => Some("Flex"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for LayoutMode {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for LayoutMode {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for LayoutMode {
+ type Output = LayoutMode;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for LayoutMode {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for LayoutMode {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for LayoutMode {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_LAYOUT_WRAP: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_LAYOUT_WRAP: u8 = 2;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_LAYOUT_WRAP: [LayoutWrap; 3] = [
+ LayoutWrap::None,
+ LayoutWrap::Wrap,
+ LayoutWrap::NoWrap,
+];
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct LayoutWrap(pub u8);
+#[allow(non_upper_case_globals)]
+impl LayoutWrap {
+ pub const None: Self = Self(0);
+ pub const Wrap: Self = Self(1);
+ pub const NoWrap: Self = Self(2);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 2;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::None,
+ Self::Wrap,
+ Self::NoWrap,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::None => Some("None"),
+ Self::Wrap => Some("Wrap"),
+ Self::NoWrap => Some("NoWrap"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for LayoutWrap {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for LayoutWrap {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for LayoutWrap {
+ type Output = LayoutWrap;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for LayoutWrap {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for LayoutWrap {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for LayoutWrap {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_LAYOUT_POSITIONING: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_LAYOUT_POSITIONING: u8 = 1;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_LAYOUT_POSITIONING: [LayoutPositioning; 2] = [
+ LayoutPositioning::Auto,
+ LayoutPositioning::Absolute,
+];
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct LayoutPositioning(pub u8);
+#[allow(non_upper_case_globals)]
+impl LayoutPositioning {
+ pub const Auto: Self = Self(0);
+ pub const Absolute: Self = Self(1);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 1;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::Auto,
+ Self::Absolute,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::Auto => Some("Auto"),
+ Self::Absolute => Some("Absolute"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for LayoutPositioning {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for LayoutPositioning {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for LayoutPositioning {
+ type Output = LayoutPositioning;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for LayoutPositioning {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for LayoutPositioning {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for LayoutPositioning {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_MAIN_AXIS_ALIGNMENT: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_MAIN_AXIS_ALIGNMENT: u8 = 7;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_MAIN_AXIS_ALIGNMENT: [MainAxisAlignment; 8] = [
+ MainAxisAlignment::None,
+ MainAxisAlignment::Start,
+ MainAxisAlignment::End,
+ MainAxisAlignment::Center,
+ MainAxisAlignment::SpaceBetween,
+ MainAxisAlignment::SpaceAround,
+ MainAxisAlignment::SpaceEvenly,
+ MainAxisAlignment::Stretch,
+];
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct MainAxisAlignment(pub u8);
+#[allow(non_upper_case_globals)]
+impl MainAxisAlignment {
+ pub const None: Self = Self(0);
+ pub const Start: Self = Self(1);
+ pub const End: Self = Self(2);
+ pub const Center: Self = Self(3);
+ pub const SpaceBetween: Self = Self(4);
+ pub const SpaceAround: Self = Self(5);
+ pub const SpaceEvenly: Self = Self(6);
+ pub const Stretch: Self = Self(7);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 7;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::None,
+ Self::Start,
+ Self::End,
+ Self::Center,
+ Self::SpaceBetween,
+ Self::SpaceAround,
+ Self::SpaceEvenly,
+ Self::Stretch,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::None => Some("None"),
+ Self::Start => Some("Start"),
+ Self::End => Some("End"),
+ Self::Center => Some("Center"),
+ Self::SpaceBetween => Some("SpaceBetween"),
+ Self::SpaceAround => Some("SpaceAround"),
+ Self::SpaceEvenly => Some("SpaceEvenly"),
+ Self::Stretch => Some("Stretch"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for MainAxisAlignment {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for MainAxisAlignment {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for MainAxisAlignment {
+ type Output = MainAxisAlignment;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for MainAxisAlignment {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for MainAxisAlignment {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for MainAxisAlignment {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_CROSS_AXIS_ALIGNMENT: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_CROSS_AXIS_ALIGNMENT: u8 = 4;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_CROSS_AXIS_ALIGNMENT: [CrossAxisAlignment; 5] = [
+ CrossAxisAlignment::None,
+ CrossAxisAlignment::Start,
+ CrossAxisAlignment::End,
+ CrossAxisAlignment::Center,
+ CrossAxisAlignment::Stretch,
+];
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct CrossAxisAlignment(pub u8);
+#[allow(non_upper_case_globals)]
+impl CrossAxisAlignment {
+ pub const None: Self = Self(0);
+ pub const Start: Self = Self(1);
+ pub const End: Self = Self(2);
+ pub const Center: Self = Self(3);
+ pub const Stretch: Self = Self(4);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 4;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::None,
+ Self::Start,
+ Self::End,
+ Self::Center,
+ Self::Stretch,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::None => Some("None"),
+ Self::Start => Some("Start"),
+ Self::End => Some("End"),
+ Self::Center => Some("Center"),
+ Self::Stretch => Some("Stretch"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for CrossAxisAlignment {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for CrossAxisAlignment {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for CrossAxisAlignment {
+ type Output = CrossAxisAlignment;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for CrossAxisAlignment {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for CrossAxisAlignment {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for CrossAxisAlignment {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_STROKE_ALIGN: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_STROKE_ALIGN: u8 = 2;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_STROKE_ALIGN: [StrokeAlign; 3] = [
+ StrokeAlign::Inside,
+ StrokeAlign::Center,
+ StrokeAlign::Outside,
+];
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct StrokeAlign(pub u8);
+#[allow(non_upper_case_globals)]
+impl StrokeAlign {
+ pub const Inside: Self = Self(0);
+ pub const Center: Self = Self(1);
+ pub const Outside: Self = Self(2);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 2;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::Inside,
+ Self::Center,
+ Self::Outside,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::Inside => Some("Inside"),
+ Self::Center => Some("Center"),
+ Self::Outside => Some("Outside"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for StrokeAlign {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for StrokeAlign {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for StrokeAlign {
+ type Output = StrokeAlign;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for StrokeAlign {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for StrokeAlign {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for StrokeAlign {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_STROKE_CAP: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_STROKE_CAP: u8 = 2;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_STROKE_CAP: [StrokeCap; 3] = [
+ StrokeCap::Butt,
+ StrokeCap::Round,
+ StrokeCap::Square,
+];
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct StrokeCap(pub u8);
+#[allow(non_upper_case_globals)]
+impl StrokeCap {
+ pub const Butt: Self = Self(0);
+ pub const Round: Self = Self(1);
+ pub const Square: Self = Self(2);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 2;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::Butt,
+ Self::Round,
+ Self::Square,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::Butt => Some("Butt"),
+ Self::Round => Some("Round"),
+ Self::Square => Some("Square"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for StrokeCap {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for StrokeCap {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for StrokeCap {
+ type Output = StrokeCap;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for StrokeCap {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for StrokeCap {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for StrokeCap {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_STROKE_JOIN: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_STROKE_JOIN: u8 = 2;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_STROKE_JOIN: [StrokeJoin; 3] = [
+ StrokeJoin::Miter,
+ StrokeJoin::Round,
+ StrokeJoin::Bevel,
+];
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct StrokeJoin(pub u8);
+#[allow(non_upper_case_globals)]
+impl StrokeJoin {
+ pub const Miter: Self = Self(0);
+ pub const Round: Self = Self(1);
+ pub const Bevel: Self = Self(2);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 2;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::Miter,
+ Self::Round,
+ Self::Bevel,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::Miter => Some("Miter"),
+ Self::Round => Some("Round"),
+ Self::Bevel => Some("Bevel"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for StrokeJoin {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for StrokeJoin {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for StrokeJoin {
+ type Output = StrokeJoin;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for StrokeJoin {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for StrokeJoin {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for StrokeJoin {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_STROKE_MARKER_PRESET: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_STROKE_MARKER_PRESET: u8 = 6;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_STROKE_MARKER_PRESET: [StrokeMarkerPreset; 7] = [
+ StrokeMarkerPreset::None,
+ StrokeMarkerPreset::RightTriangleOpen,
+ StrokeMarkerPreset::EquilateralTriangle,
+ StrokeMarkerPreset::Circle,
+ StrokeMarkerPreset::Square,
+ StrokeMarkerPreset::Diamond,
+ StrokeMarkerPreset::VerticalBar,
+];
+
+/// Marker decoration placed at stroke endpoints or vector vertices.
+///
+/// Unlike StrokeCap (which maps to native backend caps like Skia PaintCap),
+/// StrokeMarkerPreset represents explicit marker geometry drawn on top of the
+/// stroke path. When a decoration is present at an endpoint, the renderer
+/// uses Butt cap at that endpoint and draws the marker geometry instead.
+///
+/// See: docs/wg/feat-2d/curve-decoration.md
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct StrokeMarkerPreset(pub u8);
+#[allow(non_upper_case_globals)]
+impl StrokeMarkerPreset {
+ /// No decoration (endpoint uses the node's stroke_cap as normal).
+ pub const None: Self = Self(0);
+ /// Right triangle (90° at tip), open stroked chevron — not filled.
+ pub const RightTriangleOpen: Self = Self(1);
+ /// Filled equilateral triangle pointing forward.
+ pub const EquilateralTriangle: Self = Self(2);
+ /// Filled circle.
+ pub const Circle: Self = Self(3);
+ /// Filled axis-aligned square.
+ pub const Square: Self = Self(4);
+ /// Filled diamond (square rotated 45°).
+ pub const Diamond: Self = Self(5);
+ /// Filled vertical bar (rectangle) perpendicular to the stroke.
+ pub const VerticalBar: Self = Self(6);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 6;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::None,
+ Self::RightTriangleOpen,
+ Self::EquilateralTriangle,
+ Self::Circle,
+ Self::Square,
+ Self::Diamond,
+ Self::VerticalBar,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::None => Some("None"),
+ Self::RightTriangleOpen => Some("RightTriangleOpen"),
+ Self::EquilateralTriangle => Some("EquilateralTriangle"),
+ Self::Circle => Some("Circle"),
+ Self::Square => Some("Square"),
+ Self::Diamond => Some("Diamond"),
+ Self::VerticalBar => Some("VerticalBar"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for StrokeMarkerPreset {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for StrokeMarkerPreset {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for StrokeMarkerPreset {
+ type Output = StrokeMarkerPreset;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for StrokeMarkerPreset {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for StrokeMarkerPreset {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for StrokeMarkerPreset {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_TEXT_ALIGN: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_TEXT_ALIGN: u8 = 3;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_TEXT_ALIGN: [TextAlign; 4] = [
+ TextAlign::Left,
+ TextAlign::Right,
+ TextAlign::Center,
+ TextAlign::Justify,
+];
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct TextAlign(pub u8);
+#[allow(non_upper_case_globals)]
+impl TextAlign {
+ pub const Left: Self = Self(0);
+ pub const Right: Self = Self(1);
+ pub const Center: Self = Self(2);
+ pub const Justify: Self = Self(3);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 3;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::Left,
+ Self::Right,
+ Self::Center,
+ Self::Justify,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::Left => Some("Left"),
+ Self::Right => Some("Right"),
+ Self::Center => Some("Center"),
+ Self::Justify => Some("Justify"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for TextAlign {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for TextAlign {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for TextAlign {
+ type Output = TextAlign;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for TextAlign {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for TextAlign {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for TextAlign {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_TEXT_ALIGN_VERTICAL: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_TEXT_ALIGN_VERTICAL: u8 = 2;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_TEXT_ALIGN_VERTICAL: [TextAlignVertical; 3] = [
+ TextAlignVertical::Top,
+ TextAlignVertical::Center,
+ TextAlignVertical::Bottom,
+];
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct TextAlignVertical(pub u8);
+#[allow(non_upper_case_globals)]
+impl TextAlignVertical {
+ pub const Top: Self = Self(0);
+ pub const Center: Self = Self(1);
+ pub const Bottom: Self = Self(2);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 2;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::Top,
+ Self::Center,
+ Self::Bottom,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::Top => Some("Top"),
+ Self::Center => Some("Center"),
+ Self::Bottom => Some("Bottom"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for TextAlignVertical {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for TextAlignVertical {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for TextAlignVertical {
+ type Output = TextAlignVertical;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for TextAlignVertical {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for TextAlignVertical {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for TextAlignVertical {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_BOOLEAN_PATH_OPERATION: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_BOOLEAN_PATH_OPERATION: u8 = 3;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_BOOLEAN_PATH_OPERATION: [BooleanPathOperation; 4] = [
+ BooleanPathOperation::Union,
+ BooleanPathOperation::Intersection,
+ BooleanPathOperation::Difference,
+ BooleanPathOperation::Xor,
+];
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct BooleanPathOperation(pub u8);
+#[allow(non_upper_case_globals)]
+impl BooleanPathOperation {
+ pub const Union: Self = Self(0);
+ pub const Intersection: Self = Self(1);
+ pub const Difference: Self = Self(2);
+ pub const Xor: Self = Self(3);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 3;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::Union,
+ Self::Intersection,
+ Self::Difference,
+ Self::Xor,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::Union => Some("Union"),
+ Self::Intersection => Some("Intersection"),
+ Self::Difference => Some("Difference"),
+ Self::Xor => Some("Xor"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for BooleanPathOperation {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for BooleanPathOperation {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for BooleanPathOperation {
+ type Output = BooleanPathOperation;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for BooleanPathOperation {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for BooleanPathOperation {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for BooleanPathOperation {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_SCENE_CONSTRAINTS_CHILDREN: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_SCENE_CONSTRAINTS_CHILDREN: u8 = 1;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_SCENE_CONSTRAINTS_CHILDREN: [SceneConstraintsChildren; 2] = [
+ SceneConstraintsChildren::Single,
+ SceneConstraintsChildren::Multiple,
+];
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct SceneConstraintsChildren(pub u8);
+#[allow(non_upper_case_globals)]
+impl SceneConstraintsChildren {
+ pub const Single: Self = Self(0);
+ pub const Multiple: Self = Self(1);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 1;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::Single,
+ Self::Multiple,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::Single => Some("Single"),
+ Self::Multiple => Some("Multiple"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for SceneConstraintsChildren {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for SceneConstraintsChildren {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for SceneConstraintsChildren {
+ type Output = SceneConstraintsChildren;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for SceneConstraintsChildren {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for SceneConstraintsChildren {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for SceneConstraintsChildren {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_FILL_RULE: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_FILL_RULE: u8 = 1;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_FILL_RULE: [FillRule; 2] = [
+ FillRule::NonZero,
+ FillRule::EvenOdd,
+];
+
+/// Rust: `FillRule`
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct FillRule(pub u8);
+#[allow(non_upper_case_globals)]
+impl FillRule {
+ pub const NonZero: Self = Self(0);
+ pub const EvenOdd: Self = Self(1);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 1;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::NonZero,
+ Self::EvenOdd,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::NonZero => Some("NonZero"),
+ Self::EvenOdd => Some("EvenOdd"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for FillRule {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for FillRule {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for FillRule {
+ type Output = FillRule;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for FillRule {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for FillRule {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for FillRule {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_IMAGE_MASK_TYPE: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_IMAGE_MASK_TYPE: u8 = 1;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_IMAGE_MASK_TYPE: [ImageMaskType; 2] = [
+ ImageMaskType::Alpha,
+ ImageMaskType::Luminance,
+];
+
+/// Rust: `ImageMaskType`
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct ImageMaskType(pub u8);
+#[allow(non_upper_case_globals)]
+impl ImageMaskType {
+ pub const Alpha: Self = Self(0);
+ pub const Luminance: Self = Self(1);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 1;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::Alpha,
+ Self::Luminance,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::Alpha => Some("Alpha"),
+ Self::Luminance => Some("Luminance"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for ImageMaskType {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for ImageMaskType {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for ImageMaskType {
+ type Output = ImageMaskType;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for ImageMaskType {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for ImageMaskType {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for ImageMaskType {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_LAYER_MASK_TYPE: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_LAYER_MASK_TYPE: u8 = 2;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_LAYER_MASK_TYPE: [LayerMaskType; 3] = [
+ LayerMaskType::NONE,
+ LayerMaskType::LayerMaskTypeImage,
+ LayerMaskType::LayerMaskTypeGeometry,
+];
+
+/// Rust: `LayerMaskType`
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct LayerMaskType(pub u8);
+#[allow(non_upper_case_globals)]
+impl LayerMaskType {
+ pub const NONE: Self = Self(0);
+ pub const LayerMaskTypeImage: Self = Self(1);
+ pub const LayerMaskTypeGeometry: Self = Self(2);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 2;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::NONE,
+ Self::LayerMaskTypeImage,
+ Self::LayerMaskTypeGeometry,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::NONE => Some("NONE"),
+ Self::LayerMaskTypeImage => Some("LayerMaskTypeImage"),
+ Self::LayerMaskTypeGeometry => Some("LayerMaskTypeGeometry"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for LayerMaskType {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for LayerMaskType {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for LayerMaskType {
+ type Output = LayerMaskType;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for LayerMaskType {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for LayerMaskType {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for LayerMaskType {}
+pub struct LayerMaskTypeUnionTableOffset {}
+
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_TEXT_TRANSFORM: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_TEXT_TRANSFORM: u8 = 3;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_TEXT_TRANSFORM: [TextTransform; 4] = [
+ TextTransform::None,
+ TextTransform::Uppercase,
+ TextTransform::Lowercase,
+ TextTransform::Capitalize,
+];
+
+/// Rust: `TextTransform`
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct TextTransform(pub u8);
+#[allow(non_upper_case_globals)]
+impl TextTransform {
+ pub const None: Self = Self(0);
+ pub const Uppercase: Self = Self(1);
+ pub const Lowercase: Self = Self(2);
+ pub const Capitalize: Self = Self(3);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 3;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::None,
+ Self::Uppercase,
+ Self::Lowercase,
+ Self::Capitalize,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::None => Some("None"),
+ Self::Uppercase => Some("Uppercase"),
+ Self::Lowercase => Some("Lowercase"),
+ Self::Capitalize => Some("Capitalize"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for TextTransform {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for TextTransform {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for TextTransform {
+ type Output = TextTransform;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for TextTransform {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for TextTransform {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for TextTransform {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_TEXT_DECORATION_LINE: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_TEXT_DECORATION_LINE: u8 = 3;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_TEXT_DECORATION_LINE: [TextDecorationLine; 4] = [
+ TextDecorationLine::None,
+ TextDecorationLine::Underline,
+ TextDecorationLine::Overline,
+ TextDecorationLine::LineThrough,
+];
+
+/// Rust: `TextDecorationLine`
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct TextDecorationLine(pub u8);
+#[allow(non_upper_case_globals)]
+impl TextDecorationLine {
+ pub const None: Self = Self(0);
+ pub const Underline: Self = Self(1);
+ pub const Overline: Self = Self(2);
+ pub const LineThrough: Self = Self(3);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 3;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::None,
+ Self::Underline,
+ Self::Overline,
+ Self::LineThrough,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::None => Some("None"),
+ Self::Underline => Some("Underline"),
+ Self::Overline => Some("Overline"),
+ Self::LineThrough => Some("LineThrough"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for TextDecorationLine {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for TextDecorationLine {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for TextDecorationLine {
+ type Output = TextDecorationLine;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for TextDecorationLine {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for TextDecorationLine {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for TextDecorationLine {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_TEXT_DECORATION_STYLE: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_TEXT_DECORATION_STYLE: u8 = 4;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_TEXT_DECORATION_STYLE: [TextDecorationStyle; 5] = [
+ TextDecorationStyle::Solid,
+ TextDecorationStyle::Double,
+ TextDecorationStyle::Dotted,
+ TextDecorationStyle::Dashed,
+ TextDecorationStyle::Wavy,
+];
+
+/// Rust: `TextDecorationStyle`
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct TextDecorationStyle(pub u8);
+#[allow(non_upper_case_globals)]
+impl TextDecorationStyle {
+ pub const Solid: Self = Self(0);
+ pub const Double: Self = Self(1);
+ pub const Dotted: Self = Self(2);
+ pub const Dashed: Self = Self(3);
+ pub const Wavy: Self = Self(4);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 4;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::Solid,
+ Self::Double,
+ Self::Dotted,
+ Self::Dashed,
+ Self::Wavy,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::Solid => Some("Solid"),
+ Self::Double => Some("Double"),
+ Self::Dotted => Some("Dotted"),
+ Self::Dashed => Some("Dashed"),
+ Self::Wavy => Some("Wavy"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for TextDecorationStyle {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for TextDecorationStyle {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for TextDecorationStyle {
+ type Output = TextDecorationStyle;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for TextDecorationStyle {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for TextDecorationStyle {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for TextDecorationStyle {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_FONT_OPTICAL_SIZING_KIND: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_FONT_OPTICAL_SIZING_KIND: u8 = 2;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_FONT_OPTICAL_SIZING_KIND: [FontOpticalSizingKind; 3] = [
+ FontOpticalSizingKind::Auto,
+ FontOpticalSizingKind::None,
+ FontOpticalSizingKind::Fixed,
+];
+
+/// Rust: `FontOpticalSizing` (Auto | None | Fixed(f32))
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct FontOpticalSizingKind(pub u8);
+#[allow(non_upper_case_globals)]
+impl FontOpticalSizingKind {
+ pub const Auto: Self = Self(0);
+ pub const None: Self = Self(1);
+ pub const Fixed: Self = Self(2);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 2;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::Auto,
+ Self::None,
+ Self::Fixed,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::Auto => Some("Auto"),
+ Self::None => Some("None"),
+ Self::Fixed => Some("Fixed"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for FontOpticalSizingKind {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for FontOpticalSizingKind {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for FontOpticalSizingKind {
+ type Output = FontOpticalSizingKind;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for FontOpticalSizingKind {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for FontOpticalSizingKind {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for FontOpticalSizingKind {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_TEXT_DIMENSION_KIND: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_TEXT_DIMENSION_KIND: u8 = 2;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_TEXT_DIMENSION_KIND: [TextDimensionKind; 3] = [
+ TextDimensionKind::Normal,
+ TextDimensionKind::Fixed,
+ TextDimensionKind::Factor,
+];
+
+/// `TextLineHeight` (Normal | Fixed(f32) | Factor(f32))
+/// `TextLetterSpacing` (Normal | Fixed(f32) | Factor(f32))
+/// `TextWordSpacing` (Normal | Fixed(f32) | Factor(f32))
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct TextDimensionKind(pub u8);
+#[allow(non_upper_case_globals)]
+impl TextDimensionKind {
+ pub const Normal: Self = Self(0);
+ pub const Fixed: Self = Self(1);
+ pub const Factor: Self = Self(2);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 2;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::Normal,
+ Self::Fixed,
+ Self::Factor,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::Normal => Some("Normal"),
+ Self::Fixed => Some("Fixed"),
+ Self::Factor => Some("Factor"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for TextDimensionKind {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for TextDimensionKind {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for TextDimensionKind {
+ type Output = TextDimensionKind;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for TextDimensionKind {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for TextDimensionKind {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for TextDimensionKind {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_RESOURCE_REF: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_RESOURCE_REF: u8 = 2;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_RESOURCE_REF: [ResourceRef; 3] = [
+ ResourceRef::NONE,
+ ResourceRef::ResourceRefHASH,
+ ResourceRef::ResourceRefRID,
+];
+
+/// Rust: `ResourceRef`
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct ResourceRef(pub u8);
+#[allow(non_upper_case_globals)]
+impl ResourceRef {
+ pub const NONE: Self = Self(0);
+ pub const ResourceRefHASH: Self = Self(1);
+ pub const ResourceRefRID: Self = Self(2);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 2;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::NONE,
+ Self::ResourceRefHASH,
+ Self::ResourceRefRID,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::NONE => Some("NONE"),
+ Self::ResourceRefHASH => Some("ResourceRefHASH"),
+ Self::ResourceRefRID => Some("ResourceRefRID"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for ResourceRef {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for ResourceRef {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for ResourceRef {
+ type Output = ResourceRef;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for ResourceRef {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for ResourceRef {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for ResourceRef {}
+pub struct ResourceRefUnionTableOffset {}
+
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_IMAGE_PAINT_FIT: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_IMAGE_PAINT_FIT: u8 = 3;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_IMAGE_PAINT_FIT: [ImagePaintFit; 4] = [
+ ImagePaintFit::NONE,
+ ImagePaintFit::ImagePaintFitFit,
+ ImagePaintFit::ImagePaintFitTransform,
+ ImagePaintFit::ImagePaintFitTile,
+];
+
+/// Rust: `ImagePaintFit`
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct ImagePaintFit(pub u8);
+#[allow(non_upper_case_globals)]
+impl ImagePaintFit {
+ pub const NONE: Self = Self(0);
+ pub const ImagePaintFitFit: Self = Self(1);
+ pub const ImagePaintFitTransform: Self = Self(2);
+ pub const ImagePaintFitTile: Self = Self(3);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 3;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::NONE,
+ Self::ImagePaintFitFit,
+ Self::ImagePaintFitTransform,
+ Self::ImagePaintFitTile,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::NONE => Some("NONE"),
+ Self::ImagePaintFitFit => Some("ImagePaintFitFit"),
+ Self::ImagePaintFitTransform => Some("ImagePaintFitTransform"),
+ Self::ImagePaintFitTile => Some("ImagePaintFitTile"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for ImagePaintFit {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for ImagePaintFit {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for ImagePaintFit {
+ type Output = ImagePaintFit;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for ImagePaintFit {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for ImagePaintFit {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for ImagePaintFit {}
+pub struct ImagePaintFitUnionTableOffset {}
+
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_PAINT: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_PAINT: u8 = 6;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_PAINT: [Paint; 7] = [
+ Paint::NONE,
+ Paint::SolidPaint,
+ Paint::LinearGradientPaint,
+ Paint::RadialGradientPaint,
+ Paint::SweepGradientPaint,
+ Paint::DiamondGradientPaint,
+ Paint::ImagePaint,
+];
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct Paint(pub u8);
+#[allow(non_upper_case_globals)]
+impl Paint {
+ pub const NONE: Self = Self(0);
+ pub const SolidPaint: Self = Self(1);
+ pub const LinearGradientPaint: Self = Self(2);
+ pub const RadialGradientPaint: Self = Self(3);
+ pub const SweepGradientPaint: Self = Self(4);
+ pub const DiamondGradientPaint: Self = Self(5);
+ pub const ImagePaint: Self = Self(6);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 6;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::NONE,
+ Self::SolidPaint,
+ Self::LinearGradientPaint,
+ Self::RadialGradientPaint,
+ Self::SweepGradientPaint,
+ Self::DiamondGradientPaint,
+ Self::ImagePaint,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::NONE => Some("NONE"),
+ Self::SolidPaint => Some("SolidPaint"),
+ Self::LinearGradientPaint => Some("LinearGradientPaint"),
+ Self::RadialGradientPaint => Some("RadialGradientPaint"),
+ Self::SweepGradientPaint => Some("SweepGradientPaint"),
+ Self::DiamondGradientPaint => Some("DiamondGradientPaint"),
+ Self::ImagePaint => Some("ImagePaint"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for Paint {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for Paint {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for Paint {
+ type Output = Paint;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for Paint {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for Paint {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for Paint {}
+pub struct PaintUnionTableOffset {}
+
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_EDGE_POINT: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_EDGE_POINT: u8 = 2;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_EDGE_POINT: [EdgePoint; 3] = [
+ EdgePoint::NONE,
+ EdgePoint::EdgePointPosition2D,
+ EdgePoint::EdgePointNodeAnchor,
+];
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct EdgePoint(pub u8);
+#[allow(non_upper_case_globals)]
+impl EdgePoint {
+ pub const NONE: Self = Self(0);
+ pub const EdgePointPosition2D: Self = Self(1);
+ pub const EdgePointNodeAnchor: Self = Self(2);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 2;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::NONE,
+ Self::EdgePointPosition2D,
+ Self::EdgePointNodeAnchor,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::NONE => Some("NONE"),
+ Self::EdgePointPosition2D => Some("EdgePointPosition2D"),
+ Self::EdgePointNodeAnchor => Some("EdgePointNodeAnchor"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for EdgePoint {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for EdgePoint {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for EdgePoint {
+ type Output = EdgePoint;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for EdgePoint {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for EdgePoint {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for EdgePoint {}
+pub struct EdgePointUnionTableOffset {}
+
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_FE_BLUR: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_FE_BLUR: u8 = 2;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_FE_BLUR: [FeBlur; 3] = [
+ FeBlur::NONE,
+ FeBlur::FeGaussianBlur,
+ FeBlur::FeProgressiveBlur,
+];
+
+/// Rust: `FeBlur` (enum)
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct FeBlur(pub u8);
+#[allow(non_upper_case_globals)]
+impl FeBlur {
+ pub const NONE: Self = Self(0);
+ pub const FeGaussianBlur: Self = Self(1);
+ pub const FeProgressiveBlur: Self = Self(2);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 2;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::NONE,
+ Self::FeGaussianBlur,
+ Self::FeProgressiveBlur,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::NONE => Some("NONE"),
+ Self::FeGaussianBlur => Some("FeGaussianBlur"),
+ Self::FeProgressiveBlur => Some("FeProgressiveBlur"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for FeBlur {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for FeBlur {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for FeBlur {
+ type Output = FeBlur;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for FeBlur {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for FeBlur {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for FeBlur {}
+pub struct FeBlurUnionTableOffset {}
+
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_FILTER_SHADOW_EFFECT_KIND: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_FILTER_SHADOW_EFFECT_KIND: u8 = 1;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_FILTER_SHADOW_EFFECT_KIND: [FilterShadowEffectKind; 2] = [
+ FilterShadowEffectKind::DropShadow,
+ FilterShadowEffectKind::InnerShadow,
+];
+
+/// Rust: `FilterShadowEffect` (enum)
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct FilterShadowEffectKind(pub u8);
+#[allow(non_upper_case_globals)]
+impl FilterShadowEffectKind {
+ pub const DropShadow: Self = Self(0);
+ pub const InnerShadow: Self = Self(1);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 1;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::DropShadow,
+ Self::InnerShadow,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::DropShadow => Some("DropShadow"),
+ Self::InnerShadow => Some("InnerShadow"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for FilterShadowEffectKind {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for FilterShadowEffectKind {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for FilterShadowEffectKind {
+ type Output = FilterShadowEffectKind;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for FilterShadowEffectKind {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for FilterShadowEffectKind {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for FilterShadowEffectKind {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_NOISE_EFFECT_COLORS_KIND: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_NOISE_EFFECT_COLORS_KIND: u8 = 2;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_NOISE_EFFECT_COLORS_KIND: [NoiseEffectColorsKind; 3] = [
+ NoiseEffectColorsKind::Mono,
+ NoiseEffectColorsKind::Duo,
+ NoiseEffectColorsKind::Multi,
+];
+
+/// Rust: `NoiseEffectColors` (enum)
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct NoiseEffectColorsKind(pub u8);
+#[allow(non_upper_case_globals)]
+impl NoiseEffectColorsKind {
+ pub const Mono: Self = Self(0);
+ pub const Duo: Self = Self(1);
+ pub const Multi: Self = Self(2);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 2;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::Mono,
+ Self::Duo,
+ Self::Multi,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::Mono => Some("Mono"),
+ Self::Duo => Some("Duo"),
+ Self::Multi => Some("Multi"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for NoiseEffectColorsKind {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for NoiseEffectColorsKind {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for NoiseEffectColorsKind {
+ type Output = NoiseEffectColorsKind;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for NoiseEffectColorsKind {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for NoiseEffectColorsKind {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for NoiseEffectColorsKind {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_CANONICAL_LAYER_SHAPE: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_CANONICAL_LAYER_SHAPE: u8 = 6;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_CANONICAL_LAYER_SHAPE: [CanonicalLayerShape; 7] = [
+ CanonicalLayerShape::NONE,
+ CanonicalLayerShape::CanonicalShapeRectangular,
+ CanonicalLayerShape::CanonicalShapeElliptical,
+ CanonicalLayerShape::CanonicalShapePointsPolygon,
+ CanonicalLayerShape::CanonicalShapeRegularPolygon,
+ CanonicalLayerShape::CanonicalShapeRegularStarPolygon,
+ CanonicalLayerShape::CanonicalShapePath,
+];
+
+/// Canonical layer shape descriptor (geometry-only, layout-resolved).
+///
+/// `CanonicalLayerShape` is a *minimal*, *layout-independent* description of a
+/// primitive shape used by layer-backed nodes (e.g. `BasicShapeNode`).
+///
+/// Core semantics:
+/// - This union intentionally does NOT encode size (no width/height).
+/// - The concrete geometry is produced by mapping the selected shape variant into
+/// the node’s resolved layout box at render time.
+/// - Shape-specific parameters are expressed in normalized or ratio form:
+/// * points/polygon/path use 0..1 normalized coordinates (scaled to the box)
+/// * ellipse ring/sector uses ratios + angles (interpreted in the box)
+/// - All styling (fills, strokes, effects, corner traits, etc.) lives outside the
+/// shape descriptor on the owning node/traits. This union is geometry-only.
+///
+/// Evolution rules:
+/// - New primitive shape variants may be added by introducing a new `CanonicalShape*`
+/// table and adding it to this union (additive change).
+/// - Consumers must tolerate unknown union members (e.g. skip, treat as `UnknownNode`,
+/// or fall back to a rectangle) rather than hard-failing, to preserve forward
+/// compatibility.
+///
+/// Notes:
+/// - The “Canonical” prefix indicates the representation is the stable, box-mapped
+/// geometry form used in the archive, not a fully resolved mesh/path at a fixed size.
+/// - Even when a variant currently has no fields (e.g. rectangular), it is kept as a
+/// distinct member to preserve explicit author intent and allow future extensions
+/// without changing other variants.
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct CanonicalLayerShape(pub u8);
+#[allow(non_upper_case_globals)]
+impl CanonicalLayerShape {
+ pub const NONE: Self = Self(0);
+ pub const CanonicalShapeRectangular: Self = Self(1);
+ pub const CanonicalShapeElliptical: Self = Self(2);
+ pub const CanonicalShapePointsPolygon: Self = Self(3);
+ pub const CanonicalShapeRegularPolygon: Self = Self(4);
+ pub const CanonicalShapeRegularStarPolygon: Self = Self(5);
+ pub const CanonicalShapePath: Self = Self(6);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 6;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::NONE,
+ Self::CanonicalShapeRectangular,
+ Self::CanonicalShapeElliptical,
+ Self::CanonicalShapePointsPolygon,
+ Self::CanonicalShapeRegularPolygon,
+ Self::CanonicalShapeRegularStarPolygon,
+ Self::CanonicalShapePath,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::NONE => Some("NONE"),
+ Self::CanonicalShapeRectangular => Some("CanonicalShapeRectangular"),
+ Self::CanonicalShapeElliptical => Some("CanonicalShapeElliptical"),
+ Self::CanonicalShapePointsPolygon => Some("CanonicalShapePointsPolygon"),
+ Self::CanonicalShapeRegularPolygon => Some("CanonicalShapeRegularPolygon"),
+ Self::CanonicalShapeRegularStarPolygon => Some("CanonicalShapeRegularStarPolygon"),
+ Self::CanonicalShapePath => Some("CanonicalShapePath"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for CanonicalLayerShape {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for CanonicalLayerShape {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for CanonicalLayerShape {
+ type Output = CanonicalLayerShape;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for CanonicalLayerShape {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for CanonicalLayerShape {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for CanonicalLayerShape {}
+pub struct CanonicalLayerShapeUnionTableOffset {}
+
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_LAYOUT_DIMENSION_UNIT: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_LAYOUT_DIMENSION_UNIT: u8 = 1;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_LAYOUT_DIMENSION_UNIT: [LayoutDimensionUnit; 2] = [
+ LayoutDimensionUnit::LengthPx,
+ LayoutDimensionUnit::Percentage,
+];
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct LayoutDimensionUnit(pub u8);
+#[allow(non_upper_case_globals)]
+impl LayoutDimensionUnit {
+ pub const LengthPx: Self = Self(0);
+ pub const Percentage: Self = Self(1);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 1;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::LengthPx,
+ Self::Percentage,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::LengthPx => Some("LengthPx"),
+ Self::Percentage => Some("Percentage"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for LayoutDimensionUnit {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for LayoutDimensionUnit {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for LayoutDimensionUnit {
+ type Output = LayoutDimensionUnit;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for LayoutDimensionUnit {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for LayoutDimensionUnit {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for LayoutDimensionUnit {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_POSITIONING_SIDE_OFFSET_KIND: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_POSITIONING_SIDE_OFFSET_KIND: u8 = 1;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_POSITIONING_SIDE_OFFSET_KIND: [PositioningSideOffsetKind; 2] = [
+ PositioningSideOffsetKind::Px,
+ PositioningSideOffsetKind::Percent,
+];
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct PositioningSideOffsetKind(pub u8);
+#[allow(non_upper_case_globals)]
+impl PositioningSideOffsetKind {
+ pub const Px: Self = Self(0);
+ pub const Percent: Self = Self(1);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 1;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::Px,
+ Self::Percent,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::Px => Some("Px"),
+ Self::Percent => Some("Percent"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for PositioningSideOffsetKind {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for PositioningSideOffsetKind {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for PositioningSideOffsetKind {
+ type Output = PositioningSideOffsetKind;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for PositioningSideOffsetKind {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for PositioningSideOffsetKind {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for PositioningSideOffsetKind {}
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_LAYOUT_POSITIONING_BASIS: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_LAYOUT_POSITIONING_BASIS: u8 = 2;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_LAYOUT_POSITIONING_BASIS: [LayoutPositioningBasis; 3] = [
+ LayoutPositioningBasis::NONE,
+ LayoutPositioningBasis::LayoutPositioningCartesian,
+ LayoutPositioningBasis::LayoutPositioningInset,
+];
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct LayoutPositioningBasis(pub u8);
+#[allow(non_upper_case_globals)]
+impl LayoutPositioningBasis {
+ pub const NONE: Self = Self(0);
+ pub const LayoutPositioningCartesian: Self = Self(1);
+ pub const LayoutPositioningInset: Self = Self(2);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 2;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::NONE,
+ Self::LayoutPositioningCartesian,
+ Self::LayoutPositioningInset,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::NONE => Some("NONE"),
+ Self::LayoutPositioningCartesian => Some("LayoutPositioningCartesian"),
+ Self::LayoutPositioningInset => Some("LayoutPositioningInset"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for LayoutPositioningBasis {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for LayoutPositioningBasis {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for LayoutPositioningBasis {
+ type Output = LayoutPositioningBasis;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for LayoutPositioningBasis {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for LayoutPositioningBasis {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for LayoutPositioningBasis {}
+pub struct LayoutPositioningBasisUnionTableOffset {}
+
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MIN_NODE: u8 = 0;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+pub const ENUM_MAX_NODE: u8 = 10;
+#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
+#[allow(non_camel_case_types)]
+pub const ENUM_VALUES_NODE: [Node; 11] = [
+ Node::NONE,
+ Node::UnknownNode,
+ Node::SceneNode,
+ Node::GroupNode,
+ Node::InitialContainerNode,
+ Node::ContainerNode,
+ Node::BooleanOperationNode,
+ Node::BasicShapeNode,
+ Node::LineNode,
+ Node::VectorNode,
+ Node::TextSpanNode,
+];
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
+#[repr(transparent)]
+pub struct Node(pub u8);
+#[allow(non_upper_case_globals)]
+impl Node {
+ pub const NONE: Self = Self(0);
+ pub const UnknownNode: Self = Self(1);
+ pub const SceneNode: Self = Self(2);
+ pub const GroupNode: Self = Self(3);
+ pub const InitialContainerNode: Self = Self(4);
+ pub const ContainerNode: Self = Self(5);
+ pub const BooleanOperationNode: Self = Self(6);
+ pub const BasicShapeNode: Self = Self(7);
+ pub const LineNode: Self = Self(8);
+ pub const VectorNode: Self = Self(9);
+ pub const TextSpanNode: Self = Self(10);
+
+ pub const ENUM_MIN: u8 = 0;
+ pub const ENUM_MAX: u8 = 10;
+ pub const ENUM_VALUES: &'static [Self] = &[
+ Self::NONE,
+ Self::UnknownNode,
+ Self::SceneNode,
+ Self::GroupNode,
+ Self::InitialContainerNode,
+ Self::ContainerNode,
+ Self::BooleanOperationNode,
+ Self::BasicShapeNode,
+ Self::LineNode,
+ Self::VectorNode,
+ Self::TextSpanNode,
+ ];
+ /// Returns the variant's name or "" if unknown.
+ pub fn variant_name(self) -> Option<&'static str> {
+ match self {
+ Self::NONE => Some("NONE"),
+ Self::UnknownNode => Some("UnknownNode"),
+ Self::SceneNode => Some("SceneNode"),
+ Self::GroupNode => Some("GroupNode"),
+ Self::InitialContainerNode => Some("InitialContainerNode"),
+ Self::ContainerNode => Some("ContainerNode"),
+ Self::BooleanOperationNode => Some("BooleanOperationNode"),
+ Self::BasicShapeNode => Some("BasicShapeNode"),
+ Self::LineNode => Some("LineNode"),
+ Self::VectorNode => Some("VectorNode"),
+ Self::TextSpanNode => Some("TextSpanNode"),
+ _ => None,
+ }
+ }
+}
+impl ::core::fmt::Debug for Node {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(name) = self.variant_name() {
+ f.write_str(name)
+ } else {
+ f.write_fmt(format_args!("", self.0))
+ }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for Node {
+ type Inner = Self;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) };
+ Self(b)
+ }
+}
+
+impl ::flatbuffers::Push for Node {
+ type Output = Node;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) };
+ }
+}
+
+impl ::flatbuffers::EndianScalar for Node {
+ type Scalar = u8;
+ #[inline]
+ fn to_little_endian(self) -> u8 {
+ self.0.to_le()
+ }
+ #[inline]
+ #[allow(clippy::wrong_self_convention)]
+ fn from_little_endian(v: u8) -> Self {
+ let b = u8::from_le(v);
+ Self(b)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for Node {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for Node {}
+pub struct NodeUnionTableOffset {}
+
+/// Rust: `CGPoint { x: f32, y: f32 }`
+// struct CGPoint, aligned to 4
+#[repr(transparent)]
+#[derive(Clone, Copy, PartialEq)]
+pub struct CGPoint(pub [u8; 8]);
+impl Default for CGPoint {
+ fn default() -> Self {
+ Self([0; 8])
+ }
+}
+impl ::core::fmt::Debug for CGPoint {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ f.debug_struct("CGPoint")
+ .field("x", &self.x())
+ .field("y", &self.y())
+ .finish()
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for CGPoint {}
+impl<'a> ::flatbuffers::Follow<'a> for CGPoint {
+ type Inner = &'a CGPoint;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ unsafe { <&'a CGPoint>::follow(buf, loc) }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for &'a CGPoint {
+ type Inner = &'a CGPoint;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ unsafe { ::flatbuffers::follow_cast_ref::(buf, loc) }
+ }
+}
+impl<'b> ::flatbuffers::Push for CGPoint {
+ type Output = CGPoint;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ let src = unsafe { ::core::slice::from_raw_parts(self as *const CGPoint as *const u8, ::size()) };
+ dst.copy_from_slice(src);
+ }
+ #[inline]
+ fn alignment() -> ::flatbuffers::PushAlignment {
+ ::flatbuffers::PushAlignment::new(4)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for CGPoint {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ v.in_buffer::(pos)
+ }
+}
+
+impl<'a> CGPoint {
+ #[allow(clippy::too_many_arguments)]
+ pub fn new(
+ x: f32,
+ y: f32,
+ ) -> Self {
+ let mut s = Self([0; 8]);
+ s.set_x(x);
+ s.set_y(y);
+ s
+ }
+
+ pub fn x(&self) -> f32 {
+ let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit();
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ ::flatbuffers::EndianScalar::from_little_endian(unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ self.0[0..].as_ptr(),
+ mem.as_mut_ptr() as *mut u8,
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ mem.assume_init()
+ })
+ }
+
+ pub fn set_x(&mut self, x: f32) {
+ let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ &x_le as *const _ as *const u8,
+ self.0[0..].as_mut_ptr(),
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ }
+ }
+
+ pub fn y(&self) -> f32 {
+ let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit();
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ ::flatbuffers::EndianScalar::from_little_endian(unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ self.0[4..].as_ptr(),
+ mem.as_mut_ptr() as *mut u8,
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ mem.assume_init()
+ })
+ }
+
+ pub fn set_y(&mut self, x: f32) {
+ let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ &x_le as *const _ as *const u8,
+ self.0[4..].as_mut_ptr(),
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ }
+ }
+
+}
+
+/// `Alignment(pub f32, pub f32)` (cNDC, range typically [-1, 1])
+///
+/// Alignment(0,0) is the center of the rectangle.
+// struct Alignment, aligned to 4
+#[repr(transparent)]
+#[derive(Clone, Copy, PartialEq)]
+pub struct Alignment(pub [u8; 8]);
+impl Default for Alignment {
+ fn default() -> Self {
+ Self([0; 8])
+ }
+}
+impl ::core::fmt::Debug for Alignment {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ f.debug_struct("Alignment")
+ .field("x", &self.x())
+ .field("y", &self.y())
+ .finish()
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for Alignment {}
+impl<'a> ::flatbuffers::Follow<'a> for Alignment {
+ type Inner = &'a Alignment;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ unsafe { <&'a Alignment>::follow(buf, loc) }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for &'a Alignment {
+ type Inner = &'a Alignment;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ unsafe { ::flatbuffers::follow_cast_ref::(buf, loc) }
+ }
+}
+impl<'b> ::flatbuffers::Push for Alignment {
+ type Output = Alignment;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ let src = unsafe { ::core::slice::from_raw_parts(self as *const Alignment as *const u8, ::size()) };
+ dst.copy_from_slice(src);
+ }
+ #[inline]
+ fn alignment() -> ::flatbuffers::PushAlignment {
+ ::flatbuffers::PushAlignment::new(4)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for Alignment {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ v.in_buffer::(pos)
+ }
+}
+
+impl<'a> Alignment {
+ #[allow(clippy::too_many_arguments)]
+ pub fn new(
+ x: f32,
+ y: f32,
+ ) -> Self {
+ let mut s = Self([0; 8]);
+ s.set_x(x);
+ s.set_y(y);
+ s
+ }
+
+ pub fn x(&self) -> f32 {
+ let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit();
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ ::flatbuffers::EndianScalar::from_little_endian(unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ self.0[0..].as_ptr(),
+ mem.as_mut_ptr() as *mut u8,
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ mem.assume_init()
+ })
+ }
+
+ pub fn set_x(&mut self, x: f32) {
+ let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ &x_le as *const _ as *const u8,
+ self.0[0..].as_mut_ptr(),
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ }
+ }
+
+ pub fn y(&self) -> f32 {
+ let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit();
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ ::flatbuffers::EndianScalar::from_little_endian(unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ self.0[4..].as_ptr(),
+ mem.as_mut_ptr() as *mut u8,
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ mem.assume_init()
+ })
+ }
+
+ pub fn set_y(&mut self, x: f32) {
+ let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ &x_le as *const _ as *const u8,
+ self.0[4..].as_mut_ptr(),
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ }
+ }
+
+}
+
+/// Rust: `Uv(pub f32, pub f32)` (normalized [0, 1] domain)
+// struct UV, aligned to 4
+#[repr(transparent)]
+#[derive(Clone, Copy, PartialEq)]
+pub struct UV(pub [u8; 8]);
+impl Default for UV {
+ fn default() -> Self {
+ Self([0; 8])
+ }
+}
+impl ::core::fmt::Debug for UV {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ f.debug_struct("UV")
+ .field("u", &self.u())
+ .field("v", &self.v())
+ .finish()
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for UV {}
+impl<'a> ::flatbuffers::Follow<'a> for UV {
+ type Inner = &'a UV;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ unsafe { <&'a UV>::follow(buf, loc) }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for &'a UV {
+ type Inner = &'a UV;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ unsafe { ::flatbuffers::follow_cast_ref::(buf, loc) }
+ }
+}
+impl<'b> ::flatbuffers::Push for UV {
+ type Output = UV;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ let src = unsafe { ::core::slice::from_raw_parts(self as *const UV as *const u8, ::size()) };
+ dst.copy_from_slice(src);
+ }
+ #[inline]
+ fn alignment() -> ::flatbuffers::PushAlignment {
+ ::flatbuffers::PushAlignment::new(4)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for UV {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ v.in_buffer::(pos)
+ }
+}
+
+impl<'a> UV {
+ #[allow(clippy::too_many_arguments)]
+ pub fn new(
+ u: f32,
+ v: f32,
+ ) -> Self {
+ let mut s = Self([0; 8]);
+ s.set_u(u);
+ s.set_v(v);
+ s
+ }
+
+ pub fn u(&self) -> f32 {
+ let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit();
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ ::flatbuffers::EndianScalar::from_little_endian(unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ self.0[0..].as_ptr(),
+ mem.as_mut_ptr() as *mut u8,
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ mem.assume_init()
+ })
+ }
+
+ pub fn set_u(&mut self, x: f32) {
+ let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ &x_le as *const _ as *const u8,
+ self.0[0..].as_mut_ptr(),
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ }
+ }
+
+ pub fn v(&self) -> f32 {
+ let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit();
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ ::flatbuffers::EndianScalar::from_little_endian(unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ self.0[4..].as_ptr(),
+ mem.as_mut_ptr() as *mut u8,
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ mem.assume_init()
+ })
+ }
+
+ pub fn set_v(&mut self, x: f32) {
+ let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ &x_le as *const _ as *const u8,
+ self.0[4..].as_mut_ptr(),
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ }
+ }
+
+}
+
+/// Rust: (no dedicated cg struct) used throughout as (w,h). Keep for schema convenience.
+// struct CGSize, aligned to 4
+#[repr(transparent)]
+#[derive(Clone, Copy, PartialEq)]
+pub struct CGSize(pub [u8; 8]);
+impl Default for CGSize {
+ fn default() -> Self {
+ Self([0; 8])
+ }
+}
+impl ::core::fmt::Debug for CGSize {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ f.debug_struct("CGSize")
+ .field("width", &self.width())
+ .field("height", &self.height())
+ .finish()
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for CGSize {}
+impl<'a> ::flatbuffers::Follow<'a> for CGSize {
+ type Inner = &'a CGSize;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ unsafe { <&'a CGSize>::follow(buf, loc) }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for &'a CGSize {
+ type Inner = &'a CGSize;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ unsafe { ::flatbuffers::follow_cast_ref::(buf, loc) }
+ }
+}
+impl<'b> ::flatbuffers::Push for CGSize {
+ type Output = CGSize;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ let src = unsafe { ::core::slice::from_raw_parts(self as *const CGSize as *const u8, ::size()) };
+ dst.copy_from_slice(src);
+ }
+ #[inline]
+ fn alignment() -> ::flatbuffers::PushAlignment {
+ ::flatbuffers::PushAlignment::new(4)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for CGSize {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ v.in_buffer::(pos)
+ }
+}
+
+impl<'a> CGSize {
+ #[allow(clippy::too_many_arguments)]
+ pub fn new(
+ width: f32,
+ height: f32,
+ ) -> Self {
+ let mut s = Self([0; 8]);
+ s.set_width(width);
+ s.set_height(height);
+ s
+ }
+
+ pub fn width(&self) -> f32 {
+ let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit();
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ ::flatbuffers::EndianScalar::from_little_endian(unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ self.0[0..].as_ptr(),
+ mem.as_mut_ptr() as *mut u8,
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ mem.assume_init()
+ })
+ }
+
+ pub fn set_width(&mut self, x: f32) {
+ let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ &x_le as *const _ as *const u8,
+ self.0[0..].as_mut_ptr(),
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ }
+ }
+
+ pub fn height(&self) -> f32 {
+ let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit();
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ ::flatbuffers::EndianScalar::from_little_endian(unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ self.0[4..].as_ptr(),
+ mem.as_mut_ptr() as *mut u8,
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ mem.assume_init()
+ })
+ }
+
+ pub fn set_height(&mut self, x: f32) {
+ let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ &x_le as *const _ as *const u8,
+ self.0[4..].as_mut_ptr(),
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ }
+ }
+
+}
+
+/// RGBA in linear float space (0..1).
+// struct RGBA32F, aligned to 4
+#[repr(transparent)]
+#[derive(Clone, Copy, PartialEq)]
+pub struct RGBA32F(pub [u8; 16]);
+impl Default for RGBA32F {
+ fn default() -> Self {
+ Self([0; 16])
+ }
+}
+impl ::core::fmt::Debug for RGBA32F {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ f.debug_struct("RGBA32F")
+ .field("r", &self.r())
+ .field("g", &self.g())
+ .field("b", &self.b())
+ .field("a", &self.a())
+ .finish()
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for RGBA32F {}
+impl<'a> ::flatbuffers::Follow<'a> for RGBA32F {
+ type Inner = &'a RGBA32F;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ unsafe { <&'a RGBA32F>::follow(buf, loc) }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for &'a RGBA32F {
+ type Inner = &'a RGBA32F;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ unsafe { ::flatbuffers::follow_cast_ref::(buf, loc) }
+ }
+}
+impl<'b> ::flatbuffers::Push for RGBA32F {
+ type Output = RGBA32F;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ let src = unsafe { ::core::slice::from_raw_parts(self as *const RGBA32F as *const u8, ::size()) };
+ dst.copy_from_slice(src);
+ }
+ #[inline]
+ fn alignment() -> ::flatbuffers::PushAlignment {
+ ::flatbuffers::PushAlignment::new(4)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for RGBA32F {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ v.in_buffer::(pos)
+ }
+}
+
+impl<'a> RGBA32F {
+ #[allow(clippy::too_many_arguments)]
+ pub fn new(
+ r: f32,
+ g: f32,
+ b: f32,
+ a: f32,
+ ) -> Self {
+ let mut s = Self([0; 16]);
+ s.set_r(r);
+ s.set_g(g);
+ s.set_b(b);
+ s.set_a(a);
+ s
+ }
+
+ pub fn r(&self) -> f32 {
+ let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit();
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ ::flatbuffers::EndianScalar::from_little_endian(unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ self.0[0..].as_ptr(),
+ mem.as_mut_ptr() as *mut u8,
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ mem.assume_init()
+ })
+ }
+
+ pub fn set_r(&mut self, x: f32) {
+ let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ &x_le as *const _ as *const u8,
+ self.0[0..].as_mut_ptr(),
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ }
+ }
+
+ pub fn g(&self) -> f32 {
+ let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit();
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ ::flatbuffers::EndianScalar::from_little_endian(unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ self.0[4..].as_ptr(),
+ mem.as_mut_ptr() as *mut u8,
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ mem.assume_init()
+ })
+ }
+
+ pub fn set_g(&mut self, x: f32) {
+ let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ &x_le as *const _ as *const u8,
+ self.0[4..].as_mut_ptr(),
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ }
+ }
+
+ pub fn b(&self) -> f32 {
+ let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit();
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ ::flatbuffers::EndianScalar::from_little_endian(unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ self.0[8..].as_ptr(),
+ mem.as_mut_ptr() as *mut u8,
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ mem.assume_init()
+ })
+ }
+
+ pub fn set_b(&mut self, x: f32) {
+ let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ &x_le as *const _ as *const u8,
+ self.0[8..].as_mut_ptr(),
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ }
+ }
+
+ pub fn a(&self) -> f32 {
+ let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit();
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ ::flatbuffers::EndianScalar::from_little_endian(unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ self.0[12..].as_ptr(),
+ mem.as_mut_ptr() as *mut u8,
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ mem.assume_init()
+ })
+ }
+
+ pub fn set_a(&mut self, x: f32) {
+ let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ &x_le as *const _ as *const u8,
+ self.0[12..].as_mut_ptr(),
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ }
+ }
+
+}
+
+/// Rust: `CGTransform2D { m00..m12: f32 }` (and compatible with math2 `AffineTransform`).
+///
+/// Matrix layout:
+/// [ m00 m01 m02 ]
+/// [ m10 m11 m12 ]
+/// [ 0 0 1 ]
+///
+/// Struct representation (no defaults in FlatBuffers structs).
+// struct CGTransform2D, aligned to 4
+#[repr(transparent)]
+#[derive(Clone, Copy, PartialEq)]
+pub struct CGTransform2D(pub [u8; 24]);
+impl Default for CGTransform2D {
+ fn default() -> Self {
+ Self([0; 24])
+ }
+}
+impl ::core::fmt::Debug for CGTransform2D {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ f.debug_struct("CGTransform2D")
+ .field("m00", &self.m00())
+ .field("m01", &self.m01())
+ .field("m02", &self.m02())
+ .field("m10", &self.m10())
+ .field("m11", &self.m11())
+ .field("m12", &self.m12())
+ .finish()
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for CGTransform2D {}
+impl<'a> ::flatbuffers::Follow<'a> for CGTransform2D {
+ type Inner = &'a CGTransform2D;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ unsafe { <&'a CGTransform2D>::follow(buf, loc) }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for &'a CGTransform2D {
+ type Inner = &'a CGTransform2D;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ unsafe { ::flatbuffers::follow_cast_ref::(buf, loc) }
+ }
+}
+impl<'b> ::flatbuffers::Push for CGTransform2D {
+ type Output = CGTransform2D;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ let src = unsafe { ::core::slice::from_raw_parts(self as *const CGTransform2D as *const u8, ::size()) };
+ dst.copy_from_slice(src);
+ }
+ #[inline]
+ fn alignment() -> ::flatbuffers::PushAlignment {
+ ::flatbuffers::PushAlignment::new(4)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for CGTransform2D {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ v.in_buffer::(pos)
+ }
+}
+
+impl<'a> CGTransform2D {
+ #[allow(clippy::too_many_arguments)]
+ pub fn new(
+ m00: f32,
+ m01: f32,
+ m02: f32,
+ m10: f32,
+ m11: f32,
+ m12: f32,
+ ) -> Self {
+ let mut s = Self([0; 24]);
+ s.set_m00(m00);
+ s.set_m01(m01);
+ s.set_m02(m02);
+ s.set_m10(m10);
+ s.set_m11(m11);
+ s.set_m12(m12);
+ s
+ }
+
+ pub fn m00(&self) -> f32 {
+ let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit();
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ ::flatbuffers::EndianScalar::from_little_endian(unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ self.0[0..].as_ptr(),
+ mem.as_mut_ptr() as *mut u8,
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ mem.assume_init()
+ })
+ }
+
+ pub fn set_m00(&mut self, x: f32) {
+ let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ &x_le as *const _ as *const u8,
+ self.0[0..].as_mut_ptr(),
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ }
+ }
+
+ pub fn m01(&self) -> f32 {
+ let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit();
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ ::flatbuffers::EndianScalar::from_little_endian(unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ self.0[4..].as_ptr(),
+ mem.as_mut_ptr() as *mut u8,
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ mem.assume_init()
+ })
+ }
+
+ pub fn set_m01(&mut self, x: f32) {
+ let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ &x_le as *const _ as *const u8,
+ self.0[4..].as_mut_ptr(),
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ }
+ }
+
+ pub fn m02(&self) -> f32 {
+ let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit();
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ ::flatbuffers::EndianScalar::from_little_endian(unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ self.0[8..].as_ptr(),
+ mem.as_mut_ptr() as *mut u8,
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ mem.assume_init()
+ })
+ }
+
+ pub fn set_m02(&mut self, x: f32) {
+ let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ &x_le as *const _ as *const u8,
+ self.0[8..].as_mut_ptr(),
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ }
+ }
+
+ pub fn m10(&self) -> f32 {
+ let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit();
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ ::flatbuffers::EndianScalar::from_little_endian(unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ self.0[12..].as_ptr(),
+ mem.as_mut_ptr() as *mut u8,
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ mem.assume_init()
+ })
+ }
+
+ pub fn set_m10(&mut self, x: f32) {
+ let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ &x_le as *const _ as *const u8,
+ self.0[12..].as_mut_ptr(),
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ }
+ }
+
+ pub fn m11(&self) -> f32 {
+ let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit();
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ ::flatbuffers::EndianScalar::from_little_endian(unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ self.0[16..].as_ptr(),
+ mem.as_mut_ptr() as *mut u8,
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ mem.assume_init()
+ })
+ }
+
+ pub fn set_m11(&mut self, x: f32) {
+ let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ &x_le as *const _ as *const u8,
+ self.0[16..].as_mut_ptr(),
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ }
+ }
+
+ pub fn m12(&self) -> f32 {
+ let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit();
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ ::flatbuffers::EndianScalar::from_little_endian(unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ self.0[20..].as_ptr(),
+ mem.as_mut_ptr() as *mut u8,
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ mem.assume_init()
+ })
+ }
+
+ pub fn set_m12(&mut self, x: f32) {
+ let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ &x_le as *const _ as *const u8,
+ self.0[20..].as_mut_ptr(),
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ }
+ }
+
+}
+
+/// Rust: `Radius { rx: f32, ry: f32 }`
+// struct CGRadius, aligned to 4
+#[repr(transparent)]
+#[derive(Clone, Copy, PartialEq)]
+pub struct CGRadius(pub [u8; 8]);
+impl Default for CGRadius {
+ fn default() -> Self {
+ Self([0; 8])
+ }
+}
+impl ::core::fmt::Debug for CGRadius {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ f.debug_struct("CGRadius")
+ .field("rx", &self.rx())
+ .field("ry", &self.ry())
+ .finish()
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for CGRadius {}
+impl<'a> ::flatbuffers::Follow<'a> for CGRadius {
+ type Inner = &'a CGRadius;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ unsafe { <&'a CGRadius>::follow(buf, loc) }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for &'a CGRadius {
+ type Inner = &'a CGRadius;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ unsafe { ::flatbuffers::follow_cast_ref::(buf, loc) }
+ }
+}
+impl<'b> ::flatbuffers::Push for CGRadius {
+ type Output = CGRadius;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ let src = unsafe { ::core::slice::from_raw_parts(self as *const CGRadius as *const u8, ::size()) };
+ dst.copy_from_slice(src);
+ }
+ #[inline]
+ fn alignment() -> ::flatbuffers::PushAlignment {
+ ::flatbuffers::PushAlignment::new(4)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for CGRadius {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ v.in_buffer::(pos)
+ }
+}
+
+impl<'a> CGRadius {
+ #[allow(clippy::too_many_arguments)]
+ pub fn new(
+ rx: f32,
+ ry: f32,
+ ) -> Self {
+ let mut s = Self([0; 8]);
+ s.set_rx(rx);
+ s.set_ry(ry);
+ s
+ }
+
+ pub fn rx(&self) -> f32 {
+ let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit();
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ ::flatbuffers::EndianScalar::from_little_endian(unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ self.0[0..].as_ptr(),
+ mem.as_mut_ptr() as *mut u8,
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ mem.assume_init()
+ })
+ }
+
+ pub fn set_rx(&mut self, x: f32) {
+ let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ &x_le as *const _ as *const u8,
+ self.0[0..].as_mut_ptr(),
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ }
+ }
+
+ pub fn ry(&self) -> f32 {
+ let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit();
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ ::flatbuffers::EndianScalar::from_little_endian(unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ self.0[4..].as_ptr(),
+ mem.as_mut_ptr() as *mut u8,
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ mem.assume_init()
+ })
+ }
+
+ pub fn set_ry(&mut self, x: f32) {
+ let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ &x_le as *const _ as *const u8,
+ self.0[4..].as_mut_ptr(),
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ }
+ }
+
+}
+
+// struct EdgeInsets, aligned to 4
+#[repr(transparent)]
+#[derive(Clone, Copy, PartialEq)]
+pub struct EdgeInsets(pub [u8; 16]);
+impl Default for EdgeInsets {
+ fn default() -> Self {
+ Self([0; 16])
+ }
+}
+impl ::core::fmt::Debug for EdgeInsets {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ f.debug_struct("EdgeInsets")
+ .field("top", &self.top())
+ .field("right", &self.right())
+ .field("bottom", &self.bottom())
+ .field("left", &self.left())
+ .finish()
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for EdgeInsets {}
+impl<'a> ::flatbuffers::Follow<'a> for EdgeInsets {
+ type Inner = &'a EdgeInsets;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ unsafe { <&'a EdgeInsets>::follow(buf, loc) }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for &'a EdgeInsets {
+ type Inner = &'a EdgeInsets;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ unsafe { ::flatbuffers::follow_cast_ref::(buf, loc) }
+ }
+}
+impl<'b> ::flatbuffers::Push for EdgeInsets {
+ type Output = EdgeInsets;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ let src = unsafe { ::core::slice::from_raw_parts(self as *const EdgeInsets as *const u8, ::size()) };
+ dst.copy_from_slice(src);
+ }
+ #[inline]
+ fn alignment() -> ::flatbuffers::PushAlignment {
+ ::flatbuffers::PushAlignment::new(4)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for EdgeInsets {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ v.in_buffer::(pos)
+ }
+}
+
+impl<'a> EdgeInsets {
+ #[allow(clippy::too_many_arguments)]
+ pub fn new(
+ top: f32,
+ right: f32,
+ bottom: f32,
+ left: f32,
+ ) -> Self {
+ let mut s = Self([0; 16]);
+ s.set_top(top);
+ s.set_right(right);
+ s.set_bottom(bottom);
+ s.set_left(left);
+ s
+ }
+
+ pub fn top(&self) -> f32 {
+ let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit();
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ ::flatbuffers::EndianScalar::from_little_endian(unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ self.0[0..].as_ptr(),
+ mem.as_mut_ptr() as *mut u8,
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ mem.assume_init()
+ })
+ }
+
+ pub fn set_top(&mut self, x: f32) {
+ let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ &x_le as *const _ as *const u8,
+ self.0[0..].as_mut_ptr(),
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ }
+ }
+
+ pub fn right(&self) -> f32 {
+ let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit();
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ ::flatbuffers::EndianScalar::from_little_endian(unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ self.0[4..].as_ptr(),
+ mem.as_mut_ptr() as *mut u8,
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ mem.assume_init()
+ })
+ }
+
+ pub fn set_right(&mut self, x: f32) {
+ let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ &x_le as *const _ as *const u8,
+ self.0[4..].as_mut_ptr(),
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ }
+ }
+
+ pub fn bottom(&self) -> f32 {
+ let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit();
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ ::flatbuffers::EndianScalar::from_little_endian(unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ self.0[8..].as_ptr(),
+ mem.as_mut_ptr() as *mut u8,
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ mem.assume_init()
+ })
+ }
+
+ pub fn set_bottom(&mut self, x: f32) {
+ let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ &x_le as *const _ as *const u8,
+ self.0[8..].as_mut_ptr(),
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ }
+ }
+
+ pub fn left(&self) -> f32 {
+ let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit();
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ ::flatbuffers::EndianScalar::from_little_endian(unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ self.0[12..].as_ptr(),
+ mem.as_mut_ptr() as *mut u8,
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ mem.assume_init()
+ })
+ }
+
+ pub fn set_left(&mut self, x: f32) {
+ let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ &x_le as *const _ as *const u8,
+ self.0[12..].as_mut_ptr(),
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ }
+ }
+
+}
+
+/// Rust: `RectangularCornerRadius { tl,tr,bl,br: Radius }`
+// struct RectangularCornerRadius, aligned to 4
+#[repr(transparent)]
+#[derive(Clone, Copy, PartialEq)]
+pub struct RectangularCornerRadius(pub [u8; 32]);
+impl Default for RectangularCornerRadius {
+ fn default() -> Self {
+ Self([0; 32])
+ }
+}
+impl ::core::fmt::Debug for RectangularCornerRadius {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ f.debug_struct("RectangularCornerRadius")
+ .field("tl", &self.tl())
+ .field("tr", &self.tr())
+ .field("bl", &self.bl())
+ .field("br", &self.br())
+ .finish()
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for RectangularCornerRadius {}
+impl<'a> ::flatbuffers::Follow<'a> for RectangularCornerRadius {
+ type Inner = &'a RectangularCornerRadius;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ unsafe { <&'a RectangularCornerRadius>::follow(buf, loc) }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for &'a RectangularCornerRadius {
+ type Inner = &'a RectangularCornerRadius;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ unsafe { ::flatbuffers::follow_cast_ref::(buf, loc) }
+ }
+}
+impl<'b> ::flatbuffers::Push for RectangularCornerRadius {
+ type Output = RectangularCornerRadius;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ let src = unsafe { ::core::slice::from_raw_parts(self as *const RectangularCornerRadius as *const u8, ::size()) };
+ dst.copy_from_slice(src);
+ }
+ #[inline]
+ fn alignment() -> ::flatbuffers::PushAlignment {
+ ::flatbuffers::PushAlignment::new(4)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for RectangularCornerRadius {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ v.in_buffer::(pos)
+ }
+}
+
+impl<'a> RectangularCornerRadius {
+ #[allow(clippy::too_many_arguments)]
+ pub fn new(
+ tl: &CGRadius,
+ tr: &CGRadius,
+ bl: &CGRadius,
+ br: &CGRadius,
+ ) -> Self {
+ let mut s = Self([0; 32]);
+ s.set_tl(tl);
+ s.set_tr(tr);
+ s.set_bl(bl);
+ s.set_br(br);
+ s
+ }
+
+ pub fn tl(&self) -> &CGRadius {
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid struct in this slot
+ unsafe { &*(self.0[0..].as_ptr() as *const CGRadius) }
+ }
+
+ #[allow(clippy::identity_op)]
+ pub fn set_tl(&mut self, x: &CGRadius) {
+ self.0[0..0 + 8].copy_from_slice(&x.0)
+ }
+
+ pub fn tr(&self) -> &CGRadius {
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid struct in this slot
+ unsafe { &*(self.0[8..].as_ptr() as *const CGRadius) }
+ }
+
+ #[allow(clippy::identity_op)]
+ pub fn set_tr(&mut self, x: &CGRadius) {
+ self.0[8..8 + 8].copy_from_slice(&x.0)
+ }
+
+ pub fn bl(&self) -> &CGRadius {
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid struct in this slot
+ unsafe { &*(self.0[16..].as_ptr() as *const CGRadius) }
+ }
+
+ #[allow(clippy::identity_op)]
+ pub fn set_bl(&mut self, x: &CGRadius) {
+ self.0[16..16 + 8].copy_from_slice(&x.0)
+ }
+
+ pub fn br(&self) -> &CGRadius {
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid struct in this slot
+ unsafe { &*(self.0[24..].as_ptr() as *const CGRadius) }
+ }
+
+ #[allow(clippy::identity_op)]
+ pub fn set_br(&mut self, x: &CGRadius) {
+ self.0[24..24 + 8].copy_from_slice(&x.0)
+ }
+
+}
+
+/// Per-side stroke widths (archive model).
+///
+/// Struct representation. Note: structs cannot be null/omitted; all-zeros can be
+/// interpreted as "not used" by codec/runtime if desired.
+// struct RectangularStrokeWidth, aligned to 4
+#[repr(transparent)]
+#[derive(Clone, Copy, PartialEq)]
+pub struct RectangularStrokeWidth(pub [u8; 16]);
+impl Default for RectangularStrokeWidth {
+ fn default() -> Self {
+ Self([0; 16])
+ }
+}
+impl ::core::fmt::Debug for RectangularStrokeWidth {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ f.debug_struct("RectangularStrokeWidth")
+ .field("stroke_top_width", &self.stroke_top_width())
+ .field("stroke_right_width", &self.stroke_right_width())
+ .field("stroke_bottom_width", &self.stroke_bottom_width())
+ .field("stroke_left_width", &self.stroke_left_width())
+ .finish()
+ }
+}
+
+impl ::flatbuffers::SimpleToVerifyInSlice for RectangularStrokeWidth {}
+impl<'a> ::flatbuffers::Follow<'a> for RectangularStrokeWidth {
+ type Inner = &'a RectangularStrokeWidth;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ unsafe { <&'a RectangularStrokeWidth>::follow(buf, loc) }
+ }
+}
+impl<'a> ::flatbuffers::Follow<'a> for &'a RectangularStrokeWidth {
+ type Inner = &'a RectangularStrokeWidth;
+ #[inline]
+ unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ unsafe { ::flatbuffers::follow_cast_ref::(buf, loc) }
+ }
+}
+impl<'b> ::flatbuffers::Push for RectangularStrokeWidth {
+ type Output = RectangularStrokeWidth;
+ #[inline]
+ unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
+ let src = unsafe { ::core::slice::from_raw_parts(self as *const RectangularStrokeWidth as *const u8, ::size()) };
+ dst.copy_from_slice(src);
+ }
+ #[inline]
+ fn alignment() -> ::flatbuffers::PushAlignment {
+ ::flatbuffers::PushAlignment::new(4)
+ }
+}
+
+impl<'a> ::flatbuffers::Verifiable for RectangularStrokeWidth {
+ #[inline]
+ fn run_verifier(
+ v: &mut ::flatbuffers::Verifier, pos: usize
+ ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
+ v.in_buffer::(pos)
+ }
+}
+
+impl<'a> RectangularStrokeWidth {
+ #[allow(clippy::too_many_arguments)]
+ pub fn new(
+ stroke_top_width: f32,
+ stroke_right_width: f32,
+ stroke_bottom_width: f32,
+ stroke_left_width: f32,
+ ) -> Self {
+ let mut s = Self([0; 16]);
+ s.set_stroke_top_width(stroke_top_width);
+ s.set_stroke_right_width(stroke_right_width);
+ s.set_stroke_bottom_width(stroke_bottom_width);
+ s.set_stroke_left_width(stroke_left_width);
+ s
+ }
+
+ pub fn stroke_top_width(&self) -> f32 {
+ let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit();
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ ::flatbuffers::EndianScalar::from_little_endian(unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ self.0[0..].as_ptr(),
+ mem.as_mut_ptr() as *mut u8,
+ ::core::mem::size_of::<::Scalar>(),
+ );
+ mem.assume_init()
+ })
+ }
+
+ pub fn set_stroke_top_width(&mut self, x: f32) {
+ let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
+ // Safety:
+ // Created from a valid Table for this object
+ // Which contains a valid value in this slot
+ unsafe {
+ ::core::ptr::copy_nonoverlapping(
+ &x_le as *const _ as *const u8,
+ self.0[0..].as_mut_ptr(),
+ ::core::mem::size_of::<