Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions docs/validation/native-desktop-environment-814.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Native desktop environment ingress (#814)

`webscene_engine_set_desktop_environment_v1` is the product-neutral host ABI
for desktop appearance, display, power, and session state. The 64-byte v1 value
is copied during the call. Unknown versions, flags, invalid DPI/scale values,
and non-zero reserved data are rejected. Equal snapshots do not wake the
worker.

Appearance updates reuse the existing targeted media-query recascade and live
`matchMedia` delivery. System color values are read from the same worker-local
environment during CSS and scene work. Display, suspend/resume, availability,
lock/unlock, and session-ending changes are reduced to the newest snapshot and
dispatched from the JavaScript worker. No timer, polling thread, document scan,
or idle animation frame is introduced.

## Authored gates

- C and managed ABI size/version/source layout contracts.
- Malformed and future-version rejection.
- 10,000 duplicate notifications produce no additional worker wake.
- Dark/light, forced-colors, prefers-contrast, live `matchMedia`, and system
color behavior.
- Suspend/resume, display availability/topology/DPI, lock/unlock, and
session-ending transition ordering and navigation cleanup.
- Cascade/layout/scene counters prove paint-only state avoids layout and
unrelated selector work.
- Idle CPU/frame/wake, notification latency, and RSS plateau measurements.
- Unchanged Code OSS visual and lifecycle comparisons.

Execution is intentionally deferred under the current fast-integration
direction; this document records the required qualification lane.
8 changes: 8 additions & 0 deletions experiments/WebScene.NativeEngine.Probe/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ include(CTest)
include(FetchContent)

if(BUILD_TESTING)
add_executable(webscene_desktop_environment_header_tests
tests/desktop_environment_header_tests.c)
target_compile_features(webscene_desktop_environment_header_tests PRIVATE c_std_11)
target_include_directories(webscene_desktop_environment_header_tests PRIVATE native)
add_test(NAME webscene_desktop_environment_header_tests
COMMAND webscene_desktop_environment_header_tests)
set_tests_properties(webscene_desktop_environment_header_tests PROPERTIES
LABELS "native;desktop-environment;abi;c11;performance" TIMEOUT 10)
add_executable(webscene_pointer_input_metadata_tests
tests/pointer_input_metadata_tests.cpp)
target_compile_features(webscene_pointer_input_metadata_tests PRIVATE cxx_std_20)
Expand Down
4 changes: 4 additions & 0 deletions experiments/WebScene.NativeEngine.Probe/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ stable `fillStyle`, composite mode, or shadow state.
component-owned iframe, script, and stylesheet resources.
- `webscene_engine_set_preferred_color_scheme` provides the host's effective
light/dark preference for CSS media queries and `Window.matchMedia`.
- `webscene_engine_set_desktop_environment_v1` copies a fixed 64-byte native
appearance/display/session snapshot, coalesces equal values, refreshes only
affected media/CSS state, and dispatches bounded lifecycle transitions from
the worker. It adds no host poller or idle animation frame.
- `webscene_engine_execute_script` is the fire-and-forget execution boundary.
- `webscene_engine_begin_evaluate_v3` and
`webscene_engine_begin_invoke_v3` are the leased tagged-result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ struct accessibility_preferences final {
bool forced_colors{false};
bool reduced_motion{false};
bool contrast_more{false};
bool native_system_colors{false};
uint32_t accent_rgba{0x0067c0ffU};
uint32_t accent_text_rgba{0xffffffffU};
uint32_t canvas_rgba{0xffffffffU};
uint32_t canvas_text_rgba{0x000000ffU};
uint32_t highlight_rgba{0x0067c0ffU};
uint32_t highlight_text_rgba{0xffffffffU};
};

inline thread_local accessibility_preferences active_accessibility_preferences{};
Expand All @@ -39,8 +46,10 @@ inline std::optional<uint32_t> system_color_rgba(std::string_view input)
const auto dark = preferences.dark;
const auto forced = preferences.forced_colors;

if (name == "canvas") return dark ? 0x1e1e1effU : 0xffffffffU;
if (name == "canvastext") return dark ? 0xffffffffU : 0x000000ffU;
if (name == "canvas") return preferences.native_system_colors
? preferences.canvas_rgba : (dark ? 0x1e1e1effU : 0xffffffffU);
if (name == "canvastext") return preferences.native_system_colors
? preferences.canvas_text_rgba : (dark ? 0xffffffffU : 0x000000ffU);
if (name == "buttonface" || name == "field") {
return forced ? (dark ? 0x000000ffU : 0xffffffffU)
: (dark ? 0x333333ffU : 0xefefefffU);
Expand All @@ -49,11 +58,15 @@ inline std::optional<uint32_t> system_color_rgba(std::string_view input)
return dark ? 0xffffffffU : 0x000000ffU;
}
if (name == "graytext") return dark ? 0xaaaaaaffU : 0x6d6d6dffU;
if (name == "highlight" || name == "selecteditem" || name == "accentcolor") {
return dark ? 0x6aa9ffffU : 0x0067c0ffU;
}
if (name == "highlight" || name == "selecteditem") return preferences.native_system_colors
? preferences.highlight_rgba : (dark ? 0x6aa9ffffU : 0x0067c0ffU);
if (name == "accentcolor") return preferences.native_system_colors
? preferences.accent_rgba : (dark ? 0x6aa9ffffU : 0x0067c0ffU);
if (name == "highlighttext" || name == "selecteditemtext"
|| name == "accentcolortext") return 0xffffffffU;
) return preferences.native_system_colors
? preferences.highlight_text_rgba : 0xffffffffU;
if (name == "accentcolortext") return preferences.native_system_colors
? preferences.accent_text_rgba : 0xffffffffU;
if (name == "linktext") return dark ? 0x8ab4f8ffU : 0x0000eeffU;
if (name == "visitedtext") return dark ? 0xc58af9ffU : 0x551a8bffU;
if (name == "activetext") return 0xff0000ffU;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ static_assert(sizeof(webscene_interop_pool_metrics_v3) == 200);
static_assert(sizeof(webscene_runtime_work_metrics) == 168);
static_assert(sizeof(webscene_document_script) == 40);
static_assert(sizeof(webscene_navigation_options) == 16);
static_assert(sizeof(webscene_desktop_environment_v1) == 64);

struct queued_input_event : webscene_input_event {
uint64_t observed_compositor_timestamp = 0;
Expand Down Expand Up @@ -1273,6 +1274,23 @@ struct webscene_engine final {
std::atomic<uint32_t> accessibility_preference_flags_{
WEBSCENE_ACCESSIBILITY_PREFERENCE_NONE_V1};
std::atomic<bool> accessibility_preferences_changed_{false};
mutable std::mutex desktop_environment_mutex_;
webscene_desktop_environment_v1 desktop_environment_{
sizeof(webscene_desktop_environment_v1),
WEBSCENE_DESKTOP_ENVIRONMENT_VERSION_1,
WEBSCENE_DESKTOP_ENVIRONMENT_DISPLAY_AVAILABLE_V1,
WEBSCENE_PREFERRED_COLOR_SCHEME_LIGHT,
96U, 96U, 1000U, 0U, 0U,
0x0067c0ffU, 0xffffffffU, 0xffffffffU,
0x000000ffU, 0x0067c0ffU, 0xffffffffU};
std::atomic<bool> desktop_environment_changed_{false};
std::atomic<bool> desktop_environment_published_{false};
std::atomic<uint32_t> desktop_accent_rgba_{0x0067c0ffU};
std::atomic<uint32_t> desktop_accent_text_rgba_{0xffffffffU};
std::atomic<uint32_t> desktop_canvas_rgba_{0xffffffffU};
std::atomic<uint32_t> desktop_canvas_text_rgba_{0x000000ffU};
std::atomic<uint32_t> desktop_highlight_rgba_{0x0067c0ffU};
std::atomic<uint32_t> desktop_highlight_text_rgba_{0xffffffffU};
std::atomic<uint8_t> host_animation_frame_requested_{0U};
std::atomic<uint64_t> observed_host_timestamp_microseconds_{0U};
std::atomic<uint64_t> observed_compositor_timestamp_microseconds_{0U};
Expand Down Expand Up @@ -2576,6 +2594,18 @@ uint8_t webscene_engine_set_accessibility_preferences_v1(
: 0U;
}

uint8_t webscene_engine_set_desktop_environment_v1(
webscene_engine* engine,
const webscene_desktop_environment_v1* environment)
{
if (engine == nullptr || environment == nullptr) return 0U;
try {
return engine->set_desktop_environment(*environment) ? 1U : 0U;
} catch (...) {
return 0U;
}
}

namespace {
struct semantic_snapshot_lease_v1 final {
std::shared_ptr<const webscene_native::semantic_snapshot_data_v1> value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,43 @@ typedef enum webscene_accessibility_preference_flags_v1 {
WEBSCENE_ACCESSIBILITY_PREFERENCE_MORE_CONTRAST_V1 = 1U << 2U
} webscene_accessibility_preference_flags_v1;

#define WEBSCENE_DESKTOP_ENVIRONMENT_VERSION_1 1U

/*
* Immutable host-owned desktop state copied synchronously by
* webscene_engine_set_desktop_environment_v1. Colors are packed RGBA8. A host
* publishes a complete snapshot; omitted transitions are represented by
* clearing their flag. display_generation changes when the display topology
* changes, while dpi values describe the display containing the surface.
*/
typedef enum webscene_desktop_environment_flags_v1 {
WEBSCENE_DESKTOP_ENVIRONMENT_NONE_V1 = 0,
WEBSCENE_DESKTOP_ENVIRONMENT_FORCED_COLORS_V1 = 1U << 0U,
WEBSCENE_DESKTOP_ENVIRONMENT_HIGH_CONTRAST_V1 = 1U << 1U,
WEBSCENE_DESKTOP_ENVIRONMENT_SUSPENDED_V1 = 1U << 2U,
WEBSCENE_DESKTOP_ENVIRONMENT_DISPLAY_AVAILABLE_V1 = 1U << 3U,
WEBSCENE_DESKTOP_ENVIRONMENT_SESSION_LOCKED_V1 = 1U << 4U,
WEBSCENE_DESKTOP_ENVIRONMENT_SESSION_ENDING_V1 = 1U << 5U
} webscene_desktop_environment_flags_v1;

typedef struct webscene_desktop_environment_v1 {
uint32_t struct_size;
uint32_t version;
uint32_t flags;
uint32_t preferred_color_scheme;
uint32_t dpi_x;
uint32_t dpi_y;
uint32_t scale_milli;
uint32_t reserved0;
uint64_t display_generation;
uint32_t accent_rgba;
uint32_t accent_text_rgba;
uint32_t canvas_rgba;
uint32_t canvas_text_rgba;
uint32_t highlight_rgba;
uint32_t highlight_text_rgba;
} webscene_desktop_environment_v1;

/*
* Immutable, host-readable accessibility projection. Strings are UTF-8
* slices into semantic_snapshot_view.string_bytes. Node and relationship
Expand Down Expand Up @@ -2107,6 +2144,15 @@ WEBSCENE_API uint8_t webscene_engine_set_preferred_color_scheme(
WEBSCENE_API uint8_t webscene_engine_set_accessibility_preferences_v1(
webscene_engine* engine,
uint32_t preference_flags);
/*
* Publishes one complete desktop environment snapshot. The call rejects
* unknown flags, malformed dimensions, non-zero reserved data, and unsupported
* versions; it never retains host memory. Equal snapshots are coalesced and do
* not wake the worker.
*/
WEBSCENE_API uint8_t webscene_engine_set_desktop_environment_v1(
webscene_engine* engine,
const webscene_desktop_environment_v1* environment);
/*
* Requests an updated semantic publication and acquires the latest completed
* immutable snapshot. The first call may return null while the engine worker
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,80 @@
return true;
}

bool set_desktop_environment(
const webscene_desktop_environment_v1& environment)
{
constexpr auto supported_flags =
WEBSCENE_DESKTOP_ENVIRONMENT_FORCED_COLORS_V1
| WEBSCENE_DESKTOP_ENVIRONMENT_HIGH_CONTRAST_V1
| WEBSCENE_DESKTOP_ENVIRONMENT_SUSPENDED_V1
| WEBSCENE_DESKTOP_ENVIRONMENT_DISPLAY_AVAILABLE_V1
| WEBSCENE_DESKTOP_ENVIRONMENT_SESSION_LOCKED_V1
| WEBSCENE_DESKTOP_ENVIRONMENT_SESSION_ENDING_V1;
if (environment.struct_size != sizeof(webscene_desktop_environment_v1)
|| environment.version != WEBSCENE_DESKTOP_ENVIRONMENT_VERSION_1
|| (environment.flags & ~supported_flags) != 0U
|| environment.reserved0 != 0U
|| (environment.preferred_color_scheme
!= WEBSCENE_PREFERRED_COLOR_SCHEME_LIGHT
&& environment.preferred_color_scheme
!= WEBSCENE_PREFERRED_COLOR_SCHEME_DARK)
|| environment.dpi_x == 0U || environment.dpi_x > 10000U
|| environment.dpi_y == 0U || environment.dpi_y > 10000U
|| environment.scale_milli < 100U
|| environment.scale_milli > 10000U) {
return false;
}

{
std::lock_guard lock(desktop_environment_mutex_);
if (std::memcmp(
&desktop_environment_, &environment,
sizeof(webscene_desktop_environment_v1)) == 0) {
return true;
}
desktop_environment_ = environment;
}

preferred_color_scheme_.store(
environment.preferred_color_scheme, std::memory_order_release);
auto accessibility = accessibility_preference_flags_.load(
std::memory_order_acquire);
accessibility &= ~(
WEBSCENE_ACCESSIBILITY_PREFERENCE_FORCED_COLORS_V1
| WEBSCENE_ACCESSIBILITY_PREFERENCE_MORE_CONTRAST_V1);
if ((environment.flags
& WEBSCENE_DESKTOP_ENVIRONMENT_FORCED_COLORS_V1) != 0U) {
accessibility |= WEBSCENE_ACCESSIBILITY_PREFERENCE_FORCED_COLORS_V1;
}
if ((environment.flags
& WEBSCENE_DESKTOP_ENVIRONMENT_HIGH_CONTRAST_V1) != 0U) {
accessibility |= WEBSCENE_ACCESSIBILITY_PREFERENCE_MORE_CONTRAST_V1;
}
accessibility_preference_flags_.store(
accessibility, std::memory_order_release);
desktop_accent_rgba_.store(environment.accent_rgba, std::memory_order_release);
desktop_accent_text_rgba_.store(
environment.accent_text_rgba, std::memory_order_release);
desktop_canvas_rgba_.store(environment.canvas_rgba, std::memory_order_release);
desktop_canvas_text_rgba_.store(
environment.canvas_text_rgba, std::memory_order_release);
desktop_highlight_rgba_.store(
environment.highlight_rgba, std::memory_order_release);
desktop_highlight_text_rgba_.store(
environment.highlight_text_rgba, std::memory_order_release);
desktop_environment_published_.store(true, std::memory_order_release);
desktop_environment_changed_.store(true, std::memory_order_release);
signal_worker();
return true;
}

webscene_desktop_environment_v1 desktop_environment() const
{
std::lock_guard lock(desktop_environment_mutex_);
return desktop_environment_;
}

uint32_t cursor() const noexcept
{
return current_cursor_.load(std::memory_order_acquire);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,14 @@
scheme == WEBSCENE_PREFERRED_COLOR_SCHEME_DARK,
(accessibility & WEBSCENE_ACCESSIBILITY_PREFERENCE_FORCED_COLORS_V1) != 0U,
(accessibility & WEBSCENE_ACCESSIBILITY_PREFERENCE_REDUCED_MOTION_V1) != 0U,
(accessibility & WEBSCENE_ACCESSIBILITY_PREFERENCE_MORE_CONTRAST_V1) != 0U});
(accessibility & WEBSCENE_ACCESSIBILITY_PREFERENCE_MORE_CONTRAST_V1) != 0U,
desktop_environment_published_.load(std::memory_order_acquire),
desktop_accent_rgba_.load(std::memory_order_acquire),
desktop_accent_text_rgba_.load(std::memory_order_acquire),
desktop_canvas_rgba_.load(std::memory_order_acquire),
desktop_canvas_text_rgba_.load(std::memory_order_acquire),
desktop_highlight_rgba_.load(std::memory_order_acquire),
desktop_highlight_text_rgba_.load(std::memory_order_acquire)});
return webscene_native::v8_dom_runtime::viewport_metrics{
static_cast<float>(viewport_width_),
static_cast<float>(viewport_height_),
Expand Down Expand Up @@ -671,9 +678,18 @@
const auto accessibility_changed = accessibility_preferences_changed_.exchange(
false,
std::memory_order_acq_rel);
if (!scheme_changed && !accessibility_changed) {
const auto desktop_changed = desktop_environment_changed_.exchange(
false,
std::memory_order_acq_rel);
if (!scheme_changed && !accessibility_changed && !desktop_changed) {
return false;
}
if (desktop_changed && runtime_ != nullptr
&& !runtime_->apply_desktop_environment(
desktop_environment())) {
script_errors_.fetch_add(1, std::memory_order_relaxed);
set_last_error(runtime_->last_error());
}
if (runtime_ != nullptr
&& !runtime_->refresh_media_environment()) {
script_errors_.fetch_add(1, std::memory_order_relaxed);
Expand Down Expand Up @@ -1942,6 +1958,8 @@
std::memory_order_acquire)
|| accessibility_preferences_changed_.load(
std::memory_order_acquire)
|| desktop_environment_changed_.load(
std::memory_order_acquire)
|| semantic_actions_pending_.load(
std::memory_order_acquire)
|| semantic_delta_pending_.load(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7753,6 +7753,13 @@ bool v8_dom_runtime::set_visible(bool visible)
&& impl_->promote_pending_promise_error();
}

bool v8_dom_runtime::apply_desktop_environment(
const webscene_desktop_environment_v1& environment)
{
return impl_->apply_desktop_environment(environment)
&& impl_->promote_pending_promise_error();
}

bool v8_dom_runtime::set_focused(bool focused)
{
return impl_->set_focused(focused)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,8 @@ class v8_dom_runtime final {
bool has_open_gpu_output() const;
void update_gpu_presentation_images(const std::vector<std::shared_ptr<const webscene_gpu_image_lease_v3>>& images);
bool refresh_media_environment();
bool apply_desktop_environment(
const webscene_desktop_environment_v1& environment);
bool set_visible(bool visible);
bool set_focused(bool focused);
bool set_fullscreen(bool fullscreen);
Expand Down
Loading
Loading