Files
electron/shell/renderer/electron_api_service_impl.cc
T
18f7d6cc5c chore: bump chromium to 157.0.8085.0 (main) (#54590)
* chore: bump chromium in DEPS to 157.0.8079.0

* chore: update patches

* 8426044: Deduplicate notifications for find-in-page

Upstream removed WebContentsDelegate::FindReply() in favor of
WebContentsObserver::DidReceiveFindReply(). Moved Electron's
found-in-page handling from the delegate forwarder to the observer
forwarder on the NativeLifecycle peer.

Ref: https://chromium-review.googlesource.com/c/chromium/src/+/8426044

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* 8471431: siso: don't include optional LLVM tools in clang inputs

https://crrev.com/c/8471431 narrowed the
third_party/llvm-build/Release+Asserts:headers filegroup glob from
bin/clang-* to bin/clang-cl, bin/clang-cl.exe and bin/clang-[0-9]*.
siso uploads that filegroup as a precomputed subtree and drops other
inputs under it, so bin/clang-tidy no longer reached the RBE workers and
the clang-tidy steps failed with exit 127.

build-tools now adds bin/clang-tidy back to that filegroup:
https://github.com/electron/build-tools/pull/910

Ref: https://chromium-review.googlesource.com/c/chromium/src/+/8471431

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V38FjDEdZgMvFpf5Fmp65m

* chore: bump chromium in DEPS to 157.0.8081.0

* 8469895: [VideoCapture] Remove unsafe lifetime assumptions in InProcessVideoCaptureDeviceLauncher

Ref: https://chromium-review.googlesource.com/c/chromium/src/+/8469895

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* 8261571: dbus: Let desktop Linux end the session instead of crashing when a bus is lost

Upstream landed Bus::Options::disconnected_callback and a reworked
dbus_thread_linux that takes the embedder's callback via Initialize(),
which supersedes both the backport patch and the downstream
SetDisconnectedCallback() shim. Removed both patches and switched
ElectronBrowserMainParts to dbus_thread_linux::Initialize().

Ref: https://chromium-review.googlesource.com/c/chromium/src/+/8261571

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* 8470272: [find-in-page] Fix endless frame traversal around an inner WebContents

Ref: https://chromium-review.googlesource.com/c/chromium/src/+/8470272

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* chore: update patches

* 8424588: [mojo] (Mostly) ban untyped `handle` use

TakeHeapSnapshot now takes handle<platform>, so the browser passes the
mojo::PlatformHandle directly and the renderer receives it without
unwrapping.

Ref: https://chromium-review.googlesource.com/c/chromium/src/+/8424588

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* 8465643: Forward proxy auth for requests without login prompts

Plumb the new do_not_prompt_for_login flag through
URLLoaderNetworkObserver, SimpleURLLoaderClient and CreateLoginDelegate.
Electron keeps routing these challenges to the 'login' event, which is
its non-UI credential source, mirroring how Chrome still consults
extensions for them.

Ref: https://chromium-review.googlesource.com/c/chromium/src/+/8465643

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* 8422739: Enforce cross-origin access control in WebUIURLLoaderFactory

CreateWebUIURLLoaderFactory now requires a request initiator origin
lock. Pass the frame's initiator origin that content already hands to
RegisterNonNetworkSubresourceURLLoaderFactories; the lock only gates
chrome-untrusted:// initiators, so component extensions keep their
access to chrome://resources.

Ref: https://chromium-review.googlesource.com/c/chromium/src/+/8422739

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* chore: bump chromium in DEPS to 157.0.8083.0

* 8497008: CATransaction: Clean up old flags

Ref: https://chromium-review.googlesource.com/c/chromium/src/+/8497008

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* 8499815: Ruff: reformat third_party/blink.

Ref: https://chromium-review.googlesource.com/c/chromium/src/+/8499815

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* 8455902: gin: Mark Invoker as stack allocated and drop raw_ptr for its Arguments

Ref: https://chromium-review.googlesource.com/c/chromium/src/+/8455902

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* chore: update patches

* 8469168: Change DataPipeGetter::Read to return result as base::expected

Ref: https://chromium-review.googlesource.com/c/chromium/src/+/8469168

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* 8480632: Ignore stale UpdateDragOperation replies from non-current RWH on Android

Ref: https://chromium-review.googlesource.com/c/chromium/src/+/8480632

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* chore: bump chromium in DEPS to 157.0.8085.0

* chore: update patches

* 8463605: [Clear-Site-Data] Prevent cross-site fetch clearing unpartitioned data

Ref: https://chromium-review.googlesource.com/c/chromium/src/+/8463605

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* 8448270: [Linux] Support XDG NetworkMonitor portal in NetworkChangeNotifierLinux

The browser process now opens a private session bus for the portal, with
no Bus::Options::disconnected_callback, so it aborts when the session bus
is lost. That is what fails "when a D-Bus bus goes away > exits cleanly
instead of crashing" on Linux. Carry the upstream fix until it rolls in.

Ref: https://chromium-review.googlesource.com/c/chromium/src/+/8448270
Ref: https://chromium-review.googlesource.com/c/chromium/src/+/8512441#nolint

* 8465423: Use C++20 std::numbers::pi in blink

Backport the upstream fix for Windows math constants.

Ref: https://chromium-review.googlesource.com/c/chromium/src/+/8465423
Ref: https://chromium-review.googlesource.com/c/chromium/src/+/8510323#nolint

* 8489251: Exit tab fullscreen when the held-Esc timer fires under keyboard lock

Ref: https://chromium-review.googlesource.com/c/chromium/src/+/8489251

* 8366647: [snapshot] Optional SHA256 code cache source hashing

Ref: https://chromium-review.googlesource.com/c/v8/v8/+/8366647

* fix: disable V8 metagen feature

Refs https://issues.chromium.org/issues/531344950
Skip-Lint: General feature disablement, no specific to a particular CL.

* 8503816: Enable AperitifHelpers by default

Disable AperitifHelpers on macOS until Electron adopts the new helpers.
Ref: https://chromium-review.googlesource.com/c/chromium/src/+/8503816

* build: pin build-tools to merged siso clang-tidy fix

electron/build-tools#910 squash-merged as 32e2253f7c5696d85a77fe19d54d284cf9a62322; re-pin from the PR branch commit a411ee5 so CI no longer depends on the deleted branch.

Skip-Lint: build-tools pin, not a Chromium CL adaptation
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V38FjDEdZgMvFpf5Fmp65m

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: electron-claude[bot] <279139701+electron-claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
Co-authored-by: deepak1556 <hop2deep@gmail.com>
2026-10-07 22:34:15 -04:00

512 lines
19 KiB
C++

// Copyright (c) 2019 Slack Technologies, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "electron/shell/renderer/electron_api_service_impl.h"
#include <tuple>
#include <utility>
#include <vector>
#include "gin/converter.h"
#include "mojo/public/cpp/platform/platform_handle.h"
#include "shell/common/api/electron_api_shared_texture.h"
#include "shell/common/gin_converters/blink_converter.h"
#include "shell/common/gin_converters/serialized_value_converter.h"
#include "shell/common/gin_helper/dictionary.h"
#include "shell/common/heap_snapshot.h"
#include "shell/common/thread_restrictions.h"
#include "shell/common/v8_util.h"
#include "shell/renderer/electron_ipc_native.h"
#include "shell/renderer/preload_utils.h"
#include "base/functional/callback_helpers.h"
#include "base/no_destructor.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_thread.h"
#include "shell/renderer/renderer_client_base.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
#include "third_party/blink/public/platform/scheduler/web_agent_group_scheduler.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_url.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_frame_widget.h"
#include "third_party/blink/public/web/web_input_method_controller.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_message_port_converter.h"
#include "third_party/blink/public/web/web_script_source.h"
#include "third_party/blink/public/web/web_view.h"
#include "ui/base/ime/ime_text_span.h"
#include "url/gurl.h"
#include "v8/include/v8-context.h"
#include "v8/include/v8-exception.h"
#include "v8/include/v8-function.h"
namespace electron {
namespace {
mojom::RendererStartupDataPtr* GetPendingNewWindowStartupData() {
// Process-global, no locking: set, RenderFrame creation, and take are all
// one synchronous call stack inside window.open() on the renderer main
// thread.
DCHECK(content::RenderThread::Get())
<< "must be called from the renderer main thread";
static base::NoDestructor<mojom::RendererStartupDataPtr> pending;
return pending.get();
}
} // namespace
namespace {
// Replies to an ExecuteJavaScript() call with the script's completion value
// (Blink has already awaited it if it was a thenable) or with what it threw.
// Failures that have no value to report go back as a message so that nothing
// here touches V8 when Blink calls back while tearing the context down.
void ReplyWithScriptResult(
mojom::ElectronFrame::ExecuteJavaScriptCallback callback,
const std::vector<v8::Local<v8::Value>>& results,
const std::vector<v8::Local<v8::Value>>& rejections) {
if (results.empty()) {
std::move(callback).Run(
false, electron::SerializedValue(),
"WebFrame was removed before script could run. This normally means "
"the underlying frame was destroyed");
return;
}
bool success = false;
v8::Local<v8::Value> value;
if (!rejections.empty() && !rejections[0].IsEmpty()) {
value = rejections[0];
} else if (results[0].IsEmpty()) {
std::move(callback).Run(
false, electron::SerializedValue(),
"Script failed to execute, this normally means an error was thrown. "
"Check the renderer console for the error.");
return;
} else {
success = true;
value = results[0];
}
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::TryCatch try_catch(isolate);
electron::SerializedValue serialized;
if (!electron::SerializeV8Value(isolate, value, &serialized)) {
std::string error = "An object could not be cloned.";
v8::Local<v8::Value> message;
if (try_catch.HasCaught() && !try_catch.HasTerminated() &&
try_catch.Exception()->IsObject() &&
try_catch.Exception()
.As<v8::Object>()
->Get(isolate->GetCurrentContext(),
gin::StringToSymbol(isolate, "message"))
.ToLocal(&message) &&
message->IsString()) {
gin::ConvertFromV8(isolate, message, &error);
}
std::move(callback).Run(false, electron::SerializedValue(), error);
return;
}
std::move(callback).Run(success, std::move(serialized), std::string());
}
} // namespace
ElectronApiServiceImpl::~ElectronApiServiceImpl() = default;
ElectronApiServiceImpl::ElectronApiServiceImpl(
content::RenderFrame* render_frame,
RendererClientBase* renderer_client)
: content::RenderFrameObserver(render_frame),
content::RenderFrameObserverTracker<ElectronApiServiceImpl>(render_frame),
renderer_client_(renderer_client) {
registry_.AddInterface<mojom::ElectronRenderer>(base::BindRepeating(
&ElectronApiServiceImpl::BindTo, base::Unretained(this)));
// Associated with content.mojom.Frame, so SetStartupData() arrives before
// the CommitNavigation that follows it — i.e. before DidCreateScriptContext.
render_frame->GetAssociatedInterfaceRegistry()
->AddInterface<mojom::ElectronFrame>(base::BindRepeating(
&ElectronApiServiceImpl::BindFrameReceiver, base::Unretained(this)));
// window.open() popup's about:blank fires DidCreateScriptContext before
// any push can land; the browser attaches its startup data to the
// CreateNewWindowReply and SetPendingCreateNewWindowStartupData() stashes it
// for us on this same call stack. The first real navigation replaces it.
startup_data_ = std::exchange(*GetPendingNewWindowStartupData(), nullptr);
}
// static
void ElectronApiServiceImpl::SetPendingNewWindowStartupData(
mojom::RendererStartupDataPtr data) {
*GetPendingNewWindowStartupData() = std::move(data);
}
void ElectronApiServiceImpl::BindFrameReceiver(
mojo::PendingAssociatedReceiver<mojom::ElectronFrame> receiver) {
if (frame_receiver_.is_bound())
frame_receiver_.reset();
frame_receiver_.Bind(std::move(receiver));
}
void ElectronApiServiceImpl::SetStartupData(
mojom::RendererStartupDataPtr data) {
startup_data_ = std::move(data);
}
void ElectronApiServiceImpl::BindTo(
mojo::PendingReceiver<mojom::ElectronRenderer> receiver) {
if (document_created_) {
if (receiver_.is_bound())
receiver_.reset();
receiver_.Bind(std::move(receiver));
receiver_.set_disconnect_handler(base::BindOnce(
&ElectronApiServiceImpl::OnConnectionError, GetWeakPtr()));
} else {
pending_receiver_ = std::move(receiver);
}
}
void ElectronApiServiceImpl::OnInterfaceRequestForFrame(
const std::string& interface_name,
mojo::ScopedMessagePipeHandle* interface_pipe) {
registry_.TryBindInterface(interface_name, interface_pipe);
}
void ElectronApiServiceImpl::DidCreateDocumentElement() {
document_created_ = true;
if (pending_receiver_) {
if (receiver_.is_bound())
receiver_.reset();
receiver_.Bind(std::move(pending_receiver_));
receiver_.set_disconnect_handler(base::BindOnce(
&ElectronApiServiceImpl::OnConnectionError, GetWeakPtr()));
}
}
void ElectronApiServiceImpl::OnDestruct() {
delete this;
}
void ElectronApiServiceImpl::OnConnectionError() {
if (receiver_.is_bound())
receiver_.reset();
}
void ElectronApiServiceImpl::Message(bool internal,
const std::string& channel,
electron::SerializedValue arguments) {
blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
if (!frame)
return;
v8::Isolate* isolate = frame->GetAgentGroupScheduler()->Isolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = renderer_client_->GetContext(frame, isolate);
v8::Context::Scope context_scope(context);
v8::Local<v8::Value> args = gin::ConvertToV8(isolate, arguments);
ipc_native::EmitIPCEvent(isolate, context, internal, channel, {}, args);
}
void ElectronApiServiceImpl::ReceivePostMessage(
const std::string& channel,
blink::TransferableMessage message) {
blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
if (!frame)
return;
v8::Isolate* isolate = frame->GetAgentGroupScheduler()->Isolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = renderer_client_->GetContext(frame, isolate);
v8::Context::Scope context_scope(context);
v8::Local<v8::Value> message_value = DeserializeV8Value(isolate, message);
std::vector<v8::Local<v8::Value>> ports;
for (auto& port : message.ports) {
ports.emplace_back(
blink::WebMessagePortConverter::EntangleAndInjectMessagePortChannel(
isolate, context, std::move(port)));
}
std::vector<v8::Local<v8::Value>> args = {message_value};
ipc_native::EmitIPCEvent(isolate, context, false, channel, ports,
gin::ConvertToV8(isolate, args));
}
void ElectronApiServiceImpl::TakeHeapSnapshot(
mojo::PlatformHandle file,
TakeHeapSnapshotCallback callback) {
blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
if (!frame)
return;
ScopedAllowBlockingForElectron allow_blocking;
if (!file.is_valid()) {
LOG(ERROR) << "Unable to get the file handle from mojo.";
std::move(callback).Run(false);
return;
}
base::File base_file(file.TakePlatformFile());
v8::Isolate* isolate = frame->GetAgentGroupScheduler()->Isolate();
bool success = electron::TakeHeapSnapshot(isolate, &base_file);
std::move(callback).Run(success);
}
void ElectronApiServiceImpl::ExecuteJavaScript(
int32_t world_id,
std::vector<mojom::ScriptSourcePtr> sources,
bool has_user_gesture,
ExecuteJavaScriptCallback callback) {
blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
std::vector<blink::WebScriptSource> web_sources;
web_sources.reserve(sources.size());
for (const auto& source : sources) {
web_sources.emplace_back(blink::WebString::FromUtf16(source->code),
blink::WebURL(GURL(source->url)));
}
frame->RequestExecuteScript(
world_id, web_sources,
has_user_gesture ? blink::mojom::UserActivationOption::kActivate
: blink::mojom::UserActivationOption::kDoNotActivate,
blink::mojom::EvaluationTiming::kSynchronous,
blink::mojom::LoadEventBlockingOption::kDoNotBlock, base::NullCallback(),
base::BindOnce(&ReplyWithScriptResult, std::move(callback)),
blink::BackForwardCacheAware::kAllow,
blink::mojom::WantResultOption::kWantResult,
blink::mojom::PromiseResultOption::kAwait,
/*script_injector_id=*/blink::WebString());
}
void ElectronApiServiceImpl::InsertCSS(const std::string& css,
const std::string& css_origin,
InsertCSSCallback callback) {
blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
std::move(callback).Run(
frame->GetDocument()
.InsertStyleSheet(blink::WebString::FromUtf8(css), nullptr,
css_origin == "user" ? blink::WebCssOrigin::kUser
: blink::WebCssOrigin::kAuthor)
.Utf16());
}
void ElectronApiServiceImpl::RemoveInsertedCSS(
const std::u16string& key,
RemoveInsertedCSSCallback callback) {
render_frame()->GetWebFrame()->GetDocument().RemoveInsertedStyleSheet(
blink::WebString::FromUtf16(key));
std::move(callback).Run();
}
void ElectronApiServiceImpl::InsertText(const std::string& text,
InsertTextCallback callback) {
render_frame()
->GetWebFrame()
->FrameWidget()
->GetActiveWebInputMethodController()
->CommitText(blink::WebString::FromUtf8(text),
std::vector<ui::ImeTextSpan>(), blink::WebRange(), 0);
std::move(callback).Run();
}
void ElectronApiServiceImpl::SetVisualZoomLevelLimits(
double min_level,
double max_level,
SetVisualZoomLevelLimitsCallback callback) {
blink::WebView* web_view = render_frame()->GetWebFrame()->View();
web_view->SetDefaultPageScaleLimits(min_level, max_level);
// Without an explicit initial scale Blink starts the page at the minimum,
// so a minimum below 1 would shrink the page instead of only allowing it.
web_view->SetInitialPageScaleOverride(1.f);
std::move(callback).Run();
}
namespace {
// release() of the object handed to the shared texture receiver: releases the
// imported texture, then tells the browser this frame no longer references it.
void ReleaseReceivedSharedTexture(
const v8::FunctionCallbackInfo<v8::Value>& info) {
v8::Isolate* isolate = info.GetIsolate();
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Local<v8::Array> data = info.Data().As<v8::Array>();
v8::Local<v8::Value> imported, texture_id, release;
if (!data->Get(context, 0).ToLocal(&imported) || !imported->IsObject() ||
!data->Get(context, 1).ToLocal(&texture_id) ||
!imported.As<v8::Object>()
->Get(context, gin::StringToSymbol(isolate, "release"))
.ToLocal(&release) ||
!release->IsFunction()) {
return;
}
v8::Local<v8::Function> notify_browser;
if (!v8::Function::New(
context,
[](const v8::FunctionCallbackInfo<v8::Value>& info) {
v8::Isolate* isolate = info.GetIsolate();
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Local<v8::Value> binding = preload_utils::GetBinding(
isolate, gin::StringToV8(isolate, "electron_renderer_ipc"));
v8::Local<v8::Value> ipc_renderer, invoke;
if (binding.IsEmpty() || !binding->IsObject() ||
!binding.As<v8::Object>()
->Get(context,
gin::StringToSymbol(isolate, "ipcRenderer"))
.ToLocal(&ipc_renderer) ||
!ipc_renderer->IsObject() ||
!ipc_renderer.As<v8::Object>()
->Get(context, gin::StringToSymbol(isolate, "invoke"))
.ToLocal(&invoke) ||
!invoke->IsFunction()) {
return;
}
v8::Local<v8::Value> args[] = {
gin::StringToV8(
isolate, "IMPORT_SHARED_TEXTURE_RELEASE_RENDERER_TO_MAIN"),
info.Data()};
v8::Local<v8::Value> result;
if (invoke.As<v8::Function>()
->Call(context, ipc_renderer, 2, args)
.ToLocal(&result)) {
info.GetReturnValue().Set(result);
}
},
texture_id, 0, v8::ConstructorBehavior::kThrow)
.ToLocal(&notify_browser)) {
return;
}
v8::Local<v8::Value> argv[] = {notify_browser};
v8::Local<v8::Value> result;
if (release.As<v8::Function>()
->Call(context, imported, 1, argv)
.ToLocal(&result)) {
info.GetReturnValue().Set(result);
}
}
} // namespace
void ElectronApiServiceImpl::ReceiveSharedTexture(
electron::SerializedValue transfer,
const std::string& texture_id,
electron::SerializedValue args,
ReceiveSharedTextureCallback callback) {
blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
v8::Isolate* isolate = frame->GetAgentGroupScheduler()->Isolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = renderer_client_->GetContext(frame, isolate);
v8::Context::Scope context_scope(context);
v8::MicrotasksScope microtasks_scope(context,
v8::MicrotasksScope::kRunMicrotasks);
v8::TryCatch try_catch(isolate);
auto reply_error = [&]() {
v8::Local<v8::Value> error =
try_catch.HasCaught()
? try_catch.Exception()
: v8::Exception::Error(
gin::StringToV8(isolate, "Failed to import shared texture"));
try_catch.Reset();
electron::SerializedValue serialized;
if (!electron::SerializeV8Value(isolate, error, &serialized)) {
std::move(callback).Run(false, electron::SerializedValue(),
"Failed to import shared texture");
return;
}
std::move(callback).Run(false, std::move(serialized), std::string());
};
auto get = [&](v8::Local<v8::Value> object, const char* key,
v8::Local<v8::Value>* out) {
return object->IsObject() &&
object.As<v8::Object>()
->Get(context, gin::StringToSymbol(isolate, key))
.ToLocal(out);
};
// imported = sharedTexture.subtle.finishTransferSharedTexture({...transfer,
// id})
v8::Local<v8::Value> transfer_value = gin::ConvertToV8(isolate, transfer);
if (!transfer_value->IsObject() ||
transfer_value.As<v8::Object>()
->Set(context, gin::StringToSymbol(isolate, "id"),
gin::StringToV8(isolate, texture_id))
.IsNothing()) {
return reply_error();
}
v8::Local<v8::Value> imported =
api::shared_texture::FinishTransferSharedTexture(isolate, transfer_value);
if (try_catch.HasCaught() || imported.IsEmpty() || !imported->IsObject())
return reply_error();
// Reply with imported.getFrameCreationSyncToken().
v8::Local<v8::Value> get_sync_token, sync_token;
electron::SerializedValue serialized_token;
if (!get(imported, "getFrameCreationSyncToken", &get_sync_token) ||
!get_sync_token->IsFunction() ||
!get_sync_token.As<v8::Function>()
->Call(context, imported, 0, nullptr)
.ToLocal(&sync_token) ||
!electron::SerializeV8Value(isolate, sync_token, &serialized_token)) {
return reply_error();
}
std::move(callback).Run(true, std::move(serialized_token), std::string());
// receiver({ importedSharedTexture: { textureId, subtle, getVideoFrame,
// release } }, ...args)
try_catch.SetVerbose(true);
gin_helper::Dictionary global(isolate, context->Global());
v8::Local<v8::Value> receiver;
if (!global.GetHidden("sharedTextureReceiver", &receiver) ||
!receiver->IsFunction()) {
return;
}
v8::Local<v8::Value> get_video_frame;
if (!get(imported, "getVideoFrame", &get_video_frame))
return;
v8::Local<v8::Value> release_data_items[] = {
imported, gin::StringToV8(isolate, texture_id)};
v8::Local<v8::Function> release;
if (!v8::Function::New(context, ReleaseReceivedSharedTexture,
v8::Array::New(isolate, release_data_items, 2), 0,
v8::ConstructorBehavior::kThrow)
.ToLocal(&release)) {
return;
}
auto wrapper = gin_helper::Dictionary::CreateEmpty(isolate);
wrapper.Set("textureId", texture_id);
wrapper.Set("subtle", imported);
wrapper.Set("getVideoFrame", get_video_frame);
wrapper.Set("release", release.As<v8::Value>());
auto data = gin_helper::Dictionary::CreateEmpty(isolate);
data.Set("importedSharedTexture", wrapper);
v8::LocalVector<v8::Value> argv(isolate, {data.GetHandle()});
v8::Local<v8::Value> extra = gin::ConvertToV8(isolate, args);
if (extra->IsArray()) {
v8::Local<v8::Array> extra_array = extra.As<v8::Array>();
for (uint32_t i = 0; i < extra_array->Length(); ++i) {
v8::Local<v8::Value> item;
if (extra_array->Get(context, i).ToLocal(&item))
argv.push_back(item);
}
}
std::ignore = receiver.As<v8::Function>()->Call(
context, v8::Undefined(isolate), static_cast<int>(argv.size()),
argv.data());
}
} // namespace electron