add cef native render
This commit is contained in:
parent
e9604915d9
commit
e12567aded
@ -100,6 +100,10 @@ class BrowserWindow : public ClientHandler::Delegate {
|
||||
// Returns the window handle.
|
||||
virtual ClientWindowHandle GetWindowHandle() const = 0;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
virtual LRESULT OnMessage(CefWindowHandle temp_handle, UINT message, WPARAM wParam, LPARAM lParam) = 0;
|
||||
#endif
|
||||
|
||||
// Returns the browser owned by the window.
|
||||
CefRefPtr<CefBrowser> GetBrowser() const;
|
||||
|
||||
|
@ -40,7 +40,7 @@ void BrowserWindowOsrWin::GetPopupConfig(CefWindowHandle temp_handle,
|
||||
|
||||
windowInfo.SetAsWindowless(temp_handle);
|
||||
windowInfo.shared_texture_enabled =
|
||||
osr_window_->settings().shared_texture_enabled;
|
||||
osr_window_->settings().render_type == OsrRendererSettings::OsrRendererType::D3D11;
|
||||
windowInfo.external_begin_frame_enabled =
|
||||
osr_window_->settings().external_begin_frame_enabled;
|
||||
|
||||
@ -109,6 +109,15 @@ ClientWindowHandle BrowserWindowOsrWin::GetWindowHandle() const {
|
||||
return osr_hwnd_;
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
LRESULT BrowserWindowOsrWin::OnMessage(HWND temp_handle, UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
if (osr_window_) {
|
||||
return osr_window_->OnMessage(temp_handle, message, wParam, lParam);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void BrowserWindowOsrWin::OnBrowserClosed(CefRefPtr<CefBrowser> browser) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "CEF/BrowserWindow.h"
|
||||
#include "CEF/osr_window_win.h"
|
||||
#include "CEF/OsrWindowWin.h"
|
||||
|
||||
// Represents a native child window hosting a single off-screen browser
|
||||
// instance. The methods of this class must be called on the main thread unless
|
||||
@ -42,6 +42,9 @@ class BrowserWindowOsrWin : public BrowserWindow,
|
||||
void SetDeviceScaleFactor(float device_scale_factor) override;
|
||||
float GetDeviceScaleFactor() const override;
|
||||
ClientWindowHandle GetWindowHandle() const override;
|
||||
#if defined(OS_WIN)
|
||||
virtual LRESULT OnMessage(CefWindowHandle temp_handle, UINT message, WPARAM wParam, LPARAM lParam) override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
// ClienHandler::Delegate methods.
|
||||
|
@ -2,12 +2,10 @@
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#include "tests/cefclient/browser/browser_window_std_win.h"
|
||||
#include "CEF/BrowserWindowStdWin.h"
|
||||
|
||||
#include "tests/cefclient/browser/client_handler_std.h"
|
||||
#include "tests/shared/browser/main_message_loop.h"
|
||||
|
||||
namespace client {
|
||||
#include "CEF/ClientHandlerStd.h"
|
||||
#include "CEF/MainMessageLoop.h"
|
||||
|
||||
BrowserWindowStdWin::BrowserWindowStdWin(Delegate* delegate,
|
||||
bool with_controls,
|
||||
@ -116,5 +114,3 @@ ClientWindowHandle BrowserWindowStdWin::GetWindowHandle() const {
|
||||
return browser_->GetHost()->GetWindowHandle();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
|
@ -2,13 +2,8 @@
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#ifndef CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_STD_WIN_H_
|
||||
#define CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_STD_WIN_H_
|
||||
#pragma once
|
||||
|
||||
#include "tests/cefclient/browser/browser_window.h"
|
||||
|
||||
namespace client {
|
||||
#include "CEF/BrowserWindow.h"
|
||||
|
||||
// Represents a native child window hosting a single windowed browser instance.
|
||||
// The methods of this class must be called on the main thread unless otherwise
|
||||
@ -41,11 +36,12 @@ class BrowserWindowStdWin : public BrowserWindow {
|
||||
void SetBounds(int x, int y, size_t width, size_t height) override;
|
||||
void SetFocus(bool focus) override;
|
||||
ClientWindowHandle GetWindowHandle() const override;
|
||||
#if defined(OS_WIN)
|
||||
virtual LRESULT OnMessage(CefWindowHandle temp_handle, UINT message, WPARAM wParam, LPARAM lParam) override {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(BrowserWindowStdWin);
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
|
||||
#endif // CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_STD_WIN_H_
|
||||
|
@ -975,7 +975,7 @@ CefRefPtr<CefResponseFilter> ClientHandler::GetResourceResponseFilter(
|
||||
CefRefPtr<CefResponse> response) {
|
||||
CEF_REQUIRE_IO_THREAD();
|
||||
|
||||
return GetResourceResponseFilter(browser, frame, request,
|
||||
return test_runner::GetResourceResponseFilter(browser, frame, request,
|
||||
response);
|
||||
}
|
||||
|
||||
|
@ -66,6 +66,7 @@ class ClientHandlerOsr : public ClientHandler,
|
||||
|
||||
virtual void UpdateAccessibilityTree(CefRefPtr<CefValue> value) = 0;
|
||||
virtual void UpdateAccessibilityLocation(CefRefPtr<CefValue> value) = 0;
|
||||
virtual void OnSize() = 0;
|
||||
|
||||
protected:
|
||||
virtual ~OsrDelegate() {}
|
||||
|
@ -133,7 +133,7 @@ HumanAppContextImpl::HumanAppContextImpl(CefRefPtr<CefCommandLine> command_line,
|
||||
|
||||
if (background_color_ == 0 && !use_views_) {
|
||||
// Set an explicit background color.
|
||||
background_color_ = CefColorSetARGB(255, 255, 255, 255);
|
||||
background_color_ = CefColorSetARGB(0, 255, 255, 255);
|
||||
}
|
||||
|
||||
// |browser_background_color_| should remain 0 to enable transparent painting.
|
||||
@ -220,7 +220,8 @@ void HumanAppContextImpl::PopulateOsrSettings(OsrRendererSettings* settings) {
|
||||
command_line_->HasSwitch(kShowUpdateRect);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
settings->shared_texture_enabled = shared_texture_enabled_;
|
||||
settings->render_type = shared_texture_enabled_ ?
|
||||
OsrRendererSettings::OsrRendererType::D3D11 : OsrRendererSettings::OsrRendererType::Navtive;
|
||||
#endif
|
||||
settings->external_begin_frame_enabled = external_begin_frame_enabled_;
|
||||
settings->begin_frame_rate = windowless_frame_rate_;
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "include/cef_app.h"
|
||||
#include "include/cef_command_line.h"
|
||||
#include "CEF/HumanAppContext.h"
|
||||
#include "CEF/RootWindoManager.h"
|
||||
|
||||
|
||||
|
||||
|
107
src/CEF/Main.cpp
107
src/CEF/Main.cpp
@ -1,6 +1,7 @@
|
||||
#if 1
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include "HumanAppContextImpl.h"
|
||||
#include "Core/Core.h"
|
||||
|
||||
#include "include/cef_command_line.h"
|
||||
@ -8,6 +9,11 @@
|
||||
#include "CEF/HumanAppBrowser.h"
|
||||
#include "CEF/HumanAppRenderer.h"
|
||||
#include "CEF/HumanAppOther.h"
|
||||
#include "CEF/MainMessageLoopMultithreadedWin.h"
|
||||
#include "CEF/MainMessageLoopExternalPump.h"
|
||||
#include "CEF/TestRunner.h"
|
||||
#include "CEF/RootWindow.h"
|
||||
#include "CEF/HumanAppSwitches.h"
|
||||
|
||||
|
||||
static int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,
|
||||
@ -31,32 +37,23 @@ static int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevI
|
||||
// Provide CEF with command-line arguments.
|
||||
CefMainArgs main_args(hInstance);
|
||||
|
||||
// CEF applications have multiple sub-processes (render, GPU, etc) that share
|
||||
// the same executable. This function checks the command-line and, if this is
|
||||
// a sub-process, executes the appropriate logic.
|
||||
int exit_code = CefExecuteProcess(main_args, nullptr, sandbox_info);
|
||||
if (exit_code >= 0) {
|
||||
// The sub-process has completed so return here.
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
// Parse command-line arguments for use in this method.
|
||||
CefRefPtr<CefCommandLine> command_line = CefCommandLine::CreateCommandLine();
|
||||
command_line->InitFromString(::GetCommandLineW());
|
||||
|
||||
// Specify CEF global settings here.
|
||||
CefSettings settings;
|
||||
|
||||
if (command_line->HasSwitch("enable-chrome-runtime")) {
|
||||
// Enable experimental Chrome runtime. See issue #2969 for details.
|
||||
settings.chrome_runtime = true;
|
||||
}
|
||||
|
||||
#if !defined(CEF_USE_SANDBOX)
|
||||
settings.no_sandbox = true;
|
||||
#endif
|
||||
|
||||
// SimpleApp implements application-level callbacks for the browser process.
|
||||
// // Specify CEF global settings here.
|
||||
// CefSettings settings;
|
||||
//
|
||||
// if (command_line->HasSwitch("enable-chrome-runtime")) {
|
||||
// // Enable experimental Chrome runtime. See issue #2969 for details.
|
||||
// settings.chrome_runtime = true;
|
||||
// }
|
||||
//
|
||||
// #if !defined(CEF_USE_SANDBOX)
|
||||
// settings.no_sandbox = true;
|
||||
// #endif
|
||||
//
|
||||
// // SimpleApp implements application-level callbacks for the browser process.
|
||||
// It will create the first browser instance in OnContextInitialized() after
|
||||
// CEF has initialized.
|
||||
CefRefPtr<CefApp> app;
|
||||
@ -68,16 +65,64 @@ static int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevI
|
||||
else if (process_type == HumanApp::OtherProcess)
|
||||
app = new HumanAppOther();
|
||||
|
||||
// Initialize CEF.
|
||||
CefInitialize(main_args, settings, app.get(), sandbox_info);
|
||||
int exit_code = CefExecuteProcess(main_args, app, sandbox_info);
|
||||
if (exit_code >= 0)
|
||||
return exit_code;
|
||||
|
||||
// Run the CEF message loop. This will block until CefQuitMessageLoop() is
|
||||
// called.
|
||||
CefRunMessageLoop();
|
||||
// Create the main context object.
|
||||
auto context = std::make_unique<HumanAppContextImpl>(command_line, true);
|
||||
|
||||
CefSettings settings;
|
||||
|
||||
#if !defined(CEF_USE_SANDBOX)
|
||||
settings.no_sandbox = true;
|
||||
#endif
|
||||
|
||||
// Populate the settings based on command line arguments.
|
||||
context->PopulateSettings(&settings);
|
||||
|
||||
settings.windowless_rendering_enabled = true;
|
||||
settings.background_color = CefColorSetARGB(0, 0, 0, 0);
|
||||
|
||||
// Create the main message loop object.
|
||||
std::unique_ptr<MainMessageLoop> message_loop;
|
||||
if (settings.multi_threaded_message_loop)
|
||||
message_loop.reset(new MainMessageLoopMultithreadedWin);
|
||||
else if (settings.external_message_pump)
|
||||
message_loop = MainMessageLoopExternalPump::Create();
|
||||
else
|
||||
message_loop.reset(new MainMessageLoopStd);
|
||||
|
||||
// Initialize CEF.
|
||||
context->Initialize(main_args, settings, app, sandbox_info);
|
||||
|
||||
// Register scheme handlers.
|
||||
test_runner::RegisterSchemeHandlers();
|
||||
|
||||
auto window_config = std::make_unique<RootWindowConfig>();
|
||||
window_config->always_on_top =
|
||||
command_line->HasSwitch(kAlwaysOnTop);
|
||||
window_config->with_controls =
|
||||
command_line->HasSwitch(kHideControls);
|
||||
window_config->with_osr =
|
||||
settings.windowless_rendering_enabled ? true : false;
|
||||
|
||||
window_config->url = "file:///C:/Users/jiege/Downloads/lrc%20demo/lrc%20demo.html";
|
||||
|
||||
// Create the first window.
|
||||
context->GetRootWindowManager()->CreateRootWindow(std::move(window_config));
|
||||
|
||||
// Run the message loop. This will block until Quit() is called by the
|
||||
// RootWindowManager after all windows have been destroyed.
|
||||
int result = message_loop->Run();
|
||||
|
||||
// Shut down CEF.
|
||||
CefShutdown();
|
||||
context->Shutdown();
|
||||
|
||||
return 0;
|
||||
// Release objects in reverse order of creation.
|
||||
message_loop.reset();
|
||||
context.reset();
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
163
src/CEF/MainMessageLoopMultithreadedWin.cpp
Normal file
163
src/CEF/MainMessageLoopMultithreadedWin.cpp
Normal file
@ -0,0 +1,163 @@
|
||||
// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#include "CEF/MainMessageLoopMultithreadedWin.h"
|
||||
|
||||
#include "include/base/cef_callback.h"
|
||||
#include "include/base/cef_logging.h"
|
||||
#include "include/cef_app.h"
|
||||
#include "CEF/resource.h"
|
||||
#include "CEF/UtilWin.h"
|
||||
|
||||
const wchar_t kWndClass[] = L"Client_MessageWindow";
|
||||
const wchar_t kTaskMessageName[] = L"Client_CustomTask";
|
||||
|
||||
MainMessageLoopMultithreadedWin::MainMessageLoopMultithreadedWin()
|
||||
: thread_id_(base::PlatformThread::CurrentId()),
|
||||
task_message_id_(RegisterWindowMessage(kTaskMessageName)),
|
||||
dialog_hwnd_(nullptr),
|
||||
message_hwnd_(nullptr) {}
|
||||
|
||||
MainMessageLoopMultithreadedWin::~MainMessageLoopMultithreadedWin() {
|
||||
DCHECK(RunsTasksOnCurrentThread());
|
||||
DCHECK(!message_hwnd_);
|
||||
DCHECK(queued_tasks_.empty());
|
||||
}
|
||||
|
||||
int MainMessageLoopMultithreadedWin::Run() {
|
||||
DCHECK(RunsTasksOnCurrentThread());
|
||||
|
||||
HINSTANCE hInstance = ::GetModuleHandle(nullptr);
|
||||
|
||||
{
|
||||
base::AutoLock lock_scope(lock_);
|
||||
|
||||
// Create the hidden window for message processing.
|
||||
message_hwnd_ = CreateMessageWindow(hInstance);
|
||||
CHECK(message_hwnd_);
|
||||
|
||||
// Store a pointer to |this| in the window's user data.
|
||||
SetUserDataPtr(message_hwnd_, this);
|
||||
|
||||
// Execute any tasks that are currently queued.
|
||||
while (!queued_tasks_.empty()) {
|
||||
PostTaskInternal(queued_tasks_.front());
|
||||
queued_tasks_.pop();
|
||||
}
|
||||
}
|
||||
|
||||
HACCEL hAccelTable =
|
||||
LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_CEFCLIENT));
|
||||
|
||||
MSG msg;
|
||||
|
||||
// Run the application message loop.
|
||||
while (GetMessage(&msg, nullptr, 0, 0)) {
|
||||
// Allow processing of dialog messages.
|
||||
if (dialog_hwnd_ && IsDialogMessage(dialog_hwnd_, &msg))
|
||||
continue;
|
||||
|
||||
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
base::AutoLock lock_scope(lock_);
|
||||
|
||||
// Destroy the message window.
|
||||
DestroyWindow(message_hwnd_);
|
||||
message_hwnd_ = nullptr;
|
||||
}
|
||||
|
||||
return static_cast<int>(msg.wParam);
|
||||
}
|
||||
|
||||
void MainMessageLoopMultithreadedWin::Quit() {
|
||||
// Execute PostQuitMessage(0) on the main thread.
|
||||
PostClosure(base::BindOnce(::PostQuitMessage, 0));
|
||||
}
|
||||
|
||||
void MainMessageLoopMultithreadedWin::PostTask(CefRefPtr<CefTask> task) {
|
||||
base::AutoLock lock_scope(lock_);
|
||||
PostTaskInternal(task);
|
||||
}
|
||||
|
||||
bool MainMessageLoopMultithreadedWin::RunsTasksOnCurrentThread() const {
|
||||
return (thread_id_ == base::PlatformThread::CurrentId());
|
||||
}
|
||||
|
||||
void MainMessageLoopMultithreadedWin::SetCurrentModelessDialog(
|
||||
HWND hWndDialog) {
|
||||
DCHECK(RunsTasksOnCurrentThread());
|
||||
|
||||
#if DCHECK_IS_ON()
|
||||
if (hWndDialog) {
|
||||
// A new dialog reference should not be set while one is currently set.
|
||||
DCHECK(!dialog_hwnd_);
|
||||
}
|
||||
#endif
|
||||
dialog_hwnd_ = hWndDialog;
|
||||
}
|
||||
|
||||
// static
|
||||
HWND MainMessageLoopMultithreadedWin::CreateMessageWindow(HINSTANCE hInstance) {
|
||||
WNDCLASSEX wc = {0};
|
||||
wc.cbSize = sizeof(wc);
|
||||
wc.lpfnWndProc = MessageWndProc;
|
||||
wc.hInstance = hInstance;
|
||||
wc.lpszClassName = kWndClass;
|
||||
RegisterClassEx(&wc);
|
||||
|
||||
return CreateWindow(kWndClass, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hInstance,
|
||||
0);
|
||||
}
|
||||
|
||||
// static
|
||||
LRESULT CALLBACK
|
||||
MainMessageLoopMultithreadedWin::MessageWndProc(HWND hWnd,
|
||||
UINT message,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam) {
|
||||
MainMessageLoopMultithreadedWin* self =
|
||||
GetUserDataPtr<MainMessageLoopMultithreadedWin*>(hWnd);
|
||||
|
||||
if (self && message == self->task_message_id_) {
|
||||
// Execute the task.
|
||||
CefTask* task = reinterpret_cast<CefTask*>(wParam);
|
||||
task->Execute();
|
||||
|
||||
// Release the reference added in PostTaskInternal. This will likely result
|
||||
// in |task| being deleted.
|
||||
task->Release();
|
||||
} else {
|
||||
switch (message) {
|
||||
case WM_NCDESTROY:
|
||||
// Clear the reference to |self|.
|
||||
SetUserDataPtr(hWnd, nullptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
void MainMessageLoopMultithreadedWin::PostTaskInternal(
|
||||
CefRefPtr<CefTask> task) {
|
||||
lock_.AssertAcquired();
|
||||
|
||||
if (!message_hwnd_) {
|
||||
// Queue the task until the message loop starts running.
|
||||
queued_tasks_.push(task);
|
||||
return;
|
||||
}
|
||||
|
||||
// Add a reference that will be released in MessageWndProc.
|
||||
task->AddRef();
|
||||
|
||||
// Post the task for execution by the message window.
|
||||
PostMessage(message_hwnd_, task_message_id_,
|
||||
reinterpret_cast<WPARAM>(task.get()), 0);
|
||||
}
|
55
src/CEF/MainMessageLoopMultithreadedWin.h
Normal file
55
src/CEF/MainMessageLoopMultithreadedWin.h
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <queue>
|
||||
|
||||
#include "include/base/cef_lock.h"
|
||||
#include "include/base/cef_platform_thread.h"
|
||||
#include "CEF/MainMessageLoop.h"
|
||||
|
||||
// Represents the main message loop in the browser process when using multi-
|
||||
// threaded message loop mode on Windows. In this mode there is no Chromium
|
||||
// message loop running on the main application thread. Instead, this
|
||||
// implementation utilizes a hidden message window for running tasks.
|
||||
class MainMessageLoopMultithreadedWin : public MainMessageLoop {
|
||||
public:
|
||||
MainMessageLoopMultithreadedWin();
|
||||
~MainMessageLoopMultithreadedWin();
|
||||
|
||||
// MainMessageLoop methods.
|
||||
int Run() override;
|
||||
void Quit() override;
|
||||
void PostTask(CefRefPtr<CefTask> task) override;
|
||||
bool RunsTasksOnCurrentThread() const override;
|
||||
void SetCurrentModelessDialog(HWND hWndDialog) override;
|
||||
|
||||
private:
|
||||
// Create the message window.
|
||||
static HWND CreateMessageWindow(HINSTANCE hInstance);
|
||||
|
||||
// Window procedure for the message window.
|
||||
static LRESULT CALLBACK MessageWndProc(HWND hWnd,
|
||||
UINT message,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam);
|
||||
|
||||
void PostTaskInternal(CefRefPtr<CefTask> task);
|
||||
|
||||
base::PlatformThreadId thread_id_;
|
||||
UINT task_message_id_;
|
||||
|
||||
// Only accessed on the main thread.
|
||||
HWND dialog_hwnd_;
|
||||
|
||||
base::Lock lock_;
|
||||
|
||||
// Must be protected by |lock_|.
|
||||
HWND message_hwnd_;
|
||||
std::queue<CefRefPtr<CefTask>> queued_tasks_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MainMessageLoopMultithreadedWin);
|
||||
};
|
@ -2,10 +2,8 @@
|
||||
// 2013 The Chromium Authors. All rights reserved. Use of this source code is
|
||||
// governed by a BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#include "tests/cefclient/browser/osr_accessibility_helper.h"
|
||||
#include "tests/cefclient/browser/osr_accessibility_node.h"
|
||||
|
||||
namespace client {
|
||||
#include "CEF/OsrAccessibilityHelper.h"
|
||||
#include "CEF/OsrAccessibilityNode.h"
|
||||
|
||||
OsrAXTree::OsrAXTree() : root_node_id_(-1) {}
|
||||
|
||||
@ -266,5 +264,3 @@ OsrAXNode* OsrAccessibilityHelper::GetNode(const CefString& treeId,
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
|
@ -2,14 +2,10 @@
|
||||
// 2013 The Chromium Authors. All rights reserved. Use of this source code is
|
||||
// governed by a BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#ifndef CEF_TESTS_CEFCLIENT_BROWSER_OSR_ACCESSIBILITY_HELPER_H_
|
||||
#define CEF_TESTS_CEFCLIENT_BROWSER_OSR_ACCESSIBILITY_HELPER_H_
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "include/cef_browser.h"
|
||||
|
||||
namespace client {
|
||||
|
||||
class OsrAXNode;
|
||||
class OsrAccessibilityHelper;
|
||||
@ -75,7 +71,3 @@ class OsrAccessibilityHelper {
|
||||
CefRefPtr<CefBrowser> browser_;
|
||||
std::map<CefString, OsrAXTree> accessibility_node_map_;
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
|
||||
#endif // CEF_TESTS_CEFCLIENT_BROWSER_OSR_ACCESSIBILITY_HELPER_H_
|
||||
|
169
src/CEF/OsrAccessibilityNode.cpp
Normal file
169
src/CEF/OsrAccessibilityNode.cpp
Normal file
@ -0,0 +1,169 @@
|
||||
// Copyright 2017 The Chromium Embedded Framework Authors. Portions copyright
|
||||
// 2013 The Chromium Authors. All rights reserved. Use of this source code is
|
||||
// governed by a BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// Base class implementation for CEF Acccessibility node. This is subclassed and
|
||||
// used by both IAccessible/NSAccessibility protocol implementation.
|
||||
|
||||
#include "CEF/OsrAccessibilityNode.h"
|
||||
|
||||
#include "CEF/OsrAccessibilityHelper.h"
|
||||
|
||||
OsrAXNode::OsrAXNode(const CefString& treeId,
|
||||
int nodeId,
|
||||
CefRefPtr<CefDictionaryValue> value,
|
||||
OsrAccessibilityHelper* helper)
|
||||
: tree_id_(treeId),
|
||||
node_id_(nodeId),
|
||||
platform_accessibility_(nullptr),
|
||||
parent_(nullptr),
|
||||
offset_container_id_(-1),
|
||||
accessibility_helper_(helper) {
|
||||
UpdateValue(value);
|
||||
}
|
||||
|
||||
void OsrAXNode::UpdateLocation(CefRefPtr<CefDictionaryValue> value) {
|
||||
// Update Bounds
|
||||
if (value->HasKey("bounds")) {
|
||||
CefRefPtr<CefDictionaryValue> loc = value->GetDictionary("bounds");
|
||||
if (loc) {
|
||||
location_ = CefRect(loc->GetDouble("x"), loc->GetDouble("y"),
|
||||
loc->GetDouble("width"), loc->GetDouble("height"));
|
||||
}
|
||||
}
|
||||
// Update offsets
|
||||
if (value->HasKey("offset_container_id")) {
|
||||
offset_container_id_ = OsrAccessibilityHelper::CastToInt(
|
||||
value->GetValue("offset_container_id"));
|
||||
}
|
||||
}
|
||||
|
||||
void OsrAXNode::UpdateValue(CefRefPtr<CefDictionaryValue> value) {
|
||||
if (value->HasKey("role"))
|
||||
role_ = value->GetString("role");
|
||||
|
||||
if (value->HasKey("child_ids")) {
|
||||
CefRefPtr<CefListValue> childs = value->GetList("child_ids");
|
||||
// Reset child Ids
|
||||
child_ids_.clear();
|
||||
for (size_t idx = 0; idx < childs->GetSize(); idx++)
|
||||
child_ids_.push_back(
|
||||
OsrAccessibilityHelper::CastToInt(childs->GetValue(idx)));
|
||||
}
|
||||
// Update Location
|
||||
if (value->HasKey("location")) {
|
||||
CefRefPtr<CefDictionaryValue> loc = value->GetDictionary("location");
|
||||
if (loc) {
|
||||
location_ = CefRect(loc->GetDouble("x"), loc->GetDouble("y"),
|
||||
loc->GetDouble("width"), loc->GetDouble("height"));
|
||||
}
|
||||
}
|
||||
// Update offsets
|
||||
if (value->HasKey("offset_container_id")) {
|
||||
offset_container_id_ = OsrAccessibilityHelper::CastToInt(
|
||||
value->GetValue("offset_container_id"));
|
||||
}
|
||||
// Update attributes
|
||||
if (value->HasKey("attributes")) {
|
||||
child_tree_id_ = "";
|
||||
|
||||
attributes_ = value->GetDictionary("attributes");
|
||||
|
||||
if (attributes_) {
|
||||
scroll_.x = attributes_->HasKey("scrollX")
|
||||
? OsrAccessibilityHelper::CastToInt(
|
||||
attributes_->GetValue("scrollX"))
|
||||
: 0;
|
||||
scroll_.y = attributes_->HasKey("scrollY")
|
||||
? OsrAccessibilityHelper::CastToInt(
|
||||
attributes_->GetValue("scrollY"))
|
||||
: 0;
|
||||
}
|
||||
|
||||
if (attributes_ && attributes_->HasKey("childTreeId")) {
|
||||
child_tree_id_ = attributes_->GetString("childTreeId");
|
||||
}
|
||||
if (attributes_ && attributes_->HasKey("name"))
|
||||
name_ = attributes_->GetString("name");
|
||||
if (attributes_ && attributes_->HasKey("value"))
|
||||
value_ = attributes_->GetString("value");
|
||||
if (attributes_ && attributes_->HasKey("description"))
|
||||
description_ = attributes_->GetString("description");
|
||||
}
|
||||
}
|
||||
|
||||
CefWindowHandle OsrAXNode::GetWindowHandle() const {
|
||||
if (accessibility_helper_)
|
||||
return accessibility_helper_->GetWindowHandle();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CefRefPtr<CefBrowser> OsrAXNode::GetBrowser() const {
|
||||
if (accessibility_helper_)
|
||||
return accessibility_helper_->GetBrowser();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void OsrAXNode::SetParent(OsrAXNode* parent) {
|
||||
parent_ = parent;
|
||||
}
|
||||
|
||||
CefRect OsrAXNode::AxLocation() const {
|
||||
CefRect loc = location_;
|
||||
loc.x -= scroll_.x;
|
||||
loc.y -= scroll_.y;
|
||||
OsrAXNode* offsetNode =
|
||||
accessibility_helper_->GetNode(OsrAXTreeId(), offset_container_id_);
|
||||
if (!offsetNode) {
|
||||
OsrAXNode* p = parent_;
|
||||
while (p) {
|
||||
if (p->OsrAXTreeId() != OsrAXTreeId()) {
|
||||
offsetNode = p;
|
||||
break;
|
||||
}
|
||||
p = p->parent_;
|
||||
}
|
||||
}
|
||||
// Add offset from parent Location
|
||||
if (offsetNode) {
|
||||
CefRect offset = offsetNode->AxLocation();
|
||||
loc.x += offset.x;
|
||||
loc.y += offset.y;
|
||||
}
|
||||
return loc;
|
||||
}
|
||||
|
||||
int OsrAXNode::GetChildCount() const {
|
||||
int count = static_cast<int>(child_ids_.size());
|
||||
if (!child_tree_id_.empty()) {
|
||||
OsrAXNode* childTreeRootNode =
|
||||
accessibility_helper_->GetTreeRootNode(child_tree_id_);
|
||||
if (childTreeRootNode) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
OsrAXNode* OsrAXNode::ChildAtIndex(int index) const {
|
||||
int count = static_cast<int>(child_ids_.size());
|
||||
if (index < count)
|
||||
return accessibility_helper_->GetNode(OsrAXTreeId(), child_ids_[index]);
|
||||
if ((index == count) && (!child_tree_id_.empty())) {
|
||||
OsrAXNode* childTreeRootNode =
|
||||
accessibility_helper_->GetTreeRootNode(child_tree_id_);
|
||||
if (childTreeRootNode) {
|
||||
return childTreeRootNode;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Create and return the platform specific OsrAXNode Object
|
||||
OsrAXNode* OsrAXNode::CreateNode(const CefString& treeId,
|
||||
int nodeId,
|
||||
CefRefPtr<CefDictionaryValue> value,
|
||||
OsrAccessibilityHelper* helper) {
|
||||
return new OsrAXNode(treeId, nodeId, value, helper);
|
||||
}
|
116
src/CEF/OsrAccessibilityNode.h
Normal file
116
src/CEF/OsrAccessibilityNode.h
Normal file
@ -0,0 +1,116 @@
|
||||
// Copyright 2017 The Chromium Embedded Framework Authors. Portions copyright
|
||||
// 2013 The Chromium Authors. All rights reserved. Use of this source code is
|
||||
// governed by a BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "include/cef_browser.h"
|
||||
|
||||
#if defined(OS_MAC)
|
||||
typedef void CefNativeAccessible;
|
||||
#if __OBJC__
|
||||
#if __has_feature(objc_arc)
|
||||
#define CAST_CEF_NATIVE_ACCESSIBLE_TO_NSOBJECT(accessible) \
|
||||
(__bridge NSObject*)accessible
|
||||
#define CAST_NSOBJECT_TO_CEF_NATIVE_ACCESSIBLE(object) \
|
||||
(__bridge CefNativeAccessible*)object
|
||||
#else // __has_feature(objc_arc)
|
||||
#define CAST_CEF_NATIVE_ACCESSIBLE_TO_NSOBJECT(accessible) (NSObject*)accessible
|
||||
#define CAST_NSOBJECT_TO_CEF_NATIVE_ACCESSIBLE(object) \
|
||||
(__bridge CefNativeAccessible*)object
|
||||
#endif // __has_feature(objc_arc)
|
||||
#endif // __OBJC__
|
||||
#elif defined(OS_WIN)
|
||||
struct IAccessible;
|
||||
typedef IAccessible CefNativeAccessible;
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
|
||||
class OsrAccessibilityHelper;
|
||||
|
||||
// OsrAXNode is the base class for implementation for the NSAccessibility
|
||||
// protocol for interacting with VoiceOver and other accessibility clients.
|
||||
class OsrAXNode {
|
||||
public:
|
||||
// Create and return the platform specific OsrAXNode Object.
|
||||
static OsrAXNode* CreateNode(const CefString& treeId,
|
||||
int nodeId,
|
||||
CefRefPtr<CefDictionaryValue> value,
|
||||
OsrAccessibilityHelper* helper);
|
||||
|
||||
// Update Value.
|
||||
void UpdateValue(CefRefPtr<CefDictionaryValue> value);
|
||||
|
||||
// UpdateLocation
|
||||
void UpdateLocation(CefRefPtr<CefDictionaryValue> value);
|
||||
|
||||
// Fire a platform-specific notification that an event has occurred on
|
||||
// this object.
|
||||
void NotifyAccessibilityEvent(std::string event_type) const;
|
||||
|
||||
// Call Destroy rather than deleting this, because the subclass may
|
||||
// use reference counting.
|
||||
void Destroy();
|
||||
|
||||
// Return NSAccessibility Object for Mac/ IAccessible for Windows
|
||||
CefNativeAccessible* GetNativeAccessibleObject(OsrAXNode* parent);
|
||||
|
||||
CefNativeAccessible* GetParentAccessibleObject() const {
|
||||
return parent_ ? parent_->platform_accessibility_ : nullptr;
|
||||
}
|
||||
|
||||
OsrAccessibilityHelper* GetAccessibilityHelper() const {
|
||||
return accessibility_helper_;
|
||||
}
|
||||
|
||||
int GetChildCount() const;
|
||||
|
||||
// Return the Child at the specified index
|
||||
OsrAXNode* ChildAtIndex(int index) const;
|
||||
|
||||
const CefString& AxRole() const { return role_; }
|
||||
|
||||
const CefString& OsrAXTreeId() const { return tree_id_; }
|
||||
|
||||
int OsrAXNodeId() const { return node_id_; }
|
||||
|
||||
const CefString& AxValue() const { return value_; }
|
||||
|
||||
const CefString& AxName() const { return name_; }
|
||||
|
||||
const CefString& AxDescription() const { return description_; }
|
||||
|
||||
CefRect AxLocation() const;
|
||||
|
||||
CefWindowHandle GetWindowHandle() const;
|
||||
|
||||
CefRefPtr<CefBrowser> GetBrowser() const;
|
||||
|
||||
void SetParent(OsrAXNode* parent);
|
||||
|
||||
protected:
|
||||
OsrAXNode(const CefString& treeId,
|
||||
int nodeId,
|
||||
CefRefPtr<CefDictionaryValue> value,
|
||||
OsrAccessibilityHelper* helper);
|
||||
|
||||
CefString tree_id_;
|
||||
int node_id_;
|
||||
CefString child_tree_id_;
|
||||
CefString role_;
|
||||
CefString value_;
|
||||
CefString name_;
|
||||
CefString description_;
|
||||
CefRect location_;
|
||||
CefPoint scroll_;
|
||||
std::vector<int> child_ids_;
|
||||
CefNativeAccessible* platform_accessibility_;
|
||||
OsrAXNode* parent_;
|
||||
int offset_container_id_;
|
||||
OsrAccessibilityHelper* accessibility_helper_;
|
||||
CefRefPtr<CefDictionaryValue> attributes_;
|
||||
};
|
684
src/CEF/OsrAccessibilityNodeWin.cpp
Normal file
684
src/CEF/OsrAccessibilityNodeWin.cpp
Normal file
@ -0,0 +1,684 @@
|
||||
// Copyright 2017 The Chromium Embedded Framework Authors. Portions copyright
|
||||
// 2013 The Chromium Authors. All rights reserved. Use of this source code is
|
||||
// governed by a BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// This class implements our accessible proxy object that handles moving
|
||||
// data back and forth between MSAA clients and CefClient renderers.
|
||||
// Sample implementation based on ui\accessibility\ax_platform_node_win.h
|
||||
|
||||
#include "CEF/OsrAccessibilityNode.h"
|
||||
|
||||
#if defined(CEF_USE_ATL)
|
||||
|
||||
#include <atlbase.h>
|
||||
#include <oleacc.h>
|
||||
#include <string>
|
||||
|
||||
#include "CEF/OsrAccessibilityHelper.h"
|
||||
|
||||
// Return CO_E_OBJNOTCONNECTED for accessible objects thar still exists but the
|
||||
// window and/or object it references has been destroyed.
|
||||
#define DATACHECK(node) (node) ? S_OK : CO_E_OBJNOTCONNECTED
|
||||
#define VALID_CHILDID(varChild) ((varChild.vt == VT_I4))
|
||||
|
||||
// Helper function to convert a rectangle from client coordinates to screen
|
||||
// coordinates.
|
||||
void ClientToScreen(HWND hwnd, LPRECT lpRect) {
|
||||
if (lpRect) {
|
||||
POINT ptTL = {lpRect->left, lpRect->top};
|
||||
POINT ptBR = {lpRect->right, lpRect->bottom};
|
||||
// Win32 API only provides the call for a point.
|
||||
ClientToScreen(hwnd, &ptTL);
|
||||
ClientToScreen(hwnd, &ptBR);
|
||||
SetRect(lpRect, ptTL.x, ptTL.y, ptBR.x, ptBR.y);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to convert to MSAARole
|
||||
int AxRoleToMSAARole(const std::string& role_string) {
|
||||
if (role_string == "alert")
|
||||
return ROLE_SYSTEM_ALERT;
|
||||
if (role_string == "application")
|
||||
return ROLE_SYSTEM_APPLICATION;
|
||||
if (role_string == "buttonDropDown")
|
||||
return ROLE_SYSTEM_BUTTONDROPDOWN;
|
||||
if (role_string == "popUpButton")
|
||||
return ROLE_SYSTEM_BUTTONMENU;
|
||||
if (role_string == "checkBox")
|
||||
return ROLE_SYSTEM_CHECKBUTTON;
|
||||
if (role_string == "comboBox")
|
||||
return ROLE_SYSTEM_COMBOBOX;
|
||||
if (role_string == "dialog")
|
||||
return ROLE_SYSTEM_DIALOG;
|
||||
if (role_string == "genericContainer")
|
||||
return ROLE_SYSTEM_GROUPING;
|
||||
if (role_string == "group")
|
||||
return ROLE_SYSTEM_GROUPING;
|
||||
if (role_string == "image")
|
||||
return ROLE_SYSTEM_GRAPHIC;
|
||||
if (role_string == "link")
|
||||
return ROLE_SYSTEM_LINK;
|
||||
if (role_string == "locationBar")
|
||||
return ROLE_SYSTEM_GROUPING;
|
||||
if (role_string == "menuBar")
|
||||
return ROLE_SYSTEM_MENUBAR;
|
||||
if (role_string == "menuItem")
|
||||
return ROLE_SYSTEM_MENUITEM;
|
||||
if (role_string == "menuListPopup")
|
||||
return ROLE_SYSTEM_MENUPOPUP;
|
||||
if (role_string == "tree")
|
||||
return ROLE_SYSTEM_OUTLINE;
|
||||
if (role_string == "treeItem")
|
||||
return ROLE_SYSTEM_OUTLINEITEM;
|
||||
if (role_string == "tab")
|
||||
return ROLE_SYSTEM_PAGETAB;
|
||||
if (role_string == "tabList")
|
||||
return ROLE_SYSTEM_PAGETABLIST;
|
||||
if (role_string == "pane")
|
||||
return ROLE_SYSTEM_PANE;
|
||||
if (role_string == "progressIndicator")
|
||||
return ROLE_SYSTEM_PROGRESSBAR;
|
||||
if (role_string == "button")
|
||||
return ROLE_SYSTEM_PUSHBUTTON;
|
||||
if (role_string == "radioButton")
|
||||
return ROLE_SYSTEM_RADIOBUTTON;
|
||||
if (role_string == "scrollBar")
|
||||
return ROLE_SYSTEM_SCROLLBAR;
|
||||
if (role_string == "splitter")
|
||||
return ROLE_SYSTEM_SEPARATOR;
|
||||
if (role_string == "slider")
|
||||
return ROLE_SYSTEM_SLIDER;
|
||||
if (role_string == "staticText")
|
||||
return ROLE_SYSTEM_STATICTEXT;
|
||||
if (role_string == "textField")
|
||||
return ROLE_SYSTEM_TEXT;
|
||||
if (role_string == "titleBar")
|
||||
return ROLE_SYSTEM_TITLEBAR;
|
||||
if (role_string == "toolbar")
|
||||
return ROLE_SYSTEM_TOOLBAR;
|
||||
if (role_string == "webView")
|
||||
return ROLE_SYSTEM_GROUPING;
|
||||
if (role_string == "window")
|
||||
return ROLE_SYSTEM_WINDOW;
|
||||
if (role_string == "client")
|
||||
return ROLE_SYSTEM_CLIENT;
|
||||
// This is the default role for MSAA.
|
||||
return ROLE_SYSTEM_CLIENT;
|
||||
}
|
||||
|
||||
static inline int MiddleX(const CefRect& rect) {
|
||||
return rect.x + rect.width / 2;
|
||||
}
|
||||
|
||||
static inline int MiddleY(const CefRect& rect) {
|
||||
return rect.y + rect.height / 2;
|
||||
}
|
||||
|
||||
struct CefIAccessible : public IAccessible {
|
||||
public:
|
||||
// Implement IUnknown
|
||||
STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject) override;
|
||||
STDMETHODIMP_(ULONG) AddRef() override;
|
||||
STDMETHODIMP_(ULONG) Release() override;
|
||||
|
||||
//
|
||||
// IAccessible methods.
|
||||
//
|
||||
// Retrieves the child element or child object at a given point on the screen.
|
||||
STDMETHODIMP accHitTest(LONG x_left, LONG y_top, VARIANT* child) override;
|
||||
|
||||
// Performs the object's default action.
|
||||
STDMETHODIMP accDoDefaultAction(VARIANT var_id) override;
|
||||
|
||||
// Retrieves the specified object's current screen location.
|
||||
STDMETHODIMP accLocation(LONG* x_left,
|
||||
LONG* y_top,
|
||||
LONG* width,
|
||||
LONG* height,
|
||||
VARIANT var_id) override;
|
||||
|
||||
// Traverses to another UI element and retrieves the object.
|
||||
STDMETHODIMP accNavigate(LONG nav_dir, VARIANT start, VARIANT* end) override;
|
||||
|
||||
// Retrieves an IDispatch interface pointer for the specified child.
|
||||
STDMETHODIMP get_accChild(VARIANT var_child, IDispatch** disp_child) override;
|
||||
|
||||
// Retrieves the number of accessible children.
|
||||
STDMETHODIMP get_accChildCount(LONG* child_count) override;
|
||||
|
||||
// Retrieves a string that describes the object's default action.
|
||||
STDMETHODIMP get_accDefaultAction(VARIANT var_id,
|
||||
BSTR* default_action) override;
|
||||
|
||||
// Retrieves the tooltip description.
|
||||
STDMETHODIMP get_accDescription(VARIANT var_id, BSTR* desc) override;
|
||||
|
||||
// Retrieves the object that has the keyboard focus.
|
||||
STDMETHODIMP get_accFocus(VARIANT* focus_child) override;
|
||||
|
||||
// Retrieves the specified object's shortcut.
|
||||
STDMETHODIMP get_accKeyboardShortcut(VARIANT var_id,
|
||||
BSTR* access_key) override;
|
||||
|
||||
// Retrieves the name of the specified object.
|
||||
STDMETHODIMP get_accName(VARIANT var_id, BSTR* name) override;
|
||||
|
||||
// Retrieves the IDispatch interface of the object's parent.
|
||||
STDMETHODIMP get_accParent(IDispatch** disp_parent) override;
|
||||
|
||||
// Retrieves information describing the role of the specified object.
|
||||
STDMETHODIMP get_accRole(VARIANT var_id, VARIANT* role) override;
|
||||
|
||||
// Retrieves the current state of the specified object.
|
||||
STDMETHODIMP get_accState(VARIANT var_id, VARIANT* state) override;
|
||||
|
||||
// Gets the help string for the specified object.
|
||||
STDMETHODIMP get_accHelp(VARIANT var_id, BSTR* help) override;
|
||||
|
||||
// Retrieve or set the string value associated with the specified object.
|
||||
// Setting the value is not typically used by screen readers, but it's
|
||||
// used frequently by automation software.
|
||||
STDMETHODIMP get_accValue(VARIANT var_id, BSTR* value) override;
|
||||
STDMETHODIMP put_accValue(VARIANT var_id, BSTR new_value) override;
|
||||
|
||||
// IAccessible methods not implemented.
|
||||
STDMETHODIMP get_accSelection(VARIANT* selected) override;
|
||||
STDMETHODIMP accSelect(LONG flags_sel, VARIANT var_id) override;
|
||||
STDMETHODIMP get_accHelpTopic(BSTR* help_file,
|
||||
VARIANT var_id,
|
||||
LONG* topic_id) override;
|
||||
STDMETHODIMP put_accName(VARIANT var_id, BSTR put_name) override;
|
||||
|
||||
// Implement IDispatch
|
||||
STDMETHODIMP GetTypeInfoCount(unsigned int FAR* pctinfo) override;
|
||||
STDMETHODIMP GetTypeInfo(unsigned int iTInfo,
|
||||
LCID lcid,
|
||||
ITypeInfo FAR* FAR* ppTInfo) override;
|
||||
STDMETHODIMP GetIDsOfNames(REFIID riid,
|
||||
OLECHAR FAR* FAR* rgszNames,
|
||||
unsigned int cNames,
|
||||
LCID lcid,
|
||||
DISPID FAR* rgDispId) override;
|
||||
STDMETHODIMP Invoke(DISPID dispIdMember,
|
||||
REFIID riid,
|
||||
LCID lcid,
|
||||
WORD wFlags,
|
||||
DISPPARAMS FAR* pDispParams,
|
||||
VARIANT FAR* pVarResult,
|
||||
EXCEPINFO FAR* pExcepInfo,
|
||||
unsigned int FAR* puArgErr) override;
|
||||
|
||||
CefIAccessible(OsrAXNode* node) : ref_count_(0), node_(node) {}
|
||||
|
||||
// Remove the node reference when OsrAXNode is destroyed, so that
|
||||
// MSAA clients get CO_E_OBJNOTCONNECTED
|
||||
void MarkDestroyed() { node_ = nullptr; }
|
||||
|
||||
protected:
|
||||
virtual ~CefIAccessible() {}
|
||||
|
||||
// Ref Count
|
||||
ULONG ref_count_;
|
||||
// OsrAXNode* proxy object
|
||||
OsrAXNode* node_;
|
||||
};
|
||||
|
||||
// Implement IUnknown
|
||||
// *********************
|
||||
|
||||
// Handles ref counting and querying for other supported interfaces.
|
||||
// We only support, IUnknown, IDispatch and IAccessible.
|
||||
STDMETHODIMP CefIAccessible::QueryInterface(REFIID riid, void** ppvObject) {
|
||||
if (riid == IID_IAccessible)
|
||||
*ppvObject = static_cast<IAccessible*>(this);
|
||||
else if (riid == IID_IDispatch)
|
||||
*ppvObject = static_cast<IDispatch*>(this);
|
||||
else if (riid == IID_IUnknown)
|
||||
*ppvObject = static_cast<IUnknown*>(this);
|
||||
else
|
||||
*ppvObject = nullptr;
|
||||
|
||||
if (*ppvObject)
|
||||
reinterpret_cast<IUnknown*>(*ppvObject)->AddRef();
|
||||
|
||||
return (*ppvObject) ? S_OK : E_NOINTERFACE;
|
||||
}
|
||||
|
||||
// Increments COM objects refcount required by IUnknown for reference counting
|
||||
STDMETHODIMP_(ULONG) CefIAccessible::AddRef() {
|
||||
return InterlockedIncrement((LONG volatile*)&ref_count_);
|
||||
}
|
||||
|
||||
STDMETHODIMP_(ULONG) CefIAccessible::Release() {
|
||||
ULONG ulRefCnt = InterlockedDecrement((LONG volatile*)&ref_count_);
|
||||
if (ulRefCnt == 0) {
|
||||
// Remove reference from OsrAXNode
|
||||
if (node_)
|
||||
node_->Destroy();
|
||||
delete this;
|
||||
}
|
||||
|
||||
return ulRefCnt;
|
||||
}
|
||||
|
||||
// Implement IAccessible
|
||||
// *********************
|
||||
|
||||
// Returns the parent IAccessible in the form of an IDispatch interface.
|
||||
STDMETHODIMP CefIAccessible::get_accParent(IDispatch** ppdispParent) {
|
||||
HRESULT retCode = DATACHECK(node_);
|
||||
if (SUCCEEDED(retCode)) {
|
||||
if (ppdispParent) {
|
||||
CefNativeAccessible* parent = node_->GetParentAccessibleObject();
|
||||
if (!parent) {
|
||||
// Find our parent window
|
||||
HWND hWnd = ::GetParent(node_->GetWindowHandle());
|
||||
// if we have a window attempt to get its IAccessible pointer
|
||||
if (hWnd) {
|
||||
AccessibleObjectFromWindow(hWnd, (DWORD)OBJID_CLIENT, IID_IAccessible,
|
||||
(void**)(&parent));
|
||||
}
|
||||
}
|
||||
|
||||
if (parent)
|
||||
parent->AddRef();
|
||||
*ppdispParent = parent;
|
||||
retCode = (*ppdispParent) ? S_OK : S_FALSE;
|
||||
}
|
||||
} else {
|
||||
retCode = E_INVALIDARG;
|
||||
}
|
||||
return retCode;
|
||||
}
|
||||
|
||||
// Returns the number of children we have for this element.
|
||||
STDMETHODIMP CefIAccessible::get_accChildCount(long* pcountChildren) {
|
||||
HRESULT retCode = DATACHECK(node_);
|
||||
if (SUCCEEDED(retCode) && pcountChildren) {
|
||||
// Get Child node count for this from Accessibility tree
|
||||
*pcountChildren = node_->GetChildCount();
|
||||
} else {
|
||||
retCode = E_INVALIDARG;
|
||||
}
|
||||
return retCode;
|
||||
}
|
||||
|
||||
// Returns a child IAccessible object.
|
||||
STDMETHODIMP CefIAccessible::get_accChild(VARIANT varChild,
|
||||
IDispatch** ppdispChild) {
|
||||
HRESULT retCode = DATACHECK(node_);
|
||||
if (SUCCEEDED(retCode)) {
|
||||
int numChilds = node_->GetChildCount();
|
||||
// Mark Leaf node if there are no child
|
||||
if (numChilds <= 0) {
|
||||
*ppdispChild = nullptr;
|
||||
return S_FALSE;
|
||||
} else {
|
||||
if (ppdispChild && VALID_CHILDID(varChild)) {
|
||||
if (varChild.lVal == CHILDID_SELF) {
|
||||
*ppdispChild = this;
|
||||
} else {
|
||||
// Convert to 0 based index and get Child Node.
|
||||
OsrAXNode* child = node_->ChildAtIndex(varChild.lVal - 1);
|
||||
// Fallback to focused node
|
||||
if (!child)
|
||||
child = node_->GetAccessibilityHelper()->GetFocusedNode();
|
||||
|
||||
*ppdispChild = child->GetNativeAccessibleObject(node_);
|
||||
}
|
||||
if (*ppdispChild == nullptr)
|
||||
retCode = S_FALSE;
|
||||
else
|
||||
(*ppdispChild)->AddRef();
|
||||
}
|
||||
}
|
||||
}
|
||||
return retCode;
|
||||
}
|
||||
|
||||
// Check and returns the accessible name for element from accessibility tree
|
||||
STDMETHODIMP CefIAccessible::get_accName(VARIANT varChild, BSTR* pszName) {
|
||||
HRESULT retCode = DATACHECK(node_);
|
||||
if (SUCCEEDED(retCode)) {
|
||||
if (pszName && VALID_CHILDID(varChild)) {
|
||||
std::wstring name = node_->AxName();
|
||||
CComBSTR bstrResult(name.c_str());
|
||||
*pszName = bstrResult.Detach();
|
||||
}
|
||||
} else {
|
||||
retCode = E_INVALIDARG;
|
||||
}
|
||||
return retCode;
|
||||
}
|
||||
|
||||
// Check and returns the value for element from accessibility tree
|
||||
STDMETHODIMP CefIAccessible::get_accValue(VARIANT varChild, BSTR* pszValue) {
|
||||
HRESULT retCode = DATACHECK(node_);
|
||||
if (SUCCEEDED(retCode)) {
|
||||
if (pszValue && VALID_CHILDID(varChild)) {
|
||||
std::wstring name = node_->AxValue();
|
||||
CComBSTR bstrResult(name.c_str());
|
||||
*pszValue = bstrResult.Detach();
|
||||
}
|
||||
} else {
|
||||
retCode = E_INVALIDARG;
|
||||
}
|
||||
return retCode;
|
||||
}
|
||||
|
||||
// Check and returns the description for element from accessibility tree
|
||||
STDMETHODIMP CefIAccessible::get_accDescription(VARIANT varChild,
|
||||
BSTR* pszDescription) {
|
||||
HRESULT retCode = DATACHECK(node_);
|
||||
if (SUCCEEDED(retCode)) {
|
||||
if (pszDescription && VALID_CHILDID(varChild)) {
|
||||
std::wstring name = node_->AxDescription();
|
||||
CComBSTR bstrResult(name.c_str());
|
||||
*pszDescription = bstrResult.Detach();
|
||||
}
|
||||
} else {
|
||||
retCode = E_INVALIDARG;
|
||||
}
|
||||
return retCode;
|
||||
}
|
||||
|
||||
// Check and returns the MSAA Role for element from accessibility tree
|
||||
STDMETHODIMP CefIAccessible::get_accRole(VARIANT varChild, VARIANT* pvarRole) {
|
||||
HRESULT retCode = DATACHECK(node_);
|
||||
if (SUCCEEDED(retCode)) {
|
||||
// Get the accessibilty role and Map to MSAA Role
|
||||
if (pvarRole) {
|
||||
pvarRole->vt = VT_I4;
|
||||
pvarRole->lVal = AxRoleToMSAARole(node_->AxRole());
|
||||
} else {
|
||||
retCode = E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
return retCode;
|
||||
}
|
||||
|
||||
// Check and returns Accessibility State for element from accessibility tree
|
||||
STDMETHODIMP CefIAccessible::get_accState(VARIANT varChild,
|
||||
VARIANT* pvarState) {
|
||||
HRESULT retCode = DATACHECK(node_);
|
||||
if (SUCCEEDED(retCode)) {
|
||||
if (pvarState) {
|
||||
pvarState->vt = VT_I4;
|
||||
pvarState->lVal =
|
||||
(GetFocus() == node_->GetWindowHandle()) ? STATE_SYSTEM_FOCUSED : 0;
|
||||
pvarState->lVal |= STATE_SYSTEM_PRESSED;
|
||||
pvarState->lVal |= STATE_SYSTEM_FOCUSABLE;
|
||||
|
||||
// For child
|
||||
if (varChild.lVal == CHILDID_SELF) {
|
||||
DWORD dwStyle = GetWindowLong(node_->GetWindowHandle(), GWL_STYLE);
|
||||
pvarState->lVal |=
|
||||
((dwStyle & WS_VISIBLE) == 0) ? STATE_SYSTEM_INVISIBLE : 0;
|
||||
pvarState->lVal |=
|
||||
((dwStyle & WS_DISABLED) > 0) ? STATE_SYSTEM_UNAVAILABLE : 0;
|
||||
}
|
||||
} else {
|
||||
retCode = E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
return retCode;
|
||||
}
|
||||
|
||||
// Check and returns Accessibility Shortcut if any for element
|
||||
STDMETHODIMP CefIAccessible::get_accKeyboardShortcut(
|
||||
VARIANT varChild,
|
||||
BSTR* pszKeyboardShortcut) {
|
||||
HRESULT retCode = DATACHECK(node_);
|
||||
if (SUCCEEDED(retCode)) {
|
||||
if (pszKeyboardShortcut && VALID_CHILDID(varChild))
|
||||
*pszKeyboardShortcut = ::SysAllocString(L"None");
|
||||
else
|
||||
retCode = E_INVALIDARG;
|
||||
}
|
||||
return retCode;
|
||||
}
|
||||
|
||||
// Return focused element from the accessibility tree
|
||||
STDMETHODIMP CefIAccessible::get_accFocus(VARIANT* pFocusChild) {
|
||||
HRESULT retCode = DATACHECK(node_);
|
||||
if (SUCCEEDED(retCode)) {
|
||||
OsrAXNode* focusedNode = node_->GetAccessibilityHelper()->GetFocusedNode();
|
||||
CefNativeAccessible* nativeObj = nullptr;
|
||||
if (focusedNode)
|
||||
nativeObj = focusedNode->GetNativeAccessibleObject(nullptr);
|
||||
|
||||
if (nativeObj) {
|
||||
if (nativeObj == this) {
|
||||
pFocusChild->vt = VT_I4;
|
||||
pFocusChild->lVal = CHILDID_SELF;
|
||||
} else {
|
||||
pFocusChild->vt = VT_DISPATCH;
|
||||
pFocusChild->pdispVal = nativeObj;
|
||||
pFocusChild->pdispVal->AddRef();
|
||||
}
|
||||
} else {
|
||||
pFocusChild->vt = VT_EMPTY;
|
||||
}
|
||||
}
|
||||
return retCode;
|
||||
}
|
||||
|
||||
// Return a selection list for multiple selection items.
|
||||
STDMETHODIMP CefIAccessible::get_accSelection(VARIANT* pvarChildren) {
|
||||
HRESULT retCode = DATACHECK(node_);
|
||||
if (SUCCEEDED(retCode)) {
|
||||
if (pvarChildren)
|
||||
pvarChildren->vt = VT_EMPTY;
|
||||
else
|
||||
retCode = E_INVALIDARG;
|
||||
}
|
||||
return retCode;
|
||||
}
|
||||
|
||||
// Return a string description of the default action of our element, eg. push
|
||||
STDMETHODIMP CefIAccessible::get_accDefaultAction(VARIANT varChild,
|
||||
BSTR* pszDefaultAction) {
|
||||
HRESULT retCode = DATACHECK(node_);
|
||||
if (SUCCEEDED(retCode)) {
|
||||
if (pszDefaultAction && VALID_CHILDID(varChild))
|
||||
*pszDefaultAction = ::SysAllocString(L"Push");
|
||||
else
|
||||
retCode = E_INVALIDARG;
|
||||
}
|
||||
return retCode;
|
||||
}
|
||||
|
||||
// child item selectionor for an item to take focus.
|
||||
STDMETHODIMP CefIAccessible::accSelect(long flagsSelect, VARIANT varChild) {
|
||||
HRESULT retCode = DATACHECK(node_);
|
||||
if (SUCCEEDED(retCode)) {
|
||||
if (VALID_CHILDID(varChild)) {
|
||||
HWND hwnd = node_->GetWindowHandle();
|
||||
// we only support SELFLAG_TAKEFOCUS.
|
||||
if (((flagsSelect & SELFLAG_TAKEFOCUS) > 0) && (GetFocus() == hwnd)) {
|
||||
RECT rcWnd;
|
||||
GetClientRect(hwnd, &rcWnd);
|
||||
InvalidateRect(hwnd, &rcWnd, FALSE);
|
||||
} else {
|
||||
retCode = S_FALSE;
|
||||
}
|
||||
} else {
|
||||
retCode = E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
|
||||
return retCode;
|
||||
}
|
||||
|
||||
// Returns back the screen coordinates of our element or one of its childs
|
||||
STDMETHODIMP CefIAccessible::accLocation(long* pxLeft,
|
||||
long* pyTop,
|
||||
long* pcxWidth,
|
||||
long* pcyHeight,
|
||||
VARIANT varChild) {
|
||||
HRESULT retCode = DATACHECK(node_);
|
||||
if (SUCCEEDED(retCode)) {
|
||||
if (pxLeft && pyTop && pcxWidth && pcyHeight && VALID_CHILDID(varChild)) {
|
||||
CefRect loc = node_->AxLocation();
|
||||
RECT rcItem = {loc.x, loc.y, loc.x + loc.width, loc.y + loc.height};
|
||||
HWND hwnd = node_->GetWindowHandle();
|
||||
ClientToScreen(hwnd, &rcItem);
|
||||
|
||||
*pxLeft = rcItem.left;
|
||||
*pyTop = rcItem.top;
|
||||
*pcxWidth = rcItem.right - rcItem.left;
|
||||
*pcyHeight = rcItem.bottom - rcItem.top;
|
||||
} else {
|
||||
retCode = E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
return retCode;
|
||||
}
|
||||
|
||||
// Allow clients to move the keyboard focus within the control
|
||||
// Deprecated
|
||||
STDMETHODIMP CefIAccessible::accNavigate(long navDir,
|
||||
VARIANT varStart,
|
||||
VARIANT* pvarEndUpAt) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
// Check if the coordinates provided are within our element or child items.
|
||||
STDMETHODIMP CefIAccessible::accHitTest(long xLeft,
|
||||
long yTop,
|
||||
VARIANT* pvarChild) {
|
||||
HRESULT retCode = DATACHECK(node_);
|
||||
if (SUCCEEDED(retCode)) {
|
||||
if (pvarChild) {
|
||||
pvarChild->vt = VT_EMPTY;
|
||||
|
||||
CefRect loc = node_->AxLocation();
|
||||
RECT rcItem = {loc.x, loc.y, loc.x + loc.width, loc.y + loc.height};
|
||||
POINT pt = {xLeft, yTop};
|
||||
|
||||
ClientToScreen(node_->GetWindowHandle(), &rcItem);
|
||||
|
||||
if (PtInRect(&rcItem, pt)) {
|
||||
pvarChild->vt = VT_I4;
|
||||
pvarChild->lVal = 1;
|
||||
}
|
||||
} else {
|
||||
retCode = E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
|
||||
return retCode;
|
||||
}
|
||||
|
||||
// Forces the default action of our element. In simplest cases, send a click.
|
||||
STDMETHODIMP CefIAccessible::accDoDefaultAction(VARIANT varChild) {
|
||||
HRESULT retCode = DATACHECK(node_);
|
||||
if (SUCCEEDED(retCode) && VALID_CHILDID(varChild)) {
|
||||
// doing our default action for out button is to simply click the button.
|
||||
CefRefPtr<CefBrowser> browser = node_->GetBrowser();
|
||||
if (browser) {
|
||||
CefMouseEvent mouse_event;
|
||||
const CefRect& rect = node_->AxLocation();
|
||||
mouse_event.x = MiddleX(rect);
|
||||
mouse_event.y = MiddleY(rect);
|
||||
|
||||
mouse_event.modifiers = 0;
|
||||
browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_LEFT, false, 1);
|
||||
browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_LEFT, true, 1);
|
||||
}
|
||||
} else {
|
||||
retCode = E_INVALIDARG;
|
||||
}
|
||||
|
||||
return retCode;
|
||||
}
|
||||
|
||||
// Set the name for an element in the accessibility tree
|
||||
STDMETHODIMP CefIAccessible::put_accName(VARIANT varChild, BSTR szName) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
// Set the value for an element in the accessibility tree
|
||||
STDMETHODIMP CefIAccessible::put_accValue(VARIANT varChild, BSTR szValue) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
// Return E_NOTIMPL as no help file/ topic
|
||||
STDMETHODIMP CefIAccessible::get_accHelp(VARIANT varChild, BSTR* pszHelp) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP CefIAccessible::get_accHelpTopic(BSTR* pszHelpFile,
|
||||
VARIANT varChild,
|
||||
long* pidTopic) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
// IDispatch - We are not going to return E_NOTIMPL from IDispatch methods and
|
||||
// let Active Accessibility implement the IAccessible interface for them.
|
||||
STDMETHODIMP CefIAccessible::GetTypeInfoCount(unsigned int FAR* pctinfo) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP CefIAccessible::GetTypeInfo(unsigned int iTInfo,
|
||||
LCID lcid,
|
||||
ITypeInfo FAR* FAR* ppTInfo) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP CefIAccessible::GetIDsOfNames(REFIID riid,
|
||||
OLECHAR FAR* FAR* rgszNames,
|
||||
unsigned int cNames,
|
||||
LCID lcid,
|
||||
DISPID FAR* rgDispId) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP CefIAccessible::Invoke(DISPID dispIdMember,
|
||||
REFIID riid,
|
||||
LCID lcid,
|
||||
WORD wFlags,
|
||||
DISPPARAMS FAR* pDispParams,
|
||||
VARIANT FAR* pVarResult,
|
||||
EXCEPINFO FAR* pExcepInfo,
|
||||
unsigned int FAR* puArgErr) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
void OsrAXNode::NotifyAccessibilityEvent(std::string event_type) const {
|
||||
if (event_type == "focus") {
|
||||
// Notify Screen Reader of focus change
|
||||
::NotifyWinEvent(EVENT_OBJECT_FOCUS, GetWindowHandle(), OBJID_CLIENT,
|
||||
node_id_);
|
||||
}
|
||||
}
|
||||
|
||||
void OsrAXNode::Destroy() {
|
||||
CefIAccessible* ptr = static_cast<CefIAccessible*>(platform_accessibility_);
|
||||
if (ptr)
|
||||
ptr->MarkDestroyed();
|
||||
platform_accessibility_ = nullptr;
|
||||
}
|
||||
|
||||
// Create and return NSAccessibility Implementation Object for Window
|
||||
CefNativeAccessible* OsrAXNode::GetNativeAccessibleObject(OsrAXNode* parent) {
|
||||
if (!platform_accessibility_) {
|
||||
platform_accessibility_ = new CefIAccessible(this);
|
||||
platform_accessibility_->AddRef();
|
||||
SetParent(parent);
|
||||
}
|
||||
return platform_accessibility_;
|
||||
}
|
||||
|
||||
|
||||
#else // !defined(CEF_USE_ATL)
|
||||
|
||||
void OsrAXNode::NotifyAccessibilityEvent(std::string event_type) const {}
|
||||
|
||||
void OsrAXNode::Destroy() {}
|
||||
|
||||
CefNativeAccessible* OsrAXNode::GetNativeAccessibleObject(OsrAXNode* parent) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#endif // !defined(CEF_USE_ATL)
|
926
src/CEF/OsrD3D11Win.cpp
Normal file
926
src/CEF/OsrD3D11Win.cpp
Normal file
@ -0,0 +1,926 @@
|
||||
// Copyright 2018 The Chromium Embedded Framework Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be found
|
||||
// in the LICENSE file.
|
||||
//
|
||||
// Portions Copyright (c) 2018 Daktronics with the following MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
|
||||
#include "CEF/OsrD3D11Win.h"
|
||||
|
||||
#include <iomanip> // For std::setw.
|
||||
|
||||
#if OS_WIN && ARCH_CPU_ARM_FAMILY
|
||||
#define __prefetch(x) x
|
||||
#endif
|
||||
#include <d3dcompiler.h>
|
||||
#include <directxmath.h>
|
||||
|
||||
#include "include/base/cef_logging.h"
|
||||
#include "include/internal/cef_string.h"
|
||||
#include "CEF/UtilWin.h"
|
||||
|
||||
// Wrap a raw COM pointer in a shared_ptr for auto Release().
|
||||
namespace d3d11 {
|
||||
template <class T>
|
||||
std::shared_ptr<T> to_com_ptr(T* obj) {
|
||||
return std::shared_ptr<T>(obj, [](T* p) {
|
||||
if (p)
|
||||
p->Release();
|
||||
});
|
||||
}
|
||||
|
||||
struct SimpleVertex {
|
||||
DirectX::XMFLOAT3 pos;
|
||||
DirectX::XMFLOAT2 tex;
|
||||
};
|
||||
|
||||
Context::Context(ID3D11DeviceContext* ctx) : ctx_(to_com_ptr(ctx)) {}
|
||||
|
||||
void Context::flush() {
|
||||
ctx_->Flush();
|
||||
}
|
||||
|
||||
SwapChain::SwapChain(IDXGISwapChain* swapchain,
|
||||
ID3D11RenderTargetView* rtv,
|
||||
ID3D11SamplerState* sampler,
|
||||
ID3D11BlendState* blender)
|
||||
: sampler_(to_com_ptr(sampler)),
|
||||
blender_(to_com_ptr(blender)),
|
||||
swapchain_(to_com_ptr(swapchain)),
|
||||
rtv_(to_com_ptr(rtv)),
|
||||
width_(0),
|
||||
height_(0) {}
|
||||
|
||||
void SwapChain::bind(const std::shared_ptr<Context>& ctx) {
|
||||
ctx_ = ctx;
|
||||
ID3D11DeviceContext* d3d11_ctx = (ID3D11DeviceContext*)(*ctx_);
|
||||
|
||||
ID3D11RenderTargetView* rtv[1] = {rtv_.get()};
|
||||
d3d11_ctx->OMSetRenderTargets(1, rtv, nullptr);
|
||||
|
||||
// Set default blending state.
|
||||
if (blender_) {
|
||||
float factor[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
d3d11_ctx->OMSetBlendState(blender_.get(), factor, 0xffffffff);
|
||||
}
|
||||
|
||||
// Set default sampler state.
|
||||
if (sampler_) {
|
||||
ID3D11SamplerState* samplers[1] = {sampler_.get()};
|
||||
d3d11_ctx->PSSetSamplers(0, 1, samplers);
|
||||
}
|
||||
}
|
||||
|
||||
void SwapChain::unbind() {
|
||||
ctx_.reset();
|
||||
}
|
||||
|
||||
void SwapChain::clear(float red, float green, float blue, float alpha) {
|
||||
ID3D11DeviceContext* d3d11_ctx = (ID3D11DeviceContext*)(*ctx_);
|
||||
CHECK(d3d11_ctx);
|
||||
|
||||
FLOAT color[4] = {red, green, blue, alpha};
|
||||
d3d11_ctx->ClearRenderTargetView(rtv_.get(), color);
|
||||
}
|
||||
|
||||
void SwapChain::present(int sync_interval) {
|
||||
swapchain_->Present(sync_interval, 0);
|
||||
}
|
||||
|
||||
void SwapChain::resize(int width, int height) {
|
||||
if (width <= 0 || height <= 0 || width == width_ || height == height_) {
|
||||
return;
|
||||
}
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
|
||||
ID3D11DeviceContext* d3d11_ctx = (ID3D11DeviceContext*)(*ctx_);
|
||||
CHECK(d3d11_ctx);
|
||||
|
||||
d3d11_ctx->OMSetRenderTargets(0, 0, 0);
|
||||
rtv_.reset();
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC desc;
|
||||
swapchain_->GetDesc(&desc);
|
||||
auto hr = swapchain_->ResizeBuffers(0, width, height, desc.BufferDesc.Format,
|
||||
desc.Flags);
|
||||
if (FAILED(hr)) {
|
||||
LOG(ERROR) << "d3d11: Failed to resize swapchain (" << width << "x"
|
||||
<< height << ")";
|
||||
return;
|
||||
}
|
||||
|
||||
ID3D11Texture2D* buffer = nullptr;
|
||||
hr = swapchain_->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&buffer);
|
||||
if (FAILED(hr)) {
|
||||
LOG(ERROR) << "d3d11: Failed to resize swapchain (" << width << "x"
|
||||
<< height << ")";
|
||||
return;
|
||||
}
|
||||
|
||||
ID3D11Device* dev = nullptr;
|
||||
d3d11_ctx->GetDevice(&dev);
|
||||
if (dev) {
|
||||
D3D11_RENDER_TARGET_VIEW_DESC vdesc = {};
|
||||
vdesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
|
||||
vdesc.Texture2D.MipSlice = 0;
|
||||
vdesc.Format = desc.BufferDesc.Format;
|
||||
|
||||
ID3D11RenderTargetView* view = nullptr;
|
||||
hr = dev->CreateRenderTargetView(buffer, &vdesc, &view);
|
||||
if (SUCCEEDED(hr)) {
|
||||
rtv_ = to_com_ptr(view);
|
||||
d3d11_ctx->OMSetRenderTargets(1, &view, nullptr);
|
||||
}
|
||||
dev->Release();
|
||||
}
|
||||
buffer->Release();
|
||||
|
||||
D3D11_VIEWPORT vp;
|
||||
vp.Width = static_cast<float>(width);
|
||||
vp.Height = static_cast<float>(height);
|
||||
vp.MinDepth = D3D11_MIN_DEPTH;
|
||||
vp.MaxDepth = D3D11_MAX_DEPTH;
|
||||
vp.TopLeftX = 0;
|
||||
vp.TopLeftY = 0;
|
||||
d3d11_ctx->RSSetViewports(1, &vp);
|
||||
}
|
||||
|
||||
Effect::Effect(ID3D11VertexShader* vsh,
|
||||
ID3D11PixelShader* psh,
|
||||
ID3D11InputLayout* layout)
|
||||
: vsh_(to_com_ptr(vsh)),
|
||||
psh_(to_com_ptr(psh)),
|
||||
layout_(to_com_ptr(layout)) {}
|
||||
|
||||
void Effect::bind(const std::shared_ptr<Context>& ctx) {
|
||||
ctx_ = ctx;
|
||||
ID3D11DeviceContext* d3d11_ctx = (ID3D11DeviceContext*)(*ctx_);
|
||||
|
||||
d3d11_ctx->IASetInputLayout(layout_.get());
|
||||
d3d11_ctx->VSSetShader(vsh_.get(), nullptr, 0);
|
||||
d3d11_ctx->PSSetShader(psh_.get(), nullptr, 0);
|
||||
}
|
||||
|
||||
void Effect::unbind() {}
|
||||
|
||||
Geometry::Geometry(D3D_PRIMITIVE_TOPOLOGY primitive,
|
||||
uint32_t vertices,
|
||||
uint32_t stride,
|
||||
ID3D11Buffer* buffer)
|
||||
: primitive_(primitive),
|
||||
vertices_(vertices),
|
||||
stride_(stride),
|
||||
buffer_(to_com_ptr(buffer)) {}
|
||||
|
||||
void Geometry::bind(const std::shared_ptr<Context>& ctx) {
|
||||
ctx_ = ctx;
|
||||
ID3D11DeviceContext* d3d11_ctx = (ID3D11DeviceContext*)(*ctx_);
|
||||
|
||||
// TODO: Handle offset.
|
||||
uint32_t offset = 0;
|
||||
|
||||
ID3D11Buffer* buffers[1] = {buffer_.get()};
|
||||
d3d11_ctx->IASetVertexBuffers(0, 1, buffers, &stride_, &offset);
|
||||
d3d11_ctx->IASetPrimitiveTopology(primitive_);
|
||||
}
|
||||
|
||||
void Geometry::unbind() {}
|
||||
|
||||
void Geometry::draw() {
|
||||
ID3D11DeviceContext* d3d11_ctx = (ID3D11DeviceContext*)(*ctx_);
|
||||
CHECK(d3d11_ctx);
|
||||
|
||||
// TODO: Handle offset.
|
||||
d3d11_ctx->Draw(vertices_, 0);
|
||||
}
|
||||
|
||||
Texture2D::Texture2D(ID3D11Texture2D* tex, ID3D11ShaderResourceView* srv)
|
||||
: texture_(to_com_ptr(tex)), srv_(to_com_ptr(srv)) {
|
||||
share_handle_ = nullptr;
|
||||
|
||||
IDXGIResource* res = nullptr;
|
||||
if (SUCCEEDED(texture_->QueryInterface(__uuidof(IDXGIResource),
|
||||
reinterpret_cast<void**>(&res)))) {
|
||||
res->GetSharedHandle(&share_handle_);
|
||||
res->Release();
|
||||
}
|
||||
|
||||
// Are we using a keyed mutex?
|
||||
IDXGIKeyedMutex* mutex = nullptr;
|
||||
if (SUCCEEDED(texture_->QueryInterface(__uuidof(IDXGIKeyedMutex),
|
||||
(void**)&mutex))) {
|
||||
keyed_mutex_ = to_com_ptr(mutex);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Texture2D::width() const {
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
texture_->GetDesc(&desc);
|
||||
return desc.Width;
|
||||
}
|
||||
|
||||
uint32_t Texture2D::height() const {
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
texture_->GetDesc(&desc);
|
||||
return desc.Height;
|
||||
}
|
||||
|
||||
DXGI_FORMAT Texture2D::format() const {
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
texture_->GetDesc(&desc);
|
||||
return desc.Format;
|
||||
}
|
||||
|
||||
bool Texture2D::has_mutex() const {
|
||||
return (keyed_mutex_.get() != nullptr);
|
||||
}
|
||||
|
||||
bool Texture2D::lock_key(uint64_t key, uint32_t timeout_ms) {
|
||||
if (keyed_mutex_) {
|
||||
const auto hr = keyed_mutex_->AcquireSync(key, timeout_ms);
|
||||
return (hr == S_OK);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Texture2D::unlock_key(uint64_t key) {
|
||||
if (keyed_mutex_) {
|
||||
keyed_mutex_->ReleaseSync(key);
|
||||
}
|
||||
}
|
||||
|
||||
void Texture2D::bind(const std::shared_ptr<Context>& ctx) {
|
||||
ctx_ = ctx;
|
||||
ID3D11DeviceContext* d3d11_ctx = (ID3D11DeviceContext*)(*ctx_);
|
||||
if (srv_) {
|
||||
ID3D11ShaderResourceView* views[1] = {srv_.get()};
|
||||
d3d11_ctx->PSSetShaderResources(0, 1, views);
|
||||
}
|
||||
}
|
||||
|
||||
void Texture2D::unbind() {}
|
||||
|
||||
void* Texture2D::share_handle() const {
|
||||
return share_handle_;
|
||||
}
|
||||
|
||||
void Texture2D::copy_from(const std::shared_ptr<Texture2D>& other) {
|
||||
ID3D11DeviceContext* d3d11_ctx = (ID3D11DeviceContext*)(*ctx_);
|
||||
CHECK(d3d11_ctx);
|
||||
if (other) {
|
||||
d3d11_ctx->CopyResource(texture_.get(), other->texture_.get());
|
||||
}
|
||||
}
|
||||
|
||||
Device::Device(ID3D11Device* pdev, ID3D11DeviceContext* pctx)
|
||||
: device_(to_com_ptr(pdev)), ctx_(std::make_shared<Context>(pctx)) {
|
||||
lib_compiler_ = LoadLibrary(L"d3dcompiler_47.dll");
|
||||
}
|
||||
|
||||
// static
|
||||
std::shared_ptr<Device> Device::create() {
|
||||
UINT flags = 0;
|
||||
#ifdef _DEBUG
|
||||
flags |= D3D11_CREATE_DEVICE_DEBUG;
|
||||
#endif
|
||||
|
||||
D3D_FEATURE_LEVEL feature_levels[] = {
|
||||
D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1,
|
||||
D3D_FEATURE_LEVEL_10_0,
|
||||
// D3D_FEATURE_LEVEL_9_3,
|
||||
};
|
||||
UINT num_feature_levels = sizeof(feature_levels) / sizeof(feature_levels[0]);
|
||||
|
||||
ID3D11Device* pdev = nullptr;
|
||||
ID3D11DeviceContext* pctx = nullptr;
|
||||
|
||||
D3D_FEATURE_LEVEL selected_level;
|
||||
HRESULT hr = D3D11CreateDevice(
|
||||
nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, flags, feature_levels,
|
||||
num_feature_levels, D3D11_SDK_VERSION, &pdev, &selected_level, &pctx);
|
||||
|
||||
if (hr == E_INVALIDARG) {
|
||||
// DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1
|
||||
// so we need to retry without it.
|
||||
hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, flags,
|
||||
&feature_levels[1], num_feature_levels - 1,
|
||||
D3D11_SDK_VERSION, &pdev, &selected_level, &pctx);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
const auto dev = std::make_shared<Device>(pdev, pctx);
|
||||
|
||||
LOG(INFO) << "d3d11: Selected adapter " << dev->adapter_name()
|
||||
<< " and feature level 0x" << std::setw(4) << std::hex
|
||||
<< selected_level;
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string Device::adapter_name() const {
|
||||
IDXGIDevice* dxgi_dev = nullptr;
|
||||
auto hr = device_->QueryInterface(__uuidof(dxgi_dev), (void**)&dxgi_dev);
|
||||
if (SUCCEEDED(hr)) {
|
||||
IDXGIAdapter* dxgi_adapt = nullptr;
|
||||
hr = dxgi_dev->GetAdapter(&dxgi_adapt);
|
||||
dxgi_dev->Release();
|
||||
if (SUCCEEDED(hr)) {
|
||||
DXGI_ADAPTER_DESC desc;
|
||||
hr = dxgi_adapt->GetDesc(&desc);
|
||||
dxgi_adapt->Release();
|
||||
if (SUCCEEDED(hr)) {
|
||||
return CefString(desc.Description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "n/a";
|
||||
}
|
||||
|
||||
std::shared_ptr<Context> Device::immedidate_context() {
|
||||
return ctx_;
|
||||
}
|
||||
|
||||
std::shared_ptr<SwapChain> Device::create_swapchain(HWND window,
|
||||
int width,
|
||||
int height) {
|
||||
HRESULT hr;
|
||||
IDXGIFactory1* dxgi_factory = nullptr;
|
||||
|
||||
// Default size to the window size unless specified.
|
||||
RECT rc_bounds;
|
||||
GetClientRect(window, &rc_bounds);
|
||||
if (width <= 0) {
|
||||
width = rc_bounds.right - rc_bounds.left;
|
||||
}
|
||||
if (height <= 0) {
|
||||
height = rc_bounds.bottom - rc_bounds.top;
|
||||
}
|
||||
|
||||
{
|
||||
IDXGIDevice* dxgi_dev = nullptr;
|
||||
hr = device_->QueryInterface(__uuidof(IDXGIDevice),
|
||||
reinterpret_cast<void**>(&dxgi_dev));
|
||||
if (FAILED(hr)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IDXGIAdapter* adapter = nullptr;
|
||||
hr = dxgi_dev->GetAdapter(&adapter);
|
||||
dxgi_dev->Release();
|
||||
if (FAILED(hr)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
hr = adapter->GetParent(__uuidof(IDXGIFactory1),
|
||||
reinterpret_cast<void**>(&dxgi_factory));
|
||||
adapter->Release();
|
||||
}
|
||||
|
||||
if (!dxgi_factory) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IDXGISwapChain* swapchain = nullptr;
|
||||
|
||||
// Create swap chain.
|
||||
IDXGIFactory2* dxgi_factory2 = nullptr;
|
||||
hr = dxgi_factory->QueryInterface(__uuidof(IDXGIFactory2),
|
||||
reinterpret_cast<void**>(&dxgi_factory2));
|
||||
if (dxgi_factory2) {
|
||||
DXGI_SWAP_CHAIN_DESC1 sd;
|
||||
ZeroMemory(&sd, sizeof(sd));
|
||||
sd.Width = width;
|
||||
sd.Height = height;
|
||||
sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
sd.SampleDesc.Count = 1;
|
||||
sd.SampleDesc.Quality = 0;
|
||||
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
sd.BufferCount = 1;
|
||||
|
||||
IDXGISwapChain1* swapchain1 = nullptr;
|
||||
hr = dxgi_factory2->CreateSwapChainForHwnd(device_.get(), window, &sd,
|
||||
nullptr, nullptr, &swapchain1);
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = swapchain1->QueryInterface(__uuidof(IDXGISwapChain),
|
||||
reinterpret_cast<void**>(&swapchain));
|
||||
swapchain1->Release();
|
||||
}
|
||||
|
||||
dxgi_factory2->Release();
|
||||
} else {
|
||||
// DirectX 11.0 systems.
|
||||
DXGI_SWAP_CHAIN_DESC sd;
|
||||
ZeroMemory(&sd, sizeof(sd));
|
||||
sd.BufferCount = 1;
|
||||
sd.BufferDesc.Width = width;
|
||||
sd.BufferDesc.Height = height;
|
||||
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
sd.BufferDesc.RefreshRate.Numerator = 60;
|
||||
sd.BufferDesc.RefreshRate.Denominator = 1;
|
||||
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
sd.OutputWindow = window;
|
||||
sd.SampleDesc.Count = 1;
|
||||
sd.SampleDesc.Quality = 0;
|
||||
sd.Windowed = TRUE;
|
||||
|
||||
hr = dxgi_factory->CreateSwapChain(device_.get(), &sd, &swapchain);
|
||||
}
|
||||
|
||||
// We don't handle full-screen swapchains so we block the ALT+ENTER shortcut.
|
||||
dxgi_factory->MakeWindowAssociation(window, DXGI_MWA_NO_ALT_ENTER);
|
||||
dxgi_factory->Release();
|
||||
|
||||
if (!swapchain) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ID3D11Texture2D* back_buffer = nullptr;
|
||||
hr = swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D),
|
||||
reinterpret_cast<void**>(&back_buffer));
|
||||
if (FAILED(hr)) {
|
||||
swapchain->Release();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ID3D11RenderTargetView* rtv = nullptr;
|
||||
hr = device_->CreateRenderTargetView(back_buffer, nullptr, &rtv);
|
||||
back_buffer->Release();
|
||||
if (FAILED(hr)) {
|
||||
swapchain->Release();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto ctx = (ID3D11DeviceContext*)(*ctx_);
|
||||
|
||||
ctx->OMSetRenderTargets(1, &rtv, nullptr);
|
||||
|
||||
// Setup the viewport.
|
||||
D3D11_VIEWPORT vp;
|
||||
vp.Width = (FLOAT)width;
|
||||
vp.Height = (FLOAT)height;
|
||||
vp.MinDepth = 0.0f;
|
||||
vp.MaxDepth = 1.0f;
|
||||
vp.TopLeftX = 0;
|
||||
vp.TopLeftY = 0;
|
||||
ctx->RSSetViewports(1, &vp);
|
||||
|
||||
// Create a default sampler to use.
|
||||
ID3D11SamplerState* sampler = nullptr;
|
||||
{
|
||||
D3D11_SAMPLER_DESC desc = {};
|
||||
desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
|
||||
desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
|
||||
desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
|
||||
desc.ComparisonFunc = D3D11_COMPARISON_NEVER;
|
||||
desc.MinLOD = 0.0f;
|
||||
desc.MaxLOD = D3D11_FLOAT32_MAX;
|
||||
desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
|
||||
device_->CreateSamplerState(&desc, &sampler);
|
||||
}
|
||||
|
||||
// Create a default blend state to use (pre-multiplied alpha).
|
||||
ID3D11BlendState* blender = nullptr;
|
||||
{
|
||||
D3D11_BLEND_DESC desc;
|
||||
desc.AlphaToCoverageEnable = FALSE;
|
||||
desc.IndependentBlendEnable = FALSE;
|
||||
const auto count = sizeof(desc.RenderTarget) / sizeof(desc.RenderTarget[0]);
|
||||
for (size_t n = 0; n < count; ++n) {
|
||||
desc.RenderTarget[n].BlendEnable = TRUE;
|
||||
desc.RenderTarget[n].SrcBlend = D3D11_BLEND_ONE;
|
||||
desc.RenderTarget[n].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
|
||||
desc.RenderTarget[n].SrcBlendAlpha = D3D11_BLEND_ONE;
|
||||
desc.RenderTarget[n].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
|
||||
desc.RenderTarget[n].BlendOp = D3D11_BLEND_OP_ADD;
|
||||
desc.RenderTarget[n].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
||||
desc.RenderTarget[n].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
||||
}
|
||||
device_->CreateBlendState(&desc, &blender);
|
||||
}
|
||||
|
||||
return std::make_shared<SwapChain>(swapchain, rtv, sampler, blender);
|
||||
}
|
||||
|
||||
std::shared_ptr<Geometry> Device::create_quad(float x,
|
||||
float y,
|
||||
float width,
|
||||
float height,
|
||||
bool flip) {
|
||||
x = (x * 2.0f) - 1.0f;
|
||||
y = 1.0f - (y * 2.0f);
|
||||
width = width * 2.0f;
|
||||
height = height * 2.0f;
|
||||
float z = 1.0f;
|
||||
|
||||
SimpleVertex vertices[] = {
|
||||
|
||||
{DirectX::XMFLOAT3(x, y, z), DirectX::XMFLOAT2(0.0f, 0.0f)},
|
||||
{DirectX::XMFLOAT3(x + width, y, z), DirectX::XMFLOAT2(1.0f, 0.0f)},
|
||||
{DirectX::XMFLOAT3(x, y - height, z), DirectX::XMFLOAT2(0.0f, 1.0f)},
|
||||
{DirectX::XMFLOAT3(x + width, y - height, z),
|
||||
DirectX::XMFLOAT2(1.0f, 1.0f)}};
|
||||
|
||||
if (flip) {
|
||||
DirectX::XMFLOAT2 tmp(vertices[2].tex);
|
||||
vertices[2].tex = vertices[0].tex;
|
||||
vertices[0].tex = tmp;
|
||||
|
||||
tmp = vertices[3].tex;
|
||||
vertices[3].tex = vertices[1].tex;
|
||||
vertices[1].tex = tmp;
|
||||
}
|
||||
|
||||
D3D11_BUFFER_DESC desc = {};
|
||||
desc.Usage = D3D11_USAGE_DEFAULT;
|
||||
desc.ByteWidth = sizeof(SimpleVertex) * 4;
|
||||
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
||||
desc.CPUAccessFlags = 0;
|
||||
|
||||
D3D11_SUBRESOURCE_DATA srd = {};
|
||||
srd.pSysMem = vertices;
|
||||
|
||||
ID3D11Buffer* buffer = nullptr;
|
||||
const auto hr = device_->CreateBuffer(&desc, &srd, &buffer);
|
||||
if (SUCCEEDED(hr)) {
|
||||
return std::make_shared<Geometry>(
|
||||
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, 4,
|
||||
static_cast<uint32_t>(sizeof(SimpleVertex)), buffer);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<Texture2D> Device::open_shared_texture(void* handle) {
|
||||
ID3D11Texture2D* tex = nullptr;
|
||||
auto hr = device_->OpenSharedResource(handle, __uuidof(ID3D11Texture2D),
|
||||
(void**)(&tex));
|
||||
if (FAILED(hr)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
D3D11_TEXTURE2D_DESC td;
|
||||
tex->GetDesc(&td);
|
||||
|
||||
ID3D11ShaderResourceView* srv = nullptr;
|
||||
|
||||
if (td.BindFlags & D3D11_BIND_SHADER_RESOURCE) {
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc;
|
||||
srv_desc.Format = td.Format;
|
||||
srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
srv_desc.Texture2D.MostDetailedMip = 0;
|
||||
srv_desc.Texture2D.MipLevels = 1;
|
||||
|
||||
hr = device_->CreateShaderResourceView(tex, &srv_desc, &srv);
|
||||
if (FAILED(hr)) {
|
||||
tex->Release();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_shared<Texture2D>(tex, srv);
|
||||
}
|
||||
|
||||
std::shared_ptr<Texture2D> Device::create_texture(int width,
|
||||
int height,
|
||||
DXGI_FORMAT format,
|
||||
const void* data,
|
||||
size_t row_stride) {
|
||||
D3D11_TEXTURE2D_DESC td;
|
||||
td.ArraySize = 1;
|
||||
td.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||
td.CPUAccessFlags = 0;
|
||||
td.Format = format;
|
||||
td.Width = width;
|
||||
td.Height = height;
|
||||
td.MipLevels = 1;
|
||||
td.MiscFlags = 0;
|
||||
td.SampleDesc.Count = 1;
|
||||
td.SampleDesc.Quality = 0;
|
||||
td.Usage = D3D11_USAGE_DEFAULT;
|
||||
|
||||
D3D11_SUBRESOURCE_DATA srd;
|
||||
srd.pSysMem = data;
|
||||
srd.SysMemPitch = static_cast<uint32_t>(row_stride);
|
||||
srd.SysMemSlicePitch = 0;
|
||||
|
||||
ID3D11Texture2D* tex = nullptr;
|
||||
auto hr = device_->CreateTexture2D(&td, data ? &srd : nullptr, &tex);
|
||||
if (FAILED(hr)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc;
|
||||
srv_desc.Format = td.Format;
|
||||
srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
srv_desc.Texture2D.MostDetailedMip = 0;
|
||||
srv_desc.Texture2D.MipLevels = 1;
|
||||
|
||||
ID3D11ShaderResourceView* srv = nullptr;
|
||||
hr = device_->CreateShaderResourceView(tex, &srv_desc, &srv);
|
||||
if (FAILED(hr)) {
|
||||
tex->Release();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::make_shared<Texture2D>(tex, srv);
|
||||
}
|
||||
|
||||
std::shared_ptr<ID3DBlob> Device::compile_shader(const std::string& source_code,
|
||||
const std::string& entry_point,
|
||||
const std::string& model) {
|
||||
if (!lib_compiler_) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
typedef HRESULT(WINAPI * PFN_D3DCOMPILE)(
|
||||
LPCVOID, SIZE_T, LPCSTR, const D3D_SHADER_MACRO*, ID3DInclude*, LPCSTR,
|
||||
LPCSTR, UINT, UINT, ID3DBlob**, ID3DBlob**);
|
||||
|
||||
const auto fnc_compile = reinterpret_cast<PFN_D3DCOMPILE>(
|
||||
GetProcAddress(lib_compiler_, "D3DCompile"));
|
||||
if (!fnc_compile) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DWORD flags = D3DCOMPILE_ENABLE_STRICTNESS;
|
||||
|
||||
#if defined(NDEBUG)
|
||||
// flags |= D3DCOMPILE_OPTIMIZATION_LEVEL3;
|
||||
// flags |= D3DCOMPILE_AVOID_FLOW_CONTROL;
|
||||
#else
|
||||
flags |= D3DCOMPILE_DEBUG;
|
||||
flags |= D3DCOMPILE_SKIP_OPTIMIZATION;
|
||||
#endif
|
||||
|
||||
ID3DBlob* blob = nullptr;
|
||||
ID3DBlob* blob_err = nullptr;
|
||||
|
||||
const auto psrc = source_code.c_str();
|
||||
const auto len = source_code.size() + 1;
|
||||
|
||||
const auto hr =
|
||||
fnc_compile(psrc, len, nullptr, nullptr, nullptr, entry_point.c_str(),
|
||||
model.c_str(), flags, 0, &blob, &blob_err);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
if (blob_err) {
|
||||
// TODO: Log the error.
|
||||
blob_err->Release();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (blob_err) {
|
||||
blob_err->Release();
|
||||
}
|
||||
|
||||
return std::shared_ptr<ID3DBlob>(blob, [](ID3DBlob* p) {
|
||||
if (p)
|
||||
p->Release();
|
||||
});
|
||||
}
|
||||
|
||||
std::shared_ptr<Effect> Device::create_default_effect() {
|
||||
const auto vsh =
|
||||
R"--(struct VS_INPUT
|
||||
{
|
||||
float4 pos : POSITION;
|
||||
float2 tex : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct VS_OUTPUT
|
||||
{
|
||||
float4 pos : SV_POSITION;
|
||||
float2 tex : TEXCOORD0;
|
||||
};
|
||||
|
||||
VS_OUTPUT main(VS_INPUT input)
|
||||
{
|
||||
VS_OUTPUT output;
|
||||
output.pos = input.pos;
|
||||
output.tex = input.tex;
|
||||
return output;
|
||||
})--";
|
||||
|
||||
const auto psh =
|
||||
R"--(Texture2D tex0 : register(t0);
|
||||
SamplerState samp0 : register(s0);
|
||||
|
||||
struct VS_OUTPUT
|
||||
{
|
||||
float4 pos : SV_POSITION;
|
||||
float2 tex : TEXCOORD0;
|
||||
};
|
||||
|
||||
float4 main(VS_OUTPUT input) : SV_Target
|
||||
{
|
||||
return tex0.Sample(samp0, input.tex);
|
||||
})--";
|
||||
|
||||
return create_effect(vsh, "main", "vs_4_0", psh, "main", "ps_4_0");
|
||||
}
|
||||
|
||||
std::shared_ptr<Effect> Device::create_effect(const std::string& vertex_code,
|
||||
const std::string& vertex_entry,
|
||||
const std::string& vertex_model,
|
||||
const std::string& pixel_code,
|
||||
const std::string& pixel_entry,
|
||||
const std::string& pixel_model) {
|
||||
const auto vs_blob = compile_shader(vertex_code, vertex_entry, vertex_model);
|
||||
|
||||
ID3D11VertexShader* vshdr = nullptr;
|
||||
ID3D11InputLayout* layout = nullptr;
|
||||
|
||||
if (vs_blob) {
|
||||
device_->CreateVertexShader(vs_blob->GetBufferPointer(),
|
||||
vs_blob->GetBufferSize(), nullptr, &vshdr);
|
||||
|
||||
D3D11_INPUT_ELEMENT_DESC layout_desc[] = {
|
||||
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,
|
||||
D3D11_INPUT_PER_VERTEX_DATA, 0},
|
||||
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12,
|
||||
D3D11_INPUT_PER_VERTEX_DATA, 0},
|
||||
};
|
||||
|
||||
UINT elements = ARRAYSIZE(layout_desc);
|
||||
|
||||
// Create the input layout.
|
||||
device_->CreateInputLayout(layout_desc, elements,
|
||||
vs_blob->GetBufferPointer(),
|
||||
vs_blob->GetBufferSize(), &layout);
|
||||
}
|
||||
|
||||
const auto ps_blob = compile_shader(pixel_code, pixel_entry, pixel_model);
|
||||
ID3D11PixelShader* pshdr = nullptr;
|
||||
if (ps_blob) {
|
||||
device_->CreatePixelShader(ps_blob->GetBufferPointer(),
|
||||
ps_blob->GetBufferSize(), nullptr, &pshdr);
|
||||
}
|
||||
|
||||
return std::make_shared<Effect>(vshdr, pshdr, layout);
|
||||
}
|
||||
|
||||
Layer::Layer(const std::shared_ptr<Device>& device, bool flip)
|
||||
: device_(device), flip_(flip) {
|
||||
bounds_.x = bounds_.y = bounds_.width = bounds_.height = 0.0f;
|
||||
}
|
||||
|
||||
Layer::~Layer() {}
|
||||
|
||||
void Layer::attach(const std::shared_ptr<Composition>& parent) {
|
||||
composition_ = parent;
|
||||
}
|
||||
|
||||
std::shared_ptr<Composition> Layer::composition() const {
|
||||
return composition_.lock();
|
||||
}
|
||||
|
||||
Rect Layer::bounds() const {
|
||||
return bounds_;
|
||||
}
|
||||
|
||||
void Layer::move(float x, float y, float width, float height) {
|
||||
bounds_.x = x;
|
||||
bounds_.y = y;
|
||||
bounds_.width = width;
|
||||
bounds_.height = height;
|
||||
|
||||
// It's not efficient to create the quad everytime we move, but for now we're
|
||||
// just trying to get something on-screen.
|
||||
geometry_.reset();
|
||||
}
|
||||
|
||||
void Layer::tick(double) {
|
||||
// Nothing to update in the base class.
|
||||
}
|
||||
|
||||
void Layer::render_texture(const std::shared_ptr<Context>& ctx,
|
||||
const std::shared_ptr<Texture2D>& texture) {
|
||||
if (!geometry_) {
|
||||
geometry_ = device_->create_quad(bounds_.x, bounds_.y, bounds_.width,
|
||||
bounds_.height, flip_);
|
||||
}
|
||||
|
||||
if (geometry_ && texture) {
|
||||
// We need a shader.
|
||||
if (!effect_) {
|
||||
effect_ = device_->create_default_effect();
|
||||
}
|
||||
|
||||
// Bind our states/resource to the pipeline.
|
||||
ScopedBinder<Geometry> quad_binder(ctx, geometry_);
|
||||
ScopedBinder<Effect> fx_binder(ctx, effect_);
|
||||
ScopedBinder<Texture2D> tex_binder(ctx, texture);
|
||||
|
||||
// Draw the quad.
|
||||
geometry_->draw();
|
||||
}
|
||||
}
|
||||
|
||||
Composition::Composition(const std::shared_ptr<Device>& device,
|
||||
int width,
|
||||
int height)
|
||||
: width_(width), height_(height), vsync_(true), device_(device) {
|
||||
fps_ = 0.0;
|
||||
time_ = 0.0;
|
||||
frame_ = 0;
|
||||
fps_start_ = GetTimeNow();
|
||||
}
|
||||
|
||||
bool Composition::is_vsync() const {
|
||||
return vsync_;
|
||||
}
|
||||
|
||||
double Composition::time() const {
|
||||
return time_;
|
||||
}
|
||||
|
||||
double Composition::fps() const {
|
||||
return fps_;
|
||||
}
|
||||
|
||||
void Composition::add_layer(const std::shared_ptr<Layer>& layer) {
|
||||
if (layer) {
|
||||
layers_.push_back(layer);
|
||||
|
||||
// Attach ourselves as the parent.
|
||||
layer->attach(shared_from_this());
|
||||
}
|
||||
}
|
||||
|
||||
bool Composition::remove_layer(const std::shared_ptr<Layer>& layer) {
|
||||
size_t match = 0;
|
||||
if (layer) {
|
||||
for (auto i = layers_.begin(); i != layers_.end();) {
|
||||
if ((*i).get() == layer.get()) {
|
||||
i = layers_.erase(i);
|
||||
match++;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (match > 0);
|
||||
}
|
||||
|
||||
void Composition::resize(bool vsync, int width, int height) {
|
||||
vsync_ = vsync;
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
}
|
||||
|
||||
void Composition::tick(double t) {
|
||||
time_ = t;
|
||||
for (const auto& layer : layers_) {
|
||||
layer->tick(t);
|
||||
}
|
||||
}
|
||||
|
||||
void Composition::render(const std::shared_ptr<Context>& ctx) {
|
||||
// Use painter's algorithm and render our layers in order (not doing any dept
|
||||
// or 3D here).
|
||||
for (const auto& layer : layers_) {
|
||||
layer->render(ctx);
|
||||
}
|
||||
|
||||
frame_++;
|
||||
const auto now = GetTimeNow();
|
||||
if ((now - fps_start_) > 1000000) {
|
||||
fps_ = frame_ / double((now - fps_start_) / 1000000.0);
|
||||
frame_ = 0;
|
||||
fps_start_ = now;
|
||||
}
|
||||
}
|
||||
|
||||
FrameBuffer::FrameBuffer(const std::shared_ptr<Device>& device)
|
||||
: device_(device) {}
|
||||
|
||||
void FrameBuffer::on_paint(void* shared_handle) {
|
||||
// Did the shared texture change?
|
||||
if (shared_buffer_ && shared_handle != shared_buffer_->share_handle()) {
|
||||
shared_buffer_.reset();
|
||||
}
|
||||
|
||||
// Open the shared texture.
|
||||
if (!shared_buffer_) {
|
||||
shared_buffer_ = device_->open_shared_texture((void*)shared_handle);
|
||||
if (!shared_buffer_) {
|
||||
LOG(ERROR) << "d3d11: Could not open shared texture!";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
322
src/CEF/OsrD3D11Win.h
Normal file
322
src/CEF/OsrD3D11Win.h
Normal file
@ -0,0 +1,322 @@
|
||||
// Copyright 2018 The Chromium Embedded Framework Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be found
|
||||
// in the LICENSE file.
|
||||
//
|
||||
// Portions Copyright (c) 2018 Daktronics with the following MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <d3d11_1.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "include/base/cef_macros.h"
|
||||
|
||||
namespace d3d11 {
|
||||
class Composition;
|
||||
class Context;
|
||||
class Effect;
|
||||
class Geometry;
|
||||
class SwapChain;
|
||||
class Texture2D;
|
||||
|
||||
// Basic rect for floats.
|
||||
struct Rect {
|
||||
float x;
|
||||
float y;
|
||||
float width;
|
||||
float height;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class ScopedBinder {
|
||||
public:
|
||||
ScopedBinder(const std::shared_ptr<Context>& ctx,
|
||||
const std::shared_ptr<T>& target)
|
||||
: target_(target) {
|
||||
if (target_) {
|
||||
target_->bind(ctx);
|
||||
}
|
||||
}
|
||||
~ScopedBinder() {
|
||||
if (target_) {
|
||||
target_->unbind();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const std::shared_ptr<T> target_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ScopedBinder);
|
||||
};
|
||||
|
||||
class Context {
|
||||
public:
|
||||
Context(ID3D11DeviceContext*);
|
||||
|
||||
void flush();
|
||||
|
||||
operator ID3D11DeviceContext*() { return ctx_.get(); }
|
||||
|
||||
private:
|
||||
const std::shared_ptr<ID3D11DeviceContext> ctx_;
|
||||
};
|
||||
|
||||
// Encapsulate a D3D11 Device object.
|
||||
class Device {
|
||||
public:
|
||||
Device(ID3D11Device*, ID3D11DeviceContext*);
|
||||
|
||||
static std::shared_ptr<Device> create();
|
||||
|
||||
std::string adapter_name() const;
|
||||
|
||||
operator ID3D11Device*() { return device_.get(); }
|
||||
|
||||
std::shared_ptr<Context> immedidate_context();
|
||||
|
||||
std::shared_ptr<SwapChain> create_swapchain(HWND,
|
||||
int width = 0,
|
||||
int height = 0);
|
||||
|
||||
std::shared_ptr<Geometry> create_quad(float x,
|
||||
float y,
|
||||
float width,
|
||||
float height,
|
||||
bool flip = false);
|
||||
|
||||
std::shared_ptr<Texture2D> create_texture(int width,
|
||||
int height,
|
||||
DXGI_FORMAT format,
|
||||
const void* data,
|
||||
size_t row_stride);
|
||||
|
||||
std::shared_ptr<Texture2D> open_shared_texture(void*);
|
||||
|
||||
// Create some basic shaders so we can draw a textured-quad.
|
||||
std::shared_ptr<Effect> create_default_effect();
|
||||
|
||||
std::shared_ptr<Effect> create_effect(const std::string& vertex_code,
|
||||
const std::string& vertex_entry,
|
||||
const std::string& vertex_model,
|
||||
const std::string& pixel_code,
|
||||
const std::string& pixel_entry,
|
||||
const std::string& pixel_model);
|
||||
|
||||
private:
|
||||
std::shared_ptr<ID3DBlob> compile_shader(const std::string& source_code,
|
||||
const std::string& entry_point,
|
||||
const std::string& model);
|
||||
|
||||
HMODULE lib_compiler_;
|
||||
|
||||
const std::shared_ptr<ID3D11Device> device_;
|
||||
const std::shared_ptr<Context> ctx_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Device);
|
||||
};
|
||||
|
||||
// Encapsulate a DXGI swapchain for a window.
|
||||
class SwapChain {
|
||||
public:
|
||||
SwapChain(IDXGISwapChain*,
|
||||
ID3D11RenderTargetView*,
|
||||
ID3D11SamplerState*,
|
||||
ID3D11BlendState*);
|
||||
|
||||
void bind(const std::shared_ptr<Context>& ctx);
|
||||
void unbind();
|
||||
|
||||
void clear(float red, float green, float blue, float alpha);
|
||||
|
||||
void present(int sync_interval);
|
||||
void resize(int width, int height);
|
||||
|
||||
int width() const { return width_; }
|
||||
int height() const { return height_; }
|
||||
|
||||
private:
|
||||
const std::shared_ptr<ID3D11SamplerState> sampler_;
|
||||
const std::shared_ptr<ID3D11BlendState> blender_;
|
||||
const std::shared_ptr<IDXGISwapChain> swapchain_;
|
||||
std::shared_ptr<ID3D11RenderTargetView> rtv_;
|
||||
std::shared_ptr<Context> ctx_;
|
||||
int width_;
|
||||
int height_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SwapChain);
|
||||
};
|
||||
|
||||
class Texture2D {
|
||||
public:
|
||||
Texture2D(ID3D11Texture2D* tex, ID3D11ShaderResourceView* srv);
|
||||
|
||||
void bind(std::shared_ptr<Context> const& ctx);
|
||||
void unbind();
|
||||
|
||||
uint32_t width() const;
|
||||
uint32_t height() const;
|
||||
DXGI_FORMAT format() const;
|
||||
|
||||
bool has_mutex() const;
|
||||
|
||||
bool lock_key(uint64_t key, uint32_t timeout_ms);
|
||||
void unlock_key(uint64_t key);
|
||||
|
||||
void* share_handle() const;
|
||||
|
||||
void copy_from(const std::shared_ptr<Texture2D>&);
|
||||
|
||||
private:
|
||||
HANDLE share_handle_;
|
||||
|
||||
const std::shared_ptr<ID3D11Texture2D> texture_;
|
||||
const std::shared_ptr<ID3D11ShaderResourceView> srv_;
|
||||
std::shared_ptr<IDXGIKeyedMutex> keyed_mutex_;
|
||||
std::shared_ptr<Context> ctx_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Texture2D);
|
||||
};
|
||||
|
||||
class Effect {
|
||||
public:
|
||||
Effect(ID3D11VertexShader* vsh,
|
||||
ID3D11PixelShader* psh,
|
||||
ID3D11InputLayout* layout);
|
||||
|
||||
void bind(const std::shared_ptr<Context>& ctx);
|
||||
void unbind();
|
||||
|
||||
private:
|
||||
const std::shared_ptr<ID3D11VertexShader> vsh_;
|
||||
const std::shared_ptr<ID3D11PixelShader> psh_;
|
||||
const std::shared_ptr<ID3D11InputLayout> layout_;
|
||||
std::shared_ptr<Context> ctx_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Effect);
|
||||
};
|
||||
|
||||
class Geometry {
|
||||
public:
|
||||
Geometry(D3D_PRIMITIVE_TOPOLOGY primitive,
|
||||
uint32_t vertices,
|
||||
uint32_t stride,
|
||||
ID3D11Buffer*);
|
||||
|
||||
void bind(const std::shared_ptr<Context>& ctx);
|
||||
void unbind();
|
||||
|
||||
void draw();
|
||||
|
||||
private:
|
||||
D3D_PRIMITIVE_TOPOLOGY primitive_;
|
||||
uint32_t vertices_;
|
||||
uint32_t stride_;
|
||||
const std::shared_ptr<ID3D11Buffer> buffer_;
|
||||
std::shared_ptr<Context> ctx_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Geometry);
|
||||
};
|
||||
|
||||
// Abstraction for a 2D layer within a composition.
|
||||
class Layer {
|
||||
public:
|
||||
Layer(const std::shared_ptr<Device>& device, bool flip);
|
||||
virtual ~Layer();
|
||||
|
||||
void attach(const std::shared_ptr<Composition>&);
|
||||
|
||||
// Uses normalized 0-1.0 coordinates.
|
||||
virtual void move(float x, float y, float width, float height);
|
||||
|
||||
virtual void tick(double t);
|
||||
virtual void render(const std::shared_ptr<Context>& ctx) = 0;
|
||||
|
||||
Rect bounds() const;
|
||||
|
||||
std::shared_ptr<Composition> composition() const;
|
||||
|
||||
protected:
|
||||
// Helper method for derived classes to draw a textured-quad.
|
||||
void render_texture(const std::shared_ptr<Context>& ctx,
|
||||
const std::shared_ptr<Texture2D>& texture);
|
||||
|
||||
const std::shared_ptr<Device> device_;
|
||||
const bool flip_;
|
||||
|
||||
Rect bounds_;
|
||||
std::shared_ptr<Geometry> geometry_;
|
||||
std::shared_ptr<Effect> effect_;
|
||||
|
||||
private:
|
||||
std::weak_ptr<Composition> composition_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Layer);
|
||||
};
|
||||
|
||||
// A collection of layers. Will render 1-N layers to a D3D11 device.
|
||||
class Composition : public std::enable_shared_from_this<Composition> {
|
||||
public:
|
||||
Composition(const std::shared_ptr<Device>& device,
|
||||
int width = 0,
|
||||
int height = 0);
|
||||
|
||||
int width() const { return width_; }
|
||||
int height() const { return height_; }
|
||||
|
||||
double fps() const;
|
||||
double time() const;
|
||||
|
||||
bool is_vsync() const;
|
||||
|
||||
void tick(double);
|
||||
void render(const std::shared_ptr<Context>&);
|
||||
|
||||
void add_layer(const std::shared_ptr<Layer>& layer);
|
||||
bool remove_layer(const std::shared_ptr<Layer>& layer);
|
||||
void resize(bool vsync, int width, int height);
|
||||
|
||||
private:
|
||||
int width_;
|
||||
int height_;
|
||||
uint32_t frame_;
|
||||
int64_t fps_start_;
|
||||
double fps_;
|
||||
double time_;
|
||||
bool vsync_;
|
||||
|
||||
const std::shared_ptr<Device> device_;
|
||||
std::vector<std::shared_ptr<Layer>> layers_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Composition);
|
||||
};
|
||||
|
||||
class FrameBuffer {
|
||||
public:
|
||||
explicit FrameBuffer(const std::shared_ptr<Device>& device);
|
||||
|
||||
// Called in response to CEF's OnAcceleratedPaint notification.
|
||||
void on_paint(void* shared_handle);
|
||||
|
||||
// Returns what should be considered the front buffer.
|
||||
std::shared_ptr<Texture2D> texture() const { return shared_buffer_; }
|
||||
|
||||
private:
|
||||
const std::shared_ptr<Device> device_;
|
||||
std::shared_ptr<Texture2D> shared_buffer_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(FrameBuffer);
|
||||
};
|
||||
} // namespace d3d11
|
30
src/CEF/OsrDragdropEvents.h
Normal file
30
src/CEF/OsrDragdropEvents.h
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "include/cef_render_handler.h"
|
||||
#include "tests/cefclient/browser/client_handler.h"
|
||||
|
||||
class OsrDragEvents {
|
||||
public:
|
||||
virtual CefBrowserHost::DragOperationsMask OnDragEnter(
|
||||
CefRefPtr<CefDragData> drag_data,
|
||||
CefMouseEvent ev,
|
||||
CefBrowserHost::DragOperationsMask effect) = 0;
|
||||
|
||||
virtual CefBrowserHost::DragOperationsMask OnDragOver(
|
||||
CefMouseEvent ev,
|
||||
CefBrowserHost::DragOperationsMask effect) = 0;
|
||||
|
||||
virtual void OnDragLeave() = 0;
|
||||
|
||||
virtual CefBrowserHost::DragOperationsMask OnDrop(
|
||||
CefMouseEvent ev,
|
||||
CefBrowserHost::DragOperationsMask effect) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~OsrDragEvents() {}
|
||||
};
|
652
src/CEF/OsrDragdropWin.cpp
Normal file
652
src/CEF/OsrDragdropWin.cpp
Normal file
@ -0,0 +1,652 @@
|
||||
// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#include "CEF/OsrDragdropWin.h"
|
||||
|
||||
#if defined(CEF_USE_ATL)
|
||||
|
||||
#include <shellapi.h>
|
||||
#include <shlobj.h>
|
||||
#include <windowsx.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "include/wrapper/cef_helpers.h"
|
||||
#include "CEF/BytesWriteHandler.h"
|
||||
#include "CEF/resource.h"
|
||||
#include "CEF/UtilWin.h"
|
||||
|
||||
|
||||
DWORD DragOperationToDropEffect(CefRenderHandler::DragOperation allowed_ops) {
|
||||
DWORD effect = DROPEFFECT_NONE;
|
||||
if (allowed_ops & DRAG_OPERATION_COPY)
|
||||
effect |= DROPEFFECT_COPY;
|
||||
if (allowed_ops & DRAG_OPERATION_LINK)
|
||||
effect |= DROPEFFECT_LINK;
|
||||
if (allowed_ops & DRAG_OPERATION_MOVE)
|
||||
effect |= DROPEFFECT_MOVE;
|
||||
return effect;
|
||||
}
|
||||
|
||||
CefRenderHandler::DragOperationsMask DropEffectToDragOperation(DWORD effect) {
|
||||
DWORD operation = DRAG_OPERATION_NONE;
|
||||
if (effect & DROPEFFECT_COPY)
|
||||
operation |= DRAG_OPERATION_COPY;
|
||||
if (effect & DROPEFFECT_LINK)
|
||||
operation |= DRAG_OPERATION_LINK;
|
||||
if (effect & DROPEFFECT_MOVE)
|
||||
operation |= DRAG_OPERATION_MOVE;
|
||||
return static_cast<CefRenderHandler::DragOperationsMask>(operation);
|
||||
}
|
||||
|
||||
CefMouseEvent ToMouseEvent(POINTL p, DWORD key_state, HWND hWnd) {
|
||||
CefMouseEvent ev;
|
||||
POINT screen_point = {p.x, p.y};
|
||||
ScreenToClient(hWnd, &screen_point);
|
||||
ev.x = screen_point.x;
|
||||
ev.y = screen_point.y;
|
||||
ev.modifiers = GetCefMouseModifiers(key_state);
|
||||
return ev;
|
||||
}
|
||||
|
||||
void GetStorageForBytes(STGMEDIUM* storage, const void* data, size_t bytes) {
|
||||
HANDLE handle = GlobalAlloc(GPTR, static_cast<int>(bytes));
|
||||
if (handle) {
|
||||
memcpy(handle, data, bytes);
|
||||
}
|
||||
|
||||
storage->hGlobal = handle;
|
||||
storage->tymed = TYMED_HGLOBAL;
|
||||
storage->pUnkForRelease = nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void GetStorageForString(STGMEDIUM* stgmed, const std::basic_string<T>& data) {
|
||||
GetStorageForBytes(
|
||||
stgmed, data.c_str(),
|
||||
(data.size() + 1) * sizeof(typename std::basic_string<T>::value_type));
|
||||
}
|
||||
|
||||
void GetStorageForFileDescriptor(STGMEDIUM* storage,
|
||||
const std::wstring& file_name) {
|
||||
DCHECK(!file_name.empty());
|
||||
HANDLE hdata = GlobalAlloc(GPTR, sizeof(FILEGROUPDESCRIPTOR));
|
||||
|
||||
FILEGROUPDESCRIPTOR* descriptor =
|
||||
reinterpret_cast<FILEGROUPDESCRIPTOR*>(hdata);
|
||||
descriptor->cItems = 1;
|
||||
descriptor->fgd[0].dwFlags = FD_LINKUI;
|
||||
wcsncpy_s(descriptor->fgd[0].cFileName, MAX_PATH, file_name.c_str(),
|
||||
std::min(file_name.size(), static_cast<size_t>(MAX_PATH - 1u)));
|
||||
|
||||
storage->tymed = TYMED_HGLOBAL;
|
||||
storage->hGlobal = hdata;
|
||||
storage->pUnkForRelease = nullptr;
|
||||
}
|
||||
|
||||
// Helper method for converting from text/html to MS CF_HTML.
|
||||
// Documentation for the CF_HTML format is available at
|
||||
// http://msdn.microsoft.com/en-us/library/aa767917(VS.85).aspx
|
||||
std::string HtmlToCFHtml(const std::string& html, const std::string& base_url) {
|
||||
if (html.empty())
|
||||
return std::string();
|
||||
|
||||
#define MAX_DIGITS 10
|
||||
#define MAKE_NUMBER_FORMAT_1(digits) MAKE_NUMBER_FORMAT_2(digits)
|
||||
#define MAKE_NUMBER_FORMAT_2(digits) "%0" #digits "u"
|
||||
#define NUMBER_FORMAT MAKE_NUMBER_FORMAT_1(MAX_DIGITS)
|
||||
|
||||
static const char* header =
|
||||
"Version:0.9\r\n"
|
||||
"StartHTML:" NUMBER_FORMAT
|
||||
"\r\n"
|
||||
"EndHTML:" NUMBER_FORMAT
|
||||
"\r\n"
|
||||
"StartFragment:" NUMBER_FORMAT
|
||||
"\r\n"
|
||||
"EndFragment:" NUMBER_FORMAT "\r\n";
|
||||
static const char* source_url_prefix = "SourceURL:";
|
||||
|
||||
static const char* start_markup = "<html>\r\n<body>\r\n<!--StartFragment-->";
|
||||
static const char* end_markup = "<!--EndFragment-->\r\n</body>\r\n</html>";
|
||||
|
||||
// Calculate offsets
|
||||
size_t start_html_offset =
|
||||
strlen(header) - strlen(NUMBER_FORMAT) * 4 + MAX_DIGITS * 4;
|
||||
if (!base_url.empty()) {
|
||||
start_html_offset +=
|
||||
strlen(source_url_prefix) + base_url.length() + 2; // Add 2 for \r\n.
|
||||
}
|
||||
size_t start_fragment_offset = start_html_offset + strlen(start_markup);
|
||||
size_t end_fragment_offset = start_fragment_offset + html.length();
|
||||
size_t end_html_offset = end_fragment_offset + strlen(end_markup);
|
||||
char raw_result[1024];
|
||||
_snprintf(raw_result, sizeof(1024), header, start_html_offset,
|
||||
end_html_offset, start_fragment_offset, end_fragment_offset);
|
||||
std::string result = raw_result;
|
||||
if (!base_url.empty()) {
|
||||
result.append(source_url_prefix);
|
||||
result.append(base_url);
|
||||
result.append("\r\n");
|
||||
}
|
||||
result.append(start_markup);
|
||||
result.append(html);
|
||||
result.append(end_markup);
|
||||
|
||||
#undef MAX_DIGITS
|
||||
#undef MAKE_NUMBER_FORMAT_1
|
||||
#undef MAKE_NUMBER_FORMAT_2
|
||||
#undef NUMBER_FORMAT
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void CFHtmlExtractMetadata(const std::string& cf_html,
|
||||
std::string* base_url,
|
||||
size_t* html_start,
|
||||
size_t* fragment_start,
|
||||
size_t* fragment_end) {
|
||||
// Obtain base_url if present.
|
||||
if (base_url) {
|
||||
static std::string src_url_str("SourceURL:");
|
||||
size_t line_start = cf_html.find(src_url_str);
|
||||
if (line_start != std::string::npos) {
|
||||
size_t src_end = cf_html.find("\n", line_start);
|
||||
size_t src_start = line_start + src_url_str.length();
|
||||
if (src_end != std::string::npos && src_start != std::string::npos) {
|
||||
*base_url = cf_html.substr(src_start, src_end - src_start);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find the markup between "<!--StartFragment-->" and "<!--EndFragment-->".
|
||||
// If the comments cannot be found, like copying from OpenOffice Writer,
|
||||
// we simply fall back to using StartFragment/EndFragment bytecount values
|
||||
// to determine the fragment indexes.
|
||||
std::string cf_html_lower = cf_html;
|
||||
size_t markup_start = cf_html_lower.find("<html", 0);
|
||||
if (html_start) {
|
||||
*html_start = markup_start;
|
||||
}
|
||||
size_t tag_start = cf_html.find("<!--StartFragment", markup_start);
|
||||
if (tag_start == std::string::npos) {
|
||||
static std::string start_fragment_str("StartFragment:");
|
||||
size_t start_fragment_start = cf_html.find(start_fragment_str);
|
||||
if (start_fragment_start != std::string::npos) {
|
||||
*fragment_start =
|
||||
static_cast<size_t>(atoi(cf_html.c_str() + start_fragment_start +
|
||||
start_fragment_str.length()));
|
||||
}
|
||||
|
||||
static std::string end_fragment_str("EndFragment:");
|
||||
size_t end_fragment_start = cf_html.find(end_fragment_str);
|
||||
if (end_fragment_start != std::string::npos) {
|
||||
*fragment_end = static_cast<size_t>(atoi(
|
||||
cf_html.c_str() + end_fragment_start + end_fragment_str.length()));
|
||||
}
|
||||
} else {
|
||||
*fragment_start = cf_html.find('>', tag_start) + 1;
|
||||
size_t tag_end = cf_html.rfind("<!--EndFragment", std::string::npos);
|
||||
*fragment_end = cf_html.rfind('<', tag_end);
|
||||
}
|
||||
}
|
||||
|
||||
void CFHtmlToHtml(const std::string& cf_html,
|
||||
std::string* html,
|
||||
std::string* base_url) {
|
||||
size_t frag_start = std::string::npos;
|
||||
size_t frag_end = std::string::npos;
|
||||
|
||||
CFHtmlExtractMetadata(cf_html, base_url, nullptr, &frag_start, &frag_end);
|
||||
|
||||
if (html && frag_start != std::string::npos &&
|
||||
frag_end != std::string::npos) {
|
||||
*html = cf_html.substr(frag_start, frag_end - frag_start);
|
||||
}
|
||||
}
|
||||
|
||||
const DWORD moz_url_format = ::RegisterClipboardFormat(L"text/x-moz-url");
|
||||
const DWORD html_format = ::RegisterClipboardFormat(L"HTML Format");
|
||||
const DWORD file_desc_format = ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR);
|
||||
const DWORD file_contents_format =
|
||||
::RegisterClipboardFormat(CFSTR_FILECONTENTS);
|
||||
|
||||
bool DragDataToDataObject(CefRefPtr<CefDragData> drag_data,
|
||||
IDataObject** data_object) {
|
||||
const int kMaxDataObjects = 10;
|
||||
FORMATETC fmtetcs[kMaxDataObjects];
|
||||
STGMEDIUM stgmeds[kMaxDataObjects];
|
||||
FORMATETC fmtetc = {0, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
|
||||
int curr_index = 0;
|
||||
CefString text = drag_data->GetFragmentText();
|
||||
if (!text.empty()) {
|
||||
fmtetc.cfFormat = CF_UNICODETEXT;
|
||||
fmtetcs[curr_index] = fmtetc;
|
||||
GetStorageForString(&stgmeds[curr_index], text.ToWString());
|
||||
curr_index++;
|
||||
}
|
||||
if (drag_data->IsLink() && !drag_data->GetLinkURL().empty()) {
|
||||
std::wstring x_moz_url_str = drag_data->GetLinkURL().ToWString();
|
||||
x_moz_url_str += '\n';
|
||||
x_moz_url_str += drag_data->GetLinkTitle().ToWString();
|
||||
fmtetc.cfFormat = moz_url_format;
|
||||
fmtetcs[curr_index] = fmtetc;
|
||||
GetStorageForString(&stgmeds[curr_index], x_moz_url_str);
|
||||
curr_index++;
|
||||
}
|
||||
CefString html = drag_data->GetFragmentHtml();
|
||||
if (!html.empty()) {
|
||||
CefString base_url = drag_data->GetFragmentBaseURL();
|
||||
std::string cfhtml = HtmlToCFHtml(html.ToString(), base_url.ToString());
|
||||
fmtetc.cfFormat = html_format;
|
||||
fmtetcs[curr_index] = fmtetc;
|
||||
GetStorageForString(&stgmeds[curr_index], cfhtml);
|
||||
curr_index++;
|
||||
}
|
||||
|
||||
size_t bufferSize = drag_data->GetFileContents(nullptr);
|
||||
if (bufferSize) {
|
||||
CefRefPtr<BytesWriteHandler> handler = new BytesWriteHandler(bufferSize);
|
||||
CefRefPtr<CefStreamWriter> writer =
|
||||
CefStreamWriter::CreateForHandler(handler.get());
|
||||
drag_data->GetFileContents(writer);
|
||||
DCHECK_EQ(handler->GetDataSize(), static_cast<int64>(bufferSize));
|
||||
CefString fileName = drag_data->GetFileName();
|
||||
GetStorageForFileDescriptor(&stgmeds[curr_index], fileName.ToWString());
|
||||
fmtetc.cfFormat = file_desc_format;
|
||||
fmtetcs[curr_index] = fmtetc;
|
||||
curr_index++;
|
||||
GetStorageForBytes(&stgmeds[curr_index], handler->GetData(),
|
||||
handler->GetDataSize());
|
||||
fmtetc.cfFormat = file_contents_format;
|
||||
fmtetcs[curr_index] = fmtetc;
|
||||
curr_index++;
|
||||
}
|
||||
DCHECK_LT(curr_index, kMaxDataObjects);
|
||||
|
||||
CComPtr<DataObjectWin> obj =
|
||||
DataObjectWin::Create(fmtetcs, stgmeds, curr_index);
|
||||
(*data_object) = obj.Detach();
|
||||
return true;
|
||||
}
|
||||
|
||||
CefRefPtr<CefDragData> DataObjectToDragData(IDataObject* data_object) {
|
||||
CefRefPtr<CefDragData> drag_data = CefDragData::Create();
|
||||
IEnumFORMATETC* enumFormats = nullptr;
|
||||
HRESULT res = data_object->EnumFormatEtc(DATADIR_GET, &enumFormats);
|
||||
if (res != S_OK)
|
||||
return drag_data;
|
||||
enumFormats->Reset();
|
||||
const int kCelt = 10;
|
||||
|
||||
ULONG celtFetched;
|
||||
do {
|
||||
celtFetched = kCelt;
|
||||
FORMATETC rgelt[kCelt];
|
||||
res = enumFormats->Next(kCelt, rgelt, &celtFetched);
|
||||
for (unsigned i = 0; i < celtFetched; i++) {
|
||||
CLIPFORMAT format = rgelt[i].cfFormat;
|
||||
if (!(format == CF_UNICODETEXT || format == CF_TEXT ||
|
||||
format == moz_url_format || format == html_format ||
|
||||
format == CF_HDROP) ||
|
||||
rgelt[i].tymed != TYMED_HGLOBAL)
|
||||
continue;
|
||||
STGMEDIUM medium;
|
||||
if (data_object->GetData(&rgelt[i], &medium) == S_OK) {
|
||||
if (!medium.hGlobal) {
|
||||
ReleaseStgMedium(&medium);
|
||||
continue;
|
||||
}
|
||||
void* hGlobal = GlobalLock(medium.hGlobal);
|
||||
if (!hGlobal) {
|
||||
ReleaseStgMedium(&medium);
|
||||
continue;
|
||||
}
|
||||
if (format == CF_UNICODETEXT) {
|
||||
CefString text;
|
||||
text.FromWString((std::wstring::value_type*)hGlobal);
|
||||
drag_data->SetFragmentText(text);
|
||||
} else if (format == CF_TEXT) {
|
||||
CefString text;
|
||||
text.FromString((std::string::value_type*)hGlobal);
|
||||
drag_data->SetFragmentText(text);
|
||||
} else if (format == moz_url_format) {
|
||||
std::wstring html((std::wstring::value_type*)hGlobal);
|
||||
size_t pos = html.rfind('\n');
|
||||
CefString url(html.substr(0, pos));
|
||||
CefString title(html.substr(pos + 1));
|
||||
drag_data->SetLinkURL(url);
|
||||
drag_data->SetLinkTitle(title);
|
||||
} else if (format == html_format) {
|
||||
std::string cf_html((std::string::value_type*)hGlobal);
|
||||
std::string base_url;
|
||||
std::string html;
|
||||
CFHtmlToHtml(cf_html, &html, &base_url);
|
||||
drag_data->SetFragmentHtml(html);
|
||||
drag_data->SetFragmentBaseURL(base_url);
|
||||
}
|
||||
if (format == CF_HDROP) {
|
||||
HDROP hdrop = (HDROP)hGlobal;
|
||||
const int kMaxFilenameLen = 4096;
|
||||
const unsigned num_files = DragQueryFileW(hdrop, 0xffffffff, 0, 0);
|
||||
for (unsigned int x = 0; x < num_files; ++x) {
|
||||
wchar_t filename[kMaxFilenameLen];
|
||||
if (!DragQueryFileW(hdrop, x, filename, kMaxFilenameLen))
|
||||
continue;
|
||||
WCHAR* name = wcsrchr(filename, '\\');
|
||||
drag_data->AddFile(filename, (name ? name + 1 : filename));
|
||||
}
|
||||
}
|
||||
if (medium.hGlobal)
|
||||
GlobalUnlock(medium.hGlobal);
|
||||
if (format == CF_HDROP)
|
||||
DragFinish((HDROP)hGlobal);
|
||||
else
|
||||
ReleaseStgMedium(&medium);
|
||||
}
|
||||
}
|
||||
} while (res == S_OK);
|
||||
enumFormats->Release();
|
||||
return drag_data;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
CComPtr<DropTargetWin> DropTargetWin::Create(OsrDragEvents* callback,
|
||||
HWND hWnd) {
|
||||
return CComPtr<DropTargetWin>(new DropTargetWin(callback, hWnd));
|
||||
}
|
||||
|
||||
HRESULT DropTargetWin::DragEnter(IDataObject* data_object,
|
||||
DWORD key_state,
|
||||
POINTL cursor_position,
|
||||
DWORD* effect) {
|
||||
if (!callback_)
|
||||
return E_UNEXPECTED;
|
||||
|
||||
CefRefPtr<CefDragData> drag_data = current_drag_data_;
|
||||
if (!drag_data) {
|
||||
drag_data = DataObjectToDragData(data_object);
|
||||
}
|
||||
CefMouseEvent ev = ToMouseEvent(cursor_position, key_state, hWnd_);
|
||||
CefBrowserHost::DragOperationsMask mask = DropEffectToDragOperation(*effect);
|
||||
mask = callback_->OnDragEnter(drag_data, ev, mask);
|
||||
*effect = DragOperationToDropEffect(mask);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
CefBrowserHost::DragOperationsMask DropTargetWin::StartDragging(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefDragData> drag_data,
|
||||
CefRenderHandler::DragOperationsMask allowed_ops,
|
||||
int x,
|
||||
int y) {
|
||||
CComPtr<IDataObject> dataObject;
|
||||
DWORD resEffect = DROPEFFECT_NONE;
|
||||
if (DragDataToDataObject(drag_data, &dataObject)) {
|
||||
CComPtr<DropSourceWin> dropSource = DropSourceWin::Create();
|
||||
DWORD effect = DragOperationToDropEffect(allowed_ops);
|
||||
current_drag_data_ = drag_data->Clone();
|
||||
current_drag_data_->ResetFileContents();
|
||||
HRESULT res = DoDragDrop(dataObject, dropSource, effect, &resEffect);
|
||||
if (res != DRAGDROP_S_DROP)
|
||||
resEffect = DROPEFFECT_NONE;
|
||||
current_drag_data_ = nullptr;
|
||||
}
|
||||
return DropEffectToDragOperation(resEffect);
|
||||
}
|
||||
|
||||
HRESULT DropTargetWin::DragOver(DWORD key_state,
|
||||
POINTL cursor_position,
|
||||
DWORD* effect) {
|
||||
if (!callback_)
|
||||
return E_UNEXPECTED;
|
||||
CefMouseEvent ev = ToMouseEvent(cursor_position, key_state, hWnd_);
|
||||
CefBrowserHost::DragOperationsMask mask = DropEffectToDragOperation(*effect);
|
||||
mask = callback_->OnDragOver(ev, mask);
|
||||
*effect = DragOperationToDropEffect(mask);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT DropTargetWin::DragLeave() {
|
||||
if (!callback_)
|
||||
return E_UNEXPECTED;
|
||||
callback_->OnDragLeave();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT DropTargetWin::Drop(IDataObject* data_object,
|
||||
DWORD key_state,
|
||||
POINTL cursor_position,
|
||||
DWORD* effect) {
|
||||
if (!callback_)
|
||||
return E_UNEXPECTED;
|
||||
CefMouseEvent ev = ToMouseEvent(cursor_position, key_state, hWnd_);
|
||||
CefBrowserHost::DragOperationsMask mask = DropEffectToDragOperation(*effect);
|
||||
mask = callback_->OnDrop(ev, mask);
|
||||
*effect = DragOperationToDropEffect(mask);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
CComPtr<DropSourceWin> DropSourceWin::Create() {
|
||||
return CComPtr<DropSourceWin>(new DropSourceWin());
|
||||
}
|
||||
|
||||
HRESULT DropSourceWin::GiveFeedback(DWORD dwEffect) {
|
||||
return DRAGDROP_S_USEDEFAULTCURSORS;
|
||||
}
|
||||
|
||||
HRESULT DropSourceWin::QueryContinueDrag(BOOL fEscapePressed,
|
||||
DWORD grfKeyState) {
|
||||
if (fEscapePressed) {
|
||||
return DRAGDROP_S_CANCEL;
|
||||
}
|
||||
|
||||
if (!(grfKeyState & MK_LBUTTON)) {
|
||||
return DRAGDROP_S_DROP;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT DragEnumFormatEtc::CreateEnumFormatEtc(
|
||||
UINT cfmt,
|
||||
FORMATETC* afmt,
|
||||
IEnumFORMATETC** ppEnumFormatEtc) {
|
||||
if (cfmt == 0 || afmt == 0 || ppEnumFormatEtc == 0)
|
||||
return E_INVALIDARG;
|
||||
|
||||
*ppEnumFormatEtc = new DragEnumFormatEtc(afmt, cfmt);
|
||||
|
||||
return (*ppEnumFormatEtc) ? S_OK : E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
HRESULT DragEnumFormatEtc::Next(ULONG celt,
|
||||
FORMATETC* pFormatEtc,
|
||||
ULONG* pceltFetched) {
|
||||
ULONG copied = 0;
|
||||
|
||||
// copy the FORMATETC structures into the caller's buffer
|
||||
while (m_nIndex < m_nNumFormats && copied < celt) {
|
||||
DeepCopyFormatEtc(&pFormatEtc[copied], &m_pFormatEtc[m_nIndex]);
|
||||
copied++;
|
||||
m_nIndex++;
|
||||
}
|
||||
|
||||
// store result
|
||||
if (pceltFetched != 0)
|
||||
*pceltFetched = copied;
|
||||
|
||||
// did we copy all that was requested?
|
||||
return (copied == celt) ? S_OK : S_FALSE;
|
||||
}
|
||||
HRESULT DragEnumFormatEtc::Skip(ULONG celt) {
|
||||
m_nIndex += celt;
|
||||
return (m_nIndex <= m_nNumFormats) ? S_OK : S_FALSE;
|
||||
}
|
||||
HRESULT DragEnumFormatEtc::Reset(void) {
|
||||
m_nIndex = 0;
|
||||
return S_OK;
|
||||
}
|
||||
HRESULT DragEnumFormatEtc::Clone(IEnumFORMATETC** ppEnumFormatEtc) {
|
||||
HRESULT hResult;
|
||||
|
||||
// make a duplicate enumerator
|
||||
hResult = CreateEnumFormatEtc(m_nNumFormats, m_pFormatEtc, ppEnumFormatEtc);
|
||||
|
||||
if (hResult == S_OK) {
|
||||
// manually set the index state
|
||||
reinterpret_cast<DragEnumFormatEtc*>(*ppEnumFormatEtc)->m_nIndex = m_nIndex;
|
||||
}
|
||||
|
||||
return hResult;
|
||||
}
|
||||
|
||||
DragEnumFormatEtc::DragEnumFormatEtc(FORMATETC* pFormatEtc, int nNumFormats) {
|
||||
AddRef();
|
||||
|
||||
m_nIndex = 0;
|
||||
m_nNumFormats = nNumFormats;
|
||||
m_pFormatEtc = new FORMATETC[nNumFormats];
|
||||
|
||||
// make a new copy of each FORMATETC structure
|
||||
for (int i = 0; i < nNumFormats; i++) {
|
||||
DeepCopyFormatEtc(&m_pFormatEtc[i], &pFormatEtc[i]);
|
||||
}
|
||||
}
|
||||
DragEnumFormatEtc::~DragEnumFormatEtc() {
|
||||
// first free any DVTARGETDEVICE structures
|
||||
for (ULONG i = 0; i < m_nNumFormats; i++) {
|
||||
if (m_pFormatEtc[i].ptd)
|
||||
CoTaskMemFree(m_pFormatEtc[i].ptd);
|
||||
}
|
||||
|
||||
// now free the main array
|
||||
delete[] m_pFormatEtc;
|
||||
}
|
||||
|
||||
void DragEnumFormatEtc::DeepCopyFormatEtc(FORMATETC* dest, FORMATETC* source) {
|
||||
// copy the source FORMATETC into dest
|
||||
*dest = *source;
|
||||
if (source->ptd) {
|
||||
// allocate memory for the DVTARGETDEVICE if necessary
|
||||
dest->ptd = reinterpret_cast<DVTARGETDEVICE*>(
|
||||
CoTaskMemAlloc(sizeof(DVTARGETDEVICE)));
|
||||
|
||||
// copy the contents of the source DVTARGETDEVICE into dest->ptd
|
||||
*(dest->ptd) = *(source->ptd);
|
||||
}
|
||||
}
|
||||
|
||||
CComPtr<DataObjectWin> DataObjectWin::Create(FORMATETC* fmtetc,
|
||||
STGMEDIUM* stgmed,
|
||||
int count) {
|
||||
return CComPtr<DataObjectWin>(new DataObjectWin(fmtetc, stgmed, count));
|
||||
}
|
||||
|
||||
HRESULT DataObjectWin::GetDataHere(FORMATETC* pFormatEtc, STGMEDIUM* pmedium) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT DataObjectWin::QueryGetData(FORMATETC* pFormatEtc) {
|
||||
return (LookupFormatEtc(pFormatEtc) == -1) ? DV_E_FORMATETC : S_OK;
|
||||
}
|
||||
|
||||
HRESULT DataObjectWin::GetCanonicalFormatEtc(FORMATETC* pFormatEct,
|
||||
FORMATETC* pFormatEtcOut) {
|
||||
pFormatEtcOut->ptd = nullptr;
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT DataObjectWin::SetData(FORMATETC* pFormatEtc,
|
||||
STGMEDIUM* pMedium,
|
||||
BOOL fRelease) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT DataObjectWin::DAdvise(FORMATETC* pFormatEtc,
|
||||
DWORD advf,
|
||||
IAdviseSink*,
|
||||
DWORD*) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT DataObjectWin::DUnadvise(DWORD dwConnection) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT DataObjectWin::EnumDAdvise(IEnumSTATDATA** ppEnumAdvise) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT DataObjectWin::EnumFormatEtc(DWORD dwDirection,
|
||||
IEnumFORMATETC** ppEnumFormatEtc) {
|
||||
return DragEnumFormatEtc::CreateEnumFormatEtc(m_nNumFormats, m_pFormatEtc,
|
||||
ppEnumFormatEtc);
|
||||
}
|
||||
|
||||
HRESULT DataObjectWin::GetData(FORMATETC* pFormatEtc, STGMEDIUM* pMedium) {
|
||||
int idx;
|
||||
|
||||
// try to match the specified FORMATETC with one of our supported formats
|
||||
if ((idx = LookupFormatEtc(pFormatEtc)) == -1)
|
||||
return DV_E_FORMATETC;
|
||||
|
||||
// found a match - transfer data into supplied storage medium
|
||||
pMedium->tymed = m_pFormatEtc[idx].tymed;
|
||||
pMedium->pUnkForRelease = 0;
|
||||
|
||||
// copy the data into the caller's storage medium
|
||||
switch (m_pFormatEtc[idx].tymed) {
|
||||
case TYMED_HGLOBAL:
|
||||
pMedium->hGlobal = DupGlobalMem(m_pStgMedium[idx].hGlobal);
|
||||
break;
|
||||
|
||||
default:
|
||||
return DV_E_FORMATETC;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HGLOBAL DataObjectWin::DupGlobalMem(HGLOBAL hMem) {
|
||||
DWORD len = GlobalSize(hMem);
|
||||
PVOID source = GlobalLock(hMem);
|
||||
PVOID dest = GlobalAlloc(GMEM_FIXED, len);
|
||||
|
||||
memcpy(dest, source, len);
|
||||
GlobalUnlock(hMem);
|
||||
return dest;
|
||||
}
|
||||
|
||||
int DataObjectWin::LookupFormatEtc(FORMATETC* pFormatEtc) {
|
||||
// check each of our formats in turn to see if one matches
|
||||
for (int i = 0; i < m_nNumFormats; i++) {
|
||||
if ((m_pFormatEtc[i].tymed & pFormatEtc->tymed) &&
|
||||
m_pFormatEtc[i].cfFormat == pFormatEtc->cfFormat &&
|
||||
m_pFormatEtc[i].dwAspect == pFormatEtc->dwAspect) {
|
||||
// return index of stored format
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// error, format not found
|
||||
return -1;
|
||||
}
|
||||
|
||||
DataObjectWin::DataObjectWin(FORMATETC* fmtetc, STGMEDIUM* stgmed, int count)
|
||||
: ref_count_(0) {
|
||||
m_nNumFormats = count;
|
||||
|
||||
m_pFormatEtc = new FORMATETC[count];
|
||||
m_pStgMedium = new STGMEDIUM[count];
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
m_pFormatEtc[i] = fmtetc[i];
|
||||
m_pStgMedium[i] = stgmed[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // defined(CEF_USE_ATL)
|
183
src/CEF/OsrDragdropWin.h
Normal file
183
src/CEF/OsrDragdropWin.h
Normal file
@ -0,0 +1,183 @@
|
||||
// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
// When generating projects with CMake the CEF_USE_ATL value will be defined
|
||||
// automatically if using a supported Visual Studio version. Pass -DUSE_ATL=OFF
|
||||
// to the CMake command-line to disable use of ATL.
|
||||
// Uncomment this line to manually enable ATL support.
|
||||
// #define CEF_USE_ATL 1
|
||||
|
||||
#if defined(CEF_USE_ATL)
|
||||
|
||||
#include <atlcomcli.h>
|
||||
#include <objidl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "CEF/OsrDragdropEvents.h"
|
||||
|
||||
#define DEFAULT_QUERY_INTERFACE(__Class) \
|
||||
HRESULT __stdcall QueryInterface(const IID& iid, void** object) { \
|
||||
*object = nullptr; \
|
||||
if (IsEqualIID(iid, IID_IUnknown)) { \
|
||||
IUnknown* obj = this; \
|
||||
*object = obj; \
|
||||
} else if (IsEqualIID(iid, IID_##__Class)) { \
|
||||
__Class* obj = this; \
|
||||
*object = obj; \
|
||||
} else { \
|
||||
return E_NOINTERFACE; \
|
||||
} \
|
||||
AddRef(); \
|
||||
return S_OK; \
|
||||
}
|
||||
#define IUNKNOWN_IMPLEMENTATION \
|
||||
ULONG __stdcall AddRef() { return ++ref_count_; } \
|
||||
ULONG __stdcall Release() { \
|
||||
if (--ref_count_ == 0) { \
|
||||
delete this; \
|
||||
return 0U; \
|
||||
} \
|
||||
return ref_count_; \
|
||||
} \
|
||||
\
|
||||
protected: \
|
||||
ULONG ref_count_;
|
||||
|
||||
class DropTargetWin : public IDropTarget {
|
||||
public:
|
||||
static CComPtr<DropTargetWin> Create(OsrDragEvents* callback, HWND hWnd);
|
||||
|
||||
CefBrowserHost::DragOperationsMask StartDragging(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefDragData> drag_data,
|
||||
CefRenderHandler::DragOperationsMask allowed_ops,
|
||||
int x,
|
||||
int y);
|
||||
|
||||
// IDropTarget implementation:
|
||||
HRESULT __stdcall DragEnter(IDataObject* data_object,
|
||||
DWORD key_state,
|
||||
POINTL cursor_position,
|
||||
DWORD* effect);
|
||||
|
||||
HRESULT __stdcall DragOver(DWORD key_state,
|
||||
POINTL cursor_position,
|
||||
DWORD* effect);
|
||||
|
||||
HRESULT __stdcall DragLeave();
|
||||
|
||||
HRESULT __stdcall Drop(IDataObject* data_object,
|
||||
DWORD key_state,
|
||||
POINTL cursor_position,
|
||||
DWORD* effect);
|
||||
|
||||
DEFAULT_QUERY_INTERFACE(IDropTarget)
|
||||
IUNKNOWN_IMPLEMENTATION
|
||||
|
||||
protected:
|
||||
DropTargetWin(OsrDragEvents* callback, HWND hWnd)
|
||||
: ref_count_(0), callback_(callback), hWnd_(hWnd) {}
|
||||
virtual ~DropTargetWin() {}
|
||||
|
||||
private:
|
||||
OsrDragEvents* callback_;
|
||||
HWND hWnd_;
|
||||
|
||||
CefRefPtr<CefDragData> current_drag_data_;
|
||||
};
|
||||
|
||||
class DropSourceWin : public IDropSource {
|
||||
public:
|
||||
static CComPtr<DropSourceWin> Create();
|
||||
|
||||
// IDropSource implementation:
|
||||
HRESULT __stdcall GiveFeedback(DWORD dwEffect);
|
||||
|
||||
HRESULT __stdcall QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState);
|
||||
|
||||
DEFAULT_QUERY_INTERFACE(IDropSource)
|
||||
IUNKNOWN_IMPLEMENTATION
|
||||
|
||||
protected:
|
||||
explicit DropSourceWin() : ref_count_(0) {}
|
||||
virtual ~DropSourceWin() {}
|
||||
};
|
||||
|
||||
class DragEnumFormatEtc : public IEnumFORMATETC {
|
||||
public:
|
||||
static HRESULT CreateEnumFormatEtc(UINT cfmt,
|
||||
FORMATETC* afmt,
|
||||
IEnumFORMATETC** ppEnumFormatEtc);
|
||||
|
||||
//
|
||||
// IEnumFormatEtc members
|
||||
//
|
||||
HRESULT __stdcall Next(ULONG celt,
|
||||
FORMATETC* pFormatEtc,
|
||||
ULONG* pceltFetched);
|
||||
HRESULT __stdcall Skip(ULONG celt);
|
||||
HRESULT __stdcall Reset(void);
|
||||
HRESULT __stdcall Clone(IEnumFORMATETC** ppEnumFormatEtc);
|
||||
|
||||
//
|
||||
// Construction / Destruction
|
||||
//
|
||||
DragEnumFormatEtc(FORMATETC* pFormatEtc, int nNumFormats);
|
||||
virtual ~DragEnumFormatEtc();
|
||||
|
||||
static void DeepCopyFormatEtc(FORMATETC* dest, FORMATETC* source);
|
||||
|
||||
DEFAULT_QUERY_INTERFACE(IEnumFORMATETC)
|
||||
IUNKNOWN_IMPLEMENTATION
|
||||
|
||||
private:
|
||||
ULONG m_nIndex; // current enumerator index
|
||||
ULONG m_nNumFormats; // number of FORMATETC members
|
||||
FORMATETC* m_pFormatEtc; // array of FORMATETC objects
|
||||
};
|
||||
|
||||
class DataObjectWin : public IDataObject {
|
||||
public:
|
||||
static CComPtr<DataObjectWin> Create(FORMATETC* fmtetc,
|
||||
STGMEDIUM* stgmed,
|
||||
int count);
|
||||
|
||||
// IDataObject memberS
|
||||
HRESULT __stdcall GetDataHere(FORMATETC* pFormatEtc, STGMEDIUM* pmedium);
|
||||
HRESULT __stdcall QueryGetData(FORMATETC* pFormatEtc);
|
||||
HRESULT __stdcall GetCanonicalFormatEtc(FORMATETC* pFormatEct,
|
||||
FORMATETC* pFormatEtcOut);
|
||||
HRESULT __stdcall SetData(FORMATETC* pFormatEtc,
|
||||
STGMEDIUM* pMedium,
|
||||
BOOL fRelease);
|
||||
HRESULT __stdcall DAdvise(FORMATETC* pFormatEtc,
|
||||
DWORD advf,
|
||||
IAdviseSink*,
|
||||
DWORD*);
|
||||
HRESULT __stdcall DUnadvise(DWORD dwConnection);
|
||||
HRESULT __stdcall EnumDAdvise(IEnumSTATDATA** ppEnumAdvise);
|
||||
|
||||
HRESULT __stdcall EnumFormatEtc(DWORD dwDirection,
|
||||
IEnumFORMATETC** ppEnumFormatEtc);
|
||||
HRESULT __stdcall GetData(FORMATETC* pFormatEtc, STGMEDIUM* pMedium);
|
||||
|
||||
DEFAULT_QUERY_INTERFACE(IDataObject)
|
||||
IUNKNOWN_IMPLEMENTATION
|
||||
|
||||
protected:
|
||||
int m_nNumFormats;
|
||||
FORMATETC* m_pFormatEtc;
|
||||
STGMEDIUM* m_pStgMedium;
|
||||
|
||||
static HGLOBAL DupGlobalMem(HGLOBAL hMem);
|
||||
|
||||
int LookupFormatEtc(FORMATETC* pFormatEtc);
|
||||
|
||||
explicit DataObjectWin(FORMATETC* fmtetc, STGMEDIUM* stgmed, int count);
|
||||
virtual ~DataObjectWin() {}
|
||||
};
|
||||
|
||||
#endif // defined(CEF_USE_ATL)
|
385
src/CEF/OsrImeHandlerWin.cpp
Normal file
385
src/CEF/OsrImeHandlerWin.cpp
Normal file
@ -0,0 +1,385 @@
|
||||
// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
|
||||
// 2013 The Chromium Authors. All rights reserved. Use of this source code is
|
||||
// governed by a BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// Implementation based on ui/base/ime/win/imm32_manager.cc from Chromium.
|
||||
|
||||
#include <msctf.h>
|
||||
#include <windowsx.h>
|
||||
|
||||
#include "include/base/cef_build.h"
|
||||
#include "CEF/OsrImeHandlerWin.h"
|
||||
#include "CEF/resource.h"
|
||||
#include "CEF/GeometryUtil.h"
|
||||
#include "CEF/MainMessageLoop.h"
|
||||
#include "CEF/UtilWin.h"
|
||||
|
||||
#define ColorUNDERLINE \
|
||||
0xFF000000 // Black SkColor value for underline,
|
||||
// same as Blink.
|
||||
#define ColorBKCOLOR \
|
||||
0x00000000 // White SkColor value for background,
|
||||
// same as Blink.
|
||||
|
||||
// Determines whether or not the given attribute represents a selection
|
||||
bool IsSelectionAttribute(char attribute) {
|
||||
return (attribute == ATTR_TARGET_CONVERTED ||
|
||||
attribute == ATTR_TARGET_NOTCONVERTED);
|
||||
}
|
||||
|
||||
// Helper function for OsrImeHandlerWin::GetCompositionInfo() method,
|
||||
// to get the target range that's selected by the user in the current
|
||||
// composition string.
|
||||
void GetCompositionSelectionRange(HIMC imc,
|
||||
int* target_start,
|
||||
int* target_end) {
|
||||
int attribute_size = ::ImmGetCompositionString(imc, GCS_COMPATTR, nullptr, 0);
|
||||
if (attribute_size > 0) {
|
||||
int start = 0;
|
||||
int end = 0;
|
||||
std::vector<char> attribute_data(attribute_size);
|
||||
|
||||
::ImmGetCompositionString(imc, GCS_COMPATTR, &attribute_data[0],
|
||||
attribute_size);
|
||||
for (start = 0; start < attribute_size; ++start) {
|
||||
if (IsSelectionAttribute(attribute_data[start]))
|
||||
break;
|
||||
}
|
||||
for (end = start; end < attribute_size; ++end) {
|
||||
if (!IsSelectionAttribute(attribute_data[end]))
|
||||
break;
|
||||
}
|
||||
|
||||
*target_start = start;
|
||||
*target_end = end;
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function for OsrImeHandlerWin::GetCompositionInfo() method, to get
|
||||
// underlines information of the current composition string.
|
||||
void GetCompositionUnderlines(
|
||||
HIMC imc,
|
||||
int target_start,
|
||||
int target_end,
|
||||
std::vector<CefCompositionUnderline>& underlines) {
|
||||
int clause_size = ::ImmGetCompositionString(imc, GCS_COMPCLAUSE, nullptr, 0);
|
||||
int clause_length = clause_size / sizeof(uint32);
|
||||
if (clause_length) {
|
||||
std::vector<uint32> clause_data(clause_length);
|
||||
|
||||
::ImmGetCompositionString(imc, GCS_COMPCLAUSE, &clause_data[0],
|
||||
clause_size);
|
||||
for (int i = 0; i < clause_length - 1; ++i) {
|
||||
cef_composition_underline_t underline;
|
||||
underline.range.from = clause_data[i];
|
||||
underline.range.to = clause_data[i + 1];
|
||||
underline.color = ColorUNDERLINE;
|
||||
underline.background_color = ColorBKCOLOR;
|
||||
underline.thick = 0;
|
||||
|
||||
// Use thick underline for the target clause.
|
||||
if (underline.range.from >= target_start &&
|
||||
underline.range.to <= target_end) {
|
||||
underline.thick = 1;
|
||||
}
|
||||
underlines.push_back(underline);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OsrImeHandlerWin::OsrImeHandlerWin(HWND hwnd)
|
||||
: is_composing_(false),
|
||||
input_language_id_(LANG_USER_DEFAULT),
|
||||
system_caret_(false),
|
||||
cursor_index_(-1),
|
||||
hwnd_(hwnd) {
|
||||
ime_rect_ = {-1, -1, 0, 0};
|
||||
}
|
||||
|
||||
OsrImeHandlerWin::~OsrImeHandlerWin() {
|
||||
DestroyImeWindow();
|
||||
}
|
||||
|
||||
void OsrImeHandlerWin::SetInputLanguage() {
|
||||
// Retrieve the current input language from the system's keyboard layout.
|
||||
// Using GetKeyboardLayoutName instead of GetKeyboardLayout, because
|
||||
// the language from GetKeyboardLayout is the language under where the
|
||||
// keyboard layout is installed. And the language from GetKeyboardLayoutName
|
||||
// indicates the language of the keyboard layout itself.
|
||||
// See crbug.com/344834.
|
||||
WCHAR keyboard_layout[KL_NAMELENGTH];
|
||||
if (::GetKeyboardLayoutNameW(keyboard_layout)) {
|
||||
input_language_id_ =
|
||||
static_cast<LANGID>(_wtoi(&keyboard_layout[KL_NAMELENGTH >> 1]));
|
||||
} else {
|
||||
input_language_id_ = 0x0409; // Fallback to en-US.
|
||||
}
|
||||
}
|
||||
|
||||
void OsrImeHandlerWin::CreateImeWindow() {
|
||||
// Chinese/Japanese IMEs somehow ignore function calls to
|
||||
// ::ImmSetCandidateWindow(), and use the position of the current system
|
||||
// caret instead -::GetCaretPos().
|
||||
// Therefore, we create a temporary system caret for Chinese IMEs and use
|
||||
// it during this input context.
|
||||
// Since some third-party Japanese IME also uses ::GetCaretPos() to determine
|
||||
// their window position, we also create a caret for Japanese IMEs.
|
||||
if (PRIMARYLANGID(input_language_id_) == LANG_CHINESE ||
|
||||
PRIMARYLANGID(input_language_id_) == LANG_JAPANESE) {
|
||||
if (!system_caret_) {
|
||||
if (::CreateCaret(hwnd_, nullptr, 1, 1))
|
||||
system_caret_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OsrImeHandlerWin::DestroyImeWindow() {
|
||||
// Destroy the system caret if we have created for this IME input context.
|
||||
if (system_caret_) {
|
||||
::DestroyCaret();
|
||||
system_caret_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void OsrImeHandlerWin::MoveImeWindow() {
|
||||
// Does nothing when the target window has no input focus.
|
||||
if (GetFocus() != hwnd_)
|
||||
return;
|
||||
|
||||
CefRect rc = ime_rect_;
|
||||
int location = cursor_index_;
|
||||
|
||||
// If location is not specified fall back to the composition range start.
|
||||
if (location == -1)
|
||||
location = composition_range_.from;
|
||||
|
||||
// Offset location by the composition range start if required.
|
||||
if (location >= composition_range_.from)
|
||||
location -= composition_range_.from;
|
||||
|
||||
if (location < static_cast<int>(composition_bounds_.size()))
|
||||
rc = composition_bounds_[location];
|
||||
else
|
||||
return;
|
||||
|
||||
HIMC imc = ::ImmGetContext(hwnd_);
|
||||
if (imc) {
|
||||
const int kCaretMargin = 1;
|
||||
if (PRIMARYLANGID(input_language_id_) == LANG_CHINESE) {
|
||||
// Chinese IMEs ignore function calls to ::ImmSetCandidateWindow()
|
||||
// when a user disables TSF (Text Service Framework) and CUAS (Cicero
|
||||
// Unaware Application Support).
|
||||
// On the other hand, when a user enables TSF and CUAS, Chinese IMEs
|
||||
// ignore the position of the current system caret and use the
|
||||
// parameters given to ::ImmSetCandidateWindow() with its 'dwStyle'
|
||||
// parameter CFS_CANDIDATEPOS.
|
||||
// Therefore, we do not only call ::ImmSetCandidateWindow() but also
|
||||
// set the positions of the temporary system caret if it exists.
|
||||
CANDIDATEFORM candidate_position = {
|
||||
0, CFS_CANDIDATEPOS, {rc.x, rc.y}, {0, 0, 0, 0}};
|
||||
::ImmSetCandidateWindow(imc, &candidate_position);
|
||||
}
|
||||
if (system_caret_) {
|
||||
switch (PRIMARYLANGID(input_language_id_)) {
|
||||
case LANG_JAPANESE:
|
||||
::SetCaretPos(rc.x, rc.y + rc.height);
|
||||
break;
|
||||
default:
|
||||
::SetCaretPos(rc.x, rc.y);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (PRIMARYLANGID(input_language_id_) == LANG_KOREAN) {
|
||||
// Korean IMEs require the lower-left corner of the caret to move their
|
||||
// candidate windows.
|
||||
rc.y += kCaretMargin;
|
||||
}
|
||||
|
||||
// Japanese IMEs and Korean IMEs also use the rectangle given to
|
||||
// ::ImmSetCandidateWindow() with its 'dwStyle' parameter CFS_EXCLUDE
|
||||
// Therefore, we also set this parameter here.
|
||||
CANDIDATEFORM exclude_rectangle = {
|
||||
0,
|
||||
CFS_EXCLUDE,
|
||||
{rc.x, rc.y},
|
||||
{rc.x, rc.y, rc.x + rc.width, rc.y + rc.height}};
|
||||
::ImmSetCandidateWindow(imc, &exclude_rectangle);
|
||||
|
||||
::ImmReleaseContext(hwnd_, imc);
|
||||
}
|
||||
}
|
||||
|
||||
void OsrImeHandlerWin::CleanupComposition() {
|
||||
// Notify the IMM attached to the given window to complete the ongoing
|
||||
// composition (when given window is de-activated while composing and
|
||||
// re-activated) and reset the composition status.
|
||||
if (is_composing_) {
|
||||
HIMC imc = ::ImmGetContext(hwnd_);
|
||||
if (imc) {
|
||||
::ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
|
||||
::ImmReleaseContext(hwnd_, imc);
|
||||
}
|
||||
ResetComposition();
|
||||
}
|
||||
}
|
||||
|
||||
void OsrImeHandlerWin::ResetComposition() {
|
||||
// Reset the composition status.
|
||||
is_composing_ = false;
|
||||
cursor_index_ = -1;
|
||||
}
|
||||
|
||||
void OsrImeHandlerWin::GetCompositionInfo(
|
||||
HIMC imc,
|
||||
LPARAM lparam,
|
||||
CefString& composition_text,
|
||||
std::vector<CefCompositionUnderline>& underlines,
|
||||
int& composition_start) {
|
||||
// We only care about GCS_COMPATTR, GCS_COMPCLAUSE and GCS_CURSORPOS, and
|
||||
// convert them into underlines and selection range respectively.
|
||||
underlines.clear();
|
||||
|
||||
int length = static_cast<int>(composition_text.length());
|
||||
|
||||
// Find out the range selected by the user.
|
||||
int target_start = length;
|
||||
int target_end = length;
|
||||
if (lparam & GCS_COMPATTR)
|
||||
GetCompositionSelectionRange(imc, &target_start, &target_end);
|
||||
|
||||
// Retrieve the selection range information. If CS_NOMOVECARET is specified
|
||||
// it means the cursor should not be moved and we therefore place the caret at
|
||||
// the beginning of the composition string. Otherwise we should honour the
|
||||
// GCS_CURSORPOS value if it's available.
|
||||
// TODO(suzhe): Due to a bug in WebKit we currently can't use selection range
|
||||
// with composition string.
|
||||
// See: https://bugs.webkit.org/show_bug.cgi?id=40805
|
||||
if (!(lparam & CS_NOMOVECARET) && (lparam & GCS_CURSORPOS)) {
|
||||
// IMM32 does not support non-zero-width selection in a composition. So
|
||||
// always use the caret position as selection range.
|
||||
int cursor = ::ImmGetCompositionString(imc, GCS_CURSORPOS, nullptr, 0);
|
||||
composition_start = cursor;
|
||||
} else {
|
||||
composition_start = 0;
|
||||
}
|
||||
|
||||
// Retrieve the clause segmentations and convert them to underlines.
|
||||
if (lparam & GCS_COMPCLAUSE)
|
||||
GetCompositionUnderlines(imc, target_start, target_end, underlines);
|
||||
|
||||
// Set default underlines in case there is no clause information.
|
||||
if (!underlines.size()) {
|
||||
CefCompositionUnderline underline;
|
||||
underline.color = ColorUNDERLINE;
|
||||
underline.background_color = ColorBKCOLOR;
|
||||
if (target_start > 0) {
|
||||
underline.range.from = 0;
|
||||
underline.range.to = target_start;
|
||||
underline.thick = 0;
|
||||
underlines.push_back(underline);
|
||||
}
|
||||
if (target_end > target_start) {
|
||||
underline.range.from = target_start;
|
||||
underline.range.to = target_end;
|
||||
underline.thick = 1;
|
||||
underlines.push_back(underline);
|
||||
}
|
||||
if (target_end < length) {
|
||||
underline.range.from = target_end;
|
||||
underline.range.to = length;
|
||||
underline.thick = 0;
|
||||
underlines.push_back(underline);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool OsrImeHandlerWin::GetString(HIMC imc,
|
||||
WPARAM lparam,
|
||||
int type,
|
||||
CefString& result) {
|
||||
if (!(lparam & type))
|
||||
return false;
|
||||
LONG string_size = ::ImmGetCompositionString(imc, type, nullptr, 0);
|
||||
if (string_size <= 0)
|
||||
return false;
|
||||
|
||||
// For trailing nullptr - ImmGetCompositionString excludes that.
|
||||
string_size += sizeof(WCHAR);
|
||||
|
||||
std::vector<wchar_t> buffer(string_size);
|
||||
::ImmGetCompositionString(imc, type, &buffer[0], string_size);
|
||||
result.FromWString(&buffer[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OsrImeHandlerWin::GetResult(LPARAM lparam, CefString& result) {
|
||||
bool ret = false;
|
||||
HIMC imc = ::ImmGetContext(hwnd_);
|
||||
if (imc) {
|
||||
ret = GetString(imc, lparam, GCS_RESULTSTR, result);
|
||||
::ImmReleaseContext(hwnd_, imc);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool OsrImeHandlerWin::GetComposition(
|
||||
LPARAM lparam,
|
||||
CefString& composition_text,
|
||||
std::vector<CefCompositionUnderline>& underlines,
|
||||
int& composition_start) {
|
||||
bool ret = false;
|
||||
HIMC imc = ::ImmGetContext(hwnd_);
|
||||
if (imc) {
|
||||
// Copy the composition string to the CompositionText object.
|
||||
ret = GetString(imc, lparam, GCS_COMPSTR, composition_text);
|
||||
|
||||
if (ret) {
|
||||
// Retrieve the composition underlines and selection range information.
|
||||
GetCompositionInfo(imc, lparam, composition_text, underlines,
|
||||
composition_start);
|
||||
|
||||
// Mark that there is an ongoing composition.
|
||||
is_composing_ = true;
|
||||
}
|
||||
|
||||
::ImmReleaseContext(hwnd_, imc);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void OsrImeHandlerWin::DisableIME() {
|
||||
CleanupComposition();
|
||||
::ImmAssociateContextEx(hwnd_, nullptr, 0);
|
||||
}
|
||||
|
||||
void OsrImeHandlerWin::CancelIME() {
|
||||
if (is_composing_) {
|
||||
HIMC imc = ::ImmGetContext(hwnd_);
|
||||
if (imc) {
|
||||
::ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
|
||||
::ImmReleaseContext(hwnd_, imc);
|
||||
}
|
||||
ResetComposition();
|
||||
}
|
||||
}
|
||||
|
||||
void OsrImeHandlerWin::EnableIME() {
|
||||
// Load the default IME context.
|
||||
::ImmAssociateContextEx(hwnd_, nullptr, IACE_DEFAULT);
|
||||
}
|
||||
|
||||
void OsrImeHandlerWin::UpdateCaretPosition(int index) {
|
||||
// Save the caret position.
|
||||
cursor_index_ = index;
|
||||
// Move the IME window.
|
||||
MoveImeWindow();
|
||||
}
|
||||
|
||||
void OsrImeHandlerWin::ChangeCompositionRange(
|
||||
const CefRange& selection_range,
|
||||
const std::vector<CefRect>& bounds) {
|
||||
composition_range_ = selection_range;
|
||||
composition_bounds_ = bounds;
|
||||
MoveImeWindow();
|
||||
}
|
108
src/CEF/OsrImeHandlerWin.h
Normal file
108
src/CEF/OsrImeHandlerWin.h
Normal file
@ -0,0 +1,108 @@
|
||||
// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
|
||||
// 2013 The Chromium Authors. All rights reserved. Use of this source code is
|
||||
// governed by a BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <vector>
|
||||
|
||||
#include "include/internal/cef_types_wrappers.h"
|
||||
|
||||
|
||||
// Handles IME for the native parent window that hosts an off-screen browser.
|
||||
// This object is only accessed on the CEF UI thread.
|
||||
class OsrImeHandlerWin {
|
||||
public:
|
||||
explicit OsrImeHandlerWin(HWND hwnd);
|
||||
virtual ~OsrImeHandlerWin();
|
||||
|
||||
// Retrieves whether or not there is an ongoing composition.
|
||||
bool is_composing() const { return is_composing_; }
|
||||
|
||||
// Retrieves the input language from Windows and update it.
|
||||
void SetInputLanguage();
|
||||
|
||||
// Creates the IME caret windows if required.
|
||||
void CreateImeWindow();
|
||||
|
||||
// Destroys the IME caret windows.
|
||||
void DestroyImeWindow();
|
||||
|
||||
// Cleans up the all resources attached to the given IMM32Manager object, and
|
||||
// reset its composition status.
|
||||
void CleanupComposition();
|
||||
|
||||
// Resets the composition status and cancels the ongoing composition.
|
||||
void ResetComposition();
|
||||
|
||||
// Retrieves a composition result of the ongoing composition if it exists.
|
||||
bool GetResult(LPARAM lparam, CefString& result);
|
||||
|
||||
// Retrieves the current composition status of the ongoing composition.
|
||||
// Includes composition text, underline information and selection range in the
|
||||
// composition text. IMM32 does not support char selection.
|
||||
bool GetComposition(LPARAM lparam,
|
||||
CefString& composition_text,
|
||||
std::vector<CefCompositionUnderline>& underlines,
|
||||
int& composition_start);
|
||||
|
||||
// Enables the IME attached to the given window.
|
||||
virtual void EnableIME();
|
||||
|
||||
// Disables the IME attached to the given window.
|
||||
virtual void DisableIME();
|
||||
|
||||
// Cancels an ongoing composition of the IME.
|
||||
virtual void CancelIME();
|
||||
|
||||
// Updates the IME caret position of the given window.
|
||||
void UpdateCaretPosition(int index);
|
||||
|
||||
// Updates the composition range. |selected_range| is the range of characters
|
||||
// that have been selected. |character_bounds| is the bounds of each character
|
||||
// in view device coordinates.
|
||||
void ChangeCompositionRange(const CefRange& selection_range,
|
||||
const std::vector<CefRect>& character_bounds);
|
||||
|
||||
// Updates the position of the IME windows.
|
||||
void MoveImeWindow();
|
||||
|
||||
private:
|
||||
// Retrieves the composition information.
|
||||
void GetCompositionInfo(HIMC imm_context,
|
||||
LPARAM lparam,
|
||||
CefString& composition_text,
|
||||
std::vector<CefCompositionUnderline>& underlines,
|
||||
int& composition_start);
|
||||
|
||||
// Retrieves a string from the IMM.
|
||||
bool GetString(HIMC imm_context, WPARAM lparam, int type, CefString& result);
|
||||
|
||||
// Represents whether or not there is an ongoing composition.
|
||||
bool is_composing_;
|
||||
|
||||
// The current composition character range and its bounds.
|
||||
std::vector<CefRect> composition_bounds_;
|
||||
|
||||
// The current input Language ID retrieved from Windows -
|
||||
// used for processing language-specific operations in IME.
|
||||
LANGID input_language_id_;
|
||||
|
||||
// Represents whether or not the current input context has created a system
|
||||
// caret to set the position of its IME candidate window.
|
||||
bool system_caret_;
|
||||
|
||||
// The rectangle of the input caret retrieved from a renderer process.
|
||||
CefRect ime_rect_;
|
||||
|
||||
// The current cursor index in composition string.
|
||||
int cursor_index_;
|
||||
|
||||
// The composition range in the string. This may be used to determine the
|
||||
// offset in composition bounds.
|
||||
CefRange composition_range_;
|
||||
|
||||
// Hwnd associated with this instance.
|
||||
HWND hwnd_;
|
||||
};
|
79
src/CEF/OsrRenderHandlerWin.cpp
Normal file
79
src/CEF/OsrRenderHandlerWin.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
// Copyright 2018 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#include "CEF/OsrRenderHandlerWin.h"
|
||||
|
||||
#include "include/base/cef_callback.h"
|
||||
#include "include/wrapper/cef_closure_task.h"
|
||||
#include "include/wrapper/cef_helpers.h"
|
||||
#include "CEF/UtilWin.h"
|
||||
|
||||
OsrRenderHandlerWin::OsrRenderHandlerWin(const OsrRendererSettings& settings,
|
||||
HWND hwnd)
|
||||
: settings_(settings),
|
||||
hwnd_(hwnd),
|
||||
begin_frame_pending_(false),
|
||||
weak_factory_(this) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
DCHECK(hwnd_);
|
||||
}
|
||||
|
||||
OsrRenderHandlerWin::~OsrRenderHandlerWin() {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWin::SetBrowser(CefRefPtr<CefBrowser> browser) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
browser_ = browser;
|
||||
if (browser_ && settings_.external_begin_frame_enabled) {
|
||||
// Start the BeginFrame timer.
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWin::Invalidate() {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
if (begin_frame_pending_) {
|
||||
// The timer is already running.
|
||||
return;
|
||||
}
|
||||
|
||||
// Trigger the BeginFrame timer.
|
||||
CHECK_GT(settings_.begin_frame_rate, 0);
|
||||
const float delay_us = (1.0 / double(settings_.begin_frame_rate)) * 1000000.0;
|
||||
TriggerBeginFrame(0, delay_us);
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWin::TriggerBeginFrame(uint64_t last_time_us,
|
||||
float delay_us) {
|
||||
if (begin_frame_pending_ && !settings_.external_begin_frame_enabled) {
|
||||
// Render immediately and then wait for the next call to Invalidate() or
|
||||
// On[Accelerated]Paint().
|
||||
begin_frame_pending_ = false;
|
||||
Render();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto now = GetTimeNow();
|
||||
float offset = now - last_time_us;
|
||||
if (offset > delay_us) {
|
||||
offset = delay_us;
|
||||
}
|
||||
|
||||
if (!begin_frame_pending_) {
|
||||
begin_frame_pending_ = true;
|
||||
}
|
||||
|
||||
// Trigger again after the necessary delay to maintain the desired frame rate.
|
||||
CefPostDelayedTask(TID_UI,
|
||||
base::BindOnce(&OsrRenderHandlerWin::TriggerBeginFrame,
|
||||
weak_factory_.GetWeakPtr(), now, delay_us),
|
||||
int64(offset / 1000.0));
|
||||
|
||||
if (settings_.external_begin_frame_enabled && browser_) {
|
||||
// We're running the BeginFrame timer. Trigger rendering via
|
||||
// On[Accelerated]Paint().
|
||||
browser_->GetHost()->SendExternalBeginFrame();
|
||||
}
|
||||
}
|
74
src/CEF/OsrRenderHandlerWin.h
Normal file
74
src/CEF/OsrRenderHandlerWin.h
Normal file
@ -0,0 +1,74 @@
|
||||
// Copyright 2018 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "include/base/cef_weak_ptr.h"
|
||||
#include "include/cef_render_handler.h"
|
||||
#include "CEF/OsrRendererSettings.h"
|
||||
|
||||
// Abstract base class for implementing OSR rendering with different backends on
|
||||
// Windows. Methods are only called on the UI thread.
|
||||
class OsrRenderHandlerWin {
|
||||
public:
|
||||
OsrRenderHandlerWin(const OsrRendererSettings& settings, HWND hwnd);
|
||||
virtual ~OsrRenderHandlerWin();
|
||||
|
||||
void SetBrowser(CefRefPtr<CefBrowser> browser);
|
||||
|
||||
// Rotate the texture based on mouse events.
|
||||
virtual void SetSpin(float spinX, float spinY) = 0;
|
||||
virtual void IncrementSpin(float spinDX, float spinDY) = 0;
|
||||
|
||||
// Popup hit testing.
|
||||
virtual bool IsOverPopupWidget(int x, int y) const = 0;
|
||||
virtual int GetPopupXOffset() const = 0;
|
||||
virtual int GetPopupYOffset() const = 0;
|
||||
|
||||
// CefRenderHandler callbacks.
|
||||
virtual void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) = 0;
|
||||
// |rect| must be in pixel coordinates.
|
||||
virtual void OnPopupSize(CefRefPtr<CefBrowser> browser,
|
||||
const CefRect& rect) = 0;
|
||||
|
||||
// Used when not rendering with shared textures.
|
||||
virtual void OnPaint(CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
const void* buffer,
|
||||
int width,
|
||||
int height) = 0;
|
||||
|
||||
// Used when rendering with shared textures.
|
||||
virtual void OnAcceleratedPaint(CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
void* share_handle) = 0;
|
||||
|
||||
bool send_begin_frame() const {
|
||||
return settings_.external_begin_frame_enabled;
|
||||
}
|
||||
HWND hwnd() const { return hwnd_; }
|
||||
|
||||
protected:
|
||||
// Called to trigger the BeginFrame timer.
|
||||
void Invalidate();
|
||||
|
||||
// Called by the BeginFrame timer.
|
||||
virtual void Render() = 0;
|
||||
|
||||
private:
|
||||
void TriggerBeginFrame(uint64_t last_time_us, float delay_us);
|
||||
|
||||
// The below members are only accessed on the UI thread.
|
||||
const OsrRendererSettings settings_;
|
||||
const HWND hwnd_;
|
||||
bool begin_frame_pending_;
|
||||
CefRefPtr<CefBrowser> browser_;
|
||||
|
||||
// Must be the last member.
|
||||
base::WeakPtrFactory<OsrRenderHandlerWin> weak_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(OsrRenderHandlerWin);
|
||||
};
|
213
src/CEF/OsrRenderHandlerWinD3D11.cpp
Normal file
213
src/CEF/OsrRenderHandlerWinD3D11.cpp
Normal file
@ -0,0 +1,213 @@
|
||||
// Copyright 2018 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#include "CEF/OsrRenderHandlerWinD3D11.h"
|
||||
|
||||
#include "include/base/cef_callback.h"
|
||||
#include "include/wrapper/cef_closure_task.h"
|
||||
#include "include/wrapper/cef_helpers.h"
|
||||
#include "CEF/UtilWin.h"
|
||||
|
||||
BrowserLayer::BrowserLayer(const std::shared_ptr<d3d11::Device>& device)
|
||||
: Layer(device, true /* flip */) {
|
||||
frame_buffer_ = std::make_shared<d3d11::FrameBuffer>(device_);
|
||||
}
|
||||
|
||||
void BrowserLayer::render(const std::shared_ptr<d3d11::Context>& ctx) {
|
||||
// Use the base class method to draw our texture.
|
||||
render_texture(ctx, frame_buffer_->texture());
|
||||
}
|
||||
|
||||
void BrowserLayer::on_paint(void* share_handle) {
|
||||
frame_buffer_->on_paint(share_handle);
|
||||
}
|
||||
|
||||
std::pair<uint32_t, uint32_t> BrowserLayer::texture_size() const {
|
||||
const auto texture = frame_buffer_->texture();
|
||||
return std::make_pair(texture->width(), texture->height());
|
||||
}
|
||||
|
||||
PopupLayer::PopupLayer(const std::shared_ptr<d3d11::Device>& device)
|
||||
: BrowserLayer(device) {}
|
||||
|
||||
void PopupLayer::set_bounds(const CefRect& bounds) {
|
||||
const auto comp = composition();
|
||||
if (!comp)
|
||||
return;
|
||||
|
||||
const auto outer_width = comp->width();
|
||||
const auto outer_height = comp->height();
|
||||
if (outer_width == 0 || outer_height == 0)
|
||||
return;
|
||||
|
||||
original_bounds_ = bounds;
|
||||
bounds_ = bounds;
|
||||
|
||||
// If x or y are negative, move them to 0.
|
||||
if (bounds_.x < 0)
|
||||
bounds_.x = 0;
|
||||
if (bounds_.y < 0)
|
||||
bounds_.y = 0;
|
||||
// If popup goes outside the view, try to reposition origin
|
||||
if (bounds_.x + bounds_.width > outer_width)
|
||||
bounds_.x = outer_width - bounds_.width;
|
||||
if (bounds_.y + bounds_.height > outer_height)
|
||||
bounds_.y = outer_height - bounds_.height;
|
||||
// If x or y became negative, move them to 0 again.
|
||||
if (bounds_.x < 0)
|
||||
bounds_.x = 0;
|
||||
if (bounds_.y < 0)
|
||||
bounds_.y = 0;
|
||||
|
||||
const auto x = bounds_.x / float(outer_width);
|
||||
const auto y = bounds_.y / float(outer_height);
|
||||
const auto w = bounds_.width / float(outer_width);
|
||||
const auto h = bounds_.height / float(outer_height);
|
||||
move(x, y, w, h);
|
||||
}
|
||||
|
||||
OsrRenderHandlerWinD3D11::OsrRenderHandlerWinD3D11(
|
||||
const OsrRendererSettings& settings,
|
||||
HWND hwnd)
|
||||
: OsrRenderHandlerWin(settings, hwnd), start_time_(0) {}
|
||||
|
||||
bool OsrRenderHandlerWinD3D11::Initialize(CefRefPtr<CefBrowser> browser,
|
||||
int width,
|
||||
int height) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
// Create a D3D11 device instance.
|
||||
device_ = d3d11::Device::create();
|
||||
DCHECK(device_);
|
||||
if (!device_)
|
||||
return false;
|
||||
|
||||
// Create a D3D11 swapchain for the window.
|
||||
swap_chain_ = device_->create_swapchain(hwnd());
|
||||
DCHECK(swap_chain_);
|
||||
if (!swap_chain_)
|
||||
return false;
|
||||
|
||||
// Create the browser layer.
|
||||
browser_layer_ = std::make_shared<BrowserLayer>(device_);
|
||||
|
||||
// Set up the composition.
|
||||
composition_ = std::make_shared<d3d11::Composition>(device_, width, height);
|
||||
composition_->add_layer(browser_layer_);
|
||||
|
||||
// Size to the whole composition.
|
||||
browser_layer_->move(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
|
||||
start_time_ = GetTimeNow();
|
||||
|
||||
SetBrowser(browser);
|
||||
return true;
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinD3D11::SetSpin(float spinX, float spinY) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
// Spin support is not implemented.
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinD3D11::IncrementSpin(float spinDX, float spinDY) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
// Spin support is not implemented.
|
||||
}
|
||||
|
||||
bool OsrRenderHandlerWinD3D11::IsOverPopupWidget(int x, int y) const {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
return popup_layer_ && popup_layer_->contains(x, y);
|
||||
}
|
||||
|
||||
int OsrRenderHandlerWinD3D11::GetPopupXOffset() const {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
if (popup_layer_)
|
||||
return popup_layer_->xoffset();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int OsrRenderHandlerWinD3D11::GetPopupYOffset() const {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
if (popup_layer_)
|
||||
return popup_layer_->yoffset();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinD3D11::OnPopupShow(CefRefPtr<CefBrowser> browser,
|
||||
bool show) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
if (show) {
|
||||
DCHECK(!popup_layer_);
|
||||
|
||||
// Create a new layer.
|
||||
popup_layer_ = std::make_shared<PopupLayer>(device_);
|
||||
composition_->add_layer(popup_layer_);
|
||||
} else {
|
||||
DCHECK(popup_layer_);
|
||||
|
||||
composition_->remove_layer(popup_layer_);
|
||||
popup_layer_ = nullptr;
|
||||
|
||||
Render();
|
||||
}
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinD3D11::OnPopupSize(CefRefPtr<CefBrowser> browser,
|
||||
const CefRect& rect) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
popup_layer_->set_bounds(rect);
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinD3D11::OnPaint(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
const void* buffer,
|
||||
int width,
|
||||
int height) {
|
||||
// Not used with this implementation.
|
||||
NOTREACHED();
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinD3D11::OnAcceleratedPaint(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
void* share_handle) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
if (type == PET_POPUP) {
|
||||
popup_layer_->on_paint(share_handle);
|
||||
} else {
|
||||
browser_layer_->on_paint(share_handle);
|
||||
}
|
||||
|
||||
Render();
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinD3D11::Render() {
|
||||
// Update composition + layers based on time.
|
||||
const auto t = (GetTimeNow() - start_time_) / 1000000.0;
|
||||
composition_->tick(t);
|
||||
|
||||
auto ctx = device_->immedidate_context();
|
||||
swap_chain_->bind(ctx);
|
||||
|
||||
const auto texture_size = browser_layer_->texture_size();
|
||||
|
||||
// Resize the composition and swap chain to match the texture if necessary.
|
||||
composition_->resize(!send_begin_frame(), texture_size.first,
|
||||
texture_size.second);
|
||||
swap_chain_->resize(texture_size.first, texture_size.second);
|
||||
|
||||
// Clear the render target.
|
||||
swap_chain_->clear(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
|
||||
// Render the scene.
|
||||
composition_->render(ctx);
|
||||
|
||||
// Present to window.
|
||||
swap_chain_->present(send_begin_frame() ? 0 : 1);
|
||||
}
|
83
src/CEF/OsrRenderHandlerWinD3D11.h
Normal file
83
src/CEF/OsrRenderHandlerWinD3D11.h
Normal file
@ -0,0 +1,83 @@
|
||||
// Copyright 2018 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CEF/OsrD3D11Win.h"
|
||||
#include "CEF/OsrRenderHandlerWin.h"
|
||||
#include "CEF/OsrRendererSettings.h"
|
||||
|
||||
class BrowserLayer : public d3d11::Layer {
|
||||
public:
|
||||
explicit BrowserLayer(const std::shared_ptr<d3d11::Device>& device);
|
||||
|
||||
void render(const std::shared_ptr<d3d11::Context>& ctx) override;
|
||||
|
||||
void on_paint(void* share_handle);
|
||||
|
||||
// After calling on_paint() we can query the texture size.
|
||||
std::pair<uint32_t, uint32_t> texture_size() const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<d3d11::FrameBuffer> frame_buffer_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(BrowserLayer);
|
||||
};
|
||||
|
||||
class PopupLayer : public BrowserLayer {
|
||||
public:
|
||||
explicit PopupLayer(const std::shared_ptr<d3d11::Device>& device);
|
||||
|
||||
void set_bounds(const CefRect& bounds);
|
||||
|
||||
bool contains(int x, int y) const { return bounds_.Contains(x, y); }
|
||||
int xoffset() const { return original_bounds_.x - bounds_.x; }
|
||||
int yoffset() const { return original_bounds_.y - bounds_.y; }
|
||||
|
||||
private:
|
||||
CefRect original_bounds_;
|
||||
CefRect bounds_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(PopupLayer);
|
||||
};
|
||||
|
||||
class OsrRenderHandlerWinD3D11 : public OsrRenderHandlerWin {
|
||||
public:
|
||||
OsrRenderHandlerWinD3D11(const OsrRendererSettings& settings, HWND hwnd);
|
||||
|
||||
// Must be called immediately after object creation.
|
||||
// May fail if D3D11 cannot be initialized.
|
||||
bool Initialize(CefRefPtr<CefBrowser> browser, int width, int height);
|
||||
|
||||
void SetSpin(float spinX, float spinY) override;
|
||||
void IncrementSpin(float spinDX, float spinDY) override;
|
||||
bool IsOverPopupWidget(int x, int y) const override;
|
||||
int GetPopupXOffset() const override;
|
||||
int GetPopupYOffset() const override;
|
||||
void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) override;
|
||||
void OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect) override;
|
||||
void OnPaint(CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
const void* buffer,
|
||||
int width,
|
||||
int height) override;
|
||||
void OnAcceleratedPaint(CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
void* share_handle) override;
|
||||
|
||||
private:
|
||||
void Render() override;
|
||||
|
||||
uint64_t start_time_;
|
||||
std::shared_ptr<d3d11::Device> device_;
|
||||
std::shared_ptr<d3d11::SwapChain> swap_chain_;
|
||||
std::shared_ptr<d3d11::Composition> composition_;
|
||||
std::shared_ptr<BrowserLayer> browser_layer_;
|
||||
std::shared_ptr<PopupLayer> popup_layer_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(OsrRenderHandlerWinD3D11);
|
||||
};
|
196
src/CEF/OsrRenderHandlerWinGL.cpp
Normal file
196
src/CEF/OsrRenderHandlerWinGL.cpp
Normal file
@ -0,0 +1,196 @@
|
||||
// Copyright 2018 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#include "CEF/OsrRenderHandlerWinGL.h"
|
||||
|
||||
#include "include/base/cef_callback.h"
|
||||
#include "include/wrapper/cef_closure_task.h"
|
||||
#include "include/wrapper/cef_helpers.h"
|
||||
#include "CEF/UtilWin.h"
|
||||
|
||||
|
||||
// Helper that calls wglMakeCurrent.
|
||||
class ScopedGLContext {
|
||||
public:
|
||||
ScopedGLContext(HDC hdc, HGLRC hglrc, bool swap_buffers)
|
||||
: hdc_(hdc), swap_buffers_(swap_buffers) {
|
||||
BOOL result = wglMakeCurrent(hdc, hglrc);
|
||||
ALLOW_UNUSED_LOCAL(result);
|
||||
DCHECK(result);
|
||||
}
|
||||
~ScopedGLContext() {
|
||||
BOOL result = wglMakeCurrent(nullptr, nullptr);
|
||||
DCHECK(result);
|
||||
if (swap_buffers_) {
|
||||
result = SwapBuffers(hdc_);
|
||||
DCHECK(result);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const HDC hdc_;
|
||||
const bool swap_buffers_;
|
||||
};
|
||||
|
||||
|
||||
OsrRenderHandlerWinGL::OsrRenderHandlerWinGL(
|
||||
const OsrRendererSettings& settings,
|
||||
HWND hwnd)
|
||||
: OsrRenderHandlerWin(settings, hwnd),
|
||||
renderer_(settings),
|
||||
hdc_(nullptr),
|
||||
hrc_(nullptr),
|
||||
painting_popup_(false) {}
|
||||
|
||||
void OsrRenderHandlerWinGL::Initialize(CefRefPtr<CefBrowser> browser) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
SetBrowser(browser);
|
||||
}
|
||||
|
||||
OsrRenderHandlerWinGL::~OsrRenderHandlerWinGL() {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
DisableGL();
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinGL::SetSpin(float spinX, float spinY) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
renderer_.SetSpin(spinX, spinY);
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinGL::IncrementSpin(float spinDX, float spinDY) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
renderer_.IncrementSpin(spinDX, spinDY);
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
bool OsrRenderHandlerWinGL::IsOverPopupWidget(int x, int y) const {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
const CefRect& rc = renderer_.popup_rect();
|
||||
int popup_right = rc.x + rc.width;
|
||||
int popup_bottom = rc.y + rc.height;
|
||||
return (x >= rc.x) && (x < popup_right) && (y >= rc.y) && (y < popup_bottom);
|
||||
}
|
||||
|
||||
int OsrRenderHandlerWinGL::GetPopupXOffset() const {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
return renderer_.original_popup_rect().x - renderer_.popup_rect().x;
|
||||
}
|
||||
|
||||
int OsrRenderHandlerWinGL::GetPopupYOffset() const {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
return renderer_.original_popup_rect().y - renderer_.popup_rect().y;
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinGL::OnPopupShow(CefRefPtr<CefBrowser> browser,
|
||||
bool show) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
if (!show) {
|
||||
renderer_.ClearPopupRects();
|
||||
browser->GetHost()->Invalidate(PET_VIEW);
|
||||
}
|
||||
|
||||
renderer_.OnPopupShow(browser, show);
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinGL::OnPopupSize(CefRefPtr<CefBrowser> browser,
|
||||
const CefRect& rect) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
renderer_.OnPopupSize(browser, rect);
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinGL::OnPaint(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
const void* buffer,
|
||||
int width,
|
||||
int height) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
if (painting_popup_) {
|
||||
renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height);
|
||||
return;
|
||||
}
|
||||
if (!hdc_) {
|
||||
EnableGL();
|
||||
}
|
||||
|
||||
ScopedGLContext scoped_gl_context(hdc_, hrc_, true);
|
||||
renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height);
|
||||
if (type == PET_VIEW && !renderer_.popup_rect().IsEmpty()) {
|
||||
painting_popup_ = true;
|
||||
browser->GetHost()->Invalidate(PET_POPUP);
|
||||
painting_popup_ = false;
|
||||
}
|
||||
renderer_.Render();
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinGL::OnAcceleratedPaint(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
void* share_handle) {
|
||||
// Not used with this implementation.
|
||||
NOTREACHED();
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinGL::Render() {
|
||||
if (!hdc_) {
|
||||
EnableGL();
|
||||
}
|
||||
|
||||
ScopedGLContext scoped_gl_context(hdc_, hrc_, true);
|
||||
renderer_.Render();
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinGL::EnableGL() {
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
int format;
|
||||
|
||||
// Get the device context.
|
||||
hdc_ = GetDC(hwnd());
|
||||
|
||||
// Set the pixel format for the DC.
|
||||
ZeroMemory(&pfd, sizeof(pfd));
|
||||
pfd.nSize = sizeof(pfd);
|
||||
pfd.nVersion = 1;
|
||||
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
|
||||
pfd.iPixelType = PFD_TYPE_RGBA;
|
||||
pfd.cColorBits = 24;
|
||||
pfd.cDepthBits = 16;
|
||||
pfd.iLayerType = PFD_MAIN_PLANE;
|
||||
format = ChoosePixelFormat(hdc_, &pfd);
|
||||
SetPixelFormat(hdc_, format, &pfd);
|
||||
|
||||
// Create and enable the render context.
|
||||
hrc_ = wglCreateContext(hdc_);
|
||||
|
||||
ScopedGLContext scoped_gl_context(hdc_, hrc_, false);
|
||||
renderer_.Initialize();
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinGL::DisableGL() {
|
||||
if (!hdc_) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
ScopedGLContext scoped_gl_context(hdc_, hrc_, false);
|
||||
renderer_.Cleanup();
|
||||
}
|
||||
|
||||
if (IsWindow(hwnd())) {
|
||||
// wglDeleteContext will make the context not current before deleting it.
|
||||
BOOL result = wglDeleteContext(hrc_);
|
||||
ALLOW_UNUSED_LOCAL(result);
|
||||
DCHECK(result);
|
||||
ReleaseDC(hwnd(), hdc_);
|
||||
}
|
||||
|
||||
hdc_ = nullptr;
|
||||
hrc_ = nullptr;
|
||||
}
|
||||
|
49
src/CEF/OsrRenderHandlerWinGL.h
Normal file
49
src/CEF/OsrRenderHandlerWinGL.h
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright 2018 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CEF/OsrRenderHandlerWin.h"
|
||||
#include "CEF/OsrRenderer.h"
|
||||
|
||||
class OsrRenderHandlerWinGL : public OsrRenderHandlerWin {
|
||||
public:
|
||||
OsrRenderHandlerWinGL(const OsrRendererSettings& settings, HWND hwnd);
|
||||
virtual ~OsrRenderHandlerWinGL();
|
||||
|
||||
// Must be called immediately after object creation.
|
||||
void Initialize(CefRefPtr<CefBrowser> browser);
|
||||
|
||||
void SetSpin(float spinX, float spinY) override;
|
||||
void IncrementSpin(float spinDX, float spinDY) override;
|
||||
bool IsOverPopupWidget(int x, int y) const override;
|
||||
int GetPopupXOffset() const override;
|
||||
int GetPopupYOffset() const override;
|
||||
void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) override;
|
||||
void OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect) override;
|
||||
void OnPaint(CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
const void* buffer,
|
||||
int width,
|
||||
int height) override;
|
||||
void OnAcceleratedPaint(CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
void* share_handle) override;
|
||||
|
||||
private:
|
||||
void Render() override;
|
||||
|
||||
void EnableGL();
|
||||
void DisableGL();
|
||||
|
||||
// The below members are only accessed on the UI thread.
|
||||
OsrRenderer renderer_;
|
||||
HDC hdc_;
|
||||
HGLRC hrc_;
|
||||
bool painting_popup_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(OsrRenderHandlerWinGL);
|
||||
};
|
182
src/CEF/OsrRenderHandlerWinNative.cpp
Normal file
182
src/CEF/OsrRenderHandlerWinNative.cpp
Normal file
@ -0,0 +1,182 @@
|
||||
// Copyright 2018 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#include "CEF/OsrRenderHandlerWinNative.h"
|
||||
|
||||
#include "include/base/cef_callback.h"
|
||||
#include "include/wrapper/cef_closure_task.h"
|
||||
#include "include/wrapper/cef_helpers.h"
|
||||
#include "CEF/UtilWin.h"
|
||||
|
||||
#include "stb/stb_image_write.h"
|
||||
|
||||
OsrRenderHandlerWinNative::OsrRenderHandlerWinNative(
|
||||
const OsrRendererSettings& settings,
|
||||
HWND hwnd)
|
||||
: OsrRenderHandlerWin(settings, hwnd),
|
||||
hdc_(nullptr),
|
||||
hrc_(nullptr),
|
||||
painting_popup_(false),
|
||||
view_width_(0),
|
||||
view_height_(0),
|
||||
spin_x_(0),
|
||||
spin_y_(0) {}
|
||||
|
||||
void OsrRenderHandlerWinNative::Initialize(CefRefPtr<CefBrowser> browser) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
SetBrowser(browser);
|
||||
}
|
||||
|
||||
OsrRenderHandlerWinNative::~OsrRenderHandlerWinNative() {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinNative::SetSpin(float spinX, float spinY) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
spin_x_ = spinX;
|
||||
spin_y_ = spinY;
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinNative::IncrementSpin(float spinDX, float spinDY) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
spin_x_ -= spinDX;
|
||||
spin_y_ -= spinDY;
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
bool OsrRenderHandlerWinNative::IsOverPopupWidget(int x, int y) const {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
const CefRect& rc = popup_rect_;
|
||||
int popup_right = rc.x + rc.width;
|
||||
int popup_bottom = rc.y + rc.height;
|
||||
return (x >= rc.x) && (x < popup_right) && (y >= rc.y) && (y < popup_bottom);
|
||||
}
|
||||
|
||||
int OsrRenderHandlerWinNative::GetPopupXOffset() const {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
return original_popup_rect_.x - popup_rect_.x;
|
||||
}
|
||||
|
||||
int OsrRenderHandlerWinNative::GetPopupYOffset() const {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
return original_popup_rect_.y - popup_rect_.y;
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinNative::OnPopupShow(CefRefPtr<CefBrowser> browser,
|
||||
bool show) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
if (!show) {
|
||||
popup_rect_.Set(0, 0, 0, 0);
|
||||
original_popup_rect_.Set(0, 0, 0, 0);
|
||||
browser->GetHost()->Invalidate(PET_VIEW);
|
||||
}
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinNative::OnPopupSize(CefRefPtr<CefBrowser> browser,
|
||||
const CefRect& rect) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
if (rect.width <= 0 || rect.height <= 0)
|
||||
return;
|
||||
original_popup_rect_ = rect;
|
||||
popup_rect_ = GetPopupRectInWebView(original_popup_rect_);
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinNative::OnPaint(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
const void* buffer,
|
||||
int width,
|
||||
int height) {
|
||||
CEF_REQUIRE_UI_THREAD()
|
||||
// stbi_write_png("d:/3.png", width, height, 4, buffer, width * 4);
|
||||
|
||||
HDC hDc = GetDC(hwnd());
|
||||
HDC hMemDC = CreateCompatibleDC(hDc);
|
||||
RECT rct;
|
||||
GetClientRect(hwnd(), &rct);
|
||||
BITMAPINFO bmi = { 0 };
|
||||
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
|
||||
bmi.bmiHeader.biWidth = width;
|
||||
bmi.bmiHeader.biHeight = height;
|
||||
bmi.bmiHeader.biPlanes = 1;
|
||||
bmi.bmiHeader.biBitCount = 32;
|
||||
bmi.bmiHeader.biCompression = BI_RGB;
|
||||
bmi.bmiHeader.biSizeImage = 0;
|
||||
|
||||
DWORD *pvBits = nullptr;
|
||||
HBITMAP hBitmap = CreateDIBSection(hDc, &bmi, DIB_RGB_COLORS, reinterpret_cast<void**>(&pvBits), NULL, 0);
|
||||
const int iTotal = width * height * 4;
|
||||
for (int i = 0; i != height; ++i)
|
||||
{
|
||||
for (int j = 0; j != width; ++j)
|
||||
{
|
||||
pvBits[i * width + j] = reinterpret_cast<const DWORD*>(buffer)[(height - i - 1) * width + j];
|
||||
byte *pByte = (byte*)&pvBits[i * width + j];
|
||||
pByte[0] = pByte[0] * pByte[3] / 255;
|
||||
pByte[1] = pByte[1] * pByte[3] / 255;
|
||||
pByte[2] = pByte[2] * pByte[3] / 255;
|
||||
}
|
||||
}
|
||||
|
||||
GdiFlush();
|
||||
SelectObject(hMemDC, hBitmap);
|
||||
|
||||
POINT ptSrc;
|
||||
ptSrc.x = 0;
|
||||
ptSrc.y = 0;
|
||||
POINT ptDst = ptSrc;
|
||||
ClientToScreen(hwnd(), &ptDst);
|
||||
SIZE szSrc;
|
||||
szSrc.cx = width;
|
||||
szSrc.cy = height;
|
||||
BLENDFUNCTION bf;
|
||||
bf.BlendOp = AC_SRC_OVER;
|
||||
bf.BlendFlags = 0;
|
||||
bf.SourceConstantAlpha = 255;
|
||||
bf.AlphaFormat = AC_SRC_ALPHA;
|
||||
PAINTSTRUCT ps;
|
||||
BeginPaint(hwnd(), &ps);
|
||||
EndPaint(hwnd(), &ps);
|
||||
UpdateLayeredWindow(hwnd(), hDc, &ptDst, &szSrc, hMemDC,
|
||||
&ptSrc, 0, &bf, ULW_ALPHA);
|
||||
DeleteDC(hMemDC);
|
||||
DeleteObject(hBitmap);
|
||||
ReleaseDC(hwnd(), hDc);
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinNative::OnAcceleratedPaint(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
void* share_handle) {
|
||||
// Not used with this implementation.
|
||||
NOTREACHED();
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinNative::Render() {
|
||||
|
||||
}
|
||||
|
||||
CefRect OsrRenderHandlerWinNative::GetPopupRectInWebView(const CefRect& original_rect) {
|
||||
CefRect rc(original_rect);
|
||||
// if x or y are negative, move them to 0.
|
||||
if (rc.x < 0)
|
||||
rc.x = 0;
|
||||
if (rc.y < 0)
|
||||
rc.y = 0;
|
||||
// if popup goes outside the view, try to reposition origin
|
||||
if (rc.x + rc.width > view_width_)
|
||||
rc.x = view_width_ - rc.width;
|
||||
if (rc.y + rc.height > view_height_)
|
||||
rc.y = view_height_ - rc.height;
|
||||
// if x or y became negative, move them to 0 again.
|
||||
if (rc.x < 0)
|
||||
rc.x = 0;
|
||||
if (rc.y < 0)
|
||||
rc.y = 0;
|
||||
return rc;
|
||||
}
|
55
src/CEF/OsrRenderHandlerWinNative.h
Normal file
55
src/CEF/OsrRenderHandlerWinNative.h
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright 2018 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CEF/OsrRenderHandlerWin.h"
|
||||
|
||||
class OsrRenderHandlerWinNative : public OsrRenderHandlerWin {
|
||||
public:
|
||||
OsrRenderHandlerWinNative(const OsrRendererSettings& settings, HWND hwnd);
|
||||
virtual ~OsrRenderHandlerWinNative();
|
||||
|
||||
// Must be called immediately after object creation.
|
||||
void Initialize(CefRefPtr<CefBrowser> browser);
|
||||
|
||||
void SetSpin(float spinX, float spinY) override;
|
||||
void IncrementSpin(float spinDX, float spinDY) override;
|
||||
bool IsOverPopupWidget(int x, int y) const override;
|
||||
int GetPopupXOffset() const override;
|
||||
int GetPopupYOffset() const override;
|
||||
void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) override;
|
||||
void OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect) override;
|
||||
void OnPaint(CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
const void* buffer,
|
||||
int width,
|
||||
int height) override;
|
||||
void OnAcceleratedPaint(CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
void* share_handle) override;
|
||||
|
||||
private:
|
||||
void Render() override;
|
||||
|
||||
CefRect GetPopupRectInWebView(const CefRect& original_rect);
|
||||
|
||||
// The below members are only accessed on the UI thread.
|
||||
|
||||
HDC hdc_;
|
||||
HGLRC hrc_;
|
||||
bool painting_popup_;
|
||||
|
||||
int view_width_;
|
||||
int view_height_;
|
||||
CefRect popup_rect_;
|
||||
CefRect original_popup_rect_;
|
||||
float spin_x_;
|
||||
float spin_y_;
|
||||
CefRect update_rect_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(OsrRenderHandlerWinNative);
|
||||
};
|
394
src/CEF/OsrRenderer.cpp
Normal file
394
src/CEF/OsrRenderer.cpp
Normal file
@ -0,0 +1,394 @@
|
||||
// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "CEF/OsrRenderer.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <gl/gl.h>
|
||||
#elif defined(OS_MAC)
|
||||
#include <OpenGL/gl.h>
|
||||
#elif defined(OS_LINUX)
|
||||
#include <GL/gl.h>
|
||||
#else
|
||||
#error Platform is not supported.
|
||||
#endif
|
||||
|
||||
#include "include/base/cef_logging.h"
|
||||
#include "include/wrapper/cef_helpers.h"
|
||||
|
||||
#ifndef GL_BGR
|
||||
#define GL_BGR 0x80E0
|
||||
#endif
|
||||
#ifndef GL_BGRA
|
||||
#define GL_BGRA 0x80E1
|
||||
#endif
|
||||
#ifndef GL_UNSIGNED_INT_8_8_8_8_REV
|
||||
#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
|
||||
#endif
|
||||
|
||||
// DCHECK on gl errors.
|
||||
#if DCHECK_IS_ON()
|
||||
#define VERIFY_NO_ERROR \
|
||||
{ \
|
||||
int _gl_error = glGetError(); \
|
||||
DCHECK(_gl_error == GL_NO_ERROR) << "glGetError returned " << _gl_error; \
|
||||
}
|
||||
#else
|
||||
#define VERIFY_NO_ERROR
|
||||
#endif
|
||||
|
||||
OsrRenderer::OsrRenderer(const OsrRendererSettings& settings)
|
||||
: settings_(settings),
|
||||
initialized_(false),
|
||||
texture_id_(0),
|
||||
view_width_(0),
|
||||
view_height_(0),
|
||||
spin_x_(0),
|
||||
spin_y_(0) {}
|
||||
|
||||
OsrRenderer::~OsrRenderer() {
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
void OsrRenderer::Initialize() {
|
||||
if (initialized_)
|
||||
return;
|
||||
|
||||
glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
|
||||
VERIFY_NO_ERROR;
|
||||
|
||||
if (IsTransparent()) {
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
VERIFY_NO_ERROR;
|
||||
} else {
|
||||
glClearColor(float(CefColorGetR(settings_.background_color)) / 255.0f,
|
||||
float(CefColorGetG(settings_.background_color)) / 255.0f,
|
||||
float(CefColorGetB(settings_.background_color)) / 255.0f,
|
||||
1.0f);
|
||||
VERIFY_NO_ERROR;
|
||||
}
|
||||
|
||||
// Necessary for non-power-of-2 textures to render correctly.
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
VERIFY_NO_ERROR;
|
||||
|
||||
// Create the texture.
|
||||
glGenTextures(1, &texture_id_);
|
||||
VERIFY_NO_ERROR;
|
||||
DCHECK_NE(texture_id_, 0U);
|
||||
VERIFY_NO_ERROR;
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture_id_);
|
||||
VERIFY_NO_ERROR;
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
VERIFY_NO_ERROR;
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
VERIFY_NO_ERROR;
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
VERIFY_NO_ERROR;
|
||||
|
||||
initialized_ = true;
|
||||
}
|
||||
|
||||
void OsrRenderer::Cleanup() {
|
||||
if (texture_id_ != 0)
|
||||
glDeleteTextures(1, &texture_id_);
|
||||
}
|
||||
|
||||
void OsrRenderer::Render() {
|
||||
if (view_width_ == 0 || view_height_ == 0)
|
||||
return;
|
||||
|
||||
DCHECK(initialized_);
|
||||
|
||||
struct {
|
||||
float tu, tv;
|
||||
float x, y, z;
|
||||
} static vertices[] = {{0.0f, 1.0f, -1.0f, -1.0f, 0.0f},
|
||||
{1.0f, 1.0f, 1.0f, -1.0f, 0.0f},
|
||||
{1.0f, 0.0f, 1.0f, 1.0f, 0.0f},
|
||||
{0.0f, 0.0f, -1.0f, 1.0f, 0.0f}};
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
VERIFY_NO_ERROR;
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
VERIFY_NO_ERROR;
|
||||
glLoadIdentity();
|
||||
VERIFY_NO_ERROR;
|
||||
|
||||
// Match GL units to screen coordinates.
|
||||
glViewport(0, 0, view_width_, view_height_);
|
||||
VERIFY_NO_ERROR;
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
VERIFY_NO_ERROR;
|
||||
glLoadIdentity();
|
||||
VERIFY_NO_ERROR;
|
||||
|
||||
// Draw the background gradient.
|
||||
glPushAttrib(GL_ALL_ATTRIB_BITS);
|
||||
VERIFY_NO_ERROR;
|
||||
// Don't check for errors until glEnd().
|
||||
glBegin(GL_QUADS);
|
||||
glColor4f(1.0, 0.0, 0.0, 1.0); // red
|
||||
glVertex2f(-1.0, -1.0);
|
||||
glVertex2f(1.0, -1.0);
|
||||
glColor4f(0.0, 0.0, 1.0, 1.0); // blue
|
||||
glVertex2f(1.0, 1.0);
|
||||
glVertex2f(-1.0, 1.0);
|
||||
glEnd();
|
||||
VERIFY_NO_ERROR;
|
||||
glPopAttrib();
|
||||
VERIFY_NO_ERROR;
|
||||
|
||||
// Rotate the view based on the mouse spin.
|
||||
if (spin_x_ != 0) {
|
||||
glRotatef(-spin_x_, 1.0f, 0.0f, 0.0f);
|
||||
VERIFY_NO_ERROR;
|
||||
}
|
||||
if (spin_y_ != 0) {
|
||||
glRotatef(-spin_y_, 0.0f, 1.0f, 0.0f);
|
||||
VERIFY_NO_ERROR;
|
||||
}
|
||||
|
||||
if (IsTransparent()) {
|
||||
// Alpha blending style. Texture values have premultiplied alpha.
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
VERIFY_NO_ERROR;
|
||||
|
||||
// Enable alpha blending.
|
||||
glEnable(GL_BLEND);
|
||||
VERIFY_NO_ERROR;
|
||||
}
|
||||
|
||||
// Enable 2D textures.
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
VERIFY_NO_ERROR;
|
||||
|
||||
// Draw the facets with the texture.
|
||||
DCHECK_NE(texture_id_, 0U);
|
||||
VERIFY_NO_ERROR;
|
||||
glBindTexture(GL_TEXTURE_2D, texture_id_);
|
||||
VERIFY_NO_ERROR;
|
||||
glInterleavedArrays(GL_T2F_V3F, 0, vertices);
|
||||
VERIFY_NO_ERROR;
|
||||
glDrawArrays(GL_QUADS, 0, 4);
|
||||
VERIFY_NO_ERROR;
|
||||
|
||||
// Disable 2D textures.
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
VERIFY_NO_ERROR;
|
||||
|
||||
if (IsTransparent()) {
|
||||
// Disable alpha blending.
|
||||
glDisable(GL_BLEND);
|
||||
VERIFY_NO_ERROR;
|
||||
}
|
||||
|
||||
// Draw a rectangle around the update region.
|
||||
if (settings_.show_update_rect && !update_rect_.IsEmpty()) {
|
||||
int left = update_rect_.x;
|
||||
int right = update_rect_.x + update_rect_.width;
|
||||
int top = update_rect_.y;
|
||||
int bottom = update_rect_.y + update_rect_.height;
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
// Shrink the box so that top & right sides are drawn.
|
||||
top += 1;
|
||||
right -= 1;
|
||||
#else
|
||||
// Shrink the box so that left & bottom sides are drawn.
|
||||
left += 1;
|
||||
bottom -= 1;
|
||||
#endif
|
||||
|
||||
glPushAttrib(GL_ALL_ATTRIB_BITS);
|
||||
VERIFY_NO_ERROR
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
VERIFY_NO_ERROR;
|
||||
glPushMatrix();
|
||||
VERIFY_NO_ERROR;
|
||||
glLoadIdentity();
|
||||
VERIFY_NO_ERROR;
|
||||
glOrtho(0, view_width_, view_height_, 0, 0, 1);
|
||||
VERIFY_NO_ERROR;
|
||||
|
||||
glLineWidth(1);
|
||||
VERIFY_NO_ERROR;
|
||||
glColor3f(1.0f, 0.0f, 0.0f);
|
||||
VERIFY_NO_ERROR;
|
||||
// Don't check for errors until glEnd().
|
||||
glBegin(GL_LINE_STRIP);
|
||||
glVertex2i(left, top);
|
||||
glVertex2i(right, top);
|
||||
glVertex2i(right, bottom);
|
||||
glVertex2i(left, bottom);
|
||||
glVertex2i(left, top);
|
||||
glEnd();
|
||||
VERIFY_NO_ERROR;
|
||||
|
||||
glPopMatrix();
|
||||
VERIFY_NO_ERROR;
|
||||
glPopAttrib();
|
||||
VERIFY_NO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
void OsrRenderer::OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) {
|
||||
if (!show) {
|
||||
// Clear the popup rectangle.
|
||||
ClearPopupRects();
|
||||
}
|
||||
}
|
||||
|
||||
void OsrRenderer::OnPopupSize(CefRefPtr<CefBrowser> browser,
|
||||
const CefRect& rect) {
|
||||
if (rect.width <= 0 || rect.height <= 0)
|
||||
return;
|
||||
original_popup_rect_ = rect;
|
||||
popup_rect_ = GetPopupRectInWebView(original_popup_rect_);
|
||||
}
|
||||
|
||||
CefRect OsrRenderer::GetPopupRectInWebView(const CefRect& original_rect) {
|
||||
CefRect rc(original_rect);
|
||||
// if x or y are negative, move them to 0.
|
||||
if (rc.x < 0)
|
||||
rc.x = 0;
|
||||
if (rc.y < 0)
|
||||
rc.y = 0;
|
||||
// if popup goes outside the view, try to reposition origin
|
||||
if (rc.x + rc.width > view_width_)
|
||||
rc.x = view_width_ - rc.width;
|
||||
if (rc.y + rc.height > view_height_)
|
||||
rc.y = view_height_ - rc.height;
|
||||
// if x or y became negative, move them to 0 again.
|
||||
if (rc.x < 0)
|
||||
rc.x = 0;
|
||||
if (rc.y < 0)
|
||||
rc.y = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
void OsrRenderer::ClearPopupRects() {
|
||||
popup_rect_.Set(0, 0, 0, 0);
|
||||
original_popup_rect_.Set(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void OsrRenderer::OnPaint(CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
const void* buffer,
|
||||
int width,
|
||||
int height) {
|
||||
if (!initialized_)
|
||||
Initialize();
|
||||
|
||||
if (IsTransparent()) {
|
||||
// Enable alpha blending.
|
||||
glEnable(GL_BLEND);
|
||||
VERIFY_NO_ERROR;
|
||||
}
|
||||
|
||||
// Enable 2D textures.
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
VERIFY_NO_ERROR;
|
||||
|
||||
DCHECK_NE(texture_id_, 0U);
|
||||
glBindTexture(GL_TEXTURE_2D, texture_id_);
|
||||
VERIFY_NO_ERROR;
|
||||
|
||||
if (type == PET_VIEW) {
|
||||
int old_width = view_width_;
|
||||
int old_height = view_height_;
|
||||
|
||||
view_width_ = width;
|
||||
view_height_ = height;
|
||||
|
||||
if (settings_.show_update_rect)
|
||||
update_rect_ = dirtyRects[0];
|
||||
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, view_width_);
|
||||
VERIFY_NO_ERROR;
|
||||
|
||||
if (old_width != view_width_ || old_height != view_height_ ||
|
||||
(dirtyRects.size() == 1 &&
|
||||
dirtyRects[0] == CefRect(0, 0, view_width_, view_height_))) {
|
||||
// Update/resize the whole texture.
|
||||
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
|
||||
VERIFY_NO_ERROR;
|
||||
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
|
||||
VERIFY_NO_ERROR;
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view_width_, view_height_, 0,
|
||||
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buffer);
|
||||
VERIFY_NO_ERROR;
|
||||
} else {
|
||||
// Update just the dirty rectangles.
|
||||
CefRenderHandler::RectList::const_iterator i = dirtyRects.begin();
|
||||
for (; i != dirtyRects.end(); ++i) {
|
||||
const CefRect& rect = *i;
|
||||
DCHECK(rect.x + rect.width <= view_width_);
|
||||
DCHECK(rect.y + rect.height <= view_height_);
|
||||
glPixelStorei(GL_UNPACK_SKIP_PIXELS, rect.x);
|
||||
VERIFY_NO_ERROR;
|
||||
glPixelStorei(GL_UNPACK_SKIP_ROWS, rect.y);
|
||||
VERIFY_NO_ERROR;
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x, rect.y, rect.width,
|
||||
rect.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
buffer);
|
||||
VERIFY_NO_ERROR;
|
||||
}
|
||||
}
|
||||
} else if (type == PET_POPUP && popup_rect_.width > 0 &&
|
||||
popup_rect_.height > 0) {
|
||||
int skip_pixels = 0, x = popup_rect_.x;
|
||||
int skip_rows = 0, y = popup_rect_.y;
|
||||
int w = width;
|
||||
int h = height;
|
||||
|
||||
// Adjust the popup to fit inside the view.
|
||||
if (x < 0) {
|
||||
skip_pixels = -x;
|
||||
x = 0;
|
||||
}
|
||||
if (y < 0) {
|
||||
skip_rows = -y;
|
||||
y = 0;
|
||||
}
|
||||
if (x + w > view_width_)
|
||||
w -= x + w - view_width_;
|
||||
if (y + h > view_height_)
|
||||
h -= y + h - view_height_;
|
||||
|
||||
// Update the popup rectangle.
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
|
||||
VERIFY_NO_ERROR;
|
||||
glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels);
|
||||
VERIFY_NO_ERROR;
|
||||
glPixelStorei(GL_UNPACK_SKIP_ROWS, skip_rows);
|
||||
VERIFY_NO_ERROR;
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_BGRA,
|
||||
GL_UNSIGNED_INT_8_8_8_8_REV, buffer);
|
||||
VERIFY_NO_ERROR;
|
||||
}
|
||||
|
||||
// Disable 2D textures.
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
VERIFY_NO_ERROR;
|
||||
|
||||
if (IsTransparent()) {
|
||||
// Disable alpha blending.
|
||||
glDisable(GL_BLEND);
|
||||
VERIFY_NO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
void OsrRenderer::SetSpin(float spinX, float spinY) {
|
||||
spin_x_ = spinX;
|
||||
spin_y_ = spinY;
|
||||
}
|
||||
|
||||
void OsrRenderer::IncrementSpin(float spinDX, float spinDY) {
|
||||
spin_x_ -= spinDX;
|
||||
spin_y_ -= spinDY;
|
||||
}
|
67
src/CEF/OsrRenderer.h
Normal file
67
src/CEF/OsrRenderer.h
Normal file
@ -0,0 +1,67 @@
|
||||
// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "include/cef_browser.h"
|
||||
#include "include/cef_render_handler.h"
|
||||
#include "CEF/OsrRendererSettings.h"
|
||||
|
||||
class OsrRenderer {
|
||||
public:
|
||||
explicit OsrRenderer(const OsrRendererSettings& settings);
|
||||
~OsrRenderer();
|
||||
|
||||
// Initialize the OpenGL environment.
|
||||
void Initialize();
|
||||
|
||||
// Clean up the OpenGL environment.
|
||||
void Cleanup();
|
||||
|
||||
// Render to the screen.
|
||||
void Render();
|
||||
|
||||
// Forwarded from CefRenderHandler callbacks.
|
||||
void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show);
|
||||
// |rect| must be in pixel coordinates.
|
||||
void OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect);
|
||||
void OnPaint(CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
const void* buffer,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
// Apply spin.
|
||||
void SetSpin(float spinX, float spinY);
|
||||
void IncrementSpin(float spinDX, float spinDY);
|
||||
|
||||
int GetViewWidth() const { return view_width_; }
|
||||
int GetViewHeight() const { return view_height_; }
|
||||
|
||||
CefRect popup_rect() const { return popup_rect_; }
|
||||
CefRect original_popup_rect() const { return original_popup_rect_; }
|
||||
|
||||
void ClearPopupRects();
|
||||
|
||||
private:
|
||||
CefRect GetPopupRectInWebView(const CefRect& original_rect);
|
||||
|
||||
inline bool IsTransparent() const {
|
||||
return CefColorGetA(settings_.background_color) == 0;
|
||||
}
|
||||
|
||||
const OsrRendererSettings settings_;
|
||||
bool initialized_;
|
||||
unsigned int texture_id_;
|
||||
int view_width_;
|
||||
int view_height_;
|
||||
CefRect popup_rect_;
|
||||
CefRect original_popup_rect_;
|
||||
float spin_x_;
|
||||
float spin_y_;
|
||||
CefRect update_rect_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(OsrRenderer);
|
||||
};
|
@ -4,13 +4,21 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fwd.hpp>
|
||||
|
||||
#include "include/internal/cef_types.h"
|
||||
|
||||
struct OsrRendererSettings {
|
||||
enum class OsrRendererType : unsigned char {
|
||||
Unknown = 0,
|
||||
OpenGL = 1,
|
||||
D3D11 = 2,
|
||||
Navtive = 3
|
||||
};
|
||||
OsrRendererSettings()
|
||||
: show_update_rect(false),
|
||||
background_color(0),
|
||||
shared_texture_enabled(false),
|
||||
render_type(OsrRendererType::Unknown),
|
||||
external_begin_frame_enabled(false),
|
||||
begin_frame_rate(0) {}
|
||||
|
||||
@ -21,7 +29,8 @@ struct OsrRendererSettings {
|
||||
cef_color_t background_color;
|
||||
|
||||
// Render using shared textures. Supported on Windows only via D3D11.
|
||||
bool shared_texture_enabled;
|
||||
// bool shared_texture_enabled;
|
||||
OsrRendererType render_type;
|
||||
|
||||
// Client implements a BeginFrame timer by calling
|
||||
// CefBrowserHost::SendExternalBeginFrame at the specified frame rate.
|
||||
|
@ -11,12 +11,11 @@
|
||||
|
||||
#include "include/base/cef_build.h"
|
||||
#include "CEF/HumanAppContext.h"
|
||||
#include "CEF/osr_accessibility_helper.h"
|
||||
#include "CEF/osr_accessibility_node.h"
|
||||
#include "CEF/osr_ime_handler_win.h"
|
||||
#include "CEF/osr_render_handler_win_d3d11.h"
|
||||
#include "CEF/osr_render_handler_win_gl.h"
|
||||
#include "CEF/osr_render_handler_win_native.h"
|
||||
#include "CEF/OsrAccessibilityHelper.h"
|
||||
#include "CEF/OsrImeHandlerWin.h"
|
||||
#include "CEF/OsrRenderHandlerWinD3D11.h"
|
||||
#include "CEF/OsrRenderHandlerWinGL.h"
|
||||
#include "CEF/OsrRenderHandlerWinNative.h"
|
||||
#include "CEF/resource.h"
|
||||
#include "CEF/GeometryUtil.h"
|
||||
#include "CEF/MainMessageLoop.h"
|
||||
@ -127,9 +126,14 @@ void OsrWindowWin::CreateBrowser(HWND parent_hwnd,
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Create the native window.
|
||||
Create(parent_hwnd, rect);
|
||||
|
||||
#else
|
||||
client_rect_ = rect;
|
||||
hwnd_ = parent_hwnd;
|
||||
NotifyNativeWindowCreated(hwnd_);
|
||||
#endif
|
||||
CefWindowInfo window_info;
|
||||
window_info.SetAsWindowless(hwnd_);
|
||||
|
||||
@ -138,7 +142,7 @@ void OsrWindowWin::CreateBrowser(HWND parent_hwnd,
|
||||
window_info.ex_style |= WS_EX_NOACTIVATE;
|
||||
}
|
||||
|
||||
window_info.shared_texture_enabled = settings_.shared_texture_enabled;
|
||||
window_info.shared_texture_enabled = settings_.render_type == OsrRendererSettings::OsrRendererType::D3D11;
|
||||
window_info.external_begin_frame_enabled =
|
||||
settings_.external_begin_frame_enabled;
|
||||
|
||||
@ -275,7 +279,7 @@ void OsrWindowWin::Create(HWND parent_hwnd, const RECT& rect) {
|
||||
|
||||
HINSTANCE hInst = ::GetModuleHandle(nullptr);
|
||||
|
||||
const cef_color_t background_color = MainContext::Get()->GetBackgroundColor();
|
||||
const cef_color_t background_color = HumanAppContext::Get()->GetBackgroundColor();
|
||||
const HBRUSH background_brush = CreateSolidBrush(
|
||||
RGB(CefColorGetR(background_color), CefColorGetG(background_color),
|
||||
CefColorGetB(background_color)));
|
||||
@ -302,6 +306,9 @@ void OsrWindowWin::Create(HWND parent_hwnd, const RECT& rect) {
|
||||
// Associate |this| with the window.
|
||||
SetUserDataPtr(hwnd_, this);
|
||||
|
||||
// client_rect_ = rect;
|
||||
// hwnd_ = parent_hwnd;
|
||||
|
||||
#if defined(CEF_USE_ATL)
|
||||
accessibility_root_ = nullptr;
|
||||
|
||||
@ -311,10 +318,10 @@ void OsrWindowWin::Create(HWND parent_hwnd, const RECT& rect) {
|
||||
DCHECK_EQ(register_res, S_OK);
|
||||
#endif
|
||||
|
||||
ime_handler_.reset(new OsrImeHandlerWin(hwnd_));
|
||||
// ime_handler_.reset(new OsrImeHandlerWin(hwnd_));
|
||||
|
||||
// Enable Touch Events if requested
|
||||
if (client::MainContext::Get()->TouchEventsEnabled())
|
||||
if (HumanAppContext::Get()->TouchEventsEnabled())
|
||||
RegisterTouchWindow(hwnd_, 0);
|
||||
|
||||
// Notify the window owner.
|
||||
@ -335,7 +342,7 @@ void OsrWindowWin::Destroy() {
|
||||
|
||||
// Destroy the native window.
|
||||
::DestroyWindow(hwnd_);
|
||||
ime_handler_.reset();
|
||||
// ime_handler_.reset();
|
||||
hwnd_ = nullptr;
|
||||
}
|
||||
|
||||
@ -385,65 +392,65 @@ void OsrWindowWin::OnIMESetContext(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
::DefWindowProc(hwnd_, message, wParam, lParam);
|
||||
|
||||
// Create Caret Window if required
|
||||
if (ime_handler_) {
|
||||
ime_handler_->CreateImeWindow();
|
||||
ime_handler_->MoveImeWindow();
|
||||
}
|
||||
// if (ime_handler_) {
|
||||
// ime_handler_->CreateImeWindow();
|
||||
// ime_handler_->MoveImeWindow();
|
||||
// }
|
||||
}
|
||||
|
||||
void OsrWindowWin::OnIMEStartComposition() {
|
||||
if (ime_handler_) {
|
||||
ime_handler_->CreateImeWindow();
|
||||
ime_handler_->MoveImeWindow();
|
||||
ime_handler_->ResetComposition();
|
||||
}
|
||||
// if (ime_handler_) {
|
||||
// ime_handler_->CreateImeWindow();
|
||||
// ime_handler_->MoveImeWindow();
|
||||
// ime_handler_->ResetComposition();
|
||||
// }
|
||||
}
|
||||
|
||||
void OsrWindowWin::OnIMEComposition(UINT message,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam) {
|
||||
if (browser_ && ime_handler_) {
|
||||
CefString cTextStr;
|
||||
if (ime_handler_->GetResult(lParam, cTextStr)) {
|
||||
// Send the text to the browser. The |replacement_range| and
|
||||
// |relative_cursor_pos| params are not used on Windows, so provide
|
||||
// default invalid values.
|
||||
browser_->GetHost()->ImeCommitText(cTextStr,
|
||||
CefRange(UINT32_MAX, UINT32_MAX), 0);
|
||||
ime_handler_->ResetComposition();
|
||||
// Continue reading the composition string - Japanese IMEs send both
|
||||
// GCS_RESULTSTR and GCS_COMPSTR.
|
||||
}
|
||||
|
||||
std::vector<CefCompositionUnderline> underlines;
|
||||
int composition_start = 0;
|
||||
|
||||
if (ime_handler_->GetComposition(lParam, cTextStr, underlines,
|
||||
composition_start)) {
|
||||
// Send the composition string to the browser. The |replacement_range|
|
||||
// param is not used on Windows, so provide a default invalid value.
|
||||
browser_->GetHost()->ImeSetComposition(
|
||||
cTextStr, underlines, CefRange(UINT32_MAX, UINT32_MAX),
|
||||
CefRange(composition_start,
|
||||
static_cast<int>(composition_start + cTextStr.length())));
|
||||
|
||||
// Update the Candidate Window position. The cursor is at the end so
|
||||
// subtract 1. This is safe because IMM32 does not support non-zero-width
|
||||
// in a composition. Also, negative values are safely ignored in
|
||||
// MoveImeWindow
|
||||
ime_handler_->UpdateCaretPosition(composition_start - 1);
|
||||
} else {
|
||||
OnIMECancelCompositionEvent();
|
||||
}
|
||||
}
|
||||
// if (browser_ && ime_handler_) {
|
||||
// CefString cTextStr;
|
||||
// if (ime_handler_->GetResult(lParam, cTextStr)) {
|
||||
// // Send the text to the browser. The |replacement_range| and
|
||||
// // |relative_cursor_pos| params are not used on Windows, so provide
|
||||
// // default invalid values.
|
||||
// browser_->GetHost()->ImeCommitText(cTextStr,
|
||||
// CefRange(UINT32_MAX, UINT32_MAX), 0);
|
||||
// ime_handler_->ResetComposition();
|
||||
// // Continue reading the composition string - Japanese IMEs send both
|
||||
// // GCS_RESULTSTR and GCS_COMPSTR.
|
||||
// }
|
||||
//
|
||||
// std::vector<CefCompositionUnderline> underlines;
|
||||
// int composition_start = 0;
|
||||
//
|
||||
// if (ime_handler_->GetComposition(lParam, cTextStr, underlines,
|
||||
// composition_start)) {
|
||||
// // Send the composition string to the browser. The |replacement_range|
|
||||
// // param is not used on Windows, so provide a default invalid value.
|
||||
// browser_->GetHost()->ImeSetComposition(
|
||||
// cTextStr, underlines, CefRange(UINT32_MAX, UINT32_MAX),
|
||||
// CefRange(composition_start,
|
||||
// static_cast<int>(composition_start + cTextStr.length())));
|
||||
//
|
||||
// // Update the Candidate Window position. The cursor is at the end so
|
||||
// // subtract 1. This is safe because IMM32 does not support non-zero-width
|
||||
// // in a composition. Also, negative values are safely ignored in
|
||||
// // MoveImeWindow
|
||||
// ime_handler_->UpdateCaretPosition(composition_start - 1);
|
||||
// } else {
|
||||
// OnIMECancelCompositionEvent();
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
void OsrWindowWin::OnIMECancelCompositionEvent() {
|
||||
if (browser_ && ime_handler_) {
|
||||
browser_->GetHost()->ImeCancelComposition();
|
||||
ime_handler_->ResetComposition();
|
||||
ime_handler_->DestroyImeWindow();
|
||||
}
|
||||
// if (browser_ && ime_handler_) {
|
||||
// browser_->GetHost()->ImeCancelComposition();
|
||||
// ime_handler_->ResetComposition();
|
||||
// ime_handler_->DestroyImeWindow();
|
||||
// }
|
||||
}
|
||||
|
||||
// static
|
||||
@ -458,102 +465,7 @@ LRESULT CALLBACK OsrWindowWin::OsrWndProc(HWND hWnd,
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
|
||||
// We want to handle IME events before the OS does any default handling.
|
||||
switch (message) {
|
||||
case WM_IME_SETCONTEXT:
|
||||
self->OnIMESetContext(message, wParam, lParam);
|
||||
return 0;
|
||||
case WM_IME_STARTCOMPOSITION:
|
||||
self->OnIMEStartComposition();
|
||||
return 0;
|
||||
case WM_IME_COMPOSITION:
|
||||
self->OnIMEComposition(message, wParam, lParam);
|
||||
return 0;
|
||||
case WM_IME_ENDCOMPOSITION:
|
||||
self->OnIMECancelCompositionEvent();
|
||||
// Let WTL call::DefWindowProc() and release its resources.
|
||||
break;
|
||||
#if defined(CEF_USE_ATL)
|
||||
case WM_GETOBJECT: {
|
||||
// Only the lower 32 bits of lParam are valid when checking the object id
|
||||
// because it sometimes gets sign-extended incorrectly (but not always).
|
||||
DWORD obj_id = static_cast<DWORD>(static_cast<DWORD_PTR>(lParam));
|
||||
|
||||
// Accessibility readers will send an OBJID_CLIENT message.
|
||||
if (static_cast<DWORD>(OBJID_CLIENT) == obj_id) {
|
||||
if (self->accessibility_root_) {
|
||||
return LresultFromObject(
|
||||
IID_IAccessible, wParam,
|
||||
static_cast<IAccessible*>(self->accessibility_root_));
|
||||
} else {
|
||||
// Notify the renderer to enable accessibility.
|
||||
if (self->browser_ && self->browser_->GetHost())
|
||||
self->browser_->GetHost()->SetAccessibilityState(STATE_ENABLED);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
#endif
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_RBUTTONDOWN:
|
||||
case WM_MBUTTONDOWN:
|
||||
case WM_LBUTTONUP:
|
||||
case WM_RBUTTONUP:
|
||||
case WM_MBUTTONUP:
|
||||
case WM_MOUSEMOVE:
|
||||
case WM_MOUSELEAVE:
|
||||
case WM_MOUSEWHEEL:
|
||||
self->OnMouseEvent(message, wParam, lParam);
|
||||
break;
|
||||
|
||||
case WM_SIZE:
|
||||
self->OnSize();
|
||||
break;
|
||||
|
||||
case WM_SETFOCUS:
|
||||
case WM_KILLFOCUS:
|
||||
self->OnFocus(message == WM_SETFOCUS);
|
||||
break;
|
||||
|
||||
case WM_CAPTURECHANGED:
|
||||
case WM_CANCELMODE:
|
||||
self->OnCaptureLost();
|
||||
break;
|
||||
|
||||
case WM_SYSCHAR:
|
||||
case WM_SYSKEYDOWN:
|
||||
case WM_SYSKEYUP:
|
||||
case WM_KEYDOWN:
|
||||
case WM_KEYUP:
|
||||
case WM_CHAR:
|
||||
self->OnKeyEvent(message, wParam, lParam);
|
||||
break;
|
||||
|
||||
case WM_PAINT:
|
||||
self->OnPaint();
|
||||
return 0;
|
||||
|
||||
case WM_ERASEBKGND:
|
||||
if (self->OnEraseBkgnd())
|
||||
break;
|
||||
// Don't erase the background.
|
||||
return 0;
|
||||
|
||||
// If your application does not require Win7 support, please do consider
|
||||
// using WM_POINTER* messages instead of WM_TOUCH. WM_POINTER are more
|
||||
// intutive, complete and simpler to code.
|
||||
// https://msdn.microsoft.com/en-us/library/hh454903(v=vs.85).aspx
|
||||
case WM_TOUCH:
|
||||
if (self->OnTouchEvent(message, wParam, lParam))
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case WM_NCDESTROY:
|
||||
// Clear the reference to |self|.
|
||||
SetUserDataPtr(hWnd, nullptr);
|
||||
self->hwnd_ = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
return self->OnMessage(hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
void OsrWindowWin::OnMouseEvent(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
@ -756,6 +668,105 @@ void OsrWindowWin::OnSize() {
|
||||
browser_->GetHost()->WasResized();
|
||||
}
|
||||
|
||||
LRESULT OsrWindowWin::OnMessage(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
switch (message) {
|
||||
case WM_IME_SETCONTEXT:
|
||||
OnIMESetContext(message, wParam, lParam);
|
||||
return 0;
|
||||
case WM_IME_STARTCOMPOSITION:
|
||||
OnIMEStartComposition();
|
||||
return 0;
|
||||
case WM_IME_COMPOSITION:
|
||||
OnIMEComposition(message, wParam, lParam);
|
||||
return 0;
|
||||
case WM_IME_ENDCOMPOSITION:
|
||||
OnIMECancelCompositionEvent();
|
||||
// Let WTL call::DefWindowProc() and release its resources.
|
||||
break;
|
||||
#if defined(CEF_USE_ATL)
|
||||
case WM_GETOBJECT: {
|
||||
// Only the lower 32 bits of lParam are valid when checking the object id
|
||||
// because it sometimes gets sign-extended incorrectly (but not always).
|
||||
DWORD obj_id = static_cast<DWORD>(static_cast<DWORD_PTR>(lParam));
|
||||
|
||||
// Accessibility readers will send an OBJID_CLIENT message.
|
||||
if (static_cast<DWORD>(OBJID_CLIENT) == obj_id) {
|
||||
if (self->accessibility_root_) {
|
||||
return LresultFromObject(
|
||||
IID_IAccessible, wParam,
|
||||
static_cast<IAccessible*>(self->accessibility_root_));
|
||||
} else {
|
||||
// Notify the renderer to enable accessibility.
|
||||
if (self->browser_ && self->browser_->GetHost())
|
||||
self->browser_->GetHost()->SetAccessibilityState(STATE_ENABLED);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
#endif
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_RBUTTONDOWN:
|
||||
case WM_MBUTTONDOWN:
|
||||
case WM_LBUTTONUP:
|
||||
case WM_RBUTTONUP:
|
||||
case WM_MBUTTONUP:
|
||||
case WM_MOUSEMOVE:
|
||||
case WM_MOUSELEAVE:
|
||||
case WM_MOUSEWHEEL:
|
||||
OnMouseEvent(message, wParam, lParam);
|
||||
break;
|
||||
|
||||
case WM_SIZE:
|
||||
OnSize();
|
||||
break;
|
||||
|
||||
case WM_SETFOCUS:
|
||||
case WM_KILLFOCUS:
|
||||
OnFocus(message == WM_SETFOCUS);
|
||||
break;
|
||||
|
||||
case WM_CAPTURECHANGED:
|
||||
case WM_CANCELMODE:
|
||||
OnCaptureLost();
|
||||
break;
|
||||
|
||||
case WM_SYSCHAR:
|
||||
case WM_SYSKEYDOWN:
|
||||
case WM_SYSKEYUP:
|
||||
case WM_KEYDOWN:
|
||||
case WM_KEYUP:
|
||||
case WM_CHAR:
|
||||
OnKeyEvent(message, wParam, lParam);
|
||||
break;
|
||||
|
||||
case WM_PAINT:
|
||||
OnPaint();
|
||||
return 0;
|
||||
|
||||
case WM_ERASEBKGND:
|
||||
if (OnEraseBkgnd())
|
||||
break;
|
||||
// Don't erase the background.
|
||||
return 0;
|
||||
|
||||
// If your application does not require Win7 support, please do consider
|
||||
// using WM_POINTER* messages instead of WM_TOUCH. WM_POINTER are more
|
||||
// intutive, complete and simpler to code.
|
||||
// https://msdn.microsoft.com/en-us/library/hh454903(v=vs.85).aspx
|
||||
case WM_TOUCH:
|
||||
if (OnTouchEvent(message, wParam, lParam))
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case WM_NCDESTROY:
|
||||
// Clear the reference to |self|.
|
||||
SetUserDataPtr(hWnd, nullptr);
|
||||
hwnd_ = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
void OsrWindowWin::OnFocus(bool setFocus) {
|
||||
if (browser_)
|
||||
browser_->GetHost()->SetFocus(setFocus);
|
||||
@ -1085,16 +1096,16 @@ void OsrWindowWin::OnImeCompositionRangeChanged(
|
||||
const CefRenderHandler::RectList& character_bounds) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
if (ime_handler_) {
|
||||
// Convert from view coordinates to device coordinates.
|
||||
CefRenderHandler::RectList device_bounds;
|
||||
CefRenderHandler::RectList::const_iterator it = character_bounds.begin();
|
||||
for (; it != character_bounds.end(); ++it) {
|
||||
device_bounds.push_back(LogicalToDevice(*it, device_scale_factor_));
|
||||
}
|
||||
|
||||
ime_handler_->ChangeCompositionRange(selection_range, device_bounds);
|
||||
}
|
||||
// if (ime_handler_) {
|
||||
// // Convert from view coordinates to device coordinates.
|
||||
// CefRenderHandler::RectList device_bounds;
|
||||
// CefRenderHandler::RectList::const_iterator it = character_bounds.begin();
|
||||
// for (; it != character_bounds.end(); ++it) {
|
||||
// device_bounds.push_back(LogicalToDevice(*it, device_scale_factor_));
|
||||
// }
|
||||
//
|
||||
// ime_handler_->ChangeCompositionRange(selection_range, device_bounds);
|
||||
// }
|
||||
}
|
||||
|
||||
void OsrWindowWin::UpdateAccessibilityTree(CefRefPtr<CefValue> value) {
|
||||
@ -1170,7 +1181,7 @@ CefBrowserHost::DragOperationsMask OsrWindowWin::OnDrop(
|
||||
void OsrWindowWin::EnsureRenderHandler() {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
if (!render_handler_) {
|
||||
if (settings_.shared_texture_enabled) {
|
||||
if (OsrRendererSettings::OsrRendererType::D3D11 == settings_.render_type) {
|
||||
// Try to initialize D3D11 rendering.
|
||||
auto render_handler = new OsrRenderHandlerWinD3D11(settings_, hwnd_);
|
||||
if (render_handler->Initialize(browser_,
|
||||
@ -1181,15 +1192,11 @@ void OsrWindowWin::EnsureRenderHandler() {
|
||||
LOG(ERROR) << "Failed to initialize D3D11 rendering.";
|
||||
delete render_handler;
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to GL rendering.
|
||||
//if (!render_handler_) {
|
||||
// auto render_handler = new OsrRenderHandlerWinGL(settings_, hwnd_);
|
||||
// render_handler->Initialize(browser_);
|
||||
// render_handler_.reset(render_handler);
|
||||
//}
|
||||
if (!render_handler_) {
|
||||
} else if (OsrRendererSettings::OsrRendererType::OpenGL == settings_.render_type) {
|
||||
auto render_handler = new OsrRenderHandlerWinGL(settings_, hwnd_);
|
||||
render_handler->Initialize(browser_);
|
||||
render_handler_.reset(render_handler);
|
||||
} else {
|
||||
auto render_handler = new OsrRenderHandlerWinNative(settings_, hwnd_);
|
||||
render_handler->Initialize(browser_);
|
||||
render_handler_.reset(render_handler);
|
||||
|
@ -8,11 +8,11 @@
|
||||
#include "include/base/cef_ref_counted.h"
|
||||
#include "include/wrapper/cef_closure_task.h"
|
||||
#include "include/wrapper/cef_helpers.h"
|
||||
#include "CEF/ClientHandlerOSR.h.h"
|
||||
#include "CEF/osr_accessibility_node.h"
|
||||
#include "CEF/osr_dragdrop_win.h"
|
||||
#include "CEF/osr_render_handler_win.h"
|
||||
#include "CEF/osr_renderer_settings.h"
|
||||
#include "CEF/ClientHandlerOSR.h"
|
||||
#include "CEF/OsrAccessibilityNode.h"
|
||||
#include "CEF/OsrDragdropWin.h"
|
||||
#include "CEF/OsrRenderHandlerWin.h"
|
||||
#include "CEF/OsrRendererSettings.h"
|
||||
|
||||
class OsrAccessibilityHelper;
|
||||
class OsrImeHandlerWin;
|
||||
@ -62,6 +62,8 @@ class OsrWindowWin
|
||||
void SetDeviceScaleFactor(float device_scale_factor);
|
||||
|
||||
const OsrRendererSettings& settings() const { return settings_; }
|
||||
void OnSize() override;
|
||||
LRESULT OnMessage(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
private:
|
||||
// Only allow deletion via scoped_refptr.
|
||||
@ -84,7 +86,6 @@ class OsrWindowWin
|
||||
|
||||
// WndProc message handlers.
|
||||
void OnMouseEvent(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
void OnSize();
|
||||
void OnFocus(bool setFocus);
|
||||
void OnCaptureLost();
|
||||
void OnKeyEvent(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
@ -172,7 +173,7 @@ class OsrWindowWin
|
||||
std::unique_ptr<OsrRenderHandlerWin> render_handler_;
|
||||
|
||||
// Class that encapsulates IMM32 APIs and controls IMEs attached to a window.
|
||||
std::unique_ptr<OsrImeHandlerWin> ime_handler_;
|
||||
// std::unique_ptr<OsrImeHandlerWin> ime_handler_;
|
||||
|
||||
RECT client_rect_;
|
||||
float device_scale_factor_;
|
||||
|
@ -2,7 +2,7 @@
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#include "CEF//RootWindow.h"
|
||||
#include "CEF/RootWindow.h"
|
||||
|
||||
// #include "CEF/Rroot_window_views.h"
|
||||
|
||||
@ -14,7 +14,6 @@
|
||||
#include "tests/cefclient/browser/root_window_mac.h"
|
||||
#endif
|
||||
|
||||
namespace client {
|
||||
|
||||
// static
|
||||
scoped_refptr<RootWindow> RootWindow::Create(bool use_views) {
|
||||
@ -33,4 +32,3 @@ scoped_refptr<RootWindow> RootWindow::Create(bool use_views) {
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
|
@ -84,7 +84,7 @@ float GetWindowScaleFactor(HWND hwnd) {
|
||||
return static_cast<float>(func_ptr(hwnd)) / DPI_1X;
|
||||
}
|
||||
|
||||
return client::GetDeviceScaleFactor();
|
||||
return GetDeviceScaleFactor();
|
||||
}
|
||||
|
||||
int GetButtonWidth(HWND hwnd) {
|
||||
@ -95,7 +95,6 @@ int GetURLBarHeight(HWND hwnd) {
|
||||
return LogicalToDevice(URLBAR_HEIGHT, GetWindowScaleFactor(hwnd));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
RootWindowWin::RootWindowWin()
|
||||
: with_controls_(false),
|
||||
@ -303,7 +302,7 @@ bool RootWindowWin::WithExtension() const {
|
||||
void RootWindowWin::CreateBrowserWindow(const std::string& startup_url) {
|
||||
if (with_osr_) {
|
||||
OsrRendererSettings settings = {};
|
||||
MainContext::Get()->PopulateOsrSettings(&settings);
|
||||
HumanAppContext::Get()->PopulateOsrSettings(&settings);
|
||||
settings.background_color = CefColorSetARGB(0, 0, 0, 0);
|
||||
browser_window_.reset(
|
||||
new BrowserWindowOsrWin(this, with_controls_, startup_url, settings));
|
||||
@ -321,10 +320,10 @@ void RootWindowWin::CreateRootWindow(const CefBrowserSettings& settings,
|
||||
HINSTANCE hInstance = GetModuleHandle(nullptr);
|
||||
|
||||
// Load strings from the resource file.
|
||||
const std::wstring& window_title = GetResourceString(IDS_APP_TITLE);
|
||||
const std::wstring& window_class = GetResourceString(IDC_CEFCLIENT);
|
||||
constexpr wchar_t* window_title = L"HuamanRender";
|
||||
constexpr wchar_t* window_class = L"HuamanRenderClass";
|
||||
|
||||
const cef_color_t background_color = MainContext::Get()->GetBackgroundColor();
|
||||
const cef_color_t background_color = HumanAppContext::Get()->GetBackgroundColor();
|
||||
const HBRUSH background_brush = CreateSolidBrush(
|
||||
RGB(CefColorGetR(background_color), CefColorGetG(background_color),
|
||||
CefColorGetB(background_color)));
|
||||
@ -338,7 +337,7 @@ void RootWindowWin::CreateRootWindow(const CefBrowserSettings& settings,
|
||||
|
||||
CefRefPtr<CefCommandLine> command_line =
|
||||
CefCommandLine::GetGlobalCommandLine();
|
||||
const bool no_activate = command_line->HasSwitch(switches::kNoActivate);
|
||||
const bool no_activate = command_line->HasSwitch(kNoActivate);
|
||||
|
||||
const DWORD dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;
|
||||
DWORD dwExStyle = always_on_top_ ? WS_EX_TOPMOST : 0;
|
||||
@ -346,6 +345,7 @@ void RootWindowWin::CreateRootWindow(const CefBrowserSettings& settings,
|
||||
// Don't activate the browser window on creation.
|
||||
dwExStyle |= WS_EX_NOACTIVATE;
|
||||
}
|
||||
// dwExStyle |= WS_EX_NOREDIRECTIONBITMAP ;
|
||||
|
||||
int x, y, width, height;
|
||||
if (::IsRectEmpty(&start_rect_)) {
|
||||
@ -365,9 +365,14 @@ void RootWindowWin::CreateRootWindow(const CefBrowserSettings& settings,
|
||||
browser_settings_ = settings;
|
||||
|
||||
// Create the main window initially hidden.
|
||||
CreateWindowEx(dwExStyle, window_class.c_str(), window_title.c_str(), dwStyle,
|
||||
CreateWindowEx(dwExStyle, window_class, window_title, dwStyle,
|
||||
x, y, width, height, nullptr, nullptr, hInstance, this);
|
||||
CHECK(hwnd_);
|
||||
// SetWindowLong(hwnd_,GWL_STYLE,WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_SYSMENU);
|
||||
SetWindowLong(hwnd_, GWL_EXSTYLE,
|
||||
GetWindowLong(hwnd_, GWL_EXSTYLE) | WS_EX_LAYERED );
|
||||
|
||||
// SetLayeredWindowAttributes(hwnd_, RGB(255, 0, 0), 0, LWA_COLORKEY);
|
||||
|
||||
if (!called_enable_non_client_dpi_scaling_ && IsProcessPerMonitorDpiAware()) {
|
||||
// This call gets Windows to scale the non-client area when WM_DPICHANGED
|
||||
@ -389,7 +394,7 @@ void RootWindowWin::CreateRootWindow(const CefBrowserSettings& settings,
|
||||
|
||||
// static
|
||||
void RootWindowWin::RegisterRootClass(HINSTANCE hInstance,
|
||||
const std::wstring& window_class,
|
||||
const wchar_t* window_class,
|
||||
HBRUSH background_brush) {
|
||||
// Only register the class one time.
|
||||
static bool class_registered = false;
|
||||
@ -410,7 +415,7 @@ void RootWindowWin::RegisterRootClass(HINSTANCE hInstance,
|
||||
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||
wcex.hbrBackground = background_brush;
|
||||
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_CEFCLIENT);
|
||||
wcex.lpszClassName = window_class.c_str();
|
||||
wcex.lpszClassName = window_class;
|
||||
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
|
||||
|
||||
RegisterClassEx(&wcex);
|
||||
@ -504,10 +509,25 @@ LRESULT CALLBACK RootWindowWin::RootWndProc(HWND hWnd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (WM_NCCREATE == message) {
|
||||
CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lParam);
|
||||
self = reinterpret_cast<RootWindowWin*>(cs->lpCreateParams);
|
||||
DCHECK(self);
|
||||
// Associate |self| with the main window.
|
||||
SetUserDataPtr(hWnd, self);
|
||||
self->hwnd_ = hWnd;
|
||||
|
||||
self->OnNCCreate(cs);
|
||||
}
|
||||
|
||||
// Callback for the main window
|
||||
return self->OnMessage(hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
LRESULT RootWindowWin::OnMessage(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
switch (message) {
|
||||
case WM_COMMAND:
|
||||
if (self->OnCommand(LOWORD(wParam)))
|
||||
if (OnCommand(LOWORD(wParam)))
|
||||
return 0;
|
||||
break;
|
||||
|
||||
@ -518,39 +538,31 @@ LRESULT CALLBACK RootWindowWin::RootWndProc(HWND hWnd,
|
||||
|
||||
// Accessibility readers will send an OBJID_CLIENT message.
|
||||
if (static_cast<DWORD>(OBJID_CLIENT) == obj_id) {
|
||||
if (self->GetBrowser() && self->GetBrowser()->GetHost())
|
||||
self->GetBrowser()->GetHost()->SetAccessibilityState(STATE_ENABLED);
|
||||
if (GetBrowser() && GetBrowser()->GetHost())
|
||||
GetBrowser()->GetHost()->SetAccessibilityState(STATE_ENABLED);
|
||||
}
|
||||
} break;
|
||||
|
||||
case WM_PAINT:
|
||||
self->OnPaint();
|
||||
return 0;
|
||||
|
||||
case WM_ACTIVATE:
|
||||
self->OnActivate(LOWORD(wParam) != WA_INACTIVE);
|
||||
OnActivate(LOWORD(wParam) != WA_INACTIVE);
|
||||
// Allow DefWindowProc to set keyboard focus.
|
||||
break;
|
||||
|
||||
case WM_SETFOCUS:
|
||||
self->OnFocus();
|
||||
return 0;
|
||||
|
||||
case WM_SIZE:
|
||||
self->OnSize(wParam == SIZE_MINIMIZED);
|
||||
OnSize(message, wParam, lParam);
|
||||
break;
|
||||
|
||||
case WM_MOVING:
|
||||
case WM_MOVE:
|
||||
self->OnMove();
|
||||
OnMove();
|
||||
return 0;
|
||||
|
||||
case WM_DPICHANGED:
|
||||
self->OnDpiChanged(wParam, lParam);
|
||||
OnDpiChanged(wParam, lParam);
|
||||
break;
|
||||
|
||||
case WM_ERASEBKGND:
|
||||
if (self->OnEraseBkgnd())
|
||||
if (OnEraseBkgnd())
|
||||
break;
|
||||
// Don't erase the background.
|
||||
return 0;
|
||||
@ -570,7 +582,7 @@ LRESULT CALLBACK RootWindowWin::RootWndProc(HWND hWnd,
|
||||
break;
|
||||
|
||||
case WM_CLOSE:
|
||||
if (self->OnClose())
|
||||
if (OnClose())
|
||||
return 0; // Cancel the close.
|
||||
break;
|
||||
|
||||
@ -580,7 +592,7 @@ LRESULT CALLBACK RootWindowWin::RootWndProc(HWND hWnd,
|
||||
POINTS points = MAKEPOINTS(lParam);
|
||||
POINT point = {points.x, points.y};
|
||||
::ScreenToClient(hWnd, &point);
|
||||
if (::PtInRegion(self->draggable_region_, point.x, point.y)) {
|
||||
if (::PtInRegion(draggable_region_, point.x, point.y)) {
|
||||
// If cursor is inside a draggable region return HTCAPTION to allow
|
||||
// dragging.
|
||||
return HTCAPTION;
|
||||
@ -589,44 +601,157 @@ LRESULT CALLBACK RootWindowWin::RootWndProc(HWND hWnd,
|
||||
return hit;
|
||||
}
|
||||
|
||||
case WM_NCCREATE: {
|
||||
CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lParam);
|
||||
self = reinterpret_cast<RootWindowWin*>(cs->lpCreateParams);
|
||||
DCHECK(self);
|
||||
// Associate |self| with the main window.
|
||||
SetUserDataPtr(hWnd, self);
|
||||
self->hwnd_ = hWnd;
|
||||
|
||||
self->OnNCCreate(cs);
|
||||
} break;
|
||||
|
||||
case WM_CREATE:
|
||||
self->OnCreate(reinterpret_cast<CREATESTRUCT*>(lParam));
|
||||
OnCreate(reinterpret_cast<CREATESTRUCT*>(lParam));
|
||||
break;
|
||||
|
||||
case WM_NCDESTROY:
|
||||
// Clear the reference to |self|.
|
||||
SetUserDataPtr(hWnd, nullptr);
|
||||
self->hwnd_ = nullptr;
|
||||
self->OnDestroyed();
|
||||
OnNCDestory(message, wParam, lParam);
|
||||
break;
|
||||
case WM_IME_SETCONTEXT:
|
||||
OnIMESetContext(message, wParam, lParam);
|
||||
return 0;
|
||||
case WM_IME_STARTCOMPOSITION:
|
||||
OnIMEStartComposition(message, wParam, lParam);
|
||||
return 0;
|
||||
case WM_IME_COMPOSITION:
|
||||
OnIMEComposition(message, wParam, lParam);
|
||||
return 0;
|
||||
case WM_IME_ENDCOMPOSITION:
|
||||
OnIMECancelCompositionEvent(message, wParam, lParam);
|
||||
// Let WTL call::DefWindowProc() and release its resources.
|
||||
break;
|
||||
#if defined(CEF_USE_ATL)
|
||||
case WM_GETOBJECT: {
|
||||
// Only the lower 32 bits of lParam are valid when checking the object id
|
||||
// because it sometimes gets sign-extended incorrectly (but not always).
|
||||
DWORD obj_id = static_cast<DWORD>(static_cast<DWORD_PTR>(lParam));
|
||||
|
||||
// Accessibility readers will send an OBJID_CLIENT message.
|
||||
if (static_cast<DWORD>(OBJID_CLIENT) == obj_id) {
|
||||
if (self->accessibility_root_) {
|
||||
return LresultFromObject(
|
||||
IID_IAccessible, wParam,
|
||||
static_cast<IAccessible*>(self->accessibility_root_));
|
||||
} else {
|
||||
// Notify the renderer to enable accessibility.
|
||||
if (self->browser_ && self->browser_->GetHost())
|
||||
self->browser_->GetHost()->SetAccessibilityState(STATE_ENABLED);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
#endif
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_RBUTTONDOWN:
|
||||
case WM_MBUTTONDOWN:
|
||||
case WM_LBUTTONUP:
|
||||
case WM_RBUTTONUP:
|
||||
case WM_MBUTTONUP:
|
||||
case WM_MOUSEMOVE:
|
||||
case WM_MOUSELEAVE:
|
||||
case WM_MOUSEWHEEL:
|
||||
OnMouseEvent(message, wParam, lParam);
|
||||
break;
|
||||
|
||||
case WM_SETFOCUS:
|
||||
case WM_KILLFOCUS:
|
||||
OnFocus(message, wParam, lParam);
|
||||
break;
|
||||
|
||||
case WM_CAPTURECHANGED:
|
||||
case WM_CANCELMODE:
|
||||
OnCaptureLost(message, wParam, lParam);
|
||||
break;
|
||||
|
||||
case WM_SYSCHAR:
|
||||
case WM_SYSKEYDOWN:
|
||||
case WM_SYSKEYUP:
|
||||
case WM_KEYDOWN:
|
||||
case WM_KEYUP:
|
||||
case WM_CHAR:
|
||||
OnKeyEvent(message, wParam, lParam);
|
||||
break;
|
||||
|
||||
case WM_PAINT:
|
||||
OnPaint(message, wParam, lParam);
|
||||
return 0;
|
||||
|
||||
// If your application does not require Win7 support, please do consider
|
||||
// using WM_POINTER* messages instead of WM_TOUCH. WM_POINTER are more
|
||||
// intutive, complete and simpler to code.
|
||||
// https://msdn.microsoft.com/en-us/library/hh454903(v=vs.85).aspx
|
||||
case WM_TOUCH:
|
||||
OnTouchEvent(message, wParam, lParam);
|
||||
break;
|
||||
}
|
||||
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
void RootWindowWin::OnPaint() {
|
||||
PAINTSTRUCT ps;
|
||||
BeginPaint(hwnd_, &ps);
|
||||
EndPaint(hwnd_, &ps);
|
||||
void RootWindowWin::OnIMESetContext(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
if (browser_window_ && ::IsWindowEnabled(hwnd_))
|
||||
browser_window_->OnMessage(hwnd_, message, wParam, lParam);
|
||||
}
|
||||
|
||||
void RootWindowWin::OnFocus() {
|
||||
void RootWindowWin::OnIMEStartComposition(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
if (browser_window_ && ::IsWindowEnabled(hwnd_))
|
||||
browser_window_->OnMessage(hwnd_, message, wParam, lParam);
|
||||
}
|
||||
|
||||
void RootWindowWin::OnIMEComposition(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
if (browser_window_ && ::IsWindowEnabled(hwnd_))
|
||||
browser_window_->OnMessage(hwnd_, message, wParam, lParam);
|
||||
}
|
||||
|
||||
void RootWindowWin::OnIMECancelCompositionEvent(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
if (browser_window_ && ::IsWindowEnabled(hwnd_))
|
||||
browser_window_->OnMessage(hwnd_, message, wParam, lParam);
|
||||
}
|
||||
|
||||
void RootWindowWin::OnMouseEvent(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
if (browser_window_ && ::IsWindowEnabled(hwnd_))
|
||||
browser_window_->OnMessage(hwnd_, message, wParam, lParam);
|
||||
}
|
||||
|
||||
void RootWindowWin::OnCaptureLost(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
if (browser_window_ && ::IsWindowEnabled(hwnd_))
|
||||
browser_window_->OnMessage(hwnd_, message, wParam, lParam);
|
||||
}
|
||||
|
||||
void RootWindowWin::OnKeyEvent(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
if (browser_window_ && ::IsWindowEnabled(hwnd_))
|
||||
browser_window_->OnMessage(hwnd_, message, wParam, lParam);
|
||||
}
|
||||
|
||||
void RootWindowWin::OnTouchEvent(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
if (browser_window_ && ::IsWindowEnabled(hwnd_))
|
||||
browser_window_->OnMessage(hwnd_, message, wParam, lParam);
|
||||
}
|
||||
|
||||
void RootWindowWin::OnNCDestory(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
if (browser_window_ && ::IsWindowEnabled(hwnd_))
|
||||
browser_window_->OnMessage(hwnd_, message, wParam, lParam);
|
||||
|
||||
// Clear the reference to |self|.
|
||||
SetUserDataPtr(hwnd_, nullptr);
|
||||
hwnd_ = nullptr;
|
||||
OnDestroyed();
|
||||
}
|
||||
|
||||
void RootWindowWin::OnPaint(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
if (browser_window_ && ::IsWindowEnabled(hwnd_))
|
||||
browser_window_->OnMessage(hwnd_, message, wParam, lParam);
|
||||
// PAINTSTRUCT ps;
|
||||
// BeginPaint(hwnd_, &ps);
|
||||
// EndPaint(hwnd_, &ps);
|
||||
}
|
||||
|
||||
void RootWindowWin::OnFocus(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
// Selecting "Close window" from the task bar menu may send a focus
|
||||
// notification even though the window is currently disabled (e.g. while a
|
||||
// modal JS dialog is displayed).
|
||||
if (browser_window_ && ::IsWindowEnabled(hwnd_))
|
||||
browser_window_->SetFocus(true);
|
||||
browser_window_->OnMessage(hwnd_, message, wParam, lParam);
|
||||
}
|
||||
|
||||
void RootWindowWin::OnActivate(bool active) {
|
||||
@ -634,16 +759,17 @@ void RootWindowWin::OnActivate(bool active) {
|
||||
delegate_->OnRootWindowActivated(this);
|
||||
}
|
||||
|
||||
void RootWindowWin::OnSize(bool minimized) {
|
||||
if (minimized) {
|
||||
void RootWindowWin::OnSize(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
if (wParam == SIZE_MINIMIZED) {
|
||||
// Notify the browser window that it was hidden and do nothing further.
|
||||
if (browser_window_)
|
||||
browser_window_->Hide();
|
||||
return;
|
||||
}
|
||||
|
||||
if (browser_window_)
|
||||
if (browser_window_) {
|
||||
browser_window_->Show();
|
||||
}
|
||||
|
||||
RECT rect;
|
||||
GetClientRect(hwnd_, &rect);
|
||||
@ -715,7 +841,8 @@ void RootWindowWin::OnSize(bool minimized) {
|
||||
DCHECK(result);
|
||||
} else if (browser_window_) {
|
||||
// Size the browser window to the whole client area.
|
||||
browser_window_->SetBounds(0, 0, rect.right, rect.bottom);
|
||||
// browser_window_->SetBounds(0, 0, rect.right, rect.bottom);
|
||||
browser_window_->OnMessage(hwnd_, message, wParam, lParam);
|
||||
}
|
||||
}
|
||||
|
||||
@ -990,7 +1117,7 @@ void RootWindowWin::OnBrowserCreated(CefRefPtr<CefBrowser> browser) {
|
||||
CreateRootWindow(CefBrowserSettings(), false);
|
||||
} else {
|
||||
// Make sure the browser is sized correctly.
|
||||
OnSize(false);
|
||||
// OnSize(false);
|
||||
}
|
||||
|
||||
delegate_->OnBrowserCreated(this, browser);
|
||||
@ -1031,8 +1158,8 @@ void RootWindowWin::OnSetFullscreen(bool fullscreen) {
|
||||
|
||||
CefRefPtr<CefBrowser> browser = GetBrowser();
|
||||
if (browser) {
|
||||
std::unique_ptr<window_test::WindowTestRunnerWin> test_runner(
|
||||
new window_test::WindowTestRunnerWin());
|
||||
std::unique_ptr<WindowTestRunnerWin> test_runner(
|
||||
new WindowTestRunnerWin());
|
||||
if (fullscreen)
|
||||
test_runner->Maximize(browser);
|
||||
else
|
||||
@ -1100,7 +1227,6 @@ void RootWindowWin::OnSetLoadingState(bool isLoading,
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
LPCWSTR kParentWndProc = L"CefParentWndProc";
|
||||
LPCWSTR kDraggableRegion = L"CefDraggableRegion";
|
||||
|
@ -52,7 +52,7 @@ class RootWindowWin : public RootWindow, public BrowserWindow::Delegate {
|
||||
|
||||
// Register the root window class.
|
||||
static void RegisterRootClass(HINSTANCE hInstance,
|
||||
const std::wstring& window_class,
|
||||
const wchar_t* window_class,
|
||||
HBRUSH background_brush);
|
||||
|
||||
// Window procedure for the edit field.
|
||||
@ -73,11 +73,21 @@ class RootWindowWin : public RootWindow, public BrowserWindow::Delegate {
|
||||
WPARAM wParam,
|
||||
LPARAM lParam);
|
||||
|
||||
LRESULT OnMessage(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
|
||||
void OnIMESetContext(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
void OnIMEStartComposition(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
void OnIMEComposition(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
void OnIMECancelCompositionEvent(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
void OnMouseEvent(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
void OnCaptureLost(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
void OnKeyEvent(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
void OnTouchEvent(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
void OnNCDestory(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
// Event handlers.
|
||||
void OnPaint();
|
||||
void OnFocus();
|
||||
void OnPaint(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
void OnFocus(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
void OnActivate(bool active);
|
||||
void OnSize(bool minimized);
|
||||
void OnSize(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
void OnMove();
|
||||
void OnDpiChanged(WPARAM wParam, LPARAM lParam);
|
||||
bool OnEraseBkgnd();
|
||||
|
@ -139,7 +139,9 @@ class ClientSchemeHandlerFactory : public CefSchemeHandlerFactory {
|
||||
DISALLOW_COPY_AND_ASSIGN(ClientSchemeHandlerFactory);
|
||||
};
|
||||
|
||||
namespace scheme_test {
|
||||
void RegisterSchemeHandlers() {
|
||||
CefRegisterSchemeHandlerFactory("client", "tests",
|
||||
new ClientSchemeHandlerFactory());
|
||||
}
|
||||
}
|
@ -7,5 +7,6 @@
|
||||
// Create and register the custom scheme handler. See
|
||||
// common/scheme_handler_common.h for registration of the custom scheme
|
||||
// name/type which must occur in all processes. Called from test_runner.cc.
|
||||
namespace scheme_test {
|
||||
void RegisterSchemeHandlers();
|
||||
|
||||
}
|
||||
|
@ -844,15 +844,16 @@ namespace test_runner {
|
||||
|
||||
void RegisterSchemeHandlers() {
|
||||
// Register the scheme handler.
|
||||
RegisterSchemeHandlers();
|
||||
}
|
||||
scheme_test::RegisterSchemeHandlers();
|
||||
}
|
||||
|
||||
CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefRequest> request,
|
||||
CefRefPtr<CefResponse> response) {
|
||||
// Create the response filter.
|
||||
return GetResourceResponseFilter(browser, frame,
|
||||
return response_filter_test::GetResourceResponseFilter(browser, frame,
|
||||
request, response);
|
||||
}
|
||||
}
|
@ -52,7 +52,6 @@ namespace test_runner {
|
||||
|
||||
// Register scheme handlers for tests.
|
||||
void RegisterSchemeHandlers();
|
||||
}
|
||||
|
||||
// Create a resource response filter for tests.
|
||||
CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
|
||||
@ -60,3 +59,4 @@ CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefRequest> request,
|
||||
CefRefPtr<CefResponse> response);
|
||||
}
|
||||
|
@ -79,6 +79,10 @@ target_link_libraries(
|
||||
opengl32
|
||||
glew32s
|
||||
glfw3
|
||||
d3d11
|
||||
glu32
|
||||
imm32
|
||||
opengl32
|
||||
debug spdlogd
|
||||
optimized spdlog
|
||||
debug Debug/libcef
|
||||
|
Loading…
Reference in New Issue
Block a user