diff --git a/bridge/core/api/element.cc b/bridge/core/api/element.cc index 89b7b4ac0..0c2cdb536 100644 --- a/bridge/core/api/element.cc +++ b/bridge/core/api/element.cc @@ -1,8 +1,29 @@ -/* - * Copyright (C) 2022-present The WebF authors. All rights reserved. - */ - -#include "plugin_api/element.h" -#include "core/dom/container_node.h" - -namespace webf {} // namespace webf \ No newline at end of file +/* + * Copyright (C) 2022-present The WebF authors. All rights reserved. + */ + +#include "plugin_api/element.h" +#include "core/api/exception_state.h" +#include "core/dom/element.h" +#include "core/dom/container_node.h" + +namespace webf { + +void ElementPublicMethods::ToBlob(Element* ptr, + WebFNativeFunctionContext* callback_context, + SharedExceptionState* shared_exception_state) { + auto* element = static_cast(ptr); + auto callback_impl = WebFNativeFunction::Create(callback_context, shared_exception_state); + return element->toBlob(callback_impl, shared_exception_state->exception_state); +} + +void ElementPublicMethods::ToBlobWithDevicePixelRatio(Element* ptr, + double device_pixel_ratio, + WebFNativeFunctionContext* callback_context, + SharedExceptionState* shared_exception_state) { + auto* element = static_cast(ptr); + auto callback_impl = WebFNativeFunction::Create(callback_context, shared_exception_state); + return element->toBlob(device_pixel_ratio, callback_impl, shared_exception_state->exception_state); +} + +} // namespace webf \ No newline at end of file diff --git a/bridge/core/dom/element.cc b/bridge/core/dom/element.cc index dd373e716..bbea6af7f 100644 --- a/bridge/core/dom/element.cc +++ b/bridge/core/dom/element.cc @@ -385,9 +385,9 @@ Element& Element::CloneWithoutAttributesAndChildren(Document& factory) const { return *(factory.createElement(local_name_, ASSERT_NO_EXCEPTION())); } -class ElementSnapshotReader { +class ElementSnapshotPromiseReader { public: - ElementSnapshotReader(ExecutingContext* context, + ElementSnapshotPromiseReader(ExecutingContext* context, Element* element, std::shared_ptr resolver, double device_pixel_ratio) @@ -406,17 +406,17 @@ class ElementSnapshotReader { double device_pixel_ratio_; }; -void ElementSnapshotReader::Start() { +void ElementSnapshotPromiseReader::Start() { context_->FlushUICommand(element_, FlushUICommandReason::kDependentsOnElement | FlushUICommandReason::kDependentsOnLayout); auto callback = [](void* ptr, double contextId, char* error, uint8_t* bytes, int32_t length) -> void { - auto* reader = static_cast(ptr); + auto* reader = static_cast(ptr); auto* context = reader->context_; reader->context_->dartIsolateContext()->dispatcher()->PostToJs( context->isDedicated(), context->contextId(), - [](ElementSnapshotReader* reader, char* error, uint8_t* bytes, int32_t length) { + [](ElementSnapshotPromiseReader* reader, char* error, uint8_t* bytes, int32_t length) { if (error != nullptr) { reader->HandleFailed(error); dart_free(error); @@ -433,7 +433,7 @@ void ElementSnapshotReader::Start() { element_->bindingObject(), device_pixel_ratio_); } -void ElementSnapshotReader::HandleSnapshot(uint8_t* bytes, int32_t length) { +void ElementSnapshotPromiseReader::HandleSnapshot(uint8_t* bytes, int32_t length) { MemberMutationScope mutation_scope{context_}; Blob* blob = Blob::Create(context_); blob->SetMineType("image/png"); @@ -441,7 +441,7 @@ void ElementSnapshotReader::HandleSnapshot(uint8_t* bytes, int32_t length) { resolver_->Resolve(blob); } -void ElementSnapshotReader::HandleFailed(const char* error) { +void ElementSnapshotPromiseReader::HandleFailed(const char* error) { MemberMutationScope mutation_scope{context_}; ExceptionState exception_state; exception_state.ThrowException(context_->ctx(), ErrorType::InternalError, error); @@ -450,6 +450,58 @@ void ElementSnapshotReader::HandleFailed(const char* error) { JS_FreeValue(context_->ctx(), exception_value); } +class ElementSnapshotNativeFunctionReader { + public: + ElementSnapshotNativeFunctionReader(ExecutingContext* context, + Element* element, + std::shared_ptr function, + double device_pixel_ratio) + : context_(context), element_(element), function_(std::move(function)), device_pixel_ratio_(device_pixel_ratio) { + Start(); + }; + + void Start(); + + private: + ExecutingContext* context_; + Element* element_; + std::shared_ptr function_{nullptr}; + double device_pixel_ratio_; +}; + +void ElementSnapshotNativeFunctionReader::Start() { + context_->FlushUICommand(element_, + FlushUICommandReason::kDependentsOnElement | FlushUICommandReason::kDependentsOnLayout); + + auto callback = [](void* ptr, double contextId, char* error, uint8_t* bytes, int32_t length) -> void { + auto* reader = static_cast(ptr); + auto* context = reader->context_; + + reader->context_->dartIsolateContext()->dispatcher()->PostToJs( + context->isDedicated(), context->contextId(), + [](ElementSnapshotNativeFunctionReader* reader, char* error, uint8_t* bytes, int32_t length) { + if (error != nullptr) { + NativeValue error_object = Native_NewCString(error); + reader->function_->Invoke(reader->context_, 1, &error_object); + dart_free(error); + } else { + auto params = new NativeValue[2]; + params[0] = Native_NewNull(); + params[1] = Native_NewUint8Bytes(length, bytes); + reader->function_->Invoke(reader->context_, 2, params); + dart_free(bytes); + } + + reader->context_->RunRustFutureTasks(); + delete reader; + }, + reader, error, bytes, length); + }; + + context_->dartMethodPtr()->toBlob(context_->isDedicated(), this, context_->contextId(), callback, + element_->bindingObject(), device_pixel_ratio_); +} + ScriptPromise Element::toBlob(ExceptionState& exception_state) { Window* window = GetExecutingContext()->window(); double device_pixel_ratio = NativeValueConverter::FromNativeValue(window->GetBindingProperty( @@ -460,10 +512,22 @@ ScriptPromise Element::toBlob(ExceptionState& exception_state) { ScriptPromise Element::toBlob(double device_pixel_ratio, ExceptionState& exception_state) { auto resolver = ScriptPromiseResolver::Create(GetExecutingContext()); - new ElementSnapshotReader(GetExecutingContext(), this, resolver, device_pixel_ratio); + new ElementSnapshotPromiseReader(GetExecutingContext(), this, resolver, device_pixel_ratio); return resolver->Promise(); } +void Element::toBlob(const std::shared_ptr& callback, ExceptionState& exception_state) { + Window* window = GetExecutingContext()->window(); + double device_pixel_ratio = NativeValueConverter::FromNativeValue(window->GetBindingProperty( + binding_call_methods::kdevicePixelRatio, + FlushUICommandReason::kDependentsOnElement | FlushUICommandReason::kDependentsOnLayout, exception_state)); + return toBlob(device_pixel_ratio, callback, exception_state); +} + +void Element::toBlob(double device_pixel_ratio, const std::shared_ptr& callback, ExceptionState& exception_state) { + new ElementSnapshotNativeFunctionReader(GetExecutingContext(), this, callback, device_pixel_ratio); +} + ScriptValue Element::___testGlobalToLocal__(double x, double y, webf::ExceptionState& exception_state) { const NativeValue args[] = { NativeValueConverter::ToNativeValue(x), diff --git a/bridge/core/dom/element.h b/bridge/core/dom/element.h index 0707eed23..8fc0a3118 100644 --- a/bridge/core/dom/element.h +++ b/bridge/core/dom/element.h @@ -7,6 +7,7 @@ #include "bindings/qjs/cppgc/garbage_collected.h" #include "bindings/qjs/script_promise.h" +#include "core/native/native_function.h" #include "container_node.h" #include "core/css/inline_css_style_declaration.h" #include "element_data.h" @@ -80,6 +81,8 @@ class Element : public ContainerNode { ScriptPromise toBlob(double device_pixel_ratio, ExceptionState& exception_state); ScriptPromise toBlob(ExceptionState& exception_state); + void toBlob(double device_pixel_ratio, const std::shared_ptr& callback, ExceptionState& exception_state); + void toBlob(const std::shared_ptr& callback, ExceptionState& exception_state); ScriptValue ___testGlobalToLocal__(double x, double y, ExceptionState& exception_state); diff --git a/bridge/include/plugin_api/element.h b/bridge/include/plugin_api/element.h index 5e9fbb4e4..bee94a51e 100644 --- a/bridge/include/plugin_api/element.h +++ b/bridge/include/plugin_api/element.h @@ -14,10 +14,22 @@ class SharedExceptionState; class ExecutingContext; class Element; class Document; +typedef struct WebFNativeFunctionContext WebFNativeFunctionContext; + +using PublicElementToBlob = void (*)(Element*, WebFNativeFunctionContext*, SharedExceptionState*); +using PublicElementToBlobWithDevicePixelRatio = void (*)(Element*, double, WebFNativeFunctionContext*, SharedExceptionState*); struct ElementPublicMethods : WebFPublicMethods { + static void ToBlob(Element* element, WebFNativeFunctionContext* context, SharedExceptionState* exception_state); + static void ToBlobWithDevicePixelRatio(Element* element, + double device_pixel_ratio, + WebFNativeFunctionContext* context, + SharedExceptionState* exception_state); + double version{1.0}; ContainerNodePublicMethods container_node; + PublicElementToBlob element_to_blob{ToBlob}; + PublicElementToBlobWithDevicePixelRatio element_to_blob_with_device_pixel_ratio{ToBlobWithDevicePixelRatio}; }; } // namespace webf diff --git a/bridge/rusty_webf_sys/src/dom/element.rs b/bridge/rusty_webf_sys/src/dom/element.rs index cb42d9c15..d873621ee 100644 --- a/bridge/rusty_webf_sys/src/dom/element.rs +++ b/bridge/rusty_webf_sys/src/dom/element.rs @@ -9,36 +9,22 @@ use crate::*; pub struct ElementRustMethods { pub version: c_double, pub container_node: ContainerNodeRustMethods, + pub to_blob: extern "C" fn(*const OpaquePtr, *const WebFNativeFunctionContext, *const OpaquePtr) -> c_void, + pub to_blob_with_device_pixel_ratio: extern "C" fn(*const OpaquePtr, c_double, *const WebFNativeFunctionContext, *const OpaquePtr) -> c_void, } impl RustMethods for ElementRustMethods {} -#[repr(C)] -enum ElementType { - kHTMLDIVElement, - kHTMLAnchorElement, - kHTMLHeadElement, - kHTMLBodyElement, - kHTMLHTMLElement, - kHTMLImageElement, - kHTMLLinkElement, - kHTMLScriptElement, - kHTMLTemplateElement, - kHTMLUnknownElement, - kHTMLCanvasElement, - kHTMLWidgetElement, - kHTMLButtonElement, - kHTMLFormElement, - kHTMLInputElement, - kHTMLTextAreaElement -} - pub struct Element { container_node: ContainerNode, method_pointer: *const ElementRustMethods, } -impl Element {} +impl Element { + pub fn to_blob(&self, exception_state: &ExceptionState) -> WebFNativeFuture> { + unimplemented!() + } +} pub trait ElementMethods: ContainerNodeMethods {}