Provide a generic JavaScript message router implementation (issue #1183).
git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@1574 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
parent
78bfefee5e
commit
0df95ca529
7
cef.gyp
7
cef.gyp
|
@ -400,6 +400,7 @@
|
|||
'tests/cefclient/client_switches.cpp',
|
||||
'tests/cefclient/client_switches.h',
|
||||
'tests/cefclient/res/osr_test.html',
|
||||
'tests/unittests/browser_info_map_unittest.cc',
|
||||
'tests/unittests/command_line_unittest.cc',
|
||||
'tests/unittests/cookie_unittest.cc',
|
||||
'tests/unittests/dialog_unittest.cc',
|
||||
|
@ -409,6 +410,7 @@
|
|||
'tests/unittests/geolocation_unittest.cc',
|
||||
'tests/unittests/jsdialog_unittest.cc',
|
||||
'tests/unittests/life_span_unittest.cc',
|
||||
'tests/unittests/message_router_unittest.cc',
|
||||
'tests/unittests/navigation_unittest.cc',
|
||||
'tests/unittests/os_rendering_unittest.cc',
|
||||
'tests/unittests/process_message_unittest.cc',
|
||||
|
@ -416,6 +418,8 @@
|
|||
'tests/unittests/request_handler_unittest.cc',
|
||||
'tests/unittests/request_unittest.cc',
|
||||
'tests/cefclient/resource_util.h',
|
||||
'tests/unittests/routing_test_handler.cc',
|
||||
'tests/unittests/routing_test_handler.h',
|
||||
'tests/unittests/run_all_unittests.cc',
|
||||
'tests/unittests/scheme_handler_unittest.cc',
|
||||
'tests/unittests/stream_unittest.cc',
|
||||
|
@ -1524,10 +1528,13 @@
|
|||
'tests/unittests/client_app_delegates.cc',
|
||||
'tests/unittests/cookie_unittest.cc',
|
||||
'tests/unittests/dom_unittest.cc',
|
||||
'tests/unittests/message_router_unittest.cc',
|
||||
'tests/unittests/navigation_unittest.cc',
|
||||
'tests/unittests/process_message_unittest.cc',
|
||||
'tests/unittests/request_handler_unittest.cc',
|
||||
'tests/unittests/request_unittest.cc',
|
||||
'tests/unittests/routing_test_handler.cc',
|
||||
'tests/unittests/routing_test_handler.h',
|
||||
'tests/unittests/scheme_handler_unittest.cc',
|
||||
'tests/unittests/urlrequest_unittest.cc',
|
||||
'tests/unittests/test_handler.cc',
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
],
|
||||
'includes_wrapper': [
|
||||
'include/wrapper/cef_byte_read_handler.h',
|
||||
'include/wrapper/cef_message_router.h',
|
||||
'include/wrapper/cef_stream_resource_handler.h',
|
||||
'include/wrapper/cef_xml_object.h',
|
||||
'include/wrapper/cef_zip_archive.h',
|
||||
|
@ -67,13 +68,16 @@
|
|||
],
|
||||
'libcef_dll_wrapper_sources_common': [
|
||||
'libcef_dll/cef_logging.h',
|
||||
'libcef_dll/cef_macros.h',
|
||||
'libcef_dll/cpptoc/base_cpptoc.h',
|
||||
'libcef_dll/cpptoc/cpptoc.h',
|
||||
'libcef_dll/ctocpp/base_ctocpp.h',
|
||||
'libcef_dll/ctocpp/ctocpp.h',
|
||||
'libcef_dll/transfer_util.cpp',
|
||||
'libcef_dll/transfer_util.h',
|
||||
'libcef_dll/wrapper/cef_browser_info_map.h',
|
||||
'libcef_dll/wrapper/cef_byte_read_handler.cc',
|
||||
'libcef_dll/wrapper/cef_message_router.cc',
|
||||
'libcef_dll/wrapper/cef_stream_resource_handler.cc',
|
||||
'libcef_dll/wrapper/cef_xml_object.cc',
|
||||
'libcef_dll/wrapper/cef_zip_archive.cc',
|
||||
|
|
|
@ -106,6 +106,18 @@ typedef uint32 cef_color_t;
|
|||
(static_cast<unsigned>(g) << 8) | \
|
||||
(static_cast<unsigned>(b) << 0))
|
||||
|
||||
// Return an int64 value with the specified low and high int32 component values.
|
||||
#define CefInt64Set(int32_low, int32_high) \
|
||||
static_cast<int64>((static_cast<uint32>(int32_low)) | \
|
||||
(static_cast<int64>(static_cast<int32>(int32_high))) << 32)
|
||||
|
||||
// Return the low int32 value from an int64 value.
|
||||
#define CefInt64GetLow(int64_val) static_cast<int32>(int64_val)
|
||||
// Return the high int32 value from an int64 value.
|
||||
#define CefInt64GetHigh(int64_val) \
|
||||
static_cast<int32>((static_cast<int64>(int64_val) >> 32) & 0xFFFFFFFFL)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,417 @@
|
|||
// Copyright (c) 2014 Marshall A. Greenblatt. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the name Chromium Embedded
|
||||
// Framework nor the names of its contributors may be used to endorse
|
||||
// or promote products derived from this software without specific prior
|
||||
// written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// The contents of this file are only available to applications that link
|
||||
// against the libcef_dll_wrapper target.
|
||||
//
|
||||
|
||||
#ifndef CEF_INCLUDE_WRAPPER_CEF_MESSAGE_ROUTER_H_
|
||||
#define CEF_INCLUDE_WRAPPER_CEF_MESSAGE_ROUTER_H_
|
||||
#pragma once
|
||||
|
||||
#include "include/cef_base.h"
|
||||
#include "include/cef_browser.h"
|
||||
#include "include/cef_process_message.h"
|
||||
#include "include/cef_v8.h"
|
||||
|
||||
// The below classes implement support for routing aynchronous messages between
|
||||
// JavaScript running in the renderer process and C++ running in the browser
|
||||
// process. An application interacts with the router by passing it data from
|
||||
// standard CEF C++ callbacks (OnBeforeBrowse, OnProcessMessageRecieved,
|
||||
// OnContextCreated, etc). The renderer-side router supports generic JavaScript
|
||||
// callback registration and execution while the browser-side router supports
|
||||
// application-specific logic via one or more application-provided Handler
|
||||
// instances.
|
||||
//
|
||||
// The renderer-side router implementation exposes a query function and a cancel
|
||||
// function via the JavaScript 'window' object:
|
||||
//
|
||||
// // Create and send a new query.
|
||||
// var request_id = window.cefQuery({
|
||||
// request: 'my_request',
|
||||
// persistent: false,
|
||||
// onSuccess: function(response) {},
|
||||
// onFailure: function(error_code, error_message) {}
|
||||
// });
|
||||
//
|
||||
// // Optionally cancel the query.
|
||||
// window.cefQueryCancel(request_id);
|
||||
//
|
||||
// When |window.cefQuery| is executed the request is sent asynchronously to one
|
||||
// or more C++ Handler objects registered in the browser process. Each C++
|
||||
// Handler can choose to either handle or ignore the query in the
|
||||
// Handler::OnQuery callback. If a Handler chooses to handle the query then it
|
||||
// should execute Callback::Success when a response is available or
|
||||
// Callback::Failure if an error occurs. This will result in asynchronous
|
||||
// execution of the associated JavaScript callback in the renderer process. Any
|
||||
// queries unhandled by C++ code in the browser process will be automatically
|
||||
// canceled and the associated JavaScript onFailure callback will be executed
|
||||
// with an error code of -1.
|
||||
//
|
||||
// Queries can be either persistent or non-persistent. If the query is
|
||||
// persistent than the callbacks will remain registered until one of the
|
||||
// following conditions are met:
|
||||
//
|
||||
// A. The query is canceled in JavaScript using the |window.cefQueryCancel|
|
||||
// function.
|
||||
// B. The query is canceled in C++ code using the Callback::Failure function.
|
||||
// C. The context associated with the query is released due to browser
|
||||
// destruction, navigation or renderer process termination.
|
||||
//
|
||||
// If the query is non-persistent then the registration will be removed after
|
||||
// the JavaScript callback is executed a single time. If a query is canceled for
|
||||
// a reason other than Callback::Failure being executed then the associated
|
||||
// Handler's OnQueryCanceled method will be called.
|
||||
//
|
||||
// Some possible usage patterns include:
|
||||
//
|
||||
// One-time Request. Use a non-persistent query to send a JavaScript request.
|
||||
// The Handler evaluates the request and returns the response. The query is
|
||||
// then discarded.
|
||||
//
|
||||
// Broadcast. Use a persistent query to register as a JavaScript broadcast
|
||||
// receiver. The Handler keeps track of all registered Callbacks and executes
|
||||
// them sequentially to deliver the broadcast message.
|
||||
//
|
||||
// Subscription. Use a persistent query to register as a JavaScript subscription
|
||||
// receiver. The Handler initiates the subscription feed on the first request
|
||||
// and delivers responses to all registered subscribers as they become
|
||||
// available. The Handler cancels the subscription feed when there are no
|
||||
// longer any registered JavaScript receivers.
|
||||
//
|
||||
// Message routing occurs on a per-browser and per-context basis. Consequently,
|
||||
// additional application logic can be applied by restricting which browser or
|
||||
// context instances are passed into the router. If you choose to use this
|
||||
// approach do so cautiously. In order for the router to function correctly any
|
||||
// browser or context instance passed into a single router callback must then
|
||||
// be passed into all router callbacks.
|
||||
//
|
||||
// There is generally no need to have multiple renderer-side routers unless you
|
||||
// wish to have multiple bindings with different JavaScript function names. It
|
||||
// can be useful to have multiple browser-side routers with different client-
|
||||
// provided Handler instances when implementing different behaviors on a per-
|
||||
// browser basis.
|
||||
//
|
||||
// This implementation places no formatting restrictions on payload content.
|
||||
// An application may choose to exchange anything from simple formatted
|
||||
// strings to serialized XML or JSON data.
|
||||
//
|
||||
//
|
||||
// EXAMPLE USAGE
|
||||
//
|
||||
// 1. Define the router configuration. You can optionally specify settings
|
||||
// like the JavaScript function names. The configuration must be the same in
|
||||
// both the browser and renderer processes. If using multiple routers in the
|
||||
// same application make sure to specify unique function names for each
|
||||
// router configuration.
|
||||
//
|
||||
// // Example config object showing the default values.
|
||||
// CefMessageRouterConfig config;
|
||||
// config.js_query_function = "cefQuery";
|
||||
// config.js_cancel_function = "cefQueryCancel";
|
||||
//
|
||||
// 2. Create an instance of CefMessageRouterBrowserSide in the browser process.
|
||||
// You might choose to make it a member of your CefClient implementation,
|
||||
// for example.
|
||||
//
|
||||
// browser_side_router_ = CefMessageRouterBrowserSide::Create(config);
|
||||
//
|
||||
// 3. Register one or more Handlers. The Handler instances must either outlive
|
||||
// the router or be removed from the router before they're deleted.
|
||||
//
|
||||
// browser_side_router_->AddHandler(my_handler);
|
||||
//
|
||||
// 4. Call all required CefMessageRouterBrowserSide methods from other callbacks
|
||||
// in your CefClient implementation (OnBeforeClose, etc). See the
|
||||
// CefMessageRouterBrowserSide class documentation for the complete list of
|
||||
// methods.
|
||||
//
|
||||
// 5. Create an instance of CefMessageRouterRendererSide in the renderer process.
|
||||
// You might choose to make it a member of your CefApp implementation, for
|
||||
// example.
|
||||
//
|
||||
// renderer_side_router_ = CefMessageRouterRendererSide::Create(config);
|
||||
//
|
||||
// 6. Call all required CefMessageRouterRendererSide methods from other
|
||||
// callbacks in your CefRenderProcessHandler implementation
|
||||
// (OnContextCreated, etc). See the CefMessageRouterRendererSide class
|
||||
// documentation for the complete list of methods.
|
||||
//
|
||||
// 7. Execute the query function from JavaScript code.
|
||||
//
|
||||
// window.cefQuery({request: 'my_request',
|
||||
// persistent: false,
|
||||
// onSuccess: function(response) { print(response); },
|
||||
// onFailure: function(error_code, error_message) {} });
|
||||
//
|
||||
// 8. Handle the query in your Handler::OnQuery implementation and execute the
|
||||
// appropriate callback either immediately or asynchronously.
|
||||
//
|
||||
// void MyHandler::OnQuery(int64 query_id,
|
||||
// CefRefPtr<CefBrowser> browser,
|
||||
// CefRefPtr<CefFrame> frame,
|
||||
// const CefString& request,
|
||||
// bool persistent,
|
||||
// CefRefPtr<Callback> callback) {
|
||||
// if (request == "my_request") {
|
||||
// callback->Continue("my_response");
|
||||
// return true;
|
||||
// }
|
||||
// return false; // Not handled.
|
||||
// }
|
||||
//
|
||||
// 9. Notice that the onSuccess callback is executed in JavaScript.
|
||||
|
||||
///
|
||||
// Used to configure the query router. The same values must be passed to both
|
||||
// CefMessageRouterBrowserSide and CefMessageRouterRendererSide. If using multiple
|
||||
// router pairs make sure to choose values that do not conflict.
|
||||
///
|
||||
struct CefMessageRouterConfig {
|
||||
CefMessageRouterConfig();
|
||||
|
||||
// Name of the JavaScript function that will be added to the 'window' object
|
||||
// for sending a query. The default value is "cefQuery".
|
||||
CefString js_query_function;
|
||||
|
||||
// Name of the JavaScript function that will be added to the 'window' object
|
||||
// for canceling a pending query. The default value is "cefQueryCancel".
|
||||
CefString js_cancel_function;
|
||||
};
|
||||
|
||||
///
|
||||
// Implements the browser side of query routing. The methods of this class may
|
||||
// be called on any browser process thread unless otherwise indicated.
|
||||
///
|
||||
class CefMessageRouterBrowserSide : public CefBase {
|
||||
public:
|
||||
///
|
||||
// Callback associated with a single pending asynchronous query. Execute the
|
||||
// Success or Failure method to send an asynchronous response to the
|
||||
// associated JavaScript handler. It is a runtime error to destroy a Callback
|
||||
// object associated with an uncanceled query without first executing one of
|
||||
// the callback methods. The methods of this class may be called on any
|
||||
// browser process thread.
|
||||
///
|
||||
class Callback : public CefBase {
|
||||
public:
|
||||
///
|
||||
// Notify the associated JavaScript onSuccess callback that the query has
|
||||
// completed successfully with the specified |response|.
|
||||
///
|
||||
virtual void Success(const CefString& response) =0;
|
||||
|
||||
///
|
||||
// Notify the associated JavaScript onFailure callback that the query has
|
||||
// failed with the specified |error_code| and |error_message|.
|
||||
///
|
||||
virtual void Failure(int error_code, const CefString& error_message) =0;
|
||||
};
|
||||
|
||||
///
|
||||
// Implement this interface to handle queries. All methods will be executed on
|
||||
// the browser process UI thread.
|
||||
///
|
||||
class Handler {
|
||||
public:
|
||||
typedef CefMessageRouterBrowserSide::Callback Callback;
|
||||
|
||||
///
|
||||
// Executed when a new query is received. |query_id| uniquely identifies the
|
||||
// query for the life span of the router. Return true to handle the query
|
||||
// or false to propagate the query to other registered handlers, if any. If
|
||||
// no handlers return true from this method then the query will be
|
||||
// automatically canceled with an error code of -1 delivered to the
|
||||
// JavaScript onFailure callback. If this method returns true then a
|
||||
// Callback method must be executed either in this method or asynchronously
|
||||
// to complete the query.
|
||||
///
|
||||
virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int64 query_id,
|
||||
const CefString& request,
|
||||
bool persistent,
|
||||
CefRefPtr<Callback> callback) {
|
||||
return false;
|
||||
}
|
||||
|
||||
///
|
||||
// Executed when a query has been canceled either explicitly using the
|
||||
// JavaScript cancel function or implicitly due to browser destruction,
|
||||
// navigation or renderer process termination. It will only be called for
|
||||
// the single handler that returned true from OnQuery for the same
|
||||
// |query_id|. No references to the associated Callback object should be
|
||||
// kept after this method is called, nor should any Callback methods be
|
||||
// executed.
|
||||
///
|
||||
virtual void OnQueryCanceled(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int64 query_id) {}
|
||||
|
||||
virtual ~Handler() {}
|
||||
};
|
||||
|
||||
///
|
||||
// Create a new router with the specified configuration.
|
||||
///
|
||||
static CefRefPtr<CefMessageRouterBrowserSide> Create(
|
||||
const CefMessageRouterConfig& config);
|
||||
|
||||
///
|
||||
// Add a new query handler. If |first| is true it will be added as the first
|
||||
// handler, otherwise it will be added as the last handler. Returns true if
|
||||
// the handler is added successfully or false if the handler has already been
|
||||
// added. Must be called on the browser process UI thread. The Handler object
|
||||
// must either outlive the router or be removed before deletion.
|
||||
///
|
||||
virtual bool AddHandler(Handler* handler, bool first) =0;
|
||||
|
||||
///
|
||||
// Remove an existing query handler. Any pending queries associated with the
|
||||
// handler will be canceled. Handler::OnQueryCanceled will be called and the
|
||||
// associated JavaScript onFailure callback will be executed with an error
|
||||
// code of -1. Returns true if the handler is removed successfully or false
|
||||
// if the handler is not found. Must be called on the browser process UI
|
||||
// thread.
|
||||
///
|
||||
virtual bool RemoveHandler(Handler* handler) =0;
|
||||
|
||||
///
|
||||
// Cancel all pending queries associated with either |browser| or |handler|.
|
||||
// If both |browser| and |handler| are NULL all pending queries will be
|
||||
// canceled. Handler::OnQueryCanceled will be called and the associated
|
||||
// JavaScript onFailure callback will be executed in all cases with an error
|
||||
// code of -1.
|
||||
///
|
||||
virtual void CancelPending(CefRefPtr<CefBrowser> browser,
|
||||
Handler* handler) =0;
|
||||
|
||||
///
|
||||
// Returns the number of queries currently pending for the specified |browser|
|
||||
// and/or |handler|. Either or both values may be empty. Must be called on the
|
||||
// browser process UI thread.
|
||||
///
|
||||
virtual int GetPendingCount(CefRefPtr<CefBrowser> browser,
|
||||
Handler* handler) =0;
|
||||
|
||||
|
||||
// The below methods should be called from other CEF handlers. They must be
|
||||
// called exactly as documented for the router to function correctly.
|
||||
|
||||
///
|
||||
// Call from CefLifeSpanHandler::OnBeforeClose. Any pending queries associated
|
||||
// with |browser| will be canceled and Handler::OnQueryCanceled will be called.
|
||||
// No JavaScript callbacks will be executed since this indicates destruction
|
||||
// of the browser.
|
||||
///
|
||||
virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) =0;
|
||||
|
||||
///
|
||||
// Call from CefRequestHandler::OnRenderProcessTerminated. Any pending queries
|
||||
// associated with |browser| will be canceled and Handler::OnQueryCanceled
|
||||
// will be called. No JavaScript callbacks will be executed since this
|
||||
// indicates destruction of the context.
|
||||
///
|
||||
virtual void OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser) =0;
|
||||
|
||||
///
|
||||
// Call from CefRequestHandler::OnBeforeBrowse only if the navigation is
|
||||
// allowed to proceed. If |frame| is the main frame then any pending queries
|
||||
// associated with |browser| will be canceled and Handler::OnQueryCanceled
|
||||
// will be called. No JavaScript callbacks will be executed since this
|
||||
// indicates destruction of the context.
|
||||
///
|
||||
virtual void OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame) =0;
|
||||
|
||||
///
|
||||
// Call from CefClient::OnProcessMessageReceived. Returns true if the message
|
||||
// is handled by this router or false otherwise.
|
||||
///
|
||||
virtual bool OnProcessMessageReceived(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) =0;
|
||||
};
|
||||
|
||||
///
|
||||
// Implements the renderer side of query routing. The methods of this class must
|
||||
// be called on the render process main thread.
|
||||
///
|
||||
class CefMessageRouterRendererSide : public CefBase {
|
||||
public:
|
||||
virtual ~CefMessageRouterRendererSide() {}
|
||||
|
||||
///
|
||||
// Create a new router with the specified configuration.
|
||||
///
|
||||
static CefRefPtr<CefMessageRouterRendererSide> Create(
|
||||
const CefMessageRouterConfig& config);
|
||||
|
||||
///
|
||||
// Returns the number of queries currently pending for the specified |browser|
|
||||
// and/or |context|. Either or both values may be empty.
|
||||
///
|
||||
virtual int GetPendingCount(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefV8Context> context) =0;
|
||||
|
||||
|
||||
// The below methods should be called from other CEF handlers. They must be
|
||||
// called exactly as documented for the router to function correctly.
|
||||
|
||||
///
|
||||
// Call from CefRenderProcessHandler::OnContextCreated. Registers the
|
||||
// JavaScripts functions with the new context.
|
||||
///
|
||||
virtual void OnContextCreated(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Context> context) =0;
|
||||
|
||||
///
|
||||
// Call from CefRenderProcessHandler::OnContextReleased. Any pending queries
|
||||
// associated with the released context will be canceled and
|
||||
// Handler::OnQueryCanceled will be called in the browser process.
|
||||
///
|
||||
virtual void OnContextReleased(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Context> context) =0;
|
||||
|
||||
///
|
||||
// Call from CefRenderProcessHandler::OnProcessMessageReceived. Returns true
|
||||
// if the message is handled by this router or false otherwise.
|
||||
///
|
||||
virtual bool OnProcessMessageReceived(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) =0;
|
||||
};
|
||||
|
||||
#endif // CEF_INCLUDE_WRAPPER_CEF_MESSAGE_ROUTER_H_
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2009 The Chromium Embedded Framework Authors. All rights
|
||||
// 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.
|
||||
|
||||
|
@ -6,17 +6,28 @@
|
|||
#define CEF_LIBCEF_DLL_CEF_LOGGING_H_
|
||||
#pragma once
|
||||
|
||||
#include "include/cef_task.h"
|
||||
|
||||
#ifdef BUILDING_CEF_SHARED
|
||||
#include "base/logging.h"
|
||||
#else
|
||||
#else // !BUILDING_CEF_SHARED
|
||||
#include <assert.h> // NOLINT(build/include_order)
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define DCHECK(condition) assert(condition)
|
||||
#else
|
||||
#define DCHECK(condition) ((void)0)
|
||||
#endif
|
||||
|
||||
#define DCHECK_EQ(val1, val2) DCHECK(val1 == val2)
|
||||
#define DCHECK_NE(val1, val2) DCHECK(val1 != val2)
|
||||
#define DCHECK_LE(val1, val2) DCHECK(val1 <= val2)
|
||||
#define DCHECK_LT(val1, val2) DCHECK(val1 < val2)
|
||||
#define DCHECK_GE(val1, val2) DCHECK(val1 >= val2)
|
||||
#define DCHECK_GT(val1, val2) DCHECK(val1 > val2)
|
||||
#endif
|
||||
#endif // !BUILDING_CEF_SHARED
|
||||
|
||||
#define CEF_REQUIRE_UI_THREAD() DCHECK(CefCurrentlyOn(TID_UI));
|
||||
#define CEF_REQUIRE_RENDERER_THREAD() DCHECK(CefCurrentlyOn(TID_RENDERER));
|
||||
|
||||
#endif // CEF_LIBCEF_DLL_CEF_LOGGING_H_
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
// 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.
|
||||
|
||||
#ifndef CEF_LIBCEF_DLL_CEF_MACROS_H_
|
||||
#define CEF_LIBCEF_DLL_CEF_MACROS_H_
|
||||
#pragma once
|
||||
|
||||
#ifdef BUILDING_CEF_SHARED
|
||||
#include "base/macros.h"
|
||||
#else // !BUILDING_CEF_SHARED
|
||||
|
||||
// A macro to disallow the copy constructor and operator= functions
|
||||
// This should be used in the private: declarations for a class
|
||||
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
||||
TypeName(const TypeName&); \
|
||||
void operator=(const TypeName&)
|
||||
|
||||
#endif // !BUILDING_CEF_SHARED
|
||||
|
||||
#endif // CEF_LIBCEF_DLL_CEF_MACROS_H_
|
||||
// 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.
|
||||
|
||||
#ifndef CEF_LIBCEF_DLL_CEF_MACROS_H_
|
||||
#define CEF_LIBCEF_DLL_CEF_MACROS_H_
|
||||
#pragma once
|
||||
|
||||
#ifdef BUILDING_CEF_SHARED
|
||||
#include "base/macros.h"
|
||||
#else // !BUILDING_CEF_SHARED
|
||||
|
||||
// A macro to disallow the copy constructor and operator= functions
|
||||
// This should be used in the private: declarations for a class
|
||||
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
||||
TypeName(const TypeName&); \
|
||||
void operator=(const TypeName&)
|
||||
|
||||
#endif // !BUILDING_CEF_SHARED
|
||||
|
||||
#endif // CEF_LIBCEF_DLL_CEF_MACROS_H_
|
|
@ -0,0 +1,264 @@
|
|||
// 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.
|
||||
|
||||
#ifndef CEF_LIBCEF_DLL_WRAPPER_CEF_BROWSER_INFO_MAP_H_
|
||||
#define CEF_LIBCEF_DLL_WRAPPER_CEF_BROWSER_INFO_MAP_H_
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include "libcef_dll/cef_logging.h"
|
||||
#include "libcef_dll/cef_macros.h"
|
||||
|
||||
// Default traits for CefBrowserInfoMap. Override to provide different object
|
||||
// destruction behavior.
|
||||
template<typename ObjectType>
|
||||
struct DefaultCefBrowserInfoMapTraits {
|
||||
static void Destruct(ObjectType info) {
|
||||
delete info;
|
||||
}
|
||||
};
|
||||
|
||||
// Maps an arbitrary IdType to an arbitrary ObjectType on a per-browser basis.
|
||||
template <typename IdType,
|
||||
typename ObjectType,
|
||||
typename Traits = DefaultCefBrowserInfoMapTraits<ObjectType> >
|
||||
class CefBrowserInfoMap {
|
||||
public:
|
||||
// Implement this interface to visit and optionally delete objects in the map.
|
||||
class Visitor {
|
||||
public:
|
||||
typedef IdType InfoIdType;
|
||||
typedef ObjectType InfoObjectType;
|
||||
|
||||
// Called once for each info object. Set |remove| to true to remove the
|
||||
// object from the map. It is safe to destruct removed objects in this
|
||||
// callback. Return true to continue iterating or false to stop iterating.
|
||||
virtual bool OnNextInfo(int browser_id,
|
||||
InfoIdType info_id,
|
||||
InfoObjectType info,
|
||||
bool* remove) =0;
|
||||
|
||||
protected:
|
||||
virtual ~Visitor() {}
|
||||
};
|
||||
|
||||
CefBrowserInfoMap() {}
|
||||
|
||||
~CefBrowserInfoMap() {
|
||||
clear();
|
||||
}
|
||||
|
||||
// Add an object associated with the specified ID values.
|
||||
void Add(int browser_id, IdType info_id, ObjectType info) {
|
||||
InfoMap* info_map = NULL;
|
||||
typename BrowserInfoMap::const_iterator it_browser =
|
||||
browser_info_map_.find(browser_id);
|
||||
if (it_browser == browser_info_map_.end()) {
|
||||
// No InfoMap exists for the browser ID so create it.
|
||||
info_map = new InfoMap;
|
||||
browser_info_map_.insert(std::make_pair(browser_id, info_map));
|
||||
} else {
|
||||
info_map = it_browser->second;
|
||||
// The specified ID should not already exist in the map.
|
||||
DCHECK_EQ(info_map->find(info_id), info_map->end());
|
||||
}
|
||||
|
||||
info_map->insert(std::make_pair(info_id, info));
|
||||
}
|
||||
|
||||
// Find the object with the specified ID values. |visitor| can optionally be
|
||||
// used to evaluate or remove the object at the same time. If the object is
|
||||
// removed using the Visitor the caller is responsible for destroying it.
|
||||
ObjectType Find(int browser_id, IdType info_id, Visitor* vistor) {
|
||||
if (browser_info_map_.empty())
|
||||
return ObjectType();
|
||||
|
||||
typename BrowserInfoMap::iterator it_browser =
|
||||
browser_info_map_.find(browser_id);
|
||||
if (it_browser == browser_info_map_.end())
|
||||
return ObjectType();
|
||||
|
||||
InfoMap* info_map = it_browser->second;
|
||||
typename InfoMap::iterator it_info = info_map->find(info_id);
|
||||
if (it_info == info_map->end())
|
||||
return ObjectType();
|
||||
|
||||
ObjectType info = it_info->second;
|
||||
|
||||
bool remove = false;
|
||||
if (vistor)
|
||||
vistor->OnNextInfo(browser_id, it_info->first, info, &remove);
|
||||
if (remove) {
|
||||
info_map->erase(it_info);
|
||||
|
||||
if (info_map->empty()) {
|
||||
// No more entries in the InfoMap so remove it.
|
||||
browser_info_map_.erase(it_browser);
|
||||
delete info_map;
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
// Find all objects. If any objects are removed using the Visitor the caller
|
||||
// is responsible for destroying them.
|
||||
void FindAll(Visitor* visitor) {
|
||||
DCHECK(visitor);
|
||||
|
||||
if (browser_info_map_.empty())
|
||||
return;
|
||||
|
||||
bool remove, keepgoing;
|
||||
|
||||
typename BrowserInfoMap::iterator it_browser = browser_info_map_.begin();
|
||||
while (it_browser != browser_info_map_.end()) {
|
||||
InfoMap* info_map = it_browser->second;
|
||||
|
||||
typename InfoMap::iterator it_info = info_map->begin();
|
||||
while (it_info != info_map->end()) {
|
||||
remove = false;
|
||||
keepgoing = visitor->OnNextInfo(it_browser->first, it_info->first,
|
||||
it_info->second, &remove);
|
||||
|
||||
if (remove)
|
||||
info_map->erase(it_info++);
|
||||
else
|
||||
++it_info;
|
||||
|
||||
if (!keepgoing)
|
||||
break;
|
||||
}
|
||||
|
||||
if (info_map->empty()) {
|
||||
// No more entries in the InfoMap so remove it.
|
||||
browser_info_map_.erase(it_browser++);
|
||||
delete info_map;
|
||||
} else {
|
||||
++it_browser;
|
||||
}
|
||||
|
||||
if (!keepgoing)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Find all objects associated with the specified browser. If any objects are
|
||||
// removed using the Visitor the caller is responsible for destroying them.
|
||||
void FindAll(int browser_id, Visitor* visitor) {
|
||||
DCHECK(visitor);
|
||||
|
||||
if (browser_info_map_.empty())
|
||||
return;
|
||||
|
||||
typename BrowserInfoMap::iterator it_browser =
|
||||
browser_info_map_.find(browser_id);
|
||||
if (it_browser == browser_info_map_.end())
|
||||
return;
|
||||
|
||||
InfoMap* info_map = it_browser->second;
|
||||
bool remove, keepgoing;
|
||||
|
||||
typename InfoMap::iterator it_info = info_map->begin();
|
||||
while (it_info != info_map->end()) {
|
||||
remove = false;
|
||||
keepgoing = visitor->OnNextInfo(browser_id, it_info->first,
|
||||
it_info->second, &remove);
|
||||
|
||||
if (remove)
|
||||
info_map->erase(it_info++);
|
||||
else
|
||||
++it_info;
|
||||
|
||||
if (!keepgoing)
|
||||
break;
|
||||
}
|
||||
|
||||
if (info_map->empty()) {
|
||||
// No more entries in the InfoMap so remove it.
|
||||
browser_info_map_.erase(it_browser);
|
||||
delete info_map;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if the map is empty.
|
||||
bool empty() const { return browser_info_map_.empty(); }
|
||||
|
||||
// Returns the number of objects in the map.
|
||||
size_t size() const {
|
||||
if (browser_info_map_.empty())
|
||||
return 0;
|
||||
|
||||
size_t size = 0;
|
||||
typename BrowserInfoMap::const_iterator it_browser =
|
||||
browser_info_map_.begin();
|
||||
for (; it_browser != browser_info_map_.end(); ++it_browser)
|
||||
size += it_browser->second->size();
|
||||
return size;
|
||||
}
|
||||
|
||||
// Returns the number of objects in the map that are associated with the
|
||||
// specified browser.
|
||||
size_t size(int browser_id) const {
|
||||
if (browser_info_map_.empty())
|
||||
return 0;
|
||||
|
||||
typename BrowserInfoMap::const_iterator it_browser =
|
||||
browser_info_map_.find(browser_id);
|
||||
if (it_browser != browser_info_map_.end())
|
||||
return it_browser->second->size();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Remove all objects from the map. The objects will be destructed.
|
||||
void clear() {
|
||||
if (browser_info_map_.empty())
|
||||
return;
|
||||
|
||||
typename BrowserInfoMap::const_iterator it_browser =
|
||||
browser_info_map_.begin();
|
||||
for (; it_browser != browser_info_map_.end(); ++it_browser) {
|
||||
InfoMap* info_map = it_browser->second;
|
||||
typename InfoMap::const_iterator it_info = info_map->begin();
|
||||
for (; it_info != info_map->end(); ++it_info)
|
||||
Traits::Destruct(it_info->second);
|
||||
delete info_map;
|
||||
}
|
||||
browser_info_map_.clear();
|
||||
}
|
||||
|
||||
// Remove all objects from the map that are associated with the specified
|
||||
// browser. The objects will be destructed.
|
||||
void clear(int browser_id) {
|
||||
if (browser_info_map_.empty())
|
||||
return;
|
||||
|
||||
typename BrowserInfoMap::iterator it_browser =
|
||||
browser_info_map_.find(browser_id);
|
||||
if (it_browser == browser_info_map_.end())
|
||||
return;
|
||||
|
||||
InfoMap* info_map = it_browser->second;
|
||||
typename InfoMap::const_iterator it_info = info_map->begin();
|
||||
for (; it_info != info_map->end(); ++it_info)
|
||||
Traits::Destruct(it_info->second);
|
||||
|
||||
browser_info_map_.erase(it_browser);
|
||||
delete info_map;
|
||||
}
|
||||
|
||||
private:
|
||||
// Map IdType to ObjectType instance.
|
||||
typedef std::map<IdType, ObjectType> InfoMap;
|
||||
// Map browser ID to InfoMap instance.
|
||||
typedef std::map<int, InfoMap*> BrowserInfoMap;
|
||||
|
||||
BrowserInfoMap browser_info_map_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CefBrowserInfoMap);
|
||||
};
|
||||
|
||||
|
||||
#endif // CEF_LIBCEF_DLL_WRAPPER_CEF_BROWSER_INFO_MAP_H_
|
File diff suppressed because it is too large
Load Diff
|
@ -13,54 +13,43 @@ namespace binding_test {
|
|||
|
||||
namespace {
|
||||
|
||||
const char* kMessageName = "binding_test";
|
||||
const char kTestUrl[] = "http://tests/binding";
|
||||
const char kTestMessageName[] = "BindingTest";
|
||||
|
||||
// Handle messages in the browser process.
|
||||
class ProcessMessageDelegate : public ClientHandler::ProcessMessageDelegate {
|
||||
class Handler : public CefMessageRouterBrowserSide::Handler {
|
||||
public:
|
||||
ProcessMessageDelegate() {
|
||||
}
|
||||
Handler() {}
|
||||
|
||||
// From ClientHandler::ProcessMessageDelegate.
|
||||
virtual bool OnProcessMessageReceived(
|
||||
CefRefPtr<ClientHandler> handler,
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) OVERRIDE {
|
||||
std::string message_name = message->GetName();
|
||||
if (message_name == kMessageName) {
|
||||
// Handle the message.
|
||||
std::string result;
|
||||
|
||||
CefRefPtr<CefListValue> args = message->GetArgumentList();
|
||||
if (args->GetSize() > 0 && args->GetType(0) == VTYPE_STRING) {
|
||||
// Our result is a reverse of the original message.
|
||||
result = args->GetString(0);
|
||||
std::reverse(result.begin(), result.end());
|
||||
} else {
|
||||
result = "Invalid request";
|
||||
}
|
||||
|
||||
// Send the result back to the render process.
|
||||
CefRefPtr<CefProcessMessage> response =
|
||||
CefProcessMessage::Create(kMessageName);
|
||||
response->GetArgumentList()->SetString(0, result);
|
||||
browser->SendProcessMessage(PID_RENDERER, response);
|
||||
// Called due to cefQuery execution in binding.html.
|
||||
virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int64 query_id,
|
||||
const CefString& request,
|
||||
bool persistent,
|
||||
CefRefPtr<Callback> callback) OVERRIDE {
|
||||
// Only handle messages from the test URL.
|
||||
const std::string& url = frame->GetURL();
|
||||
if (url.find(kTestUrl) != 0)
|
||||
return false;
|
||||
|
||||
const std::string& message_name = request;
|
||||
if (message_name.find(kTestMessageName) == 0) {
|
||||
// Reverse the string and return.
|
||||
std::string result = message_name.substr(sizeof(kTestMessageName));
|
||||
std::reverse(result.begin(), result.end());
|
||||
callback->Success(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
IMPLEMENT_REFCOUNTING(ProcessMessageDelegate);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void CreateProcessMessageDelegates(
|
||||
ClientHandler::ProcessMessageDelegateSet& delegates) {
|
||||
delegates.insert(new ProcessMessageDelegate);
|
||||
void CreateMessageHandlers(ClientHandler::MessageHandlerSet& handlers) {
|
||||
handlers.insert(new Handler());
|
||||
}
|
||||
|
||||
} // namespace binding_test
|
||||
|
|
|
@ -10,9 +10,8 @@
|
|||
|
||||
namespace binding_test {
|
||||
|
||||
// Delegate creation. Called from ClientHandler.
|
||||
void CreateProcessMessageDelegates(
|
||||
ClientHandler::ProcessMessageDelegateSet& delegates);
|
||||
// Handler creation. Called from ClientHandler.
|
||||
void CreateMessageHandlers(ClientHandler::MessageHandlerSet& handlers);
|
||||
|
||||
} // namespace binding_test
|
||||
|
||||
|
|
|
@ -14,201 +14,21 @@
|
|||
#include "include/cef_v8.h"
|
||||
#include "util.h" // NOLINT(build/include)
|
||||
|
||||
namespace {
|
||||
|
||||
// Forward declarations.
|
||||
void SetList(CefRefPtr<CefV8Value> source, CefRefPtr<CefListValue> target);
|
||||
void SetList(CefRefPtr<CefListValue> source, CefRefPtr<CefV8Value> target);
|
||||
|
||||
// Transfer a V8 value to a List index.
|
||||
void SetListValue(CefRefPtr<CefListValue> list, int index,
|
||||
CefRefPtr<CefV8Value> value) {
|
||||
if (value->IsArray()) {
|
||||
CefRefPtr<CefListValue> new_list = CefListValue::Create();
|
||||
SetList(value, new_list);
|
||||
list->SetList(index, new_list);
|
||||
} else if (value->IsString()) {
|
||||
list->SetString(index, value->GetStringValue());
|
||||
} else if (value->IsBool()) {
|
||||
list->SetBool(index, value->GetBoolValue());
|
||||
} else if (value->IsInt()) {
|
||||
list->SetInt(index, value->GetIntValue());
|
||||
} else if (value->IsDouble()) {
|
||||
list->SetDouble(index, value->GetDoubleValue());
|
||||
}
|
||||
}
|
||||
|
||||
// Transfer a V8 array to a List.
|
||||
void SetList(CefRefPtr<CefV8Value> source, CefRefPtr<CefListValue> target) {
|
||||
ASSERT(source->IsArray());
|
||||
|
||||
int arg_length = source->GetArrayLength();
|
||||
if (arg_length == 0)
|
||||
return;
|
||||
|
||||
// Start with null types in all spaces.
|
||||
target->SetSize(arg_length);
|
||||
|
||||
for (int i = 0; i < arg_length; ++i)
|
||||
SetListValue(target, i, source->GetValue(i));
|
||||
}
|
||||
|
||||
// Transfer a List value to a V8 array index.
|
||||
void SetListValue(CefRefPtr<CefV8Value> list, int index,
|
||||
CefRefPtr<CefListValue> value) {
|
||||
CefRefPtr<CefV8Value> new_value;
|
||||
|
||||
CefValueType type = value->GetType(index);
|
||||
switch (type) {
|
||||
case VTYPE_LIST: {
|
||||
CefRefPtr<CefListValue> list = value->GetList(index);
|
||||
new_value = CefV8Value::CreateArray(static_cast<int>(list->GetSize()));
|
||||
SetList(list, new_value);
|
||||
} break;
|
||||
case VTYPE_BOOL:
|
||||
new_value = CefV8Value::CreateBool(value->GetBool(index));
|
||||
break;
|
||||
case VTYPE_DOUBLE:
|
||||
new_value = CefV8Value::CreateDouble(value->GetDouble(index));
|
||||
break;
|
||||
case VTYPE_INT:
|
||||
new_value = CefV8Value::CreateInt(value->GetInt(index));
|
||||
break;
|
||||
case VTYPE_STRING:
|
||||
new_value = CefV8Value::CreateString(value->GetString(index));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (new_value.get()) {
|
||||
list->SetValue(index, new_value);
|
||||
} else {
|
||||
list->SetValue(index, CefV8Value::CreateNull());
|
||||
}
|
||||
}
|
||||
|
||||
// Transfer a List to a V8 array.
|
||||
void SetList(CefRefPtr<CefListValue> source, CefRefPtr<CefV8Value> target) {
|
||||
ASSERT(target->IsArray());
|
||||
|
||||
int arg_length = static_cast<int>(source->GetSize());
|
||||
if (arg_length == 0)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < arg_length; ++i)
|
||||
SetListValue(target, i, source);
|
||||
}
|
||||
|
||||
|
||||
// Handles the native implementation for the client_app extension.
|
||||
class ClientAppExtensionHandler : public CefV8Handler {
|
||||
public:
|
||||
explicit ClientAppExtensionHandler(CefRefPtr<ClientApp> client_app)
|
||||
: client_app_(client_app) {
|
||||
}
|
||||
|
||||
virtual bool Execute(const CefString& name,
|
||||
CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception) {
|
||||
bool handled = false;
|
||||
|
||||
if (name == "sendMessage") {
|
||||
// Send a message to the browser process.
|
||||
if ((arguments.size() == 1 || arguments.size() == 2) &&
|
||||
arguments[0]->IsString()) {
|
||||
CefRefPtr<CefBrowser> browser =
|
||||
CefV8Context::GetCurrentContext()->GetBrowser();
|
||||
ASSERT(browser.get());
|
||||
|
||||
CefString name = arguments[0]->GetStringValue();
|
||||
if (!name.empty()) {
|
||||
CefRefPtr<CefProcessMessage> message =
|
||||
CefProcessMessage::Create(name);
|
||||
|
||||
// Translate the arguments, if any.
|
||||
if (arguments.size() == 2 && arguments[1]->IsArray())
|
||||
SetList(arguments[1], message->GetArgumentList());
|
||||
|
||||
browser->SendProcessMessage(PID_BROWSER, message);
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
} else if (name == "setMessageCallback") {
|
||||
// Set a message callback.
|
||||
if (arguments.size() == 2 && arguments[0]->IsString() &&
|
||||
arguments[1]->IsFunction()) {
|
||||
std::string name = arguments[0]->GetStringValue();
|
||||
CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
|
||||
int browser_id = context->GetBrowser()->GetIdentifier();
|
||||
client_app_->SetMessageCallback(name, browser_id, context,
|
||||
arguments[1]);
|
||||
handled = true;
|
||||
}
|
||||
} else if (name == "removeMessageCallback") {
|
||||
// Remove a message callback.
|
||||
if (arguments.size() == 1 && arguments[0]->IsString()) {
|
||||
std::string name = arguments[0]->GetStringValue();
|
||||
CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
|
||||
int browser_id = context->GetBrowser()->GetIdentifier();
|
||||
bool removed = client_app_->RemoveMessageCallback(name, browser_id);
|
||||
retval = CefV8Value::CreateBool(removed);
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!handled)
|
||||
exception = "Invalid method arguments";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
CefRefPtr<ClientApp> client_app_;
|
||||
|
||||
IMPLEMENT_REFCOUNTING(ClientAppExtensionHandler);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
ClientApp::ClientApp() {
|
||||
CreateBrowserDelegates(browser_delegates_);
|
||||
CreateRenderDelegates(render_delegates_);
|
||||
}
|
||||
|
||||
void ClientApp::OnRegisterCustomSchemes(
|
||||
CefRefPtr<CefSchemeRegistrar> registrar) {
|
||||
// Default schemes that support cookies.
|
||||
cookieable_schemes_.push_back("http");
|
||||
cookieable_schemes_.push_back("https");
|
||||
}
|
||||
|
||||
void ClientApp::SetMessageCallback(const std::string& message_name,
|
||||
int browser_id,
|
||||
CefRefPtr<CefV8Context> context,
|
||||
CefRefPtr<CefV8Value> function) {
|
||||
ASSERT(CefCurrentlyOn(TID_RENDERER));
|
||||
|
||||
callback_map_.insert(
|
||||
std::make_pair(std::make_pair(message_name, browser_id),
|
||||
std::make_pair(context, function)));
|
||||
}
|
||||
|
||||
bool ClientApp::RemoveMessageCallback(const std::string& message_name,
|
||||
int browser_id) {
|
||||
ASSERT(CefCurrentlyOn(TID_RENDERER));
|
||||
|
||||
CallbackMap::iterator it =
|
||||
callback_map_.find(std::make_pair(message_name, browser_id));
|
||||
if (it != callback_map_.end()) {
|
||||
callback_map_.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
RegisterCustomSchemes(registrar, cookieable_schemes_);
|
||||
}
|
||||
|
||||
void ClientApp::OnContextInitialized() {
|
||||
CreateBrowserDelegates(browser_delegates_);
|
||||
|
||||
// Register cookieable schemes with the global cookie manager.
|
||||
CefRefPtr<CefCookieManager> manager = CefCookieManager::GetGlobalManager();
|
||||
ASSERT(manager.get());
|
||||
|
@ -234,34 +54,14 @@ void ClientApp::OnRenderProcessThreadCreated(
|
|||
}
|
||||
|
||||
void ClientApp::OnRenderThreadCreated(CefRefPtr<CefListValue> extra_info) {
|
||||
CreateRenderDelegates(render_delegates_);
|
||||
|
||||
RenderDelegateSet::iterator it = render_delegates_.begin();
|
||||
for (; it != render_delegates_.end(); ++it)
|
||||
(*it)->OnRenderThreadCreated(this, extra_info);
|
||||
}
|
||||
|
||||
void ClientApp::OnWebKitInitialized() {
|
||||
// Register the client_app extension.
|
||||
std::string app_code =
|
||||
"var app;"
|
||||
"if (!app)"
|
||||
" app = {};"
|
||||
"(function() {"
|
||||
" app.sendMessage = function(name, arguments) {"
|
||||
" native function sendMessage();"
|
||||
" return sendMessage(name, arguments);"
|
||||
" };"
|
||||
" app.setMessageCallback = function(name, callback) {"
|
||||
" native function setMessageCallback();"
|
||||
" return setMessageCallback(name, callback);"
|
||||
" };"
|
||||
" app.removeMessageCallback = function(name) {"
|
||||
" native function removeMessageCallback();"
|
||||
" return removeMessageCallback(name);"
|
||||
" };"
|
||||
"})();";
|
||||
CefRegisterExtension("v8/app", app_code,
|
||||
new ClientAppExtensionHandler(this));
|
||||
|
||||
RenderDelegateSet::iterator it = render_delegates_.begin();
|
||||
for (; it != render_delegates_.end(); ++it)
|
||||
(*it)->OnWebKitInitialized(this);
|
||||
|
@ -281,7 +81,6 @@ void ClientApp::OnBrowserDestroyed(CefRefPtr<CefBrowser> browser) {
|
|||
|
||||
CefRefPtr<CefLoadHandler> ClientApp::GetLoadHandler() {
|
||||
CefRefPtr<CefLoadHandler> load_handler;
|
||||
|
||||
RenderDelegateSet::iterator it = render_delegates_.begin();
|
||||
for (; it != render_delegates_.end() && !load_handler.get(); ++it)
|
||||
load_handler = (*it)->GetLoadHandler(this);
|
||||
|
@ -319,18 +118,6 @@ void ClientApp::OnContextReleased(CefRefPtr<CefBrowser> browser,
|
|||
RenderDelegateSet::iterator it = render_delegates_.begin();
|
||||
for (; it != render_delegates_.end(); ++it)
|
||||
(*it)->OnContextReleased(this, browser, frame, context);
|
||||
|
||||
// Remove any JavaScript callbacks registered for the context that has been
|
||||
// released.
|
||||
if (!callback_map_.empty()) {
|
||||
CallbackMap::iterator it = callback_map_.begin();
|
||||
for (; it != callback_map_.end();) {
|
||||
if (it->second.first->IsSame(context))
|
||||
callback_map_.erase(it++);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClientApp::OnUncaughtException(CefRefPtr<CefBrowser> browser,
|
||||
|
@ -367,47 +154,5 @@ bool ClientApp::OnProcessMessageReceived(
|
|||
message);
|
||||
}
|
||||
|
||||
if (handled)
|
||||
return true;
|
||||
|
||||
// Execute the registered JavaScript callback if any.
|
||||
if (!callback_map_.empty()) {
|
||||
CefString message_name = message->GetName();
|
||||
CallbackMap::const_iterator it = callback_map_.find(
|
||||
std::make_pair(message_name.ToString(),
|
||||
browser->GetIdentifier()));
|
||||
if (it != callback_map_.end()) {
|
||||
// Keep a local reference to the objects. The callback may remove itself
|
||||
// from the callback map.
|
||||
CefRefPtr<CefV8Context> context = it->second.first;
|
||||
CefRefPtr<CefV8Value> callback = it->second.second;
|
||||
|
||||
// Enter the context.
|
||||
context->Enter();
|
||||
|
||||
CefV8ValueList arguments;
|
||||
|
||||
// First argument is the message name.
|
||||
arguments.push_back(CefV8Value::CreateString(message_name));
|
||||
|
||||
// Second argument is the list of message arguments.
|
||||
CefRefPtr<CefListValue> list = message->GetArgumentList();
|
||||
CefRefPtr<CefV8Value> args =
|
||||
CefV8Value::CreateArray(static_cast<int>(list->GetSize()));
|
||||
SetList(list, args);
|
||||
arguments.push_back(args);
|
||||
|
||||
// Execute the callback.
|
||||
CefRefPtr<CefV8Value> retval = callback->ExecuteFunction(NULL, arguments);
|
||||
if (retval.get()) {
|
||||
if (retval->IsBool())
|
||||
handled = retval->GetBoolValue();
|
||||
}
|
||||
|
||||
// Exit the context.
|
||||
context->Exit();
|
||||
}
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
|
|
@ -103,22 +103,6 @@ class ClientApp : public CefApp,
|
|||
|
||||
ClientApp();
|
||||
|
||||
// Set a JavaScript callback for the specified |message_name| and |browser_id|
|
||||
// combination. Will automatically be removed when the associated context is
|
||||
// released. Callbacks can also be set in JavaScript using the
|
||||
// app.setMessageCallback function.
|
||||
void SetMessageCallback(const std::string& message_name,
|
||||
int browser_id,
|
||||
CefRefPtr<CefV8Context> context,
|
||||
CefRefPtr<CefV8Value> function);
|
||||
|
||||
// Removes the JavaScript callback for the specified |message_name| and
|
||||
// |browser_id| combination. Returns true if a callback was removed. Callbacks
|
||||
// can also be removed in JavaScript using the app.removeMessageCallback
|
||||
// function.
|
||||
bool RemoveMessageCallback(const std::string& message_name,
|
||||
int browser_id);
|
||||
|
||||
private:
|
||||
// Creates all of the BrowserDelegate objects. Implemented in
|
||||
// client_app_delegates.
|
||||
|
@ -134,9 +118,7 @@ class ClientApp : public CefApp,
|
|||
|
||||
// CefApp methods.
|
||||
virtual void OnRegisterCustomSchemes(
|
||||
CefRefPtr<CefSchemeRegistrar> registrar) OVERRIDE {
|
||||
RegisterCustomSchemes(registrar, cookieable_schemes_);
|
||||
}
|
||||
CefRefPtr<CefSchemeRegistrar> registrar) OVERRIDE;
|
||||
virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler()
|
||||
OVERRIDE { return this; }
|
||||
virtual CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler()
|
||||
|
@ -181,19 +163,14 @@ class ClientApp : public CefApp,
|
|||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) OVERRIDE;
|
||||
|
||||
// Map of message callbacks.
|
||||
typedef std::map<std::pair<std::string, int>,
|
||||
std::pair<CefRefPtr<CefV8Context>, CefRefPtr<CefV8Value> > >
|
||||
CallbackMap;
|
||||
CallbackMap callback_map_;
|
||||
|
||||
// Set of supported BrowserDelegates.
|
||||
// Set of supported BrowserDelegates. Only used in the browser process.
|
||||
BrowserDelegateSet browser_delegates_;
|
||||
|
||||
// Set of supported RenderDelegates.
|
||||
// Set of supported RenderDelegates. Only used in the renderer process.
|
||||
RenderDelegateSet render_delegates_;
|
||||
|
||||
// Schemes that will be registered with the global cookie manager.
|
||||
// Schemes that will be registered with the global cookie manager. Used in
|
||||
// both the browser and renderer process.
|
||||
std::vector<CefString> cookieable_schemes_;
|
||||
|
||||
IMPLEMENT_REFCOUNTING(ClientApp);
|
||||
|
|
|
@ -98,7 +98,15 @@ ClientHandler::ClientHandler()
|
|||
m_StopHwnd(NULL),
|
||||
m_ReloadHwnd(NULL),
|
||||
m_bFocusOnEditableField(false) {
|
||||
CreateProcessMessageDelegates(process_message_delegates_);
|
||||
// Create the browser-side router for query handling.
|
||||
CefMessageRouterConfig config;
|
||||
message_router_ = CefMessageRouterBrowserSide::Create(config);
|
||||
|
||||
// Register handlers with the router.
|
||||
CreateMessageHandlers(message_handler_set_);
|
||||
MessageHandlerSet::const_iterator it = message_handler_set_.begin();
|
||||
for (; it != message_handler_set_.end(); ++it)
|
||||
message_router_->AddHandler(*(it), false);
|
||||
|
||||
// Read command line settings.
|
||||
CefRefPtr<CefCommandLine> command_line =
|
||||
|
@ -120,6 +128,11 @@ bool ClientHandler::OnProcessMessageReceived(
|
|||
CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) {
|
||||
if (message_router_->OnProcessMessageReceived(browser, source_process,
|
||||
message)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for messages from the client renderer.
|
||||
std::string message_name = message->GetName();
|
||||
if (message_name == client_renderer::kFocusedNodeChangedMessage) {
|
||||
|
@ -131,16 +144,7 @@ bool ClientHandler::OnProcessMessageReceived(
|
|||
return true;
|
||||
}
|
||||
|
||||
bool handled = false;
|
||||
|
||||
// Execute delegate callbacks.
|
||||
ProcessMessageDelegateSet::iterator it = process_message_delegates_.begin();
|
||||
for (; it != process_message_delegates_.end() && !handled; ++it) {
|
||||
handled = (*it)->OnProcessMessageReceived(this, browser, source_process,
|
||||
message);
|
||||
}
|
||||
|
||||
return handled;
|
||||
return false;
|
||||
}
|
||||
|
||||
void ClientHandler::OnBeforeContextMenu(
|
||||
|
@ -343,6 +347,8 @@ bool ClientHandler::DoClose(CefRefPtr<CefBrowser> browser) {
|
|||
void ClientHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
|
||||
REQUIRE_UI_THREAD();
|
||||
|
||||
message_router_->OnBeforeClose(browser);
|
||||
|
||||
if (m_BrowserId == browser->GetIdentifier()) {
|
||||
// Free the browser pointer so that the browser can be destroyed
|
||||
m_Browser = NULL;
|
||||
|
@ -363,7 +369,17 @@ void ClientHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
|
|||
}
|
||||
|
||||
if (--m_BrowserCount == 0) {
|
||||
// All browser windows have closed. Quit the application message loop.
|
||||
// All browser windows have closed.
|
||||
// Remove and delete message router handlers.
|
||||
MessageHandlerSet::const_iterator it = message_handler_set_.begin();
|
||||
for (; it != message_handler_set_.end(); ++it) {
|
||||
message_router_->RemoveHandler(*(it));
|
||||
delete *(it);
|
||||
}
|
||||
message_handler_set_.clear();
|
||||
message_router_ = NULL;
|
||||
|
||||
// Quit the application message loop.
|
||||
AppQuitMessageLoop();
|
||||
}
|
||||
}
|
||||
|
@ -412,10 +428,18 @@ void ClientHandler::OnLoadError(CefRefPtr<CefBrowser> browser,
|
|||
frame->LoadString(ss.str(), failedUrl);
|
||||
}
|
||||
|
||||
bool ClientHandler::OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefRequest> request,
|
||||
bool is_redirect) {
|
||||
message_router_->OnBeforeBrowse(browser, frame);
|
||||
return false;
|
||||
}
|
||||
|
||||
CefRefPtr<CefResourceHandler> ClientHandler::GetResourceHandler(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefRequest> request) {
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefRequest> request) {
|
||||
std::string url = request->GetURL();
|
||||
if (url.find(kTestOrigin) == 0) {
|
||||
// Handle URLs in the test origin.
|
||||
|
@ -469,6 +493,8 @@ void ClientHandler::OnProtocolExecution(CefRefPtr<CefBrowser> browser,
|
|||
|
||||
void ClientHandler::OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser,
|
||||
TerminationStatus status) {
|
||||
message_router_->OnRenderProcessTerminated(browser);
|
||||
|
||||
// Load the startup URL if that's not the website that we terminated on.
|
||||
CefRefPtr<CefFrame> frame = browser->GetMainFrame();
|
||||
std::string url = frame->GetURL();
|
||||
|
@ -693,16 +719,15 @@ bool ClientHandler::Save(const std::string& path, const std::string& data) {
|
|||
}
|
||||
|
||||
// static
|
||||
void ClientHandler::CreateProcessMessageDelegates(
|
||||
ProcessMessageDelegateSet& delegates) {
|
||||
// Create the binding test delegates.
|
||||
binding_test::CreateProcessMessageDelegates(delegates);
|
||||
void ClientHandler::CreateMessageHandlers(MessageHandlerSet& handlers) {
|
||||
// Create the dialog test handlers.
|
||||
dialog_test::CreateMessageHandlers(handlers);
|
||||
|
||||
// Create the dialog test delegates.
|
||||
dialog_test::CreateProcessMessageDelegates(delegates);
|
||||
// Create the binding test handlers.
|
||||
binding_test::CreateMessageHandlers(handlers);
|
||||
|
||||
// Create the window test delegates.
|
||||
window_test::CreateProcessMessageDelegates(delegates);
|
||||
// Create the window test handlers.
|
||||
window_test::CreateMessageHandlers(handlers);
|
||||
}
|
||||
|
||||
void ClientHandler::BuildTestMenu(CefRefPtr<CefMenuModel> model) {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <set>
|
||||
#include <string>
|
||||
#include "include/cef_client.h"
|
||||
#include "include/wrapper/cef_message_router.h"
|
||||
#include "cefclient/util.h"
|
||||
|
||||
|
||||
|
@ -32,32 +33,14 @@ class ClientHandler : public CefClient,
|
|||
public CefRenderHandler,
|
||||
public CefRequestHandler {
|
||||
public:
|
||||
// Interface for process message delegates. Do not perform work in the
|
||||
// RenderDelegate constructor.
|
||||
class ProcessMessageDelegate : public virtual CefBase {
|
||||
public:
|
||||
// Called when a process message is received. Return true if the message was
|
||||
// handled and should not be passed on to other handlers.
|
||||
// ProcessMessageDelegates should check for unique message names to avoid
|
||||
// interfering with each other.
|
||||
virtual bool OnProcessMessageReceived(
|
||||
CefRefPtr<ClientHandler> handler,
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::set<CefRefPtr<ProcessMessageDelegate> >
|
||||
ProcessMessageDelegateSet;
|
||||
|
||||
// Interface implemented to handle off-screen rendering.
|
||||
class RenderHandler : public CefRenderHandler {
|
||||
public:
|
||||
virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) =0;
|
||||
};
|
||||
|
||||
typedef std::set<CefMessageRouterBrowserSide::Handler*> MessageHandlerSet;
|
||||
|
||||
ClientHandler();
|
||||
virtual ~ClientHandler();
|
||||
|
||||
|
@ -174,6 +157,10 @@ class ClientHandler : public CefClient,
|
|||
const CefString& failedUrl) OVERRIDE;
|
||||
|
||||
// CefRequestHandler methods
|
||||
virtual bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefRequest> request,
|
||||
bool is_redirect) OVERRIDE;
|
||||
virtual CefRefPtr<CefResourceHandler> GetResourceHandler(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
|
@ -264,9 +251,9 @@ class ClientHandler : public CefClient,
|
|||
void SetLoading(bool isLoading);
|
||||
void SetNavState(bool canGoBack, bool canGoForward);
|
||||
|
||||
// Create all of ProcessMessageDelegate objects.
|
||||
static void CreateProcessMessageDelegates(
|
||||
ProcessMessageDelegateSet& delegates);
|
||||
// Create all CefMessageRouterBrowserSide::Handler objects. They will be
|
||||
// deleted when the ClientHandler is destroyed.
|
||||
static void CreateMessageHandlers(MessageHandlerSet& handlers);
|
||||
|
||||
// Test context menu creation.
|
||||
void BuildTestMenu(CefRefPtr<CefMenuModel> model);
|
||||
|
@ -317,15 +304,19 @@ class ClientHandler : public CefClient,
|
|||
// True if an editable field currently has focus.
|
||||
bool m_bFocusOnEditableField;
|
||||
|
||||
// Registered delegates.
|
||||
ProcessMessageDelegateSet process_message_delegates_;
|
||||
|
||||
// The startup URL.
|
||||
std::string m_StartupURL;
|
||||
|
||||
// True if mouse cursor change is disabled.
|
||||
bool m_bMouseCursorChangeDisabled;
|
||||
|
||||
// Handles the browser side of query routing. The renderer side is handled
|
||||
// in client_renderer.cpp.
|
||||
CefRefPtr<CefMessageRouterBrowserSide> message_router_;
|
||||
|
||||
// Set of Handlers registered with the message router.
|
||||
MessageHandlerSet message_handler_set_;
|
||||
|
||||
// Number of currently existing browser windows. The application will exit
|
||||
// when the number of windows reaches 0.
|
||||
static int m_BrowserCount;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <string>
|
||||
|
||||
#include "include/cef_dom.h"
|
||||
#include "include/wrapper/cef_message_router.h"
|
||||
#include "cefclient/util.h"
|
||||
|
||||
namespace client_renderer {
|
||||
|
@ -22,6 +23,26 @@ class ClientRenderDelegate : public ClientApp::RenderDelegate {
|
|||
: last_node_is_editable_(false) {
|
||||
}
|
||||
|
||||
virtual void OnWebKitInitialized(CefRefPtr<ClientApp> app) OVERRIDE {
|
||||
// Create the renderer-side router for query handling.
|
||||
CefMessageRouterConfig config;
|
||||
message_router_ = CefMessageRouterRendererSide::Create(config);
|
||||
}
|
||||
|
||||
virtual void OnContextCreated(CefRefPtr<ClientApp> app,
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Context> context) OVERRIDE {
|
||||
message_router_->OnContextCreated(browser, frame, context);
|
||||
}
|
||||
|
||||
virtual void OnContextReleased(CefRefPtr<ClientApp> app,
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Context> context) OVERRIDE {
|
||||
message_router_->OnContextReleased(browser, frame, context);
|
||||
}
|
||||
|
||||
virtual void OnFocusedNodeChanged(CefRefPtr<ClientApp> app,
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
|
@ -37,9 +58,21 @@ class ClientRenderDelegate : public ClientApp::RenderDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
virtual bool OnProcessMessageReceived(
|
||||
CefRefPtr<ClientApp> app,
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) OVERRIDE {
|
||||
return message_router_->OnProcessMessageReceived(
|
||||
browser, source_process, message);
|
||||
}
|
||||
|
||||
private:
|
||||
bool last_node_is_editable_;
|
||||
|
||||
// Handles the renderer side of query routing.
|
||||
CefRefPtr<CefMessageRouterRendererSide> message_router_;
|
||||
|
||||
IMPLEMENT_REFCOUNTING(ClientRenderDelegate);
|
||||
};
|
||||
|
||||
|
|
|
@ -11,54 +11,54 @@ namespace dialog_test {
|
|||
|
||||
namespace {
|
||||
|
||||
const char* kTestUrl = "http://tests/dialogs";
|
||||
const char* kFileOpenMessageName = "DialogTest.FileOpen";
|
||||
const char* kFileOpenMultipleMessageName = "DialogTest.FileOpenMultiple";
|
||||
const char* kFileSaveMessageName = "DialogTest.FileSave";
|
||||
const char kTestUrl[] = "http://tests/dialogs";
|
||||
const char kFileOpenMessageName[] = "DialogTest.FileOpen";
|
||||
const char kFileOpenMultipleMessageName[] = "DialogTest.FileOpenMultiple";
|
||||
const char kFileSaveMessageName[] = "DialogTest.FileSave";
|
||||
|
||||
class RunFileDialogCallback : public CefRunFileDialogCallback {
|
||||
// Callback executed when the file dialog is dismissed.
|
||||
class DialogCallback : public CefRunFileDialogCallback {
|
||||
public:
|
||||
explicit RunFileDialogCallback(const std::string& message_name)
|
||||
: message_name_(message_name) {
|
||||
explicit DialogCallback(
|
||||
CefRefPtr<CefMessageRouterBrowserSide::Callback> router_callback)
|
||||
: router_callback_(router_callback) {
|
||||
}
|
||||
|
||||
virtual void OnFileDialogDismissed(
|
||||
CefRefPtr<CefBrowserHost> browser_host,
|
||||
const std::vector<CefString>& file_paths) OVERRIDE {
|
||||
// Send a message back to the render process with the same name and the list
|
||||
// of file paths.
|
||||
CefRefPtr<CefProcessMessage> message =
|
||||
CefProcessMessage::Create(message_name_);
|
||||
CefRefPtr<CefListValue> args = message->GetArgumentList();
|
||||
CefRefPtr<CefListValue> val = CefListValue::Create();
|
||||
for (int i = 0; i < static_cast<int>(file_paths.size()); ++i)
|
||||
val->SetString(i, file_paths[i]);
|
||||
args->SetList(0, val);
|
||||
// Send a message back to the render process with the list of file paths.
|
||||
std::string response;
|
||||
for (int i = 0; i < static_cast<int>(file_paths.size()); ++i) {
|
||||
if (!response.empty())
|
||||
response += "|"; // Use a delimiter disallowed in file paths.
|
||||
response += file_paths[i];
|
||||
}
|
||||
|
||||
// This will result in a call to the callback registered via JavaScript in
|
||||
// dialogs.html.
|
||||
browser_host->GetBrowser()->SendProcessMessage(PID_RENDERER, message);
|
||||
router_callback_->Success(response);
|
||||
router_callback_ = NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string message_name_;
|
||||
CefRefPtr<CefMessageRouterBrowserSide::Callback> router_callback_;
|
||||
|
||||
IMPLEMENT_REFCOUNTING(RunFileDialogCallback);
|
||||
IMPLEMENT_REFCOUNTING(DialogCallback);
|
||||
};
|
||||
|
||||
// Handle messages in the browser process.
|
||||
class ProcessMessageDelegate : public ClientHandler::ProcessMessageDelegate {
|
||||
class Handler : public CefMessageRouterBrowserSide::Handler {
|
||||
public:
|
||||
ProcessMessageDelegate() {
|
||||
}
|
||||
Handler() {}
|
||||
|
||||
// From ClientHandler::ProcessMessageDelegate.
|
||||
virtual bool OnProcessMessageReceived(
|
||||
CefRefPtr<ClientHandler> handler,
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) OVERRIDE {
|
||||
std::string url = browser->GetMainFrame()->GetURL();
|
||||
// Called due to cefQuery execution in dialogs.html.
|
||||
virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int64 query_id,
|
||||
const CefString& request,
|
||||
bool persistent,
|
||||
CefRefPtr<Callback> callback) OVERRIDE {
|
||||
// Only handle messages from the test URL.
|
||||
const std::string& url = frame->GetURL();
|
||||
if (url.find(kTestUrl) != 0)
|
||||
return false;
|
||||
|
||||
|
@ -68,35 +68,31 @@ class ProcessMessageDelegate : public ClientHandler::ProcessMessageDelegate {
|
|||
file_types.push_back(".log");
|
||||
file_types.push_back(".patch");
|
||||
|
||||
std::string message_name = message->GetName();
|
||||
CefRefPtr<DialogCallback> dialog_callback(new DialogCallback(callback));
|
||||
|
||||
const std::string& message_name = request;
|
||||
if (message_name == kFileOpenMessageName) {
|
||||
browser->GetHost()->RunFileDialog(FILE_DIALOG_OPEN, "My Open Dialog",
|
||||
"test.txt", file_types, new RunFileDialogCallback(message_name));
|
||||
return true;
|
||||
"test.txt", file_types, dialog_callback.get());
|
||||
} else if (message_name == kFileOpenMultipleMessageName) {
|
||||
browser->GetHost()->RunFileDialog(FILE_DIALOG_OPEN_MULTIPLE,
|
||||
"My Open Multiple Dialog", CefString(), file_types,
|
||||
new RunFileDialogCallback(message_name));
|
||||
return true;
|
||||
dialog_callback.get());
|
||||
} else if (message_name == kFileSaveMessageName) {
|
||||
browser->GetHost()->RunFileDialog(FILE_DIALOG_SAVE, "My Save Dialog",
|
||||
"test.txt", file_types, new RunFileDialogCallback(message_name));
|
||||
return true;
|
||||
"test.txt", file_types, dialog_callback.get());
|
||||
} else {
|
||||
ASSERT(false); // Not reached.
|
||||
}
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
IMPLEMENT_REFCOUNTING(ProcessMessageDelegate);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void CreateProcessMessageDelegates(
|
||||
ClientHandler::ProcessMessageDelegateSet& delegates) {
|
||||
delegates.insert(new ProcessMessageDelegate);
|
||||
void CreateMessageHandlers(ClientHandler::MessageHandlerSet& handlers) {
|
||||
handlers.insert(new Handler());
|
||||
}
|
||||
|
||||
} // namespace dialog_test
|
||||
|
|
|
@ -10,9 +10,8 @@
|
|||
|
||||
namespace dialog_test {
|
||||
|
||||
// Delegate creation. Called from ClientHandler.
|
||||
void CreateProcessMessageDelegates(
|
||||
ClientHandler::ProcessMessageDelegateSet& delegates);
|
||||
/// Handler creation. Called from ClientHandler.
|
||||
void CreateMessageHandlers(ClientHandler::MessageHandlerSet& handlers);
|
||||
|
||||
} // namespace dialog_test
|
||||
|
||||
|
|
|
@ -3,15 +3,16 @@
|
|||
<title>Binding Test</title>
|
||||
<script language="JavaScript">
|
||||
|
||||
// Register the callback for messages from the browser process.
|
||||
app.setMessageCallback('binding_test', function(name, args) {
|
||||
document.getElementById('result').value = "Response: "+args[0];
|
||||
});
|
||||
|
||||
// Send a message to the browser process.
|
||||
// Send a query to the browser process.
|
||||
function sendMessage() {
|
||||
var msg = document.getElementById("message").value;
|
||||
app.sendMessage('binding_test', [msg]);
|
||||
// Results in a call to the OnQuery method in binding_test.cpp
|
||||
window.cefQuery({
|
||||
request: 'BindingTest:' + document.getElementById("message").value,
|
||||
onSuccess: function(response) {
|
||||
document.getElementById('result').value = 'Response: '+response;
|
||||
},
|
||||
onFailure: function(error_code, error_message) {}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -35,14 +35,14 @@ function show_file_dialog(element, test) {
|
|||
var message = 'DialogTest.' + test;
|
||||
var target = document.getElementById(element);
|
||||
|
||||
// Register for the callback from OnFileDialogDismissed in dialog_test.cpp.
|
||||
app.setMessageCallback(message, function(msg, paths) {
|
||||
target.innerText = paths.join();
|
||||
app.removeMessageCallback(message);
|
||||
// Results in a call to the OnQuery method in dialog_test.cpp
|
||||
window.cefQuery({
|
||||
request: message,
|
||||
onSuccess: function(response) {
|
||||
target.innerText = response;
|
||||
},
|
||||
onFailure: function(error_code, error_message) {}
|
||||
});
|
||||
|
||||
// This will result in a call to OnProcessMessageReceived in dialog_test.cpp.
|
||||
app.sendMessage(message);
|
||||
}
|
||||
|
||||
window.addEventListener('load', setup, false);
|
||||
|
|
|
@ -8,10 +8,6 @@
|
|||
#LI11select {width: 75px;}
|
||||
</style>
|
||||
<script>
|
||||
function sendBrowserMessage(paramString) {
|
||||
app.sendMessage("osrtest", [paramString]);
|
||||
}
|
||||
|
||||
function getElement(id) { return document.getElementById(id); }
|
||||
function makeH1Red() { getElement('LI00').style.color='red'; }
|
||||
function makeH1Black() { getElement('LI00').style.color='black'; }
|
||||
|
@ -22,12 +18,13 @@
|
|||
}
|
||||
|
||||
function onEventTest(event) {
|
||||
var param = event.type;
|
||||
var param = 'osr' + event.type;
|
||||
|
||||
if (event.type == "click")
|
||||
param += event.button;
|
||||
|
||||
sendBrowserMessage(param);
|
||||
// Results in a call to the OnQuery method in os_rendering_unittest.cc.
|
||||
window.testQuery({request: param});
|
||||
}
|
||||
|
||||
</script>
|
||||
|
|
|
@ -3,8 +3,12 @@
|
|||
<title>Window Test</title>
|
||||
<script>
|
||||
function send_message(test, params) {
|
||||
// This will result in a call to OnProcessMessageReceived in window_test.cpp.
|
||||
app.sendMessage('WindowTest.' + test, params);
|
||||
var message = 'WindowTest.' + test;
|
||||
if (typeof params != 'undefined')
|
||||
message += ':' + params;
|
||||
|
||||
// Results in a call to the OnQuery method in window_test.cpp.
|
||||
window.cefQuery({'request' : message});
|
||||
}
|
||||
|
||||
function minimize() {
|
||||
|
@ -28,7 +32,7 @@ function position() {
|
|||
if (isNaN(x) || isNaN(y) || isNaN(width) || isNaN(height))
|
||||
alert('Please specify a valid numeric value.');
|
||||
else
|
||||
send_message('Position', [x, y, width, height]);
|
||||
send_message('Position', x + ',' + y + ',' + width + ',' + height);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
#include "cefclient/window_test.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "include/wrapper/cef_stream_resource_handler.h"
|
||||
|
||||
|
@ -13,56 +15,66 @@ namespace window_test {
|
|||
|
||||
namespace {
|
||||
|
||||
const char* kMessagePositionName = "WindowTest.Position";
|
||||
const char* kMessageMinimizeName = "WindowTest.Minimize";
|
||||
const char* kMessageMaximizeName = "WindowTest.Maximize";
|
||||
const char* kMessageRestoreName = "WindowTest.Restore";
|
||||
const char kTestUrl[] = "http://tests/window";
|
||||
const char kMessagePositionName[] = "WindowTest.Position";
|
||||
const char kMessageMinimizeName[] = "WindowTest.Minimize";
|
||||
const char kMessageMaximizeName[] = "WindowTest.Maximize";
|
||||
const char kMessageRestoreName[] = "WindowTest.Restore";
|
||||
|
||||
// Handle messages in the browser process.
|
||||
class ProcessMessageDelegate : public ClientHandler::ProcessMessageDelegate {
|
||||
class Handler : public CefMessageRouterBrowserSide::Handler {
|
||||
public:
|
||||
ProcessMessageDelegate() {
|
||||
}
|
||||
Handler() {}
|
||||
|
||||
// From ClientHandler::ProcessMessageDelegate.
|
||||
virtual bool OnProcessMessageReceived(
|
||||
CefRefPtr<ClientHandler> handler,
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) OVERRIDE {
|
||||
std::string message_name = message->GetName();
|
||||
if (message_name == kMessagePositionName) {
|
||||
CefRefPtr<CefListValue> args = message->GetArgumentList();
|
||||
if (args->GetSize() >= 4) {
|
||||
int x = args->GetInt(0);
|
||||
int y = args->GetInt(1);
|
||||
int width = args->GetInt(2);
|
||||
int height = args->GetInt(3);
|
||||
SetPos(browser->GetHost()->GetWindowHandle(), x, y, width, height);
|
||||
// Called due to cefBroadcast execution in window.html.
|
||||
virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int64 query_id,
|
||||
const CefString& request,
|
||||
bool persistent,
|
||||
CefRefPtr<Callback> callback) OVERRIDE {
|
||||
// Only handle messages from the test URL.
|
||||
const std::string& url = frame->GetURL();
|
||||
if (url.find(kTestUrl) != 0)
|
||||
return false;
|
||||
|
||||
const std::string& message_name = request;
|
||||
if (message_name.find(kMessagePositionName) == 0) {
|
||||
// Parse the comma-delimited list of integer values.
|
||||
std::vector<int> vec;
|
||||
const std::string& vals =
|
||||
message_name.substr(sizeof(kMessagePositionName));
|
||||
std::stringstream ss(vals);
|
||||
int i;
|
||||
while (ss >> i) {
|
||||
vec.push_back(i);
|
||||
if (ss.peek() == ',')
|
||||
ss.ignore();
|
||||
}
|
||||
|
||||
if (vec.size() == 4) {
|
||||
SetPos(browser->GetHost()->GetWindowHandle(),
|
||||
vec[0], vec[1], vec[2], vec[3]);
|
||||
}
|
||||
return true;
|
||||
} else if (message_name == kMessageMinimizeName) {
|
||||
Minimize(browser->GetHost()->GetWindowHandle());
|
||||
return true;
|
||||
} else if (message_name == kMessageMaximizeName) {
|
||||
Maximize(browser->GetHost()->GetWindowHandle());
|
||||
return true;
|
||||
} else if (message_name == kMessageRestoreName) {
|
||||
Restore(browser->GetHost()->GetWindowHandle());
|
||||
return true;
|
||||
} else {
|
||||
ASSERT(false); // Not reached.
|
||||
}
|
||||
|
||||
return false;
|
||||
callback->Success("");
|
||||
return true;
|
||||
}
|
||||
|
||||
IMPLEMENT_REFCOUNTING(ProcessMessageDelegate);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void CreateProcessMessageDelegates(
|
||||
ClientHandler::ProcessMessageDelegateSet& delegates) {
|
||||
delegates.insert(new ProcessMessageDelegate);
|
||||
void CreateMessageHandlers(ClientHandler::MessageHandlerSet& handlers) {
|
||||
handlers.insert(new Handler());
|
||||
}
|
||||
|
||||
void ModifyBounds(const CefRect& display, CefRect& window) {
|
||||
|
|
|
@ -10,9 +10,8 @@
|
|||
|
||||
namespace window_test {
|
||||
|
||||
// Delegate creation. Called from ClientHandler.
|
||||
void CreateProcessMessageDelegates(
|
||||
ClientHandler::ProcessMessageDelegateSet& delegates);
|
||||
/// Handler creation. Called from ClientHandler.
|
||||
void CreateMessageHandlers(ClientHandler::MessageHandlerSet& handlers);
|
||||
|
||||
// Fit |window| inside |display|. Coordinates are relative to the upper-left
|
||||
// corner of the display.
|
||||
|
|
|
@ -0,0 +1,718 @@
|
|||
// 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 <list>
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "libcef_dll/wrapper/cef_browser_info_map.h"
|
||||
|
||||
namespace {
|
||||
|
||||
struct MyObject {
|
||||
MyObject(int val = 0) : member(val) {}
|
||||
int member;
|
||||
};
|
||||
|
||||
int g_destruct_ct = 0;
|
||||
|
||||
struct MyObjectTraits {
|
||||
static void Destruct(MyObject info) {
|
||||
g_destruct_ct++;
|
||||
}
|
||||
};
|
||||
|
||||
typedef CefBrowserInfoMap<int, MyObject, MyObjectTraits> MyObjectMap;
|
||||
|
||||
class MyVisitor : public MyObjectMap::Visitor {
|
||||
public:
|
||||
MyVisitor(bool remove = false,
|
||||
int remove_browser_id = 0,
|
||||
InfoIdType remove_info_id = 0)
|
||||
: remove_(remove),
|
||||
remove_browser_id_(remove_browser_id),
|
||||
remove_info_id_(remove_info_id) {}
|
||||
|
||||
virtual bool OnNextInfo(int browser_id,
|
||||
InfoIdType info_id,
|
||||
InfoObjectType info,
|
||||
bool* remove) OVERRIDE {
|
||||
Info info_rec;
|
||||
info_rec.browser_id = browser_id;
|
||||
info_rec.info_id = info_id;
|
||||
info_rec.info = info;
|
||||
info_list_.push_back(info_rec);
|
||||
|
||||
// Based on test configuration remove no objects, all objects, or only the
|
||||
// specified object.
|
||||
*remove = remove_ || (browser_id == remove_browser_id_ &&
|
||||
info_id == remove_info_id_);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns true if the specified info was passed to OnNextInfo. Removes the
|
||||
// record if found.
|
||||
bool Exists(int browser_id,
|
||||
InfoIdType info_id,
|
||||
InfoObjectType info) {
|
||||
InfoList::iterator it = info_list_.begin();
|
||||
for (; it != info_list_.end(); ++it) {
|
||||
const Info& found_info = *it;
|
||||
if (browser_id == found_info.browser_id &&
|
||||
info_id == found_info.info_id &&
|
||||
info.member == found_info.info.member) {
|
||||
info_list_.erase(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t info_size() const { return info_list_.size(); }
|
||||
|
||||
private:
|
||||
bool remove_;
|
||||
int remove_browser_id_;
|
||||
InfoIdType remove_info_id_;
|
||||
|
||||
struct Info {
|
||||
int browser_id;
|
||||
InfoIdType info_id;
|
||||
InfoObjectType info;
|
||||
};
|
||||
|
||||
// Track calls to OnNextInfo.
|
||||
typedef std::list<Info> InfoList;
|
||||
InfoList info_list_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(BrowserInfoMapTest, AddSingleBrowser) {
|
||||
MyObjectMap map;
|
||||
const int kBrowserId = 1;
|
||||
|
||||
g_destruct_ct = 0;
|
||||
|
||||
EXPECT_EQ(0U, map.size());
|
||||
EXPECT_EQ(0U, map.size(kBrowserId));
|
||||
|
||||
MyObject obj1(1);
|
||||
map.Add(kBrowserId, 1, obj1);
|
||||
EXPECT_EQ(1U, map.size());
|
||||
EXPECT_EQ(1U, map.size(kBrowserId));
|
||||
|
||||
MyObject obj2(2);
|
||||
map.Add(kBrowserId, 2, obj2);
|
||||
EXPECT_EQ(2U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId));
|
||||
|
||||
MyObject obj3(3);
|
||||
map.Add(kBrowserId, 3, obj3);
|
||||
EXPECT_EQ(3U, map.size());
|
||||
EXPECT_EQ(3U, map.size(kBrowserId));
|
||||
|
||||
EXPECT_EQ(0, g_destruct_ct);
|
||||
|
||||
map.clear(kBrowserId);
|
||||
EXPECT_EQ(0U, map.size());
|
||||
EXPECT_EQ(0U, map.size(kBrowserId));
|
||||
|
||||
EXPECT_EQ(3, g_destruct_ct);
|
||||
}
|
||||
|
||||
TEST(BrowserInfoMapTest, AddMultipleBrowsers) {
|
||||
MyObjectMap map;
|
||||
const int kBrowserId1 = 1;
|
||||
const int kBrowserId2 = 2;
|
||||
|
||||
g_destruct_ct = 0;
|
||||
|
||||
EXPECT_EQ(0U, map.size());
|
||||
EXPECT_EQ(0U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(0U, map.size(kBrowserId2));
|
||||
|
||||
MyObject obj1(1);
|
||||
map.Add(kBrowserId1, 1, obj1);
|
||||
EXPECT_EQ(1U, map.size());
|
||||
EXPECT_EQ(1U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(0U, map.size(kBrowserId2));
|
||||
|
||||
MyObject obj2(2);
|
||||
map.Add(kBrowserId1, 2, obj2);
|
||||
EXPECT_EQ(2U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(0U, map.size(kBrowserId2));
|
||||
|
||||
MyObject obj3(3);
|
||||
map.Add(kBrowserId2, 3, obj3);
|
||||
EXPECT_EQ(3U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(1U, map.size(kBrowserId2));
|
||||
|
||||
MyObject obj4(4);
|
||||
map.Add(kBrowserId2, 4, obj4);
|
||||
EXPECT_EQ(4U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
EXPECT_EQ(0, g_destruct_ct);
|
||||
|
||||
map.clear(kBrowserId1);
|
||||
EXPECT_EQ(2U, map.size());
|
||||
EXPECT_EQ(0U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
EXPECT_EQ(2, g_destruct_ct);
|
||||
|
||||
map.clear(kBrowserId2);
|
||||
EXPECT_EQ(0U, map.size());
|
||||
EXPECT_EQ(0U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(0U, map.size(kBrowserId2));
|
||||
|
||||
EXPECT_EQ(4, g_destruct_ct);
|
||||
}
|
||||
|
||||
TEST(BrowserInfoMapTest, FindSingleBrowser) {
|
||||
MyObjectMap map;
|
||||
const int kBrowserId = 1;
|
||||
|
||||
g_destruct_ct = 0;
|
||||
|
||||
// obj1 not added yet.
|
||||
MyObject nf1 = map.Find(kBrowserId, 1, NULL);
|
||||
EXPECT_EQ(0, nf1.member);
|
||||
|
||||
MyObject obj1(1);
|
||||
map.Add(kBrowserId, 1, obj1);
|
||||
|
||||
// obj1 should exist.
|
||||
MyObject f1 = map.Find(kBrowserId, 1, NULL);
|
||||
EXPECT_EQ(obj1.member, f1.member);
|
||||
|
||||
// obj2 not added yet.
|
||||
MyObject nf2 = map.Find(kBrowserId, 2, NULL);
|
||||
EXPECT_EQ(0, nf2.member);
|
||||
|
||||
MyObject obj2(2);
|
||||
map.Add(kBrowserId, 2, obj2);
|
||||
|
||||
// obj2 should exist.
|
||||
MyObject f2 = map.Find(kBrowserId, 2, NULL);
|
||||
EXPECT_EQ(obj2.member, f2.member);
|
||||
|
||||
// find obj1 again.
|
||||
MyObject f1b = map.Find(kBrowserId, 1, NULL);
|
||||
EXPECT_EQ(obj1.member, f1b.member);
|
||||
|
||||
// find obj2 again.
|
||||
MyObject f2b = map.Find(kBrowserId, 2, NULL);
|
||||
EXPECT_EQ(obj2.member, f2b.member);
|
||||
|
||||
// doesn't exist.
|
||||
MyObject nf3 = map.Find(kBrowserId, 3, NULL);
|
||||
EXPECT_EQ(0, nf3.member);
|
||||
MyObject nf4 = map.Find(10, 1, NULL);
|
||||
EXPECT_EQ(0, nf4.member);
|
||||
MyObject nf5 = map.Find(10, 3, NULL);
|
||||
EXPECT_EQ(0, nf5.member);
|
||||
|
||||
EXPECT_EQ(0, g_destruct_ct);
|
||||
map.clear();
|
||||
EXPECT_EQ(2, g_destruct_ct);
|
||||
}
|
||||
|
||||
TEST(BrowserInfoMapTest, FindMultipleBrowsers) {
|
||||
MyObjectMap map;
|
||||
const int kBrowserId1 = 1;
|
||||
const int kBrowserId2 = 2;
|
||||
|
||||
g_destruct_ct = 0;
|
||||
|
||||
// obj1 not added yet.
|
||||
MyObject nf1 = map.Find(kBrowserId1, 1, NULL);
|
||||
EXPECT_EQ(0, nf1.member);
|
||||
|
||||
MyObject obj1(1);
|
||||
map.Add(kBrowserId1, 1, obj1);
|
||||
|
||||
// obj1 should exist.
|
||||
MyObject f1 = map.Find(kBrowserId1, 1, NULL);
|
||||
EXPECT_EQ(obj1.member, f1.member);
|
||||
|
||||
// obj2 not added yet.
|
||||
MyObject nf2 = map.Find(kBrowserId1, 2, NULL);
|
||||
EXPECT_EQ(0, nf2.member);
|
||||
|
||||
MyObject obj2(2);
|
||||
map.Add(kBrowserId1, 2, obj2);
|
||||
|
||||
// obj2 should exist.
|
||||
MyObject f2 = map.Find(kBrowserId1, 2, NULL);
|
||||
EXPECT_EQ(obj2.member, f2.member);
|
||||
|
||||
// obj3 not added yet.
|
||||
MyObject nf3 = map.Find(kBrowserId2, 3, NULL);
|
||||
EXPECT_EQ(0, nf3.member);
|
||||
|
||||
MyObject obj3(3);
|
||||
map.Add(kBrowserId2, 3, obj3);
|
||||
|
||||
// obj3 should exist.
|
||||
MyObject f3 = map.Find(kBrowserId2, 3, NULL);
|
||||
EXPECT_EQ(obj3.member, f3.member);
|
||||
|
||||
// obj4 not added yet.
|
||||
MyObject nf4 = map.Find(kBrowserId2, 4, NULL);
|
||||
EXPECT_EQ(0, nf4.member);
|
||||
|
||||
MyObject obj4(4);
|
||||
map.Add(kBrowserId2, 4, obj4);
|
||||
|
||||
// obj4 should exist.
|
||||
MyObject f4 = map.Find(kBrowserId2, 4, NULL);
|
||||
EXPECT_EQ(obj4.member, f4.member);
|
||||
|
||||
// obj1-3 should exist.
|
||||
MyObject f1b = map.Find(kBrowserId1, 1, NULL);
|
||||
EXPECT_EQ(obj1.member, f1b.member);
|
||||
MyObject f2b = map.Find(kBrowserId1, 2, NULL);
|
||||
EXPECT_EQ(obj2.member, f2b.member);
|
||||
MyObject f3b = map.Find(kBrowserId2, 3, NULL);
|
||||
EXPECT_EQ(obj3.member, f3b.member);
|
||||
|
||||
// wrong browser
|
||||
MyObject nf5 = map.Find(kBrowserId1, 4, NULL);
|
||||
EXPECT_EQ(0, nf5.member);
|
||||
MyObject nf6 = map.Find(kBrowserId2, 1, NULL);
|
||||
EXPECT_EQ(0, nf6.member);
|
||||
|
||||
// deosn't exist
|
||||
MyObject nf7 = map.Find(kBrowserId2, 5, NULL);
|
||||
EXPECT_EQ(0, nf7.member);
|
||||
MyObject nf8 = map.Find(8, 1, NULL);
|
||||
EXPECT_EQ(0, nf8.member);
|
||||
MyObject nf9 = map.Find(8, 10, NULL);
|
||||
EXPECT_EQ(0, nf9.member);
|
||||
|
||||
EXPECT_EQ(0, g_destruct_ct);
|
||||
map.clear();
|
||||
EXPECT_EQ(4, g_destruct_ct);
|
||||
}
|
||||
|
||||
TEST(BrowserInfoMapTest, Find) {
|
||||
MyObjectMap map;
|
||||
const int kBrowserId1 = 1;
|
||||
const int kBrowserId2 = 2;
|
||||
|
||||
g_destruct_ct = 0;
|
||||
|
||||
MyObject obj1(1);
|
||||
map.Add(kBrowserId1, 1, obj1);
|
||||
|
||||
MyObject obj2(2);
|
||||
map.Add(kBrowserId1, 2, obj2);
|
||||
|
||||
MyObject obj3(3);
|
||||
map.Add(kBrowserId2, 3, obj3);
|
||||
|
||||
MyObject obj4(4);
|
||||
map.Add(kBrowserId2, 4, obj4);
|
||||
|
||||
EXPECT_EQ(4U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
// should only visit the single object
|
||||
MyVisitor visitor;
|
||||
map.Find(kBrowserId2, 4, &visitor);
|
||||
EXPECT_EQ(1U, visitor.info_size());
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId2, 4, obj4));
|
||||
EXPECT_EQ(0U, visitor.info_size());
|
||||
|
||||
EXPECT_EQ(4U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
EXPECT_EQ(0, g_destruct_ct);
|
||||
map.clear();
|
||||
EXPECT_EQ(4, g_destruct_ct);
|
||||
}
|
||||
|
||||
TEST(BrowserInfoMapTest, FindAndRemove) {
|
||||
MyObjectMap map;
|
||||
const int kBrowserId1 = 1;
|
||||
const int kBrowserId2 = 2;
|
||||
|
||||
g_destruct_ct = 0;
|
||||
|
||||
MyObject obj1(1);
|
||||
map.Add(kBrowserId1, 1, obj1);
|
||||
|
||||
MyObject obj2(2);
|
||||
map.Add(kBrowserId1, 2, obj2);
|
||||
|
||||
MyObject obj3(3);
|
||||
map.Add(kBrowserId2, 3, obj3);
|
||||
|
||||
MyObject obj4(4);
|
||||
map.Add(kBrowserId2, 4, obj4);
|
||||
|
||||
EXPECT_EQ(4U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
// should only visit and remove the single object.
|
||||
MyVisitor visitor(true);
|
||||
map.Find(kBrowserId1, 2, &visitor);
|
||||
EXPECT_EQ(1U, visitor.info_size());
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId1, 2, obj2));
|
||||
EXPECT_EQ(0U, visitor.info_size());
|
||||
|
||||
EXPECT_EQ(3U, map.size());
|
||||
EXPECT_EQ(1U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
// visited object shouldn't exist
|
||||
MyObject nf2 = map.Find(kBrowserId1, 2, NULL);
|
||||
EXPECT_EQ(0, nf2.member);
|
||||
|
||||
// other objects should exist
|
||||
MyObject nf1 = map.Find(kBrowserId1, 1, NULL);
|
||||
EXPECT_EQ(obj1.member, nf1.member);
|
||||
MyObject nf3 = map.Find(kBrowserId2, 3, NULL);
|
||||
EXPECT_EQ(obj3.member, nf3.member);
|
||||
MyObject nf4 = map.Find(kBrowserId2, 4, NULL);
|
||||
EXPECT_EQ(obj4.member, nf4.member);
|
||||
|
||||
EXPECT_EQ(0, g_destruct_ct);
|
||||
map.clear();
|
||||
// should destruct the remaining 3 objects
|
||||
EXPECT_EQ(3, g_destruct_ct);
|
||||
}
|
||||
|
||||
TEST(BrowserInfoMapTest, FindAll) {
|
||||
MyObjectMap map;
|
||||
const int kBrowserId1 = 1;
|
||||
const int kBrowserId2 = 2;
|
||||
|
||||
g_destruct_ct = 0;
|
||||
|
||||
MyObject obj1(1);
|
||||
map.Add(kBrowserId1, 1, obj1);
|
||||
|
||||
MyObject obj2(2);
|
||||
map.Add(kBrowserId1, 2, obj2);
|
||||
|
||||
MyObject obj3(3);
|
||||
map.Add(kBrowserId2, 3, obj3);
|
||||
|
||||
MyObject obj4(4);
|
||||
map.Add(kBrowserId2, 4, obj4);
|
||||
|
||||
EXPECT_EQ(4U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
// should visit all objects
|
||||
MyVisitor visitor;
|
||||
map.FindAll(&visitor);
|
||||
EXPECT_EQ(4U, visitor.info_size());
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId1, 1, obj1));
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId1, 2, obj2));
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId2, 3, obj3));
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId2, 4, obj4));
|
||||
// should be no unexpected visits
|
||||
EXPECT_EQ(0U, visitor.info_size());
|
||||
|
||||
EXPECT_EQ(4U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
EXPECT_EQ(0, g_destruct_ct);
|
||||
map.clear();
|
||||
EXPECT_EQ(4, g_destruct_ct);
|
||||
}
|
||||
|
||||
TEST(BrowserInfoMapTest, FindAllByBrowser) {
|
||||
MyObjectMap map;
|
||||
const int kBrowserId1 = 1;
|
||||
const int kBrowserId2 = 2;
|
||||
|
||||
g_destruct_ct = 0;
|
||||
|
||||
MyObject obj1(1);
|
||||
map.Add(kBrowserId1, 1, obj1);
|
||||
|
||||
MyObject obj2(2);
|
||||
map.Add(kBrowserId1, 2, obj2);
|
||||
|
||||
MyObject obj3(3);
|
||||
map.Add(kBrowserId2, 3, obj3);
|
||||
|
||||
MyObject obj4(4);
|
||||
map.Add(kBrowserId2, 4, obj4);
|
||||
|
||||
EXPECT_EQ(4U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
// should only visit browser2 objects
|
||||
MyVisitor visitor;
|
||||
map.FindAll(kBrowserId2, &visitor);
|
||||
EXPECT_EQ(2U, visitor.info_size());
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId2, 3, obj3));
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId2, 4, obj4));
|
||||
// should be no unexpected visits
|
||||
EXPECT_EQ(0U, visitor.info_size());
|
||||
|
||||
EXPECT_EQ(4U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
EXPECT_EQ(0, g_destruct_ct);
|
||||
map.clear();
|
||||
EXPECT_EQ(4, g_destruct_ct);
|
||||
}
|
||||
|
||||
TEST(BrowserInfoMapTest, FindAllAndRemoveAll) {
|
||||
MyObjectMap map;
|
||||
const int kBrowserId1 = 1;
|
||||
const int kBrowserId2 = 2;
|
||||
|
||||
g_destruct_ct = 0;
|
||||
|
||||
MyObject obj1(1);
|
||||
map.Add(kBrowserId1, 1, obj1);
|
||||
|
||||
MyObject obj2(2);
|
||||
map.Add(kBrowserId1, 2, obj2);
|
||||
|
||||
MyObject obj3(3);
|
||||
map.Add(kBrowserId2, 3, obj3);
|
||||
|
||||
MyObject obj4(4);
|
||||
map.Add(kBrowserId2, 4, obj4);
|
||||
|
||||
EXPECT_EQ(4U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
// should visit all objects
|
||||
MyVisitor visitor(true);
|
||||
map.FindAll(&visitor);
|
||||
EXPECT_EQ(4U, visitor.info_size());
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId1, 1, obj1));
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId1, 2, obj2));
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId2, 3, obj3));
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId2, 4, obj4));
|
||||
// should be no unexpected visits
|
||||
EXPECT_EQ(0U, visitor.info_size());
|
||||
|
||||
EXPECT_EQ(0U, map.size());
|
||||
EXPECT_EQ(0U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(0U, map.size(kBrowserId2));
|
||||
|
||||
EXPECT_EQ(0, g_destruct_ct);
|
||||
}
|
||||
|
||||
TEST(BrowserInfoMapTest, FindAllAndRemoveOne) {
|
||||
MyObjectMap map;
|
||||
const int kBrowserId1 = 1;
|
||||
const int kBrowserId2 = 2;
|
||||
|
||||
g_destruct_ct = 0;
|
||||
|
||||
MyObject obj1(1);
|
||||
map.Add(kBrowserId1, 1, obj1);
|
||||
|
||||
MyObject obj2(2);
|
||||
map.Add(kBrowserId1, 2, obj2);
|
||||
|
||||
MyObject obj3(3);
|
||||
map.Add(kBrowserId2, 3, obj3);
|
||||
|
||||
MyObject obj4(4);
|
||||
map.Add(kBrowserId2, 4, obj4);
|
||||
|
||||
EXPECT_EQ(4U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
// should visit all objects and remove one
|
||||
MyVisitor visitor(false, kBrowserId2, 3);
|
||||
map.FindAll(&visitor);
|
||||
EXPECT_EQ(4U, visitor.info_size());
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId1, 1, obj1));
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId1, 2, obj2));
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId2, 3, obj3));
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId2, 4, obj4));
|
||||
// should be no unexpected visits
|
||||
EXPECT_EQ(0U, visitor.info_size());
|
||||
|
||||
EXPECT_EQ(3U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(1U, map.size(kBrowserId2));
|
||||
|
||||
// removed object shouldn't exist
|
||||
MyObject nf3 = map.Find(kBrowserId2, 3, NULL);
|
||||
EXPECT_EQ(0, nf3.member);
|
||||
|
||||
// other objects should exist
|
||||
MyObject f1 = map.Find(kBrowserId1, 1, NULL);
|
||||
EXPECT_EQ(obj1.member, f1.member);
|
||||
MyObject f2 = map.Find(kBrowserId1, 2, NULL);
|
||||
EXPECT_EQ(obj2.member, f2.member);
|
||||
MyObject f4 = map.Find(kBrowserId2, 4, NULL);
|
||||
EXPECT_EQ(obj4.member, f4.member);
|
||||
|
||||
EXPECT_EQ(0, g_destruct_ct);
|
||||
map.clear();
|
||||
// should destruct the remaining 3 objects
|
||||
EXPECT_EQ(3, g_destruct_ct);
|
||||
}
|
||||
|
||||
TEST(BrowserInfoMapTest, FindAllAndRemoveAllByBrowser) {
|
||||
MyObjectMap map;
|
||||
const int kBrowserId1 = 1;
|
||||
const int kBrowserId2 = 2;
|
||||
|
||||
g_destruct_ct = 0;
|
||||
|
||||
MyObject obj1(1);
|
||||
map.Add(kBrowserId1, 1, obj1);
|
||||
|
||||
MyObject obj2(2);
|
||||
map.Add(kBrowserId1, 2, obj2);
|
||||
|
||||
MyObject obj3(3);
|
||||
map.Add(kBrowserId2, 3, obj3);
|
||||
|
||||
MyObject obj4(4);
|
||||
map.Add(kBrowserId2, 4, obj4);
|
||||
|
||||
EXPECT_EQ(4U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
// should only visit browser1 objects
|
||||
MyVisitor visitor(true);
|
||||
map.FindAll(kBrowserId1, &visitor);
|
||||
EXPECT_EQ(2U, visitor.info_size());
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId1, 1, obj1));
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId1, 2, obj2));
|
||||
// should be no unexpected visits
|
||||
EXPECT_EQ(0U, visitor.info_size());
|
||||
|
||||
EXPECT_EQ(2U, map.size());
|
||||
EXPECT_EQ(0U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
// browser1 objects shouldn't exist
|
||||
MyObject nf1 = map.Find(kBrowserId1, 1, NULL);
|
||||
EXPECT_EQ(0, nf1.member);
|
||||
MyObject nf2 = map.Find(kBrowserId1, 2, NULL);
|
||||
EXPECT_EQ(0, nf2.member);
|
||||
|
||||
// browser 2 objects should exist
|
||||
MyObject f3 = map.Find(kBrowserId2, 3, NULL);
|
||||
EXPECT_EQ(obj3.member, f3.member);
|
||||
MyObject f4 = map.Find(kBrowserId2, 4, NULL);
|
||||
EXPECT_EQ(obj4.member, f4.member);
|
||||
|
||||
EXPECT_EQ(0, g_destruct_ct);
|
||||
map.clear();
|
||||
// should destruct the remaining 2 objects
|
||||
EXPECT_EQ(2, g_destruct_ct);
|
||||
}
|
||||
|
||||
TEST(BrowserInfoMapTest, FindAllAndRemoveOneByBrowser) {
|
||||
MyObjectMap map;
|
||||
const int kBrowserId1 = 1;
|
||||
const int kBrowserId2 = 2;
|
||||
|
||||
g_destruct_ct = 0;
|
||||
|
||||
MyObject obj1(1);
|
||||
map.Add(kBrowserId1, 1, obj1);
|
||||
|
||||
MyObject obj2(2);
|
||||
map.Add(kBrowserId1, 2, obj2);
|
||||
|
||||
MyObject obj3(3);
|
||||
map.Add(kBrowserId2, 3, obj3);
|
||||
|
||||
MyObject obj4(4);
|
||||
map.Add(kBrowserId2, 4, obj4);
|
||||
|
||||
EXPECT_EQ(4U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(2U, map.size(kBrowserId2));
|
||||
|
||||
// should visit browser2 objects and remove one
|
||||
MyVisitor visitor(false, kBrowserId2, 4);
|
||||
map.FindAll(kBrowserId2, &visitor);
|
||||
EXPECT_EQ(2U, visitor.info_size());
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId2, 3, obj3));
|
||||
EXPECT_TRUE(visitor.Exists(kBrowserId2, 4, obj4));
|
||||
// should be no unexpected visits
|
||||
EXPECT_EQ(0U, visitor.info_size());
|
||||
|
||||
EXPECT_EQ(3U, map.size());
|
||||
EXPECT_EQ(2U, map.size(kBrowserId1));
|
||||
EXPECT_EQ(1U, map.size(kBrowserId2));
|
||||
|
||||
// removed object shouldn't exist
|
||||
MyObject nf4 = map.Find(kBrowserId2, 4, NULL);
|
||||
EXPECT_EQ(0, nf4.member);
|
||||
|
||||
// other objects should exist
|
||||
MyObject f1 = map.Find(kBrowserId1, 1, NULL);
|
||||
EXPECT_EQ(obj1.member, f1.member);
|
||||
MyObject f2 = map.Find(kBrowserId1, 2, NULL);
|
||||
EXPECT_EQ(obj2.member, f2.member);
|
||||
MyObject f3 = map.Find(kBrowserId2, 3, NULL);
|
||||
EXPECT_EQ(obj3.member, f3.member);
|
||||
|
||||
EXPECT_EQ(0, g_destruct_ct);
|
||||
map.clear();
|
||||
// should destruct the remaining 3 objects
|
||||
EXPECT_EQ(3, g_destruct_ct);
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
class MyHeapObject {
|
||||
public:
|
||||
MyHeapObject(int* destroy_ct) : destroy_ct_(destroy_ct) {}
|
||||
~MyHeapObject() {
|
||||
(*destroy_ct_)++;
|
||||
}
|
||||
|
||||
private:
|
||||
int* destroy_ct_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(BrowserInfoMapTest, DefaultTraits) {
|
||||
CefBrowserInfoMap<int, MyHeapObject*> map;
|
||||
|
||||
int destroy_ct = 0;
|
||||
map.Add(1, 1, new MyHeapObject(&destroy_ct));
|
||||
map.Add(1, 2, new MyHeapObject(&destroy_ct));
|
||||
map.Add(2, 1, new MyHeapObject(&destroy_ct));
|
||||
map.Add(2, 2, new MyHeapObject(&destroy_ct));
|
||||
map.Add(3, 1, new MyHeapObject(&destroy_ct));
|
||||
map.Add(3, 2, new MyHeapObject(&destroy_ct));
|
||||
|
||||
EXPECT_EQ(6U, map.size());
|
||||
|
||||
map.clear(1);
|
||||
EXPECT_EQ(4U, map.size());
|
||||
EXPECT_EQ(2, destroy_ct);
|
||||
|
||||
map.clear();
|
||||
EXPECT_EQ(0U, map.size());
|
||||
EXPECT_EQ(6, destroy_ct);
|
||||
}
|
|
@ -21,6 +21,16 @@ void ClientApp::CreateBrowserDelegates(BrowserDelegateSet& delegates) {
|
|||
|
||||
// static
|
||||
void ClientApp::CreateRenderDelegates(RenderDelegateSet& delegates) {
|
||||
// Bring in the routing test handler delegate.
|
||||
extern void CreateRoutingTestHandlerDelegate(
|
||||
ClientApp::RenderDelegateSet& delegates);
|
||||
CreateRoutingTestHandlerDelegate(delegates);
|
||||
|
||||
// Bring in the message router tests.
|
||||
extern void CreateMessageRouterRendererTests(
|
||||
ClientApp::RenderDelegateSet& delegates);
|
||||
CreateMessageRouterRendererTests(delegates);
|
||||
|
||||
// Bring in the process message tests.
|
||||
extern void CreateProcessMessageRendererTests(
|
||||
ClientApp::RenderDelegateSet& delegates);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// can be found in the LICENSE file.
|
||||
|
||||
#include "include/cef_runnable.h"
|
||||
#include "tests/unittests/test_handler.h"
|
||||
#include "tests/unittests/routing_test_handler.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
|
@ -13,7 +13,7 @@ const char kUnloadDialogText[] = "Are you sure?";
|
|||
const char kUnloadMsg[] = "LifeSpanTestHandler.Unload";
|
||||
|
||||
// Browser side.
|
||||
class LifeSpanTestHandler : public TestHandler {
|
||||
class LifeSpanTestHandler : public RoutingTestHandler {
|
||||
public:
|
||||
struct Settings {
|
||||
Settings()
|
||||
|
@ -35,9 +35,9 @@ class LifeSpanTestHandler : public TestHandler {
|
|||
virtual void RunTest() OVERRIDE {
|
||||
// Add the resources that we will navigate to/from.
|
||||
std::string page = "<html><script>";
|
||||
|
||||
page += "window.onunload = function() { app.sendMessage('" +
|
||||
std::string(kUnloadMsg) + "'); };";
|
||||
|
||||
page += "window.onunload = function() { window.testQuery({request:'" +
|
||||
std::string(kUnloadMsg) + "'}); };";
|
||||
|
||||
if (settings_.add_onunload_handler) {
|
||||
page += "window.onbeforeunload = function() { return '" +
|
||||
|
@ -53,7 +53,7 @@ class LifeSpanTestHandler : public TestHandler {
|
|||
|
||||
virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE {
|
||||
got_after_created_.yes();
|
||||
TestHandler::OnAfterCreated(browser);
|
||||
RoutingTestHandler::OnAfterCreated(browser);
|
||||
}
|
||||
|
||||
virtual bool DoClose(CefRefPtr<CefBrowser> browser) OVERRIDE {
|
||||
|
@ -78,7 +78,7 @@ class LifeSpanTestHandler : public TestHandler {
|
|||
EXPECT_TRUE(browser->IsSame(GetBrowser()));
|
||||
}
|
||||
|
||||
TestHandler::OnBeforeClose(browser);
|
||||
RoutingTestHandler::OnBeforeClose(browser);
|
||||
}
|
||||
|
||||
virtual bool OnBeforeUnloadDialog(
|
||||
|
@ -116,18 +116,18 @@ class LifeSpanTestHandler : public TestHandler {
|
|||
browser->GetHost()->CloseBrowser(settings_.force_close);
|
||||
}
|
||||
|
||||
virtual bool OnProcessMessageReceived(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) OVERRIDE {
|
||||
const std::string& message_name = message->GetName();
|
||||
if (message_name == kUnloadMsg) {
|
||||
virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int64 query_id,
|
||||
const CefString& request,
|
||||
bool persistent,
|
||||
CefRefPtr<Callback> callback) OVERRIDE {
|
||||
if (request.ToString() == kUnloadMsg) {
|
||||
if (!executing_delay_close_)
|
||||
got_unload_message_.yes();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
callback->Success("");
|
||||
return true;
|
||||
}
|
||||
|
||||
TrackCallback got_after_created_;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -8,7 +8,7 @@
|
|||
|
||||
#include "tests/cefclient/client_app.h"
|
||||
#include "tests/cefclient/resource_util.h"
|
||||
#include "tests/unittests/test_handler.h"
|
||||
#include "tests/unittests/routing_test_handler.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "ui/events/keycodes/keyboard_codes.h"
|
||||
|
@ -190,7 +190,7 @@ enum OSRTestType {
|
|||
};
|
||||
|
||||
// Used in the browser process.
|
||||
class OSRTestHandler : public TestHandler,
|
||||
class OSRTestHandler : public RoutingTestHandler,
|
||||
public CefRenderHandler,
|
||||
public CefContextMenuHandler {
|
||||
public:
|
||||
|
@ -224,7 +224,7 @@ class OSRTestHandler : public TestHandler,
|
|||
EXPECT_TRUE(browser->GetHost()->IsWindowRenderingDisabled());
|
||||
DestroySucceededTestSoon();
|
||||
}
|
||||
TestHandler::OnAfterCreated(browser);
|
||||
RoutingTestHandler::OnAfterCreated(browser);
|
||||
}
|
||||
|
||||
virtual void OnLoadEnd(CefRefPtr<CefBrowser> browser,
|
||||
|
@ -247,37 +247,33 @@ class OSRTestHandler : public TestHandler,
|
|||
}
|
||||
}
|
||||
|
||||
virtual bool OnProcessMessageReceived(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) OVERRIDE {
|
||||
virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int64 query_id,
|
||||
const CefString& request,
|
||||
bool persistent,
|
||||
CefRefPtr<Callback> callback) OVERRIDE {
|
||||
EXPECT_TRUE(browser.get());
|
||||
EXPECT_EQ(PID_RENDERER, source_process);
|
||||
EXPECT_TRUE(message.get());
|
||||
EXPECT_TRUE(message->IsReadOnly());
|
||||
|
||||
if (!started())
|
||||
return false;
|
||||
|
||||
const CefString kMessageName = "osrtest";
|
||||
EXPECT_EQ(kMessageName, message->GetName());
|
||||
|
||||
CefString stringParam = message->GetArgumentList()->GetString(0);
|
||||
const std::string& messageStr = request;
|
||||
switch(test_type_) {
|
||||
case OSR_TEST_FOCUS:
|
||||
EXPECT_EQ(stringParam, std::string("focus"));
|
||||
EXPECT_STREQ(messageStr.c_str(), "osrfocus");
|
||||
DestroySucceededTestSoon();
|
||||
break;
|
||||
case OSR_TEST_CLICK_LEFT:
|
||||
EXPECT_EQ(stringParam, std::string("click0"));
|
||||
EXPECT_STREQ(messageStr.c_str(), "osrclick0");
|
||||
DestroySucceededTestSoon();
|
||||
break;
|
||||
case OSR_TEST_CLICK_MIDDLE:
|
||||
EXPECT_EQ(stringParam, std::string("click1"));
|
||||
EXPECT_STREQ(messageStr.c_str(), "osrclick1");
|
||||
DestroySucceededTestSoon();
|
||||
break;
|
||||
case OSR_TEST_MOUSE_MOVE:
|
||||
EXPECT_EQ(stringParam, std::string("mousemove"));
|
||||
EXPECT_STREQ(messageStr.c_str(), "osrmousemove");
|
||||
DestroySucceededTestSoon();
|
||||
break;
|
||||
default:
|
||||
|
@ -285,6 +281,7 @@ class OSRTestHandler : public TestHandler,
|
|||
break;
|
||||
}
|
||||
|
||||
callback->Success("");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,11 +12,8 @@
|
|||
namespace {
|
||||
|
||||
// Unique values for the SendRecv test.
|
||||
const char* kSendRecvUrlNative =
|
||||
"http://tests/ProcessMessageTest.SendRecv/Native";
|
||||
const char* kSendRecvUrlJavaScript =
|
||||
"http://tests/ProcessMessageTest.SendRecv/JavaScript";
|
||||
const char* kSendRecvMsg = "ProcessMessageTest.SendRecv";
|
||||
const char kSendRecvUrl[] = "http://tests/ProcessMessageTest.SendRecv";
|
||||
const char kSendRecvMsg[] = "ProcessMessageTest.SendRecv";
|
||||
|
||||
// Creates a test message.
|
||||
CefRefPtr<CefProcessMessage> CreateTestMessage() {
|
||||
|
@ -55,7 +52,7 @@ class SendRecvRendererTest : public ClientApp::RenderDelegate {
|
|||
EXPECT_TRUE(message.get());
|
||||
|
||||
std::string url = browser->GetMainFrame()->GetURL();
|
||||
if (url == kSendRecvUrlNative) {
|
||||
if (url == kSendRecvUrl) {
|
||||
// Echo the message back to the sender natively.
|
||||
EXPECT_TRUE(browser->SendProcessMessage(PID_BROWSER, message));
|
||||
return true;
|
||||
|
@ -72,33 +69,14 @@ class SendRecvRendererTest : public ClientApp::RenderDelegate {
|
|||
// Browser side.
|
||||
class SendRecvTestHandler : public TestHandler {
|
||||
public:
|
||||
explicit SendRecvTestHandler(bool native)
|
||||
: native_(native) {
|
||||
SendRecvTestHandler() {
|
||||
}
|
||||
|
||||
virtual void RunTest() OVERRIDE {
|
||||
message_ = CreateTestMessage();
|
||||
|
||||
if (native_) {
|
||||
// Native test.
|
||||
AddResource(kSendRecvUrlNative, "<html><body>TEST NATIVE</body></html>",
|
||||
"text/html");
|
||||
CreateBrowser(kSendRecvUrlNative);
|
||||
} else {
|
||||
// JavaScript test.
|
||||
std::string content =
|
||||
"<html><head>\n"
|
||||
"<script>\n"
|
||||
"function cb(name, args) {\n"
|
||||
" app.sendMessage(name, args);\n"
|
||||
"}\n"
|
||||
"app.setMessageCallback('"+std::string(kSendRecvMsg)+"', cb);\n"
|
||||
"</script>\n"
|
||||
"<body>TEST JAVASCRIPT</body>\n"
|
||||
"</head></html>";
|
||||
AddResource(kSendRecvUrlJavaScript, content, "text/html");
|
||||
CreateBrowser(kSendRecvUrlJavaScript);
|
||||
}
|
||||
AddResource(kSendRecvUrl, "<html><body>TEST</body></html>", "text/html");
|
||||
CreateBrowser(kSendRecvUrl);
|
||||
}
|
||||
|
||||
virtual void OnLoadEnd(CefRefPtr<CefBrowser> browser,
|
||||
|
@ -128,30 +106,21 @@ class SendRecvTestHandler : public TestHandler {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool native_;
|
||||
CefRefPtr<CefProcessMessage> message_;
|
||||
TrackCallback got_message_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// Verify native send and recieve
|
||||
TEST(ProcessMessageTest, SendRecvNative) {
|
||||
CefRefPtr<SendRecvTestHandler> handler = new SendRecvTestHandler(true);
|
||||
// Verify send and recieve.
|
||||
TEST(ProcessMessageTest, SendRecv) {
|
||||
CefRefPtr<SendRecvTestHandler> handler = new SendRecvTestHandler();
|
||||
handler->ExecuteTest();
|
||||
|
||||
EXPECT_TRUE(handler->got_message_);
|
||||
}
|
||||
|
||||
// Verify JavaScript send and recieve
|
||||
TEST(ProcessMessageTest, SendRecvJavaScript) {
|
||||
CefRefPtr<SendRecvTestHandler> handler = new SendRecvTestHandler(false);
|
||||
handler->ExecuteTest();
|
||||
|
||||
EXPECT_TRUE(handler->got_message_);
|
||||
}
|
||||
|
||||
// Verify create
|
||||
// Verify create.
|
||||
TEST(ProcessMessageTest, Create) {
|
||||
CefRefPtr<CefProcessMessage> message =
|
||||
CefProcessMessage::Create(kSendRecvMsg);
|
||||
|
@ -167,7 +136,7 @@ TEST(ProcessMessageTest, Create) {
|
|||
EXPECT_FALSE(args->IsReadOnly());
|
||||
}
|
||||
|
||||
// Verify copy
|
||||
// Verify copy.
|
||||
TEST(ProcessMessageTest, Copy) {
|
||||
CefRefPtr<CefProcessMessage> message = CreateTestMessage();
|
||||
CefRefPtr<CefProcessMessage> message2 = message->Copy();
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
// 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 "tests/unittests/routing_test_handler.h"
|
||||
#include "tests/cefclient/client_app.h"
|
||||
|
||||
namespace {
|
||||
|
||||
void SetRouterConfig(CefMessageRouterConfig& config) {
|
||||
config.js_query_function = "testQuery";
|
||||
config.js_cancel_function = "testQueryCancel";
|
||||
}
|
||||
|
||||
// Handle the renderer side of the routing implementation.
|
||||
class RoutingRenderDelegate : public ClientApp::RenderDelegate {
|
||||
public:
|
||||
RoutingRenderDelegate() {}
|
||||
|
||||
virtual void OnWebKitInitialized(CefRefPtr<ClientApp> app) OVERRIDE {
|
||||
// Create the renderer-side router for query handling.
|
||||
CefMessageRouterConfig config;
|
||||
SetRouterConfig(config);
|
||||
message_router_ = CefMessageRouterRendererSide::Create(config);
|
||||
}
|
||||
|
||||
virtual void OnContextCreated(CefRefPtr<ClientApp> app,
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Context> context) OVERRIDE {
|
||||
message_router_->OnContextCreated(browser, frame, context);
|
||||
}
|
||||
|
||||
virtual void OnContextReleased(CefRefPtr<ClientApp> app,
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Context> context) OVERRIDE {
|
||||
message_router_->OnContextReleased(browser, frame, context);
|
||||
}
|
||||
|
||||
virtual bool OnProcessMessageReceived(
|
||||
CefRefPtr<ClientApp> app,
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) OVERRIDE {
|
||||
return message_router_->OnProcessMessageReceived(
|
||||
browser, source_process, message);
|
||||
}
|
||||
|
||||
private:
|
||||
CefRefPtr<CefMessageRouterRendererSide> message_router_;
|
||||
|
||||
IMPLEMENT_REFCOUNTING(RoutingRenderDelegate);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
RoutingTestHandler::RoutingTestHandler() {
|
||||
}
|
||||
|
||||
void RoutingTestHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
|
||||
if (!message_router_) {
|
||||
// Create the browser-side router for query handling.
|
||||
CefMessageRouterConfig config;
|
||||
SetRouterConfig(config);
|
||||
message_router_ = CefMessageRouterBrowserSide::Create(config);
|
||||
message_router_->AddHandler(this, false);
|
||||
}
|
||||
TestHandler::OnAfterCreated(browser);
|
||||
}
|
||||
|
||||
void RoutingTestHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
|
||||
message_router_->OnBeforeClose(browser);
|
||||
TestHandler::OnBeforeClose(browser);
|
||||
}
|
||||
|
||||
void RoutingTestHandler::OnRenderProcessTerminated(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
TerminationStatus status) {
|
||||
message_router_->OnRenderProcessTerminated(browser);
|
||||
}
|
||||
|
||||
bool RoutingTestHandler::OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefRequest> request,
|
||||
bool is_redirect) {
|
||||
message_router_->OnBeforeBrowse(browser, frame);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RoutingTestHandler::OnProcessMessageReceived(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) {
|
||||
return message_router_->OnProcessMessageReceived(
|
||||
browser, source_process, message);
|
||||
}
|
||||
|
||||
// Entry point for creating the test delegate.
|
||||
// Called from client_app_delegates.cc.
|
||||
void CreateRoutingTestHandlerDelegate(
|
||||
ClientApp::RenderDelegateSet& delegates) {
|
||||
delegates.insert(new RoutingRenderDelegate);
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
// 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.
|
||||
|
||||
#ifndef CEF_TESTS_UNITTESTS_ROUTING_TEST_HANDLER_H_
|
||||
#define CEF_TESTS_UNITTESTS_ROUTING_TEST_HANDLER_H_
|
||||
#pragma once
|
||||
|
||||
#include "include/wrapper/cef_message_router.h"
|
||||
#include "tests/unittests/test_handler.h"
|
||||
|
||||
// Extends TestHandler to provide message routing functionality. The
|
||||
// RoutingTestHandler implementation must be called from subclass
|
||||
// overrides unless otherwise indicated.
|
||||
class RoutingTestHandler :
|
||||
public TestHandler,
|
||||
public CefMessageRouterBrowserSide::Handler {
|
||||
public:
|
||||
RoutingTestHandler();
|
||||
|
||||
virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;
|
||||
virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE;
|
||||
virtual void OnRenderProcessTerminated(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
TerminationStatus status) OVERRIDE;
|
||||
|
||||
// Only call this method if the navigation isn't canceled.
|
||||
virtual bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefRequest> request,
|
||||
bool is_redirect) OVERRIDE;
|
||||
|
||||
// Returns true if the router handled the navigation.
|
||||
virtual bool OnProcessMessageReceived(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) OVERRIDE;
|
||||
|
||||
private:
|
||||
CefRefPtr<CefMessageRouterBrowserSide> message_router_;
|
||||
};
|
||||
|
||||
|
||||
#endif // CEF_TESTS_UNITTESTS_ROUTING_TEST_HANDLER_H_
|
|
@ -3,7 +3,6 @@
|
|||
// can be found in the LICENSE file.
|
||||
|
||||
#include "tests/unittests/test_handler.h"
|
||||
#include "base/logging.h"
|
||||
#include "include/cef_command_line.h"
|
||||
#include "include/cef_runnable.h"
|
||||
#include "include/cef_stream.h"
|
||||
|
@ -47,16 +46,16 @@ void TestHandler::CompletionState::WaitForTests() {
|
|||
|
||||
TestHandler::Collection::Collection(CompletionState* completion_state)
|
||||
: completion_state_(completion_state) {
|
||||
DCHECK(completion_state_);
|
||||
EXPECT_TRUE(completion_state_);
|
||||
}
|
||||
|
||||
void TestHandler::Collection::AddTestHandler(TestHandler* test_handler) {
|
||||
DCHECK_EQ(test_handler->completion_state_, completion_state_);
|
||||
EXPECT_EQ(test_handler->completion_state_, completion_state_);
|
||||
handler_list_.push_back(test_handler);
|
||||
}
|
||||
|
||||
void TestHandler::Collection::ExecuteTests() {
|
||||
DCHECK_GT(handler_list_.size(), 0UL);
|
||||
EXPECT_GT(handler_list_.size(), 0UL);
|
||||
|
||||
TestHandlerList::const_iterator it;
|
||||
|
||||
|
@ -79,7 +78,8 @@ void TestHandler::Collection::ExecuteTests() {
|
|||
int TestHandler::browser_count_ = 0;
|
||||
|
||||
TestHandler::TestHandler(CompletionState* completion_state)
|
||||
: browser_id_(0) {
|
||||
: first_browser_id_(0),
|
||||
signal_completion_when_all_browsers_close_(true) {
|
||||
if (completion_state) {
|
||||
completion_state_ = completion_state;
|
||||
completion_state_owned_ = false;
|
||||
|
@ -90,31 +90,48 @@ TestHandler::TestHandler(CompletionState* completion_state)
|
|||
}
|
||||
|
||||
TestHandler::~TestHandler() {
|
||||
EXPECT_TRUE(browser_map_.empty());
|
||||
|
||||
if (completion_state_owned_)
|
||||
delete completion_state_;
|
||||
}
|
||||
|
||||
void TestHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
|
||||
EXPECT_UI_THREAD();
|
||||
|
||||
browser_count_++;
|
||||
|
||||
AutoLock lock_scope(this);
|
||||
if (!browser->IsPopup()) {
|
||||
// Keep the main child window, but not popup windows
|
||||
browser_ = browser;
|
||||
browser_id_ = browser->GetIdentifier();
|
||||
// Keep non-popup browsers.
|
||||
const int browser_id = browser->GetIdentifier();
|
||||
EXPECT_EQ(browser_map_.find(browser_id), browser_map_.end());
|
||||
if (browser_map_.empty()) {
|
||||
first_browser_id_ = browser_id;
|
||||
first_browser_ = browser;
|
||||
}
|
||||
browser_map_.insert(std::make_pair(browser_id, browser));
|
||||
}
|
||||
}
|
||||
|
||||
void TestHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
|
||||
{
|
||||
AutoLock lock_scope(this);
|
||||
if (browser_id_ == browser->GetIdentifier()) {
|
||||
// Free the browser pointer so that the browser can be destroyed
|
||||
browser_ = NULL;
|
||||
browser_id_ = 0;
|
||||
EXPECT_UI_THREAD();
|
||||
|
||||
if (!browser->IsPopup()) {
|
||||
// Free the browser pointer so that the browser can be destroyed.
|
||||
const int browser_id = browser->GetIdentifier();
|
||||
BrowserMap::iterator it = browser_map_.find(browser_id);
|
||||
EXPECT_NE(it, browser_map_.end());
|
||||
browser_map_.erase(it);
|
||||
|
||||
if (browser_id == first_browser_id_) {
|
||||
first_browser_id_ = 0;
|
||||
first_browser_ = NULL;
|
||||
}
|
||||
|
||||
if (browser_map_.empty() &&
|
||||
signal_completion_when_all_browsers_close_) {
|
||||
// Signal that the test is now complete.
|
||||
completion_state_->TestComplete();
|
||||
TestComplete();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,7 +142,7 @@ CefRefPtr<CefResourceHandler> TestHandler::GetResourceHandler(
|
|||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefRequest> request) {
|
||||
AutoLock lock_scope(this);
|
||||
EXPECT_IO_THREAD();
|
||||
|
||||
if (resource_map_.size() > 0) {
|
||||
CefString url = request->GetURL();
|
||||
|
@ -150,8 +167,22 @@ CefRefPtr<CefResourceHandler> TestHandler::GetResourceHandler(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
CefRefPtr<CefBrowser> TestHandler::GetBrowser() {
|
||||
return first_browser_;
|
||||
}
|
||||
|
||||
int TestHandler::GetBrowserId() {
|
||||
return first_browser_id_;
|
||||
}
|
||||
|
||||
void TestHandler::GetAllBrowsers(BrowserMap* map) {
|
||||
EXPECT_UI_THREAD();
|
||||
EXPECT_TRUE(map);
|
||||
*map = browser_map_;
|
||||
}
|
||||
|
||||
void TestHandler::ExecuteTest() {
|
||||
DCHECK_EQ(completion_state_->total(), 1);
|
||||
EXPECT_EQ(completion_state_->total(), 1);
|
||||
|
||||
// Run the test
|
||||
RunTest();
|
||||
|
@ -166,9 +197,21 @@ void TestHandler::SetupComplete() {
|
|||
}
|
||||
|
||||
void TestHandler::DestroyTest() {
|
||||
AutoLock lock_scope(this);
|
||||
if (browser_id_ != 0)
|
||||
browser_->GetHost()->CloseBrowser(false);
|
||||
if (!CefCurrentlyOn(TID_UI)) {
|
||||
CefPostTask(TID_UI, NewCefRunnableMethod(this, &TestHandler::DestroyTest));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!browser_map_.empty()) {
|
||||
// Use a copy of the map since the original may be modified while we're
|
||||
// iterating.
|
||||
BrowserMap browser_map = browser_map_;
|
||||
|
||||
// Tell all non-popup browsers to close.
|
||||
BrowserMap::const_iterator it = browser_map.begin();
|
||||
for (; it != browser_map.end(); ++it)
|
||||
it->second->GetHost()->CloseBrowser(false);
|
||||
}
|
||||
}
|
||||
|
||||
void TestHandler::CreateBrowser(
|
||||
|
@ -187,6 +230,13 @@ void TestHandler::CreateBrowser(
|
|||
void TestHandler::AddResource(const std::string& url,
|
||||
const std::string& content,
|
||||
const std::string& mimeType) {
|
||||
if (!CefCurrentlyOn(TID_IO)) {
|
||||
CefPostTask(TID_IO,
|
||||
NewCefRunnableMethod(this, &TestHandler::AddResource, url, content,
|
||||
mimeType));
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore the query component, if any.
|
||||
std::string urlStr = url;
|
||||
size_t idx = urlStr.find('?');
|
||||
|
@ -198,9 +248,25 @@ void TestHandler::AddResource(const std::string& url,
|
|||
}
|
||||
|
||||
void TestHandler::ClearResources() {
|
||||
if (!CefCurrentlyOn(TID_IO)) {
|
||||
CefPostTask(TID_IO,
|
||||
NewCefRunnableMethod(this, &TestHandler::ClearResources));
|
||||
return;
|
||||
}
|
||||
|
||||
resource_map_.clear();
|
||||
}
|
||||
|
||||
void TestHandler::TestComplete() {
|
||||
if (!CefCurrentlyOn(TID_UI)) {
|
||||
CefPostTask(TID_UI, NewCefRunnableMethod(this, &TestHandler::TestComplete));
|
||||
return;
|
||||
}
|
||||
|
||||
EXPECT_TRUE(browser_map_.empty());
|
||||
completion_state_->TestComplete();
|
||||
}
|
||||
|
||||
|
||||
// global functions
|
||||
|
||||
|
|
|
@ -94,6 +94,8 @@ class TestHandler : public CefClient,
|
|||
TestHandlerList handler_list_;
|
||||
};
|
||||
|
||||
typedef std::map<int, CefRefPtr<CefBrowser> > BrowserMap;
|
||||
|
||||
// The |completion_state| object if specified must outlive this class.
|
||||
explicit TestHandler(CompletionState* completion_state = NULL);
|
||||
virtual ~TestHandler();
|
||||
|
@ -149,8 +151,13 @@ class TestHandler : public CefClient,
|
|||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefRequest> request) OVERRIDE;
|
||||
|
||||
CefRefPtr<CefBrowser> GetBrowser() { return browser_; }
|
||||
int GetBrowserId() { return browser_id_; }
|
||||
// These methods should only be used if at most one non-popup browser exists.
|
||||
CefRefPtr<CefBrowser> GetBrowser();
|
||||
int GetBrowserId();
|
||||
|
||||
// Copies the map of all the currently existing browsers into |map|. Must be
|
||||
// called on the UI thread.
|
||||
void GetAllBrowsers(BrowserMap* map);
|
||||
|
||||
// Called by the test function to execute the test. This method blocks until
|
||||
// the test is complete. Do not reference the object after this method
|
||||
|
@ -166,8 +173,11 @@ class TestHandler : public CefClient,
|
|||
// Collection.
|
||||
virtual void SetupComplete();
|
||||
|
||||
// Destroy the browser window. Once the window is destroyed test completion
|
||||
// will be signaled.
|
||||
// Close any existing non-popup browsers. Test completion will be signaled
|
||||
// once all the browsers have closed if
|
||||
// |signal_completion_when_all_browsers_close_| is true (default value).
|
||||
// If no browsers exist then this method will do nothing and
|
||||
// TestComplete() must be called manually.
|
||||
virtual void DestroyTest();
|
||||
|
||||
void CreateBrowser(const CefString& url,
|
||||
|
@ -178,26 +188,44 @@ class TestHandler : public CefClient,
|
|||
const std::string& mimeType);
|
||||
void ClearResources();
|
||||
|
||||
void SetSignalCompletionWhenAllBrowsersClose(bool val) {
|
||||
signal_completion_when_all_browsers_close_ = val;
|
||||
}
|
||||
bool SignalCompletionWhenAllBrowsersClose() const {
|
||||
return signal_completion_when_all_browsers_close_;
|
||||
}
|
||||
|
||||
// Signal that the test is complete. This will be called automatically when
|
||||
// all existing non-popup browsers are closed if
|
||||
// |signal_completion_when_all_browsers_close_| is true (default value). It
|
||||
// is an error to call this method before all browsers have closed.
|
||||
void TestComplete();
|
||||
|
||||
private:
|
||||
// The child browser window
|
||||
CefRefPtr<CefBrowser> browser_;
|
||||
|
||||
// The browser window identifier
|
||||
int browser_id_;
|
||||
|
||||
// Used to notify when the test is complete
|
||||
// Used to notify when the test is complete. Can be accessed on any thread.
|
||||
CompletionState* completion_state_;
|
||||
bool completion_state_owned_;
|
||||
|
||||
// Map of resources that can be automatically loaded
|
||||
// Map browser ID to browser object for non-popup browsers. Only accessed on
|
||||
// the UI thread.
|
||||
BrowserMap browser_map_;
|
||||
|
||||
// Values for the first created browser. Modified on the UI thread but can be
|
||||
// accessed on any thread.
|
||||
int first_browser_id_;
|
||||
CefRefPtr<CefBrowser> first_browser_;
|
||||
|
||||
// Map of resources that can be automatically loaded. Only accessed on the
|
||||
// IO thread.
|
||||
typedef std::map<std::string, std::pair<std::string, std::string> >
|
||||
ResourceMap;
|
||||
ResourceMap resource_map_;
|
||||
|
||||
// If true test completion will be signaled when all browsers have closed.
|
||||
bool signal_completion_when_all_browsers_close_;
|
||||
|
||||
// Include the default reference counting implementation.
|
||||
IMPLEMENT_REFCOUNTING(TestHandler);
|
||||
// Include the default locking implementation.
|
||||
IMPLEMENT_LOCKING(TestHandler);
|
||||
|
||||
// Used to track the number of currently existing browser windows.
|
||||
static int browser_count_;
|
||||
|
@ -215,4 +243,8 @@ void WaitForThread(CefRefPtr<CefTaskRunner> task_runner);
|
|||
// Returns true if the currently running test has failed.
|
||||
bool TestFailed();
|
||||
|
||||
#define EXPECT_UI_THREAD() EXPECT_TRUE(CefCurrentlyOn(TID_UI));
|
||||
#define EXPECT_IO_THREAD() EXPECT_TRUE(CefCurrentlyOn(TID_IO));
|
||||
#define EXPECT_RENDERER_THREAD() EXPECT_TRUE(CefCurrentlyOn(TID_RENDERER));
|
||||
|
||||
#endif // CEF_TESTS_UNITTESTS_TEST_HANDLER_H_
|
||||
|
|
Loading…
Reference in New Issue