This commit is contained in:
JackLee 2025-03-29 20:45:04 +08:00
parent 3799234c56
commit 0245968901
19 changed files with 1849 additions and 6 deletions

View File

@ -13,7 +13,11 @@
<!-- 引入 jsPDF 库用于导出 PDF -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
<style>
html{
background-color: white;
}
body {
background-color: white;
font-family: Arial, sans-serif;
display: flex;
flex-direction: column;

View File

@ -0,0 +1,73 @@
#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

@ -0,0 +1,67 @@
//
// 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

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

View File

@ -0,0 +1,22 @@
//
// 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

@ -0,0 +1,208 @@
#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

@ -0,0 +1,180 @@
#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

@ -0,0 +1,517 @@
#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

@ -0,0 +1,221 @@
#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

@ -0,0 +1,127 @@
#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(), 0, 0);
QRegion mask = QRegion(path.toFillPolygon().toPolygon());
// apply the mask
setMask(mask);
}

View File

@ -0,0 +1,57 @@
#ifndef CUSTOMCEFVIEW_H
#define CUSTOMCEFVIEW_H
#include <QScreen>
#include <QPainter>
#include <QCefView.h>
#include <CefViewBrowserClient.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

@ -55,6 +55,7 @@ CefWidget::CefWidget(QWidget *parent)
setWindowFlags(Qt::Window); // 使用标准窗口样式
setAttribute(Qt::WA_TranslucentBackground, false);
initBrowser();
setObjectName("CefWidget");
}
CefWidget::~CefWidget()
@ -70,9 +71,7 @@ void CefWidget::initBrowser()
}
setting.setWindowlessFrameRate(1000);
setting.setHardwareAcceleration(true);
QColor background(0, 255, 0, 255);
setting.setBackgroundColor(background);
m_CefWidget = new QCefView("about:blank", &setting, this);
m_CefWidget = new CefViewWidget("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);
@ -86,6 +85,7 @@ void CefWidget::initBrowser()
m_CefWidget->navigateToString(html_template);
}
}
void CefWidget::initResHtmlTemplate(){
QString template_file = ":/res/template/cmarkdown_template.html";
QFile file(template_file);

View File

@ -7,8 +7,8 @@
#include <QWidget>
#include <QLineEdit>
#include <QPushButton>
#include <QCefView.h>
//#include <QCefView.h>
#include "CefViewWidget.h"
class CefWidget : public QWidget
{
Q_OBJECT
@ -32,7 +32,7 @@ private:
QLineEdit* m_TextToUrl={};
QPushButton* m_BtnToUrl={};
QPushButton* m_BtnToString={};
QCefView* m_CefWidget ={};
CefViewWidget* m_CefWidget ={};
QCefSetting setting;
bool DevMode=true;
QString html_template;

View File

@ -0,0 +1,141 @@
//
// 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

@ -0,0 +1,57 @@
//
// 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

@ -0,0 +1,64 @@
//
// 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

@ -0,0 +1,21 @@
//
// 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

@ -0,0 +1,52 @@
#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

@ -0,0 +1,26 @@
#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