// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. #include "CEF/HumanAppRenderer.h" #include #include #include "include/cef_crash_util.h" #include "include/cef_dom.h" #include "include/wrapper/cef_helpers.h" #include "include/wrapper/cef_message_router.h" #include "CEF/RenderContent.h" const char kFocusedNodeChangedMessage[] = "ClientRenderer.FocusedNodeChanged"; class ClientRenderDelegate : public HumanAppRenderer::Delegate { public: ClientRenderDelegate() : last_node_is_editable_(false) {} void OnWebKitInitialized(CefRefPtr app) override { if (CefCrashReportingEnabled()) { // Set some crash keys for testing purposes. Keys must be defined in the // "crash_reporter.cfg" file. See cef_crash_util.h for details. CefSetCrashKeyValue("testkey_small1", "value1_small_renderer"); CefSetCrashKeyValue("testkey_small2", "value2_small_renderer"); CefSetCrashKeyValue("testkey_medium1", "value1_medium_renderer"); CefSetCrashKeyValue("testkey_medium2", "value2_medium_renderer"); CefSetCrashKeyValue("testkey_large1", "value1_large_renderer"); CefSetCrashKeyValue("testkey_large2", "value2_large_renderer"); } // Create the renderer-side router for query handling. CefMessageRouterConfig config; message_router_ = CefMessageRouterRendererSide::Create(config); } void OnContextCreated(CefRefPtr app, CefRefPtr browser, CefRefPtr frame, CefRefPtr context) override { message_router_->OnContextCreated(browser, frame, context); } void OnContextReleased(CefRefPtr app, CefRefPtr browser, CefRefPtr frame, CefRefPtr context) override { message_router_->OnContextReleased(browser, frame, context); } void OnFocusedNodeChanged(CefRefPtr app, CefRefPtr browser, CefRefPtr frame, CefRefPtr node) override { bool is_editable = (node.get() && node->IsEditable()); if (is_editable != last_node_is_editable_) { // Notify the browser of the change in focused element type. last_node_is_editable_ = is_editable; CefRefPtr message = CefProcessMessage::Create(kFocusedNodeChangedMessage); message->GetArgumentList()->SetBool(0, is_editable); frame->SendProcessMessage(PID_BROWSER, message); } } bool OnProcessMessageReceived(CefRefPtr app, CefRefPtr browser, CefRefPtr frame, CefProcessId source_process, CefRefPtr message) override { return message_router_->OnProcessMessageReceived(browser, frame, source_process, message); } private: bool last_node_is_editable_; // Handles the renderer side of query routing. CefRefPtr message_router_; DISALLOW_COPY_AND_ASSIGN(ClientRenderDelegate); IMPLEMENT_REFCOUNTING(ClientRenderDelegate); }; const char kGetPerfTests[] = "GetPerfTests"; const char kRunPerfTest[] = "RunPerfTest"; const char kPerfTestReturnValue[] = "PerfTestReturnValue"; class V8Handler : public CefV8Handler { public: V8Handler() {} virtual bool Execute(const CefString& name, CefRefPtr object, const CefV8ValueList& arguments, CefRefPtr& retval, CefString& exception) override { if (name == kRunPerfTest) { if (arguments.size() == 1 && arguments[0]->IsString()) { bool found = false; std::string test = arguments[0]->GetStringValue(); for (int i = 0; i < kPerfTestsCount; ++i) { if (test == kPerfTests[i].name) { // Execute the test. int64 delta = kPerfTests[i].test(kPerfTests[i].iterations); retval = CefV8Value::CreateInt(delta); found = true; break; } } if (!found) { std::string msg = "Unknown test: "; msg.append(test); exception = msg; } } else { exception = "Invalid function parameters"; } } else if (name == kGetPerfTests) { // Retrieve the list of perf tests. retval = CefV8Value::CreateArray(kPerfTestsCount); for (int i = 0; i < kPerfTestsCount; ++i) { CefRefPtr val = CefV8Value::CreateArray(2); val->SetValue(0, CefV8Value::CreateString(kPerfTests[i].name)); val->SetValue(1, CefV8Value::CreateUInt(kPerfTests[i].iterations)); retval->SetValue(i, val); } } else if (name == kPerfTestReturnValue) { if (arguments.size() == 0) { retval = CefV8Value::CreateInt(1); } else if (arguments.size() == 1 && arguments[0]->IsInt()) { int32 type = arguments[0]->GetIntValue(); CefTime date; switch (type) { case 0: retval = CefV8Value::CreateUndefined(); break; case 1: retval = CefV8Value::CreateNull(); break; case 2: retval = CefV8Value::CreateBool(true); break; case 3: retval = CefV8Value::CreateInt(1); break; case 4: retval = CefV8Value::CreateUInt(1); break; case 5: retval = CefV8Value::CreateDouble(1.234); break; case 6: date.Now(); retval = CefV8Value::CreateDate(date); break; case 7: retval = CefV8Value::CreateString("Hello, world!"); break; case 8: retval = CefV8Value::CreateObject(nullptr, nullptr); break; case 9: retval = CefV8Value::CreateArray(8); break; case 10: // retval = CefV8Value::CreateFunction(...); exception = "Not implemented"; break; default: exception = "Not supported"; } } } return true; } private: IMPLEMENT_REFCOUNTING(V8Handler); }; // Handle bindings in the render process. class RenderDelegate : public HumanAppRenderer::Delegate { public: RenderDelegate() {} virtual void OnContextCreated(CefRefPtr app, CefRefPtr browser, CefRefPtr frame, CefRefPtr context) override { CefRefPtr object = context->GetGlobal(); CefRefPtr handler = new V8Handler(); // Bind test functions. object->SetValue(kGetPerfTests, CefV8Value::CreateFunction(kGetPerfTests, handler), V8_PROPERTY_ATTRIBUTE_READONLY); object->SetValue(kRunPerfTest, CefV8Value::CreateFunction(kRunPerfTest, handler), V8_PROPERTY_ATTRIBUTE_READONLY); object->SetValue(kPerfTestReturnValue, CefV8Value::CreateFunction(kPerfTestReturnValue, handler), V8_PROPERTY_ATTRIBUTE_READONLY); } private: IMPLEMENT_REFCOUNTING(RenderDelegate); }; HumanAppRenderer::HumanAppRenderer() { CreateDelegates(delegates_); } void HumanAppRenderer::CreateDelegates(DelegateSet& delegates) { delegates.insert(new ClientRenderDelegate); } void HumanAppRenderer::OnWebKitInitialized() { DelegateSet::iterator it = delegates_.begin(); for (; it != delegates_.end(); ++it) (*it)->OnWebKitInitialized(this); } void HumanAppRenderer::OnBrowserCreated( CefRefPtr browser, CefRefPtr extra_info) { DelegateSet::iterator it = delegates_.begin(); for (; it != delegates_.end(); ++it) (*it)->OnBrowserCreated(this, browser, extra_info); } void HumanAppRenderer::OnBrowserDestroyed(CefRefPtr browser) { DelegateSet::iterator it = delegates_.begin(); for (; it != delegates_.end(); ++it) (*it)->OnBrowserDestroyed(this, browser); } CefRefPtr HumanAppRenderer::GetLoadHandler() { CefRefPtr load_handler; DelegateSet::iterator it = delegates_.begin(); for (; it != delegates_.end() && !load_handler.get(); ++it) load_handler = (*it)->GetLoadHandler(this); return load_handler; } void HumanAppRenderer::OnContextCreated(CefRefPtr browser, CefRefPtr frame, CefRefPtr context) { DelegateSet::iterator it = delegates_.begin(); for (; it != delegates_.end(); ++it) (*it)->OnContextCreated(this, browser, frame, context); } void HumanAppRenderer::OnContextReleased(CefRefPtr browser, CefRefPtr frame, CefRefPtr context) { DelegateSet::iterator it = delegates_.begin(); for (; it != delegates_.end(); ++it) (*it)->OnContextReleased(this, browser, frame, context); } void HumanAppRenderer::OnUncaughtException( CefRefPtr browser, CefRefPtr frame, CefRefPtr context, CefRefPtr exception, CefRefPtr stackTrace) { DelegateSet::iterator it = delegates_.begin(); for (; it != delegates_.end(); ++it) { (*it)->OnUncaughtException(this, browser, frame, context, exception, stackTrace); } } void HumanAppRenderer::OnFocusedNodeChanged(CefRefPtr browser, CefRefPtr frame, CefRefPtr node) { DelegateSet::iterator it = delegates_.begin(); for (; it != delegates_.end(); ++it) (*it)->OnFocusedNodeChanged(this, browser, frame, node); } bool HumanAppRenderer::OnProcessMessageReceived( CefRefPtr browser, CefRefPtr frame, CefProcessId source_process, CefRefPtr message) { DCHECK_EQ(source_process, PID_BROWSER); bool handled = false; DelegateSet::iterator it = delegates_.begin(); for (; it != delegates_.end() && !handled; ++it) { handled = (*it)->OnProcessMessageReceived(this, browser, frame, source_process, message); } return handled; }