2026-05-03 14:25:00 +00:00
|
|
|
[package]
|
2026-05-16 15:49:58 +00:00
|
|
|
name = "op-host-native"
|
2026-05-03 14:25:00 +00:00
|
|
|
version.workspace = true
|
|
|
|
|
edition.workspace = true
|
|
|
|
|
rust-version.workspace = true
|
|
|
|
|
license.workspace = true
|
2026-05-16 15:49:58 +00:00
|
|
|
description = "OpenPencil native host — winit + skia-safe + accesskit backend, integrating jian-skia + jian-host-desktop sub-pieces (spec v19 §3 / §5.2.1)"
|
2026-05-03 14:25:00 +00:00
|
|
|
|
|
|
|
|
[lib]
|
2026-05-16 15:49:58 +00:00
|
|
|
name = "op_host_native"
|
2026-05-03 14:25:00 +00:00
|
|
|
path = "src/lib.rs"
|
|
|
|
|
|
|
|
|
|
[dependencies]
|
2026-05-16 15:49:58 +00:00
|
|
|
# Phase 7.3 reorg: openpencil-shell-core dissolved — widget facade /
|
|
|
|
|
# theme / layout scene / scene vars / render-backend / gesture types
|
|
|
|
|
# all resolve through the op-editor-ui crate.
|
|
|
|
|
op-editor-ui = { path = "../op-editor-ui" }
|
2026-05-03 14:25:00 +00:00
|
|
|
|
2026-05-16 11:29:34 +00:00
|
|
|
# `WidgetHostNative`'s single source of truth — the canonical-model
|
|
|
|
|
# `op_editor_core::EditorState`. The host derives a read-only paint
|
|
|
|
|
# `Document` from it each frame (see `widget_host.rs`).
|
2026-05-16 09:30:44 +00:00
|
|
|
op-editor-core = { path = "../op-editor-core" }
|
|
|
|
|
|
2026-05-05 13:12:00 +00:00
|
|
|
# Native-only deps cfg-gated outside wasm32. This is critical (resolves codex round 2 B1 BLOCK):
|
|
|
|
|
# without cfg-gate, cargo would fetch + run skia-safe's build.rs (which fails on wasm32),
|
|
|
|
|
# and the Step 5 grep `must NOT be compiled for wasm32` would never match — masked by
|
|
|
|
|
# the skia build error.
|
2026-05-03 14:25:00 +00:00
|
|
|
#
|
2026-05-05 13:12:00 +00:00
|
|
|
# v19 pivot (Task 1): add P0-pinned GL stack + jian-skia + jian-host-desktop.
|
|
|
|
|
# - P0 dep-stack pin comes from the P0 probe (plan v7 §Task P0; skia-safe 0.97 + glow 0.17 +
|
feat(workspace): pin Jian submodule and shell wrapper deps (Step 1a Task 1)
Anchor v19 pivot at the workspace level: vendor Jian as a git submodule
pinned to fork commit ad13ce6 (P0.5 mini-gate GO; skia-safe 0.78 → 0.97 +
new pub draw_on_canvas adapter), wire jian-core / jian-skia / jian-host-desktop
as path deps with explicit version per spec §12.2, and re-export the
Jian render/geometry/scene types from shell-core so shell-native can
translate the OP RenderBackend facade into jian DrawOp commands.
shell-core stays wasm32-clean: only jian-core (already wasm32-validated
in P0.5) plus glam / bitflags / thiserror / tracing land here.
shell-native picks up the full P0-pinned GL stack (skia-safe 0.97.0,
glutin 0.32.3, glutin-winit 0.5.0, glow 0.17.0, winit 0.30.13,
raw-window-handle 0.6.2, scopeguard 1.2) plus jian-skia (textlayout)
and target-gated jian-host-desktop (default-features = false, no `run`
feature so we skip Jian's softbuffer raster present path — OP owns its
own GPU swap_buffers per spec §3.6).
Adds OP RenderBackend trait + Rect / Color (with RED/GREEN/BLUE/BLACK/
WHITE/TRANSPARENT named constants per spec §5.2) + TextLayout facade
that wraps jian_core::render::TextRun explicitly (TextRun has no Default
impl, fields enumerated to honour spec §5.2 round-2 CONCERN-1 fix).
Boundary checks all pass:
- wasm32 shell-web metadata: no jian-host-desktop / jian-skia
- aarch64-linux-android shell-native metadata: no jian-host-desktop
- shell-core src: no glutin / skia_safe / winit / glow imports
Tasks 2-4 (SharedSkiaContext + NativeBackend + ShellEvent mapping +
acceptance) follow per plan v7.
2026-05-05 13:00:00 +00:00
|
|
|
# glutin 0.32.3 + glutin-winit 0.5.0 + winit 0.30.13 + raw-window-handle 0.6.2 +
|
2026-05-05 13:12:00 +00:00
|
|
|
# scopeguard 1.2 all GO on macOS/Windows/Linux).
|
|
|
|
|
# - jian-skia (textlayout feature) provides SkiaBackend impl + skia textlayout (replaces parley).
|
|
|
|
|
# - jian-host-desktop (target-gated desktop only, without the `run` feature) reuses
|
|
|
|
|
# PointerTranslator / scene::collect_draws_with_state / DesktopHost config helpers;
|
|
|
|
|
# OP runs its own GPU event loop and does not call jian_host_desktop::run (softbuffer
|
|
|
|
|
# raster present is not needed).
|
2026-05-05 04:32:03 +00:00
|
|
|
#
|
fix(shell-native): cfg-gate desktop GL stack so iOS/Android cargo check passes
Spec v19 §11 invariant 1 requires shell-native to compile on iOS / Android
cargo check, with the `GlContextProvider` trait (invariant 2) importable on
every non-wasm target. Previously the desktop GL stack (glutin / winit /
skia-safe) was referenced unconditionally in src/, so mobile cargo check
broke the moment the Cargo.toml target-gated those deps to macOS / Linux /
Windows.
This change cfg-gates the desktop-only modules and items so the mobile
cargo check builds only the cross-platform surface:
- src/lib.rs: gate `backend` + `canvas_view_stub` modules and their
re-exports to desktop OS targets; add `EaglProvider` / `AndroidEglProvider`
re-exports under `target_os = "ios"` / `"android"`. `GlContextProvider`,
`ProviderError`, `ProviderResult` stay always-on (per §11 invariant 2).
- src/context/mod.rs: split into a cross-platform trait surface +
per-platform provider re-exports; gate `shared` (depends on `skia_safe` +
`winit`) to desktop only.
- src/context/provider.rs: cfg-gate `GlutinProvider` struct + impls + the
`pick_display_api` helper to desktop OS only; localize `CString` /
`NonZeroU32` imports inside fn bodies; gate `from_error` to desktop to
silence dead_code on mobile (the only caller is `GlutinProvider`).
- Cargo.toml: split deps into a cross-platform `cfg(not(wasm32))` block
(jian-core + glow + raw-window-handle, all required by the trait
signature on every non-wasm target) and a desktop-only block (skia-safe,
glutin, glutin-winit, winit, scopeguard, jian-skia, jian-host-desktop).
Merges the previously duplicate desktop `[target...]` table headers that
cargo rejected.
- ci: rust-multiplatform.yml mobile-check job now runs cargo check on
shell-native too (per the comment update there).
Verification:
- cargo check -p openpencil-shell-native --target aarch64-apple-darwin: PASS
- cargo check -p openpencil-shell-native --target aarch64-apple-ios: PASS
- cargo check -p openpencil-shell-native --target aarch64-linux-android: PASS
- cargo check -p openpencil-shell-native --target wasm32-unknown-unknown:
FAILS with the spec §1.2 `compile_error!` (intended).
- cargo test -p openpencil-shell-native: 14/14 PASS.
- cargo clippy -p openpencil-shell-native --all-targets -- -D warnings: clean
on macOS, iOS, Android targets.
- cargo fmt --check: clean.
2026-05-05 14:24:00 +00:00
|
|
|
# Desktop GL stack — target-gated to macOS / Linux / Windows. iOS / Android
|
|
|
|
|
# pull EaglProvider / AndroidEglProvider stubs (Step 1f) which don't need
|
|
|
|
|
# glutin / winit / desktop skia-safe gl bindings; spec §11 invariant 1 says
|
|
|
|
|
# shell-native must compile on mobile cargo check (verified by CI mobile-check
|
|
|
|
|
# job in rust-multiplatform.yml). winit features note: on Linux you MUST
|
|
|
|
|
# explicitly enable `x11` and/or `wayland`, otherwise `platform_impl/mod.rs`
|
|
|
|
|
# triggers `compile_error!`. macOS / Windows backends are auto-enabled via
|
|
|
|
|
# cfg(target_os) and need no feature flag.
|
|
|
|
|
# Cross-platform abstraction deps — pulled for ALL non-wasm targets including
|
|
|
|
|
# iOS / Android. The `GlContextProvider` trait (spec §3.1) references
|
|
|
|
|
# `glow::Context` in its method signatures and Step 1f Eagl / AndroidEgl
|
|
|
|
|
# stubs reference `raw_window_handle` for `on_resume`; both must be importable
|
|
|
|
|
# on mobile per spec §11 invariant 2. `glow` and `raw-window-handle` are
|
|
|
|
|
# pure-Rust thin bindings — no native build steps on iOS / Android.
|
|
|
|
|
# `jian-core` is wasm32-clean per P0.5 and platform-neutral on mobile.
|
2026-05-03 14:25:00 +00:00
|
|
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
fix(shell-native): cfg-gate desktop GL stack so iOS/Android cargo check passes
Spec v19 §11 invariant 1 requires shell-native to compile on iOS / Android
cargo check, with the `GlContextProvider` trait (invariant 2) importable on
every non-wasm target. Previously the desktop GL stack (glutin / winit /
skia-safe) was referenced unconditionally in src/, so mobile cargo check
broke the moment the Cargo.toml target-gated those deps to macOS / Linux /
Windows.
This change cfg-gates the desktop-only modules and items so the mobile
cargo check builds only the cross-platform surface:
- src/lib.rs: gate `backend` + `canvas_view_stub` modules and their
re-exports to desktop OS targets; add `EaglProvider` / `AndroidEglProvider`
re-exports under `target_os = "ios"` / `"android"`. `GlContextProvider`,
`ProviderError`, `ProviderResult` stay always-on (per §11 invariant 2).
- src/context/mod.rs: split into a cross-platform trait surface +
per-platform provider re-exports; gate `shared` (depends on `skia_safe` +
`winit`) to desktop only.
- src/context/provider.rs: cfg-gate `GlutinProvider` struct + impls + the
`pick_display_api` helper to desktop OS only; localize `CString` /
`NonZeroU32` imports inside fn bodies; gate `from_error` to desktop to
silence dead_code on mobile (the only caller is `GlutinProvider`).
- Cargo.toml: split deps into a cross-platform `cfg(not(wasm32))` block
(jian-core + glow + raw-window-handle, all required by the trait
signature on every non-wasm target) and a desktop-only block (skia-safe,
glutin, glutin-winit, winit, scopeguard, jian-skia, jian-host-desktop).
Merges the previously duplicate desktop `[target...]` table headers that
cargo rejected.
- ci: rust-multiplatform.yml mobile-check job now runs cargo check on
shell-native too (per the comment update there).
Verification:
- cargo check -p openpencil-shell-native --target aarch64-apple-darwin: PASS
- cargo check -p openpencil-shell-native --target aarch64-apple-ios: PASS
- cargo check -p openpencil-shell-native --target aarch64-linux-android: PASS
- cargo check -p openpencil-shell-native --target wasm32-unknown-unknown:
FAILS with the spec §1.2 `compile_error!` (intended).
- cargo test -p openpencil-shell-native: 14/14 PASS.
- cargo clippy -p openpencil-shell-native --all-targets -- -D warnings: clean
on macOS, iOS, Android targets.
- cargo fmt --check: clean.
2026-05-05 14:24:00 +00:00
|
|
|
jian-core = { path = "../../vendor/jian/crates/jian-core", version = "0.0.1" }
|
|
|
|
|
glow = "0.17.0"
|
|
|
|
|
raw-window-handle = "0.6.2"
|
|
|
|
|
|
2026-05-16 11:29:34 +00:00
|
|
|
# The canonical loader / `EditorState` → paint-`Document` bridge.
|
|
|
|
|
# Desktop-side (depends on skia via jian-skia's SkiaMeasure), so it
|
|
|
|
|
# is gated outside wasm32 alongside the rest of the native stack.
|
|
|
|
|
op-pen-loader = { path = "../op-pen-loader" }
|
|
|
|
|
|
|
|
|
|
# The canonical `.op` schema — `WidgetHostNative` names
|
|
|
|
|
# `VariableScalar` when committing variable-row edits onto
|
|
|
|
|
# `EditorState`. Already a transitive dep via op-editor-core.
|
|
|
|
|
jian-ops-schema = { path = "../../vendor/jian/crates/jian-ops-schema" }
|
|
|
|
|
|
feat(shell-native): extend widget stack to iOS + Android cargo check
Per 2026-05-10 user directive ("extend, jian 最后也会需要 ios 和
android"): lift the desktop-only cfg gate so the widget render
stack (skia-safe + jian-skia + NativeBackend + widget_host)
compiles for iOS (`aarch64-apple-ios`) AND Android
(`aarch64-linux-android`) cargo check too. Mobile shells now have
a real widget-rendering surface to target in Step 1f, and the
"shell-core widgets are platform-agnostic" claim from spec §1.4
is now compile-verified across desktop trio + mobile pair + wasm.
Cargo.toml restructure (`crates/openpencil-shell-native/Cargo.toml`):
- New `[target.'cfg(any(macos, linux, windows, ios, android))']`
block for the cross-platform widget stack: `skia-safe = "0.97"`
(default-features = false; binary-cache + textlayout) and
`jian-skia` (textlayout). Both pull on every desktop trio +
mobile pair target.
- Existing desktop-only block kept for the GUI host stack: adds
`gl` to skia-safe's features (iOS deprecated GL — Metal goes
in Step 1f; Android GL/Vulkan via the platform provider not
via skia-safe's bundled bindings here), plus glutin / glutin-
winit / winit / scopeguard / jian-host-desktop. Cargo
deduplicates: skia-safe resolves to one crate-version with
feature-union (binary-cache + textlayout from the wider block
+ gl from the desktop block on desktop-only).
src/lib.rs gate lift:
- `pub mod backend;` and `pub mod widget_host;` cfg now includes
`target_os = "ios"` and `target_os = "android"`. `pub use`
re-exports follow.
- `canvas_view_stub` stays desktop-only (uses glow GL-isolation
probe with no mobile equivalent).
- Comment block at the cfg site cites the user directive +
Step 1f handoff (real EaglProvider / AndroidEglProvider impls
+ Metal / Vulkan / event integration).
Boundary script revision (`tools/check-jian-boundaries.sh`):
- Invariant 2 was: mobile targets must NOT pull jian-host-desktop
OR jian-skia. Per the user directive, jian-skia is now ALLOWED
on mobile (the widget render stack uses it). jian-host-desktop
remains forbidden — it carries winit / glutin / desktop
GLContextProvider impls that have no mobile equivalent.
- Header comment block + active grep narrowed accordingly. The
Step 1f path through EaglProvider / AndroidEglProvider is the
spec-blessed mobile host plugin point (no IPC / CLI needed).
Verification:
- `cargo check -p openpencil-shell-native --target
aarch64-apple-ios` — green (skia-bindings + jian-skia +
shell-native all compile)
- `cargo check -p openpencil-shell-native --target
aarch64-linux-android` — green (same)
- `cargo check -p openpencil-shell-native` — green (no desktop
regression)
- `cargo check -p openpencil-shell-core --target
wasm32-unknown-unknown` — green (shell-core stays wasm32-clean)
- `cargo test -p openpencil-shell-core --test widgets_static` —
21/21 passing (widget logic untouched)
- `bash tools/check-wasm-bundle.sh` — PASS:
- 0 env.* imports
- 622 156 bytes gzip = 59% of 1 MiB ceiling (no web regression)
- `bash tools/check-widget-boundary.sh` — PASS
- `bash tools/check-jian-boundaries.sh` — 4/4 invariants pass
(Invariant 2 revised to allow jian-skia on mobile)
What's still mobile-pending (Step 1f scope):
- `EaglProvider` (iOS) — Metal-backed `GlContextProvider` impl
(skia-safe `metal` feature when iOS host actually runs)
- `AndroidEglProvider` (Android) — GL/Vulkan-backed impl
- Mobile host runners (UIKit AppDelegate / Activity wrappers)
- Mobile event translation (jian-host-ios / jian-host-android —
siblings of jian-host-desktop)
- `inspector_window` example is desktop-only by design (winit +
SharedSkiaContext::new_desktop); mobile shells will land their
own UIKit / Activity runners that consume the SAME
`WidgetHostNative::paint(&mut frame, width)` surface
The widget glue itself (NativeFrameBackend + WidgetHostNative)
is platform-agnostic in shape — no winit / glutin / EGL types
leak in. Step 1f mobile work plugs in providers, not widgets.
2026-05-10 02:16:36 +00:00
|
|
|
# Cross-platform widget render stack (desktop + mobile, NOT wasm).
|
|
|
|
|
#
|
2026-05-17 01:33:41 +00:00
|
|
|
# 2026-05-10 mobile extension (per user note that jian will eventually
|
|
|
|
|
# need iOS and Android): skia-safe + jian-skia move out of the desktop-only
|
feat(shell-native): extend widget stack to iOS + Android cargo check
Per 2026-05-10 user directive ("extend, jian 最后也会需要 ios 和
android"): lift the desktop-only cfg gate so the widget render
stack (skia-safe + jian-skia + NativeBackend + widget_host)
compiles for iOS (`aarch64-apple-ios`) AND Android
(`aarch64-linux-android`) cargo check too. Mobile shells now have
a real widget-rendering surface to target in Step 1f, and the
"shell-core widgets are platform-agnostic" claim from spec §1.4
is now compile-verified across desktop trio + mobile pair + wasm.
Cargo.toml restructure (`crates/openpencil-shell-native/Cargo.toml`):
- New `[target.'cfg(any(macos, linux, windows, ios, android))']`
block for the cross-platform widget stack: `skia-safe = "0.97"`
(default-features = false; binary-cache + textlayout) and
`jian-skia` (textlayout). Both pull on every desktop trio +
mobile pair target.
- Existing desktop-only block kept for the GUI host stack: adds
`gl` to skia-safe's features (iOS deprecated GL — Metal goes
in Step 1f; Android GL/Vulkan via the platform provider not
via skia-safe's bundled bindings here), plus glutin / glutin-
winit / winit / scopeguard / jian-host-desktop. Cargo
deduplicates: skia-safe resolves to one crate-version with
feature-union (binary-cache + textlayout from the wider block
+ gl from the desktop block on desktop-only).
src/lib.rs gate lift:
- `pub mod backend;` and `pub mod widget_host;` cfg now includes
`target_os = "ios"` and `target_os = "android"`. `pub use`
re-exports follow.
- `canvas_view_stub` stays desktop-only (uses glow GL-isolation
probe with no mobile equivalent).
- Comment block at the cfg site cites the user directive +
Step 1f handoff (real EaglProvider / AndroidEglProvider impls
+ Metal / Vulkan / event integration).
Boundary script revision (`tools/check-jian-boundaries.sh`):
- Invariant 2 was: mobile targets must NOT pull jian-host-desktop
OR jian-skia. Per the user directive, jian-skia is now ALLOWED
on mobile (the widget render stack uses it). jian-host-desktop
remains forbidden — it carries winit / glutin / desktop
GLContextProvider impls that have no mobile equivalent.
- Header comment block + active grep narrowed accordingly. The
Step 1f path through EaglProvider / AndroidEglProvider is the
spec-blessed mobile host plugin point (no IPC / CLI needed).
Verification:
- `cargo check -p openpencil-shell-native --target
aarch64-apple-ios` — green (skia-bindings + jian-skia +
shell-native all compile)
- `cargo check -p openpencil-shell-native --target
aarch64-linux-android` — green (same)
- `cargo check -p openpencil-shell-native` — green (no desktop
regression)
- `cargo check -p openpencil-shell-core --target
wasm32-unknown-unknown` — green (shell-core stays wasm32-clean)
- `cargo test -p openpencil-shell-core --test widgets_static` —
21/21 passing (widget logic untouched)
- `bash tools/check-wasm-bundle.sh` — PASS:
- 0 env.* imports
- 622 156 bytes gzip = 59% of 1 MiB ceiling (no web regression)
- `bash tools/check-widget-boundary.sh` — PASS
- `bash tools/check-jian-boundaries.sh` — 4/4 invariants pass
(Invariant 2 revised to allow jian-skia on mobile)
What's still mobile-pending (Step 1f scope):
- `EaglProvider` (iOS) — Metal-backed `GlContextProvider` impl
(skia-safe `metal` feature when iOS host actually runs)
- `AndroidEglProvider` (Android) — GL/Vulkan-backed impl
- Mobile host runners (UIKit AppDelegate / Activity wrappers)
- Mobile event translation (jian-host-ios / jian-host-android —
siblings of jian-host-desktop)
- `inspector_window` example is desktop-only by design (winit +
SharedSkiaContext::new_desktop); mobile shells will land their
own UIKit / Activity runners that consume the SAME
`WidgetHostNative::paint(&mut frame, width)` surface
The widget glue itself (NativeFrameBackend + WidgetHostNative)
is platform-agnostic in shape — no winit / glutin / EGL types
leak in. Step 1f mobile work plugs in providers, not widgets.
2026-05-10 02:16:36 +00:00
|
|
|
# block so `NativeBackend` + `widget_host` compile on iOS / Android
|
|
|
|
|
# too. skia-safe's `gl` feature is desktop-only (iOS deprecated GL —
|
|
|
|
|
# Metal goes in Step 1f; Android uses GL/Vulkan via the platform
|
|
|
|
|
# provider, not via skia-safe's bundled GL bindings here).
|
|
|
|
|
# Mobile cargo check pulls skia-safe with no GL feature, exercising
|
|
|
|
|
# only the raster + textlayout paths that the inspector slice needs.
|
2026-05-10 02:17:10 +00:00
|
|
|
# Spec §12.3 jian boundary invariants 2 & 3 — REVISED 2026-05-10:
|
|
|
|
|
# Invariant 2 now allows `jian-skia` on mobile (the widget render
|
|
|
|
|
# stack uses it); `jian-host-desktop` remains forbidden on mobile
|
|
|
|
|
# because it carries winit / glutin / desktop-only host glue.
|
|
|
|
|
# Invariant 3 (wasm32 forbids both) is unchanged. The
|
|
|
|
|
# `tools/check-jian-boundaries.sh` script enforces the revised set
|
|
|
|
|
# alongside the script header rationale.
|
feat(shell-native): extend widget stack to iOS + Android cargo check
Per 2026-05-10 user directive ("extend, jian 最后也会需要 ios 和
android"): lift the desktop-only cfg gate so the widget render
stack (skia-safe + jian-skia + NativeBackend + widget_host)
compiles for iOS (`aarch64-apple-ios`) AND Android
(`aarch64-linux-android`) cargo check too. Mobile shells now have
a real widget-rendering surface to target in Step 1f, and the
"shell-core widgets are platform-agnostic" claim from spec §1.4
is now compile-verified across desktop trio + mobile pair + wasm.
Cargo.toml restructure (`crates/openpencil-shell-native/Cargo.toml`):
- New `[target.'cfg(any(macos, linux, windows, ios, android))']`
block for the cross-platform widget stack: `skia-safe = "0.97"`
(default-features = false; binary-cache + textlayout) and
`jian-skia` (textlayout). Both pull on every desktop trio +
mobile pair target.
- Existing desktop-only block kept for the GUI host stack: adds
`gl` to skia-safe's features (iOS deprecated GL — Metal goes
in Step 1f; Android GL/Vulkan via the platform provider not
via skia-safe's bundled bindings here), plus glutin / glutin-
winit / winit / scopeguard / jian-host-desktop. Cargo
deduplicates: skia-safe resolves to one crate-version with
feature-union (binary-cache + textlayout from the wider block
+ gl from the desktop block on desktop-only).
src/lib.rs gate lift:
- `pub mod backend;` and `pub mod widget_host;` cfg now includes
`target_os = "ios"` and `target_os = "android"`. `pub use`
re-exports follow.
- `canvas_view_stub` stays desktop-only (uses glow GL-isolation
probe with no mobile equivalent).
- Comment block at the cfg site cites the user directive +
Step 1f handoff (real EaglProvider / AndroidEglProvider impls
+ Metal / Vulkan / event integration).
Boundary script revision (`tools/check-jian-boundaries.sh`):
- Invariant 2 was: mobile targets must NOT pull jian-host-desktop
OR jian-skia. Per the user directive, jian-skia is now ALLOWED
on mobile (the widget render stack uses it). jian-host-desktop
remains forbidden — it carries winit / glutin / desktop
GLContextProvider impls that have no mobile equivalent.
- Header comment block + active grep narrowed accordingly. The
Step 1f path through EaglProvider / AndroidEglProvider is the
spec-blessed mobile host plugin point (no IPC / CLI needed).
Verification:
- `cargo check -p openpencil-shell-native --target
aarch64-apple-ios` — green (skia-bindings + jian-skia +
shell-native all compile)
- `cargo check -p openpencil-shell-native --target
aarch64-linux-android` — green (same)
- `cargo check -p openpencil-shell-native` — green (no desktop
regression)
- `cargo check -p openpencil-shell-core --target
wasm32-unknown-unknown` — green (shell-core stays wasm32-clean)
- `cargo test -p openpencil-shell-core --test widgets_static` —
21/21 passing (widget logic untouched)
- `bash tools/check-wasm-bundle.sh` — PASS:
- 0 env.* imports
- 622 156 bytes gzip = 59% of 1 MiB ceiling (no web regression)
- `bash tools/check-widget-boundary.sh` — PASS
- `bash tools/check-jian-boundaries.sh` — 4/4 invariants pass
(Invariant 2 revised to allow jian-skia on mobile)
What's still mobile-pending (Step 1f scope):
- `EaglProvider` (iOS) — Metal-backed `GlContextProvider` impl
(skia-safe `metal` feature when iOS host actually runs)
- `AndroidEglProvider` (Android) — GL/Vulkan-backed impl
- Mobile host runners (UIKit AppDelegate / Activity wrappers)
- Mobile event translation (jian-host-ios / jian-host-android —
siblings of jian-host-desktop)
- `inspector_window` example is desktop-only by design (winit +
SharedSkiaContext::new_desktop); mobile shells will land their
own UIKit / Activity runners that consume the SAME
`WidgetHostNative::paint(&mut frame, width)` surface
The widget glue itself (NativeFrameBackend + WidgetHostNative)
is platform-agnostic in shape — no winit / glutin / EGL types
leak in. Step 1f mobile work plugs in providers, not widgets.
2026-05-10 02:16:36 +00:00
|
|
|
[target.'cfg(any(target_os = "macos", target_os = "linux", target_os = "windows", target_os = "ios", target_os = "android"))'.dependencies]
|
2026-05-10 02:17:10 +00:00
|
|
|
skia-safe = { version = "0.97.0", default-features = false, features = [
|
|
|
|
|
"binary-cache",
|
|
|
|
|
"textlayout",
|
|
|
|
|
] }
|
feat(shell-native): extend widget stack to iOS + Android cargo check
Per 2026-05-10 user directive ("extend, jian 最后也会需要 ios 和
android"): lift the desktop-only cfg gate so the widget render
stack (skia-safe + jian-skia + NativeBackend + widget_host)
compiles for iOS (`aarch64-apple-ios`) AND Android
(`aarch64-linux-android`) cargo check too. Mobile shells now have
a real widget-rendering surface to target in Step 1f, and the
"shell-core widgets are platform-agnostic" claim from spec §1.4
is now compile-verified across desktop trio + mobile pair + wasm.
Cargo.toml restructure (`crates/openpencil-shell-native/Cargo.toml`):
- New `[target.'cfg(any(macos, linux, windows, ios, android))']`
block for the cross-platform widget stack: `skia-safe = "0.97"`
(default-features = false; binary-cache + textlayout) and
`jian-skia` (textlayout). Both pull on every desktop trio +
mobile pair target.
- Existing desktop-only block kept for the GUI host stack: adds
`gl` to skia-safe's features (iOS deprecated GL — Metal goes
in Step 1f; Android GL/Vulkan via the platform provider not
via skia-safe's bundled bindings here), plus glutin / glutin-
winit / winit / scopeguard / jian-host-desktop. Cargo
deduplicates: skia-safe resolves to one crate-version with
feature-union (binary-cache + textlayout from the wider block
+ gl from the desktop block on desktop-only).
src/lib.rs gate lift:
- `pub mod backend;` and `pub mod widget_host;` cfg now includes
`target_os = "ios"` and `target_os = "android"`. `pub use`
re-exports follow.
- `canvas_view_stub` stays desktop-only (uses glow GL-isolation
probe with no mobile equivalent).
- Comment block at the cfg site cites the user directive +
Step 1f handoff (real EaglProvider / AndroidEglProvider impls
+ Metal / Vulkan / event integration).
Boundary script revision (`tools/check-jian-boundaries.sh`):
- Invariant 2 was: mobile targets must NOT pull jian-host-desktop
OR jian-skia. Per the user directive, jian-skia is now ALLOWED
on mobile (the widget render stack uses it). jian-host-desktop
remains forbidden — it carries winit / glutin / desktop
GLContextProvider impls that have no mobile equivalent.
- Header comment block + active grep narrowed accordingly. The
Step 1f path through EaglProvider / AndroidEglProvider is the
spec-blessed mobile host plugin point (no IPC / CLI needed).
Verification:
- `cargo check -p openpencil-shell-native --target
aarch64-apple-ios` — green (skia-bindings + jian-skia +
shell-native all compile)
- `cargo check -p openpencil-shell-native --target
aarch64-linux-android` — green (same)
- `cargo check -p openpencil-shell-native` — green (no desktop
regression)
- `cargo check -p openpencil-shell-core --target
wasm32-unknown-unknown` — green (shell-core stays wasm32-clean)
- `cargo test -p openpencil-shell-core --test widgets_static` —
21/21 passing (widget logic untouched)
- `bash tools/check-wasm-bundle.sh` — PASS:
- 0 env.* imports
- 622 156 bytes gzip = 59% of 1 MiB ceiling (no web regression)
- `bash tools/check-widget-boundary.sh` — PASS
- `bash tools/check-jian-boundaries.sh` — 4/4 invariants pass
(Invariant 2 revised to allow jian-skia on mobile)
What's still mobile-pending (Step 1f scope):
- `EaglProvider` (iOS) — Metal-backed `GlContextProvider` impl
(skia-safe `metal` feature when iOS host actually runs)
- `AndroidEglProvider` (Android) — GL/Vulkan-backed impl
- Mobile host runners (UIKit AppDelegate / Activity wrappers)
- Mobile event translation (jian-host-ios / jian-host-android —
siblings of jian-host-desktop)
- `inspector_window` example is desktop-only by design (winit +
SharedSkiaContext::new_desktop); mobile shells will land their
own UIKit / Activity runners that consume the SAME
`WidgetHostNative::paint(&mut frame, width)` surface
The widget glue itself (NativeFrameBackend + WidgetHostNative)
is platform-agnostic in shape — no winit / glutin / EGL types
leak in. Step 1f mobile work plugs in providers, not widgets.
2026-05-10 02:16:36 +00:00
|
|
|
jian-skia = { path = "../../vendor/jian/crates/jian-skia", version = "0.0.1", features = [
|
|
|
|
|
"textlayout",
|
|
|
|
|
] }
|
|
|
|
|
|
|
|
|
|
# Desktop-only GL stack — `gl` feature on skia-safe, plus glutin /
|
|
|
|
|
# glutin-winit / winit / jian-host-desktop (all GUI-host glue that
|
|
|
|
|
# does not apply to iOS / Android, where the host is a UIKit /
|
|
|
|
|
# Activity wrapper — Step 1f scope). Cargo deduplicates: skia-safe
|
|
|
|
|
# resolves to one crate version with the union of features (binary-
|
|
|
|
|
# cache + textlayout from above + gl from here on desktop only).
|
|
|
|
|
# winit features note: on Linux you MUST explicitly enable `x11`
|
|
|
|
|
# and/or `wayland`, otherwise `platform_impl/mod.rs` triggers
|
|
|
|
|
# `compile_error!`. macOS / Windows backends auto-enable via
|
|
|
|
|
# cfg(target_os) and need no feature flag.
|
fix(shell-native): cfg-gate desktop GL stack so iOS/Android cargo check passes
Spec v19 §11 invariant 1 requires shell-native to compile on iOS / Android
cargo check, with the `GlContextProvider` trait (invariant 2) importable on
every non-wasm target. Previously the desktop GL stack (glutin / winit /
skia-safe) was referenced unconditionally in src/, so mobile cargo check
broke the moment the Cargo.toml target-gated those deps to macOS / Linux /
Windows.
This change cfg-gates the desktop-only modules and items so the mobile
cargo check builds only the cross-platform surface:
- src/lib.rs: gate `backend` + `canvas_view_stub` modules and their
re-exports to desktop OS targets; add `EaglProvider` / `AndroidEglProvider`
re-exports under `target_os = "ios"` / `"android"`. `GlContextProvider`,
`ProviderError`, `ProviderResult` stay always-on (per §11 invariant 2).
- src/context/mod.rs: split into a cross-platform trait surface +
per-platform provider re-exports; gate `shared` (depends on `skia_safe` +
`winit`) to desktop only.
- src/context/provider.rs: cfg-gate `GlutinProvider` struct + impls + the
`pick_display_api` helper to desktop OS only; localize `CString` /
`NonZeroU32` imports inside fn bodies; gate `from_error` to desktop to
silence dead_code on mobile (the only caller is `GlutinProvider`).
- Cargo.toml: split deps into a cross-platform `cfg(not(wasm32))` block
(jian-core + glow + raw-window-handle, all required by the trait
signature on every non-wasm target) and a desktop-only block (skia-safe,
glutin, glutin-winit, winit, scopeguard, jian-skia, jian-host-desktop).
Merges the previously duplicate desktop `[target...]` table headers that
cargo rejected.
- ci: rust-multiplatform.yml mobile-check job now runs cargo check on
shell-native too (per the comment update there).
Verification:
- cargo check -p openpencil-shell-native --target aarch64-apple-darwin: PASS
- cargo check -p openpencil-shell-native --target aarch64-apple-ios: PASS
- cargo check -p openpencil-shell-native --target aarch64-linux-android: PASS
- cargo check -p openpencil-shell-native --target wasm32-unknown-unknown:
FAILS with the spec §1.2 `compile_error!` (intended).
- cargo test -p openpencil-shell-native: 14/14 PASS.
- cargo clippy -p openpencil-shell-native --all-targets -- -D warnings: clean
on macOS, iOS, Android targets.
- cargo fmt --check: clean.
2026-05-05 14:24:00 +00:00
|
|
|
[target.'cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))'.dependencies]
|
2026-05-10 02:17:10 +00:00
|
|
|
skia-safe = { version = "0.97.0", default-features = false, features = [
|
|
|
|
|
"binary-cache",
|
|
|
|
|
"textlayout",
|
|
|
|
|
"gl",
|
|
|
|
|
] }
|
feat(workspace): pin Jian submodule and shell wrapper deps (Step 1a Task 1)
Anchor v19 pivot at the workspace level: vendor Jian as a git submodule
pinned to fork commit ad13ce6 (P0.5 mini-gate GO; skia-safe 0.78 → 0.97 +
new pub draw_on_canvas adapter), wire jian-core / jian-skia / jian-host-desktop
as path deps with explicit version per spec §12.2, and re-export the
Jian render/geometry/scene types from shell-core so shell-native can
translate the OP RenderBackend facade into jian DrawOp commands.
shell-core stays wasm32-clean: only jian-core (already wasm32-validated
in P0.5) plus glam / bitflags / thiserror / tracing land here.
shell-native picks up the full P0-pinned GL stack (skia-safe 0.97.0,
glutin 0.32.3, glutin-winit 0.5.0, glow 0.17.0, winit 0.30.13,
raw-window-handle 0.6.2, scopeguard 1.2) plus jian-skia (textlayout)
and target-gated jian-host-desktop (default-features = false, no `run`
feature so we skip Jian's softbuffer raster present path — OP owns its
own GPU swap_buffers per spec §3.6).
Adds OP RenderBackend trait + Rect / Color (with RED/GREEN/BLUE/BLACK/
WHITE/TRANSPARENT named constants per spec §5.2) + TextLayout facade
that wraps jian_core::render::TextRun explicitly (TextRun has no Default
impl, fields enumerated to honour spec §5.2 round-2 CONCERN-1 fix).
Boundary checks all pass:
- wasm32 shell-web metadata: no jian-host-desktop / jian-skia
- aarch64-linux-android shell-native metadata: no jian-host-desktop
- shell-core src: no glutin / skia_safe / winit / glow imports
Tasks 2-4 (SharedSkiaContext + NativeBackend + ShellEvent mapping +
acceptance) follow per plan v7.
2026-05-05 13:00:00 +00:00
|
|
|
glutin = "0.32.3"
|
2026-05-21 14:23:34 +00:00
|
|
|
# `casement` — ZSeven-W's winit fork (vendored as a submodule under
|
|
|
|
|
# `vendor/casement` so CI checks out the same source the desktop binary
|
|
|
|
|
# links). The `package` key keeps the `winit` import name. `glutin-winit`
|
2026-05-18 13:45:09 +00:00
|
|
|
# is intentionally NOT used: it hard-depends on the upstream `winit`
|
|
|
|
|
# package, which would pull a second, incompatible winit into the
|
|
|
|
|
# tree. Its only use here — `GlWindow::build_surface_attributes` — is
|
|
|
|
|
# replaced by a direct `glutin::surface::SurfaceAttributesBuilder`
|
|
|
|
|
# call in `context/provider.rs`.
|
2026-05-21 14:23:34 +00:00
|
|
|
winit = { package = "casement", path = "../../vendor/casement", default-features = false, features = [
|
2026-05-05 14:12:00 +00:00
|
|
|
"x11",
|
|
|
|
|
"wayland",
|
|
|
|
|
"wayland-csd-adwaita",
|
|
|
|
|
"rwh_06",
|
|
|
|
|
] }
|
feat(workspace): pin Jian submodule and shell wrapper deps (Step 1a Task 1)
Anchor v19 pivot at the workspace level: vendor Jian as a git submodule
pinned to fork commit ad13ce6 (P0.5 mini-gate GO; skia-safe 0.78 → 0.97 +
new pub draw_on_canvas adapter), wire jian-core / jian-skia / jian-host-desktop
as path deps with explicit version per spec §12.2, and re-export the
Jian render/geometry/scene types from shell-core so shell-native can
translate the OP RenderBackend facade into jian DrawOp commands.
shell-core stays wasm32-clean: only jian-core (already wasm32-validated
in P0.5) plus glam / bitflags / thiserror / tracing land here.
shell-native picks up the full P0-pinned GL stack (skia-safe 0.97.0,
glutin 0.32.3, glutin-winit 0.5.0, glow 0.17.0, winit 0.30.13,
raw-window-handle 0.6.2, scopeguard 1.2) plus jian-skia (textlayout)
and target-gated jian-host-desktop (default-features = false, no `run`
feature so we skip Jian's softbuffer raster present path — OP owns its
own GPU swap_buffers per spec §3.6).
Adds OP RenderBackend trait + Rect / Color (with RED/GREEN/BLUE/BLACK/
WHITE/TRANSPARENT named constants per spec §5.2) + TextLayout facade
that wraps jian_core::render::TextRun explicitly (TextRun has no Default
impl, fields enumerated to honour spec §5.2 round-2 CONCERN-1 fix).
Boundary checks all pass:
- wasm32 shell-web metadata: no jian-host-desktop / jian-skia
- aarch64-linux-android shell-native metadata: no jian-host-desktop
- shell-core src: no glutin / skia_safe / winit / glow imports
Tasks 2-4 (SharedSkiaContext + NativeBackend + ShellEvent mapping +
acceptance) follow per plan v7.
2026-05-05 13:00:00 +00:00
|
|
|
scopeguard = "1.2"
|
2026-05-05 14:12:00 +00:00
|
|
|
jian-host-desktop = { path = "../../vendor/jian/crates/jian-host-desktop", version = "0.0.1", default-features = false, features = [
|
|
|
|
|
"textlayout",
|
|
|
|
|
] }
|
fix(shell-native): cfg-gate desktop GL stack so iOS/Android cargo check passes
Spec v19 §11 invariant 1 requires shell-native to compile on iOS / Android
cargo check, with the `GlContextProvider` trait (invariant 2) importable on
every non-wasm target. Previously the desktop GL stack (glutin / winit /
skia-safe) was referenced unconditionally in src/, so mobile cargo check
broke the moment the Cargo.toml target-gated those deps to macOS / Linux /
Windows.
This change cfg-gates the desktop-only modules and items so the mobile
cargo check builds only the cross-platform surface:
- src/lib.rs: gate `backend` + `canvas_view_stub` modules and their
re-exports to desktop OS targets; add `EaglProvider` / `AndroidEglProvider`
re-exports under `target_os = "ios"` / `"android"`. `GlContextProvider`,
`ProviderError`, `ProviderResult` stay always-on (per §11 invariant 2).
- src/context/mod.rs: split into a cross-platform trait surface +
per-platform provider re-exports; gate `shared` (depends on `skia_safe` +
`winit`) to desktop only.
- src/context/provider.rs: cfg-gate `GlutinProvider` struct + impls + the
`pick_display_api` helper to desktop OS only; localize `CString` /
`NonZeroU32` imports inside fn bodies; gate `from_error` to desktop to
silence dead_code on mobile (the only caller is `GlutinProvider`).
- Cargo.toml: split deps into a cross-platform `cfg(not(wasm32))` block
(jian-core + glow + raw-window-handle, all required by the trait
signature on every non-wasm target) and a desktop-only block (skia-safe,
glutin, glutin-winit, winit, scopeguard, jian-skia, jian-host-desktop).
Merges the previously duplicate desktop `[target...]` table headers that
cargo rejected.
- ci: rust-multiplatform.yml mobile-check job now runs cargo check on
shell-native too (per the comment update there).
Verification:
- cargo check -p openpencil-shell-native --target aarch64-apple-darwin: PASS
- cargo check -p openpencil-shell-native --target aarch64-apple-ios: PASS
- cargo check -p openpencil-shell-native --target aarch64-linux-android: PASS
- cargo check -p openpencil-shell-native --target wasm32-unknown-unknown:
FAILS with the spec §1.2 `compile_error!` (intended).
- cargo test -p openpencil-shell-native: 14/14 PASS.
- cargo clippy -p openpencil-shell-native --all-targets -- -D warnings: clean
on macOS, iOS, Android targets.
- cargo fmt --check: clean.
2026-05-05 13:36:00 +00:00
|
|
|
|
feat(shell-native): SharedSkiaContext + NativeBackend over Jian DrawOp
Step 1a Task 2 (spec v19 §3 / §5.2.1, plan v7).
- `SharedSkiaContext`: own GL stack + Skia DirectContext + Surface,
`Option<>`-field idempotent teardown, `with_frame(|canvas, glow|)`
callback, lifecycle hooks (on_pause/on_resume/on_low_memory) with
Android surface drop contract; tracing spans + events on every
per-frame entry point.
- `GlContextProvider` trait + `GlutinProvider` desktop impl + iOS /
Android stubs; trait carries no `Send` bound (per spec §3.1).
- `CanvasViewportStub::render_into(&Canvas)` deliberately pollutes
STENCIL_TEST + blend func to verify chrome-paint isolation.
- `NativeBackend`: frame-scoped methods mirroring OP `RenderBackend`
trait surface (no direct trait impl in 1a; Step 1c+ wraps via
`WithCanvas<'a>` newtype). Translates `fill_rect / stroke_rect /
draw_text / clip_rect / save / restore / translate` to
`jian_core::render::DrawOp` and submits via
`jian_skia::SkiaBackend::draw_on_canvas`. Public `draw_op` helper +
`to_jian_color` / `to_jian_rect` converters.
- Tests:
- `teardown_idempotent.rs` — teardown × 3 + lifecycle hook idempotence.
- `memory_loop.rs` — 100 × create/begin_frame/present/teardown × 3
with sysinfo RSS budget < 5 %.
- `tracing_spans.rs` — `tracing-test` (no-env-filter) catches
begin_frame / with_frame / present / resize / teardown / on_pause /
on_resume / on_low_memory events.
- `raster_composition.rs` — chrome-only fill_rect on raster surface,
pixel-asserts red + black + untouched-bg.
- `raster_text_smoke.rs` — "Hello 你好" through textlayout feature,
asserts visible glyph rasterisation.
- `gpu_smoke.rs` — Linux EGL pbuffer (non-ignored) + macOS invisible
winit window (graceful inconclusive when off main thread; full
path runs from `cargo run --example basic_window`) + Windows
`#[ignore]` per spec §8.1.
- `gpu_chrome_stub_composition.rs` — chrome+stub on the same GL
surface, asserts chrome pixels survive stub's GL pollution.
- Cargo.toml: add `jian-core` direct dep + `tracing` / `thiserror`
workspace deps; dev-deps `sysinfo`, `tracing-test` (with
`no-env-filter`), Linux-only `khronos-egl` + `libloading`.
`cargo build`, `cargo test`, `cargo clippy --all-targets -- -D warnings`,
`cargo fmt --all -- --check` all green on macOS.
2026-05-05 13:06:00 +00:00
|
|
|
# tracing for span instrumentation across SharedSkiaContext / NativeBackend
|
|
|
|
|
# (spec §3.3 / §5.2.1; Task 2 Step 15 dictates per-method spans).
|
|
|
|
|
[dependencies.tracing]
|
|
|
|
|
workspace = true
|
|
|
|
|
|
|
|
|
|
# thiserror for ProviderError / SharedSkiaError enums (context module).
|
|
|
|
|
[dependencies.thiserror]
|
|
|
|
|
workspace = true
|
|
|
|
|
|
|
|
|
|
# Task 2 dev-dependencies (spec §9 + plan v7 Steps 16a-16f):
|
|
|
|
|
# - sysinfo: 100-loop RSS sanity (memory_loop.rs)
|
|
|
|
|
# - tracing-test: capture span emission (tracing_spans.rs)
|
|
|
|
|
# - khronos-egl: Linux EGL pbuffer GPU smoke (gpu_smoke.rs / gpu_chrome_stub_composition.rs)
|
|
|
|
|
[dev-dependencies]
|
|
|
|
|
sysinfo = "0.30"
|
|
|
|
|
# `no-env-filter` is required for integration tests — the default filter
|
|
|
|
|
# only captures logs from the test crate itself, but our `#[tracing::instrument]`
|
2026-05-16 15:49:58 +00:00
|
|
|
# spans live inside `op_host_native::*`. (Per upstream README §136.)
|
feat(shell-native): SharedSkiaContext + NativeBackend over Jian DrawOp
Step 1a Task 2 (spec v19 §3 / §5.2.1, plan v7).
- `SharedSkiaContext`: own GL stack + Skia DirectContext + Surface,
`Option<>`-field idempotent teardown, `with_frame(|canvas, glow|)`
callback, lifecycle hooks (on_pause/on_resume/on_low_memory) with
Android surface drop contract; tracing spans + events on every
per-frame entry point.
- `GlContextProvider` trait + `GlutinProvider` desktop impl + iOS /
Android stubs; trait carries no `Send` bound (per spec §3.1).
- `CanvasViewportStub::render_into(&Canvas)` deliberately pollutes
STENCIL_TEST + blend func to verify chrome-paint isolation.
- `NativeBackend`: frame-scoped methods mirroring OP `RenderBackend`
trait surface (no direct trait impl in 1a; Step 1c+ wraps via
`WithCanvas<'a>` newtype). Translates `fill_rect / stroke_rect /
draw_text / clip_rect / save / restore / translate` to
`jian_core::render::DrawOp` and submits via
`jian_skia::SkiaBackend::draw_on_canvas`. Public `draw_op` helper +
`to_jian_color` / `to_jian_rect` converters.
- Tests:
- `teardown_idempotent.rs` — teardown × 3 + lifecycle hook idempotence.
- `memory_loop.rs` — 100 × create/begin_frame/present/teardown × 3
with sysinfo RSS budget < 5 %.
- `tracing_spans.rs` — `tracing-test` (no-env-filter) catches
begin_frame / with_frame / present / resize / teardown / on_pause /
on_resume / on_low_memory events.
- `raster_composition.rs` — chrome-only fill_rect on raster surface,
pixel-asserts red + black + untouched-bg.
- `raster_text_smoke.rs` — "Hello 你好" through textlayout feature,
asserts visible glyph rasterisation.
- `gpu_smoke.rs` — Linux EGL pbuffer (non-ignored) + macOS invisible
winit window (graceful inconclusive when off main thread; full
path runs from `cargo run --example basic_window`) + Windows
`#[ignore]` per spec §8.1.
- `gpu_chrome_stub_composition.rs` — chrome+stub on the same GL
surface, asserts chrome pixels survive stub's GL pollution.
- Cargo.toml: add `jian-core` direct dep + `tracing` / `thiserror`
workspace deps; dev-deps `sysinfo`, `tracing-test` (with
`no-env-filter`), Linux-only `khronos-egl` + `libloading`.
`cargo build`, `cargo test`, `cargo clippy --all-targets -- -D warnings`,
`cargo fmt --all -- --check` all green on macOS.
2026-05-05 13:06:00 +00:00
|
|
|
tracing-test = { version = "0.2", features = ["no-env-filter"] }
|
|
|
|
|
|
|
|
|
|
# EGL pbuffer dev-dep is Linux-only — macOS/Windows GPU smoke takes other
|
|
|
|
|
# paths (invisible winit window / manual). Gating with `target.'cfg(...)'`
|
|
|
|
|
# keeps `cargo check` on non-Linux quiet about the un-fetchable pkg-config
|
|
|
|
|
# requirement. khronos-egl 6.x covers Mesa softpipe pbuffer creation.
|
|
|
|
|
[target.'cfg(target_os = "linux")'.dev-dependencies]
|
|
|
|
|
khronos-egl = { version = "6", features = ["dynamic"] }
|
|
|
|
|
libloading = "0.8"
|