Add support for draggable regions (issue #1645).

Regions are defined using the '-webkit-app-region: drag/no-drag'
CSS property and passed to the CefDragHandler::
OnDraggableRegionsChanged callback.
This commit is contained in:
Felix Bruns 2015-04-24 15:48:32 +02:00 committed by Marshall Greenblatt
parent ead921a3f6
commit c5b8b8b9c8
27 changed files with 581 additions and 3 deletions

View File

@ -415,6 +415,7 @@
'tests/unittests/display_unittest.cc',
'tests/unittests/dom_unittest.cc',
'tests/unittests/download_unittest.cc',
'tests/unittests/draggable_regions_unittest.cc',
'tests/unittests/frame_unittest.cc',
'tests/unittests/geolocation_unittest.cc',
'tests/unittests/jsdialog_unittest.cc',

View File

@ -66,6 +66,17 @@ typedef struct _cef_drag_handler_t {
int (CEF_CALLBACK *on_drag_enter)(struct _cef_drag_handler_t* self,
struct _cef_browser_t* browser, struct _cef_drag_data_t* dragData,
cef_drag_operations_mask_t mask);
///
// Called whenever draggable regions for the browser window change. These can
// be specified using the '-webkit-app-region: drag/no-drag' CSS-property. If
// draggable regions are never defined in a document this function will also
// never be called. If the last draggable region is removed from a document
// this function will be called with an NULL vector.
///
void (CEF_CALLBACK *on_draggable_regions_changed)(
struct _cef_drag_handler_t* self, struct _cef_browser_t* browser,
size_t regionsCount, cef_draggable_region_t const* regions);
} cef_drag_handler_t;

View File

@ -61,6 +61,18 @@ class CefDragHandler : public virtual CefBase {
virtual bool OnDragEnter(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDragData> dragData,
DragOperationsMask mask) { return false; }
///
// Called whenever draggable regions for the browser window change. These can
// be specified using the '-webkit-app-region: drag/no-drag' CSS-property. If
// draggable regions are never defined in a document this method will also
// never be called. If the last draggable region is removed from a document
// this method will be called with an empty vector.
///
/*--cef()--*/
virtual void OnDraggableRegionsChanged(
CefRefPtr<CefBrowser> browser,
const std::vector<CefDraggableRegion>& regions) {}
};
#endif // CEF_INCLUDE_CEF_DRAG_HANDLER_H_

View File

@ -1265,6 +1265,21 @@ typedef struct _cef_size_t {
int height;
} cef_size_t;
///
// Structure representing a draggable region.
///
typedef struct _cef_draggable_region_t {
///
// Bounds of the region.
///
cef_rect_t bounds;
///
// True (1) this this region is draggable and false (0) otherwise.
///
int draggable;
} cef_draggable_region_t;
///
// Existing process IDs.
///

View File

@ -257,6 +257,50 @@ inline bool operator!=(const CefSize& a, const CefSize& b) {
}
struct CefDraggableRegionTraits {
typedef cef_draggable_region_t struct_type;
static inline void init(struct_type* s) {}
static inline void clear(struct_type* s) {}
static inline void set(const struct_type* src, struct_type* target,
bool copy) {
*target = *src;
}
};
///
// Class representing a draggable region.
///
class CefDraggableRegion : public CefStructBase<CefDraggableRegionTraits> {
public:
typedef CefStructBase<CefDraggableRegionTraits> parent;
CefDraggableRegion() : parent() {}
CefDraggableRegion(const cef_draggable_region_t& r) // NOLINT(runtime/explicit)
: parent(r) {}
CefDraggableRegion(const CefDraggableRegion& r) // NOLINT(runtime/explicit)
: parent(r) {}
CefDraggableRegion(const CefRect& bounds, bool draggable) : parent() {
Set(bounds, draggable);
}
void Set(const CefRect& bounds, bool draggable) {
this->bounds = bounds, this->draggable = draggable;
}
};
inline bool operator==(const CefDraggableRegion& a,
const CefDraggableRegion& b) {
return a.bounds == b.bounds && a.draggable == b.draggable;
}
inline bool operator!=(const CefDraggableRegion& a,
const CefDraggableRegion& b) {
return !(a == b);
}
struct CefScreenInfoTraits {
typedef cef_screen_info_t struct_type;

View File

@ -2659,6 +2659,8 @@ bool CefBrowserHostImpl::OnMessageReceived(const IPC::Message& message) {
IPC_BEGIN_MESSAGE_MAP(CefBrowserHostImpl, message)
IPC_MESSAGE_HANDLER(CefHostMsg_FrameIdentified, OnFrameIdentified)
IPC_MESSAGE_HANDLER(CefHostMsg_DidFinishLoad, OnDidFinishLoad)
IPC_MESSAGE_HANDLER(CefHostMsg_UpdateDraggableRegions,
OnUpdateDraggableRegions)
IPC_MESSAGE_HANDLER(CefHostMsg_Request, OnRequest)
IPC_MESSAGE_HANDLER(CefHostMsg_Response, OnResponse)
IPC_MESSAGE_HANDLER(CefHostMsg_ResponseAck, OnResponseAck)
@ -2716,6 +2718,26 @@ void CefBrowserHostImpl::OnDidFinishLoad(int64 frame_id,
OnLoadEnd(frame, validated_url, http_status_code);
}
void CefBrowserHostImpl::OnUpdateDraggableRegions(
const std::vector<Cef_DraggableRegion_Params>& regions) {
std::vector<CefDraggableRegion> draggable_regions;
draggable_regions.reserve(regions.size());
std::vector<Cef_DraggableRegion_Params>::const_iterator it = regions.begin();
for (; it != regions.end(); ++it) {
const gfx::Rect& rect(it->bounds);
const CefRect bounds(rect.x(), rect.y(), rect.width(), rect.height());
draggable_regions.push_back(CefDraggableRegion(bounds, it->draggable));
}
if (client_.get()) {
CefRefPtr<CefDragHandler> handler = client_->GetDragHandler();
if (handler.get()) {
handler->OnDraggableRegionsChanged(this, draggable_regions);
}
}
}
void CefBrowserHostImpl::OnRequest(const Cef_Request_Params& params) {
bool success = false;
std::string response;

View File

@ -64,6 +64,7 @@ class Widget;
class CefWindowX11;
#endif
struct Cef_DraggableRegion_Params;
struct Cef_Request_Params;
struct Cef_Response_Params;
class CefBrowserInfo;
@ -477,6 +478,8 @@ class CefBrowserHostImpl : public CefBrowserHost,
const GURL& validated_url,
bool is_main_frame,
int http_status_code);
void OnUpdateDraggableRegions(
const std::vector<Cef_DraggableRegion_Params>& regions);
void OnRequest(const Cef_Request_Params& params);
void OnResponse(const Cef_Response_Params& params);
void OnResponseAck(int request_id);

View File

@ -68,6 +68,12 @@ IPC_STRUCT_BEGIN(Cef_CrossOriginWhiteListEntry_Params)
IPC_STRUCT_MEMBER(bool, allow_target_subdomains)
IPC_STRUCT_END()
// Parameters structure for a draggable region.
IPC_STRUCT_BEGIN(Cef_DraggableRegion_Params)
IPC_STRUCT_MEMBER(gfx::Rect, bounds)
IPC_STRUCT_MEMBER(bool, draggable)
IPC_STRUCT_END()
// Messages sent from the browser to the renderer.
@ -189,6 +195,10 @@ IPC_MESSAGE_ROUTED1(CefHostMsg_Response,
IPC_MESSAGE_ROUTED1(CefHostMsg_ResponseAck,
int /* request_id */)
// Sent by the renderer when the draggable regions are updated.
IPC_MESSAGE_ROUTED1(CefHostMsg_UpdateDraggableRegions,
std::vector<Cef_DraggableRegion_Params> /* regions */)
// Singly-included section for struct and custom IPC traits.
#ifndef CEF_LIBCEF_COMMON_CEF_MESSAGES_H_

View File

@ -571,6 +571,19 @@ void CefBrowserImpl::FocusedNodeChanged(const blink::WebNode& node) {
}
}
void CefBrowserImpl::DraggableRegionsChanged(blink::WebFrame* frame) {
blink::WebVector<blink::WebDraggableRegion> webregions =
frame->document().draggableRegions();
std::vector<Cef_DraggableRegion_Params> regions;
for (size_t i = 0; i < webregions.size(); ++i) {
Cef_DraggableRegion_Params region;
region.bounds = webregions[i].bounds;
region.draggable = webregions[i].draggable;
regions.push_back(region);
}
Send(new CefHostMsg_UpdateDraggableRegions(routing_id(), regions));
}
bool CefBrowserImpl::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(CefBrowserImpl, message)

View File

@ -119,6 +119,7 @@ class CefBrowserImpl : public CefBrowser,
bool is_new_navigation) override;
void FrameDetached(blink::WebFrame* frame) override;
void FocusedNodeChanged(const blink::WebNode& node) override;
void DraggableRegionsChanged(blink::WebFrame* frame) override;
bool OnMessageReceived(const IPC::Message& message) override;
// RenderViewObserver::OnMessageReceived message handlers.

View File

@ -46,6 +46,37 @@ int CEF_CALLBACK drag_handler_on_drag_enter(struct _cef_drag_handler_t* self,
return _retval;
}
void CEF_CALLBACK drag_handler_on_draggable_regions_changed(
struct _cef_drag_handler_t* self, cef_browser_t* browser,
size_t regionsCount, cef_draggable_region_t const* regions) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Verify param: browser; type: refptr_diff
DCHECK(browser);
if (!browser)
return;
// Verify param: regions; type: simple_vec_byref_const
DCHECK(regionsCount == 0 || regions);
if (regionsCount > 0 && !regions)
return;
// Translate param: regions; type: simple_vec_byref_const
std::vector<CefDraggableRegion > regionsList;
if (regionsCount > 0) {
for (size_t i = 0; i < regionsCount; ++i) {
regionsList.push_back(regions[i]);
}
}
// Execute
CefDragHandlerCppToC::Get(self)->OnDraggableRegionsChanged(
CefBrowserCToCpp::Wrap(browser),
regionsList);
}
} // namespace
@ -53,6 +84,8 @@ int CEF_CALLBACK drag_handler_on_drag_enter(struct _cef_drag_handler_t* self,
CefDragHandlerCppToC::CefDragHandlerCppToC() {
GetStruct()->on_drag_enter = drag_handler_on_drag_enter;
GetStruct()->on_draggable_regions_changed =
drag_handler_on_draggable_regions_changed;
}
template<> CefRefPtr<CefDragHandler> CefCppToC<CefDragHandlerCppToC,

View File

@ -44,6 +44,44 @@ bool CefDragHandlerCToCpp::OnDragEnter(CefRefPtr<CefBrowser> browser,
return _retval?true:false;
}
void CefDragHandlerCToCpp::OnDraggableRegionsChanged(
CefRefPtr<CefBrowser> browser,
const std::vector<CefDraggableRegion>& regions) {
cef_drag_handler_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, on_draggable_regions_changed))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: browser; type: refptr_diff
DCHECK(browser.get());
if (!browser.get())
return;
// Translate param: regions; type: simple_vec_byref_const
const size_t regionsCount = regions.size();
cef_draggable_region_t* regionsList = NULL;
if (regionsCount > 0) {
regionsList = new cef_draggable_region_t[regionsCount];
DCHECK(regionsList);
if (regionsList) {
for (size_t i = 0; i < regionsCount; ++i) {
regionsList[i] = regions[i];
}
}
}
// Execute
_struct->on_draggable_regions_changed(_struct,
CefBrowserCppToC::Wrap(browser),
regionsCount,
regionsList);
// Restore param:regions; type: simple_vec_byref_const
if (regionsList)
delete [] regionsList;
}
// CONSTRUCTOR - Do not edit by hand.

View File

@ -18,6 +18,7 @@
#pragma message("Warning: "__FILE__" may be accessed DLL-side only")
#else // BUILDING_CEF_SHARED
#include <vector>
#include "include/cef_drag_handler.h"
#include "include/capi/cef_drag_handler_capi.h"
#include "libcef_dll/ctocpp/ctocpp.h"
@ -33,6 +34,8 @@ class CefDragHandlerCToCpp
// CefDragHandler methods.
bool OnDragEnter(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDragData> dragData, DragOperationsMask mask) override;
void OnDraggableRegionsChanged(CefRefPtr<CefBrowser> browser,
const std::vector<CefDraggableRegion>& regions) override;
};
#endif // BUILDING_CEF_SHARED

View File

@ -68,4 +68,10 @@ void BrowserWindow::OnSetLoadingState(bool isLoading,
delegate_->OnSetLoadingState(isLoading, canGoBack, canGoForward);
}
void BrowserWindow::OnSetDraggableRegions(
const std::vector<CefDraggableRegion>& regions) {
REQUIRE_MAIN_THREAD();
delegate_->OnSetDraggableRegions(regions);
}
} // namespace client

View File

@ -39,6 +39,10 @@ class BrowserWindow : public ClientHandler::Delegate {
bool canGoBack,
bool canGoForward) = 0;
// Set the draggable regions.
virtual void OnSetDraggableRegions(
const std::vector<CefDraggableRegion>& regions) = 0;
protected:
virtual ~Delegate() {}
};
@ -101,6 +105,8 @@ class BrowserWindow : public ClientHandler::Delegate {
void OnSetLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward) OVERRIDE;
void OnSetDraggableRegions(
const std::vector<CefDraggableRegion>& regions) OVERRIDE;
Delegate* delegate_;
CefRefPtr<CefBrowser> browser_;

View File

@ -290,6 +290,14 @@ bool ClientHandler::OnDragEnter(CefRefPtr<CefBrowser> browser,
return false;
}
void ClientHandler::OnDraggableRegionsChanged(
CefRefPtr<CefBrowser> browser,
const std::vector<CefDraggableRegion>& regions) {
CEF_REQUIRE_UI_THREAD();
NotifyDraggableRegions(regions);
}
bool ClientHandler::OnRequestGeolocationPermission(
CefRefPtr<CefBrowser> browser,
const CefString& requesting_url,
@ -676,6 +684,19 @@ void ClientHandler::NotifyLoadingState(bool isLoading,
delegate_->OnSetLoadingState(isLoading, canGoBack, canGoForward);
}
void ClientHandler::NotifyDraggableRegions(
const std::vector<CefDraggableRegion>& regions) {
if (!CURRENTLY_ON_MAIN_THREAD()) {
// Execute this method on the main thread.
MAIN_POST_CLOSURE(
base::Bind(&ClientHandler::NotifyDraggableRegions, this, regions));
return;
}
if (delegate_)
delegate_->OnSetDraggableRegions(regions);
}
void ClientHandler::BuildTestMenu(CefRefPtr<CefMenuModel> model) {
if (model->GetCount() > 0)
model->AddSeparator();

View File

@ -57,6 +57,10 @@ class ClientHandler : public CefClient,
bool canGoBack,
bool canGoForward) = 0;
// Set the draggable regions.
virtual void OnSetDraggableRegions(
const std::vector<CefDraggableRegion>& regions) = 0;
protected:
virtual ~Delegate() {}
};
@ -152,6 +156,10 @@ class ClientHandler : public CefClient,
CefRefPtr<CefDragData> dragData,
CefDragHandler::DragOperationsMask mask) OVERRIDE;
void OnDraggableRegionsChanged(
CefRefPtr<CefBrowser> browser,
const std::vector<CefDraggableRegion>& regions) OVERRIDE;
// CefGeolocationHandler methods
bool OnRequestGeolocationPermission(
CefRefPtr<CefBrowser> browser,
@ -263,6 +271,8 @@ class ClientHandler : public CefClient,
void NotifyLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward);
void NotifyDraggableRegions(
const std::vector<CefDraggableRegion>& regions);
// Test context menu creation.
void BuildTestMenu(CefRefPtr<CefMenuModel> model);
@ -288,7 +298,7 @@ class ClientHandler : public CefClient,
// Handles the browser side of query routing. The renderer side is handled
// in client_renderer.cc.
CefRefPtr<CefMessageRouterBrowserSide> message_router_;
// MAIN THREAD MEMBERS
// The following members will only be accessed on the main thread. This will
// be the same as the CEF UI thread except when using multi-threaded message

View File

@ -387,6 +387,12 @@ void RootWindowGtk::OnSetLoadingState(bool isLoading,
}
}
void RootWindowGtk::OnSetDraggableRegions(
const std::vector<CefDraggableRegion>& regions) {
REQUIRE_MAIN_THREAD();
// TODO(cef): Implement support for draggable regions on this platform.
}
void RootWindowGtk::NotifyDestroyedIfDone() {
// Notify once both the window and the browser have been destroyed.
if (window_destroyed_ && browser_destroyed_)

View File

@ -58,6 +58,8 @@ class RootWindowGtk : public RootWindow,
void OnSetLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward) OVERRIDE;
void OnSetDraggableRegions(
const std::vector<CefDraggableRegion>& regions) OVERRIDE;
void NotifyDestroyedIfDone();

View File

@ -64,6 +64,8 @@ class RootWindowMac : public RootWindow,
void OnSetLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward) OVERRIDE;
void OnSetDraggableRegions(
const std::vector<CefDraggableRegion>& regions) OVERRIDE;
void NotifyDestroyedIfDone();

View File

@ -576,6 +576,12 @@ void RootWindowMac::OnSetAddress(const std::string& url) {
}
}
void RootWindowMac::OnSetDraggableRegions(
const std::vector<CefDraggableRegion>& regions) {
REQUIRE_MAIN_THREAD();
// TODO(cef): Implement support for draggable regions on this platform.
}
void RootWindowMac::OnSetTitle(const std::string& title) {
REQUIRE_MAIN_THREAD();

View File

@ -5,6 +5,7 @@
#include "cefclient/browser/root_window_win.h"
#include "include/base/cef_bind.h"
#include "include/base/cef_build.h"
#include "include/cef_app.h"
#include "cefclient/browser/browser_window_osr_win.h"
#include "cefclient/browser/browser_window_std_win.h"
@ -51,6 +52,7 @@ RootWindowWin::RootWindowWin()
start_rect_(),
initialized_(false),
hwnd_(NULL),
draggable_region_(NULL),
back_hwnd_(NULL),
forward_hwnd_(NULL),
reload_hwnd_(NULL),
@ -66,11 +68,16 @@ RootWindowWin::RootWindowWin()
window_destroyed_(false),
browser_destroyed_(false) {
find_buff_[0] = 0;
// Create a HRGN representing the draggable window area.
draggable_region_ = ::CreateRectRgn(0, 0, 0, 0);
}
RootWindowWin::~RootWindowWin() {
REQUIRE_MAIN_THREAD();
::DeleteObject(draggable_region_);
// The window and browser should already have been destroyed.
DCHECK(window_destroyed_);
DCHECK(browser_destroyed_);
@ -513,6 +520,21 @@ LRESULT CALLBACK RootWindowWin::RootWndProc(HWND hWnd, UINT message,
return 0; // Cancel the close.
break;
case WM_NCHITTEST: {
LRESULT hit = DefWindowProc(hWnd, message, wParam, lParam);
if (hit == HTCLIENT) {
POINTS points = MAKEPOINTS(lParam);
POINT point = { points.x, points.y };
::ScreenToClient(hWnd, &point);
if (::PtInRegion(self->draggable_region_, point.x, point.y)) {
// If cursor is inside a draggable region return HTCAPTION to allow
// dragging.
return HTCAPTION;
}
}
return hit;
}
case WM_NCDESTROY:
// Clear the reference to |self|.
SetUserDataPtr(hWnd, NULL);
@ -764,6 +786,111 @@ void RootWindowWin::OnSetLoadingState(bool isLoading,
}
}
namespace {
LPCWSTR kParentWndProc = L"CefParentWndProc";
LPCWSTR kDraggableRegion = L"CefDraggableRegion";
LRESULT CALLBACK SubclassedWindowProc(
HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
WNDPROC hParentWndProc = reinterpret_cast<WNDPROC>(
::GetPropW(hWnd, kParentWndProc));
HRGN hRegion = reinterpret_cast<HRGN>(
::GetPropW(hWnd, kDraggableRegion));
if (message == WM_NCHITTEST) {
LRESULT hit = CallWindowProc(
hParentWndProc, hWnd, message, wParam, lParam);
if (hit == HTCLIENT) {
POINTS points = MAKEPOINTS(lParam);
POINT point = { points.x, points.y };
::ScreenToClient(hWnd, &point);
if (::PtInRegion(hRegion, point.x, point.y)) {
// Let the parent window handle WM_NCHITTEST by returning HTTRANSPARENT
// in child windows.
return HTTRANSPARENT;
}
}
return hit;
}
return CallWindowProc(hParentWndProc, hWnd, message, wParam, lParam);
}
void SubclassWindow(HWND hWnd, HRGN hRegion) {
HANDLE hParentWndProc = ::GetPropW(hWnd, kParentWndProc);
if (hParentWndProc) {
return;
}
SetLastError(0);
LONG_PTR hOldWndProc = SetWindowLongPtr(
hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(SubclassedWindowProc));
if (hOldWndProc == 0 && GetLastError() != ERROR_SUCCESS) {
return;
}
::SetPropW(hWnd, kParentWndProc, reinterpret_cast<HANDLE>(hOldWndProc));
::SetPropW(hWnd, kDraggableRegion, reinterpret_cast<HANDLE>(hRegion));
}
void UnSubclassWindow(HWND hWnd) {
LONG_PTR hParentWndProc = reinterpret_cast<LONG_PTR>(
::GetPropW(hWnd, kParentWndProc));
if (hParentWndProc) {
LONG_PTR hPreviousWndProc =
SetWindowLongPtr(hWnd, GWLP_WNDPROC, hParentWndProc);
ALLOW_UNUSED_LOCAL(hPreviousWndProc);
DCHECK_EQ(hPreviousWndProc,
reinterpret_cast<LONG_PTR>(SubclassedWindowProc));
}
::RemovePropW(hWnd, kParentWndProc);
::RemovePropW(hWnd, kDraggableRegion);
}
BOOL CALLBACK SubclassWindowsProc(HWND hwnd, LPARAM lParam) {
SubclassWindow(hwnd, reinterpret_cast<HRGN>(lParam));
return TRUE;
}
BOOL CALLBACK UnSubclassWindowsProc(HWND hwnd, LPARAM lParam) {
UnSubclassWindow(hwnd);
return TRUE;
}
} // namespace
void RootWindowWin::OnSetDraggableRegions(
const std::vector<CefDraggableRegion>& regions) {
REQUIRE_MAIN_THREAD();
// Reset draggable region.
::SetRectRgn(draggable_region_, 0, 0, 0, 0);
// Determine new draggable region.
std::vector<CefDraggableRegion>::const_iterator it = regions.begin();
for (;it != regions.end(); ++it) {
HRGN region = ::CreateRectRgn(
it->bounds.x, it->bounds.y,
it->bounds.x + it->bounds.width,
it->bounds.y + it->bounds.height);
::CombineRgn(
draggable_region_, draggable_region_, region,
it->draggable ? RGN_OR : RGN_DIFF);
::DeleteObject(region);
}
// Subclass child window procedures in order to do hit-testing.
// This will be a no-op, if it is already subclassed.
if (hwnd_) {
WNDENUMPROC proc = !regions.empty() ?
SubclassWindowsProc : UnSubclassWindowsProc;
::EnumChildWindows(
hwnd_, proc, reinterpret_cast<LPARAM>(draggable_region_));
}
}
void RootWindowWin::NotifyDestroyedIfDone() {
// Notify once both the window and the browser have been destroyed.
if (window_destroyed_ && browser_destroyed_)

View File

@ -90,6 +90,8 @@ class RootWindowWin : public RootWindow,
void OnSetLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward) OVERRIDE;
void OnSetDraggableRegions(
const std::vector<CefDraggableRegion>& regions) OVERRIDE;
void NotifyDestroyedIfDone();
@ -106,6 +108,9 @@ class RootWindowWin : public RootWindow,
// Main window.
HWND hwnd_;
// Draggable region.
HRGN draggable_region_;
// Buttons.
HWND back_hwnd_;
HWND forward_hwnd_;
@ -115,7 +120,7 @@ class RootWindowWin : public RootWindow,
// URL text field.
HWND edit_hwnd_;
WNDPROC edit_wndproc_old_;
// Find dialog.
HWND find_hwnd_;
UINT find_message_id_;

View File

@ -0,0 +1,171 @@
// 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 this first to avoid type conflicts with CEF headers.
#include "tests/unittests/chromium_includes.h"
#include "include/wrapper/cef_closure_task.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "tests/unittests/test_handler.h"
namespace {
const char kTestURLWithRegions[] = "http://test.com/regions";
const char kTestHTMLWithRegions[] =
"<html>"
" <body>"
" <div style=\"position: absolute; top: 50px; left: 50px; width: 200px; "
"height: 200px; background-color: red; -webkit-app-region: drag;\">"
" <div style=\"position: absolute; top: 50%; left: 50%; "
"transform: translate(-50%, -50%); width: 50px; height: 50px; "
"background-color: blue; -webkit-app-region: no-drag;\">"
" </div>"
" </div>"
" </body>"
"</html>";
const char kTestURLWithoutRegions[] = "http://test.com/no-regions";
const char kTestHTMLWithoutRegions[] =
"<html><body>Hello World!</body></html>";
const char kTestURLWithChangingRegions[] = "http://test.com/changing-regions";
const char kTestHTMLWithChangingRegions[] =
"<html>"
" <body>"
" <div id=\"layer\" style=\"position: absolute; top: 50px; left: 50px; "
"width: 200px; height: 200px; background-color: red; "
"-webkit-app-region: drag;\">"
" <div style=\"position: absolute; top: 50%; left: 50%; "
"transform: translate(-50%, -50%); width: 50px; height: 50px; "
"background-color: blue; -webkit-app-region: no-drag;\">"
" </div>"
" </div>"
" <script>"
" window.setTimeout(function() {"
" var layer = document.getElementById('layer');"
" layer.style.top = '0px';"
" layer.style.left = '0px';"
" }, 500);"
" </script>"
" </body>"
"</html>";
class DraggableRegionsTestHandler : public TestHandler {
public:
DraggableRegionsTestHandler()
: step_(kStepWithRegions) {}
void RunTest() override {
// Add HTML documents with and without draggable regions.
AddResource(kTestURLWithRegions, kTestHTMLWithRegions, "text/html");
AddResource(kTestURLWithoutRegions, kTestHTMLWithoutRegions, "text/html");
AddResource(kTestURLWithChangingRegions, kTestHTMLWithChangingRegions,
"text/html");
// Create the browser
CreateBrowser(kTestURLWithRegions);
// Time out the test after a reasonable period of time.
SetTestTimeout();
}
void OnDraggableRegionsChanged(
CefRefPtr<CefBrowser> browser,
const std::vector<CefDraggableRegion>& regions) override {
EXPECT_TRUE(CefCurrentlyOn(TID_UI));
EXPECT_TRUE(browser->IsSame(GetBrowser()));
did_call_on_draggable_regions_changed_.yes();
switch (step_) {
case kStepWithRegions:
case kStepWithChangingRegions1:
EXPECT_EQ(2U, regions.size());
EXPECT_EQ(50, regions[0].bounds.x);
EXPECT_EQ(50, regions[0].bounds.y);
EXPECT_EQ(200, regions[0].bounds.width);
EXPECT_EQ(200, regions[0].bounds.height);
EXPECT_EQ(1, regions[0].draggable);
EXPECT_EQ(125, regions[1].bounds.x);
EXPECT_EQ(125, regions[1].bounds.y);
EXPECT_EQ(50, regions[1].bounds.width);
EXPECT_EQ(50, regions[1].bounds.height);
EXPECT_EQ(0, regions[1].draggable);
break;
case kStepWithChangingRegions2:
EXPECT_EQ(2U, regions.size());
EXPECT_EQ(0, regions[0].bounds.x);
EXPECT_EQ(0, regions[0].bounds.y);
EXPECT_EQ(200, regions[0].bounds.width);
EXPECT_EQ(200, regions[0].bounds.height);
EXPECT_EQ(1, regions[0].draggable);
EXPECT_EQ(75, regions[1].bounds.x);
EXPECT_EQ(75, regions[1].bounds.y);
EXPECT_EQ(50, regions[1].bounds.width);
EXPECT_EQ(50, regions[1].bounds.height);
EXPECT_EQ(0, regions[1].draggable);
break;
case kStepWithoutRegions:
// Should not be reached.
EXPECT_TRUE(false);
break;
}
NextTest(browser);
}
void DestroyTest() override {
EXPECT_EQ(false, did_call_on_draggable_regions_changed_);
TestHandler::DestroyTest();
}
private:
void NextTest(CefRefPtr<CefBrowser> browser) {
CefRefPtr<CefFrame> frame(browser->GetMainFrame());
did_call_on_draggable_regions_changed_.reset();
switch (step_) {
case kStepWithRegions:
step_ = kStepWithChangingRegions1;
frame->LoadURL(kTestURLWithChangingRegions);
break;
case kStepWithChangingRegions1:
step_ = kStepWithChangingRegions2;
break;
case kStepWithChangingRegions2:
step_ = kStepWithoutRegions;
frame->LoadURL(kTestURLWithoutRegions);
// Needed because this test doesn't call OnDraggableRegionsChanged.
CefPostDelayedTask(TID_UI,
base::Bind(&DraggableRegionsTestHandler::DestroyTest, this), 500);
break;
case kStepWithoutRegions: {
// Should not be reached.
EXPECT_TRUE(false);
break;
}
}
}
enum Step {
kStepWithRegions,
kStepWithChangingRegions1,
kStepWithChangingRegions2,
kStepWithoutRegions,
} step_;
TrackCallback did_call_on_draggable_regions_changed_;
};
} // namespace
// Verify that draggable regions work.
TEST(DraggableRegionsTest, DraggableRegions) {
CefRefPtr<DraggableRegionsTestHandler> handler =
new DraggableRegionsTestHandler();
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}

View File

@ -805,7 +805,7 @@ class OSRTestHandler : public RoutingTestHandler,
bool StartDragging(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDragData> drag_data,
DragOperationsMask allowed_ops,
CefRenderHandler::DragOperationsMask allowed_ops,
int x, int y) override {
if (test_type_ == OSR_TEST_DRAG_DROP_START_DRAGGING && started()) {
DestroySucceededTestSoon();

View File

@ -37,6 +37,7 @@ class TestHandler : public CefClient,
public CefDialogHandler,
public CefDisplayHandler,
public CefDownloadHandler,
public CefDragHandler,
public CefGeolocationHandler,
public CefJSDialogHandler,
public CefLifeSpanHandler,
@ -139,6 +140,9 @@ class TestHandler : public CefClient,
CefRefPtr<CefDownloadHandler> GetDownloadHandler() override {
return this;
}
CefRefPtr<CefDragHandler> GetDragHandler() override {
return this;
}
CefRefPtr<CefGeolocationHandler> GetGeolocationHandler() override {
return this;
}
@ -162,6 +166,11 @@ class TestHandler : public CefClient,
const CefString& suggested_name,
CefRefPtr<CefBeforeDownloadCallback> callback) override {}
// CefDragHandler methods
void OnDraggableRegionsChanged(
CefRefPtr<CefBrowser> browser,
const std::vector<CefDraggableRegion>& regions) override {}
// CefLifeSpanHandler methods
void OnAfterCreated(CefRefPtr<CefBrowser> browser) override;
void OnBeforeClose(CefRefPtr<CefBrowser> browser) override;

View File

@ -403,6 +403,7 @@ _simpletypes = {
'CefPoint' : ['cef_point_t', 'CefPoint()'],
'CefRect' : ['cef_rect_t', 'CefRect()'],
'CefSize' : ['cef_size_t', 'CefSize()'],
'CefDraggableRegion' : ['cef_draggable_region_t', 'CefDraggableRegion()'],
'CefPageRange' : ['cef_page_range_t', 'CefPageRange()'],
'CefThreadId' : ['cef_thread_id_t', 'TID_UI'],
'CefTime' : ['cef_time_t', 'CefTime()'],