2018-09-10 02:41:13 +02:00
|
|
|
// Copyright © 2014 The CefSharp Authors. All rights reserved.
|
2014-08-29 10:53:50 +10:00
|
|
|
//
|
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
|
2018-09-10 02:41:13 +02:00
|
|
|
|
2014-08-29 10:53:50 +10:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include "Stdafx.h"
|
|
|
|
|
|
2014-09-12 00:40:33 +10:00
|
|
|
#include "CefBrowserWrapper.h"
|
2014-08-29 10:53:50 +10:00
|
|
|
#include "CefAppUnmanagedWrapper.h"
|
2018-01-22 10:24:25 +10:00
|
|
|
#include "RegisterBoundObjectHandler.h"
|
2019-07-08 13:47:22 +10:00
|
|
|
#include "BindObjectAsyncHandler.h"
|
2019-06-03 21:08:03 +10:00
|
|
|
#include "JavascriptPostMessageHandler.h"
|
2014-11-27 20:57:11 +10:00
|
|
|
#include "JavascriptRootObjectWrapper.h"
|
2020-10-06 15:19:37 +10:00
|
|
|
#include "JavascriptPromiseHandler.h"
|
2022-12-06 14:54:19 +10:00
|
|
|
#include "JavascriptPromiseResolverCatch.h"
|
|
|
|
|
#include "JavascriptPromiseResolverThen.h"
|
2019-03-20 20:33:10 +10:00
|
|
|
#include "Async\JavascriptAsyncMethodCallback.h"
|
2015-06-29 15:08:53 +10:00
|
|
|
#include "Serialization\V8Serialization.h"
|
2015-08-06 10:25:33 +02:00
|
|
|
#include "Serialization\JsObjectsSerialization.h"
|
2019-03-20 20:33:10 +10:00
|
|
|
#include "Wrapper\V8Context.h"
|
|
|
|
|
#include "Wrapper\Frame.h"
|
|
|
|
|
#include "Wrapper\Browser.h"
|
2020-12-16 10:47:34 +10:00
|
|
|
#include "..\CefSharp.Core.Runtime\Internals\Messaging\Messages.h"
|
|
|
|
|
#include "..\CefSharp.Core.Runtime\Internals\Serialization\Primitives.h"
|
2026-03-21 22:35:54 +01:00
|
|
|
#include <include/cef_parser.h>
|
2014-08-29 10:53:50 +10:00
|
|
|
|
2018-01-29 15:48:54 +10:00
|
|
|
using namespace System;
|
2014-08-29 10:53:50 +10:00
|
|
|
using namespace System::Diagnostics;
|
|
|
|
|
using namespace System::Collections::Generic;
|
2021-02-27 12:11:35 +10:00
|
|
|
using namespace CefSharp::BrowserSubprocess::Serialization;
|
2015-06-29 15:08:53 +10:00
|
|
|
using namespace CefSharp::Internals::Messaging;
|
|
|
|
|
using namespace CefSharp::Internals::Serialization;
|
2014-08-29 10:53:50 +10:00
|
|
|
|
|
|
|
|
namespace CefSharp
|
|
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
namespace BrowserSubprocess
|
2014-08-29 10:53:50 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
const CefString CefAppUnmanagedWrapper::kPromiseCreatorScript = ""
|
|
|
|
|
"(function()"
|
|
|
|
|
"{"
|
|
|
|
|
" var result = {};"
|
|
|
|
|
" var promise = new Promise(function(resolve, reject) {"
|
|
|
|
|
" result.res = resolve; result.rej = reject;"
|
|
|
|
|
" });"
|
|
|
|
|
" result.p = promise;"
|
|
|
|
|
" return result;"
|
|
|
|
|
"})();";
|
|
|
|
|
|
|
|
|
|
const CefString kRenderProcessId = CefString("RenderProcessId");
|
|
|
|
|
const CefString kRenderProcessIdCamelCase = CefString("renderProcessId");
|
|
|
|
|
|
|
|
|
|
CefRefPtr<CefRenderProcessHandler> CefAppUnmanagedWrapper::GetRenderProcessHandler()
|
|
|
|
|
{
|
|
|
|
|
return this;
|
|
|
|
|
};
|
2019-06-14 14:29:53 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
// CefRenderProcessHandler
|
|
|
|
|
void CefAppUnmanagedWrapper::OnBrowserCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefDictionaryValue> extraInfo)
|
2019-06-14 14:29:53 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
auto wrapper = gcnew CefBrowserWrapper(browser);
|
|
|
|
|
_onBrowserCreated->Invoke(wrapper);
|
2019-06-14 14:29:53 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
//Multiple CefBrowserWrappers created when opening popups
|
|
|
|
|
_browserWrappers->TryAdd(browser->GetIdentifier(), wrapper);
|
|
|
|
|
|
2024-10-26 10:41:31 +10:00
|
|
|
if (!extraInfo.get())
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
//For the main browser only we check LegacyBindingEnabled and
|
|
|
|
|
//load the objects. Popups don't send this information and checking
|
|
|
|
|
//will override the _legacyBindingEnabled field
|
|
|
|
|
if (!browser->IsPopup())
|
2019-08-11 18:28:42 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
_legacyBindingEnabled = extraInfo->GetBool("LegacyBindingEnabled");
|
2019-08-11 18:28:42 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
if (_legacyBindingEnabled)
|
|
|
|
|
{
|
|
|
|
|
auto objects = extraInfo->GetList("LegacyBindingObjects");
|
|
|
|
|
if (objects.get() && objects->IsValid())
|
2019-06-14 14:29:53 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
auto javascriptObjects = DeserializeJsObjects(objects, 0);
|
|
|
|
|
|
|
|
|
|
for each (JavascriptObject ^ obj in Enumerable::OfType<JavascriptObject^>(javascriptObjects))
|
2019-08-11 18:28:42 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
//Using LegacyBinding with multiple ChromiumWebBrowser instances that share the same
|
|
|
|
|
//render process and using LegacyBinding will cause problems for the limited caching implementation
|
|
|
|
|
//that exists at the moment, for now we'll remove an object if already exists, same behaviour
|
2026-03-21 22:35:54 +01:00
|
|
|
//as the new binding method.
|
2021-02-27 12:11:35 +10:00
|
|
|
//TODO: This should be removed when https://github.com/cefsharp/CefSharp/issues/2306
|
|
|
|
|
//Is complete as objects will be stored at the browser level
|
|
|
|
|
if (_javascriptObjects->ContainsKey(obj->JavascriptName))
|
|
|
|
|
{
|
|
|
|
|
_javascriptObjects->Remove(obj->JavascriptName);
|
|
|
|
|
}
|
|
|
|
|
_javascriptObjects->Add(obj->JavascriptName, obj);
|
2019-08-11 18:28:42 +10:00
|
|
|
}
|
2019-06-14 14:29:53 +10:00
|
|
|
}
|
|
|
|
|
}
|
2026-03-21 22:35:54 +01:00
|
|
|
}
|
2021-06-04 13:26:00 +10:00
|
|
|
|
2026-03-21 22:35:54 +01:00
|
|
|
if (extraInfo->HasKey("JavascriptBindingApiEnabled"))
|
|
|
|
|
{
|
|
|
|
|
wrapper->JavascriptBindingApiEnabled = extraInfo->GetBool("JavascriptBindingApiEnabled");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (extraInfo->HasKey("JavascriptBindingApiHasAllowOrigins"))
|
|
|
|
|
{
|
|
|
|
|
wrapper->JavascriptBindingApiHasAllowOrigins = extraInfo->GetBool("JavascriptBindingApiHasAllowOrigins");
|
2020-05-14 23:18:32 +10:00
|
|
|
|
2026-03-21 22:35:54 +01:00
|
|
|
if (wrapper->JavascriptBindingApiHasAllowOrigins)
|
2021-07-06 11:54:37 +10:00
|
|
|
{
|
2026-03-21 22:35:54 +01:00
|
|
|
auto allowOrigins = extraInfo->GetList("JavascriptBindingApiAllowOrigins");
|
|
|
|
|
if (allowOrigins.get() && allowOrigins->IsValid())
|
|
|
|
|
{
|
|
|
|
|
wrapper->JavascriptBindingApiAllowOrigins = allowOrigins->Copy();
|
|
|
|
|
}
|
2021-07-06 11:54:37 +10:00
|
|
|
}
|
2021-02-27 12:11:35 +10:00
|
|
|
}
|
2026-03-21 22:35:54 +01:00
|
|
|
|
|
|
|
|
if (extraInfo->HasKey("JsBindingPropertyName") || extraInfo->HasKey("JsBindingPropertyNameCamelCase"))
|
|
|
|
|
{
|
|
|
|
|
//TODO: Create constant for these and legacy binding strings above
|
|
|
|
|
_jsBindingPropertyName = extraInfo->GetString("JsBindingPropertyName");
|
|
|
|
|
_jsBindingPropertyNameCamelCase = extraInfo->GetString("JsBindingPropertyNameCamelCase");
|
|
|
|
|
}
|
2020-05-19 21:55:16 +10:00
|
|
|
}
|
2014-08-29 10:53:50 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
void CefAppUnmanagedWrapper::OnBrowserDestroyed(CefRefPtr<CefBrowser> browser)
|
2014-09-15 00:21:22 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
CefBrowserWrapper^ wrapper;
|
|
|
|
|
if (_browserWrappers->TryRemove(browser->GetIdentifier(), wrapper))
|
|
|
|
|
{
|
|
|
|
|
_onBrowserDestroyed->Invoke(wrapper);
|
|
|
|
|
delete wrapper;
|
|
|
|
|
}
|
|
|
|
|
};
|
2014-09-12 16:27:47 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
void CefAppUnmanagedWrapper::OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context)
|
2019-03-20 20:33:10 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
if (!Object::ReferenceEquals(_handler, nullptr))
|
|
|
|
|
{
|
|
|
|
|
Browser browserWrapper(browser);
|
|
|
|
|
Frame frameWrapper(frame);
|
|
|
|
|
V8Context contextWrapper(context);
|
2019-03-20 20:33:10 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
_handler->OnContextCreated(% browserWrapper, % frameWrapper, % contextWrapper);
|
|
|
|
|
}
|
2019-03-20 20:33:10 +10:00
|
|
|
|
2025-04-03 23:17:23 +02:00
|
|
|
//Skip additional contexts (DevTools, extensions) to avoid
|
|
|
|
|
//double binding and duplicate calls to IRenderProcessMessageHandler.OnContextCreated
|
|
|
|
|
//https://github.com/chromiumembedded/cef/issues/3867
|
|
|
|
|
bool isSameContext = frame->GetV8Context()->IsSame(context);
|
|
|
|
|
if (!isSameContext)
|
|
|
|
|
return;
|
2021-02-27 12:11:35 +10:00
|
|
|
auto rootObject = GetJsRootObjectWrapper(browser->GetIdentifier(), frame->GetIdentifier());
|
2019-06-03 21:08:03 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
if (_legacyBindingEnabled)
|
2015-10-11 20:41:17 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
if (_javascriptObjects->Count > 0 && rootObject != nullptr)
|
|
|
|
|
{
|
|
|
|
|
rootObject->Bind(_javascriptObjects->Values, context->GetGlobal());
|
|
|
|
|
}
|
2015-10-11 20:41:17 +10:00
|
|
|
}
|
2018-01-22 10:24:25 +10:00
|
|
|
|
2026-03-21 22:35:54 +01:00
|
|
|
auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier());
|
|
|
|
|
|
|
|
|
|
if (browserWrapper != nullptr && browserWrapper->JavascriptBindingApiEnabled && IsJavascriptBindingApiAllowed(browserWrapper, frame))
|
2021-02-27 12:11:35 +10:00
|
|
|
{
|
2021-06-04 13:26:00 +10:00
|
|
|
//TODO: Look at adding some sort of javascript mapping layer to reduce the code duplication
|
|
|
|
|
auto global = context->GetGlobal();
|
|
|
|
|
auto processId = System::Diagnostics::Process::GetCurrentProcess()->Id;
|
|
|
|
|
|
|
|
|
|
//TODO: JSB: Split functions into their own classes
|
|
|
|
|
//Browser wrapper is only used for BindObjectAsync
|
2025-12-03 19:00:12 +10:00
|
|
|
auto bindObjAsyncFunction = CefV8Value::CreateFunction(kBindObjectAsync, new BindObjectAsyncHandler(_registerBoundObjectRegistry, _javascriptObjects, rootObject));
|
2021-06-04 13:26:00 +10:00
|
|
|
auto unBindObjFunction = CefV8Value::CreateFunction(kDeleteBoundObject, new RegisterBoundObjectHandler(_javascriptObjects));
|
|
|
|
|
auto removeObjectFromCacheFunction = CefV8Value::CreateFunction(kRemoveObjectFromCache, new RegisterBoundObjectHandler(_javascriptObjects));
|
|
|
|
|
auto isObjectCachedFunction = CefV8Value::CreateFunction(kIsObjectCached, new RegisterBoundObjectHandler(_javascriptObjects));
|
|
|
|
|
auto postMessageFunction = CefV8Value::CreateFunction(kPostMessage, new JavascriptPostMessageHandler(rootObject == nullptr ? nullptr : rootObject->CallbackRegistry));
|
|
|
|
|
auto promiseHandlerFunction = CefV8Value::CreateFunction(kSendEvalScriptResponse, new JavascriptPromiseHandler());
|
|
|
|
|
|
|
|
|
|
//By default We'll support both CefSharp and cefSharp, for those who prefer the JS style
|
|
|
|
|
auto createCefSharpObj = !_jsBindingPropertyName.empty();
|
|
|
|
|
auto createCefSharpObjCamelCase = !_jsBindingPropertyNameCamelCase.empty();
|
|
|
|
|
|
|
|
|
|
if (createCefSharpObj)
|
|
|
|
|
{
|
2021-07-31 15:35:38 +10:00
|
|
|
auto cefSharpObj = CefV8Value::CreateObject(nullptr, nullptr);
|
2021-06-04 13:26:00 +10:00
|
|
|
cefSharpObj->SetValue(kBindObjectAsync, bindObjAsyncFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
|
|
|
|
|
cefSharpObj->SetValue(kDeleteBoundObject, unBindObjFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
|
|
|
|
|
cefSharpObj->SetValue(kRemoveObjectFromCache, removeObjectFromCacheFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
|
|
|
|
|
cefSharpObj->SetValue(kIsObjectCached, isObjectCachedFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
|
|
|
|
|
cefSharpObj->SetValue(kPostMessage, postMessageFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
|
|
|
|
|
cefSharpObj->SetValue(kSendEvalScriptResponse, promiseHandlerFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
|
|
|
|
|
cefSharpObj->SetValue(kRenderProcessId, CefV8Value::CreateInt(processId), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
|
|
|
|
|
|
|
|
|
|
global->SetValue(_jsBindingPropertyName, cefSharpObj, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
|
|
|
|
|
}
|
2018-04-26 10:20:39 +10:00
|
|
|
|
2021-06-04 13:26:00 +10:00
|
|
|
if (createCefSharpObjCamelCase)
|
|
|
|
|
{
|
2021-07-31 15:35:38 +10:00
|
|
|
auto cefSharpObjCamelCase = CefV8Value::CreateObject(nullptr, nullptr);
|
2021-06-04 13:26:00 +10:00
|
|
|
cefSharpObjCamelCase->SetValue(kBindObjectAsyncCamelCase, bindObjAsyncFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
|
|
|
|
|
cefSharpObjCamelCase->SetValue(kDeleteBoundObjectCamelCase, unBindObjFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
|
|
|
|
|
cefSharpObjCamelCase->SetValue(kRemoveObjectFromCacheCamelCase, removeObjectFromCacheFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
|
|
|
|
|
cefSharpObjCamelCase->SetValue(kIsObjectCachedCamelCase, isObjectCachedFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
|
|
|
|
|
cefSharpObjCamelCase->SetValue(kPostMessageCamelCase, postMessageFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
|
|
|
|
|
cefSharpObjCamelCase->SetValue(kSendEvalScriptResponseCamelCase, promiseHandlerFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
|
|
|
|
|
cefSharpObjCamelCase->SetValue(kRenderProcessIdCamelCase, CefV8Value::CreateInt(processId), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
|
|
|
|
|
|
|
|
|
|
global->SetValue(_jsBindingPropertyNameCamelCase, cefSharpObjCamelCase, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
|
|
|
|
|
}
|
2021-02-27 12:11:35 +10:00
|
|
|
}
|
2018-08-05 19:56:41 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
//Send a message to the browser processing signaling that OnContextCreated has been called
|
|
|
|
|
//only param is the FrameId. Previous sent only for main frame, now sent for all frames
|
|
|
|
|
//Message sent after legacy objects have been bound and the CefSharp bind async helper methods
|
|
|
|
|
//have been created
|
|
|
|
|
auto contextCreatedMessage = CefProcessMessage::Create(kOnContextCreatedRequest);
|
2018-08-05 19:56:41 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
frame->SendProcessMessage(CefProcessId::PID_BROWSER, contextCreatedMessage);
|
|
|
|
|
};
|
2014-08-29 10:53:50 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
void CefAppUnmanagedWrapper::OnContextReleased(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context)
|
2019-03-20 20:33:10 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
if (!Object::ReferenceEquals(_handler, nullptr))
|
|
|
|
|
{
|
|
|
|
|
Browser browserWrapper(browser);
|
|
|
|
|
Frame frameWrapper(frame);
|
|
|
|
|
V8Context contextWrapper(context);
|
2019-03-20 20:33:10 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
_handler->OnContextReleased(% browserWrapper, % frameWrapper, % contextWrapper);
|
|
|
|
|
}
|
2019-03-20 20:33:10 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
auto contextReleasedMessage = CefProcessMessage::Create(kOnContextReleasedRequest);
|
2017-03-07 09:23:10 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
frame->SendProcessMessage(CefProcessId::PID_BROWSER, contextReleasedMessage);
|
2017-03-07 09:23:10 +10:00
|
|
|
|
2025-12-03 19:00:12 +10:00
|
|
|
auto rootObjectWrappers = _jsRootObjectWrappersByFrameId;
|
2018-01-29 15:48:54 +10:00
|
|
|
|
2025-12-03 19:00:12 +10:00
|
|
|
//If we no longer have a _jsRootObjectWrappersByFrameId reference then there's nothing we can do
|
|
|
|
|
if (Object::ReferenceEquals(rootObjectWrappers, nullptr))
|
2021-02-27 12:11:35 +10:00
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2014-11-25 09:34:15 -05:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
JavascriptRootObjectWrapper^ wrapper;
|
2024-03-09 06:55:27 +10:00
|
|
|
if (rootObjectWrappers->TryRemove(StringUtils::ToClr(frame->GetIdentifier()), wrapper))
|
2021-02-27 12:11:35 +10:00
|
|
|
{
|
|
|
|
|
delete wrapper;
|
|
|
|
|
}
|
|
|
|
|
};
|
2014-09-12 12:48:10 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
void CefAppUnmanagedWrapper::OnFocusedNodeChanged(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefDOMNode> node)
|
2015-12-07 16:27:17 -05:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
if (!_focusedNodeChangedEnabled)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-12-07 16:27:17 -05:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
auto focusedNodeChangedMessage = CefProcessMessage::Create(kOnFocusedNodeChanged);
|
|
|
|
|
auto list = focusedNodeChangedMessage->GetArgumentList();
|
2015-12-03 15:59:27 -05:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
// The node will be empty if an element loses focus but another one
|
|
|
|
|
// doesn't gain focus. Only transfer information if the node is an
|
|
|
|
|
// element.
|
|
|
|
|
if (node != nullptr && node->IsElement())
|
|
|
|
|
{
|
|
|
|
|
// True when a node exists, false if it doesn't.
|
|
|
|
|
list->SetBool(0, true);
|
|
|
|
|
|
|
|
|
|
// Store the tag name.
|
|
|
|
|
list->SetString(1, node->GetElementTagName());
|
2015-12-07 09:48:57 -05:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
// Transfer the attributes in a Dictionary.
|
|
|
|
|
auto attributes = CefDictionaryValue::Create();
|
|
|
|
|
CefDOMNode::AttributeMap attributeMap;
|
|
|
|
|
node->GetElementAttributes(attributeMap);
|
|
|
|
|
for (auto iter : attributeMap)
|
|
|
|
|
{
|
|
|
|
|
attributes->SetString(iter.first, iter.second);
|
|
|
|
|
}
|
2015-12-07 09:48:57 -05:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
list->SetDictionary(2, attributes);
|
|
|
|
|
}
|
|
|
|
|
else
|
2015-12-07 09:48:57 -05:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
list->SetBool(0, false);
|
2015-12-07 09:48:57 -05:00
|
|
|
}
|
|
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
frame->SendProcessMessage(CefProcessId::PID_BROWSER, focusedNodeChangedMessage);
|
2015-12-07 09:48:57 -05:00
|
|
|
}
|
2021-02-27 12:11:35 +10:00
|
|
|
|
|
|
|
|
void CefAppUnmanagedWrapper::OnUncaughtException(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context, CefRefPtr<CefV8Exception> exception, CefRefPtr<CefV8StackTrace> stackTrace)
|
2015-12-07 09:48:57 -05:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
auto uncaughtExceptionMessage = CefProcessMessage::Create(kOnUncaughtException);
|
|
|
|
|
auto list = uncaughtExceptionMessage->GetArgumentList();
|
2015-12-07 09:48:57 -05:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
list->SetString(0, exception->GetMessage());
|
2015-12-03 15:59:27 -05:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
auto frames = CefListValue::Create();
|
|
|
|
|
for (auto i = 0; i < stackTrace->GetFrameCount(); i++)
|
|
|
|
|
{
|
|
|
|
|
auto stackTraceFrame = CefListValue::Create();
|
|
|
|
|
auto frameArg = stackTrace->GetFrame(i);
|
2018-03-07 00:21:31 +00:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
stackTraceFrame->SetString(0, frameArg->GetFunctionName());
|
|
|
|
|
stackTraceFrame->SetInt(1, frameArg->GetLineNumber());
|
|
|
|
|
stackTraceFrame->SetInt(2, frameArg->GetColumn());
|
|
|
|
|
stackTraceFrame->SetString(3, frameArg->GetScriptNameOrSourceURL());
|
2018-03-07 00:21:31 +00:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
frames->SetList(i, stackTraceFrame);
|
|
|
|
|
}
|
2018-03-07 00:21:31 +00:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
list->SetList(1, frames);
|
2018-03-07 00:21:31 +00:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
frame->SendProcessMessage(CefProcessId::PID_BROWSER, uncaughtExceptionMessage);
|
2018-03-07 00:21:31 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-20 21:08:41 +10:00
|
|
|
JavascriptRootObjectWrapper^ CefAppUnmanagedWrapper::GetJsRootObjectWrapper(int browserId, const CefString& frameId)
|
2018-01-29 15:48:54 +10:00
|
|
|
{
|
2025-12-03 19:00:12 +10:00
|
|
|
auto rootObjectWrappers = _jsRootObjectWrappersByFrameId;
|
2021-02-27 12:11:35 +10:00
|
|
|
|
2025-12-03 19:00:12 +10:00
|
|
|
if (Object::ReferenceEquals(rootObjectWrappers, nullptr))
|
2021-02-27 12:11:35 +10:00
|
|
|
{
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
2018-01-29 15:48:54 +10:00
|
|
|
|
2024-03-09 06:55:27 +10:00
|
|
|
auto frameIdClr = StringUtils::ToClr(frameId);
|
2018-01-29 15:48:54 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
JavascriptRootObjectWrapper^ rootObject;
|
2024-03-09 06:55:27 +10:00
|
|
|
if (!rootObjectWrappers->TryGetValue(frameIdClr, rootObject))
|
2021-02-27 12:11:35 +10:00
|
|
|
{
|
2020-07-18 13:30:54 +10:00
|
|
|
#ifdef NETCOREAPP
|
2025-12-03 19:00:12 +10:00
|
|
|
rootObject = gcnew JavascriptRootObjectWrapper();
|
2020-07-18 13:30:54 +10:00
|
|
|
#else
|
2025-12-03 19:00:12 +10:00
|
|
|
auto browserWrapper = FindBrowserWrapper(browserId);
|
|
|
|
|
|
|
|
|
|
rootObject = gcnew JavascriptRootObjectWrapper(browserWrapper == nullptr ? nullptr : browserWrapper->BrowserProcess);
|
2020-07-18 13:30:54 +10:00
|
|
|
#endif
|
2024-03-09 06:55:27 +10:00
|
|
|
rootObjectWrappers->TryAdd(frameIdClr, rootObject);
|
2021-02-27 12:11:35 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rootObject;
|
2018-01-29 15:48:54 +10:00
|
|
|
}
|
2026-03-21 22:35:54 +01:00
|
|
|
|
|
|
|
|
bool CefAppUnmanagedWrapper::IsJavascriptBindingApiAllowed(CefBrowserWrapper^ browserWrapper, CefRefPtr<CefFrame> frame)
|
|
|
|
|
{
|
|
|
|
|
if (browserWrapper == nullptr || !browserWrapper->JavascriptBindingApiHasAllowOrigins)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto allowOrigins = browserWrapper->JavascriptBindingApiAllowOrigins;
|
|
|
|
|
if (!allowOrigins.get())
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto frameUrl = frame->GetURL();
|
|
|
|
|
|
|
|
|
|
CefURLParts frameUrlParts;
|
|
|
|
|
|
|
|
|
|
if (CefParseURL(frameUrl, frameUrlParts))
|
|
|
|
|
{
|
|
|
|
|
auto originStr = frameUrlParts.origin.str;
|
|
|
|
|
auto originLen = frameUrlParts.origin.length;
|
|
|
|
|
|
|
|
|
|
if (originLen > 0 && originStr[originLen - 1] == L'/')
|
|
|
|
|
{
|
|
|
|
|
originLen--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto frameUrlOrigin = CefString(originStr, originLen);
|
|
|
|
|
|
|
|
|
|
auto size = static_cast<int>(allowOrigins->GetSize());
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < size; i++)
|
|
|
|
|
{
|
|
|
|
|
auto origin = allowOrigins->GetString(i);
|
|
|
|
|
|
|
|
|
|
if (_wcsicmp(frameUrlOrigin.ToWString().c_str(), origin.ToWString().c_str()) == 0)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2018-01-29 15:48:54 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
CefBrowserWrapper^ CefAppUnmanagedWrapper::FindBrowserWrapper(int browserId)
|
|
|
|
|
{
|
|
|
|
|
CefBrowserWrapper^ wrapper = nullptr;
|
2018-01-29 15:48:54 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
_browserWrappers->TryGetValue(browserId, wrapper);
|
2014-10-28 11:25:53 -04:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
if (wrapper == nullptr)
|
|
|
|
|
{
|
|
|
|
|
//TODO: Find the syntax for delcaring the native string directly
|
|
|
|
|
LOG(ERROR) << StringUtils::ToNative("Failed to identify BrowserWrapper in OnContextCreated BrowserId:" + browserId).ToString();
|
|
|
|
|
}
|
2014-10-28 11:25:53 -04:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
return wrapper;
|
2014-10-28 11:25:53 -04:00
|
|
|
}
|
|
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
bool CefAppUnmanagedWrapper::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefProcessId sourceProcessId, CefRefPtr<CefProcessMessage> message)
|
2015-06-27 17:01:51 +02:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
auto handled = false;
|
|
|
|
|
auto name = message->GetName();
|
|
|
|
|
auto argList = message->GetArgumentList();
|
2015-07-09 23:36:31 +02:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
//these messages are roughly handled the same way
|
|
|
|
|
if (name == kEvaluateJavascriptRequest || name == kJavascriptCallbackRequest)
|
2015-10-19 13:40:36 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
bool sendResponse = true;
|
|
|
|
|
bool success = false;
|
|
|
|
|
CefRefPtr<CefV8Value> result;
|
|
|
|
|
CefString errorMessage;
|
|
|
|
|
CefRefPtr<CefProcessMessage> response;
|
2015-10-19 13:40:36 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
if (name == kEvaluateJavascriptRequest)
|
|
|
|
|
{
|
|
|
|
|
response = CefProcessMessage::Create(kEvaluateJavascriptResponse);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
response = CefProcessMessage::Create(kJavascriptCallbackResponse);
|
|
|
|
|
}
|
2015-06-29 15:08:53 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
//both messages have callbackId stored at index 0
|
2024-03-09 06:55:27 +10:00
|
|
|
auto frameId = StringUtils::ToClr(frame->GetIdentifier());
|
2023-07-16 06:32:58 +10:00
|
|
|
int64_t callbackId = GetInt64(argList, 0);
|
2018-09-10 02:41:13 +02:00
|
|
|
|
2025-12-03 19:00:12 +10:00
|
|
|
//NOTE: In the rare case when when OnContextCreated hasn't been called we need to manually create the rootObjectWrapper
|
|
|
|
|
//It appears that OnContextCreated is only called for pages that have javascript on them, which makes sense
|
|
|
|
|
//as without javascript there is no need for a context.
|
|
|
|
|
JavascriptRootObjectWrapper^ rootObjectWrapper = GetJsRootObjectWrapper(browser->GetIdentifier(), frame->GetIdentifier());
|
|
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
if (name == kEvaluateJavascriptRequest)
|
2015-10-26 11:41:19 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
auto script = argList->GetString(1);
|
|
|
|
|
auto scriptUrl = argList->GetString(2);
|
|
|
|
|
auto startLine = argList->GetInt(3);
|
2018-09-10 02:41:13 +02:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
if (frame.get() && frame->IsValid())
|
2015-07-08 18:46:28 +02:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
auto context = frame->GetV8Context();
|
2018-09-10 02:41:13 +02:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
if (context.get() && context->Enter())
|
|
|
|
|
{
|
|
|
|
|
try
|
2015-07-08 18:46:28 +02:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
CefRefPtr<CefV8Exception> exception;
|
|
|
|
|
success = context->Eval(script, scriptUrl, startLine, result, exception);
|
|
|
|
|
|
|
|
|
|
//we need to do this here to be able to store the v8context
|
|
|
|
|
if (success)
|
2020-10-06 15:19:37 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
//If the response is a string of CefSharpDefEvalScriptRes then
|
|
|
|
|
//we don't send the response, we'll let that happen when the promise has completed.
|
|
|
|
|
if (result->IsString() && result->GetStringValue() == "CefSharpDefEvalScriptRes")
|
|
|
|
|
{
|
|
|
|
|
sendResponse = false;
|
|
|
|
|
}
|
2022-12-06 14:54:19 +10:00
|
|
|
else if (result->IsPromise())
|
|
|
|
|
{
|
|
|
|
|
sendResponse = false;
|
|
|
|
|
|
|
|
|
|
auto promiseThen = result->GetValue("then");
|
|
|
|
|
auto promiseCatch = result->GetValue("catch");
|
|
|
|
|
|
|
|
|
|
auto promiseThenFunc = CefV8Value::CreateFunction("promiseResolverThen", new JavascriptPromiseResolverThen(callbackId, false));
|
|
|
|
|
auto promiseCatchFunc = CefV8Value::CreateFunction("promiseResolverCatch", new JavascriptPromiseResolverCatch(callbackId, false));
|
|
|
|
|
|
|
|
|
|
CefV8ValueList promiseThenArgs;
|
|
|
|
|
promiseThenArgs.push_back(promiseThenFunc);
|
|
|
|
|
promiseThen->ExecuteFunction(result, promiseThenArgs);
|
|
|
|
|
|
|
|
|
|
CefV8ValueList promiseCatchArgs;
|
|
|
|
|
promiseCatchArgs.push_back(promiseCatchFunc);
|
|
|
|
|
promiseCatch->ExecuteFunction(result, promiseCatchArgs);
|
|
|
|
|
}
|
2021-02-27 12:11:35 +10:00
|
|
|
else
|
|
|
|
|
{
|
2025-12-03 19:00:12 +10:00
|
|
|
auto callbackRegistry = rootObjectWrapper == nullptr ? nullptr : rootObjectWrapper->CallbackRegistry;
|
|
|
|
|
|
|
|
|
|
if (callbackRegistry == nullptr)
|
|
|
|
|
{
|
|
|
|
|
errorMessage = StringUtils::ToNative("The callback registry for Frame " + frameId + " is no longer available.");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
auto responseArgList = response->GetArgumentList();
|
|
|
|
|
SerializeV8Object(result, responseArgList, 2, callbackRegistry);
|
|
|
|
|
}
|
2021-02-27 12:11:35 +10:00
|
|
|
}
|
2020-10-06 15:19:37 +10:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
errorMessage = StringUtils::CreateExceptionString(exception);
|
2020-10-06 15:19:37 +10:00
|
|
|
}
|
2015-07-08 18:46:28 +02:00
|
|
|
}
|
2021-02-27 12:11:35 +10:00
|
|
|
finally
|
2015-07-10 10:22:12 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
context->Exit();
|
2015-07-10 10:22:12 +10:00
|
|
|
}
|
2015-07-08 18:46:28 +02:00
|
|
|
}
|
2021-02-27 12:11:35 +10:00
|
|
|
else
|
2015-07-10 10:18:01 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
errorMessage = "Unable to Enter Context";
|
2015-07-10 10:18:01 +10:00
|
|
|
}
|
2015-07-08 18:46:28 +02:00
|
|
|
}
|
2015-07-10 10:18:01 +10:00
|
|
|
else
|
2015-06-29 15:08:53 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
errorMessage = StringUtils::ToNative("Frame " + frameId + " is no longer available, most likely the Frame has been Disposed or Removed.");
|
2015-07-07 08:12:04 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
auto callbackRegistry = rootObjectWrapper == nullptr ? nullptr : rootObjectWrapper->CallbackRegistry;
|
|
|
|
|
if (callbackRegistry == nullptr)
|
2015-10-26 11:41:19 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
errorMessage = StringUtils::ToNative("The callback registry for Frame " + frameId + " is no longer available, most likely the Frame has been Disposed.");
|
2015-10-26 11:41:19 +10:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
auto jsCallbackId = GetInt64(argList, 1);
|
2018-09-10 02:41:13 +02:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
auto callbackWrapper = callbackRegistry->FindWrapper(jsCallbackId);
|
|
|
|
|
if (callbackWrapper == nullptr)
|
2015-07-08 18:46:28 +02:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
errorMessage = StringUtils::ToNative("Unable to find JavascriptCallback with Id " + jsCallbackId + " for Frame " + frameId);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
auto context = callbackWrapper->GetContext();
|
|
|
|
|
auto value = callbackWrapper->GetValue();
|
2018-09-10 02:41:13 +02:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
if (context.get() && context->Enter())
|
|
|
|
|
{
|
|
|
|
|
try
|
2015-11-18 09:17:16 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
auto parameterList = argList->GetList(2);
|
|
|
|
|
CefV8ValueList params;
|
2015-11-18 09:17:16 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
//Needs to be called within the context as for Dictionary (mapped to struct)
|
|
|
|
|
//a V8Object will be created
|
|
|
|
|
for (CefV8ValueList::size_type i = 0; i < parameterList->GetSize(); i++)
|
|
|
|
|
{
|
|
|
|
|
params.push_back(DeserializeV8Object(parameterList, static_cast<int>(i)));
|
|
|
|
|
}
|
2018-09-10 02:41:13 +02:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
result = value->ExecuteFunction(nullptr, params);
|
|
|
|
|
success = result.get() != nullptr;
|
|
|
|
|
|
|
|
|
|
//we need to do this here to be able to store the v8context
|
|
|
|
|
if (success)
|
2021-02-15 13:43:51 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
//If the response is a string of CefSharpDefEvalScriptRes then
|
|
|
|
|
//we don't send the response, we'll let that happen when the promise has completed.
|
|
|
|
|
if (result->IsString() && result->GetStringValue() == "CefSharpDefEvalScriptRes")
|
|
|
|
|
{
|
|
|
|
|
sendResponse = false;
|
|
|
|
|
}
|
2022-12-06 14:54:19 +10:00
|
|
|
else if (result->IsPromise())
|
|
|
|
|
{
|
|
|
|
|
sendResponse = false;
|
|
|
|
|
|
|
|
|
|
auto promiseThen = result->GetValue("then");
|
|
|
|
|
auto promiseCatch = result->GetValue("catch");
|
|
|
|
|
|
|
|
|
|
auto promiseThenFunc = CefV8Value::CreateFunction("promiseResolverThen", new JavascriptPromiseResolverThen(callbackId, true));
|
|
|
|
|
auto promiseCatchFunc = CefV8Value::CreateFunction("promiseResolverCatch", new JavascriptPromiseResolverCatch(callbackId, true));
|
|
|
|
|
|
|
|
|
|
CefV8ValueList promiseThenArgs;
|
|
|
|
|
promiseThenArgs.push_back(promiseThenFunc);
|
|
|
|
|
promiseThen->ExecuteFunction(result, promiseThenArgs);
|
|
|
|
|
|
|
|
|
|
CefV8ValueList promiseCatchArgs;
|
|
|
|
|
promiseCatchArgs.push_back(promiseCatchFunc);
|
|
|
|
|
promiseCatch->ExecuteFunction(result, promiseCatchArgs);
|
|
|
|
|
}
|
2021-02-27 12:11:35 +10:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
auto responseArgList = response->GetArgumentList();
|
|
|
|
|
SerializeV8Object(result, responseArgList, 2, callbackRegistry);
|
|
|
|
|
}
|
2021-02-15 13:43:51 +10:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
auto exception = value->GetException();
|
|
|
|
|
errorMessage = StringUtils::CreateExceptionString(exception);
|
2021-02-15 13:43:51 +10:00
|
|
|
}
|
2015-10-26 11:41:19 +10:00
|
|
|
}
|
2021-02-27 12:11:35 +10:00
|
|
|
finally
|
2015-10-26 11:41:19 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
context->Exit();
|
2015-10-26 11:41:19 +10:00
|
|
|
}
|
2015-10-18 14:47:54 -07:00
|
|
|
}
|
2021-02-27 12:11:35 +10:00
|
|
|
else
|
2015-10-18 14:47:54 -07:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
errorMessage = "Unable to Enter Context";
|
2015-07-10 10:22:12 +10:00
|
|
|
}
|
2015-07-08 18:46:28 +02:00
|
|
|
}
|
2015-06-29 15:08:53 +10:00
|
|
|
}
|
|
|
|
|
}
|
2015-07-07 08:12:04 +02:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
if (sendResponse)
|
2020-10-06 15:19:37 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
auto responseArgList = response->GetArgumentList();
|
|
|
|
|
responseArgList->SetBool(0, success);
|
|
|
|
|
SetInt64(responseArgList, 1, callbackId);
|
|
|
|
|
if (!success)
|
|
|
|
|
{
|
|
|
|
|
responseArgList->SetString(2, errorMessage);
|
|
|
|
|
}
|
|
|
|
|
frame->SendProcessMessage(sourceProcessId, response);
|
2020-10-06 15:19:37 +10:00
|
|
|
}
|
2015-06-29 15:08:53 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
handled = true;
|
|
|
|
|
}
|
|
|
|
|
else if (name == kJavascriptCallbackDestroyRequest)
|
2015-10-13 13:00:39 +09:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
if (frame.get() && frame->IsValid())
|
2019-06-14 14:29:53 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
auto jsCallbackId = GetInt64(argList, 0);
|
|
|
|
|
JavascriptRootObjectWrapper^ rootObjectWrapper;
|
2025-12-03 19:00:12 +10:00
|
|
|
_jsRootObjectWrappersByFrameId->TryGetValue(StringUtils::ToClr(frame->GetIdentifier()), rootObjectWrapper);
|
2021-02-27 12:11:35 +10:00
|
|
|
if (rootObjectWrapper != nullptr && rootObjectWrapper->CallbackRegistry != nullptr)
|
|
|
|
|
{
|
|
|
|
|
rootObjectWrapper->CallbackRegistry->Deregister(jsCallbackId);
|
|
|
|
|
}
|
2019-06-14 14:29:53 +10:00
|
|
|
}
|
2015-07-07 08:12:04 +02:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
handled = true;
|
|
|
|
|
}
|
|
|
|
|
else if (name == kJavascriptRootObjectResponse)
|
2018-01-22 10:24:25 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
if (browser.get() && frame.get() && frame->IsValid())
|
2018-01-22 10:24:25 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
auto callbackId = GetInt64(argList, 0);
|
|
|
|
|
auto javascriptObjects = DeserializeJsObjects(argList, 1);
|
|
|
|
|
|
|
|
|
|
//Caching of JavascriptObjects
|
|
|
|
|
//TODO: JSB Should caching be configurable? On a per object basis?
|
|
|
|
|
for each (JavascriptObject ^ obj in Enumerable::OfType<JavascriptObject^>(javascriptObjects))
|
2018-01-22 10:24:25 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
if (_javascriptObjects->ContainsKey(obj->JavascriptName))
|
|
|
|
|
{
|
|
|
|
|
_javascriptObjects->Remove(obj->JavascriptName);
|
|
|
|
|
}
|
|
|
|
|
_javascriptObjects->Add(obj->JavascriptName, obj);
|
2018-01-22 10:24:25 +10:00
|
|
|
}
|
|
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
auto rootObject = GetJsRootObjectWrapper(browser->GetIdentifier(), frame->GetIdentifier());
|
2018-01-22 10:24:25 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
if (rootObject == nullptr)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2018-01-22 10:24:25 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
auto context = frame->GetV8Context();
|
2019-07-20 18:28:36 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
if (context.get() && context->Enter())
|
2018-01-22 10:24:25 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
JavascriptAsyncMethodCallback^ callback;
|
2018-01-22 10:24:25 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
try
|
2019-06-14 14:29:53 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
rootObject->Bind(javascriptObjects, context->GetGlobal());
|
2018-01-29 15:48:54 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
if (_registerBoundObjectRegistry->TryGetAndRemoveMethodCallback(callbackId, callback))
|
2019-06-14 14:29:53 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
//Response object has no Accessor or Interceptor
|
2021-07-31 15:35:38 +10:00
|
|
|
auto response = CefV8Value::CreateObject(nullptr, nullptr);
|
2018-01-22 10:24:25 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
response->SetValue("Count", CefV8Value::CreateInt(javascriptObjects->Count), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
|
2018-01-22 11:59:13 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
if (javascriptObjects->Count > 0)
|
|
|
|
|
{
|
|
|
|
|
//TODO: JSB Should we include a list of successfully bound object names?
|
|
|
|
|
response->SetValue("Success", CefV8Value::CreateBool(true), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
|
|
|
|
|
response->SetValue("Message", CefV8Value::CreateString("OK"), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
|
|
|
|
|
callback->Success(response);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
response->SetValue("Success", CefV8Value::CreateBool(false), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
|
|
|
|
|
response->SetValue("Message", CefV8Value::CreateString("Zero objects bounds"), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
|
|
|
|
|
callback->Success(response);
|
|
|
|
|
}
|
2018-01-22 11:59:13 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
//Send message notifying Browser Process of which objects were bound
|
|
|
|
|
//We do this after the objects have been created in the V8Context to gurantee
|
|
|
|
|
//they are accessible.
|
|
|
|
|
auto msg = CefProcessMessage::Create(kJavascriptObjectsBoundInJavascript);
|
|
|
|
|
auto args = msg->GetArgumentList();
|
2018-04-26 10:20:39 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
auto boundObjects = CefListValue::Create();
|
2018-01-22 11:59:13 +10:00
|
|
|
|
2026-02-20 21:08:41 +10:00
|
|
|
auto i = 0;
|
|
|
|
|
|
|
|
|
|
for each (auto jsObject in javascriptObjects)
|
2021-02-27 12:11:35 +10:00
|
|
|
{
|
|
|
|
|
auto dict = CefDictionaryValue::Create();
|
2026-02-20 21:08:41 +10:00
|
|
|
auto objectName = jsObject->JavascriptName;
|
2021-02-27 12:11:35 +10:00
|
|
|
dict->SetString("Name", StringUtils::ToNative(objectName));
|
|
|
|
|
dict->SetBool("IsCached", false);
|
|
|
|
|
dict->SetBool("AlreadyBound", false);
|
2018-01-22 12:18:17 +10:00
|
|
|
|
2026-02-20 21:08:41 +10:00
|
|
|
boundObjects->SetDictionary(i++, dict);
|
2021-02-27 12:11:35 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
args->SetList(0, boundObjects);
|
|
|
|
|
|
|
|
|
|
frame->SendProcessMessage(CefProcessId::PID_BROWSER, msg);
|
|
|
|
|
}
|
2018-01-22 10:24:25 +10:00
|
|
|
}
|
2021-02-27 12:11:35 +10:00
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
context->Exit();
|
2019-07-20 18:28:36 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
delete callback;
|
|
|
|
|
}
|
2019-06-14 14:29:53 +10:00
|
|
|
}
|
2018-01-22 10:24:25 +10:00
|
|
|
}
|
2021-02-27 12:11:35 +10:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
LOG(INFO) << "CefAppUnmanagedWrapper Frame Invalid";
|
|
|
|
|
}
|
2018-01-22 10:24:25 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
handled = true;
|
|
|
|
|
}
|
|
|
|
|
else if (name == kJavascriptAsyncMethodCallResponse)
|
2019-07-20 18:28:36 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
if (frame.get() && frame->IsValid())
|
|
|
|
|
{
|
2024-03-09 06:55:27 +10:00
|
|
|
auto frameId = StringUtils::ToClr(frame->GetIdentifier());
|
2021-02-27 12:11:35 +10:00
|
|
|
auto callbackId = GetInt64(argList, 0);
|
2017-03-13 11:37:55 +00:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
JavascriptRootObjectWrapper^ rootObjectWrapper;
|
2025-12-03 19:00:12 +10:00
|
|
|
_jsRootObjectWrappersByFrameId->TryGetValue(frameId, rootObjectWrapper);
|
2015-10-11 20:41:17 +10:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
if (rootObjectWrapper != nullptr)
|
2015-10-11 20:41:17 +10:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
JavascriptAsyncMethodCallback^ callback;
|
|
|
|
|
if (rootObjectWrapper->TryGetAndRemoveMethodCallback(callbackId, callback))
|
2017-03-13 11:37:55 +00:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
try
|
2017-03-13 11:37:55 +00:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
auto context = frame->GetV8Context();
|
|
|
|
|
|
|
|
|
|
if (context.get() && context->Enter())
|
2017-03-13 11:37:55 +00:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
try
|
2017-03-13 11:37:55 +00:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
auto success = argList->GetBool(1);
|
|
|
|
|
if (success)
|
|
|
|
|
{
|
|
|
|
|
callback->Success(DeserializeV8Object(argList, 2));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
callback->Fail(argList->GetString(2));
|
|
|
|
|
}
|
2017-03-13 11:37:55 +00:00
|
|
|
}
|
2021-02-27 12:11:35 +10:00
|
|
|
finally
|
2017-03-13 11:37:55 +00:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
context->Exit();
|
2017-03-13 11:37:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
2021-02-27 12:11:35 +10:00
|
|
|
else
|
2017-03-13 11:37:55 +00:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
callback->Fail("Unable to Enter Context");
|
2017-03-13 11:37:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
2021-02-27 12:11:35 +10:00
|
|
|
finally
|
2017-03-13 11:37:55 +00:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
//dispose
|
|
|
|
|
delete callback;
|
2017-03-13 11:37:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
2015-10-11 20:41:17 +10:00
|
|
|
}
|
2015-07-14 15:09:50 +02:00
|
|
|
}
|
2021-02-27 12:11:35 +10:00
|
|
|
handled = true;
|
2015-07-14 15:09:50 +02:00
|
|
|
}
|
2015-06-27 17:01:51 +02:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
return handled;
|
|
|
|
|
};
|
2015-07-14 15:09:50 +02:00
|
|
|
|
2021-02-27 12:11:35 +10:00
|
|
|
void CefAppUnmanagedWrapper::OnWebKitInitialized()
|
2015-08-01 20:25:12 +02:00
|
|
|
{
|
2021-02-27 12:11:35 +10:00
|
|
|
if (!Object::ReferenceEquals(_handler, nullptr))
|
|
|
|
|
{
|
|
|
|
|
_handler->OnWebKitInitialized();
|
|
|
|
|
}
|
2015-08-01 20:25:12 +02:00
|
|
|
}
|
2015-07-14 15:09:50 +02:00
|
|
|
}
|
2018-10-28 16:52:21 +10:00
|
|
|
}
|