openpencil/crates
Kayshen-X 987ce82a24 feat(shell-native): WidgetHostNative + inspector_window — cross-platform proof
Lands the shell-native consumer of shell-core's Step 1b widget
module so spec §1.4 is concrete: same widget code, same paint
output on macOS / Linux / Windows desktop AND
wasm32-unknown-unknown browsers. User priority for this commit
("主要是native 端") + the parallel Phase D web work.

What's added:
- `crates/openpencil-shell-native/src/widget_host.rs` (~155 LOC):
  * `NativeFrameBackend<'a>` — frame-scoped wrapper holding
    `(&mut NativeBackend, &skia_safe::Canvas)`, impls
    shell-core's `RenderBackend` by forwarding to the existing
    `NativeBackend::{fill_rect, stroke_rect, draw_text,
    clip_rect, save, restore, translate}` methods (each takes
    the canvas as a separate arg in the existing API).
    `begin_frame`/`end_frame` no-op because `SharedSkiaContext::
    with_frame` owns those bracket points; `resize` no-op because
    surface resize lives on `SharedSkiaContext::resize`. Spec
    §5.2.1 explicitly deferred this RenderBackend impl to Step
    1c+ widget tree work — this is that landing site.
  * `WidgetHostNative` — owns one of each B1/B2 widget
    (TreeWidget::sample, PropertyRow::new(200, "Width", "960"),
    Dropdown::sample, TextInput::sample). `paint(&self, frame,
    available_width)` mirrors shell-web's `WidgetHost::paint`
    exactly (16/12 px gaps, 280 px column) so the visual layout
    is identical between platforms — Phase E manual smoke
    acceptance criterion.
  * `// glue:` markers for the (future) cross-crate widget-
    boundary gate.

- `crates/openpencil-shell-native/examples/inspector_window.rs`
  (~150 LOC) — winit + SharedSkiaContext + NativeBackend +
  WidgetHostNative end-to-end. Same shape as `basic_window.rs`
  but the per-frame paint dispatches to `WidgetHostNative`
  instead of hard-coded chrome. cfg-gated to desktop OS; CI
  verifies `cargo build --examples` only.

- `crates/openpencil-shell-native/src/lib.rs` — adds `pub mod
  widget_host;` cfg-gated to desktop OS (matches the existing
  `backend` / `canvas_view_stub` gating per spec §11). Re-exports
  `NativeFrameBackend` + `WidgetHostNative` at the crate root.

Mobile (iOS / Android) considered (per 2026-05-10 user directive
"安卓和ios 不需要 ipc / 本地 cli — 只需要 custom provider"):
- The widget glue is platform-agnostic in shape — no winit /
  glutin / EGL / desktop-only types leak in. `NativeFrameBackend`
  only borrows `NativeBackend` + `&skia_safe::Canvas`;
  `WidgetHostNative` only consumes shell-core widgets + the
  `RenderBackend` trait. Both compile on any target where
  `NativeBackend` compiles.
- Today the desktop-only cfg on `widget_host` mirrors the
  desktop-only cfg on `backend` (per spec §11 invariants 1 & 3:
  mobile widget rendering lands in Step 1f). When Step 1f ships
  real `EaglProvider` (iOS) / `AndroidEglProvider` (Android)
  impls and lifts the desktop cfg, `WidgetHostNative` follows
  automatically — no rewrite, no IPC / CLI infrastructure.
- Doc comment in `widget_host.rs` + `inspector_window.rs`
  explicitly documents this Step 1f path.
- Verified both iOS (`aarch64-apple-ios`) and Android
  (`aarch64-linux-android`) cargo check still green with
  shell-native's mobile compile guard in place.

Verification:
- `cargo build -p openpencil-shell-native --example
  inspector_window` — green (desktop)
- `cargo check -p openpencil-shell-native` — green (no
  regression on Step 1a basic_window)
- `cargo check -p openpencil-shell-native --target
  aarch64-apple-ios` — green (mobile compile guard intact)
- `cargo check -p openpencil-shell-native --target
  aarch64-linux-android` — green (mobile compile guard intact)
- `cargo check -p openpencil-shell-core --target
  wasm32-unknown-unknown` — green (shell-core stays
  wasm32-clean per spec §1.2)
- `cargo test -p openpencil-shell-core --test widgets_static` —
  21/21 (no widget changes)
- `bash tools/check-wasm-bundle.sh` — PASS (web bundle still 0
  env.* / 622 KiB gzip / 59% ceiling — no regression)
- `bash tools/check-widget-boundary.sh` — PASS
- `bash tools/check-jian-boundaries.sh` — 4/4 invariants PASS

Phase D (web DOM mirror + native accesskit_winit integration)
follows.
2026-05-10 10:11:01 +08:00
..
openpencil-app feat(openpencil-app): skeleton crate (Stage F entry placeholder) 2026-05-03 22:05:00 +08:00
openpencil-shell-core fix(shell-core): Phase C stop-hook #2 — skip dropdown keys during IME 2026-05-09 21:54:00 +08:00
openpencil-shell-native feat(shell-native): WidgetHostNative + inspector_window — cross-platform proof 2026-05-10 10:11:01 +08:00
openpencil-shell-web fix(shell-web): Phase C stop-hook — owned hidden IME target 2026-05-09 21:53:00 +08:00
pen-codegen chore(workspace): cargo-deny 0.18 activation (Phase 1 Task 1.8 Step 6) 2026-05-03 23:05:00 +08:00
pen-core chore(workspace): cargo-deny 0.18 activation (Phase 1 Task 1.8 Step 6) 2026-05-03 23:05:00 +08:00
pen-engine chore(workspace): cargo-deny 0.18 activation (Phase 1 Task 1.8 Step 6) 2026-05-03 23:05:00 +08:00
pen-figma chore(workspace): cargo-deny 0.18 activation (Phase 1 Task 1.8 Step 6) 2026-05-03 23:05:00 +08:00
pen-types feat(pen-types): skeleton crate (bucket A) 2026-05-03 22:35:00 +08:00
wasm-libc-shim feat(shell): add wasm-libc-shim crate for wasm32-unknown-unknown skia bundle 2026-05-09 21:07:00 +08:00