diff --git a/cef.gyp b/cef.gyp index 6ea4ebe77..4d5abc3f4 100644 --- a/cef.gyp +++ b/cef.gyp @@ -259,6 +259,7 @@ 'tests/unittests/test_suite.h', 'tests/unittests/test_util.cc', 'tests/unittests/test_util.h', + 'tests/unittests/tracing_unittest.cc', 'tests/unittests/url_unittest.cc', 'tests/unittests/urlrequest_unittest.cc', 'tests/unittests/v8_unittest.cc', @@ -841,6 +842,9 @@ 'libcef/browser/sqlite_diagnostics_stub.cc', 'libcef/browser/stream_impl.cc', 'libcef/browser/stream_impl.h', + 'libcef/browser/trace_impl.cc', + 'libcef/browser/trace_subscriber.cc', + 'libcef/browser/trace_subscriber.h', 'libcef/browser/thread_util.h', 'libcef/browser/url_network_delegate.cc', 'libcef/browser/url_network_delegate.h', @@ -899,6 +903,8 @@ 'libcef/common/values_impl.h', 'libcef/renderer/browser_impl.cc', 'libcef/renderer/browser_impl.h', + 'libcef/renderer/chrome_bindings.cc', + 'libcef/renderer/chrome_bindings.h', 'libcef/renderer/content_renderer_client.cc', 'libcef/renderer/content_renderer_client.h', 'libcef/renderer/dom_document_impl.cc', @@ -1190,6 +1196,7 @@ 'tests/unittests/test_suite.h', 'tests/unittests/test_util.cc', 'tests/unittests/test_util.h', + 'tests/unittests/tracing_unittest.cc', 'tests/unittests/v8_unittest.cc', ], # TODO(mark): Come up with a fancier way to do this. It should only diff --git a/cef_paths.gypi b/cef_paths.gypi index abda32597..18a07d701 100644 --- a/cef_paths.gypi +++ b/cef_paths.gypi @@ -48,6 +48,7 @@ 'include/cef_stream.h', 'include/cef_string_visitor.h', 'include/cef_task.h', + 'include/cef_trace.h', 'include/cef_url.h', 'include/cef_urlrequest.h', 'include/cef_v8.h', @@ -93,6 +94,7 @@ 'include/capi/cef_stream_capi.h', 'include/capi/cef_string_visitor_capi.h', 'include/capi/cef_task_capi.h', + 'include/capi/cef_trace_capi.h', 'include/capi/cef_url_capi.h', 'include/capi/cef_urlrequest_capi.h', 'include/capi/cef_v8_capi.h', @@ -214,6 +216,8 @@ 'libcef_dll/ctocpp/string_visitor_ctocpp.h', 'libcef_dll/ctocpp/task_ctocpp.cc', 'libcef_dll/ctocpp/task_ctocpp.h', + 'libcef_dll/ctocpp/trace_client_ctocpp.cc', + 'libcef_dll/ctocpp/trace_client_ctocpp.h', 'libcef_dll/cpptoc/urlrequest_cpptoc.cc', 'libcef_dll/cpptoc/urlrequest_cpptoc.h', 'libcef_dll/ctocpp/urlrequest_client_ctocpp.cc', @@ -358,6 +362,8 @@ 'libcef_dll/cpptoc/string_visitor_cpptoc.h', 'libcef_dll/cpptoc/task_cpptoc.cc', 'libcef_dll/cpptoc/task_cpptoc.h', + 'libcef_dll/cpptoc/trace_client_cpptoc.cc', + 'libcef_dll/cpptoc/trace_client_cpptoc.h', 'libcef_dll/ctocpp/urlrequest_ctocpp.cc', 'libcef_dll/ctocpp/urlrequest_ctocpp.h', 'libcef_dll/cpptoc/urlrequest_client_cpptoc.cc', diff --git a/cef_paths2.gypi b/cef_paths2.gypi index 1ceda4f73..17e264340 100644 --- a/cef_paths2.gypi +++ b/cef_paths2.gypi @@ -13,6 +13,7 @@ 'include/cef_pack_resources.h', 'include/cef_pack_strings.h', 'include/cef_runnable.h', + 'include/cef_trace_event.h', 'include/cef_version.h', 'include/internal/cef_build.h', 'include/internal/cef_export.h', diff --git a/include/capi/cef_trace_capi.h b/include/capi/cef_trace_capi.h new file mode 100644 index 000000000..2f1d0dac3 --- /dev/null +++ b/include/capi/cef_trace_capi.h @@ -0,0 +1,129 @@ +// Copyright (c) 2012 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. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool and should not edited +// by hand. See the translator.README.txt file in the tools directory for +// more information. +// + +#ifndef CEF_INCLUDE_CAPI_CEF_TRACE_CAPI_H_ +#define CEF_INCLUDE_CAPI_CEF_TRACE_CAPI_H_ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "include/capi/cef_base_capi.h" + + +/// +// Start tracing events on all processes. Tracing begins immediately locally, +// and asynchronously on child processes as soon as they receive the +// BeginTracing request. +// +// If CefBeginTracing was called previously, or if a CefEndTracingAsync call is +// pending, CefBeginTracing will fail and return false (0). +// +// |categories| is a comma-delimited list of category wildcards. A category can +// have an optional '-' prefix to make it an excluded category. Having both +// included and excluded categories in the same list is not supported. +// +// Example: "test_MyTest*" Example: "test_MyTest*,test_OtherStuff" Example: +// "-excluded_category1,-excluded_category2" +// +// This function must be called on the browser process UI thread. +/// +CEF_EXPORT int cef_begin_tracing(struct _cef_trace_client_t* client, + const cef_string_t* categories); + +/// +// Get the maximum trace buffer percent full state across all processes. +// +// cef_trace_client_t::OnTraceBufferPercentFullReply will be called +// asynchronously after the value is determibed. When any child process reaches +// 100% full tracing will end automatically and +// cef_trace_client_t::OnEndTracingComplete will be called. This function fails +// and returns false (0) if trace is ending or disabled, no cef_trace_client_t +// was passed to CefBeginTracing, or if a previous call to +// CefGetTraceBufferPercentFullAsync is pending. +// +// This function must be called on the browser process UI thread. +/// +CEF_EXPORT int cef_get_trace_buffer_percent_full_async(); + +/// +// Stop tracing events on all processes. +// +// This function will fail and return false (0) if a previous call to +// CefEndTracingAsync is already pending or if CefBeginTracing was not called. +// +// This function must be called on the browser process UI thread. +/// +CEF_EXPORT int cef_end_tracing_async(); + +/// +// Implement this structure to receive trace notifications. The functions of +// this structure will be called on the browser process UI thread. +/// +typedef struct _cef_trace_client_t { + /// + // Base structure. + /// + cef_base_t base; + + /// + // Called 0 or more times between CefBeginTracing and OnEndTracingComplete + // with a UTF8 JSON |fragment| of the specified |fragment_size|. Do not keep a + // reference to |fragment|. + /// + void (CEF_CALLBACK *on_trace_data_collected)(struct _cef_trace_client_t* self, + const char* fragment, size_t fragment_size); + + /// + // Called in response to CefGetTraceBufferPercentFullAsync. + /// + void (CEF_CALLBACK *on_trace_buffer_percent_full_reply)( + struct _cef_trace_client_t* self, float percent_full); + + /// + // Called after all processes have sent their trace data. + /// + void (CEF_CALLBACK *on_end_tracing_complete)( + struct _cef_trace_client_t* self); +} cef_trace_client_t; + + +#ifdef __cplusplus +} +#endif + +#endif // CEF_INCLUDE_CAPI_CEF_TRACE_CAPI_H_ diff --git a/include/cef_trace.h b/include/cef_trace.h new file mode 100644 index 000000000..08c8e30b9 --- /dev/null +++ b/include/cef_trace.h @@ -0,0 +1,124 @@ +// Copyright (c) 2012 Marshall A. Greenblatt. Portons copyright (c) 2012 +// Google Inc. 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 must follow a specific format in order to +// support the CEF translator tool. See the translator.README.txt file in the +// tools directory for more information. +// + +// See cef_trace_event.h for trace macros and additonal documentation. + +#ifndef CEF_INCLUDE_CEF_TRACE_H_ +#define CEF_INCLUDE_CEF_TRACE_H_ +#pragma once + +#include "include/cef_base.h" + +/// +// Implement this interface to receive trace notifications. The methods of this +// class will be called on the browser process UI thread. +/// +/*--cef(source=client)--*/ +class CefTraceClient : public virtual CefBase { + public: + /// + // Called 0 or more times between CefBeginTracing and OnEndTracingComplete + // with a UTF8 JSON |fragment| of the specified |fragment_size|. Do not keep + // a reference to |fragment|. + /// + /*--cef()--*/ + virtual void OnTraceDataCollected(const char* fragment, + size_t fragment_size) {} + + /// + // Called in response to CefGetTraceBufferPercentFullAsync. + /// + /*--cef()--*/ + virtual void OnTraceBufferPercentFullReply(float percent_full) {} + + /// + // Called after all processes have sent their trace data. + /// + /*--cef()--*/ + virtual void OnEndTracingComplete() {} +}; + + +/// +// Start tracing events on all processes. Tracing begins immediately locally, +// and asynchronously on child processes as soon as they receive the +// BeginTracing request. +// +// If CefBeginTracing was called previously, or if a CefEndTracingAsync call is +// pending, CefBeginTracing will fail and return false. +// +// |categories| is a comma-delimited list of category wildcards. A category can +// have an optional '-' prefix to make it an excluded category. Having both +// included and excluded categories in the same list is not supported. +// +// Example: "test_MyTest*" +// Example: "test_MyTest*,test_OtherStuff" +// Example: "-excluded_category1,-excluded_category2" +// +// This function must be called on the browser process UI thread. +/// +/*--cef(optional_param=client,optional_param=categories)--*/ +bool CefBeginTracing(CefRefPtr client, + const CefString& categories); + +/// +// Get the maximum trace buffer percent full state across all processes. +// +// CefTraceClient::OnTraceBufferPercentFullReply will be called asynchronously +// after the value is determibed. When any child process reaches 100% full +// tracing will end automatically and CefTraceClient::OnEndTracingComplete +// will be called. This function fails and returns false if trace is ending or +// disabled, no CefTraceClient was passed to CefBeginTracing, or if a previous +// call to CefGetTraceBufferPercentFullAsync is pending. +// +// This function must be called on the browser process UI thread. +/// +/*--cef()--*/ +bool CefGetTraceBufferPercentFullAsync(); + +/// +// Stop tracing events on all processes. +// +// This function will fail and return false if a previous call to +// CefEndTracingAsync is already pending or if CefBeginTracing was not called. +// +// This function must be called on the browser process UI thread. +/// +/*--cef()--*/ +bool CefEndTracingAsync(); + +#endif // CEF_INCLUDE_CEF_TRACE_H_ diff --git a/include/cef_trace_event.h b/include/cef_trace_event.h new file mode 100644 index 000000000..b93a2cf9a --- /dev/null +++ b/include/cef_trace_event.h @@ -0,0 +1,465 @@ +// Copyright (c) 2012 Marshall A. Greenblatt. Portions copyright (c) 2012 +// Google Inc. 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. + +/// +// Trace events are for tracking application performance and resource usage. +// Macros are provided to track: +// Begin and end of function calls +// Counters +// +// Events are issued against categories. Whereas LOG's categories are statically +// defined, TRACE categories are created implicitly with a string. For example: +// CEF_TRACE_EVENT_INSTANT0("MY_SUBSYSTEM", "SomeImportantEvent") +// +// Events can be INSTANT, or can be pairs of BEGIN and END in the same scope: +// CEF_TRACE_EVENT_BEGIN0("MY_SUBSYSTEM", "SomethingCostly") +// doSomethingCostly() +// CEF_TRACE_EVENT_END0("MY_SUBSYSTEM", "SomethingCostly") +// Note: Our tools can't always determine the correct BEGIN/END pairs unless +// these are used in the same scope. Use ASYNC_BEGIN/ASYNC_END macros if you +// need them to be in separate scopes. +// +// A common use case is to trace entire function scopes. This issues a trace +// BEGIN and END automatically: +// void doSomethingCostly() { +// CEF_TRACE_EVENT0("MY_SUBSYSTEM", "doSomethingCostly"); +// ... +// } +// +// Additional parameters can be associated with an event: +// void doSomethingCostly2(int howMuch) { +// CEF_TRACE_EVENT1("MY_SUBSYSTEM", "doSomethingCostly", +// "howMuch", howMuch); +// ... +// } +// +// The trace system will automatically add to this information the current +// process id, thread id, and a timestamp in microseconds. +// +// To trace an asynchronous procedure such as an IPC send/receive, use +// ASYNC_BEGIN and ASYNC_END: +// [single threaded sender code] +// static int send_count = 0; +// ++send_count; +// CEF_TRACE_EVENT_ASYNC_BEGIN0("ipc", "message", send_count); +// Send(new MyMessage(send_count)); +// [receive code] +// void OnMyMessage(send_count) { +// CEF_TRACE_EVENT_ASYNC_END0("ipc", "message", send_count); +// } +// The third parameter is a unique ID to match ASYNC_BEGIN/ASYNC_END pairs. +// ASYNC_BEGIN and ASYNC_END can occur on any thread of any traced process. +// Pointers can be used for the ID parameter, and they will be mangled +// internally so that the same pointer on two different processes will not +// match. For example: +// class MyTracedClass { +// public: +// MyTracedClass() { +// CEF_TRACE_EVENT_ASYNC_BEGIN0("category", "MyTracedClass", this); +// } +// ~MyTracedClass() { +// CEF_TRACE_EVENT_ASYNC_END0("category", "MyTracedClass", this); +// } +// } +// +// The trace event also supports counters, which is a way to track a quantity +// as it varies over time. Counters are created with the following macro: +// CEF_TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter", g_myCounterValue); +// +// Counters are process-specific. The macro itself can be issued from any +// thread, however. +// +// Sometimes, you want to track two counters at once. You can do this with two +// counter macros: +// CEF_TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter0", g_myCounterValue[0]); +// CEF_TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter1", g_myCounterValue[1]); +// Or you can do it with a combined macro: +// CEF_TRACE_COUNTER2("MY_SUBSYSTEM", "myCounter", +// "bytesPinned", g_myCounterValue[0], +// "bytesAllocated", g_myCounterValue[1]); +// This indicates to the tracing UI that these counters should be displayed +// in a single graph, as a summed area chart. +// +// Since counters are in a global namespace, you may want to disembiguate with a +// unique ID, by using the CEF_TRACE_COUNTER_ID* variations. +// +// By default, trace collection is compiled in, but turned off at runtime. +// Collecting trace data is the responsibility of the embedding application. In +// CEF's case, calling BeginTracing will turn on tracing on all active +// processes. +// +// +// Memory scoping note: +// Tracing copies the pointers, not the string content, of the strings passed +// in for category, name, and arg_names. Thus, the following code will cause +// problems: +// char* str = strdup("impprtantName"); +// CEF_TRACE_EVENT_INSTANT0("SUBSYSTEM", str); // BAD! +// free(str); // Trace system now has dangling pointer +// +// To avoid this issue with the |name| and |arg_name| parameters, use the +// CEF_TRACE_EVENT_COPY_XXX overloads of the macros at additional runtime +// overhead. +// Notes: The category must always be in a long-lived char* (i.e. static const). +// The |arg_values|, when used, are always deep copied with the _COPY +// macros. +// +// +// Thread Safety: +// All macros are thread safe and can be used from any process. +/// + +#ifndef CEF_INCLUDE_CEF_TRACE_EVENT_H_ +#define CEF_INCLUDE_CEF_TRACE_EVENT_H_ +#pragma once + +#include "include/internal/cef_export.h" +#include "include/internal/cef_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Functions for tracing counters and functions; called from macros. +// - |category| string must have application lifetime (static or literal). They +// may not include "(quotes) chars. +// - |argX_name|, |argX_val|, |valueX_name|, |valeX_val| are optional parameters +// and represent pairs of name and values of arguments +// - |copy| is used to avoid memory scoping issues with the |name| and +// |arg_name| parameters by copying them +// - |id| is used to disambiguate counters with the same name, or match async +// trace events + +CEF_EXPORT void cef_trace_event(const char* category, + const char* name, + const char* arg1_name, + uint64 arg1_val, + const char* arg2_name, + uint64 arg2_val); +CEF_EXPORT void cef_trace_event_instant(const char* category, + const char* name, + const char* arg1_name, + uint64 arg1_val, + const char* arg2_name, + uint64 arg2_val, + int copy); +CEF_EXPORT void cef_trace_event_begin(const char* category, + const char* name, + const char* arg1_name, + uint64 arg1_val, + const char* arg2_name, + uint64 arg2_val, + int copy); +CEF_EXPORT void cef_trace_event_end(const char* category, + const char* name, + const char* arg1_name, + uint64 arg1_val, + const char* arg2_name, + uint64 arg2_val, + int copy); +CEF_EXPORT void cef_trace_event_if_longer_than(long long threshold_us, + const char* category, + const char* name, + const char* arg1_name, + uint64 arg1_val, + const char* arg2_name, + uint64 arg2_val); +CEF_EXPORT void cef_trace_counter(const char* category, + const char* name, + const char* value1_name, + uint64 value1_val, + const char* value2_name, + uint64 value2_val, + int copy); +CEF_EXPORT void cef_trace_counter_id(const char* category, + const char* name, + uint64 id, + const char* value1_name, + uint64 value1_val, + const char* value2_name, + uint64 value2_val, + int copy); +CEF_EXPORT void cef_trace_event_async_begin(const char* category, + const char* name, + uint64 id, + const char* arg1_name, + uint64 arg1_val, + const char* arg2_name, + uint64 arg2_val, + int copy); +CEF_EXPORT void cef_trace_event_async_step(const char* category, + const char* name, + uint64 id, + uint64 step, + const char* arg1_name, + uint64 arg1_val, + int copy); +CEF_EXPORT void cef_trace_event_async_end(const char* category, + const char* name, + uint64 id, + const char* arg1_name, + uint64 arg1_val, + const char* arg2_name, + uint64 arg2_val, + int copy); + +#ifdef __cplusplus +} +#endif + +// Records a pair of begin and end events called "name" for the current +// scope, with 0, 1 or 2 associated arguments. If the category is not +// enabled, then this does nothing. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +#define CEF_TRACE_EVENT0(category, name) \ + cef_trace_event(category, name, NULL, 0, NULL, 0) +#define CEF_TRACE_EVENT1(category, name, arg1_name, arg1_val) \ + cef_trace_event(category, name, arg1_name, arg1_val, NULL, 0) +#define CEF_TRACE_EVENT2(category, name, arg1_name, arg1_val, arg2_name, \ + arg2_val) \ + cef_trace_event(category, name, arg1_name, arg1_val, arg2_name, arg2_val) + +// Records a single event called "name" immediately, with 0, 1 or 2 +// associated arguments. If the category is not enabled, then this +// does nothing. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +#define CEF_TRACE_EVENT_INSTANT0(category, name) \ + cef_trace_event_instant(category, name, NULL, 0, NULL, 0, false) +#define CEF_TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) \ + cef_trace_event_instant(category, name, arg1_name, arg1_val, NULL, 0, false) +#define CEF_TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + cef_trace_event_instant(category, name, arg1_name, arg1_val, arg2_name, \ + arg2_val, false) +#define CEF_TRACE_EVENT_COPY_INSTANT0(category, name) \ + cef_trace_event_instant(category, name, NULL, 0, NULL, 0, true) +#define CEF_TRACE_EVENT_COPY_INSTANT1(category, name, arg1_name, arg1_val) \ + cef_trace_event_instant(category, name, arg1_name, arg1_val, NULL, 0, true) +#define CEF_TRACE_EVENT_COPY_INSTANT2(category, name, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + cef_trace_event_instant(category, name, arg1_name, arg1_val, arg2_name, \ + arg2_val, true) + +// Records a single BEGIN event called "name" immediately, with 0, 1 or 2 +// associated arguments. If the category is not enabled, then this +// does nothing. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +#define CEF_TRACE_EVENT_BEGIN0(category, name) \ + cef_trace_event_begin(category, name, NULL, 0, NULL, 0, false) +#define CEF_TRACE_EVENT_BEGIN1(category, name, arg1_name, arg1_val) \ + cef_trace_event_begin(category, name, arg1_name, arg1_val, NULL, 0, false) +#define CEF_TRACE_EVENT_BEGIN2(category, name, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + cef_trace_event_begin(category, name, arg1_name, arg1_val, arg2_name, \ + arg2_val, false) +#define CEF_TRACE_EVENT_COPY_BEGIN0(category, name) \ + cef_trace_event_begin(category, name, NULL, 0, NULL, 0, true) +#define CEF_TRACE_EVENT_COPY_BEGIN1(category, name, arg1_name, arg1_val) \ + cef_trace_event_begin(category, name, arg1_name, arg1_val, NULL, 0, true) +#define CEF_TRACE_EVENT_COPY_BEGIN2(category, name, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + cef_trace_event_begin(category, name, arg1_name, arg1_val, arg2_name, \ + arg2_val, true) + +// Records a single END event for "name" immediately. If the category +// is not enabled, then this does nothing. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +#define CEF_TRACE_EVENT_END0(category, name) \ + cef_trace_event_end(category, name, NULL, 0, NULL, 0, false) +#define CEF_TRACE_EVENT_END1(category, name, arg1_name, arg1_val) \ + cef_trace_event_end(category, name, arg1_name, arg1_val, NULL, 0, false) +#define CEF_TRACE_EVENT_END2(category, name, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + cef_trace_event_end(category, name, arg1_name, arg1_val, arg2_name, \ + arg2_val, false) +#define CEF_TRACE_EVENT_COPY_END0(category, name) \ + cef_trace_event_end(category, name, NULL, 0, NULL, 0, true) +#define CEF_TRACE_EVENT_COPY_END1(category, name, arg1_name, arg1_val) \ + cef_trace_event_end(category, name, arg1_name, arg1_val, NULL, 0, true) +#define CEF_TRACE_EVENT_COPY_END2(category, name, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + cef_trace_event_end(category, name, arg1_name, arg1_val, arg2_name, \ + arg2_val, true) + +// Time threshold event: +// Only record the event if the duration is greater than the specified +// threshold_us (time in microseconds). +// Records a pair of begin and end events called "name" for the current +// scope, with 0, 1 or 2 associated arguments. If the category is not +// enabled, then this does nothing. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +#define CEF_TRACE_EVENT_IF_LONGER_THAN0(threshold_us, category, name) \ + cef_trace_event_if_longer_than(threshold_us, category, name, NULL, 0, NULL, 0) +#define CEF_TRACE_EVENT_IF_LONGER_THAN1(threshold_us, category, name, \ + arg1_name, arg1_val) \ + cef_trace_event_if_longer_than(threshold_us, category, name, arg1_name, \ + arg1_val, NULL, 0) +#define CEF_TRACE_EVENT_IF_LONGER_THAN2(threshold_us, category, name, \ + arg1_name, arg1_val, arg2_name, arg2_val) \ + cef_trace_event_if_longer_than(threshold_us, category, name, arg1_name, \ + arg1_val, arg2_name, arg2_val) + +// Records the value of a counter called "name" immediately. Value +// must be representable as a 32 bit integer. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +#define CEF_TRACE_COUNTER1(category, name, value) \ + cef_trace_counter(category, name, NULL, value, NULL, 0, false) +#define CEF_TRACE_COPY_COUNTER1(category, name, value) \ + cef_trace_counter(category, name, NULL, value, NULL, 0, true) + +// Records the values of a multi-parted counter called "name" immediately. +// The UI will treat value1 and value2 as parts of a whole, displaying their +// values as a stacked-bar chart. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +#define CEF_TRACE_COUNTER2(category, name, value1_name, value1_val, \ + value2_name, value2_val) \ + cef_trace_counter(category, name, value1_name, value1_val, value2_name, \ + value2_val, false) +#define CEF_TRACE_COPY_COUNTER2(category, name, value1_name, value1_val, \ + value2_name, value2_val) \ + cef_trace_counter(category, name, value1_name, value1_val, value2_name, \ + value2_val, true) + +// Records the value of a counter called "name" immediately. Value +// must be representable as a 32 bit integer. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +// - |id| is used to disambiguate counters with the same name. It must either +// be a pointer or an integer value up to 64 bits. If it's a pointer, the +// bits will be xored with a hash of the process ID so that the same pointer +// on two different processes will not collide. +#define CEF_TRACE_COUNTER_ID1(category, name, id, value) \ + cef_trace_counter_id(category, name, id, NULL, value, NULL, 0, false) +#define CEF_TRACE_COPY_COUNTER_ID1(category, name, id, value) \ + cef_trace_counter_id(category, name, id, NULL, value, NULL, 0, true) + +// Records the values of a multi-parted counter called "name" immediately. +// The UI will treat value1 and value2 as parts of a whole, displaying their +// values as a stacked-bar chart. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +// - |id| is used to disambiguate counters with the same name. It must either +// be a pointer or an integer value up to 64 bits. If it's a pointer, the +// bits will be xored with a hash of the process ID so that the same pointer +// on two different processes will not collide. +#define CEF_TRACE_COUNTER_ID2(category, name, id, value1_name, value1_val, \ + value2_name, value2_val) \ + cef_trace_counter_id(category, name, id, value1_name, value1_val, \ + value2_name, value2_val, false) +#define CEF_TRACE_COPY_COUNTER_ID2(category, name, id, value1_name, \ + value1_val, value2_name, value2_val) \ + cef_trace_counter_id(category, name, id, value1_name, value1_val, \ + value2_name, value2_val, true) + + +// Records a single ASYNC_BEGIN event called "name" immediately, with 0, 1 or 2 +// associated arguments. If the category is not enabled, then this +// does nothing. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +// - |id| is used to match the ASYNC_BEGIN event with the ASYNC_END event. +// ASYNC events are considered to match if their category, name and id values +// all match. |id| must either be a pointer or an integer value up to 64 +// bits. If it's a pointer, the bits will be xored with a hash of the process +// ID sothat the same pointer on two different processes will not collide. +// An asynchronous operation can consist of multiple phases. The first phase is +// defined by the ASYNC_BEGIN calls. Additional phases can be defined using the +// ASYNC_STEP_BEGIN macros. When the operation completes, call ASYNC_END. +// An async operation can span threads and processes, but all events in that +// operation must use the same |name| and |id|. Each event can have its own +// args. +#define CEF_TRACE_EVENT_ASYNC_BEGIN0(category, name, id) \ + cef_trace_event_async_begin(category, name, id, NULL, 0, NULL, 0, false) +#define CEF_TRACE_EVENT_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \ + cef_trace_event_async_begin(category, name, id, arg1_name, arg1_val, NULL, \ + 0, false) +#define CEF_TRACE_EVENT_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + cef_trace_event_async_begin(category, name, id, arg1_name, arg1_val, \ + arg2_name, arg2_val, false) +#define CEF_TRACE_EVENT_COPY_ASYNC_BEGIN0(category, name, id) \ + cef_trace_event_async_begin(category, name, id, NULL, 0, NULL, 0, true) +#define CEF_TRACE_EVENT_COPY_ASYNC_BEGIN1(category, name, id, arg1_name, \ + arg1_val) \ + cef_trace_event_async_begin(category, name, id, arg1_name, arg1_val, NULL, \ + 0, true) +#define CEF_TRACE_EVENT_COPY_ASYNC_BEGIN2(category, name, id, arg1_name, \ + arg1_val, arg2_name, arg2_val) \ + cef_trace_event_async_begin(category, name, id, arg1_name, arg1_val, \ + arg2_name, arg2_val, true) + +// Records a single ASYNC_STEP event for |step| immediately. If the category +// is not enabled, then this does nothing. The |name| and |id| must match the +// ASYNC_BEGIN event above. The |step| param identifies this step within the +// async event. This should be called at the beginning of the next phase of an +// asynchronous operation. +#define CEF_TRACE_EVENT_ASYNC_STEP0(category, name, id, step) \ + cef_trace_event_async_step(category, name, id, step, NULL, 0, false) +#define CEF_TRACE_EVENT_ASYNC_STEP1(category, name, id, step, \ + arg1_name, arg1_val) \ + cef_trace_event_async_step(category, name, id, step, arg1_name, arg1_val, \ + false) +#define CEF_TRACE_EVENT_COPY_ASYNC_STEP0(category, name, id, step) \ + cef_trace_event_async_step(category, name, id, step, NULL, 0, true) +#define CEF_TRACE_EVENT_COPY_ASYNC_STEP1(category, name, id, step, \ + arg1_name, arg1_val) \ + cef_trace_event_async_step(category, name, id, step, arg1_name, arg1_val, \ + true) + +// Records a single ASYNC_END event for "name" immediately. If the category +// is not enabled, then this does nothing. +#define CEF_TRACE_EVENT_ASYNC_END0(category, name, id) \ + cef_trace_event_async_end(category, name, id, NULL, 0, NULL, 0, false) +#define CEF_TRACE_EVENT_ASYNC_END1(category, name, id, arg1_name, arg1_val) \ + cef_trace_event_async_end(category, name, id, arg1_name, arg1_val, NULL, 0, \ + false) +#define CEF_TRACE_EVENT_ASYNC_END2(category, name, id, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + cef_trace_event_async_end(category, name, id, arg1_name, arg1_val, \ + arg2_name, arg2_val, false) +#define CEF_TRACE_EVENT_COPY_ASYNC_END0(category, name, id) \ + cef_trace_event_async_end(category, name, id, NULL, 0, NULL, 0, true) +#define CEF_TRACE_EVENT_COPY_ASYNC_END1(category, name, id, arg1_name, \ + arg1_val) \ + cef_trace_event_async_end(category, name, id, arg1_name, arg1_val, NULL, 0, \ + true) +#define CEF_TRACE_EVENT_COPY_ASYNC_END2(category, name, id, arg1_name, \ + arg1_val, arg2_name, arg2_val) \ + cef_trace_event_async_end(category, name, id, arg1_name, arg1_val, \ + arg2_name, arg2_val, true) + +#endif // CEF_INCLUDE_CEF_TRACE_EVENT_H_ diff --git a/include/internal/cef_string_wrappers.h b/include/internal/cef_string_wrappers.h index b3012331b..135fed6b1 100644 --- a/include/internal/cef_string_wrappers.h +++ b/include/internal/cef_string_wrappers.h @@ -422,6 +422,18 @@ class CefStringBase { traits::clear(string_); } + /// + // Swap this string's contents with the specified string. + /// + void swap(CefStringBase& str) { + struct_type* tmp_string = string_; + bool tmp_owner = owner_; + string_ = str.string_; + owner_ = str.owner_; + str.string_ = tmp_string; + str.owner_ = tmp_owner; + } + // The following methods are unique to CEF string template types. diff --git a/libcef/browser/browser_host_impl.cc b/libcef/browser/browser_host_impl.cc index 70440acdc..aa4bfbba2 100644 --- a/libcef/browser/browser_host_impl.cc +++ b/libcef/browser/browser_host_impl.cc @@ -9,6 +9,7 @@ #include #include "libcef/browser/browser_context.h" +#include "libcef/browser/chrome_scheme_handler.h" #include "libcef/browser/context.h" #include "libcef/browser/devtools_delegate.h" #include "libcef/browser/navigate_params.h" @@ -651,21 +652,14 @@ void CefBrowserHostImpl::GetFrameNames(std::vector& names) { bool CefBrowserHostImpl::SendProcessMessage( CefProcessId target_process, CefRefPtr message) { - DCHECK_EQ(PID_RENDERER, target_process); DCHECK(message.get()); Cef_Request_Params params; CefProcessMessageImpl* impl = static_cast(message.get()); if (impl->CopyTo(params)) { - DCHECK(!params.name.empty()); - - params.frame_id = -1; - params.user_initiated = true; - params.request_id = -1; - params.expect_response = false; - - return Send(new CefMsg_Request(routing_id(), params)); + return SendProcessMessage(target_process, params.name, ¶ms.arguments, + true); } return false; @@ -836,8 +830,8 @@ void CefBrowserHostImpl::LoadURL(int64 frame_id, const std::string& url) { } } -void CefBrowserHostImpl::LoadString(int64 frame_id, const CefString& string, - const CefString& url) { +void CefBrowserHostImpl::LoadString(int64 frame_id, const std::string& string, + const std::string& url) { // Only known frame ids or kMainFrameId are supported. DCHECK(frame_id >= CefFrameHostImpl::kMainFrameId); @@ -848,15 +842,15 @@ void CefBrowserHostImpl::LoadString(int64 frame_id, const CefString& string, params.request_id = -1; params.expect_response = false; - params.arguments.Append(base::Value::CreateStringValue(string.ToString16())); - params.arguments.Append(base::Value::CreateStringValue(url.ToString16())); + params.arguments.Append(base::Value::CreateStringValue(string)); + params.arguments.Append(base::Value::CreateStringValue(url)); Send(new CefMsg_Request(routing_id(), params)); } void CefBrowserHostImpl::SendCommand( int64 frame_id, - const CefString& command, + const std::string& command, CefRefPtr responseHandler) { // Only known frame ids are supported. DCHECK(frame_id > CefFrameHostImpl::kMainFrameId); @@ -877,8 +871,7 @@ void CefBrowserHostImpl::SendCommand( params.expect_response = false; } - params.arguments.Append( - base::Value::CreateStringValue(command.ToString16())); + params.arguments.Append(base::Value::CreateStringValue(command)); Send(new CefMsg_Request(routing_id(), params)); } else { @@ -891,8 +884,8 @@ void CefBrowserHostImpl::SendCommand( void CefBrowserHostImpl::SendCode( int64 frame_id, bool is_javascript, - const CefString& code, - const CefString& script_url, + const std::string& code, + const std::string& script_url, int script_start_line, CefRefPtr responseHandler) { // Only known frame ids are supported. @@ -916,9 +909,8 @@ void CefBrowserHostImpl::SendCode( } params.arguments.Append(base::Value::CreateBooleanValue(is_javascript)); - params.arguments.Append(base::Value::CreateStringValue(code.ToString16())); - params.arguments.Append( - base::Value::CreateStringValue(script_url.ToString16())); + params.arguments.Append(base::Value::CreateStringValue(code)); + params.arguments.Append(base::Value::CreateStringValue(script_url)); params.arguments.Append(base::Value::CreateIntegerValue(script_start_line)); Send(new CefMsg_Request(routing_id(), params)); @@ -929,6 +921,25 @@ void CefBrowserHostImpl::SendCode( } } +bool CefBrowserHostImpl::SendProcessMessage(CefProcessId target_process, + const std::string& name, + base::ListValue* arguments, + bool user_initiated) { + DCHECK_EQ(PID_RENDERER, target_process); + DCHECK(!name.empty()); + + Cef_Request_Params params; + params.name = name; + if (arguments) + params.arguments.Swap(arguments); + params.frame_id = -1; + params.user_initiated = user_initiated; + params.request_id = -1; + params.expect_response = false; + + return Send(new CefMsg_Request(routing_id(), params)); +} + bool CefBrowserHostImpl::ViewText(const std::string& text) { return PlatformViewText(text); } @@ -1433,6 +1444,8 @@ void CefBrowserHostImpl::OnRequest(const Cef_Request_Params& params) { message.get()); message->Detach(NULL); } + } else if (params.name == scheme::kChromeProcessMessage) { + scheme::OnChromeProcessMessage(this, params.arguments); } else { // Invalid request. NOTREACHED(); diff --git a/libcef/browser/browser_host_impl.h b/libcef/browser/browser_host_impl.h index 60c4beda2..48923a160 100644 --- a/libcef/browser/browser_host_impl.h +++ b/libcef/browser/browser_host_impl.h @@ -167,18 +167,23 @@ class CefBrowserHostImpl : public CefBrowserHost, void LoadURL(int64 frame_id, const std::string& url); // Load the specified string. - void LoadString(int64 frame_id, const CefString& string, - const CefString& url); + void LoadString(int64 frame_id, const std::string& string, + const std::string& url); // Send a command to the renderer for execution. - void SendCommand(int64 frame_id, const CefString& command, + void SendCommand(int64 frame_id, const std::string& command, CefRefPtr responseHandler); // Send code to the renderer for execution. - void SendCode(int64 frame_id, bool is_javascript, const CefString& code, - const CefString& script_url, int script_start_line, + void SendCode(int64 frame_id, bool is_javascript, const std::string& code, + const std::string& script_url, int script_start_line, CefRefPtr responseHandler); + bool SendProcessMessage(CefProcessId target_process, + const std::string& name, + base::ListValue* arguments, + bool user_initiated); + // Open the specified text in the default text editor. bool ViewText(const std::string& text); diff --git a/libcef/browser/chrome_scheme_handler.cc b/libcef/browser/chrome_scheme_handler.cc index 751c1a82c..516cb5bf8 100644 --- a/libcef/browser/chrome_scheme_handler.cc +++ b/libcef/browser/chrome_scheme_handler.cc @@ -1,21 +1,32 @@ -// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights -// reserved. Use of this source code is governed by a BSD-style license that can -// be found in the LICENSE file. +// Copyright (c) 2012 The Chromium Embedded Framework Authors. +// Portions copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. #include "libcef/browser/chrome_scheme_handler.h" + #include #include + +#include "include/cef_trace.h" #include "include/cef_version.h" #include "include/cef_web_plugin.h" #include "libcef/browser/context.h" +#include "libcef/browser/frame_host_impl.h" #include "libcef/browser/internal_scheme_handler.h" +#include "libcef/browser/thread_util.h" + #include "base/command_line.h" +#include "base/file_util.h" +#include "base/logging.h" #include "base/path_service.h" #include "base/string_util.h" #include "base/stringprintf.h" #include "base/utf_string_conversions.h" +#include "base/values.h" #include "content/public/common/content_client.h" #include "grit/cef_resources.h" +#include "ipc/ipc_channel.h" #include "v8/include/v8.h" #include "webkit/user_agent/user_agent_util.h" @@ -23,17 +34,20 @@ namespace scheme { const char kChromeScheme[] = "chrome"; const char kChromeURL[] = "chrome://"; +const char kChromeProcessMessage[] = "chrome.send"; namespace { const char kChromeCreditsDomain[] = "credits"; const char kChromeLicenseDomain[] = "license"; +const char kChromeTracingDomain[] = "tracing"; const char kChromeVersionDomain[] = "version"; enum ChromeDomain { CHROME_UNKNOWN = 0, CHROME_CREDITS, CHROME_LICENSE, + CHROME_TRACING, CHROME_VERSION, }; @@ -44,6 +58,7 @@ ChromeDomain GetChromeDomain(const std::string& domain_name) { } domains[] = { { kChromeCreditsDomain, CHROME_CREDITS }, { kChromeLicenseDomain, CHROME_LICENSE }, + { kChromeTracingDomain, CHROME_TRACING }, { kChromeVersionDomain, CHROME_VERSION }, }; @@ -184,6 +199,9 @@ class Delegate : public InternalHandlerDelegate { case CHROME_LICENSE: handled = OnLicense(action); break; + case CHROME_TRACING: + handled = OnTracing(path, action); + break; case CHROME_VERSION: handled = OnVersion(action); break; @@ -192,6 +210,8 @@ class Delegate : public InternalHandlerDelegate { } if (!handled && domain != CHROME_VERSION) { + DLOG(INFO) << "Reguest for unknown chrome resource: " << + url.spec().c_str(); action->redirect_url = GURL(std::string(kChromeURL) + kChromeVersionDomain); } @@ -230,6 +250,16 @@ class Delegate : public InternalHandlerDelegate { return true; } + bool OnTracing(const std::string& path, Action* action) { + if (path == "tracing.js") { + action->resource_id = IDR_CEF_TRACING_JS; + } else { + action->mime_type = "text/html"; + action->resource_id = IDR_CEF_TRACING_HTML; + } + return true; + } + bool OnVersion(Action* action) { base::StringPiece piece = content::GetContentClient()->GetDataResource( IDR_CEF_VERSION_HTML, ui::SCALE_FACTOR_NONE); @@ -308,6 +338,262 @@ void DidFinishChromeVersionLoad(CefRefPtr frame) { CefVisitWebPluginInfo(new Visitor(frame)); } +// Test that the tracing browser window hasn't closed or navigated elsewhere. +bool IsTraceFrameValid(CefRefPtr frame) { + if (!frame->IsValid()) + return false; + + std::string tracing_url(kChromeURL); + tracing_url += kChromeTracingDomain; + + std::string url = frame->GetURL(); + if (url.find(tracing_url.c_str()) != 0) + return false; + + return true; +} + +void LoadTraceFile(CefRefPtr frame, const FilePath& path) { + CEF_REQUIRE_FILET(); + + if (!IsTraceFrameValid(frame)) + return; + + std::string file_contents; + if (!file_util::ReadFileToString(path, &file_contents)) { + frame->SendJavaScript( + "tracingController.onLoadTraceFileCanceled();", std::string(), 0); + return; + } + + // We need to escape the file contents, because it will go into a javascript + // quoted string in LoadTraceFileSuccess. We need to escape control characters + // (to have well-formed javascript statements), as well as \ and ' (the only + // special characters in a ''-quoted string). Do the escaping on this thread, + // it may take a little while for big files and we don't want to block the UI + // during that time. Also do the UTF-16 conversion here. + // Note: we're using UTF-16 because we'll need to cut the string into slices + // to give to Javascript, and it's easier to cut than UTF-8 (since JS strings + // are arrays of 16-bit values, UCS-2 really, whereas we can't cut inside of a + // multibyte UTF-8 codepoint). + size_t size = file_contents.size(); + std::string escaped_contents; + escaped_contents.reserve(size); + for (size_t i = 0; i < size; ++i) { + char c = file_contents[i]; + if (c < ' ') { + escaped_contents += base::StringPrintf("\\u%04x", c); + continue; + } + if (c == '\\' || c == '\'') + escaped_contents.push_back('\\'); + escaped_contents.push_back(c); + } + file_contents.clear(); + + const string16& contents16 = UTF8ToUTF16(escaped_contents); + + // We need to pass contents to tracingController.onLoadTraceFileComplete, but + // that may be arbitrarily big, and IPC messages are limited in size. So we + // need to cut it into pieces and rebuild the string in Javascript. + // IPC::Channel::kMaximumMessageSize is in bytes, and we need to account for + // overhead. + static const size_t kMaxSize = IPC::Channel::kMaximumMessageSize / 2 - 128; + const string16& first_prefix = ASCIIToUTF16("window.traceData = '"); + const string16& prefix = ASCIIToUTF16("window.traceData += '"); + const string16& suffix = ASCIIToUTF16("';"); + + for (size_t i = 0; i < contents16.size(); i += kMaxSize) { + string16 javascript = i == 0 ? first_prefix : prefix; + javascript += contents16.substr(i, kMaxSize) + suffix; + frame->SendJavaScript(UTF16ToUTF8(javascript), std::string(), 0); + } + + frame->SendJavaScript( + "tracingController.onLoadTraceFileComplete(JSON.parse(window.traceData));" + "delete window.traceData;", + std::string(), 0); +} + +void SaveTraceFile(CefRefPtr frame, + const FilePath& path, + scoped_ptr contents) { + CEF_REQUIRE_FILET(); + + if (!IsTraceFrameValid(frame)) + return; + + if (file_util::WriteFile(path, contents->c_str(), contents->size())) { + frame->SendJavaScript( + "tracingController.onSaveTraceFileComplete();", + std::string(), 0); + } else { + frame->SendJavaScript( + "tracingController.onSaveTraceFileCanceled();", + std::string(), 0); + } +} + +void OnChromeTracingProcessMessage(CefRefPtr browser, + const std::string& action, + const base::ListValue* arguments) { + CefRefPtr frame = + static_cast(browser->GetMainFrame().get()); + + if (action == "tracingControllerInitialized") { + // Send the client info to the tracingController. + } else if (action == "beginTracing") { + if (!arguments || arguments->GetSize() != 2) { + NOTREACHED() << "Invalid arguments to " << action.c_str(); + return; + } + + class Client : public CefTraceClient { + public: + explicit Client(CefRefPtr frame) + : frame_(frame), + ended_(false) { + } + + virtual void OnTraceDataCollected(const char* fragment, + size_t fragment_size) OVERRIDE { + const std::string& prefix = "tracingController.onTraceDataCollected(["; + const std::string& suffix = "]);"; + + std::string str; + str.reserve(prefix.size() + fragment_size + suffix.size() + 1); + str.append(prefix); + str.append(fragment, fragment_size); + str.append(suffix); + Execute(str); + } + + virtual void OnTraceBufferPercentFullReply(float percent_full) OVERRIDE { + Execute(base::StringPrintf( + "tracingController.onRequestBufferPercentFullComplete(%f);", + percent_full)); + } + + virtual void OnEndTracingComplete() OVERRIDE { + ended_ = true; + Execute("tracingController.onEndTracingComplete();"); + } + + private: + void Execute(const std::string& code) { + if (!IsTraceFrameValid(frame_) && !ended_) { + ended_ = true; + CefEndTracingAsync(); + return; + } + frame_->SendJavaScript(code, std::string(), 0); + } + + CefRefPtr frame_; + bool ended_; + IMPLEMENT_REFCOUNTING(Callback); + }; + + std::string categories; + arguments->GetString(1, &categories); + + CefRefPtr client = new Client(frame); + + // Tracing may already be running, in which case the previous client will + // continue handling it. + CefBeginTracing(client, categories); + } else if (action == "endTracingAsync") { + if (!CefEndTracingAsync()) { + // We weren't really tracing to begin with. + frame->SendJavaScript( + "tracingController.onEndTracingComplete();", + std::string(), 0); + } + } else if (action == "beginRequestBufferPercentFull") { + CefGetTraceBufferPercentFullAsync(); + } else if (action == "loadTraceFile") { + class Callback : public CefRunFileDialogCallback { + public: + explicit Callback(CefRefPtr frame) + : frame_(frame) { + } + + virtual void OnFileDialogDismissed( + CefRefPtr browser_host, + const std::vector& file_paths) OVERRIDE { + if (!IsTraceFrameValid(frame_)) + return; + + if (!file_paths.empty()) { + CEF_POST_TASK(CEF_FILET, + base::Bind(LoadTraceFile, frame_, + FilePath(file_paths.front()))); + } else { + frame_->SendJavaScript( + "tracingController.onLoadTraceFileCanceled();", + std::string(), 0); + } + } + + private: + CefRefPtr frame_; + IMPLEMENT_REFCOUNTING(Callback); + }; + + browser->GetHost()->RunFileDialog(FILE_DIALOG_OPEN, CefString(), + CefString(), std::vector(), new Callback(frame)); + } else if (action == "saveTraceFile") { + if (!arguments || arguments->GetSize() != 1) { + NOTREACHED() << "Invalid arguments to " << action.c_str(); + return; + } + + class Callback : public CefRunFileDialogCallback { + public: + Callback(CefRefPtr frame, + scoped_ptr contents) + : frame_(frame), + contents_(contents.Pass()) { + } + + virtual void OnFileDialogDismissed( + CefRefPtr browser_host, + const std::vector& file_paths) OVERRIDE { + if (!IsTraceFrameValid(frame_)) + return; + + if (!file_paths.empty()) { + CEF_POST_TASK(CEF_FILET, + base::Bind(SaveTraceFile, frame_, + FilePath(file_paths.front()), + base::Passed(contents_.Pass()))); + } else { + frame_->SendJavaScript( + "tracingController.onSaveTraceFileCanceled();", + std::string(), 0); + } + } + + private: + CefRefPtr frame_; + scoped_ptr contents_; + IMPLEMENT_REFCOUNTING(Callback); + }; + + std::string contents_str; + arguments->GetString(0, &contents_str); + + scoped_ptr contents(new std::string()); + contents_str.swap(*contents); + + browser->GetHost()->RunFileDialog(FILE_DIALOG_SAVE, CefString(), + CefString(), std::vector(), + new Callback(frame, contents.Pass())); + } else { + NOTREACHED() << "Unknown trace action: " << action.c_str(); + } +} + } // namespace void RegisterChromeHandler() { @@ -341,4 +627,26 @@ void DidFinishChromeLoad(CefRefPtr frame, } } +void OnChromeProcessMessage(CefRefPtr browser, + const base::ListValue& arguments) { + std::string action; + const base::ListValue* args = NULL; + + size_t size = arguments.GetSize(); + if (size > 0) { + arguments.GetString(0, &action); + if (size > 1) + arguments.GetList(1, &args); + } + + GURL url = GURL(browser->GetMainFrame()->GetURL().ToString()); + ChromeDomain domain = GetChromeDomain(url.host()); + switch (domain) { + case CHROME_TRACING: + OnChromeTracingProcessMessage(browser, action, args); + default: + break; + } +} + } // namespace scheme diff --git a/libcef/browser/chrome_scheme_handler.h b/libcef/browser/chrome_scheme_handler.h index 7a80a6fec..b63ea6e25 100644 --- a/libcef/browser/chrome_scheme_handler.h +++ b/libcef/browser/chrome_scheme_handler.h @@ -7,9 +7,15 @@ #pragma once #include +#include "include/cef_browser.h" #include "include/cef_frame.h" +#include "include/cef_process_message.h" #include "googleurl/src/gurl.h" +namespace base { +class ListValue; +} + namespace content { class BrowserContext; } @@ -18,6 +24,7 @@ namespace scheme { extern const char kChromeScheme[]; extern const char kChromeURL[]; +extern const char kChromeProcessMessage[]; // Register the chrome scheme handler. void RegisterChromeHandler(); @@ -30,6 +37,10 @@ bool WillHandleBrowserAboutURL(GURL* url, void DidFinishChromeLoad(CefRefPtr frame, const GURL& validated_url); +// Used to execute messages from render process bindings. +void OnChromeProcessMessage(CefRefPtr browser, + const base::ListValue& arguments); + } // namespace scheme #endif // CEF_LIBCEF_BROWSER_CHROME_SCHEME_HANDLER_H_ diff --git a/libcef/browser/context.cc b/libcef/browser/context.cc index 1e7fd7dc7..d4160038b 100644 --- a/libcef/browser/context.cc +++ b/libcef/browser/context.cc @@ -10,6 +10,7 @@ #include "libcef/browser/content_browser_client.h" #include "libcef/browser/scheme_registration.h" #include "libcef/browser/thread_util.h" +#include "libcef/browser/trace_subscriber.h" #include "libcef/common/main_delegate.h" #include "base/bind.h" @@ -356,6 +357,15 @@ CefDevToolsDelegate* CefContext::devtools_delegate() const { devtools_delegate(); } +CefTraceSubscriber* CefContext::GetTraceSubscriber() { + CEF_REQUIRE_UIT(); + if (shutting_down_) + return NULL; + if (!trace_subscriber_.get()) + trace_subscriber_.reset(new CefTraceSubscriber()); + return trace_subscriber_.get(); +} + void CefContext::OnContextInitialized() { CEF_REQUIRE_UIT(); @@ -393,6 +403,9 @@ void CefContext::FinishShutdownOnUIThread( (*it)->DestroyBrowser(); } + if (trace_subscriber_.get()) + trace_subscriber_.reset(NULL); + if (uithread_shutdown_event) uithread_shutdown_event->Signal(); } diff --git a/libcef/browser/context.h b/libcef/browser/context.h index baf860921..5976482a9 100644 --- a/libcef/browser/context.h +++ b/libcef/browser/context.h @@ -30,6 +30,7 @@ class CefBrowserContext; class CefBrowserHostImpl; class CefDevToolsDelegate; class CefMainDelegate; +class CefTraceSubscriber; class CefContext : public CefBase { public: @@ -69,6 +70,8 @@ class CefContext : public CefBase { CefBrowserContext* browser_context() const; CefDevToolsDelegate* devtools_delegate() const; + CefTraceSubscriber* GetTraceSubscriber(); + private: void OnContextInitialized(); @@ -98,6 +101,7 @@ class CefContext : public CefBase { scoped_ptr main_delegate_; scoped_ptr main_runner_; + scoped_ptr trace_subscriber_; IMPLEMENT_REFCOUNTING(CefContext); IMPLEMENT_LOCKING(CefContext); diff --git a/libcef/browser/frame_host_impl.cc b/libcef/browser/frame_host_impl.cc index 4618ca15a..a587da8e2 100644 --- a/libcef/browser/frame_host_impl.cc +++ b/libcef/browser/frame_host_impl.cc @@ -153,16 +153,7 @@ void CefFrameHostImpl::LoadString(const CefString& string, void CefFrameHostImpl::ExecuteJavaScript(const CefString& jsCode, const CefString& scriptUrl, int startLine) { - if (jsCode.empty()) - return; - if (startLine < 0) - startLine = 0; - - base::AutoLock lock_scope(state_lock_); - if (browser_) { - browser_->SendCode((is_main_frame_ ? kMainFrameId : frame_id_), true, - jsCode, scriptUrl, startLine, NULL); - } + SendJavaScript(jsCode, scriptUrl, startLine); } bool CefFrameHostImpl::IsMain() { @@ -234,6 +225,22 @@ void CefFrameHostImpl::VisitDOM(CefRefPtr visitor) { NOTREACHED() << "VisitDOM cannot be called from the browser process"; } +void CefFrameHostImpl::SendJavaScript( + const std::string& jsCode, + const std::string& scriptUrl, + int startLine) { + if (jsCode.empty()) + return; + if (startLine < 0) + startLine = 0; + + base::AutoLock lock_scope(state_lock_); + if (browser_) { + browser_->SendCode((is_main_frame_ ? kMainFrameId : frame_id_), true, + jsCode, scriptUrl, startLine, NULL); + } +} + void CefFrameHostImpl::Detach() { base::AutoLock lock_scope(state_lock_); browser_ = NULL; diff --git a/libcef/browser/frame_host_impl.h b/libcef/browser/frame_host_impl.h index eef827ff0..0b96d2dbb 100644 --- a/libcef/browser/frame_host_impl.h +++ b/libcef/browser/frame_host_impl.h @@ -56,6 +56,11 @@ class CefFrameHostImpl : public CefFrame { void SetName(const CefString& name); void SetParentId(int64 frame_id); + // Avoids unnecessary string type conversions. + void SendJavaScript(const std::string& jsCode, + const std::string& scriptUrl, + int startLine); + // Detach the frame from the browser. void Detach(); diff --git a/libcef/browser/trace_impl.cc b/libcef/browser/trace_impl.cc new file mode 100644 index 000000000..01c70df3c --- /dev/null +++ b/libcef/browser/trace_impl.cc @@ -0,0 +1,370 @@ +// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that can +// be found in the LICENSE file. + +#include "include/cef_trace.h" +#include "include/cef_trace_event.h" +#include "libcef/browser/trace_subscriber.h" +#include "libcef/browser/context.h" +#include "libcef/browser/thread_util.h" + +#include "base/debug/trace_event.h" + +bool CefBeginTracing(CefRefPtr client, + const CefString& categories) { + if (!CONTEXT_STATE_VALID()) { + NOTREACHED() << "context not valid"; + return false; + } + + if (!CEF_CURRENTLY_ON_UIT()) { + NOTREACHED() << "called on invalid thread"; + return false; + } + + CefTraceSubscriber* subscriber = _Context->GetTraceSubscriber(); + if (!subscriber) + return false; + + return subscriber->BeginTracing(client, categories); +} + +bool CefGetTraceBufferPercentFullAsync() { + if (!CONTEXT_STATE_VALID()) { + NOTREACHED() << "context not valid"; + return false; + } + + if (!CEF_CURRENTLY_ON_UIT()) { + NOTREACHED() << "called on invalid thread"; + return false; + } + + CefTraceSubscriber* subscriber = _Context->GetTraceSubscriber(); + if (!subscriber) + return false; + + return subscriber->GetTraceBufferPercentFullAsync(); +} + +bool CefEndTracingAsync() { + if (!CONTEXT_STATE_VALID()) { + NOTREACHED() << "context not valid"; + return false; + } + + if (!CEF_CURRENTLY_ON_UIT()) { + NOTREACHED() << "called on invalid thread"; + return false; + } + + CefTraceSubscriber* subscriber = _Context->GetTraceSubscriber(); + if (!subscriber) + return false; + + return subscriber->EndTracingAsync(); +} + + +// The below functions can be called from any process. + +CEF_EXPORT void cef_trace_event(const char* category, + const char* name, + const char* arg1_name, + uint64 arg1_val, + const char* arg2_name, + uint64 arg2_val) { + DCHECK(category); + DCHECK(name); + if (!category || !name) + return; + + if (arg1_name == NULL && arg2_name == NULL) { + TRACE_EVENT0(category, name); + } else if (arg2_name == NULL) { + TRACE_EVENT1(category, name, arg1_name, arg1_val); + } else { + TRACE_EVENT2(category, name, arg1_name, arg1_val, + arg2_name, arg2_val); + } +} + +CEF_EXPORT void cef_trace_event_instant(const char* category, + const char* name, + const char* arg1_name, + uint64 arg1_val, + const char* arg2_name, + uint64 arg2_val, + int copy) { + DCHECK(category); + DCHECK(name); + if (!category || !name) + return; + + if (copy) { + if (arg1_name == NULL && arg2_name == NULL) { + TRACE_EVENT_COPY_INSTANT0(category, name); + } else if (arg2_name == NULL) { + TRACE_EVENT_COPY_INSTANT1(category, name, arg1_name, arg1_val); + } else { + TRACE_EVENT_COPY_INSTANT2(category, name, arg1_name, arg1_val, + arg2_name, arg2_val); + } + } else { + if (arg1_name == NULL && arg2_name == NULL) { + TRACE_EVENT_INSTANT0(category, name); + } else if (arg2_name == NULL) { + TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val); + } else { + TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, + arg2_name, arg2_val); + } + } +} + +CEF_EXPORT void cef_trace_event_begin(const char* category, + const char* name, + const char* arg1_name, + uint64 arg1_val, + const char* arg2_name, + uint64 arg2_val, + int copy) { + DCHECK(category); + DCHECK(name); + if (!category || !name) + return; + + if (copy) { + if (arg1_name == NULL && arg2_name == NULL) { + TRACE_EVENT_COPY_BEGIN0(category, name); + } else if (arg2_name == NULL) { + TRACE_EVENT_COPY_BEGIN1(category, name, arg1_name, arg1_val); + } else { + TRACE_EVENT_COPY_BEGIN2(category, name, arg1_name, arg1_val, + arg2_name, arg2_val); + } + } else { + if (arg1_name == NULL && arg2_name == NULL) { + TRACE_EVENT_BEGIN0(category, name); + } else if (arg2_name == NULL) { + TRACE_EVENT_BEGIN1(category, name, arg1_name, arg1_val); + } else { + TRACE_EVENT_BEGIN2(category, name, arg1_name, arg1_val, + arg2_name, arg2_val); + } + } +} + +CEF_EXPORT void cef_trace_event_end(const char* category, + const char* name, + const char* arg1_name, + uint64 arg1_val, + const char* arg2_name, + uint64 arg2_val, + int copy) { + DCHECK(category); + DCHECK(name); + if (!category || !name) + return; + + if (copy) { + if (arg1_name == NULL && arg2_name == NULL) { + TRACE_EVENT_COPY_END0(category, name); + } else if (arg2_name == NULL) { + TRACE_EVENT_COPY_END1(category, name, arg1_name, arg1_val); + } else { + TRACE_EVENT_COPY_END2(category, name, arg1_name, arg1_val, + arg2_name, arg2_val); + } + } else { + if (arg1_name == NULL && arg2_name == NULL) { + TRACE_EVENT_END0(category, name); + } else if (arg2_name == NULL) { + TRACE_EVENT_END1(category, name, arg1_name, arg1_val); + } else { + TRACE_EVENT_END2(category, name, arg1_name, arg1_val, + arg2_name, arg2_val); + } + } +} + +CEF_EXPORT void cef_trace_event_if_longer_than(int64 threshold_us, + const char* category, + const char* name, + const char* arg1_name, + uint64 arg1_val, + const char* arg2_name, + uint64 arg2_val) { + DCHECK(category); + DCHECK(name); + if (!category || !name) + return; + + if (arg1_name == NULL && arg2_name == NULL) { + TRACE_EVENT_IF_LONGER_THAN0(threshold_us, category, name); + } else if (arg2_name == NULL) { + TRACE_EVENT_IF_LONGER_THAN1(threshold_us, category, name, + arg1_name, arg1_val); + } else { + TRACE_EVENT_IF_LONGER_THAN2(threshold_us, category, name, arg1_name, + arg1_val, arg2_name, arg2_val); + } +} + +CEF_EXPORT void cef_trace_counter(const char* category, + const char* name, + const char* value1_name, + uint64 value1_val, + const char* value2_name, + uint64 value2_val, + int copy) { + DCHECK(category); + DCHECK(name); + if (!category || !name) + return; + + if (copy) { + if (value1_name == NULL && value2_name == NULL) { + TRACE_COPY_COUNTER1(category, name, value1_val); + } else { + TRACE_COPY_COUNTER2(category, name, value1_name, value1_val, + value2_name, value2_val); + } + } else { + if (value1_name == NULL && value2_name == NULL) { + TRACE_COUNTER1(category, name, value1_val); + } else { + TRACE_COUNTER2(category, name, value1_name, value1_val, + value2_name, value2_val); + } + } +} + +CEF_EXPORT void cef_trace_counter_id(const char* category, + const char* name, + uint64 id, + const char* value1_name, + uint64 value1_val, + const char* value2_name, + uint64 value2_val, + int copy) { + DCHECK(category); + DCHECK(name); + if (!category || !name) + return; + + if (copy) { + if (value1_name == NULL && value2_name == NULL) { + TRACE_COPY_COUNTER_ID1(category, name, id, value1_val); + } else { + TRACE_COPY_COUNTER_ID2(category, name, id, value1_name, + value1_val, value2_name, value2_val); + } + } else { + if (value1_name == NULL && value2_name == NULL) { + TRACE_COUNTER_ID1(category, name, id, value1_val); + } else { + TRACE_COUNTER_ID2(category, name, id, value1_name, value1_val, + value2_name, value2_val); + } + } +} + +CEF_EXPORT void cef_trace_event_async_begin(const char* category, + const char* name, + uint64 id, + const char* arg1_name, + uint64 arg1_val, + const char* arg2_name, + uint64 arg2_val, + int copy) { + DCHECK(category); + DCHECK(name); + if (!category || !name) + return; + + if (copy) { + if (arg1_name == NULL && arg2_name == NULL) { + TRACE_EVENT_COPY_ASYNC_BEGIN0(category, name, id); + } else if (arg2_name == NULL) { + TRACE_EVENT_COPY_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val); + } else { + TRACE_EVENT_COPY_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, + arg2_name, arg2_val); + } + } else { + if (arg1_name == NULL && arg2_name == NULL) { + TRACE_EVENT_ASYNC_BEGIN0(category, name, id); + } else if (arg2_name == NULL) { + TRACE_EVENT_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val); + } else { + TRACE_EVENT_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, + arg2_name, arg2_val); + } + } +} + +CEF_EXPORT void cef_trace_event_async_step(const char* category, + const char* name, + uint64 id, + uint64 step, + const char* arg1_name, + uint64 arg1_val, + int copy) { + DCHECK(category); + DCHECK(name); + if (!category || !name) + return; + + if (copy) { + if (arg1_name == NULL) { + TRACE_EVENT_COPY_ASYNC_STEP0(category, name, id, step); + } else { + TRACE_EVENT_COPY_ASYNC_STEP1(category, name, id, step, + arg1_name, arg1_val); + } + } else { + if (arg1_name == NULL) { + TRACE_EVENT_ASYNC_STEP0(category, name, id, step); + } else { + TRACE_EVENT_ASYNC_STEP1(category, name, id, step, + arg1_name, arg1_val); + } + } +} + +CEF_EXPORT void cef_trace_event_async_end(const char* category, + const char* name, + uint64 id, + const char* arg1_name, + uint64 arg1_val, + const char* arg2_name, + uint64 arg2_val, + int copy) { + DCHECK(category); + DCHECK(name); + if (!category || !name) + return; + + if (copy) { + if (arg1_name == NULL && arg2_name == NULL) { + TRACE_EVENT_COPY_ASYNC_END0(category, name, id); + } else if (arg2_name == NULL) { + TRACE_EVENT_COPY_ASYNC_END1(category, name, id, arg1_name, + arg1_val); + } else { + TRACE_EVENT_COPY_ASYNC_END2(category, name, id, arg1_name, + arg1_val, arg2_name, arg2_val); + } + } else { + if (arg1_name == NULL && arg2_name == NULL) { + TRACE_EVENT_ASYNC_END0(category, name, id); + } else if (arg2_name == NULL) { + TRACE_EVENT_ASYNC_END1(category, name, id, arg1_name, + arg1_val); + } else { + TRACE_EVENT_ASYNC_END2(category, name, id, arg1_name, + arg1_val, arg2_name, arg2_val); + } + } +} diff --git a/libcef/browser/trace_subscriber.cc b/libcef/browser/trace_subscriber.cc new file mode 100644 index 000000000..896693761 --- /dev/null +++ b/libcef/browser/trace_subscriber.cc @@ -0,0 +1,78 @@ +// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that can +// be found in the LICENSE file. + +#include "libcef/browser/trace_subscriber.h" +#include "include/cef_trace.h" +#include "libcef/browser/thread_util.h" + +#include "content/public/browser/trace_controller.h" + +CefTraceSubscriber::CefTraceSubscriber() + : collecting_trace_data_(false) { + CEF_REQUIRE_UIT(); +} + +CefTraceSubscriber::~CefTraceSubscriber() { + CEF_REQUIRE_UIT(); + if (collecting_trace_data_) + content::TraceController::GetInstance()->CancelSubscriber(this); +} + +bool CefTraceSubscriber::BeginTracing(CefRefPtr client, + const std::string& categories) { + CEF_REQUIRE_UIT(); + + if (collecting_trace_data_) + return false; + + collecting_trace_data_ = true; + client_ = client; + + return content::TraceController::GetInstance()->BeginTracing( + this, categories); +} + +bool CefTraceSubscriber::EndTracingAsync() { + CEF_REQUIRE_UIT(); + + if (!collecting_trace_data_) + return false; + + return content::TraceController::GetInstance()->EndTracingAsync(this); +} + +bool CefTraceSubscriber::GetTraceBufferPercentFullAsync() { + CEF_REQUIRE_UIT(); + + if (!collecting_trace_data_ || !client_.get()) + return false; + + return content::TraceController::GetInstance()-> + GetTraceBufferPercentFullAsync(this); +} + +void CefTraceSubscriber::OnTraceDataCollected( + const scoped_refptr& trace_fragment) { + CEF_REQUIRE_UIT(); + DCHECK(collecting_trace_data_); + if (client_.get()) { + client_->OnTraceDataCollected(trace_fragment->data().c_str(), + trace_fragment->data().size()); + } +} + +void CefTraceSubscriber::OnTraceBufferPercentFullReply(float percent_full) { + CEF_REQUIRE_UIT(); + DCHECK(collecting_trace_data_); + DCHECK(client_.get()); + client_->OnTraceBufferPercentFullReply(percent_full); +} + +void CefTraceSubscriber::OnEndTracingComplete() { + CEF_REQUIRE_UIT(); + DCHECK(collecting_trace_data_); + collecting_trace_data_ = false; + if (client_.get()) + client_->OnEndTracingComplete(); +} diff --git a/libcef/browser/trace_subscriber.h b/libcef/browser/trace_subscriber.h new file mode 100644 index 000000000..3ce5e4a18 --- /dev/null +++ b/libcef/browser/trace_subscriber.h @@ -0,0 +1,38 @@ +// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that can +// be found in the LICENSE file. + +#ifndef CEF_LIBCEF_BROWSER_TRACE_SUBSCRIBER_H_ +#define CEF_LIBCEF_BROWSER_TRACE_SUBSCRIBER_H_ +#pragma once + +#include "include/cef_trace.h" + +#include "base/debug/trace_event.h" +#include "base/file_path.h" +#include "base/memory/scoped_ptr.h" +#include "content/public/browser/trace_subscriber.h" + +// May only be accessed on the browser process UI thread. +class CefTraceSubscriber : public content::TraceSubscriber { + public: + CefTraceSubscriber(); + virtual ~CefTraceSubscriber(); + + bool BeginTracing(CefRefPtr client, + const std::string& categories); + bool GetTraceBufferPercentFullAsync(); + bool EndTracingAsync(); + + private: + // content::TraceSubscriber methods: + virtual void OnTraceDataCollected( + const scoped_refptr& trace_fragment) OVERRIDE; + virtual void OnTraceBufferPercentFullReply(float percent_full) OVERRIDE; + virtual void OnEndTracingComplete() OVERRIDE; + + bool collecting_trace_data_; + CefRefPtr client_; +}; + +#endif // CEF_LIBCEF_BROWSER_TRACE_SUBSCRIBER_H_ diff --git a/libcef/common/values_impl.cc b/libcef/common/values_impl.cc index 5e1f4e96c..2a2e13ac0 100644 --- a/libcef/common/values_impl.cc +++ b/libcef/common/values_impl.cc @@ -291,7 +291,7 @@ CefString CefDictionaryValueImpl::GetString(const CefString& key) { CEF_VALUE_VERIFY_RETURN(false, CefString()); const base::Value* out_value = NULL; - string16 ret_value; + std::string ret_value; if (const_value().GetWithoutPathExpansion(key, &out_value)) out_value->GetAsString(&ret_value); @@ -392,7 +392,7 @@ bool CefDictionaryValueImpl::SetString(const CefString& key, CEF_VALUE_VERIFY_RETURN(true, false); RemoveInternal(key); mutable_value()->SetWithoutPathExpansion(key, - base::Value::CreateStringValue(value.ToString16())); + base::Value::CreateStringValue(value.ToString())); return true; } @@ -630,7 +630,7 @@ CefString CefListValueImpl::GetString(int index) { CEF_VALUE_VERIFY_RETURN(false, CefString()); const base::Value* out_value = NULL; - string16 ret_value; + std::string ret_value; if (const_value().Get(index, &out_value)) out_value->GetAsString(&ret_value); @@ -735,7 +735,7 @@ bool CefListValueImpl::SetDouble(int index, double value) { bool CefListValueImpl::SetString(int index, const CefString& value) { CEF_VALUE_VERIFY_RETURN(true, false); - base::Value* new_value = base::Value::CreateStringValue(value.ToString16()); + base::Value* new_value = base::Value::CreateStringValue(value.ToString()); if (RemoveInternal(index)) mutable_value()->Insert(index, new_value); else diff --git a/libcef/renderer/browser_impl.cc b/libcef/renderer/browser_impl.cc index 51516d2cf..664f83679 100644 --- a/libcef/renderer/browser_impl.cc +++ b/libcef/renderer/browser_impl.cc @@ -234,21 +234,12 @@ void CefBrowserImpl::GetFrameNames(std::vector& names) { bool CefBrowserImpl::SendProcessMessage(CefProcessId target_process, CefRefPtr message) { - DCHECK_EQ(PID_BROWSER, target_process); - DCHECK(message.get()); - Cef_Request_Params params; CefProcessMessageImpl* impl = static_cast(message.get()); if (impl->CopyTo(params)) { - DCHECK(!params.name.empty()); - - params.frame_id = -1; - params.user_initiated = true; - params.request_id = -1; - params.expect_response = false; - - return Send(new CefHostMsg_Request(routing_id(), params)); + return SendProcessMessage(target_process, params.name, ¶ms.arguments, + true); } return false; @@ -342,6 +333,25 @@ void CefBrowserImpl::LoadRequest(const CefMsg_LoadRequest_Params& params) { web_frame->loadRequest(request); } +bool CefBrowserImpl::SendProcessMessage(CefProcessId target_process, + const std::string& name, + base::ListValue* arguments, + bool user_initiated) { + DCHECK_EQ(PID_BROWSER, target_process); + DCHECK(!name.empty()); + + Cef_Request_Params params; + params.name = name; + if (arguments) + params.arguments.Swap(arguments); + params.frame_id = -1; + params.user_initiated = user_initiated; + params.request_id = -1; + params.expect_response = false; + + return Send(new CefHostMsg_Request(routing_id(), params)); +} + CefRefPtr CefBrowserImpl::GetWebFrameImpl( WebKit::WebFrame* frame) { DCHECK(frame); @@ -597,7 +607,7 @@ void CefBrowserImpl::OnRequest(const Cef_Request_Params& params) { DCHECK_EQ(params.arguments.GetSize(), (size_t)4); bool is_javascript = false; - string16 code, script_url; + std::string code, script_url; int script_start_line = 0; params.arguments.GetBoolean(0, &is_javascript); @@ -609,8 +619,8 @@ void CefBrowserImpl::OnRequest(const Cef_Request_Params& params) { if (is_javascript) { web_frame->executeScript( - WebScriptSource(code, - GURL(UTF16ToUTF8(script_url)), + WebScriptSource(UTF8ToUTF16(code), + GURL(script_url), script_start_line)); success = true; } else { @@ -627,7 +637,7 @@ void CefBrowserImpl::OnRequest(const Cef_Request_Params& params) { if (web_frame) { DCHECK_EQ(params.arguments.GetSize(), (size_t)1); - string16 command; + std::string command; params.arguments.GetString(0, &command); DCHECK(!command.empty()); @@ -638,7 +648,7 @@ void CefBrowserImpl::OnRequest(const Cef_Request_Params& params) { } else if (LowerCaseEqualsASCII(command, "gettext")) { response = UTF16ToUTF8(webkit_glue::DumpDocumentText(web_frame)); success = true; - } else if (web_frame->executeCommand(command)) { + } else if (web_frame->executeCommand(UTF8ToUTF16(command))) { success = true; } } @@ -651,12 +661,12 @@ void CefBrowserImpl::OnRequest(const Cef_Request_Params& params) { if (web_frame) { DCHECK_EQ(params.arguments.GetSize(), (size_t)2); - string16 string, url; + std::string string, url; params.arguments.GetString(0, &string); params.arguments.GetString(1, &url); - web_frame->loadHTMLString(UTF16ToUTF8(string), GURL(UTF16ToUTF8(url))); + web_frame->loadHTMLString(string, GURL(url)); } } } else { diff --git a/libcef/renderer/browser_impl.h b/libcef/renderer/browser_impl.h index 1dac457fd..b3693f063 100644 --- a/libcef/renderer/browser_impl.h +++ b/libcef/renderer/browser_impl.h @@ -81,6 +81,12 @@ class CefBrowserImpl : public CefBrowser, void LoadRequest(const CefMsg_LoadRequest_Params& params); + // Avoids unnecessary string type conversions. + bool SendProcessMessage(CefProcessId target_process, + const std::string& name, + base::ListValue* arguments, + bool user_initiated); + // Returns the matching CefFrameImpl reference or creates a new one. CefRefPtr GetWebFrameImpl(WebKit::WebFrame* frame); CefRefPtr GetWebFrameImpl(int64 frame_id); diff --git a/libcef/renderer/chrome_bindings.cc b/libcef/renderer/chrome_bindings.cc new file mode 100644 index 000000000..c759d2b96 --- /dev/null +++ b/libcef/renderer/chrome_bindings.cc @@ -0,0 +1,116 @@ +// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#include "libcef/renderer/chrome_bindings.h" +#include "libcef/renderer/browser_impl.h" +#include +#include "base/logging.h" +#include "base/values.h" + +namespace scheme { + +namespace { + +void SetList(CefRefPtr source, base::ListValue* target); + +// Transfer a V8 value to a List index. +void SetListValue(base::ListValue* list, int index, + CefRefPtr value) { + if (value->IsArray()) { + base::ListValue* new_list = new base::ListValue(); + SetList(value, new_list); + list->Set(index, new_list); + } else if (value->IsString()) { + list->Set(index, + base::Value::CreateStringValue(value->GetStringValue().ToString())); + } else if (value->IsBool()) { + list->Set(index, base::Value::CreateBooleanValue(value->GetBoolValue())); + } else if (value->IsInt()) { + list->Set(index, base::Value::CreateIntegerValue(value->GetIntValue())); + } else if (value->IsDouble()) { + list->Set(index, base::Value::CreateDoubleValue(value->GetDoubleValue())); + } +} + +// Transfer a V8 array to a List. +void SetList(CefRefPtr source, base::ListValue* target) { + DCHECK(source->IsArray()); + + int arg_length = source->GetArrayLength(); + if (arg_length == 0) + return; + + for (int i = 0; i < arg_length; ++i) + SetListValue(target, i, source->GetValue(i)); +} + +class V8Handler : public CefV8Handler { +public: + V8Handler() {} + + virtual bool Execute(const CefString& name, + CefRefPtr object, + const CefV8ValueList& arguments, + CefRefPtr& retval, + CefString& exception) OVERRIDE { + std::string nameStr = name; + if (nameStr == "send") { + if (arguments.size() > 0 && arguments.size() <= 2 && + arguments[0]->IsString()) { + base::ListValue args; + SetListValue(&args, 0, arguments[0]); + if (arguments.size() > 1) + SetListValue(&args, 1, arguments[1]); + + CefRefPtr browser = static_cast( + CefV8Context::GetCurrentContext()->GetBrowser().get()); + browser->SendProcessMessage(PID_BROWSER, kChromeProcessMessage, &args, + false); + + retval = CefV8Value::CreateBool(true); + } else { + exception = "Invalid number of arguments or argument format"; + } + return true; + } else if (nameStr == "bind") { + // Return the "send" object. + DCHECK(object->GetFunctionName() == "send"); + retval = object; + return true; + } + + NOTREACHED(); + return false; + } + + IMPLEMENT_REFCOUNTING(V8Handler); +}; + +} // namespace + +void OnContextCreated(CefRefPtr browser, + CefRefPtr frame, + CefRefPtr context) { + GURL url = GURL(frame->GetURL().ToString()); + if (url.scheme() != kChromeScheme) + return; + + CefRefPtr global = context->GetGlobal(); + + CefRefPtr handler = new V8Handler(); + + // Add "chrome". + CefRefPtr chrome = CefV8Value::CreateObject(NULL); + global->SetValue("chrome", chrome, V8_PROPERTY_ATTRIBUTE_NONE); + + // Add "chrome.send". + CefRefPtr send = CefV8Value::CreateFunction("send", handler); + chrome->SetValue("send", send, V8_PROPERTY_ATTRIBUTE_NONE); + + // Add "chrome.send.bind". + CefRefPtr bind = CefV8Value::CreateFunction("bind", handler); + send->SetValue("bind", bind, V8_PROPERTY_ATTRIBUTE_NONE); +} + +} // namespace scheme diff --git a/libcef/renderer/chrome_bindings.h b/libcef/renderer/chrome_bindings.h new file mode 100644 index 000000000..482bac467 --- /dev/null +++ b/libcef/renderer/chrome_bindings.h @@ -0,0 +1,24 @@ +// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#ifndef CEF_LIBCEF_RENDERER_CHROME_BINDINGS_H_ +#define CEF_LIBCEF_RENDERER_CHROME_BINDINGS_H_ +#pragma once + +#include "include/cef_v8.h" +#include "libcef/renderer/browser_impl.h" +#include "libcef/renderer/frame_impl.h" + +namespace scheme { + +extern const char kChromeScheme[]; +extern const char kChromeProcessMessage[]; + +void OnContextCreated(CefRefPtr browser, + CefRefPtr frame, + CefRefPtr context); + +} // namespace scheme + +#endif // CEF_LIBCEF_RENDERER_CHROME_BINDINGS_H_ diff --git a/libcef/renderer/content_renderer_client.cc b/libcef/renderer/content_renderer_client.cc index bc74c6fd8..d7834d18b 100644 --- a/libcef/renderer/content_renderer_client.cc +++ b/libcef/renderer/content_renderer_client.cc @@ -16,6 +16,7 @@ MSVC_POP_WARNING(); #include "libcef/common/cef_messages.h" #include "libcef/common/content_client.h" #include "libcef/renderer/browser_impl.h" +#include "libcef/renderer/chrome_bindings.h" #include "libcef/renderer/render_process_observer.h" #include "libcef/renderer/thread_util.h" #include "libcef/renderer/v8_impl.h" @@ -179,16 +180,6 @@ void CefContentRendererClient::RenderViewCreated( void CefContentRendererClient::DidCreateScriptContext( WebKit::WebFrame* frame, v8::Handle context, int extension_group, int world_id) { - // Notify the render process handler. - CefRefPtr application = CefContentClient::Get()->application(); - if (!application.get()) - return; - - CefRefPtr handler = - application->GetRenderProcessHandler(); - if (!handler.get()) - return; - CefRefPtr browserPtr = CefBrowserImpl::GetBrowserForMainFrame(frame->top()); DCHECK(browserPtr.get()); @@ -204,7 +195,16 @@ void CefContentRendererClient::DidCreateScriptContext( CefRefPtr contextPtr(new CefV8ContextImpl(context)); - handler->OnContextCreated(browserPtr.get(), framePtr.get(), contextPtr); + scheme::OnContextCreated(browserPtr, framePtr, contextPtr); + + // Notify the render process handler. + CefRefPtr application = CefContentClient::Get()->application(); + if (application.get()) { + CefRefPtr handler = + application->GetRenderProcessHandler(); + if (handler.get()) + handler->OnContextCreated(browserPtr.get(), framePtr.get(), contextPtr); + } } void CefContentRendererClient::WillReleaseScriptContext( diff --git a/libcef/resources/cef_resources.grd b/libcef/resources/cef_resources.grd index 1eaa92d25..3afbf6ad2 100644 --- a/libcef/resources/cef_resources.grd +++ b/libcef/resources/cef_resources.grd @@ -15,6 +15,8 @@ + + diff --git a/libcef_dll/cpptoc/trace_client_cpptoc.cc b/libcef_dll/cpptoc/trace_client_cpptoc.cc new file mode 100644 index 000000000..004cdd10f --- /dev/null +++ b/libcef_dll/cpptoc/trace_client_cpptoc.cc @@ -0,0 +1,79 @@ +// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#include "libcef_dll/cpptoc/trace_client_cpptoc.h" + + +// MEMBER FUNCTIONS - Body may be edited by hand. + +void CEF_CALLBACK trace_client_on_trace_data_collected( + struct _cef_trace_client_t* self, const char* fragment, + size_t fragment_size) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: fragment; type: simple_byaddr + DCHECK(fragment); + if (!fragment) + return; + + // Execute + CefTraceClientCppToC::Get(self)->OnTraceDataCollected( + fragment, + fragment_size); +} + +void CEF_CALLBACK trace_client_on_trace_buffer_percent_full_reply( + struct _cef_trace_client_t* self, float percent_full) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + + // Execute + CefTraceClientCppToC::Get(self)->OnTraceBufferPercentFullReply( + percent_full); +} + +void CEF_CALLBACK trace_client_on_end_tracing_complete( + struct _cef_trace_client_t* self) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + + // Execute + CefTraceClientCppToC::Get(self)->OnEndTracingComplete(); +} + + +// CONSTRUCTOR - Do not edit by hand. + +CefTraceClientCppToC::CefTraceClientCppToC(CefTraceClient* cls) + : CefCppToC(cls) { + struct_.struct_.on_trace_data_collected = + trace_client_on_trace_data_collected; + struct_.struct_.on_trace_buffer_percent_full_reply = + trace_client_on_trace_buffer_percent_full_reply; + struct_.struct_.on_end_tracing_complete = + trace_client_on_end_tracing_complete; +} + +#ifndef NDEBUG +template<> long CefCppToC::DebugObjCt = 0; +#endif + diff --git a/libcef_dll/cpptoc/trace_client_cpptoc.h b/libcef_dll/cpptoc/trace_client_cpptoc.h new file mode 100644 index 000000000..2704f3482 --- /dev/null +++ b/libcef_dll/cpptoc/trace_client_cpptoc.h @@ -0,0 +1,37 @@ +// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#ifndef CEF_LIBCEF_DLL_CPPTOC_TRACE_CLIENT_CPPTOC_H_ +#define CEF_LIBCEF_DLL_CPPTOC_TRACE_CLIENT_CPPTOC_H_ +#pragma once + +#ifndef USING_CEF_SHARED +#pragma message("Warning: "__FILE__" may be accessed wrapper-side only") +#else // USING_CEF_SHARED + +#include "include/cef_trace.h" +#include "include/capi/cef_trace_capi.h" +#include "libcef_dll/cpptoc/cpptoc.h" + +// Wrap a C++ class with a C structure. +// This class may be instantiated and accessed wrapper-side only. +class CefTraceClientCppToC + : public CefCppToC { + public: + explicit CefTraceClientCppToC(CefTraceClient* cls); + virtual ~CefTraceClientCppToC() {} +}; + +#endif // USING_CEF_SHARED +#endif // CEF_LIBCEF_DLL_CPPTOC_TRACE_CLIENT_CPPTOC_H_ + diff --git a/libcef_dll/ctocpp/trace_client_ctocpp.cc b/libcef_dll/ctocpp/trace_client_ctocpp.cc new file mode 100644 index 000000000..d2709dd61 --- /dev/null +++ b/libcef_dll/ctocpp/trace_client_ctocpp.cc @@ -0,0 +1,62 @@ +// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#include "libcef_dll/ctocpp/trace_client_ctocpp.h" + + +// VIRTUAL METHODS - Body may be edited by hand. + +void CefTraceClientCToCpp::OnTraceDataCollected(const char* fragment, + size_t fragment_size) { + if (CEF_MEMBER_MISSING(struct_, on_trace_data_collected)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: fragment; type: simple_byaddr + DCHECK(fragment); + if (!fragment) + return; + + // Execute + struct_->on_trace_data_collected(struct_, + fragment, + fragment_size); +} + +void CefTraceClientCToCpp::OnTraceBufferPercentFullReply(float percent_full) { + if (CEF_MEMBER_MISSING(struct_, on_trace_buffer_percent_full_reply)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + struct_->on_trace_buffer_percent_full_reply(struct_, + percent_full); +} + +void CefTraceClientCToCpp::OnEndTracingComplete() { + if (CEF_MEMBER_MISSING(struct_, on_end_tracing_complete)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + struct_->on_end_tracing_complete(struct_); +} + + +#ifndef NDEBUG +template<> long CefCToCpp::DebugObjCt = 0; +#endif + diff --git a/libcef_dll/ctocpp/trace_client_ctocpp.h b/libcef_dll/ctocpp/trace_client_ctocpp.h new file mode 100644 index 000000000..7f64cf0a1 --- /dev/null +++ b/libcef_dll/ctocpp/trace_client_ctocpp.h @@ -0,0 +1,45 @@ +// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#ifndef CEF_LIBCEF_DLL_CTOCPP_TRACE_CLIENT_CTOCPP_H_ +#define CEF_LIBCEF_DLL_CTOCPP_TRACE_CLIENT_CTOCPP_H_ +#pragma once + +#ifndef BUILDING_CEF_SHARED +#pragma message("Warning: "__FILE__" may be accessed DLL-side only") +#else // BUILDING_CEF_SHARED + +#include "include/cef_trace.h" +#include "include/capi/cef_trace_capi.h" +#include "libcef_dll/ctocpp/ctocpp.h" + +// Wrap a C structure with a C++ class. +// This class may be instantiated and accessed DLL-side only. +class CefTraceClientCToCpp + : public CefCToCpp { + public: + explicit CefTraceClientCToCpp(cef_trace_client_t* str) + : CefCToCpp( + str) {} + virtual ~CefTraceClientCToCpp() {} + + // CefTraceClient methods + virtual void OnTraceDataCollected(const char* fragment, + size_t fragment_size) OVERRIDE; + virtual void OnTraceBufferPercentFullReply(float percent_full) OVERRIDE; + virtual void OnEndTracingComplete() OVERRIDE; +}; + +#endif // BUILDING_CEF_SHARED +#endif // CEF_LIBCEF_DLL_CTOCPP_TRACE_CLIENT_CTOCPP_H_ + diff --git a/libcef_dll/libcef_dll.cc b/libcef_dll/libcef_dll.cc index 5a726e4b3..e9d737b6f 100644 --- a/libcef_dll/libcef_dll.cc +++ b/libcef_dll/libcef_dll.cc @@ -22,6 +22,8 @@ #include "include/capi/cef_scheme_capi.h" #include "include/cef_task.h" #include "include/capi/cef_task_capi.h" +#include "include/cef_trace.h" +#include "include/capi/cef_trace_capi.h" #include "include/cef_url.h" #include "include/capi/cef_url_capi.h" #include "include/cef_v8.h" @@ -88,6 +90,7 @@ #include "libcef_dll/ctocpp/scheme_handler_factory_ctocpp.h" #include "libcef_dll/ctocpp/string_visitor_ctocpp.h" #include "libcef_dll/ctocpp/task_ctocpp.h" +#include "libcef_dll/ctocpp/trace_client_ctocpp.h" #include "libcef_dll/ctocpp/urlrequest_client_ctocpp.h" #include "libcef_dll/ctocpp/v8accessor_ctocpp.h" #include "libcef_dll/ctocpp/v8handler_ctocpp.h" @@ -212,6 +215,7 @@ CEF_EXPORT void cef_shutdown() { DCHECK_EQ(CefStreamWriterCppToC::DebugObjCt, 0); DCHECK_EQ(CefStringVisitorCToCpp::DebugObjCt, 0); DCHECK_EQ(CefTaskCToCpp::DebugObjCt, 0); + DCHECK_EQ(CefTraceClientCToCpp::DebugObjCt, 0); DCHECK_EQ(CefURLRequestClientCToCpp::DebugObjCt, 0); DCHECK_EQ(CefURLRequestCppToC::DebugObjCt, 0); DCHECK_EQ(CefV8AccessorCToCpp::DebugObjCt, 0); @@ -428,6 +432,41 @@ CEF_EXPORT int cef_post_delayed_task(cef_thread_id_t threadId, return _retval; } +CEF_EXPORT int cef_begin_tracing(struct _cef_trace_client_t* client, + const cef_string_t* categories) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Unverified params: client, categories + + // Execute + bool _retval = CefBeginTracing( + CefTraceClientCToCpp::Wrap(client), + CefString(categories)); + + // Return type: bool + return _retval; +} + +CEF_EXPORT int cef_get_trace_buffer_percent_full_async() { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + bool _retval = CefGetTraceBufferPercentFullAsync(); + + // Return type: bool + return _retval; +} + +CEF_EXPORT int cef_end_tracing_async() { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + bool _retval = CefEndTracingAsync(); + + // Return type: bool + return _retval; +} + CEF_EXPORT int cef_parse_url(const cef_string_t* url, struct _cef_urlparts_t* parts) { // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING diff --git a/libcef_dll/wrapper/libcef_dll_wrapper.cc b/libcef_dll/wrapper/libcef_dll_wrapper.cc index e808c6428..2aae37853 100644 --- a/libcef_dll/wrapper/libcef_dll_wrapper.cc +++ b/libcef_dll/wrapper/libcef_dll_wrapper.cc @@ -22,6 +22,8 @@ #include "include/capi/cef_scheme_capi.h" #include "include/cef_task.h" #include "include/capi/cef_task_capi.h" +#include "include/cef_trace.h" +#include "include/capi/cef_trace_capi.h" #include "include/cef_url.h" #include "include/capi/cef_url_capi.h" #include "include/cef_v8.h" @@ -54,6 +56,7 @@ #include "libcef_dll/cpptoc/scheme_handler_factory_cpptoc.h" #include "libcef_dll/cpptoc/string_visitor_cpptoc.h" #include "libcef_dll/cpptoc/task_cpptoc.h" +#include "libcef_dll/cpptoc/trace_client_cpptoc.h" #include "libcef_dll/cpptoc/urlrequest_client_cpptoc.h" #include "libcef_dll/cpptoc/v8accessor_cpptoc.h" #include "libcef_dll/cpptoc/v8handler_cpptoc.h" @@ -204,6 +207,7 @@ CEF_GLOBAL void CefShutdown() { DCHECK_EQ(CefStreamWriterCToCpp::DebugObjCt, 0); DCHECK_EQ(CefStringVisitorCppToC::DebugObjCt, 0); DCHECK_EQ(CefTaskCppToC::DebugObjCt, 0); + DCHECK_EQ(CefTraceClientCppToC::DebugObjCt, 0); DCHECK_EQ(CefURLRequestCToCpp::DebugObjCt, 0); DCHECK_EQ(CefURLRequestClientCppToC::DebugObjCt, 0); DCHECK_EQ(CefV8AccessorCppToC::DebugObjCt, 0); @@ -411,6 +415,41 @@ CEF_GLOBAL bool CefPostDelayedTask(CefThreadId threadId, return _retval?true:false; } +CEF_GLOBAL bool CefBeginTracing(CefRefPtr client, + const CefString& categories) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Unverified params: client, categories + + // Execute + int _retval = cef_begin_tracing( + CefTraceClientCppToC::Wrap(client), + categories.GetStruct()); + + // Return type: bool + return _retval?true:false; +} + +CEF_GLOBAL bool CefGetTraceBufferPercentFullAsync() { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + int _retval = cef_get_trace_buffer_percent_full_async(); + + // Return type: bool + return _retval?true:false; +} + +CEF_GLOBAL bool CefEndTracingAsync() { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + int _retval = cef_end_tracing_async(); + + // Return type: bool + return _retval?true:false; +} + CEF_GLOBAL bool CefParseURL(const CefString& url, CefURLParts& parts) { // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING diff --git a/tests/cefclient/cefclient.rc b/tests/cefclient/cefclient.rc index c29b1485b..dc2b95c76 100644 --- a/tests/cefclient/cefclient.rc +++ b/tests/cefclient/cefclient.rc @@ -83,6 +83,8 @@ BEGIN MENUITEM "Zoom In", ID_TESTS_ZOOM_IN MENUITEM "Zoom Out", ID_TESTS_ZOOM_OUT MENUITEM "Zoom Reset", ID_TESTS_ZOOM_RESET + MENUITEM "Begin Tracing", ID_TESTS_BEGIN_TRACING + MENUITEM "End Tracing", ID_TESTS_END_TRACING END END diff --git a/tests/cefclient/cefclient_gtk.cpp b/tests/cefclient/cefclient_gtk.cpp index d2d4c21ce..c77c038a0 100644 --- a/tests/cefclient/cefclient_gtk.cpp +++ b/tests/cefclient/cefclient_gtk.cpp @@ -190,6 +190,22 @@ gboolean ZoomResetActivated(GtkWidget* widget) { return FALSE; // Don't stop this message. } +// Callback for Debug > Begin Tracing menu item. +gboolean BeginTracingActivated(GtkWidget* widget) { + if (g_handler.get()) + g_handler->BeginTracing(); + + return FALSE; // Don't stop this message. +} + +// Callback for Debug > End Tracing menu item. +gboolean EndTracingActivated(GtkWidget* widget) { + if (g_handler.get()) + g_handler->EndTracing(); + + return FALSE; // Don't stop this message. +} + // Callback for when you click the back button. void BackButtonClicked(GtkButton* button) { if (g_handler.get() && g_handler->GetBrowserId()) @@ -283,6 +299,10 @@ GtkWidget* CreateMenuBar() { G_CALLBACK(ZoomOutActivated)); AddMenuEntry(debug_menu, "Zoom Reset", G_CALLBACK(ZoomResetActivated)); + AddMenuEntry(debug_menu, "Begin Tracing", + G_CALLBACK(BeginTracingActivated)); + AddMenuEntry(debug_menu, "End Tracing", + G_CALLBACK(EndTracingActivated)); return menu_bar; } diff --git a/tests/cefclient/cefclient_mac.mm b/tests/cefclient/cefclient_mac.mm index 55e59292f..3d6e8cc45 100644 --- a/tests/cefclient/cefclient_mac.mm +++ b/tests/cefclient/cefclient_mac.mm @@ -207,6 +207,8 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) { - (IBAction)testZoomIn:(id)sender; - (IBAction)testZoomOut:(id)sender; - (IBAction)testZoomReset:(id)sender; +- (IBAction)testBeginTracing:(id)sender; +- (IBAction)testEndTracing:(id)sender; @end @implementation ClientAppDelegate @@ -282,6 +284,12 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) { [testMenu addItemWithTitle:@"Zoom Reset" action:@selector(testZoomReset:) keyEquivalent:@""]; + [testMenu addItemWithTitle:@"Begin Tracing" + action:@selector(testBeginTracing:) + keyEquivalent:@""]; + [testMenu addItemWithTitle:@"End Tracing" + action:@selector(testEndTracing:) + keyEquivalent:@""]; [testItem setSubmenu:testMenu]; [menubar addItem:testItem]; @@ -474,6 +482,15 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) { } } +- (IBAction)testBeginTracing:(id)sender { + if (g_handler.get()) + g_handler->BeginTracing(); +} + +- (IBAction)testEndTracing:(id)sender { + if (g_handler.get()) + g_handler->EndTracing(); +} // Sent by the default notification center immediately before the application // terminates. diff --git a/tests/cefclient/cefclient_win.cpp b/tests/cefclient/cefclient_win.cpp index e43df7e7d..f86687798 100644 --- a/tests/cefclient/cefclient_win.cpp +++ b/tests/cefclient/cefclient_win.cpp @@ -444,6 +444,12 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, if (browser.get()) browser->GetHost()->SetZoomLevel(0.0); return 0; + case ID_TESTS_BEGIN_TRACING: + g_handler->BeginTracing(); + return 0; + case ID_TESTS_END_TRACING: + g_handler->EndTracing(); + return 0; } break; } diff --git a/tests/cefclient/client_handler.cpp b/tests/cefclient/client_handler.cpp index a288b3de7..c1871f730 100644 --- a/tests/cefclient/client_handler.cpp +++ b/tests/cefclient/client_handler.cpp @@ -12,6 +12,7 @@ #include "include/cef_path_util.h" #include "include/cef_process_util.h" #include "include/cef_runnable.h" +#include "include/cef_trace.h" #include "include/wrapper/cef_stream_resource_handler.h" #include "cefclient/binding_test.h" #include "cefclient/cefclient.h" @@ -487,6 +488,80 @@ void ClientHandler::LaunchExternalBrowser(const std::string& url) { } } +void ClientHandler::BeginTracing() { + if (CefCurrentlyOn(TID_UI)) { + class Client : public CefTraceClient, + public CefRunFileDialogCallback { + public: + explicit Client(CefRefPtr handler) + : handler_(handler), + trace_data_("{\"traceEvents\":["), + first_(true) { + } + + virtual void OnTraceDataCollected(const char* fragment, + size_t fragment_size) OVERRIDE { + if (first_) + first_ = false; + else + trace_data_.append(","); + trace_data_.append(fragment, fragment_size); + } + + virtual void OnEndTracingComplete() OVERRIDE { + REQUIRE_UI_THREAD(); + trace_data_.append("]}"); + + static const char kDefaultFileName[] = "trace.txt"; + std::string path = handler_->GetDownloadPath(kDefaultFileName); + if (path.empty()) + path = kDefaultFileName; + + handler_->GetBrowser()->GetHost()->RunFileDialog( + FILE_DIALOG_SAVE, CefString(), path, std::vector(), + this); + } + + virtual void OnFileDialogDismissed( + CefRefPtr browser_host, + const std::vector& file_paths) OVERRIDE { + if (!file_paths.empty()) + handler_->Save(file_paths.front(), trace_data_); + } + + private: + CefRefPtr handler_; + std::string trace_data_; + bool first_; + + IMPLEMENT_REFCOUNTING(Callback); + }; + + CefBeginTracing(new Client(this), CefString()); + } else { + CefPostTask(TID_UI, + NewCefRunnableMethod(this, &ClientHandler::BeginTracing)); + } +} + +void ClientHandler::EndTracing() { + if (CefCurrentlyOn(TID_UI)) { + CefEndTracingAsync(); + } else { + CefPostTask(TID_UI, + NewCefRunnableMethod(this, &ClientHandler::BeginTracing)); + } +} + +bool ClientHandler::Save(const std::string& path, const std::string& data) { + FILE* f = fopen(path.c_str(), "w"); + if (!f) + return false; + fwrite(data.c_str(), data.size(), 1, f); + fclose(f); + return true; +} + // static void ClientHandler::CreateProcessMessageDelegates( ProcessMessageDelegateSet& delegates) { diff --git a/tests/cefclient/client_handler.h b/tests/cefclient/client_handler.h index 950a11183..b88077748 100644 --- a/tests/cefclient/client_handler.h +++ b/tests/cefclient/client_handler.h @@ -214,6 +214,11 @@ class ClientHandler : public CefClient, // Create an external browser window that loads the specified URL. static void LaunchExternalBrowser(const std::string& url); + void BeginTracing(); + void EndTracing(); + + bool Save(const std::string& path, const std::string& data); + protected: void SetLoading(bool isLoading); void SetNavState(bool canGoBack, bool canGoForward); diff --git a/tests/cefclient/resource.h b/tests/cefclient/resource.h index dd6988e3b..05ecd6b94 100644 --- a/tests/cefclient/resource.h +++ b/tests/cefclient/resource.h @@ -44,6 +44,8 @@ #define ID_TESTS_ZOOM_IN 32777 #define ID_TESTS_ZOOM_OUT 32778 #define ID_TESTS_ZOOM_RESET 32779 +#define ID_TESTS_BEGIN_TRACING 32780 +#define ID_TESTS_END_TRACING 32781 #define IDC_STATIC -1 #define IDS_BINDING 1000 #define IDS_DIALOGS 1001 diff --git a/tests/unittests/tracing_unittest.cc b/tests/unittests/tracing_unittest.cc new file mode 100644 index 000000000..16e5172f2 --- /dev/null +++ b/tests/unittests/tracing_unittest.cc @@ -0,0 +1,419 @@ +// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#include "base/synchronization/waitable_event.h" +#include "include/cef_task.h" +#include "include/cef_trace.h" +#include "include/cef_trace_event.h" +#include "tests/unittests/test_handler.h" +#include "testing/gtest/include/gtest/gtest.h" + +enum TracingTestType { + CEF_TRACE_EVENT0, + CEF_TRACE_EVENT1, + CEF_TRACE_EVENT2, + CEF_TRACE_EVENT_INSTANT0, + CEF_TRACE_EVENT_INSTANT1, + CEF_TRACE_EVENT_INSTANT2, + CEF_TRACE_EVENT_COPY_INSTANT0, + CEF_TRACE_EVENT_COPY_INSTANT1, + CEF_TRACE_EVENT_COPY_INSTANT2, + CEF_TRACE_EVENT_BEGIN0, + CEF_TRACE_EVENT_BEGIN1, + CEF_TRACE_EVENT_BEGIN2, + CEF_TRACE_EVENT_COPY_BEGIN0, + CEF_TRACE_EVENT_COPY_BEGIN1, + CEF_TRACE_EVENT_COPY_BEGIN2, + CEF_TRACE_EVENT_END0, + CEF_TRACE_EVENT_END1, + CEF_TRACE_EVENT_END2, + CEF_TRACE_EVENT_COPY_END0, + CEF_TRACE_EVENT_COPY_END1, + CEF_TRACE_EVENT_COPY_END2, + CEF_TRACE_EVENT_IF_LONGER_THAN0, + CEF_TRACE_EVENT_IF_LONGER_THAN1, + CEF_TRACE_EVENT_IF_LONGER_THAN2, + CEF_TRACE_COUNTER1, + CEF_TRACE_COPY_COUNTER1, + CEF_TRACE_COUNTER2, + CEF_TRACE_COPY_COUNTER2, + CEF_TRACE_COUNTER_ID1, + CEF_TRACE_COPY_COUNTER_ID1, + CEF_TRACE_COUNTER_ID2, + CEF_TRACE_COPY_COUNTER_ID2, + CEF_TRACE_EVENT_ASYNC_BEGIN0, + CEF_TRACE_EVENT_ASYNC_BEGIN1, + CEF_TRACE_EVENT_ASYNC_BEGIN2, + CEF_TRACE_EVENT_COPY_ASYNC_BEGIN0, + CEF_TRACE_EVENT_COPY_ASYNC_BEGIN1, + CEF_TRACE_EVENT_COPY_ASYNC_BEGIN2, + CEF_TRACE_EVENT_ASYNC_STEP0, + CEF_TRACE_EVENT_ASYNC_STEP1, + CEF_TRACE_EVENT_COPY_ASYNC_STEP0, + CEF_TRACE_EVENT_COPY_ASYNC_STEP1, + CEF_TRACE_EVENT_ASYNC_END0, + CEF_TRACE_EVENT_ASYNC_END1, + CEF_TRACE_EVENT_ASYNC_END2, + CEF_TRACE_EVENT_COPY_ASYNC_END0, + CEF_TRACE_EVENT_COPY_ASYNC_END1, + CEF_TRACE_EVENT_COPY_ASYNC_END2 +}; + +const char kTraceTestCategory[] = "test_category"; + +// Used to test begin tracing on the UI thread. +class BeginTracingTask : public CefTask { + public: + explicit BeginTracingTask(CefRefPtr client) + : client_(client) { + } + + virtual void Execute(CefThreadId threadId) OVERRIDE { + EXPECT_TRUE(CefBeginTracing(client_, kTraceTestCategory)); + } + + private: + virtual ~BeginTracingTask() {} + + CefRefPtr client_; + + IMPLEMENT_REFCOUNTING(BeginTracingTask); +}; + +// Used to test end tracing on the UI thread. +class EndTracingTask : public CefTask { + public: + EndTracingTask() {} + + virtual void Execute(CefThreadId threadId) OVERRIDE { + EXPECT_TRUE(CefEndTracingAsync()); + } + + private: + virtual ~EndTracingTask() {} + + IMPLEMENT_REFCOUNTING(EndTracingTask); +}; + +class TracingTestHandler : public CefTraceClient { + public: + TracingTestHandler(TracingTestType type, const char* trace_type) + : completion_event_(true, false), + trace_type_(trace_type), + type_(type) { + } + + virtual void OnTraceDataCollected(const char* fragment, + size_t fragment_size) OVERRIDE { + if (!trace_data_.empty()) + trace_data_.append(","); + trace_data_.append(fragment, fragment_size); + } + + virtual void OnEndTracingComplete() OVERRIDE { + EXPECT_TRUE(!trace_data_.empty()); + EXPECT_TRUE(trace_type_ != NULL); + EXPECT_TRUE(strstr(trace_data_.c_str(), trace_type_) != NULL); + completion_event_.Signal(); + } + + void RunTest() { + // BeginTracing works only on the UI thread. + CefPostTask(TID_UI, new BeginTracingTask(this)); + WaitForUIThread(); + + switch (type_) { + case CEF_TRACE_EVENT0: + CEF_TRACE_EVENT0(kTraceTestCategory, "CEF_TRACE_EVENT0"); + break; + case CEF_TRACE_EVENT1: + CEF_TRACE_EVENT1(kTraceTestCategory, "CEF_TRACE_EVENT1", "arg1", 1); + break; + case CEF_TRACE_EVENT2: + CEF_TRACE_EVENT2(kTraceTestCategory, "CEF_TRACE_EVENT2", "arg1", 1, + "arg2", 2); + break; + case CEF_TRACE_EVENT_INSTANT0: + CEF_TRACE_EVENT_INSTANT0(kTraceTestCategory, + "CEF_TRACE_EVENT_INSTANT0"); + break; + case CEF_TRACE_EVENT_INSTANT1: + CEF_TRACE_EVENT_INSTANT1(kTraceTestCategory, "CEF_TRACE_EVENT_INSTANT1", + "arg1", 1); + break; + case CEF_TRACE_EVENT_INSTANT2: + CEF_TRACE_EVENT_INSTANT2(kTraceTestCategory, "CEF_TRACE_EVENT_INSTANT2", + "arg1", 1, "arg2", 2); + break; + case CEF_TRACE_EVENT_COPY_INSTANT0: + CEF_TRACE_EVENT_COPY_INSTANT0(kTraceTestCategory, + "CEF_TRACE_EVENT_COPY_INSTANT0"); + break; + case CEF_TRACE_EVENT_COPY_INSTANT1: + CEF_TRACE_EVENT_COPY_INSTANT1(kTraceTestCategory, + "CEF_TRACE_EVENT_COPY_INSTANT1", + "arg1", 1); + break; + case CEF_TRACE_EVENT_COPY_INSTANT2: + CEF_TRACE_EVENT_COPY_INSTANT2(kTraceTestCategory, + "CEF_TRACE_EVENT_COPY_INSTANT2", + "arg1", 1, "arg2", 2); + break; + case CEF_TRACE_EVENT_BEGIN0: + CEF_TRACE_EVENT_BEGIN0(kTraceTestCategory, "CEF_TRACE_EVENT_BEGIN0"); + break; + case CEF_TRACE_EVENT_BEGIN1: + CEF_TRACE_EVENT_BEGIN1(kTraceTestCategory, "CEF_TRACE_EVENT_BEGIN1", + "arg1", 1); + break; + case CEF_TRACE_EVENT_BEGIN2: + CEF_TRACE_EVENT_BEGIN2(kTraceTestCategory, "CEF_TRACE_EVENT_BEGIN2", + "arg1", 1, "arg2", 2); + break; + case CEF_TRACE_EVENT_COPY_BEGIN0: + CEF_TRACE_EVENT_COPY_BEGIN0(kTraceTestCategory, + "CEF_TRACE_EVENT_COPY_BEGIN0"); + break; + case CEF_TRACE_EVENT_COPY_BEGIN1: + CEF_TRACE_EVENT_COPY_BEGIN1(kTraceTestCategory, + "CEF_TRACE_EVENT_COPY_BEGIN1", + "arg1", 1); + break; + case CEF_TRACE_EVENT_COPY_BEGIN2: + CEF_TRACE_EVENT_COPY_BEGIN2(kTraceTestCategory, + "CEF_TRACE_EVENT_COPY_BEGIN2", + "arg1", 1, "arg2", 2); + break; + case CEF_TRACE_EVENT_END0: + CEF_TRACE_EVENT_END0(kTraceTestCategory, "CEF_TRACE_EVENT_END0"); + break; + case CEF_TRACE_EVENT_END1: + CEF_TRACE_EVENT_END1(kTraceTestCategory, "CEF_TRACE_EVENT_END1", + "arg1", 1); + break; + case CEF_TRACE_EVENT_END2: + CEF_TRACE_EVENT_END2(kTraceTestCategory, "CEF_TRACE_EVENT_END2", + "arg1", 1, "arg2", 2); + break; + case CEF_TRACE_EVENT_COPY_END0: + CEF_TRACE_EVENT_COPY_END0(kTraceTestCategory, + "CEF_TRACE_EVENT_COPY_END0"); + break; + case CEF_TRACE_EVENT_COPY_END1: + CEF_TRACE_EVENT_COPY_END1(kTraceTestCategory, + "CEF_TRACE_EVENT_COPY_END1", "arg1", 1); + break; + case CEF_TRACE_EVENT_COPY_END2: + CEF_TRACE_EVENT_COPY_END2(kTraceTestCategory, + "CEF_TRACE_EVENT_COPY_END2", "arg1", 1, + "arg2", 2); + break; + case CEF_TRACE_EVENT_IF_LONGER_THAN0: + CEF_TRACE_EVENT_IF_LONGER_THAN0(0, kTraceTestCategory, + "CEF_TRACE_EVENT_IF_LONGER_THAN0"); + break; + case CEF_TRACE_EVENT_IF_LONGER_THAN1: + CEF_TRACE_EVENT_IF_LONGER_THAN1(0, kTraceTestCategory, + "CEF_TRACE_EVENT_IF_LONGER_THAN1", + "arg1", 1); + case CEF_TRACE_EVENT_IF_LONGER_THAN2: + CEF_TRACE_EVENT_IF_LONGER_THAN2(0, kTraceTestCategory, + "CEF_TRACE_EVENT_IF_LONGER_THAN2", + "arg1", 1, "arg2", 2); + break; + case CEF_TRACE_COUNTER1: + CEF_TRACE_COUNTER1(kTraceTestCategory, "CEF_TRACE_COUNTER1", 5); + break; + case CEF_TRACE_COPY_COUNTER1: + CEF_TRACE_COPY_COUNTER1(kTraceTestCategory, "CEF_TRACE_COPY_COUNTER1", + 5); + break; + case CEF_TRACE_COUNTER2: + CEF_TRACE_COUNTER2(kTraceTestCategory, "CEF_TRACE_COUNTER2", "val1", 5, + "val2", 10); + break; + case CEF_TRACE_COPY_COUNTER2: + CEF_TRACE_COPY_COUNTER2(kTraceTestCategory, "CEF_TRACE_COPY_COUNTER2", + "val1", 5, "val2", 10); + break; + case CEF_TRACE_COUNTER_ID1: + CEF_TRACE_COUNTER_ID1(kTraceTestCategory, "CEF_TRACE_COUNTER_ID1", 100, + 5); + break; + case CEF_TRACE_COPY_COUNTER_ID1: + CEF_TRACE_COPY_COUNTER_ID1(kTraceTestCategory, + "CEF_TRACE_COPY_COUNTER_ID1", 100, 5); + break; + case CEF_TRACE_COUNTER_ID2: + CEF_TRACE_COUNTER_ID2(kTraceTestCategory, "CEF_TRACE_COUNTER_ID2", 100, + "val1", 5, "val2", 10); + break; + case CEF_TRACE_COPY_COUNTER_ID2: + CEF_TRACE_COPY_COUNTER_ID2(kTraceTestCategory, + "CEF_TRACE_COPY_COUNTER_ID2", 100, + "val1", 5, "val2", 10); + break; + case CEF_TRACE_EVENT_ASYNC_BEGIN0: + CEF_TRACE_EVENT_ASYNC_BEGIN0(kTraceTestCategory, + "CEF_TRACE_EVENT_ASYNC_BEGIN0", 100); + break; + case CEF_TRACE_EVENT_ASYNC_BEGIN1: + CEF_TRACE_EVENT_ASYNC_BEGIN1(kTraceTestCategory, + "CEF_TRACE_EVENT_ASYNC_BEGIN1", 100, + "arg1", 1); + break; + case CEF_TRACE_EVENT_ASYNC_BEGIN2: + CEF_TRACE_EVENT_ASYNC_BEGIN2(kTraceTestCategory, + "CEF_TRACE_EVENT_ASYNC_BEGIN2", + 100, "arg1", 1, "arg2", 2); + break; + case CEF_TRACE_EVENT_COPY_ASYNC_BEGIN0: + CEF_TRACE_EVENT_COPY_ASYNC_BEGIN0(kTraceTestCategory, + "CEF_TRACE_EVENT_COPY_ASYNC_BEGIN0", + 100); + break; + case CEF_TRACE_EVENT_COPY_ASYNC_BEGIN1: + CEF_TRACE_EVENT_COPY_ASYNC_BEGIN1(kTraceTestCategory, + "CEF_TRACE_EVENT_COPY_ASYNC_BEGIN1", + 100, "arg1", 1); + break; + case CEF_TRACE_EVENT_COPY_ASYNC_BEGIN2: + CEF_TRACE_EVENT_COPY_ASYNC_BEGIN2(kTraceTestCategory, + "CEF_TRACE_EVENT_COPY_ASYNC_BEGIN2", + 100, "arg1", 1, "arg2", 2); + break; + case CEF_TRACE_EVENT_ASYNC_STEP0: + CEF_TRACE_EVENT_ASYNC_STEP0(kTraceTestCategory, + "CEF_TRACE_EVENT_ASYNC_STEP0", 100, + 1000); + break; + case CEF_TRACE_EVENT_ASYNC_STEP1: + CEF_TRACE_EVENT_ASYNC_STEP1(kTraceTestCategory, + "CEF_TRACE_EVENT_ASYNC_STEP1", 100, + 1000, "arg1", 1); + break; + case CEF_TRACE_EVENT_COPY_ASYNC_STEP0: + CEF_TRACE_EVENT_COPY_ASYNC_STEP0(kTraceTestCategory, + "CEF_TRACE_EVENT_COPY_ASYNC_STEP0", + 100, 1000); + break; + case CEF_TRACE_EVENT_COPY_ASYNC_STEP1: + CEF_TRACE_EVENT_COPY_ASYNC_STEP1(kTraceTestCategory, + "CEF_TRACE_EVENT_COPY_ASYNC_STEP1", + 100, 1000, "arg1", 1); + break; + case CEF_TRACE_EVENT_ASYNC_END0: + CEF_TRACE_EVENT_ASYNC_END0(kTraceTestCategory, + "CEF_TRACE_EVENT_ASYNC_END0", 100); + break; + case CEF_TRACE_EVENT_ASYNC_END1: + CEF_TRACE_EVENT_ASYNC_END1(kTraceTestCategory, + "CEF_TRACE_EVENT_ASYNC_END1", 100, + "arg1", 1); + break; + case CEF_TRACE_EVENT_ASYNC_END2: + CEF_TRACE_EVENT_ASYNC_END2(kTraceTestCategory, + "CEF_TRACE_EVENT_ASYNC_END2", 100, + "arg1", 1, "arg2", 2); + case CEF_TRACE_EVENT_COPY_ASYNC_END0: + CEF_TRACE_EVENT_COPY_ASYNC_END0(kTraceTestCategory, + "CEF_TRACE_EVENT_COPY_ASYNC_END0", + 100); + break; + case CEF_TRACE_EVENT_COPY_ASYNC_END1: + CEF_TRACE_EVENT_COPY_ASYNC_END1(kTraceTestCategory, + "CEF_TRACE_EVENT_COPY_ASYNC_END1", + 100, "arg1", 1); + break; + case CEF_TRACE_EVENT_COPY_ASYNC_END2: + CEF_TRACE_EVENT_COPY_ASYNC_END2(kTraceTestCategory, + "CEF_TRACE_EVENT_COPY_ASYNC_END2", + 100, "arg1", 1, "arg2", 2); + break; + } + + // Run EndTracingAsync on the UI thread. + CefPostTask(TID_UI, new EndTracingTask()); + WaitForUIThread(); + } + + void ExecuteTest() { + // Run the test. + RunTest(); + + // Wait for the test to complete. + completion_event_.Wait(); + } + + private: + virtual ~TracingTestHandler() {} + + // Handle used to notify when the test is complete. + base::WaitableEvent completion_event_; + + const char* trace_type_; + TracingTestType type_; + std::string trace_data_; + + IMPLEMENT_REFCOUNTING(TracingTestHandler); +}; + +// Helper for defining tracing tests. +#define TRACING_TEST(name, test_type) \ + TEST(TracingTest, name) { \ + CefRefPtr handler = \ + new TracingTestHandler(test_type, #test_type); \ + handler->ExecuteTest(); \ + } + +// Define the tests. +TRACING_TEST(TraceEvent0, CEF_TRACE_EVENT0); +TRACING_TEST(TraceEvent1, CEF_TRACE_EVENT1); +TRACING_TEST(TraceEvent2, CEF_TRACE_EVENT2); +TRACING_TEST(TraceEventInstant0, CEF_TRACE_EVENT_INSTANT0); +TRACING_TEST(TraceEventInstant1, CEF_TRACE_EVENT_INSTANT1); +TRACING_TEST(TraceEventInstant2, CEF_TRACE_EVENT_INSTANT2); +TRACING_TEST(TraceEventCopyInstant0, CEF_TRACE_EVENT_COPY_INSTANT0); +TRACING_TEST(TraceEventCopyInstant1, CEF_TRACE_EVENT_COPY_INSTANT1); +TRACING_TEST(TraceEventCopyInstant2, CEF_TRACE_EVENT_COPY_INSTANT2); +TRACING_TEST(TraceEventBegin0, CEF_TRACE_EVENT_BEGIN0); +TRACING_TEST(TraceEventBegin1, CEF_TRACE_EVENT_BEGIN1); +TRACING_TEST(TraceEventBegin2, CEF_TRACE_EVENT_BEGIN2); +TRACING_TEST(TraceEventCopyBegin0, CEF_TRACE_EVENT_COPY_BEGIN0); +TRACING_TEST(TraceEventCopyBegin1, CEF_TRACE_EVENT_COPY_BEGIN1); +TRACING_TEST(TraceEventCopyBegin2, CEF_TRACE_EVENT_COPY_BEGIN2); +TRACING_TEST(TraceEventEnd0, CEF_TRACE_EVENT_END0); +TRACING_TEST(TraceEventEnd1, CEF_TRACE_EVENT_END1); +TRACING_TEST(TraceEventEnd2, CEF_TRACE_EVENT_END2); +TRACING_TEST(TraceEventCopyEnd0, CEF_TRACE_EVENT_COPY_END0); +TRACING_TEST(TraceEventCopyEnd1, CEF_TRACE_EVENT_COPY_END1); +TRACING_TEST(TraceEventCopyEnd2, CEF_TRACE_EVENT_COPY_END1); +TRACING_TEST(TraceEventIfLongerThan0, CEF_TRACE_EVENT_IF_LONGER_THAN0); +TRACING_TEST(TraceEventIfLongerThan1, CEF_TRACE_EVENT_IF_LONGER_THAN1); +TRACING_TEST(TraceEventIfLongerThan2, CEF_TRACE_EVENT_IF_LONGER_THAN2); +TRACING_TEST(TraceCounter1, CEF_TRACE_COUNTER1); +TRACING_TEST(TraceCopyCounter1, CEF_TRACE_COPY_COUNTER1); +TRACING_TEST(TraceCounter2, CEF_TRACE_COUNTER2); +TRACING_TEST(TraceCopyCounter2, CEF_TRACE_COPY_COUNTER2); +TRACING_TEST(TraceCounterId1, CEF_TRACE_COUNTER_ID1); +TRACING_TEST(TraceCopyCounterId1, CEF_TRACE_COPY_COUNTER_ID1); +TRACING_TEST(TraceCounterId2, CEF_TRACE_COUNTER_ID2); +TRACING_TEST(TraceCopyCounterId2, CEF_TRACE_COPY_COUNTER_ID1); +TRACING_TEST(TraceTraceEventAsyncBegin0, CEF_TRACE_EVENT_ASYNC_BEGIN0); +TRACING_TEST(TraceTraceEventAsyncBegin1, CEF_TRACE_EVENT_ASYNC_BEGIN1); +TRACING_TEST(TraceTraceEventAsyncBegin2, CEF_TRACE_EVENT_ASYNC_BEGIN2); +TRACING_TEST(TraceTraceEventCopyAsyncBegin0, + CEF_TRACE_EVENT_COPY_ASYNC_BEGIN0); +TRACING_TEST(TraceTraceEventCopyAsyncBegin1, + CEF_TRACE_EVENT_COPY_ASYNC_BEGIN1); +TRACING_TEST(TraceTraceEventCopyAsyncBegin2, + CEF_TRACE_EVENT_COPY_ASYNC_BEGIN2); +TRACING_TEST(TraceTraceEventAsyncStep0, CEF_TRACE_EVENT_ASYNC_STEP0); +TRACING_TEST(TraceTraceEventAsyncStep1, CEF_TRACE_EVENT_ASYNC_STEP1); +TRACING_TEST(TraceEventCopyAsyncStep0, CEF_TRACE_EVENT_COPY_ASYNC_STEP0); +TRACING_TEST(TraceEventCopyAsyncStep1, CEF_TRACE_EVENT_COPY_ASYNC_STEP1); +TRACING_TEST(TraceEventAsyncEnd0, CEF_TRACE_EVENT_ASYNC_END0); +TRACING_TEST(TraceEventAsyncEnd1, CEF_TRACE_EVENT_ASYNC_END1); +TRACING_TEST(TraceEventAsyncEnd2, CEF_TRACE_EVENT_ASYNC_END2); +TRACING_TEST(TraceEventCopyAsyncEnd0, CEF_TRACE_EVENT_COPY_ASYNC_END0); diff --git a/tools/cef_parser.py b/tools/cef_parser.py index 4bc3a7940..148c6462a 100644 --- a/tools/cef_parser.py +++ b/tools/cef_parser.py @@ -364,12 +364,14 @@ _simpletypes = { 'int64' : ['int64', '0'], 'uint64' : ['uint64', '0'], 'double' : ['double', '0'], + 'float' : ['float', '0'], 'long' : ['long', '0'], 'unsigned long' : ['unsigned long', '0'], 'long long' : ['long long', '0'], 'size_t' : ['size_t', '0'], 'time_t' : ['time_t', '0'], 'bool' : ['int', '0'], + 'char': ['char', '0'], 'char* const': ['char* const', 'NULL'], 'CefCursorHandle' : ['cef_cursor_handle_t', 'NULL'], 'CefEventHandle' : ['cef_event_handle_t', 'NULL'], diff --git a/tools/patcher.py b/tools/patcher.py index ed5ff723e..09cb9c5fa 100644 --- a/tools/patcher.py +++ b/tools/patcher.py @@ -69,6 +69,11 @@ else: dir = patch['path'] patchObj = from_file(file) patchObj.apply(dir) + if 'note' in patch: + separator = '-' * 79 + '\n' + sys.stderr.write(separator) + sys.stderr.write('NOTE: '+patch['note']+'\n') + sys.stderr.write(separator) # read the current include file, if any incfile = patchdir + 'patch_state.h'