refactor(host): gate op-host-native GL stack behind opt-in gl-host feature
Phase 0 of the op-web-daemon extraction. op-host-native now defaults to a raster-only library: with the new NON-default gl-host feature off, it pulls no winit/glutin/jian-host-desktop/accesskit and skia-safe WITHOUT gl (no GL link directives). GUI consumers (op-host-desktop) opt in via features=[gl-host], so the future headless op-web-daemon can depend on op-host-native (default-features=false) for the raster export path without the desktop GUI stack. - Move NativeFrameBackend widget_host/ -> backend/ (raster; no longer drags the interactive host into the raster build). - Gate widget_host/preview/boolean_ops/canvas_view_stub + GlutinProvider / SharedSkiaContext behind gl-host. skia gl arrives only via skia-safe/gl; accesskit made optional. Mobile-safe: default features = no gl-host. Verified: raster + desktop + app build green; 385 lib tests pass under gl-host; cargo tree confirms the raster build is winit/glutin/skia-gl free. Codex-approved.
This commit is contained in:
parent
7b20644a23
commit
47e9e3cac6
|
|
@ -62,7 +62,7 @@ role = "Editor"
|
|||
# Phase 7.3 reorg: openpencil-shell-core dissolved — widget facade /
|
||||
# render-backend / layout scene paths resolve through op-editor-ui.
|
||||
op-editor-ui = { path = "../op-editor-ui" }
|
||||
op-host-native = { path = "../op-host-native", version = "0.8.0" }
|
||||
op-host-native = { path = "../op-host-native", version = "0.8.0", features = ["gl-host"] }
|
||||
# Accessibility (#67) — the platform-free `accesskit` core types
|
||||
# (`TreeUpdate` / `ActionRequest` / `ActivationHandler` …) used by the
|
||||
# desktop a11y adapter (`src/a11y.rs`). The OS-specific subclassing
|
||||
|
|
|
|||
|
|
@ -10,6 +10,40 @@ description = "OpenPencil native host — winit + skia-safe + accesskit backend,
|
|||
name = "op_host_native"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[features]
|
||||
# `gl-host` (NON-default) enables the desktop winit/glutin interactive runner
|
||||
# tier + skia-safe's `gl` feature + accesskit. Consumers that need the GUI host
|
||||
# (`op-host-desktop`, `op-app`) opt in via `features = ["gl-host"]`. Left OFF —
|
||||
# the default, used by `op-web-daemon` (via `default-features = false`) and by
|
||||
# the mobile `cargo check` (default features) — it yields a raster-only library:
|
||||
# no winit / glutin / jian-host-desktop / accesskit, and skia-safe WITHOUT `gl`
|
||||
# (so it emits no native GL link directives). The raster `NativeBackend` +
|
||||
# `NativeFrameBackend` + offscreen raster + text measurement remain. Mobile is
|
||||
# safe by construction: default features = no `gl-host`; the gated deps also live
|
||||
# only in the desktop-only target block.
|
||||
#
|
||||
# Why non-default (Approach Y): cargo can't alias skia-safe twice ("multiple
|
||||
# times with different names") and can't make it optional-in-one-target-block +
|
||||
# required-in-another; and a `skia-safe/gl` edge in a *default* feature would
|
||||
# flip gl on for mobile. Making `gl-host` non-default + opt-in is the only
|
||||
# cargo-valid, mobile-safe way to keep skia's `gl` out of the raster build.
|
||||
default = []
|
||||
gl-host = [
|
||||
"skia-safe/gl",
|
||||
"dep:glutin",
|
||||
"dep:winit",
|
||||
"dep:scopeguard",
|
||||
"dep:jian-host-desktop",
|
||||
"dep:accesskit",
|
||||
]
|
||||
|
||||
# The basic_window demo needs the GL host stack (SharedSkiaContext + winit);
|
||||
# `required-features` makes `cargo build --examples` skip it under
|
||||
# `--no-default-features` instead of failing on a missing `main`.
|
||||
[[example]]
|
||||
name = "basic_window"
|
||||
required-features = ["gl-host"]
|
||||
|
||||
[dependencies]
|
||||
# Phase 7.3 reorg: openpencil-shell-core dissolved — widget facade /
|
||||
# theme / layout scene / scene vars / render-backend / gesture types
|
||||
|
|
@ -20,7 +54,9 @@ op-editor-ui = { path = "../op-editor-ui" }
|
|||
# into an `accesskit::TreeUpdate` (see `widget_host/a11y.rs`) for the
|
||||
# desktop platform adapter to publish. Pinned to 0.24 to match
|
||||
# op-editor-ui + the platform adapter crates' transitive accesskit.
|
||||
accesskit = "0.24"
|
||||
# Optional + behind `gl-host` (its only user, `widget_host/a11y.rs`, is
|
||||
# gl-host-gated) so the raster-only build pulls no accesskit at all.
|
||||
accesskit = { version = "0.24", optional = true }
|
||||
|
||||
# Canvas Preview (Play) mode serializes the document to JSON before
|
||||
# building the jian runtime, so the saved doc is never mutated.
|
||||
|
|
@ -113,12 +149,11 @@ jian-skia = { path = "../../vendor/jian/crates/jian-skia", version = "0.0.1", fe
|
|||
# `compile_error!`. macOS / Windows backends auto-enable via
|
||||
# cfg(target_os) and need no feature flag.
|
||||
[target.'cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))'.dependencies]
|
||||
skia-safe = { version = "0.97.0", default-features = false, features = [
|
||||
"binary-cache",
|
||||
"textlayout",
|
||||
"gl",
|
||||
] }
|
||||
glutin = "0.32.3"
|
||||
# skia-safe's `gl` feature is added via the `gl-host` feature (`skia-safe/gl`),
|
||||
# NOT here — so with `gl-host` off the raster/mobile build links the 5-OS
|
||||
# skia-safe above WITHOUT `gl` and emits no native GL link directives. The 5-OS
|
||||
# entry is the single skia-safe edge; no desktop-only skia-safe entry is needed.
|
||||
glutin = { version = "0.32.3", optional = true }
|
||||
# `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`
|
||||
|
|
@ -127,14 +162,14 @@ glutin = "0.32.3"
|
|||
# tree. Its only use here — `GlWindow::build_surface_attributes` — is
|
||||
# replaced by a direct `glutin::surface::SurfaceAttributesBuilder`
|
||||
# call in `context/provider.rs`.
|
||||
winit = { package = "casement", path = "../../vendor/casement", default-features = false, features = [
|
||||
winit = { package = "casement", path = "../../vendor/casement", default-features = false, optional = true, features = [
|
||||
"x11",
|
||||
"wayland",
|
||||
"wayland-csd-adwaita",
|
||||
"rwh_06",
|
||||
] }
|
||||
scopeguard = "1.2"
|
||||
jian-host-desktop = { path = "../../vendor/jian/crates/jian-host-desktop", version = "0.0.1", default-features = false, features = [
|
||||
scopeguard = { version = "1.2", optional = true }
|
||||
jian-host-desktop = { path = "../../vendor/jian/crates/jian-host-desktop", version = "0.0.1", default-features = false, optional = true, features = [
|
||||
"textlayout",
|
||||
] }
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
//! Step 1c+ may wrap `NativeBackend` inside a `WithCanvas<'a>` newtype so
|
||||
//! the OP `RenderBackend` trait gets a real impl.
|
||||
|
||||
mod frame_backend;
|
||||
pub mod skia;
|
||||
|
||||
pub use frame_backend::NativeFrameBackend;
|
||||
pub use skia::{enumerate_system_font_families, to_jian_rect, NativeBackend};
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ pub use provider::{GlContextProvider, ProviderError, ProviderResult};
|
|||
pub use provider::AndroidEglProvider;
|
||||
#[cfg(target_os = "ios")]
|
||||
pub use provider::EaglProvider;
|
||||
#[cfg(feature = "gl-host")]
|
||||
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
|
||||
pub use provider::GlutinProvider;
|
||||
|
||||
|
|
@ -26,7 +27,9 @@ pub use provider::GlutinProvider;
|
|||
// (cfg-gated dependencies). Step 1f mobile wiring will introduce a mobile
|
||||
// twin (or generalize this one) once iOS / Android providers go from
|
||||
// `unimplemented!()` placeholders to real GL contexts.
|
||||
#[cfg(feature = "gl-host")]
|
||||
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
|
||||
mod shared;
|
||||
#[cfg(feature = "gl-host")]
|
||||
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
|
||||
pub use shared::{SharedSkiaContext, SharedSkiaError, SharedSkiaResult, SurfaceConfig};
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
//! exist as compile-time placeholders so the public API surface is frozen
|
||||
//! before Step 1f real implementations land.
|
||||
|
||||
#[cfg(feature = "gl-host")]
|
||||
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
|
||||
use std::error::Error;
|
||||
use std::sync::Arc;
|
||||
|
|
@ -34,6 +35,7 @@ impl ProviderError {
|
|||
/// desktop `GlutinProvider` to convert glutin / glutin-winit errors;
|
||||
/// `cfg(any(...))`-gated to silence `dead_code` on iOS / Android where
|
||||
/// no in-tree caller exists yet (Step 1f mobile providers will use it).
|
||||
#[cfg(feature = "gl-host")]
|
||||
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
|
||||
pub(crate) fn from_error<E: Error>(err: E) -> Self {
|
||||
Self::Failure(err.to_string())
|
||||
|
|
@ -118,6 +120,7 @@ pub trait GlContextProvider {
|
|||
/// All non-`Send` glutin handles live in [`Option`]s so `release` can
|
||||
/// drop them in a defined order (surface → context → display) without
|
||||
/// requiring `&mut self` to consume `self`.
|
||||
#[cfg(feature = "gl-host")]
|
||||
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
|
||||
pub struct GlutinProvider {
|
||||
/// Currently-current context. `None` after `release`.
|
||||
|
|
@ -130,6 +133,7 @@ pub struct GlutinProvider {
|
|||
glow: Arc<glow::Context>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "gl-host")]
|
||||
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
|
||||
impl GlutinProvider {
|
||||
/// Construct from an existing winit window. Builds a glutin display
|
||||
|
|
@ -236,6 +240,7 @@ impl GlutinProvider {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gl-host")]
|
||||
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
|
||||
fn window_surface_size(
|
||||
inner: winit::dpi::PhysicalSize<u32>,
|
||||
|
|
@ -251,6 +256,7 @@ fn window_surface_size(
|
|||
Ok((width, height))
|
||||
}
|
||||
|
||||
#[cfg(feature = "gl-host")]
|
||||
#[cfg(target_os = "macos")]
|
||||
fn pick_display_api(
|
||||
_raw: raw_window_handle::RawWindowHandle,
|
||||
|
|
@ -258,6 +264,7 @@ fn pick_display_api(
|
|||
glutin::display::DisplayApiPreference::Cgl
|
||||
}
|
||||
|
||||
#[cfg(feature = "gl-host")]
|
||||
#[cfg(target_os = "windows")]
|
||||
fn pick_display_api(
|
||||
raw: raw_window_handle::RawWindowHandle,
|
||||
|
|
@ -265,6 +272,7 @@ fn pick_display_api(
|
|||
glutin::display::DisplayApiPreference::WglThenEgl(Some(raw))
|
||||
}
|
||||
|
||||
#[cfg(feature = "gl-host")]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn pick_display_api(
|
||||
_raw: raw_window_handle::RawWindowHandle,
|
||||
|
|
@ -274,6 +282,7 @@ fn pick_display_api(
|
|||
glutin::display::DisplayApiPreference::Egl
|
||||
}
|
||||
|
||||
#[cfg(feature = "gl-host")]
|
||||
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
|
||||
impl GlContextProvider for GlutinProvider {
|
||||
#[tracing::instrument(skip(self))]
|
||||
|
|
@ -411,7 +420,7 @@ impl GlContextProvider for AndroidEglProvider {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(all(test, feature = "gl-host"))]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ pub mod context;
|
|||
target_os = "android"
|
||||
))]
|
||||
pub mod backend;
|
||||
#[cfg(feature = "gl-host")]
|
||||
#[cfg(any(
|
||||
target_os = "macos",
|
||||
target_os = "linux",
|
||||
|
|
@ -65,8 +66,10 @@ pub mod backend;
|
|||
target_os = "android"
|
||||
))]
|
||||
pub mod boolean_ops;
|
||||
#[cfg(feature = "gl-host")]
|
||||
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
|
||||
pub mod canvas_view_stub;
|
||||
#[cfg(feature = "gl-host")]
|
||||
#[cfg(any(
|
||||
target_os = "macos",
|
||||
target_os = "linux",
|
||||
|
|
@ -77,6 +80,7 @@ pub mod canvas_view_stub;
|
|||
pub mod widget_host;
|
||||
// Canvas Preview (Play) mode runtime owner — depends on the OP
|
||||
// `RenderBackend` trait (same gate as `widget_host`).
|
||||
#[cfg(feature = "gl-host")]
|
||||
#[cfg(any(
|
||||
target_os = "macos",
|
||||
target_os = "linux",
|
||||
|
|
@ -93,7 +97,8 @@ pub mod preview;
|
|||
target_os = "ios",
|
||||
target_os = "android"
|
||||
))]
|
||||
pub use backend::{to_jian_rect, NativeBackend};
|
||||
pub use backend::{to_jian_rect, NativeBackend, NativeFrameBackend};
|
||||
#[cfg(feature = "gl-host")]
|
||||
#[cfg(any(
|
||||
target_os = "macos",
|
||||
target_os = "linux",
|
||||
|
|
@ -102,6 +107,7 @@ pub use backend::{to_jian_rect, NativeBackend};
|
|||
target_os = "android"
|
||||
))]
|
||||
pub use preview::PreviewSession;
|
||||
#[cfg(feature = "gl-host")]
|
||||
#[cfg(any(
|
||||
target_os = "macos",
|
||||
target_os = "linux",
|
||||
|
|
@ -109,8 +115,9 @@ pub use preview::PreviewSession;
|
|||
target_os = "ios",
|
||||
target_os = "android"
|
||||
))]
|
||||
pub use widget_host::{CursorHint, NativeFrameBackend, WidgetHostNative};
|
||||
pub use widget_host::{CursorHint, WidgetHostNative};
|
||||
// canvas_view_stub stays desktop-only (uses glow GL-isolation probe).
|
||||
#[cfg(feature = "gl-host")]
|
||||
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
|
||||
pub use canvas_view_stub::CanvasViewportStub;
|
||||
|
||||
|
|
@ -118,6 +125,7 @@ pub use canvas_view_stub::CanvasViewportStub;
|
|||
pub use context::{GlContextProvider, ProviderError, ProviderResult};
|
||||
|
||||
// Desktop-only re-exports.
|
||||
#[cfg(feature = "gl-host")]
|
||||
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
|
||||
pub use context::{
|
||||
GlutinProvider, SharedSkiaContext, SharedSkiaError, SharedSkiaResult, SurfaceConfig,
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
//!
|
||||
//! This file is the public spine. Implementation methods are split
|
||||
//! across sibling submodules (per the 800-line-per-file ceiling):
|
||||
//! - [`frame_backend`] — `NativeFrameBackend` (`RenderBackend` impl)
|
||||
//! - `NativeFrameBackend` (`RenderBackend` impl) — moved to `crate::backend`
|
||||
//! - [`helpers`] — hex parsing + resize-bounds math + constants
|
||||
//! - [`geometry`] — canvas region / cursor hint / picker rect helpers
|
||||
//! - [`input`] — cursor-move / release / panel-resize input handlers
|
||||
|
|
@ -76,7 +76,6 @@ mod design_md_press_tests;
|
|||
#[cfg(test)]
|
||||
mod figma_import_tests;
|
||||
mod font_picker_dispatch;
|
||||
mod frame_backend;
|
||||
mod geometry;
|
||||
mod geometry_settings_hover;
|
||||
#[cfg(test)]
|
||||
|
|
@ -147,8 +146,6 @@ mod variables_panel_ux_tests;
|
|||
mod variables_preset_press;
|
||||
mod viewport_fit;
|
||||
|
||||
pub use frame_backend::NativeFrameBackend;
|
||||
|
||||
/// Cursor affordance the host suggests for a given screen point.
|
||||
/// The runner maps each variant to its native cursor (`CursorIcon`
|
||||
/// on desktop, CSS `cursor:` string on web).
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
//! Pulled out of `widget_host.rs` to keep the spine file under
|
||||
//! the 800-line ceiling.
|
||||
|
||||
use super::frame_backend::NativeFrameBackend;
|
||||
use super::helpers::{
|
||||
GIT_PANEL_CARET_H, GIT_PANEL_CARET_HALF, STATUS_INSET, TOOLBAR_INSET_X, TOOLBAR_INSET_Y,
|
||||
};
|
||||
use super::WidgetHostNative;
|
||||
use crate::backend::NativeFrameBackend;
|
||||
use op_editor_ui::widgets::editor_state_ext::theme_for;
|
||||
use op_editor_ui::widgets::{
|
||||
variables_panel::VariablesPanel, AIChatPlaceholder, AlignToolbar, CanvasViewport,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#![cfg(feature = "gl-host")]
|
||||
//! Shared test helpers for `op-host-native`.
|
||||
//!
|
||||
//! Spec v19 §9 / plan v7 Task 2 Step 16a-16f: this module supplies
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#![cfg(feature = "gl-host")]
|
||||
//! Spec v19 acceptance #2 (chrome + canvas-stub on the same GPU surface)
|
||||
//! / plan v7 Task 2 Step 16d / round 6 BLOCK-R6-2.
|
||||
//!
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#![cfg(feature = "gl-host")]
|
||||
//! Spec v19 §9.2 / acceptance #3 / plan v7 Task 2 Step 16f.
|
||||
//!
|
||||
//! Per-OS dispatch:
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#![cfg(feature = "gl-host")]
|
||||
//! Spec v19 §9.3 acceptance #6 / plan v7 Task 2 Step 16b:
|
||||
//! 100 iterations of `{ create + frame + present + teardown × 3 }` must
|
||||
//! not grow RSS by more than 5 % over baseline.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#![cfg(feature = "gl-host")]
|
||||
//! Pixel-level proof that Canvas Preview (Play) renders through the
|
||||
//! design-canvas scene painter — the "orange renders grey / layout
|
||||
//! scattered" bug, verified end-to-end on a real raster surface.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#![cfg(feature = "gl-host")]
|
||||
//! Spec v19 acceptance #2 (chrome region) / plan v7 Task 2 Step 16d.
|
||||
//!
|
||||
//! Round 5 BLOCK-R5-2 fix: this test covers **chrome only** on a raster
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#![cfg(feature = "gl-host")]
|
||||
//! Spec v19 acceptance #5 (resize / DPI no-flicker) / Phase A Gate
|
||||
//! round 2 CONCERN 2.
|
||||
//!
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#![cfg(feature = "gl-host")]
|
||||
//! Spec v19 §3.3 / plan v7 Task 2 Step 16a:
|
||||
//! `teardown` + lifecycle hooks must be idempotent.
|
||||
//!
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#![cfg(feature = "gl-host")]
|
||||
//! Spec v19 acceptance #8 / plan v7 Task 2 Step 16c:
|
||||
//! `tracing` spans must fire at `begin_frame / present / resize /
|
||||
//! teardown` (and the rest of the frame surface). `tracing-test`
|
||||
|
|
|
|||
Loading…
Reference in a new issue