From fd7a5478bc9211d3727c00ca31565861318b8a2a Mon Sep 17 00:00:00 2001 From: Jiaxun Wei Date: Sun, 29 Dec 2024 12:41:28 +0800 Subject: [PATCH 1/3] feat: add missing method of async storage --- .../rusty_webf_sys/src/frame/async_storage.rs | 96 +++++++++++++++++++ bridge/rusty_webf_sys/src/frame/storage.rs | 12 ++- bridge/rusty_webf_sys/src/webf_future.rs | 3 +- 3 files changed, 108 insertions(+), 3 deletions(-) diff --git a/bridge/rusty_webf_sys/src/frame/async_storage.rs b/bridge/rusty_webf_sys/src/frame/async_storage.rs index 09ac09db1..5c387296b 100644 --- a/bridge/rusty_webf_sys/src/frame/async_storage.rs +++ b/bridge/rusty_webf_sys/src/frame/async_storage.rs @@ -77,4 +77,100 @@ impl AsyncStorage { self.context().webf_invoke_module_with_params_and_callback("AsyncStorage", "setItem", ¶ms, general_callback, exception_state).unwrap(); future_for_return } + + pub fn remove_item(&self, key: &str, exception_state: &ExceptionState) -> WebFNativeFuture { + let key_string = NativeValue::new_string(key); + let future_for_return = WebFNativeFuture::::new(); + let future_in_callback = future_for_return.clone(); + let general_callback: WebFNativeFunction = Box::new(move |argc, argv| { + if argc == 1 { + let error_string = unsafe { (*argv).clone() }; + let error_string = error_string.to_string(); + future_in_callback.set_result(Err(error_string)); + return NativeValue::new_null(); + } + if argc == 2 { + let item_string = unsafe { (*argv.wrapping_add(1)).clone() }; + let item_string = item_string.to_string(); + future_in_callback.set_result(Ok(Some(item_string == "true"))); + return NativeValue::new_null(); + } + println!("Invalid argument count for async storage callback"); + NativeValue::new_null() + }); + self.context().webf_invoke_module_with_params_and_callback("AsyncStorage", "removeItem", &key_string, general_callback, exception_state).unwrap(); + future_for_return + } + + pub fn clear(&self, exception_state: &ExceptionState) -> WebFNativeFuture { + let params = NativeValue::new_null(); + let future_for_return = WebFNativeFuture::::new(); + let future_in_callback = future_for_return.clone(); + let general_callback: WebFNativeFunction = Box::new(move |argc, argv| { + if argc == 1 { + let error_string = unsafe { (*argv).clone() }; + let error_string = error_string.to_string(); + future_in_callback.set_result(Err(error_string)); + return NativeValue::new_null(); + } + if argc == 2 { + let item_string = unsafe { (*argv.wrapping_add(1)).clone() }; + let item_string = item_string.to_string(); + future_in_callback.set_result(Ok(Some(item_string == "true"))); + return NativeValue::new_null(); + } + println!("Invalid argument count for async storage callback"); + NativeValue::new_null() + }); + self.context().webf_invoke_module_with_params_and_callback("AsyncStorage", "clear", ¶ms, general_callback, exception_state).unwrap(); + future_for_return + } + + pub fn get_all_keys(&self, exception_state: &ExceptionState) -> WebFNativeFuture> { + let params = NativeValue::new_null(); + let future_for_return = WebFNativeFuture::>::new(); + let future_in_callback = future_for_return.clone(); + let general_callback: WebFNativeFunction = Box::new(move |argc, argv| { + if argc == 1 { + let error_string = unsafe { (*argv).clone() }; + let error_string = error_string.to_string(); + future_in_callback.set_result(Err(error_string)); + return NativeValue::new_null(); + } + if argc == 2 { + let item_keys = unsafe { (*argv.wrapping_add(1)).clone() }; + let item_keys = item_keys.to_list().iter().map(|x| x.to_string()).collect::>(); + future_in_callback.set_result(Ok(Some(item_keys))); + return NativeValue::new_null(); + } + println!("Invalid argument count for async storage callback"); + NativeValue::new_null() + }); + self.context().webf_invoke_module_with_params_and_callback("AsyncStorage", "getAllKeys", ¶ms, general_callback, exception_state).unwrap(); + future_for_return + } + + pub fn length(&self, exception_state: &ExceptionState) -> WebFNativeFuture { + let params = NativeValue::new_null(); + let future_for_return = WebFNativeFuture::::new(); + let future_in_callback = future_for_return.clone(); + let general_callback: WebFNativeFunction = Box::new(move |argc, argv| { + if argc == 1 { + let error_string = unsafe { (*argv).clone() }; + let error_string = error_string.to_string(); + future_in_callback.set_result(Err(error_string)); + return NativeValue::new_null(); + } + if argc == 2 { + let length_value = unsafe { (*argv.wrapping_add(1)).clone() }; + let length_value = length_value.to_int64(); + future_in_callback.set_result(Ok(Some(length_value))); + return NativeValue::new_null(); + } + println!("Invalid argument count for async storage callback"); + NativeValue::new_null() + }); + self.context().webf_invoke_module_with_params_and_callback("AsyncStorage", "length", ¶ms, general_callback, exception_state).unwrap(); + future_for_return + } } diff --git a/bridge/rusty_webf_sys/src/frame/storage.rs b/bridge/rusty_webf_sys/src/frame/storage.rs index be8647970..586b419a9 100644 --- a/bridge/rusty_webf_sys/src/frame/storage.rs +++ b/bridge/rusty_webf_sys/src/frame/storage.rs @@ -51,9 +51,17 @@ impl Storage { Ok(()) } - pub fn remove_item(&self, key: &str, exception_state: &ExceptionState) { + pub fn remove_item(&self, key: &str, exception_state: &ExceptionState) -> Result<(), String> { let key_string = NativeValue::new_string(key); - self.context().webf_invoke_module_with_params(&self.module_name, "removeItem", &key_string, exception_state); + let result = self.context().webf_invoke_module_with_params(&self.module_name, "removeItem", &key_string, exception_state); + + if exception_state.has_exception() { + return Err(exception_state.stringify(self.context())); + } + match result { + Ok(result) => Ok(()), + Err(err) => Err(err), + } } pub fn clear(&self, exception_state: &ExceptionState) { diff --git a/bridge/rusty_webf_sys/src/webf_future.rs b/bridge/rusty_webf_sys/src/webf_future.rs index 019ff9509..9616ab9fc 100644 --- a/bridge/rusty_webf_sys/src/webf_future.rs +++ b/bridge/rusty_webf_sys/src/webf_future.rs @@ -83,7 +83,8 @@ where } } -impl Clone for WebFNativeFuture { +impl Clone for WebFNativeFuture +{ fn clone(&self) -> Self { WebFNativeFuture { inner: self.inner.clone(), From fa777356ec68bbb5a6570192e4c207c735ad34bf Mon Sep 17 00:00:00 2001 From: Jiaxun Wei Date: Sun, 29 Dec 2024 14:47:14 +0800 Subject: [PATCH 2/3] feat: add u8 bytes native value support --- bridge/foundation/native_value.cc | 13 +++++++++++++ bridge/foundation/native_value.h | 1 + bridge/rusty_webf_sys/src/native_value.rs | 17 +++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/bridge/foundation/native_value.cc b/bridge/foundation/native_value.cc index f2ac0a63e..78d60406e 100644 --- a/bridge/foundation/native_value.cc +++ b/bridge/foundation/native_value.cc @@ -142,6 +142,19 @@ NativeValue Native_NewJSON(JSContext* ctx, const ScriptValue& value, ExceptionSt #endif } +NativeValue Native_NewUint8Bytes(uint32_t length, uint8_t* bytes) { +#if _MSC_VER + NativeValue v{}; + v.u.ptr = reinterpret_cast(bytes); + v.uint32 = length; + v.tag = NativeTag::TAG_UINT8_BYTES; + return v; +#else + return (NativeValue){ + .u = {.ptr = reinterpret_cast(bytes)}, .uint32 = length, .tag = NativeTag::TAG_UINT8_BYTES}; +#endif +} + JSPointerType GetPointerTypeOfNativePointer(NativeValue native_value) { assert(native_value.tag == NativeTag::TAG_POINTER); return static_cast(native_value.uint32); diff --git a/bridge/foundation/native_value.h b/bridge/foundation/native_value.h index c55499a8d..61dd0d8e1 100644 --- a/bridge/foundation/native_value.h +++ b/bridge/foundation/native_value.h @@ -55,6 +55,7 @@ NativeValue Native_NewInt64(int64_t value); NativeValue Native_NewList(uint32_t argc, NativeValue* argv); NativeValue Native_NewPtr(JSPointerType pointerType, void* ptr); NativeValue Native_NewJSON(JSContext* ctx, const ScriptValue& value, ExceptionState& exception_state); +NativeValue Native_NewUint8Bytes(uint32_t length, uint8_t* bytes); JSPointerType GetPointerTypeOfNativePointer(NativeValue native_value); diff --git a/bridge/rusty_webf_sys/src/native_value.rs b/bridge/rusty_webf_sys/src/native_value.rs index dc6bbd2b4..87603aa7b 100644 --- a/bridge/rusty_webf_sys/src/native_value.rs +++ b/bridge/rusty_webf_sys/src/native_value.rs @@ -226,6 +226,23 @@ impl NativeValue { } values } + + pub fn is_u8_bytes(&self) -> bool { + self.tag == NativeTag::TagUint8Bytes as i32 + } + + pub fn to_u8_bytes(&self) -> Vec { + let mut values = Vec::new(); + let ptr = unsafe { + self.u.ptr as *mut u8 + }; + for i in 0..self.uint32 { + let offset = i.try_into().unwrap(); + let val = unsafe { ptr.add(offset).read() }; + values.push(val); + } + values + } } impl Drop for NativeValue { From 0a420411b915462a46e95200c039b0e181791046 Mon Sep 17 00:00:00 2001 From: Jiaxun Wei Date: Thu, 2 Jan 2025 17:44:48 +0800 Subject: [PATCH 3/3] feat: add native function callback support for toBlob --- bridge/core/api/element.cc | 23 +++- bridge/core/dom/element.cc | 88 ++++++++++++-- bridge/core/dom/element.h | 5 + bridge/include/plugin_api/element.h | 15 +++ bridge/rusty_webf_sys/src/dom/element.rs | 112 ++++++++++++++---- .../rusty_webf_sys/src/html/html_element.rs | 10 +- webf/example/rust_builder/rust/src/lib.rs | 22 ++-- 7 files changed, 227 insertions(+), 48 deletions(-) diff --git a/bridge/core/api/element.cc b/bridge/core/api/element.cc index 89b7b4ac0..3a75a037f 100644 --- a/bridge/core/api/element.cc +++ b/bridge/core/api/element.cc @@ -3,6 +3,27 @@ */ #include "plugin_api/element.h" +#include "core/api/exception_state.h" #include "core/dom/container_node.h" +#include "core/dom/element.h" -namespace webf {} // namespace webf \ No newline at end of file +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 diff --git a/bridge/core/dom/element.cc b/bridge/core/dom/element.cc index dd373e716..3d6089c72 100644 --- a/bridge/core/dom/element.cc +++ b/bridge/core/dom/element.cc @@ -385,12 +385,12 @@ Element& Element::CloneWithoutAttributesAndChildren(Document& factory) const { return *(factory.createElement(local_name_, ASSERT_NO_EXCEPTION())); } -class ElementSnapshotReader { +class ElementSnapshotPromiseReader { public: - ElementSnapshotReader(ExecutingContext* context, - Element* element, - std::shared_ptr resolver, - double device_pixel_ratio) + ElementSnapshotPromiseReader(ExecutingContext* context, + Element* element, + std::shared_ptr resolver, + double device_pixel_ratio) : context_(context), element_(element), resolver_(std::move(resolver)), device_pixel_ratio_(device_pixel_ratio) { Start(); }; @@ -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,24 @@ 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..a1516e57f 100644 --- a/bridge/core/dom/element.h +++ b/bridge/core/dom/element.h @@ -9,6 +9,7 @@ #include "bindings/qjs/script_promise.h" #include "container_node.h" #include "core/css/inline_css_style_declaration.h" +#include "core/native/native_function.h" #include "element_data.h" #include "legacy/bounding_client_rect.h" #include "legacy/element_attributes.h" @@ -80,6 +81,10 @@ 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..b97820157 100644 --- a/bridge/include/plugin_api/element.h +++ b/bridge/include/plugin_api/element.h @@ -14,10 +14,25 @@ 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..37b355870 100644 --- a/bridge/rusty_webf_sys/src/dom/element.rs +++ b/bridge/rusty_webf_sys/src/dom/element.rs @@ -9,38 +9,97 @@ 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> { + let event_target: &EventTarget = &self.container_node.node.event_target; + + let future_for_return = WebFNativeFuture::>::new(); + let future_in_callback = future_for_return.clone(); + let general_callback: WebFNativeFunction = Box::new(move |argc, argv| { + if argc == 1 { + let error_string = unsafe { (*argv).clone() }; + let error_string = error_string.to_string(); + future_in_callback.set_result(Err(error_string)); + return NativeValue::new_null(); + } + if argc == 2 { + let result = unsafe { (*argv.wrapping_add(1)).clone() }; + let value = result.to_u8_bytes(); + future_in_callback.set_result(Ok(Some(value))); + return NativeValue::new_null(); + } + println!("Invalid argument count for async storage callback"); + NativeValue::new_null() + }); + let callback_data = Box::new(WebFNativeFunctionContextData { + func: general_callback, + }); + let callback_context_data_ptr = Box::into_raw(callback_data); + let callback_context = Box::new(WebFNativeFunctionContext { + callback: invoke_webf_native_function, + free_ptr: release_webf_native_function, + ptr: callback_context_data_ptr, + }); + let callback_context_ptr = Box::into_raw(callback_context); + unsafe { + (((*self.method_pointer).to_blob))(event_target.ptr, callback_context_ptr, exception_state.ptr); + } + future_for_return + } -pub trait ElementMethods: ContainerNodeMethods {} + pub fn to_blob_with_device_pixel_ratio(&self, device_pixel_ratio: f64, exception_state: &ExceptionState) -> WebFNativeFuture> { + let event_target: &EventTarget = &self.container_node.node.event_target; + + let future_for_return = WebFNativeFuture::>::new(); + let future_in_callback = future_for_return.clone(); + let general_callback: WebFNativeFunction = Box::new(move |argc, argv| { + if argc == 1 { + let error_string = unsafe { (*argv).clone() }; + let error_string = error_string.to_string(); + future_in_callback.set_result(Err(error_string)); + return NativeValue::new_null(); + } + if argc == 2 { + let result = unsafe { (*argv.wrapping_add(1)).clone() }; + let value = result.to_u8_bytes(); + future_in_callback.set_result(Ok(Some(value))); + return NativeValue::new_null(); + } + println!("Invalid argument count for async storage callback"); + NativeValue::new_null() + }); + let callback_data = Box::new(WebFNativeFunctionContextData { + func: general_callback, + }); + let callback_context_data_ptr = Box::into_raw(callback_data); + let callback_context = Box::new(WebFNativeFunctionContext { + callback: invoke_webf_native_function, + free_ptr: release_webf_native_function, + ptr: callback_context_data_ptr, + }); + let callback_context_ptr = Box::into_raw(callback_context); + unsafe { + (((*self.method_pointer).to_blob_with_device_pixel_ratio))(event_target.ptr, device_pixel_ratio, callback_context_ptr, exception_state.ptr); + } + future_for_return + } +} + +pub trait ElementMethods: ContainerNodeMethods { + fn to_blob(&self, exception_state: &ExceptionState) -> WebFNativeFuture>; + fn to_blob_with_device_pixel_ratio(&self, device_pixel_ratio: f64, exception_state: &ExceptionState) -> WebFNativeFuture>; +} impl ContainerNodeMethods for Element {} @@ -97,4 +156,11 @@ impl EventTargetMethods for Element { } } -impl ElementMethods for Element {} +impl ElementMethods for Element { + fn to_blob(&self, exception_state: &ExceptionState) -> WebFNativeFuture> { + self.to_blob(exception_state) + } + fn to_blob_with_device_pixel_ratio(&self, device_pixel_ratio: f64, exception_state: &ExceptionState) -> WebFNativeFuture> { + self.to_blob_with_device_pixel_ratio(device_pixel_ratio, exception_state) + } +} diff --git a/bridge/rusty_webf_sys/src/html/html_element.rs b/bridge/rusty_webf_sys/src/html/html_element.rs index d8cec4ba5..fc5f313d6 100644 --- a/bridge/rusty_webf_sys/src/html/html_element.rs +++ b/bridge/rusty_webf_sys/src/html/html_element.rs @@ -20,7 +20,15 @@ pub struct HTMLElement { pub trait HTMLElementMethods: ElementMethods {} -impl ElementMethods for HTMLElement {} +impl ElementMethods for HTMLElement { + fn to_blob(&self, exception_state: &ExceptionState) -> WebFNativeFuture> { + self.element.to_blob(exception_state) + } + + fn to_blob_with_device_pixel_ratio(&self, device_pixel_ratio: f64, exception_state: &ExceptionState) -> WebFNativeFuture> { + self.element.to_blob_with_device_pixel_ratio(device_pixel_ratio, exception_state) + } +} impl ContainerNodeMethods for HTMLElement {} diff --git a/webf/example/rust_builder/rust/src/lib.rs b/webf/example/rust_builder/rust/src/lib.rs index 638198d12..f97c7efd7 100644 --- a/webf/example/rust_builder/rust/src/lib.rs +++ b/webf/example/rust_builder/rust/src/lib.rs @@ -1,10 +1,12 @@ use std::cell::RefCell; use std::ffi::c_void; +use std::fs::{self, File}; +use std::io::Write; use std::rc::Rc; use webf_sys::event::Event; use webf_sys::executing_context::ExecutingContextRustMethods; use webf_sys::webf_future::FutureRuntime; -use webf_sys::{initialize_webf_api, AddEventListenerOptions, EventTargetMethods, RustValue}; +use webf_sys::{document, initialize_webf_api, AddEventListenerOptions, ElementMethods, EventTargetMethods, RustValue}; use webf_sys::element::Element; use webf_sys::node::NodeMethods; @@ -50,17 +52,7 @@ pub extern "C" fn init_webf_app(handle: RustValue) println!("Hello from Rust async context!"); - let result = async_storage_2.set_item("a", "b", &exception_state).await; - - match result { - Ok(_) => { - println!("Async Storage Set Item Success"); - }, - Err(err) => { - println!("Async Storage Set Item Failed: {:?}", err); - } - } - + async_storage_2.set_item("a", "b", &exception_state).await.unwrap(); let result = async_storage_2.get_item("a", &exception_state).await; match result { @@ -71,6 +63,12 @@ pub extern "C" fn init_webf_app(handle: RustValue) println!("Async Storage Get Item Failed: {:?}", err); } } + + let html_element = context.document().document_element(); + let blob = html_element.to_blob(&exception_state).await.unwrap().unwrap(); + + let mut file = File::create("output.png").unwrap(); + file.write_all(&blob).unwrap(); }); let runtime_run_task_callback = Box::new(move || {