完善浏览器

This commit is contained in:
JackLee 2025-03-29 16:44:53 +08:00
parent c41a936bbf
commit 8ff67ba1cd
25 changed files with 179 additions and 2644 deletions

View File

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<description>ctai</description>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="asInvoker"
uiAccess="false"
/>
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
</application>
</compatibility>
</assembly>

46
compatibility.manifest Normal file
View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="Win32" name="ctai" version="6.0.0.0" processorArchitecture="x86" />
<file name="chrome_100_percent.pak" loadFrom=".\cef_binary\chrome_100_percent.pak"></file>
<file name="chrome_200_percent.pak" loadFrom=".\cef_binary\chrome_200_percent.pak"></file>
<file name="chrome_elf.dll" loadFrom=".\cef_binary\chrome_elf.dll"></file>
<file name="d3dcompiler_47.dll" loadFrom=".\cef_binary\d3dcompiler_47.dll"></file>
<file name="dxcompiler.dll" loadFrom=".\cef_binary\dxcompiler.dll"></file>
<file name="dxil.dll" loadFrom=".\cef_binary\dxil.dll"></file>
<file name="icudtl.dat" loadFrom=".\cef_binary\icudtl.dat"></file>
<file name="libcef.dll" loadFrom=".\cef_binary\libcef.dll"></file>
<file name="libEGL.dll" loadFrom=".\cef_binary\libEGL.dll"></file>
<file name="libGLESv2.dll" loadFrom=".\cef_binary\libGLESv2.dll"></file>
<file name="resources.pak" loadFrom=".\cef_binary\resources.pak"></file>
<file name="snapshot_blob.bin" loadFrom=".\cef_binary\snapshot_blob.bin"></file>
<file name="v8_context_snapshot.bin" loadFrom=".\cef_binary\v8_context_snapshot.bin"></file>
<file name="vk_swiftshader.dll" loadFrom=".\cef_binary\vk_swiftshader.dll"></file>
<file name="vk_swiftshader_icd.json" loadFrom=".\cef_binary\vk_swiftshader_icd.json"></file>
<file name="vulkan-1.dll" loadFrom=".\cef_binary\vulkan-1.dll"></file>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!--The ID below indicates application support for Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!--The ID below indicates application support for Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!--The ID below indicates application support for Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!--The ID below indicates application support for Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!--The ID below indicates application support for Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- This tag is required for XAML islands usage in the process for media scenarios. -->
<!-- This version corresponds to the Windows 10 May 2019 Update. -->
<maxversiontested Id="10.0.18362.0"/>
</application>
</compatibility>
</assembly>

View File

@ -1,73 +0,0 @@
#include "CefViewAppBase.h"
#include "../Common/CefViewCoreLog.h"
#include <CefViewCoreProtocol.h>
// These flags must match the Chromium values.
const char kProcessType[] = "type";
const char kZygoteProcess[] = "zygote";
const char kRendererProcess[] = "renderer";
CefViewAppBase::CefViewAppBase(const CefString& scheme_name)
: builtin_scheme_name_(scheme_name)
{
}
// static
CefViewAppBase::ProcessType
CefViewAppBase::GetProcessType(CefRefPtr<CefCommandLine> command_line)
{
// The command-line flag won't be specified for the browser process.
if (!command_line->HasSwitch(kProcessType))
return UnkownProcess;
auto process_type = command_line->GetSwitchValue(kProcessType);
logI("process type parameter is: %s", process_type.c_str());
if (process_type == kZygoteProcess) {
// for linux only
return ZygoteProcess;
} else if (process_type == kRendererProcess) {
return RendererProcess;
}
return OtherProcess;
}
CefString
CefViewAppBase::GetBridgeObjectName(CefRefPtr<CefCommandLine> command_line)
{
if (!command_line->HasSwitch(kCefViewBridgeObjectNameKey))
return "";
auto name = command_line->GetSwitchValue(kCefViewBridgeObjectNameKey);
logI("bridge object name: %s", name.c_str());
return name;
}
CefString
CefViewAppBase::GetBuiltinSchemeName(CefRefPtr<CefCommandLine> command_line)
{
if (!command_line->HasSwitch(kCefViewBuiltinSchemeNameKey))
return "";
auto name = command_line->GetSwitchValue(kCefViewBuiltinSchemeNameKey);
logI("built-in scheme name: %s", name.c_str());
return name;
}
void
CefViewAppBase::OnRegisterCustomSchemes(CefRawPtr<CefSchemeRegistrar> registrar)
{
if (registrar) {
int options = 0 //
| CEF_SCHEME_OPTION_STANDARD //
| CEF_SCHEME_OPTION_SECURE //
| CEF_SCHEME_OPTION_CORS_ENABLED //
| CEF_SCHEME_OPTION_FETCH_ENABLED //
| 0;
auto scheme = builtin_scheme_name_.empty() ? kCefViewDefaultBuiltinSchemaName : builtin_scheme_name_;
if (!registrar->AddCustomScheme(scheme, options)) {
logE("faield to add built-in scheme: %s", scheme.c_str());
}
}
}

View File

@ -1,67 +0,0 @@
//
// CefWingAppBase.hpp
// CefViewWing
//
// Created by Sheen Tian on 2020/6/17.
//
#ifndef CefAppBase_h
#define CefAppBase_h
#pragma region stl_headers
#include <string>
#include <vector>
#pragma endregion
#pragma region cef_headers
#include <include/cef_app.h>
#pragma endregion
class CefViewAppBase : public CefApp
{
/// <summary>
///
/// </summary>
CefString builtin_scheme_name_;
public:
CefViewAppBase(const CefString& scheme_name);
enum ProcessType
{
UnkownProcess,
ZygoteProcess,
RendererProcess,
OtherProcess,
};
/// <summary>
/// Gets the current process type
/// </summary>
/// <param name="command_line">The command line</param>
/// <returns>The process type</returns>
static ProcessType GetProcessType(CefRefPtr<CefCommandLine> command_line);
/// <summary>
/// Gets the bridge object name from command line
/// </summary>
/// <param name="command_line">The command line</param>
/// <returns>The bridge object name</returns>
static CefString GetBridgeObjectName(CefRefPtr<CefCommandLine> command_line);
/// <summary>
/// Gets the built-in scheme name
/// </summary>
/// <param name="command_line">The command line</param>
/// <returns>The built-in scheme name</returns>
static CefString GetBuiltinSchemeName(CefRefPtr<CefCommandLine> command_line);
private:
/// <summary>
///
/// </summary>
/// <param name="registrar"></param>
virtual void OnRegisterCustomSchemes(CefRawPtr<CefSchemeRegistrar> registrar) override;
};
#endif

View File

@ -1,6 +0,0 @@
#include "CefViewOtherApp.h"
CefViewOtherApp::CefViewOtherApp(const CefString& scheme_name)
: CefViewAppBase(scheme_name)
{
}

View File

@ -1,22 +0,0 @@
//
// CefOtherApp.hpp
// CefViewWing
//
// Created by Sheen Tian on 2020/6/17.
//
#ifndef CefOtherApp_h
#define CefOtherApp_h
#pragma once
#include "CefViewAppBase.h"
class CefViewOtherApp : public CefViewAppBase
{
IMPLEMENT_REFCOUNTING(CefViewOtherApp);
public:
CefViewOtherApp(const CefString& scheme_name);
};
#endif

View File

@ -1,208 +0,0 @@
#include "CefViewRenderApp.h"
#pragma region cef_headers
#include <include/cef_browser.h>
#include <include/cef_command_line.h>
#include <include/wrapper/cef_helpers.h>
#pragma endregion
#include "../Common/CefViewCoreLog.h"
#include <CefViewCoreProtocol.h>
CefViewRenderApp::CefViewRenderApp(const CefString& scheme_name, const CefString& bridge_name)
: CefViewAppBase(scheme_name)
, bridge_object_name_(bridge_name)
, last_node_is_editable_(false)
{
}
CefViewRenderApp::~CefViewRenderApp() {}
//////////////////////////////////////////////////////////////////////////
CefRefPtr<CefRenderProcessHandler>
CefViewRenderApp::GetRenderProcessHandler()
{
return this;
}
void
CefViewRenderApp::OnWebKitInitialized()
{
CEF_REQUIRE_RENDERER_THREAD();
CefMessageRouterConfig config;
config.js_query_function = kCefViewQueryFuntionName;
config.js_cancel_function = kCefViewQueryCancelFunctionName;
message_router_ = CefMessageRouterRendererSide::Create(config);
}
void
CefViewRenderApp::OnBrowserCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefDictionaryValue> extra_info)
{
CEF_REQUIRE_RENDERER_THREAD();
}
void
CefViewRenderApp::OnBrowserDestroyed(CefRefPtr<CefBrowser> browser)
{
CEF_REQUIRE_RENDERER_THREAD();
}
CefRefPtr<CefLoadHandler>
CefViewRenderApp::GetLoadHandler()
{
CEF_REQUIRE_RENDERER_THREAD();
return nullptr;
}
void
CefViewRenderApp::OnContextCreated(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context)
{
CEF_REQUIRE_RENDERER_THREAD();
// [Javascript Context]
// V8 context for this frame has been initialized already,
// but the script of the page hasn't been executed now
message_router_->OnContextCreated(browser, frame, context);
// log this event
frame->ExecuteJavaScript("console.info('[JSRuntime]:frame context created')", frame->GetURL(), 0);
// binding bridge object and functions
auto frameId = frame->GetIdentifier();
auto it = frame_id_to_bridge_obj_map_.find(frameId);
if (it == frame_id_to_bridge_obj_map_.end()) {
// create and insert the bridge Object into this frame.window object
CefRefPtr<CefV8Value> objWindow = context->GetGlobal();
CefRefPtr<CefViewBridgeObject> objClient = new CefViewBridgeObject(browser, frame, objWindow, bridge_object_name_);
if (!objClient) {
log_error("Failed to create the client object");
return;
}
frame_id_to_bridge_obj_map_[frameId] = objClient;
}
}
void
CefViewRenderApp::OnContextReleased(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context)
{
CEF_REQUIRE_RENDERER_THREAD();
message_router_->OnContextReleased(browser, frame, context);
auto frameId = frame->GetIdentifier();
auto it = frame_id_to_bridge_obj_map_.find(frameId);
if (it != frame_id_to_bridge_obj_map_.end()) {
frame_id_to_bridge_obj_map_.erase(it);
}
}
void
CefViewRenderApp::OnUncaughtException(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context,
CefRefPtr<CefV8Exception> exception,
CefRefPtr<CefV8StackTrace> stackTrace)
{
CEF_REQUIRE_RENDERER_THREAD();
}
void
CefViewRenderApp::OnFocusedNodeChanged(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefDOMNode> node)
{
CEF_REQUIRE_RENDERER_THREAD();
bool is_editable = (node.get() && node->IsEditable());
if (is_editable != last_node_is_editable_) {
// Notify the browser of the change in focused element type.
last_node_is_editable_ = is_editable;
CefRefPtr<CefProcessMessage> message = CefProcessMessage::Create(kCefViewClientRenderFocusedNodeChangedMessage);
message->GetArgumentList()->SetBool(0, is_editable);
frame->SendProcessMessage(PID_BROWSER, message);
}
}
bool
CefViewRenderApp::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefProcessId source_process,
CefRefPtr<CefProcessMessage> message)
{
CEF_REQUIRE_RENDERER_THREAD();
bool handled = false;
if (message_router_->OnProcessMessageReceived(browser, frame, source_process, message)) {
handled = true;
}
if (OnTriggerEventNotifyMessage(browser, frame, source_process, message)) {
handled = true;
}
return handled;
}
bool
CefViewRenderApp::OnTriggerEventNotifyMessage(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefProcessId source_process,
CefRefPtr<CefProcessMessage> message)
{
if (message->GetName() == kCefViewClientBrowserTriggerEventMessage) {
CefRefPtr<CefListValue> args = message->GetArgumentList()->Copy();
//** arguments(CefValueList)
//** +------------+
//** | event name |
//** | event arg1 |
//** | event arg2 |
//** | event arg3 |
//** | event arg4 |
//** | ... |
//** | ... |
//** | ... |
//** | ... |
//** +------------+
if (!args || args->GetSize() <= 0) {
log_error("Invalid message arguments, event name is required");
return true;
}
if (CefValueType::VTYPE_STRING != args->GetType(0)) {
log_error("Invalid message arguments, invalid type for event name");
return true;
}
auto name = args->GetString(0);
args->Remove(0);
ExecuteEventListener(browser, frame, name, args);
return true;
}
return false;
}
void
CefViewRenderApp::ExecuteEventListener(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& name,
CefRefPtr<CefListValue> args)
{
if (browser && frame) {
auto frameId = frame->GetIdentifier();
auto it = frame_id_to_bridge_obj_map_.find(frameId);
if (it != frame_id_to_bridge_obj_map_.end()) {
const CefRefPtr<CefViewBridgeObject>& objClient = it->second;
objClient->ExecuteEventListener(name, args);
}
}
}

View File

@ -1,180 +0,0 @@
#ifndef CefRenderApp_h
#define CefRenderApp_h
#pragma once
#pragma region stl_headers
#include <unordered_map>
#pragma endregion
#pragma region cef_headers
#include <include/wrapper/cef_message_router.h>
#pragma endregion
#include <CefViewCoreGlobal.h>
#include "CefViewAppBase.h"
#include "../Bridge/CefViewBridgeObject.h"
/// <summary>
///
/// </summary>
class CefViewRenderApp
: public CefViewAppBase
, public CefRenderProcessHandler
{
// Include the default reference counting implementation.
IMPLEMENT_REFCOUNTING(CefViewRenderApp);
private:
CefString bridge_object_name_;
/// <summary>
///
/// </summary>
CefRefPtr<CefMessageRouterRendererSide> message_router_;
/// <summary>
///
/// </summary>
typedef std::unordered_map<CefFrameId, CefRefPtr<CefViewBridgeObject>> FrameID2BridgeObjMap;
FrameID2BridgeObjMap frame_id_to_bridge_obj_map_;
/// <summary>
///
/// </summary>
bool last_node_is_editable_;
public:
/// <summary>
///
/// </summary>
CefViewRenderApp(const CefString& scheme_name, const CefString& bridge_name);
/// <summary>
///
/// </summary>
~CefViewRenderApp();
private:
#pragma region CefApp
/// <summary>
///
/// </summary>
/// <returns></returns>
virtual CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() override;
#pragma endregion
#pragma region CefRenderProcessHandler
/// <summary>
///
/// </summary>
virtual void OnWebKitInitialized() override;
/// <summary>
///
/// </summary>
/// <param name="browser"></param>
/// <param name="extra_info"></param>
virtual void OnBrowserCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefDictionaryValue> extra_info) override;
/// <summary>
///
/// </summary>
/// <param name="browser"></param>
virtual void OnBrowserDestroyed(CefRefPtr<CefBrowser> browser) override;
/// <summary>
///
/// </summary>
/// <returns></returns>
virtual CefRefPtr<CefLoadHandler> GetLoadHandler() override;
/// <summary>
///
/// </summary>
/// <param name="browser"></param>
/// <param name="frame"></param>
/// <param name="context"></param>
virtual void OnContextCreated(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context) override;
/// <summary>
///
/// </summary>
/// <param name="browser"></param>
/// <param name="frame"></param>
/// <param name="context"></param>
virtual void OnContextReleased(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context) override;
/// <summary>
///
/// </summary>
/// <param name="browser"></param>
/// <param name="frame"></param>
/// <param name="context"></param>
/// <param name="exception"></param>
/// <param name="stackTrace"></param>
virtual void OnUncaughtException(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context,
CefRefPtr<CefV8Exception> exception,
CefRefPtr<CefV8StackTrace> stackTrace) override;
/// <summary>
///
/// </summary>
/// <param name="browser"></param>
/// <param name="frame"></param>
/// <param name="node"></param>
virtual void OnFocusedNodeChanged(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefDOMNode> node) override;
/// <summary>
///
/// </summary>
/// <param name="browser"></param>
/// <param name="frame"></param>
/// <param name="source_process"></param>
/// <param name="message"></param>
/// <returns></returns>
virtual bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefProcessId source_process,
CefRefPtr<CefProcessMessage> message) override;
#pragma endregion
private:
/// <summary>
///
/// </summary>
/// <param name="browser"></param>
/// <param name="frame"></param>
/// <param name="source_process"></param>
/// <param name="message"></param>
/// <returns></returns>
bool OnTriggerEventNotifyMessage(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefProcessId source_process,
CefRefPtr<CefProcessMessage> message);
/// <summary>
///
/// </summary>
/// <param name="browser"></param>
/// <param name="frame"></param>
/// <param name="name"></param>
/// <param name="list"></param>
void ExecuteEventListener(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& name,
CefRefPtr<CefListValue> args);
};
#endif

View File

@ -1,517 +0,0 @@
#include "CefViewBridgeObject.h"
#include <include/cef_version.h>
#include "../Common/CefViewCoreLog.h"
#include <CefViewCoreProtocol.h>
#if CEF_VERSION_MAJOR >= 119
class CefViewArrayBuffer : public CefV8ArrayBufferReleaseCallback
{
IMPLEMENT_REFCOUNTING(CefViewArrayBuffer);
DISALLOW_COPY_AND_ASSIGN(CefViewArrayBuffer);
public:
/// <summary>
///
/// </summary>
/// <param name="v"></param>
CefViewArrayBuffer(CefBinaryValue* v)
: m_size(0)
, m_buffer(nullptr)
{
if (v) {
auto l = v->GetSize();
if (l) {
m_buffer = std::make_unique<uint8_t[]>(l);
v->GetData(m_buffer.get(), l, 0);
m_size = l;
}
}
}
/// <summary>
///
/// </summary>
~CefViewArrayBuffer()
{
m_buffer.reset();
m_size = 0;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
void* GetBuffer()
{
// get under layer buffer address
return m_buffer.get();
}
/// <summary>
///
/// </summary>
/// <returns></returns>
size_t GetSize()
{
// return size
return m_size;
}
/// <summary>
///
/// </summary>
/// <param name="buffer"></param>
void ReleaseBuffer(void* buffer) override
{
// release under layer buffer
m_buffer.reset();
m_size = 0;
}
private:
size_t m_size;
std::unique_ptr<uint8_t[]> m_buffer;
};
#endif
CefViewBridgeObject::V8Handler::V8Handler(CefViewBridgeObject* object)
: object_(object)
{
}
bool
CefViewBridgeObject::V8Handler::Execute(const CefString& function,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception)
{
if (function == kCefViewInvokeMethodFunctionName)
ExecuteNativeMethod(object, arguments, retval, exception);
else if (function == kCefViewAddEventListenerFunctionName)
ExecuteAddEventListener(object, arguments, retval, exception);
else if (function == kCefViewRemoveEventListenerFunctionName)
ExecuteRemoveEventListener(object, arguments, retval, exception);
else if (function == kCefViewReportJSResultFunctionName)
ExecuteReportJSResult(object, arguments, retval, exception);
else
return false;
return true;
}
void
CefViewBridgeObject::V8Handler::ExecuteNativeMethod(CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception)
{
object_->AsyncExecuteNativeMethod(arguments);
retval = CefV8Value::CreateUndefined();
}
void
CefViewBridgeObject::V8Handler::ExecuteAddEventListener(CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception)
{
bool bRet = false;
if (arguments.size() == 2) {
if (arguments[0]->IsString()) {
if (arguments[1]->IsFunction()) {
CefString eventName = arguments[0]->GetStringValue();
EventListener listener;
listener.callback_ = arguments[1];
listener.context_ = CefV8Context::GetCurrentContext();
object_->AddEventListener(eventName, listener);
bRet = true;
} else
exception = "Invalid arguments; argument 2 must be a function";
} else
exception = "Invalid arguments; argument 1 must be a string";
} else
exception = "Invalid arguments; expecting 2 arguments";
retval = CefV8Value::CreateBool(bRet);
}
void
CefViewBridgeObject::V8Handler::ExecuteRemoveEventListener(CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception)
{
bool bRet = false;
if (arguments.size() == 2) {
if (arguments[0]->IsString()) {
if (arguments[1]->IsFunction()) {
CefString eventName = arguments[0]->GetStringValue();
EventListener listener;
listener.callback_ = arguments[1];
listener.context_ = CefV8Context::GetCurrentContext();
object_->RemoveEventListener(eventName, listener);
bRet = true;
} else
exception = "Invalid arguments; argument 2 must be a function";
} else
exception = "Invalid arguments; argument 1 must be a string";
} else
exception = "Invalid arguments; expecting 2 arguments";
retval = CefV8Value::CreateBool(bRet);
}
void
CefViewBridgeObject::V8Handler::ExecuteReportJSResult(CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception)
{
if (arguments.size() == 2) {
if (arguments[0]->IsString()) {
object_->AsyncExecuteReportJSResult(arguments);
} else
exception = "Invalid argument; argument 1 must be a double";
} else
exception = "Invalid argument; expecting 2 argument";
retval = CefV8Value::CreateUndefined();
}
//////////////////////////////////////////////////////////////////////////
CefViewBridgeObject::CefViewBridgeObject(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Value> global,
const CefString& name)
: name_(name.empty() ? kCefViewDefaultBridgeObjectName : name)
, bridgeObject_(nullptr)
, reportJSResultFunction_(nullptr)
, browser_(browser)
, frame_(frame)
, v8Handler_(new V8Handler(this))
{
// create bridge object and mount it on the global context(window)
bridgeObject_ = CefV8Value::CreateObject(nullptr, nullptr);
// create function "invokeMethod"
CefRefPtr<CefV8Value> funcInvokeMethod = CefV8Value::CreateFunction(kCefViewInvokeMethodFunctionName, v8Handler_);
// add this function to window object
bridgeObject_->SetValue(kCefViewInvokeMethodFunctionName,
funcInvokeMethod,
static_cast<CefV8Value::PropertyAttribute>(V8_PROPERTY_ATTRIBUTE_READONLY |
V8_PROPERTY_ATTRIBUTE_DONTENUM |
V8_PROPERTY_ATTRIBUTE_DONTDELETE));
// create function addEventListener
CefRefPtr<CefV8Value> funcAddEventListener =
CefV8Value::CreateFunction(kCefViewAddEventListenerFunctionName, v8Handler_);
// add this function to window object
bridgeObject_->SetValue(kCefViewAddEventListenerFunctionName,
funcAddEventListener,
static_cast<CefV8Value::PropertyAttribute>(V8_PROPERTY_ATTRIBUTE_READONLY |
V8_PROPERTY_ATTRIBUTE_DONTENUM |
V8_PROPERTY_ATTRIBUTE_DONTDELETE));
// create function removeListener
CefRefPtr<CefV8Value> funcRemoveEventListener =
CefV8Value::CreateFunction(kCefViewRemoveEventListenerFunctionName, v8Handler_);
// add this function to window object
bridgeObject_->SetValue(kCefViewRemoveEventListenerFunctionName,
funcRemoveEventListener,
static_cast<CefV8Value::PropertyAttribute>(V8_PROPERTY_ATTRIBUTE_READONLY |
V8_PROPERTY_ATTRIBUTE_DONTENUM |
V8_PROPERTY_ATTRIBUTE_DONTDELETE));
// mount the client object to the global context(usually the window object)
global->SetValue(name_,
bridgeObject_,
static_cast<CefV8Value::PropertyAttribute>(V8_PROPERTY_ATTRIBUTE_READONLY |
V8_PROPERTY_ATTRIBUTE_DONTENUM |
V8_PROPERTY_ATTRIBUTE_DONTDELETE));
frame_->ExecuteJavaScript("console.info('[JSRuntime]:window." + name_.ToString() + " [object] created');", frame_->GetURL(), 0);
// create "__cefview_report_js_result__" function and mount it on the global context(window)
reportJSResultFunction_ = CefV8Value::CreateFunction(kCefViewReportJSResultFunctionName, v8Handler_);
global->SetValue(kCefViewReportJSResultFunctionName,
reportJSResultFunction_,
static_cast<CefV8Value::PropertyAttribute>(V8_PROPERTY_ATTRIBUTE_READONLY |
V8_PROPERTY_ATTRIBUTE_DONTENUM |
V8_PROPERTY_ATTRIBUTE_DONTDELETE));
frame_->ExecuteJavaScript("console.info('[JSRuntime]:window." kCefViewReportJSResultFunctionName
" [function] created');",
frame_->GetURL(),
0);
}
CefRefPtr<CefV8Value>
CefViewBridgeObject::CefValueToV8Value(CefValue* cefValue)
{
CefRefPtr<CefV8Value> v8Value = CefV8Value::CreateNull();
if (!cefValue) {
return v8Value;
}
auto type = cefValue->GetType();
switch (type) {
case CefValueType::VTYPE_INVALID: {
v8Value = CefV8Value::CreateUndefined();
} break;
case CefValueType::VTYPE_NULL: {
v8Value = CefV8Value::CreateNull();
} break;
case CefValueType::VTYPE_BOOL: {
auto v = cefValue->GetBool();
v8Value = CefV8Value::CreateBool(v);
} break;
case CefValueType::VTYPE_INT: {
auto v = cefValue->GetInt();
v8Value = CefV8Value::CreateInt(v);
} break;
case CefValueType::VTYPE_DOUBLE: {
auto v = cefValue->GetDouble();
v8Value = CefV8Value::CreateDouble(v);
} break;
case CefValueType::VTYPE_STRING: {
auto v = cefValue->GetString();
v8Value = CefV8Value::CreateString(v);
} break;
case CefValueType::VTYPE_BINARY: {
#if CEF_VERSION_MAJOR >= 119
auto v = cefValue->GetBinary();
auto arryBuffer = new CefViewArrayBuffer(v.get());
v8Value = CefV8Value::CreateArrayBuffer(arryBuffer->GetBuffer(), arryBuffer->GetSize(), arryBuffer);
#else
// currently not supported
#endif
} break;
case CefValueType::VTYPE_DICTIONARY: {
auto cDict = cefValue->GetDictionary();
CefDictionaryValue::KeyList cKeys;
cDict->GetKeys(cKeys);
v8Value = CefV8Value::CreateObject(nullptr, nullptr);
for (auto& key : cKeys) {
auto cVal = cDict->GetValue(key);
auto v8Val = CefValueToV8Value(cVal.get());
v8Value->SetValue(key, v8Val.get(), V8_PROPERTY_ATTRIBUTE_NONE);
}
} break;
case CefValueType::VTYPE_LIST: {
auto cList = cefValue->GetList();
int cCount = static_cast<int>(cList->GetSize());
v8Value = CefV8Value::CreateArray(static_cast<int>(cCount));
for (int i = 0; i < cCount; i++) {
auto cVal = cList->GetValue(i);
auto v8Val = CefValueToV8Value(cVal.get());
v8Value->SetValue(i, v8Val.get());
}
} break;
default:
break;
}
return v8Value;
}
CefRefPtr<CefValue>
CefViewBridgeObject::V8ValueToCefValue(CefV8Value* v8Value)
{
CefRefPtr<CefValue> cefValue = CefValue::Create();
if (!v8Value) {
return cefValue;
}
/**
* The IsDouble, IsInt and IsUint methods return a boolean value indicating whether the CefV8Value instance is an
* target type or can be converted to the target type.If the value can be converted to the target type, the methods
* will attempt to do so and return true. If the value is not the target type or cannot be converted to the target
* type, the method will return false.
*
* For example the code below:
* auto v = CefV8Value::CreateInt(1000);
* auto isDouble = v->IsDouble();
* logD("isDouble: %d", isDouble); // true
* auto isUnint = v->IsUInt();
* logD("isUnint: %d", isUnint); // true
* auto isInt = v->IsInt();
* logD("isInt: %d", isInt); // true
*
* auto v = CefV8Value::CreateDouble(0.1);
* auto isDouble = v->IsDouble();
* logD("isDouble: %d", isDouble); // true
* auto isUnint = v->IsUInt();
* logD("isUnint: %d", isUnint); // false
* auto isInt = v->IsInt();
* logD("isInt: %d", isInt); // false
*
* so we need to keep the testing order, IsInt/IsUint - IsDouble
* since there is no Uint type in JavaScript, we just ignore it.
* Please refer to this test souce:
* https://github.com/svn2github/cef/blob/master/tests/cefclient/binding_test.cpp
*/
if (v8Value->IsNull() || v8Value->IsUndefined())
cefValue->SetNull();
else if (v8Value->IsBool())
cefValue->SetBool(v8Value->GetBoolValue());
else if (v8Value->IsInt())
cefValue->SetInt(v8Value->GetIntValue());
else if (v8Value->IsDouble())
cefValue->SetDouble(v8Value->GetDoubleValue());
else if (v8Value->IsString())
cefValue->SetString(v8Value->GetStringValue());
else if (v8Value->IsArrayBuffer()) {
#if CEF_VERSION_MAJOR >= 119
auto size = v8Value->GetArrayBufferByteLength();
auto data = v8Value->GetArrayBufferData();
cefValue->SetBinary(CefBinaryValue::Create(data, size));
#else
// currently not supported
#endif
} else if (v8Value->IsArray()) {
auto s = v8Value->GetArrayLength();
auto cefList = CefListValue::Create();
for (int i = 0; i < s; i++) {
auto v8Val = v8Value->GetValue(i);
auto cefVal = V8ValueToCefValue(v8Val.get());
cefList->SetValue(i, cefVal);
}
cefValue->SetList(cefList);
} else if (v8Value->IsObject()) {
CefDictionaryValue::KeyList keys;
v8Value->GetKeys(keys);
auto cefDict = CefDictionaryValue::Create();
for (auto& key : keys) {
auto v8Val = v8Value->GetValue(key);
auto cefVal = V8ValueToCefValue(v8Val.get());
cefDict->SetValue(key, cefVal.get());
}
cefValue->SetDictionary(cefDict);
} else
cefValue->SetNull();
return cefValue;
}
void
CefViewBridgeObject::AsyncExecuteNativeMethod(const CefV8ValueList& arguments)
{
CefRefPtr<CefProcessMessage> msg = CefProcessMessage::Create(kCefViewClientRenderInvokeMethodMessage);
//** arguments(CefValueList)
//** +-------+
//** |0 name | <- the method name
//** |1 arg1 |
//** |2 arg2 |
//** |3 arg3 |
//** |4 arg4 |
//** | ... |
//** | ... |
//** | ... |
//** | ... |
//** +-------+
CefRefPtr<CefListValue> args = msg->GetArgumentList();
// push back all the arguments
for (std::size_t i = 0; i < arguments.size(); i++) {
auto cefValue = V8ValueToCefValue(arguments[i].get());
args->SetValue(i, cefValue);
}
// send the message
if (browser_)
frame_->SendProcessMessage(PID_BROWSER, msg);
}
void
CefViewBridgeObject::AsyncExecuteReportJSResult(const CefV8ValueList& arguments)
{
CefRefPtr<CefProcessMessage> msg = CefProcessMessage::Create(kCefViewClientRenderReportJSResultMessage);
//** arguments(CefValueList)
//** +_------+
//** |0 arg | <- the context (string)
//** |1 arg | <- the result value
//** +-------+
CefRefPtr<CefListValue> args = msg->GetArgumentList();
// push back the result value
for (std::size_t i = 0; i < arguments.size(); i++) {
auto cefValue = V8ValueToCefValue(arguments[i].get());
args->SetValue(i, cefValue.get());
}
// send the message
if (browser_)
frame_->SendProcessMessage(PID_BROWSER, msg);
}
void
CefViewBridgeObject::AddEventListener(const CefString& name, const EventListener& listener)
{
auto itListenerList = eventListenerListMap_.find(name);
if (itListenerList == eventListenerListMap_.end()) {
EventListenerList eventListenerList;
eventListenerList.push_back(listener);
eventListenerListMap_[name] = eventListenerList;
} else {
EventListenerList& eventListenerList = itListenerList->second;
// does this listener exist?
bool found = false;
for (auto item : eventListenerList) {
if (item.callback_->IsSame(listener.callback_)) {
found = true;
break;
}
}
if (!found)
eventListenerList.push_back(listener);
}
}
void
CefViewBridgeObject::RemoveEventListener(const CefString& name, const EventListener& listener)
{
auto itListenerList = eventListenerListMap_.find(name);
if (itListenerList != eventListenerListMap_.end()) {
EventListenerList& eventListenerList = itListenerList->second;
for (auto itListener = eventListenerList.begin(); itListener != eventListenerList.end(); itListener++) {
if (itListener->callback_->IsSame(listener.callback_)) {
eventListenerList.erase(itListener);
break;
}
}
}
}
void
CefViewBridgeObject::ExecuteEventListener(const CefString eventName, CefRefPtr<CefListValue> args)
{
// find the listeners
auto itListenerList = eventListenerListMap_.find(eventName);
if (itListenerList == eventListenerListMap_.end()) {
return;
}
EventListenerList& eventListenerList = itListenerList->second;
for (auto listener : eventListenerList) {
listener.context_->Enter();
// convert argument list from CefValue to CefV8Value
CefV8ValueList v8ArgList;
for (size_t i = 0; i < args->GetSize(); i++) {
auto cefValue = args->GetValue(i);
auto v8Value = CefValueToV8Value(cefValue.get());
v8ArgList.push_back(v8Value.get());
}
listener.callback_->ExecuteFunction(bridgeObject_, v8ArgList);
listener.context_->Exit();
}
}

View File

@ -1,221 +0,0 @@
#pragma once
#pragma region stl_headers
#include <list>
#include <map>
#pragma endregion
#pragma region cef_headers
#include <include/cef_v8.h>
#pragma endregion
/// <summary>
///
/// </summary>
class CefViewBridgeObject : public CefBaseRefCounted
{
IMPLEMENT_REFCOUNTING(CefViewBridgeObject);
DISALLOW_COPY_AND_ASSIGN(CefViewBridgeObject);
/// <summary>
///
/// </summary>
typedef struct _EventListener
{
CefRefPtr<CefV8Value> callback_;
CefRefPtr<CefV8Context> context_;
} EventListener;
/// <summary>
///
/// </summary>
typedef std::list<EventListener> EventListenerList;
/// <summary>
///
/// </summary>
typedef std::map<CefString, std::list<EventListener>> EventListenerListMap;
/// <summary>
///
/// </summary>
class V8Handler : public CefV8Handler
{
public:
/// <summary>
///
/// </summary>
/// <param name="client"></param>
V8Handler(CefViewBridgeObject* object);
/// <summary>
///
/// </summary>
/// <param name="function"></param>
/// <param name="object"></param>
/// <param name="arguments"></param>
/// <param name="retval"></param>
/// <param name="exception"></param>
/// <returns></returns>
virtual bool Execute(const CefString& function,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception) override;
protected:
/// <summary>
///
/// </summary>
/// <param name="object"></param>
/// <param name="arguments"></param>
/// <param name="retval"></param>
/// <param name="exception"></param>
void ExecuteNativeMethod(CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception);
/// <summary>
///
/// </summary>
/// <param name="object"></param>
/// <param name="arguments"></param>
/// <param name="retval"></param>
/// <param name="exception"></param>
void ExecuteAddEventListener(CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception);
/// <summary>
///
/// </summary>
/// <param name="object"></param>
/// <param name="arguments"></param>
/// <param name="retval"></param>
/// <param name="exception"></param>
void ExecuteRemoveEventListener(CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception);
/// <summary>
///
/// </summary>
/// <param name="object"></param>
/// <param name="arguments"></param>
/// <param name="retval"></param>
/// <param name="exception"></param>
void ExecuteReportJSResult(CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception);
private:
/// <summary>
///
/// </summary>
CefViewBridgeObject* object_;
private:
IMPLEMENT_REFCOUNTING(V8Handler);
};
public:
/// <summary>
///
/// </summary>
/// <param name="browser"></param>
/// <param name="frame"></param>
/// <param name="global"></param>
/// <param name="name"></param>
CefViewBridgeObject(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Value> global,
const CefString& name);
/// <summary>
///
/// </summary>
/// <param name="v8Value"></param>
/// <param name="cefValue"></param>
/// <returns></returns>
CefRefPtr<CefV8Value> CefValueToV8Value(CefValue* cefValue);
/// <summary>
///
/// </summary>
/// <param name="v8Value"></param>
/// <returns></returns>
CefRefPtr<CefValue> V8ValueToCefValue(CefV8Value* v8Value);
/// <summary>
///
/// </summary>
/// <param name="arguments"></param>
void AsyncExecuteNativeMethod(const CefV8ValueList& arguments);
/// <summary>
///
/// </summary>
/// <param name="arguments"></param>
void AsyncExecuteReportJSResult(const CefV8ValueList& arguments);
/// <summary>
///
/// </summary>
/// <param name="name"></param>
/// <param name="listener"></param>
/// <returns></returns>
void AddEventListener(const CefString& name, const EventListener& listener);
/// <summary>
///
/// </summary>
/// <param name="name"></param>
/// <param name="listener"></param>
void RemoveEventListener(const CefString& name, const EventListener& listener);
/// <summary>
///
/// </summary>
/// <param name="eventName"></param>
/// <param name="args"></param>
void ExecuteEventListener(const CefString eventName, CefRefPtr<CefListValue> args);
private:
/// <summary>
///
/// </summary>
CefString name_;
/// <summary>
///
/// </summary>
CefRefPtr<CefV8Value> bridgeObject_;
/// <summary>
///
/// </summary>
CefRefPtr<CefV8Value> reportJSResultFunction_;
/// <summary>
///
/// </summary>
CefRefPtr<CefBrowser> browser_;
/// <summary>
///
/// </summary>
CefRefPtr<CefFrame> frame_;
/// <summary>
///
/// </summary>
CefRefPtr<V8Handler> v8Handler_;
/// <summary>
///
/// </summary>
CefViewBridgeObject::EventListenerListMap eventListenerListMap_;
};

View File

@ -1,128 +0,0 @@
#include "CefViewWidget.h"
#if defined(Q_OS_WIN)
#include <windows.h>
#elif defined(Q_OS_MAC)
#elif defined(Q_OS_LINUX)
#else
#endif
#include <QColor>
#include <QDebug>
#include <QPainterPath>
#include <QRandomGenerator>
#include <QResizeEvent>
#include <QWindow>
#include "DownloadManager.h"
CefViewWidget::CefViewWidget(const QString url, const QCefSetting* setting, QWidget* parent /* = 0*/)
: QCefView(url, setting, parent)
{
// setStyleSheet("background: blue;");
connect(this, &CefViewWidget::draggableRegionChanged, this, &CefViewWidget::onDraggableRegionChanged);
connect(this, &CefViewWidget::nativeBrowserCreated, this, &CefViewWidget::onNativeBrowserWindowCreated);
}
CefViewWidget::~CefViewWidget() {}
void
CefViewWidget::onScreenChanged(QScreen* screen)
{
if (!m_pCefWindow)
return;
updateMask();
}
void
CefViewWidget::onNativeBrowserWindowCreated(QWindow* window)
{
m_pCefWindow = window;
if (!m_pCefWindow)
return;
connect(this->window()->windowHandle(), SIGNAL(screenChanged(QScreen*)), this, SLOT(onScreenChanged(QScreen*)));
updateMask();
}
void
CefViewWidget::onDraggableRegionChanged(const QRegion& draggableRegion, const QRegion& nonDraggableRegion)
{
m_draggableRegion = draggableRegion;
m_nonDraggableRegion = nonDraggableRegion;
}
bool
CefViewWidget::onNewPopup(const QCefFrameId& sourceFrameId,
const QString& targetUrl,
QString& targetFrameName,
QCefView::CefWindowOpenDisposition targetDisposition,
QRect& rect,
QCefSetting& settings,
bool& disableJavascriptAccess)
{
// create new QCefView as popup browser
// settings.setBackgroundColor(Qt::red);
return false;
}
void
CefViewWidget::onNewDownloadItem(const QSharedPointer<QCefDownloadItem>& item, const QString& suggestedName)
{
// keep the item into list or map, and call item->start() to allow the download
DownloadManager::getInstance().AddNewDownloadItem(item);
}
void
CefViewWidget::onUpdateDownloadItem(const QSharedPointer<QCefDownloadItem>& item)
{
// control the download by invoking item->pause(), item->resume(), item->cancel()
DownloadManager::getInstance().UpdateDownloadItem(item);
}
void
CefViewWidget::resizeEvent(QResizeEvent* event)
{
// update mask first, because the new mask will be
// used in the QCefView::resizeEvent
updateMask();
QCefView::resizeEvent(event);
}
void
CefViewWidget::mousePressEvent(QMouseEvent* event)
{
QCefView::mousePressEvent(event);
#if defined(Q_OS_WIN)
if (event->buttons().testFlag(Qt::LeftButton) && m_draggableRegion.contains(event->pos())) {
HWND hWnd = ::GetAncestor((HWND)(window()->windowHandle()->winId()), GA_ROOT);
POINT pt;
::GetCursorPos(&pt);
::ReleaseCapture();
::SendMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, POINTTOPOINTS(pt));
}
#elif defined(Q_OS_MAC)
#elif defined(Q_OS_LINUX)
#else
#endif
}
void
CefViewWidget::updateMask()
{
// create a rect with rounded corner (50px radius) as mask
QPainterPath path;
path.addRoundedRect(rect(), 50, 50);
QRegion mask = QRegion(path.toFillPolygon().toPolygon());
// apply the mask
setMask(mask);
}

View File

@ -1,58 +0,0 @@
#ifndef CUSTOMCEFVIEW_H
#define CUSTOMCEFVIEW_H
#include <QScreen>
#include <QCefView.h>
/// <summary>
/// Represents the customized QCefView
/// </summary>
class CefViewWidget : public QCefView
{
Q_OBJECT
public:
CefViewWidget(const QString url, const QCefSetting* setting, QWidget* parent = 0);
~CefViewWidget();
protected slots:
void onScreenChanged(QScreen* screen);
void onNativeBrowserWindowCreated(QWindow* window);
void onDraggableRegionChanged(const QRegion& draggableRegion, const QRegion& nonDraggableRegion);
protected:
bool onNewPopup(const QCefFrameId& sourceFrameId,
const QString& targetUrl,
QString& targetFrameName,
QCefView::CefWindowOpenDisposition targetDisposition,
QRect& rect,
QCefSetting& settings,
bool& disableJavascriptAccess) override;
void onNewDownloadItem(const QSharedPointer<QCefDownloadItem>& item, const QString& suggestedName) override;
void onUpdateDownloadItem(const QSharedPointer<QCefDownloadItem>& item) override;
protected:
void resizeEvent(QResizeEvent* event) override;
void mousePressEvent(QMouseEvent* event) override;
private:
void updateMask();
private:
QWindow* m_pCefWindow = nullptr;
int m_iCornerRadius = 50;
QRegion m_draggableRegion;
QRegion m_nonDraggableRegion;
};
#endif // CUSTOMCEFVIEW_H

View File

@ -67,7 +67,7 @@ void CefWidget::initBrowser()
m_CefWidget = nullptr;
}
setting.setHardwareAcceleration(true);
m_CefWidget = new CefViewWidget("", &setting, this);
m_CefWidget = new QCefView("about:blank", &setting, this);
connect(m_CefWidget, &QCefView::invokeMethod, this, &CefWidget::onInvokeMethod);
connect(m_CefWidget, &QCefView::cefUrlRequest, this, &CefWidget::onQCefUrlRequest);
connect(m_CefWidget, &QCefView::cefQueryRequest, this, &CefWidget::onQCefQueryRequest);

View File

@ -7,7 +7,7 @@
#include <QWidget>
#include <QLineEdit>
#include <QPushButton>
#include "CefViewWidget.h"
#include <QCefView.h>
class CefWidget : public QWidget
{

View File

@ -1,141 +0,0 @@
//
// CefViewCoreLog.cpp
// CefViewCore
//
// Created by Sheen Tian on 2020/6/19.
//
#include "CefViewCoreLog.h"
#include <cstdarg>
#include <string>
#include <vector>
typedef enum log_level
{
ll_debug = 1,
ll_info,
ll_error,
ll_fatal,
} log_level;
#if defined(__APPLE__)
#include <os/log.h>
void
cefView_log(log_level level, const char* message)
{
switch (level) {
case ll_debug:
os_log_debug(OS_LOG_DEFAULT, "[DEBUG]%s", message);
break;
case ll_info:
os_log_info(OS_LOG_DEFAULT, "[INFO]%s", message);
break;
case ll_error:
os_log_error(OS_LOG_DEFAULT, "[ERROR]%s", message);
break;
case ll_fatal:
os_log_fault(OS_LOG_DEFAULT, "[FATAL]%s", message);
break;
default:
break;
}
}
#elif defined(_WIN32)
#include <Windows.h>
void
cefView_log(log_level level, const char* message)
{
std::string msg;
switch (level) {
case ll_debug:
msg = "[DEBUG]";
break;
case ll_info:
msg = "[INFO]";
break;
case ll_error:
msg = "[ERROR]";
break;
case ll_fatal:
msg = "[FATAL]";
break;
default:
msg = "[]";
break;
}
msg += message;
msg += "\r\n";
OutputDebugStringA(msg.c_str());
}
#elif defined(__linux__)
#include <syslog.h>
void
cefView_log(log_level level, const char* message)
{
switch (level) {
case ll_debug:
syslog(LOG_USER | LOG_DEBUG, "[DEBUG]%s", message);
break;
case ll_info:
syslog(LOG_USER | LOG_INFO, "[INFO]%s", message);
break;
case ll_error:
syslog(LOG_USER | LOG_ERR, "[ERROR]%s", message);
break;
case ll_fatal:
syslog(LOG_USER | LOG_CRIT, "[FATAL]%s", message);
break;
default:
break;
}
}
#else
#error "unsupported platform"
#endif
#define LOG_MSG_BUFFER_LIMIT 4096
void
log_debug(const char* fmt, ...)
{
std::vector<char> msg(LOG_MSG_BUFFER_LIMIT, 0);
va_list args;
va_start(args, fmt);
vsnprintf(msg.data(), LOG_MSG_BUFFER_LIMIT, fmt, args);
va_end(args);
cefView_log(ll_debug, msg.data());
}
void
log_info(const char* fmt, ...)
{
std::vector<char> msg(LOG_MSG_BUFFER_LIMIT, 0);
va_list args;
va_start(args, fmt);
vsnprintf(msg.data(), LOG_MSG_BUFFER_LIMIT, fmt, args);
va_end(args);
cefView_log(ll_info, msg.data());
}
void
log_error(const char* fmt, ...)
{
std::vector<char> msg(LOG_MSG_BUFFER_LIMIT, 0);
va_list args;
va_start(args, fmt);
vsnprintf(msg.data(), LOG_MSG_BUFFER_LIMIT, fmt, args);
va_end(args);
cefView_log(ll_error, msg.data());
}
void
log_fatal(const char* fmt, ...)
{
std::vector<char> msg(LOG_MSG_BUFFER_LIMIT, 0);
va_list args;
va_start(args, fmt);
vsnprintf(msg.data(), LOG_MSG_BUFFER_LIMIT, fmt, args);
va_end(args);
cefView_log(ll_fatal, msg.data());
}

View File

@ -1,57 +0,0 @@
//
// CefViewCoreLog.h
// CefViewCore
//
// Created by Sheen Tian on 2020/6/19.
//
#ifndef CefViewCoreLog_h
#define CefViewCoreLog_h
#pragma once
#include <string>
void
log_debug(const char* fmt, ...);
void
log_info(const char* fmt, ...);
void
log_error(const char* fmt, ...);
void
log_fatal(const char* fmt, ...);
class ScopeLogger
{
public:
ScopeLogger(const std::string& fn)
: functionName_(fn)
{
// enter scope
log_debug("+++ %s", functionName_.c_str());
}
~ScopeLogger()
{
// leave scope
log_debug("--- %s", functionName_.c_str());
}
std::string functionName_;
};
#if (defined(DEBUG) || defined(_DEBUG) || !defined(NDEBUG))
// DEBUG BUILD
#define logD(format, ...) log_debug(format, ##__VA_ARGS__)
#define logI(format, ...) log_info(format, ##__VA_ARGS__)
#define logE(format, ...) log_error(format, ##__VA_ARGS__)
#define logF(format, ...) log_fatal(format, ##__VA_ARGS__)
#define logScope() ScopeLogger __scope_logger__(__FUNCTION__);
#else
// RELEASE BUILD
#define logD(format, ...)
#define logI(format, ...) log_info(format, ##__VA_ARGS__)
#define logE(format, ...) log_error(format, ##__VA_ARGS__)
#define logF(format, ...) log_fatal(format, ##__VA_ARGS__)
#define logScope()
#endif
#endif /* CefViewCoreLog_hpp */

View File

@ -1,64 +0,0 @@
//
// CefViewCoreLog.cpp
// CefViewCore
//
// Created by leashi on 2022/5/10.
//
#include <CefViewCoreGlobal.h>
#include "CefViewDebug.h"
#include <string>
std::string
toString(CefRefPtr<CefBrowser> browser)
{
std::string msg;
msg += "( ";
msg += "CefBrowser:";
msg += ", ptr=" + std::to_string((int64_t)browser.get());
#if CEF_VERSION_MAJOR > 91
msg += ", IsValid=" + std::to_string(browser->IsValid());
#endif
msg += ", GetHost=" + std::to_string((int64_t)browser->GetHost().get());
msg += ", CanGoBack=" + std::to_string(browser->CanGoBack());
msg += ", CanGoForward=" + std::to_string(browser->CanGoForward());
msg += ", IsLoading=" + std::to_string(browser->IsLoading());
msg += ", GetIdentifier=" + std::to_string(browser->GetIdentifier());
msg += ", IsPopup=" + std::to_string(browser->IsPopup());
msg += ", HasDocument=" + std::to_string(browser->HasDocument());
msg += ", GetMainFrame=" + std::to_string((int64_t)browser->GetMainFrame().get());
msg += ", GetFocusedFrame=" + std::to_string((int64_t)browser->GetFocusedFrame().get());
msg += ", GetFrameCount=" + std::to_string(browser->GetFrameCount());
msg += " )";
return msg;
}
std::string
toString(CefRefPtr<CefFrame> frame)
{
std::string msg;
msg += "( ";
msg += "CefFrame:";
msg += ", ptr=" + std::to_string((int64_t)frame.get());
msg += ", IsValid=" + std::to_string(frame->IsValid());
msg += ", IsMain=" + std::to_string(frame->IsMain());
msg += ", IsFocused=" + std::to_string(frame->IsFocused());
msg += ", GetName=" + frame->GetName().ToString();
#if CEF_VERSION_MAJOR < 122
msg += ", GetIdentifier=" + std::to_string(frame->GetIdentifier());
#else
msg += ", GetIdentifier=" + frame->GetIdentifier().ToString();
#endif
msg += ", GetParent=" + std::to_string((int64_t)frame->GetParent().get());
msg += ", GetURL=" + frame->GetURL().ToString();
msg += ", GetBrowser=" + std::to_string((int64_t)frame->GetBrowser().get());
// msg += ", GetV8Context=" + std::to_string((int64_t)frame->GetV8Context().get());
msg += " )";
return msg;
}

View File

@ -1,21 +0,0 @@
//
// CefViewDebug.h
// CefViewCore
//
// Created by leashi on 2022/5/10.
//
#ifndef CefViewDebug_h
#define CefViewDebug_h
#pragma once
#include <include/cef_browser.h>
#include <include/cef_frame.h>
std::string toString(CefRefPtr<CefBrowser> browser);
std::string toString(CefRefPtr<CefFrame> frame);
#endif /* CefViewDebug_h */

View File

@ -1,52 +0,0 @@
#include "DownloadManager.h"
#include <QDebug>
DownloadManager&
DownloadManager::getInstance()
{
static DownloadManager s_instance;
return s_instance;
}
void
DownloadManager::AddNewDownloadItem(const QSharedPointer<QCefDownloadItem>& item)
{
qDebug() << "DownloadManager::AddNewDownloadItem:"
<< " id: " << item->id() << "\n"
<< " name: " << item->suggestedFileName() << "\n"
<< " path: " << item->fullPath() << "\n"
<< " percent: " << item->percentComplete() << "%, " << item->totalBytes() << "/" << item->receivedBytes()
<< "\n"
<< " canceled: " << item->isCanceled() << "\n"
<< " complete: " << item->isComplete();
m_mapDownloadingItem[item->id()] = item;
item->start("", true);
}
void
DownloadManager::UpdateDownloadItem(const QSharedPointer<QCefDownloadItem>& item)
{
qDebug() << "DownloadManager::UpdateDownloadItem:"
<< " id: " << item->id() << "\n"
<< " name: " << item->suggestedFileName() << "\n"
<< " path: " << item->fullPath() << "\n"
<< " percent: " << item->percentComplete() << "%, " << item->totalBytes() << "/" << item->receivedBytes()
<< "\n"
<< " canceled: " << item->isCanceled() << "\n"
<< " complete: " << item->isComplete();
if (item->isCanceled() || item->isComplete())
m_mapDownloadingItem.remove(item->id());
}
DownloadManager::DownloadManager() {}
DownloadManager::~DownloadManager()
{
for (auto& item : m_mapDownloadingItem) {
item->cancel();
}
m_mapDownloadingItem.clear();
}

View File

@ -1,26 +0,0 @@
#ifndef DOWNLOADMANAGER_H
#define DOWNLOADMANAGER_H
#pragma once
#include <QMap>
#include <QSharedPointer>
#include <QCefDownloadItem.h>
class DownloadManager
{
public:
static DownloadManager& getInstance();
void AddNewDownloadItem(const QSharedPointer<QCefDownloadItem>& item);
void UpdateDownloadItem(const QSharedPointer<QCefDownloadItem>& item);
private:
DownloadManager();
~DownloadManager();
QMap<qint32, QSharedPointer<QCefDownloadItem>> m_mapDownloadingItem;
};
#endif

View File

@ -1,317 +0,0 @@
#include "MainWindow.h"
#include <QCoreApplication>
#include <QDebug>
#include <QDir>
#include <QHBoxLayout>
#include <QJsonDocument>
#include <QJsonValue>
#include <QMessageBox>
#include <QRandomGenerator>
#include <QCefContext.h>
#define URL_ROOT "http://QCefViewDoc"
#define LEFT_INDEX_URL URL_ROOT "/left.html"
#define RIGHT_INDEX_URL URL_ROOT "/right.html"
MainWindow::MainWindow(QWidget* parent)
: QMainWindow(parent /*, Qt::FramelessWindowHint*/)
{
m_ui.setupUi(this);
#ifdef Q_OS_MACOS
this->m_ui.nativeContainer->setContentsMargins(0, 28, 0, 0);
#endif
setupWindow();
// setWindowFlags(Qt::FramelessWindowHint);
// setAttribute(Qt::WA_TranslucentBackground);
connect(m_ui.btn_showDevTools, &QPushButton::clicked, this, &MainWindow::onBtnShowDevToolsClicked);
connect(m_ui.btn_reloadRight, &QPushButton::clicked, this, &MainWindow::onBtnReloadRightViewClicked);
connect(m_ui.btn_recreateRight, &QPushButton::clicked, this, &MainWindow::onBtnRecreateRightViewClicked);
connect(m_ui.btn_changeColor, &QPushButton::clicked, this, &MainWindow::onBtnChangeColorClicked);
connect(m_ui.btn_setFocus, &QPushButton::clicked, this, &MainWindow::onBtnSetFocusClicked);
connect(m_ui.btn_callJSCode, &QPushButton::clicked, this, &MainWindow::onBtnCallJSCodeClicked);
connect(m_ui.btn_newBrowser, &QPushButton::clicked, this, &MainWindow::onBtnNewBrowserClicked);
connect(m_ui.btn_quitApp, &QPushButton::clicked, qApp, &QCoreApplication::quit);
// build the path to the web resource
QDir dir = QCoreApplication::applicationDirPath();
// #if defined(Q_OS_MACOS)
// QString webResourceDir = /*QString("file://") +*/ QDir::toNativeSeparators(dir.filePath("../Resources/webres"));
// #else
// QString webResourceDir = /*QString("file://") +*/ QDir::toNativeSeparators(dir.filePath("webres"));
// #endif
// // add a local folder to URL map (global)
// QCefContext::instance()->addLocalFolderResource(webResourceDir, URL_ROOT);
createLeftCefView();
createRightCefView();
}
MainWindow::~MainWindow() {}
void
MainWindow::createLeftCefView()
{
if (m_pLeftCefViewWidget) {
m_pLeftCefViewWidget->deleteLater();
m_pLeftCefViewWidget = nullptr;
}
QCefSetting setting;
setting.setWindowlessFrameRate(1000);
setting.setHardwareAcceleration(true);
setting.setWindowInitialSize(QSize(1000,800));
// setting.setBackgroundColor(Qt::magenta);
m_pLeftCefViewWidget = new CefViewWidget("https://www.testufo.com/", &setting, this);
// connect the invokeMethod to the slot
connect(m_pLeftCefViewWidget, &QCefView::invokeMethod, this, &MainWindow::onInvokeMethod);
// connect the cefQueryRequest to the slot
connect(m_pLeftCefViewWidget, &QCefView::cefUrlRequest, this, &MainWindow::onQCefUrlRequest);
connect(m_pLeftCefViewWidget, &QCefView::cefQueryRequest, this, &MainWindow::onQCefQueryRequest);
connect(m_pLeftCefViewWidget, &QCefView::reportJavascriptResult, this, &MainWindow::onJavascriptResult);
connect(m_pLeftCefViewWidget, &QCefView::loadStart, this, &MainWindow::onLoadStart);
connect(m_pLeftCefViewWidget, &QCefView::loadEnd, this, &MainWindow::onLoadEnd);
connect(m_pLeftCefViewWidget, &QCefView::loadError, this, &MainWindow::onLoadError);
m_ui.leftCefViewContainer->layout()->addWidget(m_pLeftCefViewWidget);
}
void
MainWindow::createRightCefView()
{
if (m_pRightCefViewWidget) {
m_pRightCefViewWidget->deleteLater();
m_pRightCefViewWidget = nullptr;
}
// build settings for per QCefView
QCefSetting setting;
#if CEF_VERSION_MAJOR < 100
setting.setPlugins(false);
#endif
setting.setWindowlessFrameRate(1000);
setting.setHardwareAcceleration(true);
QColor background(0, 255, 0, 255);
setting.setBackgroundColor(background);
setting.setWindowInitialSize(QSize(1000,800));
// create the QCefView widget and add it to the layout container
// m_pRightCefViewWidget = new QCefView(RIGHT_INDEX_URL, &setting, this);
m_pRightCefViewWidget = new QCefView("https://www.testufo.com/", &setting, this);
// auto vl = new QVBoxLayout(m_pRightCefViewWidget);
// auto btn = new QPushButton("TEST BUTTON OVERLAY", m_pRightCefViewWidget);
//// btn->setFixedSize(320, 240);
// btn->setStyleSheet("background-color: rgba(1, 1, 1, 0);");
// btn->setAttribute(Qt::WA_TranslucentBackground);
// btn->setWindowFlags(Qt::FramelessWindowHint);
// btn->setAttribute(Qt::WA_NoSystemBackground);
// vl->setAlignment(Qt::AlignVCenter);
// vl->addWidget(btn);
// m_pRightCefViewWidget->setLayout(vl);
// all the following values will disable the context menu for both NCW and OSR mode
// m_pRightCefViewWidget->setContextMenuPolicy(Qt::NoContextMenu);
// m_pRightCefViewWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
// m_pRightCefViewWidget->setContextMenuPolicy(Qt::CustomContextMenu);
// m_pRightCefViewWidget->setContextMenuPolicy(Qt::PreventContextMenu);
m_pRightCefViewWidget->setContextMenuPolicy(Qt::DefaultContextMenu);
// add the QCefView widget to the layout
m_ui.rightCefViewContainer->layout()->addWidget(m_pRightCefViewWidget);
}
void
MainWindow::onInvokeMethod(const QCefBrowserId& browserId,
const QCefFrameId& frameId,
const QString& method,
const QVariantList& arguments)
{
// extract the arguments and dispatch the invocation to corresponding handler
if (0 == method.compare("TestMethod")) {
QString title("QCef InvokeMethod Notify");
QString text = QString("================== Current Thread: QT_UI ==================\r\n"
"Frame: %1\r\n"
"Method: %2\r\n"
"Arguments:\r\n")
.arg(frameId)
.arg(method);
for (int i = 0; i < arguments.size(); i++) {
auto jv = QJsonValue::fromVariant(arguments[i]);
// clang-format off
text.append(
QString("%1 Type:%2, Value:%3\r\n")
.arg(i).arg(arguments[i].typeName()).arg(arguments[i].toString())
);
// clang-format on
}
auto jsonValue = QJsonDocument::fromVariant(arguments);
auto jsonString = QString(jsonValue.toJson());
text.append(QString("\r\nArguments List in JSON format:\r\n%1").arg(jsonString));
QMessageBox::information(this->window(), title, text);
} else {
}
}
void
MainWindow::onQCefUrlRequest(const QCefBrowserId& browserId, const QCefFrameId& frameId, const QString& url)
{
QString title("QCef URL Request");
QString text = QString("Current Thread: QT_UI\r\n"
"URL: %1")
.arg(url);
QMessageBox::information(this->window(), title, text);
}
void
MainWindow::onQCefQueryRequest(const QCefBrowserId& browserId, const QCefFrameId& frameId, const QCefQuery& query)
{
QString title("QCef Query Request");
QString text = QString("Current Thread: QT_UI\r\n"
"Query: %1")
.arg(query.request());
QMessageBox::information(this->window(), title, text);
QString response = query.request().toUpper();
query.setResponseResult(true, response);
m_pLeftCefViewWidget->responseQCefQuery(query);
}
void
MainWindow::onJavascriptResult(const QCefBrowserId& browserId,
const QCefFrameId& frameId,
const QString& context,
const QVariant& result)
{
auto jsonValue = QJsonDocument::fromVariant(result);
auto jsonString = QString(jsonValue.toJson());
QString title("Javascript result notification");
QString text = QString("Context: %1\r\nResult in JSON format:\r\n%2").arg(context).arg(jsonString);
QMessageBox::information(this->window(), title, text);
}
void
MainWindow::onLoadingStateChanged(const QCefBrowserId& browserId, bool isLoading, bool canGoBack, bool canGoForward)
{
qDebug() << "onLoadingStateChanged, browserId:" << browserId << ", isLoading:" << isLoading
<< ", canGoBack:" << canGoBack << ", canGoForward:" << canGoForward;
}
void
MainWindow::onLoadStart(const QCefBrowserId& browserId,
const QCefFrameId& frameId,
bool isMainFrame,
int transitionType)
{
qDebug() << "onLoadStart, browserId:" << browserId << ", frameId:" << frameId << ", isMainFrame:" << isMainFrame
<< ", transitionType:" << transitionType;
}
void
MainWindow::onLoadEnd(const QCefBrowserId& browserId, const QCefFrameId& frameId, bool isMainFrame, int httpStatusCode)
{
qDebug() << "onLoadEnd, browserId:" << browserId << ", frameId:" << frameId << ", isMainFrame:" << isMainFrame
<< ", httpStatusCode:" << httpStatusCode;
}
void
MainWindow::onLoadError(const QCefBrowserId& browserId,
const QCefFrameId& frameId,
bool isMainFrame,
int errorCode,
const QString& errorMsg,
const QString& failedUrl)
{
qDebug() << "onLoadError, browserId:" << browserId << ", frameId:" << frameId << ", isMainFrame:" << isMainFrame
<< ", errorCode:" << errorCode;
}
void
MainWindow::onBtnShowDevToolsClicked()
{
if (m_pLeftCefViewWidget) {
m_pLeftCefViewWidget->showDevTools();
}
}
void
MainWindow::onBtnReloadRightViewClicked()
{
if (m_pRightCefViewWidget) {
m_pRightCefViewWidget->navigateToUrl("https://www.google.com");
}
}
void
MainWindow::onBtnRecreateRightViewClicked()
{
createRightCefView();
}
void
MainWindow::onBtnChangeColorClicked()
{
if (m_pLeftCefViewWidget) {
// create a random color
QColor color(QRandomGenerator::global()->generate());
// create the cef event and set the arguments
QCefEvent event("colorChange");
event.arguments().append(QVariant::fromValue(color.name(QColor::HexArgb)));
// broadcast the event to all frames in all browsers created by this QCefView widget
m_pLeftCefViewWidget->broadcastEvent(event);
}
}
void
MainWindow::onBtnCallJSCodeClicked()
{
QString context = "helloQCefView";
QString code = "alert('hello QCefView'); return {k1: 'str', k2: true, k3: 100};";
m_pLeftCefViewWidget->executeJavascriptWithResult(QCefView::MainFrameID, code, "", context);
}
void
MainWindow::onBtnSetFocusClicked()
{
if (m_pLeftCefViewWidget) {
m_pLeftCefViewWidget->setFocus();
}
}
void
MainWindow::onBtnNewBrowserClicked()
{
QMainWindow* w = new QMainWindow(nullptr);
w->setAttribute(Qt::WA_DeleteOnClose);
QCefSetting settings;
QCefView* view = new QCefView("https://cefview.github.io/QCefView/", &settings, w);
w->setCentralWidget(view);
w->resize(1024, 768);
w->show();
}
#ifndef Q_OS_MACOS
void
MainWindow::setupWindow()
{
}
#endif

View File

@ -1,77 +0,0 @@
#ifndef QCEFVIEWTEST_H
#define QCEFVIEWTEST_H
#include <QCloseEvent>
#include <QMainWindow>
#include "ui_MainWindow.h"
#include "CefViewWidget.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget* parent = 0);
~MainWindow();
protected:
void createLeftCefView();
void createRightCefView();
void setupWindow();
// QCefView slots
protected slots:
void onInvokeMethod(const QCefBrowserId& browserId,
const QCefFrameId& frameId,
const QString& method,
const QVariantList& arguments);
void onQCefUrlRequest(const QCefBrowserId& browserId, const QCefFrameId& frameId, const QString& url);
void onQCefQueryRequest(const QCefBrowserId& browserId, const QCefFrameId& frameId, const QCefQuery& query);
void onJavascriptResult(const QCefBrowserId& browserId,
const QCefFrameId& frameId,
const QString& context,
const QVariant& result);
void onLoadingStateChanged(const QCefBrowserId& browserId, bool isLoading, bool canGoBack, bool canGoForward);
void onLoadStart(const QCefBrowserId& browserId, const QCefFrameId& frameId, bool isMainFrame, int transitionType);
void onLoadEnd(const QCefBrowserId& browserId, const QCefFrameId& frameId, bool isMainFrame, int httpStatusCode);
void onLoadError(const QCefBrowserId& browserId,
const QCefFrameId& frameId,
bool isMainFrame,
int errorCode,
const QString& errorMsg,
const QString& failedUrl);
// ui slots
protected slots:
void onBtnShowDevToolsClicked();
void onBtnReloadRightViewClicked();
void onBtnRecreateRightViewClicked();
void onBtnChangeColorClicked();
void onBtnSetFocusClicked();
void onBtnCallJSCodeClicked();
void onBtnNewBrowserClicked();
private:
Ui::MainWindow m_ui;
QCefView* m_pLeftCefViewWidget = nullptr;
QCefView* m_pRightCefViewWidget = nullptr;
};
#endif // QCEFVIEWTEST_H

View File

@ -1,250 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1280</width>
<height>900</height>
</rect>
</property>
<property name="windowTitle">
<string>QCefViewTest</string>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<widget class="QWidget" name="nativeContainer" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">
#nativeContainer {
background-color: rgb(170, 255, 255);
}
</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_nativeContainer">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">
#label{
font: 12pt &quot;MS Shell Dlg 2&quot;;
}
</string>
</property>
<property name="text">
<string>Native Area</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_showDevTools">
<property name="text">
<string>Show Left DevTools</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_reloadRight">
<property name="text">
<string>Reload Right QCefView</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_recreateRight">
<property name="text">
<string>Recreate Right QCefView</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_changeColor">
<property name="text">
<string>ChangeColor</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit"/>
</item>
<item>
<widget class="QPushButton" name="btn_setFocus">
<property name="text">
<string>SetFocus</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_2"/>
</item>
<item>
<widget class="QPushButton" name="btn_callJSCode">
<property name="text">
<string>CallJSCode</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_3"/>
</item>
<item>
<widget class="QPushButton" name="btn_newBrowser">
<property name="text">
<string>NewBrowser</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_quitApp">
<property name="text">
<string>Exit App</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QSplitter" name="splitter">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QWidget" name="leftCefViewContainer" native="true">
<property name="styleSheet">
<string notr="true">QWidget#leftCefViewContainer {
background-color: rgb(217, 183, 255);
}</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_cefContainer">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
</layout>
</widget>
<widget class="QWidget" name="rightCefViewContainer" native="true">
<property name="styleSheet">
<string notr="true">QWidget#rightCefViewContainer {
background-color: rgb(217, 183, 255);
}</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_cefContainer_2">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<tabstops>
<tabstop>btn_showDevTools</tabstop>
<tabstop>btn_reloadRight</tabstop>
<tabstop>btn_recreateRight</tabstop>
<tabstop>btn_changeColor</tabstop>
<tabstop>lineEdit</tabstop>
<tabstop>lineEdit_2</tabstop>
<tabstop>btn_callJSCode</tabstop>
<tabstop>lineEdit_3</tabstop>
<tabstop>btn_newBrowser</tabstop>
<tabstop>btn_quitApp</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -7,141 +7,142 @@
#include <QApplication>
#include <QStandardPaths>
#include <QCefContext.h>
#include "QCefWidget/MainWindow.h"
#include <include/cef_app.h>
#include <include/cef_client.h>
#include <include/cef_render_handler.h>
#include <include/cef_browser.h>
// // 自定义 CefApp 类
// class CefAppQt : public CefApp, public CefBrowserProcessHandler
// {
// public:
// CefAppQt() {}
// // 重写 CefApp 方法
// CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() override
// {
// return this;
// }
// // 重写 CefBrowserProcessHandler 方法
// void OnContextInitialized() override
// {
// CefWindowInfo window_info;
// CefBrowserSettings browser_settings;
// browser_settings.windowless_frame_rate = 60;
// CefBrowserHost::CreateBrowser(window_info, nullptr, "https://html5test.opensuse.org", browser_settings, nullptr, nullptr);
// }
// IMPLEMENT_REFCOUNTING(CefAppQt);
// };
// int main(int argc, char *argv[])
// {
// HINSTANCE hInstance = GetModuleHandle(NULL);
// CefMainArgs main_args(hInstance);
// // 处理多进程逻辑
// CefRefPtr<CefAppQt> app(new CefAppQt);
// int exit_code = CefExecuteProcess(main_args, app, nullptr);
// if (exit_code >= 0)
// {
// std::cerr << "exit code:" << exit_code << std::endl;
// return exit_code;
// }
// // 初始化 CEF
// CefSettings settings;
// settings.windowless_rendering_enabled = true;
// settings.multi_threaded_message_loop = false;
// settings.external_message_pump = false;
// settings.no_sandbox = true;
// // 自定义 root_cache_path
// QString cache = QDir::currentPath() + "/usercache";
// CefString(&settings.root_cache_path) = cache.toStdString();
// if (!CefInitialize(main_args, settings, app, nullptr))
// {
// std::cerr << "CEF initialization failed." << std::endl;
// return 1;
// }
// std::cout << "init CefWidget" << std::endl;
// // 初始化 Qt 应用
// QApplication a(argc, argv);
// std::cout << "CefRunMessageLoop" << std::endl;
// // 运行 CEF 消息循环
// CefRunMessageLoop();
// std::cout << "CefShutdown" << std::endl;
// // 关闭 CEF
// CefShutdown();
// return a.exec();
// }
#include "QCefWidget/CefWidget.h"
#define DEBUG_PRINT true
void debug_print_argv(int argc, char *argv[])
{
if(!argc){
return;
}
std::lock_guard<std::mutex> lock(m_mutex);
DWORD process_id = GetCurrentProcessId();
std::cout << "Process ID:"<<process_id<<" Argvs"<<std::endl;
for (int i = 0; i < argc; ++i)
{
std::cout << "Process ID:"<<process_id<<" Argv:" << i << ": " << argv[i]<<std::endl;
}
}
QString curExeDir(){
return QDir::currentPath();
}
void exsMkDir(QString Dir){
if(!QDir(Dir).exists()){
QDir().mkdir(Dir);
}
}
bool exeCinfog(int argc,char *argv[]){
if(argc<=0){
return true;
}
std::string ex_1="renderer";
std::string ex_2="utility";
for (int i = 0; i < argc; ++i){
std::string arg = argv[i];
if (arg.find(ex_1) == std::string::npos||arg.find(ex_2)== std::string::npos){
return true;
}
}
return false;
}
void initConfig(int argc,char *argv[],QCefConfig &config,QString currentDir)
{
//检测自定义缓存路径
exsMkDir(currentDir+"/user");
exsMkDir(currentDir+"/user/userCache");
//子进程路径和名字,可以利用本进程复用,
//Mingw编译下多进程情况需要设置否则程序会退出因为无法拉起子进程
if(exeCinfog(argc,argv)){
config.setBrowserSubProcessPath(currentDir+"/ctai.exe");
}
config.setRootCachePath(currentDir+"/user");
config.setCachePath(currentDir+"/user/userCache");
config.setResourceDirectoryPath(currentDir+"/cef_binary");
config.setLocalesDirectoryPath(currentDir+"/cef_binary/locales");
//浏览器标识
config.setUserAgent("Mozilla/5.0 (Windows NT 10.0; CEF/3.2272.2035) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 SoftwareInformer/1.6.1400");
//日志输出级别
config.setLogLevel(QCefConfig::LOGSEVERITY_VERBOSE);
//桥名字
config.setBridgeObjectName("CtaiClient");
//内置的协议方案名称
config.setBuiltinSchemeName("Ctai");
//无窗口渲染模式
config.setWindowlessRenderingEnabled(true);
//远程Debug端口
//config.setRemoteDebuggingPort(9000);
//请求头的语言
config.setAcceptLanguageList("zh-CN");
//允许忽略 localhost 上的 TLS/SSL 错误
config.addCommandLineSwitch("allow-insecure-localhost");
config.addCommandLineSwitch("ignore-certificate-errors-spki-list");
config.addCommandLineSwitch("ignore-ssl-errors");
//单进程模式
// config.addCommandLineSwitch("single-process");
//启用GPU加速
config.addCommandLineSwitch("enable-gpu");
//GPU加速合成
config.addCommandLineSwitch("enable-gpu-compositing");
//在进程中使用GPU渲染-开启后只有一个进程
config.addCommandLineSwitch("in-process-gpu");
//无头模式
config.addCommandLineSwitch("headless");
//密钥链
config.addCommandLineSwitch("use-mock-keychain");
//chrome运行时环境
config.addCommandLineSwitch("enable-chrome-runtime");
//Alloy 风格
config.addCommandLineSwitch("use-alloy-style");
//离屏渲染
config.addCommandLineSwitch("off-screen-rendering-enabled");
//网络服务In进程
config.addCommandLineSwitchWithValue("enable-features", "NetworkServiceInProcess");
//语言
config.addCommandLineSwitchWithValue("lang", "zh-CN");
//跨域进行远程
//config.addCommandLineSwitchWithValue("remote-allow-origins", "*");
// 禁用沙盒
config.addCommandLineSwitchWithValue("no-sandbox", "ture");
//渲染进程限制
config.addCommandLineSwitchWithValue("renderer-process-limit", "1");
//外部消息循环
config.addCommandLineSwitchWithValue("external-message-pump", "false");
//多线程消息循环
config.addCommandLineSwitchWithValue("multi-threaded-message-loop", "true");
}
int main(int argc, char *argv[])
{
QString currentDir=QDir::currentPath();
qDebug() << "UI线程ID-1: " << QThread::currentThreadId();
if (DEBUG_PRINT)
{
debug_print_argv(argc, argv);
}
QApplication a(argc, argv);
QCefConfig config;
config.setUserAgent("Mozilla/5.0 (Windows NT 10.0; CEF/3.2272.2035) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 SoftwareInformer/1.6.1400");
config.setLogLevel(QCefConfig::LOGSEVERITY_VERBOSE);
config.setBridgeObjectName("CtaiClient");
config.setBuiltinSchemeName("Ctai");
config.setWindowlessRenderingEnabled(false);
config.setRemoteDebuggingPort(9000);
//config.setCachePath(currentDir+"/user/userData");
//config.setRootCachePath(currentDir+"/user/userCache");
//config.setResourceDirectoryPath(currentDir+"/Resources");
//config.setLocalesDirectoryPath(currentDir+"/locales");
config.setAcceptLanguageList("zh-CN");
config.setBrowserSubProcessPath(currentDir+"/ctai.exe");
//config.addCommandLineSwitch("single-process");
//config.addCommandLineSwitch("enable-gpu");
//config.addCommandLineSwitch("in-process-gpu");
//config.addCommandLineSwitch("disable-gpu-compositing");
config.addCommandLineSwitch("headless");
config.addCommandLineSwitch("use-mock-keychain");
config.addCommandLineSwitch("disable-chrome-runtime");
config.addCommandLineSwitchWithValue("enable-features","NetworkServiceInProcess");
config.addCommandLineSwitchWithValue("log-severity","verbose");
config.addCommandLineSwitchWithValue("lang","zh-CN");
config.addCommandLineSwitchWithValue("builtin-scheme-name","Ctai");
config.addCommandLineSwitchWithValue("bridge-obj-name","CtaiClient");
config.addCommandLineSwitchWithValue("pack_loading_disabled","false");
//config.addCommandLineSwitchWithValue("user-data-dir","false");
//config.addCommandLineSwitchWithValue("log-file","false");
config.addCommandLineSwitchWithValue("remote-allow-origins", "*");
//禁用沙盒
config.addCommandLineSwitchWithValue("no-sandbox","ture");
//禁止多线程会话循环(单进程为true,多进程为false);
config.addCommandLineSwitchWithValue("renderer-process-limit", "1");
config.addCommandLineSwitchWithValue("external-message-pump","false");
config.addCommandLineSwitchWithValue("multi-threaded-message-loop","true");
//初始化上下文的配置
initConfig(argc,argv,config,curExeDir());
//初始化浏览器上下文
QCefContext cefContext(&a, argc, argv, &config);
MainWindow cw;
//初始化浏览器
CefWidget cw;
cw.show();
qDebug() << "UI线程ID-2: " << QThread::currentThreadId();
// qputenv("QT_QPA_PLATFORM", "windows:fontengine=freetype");
// // 加载语言包
// QTranslator qtBaseTranslator;
// if (!qtBaseTranslator.load(QStringLiteral(":/res/translator/qtbase_zh_CN.qm")))
// {
// // 处理加载翻译文件失败的情况
// qDebug() << "Failed to load translation file.";
// return -1;
// }
// a.installTranslator(&qtBaseTranslator);
// // 读取窗体的配置并初始化
// sui_init_config();
// ctai x;
// x.init_layout();
// // 仅限于windows平台
// #if defined(__WIN32__)
// x.title()->set_type(QD_TYPE::QD_EXIT);
// #endif
// x.show();
// qputenv("QT_QPA_PLATFORM", "windows:fontengine=freetype");
// // 加载语言包
// QTranslator qtBaseTranslator;
// if (!qtBaseTranslator.load(QStringLiteral(":/res/translator/qtbase_zh_CN.qm")))
// {
// // 处理加载翻译文件失败的情况
// qDebug() << "Failed to load translation file.";
// return -1;
// }
// a.installTranslator(&qtBaseTranslator);
// // 读取窗体的配置并初始化
// sui_init_config();
// ctai x;
// x.init_layout();
// // 仅限于windows平台
// #if defined(__WIN32__)
// x.title()->set_type(QD_TYPE::QD_EXIT);
// #endif
// x.show();
a.exec();
qDebug() << "EXIT";
return 0;

1
sui.rc
View File

@ -1 +1,2 @@
1 24 compatibility.manifest
IDI_ICON1 ICON DISCARDABLE "res\\img\\sui.ico"