Skip to content

Commit

Permalink
feat: add native function callback support for toBlob
Browse files Browse the repository at this point in the history
  • Loading branch information
LeuisKen committed Jan 2, 2025
1 parent fa77735 commit 452a660
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 37 deletions.
37 changes: 29 additions & 8 deletions bridge/core/api/element.cc
Original file line number Diff line number Diff line change
@@ -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
/*
* 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<webf::Element*>(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<webf::Element*>(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
80 changes: 72 additions & 8 deletions bridge/core/dom/element.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<ScriptPromiseResolver> resolver,
double device_pixel_ratio)
Expand All @@ -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<ElementSnapshotReader*>(ptr);
auto* reader = static_cast<ElementSnapshotPromiseReader*>(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);
Expand All @@ -433,15 +433,15 @@ 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");
blob->AppendBytes(bytes, length);
resolver_->Resolve<Blob*>(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);
Expand All @@ -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<WebFNativeFunction> 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<WebFNativeFunction> 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<ElementSnapshotNativeFunctionReader*>(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<NativeTypeDouble>::FromNativeValue(window->GetBindingProperty(
Expand All @@ -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<WebFNativeFunction>& callback, ExceptionState& exception_state) {
Window* window = GetExecutingContext()->window();
double device_pixel_ratio = NativeValueConverter<NativeTypeDouble>::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<WebFNativeFunction>& 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<NativeTypeDouble>::ToNativeValue(x),
Expand Down
3 changes: 3 additions & 0 deletions bridge/core/dom/element.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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<WebFNativeFunction>& callback, ExceptionState& exception_state);
void toBlob(const std::shared_ptr<WebFNativeFunction>& callback, ExceptionState& exception_state);

ScriptValue ___testGlobalToLocal__(double x, double y, ExceptionState& exception_state);

Expand Down
12 changes: 12 additions & 0 deletions bridge/include/plugin_api/element.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
28 changes: 7 additions & 21 deletions bridge/rusty_webf_sys/src/dom/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Vec<u8>> {
unimplemented!()
}
}

pub trait ElementMethods: ContainerNodeMethods {}

Expand Down

0 comments on commit 452a660

Please sign in to comment.