style(shell): convert all comments to English

Open-source codebase convention: all source-code comments in English.
Translates Chinese comments across openpencil-shell-{core,native,web}
.rs and Cargo.toml files. Logic, identifiers, and string literals
unchanged; the literal CJK fixture "Hello 你好" in raster_text_smoke
stays since it exercises the textlayout CJK path.
This commit is contained in:
Kayshen-X 2026-05-05 12:23:14 +08:00
parent 3b4b7a6f36
commit b649143667
7 changed files with 130 additions and 118 deletions

View file

@ -15,14 +15,14 @@ serde = { workspace = true, optional = true }
thiserror = { workspace = true }
tracing = { workspace = true }
# v19 pivot: glam Vec2 用作 Point2D;bitflags 用于 widget facade 内部 flag。
# v19 pivot: glam Vec2 used as Point2D; bitflags used for widget facade internal flags.
glam = { version = "0.29", default-features = false, features = ["std"] }
bitflags = "2"
# v19 pivot: re-export Jian render/geometry/scene types (spec §5.2 widget-facing facade
# wraps jian-core; native-only deps live in shell-native, jian-core itself is wasm32-clean).
# 双写 path + version per spec §12.2 ("path dep with explicit version") —— 防 cargo
# 在不同 workspace context 下因 version 不一致退化到错版本。
# Both path + version per spec §12.2 ("path dep with explicit version") — guards against
# cargo silently picking a wrong version under a different workspace context.
jian-core = { path = "../../vendor/jian/crates/jian-core", version = "0.0.1" }
[features]

View file

@ -1,17 +1,17 @@
//! Jian re-export module (spec v19 §2 / §1.2).
//!
//! `openpencil-shell-core` 是 Jian 薄 wrapper —— 把
//! `jian_core::render::{DrawOp, Paint, TextRun, …}` 经 OP 层 re-export 给
//! shell-native 内部翻译用。geometry / scene 类型加 `Jian*` 前缀,避免
//! 与 OP 自有 `Rect` / `Color` (`render_backend.rs`) 冲突。
//! `openpencil-shell-core` is a thin Jian wrapper — it re-exports
//! `jian_core::render::{DrawOp, Paint, TextRun, …}` through the OP layer for
//! shell-native's internal translation. geometry / scene types get a `Jian*`
//! prefix to avoid clashing with OP's own `Rect` / `Color` (`render_backend.rs`).
//!
//! **契约(spec §5.2.1 §746 行)**:v19 wrapper 在 NativeBackend impl 内
//! **不让 widget code 直接看到 `jian_core::render::DrawOp`** —— widget 只
//! 调 OP `RenderBackend` method。这些 re-export 是给 **shell-native 内部**
//! 翻译用,不是给 widget code 用。
//! **Contract (spec §5.2.1, line 746)**: inside the NativeBackend impl, the
//! v19 wrapper **must not let widget code see `jian_core::render::DrawOp`
//! directly** — widgets only call OP `RenderBackend` methods. These re-exports
//! are for **shell-native internal** translation, not for widget code.
// ────────────────────────────────────────────────────────────────────────────
// jian_core::render —— DrawOp 命令缓冲 + Paint / TextRun / 其它绘图描述符
// jian_core::render — DrawOp command buffer + Paint / TextRun / other draw descriptors
// ────────────────────────────────────────────────────────────────────────────
pub use jian_core::render::{
@ -20,22 +20,22 @@ pub use jian_core::render::{
};
// ────────────────────────────────────────────────────────────────────────────
// jian_core::geometry —— 加 Jian* 前缀避免与 OP `Rect` 冲突
// jian_core::geometry — `Jian*` prefix to avoid clashing with OP `Rect`
// ────────────────────────────────────────────────────────────────────────────
/// Jian 的 axis-aligned 矩形 (`euclid::Rect<f32>`)。
/// OP 自有 `crate::render_backend::Rect` 是 widget facade 用;shell-native
/// 内部翻译时把 OP `Rect` → `JianRect`(`origin/size` → `euclid::Rect::new`)。
/// Jian's axis-aligned rectangle (`euclid::Rect<f32>`).
/// OP's own `crate::render_backend::Rect` is for the widget facade; shell-native
/// translates OP `Rect` → `JianRect` internally (`origin/size` → `euclid::Rect::new`).
pub type JianRect = jian_core::geometry::Rect;
pub type Size = jian_core::geometry::Size;
pub type JianPoint = jian_core::geometry::Point;
pub type Affine2 = jian_core::geometry::Affine2;
// ────────────────────────────────────────────────────────────────────────────
// jian_core::scene —— Color (packed u32) 加 Jian* 前缀
// jian_core::scene — Color (packed u32) gets a `Jian*` prefix
// ────────────────────────────────────────────────────────────────────────────
/// Jian 的 packed-RGBA 颜色 (`pub struct Color(pub u32)`);与 OP
/// `crate::render_backend::Color` (RGBA f32 quad) 不同。NativeBackend 内部
/// 翻译 OP Color → JianColor 时用位打包。
/// Jian's packed-RGBA color (`pub struct Color(pub u32)`); distinct from OP's
/// `crate::render_backend::Color` (RGBA f32 quad). NativeBackend bit-packs when
/// translating OP Color → JianColor.
pub type JianColor = jian_core::scene::Color;

View file

@ -5,14 +5,14 @@
//! `openpencil-shell-native`; wasm-bindgen / web-sys / CanvasKit live in
//! `openpencil-shell-web`.
//!
//! v19 pivot — 该 crate 是 Jian 薄 wrapper:
//! - [`jian`] 模块 re-export `jian_core::render::{DrawOp, Paint, TextRun, …}`
//! + geometry/scene aliases,给 shell-native 内部翻译用(widget code 看不到)。
//! - [`render_backend`] 模块定义 OP 自有 widget-facing facade
//! (`RenderBackend` trait + `Rect` / `Color` / `TextLayout`,spec §5.2)。
//! v19 pivot — this crate is a thin Jian wrapper:
//! - the [`jian`] module re-exports `jian_core::render::{DrawOp, Paint, TextRun, …}`
//! + geometry/scene aliases for shell-native's internal translation (widget code never sees them).
//! - the [`render_backend`] module defines OP's own widget-facing facade
//! (`RenderBackend` trait + `Rect` / `Color` / `TextLayout`, spec §5.2).
pub mod jian;
pub mod render_backend;
// Re-export 主要 API 给上层 crate / widgets / tests 用。
// Re-export the primary API for upstream crates / widgets / tests.
pub use render_backend::{Color, Point2D, Rect, RenderBackend, TextLayout};

View file

@ -1,39 +1,42 @@
//! OP `RenderBackend` widget-facing facade (spec v19 §5.2).
//!
//! 这是 OP 的设计契约(method-style API:`fill_rect / stroke_rect / draw_text /
//! clip_rect / save / restore / translate / resize / dpi_scale`),与 Jian
//! `jian_core::render::RenderBackend`(command-buffer style,`new_surface /
//! begin_frame / draw(&DrawOp)` etc.)不直接重合。
//! This is OP's design contract (method-style API: `fill_rect / stroke_rect /
//! draw_text / clip_rect / save / restore / translate / resize / dpi_scale`),
//! which does not line up directly with Jian's
//! `jian_core::render::RenderBackend` (command-buffer style: `new_surface /
//! begin_frame / draw(&DrawOp)` etc.).
//!
//! 实现路径 (per §5.2.1):
//! - `NativeBackend` (shell-native, Step 1a 起 frame-scoped 设计):**不**直接
//! impl 该 trait,而是 expose 同名 method 但带 `canvas: &skia_safe::Canvas`
//! 显式参数。Step 1a basic_window demo 通过 `SharedSkiaContext::with_frame`
//! 闭包内调 NativeBackend method。Step 1c+ 真接入 widget tree 时再考虑用
//! `WithCanvas<'a>` newtype 把 canvas 注入 trait impl。
//! - `WebCanvasKitBackend` (shell-web, Step 1b):内部用 CanvasKit JS binding。
//! - `MobileBackend` (Step 1f):内部用 Metal / Vulkan / OpenGL ES。
//! Implementation paths (per §5.2.1):
//! - `NativeBackend` (shell-native, frame-scoped design from Step 1a onward)
//! does **not** impl this trait directly; instead it exposes same-named
//! methods that take an explicit `canvas: &skia_safe::Canvas` argument.
//! The Step 1a basic_window demo invokes NativeBackend methods inside a
//! `SharedSkiaContext::with_frame` closure. Once Step 1c+ wires in a real
//! widget tree we can revisit a `WithCanvas<'a>` newtype to inject the
//! canvas into a trait impl.
//! - `WebCanvasKitBackend` (shell-web, Step 1b): backed by CanvasKit JS bindings.
//! - `MobileBackend` (Step 1f): backed by Metal / Vulkan / OpenGL ES.
//!
//! 该模块**不**引 skia-safe / Canvas / GL 类型 —— shell-core 必须 wasm32-clean
//! (per spec §1.2 boundary)。
//! This module does **not** pull in skia-safe / Canvas / GL types — shell-core
//! must stay wasm32-clean (per spec §1.2 boundary).
use jian_core::render::{TextAlign, TextRun};
/// 2D 坐标点(spec §5.2 钉死 `glam::Vec2`)。
/// 2D coordinate point (spec §5.2 fixes this to `glam::Vec2`).
pub type Point2D = glam::Vec2;
/// 矩形(origin + size 双 Vec2 表示)。
/// Rectangle (origin + size as two Vec2s).
#[derive(Debug, Clone, Copy)]
pub struct Rect {
pub origin: Point2D,
pub size: Point2D,
}
/// RGBA color(widget facade 层;所有分量 0.0..=1.0)。
/// RGBA color (widget facade layer; all components 0.0..=1.0).
///
/// 命名常量定义在 OP 这层(spec v19 round 5 CONCERN-R5-3 fix);
/// `jian_core::scene::Color` 是 `Color(pub u32)` packed RGBA,没有
/// RED/BLACK/etc 命名常量,调用方用 `JianColor::rgb(...)` 显式构造。
/// Named constants live at the OP layer (spec v19 round 5 CONCERN-R5-3 fix);
/// `jian_core::scene::Color` is `Color(pub u32)` packed RGBA without RED/BLACK/etc
/// named constants — callers must construct it explicitly via `JianColor::rgb(...)`.
#[derive(Debug, Clone, Copy)]
pub struct Color {
pub r: f32,
@ -81,32 +84,34 @@ impl Color {
};
}
/// OP 的 TextLayout —— v19 删 parley 后定义在 OP 这层;薄薄包装
/// `jian_core::render::TextRun`。
/// OP's TextLayout — defined at the OP layer after v19 removed parley; a thin
/// wrapper over `jian_core::render::TextRun`.
///
/// 不持 layout context / glyph cache(shell-core wasm32-clean,不能引
/// skia/parley/icu);真 layout 在 NativeBackend::draw_text 时通过
/// `jian_skia::SkiaBackend` 的 textlayout feature(skia textlayout,
/// ICU+harfbuzz)做 shape + line break。
/// It does not hold a layout context or glyph cache (shell-core is wasm32-clean
/// and cannot pull in skia/parley/icu); the real layout happens inside
/// NativeBackend::draw_text via `jian_skia::SkiaBackend`'s textlayout feature
/// (skia textlayout, ICU+harfbuzz) for shaping + line breaking.
///
/// Step 1a TextLayout 仅作 "已 shape 的 TextRun 集合" 占位;
/// caret/selection/bidi/wrap 推 Step 1c+。signatures 钉死,避免后续 Step
/// API break。
/// In Step 1a, TextLayout is a placeholder for "a collection of already-shaped
/// TextRuns"; caret/selection/bidi/wrap are deferred to Step 1c+. The
/// signatures are pinned to avoid breaking the API in later steps.
#[derive(Debug, Clone)]
pub struct TextLayout {
runs: Vec<TextRun>,
}
impl TextLayout {
/// 单 run 构造(Step 1a 唯一活跃路径;Phase B/C demo + raster_text_smoke 用)。
/// Single-run constructor (the only active path in Step 1a; used by the
/// Phase B/C demo + raster_text_smoke).
///
/// 字段对齐 `jian_core::render::TextRun` (`vendor/jian/crates/jian-core/src/render/paint.rs:77-94`):
/// **TextRun 没有 `Default` impl**,必须显式构造所有字段。
/// - `content` / `font_family` / `font_size` / `color` / `origin`:调用方传入
/// Fields align with `jian_core::render::TextRun`
/// (`vendor/jian/crates/jian-core/src/render/paint.rs:77-94`):
/// **TextRun has no `Default` impl**, so every field must be set explicitly.
/// - `content` / `font_family` / `font_size` / `color` / `origin`: passed in by caller
/// - `font_weight: 400` (CSS Normal)
/// - `max_width: 0.0`("unknown; render at origin with no alignment adjustment")
/// - `max_width: 0.0` ("unknown; render at origin with no alignment adjustment")
/// - `align: TextAlign::Start`
/// - `line_height: 0.0`("default")
/// - `line_height: 0.0` ("default")
pub fn single_run(
content: &str,
font_family: &str,
@ -128,13 +133,13 @@ impl TextLayout {
Self { runs: vec![run] }
}
/// 已 shape 的 TextRun 集合视图。
/// View of the already-shaped TextRun collection.
pub fn runs(&self) -> &[TextRun] {
&self.runs
}
/// 平移所有 run 的 origin(NativeBackend::draw_text 在 widget origin
/// 基础上做平移)。返回新 layout,原 layout 不动。
/// Translates every run's origin (NativeBackend::draw_text adds this on top
/// of the widget origin). Returns a new layout; the original is unchanged.
pub fn translated(&self, offset: Point2D) -> Self {
let runs = self
.runs
@ -150,32 +155,35 @@ impl TextLayout {
}
}
/// Backend 抽象(widget-facing facade,spec §5.2)。
/// Backend abstraction (widget-facing facade, spec §5.2).
///
/// 注:trait 不加 `Send` bound —— skia-safe 类型 `!Send`(rust-skia
/// thread-bound),Backend 在 render thread 内单独使用,无跨线程需求。
/// Note: the trait has no `Send` bound — skia-safe types are `!Send`
/// (rust-skia is thread-bound), and the Backend is used solely on the render
/// thread, so cross-thread access is unnecessary.
///
/// `NativeBackend` (shell-native) 在 1a **不**直接 impl 该 trait(v19 round 3
/// BLOCK-R3-3 fix —— frame-scoped 设计避免跨帧 borrow),而是 expose 同名
/// method 但带 `canvas: &skia_safe::Canvas` 显式参数。trait 签名内不出现任何
/// Skia / GPU-backend 特定类型。
/// In 1a, `NativeBackend` (shell-native) does **not** impl this trait directly
/// (v19 round 3 BLOCK-R3-3 fix — the frame-scoped design avoids cross-frame
/// borrows); instead it exposes the same-named methods with an explicit
/// `canvas: &skia_safe::Canvas` argument. The trait signature contains no
/// Skia / GPU-backend-specific types.
pub trait RenderBackend {
/// Begin 帧,backend 内部维护 current frame state(不暴露 canvas 类型)。
/// Begin a frame; the backend tracks current frame state internally
/// (canvas type is not exposed).
fn begin_frame(&mut self);
fn end_frame(&mut self);
// 绘图 primitives —— widgets 调这些,不直接操作 canvas。
// Drawing primitives — widgets call these and never touch the canvas directly.
fn fill_rect(&mut self, rect: Rect, color: Color);
fn stroke_rect(&mut self, rect: Rect, color: Color, width: f32);
fn draw_text(&mut self, layout: &TextLayout, origin: Point2D);
fn clip_rect(&mut self, rect: Rect);
// 变换栈。
// Transform stack.
fn save(&mut self);
fn restore(&mut self);
fn translate(&mut self, offset: Point2D);
// viewport / dpi。
// Viewport / DPI.
fn resize(&mut self, width: u32, height: u32);
fn dpi_scale(&self) -> f32;
}

View file

@ -1,18 +1,18 @@
//! Task 1 Step 20-21: prove the Jian re-export wrapper compiles & is usable.
//!
//! Two anchor invariants for spec v19 §2 / §5.2:
//! 1. `DrawOp::Rect` constructible **through OP re-export path**
//! (`openpencil_shell_core::jian::DrawOp` —— shell-native 内部翻译用)。
//! 2. `TextLayout::single_run` 产生**恰好一个** `TextRun`(spec §5.2,
//! 确认 `..Default::default()` 替代成显式字段后语义等价)。
//! Two anchor invariants for spec v19 §2 / §5.2:
//! 1. `DrawOp::Rect` constructible **through the OP re-export path**
//! (`openpencil_shell_core::jian::DrawOp` — used by shell-native's internal translation).
//! 2. `TextLayout::single_run` produces **exactly one** `TextRun` (spec §5.2,
//! confirming the explicit-field replacement for `..Default::default()` is semantically equivalent).
use openpencil_shell_core::jian::{DrawOp, JianRect, Paint};
use openpencil_shell_core::render_backend::{Color, Point2D, TextLayout};
#[test]
fn drawop_rect_constructible_via_re_export() {
// 通过 OP re-export 路径构造 Jian DrawOp::Rect —— 证明 shell-core 的
// jian 模块把 jian_core::render::{DrawOp, Paint} 暴露出来了。
// Construct a Jian DrawOp::Rect via the OP re-export path — proves shell-core's
// jian module exposes jian_core::render::{DrawOp, Paint}.
let rect = JianRect::new(
jian_core::geometry::Point::new(0.0, 0.0),
jian_core::geometry::Size::new(100.0, 50.0),
@ -31,9 +31,9 @@ fn drawop_rect_constructible_via_re_export() {
#[test]
fn text_layout_single_run_creates_one_run() {
// 显式字段构造(TextRun 没 Default impl)—— 证明 spec §5.2 的
// single_run 路径产生恰好一个 run,content/font_family/font_size
// 都按调用方传入设置。
// Explicit-field construction (TextRun has no Default impl) — proves the
// spec §5.2 single_run path produces exactly one run with content /
// font_family / font_size set from the caller's arguments.
let layout = TextLayout::single_run(
"Hello",
"system-ui",
@ -57,7 +57,7 @@ fn text_layout_single_run_creates_one_run() {
#[test]
fn text_layout_translated_offsets_origin() {
// translated() 把 offset 加到每 run origin 上;原 layout 不变。
// translated() adds offset to each run's origin; the original layout is unchanged.
let layout = TextLayout::single_run(
"World",
"system-ui",
@ -70,14 +70,14 @@ fn text_layout_translated_offsets_origin() {
assert_eq!(shifted.runs()[0].origin.x, 105.0);
assert_eq!(shifted.runs()[0].origin.y, 210.0);
// 原 layout 不动
// Original layout untouched.
assert_eq!(layout.runs()[0].origin.x, 5.0);
assert_eq!(layout.runs()[0].origin.y, 10.0);
}
#[test]
fn op_color_constants_distinct() {
// spec §5.2 命名常量 6 全 —— RED/GREEN/BLUE/BLACK/WHITE/TRANSPARENT。
// spec §5.2 names all six constants — RED/GREEN/BLUE/BLACK/WHITE/TRANSPARENT.
assert_eq!(Color::RED.r, 1.0);
assert_eq!(Color::GREEN.g, 1.0);
assert_eq!(Color::BLUE.b, 1.0);

View file

@ -13,23 +13,25 @@ path = "src/lib.rs"
[dependencies]
openpencil-shell-core = { path = "../openpencil-shell-core", version = "0.1.0" }
# Native-only deps cfg-gated 在 wasm32 之外。这一步关键(解 codex round 2 B1 BLOCK):
# 如果不 cfg-gate,cargo 会先 fetch + run skia-safe 的 build.rs(在 wasm32 上构建失败),
# Step 5 grep `must NOT be compiled for wasm32` 永远命中不到——会被 skia 错误盖过。
# 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.
#
# v19 pivot (Task 1): 加 P0-pinned GL stack + jian-skia + jian-host-desktop。
# - P0 dep-stack pin 来自 P0 probe(plan v7 §Task P0;skia-safe 0.97 + glow 0.17 +
# 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 +
# glutin 0.32.3 + glutin-winit 0.5.0 + winit 0.30.13 + raw-window-handle 0.6.2 +
# scopeguard 1.2 全在 macOS/Windows/Linux GO)。
# - jian-skia (textlayout feature) 提供 SkiaBackend impl + skia textlayout(替代 parley)。
# - jian-host-desktop (target-gate desktop only, 不含 `run` feature) 复用 PointerTranslator /
# scene::collect_draws_with_state / DesktopHost config helpers;OP 自管 GPU event loop,
# 不调 jian_host_desktop::run(softbuffer raster present 不需要)。
# 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).
#
# winit features 说明:on Linux 必须显式开 `x11` 和/或 `wayland`,否则
# `platform_impl/mod.rs` 触发 `compile_error!`. macOS / Windows 各自的 backend 通过
# cfg(target_os) 默认启用,不需要 feature flag。Step 1a 三大桌面 OS CI 都跑,
# 所以同时打开 x11 + wayland 两个 Linux backend 就够。
# 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. Step 1a runs CI on all
# three desktop OSes, so enabling both x11 + wayland Linux backends is sufficient.
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
skia-safe = { version = "0.97.0", features = ["gl"] }
glutin = "0.32.3"
@ -39,21 +41,22 @@ winit = { version = "0.30.13", default-features = false, features = ["x11", "way
raw-window-handle = "0.6.2"
scopeguard = "1.2"
# Jian path deps —— 双写 path + version per spec §12.2。
# - jian-core: 暴露 DrawOp / Paint / TextRun / geometry / scene::Color。`shell-core`
# 也引 jian-core;shell-native 直接用是为了在 NativeBackend 翻译路径里直接构造
# `jian_core::render::DrawOp::*`(避免每帧经 shell-core re-export bounce)。
# - jian-skia: 提供 SkiaBackend (RenderBackend impl) + skia textlayout (textlayout
# feature 需要 ICU + harfbuzz, ~15MB;P0.5 已升 skia-safe 0.78→0.97 + 新增 pub
# draw_on_canvas).
# Jian path deps — both path + version per spec §12.2.
# - jian-core: exposes DrawOp / Paint / TextRun / geometry / scene::Color. `shell-core`
# also pulls jian-core; shell-native uses it directly so the NativeBackend translation
# path can construct `jian_core::render::DrawOp::*` without bouncing through the
# shell-core re-export each frame.
# - jian-skia: provides SkiaBackend (RenderBackend impl) + skia textlayout (the textlayout
# feature pulls ICU + harfbuzz, ~15MB; P0.5 already bumped skia-safe 0.78→0.97 and
# added a public draw_on_canvas).
jian-core = { path = "../../vendor/jian/crates/jian-core", version = "0.0.1" }
jian-skia = { path = "../../vendor/jian/crates/jian-skia", version = "0.0.1", features = ["textlayout"] }
# jian-host-desktop: target-gate desktop only (Linux/macOS/Windows);不进 android/ios
# metadata(Task 1 Step 26 boundary check 验证)。
# - default-features = false:Jian 默认 features 含 `run = ["dep:softbuffer"]` 拉
# raster present;OP 自管 GPU event loop 不需要 softbuffer。
# - features = ["textlayout"]:与 jian-skia 对齐文本路径。
# jian-host-desktop: target-gated desktop only (Linux/macOS/Windows); not pulled into
# android/ios metadata (verified by Task 1 Step 26 boundary check).
# - default-features = false: Jian's default features include `run = ["dep:softbuffer"]`
# for raster present; OP runs its own GPU event loop and doesn't need softbuffer.
# - features = ["textlayout"]: aligns the text path with jian-skia.
[target.'cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))'.dependencies]
jian-host-desktop = { path = "../../vendor/jian/crates/jian-host-desktop", version = "0.0.1", default-features = false, features = ["textlayout"] }

View file

@ -5,15 +5,16 @@
//! openpencil-shell-web --no-default-features --features web` to pass on
//! every PR.
//!
//! Step 1a Task 1 状态:仅 link-check shell-core re-export;CanvasKit
//! WebBackend 在 Step 1b 加。
//! Step 1a Task 1 status: only link-checks the shell-core re-export; the
//! CanvasKit WebBackend lands in Step 1b.
use wasm_bindgen::prelude::*;
/// Skeleton placeholder until Step 1b lands `WebCanvasKitBackend`.
///
/// 用 OP `Color::TRANSPARENT` 命名常量证明 shell-core re-export 在 wasm32
/// 链通了;这是最小 link-check(shell-core 必须 wasm32-clean per spec §1.2)。
/// Uses the OP `Color::TRANSPARENT` named constant to prove the shell-core
/// re-export links on wasm32 — this is the minimal link-check (shell-core
/// must stay wasm32-clean per spec §1.2).
#[wasm_bindgen]
pub fn placeholder() -> String {
let _t = openpencil_shell_core::Color::TRANSPARENT;