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
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Generated by tools/webidl-v8-bindings/generate.mjs. Do not edit.
// Exposure manifest SHA-256: 65954cdff2f92cf111e965bd3fcf2617570cd74a3ec7a728e2dee2e4a20c27fb
// Exposure manifest SHA-256: d1bbef499809baf809fcf8c449dffe107d5e0a7da99a144d8225e88c2ac2f4d9
// Inputs: @webref/idl 3.82.1, webidl2 24.5.0.

enum class generated_dom_interface : uint8_t {
Expand Down Expand Up @@ -1800,6 +1800,29 @@ static void generated_HTMLElement_href_set(
set_element_href(info.Data().As<v8::Name>(), value, info);
}

static void generated_HTMLElement_accept_get(
v8::Local<v8::Name>,
const v8::PropertyCallbackInfo<v8::Value>& info)
{
if (!generated_dom_receiver_is(info.GetIsolate(), info.Holder(), generated_dom_interface::HTMLElement)) {
throw_generated_illegal_invocation(info.GetIsolate());
return;
}
get_reflected_string_attribute(info.Data().As<v8::Name>(), info);
}

static void generated_HTMLElement_accept_set(
v8::Local<v8::Name>,
v8::Local<v8::Value> value,
const v8::PropertyCallbackInfo<void>& info)
{
if (!generated_dom_receiver_is(info.GetIsolate(), info.Holder(), generated_dom_interface::HTMLElement)) {
throw_generated_illegal_invocation(info.GetIsolate());
return;
}
set_reflected_string_attribute(info.Data().As<v8::Name>(), value, info);
}

static void generated_HTMLElement_download_get(
v8::Local<v8::Name>,
const v8::PropertyCallbackInfo<v8::Value>& info)
Expand Down Expand Up @@ -4004,6 +4027,21 @@ void install_generated_dom_templates(v8::Local<v8::Context>)
generated_HTMLElement_signature, 0),
v8::FunctionTemplate::New(isolate, generated_dom_prototype_attribute_set, generated_HTMLElement_href_symbol, generated_HTMLElement_signature, 1),
v8::PropertyAttribute::None);
auto generated_HTMLElement_accept_symbol = v8::Symbol::New(
isolate, js_string(isolate, "WebScene.HTMLElement.accept"));
generated_HTMLElement_template->InstanceTemplate()->SetNativeDataProperty(
generated_HTMLElement_accept_symbol,
generated_HTMLElement_accept_get,
generated_HTMLElement_accept_set,
js_string(isolate, "accept"),
v8::PropertyAttribute::None);
generated_HTMLElement_template->PrototypeTemplate()->SetAccessorProperty(
js_string(isolate, "accept"),
v8::FunctionTemplate::New(
isolate, generated_dom_prototype_attribute_get, generated_HTMLElement_accept_symbol,
generated_HTMLElement_signature, 0),
v8::FunctionTemplate::New(isolate, generated_dom_prototype_attribute_set, generated_HTMLElement_accept_symbol, generated_HTMLElement_signature, 1),
v8::PropertyAttribute::None);
auto generated_HTMLElement_download_symbol = v8::Symbol::New(
isolate, js_string(isolate, "WebScene.HTMLElement.download"));
generated_HTMLElement_template->InstanceTemplate()->SetNativeDataProperty(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ class graphics_service {
if (!commands_) commands_=std::make_shared<command_channel>(capacity,upload_limit,wake_);
return commands_;
}
std::shared_ptr<release_channel> release_endpoint(size_t capacity=256) {
std::shared_ptr<release_channel> release_endpoint(size_t capacity=4096) {
check_open();
if (!releases_) releases_=std::make_shared<release_channel>(capacity,command_endpoint(),wake_);
return releases_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -766,7 +766,33 @@ void serialize_svg_subtree(const dom_node& node, std::string& output, bool root)
bool has_color = false;
const auto css_fill = node.style.textual().svg_fill;
const auto css_stroke = node.style.textual().svg_stroke;
// Stylesheets outside the detached SVG are unavailable to the host SVG
// renderer. Project cascaded typography as presentation attributes, keeping
// local attributes and SVG inheritance when no CSS declaration overrides them.
std::vector<std::pair<std::string, std::string>> typography;
const auto collect_typography = [&](const dom_node& source, bool inherited) {
const auto add = [&](const char* name, std::string value) {
if (value.empty()) return;
if (inherited && node.attributes.contains(name)) return;
if (std::any_of(typography.begin(), typography.end(),
[&](const auto& entry) { return entry.first == name; })) return;
typography.emplace_back(name, std::move(value));
};
if (source.style.font_size >= 0) add("font-size", std::to_string(source.style.font_size));
if (source.style.font_weight > 0) add("font-weight", std::to_string(source.style.font_weight));
add("font-family", source.style.textual().font_family);
if (source.style.letter_spacing_specified) add("letter-spacing", std::to_string(source.style.letter_spacing));
if (source.style.word_spacing_specified) add("word-spacing", std::to_string(source.style.word_spacing));
add("text-anchor", source.style.textual().svg_text_anchor);
};
collect_typography(node, false);
if (root) {
for (auto* ancestor = node.parent; ancestor; ancestor = ancestor->parent)
collect_typography(*ancestor, true);
}
for (const auto& [name, value] : node.attributes) {
if (std::any_of(typography.begin(), typography.end(),
[&](const auto& entry) { return entry.first == name; })) continue;
if (name == "xmlns") has_xmlns = true;
else if (name == "id") has_id = true;
else if (name == "class") has_class = true;
Expand All @@ -791,6 +817,11 @@ void serialize_svg_subtree(const dom_node& node, std::string& output, bool root)
}
output.push_back('"');
}
for (const auto& [name, value] : typography) {
output += " " + name + "=\"";
append_xml_escaped(value, output, true);
output.push_back('"');
}
if (root && !has_xmlns) output += " xmlns=\"http://www.w3.org/2000/svg\"";
if (!has_id && !node.id_attribute.empty()) {
output += " id=\"";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,7 @@ struct node_style final {
// the live inherited foreground when the scene is serialized.
std::string svg_fill;
std::string svg_stroke;
std::string svg_text_anchor;
std::string list_style_position;
std::string list_style_type;
// Vertical corner radii are cold: circular radii use the four hot
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ native_document::allocation_metrics native_document::read_allocation_metrics() c
+ textual->cursor.capacity() + 1U
+ textual->svg_fill.capacity() + 1U
+ textual->svg_stroke.capacity() + 1U
+ textual->svg_text_anchor.capacity() + 1U
+ textual->list_style_position.capacity() + 1U
+ textual->list_style_type.capacity() + 1U;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ void native_document::append_scene(
[](unsigned char character) {
return static_cast<char>(std::tolower(character));
});
if (pseudo_background_image_lower.starts_with("linear-gradient(")
if ((pseudo_background_image_lower.starts_with("linear-gradient(") || pseudo_background_image_lower.starts_with("radial-gradient("))
&& width > 0 && height > 0) {
auto gradient_resource = std::string{"webscene-bg-v2\t"};
gradient_resource += pseudo.background_image.image_value;
Expand Down Expand Up @@ -934,7 +934,7 @@ void native_document::append_scene(
return static_cast<char>(std::tolower(character));
});
if (paint_self
&& background_image_value_lower.starts_with("linear-gradient(")
&& (background_image_value_lower.starts_with("linear-gradient(") || background_image_value_lower.starts_with("radial-gradient("))
&& node.layout.width > 0
&& node.layout.height > 0) {
auto gradient_resource = std::string{"webscene-bg-v2\t"};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@

std::array<queued_input_event, input_capacity> values_{};
std::mutex producer_mutex_;
alignas(64) std::atomic<uint32_t> write_{0};

Check warning on line 126 in experiments/WebScene.NativeEngine.Probe/native/webscene_native_engine.cpp

View workflow job for this annotation

GitHub Actions / Build and test windows-latest

'`anonymous-namespace'::input_ring': structure was padded due to alignment specifier
alignas(64) std::atomic<uint32_t> read_{0};

Check warning on line 127 in experiments/WebScene.NativeEngine.Probe/native/webscene_native_engine.cpp

View workflow job for this annotation

GitHub Actions / Build and test windows-latest

'`anonymous-namespace'::input_ring': structure was padded due to alignment specifier
};

struct canvas_layer_version final {
Expand Down Expand Up @@ -282,6 +282,7 @@
struct url_request final {
std::string url;
std::vector<webscene_native::document_start_script> document_start_scripts;
std::optional<webscene_input_event> initial_viewport;
};

#if defined(WEBSCENE_NATIVE_ENGINE_WITH_V8_INSPECTOR)
Expand Down Expand Up @@ -430,6 +431,9 @@
webscene_native::runtime_diagnostics diagnostics_;
#if defined(WEBSCENE_NATIVE_ENGINE_WITH_V8)
std::unique_ptr<webscene_native::v8_dom_runtime> runtime_;
std::atomic<bool> file_service_enabled_{false};
std::mutex file_runtime_mutex_;
bool file_runtime_ready_{false};
#if defined(WEBSCENE_NATIVE_ENGINE_WITH_V8_INSPECTOR)
std::atomic<webscene_native::v8_dom_runtime*> inspector_runtime_{nullptr};
std::atomic<engine_inspector_state*> inspector_state_{nullptr};
Expand Down Expand Up @@ -971,6 +975,13 @@
: 0U;
}

uint8_t webscene_engine_load_url_with_viewport(
webscene_engine* engine, const char* url, size_t length,
const webscene_input_event* viewport)
{
return engine && viewport && engine->load_url_with_viewport(url, length, *viewport) ? 1U : 0U;
}

uint8_t webscene_engine_enqueue(webscene_engine* engine, const webscene_input_event* event)
{
return engine != nullptr && event != nullptr && engine->enqueue(*event) ? 1U : 0U;
Expand Down Expand Up @@ -1731,3 +1742,36 @@
#if defined(WEBSCENE_GRAPHICS_SCENE_TESTS)
#include "../tests/graphics_scene_lease_tests.inc"
#endif

uint8_t webscene_engine_enable_file_service_v1(webscene_engine* engine, uint8_t enabled) {
return engine && engine->enable_file_service(enabled != 0);
}
const webscene_file_request_v1* webscene_engine_take_file_request_v1(webscene_engine* engine) {
if (!engine) return nullptr;
auto request=engine->take_file_request();
if (!request) return nullptr;
request->bind();
return &request.release()->view;
}
void webscene_file_request_release_v1(const webscene_file_request_v1* request) {
delete reinterpret_cast<const webscene_native::native_file_request*>(request);
}
uint8_t webscene_engine_complete_file_request_v1(webscene_engine* engine,
uint64_t id, uint32_t status, const webscene_file_data_v1* files,
size_t count, const char* error) {
if (!engine || !id || status>2 || count>64 || (count && !files) || (status && count)) return 0;
webscene_native::native_file_completion completion; completion.id=id; completion.status=status;
completion.error=error ? error : "";
if (completion.error.size()>4096) return 0;
size_t total=0;
for(size_t i=0;i<count;++i) {
const auto& f=files[i];
if (!f.name || !f.mime_type || (f.byte_count && !f.bytes) || f.byte_count>64u*1024u*1024u-total) return 0;
total+=f.byte_count;
webscene_native::native_file_data value; value.name=f.name; value.mime=f.mime_type;
if(value.name.size()>4096 || value.mime.size()>256) return 0;
if(f.byte_count) value.bytes.assign(f.bytes,f.bytes+f.byte_count);
completion.files.push_back(std::move(value));
}
return engine->complete_file_request(std::move(completion));
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ _webscene_engine_observe_compositor_frame
_webscene_engine_requires_animation_frame
_webscene_engine_load_url
_webscene_engine_load_url_with_options
_webscene_engine_load_url_with_viewport
_webscene_engine_prewarm
_webscene_engine_request_low_memory
_webscene_engine_release_canvas_export
Expand Down Expand Up @@ -87,3 +88,7 @@ _webscene_gpu_d3d11_seal_v3
_webscene_gpu_d3d11_poll_v3
_webscene_gpu_d3d11_destroy_v3
_webscene_engine_submit_canvas_checkpoint_v3
_webscene_engine_enable_file_service_v1
_webscene_engine_take_file_request_v1
_webscene_file_request_release_v1
_webscene_engine_complete_file_request_v1
Original file line number Diff line number Diff line change
Expand Up @@ -1155,6 +1155,11 @@ WEBSCENE_API uint8_t webscene_engine_load_url(
webscene_engine* engine,
const char* url,
size_t url_length);
/* Set the initial viewport on the worker immediately before document scripts.
* This avoids publishing a canvas initialized against default dimensions. */
WEBSCENE_API uint8_t webscene_engine_load_url_with_viewport(
webscene_engine* engine, const char* url, size_t url_length,
const webscene_input_event* viewport);
WEBSCENE_API uint8_t webscene_engine_load_url_with_options(
webscene_engine* engine,
const char* url,
Expand Down Expand Up @@ -1299,6 +1304,33 @@ WEBSCENE_API uint8_t webscene_engine_get_interop_pool_metrics_v3(
* payload is UTF-8 JSON. A too-small/null destination reports the required
* size without consuming the request; a successful full copy consumes it.
*/
/* Native file service v1. Explicit opt-in permits script-triggered native
* dialogs. Requests own immutable UTF-8 metadata and bytes until release.
* Hosts must return only user-selected bytes, never script-supplied paths.
* kind: 1 Open, 2 Save; status: 0 completed, 1 cancelled, 2 failed.
* Completion copies its inputs before returning and is delivered on the JS
* worker. Maximum 64 MiB per operation, 64 files, 16 pending requests.
* The existing host_request_available callback also signals this queue. */
typedef struct webscene_file_data_v1 {
const char* name;
const char* mime_type;
const uint8_t* bytes;
size_t byte_count;
} webscene_file_data_v1;
typedef struct webscene_file_request_v1 {
uint32_t struct_size, version;
uint64_t request_id;
uint32_t kind, multiple;
const char* accept;
webscene_file_data_v1 file;
} webscene_file_request_v1;
WEBSCENE_API uint8_t webscene_engine_enable_file_service_v1(webscene_engine* engine, uint8_t enabled);
WEBSCENE_API const webscene_file_request_v1* webscene_engine_take_file_request_v1(webscene_engine* engine);
WEBSCENE_API void webscene_file_request_release_v1(const webscene_file_request_v1* request);
WEBSCENE_API uint8_t webscene_engine_complete_file_request_v1(webscene_engine* engine,
uint64_t request_id, uint32_t status, const webscene_file_data_v1* files,
size_t file_count, const char* error_message);

WEBSCENE_API size_t webscene_engine_take_host_request(
webscene_engine* engine,
char* destination,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ private:
using script_work_request =
std::variant<
script_request,
webscene_native::native_file_completion,
url_request,
interop_evaluate_work_v3,
interop_invoke_work_v3,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,37 @@
}
#endif

bool complete_file_request(webscene_native::native_file_completion completion) {
std::lock_guard lock(script_mutex_);
if (script_work_.size() >= 1024) return false;
script_work_.emplace_back(std::move(completion));
signal_worker();
return true;
}
void retire_file_runtime() {
#if defined(WEBSCENE_NATIVE_ENGINE_WITH_V8)
std::unique_ptr<webscene_native::v8_dom_runtime> retired;
{
std::lock_guard lock(file_runtime_mutex_);
file_runtime_ready_=false;
retired=std::move(runtime_);
}
// Destruction stays on the V8 worker and outside the host queue lock.
#endif
}
bool enable_file_service(bool enabled) {

Check warning on line 115 in experiments/WebScene.NativeEngine.Probe/native/webscene_native_engine_lifecycle.inc

View workflow job for this annotation

GitHub Actions / Build and test windows-latest

'enabled': unreferenced parameter
#if defined(WEBSCENE_NATIVE_ENGINE_WITH_V8)
file_service_enabled_.store(enabled); signal_worker(); return true;
#endif
return false;
}
std::unique_ptr<webscene_native::native_file_request> take_file_request() {
#if defined(WEBSCENE_NATIVE_ENGINE_WITH_V8)
std::lock_guard lock(file_runtime_mutex_);
if (file_runtime_ready_) return runtime_->take_file_request();
#endif
return {};
}
bool enqueue(const webscene_input_event& event)
{
if (event.kind == WEBSCENE_INPUT_RESIZE) {
Expand Down Expand Up @@ -455,6 +486,15 @@
return enqueue_url(value, length, {});
}

bool load_url_with_viewport(const char* value, size_t length, const webscene_input_event& viewport)
{
if (viewport.kind != WEBSCENE_INPUT_RESIZE ||
!std::isfinite(viewport.x) || !std::isfinite(viewport.y) ||
!std::isfinite(viewport.delta_x) || viewport.x <= 0 || viewport.y <= 0 || viewport.delta_x <= 0)
return false;
return enqueue_url(value, length, {}, viewport);
}

bool load_url(
const char* value,
size_t length,
Expand Down Expand Up @@ -531,7 +571,8 @@
bool enqueue_url(
const char* value,
size_t length,
std::vector<webscene_native::document_start_script> scripts)
std::vector<webscene_native::document_start_script> scripts,
std::optional<webscene_input_event> viewport = {})

Check warning on line 575 in experiments/WebScene.NativeEngine.Probe/native/webscene_native_engine_lifecycle.inc

View workflow job for this annotation

GitHub Actions / Build and test windows-latest

'viewport': unreferenced parameter
{
#if !defined(WEBSCENE_NATIVE_ENGINE_WITH_V8)
static_cast<void>(value);
Expand All @@ -557,7 +598,7 @@
}
script_work_.emplace_back(url_request{
std::string(value, length),
std::move(scripts)});
std::move(scripts), viewport});
signal_worker();
return true;
#endif
Expand Down
Loading
Loading