summaryrefslogtreecommitdiffstats
path: root/chrome/renderer
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
commit09911bf300f1a419907a9412154760efd0b7abc3 (patch)
treef131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/renderer
parent586acc5fe142f498261f52c66862fa417c3d52d2 (diff)
downloadchromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer')
-rw-r--r--chrome/renderer/SConscript99
-rw-r--r--chrome/renderer/about_handler.cc93
-rw-r--r--chrome/renderer/about_handler.h68
-rw-r--r--chrome/renderer/automation/dom_automation_controller.cc125
-rw-r--r--chrome/renderer/automation/dom_automation_controller.h133
-rw-r--r--chrome/renderer/debug_message_handler.cc142
-rw-r--r--chrome/renderer/debug_message_handler.h82
-rw-r--r--chrome/renderer/dom_ui_bindings.cc82
-rw-r--r--chrome/renderer/dom_ui_bindings.h76
-rw-r--r--chrome/renderer/external_js_object.cc48
-rw-r--r--chrome/renderer/external_js_object.h66
-rw-r--r--chrome/renderer/localized_error.cc229
-rw-r--r--chrome/renderer/localized_error.h47
-rw-r--r--chrome/renderer/net/render_dns_master.cc189
-rw-r--r--chrome/renderer/net/render_dns_master.h134
-rw-r--r--chrome/renderer/net/render_dns_master_unittest.cc61
-rw-r--r--chrome/renderer/net/render_dns_queue.cc169
-rw-r--r--chrome/renderer/net/render_dns_queue.h117
-rw-r--r--chrome/renderer/net/render_dns_queue_unittest.cc287
-rw-r--r--chrome/renderer/plugin_channel_host.cc135
-rw-r--r--chrome/renderer/plugin_channel_host.h76
-rw-r--r--chrome/renderer/render_process.cc273
-rw-r--r--chrome/renderer/render_process.h126
-rw-r--r--chrome/renderer/render_thread.cc220
-rw-r--r--chrome/renderer/render_thread.h145
-rw-r--r--chrome/renderer/render_view.cc2469
-rw-r--r--chrome/renderer/render_view.h623
-rw-r--r--chrome/renderer/render_widget.cc769
-rw-r--r--chrome/renderer/render_widget.h277
-rw-r--r--chrome/renderer/renderer.vcproj283
-rw-r--r--chrome/renderer/renderer.vsprops12
-rw-r--r--chrome/renderer/renderer_glue.cc407
-rw-r--r--chrome/renderer/renderer_main.cc136
-rw-r--r--chrome/renderer/renderer_resources.h5
-rw-r--r--chrome/renderer/renderer_resources.rc18
-rw-r--r--chrome/renderer/resources/error_no_details.html74
-rw-r--r--chrome/renderer/resources/insecure_content_stamp.pngbin0 -> 3946 bytes
-rw-r--r--chrome/renderer/resources/neterror.html104
-rw-r--r--chrome/renderer/spellcheck_unittest.cc360
-rw-r--r--chrome/renderer/visitedlink_slave.cc88
-rw-r--r--chrome/renderer/visitedlink_slave.h62
-rw-r--r--chrome/renderer/webplugin_delegate_proxy.cc696
-rw-r--r--chrome/renderer/webplugin_delegate_proxy.h175
43 files changed, 9780 insertions, 0 deletions
diff --git a/chrome/renderer/SConscript b/chrome/renderer/SConscript
new file mode 100644
index 0000000..e9b83a8
--- /dev/null
+++ b/chrome/renderer/SConscript
@@ -0,0 +1,99 @@
+# Copyright 2008, 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 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.
+
+Import('env')
+
+env = env.Clone()
+
+
+
+#/Yu"precompiled_wtl.h"
+#/Fp"C:\src\trunk\chrome\Debug\obj\browser\precompiled_wtl.pch"
+#/Fo"C:\src\trunk\chrome\Debug\obj\browser\\"
+#/Fd"C:\src\trunk\chrome\Debug\obj\browser\vc80.pdb"
+#/W3
+#/WX
+#/FI "precompiled_wtl.h"
+
+env.Prepend(
+ CPPPATH = [
+ env.Dir('../app/resources'),
+ env.Dir('#/tools/build/win'),
+ env.Dir('#/..'),
+ ],
+ CPPDEFINES = [
+ 'U_STATIC_IMPLEMENTATION',
+ 'CERT_CHAIN_PARA_HAS_EXTRA_FIELDS',
+ 'WIN32_LEAN_AND_MEAN',
+ ],
+ CCFLAGS = [
+ '/TP',
+
+ '/Wp64',
+
+ '/wd4503',
+ '/wd4819',
+ ],
+)
+
+env.Append(
+ CPPPATH = [
+ 'third_party/wtl/include',
+ '$ICU38_DIR/public/common',
+ '$ICU38_DIR/public/i18n',
+ #Dir('#../chrome/Debug/obj/generated_resources'),
+ #Dir('#../chrome/Debug/obj/localized_strings'),
+ '$NPAPI_DIR',
+ '$SKIA_DIR/include',
+ '$SKIA_DIR/include/corecg',
+ '$SKIA_DIR/platform',
+ ],
+)
+
+input_files = [
+ 'about_handler.cc',
+ 'automation/dom_automation_controller.cc',
+ 'debug_message_handler.cc',
+ 'dom_ui_bindings.cc',
+ 'external_js_object.cc',
+ 'localized_error.cc',
+ 'net/render_dns_master.cc',
+ 'net/render_dns_queue.cc',
+ 'plugin_channel_host.cc',
+ 'render_process.cc',
+ 'render_thread.cc',
+ 'render_view.cc',
+ 'render_widget.cc',
+ 'renderer_glue.cc',
+ 'renderer_main.cc',
+ 'visitedlink_slave.cc',
+ 'webplugin_delegate_proxy.cc',
+]
+
+env.StaticLibrary('renderer', input_files)
diff --git a/chrome/renderer/about_handler.cc b/chrome/renderer/about_handler.cc
new file mode 100644
index 0000000..5a8b7a0
--- /dev/null
+++ b/chrome/renderer/about_handler.cc
@@ -0,0 +1,93 @@
+// Copyright 2008, 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 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.
+
+#include <windows.h>
+
+#include "chrome/renderer/about_handler.h"
+
+#include "googleurl/src/gurl.h"
+
+struct AboutHandlerUrl {
+ char *url;
+ void (*action)();
+};
+
+static AboutHandlerUrl about_urls[] = {
+ { "about:crash", AboutHandler::AboutCrash },
+ { "about:hang", AboutHandler::AboutHang },
+ { "about:shorthang", AboutHandler::AboutShortHang },
+ { NULL, NULL }
+};
+
+bool AboutHandler::WillHandle(const GURL& url) {
+ if (url.scheme() != "about")
+ return false;
+
+ struct AboutHandlerUrl* url_handler = about_urls;
+ while (url_handler->url) {
+ if (url == GURL(url_handler->url))
+ return true;
+ url_handler++;
+ }
+ return false;
+}
+
+// static
+bool AboutHandler::MaybeHandle(const GURL& url) {
+ if (url.scheme() != "about")
+ return false;
+
+ struct AboutHandlerUrl* url_handler = about_urls;
+ while (url_handler->url) {
+ if (url == GURL(url_handler->url)) {
+ url_handler->action();
+ return true; // theoretically :]
+ }
+ url_handler++;
+ }
+ return false;
+}
+
+// static
+void AboutHandler::AboutCrash() {
+ int *zero = NULL;
+ *zero = 0; // Null pointer dereference: kaboom!
+}
+
+// static
+void AboutHandler::AboutHang() {
+ for (;;) {
+ Sleep(1000);
+ }
+}
+
+// static
+void AboutHandler::AboutShortHang() {
+ Sleep(20000);
+}
diff --git a/chrome/renderer/about_handler.h b/chrome/renderer/about_handler.h
new file mode 100644
index 0000000..1d545a0
--- /dev/null
+++ b/chrome/renderer/about_handler.h
@@ -0,0 +1,68 @@
+// Copyright 2008, 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 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.
+
+// Contains code for handling "about:" URLs in the renderer process. We handle
+// most about: URLs in the browser process (see
+// browser/browser_about_handler.*), but test URLs like about:crash need to
+// happen in the renderer.
+
+#ifndef CHROME_RENDERER_ABOUT_HANDLER_H__
+#define CHROME_RENDERER_ABOUT_HANDLER_H__
+
+#include "base/basictypes.h"
+
+class GURL;
+
+class AboutHandler {
+ public:
+ // Given a URL, determine whether or not to handle it specially. Returns
+ // true if the URL was handled.
+ static bool MaybeHandle(const GURL& url);
+
+ // Returns true if the URL is one that this AboutHandler will handle when
+ // MaybeHandle is called.
+ static bool WillHandle(const GURL& url);
+
+ // Induces a renderer crash.
+ static void AboutCrash();
+
+ // Induces a renderer hang.
+ static void AboutHang();
+
+ // Induces a brief (20 second) hang to make sure hang monitors go away.
+ static void AboutShortHang();
+
+ private:
+ AboutHandler();
+ ~AboutHandler();
+
+ DISALLOW_EVIL_CONSTRUCTORS(AboutHandler);
+};
+
+#endif // CHROME_RENDERER_ABOUT_HANDLER_H__
diff --git a/chrome/renderer/automation/dom_automation_controller.cc b/chrome/renderer/automation/dom_automation_controller.cc
new file mode 100644
index 0000000..4d6dca3
--- /dev/null
+++ b/chrome/renderer/automation/dom_automation_controller.cc
@@ -0,0 +1,125 @@
+// Copyright 2008, 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 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.
+
+#include "chrome/renderer/automation/dom_automation_controller.h"
+
+#include "chrome/common/json_value_serializer.h"
+#include "chrome/common/render_messages.h"
+#include "base/string_util.h"
+
+IPC::Message::Sender* DomAutomationController::sender_(NULL);
+int DomAutomationController::routing_id_(MSG_ROUTING_NONE);
+int DomAutomationController::automation_id_(MSG_ROUTING_NONE);
+
+DomAutomationController::DomAutomationController(){
+ BindMethod("send", &DomAutomationController::send);
+ BindMethod("setAutomationId", &DomAutomationController::setAutomationId);
+}
+
+void DomAutomationController::send(const CppArgumentList& args,
+ CppVariant* result) {
+ if (args.size() != 1) {
+ result->SetNull();
+ return;
+ }
+
+ if (automation_id_ == MSG_ROUTING_NONE) {
+ result->SetNull();
+ return;
+ }
+
+ std::string json;
+ JSONStringValueSerializer serializer(&json);
+ Value* value = NULL;
+
+ // Warning: note that JSON officially requires the root-level object to be
+ // an object (e.g. {foo:3}) or an array, while here we're serializing
+ // strings, bools, etc. to "JSON". This only works because (a) the JSON
+ // writer is lenient, and (b) on the receiving side we wrap the JSON string
+ // in square brackets, converting it to an array, then parsing it and
+ // grabbing the 0th element to get the value out.
+ switch(args[0].type) {
+ case NPVariantType_String: {
+ value = Value::CreateStringValue(UTF8ToWide(args[0].ToString()));
+ break;
+ }
+ case NPVariantType_Bool: {
+ value = Value::CreateBooleanValue(args[0].ToBoolean());
+ break;
+ }
+ case NPVariantType_Int32: {
+ value = Value::CreateIntegerValue(args[0].ToInt32());
+ break;
+ }
+ case NPVariantType_Double: {
+ // The value that is sent back is an integer while it is treated
+ // as a double in this binding. The reason being that KJS treats
+ // any number value as a double. Refer for more details,
+ // chrome/third_party/webkit/src/JavaScriptCore/bindings/c/c_utility.cpp
+ value = Value::CreateIntegerValue(args[0].ToInt32());
+ break;
+ }
+ default: {
+ result->SetNull();
+ return;
+ }
+ }
+
+ bool succeeded = serializer.Serialize(*value);
+ if (!succeeded) {
+ result->SetNull();
+ return;
+ }
+
+ succeeded = sender_->Send(
+ new ViewHostMsg_DomOperationResponse(routing_id_, json, automation_id_));
+
+ automation_id_ = MSG_ROUTING_NONE;
+
+ result->Set(succeeded);
+ return;
+}
+
+void DomAutomationController::setAutomationId(
+ const CppArgumentList& args, CppVariant* result) {
+ if (args.size() != 1) {
+ result->SetNull();
+ return;
+ }
+
+ // The check here is for NumberType and not Int32 as
+ // KJS::JSType only defines a NumberType (no Int32)
+ if (!args[0].isNumber()) {
+ result->SetNull();
+ return;
+ }
+
+ automation_id_ = args[0].ToInt32();
+ result->Set(true);
+}
diff --git a/chrome/renderer/automation/dom_automation_controller.h b/chrome/renderer/automation/dom_automation_controller.h
new file mode 100644
index 0000000..d7ac44f
--- /dev/null
+++ b/chrome/renderer/automation/dom_automation_controller.h
@@ -0,0 +1,133 @@
+// Copyright 2008, 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 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.
+
+#ifndef CHROME_RENDERER_AUTOMATION_DOM_AUTOMATION_CONTROLLER_H__
+#define CHROME_RENDERER_AUTOMATION_DOM_AUTOMATION_CONTROLLER_H__
+
+#include "chrome/common/ipc_message.h"
+#include "webkit/glue/cpp_bound_class.h"
+
+/* DomAutomationController class:
+ Bound to Javascript window.domAutomationController object.
+ At the very basic, this object makes any native value (string, numbers,
+ boolean) from javascript available to the automation host in Cpp.
+ Any renderer implementation that is built with this binding will allow the
+ above facility.
+ The intended use of this object is to expose the DOM Objects and their
+ attributes to the automation host.
+
+ A typical usage would be like following (JS code):
+
+ var object = document.getElementById('some_id');
+ window.domAutomationController.send(object.nodeName); // get the tag name
+
+ For the exact mode of usage,
+ refer AutomationProxyTest.*DomAutomationController tests.
+
+ The class provides a single send method that can send variety of native
+ javascript values. (NPString, Number(double), Boolean)
+
+ The actual communication occurs in the following manner:
+
+ TEST MASTER RENDERER
+ (1) (3)
+ |AProxy| ----->|AProvider|----->|RenderView|------|
+ /\ | | |
+ | | | |
+ |(6) |(2) |(0) |(4)
+ | | \/ |
+ | |-------->|DAController|<----|
+ | |
+ | |(5)
+ |---------|WebContents|<----------|
+
+
+ Legends:
+ - AProxy = AutomationProxy
+ - AProvider = AutomationProvider
+ - DAController = DomAutomationController
+
+ (0) Initialization step where DAController is bound to the renderer
+ and the view_id of the renderer is supplied to the DAController for
+ routing message in (5). (routing_id_)
+ (1) A 'javascript:' url is sent from the test process to master as an IPC
+ message. A unique routing id is generated at this stage (automation_id_)
+ (2) The automation_id_ of step (1) is supplied to DAController by calling
+ the bound method setAutomationId(). This is required for routing message
+ in (6).
+ (3) The 'javascript:' url is sent for execution by calling into
+ Browser::LoadURL()
+ (4) A callback is generated as a result of domAutomationController.send()
+ into Cpp. The supplied value is received as a result of this callback.
+ (5) The value received in (4) is sent to the master along with the
+ stored automation_id_ as an IPC message. routing_id_ is used to route
+ the message. (IPC messages, ViewHostMsg_*DomAutomation* )
+ (6) The value and the automation_id_ is extracted out of the message received
+ in (5). This value is relayed to AProxy using another IPC message.
+ automation_id_ is used to route the message.
+ (IPC messages, AutomationMsg_Dom*Response)
+
+*/
+
+// TODO(vibhor): Add another method-pair like sendLater() and sendNow()
+// sendLater() should keep building a json serializer
+// sendNow() should send the above serializer as a string.
+class DomAutomationController : public CppBoundClass {
+ public:
+ DomAutomationController();
+ ~DomAutomationController() {}
+
+ // Makes the renderer send a javascript value to the app.
+ // The value to be sent can be either of type NPString,
+ // Number (double casted to int32) or boolean.
+ // The function returns true/false based on the result of actual send over
+ // IPC. It sets the return value to null on unexpected errors or arguments.
+ void send(const CppArgumentList& args, CppVariant* result);
+
+ void setAutomationId(const CppArgumentList& args, CppVariant* result);
+
+ // TODO(vibhor): Implement later
+ // static CppBindingObjectMethod sendLater;
+ // static CppBindingObjectMethod sendNow;
+
+ static void set_routing_id(int routing_id) { routing_id_ = routing_id; }
+
+ static void set_message_sender(IPC::Message::Sender* sender) {
+ sender_ = sender;
+ }
+
+ private:
+ static IPC::Message::Sender* sender_;
+
+ // Refer to the comments at the top of the file for more details.
+ static int routing_id_; // routing id to be used by first channel.
+ static int automation_id_; // routing id to be used by the next channel.
+};
+
+#endif // CHROME_RENDERER_AUTOMATION_DOM_AUTOMATION_CONTROLLER_H__
diff --git a/chrome/renderer/debug_message_handler.cc b/chrome/renderer/debug_message_handler.cc
new file mode 100644
index 0000000..60df1b2
--- /dev/null
+++ b/chrome/renderer/debug_message_handler.cc
@@ -0,0 +1,142 @@
+// Copyright 2008, 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 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.
+
+#include "chrome/renderer/debug_message_handler.h"
+#include "chrome/renderer/render_view.h"
+
+////////////////////////////////////////
+// methods called from the RenderThread
+
+DebugMessageHandler::DebugMessageHandler(RenderView* view) :
+ debugger_(NULL), view_(view), channel_(NULL) {
+ view_loop_ = MessageLoop::current();
+ view_routing_id_ = view_->routing_id();
+}
+
+DebugMessageHandler::~DebugMessageHandler() {
+}
+
+void DebugMessageHandler::EvaluateScriptUrl(const std::wstring& url) {
+ DCHECK(MessageLoop::current() == view_loop_);
+ // It's possible that this will get cleared out from under us.
+ RenderView* view = view_;
+ if (view) {
+ view->EvaluateScriptUrl(L"", url);
+ }
+}
+
+///////////////////////////////////////////////
+// all methods below called from the IO thread
+
+void DebugMessageHandler::DebuggerOutput(const std::wstring& out) {
+ DCHECK(MessageLoop::current() != view_loop_);
+ // When certain commands are sent to the debugger, but we're not paused,
+ // it's possible that no JS is running, so these commands can't be processed.
+ // In these cases, we force some trivial, no side-effect, JS to be executed
+ // so that V8 can process the commands.
+ if (((out == L"break set") || (out == L"request queued")) && view_loop_) {
+ if (view_loop_) {
+ view_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &DebugMessageHandler::EvaluateScriptUrl,
+ std::wstring(L"javascript:void(0)")));
+ }
+ } else if (channel_) {
+ channel_->Send(new ViewHostMsg_DebuggerOutput(view_routing_id_, out));
+ }
+}
+
+void DebugMessageHandler::OnAttach() {
+ DebuggerOutput(L"{'type':'event', 'event':'attach'}");
+ debugger_->Attach();
+}
+
+void DebugMessageHandler::OnSendToDebugger(const std::wstring& cmd) {
+ if (!debugger_) {
+ debugger_ = new Debugger(this);
+ if (cmd == L"" || cmd == L"attach") {
+ OnAttach();
+ } else {
+ NOTREACHED();
+ std::wstring msg =
+ StringPrintf(L"before attach, ignored command (%S)", cmd.c_str());
+ DebuggerOutput(msg);
+ }
+ } else if (cmd == L"attach") {
+ OnAttach();
+ } else if (cmd == L"quit" || cmd == L"detach") {
+ OnDetach();
+ } else {
+ debugger_->Command(cmd);
+ }
+}
+
+void DebugMessageHandler::OnDetach() {
+ if (debugger_)
+ debugger_->Detach();
+ if (view_loop_ && view_)
+ view_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ view_, &RenderView::OnDebugDetach));
+}
+
+void DebugMessageHandler::OnFilterAdded(IPC::Channel* channel) {
+ channel_ = channel;
+}
+
+void DebugMessageHandler::OnFilterRemoved() {
+ channel_ = NULL;
+ view_loop_ = NULL;
+ view_ = NULL;
+ // By the time this is called, the view is not in a state where it can
+ // receive messages from the MessageLoop, so we need to clear those first.
+ OnDetach();
+}
+
+bool DebugMessageHandler::OnMessageReceived(const IPC::Message& message) {
+ DCHECK(channel_ != NULL);
+
+ // In theory, there could be multiple debuggers running (in practice this
+ // hasn't been implemented yet), so make sure we only handle messages meant
+ // for the view we were initialized for.
+ if (message.routing_id() != view_routing_id_)
+ return false;
+
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(DebugMessageHandler, message)
+ IPC_MESSAGE_HANDLER(ViewMsg_SendToDebugger, OnSendToDebugger);
+ // If the debugger is active, then it's possible that the renderer thread
+ // is suspended handling a breakpoint. In that case, the renderer will
+ // hang forever and never exit. To avoid this, we look for close messages
+ // and tell the debugger to shutdown.
+ IPC_MESSAGE_HANDLER_GENERIC(ViewMsg_Close,
+ if (debugger_) OnDetach();
+ handled = false;)
+ IPC_MESSAGE_UNHANDLED(handled = false);
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
diff --git a/chrome/renderer/debug_message_handler.h b/chrome/renderer/debug_message_handler.h
new file mode 100644
index 0000000..87d5d9c
--- /dev/null
+++ b/chrome/renderer/debug_message_handler.h
@@ -0,0 +1,82 @@
+// Copyright 2008, 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 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.
+
+// MessageFilter object to handle messages aimed at the debugger, and to
+// dispatch them from the main thread rather than the render thread.
+// Also owns the reference to the Debugger object and handles callbacks from it.
+
+#ifndef CHROME_RENDERER_DEBUG_MESSAGE_HANDLER_H_
+#define CHROME_RENDERER_DEBUG_MESSAGE_HANDLER_H_
+
+#include "chrome/common/ipc_channel_proxy.h"
+#include "webkit/glue/debugger.h"
+
+class RenderView;
+
+class DebugMessageHandler : public IPC::ChannelProxy::MessageFilter,
+ public Debugger::Delegate {
+ public:
+ DebugMessageHandler(RenderView* view);
+ virtual ~DebugMessageHandler();
+
+ private:
+ // evaluate javascript URL in the renderer
+ void EvaluateScriptUrl(const std::wstring& url);
+
+ // Debugger::Delegate callback method to handle debugger output.
+ void DebuggerOutput(const std::wstring& out);
+
+ // Sends a command to the debugger.
+ void OnSendToDebugger(const std::wstring& cmd);
+
+ // Sends an attach event to the debugger front-end.
+ void OnAttach();
+
+ // Unregister with V8 and notify the RenderView.
+ void OnDetach();
+
+ virtual void OnFilterAdded(IPC::Channel* channel);
+ virtual void OnFilterRemoved();
+
+ // Returns true to indicate that the message was handled, or false to let
+ // the message be handled in the default way.
+ virtual bool OnMessageReceived(const IPC::Message& message);
+
+ scoped_refptr<Debugger> debugger_;
+
+ // Don't ever dereference view_ directly from another thread as it's not
+ // threadsafe, instead proxy locally via its MessageLoop.
+ RenderView* view_;
+ MessageLoop* view_loop_;
+
+ int32 view_routing_id_;
+ IPC::Channel* channel_;
+};
+
+#endif // CHROME_RENDERER_DEBUG_MESSAGE_HANDLER_H_ \ No newline at end of file
diff --git a/chrome/renderer/dom_ui_bindings.cc b/chrome/renderer/dom_ui_bindings.cc
new file mode 100644
index 0000000..e1574c1
--- /dev/null
+++ b/chrome/renderer/dom_ui_bindings.cc
@@ -0,0 +1,82 @@
+// Copyright 2008, 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 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.
+
+#include "chrome/renderer/dom_ui_bindings.h"
+
+#include "base/json_writer.h"
+#include "base/values.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/common/stl_util-inl.h"
+
+DOMUIBindings::DOMUIBindings() : routing_id_(0) {
+ BindMethod("send", &DOMUIBindings::send);
+}
+
+DOMUIBindings::~DOMUIBindings() {
+ STLDeleteContainerPointers(properties_.begin(), properties_.end());
+}
+
+void DOMUIBindings::send(const CppArgumentList& args, CppVariant* result) {
+ // We expect at least a string message identifier, and optionally take
+ // an object parameter. If we get anything else we bail.
+ if (args.size() < 1 || args.size() > 2)
+ return;
+
+ // Require the first parameter to be the message name.
+ if (!args[0].isString())
+ return;
+ const std::string message = args[0].ToString();
+
+ // If they've provided an optional message parameter, convert that into JSON.
+ std::string content;
+ if (args.size() == 2) {
+ if (!args[1].isObject())
+ return;
+ // TODO(evanm): we ought to support more than just sending arrays of
+ // strings, but it's not yet necessary for the current code.
+ std::vector<std::wstring> strings = args[1].ToStringVector();
+ ListValue value;
+ for (size_t i = 0; i < strings.size(); ++i) {
+ value.Append(Value::CreateStringValue(strings[i]));
+ }
+ JSONWriter::Write(&value, /* pretty_print= */ false, &content);
+ }
+
+ // Send the message up to the browser.
+ sender_->Send(
+ new ViewHostMsg_DOMUISend(routing_id_, message, content));
+}
+
+void DOMUIBindings::SetProperty(const std::string& name,
+ const std::string& value) {
+ CppVariant* cpp_value = new CppVariant;
+ cpp_value->Set(value);
+ BindProperty(name, cpp_value);
+ properties_.push_back(cpp_value);
+}
diff --git a/chrome/renderer/dom_ui_bindings.h b/chrome/renderer/dom_ui_bindings.h
new file mode 100644
index 0000000..a7736e3
--- /dev/null
+++ b/chrome/renderer/dom_ui_bindings.h
@@ -0,0 +1,76 @@
+// Copyright 2008, 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 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.
+
+#ifndef CHROME_RENDERER_DOM_UI_BINDINGS_H__
+#define CHROME_RENDERER_DOM_UI_BINDINGS_H__
+
+#include "chrome/common/ipc_message.h"
+#include "webkit/glue/cpp_bound_class.h"
+
+// DOMUIBindings is the class backing the "chrome" object accessible
+// from Javascript from privileged pages.
+//
+// We expose one function, for sending a message to the browser:
+// send(String name, Object argument);
+// It's plumbed through to the OnDOMUIMessage callback on RenderViewHost
+// delegate.
+class DOMUIBindings : public CppBoundClass {
+ public:
+ DOMUIBindings();
+ ~DOMUIBindings();
+
+ // The send() function provided to Javascript.
+ void send(const CppArgumentList& args, CppVariant* result);
+
+ // Set the message channel back to the browser.
+ void set_message_sender(IPC::Message::Sender* sender) {
+ sender_ = sender;
+ }
+
+ // Set the routing id for messages back to the browser.
+ void set_routing_id(int routing_id) {
+ routing_id_ = routing_id;
+ }
+
+ // Sets a property with the given name and value.
+ void SetProperty(const std::string& name, const std::string& value);
+
+ private:
+ // Our channel back to the browser is a message sender
+ // and routing id.
+ IPC::Message::Sender* sender_;
+ int routing_id_;
+
+ // The list of properties that have been set. We keep track of this so we
+ // can free them on destruction.
+ typedef std::vector<CppVariant*> PropertyList;
+ PropertyList properties_;
+};
+
+#endif // CHROME_RENDERER_DOM_UI_BINDINGS_H__
diff --git a/chrome/renderer/external_js_object.cc b/chrome/renderer/external_js_object.cc
new file mode 100644
index 0000000..dc88d29
--- /dev/null
+++ b/chrome/renderer/external_js_object.cc
@@ -0,0 +1,48 @@
+// Copyright 2008, 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 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.
+
+#include "chrome/renderer/external_js_object.h"
+
+#include "chrome/renderer/render_view.h"
+
+ExternalJSObject::ExternalJSObject() : render_view_(NULL) {
+ BindMethod("AddSearchProvider", &ExternalJSObject::AddSearchProvider);
+}
+
+void ExternalJSObject::AddSearchProvider(const CppArgumentList& args,
+ CppVariant* result) {
+ DCHECK(render_view_);
+ result->SetNull();
+
+ if (render_view_) {
+ if (args.size() < 1 || !args[0].isString())
+ return;
+ render_view_->AddSearchProvider(args[0].ToString());
+ }
+}
diff --git a/chrome/renderer/external_js_object.h b/chrome/renderer/external_js_object.h
new file mode 100644
index 0000000..3c43729
--- /dev/null
+++ b/chrome/renderer/external_js_object.h
@@ -0,0 +1,66 @@
+// Copyright 2008, 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 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.
+
+/*
+ ExternalJSObject class:
+ Bound to a JavaScript window.external object using
+ CppBoundClass::BindToJavascript(), this adds methods accessible from JS for
+ compatibility with other browsers.
+*/
+
+#ifndef CHROME_RENDERER_EXTERNAL_JS_OBJECT_H__
+#define CHROME_RENDERER_EXTERNAL_JS_OBJECT_H__
+
+#include "base/basictypes.h"
+#include "webkit/glue/cpp_bound_class.h"
+
+class RenderView;
+
+class ExternalJSObject : public CppBoundClass {
+ public:
+ // Builds the property and method lists needed to bind this class to a JS
+ // object.
+ ExternalJSObject();
+
+ // A RenderView must be set before AddSearchProvider is called, or the call
+ // will do nothing.
+ void set_render_view(RenderView* rv) { render_view_ = rv; }
+
+ // Given a URL to an OpenSearch document in the first argument, adds the
+ // corresponding search provider as a keyword search. The nonstandard
+ // capitalization is for compatibility with Firefox and IE.
+ void AddSearchProvider(const CppArgumentList& args, CppVariant* result);
+
+ private:
+ RenderView* render_view_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(ExternalJSObject);
+};
+
+#endif // CHROME_RENDERER_EXTERNAL_JS_OBJECT_H__
diff --git a/chrome/renderer/localized_error.cc b/chrome/renderer/localized_error.cc
new file mode 100644
index 0000000..261ba5b
--- /dev/null
+++ b/chrome/renderer/localized_error.cc
@@ -0,0 +1,229 @@
+// Copyright 2008, 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 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.
+
+#include "chrome/renderer/localized_error.h"
+
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "base/values.h"
+#include "chrome/common/l10n_util.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/escape.h"
+#include "net/base/net_errors.h"
+#include "webkit/glue/weberror.h"
+
+#include "generated_resources.h"
+
+namespace {
+
+// Helper method for generating the google cache lookup url.
+const std::wstring ConstructGoogleCacheUrl(const std::wstring& url) {
+ // TODO(tc): use locale based google domain
+ std::wstring cache_url(L"http://www.google.com/search?q=cache:");
+ cache_url.append(EscapeQueryParamValueUTF8(url));
+ return cache_url;
+}
+
+enum NAV_SUGGESTIONS {
+ SUGGEST_NONE = 0,
+ SUGGEST_RELOAD = 1 << 0,
+ SUGGEST_CACHE = 1 << 1,
+ SUGGEST_HOSTNAME = 1 << 2,
+};
+
+struct WebErrorNetErrorMap {
+ const int error_code;
+ const unsigned int title_resource_id;
+ const unsigned int heading_resource_id;
+ const unsigned int summary_resource_id;
+ const unsigned int details_resource_id;
+ const int suggestions; // Bitmap of SUGGEST_* values.
+};
+
+WebErrorNetErrorMap net_error_options[] = {
+ {net::ERR_TIMED_OUT,
+ IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
+ IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
+ IDS_ERRORPAGES_SUMMARY_NOT_AVAILABLE,
+ IDS_ERRORPAGES_DETAILS_TIMED_OUT,
+ SUGGEST_RELOAD | SUGGEST_CACHE,
+ },
+ {net::ERR_CONNECTION_FAILED,
+ IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
+ IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
+ IDS_ERRORPAGES_SUMMARY_NOT_AVAILABLE,
+ IDS_ERRORPAGES_DETAILS_CONNECT_FAILED,
+ SUGGEST_RELOAD | SUGGEST_CACHE,
+ },
+ {net::ERR_NAME_NOT_RESOLVED,
+ IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
+ IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
+ IDS_ERRORPAGES_SUMMARY_NOT_AVAILABLE,
+ IDS_ERRORPAGES_DETAILS_NAME_NOT_RESOLVED,
+ SUGGEST_RELOAD | SUGGEST_CACHE,
+ },
+ {net::ERR_INTERNET_DISCONNECTED,
+ IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
+ IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
+ IDS_ERRORPAGES_SUMMARY_NOT_AVAILABLE,
+ IDS_ERRORPAGES_DETAILS_DISCONNECTED,
+ SUGGEST_RELOAD,
+ },
+ {net::ERR_FILE_NOT_FOUND,
+ IDS_ERRORPAGES_TITLE_NOT_FOUND,
+ IDS_ERRORPAGES_HEADING_NOT_FOUND,
+ IDS_ERRORPAGES_SUMMARY_NOT_FOUND,
+ IDS_ERRORPAGES_DETAILS_FILE_NOT_FOUND,
+ SUGGEST_NONE,
+ },
+ {net::ERR_TOO_MANY_REDIRECTS,
+ IDS_ERRORPAGES_TITLE_LOAD_FAILED,
+ IDS_ERRORPAGES_HEADING_TOO_MANY_REDIRECTS,
+ IDS_ERRORPAGES_SUMMARY_TOO_MANY_REDIRECTS,
+ IDS_ERRORPAGES_DETAILS_TOO_MANY_REDIRECTS,
+ SUGGEST_RELOAD,
+ },
+};
+
+} // namespace
+
+void GetLocalizedErrorValues(const WebError& error,
+ DictionaryValue* error_strings) {
+ // Grab strings that are applicable to all error pages
+ error_strings->SetString(L"detailsLink",
+ l10n_util::GetString(IDS_ERRORPAGES_DETAILS_LINK));
+ error_strings->SetString(L"detailsHeading",
+ l10n_util::GetString(IDS_ERRORPAGES_DETAILS_HEADING));
+
+ // Grab the strings and settings that depend on the error type. Init
+ // options with default values.
+ WebErrorNetErrorMap options = {
+ 0,
+ IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
+ IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
+ IDS_ERRORPAGES_SUMMARY_NOT_AVAILABLE,
+ IDS_ERRORPAGES_DETAILS_UNKNOWN,
+ SUGGEST_NONE,
+ };
+ int error_code = error.GetErrorCode();
+ for (int i = 0; i < arraysize(net_error_options); ++i) {
+ if (net_error_options[i].error_code == error_code) {
+ memcpy(&options, &net_error_options[i], sizeof(WebErrorNetErrorMap));
+ break;
+ }
+ }
+
+ std::wstring suggestions_heading;
+ if (options.suggestions != SUGGEST_NONE) {
+ suggestions_heading =
+ l10n_util::GetString(IDS_ERRORPAGES_SUGGESTION_HEADING);
+ }
+ error_strings->SetString(L"suggestionsHeading", suggestions_heading);
+
+ std::wstring failed_url(UTF8ToWide(error.GetFailedURL().spec()));
+ // URLs are always LTR.
+ if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT)
+ l10n_util::WrapStringWithLTRFormatting(&failed_url);
+ error_strings->SetString(L"title",
+ l10n_util::GetStringF(options.title_resource_id,
+ failed_url.c_str()));
+ error_strings->SetString(L"heading",
+ l10n_util::GetString(options.heading_resource_id));
+
+ DictionaryValue* summary = new DictionaryValue;
+ summary->SetString(L"msg",
+ l10n_util::GetString(options.summary_resource_id));
+ // TODO(tc): we want the unicode url here since it's being displayed
+ summary->SetString(L"failedUrl", failed_url.c_str());
+ error_strings->Set(L"summary", summary);
+
+ // Error codes are expected to be negative
+ DCHECK(error_code < 0);
+ std::wstring details = l10n_util::GetString(options.details_resource_id);
+ error_strings->SetString(L"details",
+ l10n_util::GetStringF(IDS_ERRORPAGES_DETAILS_TEMPLATE,
+ IntToWString(-error_code),
+ ASCIIToWide(net::ErrorToString(error_code)),
+ details));
+
+ if (options.suggestions & SUGGEST_RELOAD) {
+ DictionaryValue* suggest_reload = new DictionaryValue;
+ suggest_reload->SetString(L"msg",
+ l10n_util::GetString(IDS_ERRORPAGES_SUGGESTION_RELOAD));
+ suggest_reload->SetString(L"reloadUrl", failed_url.c_str());
+ error_strings->Set(L"suggestionsReload", suggest_reload);
+ }
+
+ if (options.suggestions & SUGGEST_CACHE) {
+ DictionaryValue* suggest_cache = new DictionaryValue;
+ suggest_cache->SetString(L"msg",
+ l10n_util::GetString(IDS_ERRORPAGES_SUGGESTION_CACHE));
+ suggest_cache->SetString(L"cacheUrl",
+ ConstructGoogleCacheUrl(failed_url).c_str());
+ error_strings->Set(L"suggestionsCache", suggest_cache);
+ }
+
+ if (options.suggestions & SUGGEST_HOSTNAME) {
+ // Only show the "Go to hostname" suggestion if the failed_url has a path.
+ const GURL& failed_url = error.GetFailedURL();
+ if (std::string() == failed_url.path()) {
+ DictionaryValue* suggest_home_page = new DictionaryValue;
+ suggest_home_page->SetString(L"suggestionsHomepageMsg",
+ l10n_util::GetString(IDS_ERRORPAGES_SUGGESTION_HOMEPAGE));
+ std::wstring homepage(UTF8ToWide(failed_url.GetWithEmptyPath().spec()));
+ // URLs are always LTR.
+ if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT)
+ l10n_util::WrapStringWithLTRFormatting(&homepage);
+ suggest_home_page->SetString(L"homePage", homepage);
+ // TODO(tc): we actually want the unicode hostname
+ suggest_home_page->SetString(L"hostName",
+ UTF8ToWide(failed_url.host()));
+ error_strings->Set(L"suggestionsHomepage", suggest_home_page);
+ }
+ }
+}
+
+void GetFormRepostErrorValues(const GURL& display_url,
+ DictionaryValue* error_strings) {
+ std::wstring failed_url(UTF8ToWide(display_url.spec()));
+ // URLs are always LTR.
+ if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT)
+ l10n_util::WrapStringWithLTRFormatting(&failed_url);
+ error_strings->SetString(
+ L"title", l10n_util::GetStringF(IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
+ failed_url.c_str()));
+ error_strings->SetString(L"heading",
+ l10n_util::GetString(IDS_HTTP_POST_WARNING_TITLE));
+ error_strings->SetString(L"suggestionsHeading", L"");
+ DictionaryValue* summary = new DictionaryValue;
+ summary->SetString(L"msg",
+ l10n_util::GetString(IDS_ERRORPAGES_HTTP_POST_WARNING));
+ error_strings->Set(L"summary", summary);
+}
+
diff --git a/chrome/renderer/localized_error.h b/chrome/renderer/localized_error.h
new file mode 100644
index 0000000..4db6735
--- /dev/null
+++ b/chrome/renderer/localized_error.h
@@ -0,0 +1,47 @@
+// Copyright 2008, 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 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.
+
+#ifndef CHROME_RENDERER_LOCALIZED_ERROR_VALUES_H__
+#define CHROME_RENDERER_LOCALIZED_ERROR_VALUES_H__
+
+class DictionaryValue;
+class WebError;
+class GURL;
+
+void GetLocalizedErrorValues(const WebError& error,
+ DictionaryValue* error_strings);
+
+// Fills |error_strings| with values to be used to build an error page which
+// warns against reposting form data. This is special cased because the form
+// repost "error page" has no real error associated with it, and doesn't have
+// enough strings localized to meaningfully fill the net error template.
+void GetFormRepostErrorValues(const GURL& display_url,
+ DictionaryValue* error_strings);
+
+#endif // CHROME_RENDERER_LOCALIZED_ERROR_VALUES_H__
diff --git a/chrome/renderer/net/render_dns_master.cc b/chrome/renderer/net/render_dns_master.cc
new file mode 100644
index 0000000..01f8c78
--- /dev/null
+++ b/chrome/renderer/net/render_dns_master.cc
@@ -0,0 +1,189 @@
+// Copyright 2008, 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 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.
+
+// See header file for description of RenderDnsMaster class
+
+
+#include "chrome/renderer/net/render_dns_master.h"
+
+#include <ctype.h>
+
+#include "base/logging.h"
+#include "chrome/common/net/dns.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/renderer/net/render_dns_queue.h"
+#include "chrome/renderer/render_thread.h"
+
+// This API is used in the render process by renderer_glue.cc.
+// IF you are in the render process, you MUST be on the renderer thread to call.
+void DnsPrefetchCString(const char* hostname, size_t length) {
+ RenderThread::current()->Resolve(hostname, length);
+}
+
+// The number of hostnames submitted to Browser DNS resolver per call to
+// SubmitHostsnames() (which reads names from our queue).
+static const size_t kMAX_SUBMISSION_PER_TASK = 30;
+
+RenderDnsMaster::RenderDnsMaster()
+ : c_string_queue_(1000),
+#pragma warning(push)
+#pragma warning(suppress: 4355) // Okay to pass "this" here.
+ render_dns_factory_(this) {
+#pragma warning(pop)
+ Reset();
+}
+
+void RenderDnsMaster::Reset() {
+ domain_map_.clear();
+ c_string_queue_.Clear();
+ buffer_full_discard_count_ = 0;
+ numeric_ip_discard_count_ = 0;
+ new_name_count_ = 0;
+}
+
+// Push names into queue quickly!
+void RenderDnsMaster::Resolve(const char* name, size_t length) {
+ if (!length)
+ return; // Don't store empty strings in buffer.
+ if (is_numeric_ip(name, length))
+ return; // Numeric IPs have no DNS lookup significance.
+
+ size_t old_size = c_string_queue_.Size();
+ DnsQueue::PushResult result = c_string_queue_.Push(name, length);
+ if (DnsQueue::SUCCESSFUL_PUSH == result) {
+ if (1 == c_string_queue_.Size()) {
+ DCHECK(0 == old_size);
+ if (0 != old_size)
+ return; // Overkill safety net: Don't send too many InvokeLater's.
+ render_dns_factory_.RevokeAll();
+ RenderThread::current()->message_loop()->PostDelayedTask(FROM_HERE,
+ render_dns_factory_.NewRunnableMethod(
+ &RenderDnsMaster::SubmitHostnames), 10);
+ }
+ return;
+ }
+ if (DnsQueue::OVERFLOW_PUSH == result) {
+ buffer_full_discard_count_++;
+ return;
+ }
+ DCHECK(DnsQueue::REDUNDANT_PUSH == result);
+}
+
+// Extract data from the Queue, and then send it off the the Browser process
+// to be resolved.
+void RenderDnsMaster::SubmitHostnames() {
+ // Get all names out of the C_string_queue (into our map)
+ ExtractBufferedNames();
+ // TBD: IT could be that we should only extract about as many names as we are
+ // going to send to the browser. That would cause a "silly" page with a TON
+ // of URLs to start to overrun the DnsQueue, which will cause the names to
+ // be dropped (not stored in the queue). By fetching ALL names, we are
+ // taking on a lot of work, which may take a long time to process... perhaps
+ // longer than the page may be visible!?!?! If we implement a better
+ // mechanism for doing domain_map.clear() (see end of this method), then
+ // we'd automatically flush such pending work from a ridiculously link-filled
+ // page.
+
+ // Don't overload the browser DNS lookup facility, or take too long here,
+ // by only sending off kMAX_SUBMISSION_PER_TASK names to the Browser.
+ // This will help to avoid overloads when a page has a TON of links.
+ DnsPrefetchNames(kMAX_SUBMISSION_PER_TASK);
+ if (new_name_count_ > 0 || 0 < c_string_queue_.Size()) {
+ render_dns_factory_.RevokeAll();
+ RenderThread::current()->message_loop()->PostDelayedTask(FROM_HERE,
+ render_dns_factory_.NewRunnableMethod(
+ &RenderDnsMaster::SubmitHostnames), 10);
+ } else {
+ // TODO(JAR): Should we only clear the map when we navigate, or reload?
+ domain_map_.clear();
+ }
+}
+
+// Pull some hostnames from the queue, and add them to our map.
+void RenderDnsMaster::ExtractBufferedNames(size_t size_goal) {
+ size_t count(0); // Number of entries to find (0 means find all).
+ if (size_goal > 0) {
+ if (size_goal <= domain_map_.size())
+ return; // Size goal was met.
+ count = size_goal - domain_map_.size();
+ }
+
+ std::string name;
+ while (c_string_queue_.Pop(&name)) {
+ DCHECK(0 != name.size());
+ // We don't put numeric IP names into buffer.
+ DCHECK(!is_numeric_ip(name.c_str(), name.size()));
+ DomainUseMap::iterator it;
+ it = domain_map_.find(name);
+ if (domain_map_.end() == it) {
+ domain_map_[name] = kPending;
+ new_name_count_++;
+ if (0 == count) continue; // Until buffer is empty.
+ if (1 == count) break; // We found size_goal.
+ DCHECK(1 < count);
+ count--;
+ } else {
+ DCHECK(kPending == it->second || kLookupRequested == it->second);
+ }
+ }
+}
+
+void RenderDnsMaster::DnsPrefetchNames(size_t max_count) {
+ // We are on the renderer thread, and just need to send things to the browser.
+ chrome_common_net::NameList names;
+ for (DomainUseMap::iterator it = domain_map_.begin();
+ it != domain_map_.end();
+ it++) {
+ if (0 == (it->second & kLookupRequested)) {
+ it->second |= kLookupRequested;
+ names.push_back(it->first);
+ if (0 == max_count) continue; // Get all, independent of count.
+ if (1 == max_count) break;
+ max_count--;
+ DCHECK(1 <= max_count);
+ }
+ }
+ new_name_count_ -= names.size();
+ DCHECK(new_name_count_ >= 0);
+
+ RenderThread::current()->Send(new ViewHostMsg_DnsPrefetch(names));
+}
+
+// is_numeric_ip() checks to see if all characters in name are either numeric,
+// or dots. Such a name will not actually be passed to DNS, as it is an IP
+// address.
+bool RenderDnsMaster::is_numeric_ip(const char* name, size_t length) {
+ // Scan for a character outside our lookup list.
+ while (length-- > 0) {
+ if (!isdigit(*name) && '.' != *name)
+ return false;
+ name++;
+ }
+ return true;
+}
diff --git a/chrome/renderer/net/render_dns_master.h b/chrome/renderer/net/render_dns_master.h
new file mode 100644
index 0000000..31f26fe
--- /dev/null
+++ b/chrome/renderer/net/render_dns_master.h
@@ -0,0 +1,134 @@
+// Copyright 2008, 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 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.
+
+// A RenderDnsMaster instance is maintained for each RenderThread.
+// Hostnames are typically added to the embedded queue during rendering.
+// The first addition to the queue (transitioning from empty to having
+// some names) causes a processing task to be added to the Renderer Thread.
+// The processing task gathers all buffered names, and send them via IPC
+// to the browser, so that DNS lookups can be performed before the user attempts
+// to traverse a link.
+// This class removed some duplicates, and discards numeric IP addresss
+// (which wouldn't looked up in DNS anyway).
+// To limit the time during the processing task (and avoid stalling the Render
+// thread), several limits are placed on how much of the queue to process.
+// If the processing task is not able to completely empty the queue, it
+// schedules a future continuation of the task, and keeps the map of already
+// sent names. If the entire queue is processed, then the list of "sent names"
+// is cleared so that future gatherings may again pass along the same names.
+
+#ifndef CHROME_RENDERER_RENDER_NET_DNS_MASTER_H__
+#define CHROME_RENDERER_RENDER_NET_DNS_MASTER_H__
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/task.h"
+#include "chrome/renderer/net/render_dns_queue.h"
+
+// Global API consists to do Prefetching in renderer. This uses IPC to reach
+// the Browser's global functions.
+void DnsPrefetchCString(const char* hostname, size_t length);
+
+class RenderDnsMaster {
+ public:
+ RenderDnsMaster();
+
+ ~RenderDnsMaster() {}
+
+ // Push a name into the queue to be resolved.
+ void Resolve(const char* name, size_t length);
+
+ // SubmitHosts processes the buffered names, and submits them for DNS
+ // prefetching.
+ // Note that browser process may decide which names should be looked up (to
+ // pre-warm the cache) based on what has been (or not been) looked up
+ // recently.
+ // If sending for DNS lookup is incomplete (queue is not empty, or not all
+ // names in map are sent, or ...) then a task to continue processing is
+ // sent to our thread loop.
+ void SubmitHostnames();
+
+ // The following is private, but exposed for testing purposes only.
+ static bool RenderDnsMaster::is_numeric_ip(const char* name, size_t length);
+
+ private:
+ // ExtractBufferedNames pulls names from queue into the map, reducing or
+ // eliminating a waiting queue.
+ // The size_goal argument can be used to reduce the amount of
+ // processing done in this method, and can leave some data
+ // in the buffer under some circumstances.
+ // If size_goal is zero, then extraction proceeds until
+ // the queue is empty. If size goal is positive, then
+ // extraction continues until the domain_map_ contains
+ // at least the specified number of names, or the buffer is empty.
+ void ExtractBufferedNames(size_t size_goal = 0);
+
+ // DnsPrefetchNames does not check the buffer, and just sends names
+ // that are already collected in the domain_map_ for DNS lookup.
+ // If max_count is zero, then all available names are sent; and
+ // if positive, then at most max_count names will be sent.
+ void DnsPrefetchNames(size_t max_count = 0);
+
+ // Reset() restores initial state provided after construction.
+ // This discards ALL queue entries, and map entries.
+ void Reset();
+
+ // We use c_string_queue_ to hold lists of names supplied typically) by the
+ // renderer. It queues the names, at minimal cost to the renderer's thread,
+ // and allows this class to process them when time permits (in a later task).
+ DnsQueue c_string_queue_;
+
+
+ // domain_map_ contains (for each domain) one of the next two constants,
+ // depending on whether we have asked the browser process to do the actual
+ // DNS lookup.
+ static const int kLookupRequested = 0x1;
+ static const int kPending = 0x0;
+ typedef std::map<std::string, int> DomainUseMap;
+ DomainUseMap domain_map_;
+
+ // Cache a tally of the count of names that haven't yet been sent
+ // for DNS pre-fetching. Note that we *could* recalculate this
+ // count by iterating over domain_map_, looking for even values.
+ size_t new_name_count_;
+
+ // We have some metrics to examine performance. We might use
+ // these metrics to modify buffer counts etc. some day.
+ int buffer_full_discard_count_;
+ int numeric_ip_discard_count_;
+
+ ScopedRunnableMethodFactory<RenderDnsMaster> render_dns_factory_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(RenderDnsMaster);
+}; // class RenderDnsMaster
+
+#endif // CHROME_RENDERER_RENDER_NET_DNS_MASTER_H__
diff --git a/chrome/renderer/net/render_dns_master_unittest.cc b/chrome/renderer/net/render_dns_master_unittest.cc
new file mode 100644
index 0000000..beaddf7
--- /dev/null
+++ b/chrome/renderer/net/render_dns_master_unittest.cc
@@ -0,0 +1,61 @@
+// Copyright 2008, 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 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.
+
+// Single threaded tests of RenderDnsMaster functionality.
+
+#include "chrome/renderer/net/render_dns_master.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include <algorithm>
+
+namespace {
+
+class RenderDnsMasterTest : public testing::Test {
+};
+
+TEST(RenderDnsMasterTest, NumericIpDiscardCheck) {
+ // Regular names.
+ const std::string A("a.com"), B("b.net"), C("www.other.uk");
+ // Combination of digits plus dots.
+ const std::string N1("1.3."), N2("5.5.7.12");
+
+#define TESTNAME(string) RenderDnsMaster::is_numeric_ip((string.data()), \
+ (string).size())
+
+ EXPECT_TRUE(TESTNAME(N1));
+ EXPECT_TRUE(TESTNAME(N2));
+
+ EXPECT_FALSE(TESTNAME(A));
+ EXPECT_FALSE(TESTNAME(B));
+ EXPECT_FALSE(TESTNAME(C));
+
+#undef TESTNAME
+}
+
+} // namespace anonymous \ No newline at end of file
diff --git a/chrome/renderer/net/render_dns_queue.cc b/chrome/renderer/net/render_dns_queue.cc
new file mode 100644
index 0000000..6a1661c
--- /dev/null
+++ b/chrome/renderer/net/render_dns_queue.cc
@@ -0,0 +1,169 @@
+// Copyright 2008, 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 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.
+
+// See header file for description of DnsQueue class
+
+#include "chrome/renderer/net/render_dns_queue.h"
+
+#include "base/logging.h"
+#include "base/stats_counters.h"
+
+DnsQueue::DnsQueue(BufferSize size)
+ : buffer_(new char[size + 2]),
+ buffer_size_(size + 1),
+ buffer_sentinel_(size + 1),
+ size_(0) {
+ CHECK(0 < static_cast<BufferSize>(size + 3)); // Avoid overflow worries.
+ buffer_[buffer_sentinel_] = '\0'; // Guard byte to help reading data.
+ readable_ = writeable_ = 0; // Buffer starts empty.
+}
+
+DnsQueue::~DnsQueue(void) {
+}
+
+// Push takes an unterminated string plus its length.
+// The string must not contain a null terminator.
+// Exactly length chars are written, or nothing is written.
+// Returns true for success, false there was no room to push.
+DnsQueue::PushResult DnsQueue::Push(const char* source,
+ const size_t unsigned_length) {
+ BufferSize length = static_cast<BufferSize>(unsigned_length);
+ if (0 > length+1) // Avoid overflows in conversion to signed.
+ return OVERFLOW_PUSH;
+
+ // To save on sites with a LOT of links to the SAME domain, we have a
+ // a compaction hack that removes duplicates when we try to push() a
+ // match with the last push.
+ if (0 < size_ && readable_ + length < buffer_sentinel_ &&
+ 0 == strncmp(source, &buffer_[readable_], unsigned_length) &&
+ '\0' == buffer_[readable_ + unsigned_length]) {
+ SIMPLE_STATS_COUNTER(L"DNS.PrefetchDnsRedundantPush");
+
+ // We already wrote this name to the queue, so we'll skip this repeat.
+ return REDUNDANT_PUSH;
+ }
+
+ // Calling convention precludes nulls.
+ DCHECK(!length || '\0' != source[length - 1]);
+
+ DCHECK(Validate());
+
+ BufferSize available_space = readable_ - writeable_;
+
+ if (0 >= available_space) {
+ available_space += buffer_size_;
+ }
+
+ if (length + 1 >= available_space) {
+ SIMPLE_STATS_COUNTER(L"DNS.PrefetchDnsQueueFull");
+ return OVERFLOW_PUSH; // Not enough space to push.
+ }
+
+ BufferSize dest = writeable_;
+ BufferSize space_till_wrap = buffer_sentinel_ - dest;
+ if (space_till_wrap < length + 1) {
+ // Copy until we run out of room at end of buffer.
+ std::memcpy(&buffer_[dest], source, space_till_wrap);
+ // Ensure caller didn't have embedded '\0' and also
+ // ensure trailing sentinel was in place.
+ DCHECK(space_till_wrap == strlen(&buffer_[dest])); // Relies on sentinel.
+
+ length -= space_till_wrap;
+ source += space_till_wrap;
+ dest = 0; // Continue writing at start of buffer.
+ }
+
+ // Copy any remaining portion of source.
+ std::memcpy(&buffer_[dest], source, length);
+ DCHECK(dest + length < buffer_sentinel_);
+ buffer_[dest + length] = '\0'; // We need termination in our buffer.
+ DCHECK(length == strlen(&buffer_[dest])); // Preclude embedded '\0'.
+
+ dest += length + 1;
+ if (dest == buffer_sentinel_)
+ dest = 0;
+
+ writeable_ = dest;
+ size_++;
+ DCHECK(Validate());
+ return SUCCESSFUL_PUSH;
+}
+
+// Extracts the next available string from the buffer.
+// The returned string is null terminated, and hence has length
+// that is exactly one greater than the written string.
+// If the buffer is empty, then the Pop and returns false.
+bool DnsQueue::Pop(std::string* out_string) {
+ DCHECK(Validate());
+ // Sentinel will preclude memory reads beyond buffer's end.
+ DCHECK('\0' == buffer_[buffer_sentinel_]);
+
+ if (readable_ == writeable_) {
+ return false; // buffer was empty
+ }
+
+ // Constructor *may* rely on sentinel for null termination.
+ (*out_string) = &buffer_[readable_];
+ // Our sentinel_ at end of buffer precludes an overflow in cast.
+ BufferSize first_fragment_size = static_cast<BufferSize> (out_string->size());
+
+ BufferSize terminal_null;
+ if (readable_ + first_fragment_size >= buffer_sentinel_) {
+ // Sentinel was used, so we need the portion after the wrap.
+ out_string->append(&buffer_[0]); // Fragment at start of buffer.
+ // Sentinel precludes overflow in cast to signed type.
+ terminal_null = static_cast<BufferSize>(out_string->size())
+ - first_fragment_size;
+ } else {
+ terminal_null = readable_ + first_fragment_size;
+ }
+ DCHECK('\0' == buffer_[terminal_null]);
+
+ BufferSize new_readable = terminal_null + 1;
+ if (buffer_sentinel_ == new_readable)
+ new_readable = 0;
+
+ readable_ = new_readable;
+ size_--;
+ if (readable_ == writeable_ || 0 == size_) {
+ // Queue is empty, so reset to start of buffer to help with peeking.
+ readable_ = writeable_ = 0;
+ }
+ DCHECK(Validate());
+ return true;
+}
+
+bool DnsQueue::Validate() {
+ return (readable_ >= 0) &&
+ readable_ < buffer_sentinel_ &&
+ writeable_ >= 0 &&
+ writeable_ < buffer_sentinel_ &&
+ '\0' == buffer_[buffer_sentinel_] &&
+ ((0 == size_) == (readable_ == writeable_));
+}
diff --git a/chrome/renderer/net/render_dns_queue.h b/chrome/renderer/net/render_dns_queue.h
new file mode 100644
index 0000000..0a180f6
--- /dev/null
+++ b/chrome/renderer/net/render_dns_queue.h
@@ -0,0 +1,117 @@
+// Copyright 2008, 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 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.
+
+// DnsQueue is implemented as an almost FIFO circular buffer for text
+// strings that don't have embedded nulls ('\0'). The "almost" element is that
+// some duplicate strings may be removed (i.e., the string won't really be
+// pushed *if* the class happens to notice that a duplicate is already in the
+// queue).
+// The buffers internal format is null terminated character strings
+// (a.k.a., c_strings).
+// It is written to be as fast as possible during push() operations, so
+// that there will be minimal performance impact on a supplier thread.
+// The push() operation will not block, and no memory allocation is involved
+// (internally) during the push operations.
+// The one caveat is that if there is insufficient space in the buffer to
+// accept additional string via a push(), then the push() will fail, and
+// the buffer will be unmodified.
+
+// This class was designed for use in DNS prefetch operations. During
+// rendering, the supplier is the renderer (typically), and the consumer
+// is a thread that sends messages to an async DNS resolver.
+
+#ifndef CHROME_RENDERER_NET_RENDER_DNS_QUEUE_H__
+#define CHROME_RENDERER_NET_RENDER_DNS_QUEUE_H__
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/lock.h"
+#include "base/scoped_ptr.h"
+
+class DnsQueue {
+ public:
+ // BufferSize is a signed type used for indexing into a buffer.
+ typedef int32 BufferSize;
+
+ enum PushResult { SUCCESSFUL_PUSH, OVERFLOW_PUSH, REDUNDANT_PUSH };
+
+ // The size specified in the constructor creates a buffer large enough
+ // to hold at most one string of that length, or "many"
+ // strings of considerably shorter length. Note that strings
+ // are padded internally with a terminal '\0" while stored,
+ // so if you are trying to be precise and get N strings of
+ // length K to fit, you should actually construct a buffer with
+ // an internal size of N*(K+1).
+ explicit DnsQueue(BufferSize size);
+ ~DnsQueue(void);
+
+ size_t Size() const { return size_; }
+ void Clear() {
+ size_ = 0;
+ readable_ = writeable_;
+ Validate();
+ }
+
+ // Push takes an unterminated string of the given length
+ // and inserts it into the queue for later
+ // extraction by read. For each successful push(), there
+ // can later be a corresponding read() to extracted the text.
+ // The string must not contain an embedded null terminator
+ // Exactly length chars are written, or the push fails (where
+ // "fails" means nothing is written).
+ // Returns true for success, false for failure (nothing written).
+ PushResult Push(const char* source, const size_t length);
+
+ PushResult Push(std::string source) {
+ return Push(source.c_str(), source.length());
+ }
+
+ // Extract the next available string from the buffer.
+ // If the buffer is empty, then return false.
+ bool Pop(std::string* out_string);
+
+ private:
+ bool Validate(); // Checks that all internal data is valid.
+
+ const BufferSize buffer_size_; // Size one smaller than allocated space.
+ const scoped_array<char> buffer_; // Circular buffer, plus extra char ('\0').
+ const BufferSize buffer_sentinel_; // Index of extra '\0' at end of buffer_.
+
+ // If writable_ == readable_, then the buffer is empty.
+ BufferSize readable_; // Next readable char in buffer_.
+ BufferSize writeable_; // The next space in buffer_ to push.
+
+ // Number of queued strings
+ size_t size_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(DnsQueue);
+}; // class DnsQueue
+
+#endif // CHROME_RENDERER_NET_RENDER_DNS_QUEUE_H__
diff --git a/chrome/renderer/net/render_dns_queue_unittest.cc b/chrome/renderer/net/render_dns_queue_unittest.cc
new file mode 100644
index 0000000..2829264
--- /dev/null
+++ b/chrome/renderer/net/render_dns_queue_unittest.cc
@@ -0,0 +1,287 @@
+// Copyright 2008, 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 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.
+
+#include <sstream>
+
+#include "chrome/renderer/net/render_dns_queue.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Single threaded tests of DnsQueue functionality.
+
+namespace {
+
+class DnsQueueTest : public testing::Test {
+};
+
+// Define a helper class that does Push'es and Pop's of numbers.
+// This makes it easy to test a LOT of reads, and keep the expected Pop
+// value in sync with the Push value.
+class DnsQueueSequentialTester {
+ public:
+ DnsQueueSequentialTester::DnsQueueSequentialTester(
+ DnsQueue& buffer, int32 read_counter = 0, int32 write_counter = 0);
+
+ // Return of false means buffer was full, or would not take entry.
+ bool Push(void); // Push the string value of next number.
+
+ // Return of false means buffer returned wrong value.
+ bool Pop(void); // Validate string value of next read.
+
+ private:
+ DnsQueue* buffer_;
+ int32 read_counter_; // expected value of next read string.
+ int32 write_counter_; // Numerical value to write next string.
+ DISALLOW_EVIL_CONSTRUCTORS(DnsQueueSequentialTester);
+};
+
+
+DnsQueueSequentialTester::DnsQueueSequentialTester(
+ DnsQueue& buffer, int32 read_counter, int32 write_counter)
+ : buffer_(&buffer),
+ read_counter_(read_counter),
+ write_counter_(write_counter) {
+}
+
+bool DnsQueueSequentialTester::Push(void) {
+ std::ostringstream value;
+ value << write_counter_;
+
+ // Exercise both write methods intermittently.
+ DnsQueue::PushResult result = (write_counter_ % 2) ?
+ buffer_->Push(value.str().c_str(), value.str().size()) :
+ buffer_->Push(value.str());
+ if (DnsQueue::SUCCESSFUL_PUSH == result)
+ write_counter_++;
+ return DnsQueue::OVERFLOW_PUSH != result;
+}
+
+bool DnsQueueSequentialTester::Pop(void) {
+ std::string string;
+ if (buffer_->Pop(&string)) {
+ std::ostringstream expected_value;
+ expected_value << read_counter_++;
+ EXPECT_STREQ(expected_value.str().c_str(), string.c_str())
+ << "Pop did not match write for value " << read_counter_;
+ return true;
+ }
+ return false;
+}
+
+
+TEST(DnsQueueTest, BufferUseCheck) {
+ // Use a small buffer so we can see that we can't write a string as soon as it
+ // gets longer than one less than the buffer size. The extra empty character
+ // is used to keep read and write pointers from overlapping when buffer is
+ // full. This shows the buffer size can constrain writes (and we're not
+ // scribbling all over memory).
+ const int buffer_size = 3; // Just room for 2 digts plus '\0' plus blank.
+ std::string string;
+ DnsQueue buffer(buffer_size);
+ DnsQueueSequentialTester tester(buffer);
+
+ EXPECT_FALSE(tester.Pop()) << "Pop from empty buffer succeeded";
+
+ int i;
+ for (i = 0; i < 102; i++) {
+ if (!tester.Push())
+ break; // String was too large.
+ EXPECT_TRUE(tester.Pop()) << "Unable to read back data " << i;
+ EXPECT_FALSE(buffer.Pop(&string))
+ << "read from empty buffer not flagged";
+ }
+
+ EXPECT_GE(i, 100) << "Can't write 2 digit strings in 4 character buffer";
+ EXPECT_LT(i, 101) << "We wrote 3 digit strings into a 4 character buffer";
+}
+
+TEST(DnsQueueTest, SubstringUseCheck) {
+ // Verify that only substring is written/read.
+ const int buffer_size = 100;
+ const char big_string[] = "123456789";
+ std::string string;
+ DnsQueue buffer(buffer_size);
+
+ EXPECT_FALSE(buffer.Pop(&string)) << "Initial buffer not empty";
+
+ EXPECT_EQ(DnsQueue::SUCCESSFUL_PUSH, buffer.Push(big_string, 3))
+ << "Can't write string";
+ EXPECT_EQ(DnsQueue::SUCCESSFUL_PUSH, buffer.Push(big_string, 0))
+ << "Can't write null string";
+ EXPECT_EQ(DnsQueue::SUCCESSFUL_PUSH, buffer.Push(big_string, 5))
+ << "Can't write string";
+
+ EXPECT_TRUE(buffer.Pop(&string)) << "Filled buffer marked as empty";
+ EXPECT_STREQ(string.c_str(), "123") << "Can't read actual data";
+ EXPECT_TRUE(buffer.Pop(&string)) << "Filled buffer marked as empty";
+ EXPECT_STREQ(string.c_str(), "") << "Can't read null string";
+ EXPECT_TRUE(buffer.Pop(&string)) << "Filled buffer marked as empty";
+ EXPECT_STREQ(string.c_str(), "12345") << "Can't read actual data";
+
+ EXPECT_FALSE(buffer.Pop(&string))
+ << "read from empty buffer not flagged";
+}
+
+TEST(DnsQueueTest, SizeCheck) {
+ // Verify that size is correctly accounted for in buffer.
+ const int buffer_size = 100;
+ std::string input_string = "Hello";
+ std::string string;
+ DnsQueue buffer(buffer_size);
+
+ EXPECT_EQ(0, buffer.Size());
+ EXPECT_FALSE(buffer.Pop(&string));
+ EXPECT_EQ(DnsQueue::SUCCESSFUL_PUSH, buffer.Push(input_string));
+ EXPECT_EQ(1, buffer.Size());
+ EXPECT_EQ(DnsQueue::SUCCESSFUL_PUSH, buffer.Push("Hi There"));
+ EXPECT_EQ(2, buffer.Size());
+ EXPECT_TRUE(buffer.Pop(&string));
+ EXPECT_EQ(1, buffer.Size());
+ EXPECT_TRUE(buffer.Pop(&string));
+ EXPECT_EQ(0, buffer.Size());
+ EXPECT_EQ(DnsQueue::SUCCESSFUL_PUSH, buffer.Push(input_string));
+ EXPECT_EQ(1, buffer.Size());
+
+ // Check to see that the first string, if repeated, is discarded.
+ EXPECT_EQ(DnsQueue::REDUNDANT_PUSH, buffer.Push(input_string));
+ EXPECT_EQ(1, buffer.Size());
+}
+
+TEST(DnsQueueTest, FillThenEmptyCheck) {
+ // Use a big buffer so we'll get a bunch of writes in.
+ // This tests to be sure the buffer holds many strings.
+ // We also make sure they all come out intact.
+ const int buffer_size = 1000;
+ int byte_usage_counter = 1; // Separation character between pointer.
+ DnsQueue buffer(buffer_size);
+ DnsQueueSequentialTester tester(buffer);
+
+ int write_success;
+ for (write_success = 0; write_success < buffer_size; write_success++) {
+ if (!tester.Push())
+ break;
+ EXPECT_EQ(buffer.Size(), write_success + 1);
+ if (write_success > 99)
+ byte_usage_counter += 4; // 3 digit plus '\0'.
+ else if (write_success > 9)
+ byte_usage_counter += 3; // 2 digits plus '\0'.
+ else
+ byte_usage_counter += 2; // Digit plus '\0'.
+ }
+ EXPECT_LE(byte_usage_counter, buffer_size)
+ << "Written data exceeded buffer size";
+ EXPECT_GE(byte_usage_counter, buffer_size - 4)
+ << "Buffer does not appear to have filled";
+
+ EXPECT_GE(write_success, 10) << "Couldn't even write 10 one digit strings "
+ "in " << buffer_size << " byte buffer";
+
+
+ while (1) {
+ if (!tester.Pop())
+ break;
+ write_success--;
+ }
+ EXPECT_EQ(write_success, 0) << "Push and Pop count were different";
+
+ EXPECT_FALSE(tester.Pop()) << "Read from empty buffer succeeded";
+}
+
+TEST(DnsQueueTest, ClearCheck) {
+ // Use a big buffer so we'll get a bunch of writes in.
+ const int buffer_size = 1000;
+ DnsQueue buffer(buffer_size);
+ std::string string("ABC");
+ DnsQueueSequentialTester tester(buffer);
+
+ int write_success;
+ for (write_success = 0; write_success < buffer_size; write_success++) {
+ if (!tester.Push())
+ break;
+ EXPECT_EQ(buffer.Size(), write_success + 1);
+ }
+
+ buffer.Clear();
+ EXPECT_EQ(buffer.Size(), 0);
+
+ int write_success2;
+ for (write_success2 = 0; write_success2 < buffer_size; write_success2++) {
+ if (!tester.Push())
+ break;
+ EXPECT_EQ(buffer.Size(), write_success2 + 1);
+ }
+
+ for (; write_success2 > 0; write_success2--) {
+ EXPECT_EQ(buffer.Size(), write_success2);
+ EXPECT_TRUE(buffer.Pop(&string));
+ }
+
+ EXPECT_EQ(buffer.Size(), 0);
+ buffer.Clear();
+ EXPECT_EQ(buffer.Size(), 0);
+}
+
+TEST(DnsQueueTest, WrapOnVariousSubstrings) {
+ // Use a prime number for the allocated buffer size so that we tend
+ // to exercise all possible edge conditions (in circular text buffer).
+ // Once we're over 10 writes, all our strings are 2 digits long,
+ // with a '\0' terminator added making 3 characters per write.
+ // Since 3 is relatively prime to 23, we'll soon wrap (about
+ // every 6 writes). Hence after 18 writes, we'll have tested all
+ // edge conditions. We'll first do this where we empty the buffer
+ // after each write, and then again where there are some strings
+ // still in the buffer after each write.
+ const int prime_number = 23;
+ // Circular buffer needs an extra extra space to distinguish full from empty.
+ const int buffer_size = prime_number - 1;
+ DnsQueue buffer(buffer_size);
+ DnsQueueSequentialTester tester(buffer);
+
+ // First test empties between each write. Second loop
+ // has writes for each pop. Third has three pushes per pop.
+ // Third has two items pending during each write.
+ for (int j = 0; j < 3; j++) {
+ // Each group does 30 tests, which is more than 10+18
+ // which was needed to get into the thorough testing zone
+ // mentioned above.
+ for (int i = 0; i < 30; i++) {
+ EXPECT_TRUE(tester.Push()) << "write failed with only " << j
+ << " blocks in buffer";
+ EXPECT_TRUE(tester.Pop()) << "Unable to read back data ";
+ }
+ EXPECT_TRUE(tester.Push());
+ }
+
+ // Read back the accumulated 3 extra blocks.
+ EXPECT_TRUE(tester.Pop());
+ EXPECT_TRUE(tester.Pop());
+ EXPECT_TRUE(tester.Pop());
+ EXPECT_FALSE(tester.Pop());
+}
+
+}; // namespace
diff --git a/chrome/renderer/plugin_channel_host.cc b/chrome/renderer/plugin_channel_host.cc
new file mode 100644
index 0000000..a31ee83
--- /dev/null
+++ b/chrome/renderer/plugin_channel_host.cc
@@ -0,0 +1,135 @@
+// Copyright 2008, 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 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.
+
+#include "chrome/renderer/plugin_channel_host.h"
+
+#include "chrome/common/plugin_messages.h"
+
+// A simple MessageFilter that will ignore all messages and respond to sync
+// messages with an error when is_listening_ is false.
+class IsListeningFilter : public IPC::ChannelProxy::MessageFilter {
+ public:
+ IsListeningFilter() {}
+
+ // MessageFilter overrides
+ virtual void OnFilterRemoved() {}
+ virtual void OnFilterAdded(IPC::Channel* channel) { channel_ = channel; }
+ virtual bool OnMessageReceived(const IPC::Message& message);
+
+ static bool is_listening_;
+
+ private:
+ IPC::Channel* channel_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(IsListeningFilter);
+};
+
+bool IsListeningFilter::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ if (!IsListeningFilter::is_listening_) {
+ // reply to synchronous messages with an error (so they don't block while
+ // we're not listening)
+ if (message.is_sync()) {
+ IPC::Message* reply = IPC::SyncMessage::GenerateReply(&message);
+ reply->set_reply_error();
+ channel_->Send(reply);
+ }
+ handled = true;
+ } else {
+ handled = false;
+ }
+ return handled;
+}
+
+// static
+bool IsListeningFilter::is_listening_ = true;
+
+// static
+void PluginChannelHost::SetListening(bool flag) {
+ IsListeningFilter::is_listening_ = flag;
+}
+
+PluginChannelHost* PluginChannelHost::GetPluginChannelHost(
+ const std::wstring& channel_name, MessageLoop* ipc_message_loop) {
+ PluginChannelHost* result =
+ static_cast<PluginChannelHost*>(PluginChannelBase::GetChannel(
+ channel_name,
+ IPC::Channel::MODE_CLIENT,
+ ClassFactory,
+ ipc_message_loop,
+ true));
+ return result;
+}
+
+PluginChannelHost::PluginChannelHost() {
+}
+
+PluginChannelHost::~PluginChannelHost() {
+}
+
+bool PluginChannelHost::Init(MessageLoop* ipc_message_loop,
+ bool create_pipe_now) {
+ bool ret = PluginChannelBase::Init(ipc_message_loop, create_pipe_now);
+ is_listening_filter_ = new IsListeningFilter;
+ channel_->AddFilter(is_listening_filter_);
+ return ret;
+}
+
+int PluginChannelHost::GenerateRouteID() {
+ int route_id = MSG_ROUTING_NONE;
+ Send(new PluginMsg_GenerateRouteID(&route_id));
+
+ return route_id;
+}
+
+void PluginChannelHost::AddRoute(int route_id,
+ IPC::Channel::Listener* listener,
+ bool npobject) {
+ PluginChannelBase::AddRoute(route_id, listener, npobject);
+
+ if (!npobject)
+ proxies_[route_id] = listener;
+}
+
+void PluginChannelHost::RemoveRoute(int route_id) {
+ proxies_.erase(route_id);
+ PluginChannelBase::RemoveRoute(route_id);
+}
+
+void PluginChannelHost::OnChannelError() {
+ PluginChannelBase::OnChannelError();
+
+ for (ProxyMap::iterator iter = proxies_.begin();
+ iter != proxies_.end(); iter++) {
+ iter->second->OnChannelError();
+ }
+
+ proxies_.clear();
+}
+
diff --git a/chrome/renderer/plugin_channel_host.h b/chrome/renderer/plugin_channel_host.h
new file mode 100644
index 0000000..aed6f79
--- /dev/null
+++ b/chrome/renderer/plugin_channel_host.h
@@ -0,0 +1,76 @@
+// Copyright 2008, 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 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.
+
+#ifndef CHROME_PLUGIN_PLUGIN_CHANNEL_HOST_H__
+#define CHROME_PLUGIN_PLUGIN_CHANNEL_HOST_H__
+
+#include "chrome/plugin/plugin_channel_base.h"
+
+class IsListeningFilter;
+
+// Encapsulates an IPC channel between the renderer and one plugin process.
+// On the plugin side there's a corresponding PluginChannel.
+class PluginChannelHost : public PluginChannelBase {
+ public:
+ static PluginChannelHost* GetPluginChannelHost(
+ const std::wstring& channel_name, MessageLoop* ipc_message_loop);
+
+ ~PluginChannelHost();
+
+ virtual bool Init(MessageLoop* ipc_message_loop, bool create_pipe_now);
+
+ int GenerateRouteID();
+
+ void AddRoute(int route_id, IPC::Channel::Listener* listener, bool npobject);
+ void RemoveRoute(int route_id);
+
+ // IPC::Channel::Listener override
+ void OnChannelError();
+
+ static void SetListening(bool flag);
+
+ private:
+ // Called on the render thread
+ PluginChannelHost();
+
+ static PluginChannelBase* ClassFactory() { return new PluginChannelHost(); }
+
+ // Keep track of all the registered WebPluginDelegeProxies to
+ // inform about OnChannelError
+ typedef stdext::hash_map<int, IPC::Channel::Listener*> ProxyMap;
+ ProxyMap proxies_;
+
+ // An IPC MessageFilter that can be told to filter out all messages. This is
+ // used when the JS debugger is attached in order to avoid browser hangs.
+ scoped_refptr<IsListeningFilter> is_listening_filter_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(PluginChannelHost);
+};
+
+#endif // CHROME_PLUGIN_PLUGIN_CHANNEL_HOST_H__
diff --git a/chrome/renderer/render_process.cc b/chrome/renderer/render_process.cc
new file mode 100644
index 0000000..5d15ba4
--- /dev/null
+++ b/chrome/renderer/render_process.cc
@@ -0,0 +1,273 @@
+// Copyright 2008, 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 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.
+
+#include <windows.h>
+#include <objidl.h>
+#include <mlang.h>
+
+#include "chrome/renderer/render_process.h"
+
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/message_loop.h"
+#include "base/histogram.h"
+#include "chrome/browser/net/dns_global.h" // TODO(jar): DNS calls should be renderer specific, not including browser.
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/ipc_channel.h"
+#include "chrome/common/ipc_message_utils.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/renderer/render_view.h"
+#include "webkit/glue/webkit_glue.h"
+
+//-----------------------------------------------------------------------------
+
+IMLangFontLink2* RenderProcess::lang_font_link_ = NULL;
+bool RenderProcess::load_plugins_in_process_ = false;
+
+//-----------------------------------------------------------------------------
+
+RenderProcess::RenderProcess(const std::wstring& channel_name)
+ : render_thread_(channel_name),
+#pragma warning(suppress: 4355) // Okay to pass "this" here.
+ clearer_factory_(this) {
+ for (int i = 0; i < arraysize(shared_mem_cache_); ++i)
+ shared_mem_cache_[i] = NULL;
+}
+
+RenderProcess::~RenderProcess() {
+ // We need to stop the RenderThread as the clearer_factory_
+ // member could be in use while the object itself is destroyed,
+ // as a result of the containing RenderProcess object being destroyed.
+ // This race condition causes a crash when the renderer process is shutting
+ // down.
+ render_thread_.Stop();
+ ClearSharedMemCache();
+}
+
+// static
+bool RenderProcess::GlobalInit(const std::wstring &channel_name) {
+ // HACK: See http://b/issue?id=1024307 for rationale.
+ if (GetModuleHandle(L"LPK.DLL") == NULL) {
+ // Makes sure lpk.dll is loaded by gdi32 to make sure ExtTextOut() works
+ // when buffering into a EMF buffer for printing.
+ typedef BOOL (__stdcall *GdiInitializeLanguagePack)(int LoadedShapingDLLs);
+ GdiInitializeLanguagePack gdi_init_lpk =
+ reinterpret_cast<GdiInitializeLanguagePack>(GetProcAddress(
+ GetModuleHandle(L"GDI32.DLL"),
+ "GdiInitializeLanguagePack"));
+ DCHECK(gdi_init_lpk);
+ if (gdi_init_lpk) {
+ gdi_init_lpk(0);
+ }
+ }
+
+ InitializeLangFontLink();
+
+ CommandLine command_line;
+ if (command_line.HasSwitch(switches::kJavaScriptFlags)) {
+ webkit_glue::SetJavaScriptFlags(
+ command_line.GetSwitchValue(switches::kJavaScriptFlags));
+ }
+ if (command_line.HasSwitch(switches::kPlaybackMode) ||
+ command_line.HasSwitch(switches::kRecordMode)) {
+ webkit_glue::SetRecordPlaybackMode(true);
+ }
+
+ if (command_line.HasSwitch(switches::kInProcessPlugins) ||
+ command_line.HasSwitch(switches::kSingleProcess))
+ load_plugins_in_process_ = true;
+
+ if (command_line.HasSwitch(switches::kDnsPrefetchDisable)) {
+ chrome_browser_net::EnableDnsPrefetch(false);
+ }
+
+ if (command_line.HasSwitch(switches::kEnableWatchdog)) {
+ // TODO(JAR): Need to implement renderer IO msgloop watchdog.
+ }
+
+ if (command_line.HasSwitch(switches::kDumpHistogramsOnExit)) {
+ StatisticsRecorder::set_dump_on_exit(true);
+ }
+
+ ChildProcessFactory<RenderProcess> factory;
+ return ChildProcess::GlobalInit(channel_name, &factory);
+}
+
+// static
+void RenderProcess::GlobalCleanup() {
+ ChildProcess::GlobalCleanup();
+ ReleaseLangFontLink();
+}
+
+// static
+void RenderProcess::InitializeLangFontLink() {
+ // TODO(hbono): http://b/1072298 Experimentally commented out this code to
+ // prevent registry leaks caused by this IMLangFontLink2 interface.
+ // If you find any font-rendering regressions. Please feel free to blame me.
+#ifdef USE_IMLANGFONTLINK2
+ IMultiLanguage* multi_language = NULL;
+ lang_font_link_ = NULL;
+ if (S_OK != CoCreateInstance(CLSID_CMultiLanguage,
+ 0,
+ CLSCTX_ALL,
+ IID_IMultiLanguage,
+ reinterpret_cast<void**>(&multi_language))) {
+ DLOG(ERROR) << "Cannot CoCreate CMultiLanguage";
+ } else {
+ if (S_OK != multi_language->QueryInterface(IID_IMLangFontLink2,
+ reinterpret_cast<void**>(&lang_font_link_))) {
+ DLOG(ERROR) << "Cannot query LangFontLink2 interface";
+ }
+ }
+
+ if (multi_language)
+ multi_language->Release();
+#endif
+}
+
+// static
+void RenderProcess::ReleaseLangFontLink() {
+ // TODO(hbono): http://b/1072298 Experimentally commented out this code to
+ // prevent registry leaks caused by this IMLangFontLink2 interface.
+ // If you find any font-rendering regressions. Please feel free to blame me.
+#ifdef USE_IMLANGFONTLINK2
+ if (lang_font_link_)
+ lang_font_link_->Release();
+#endif
+}
+
+// static
+IMLangFontLink2* RenderProcess::GetLangFontLink() {
+ return lang_font_link_;
+}
+
+// static
+bool RenderProcess::ShouldLoadPluginsInProcess() {
+ return load_plugins_in_process_;
+}
+
+// static
+SharedMemory* RenderProcess::AllocSharedMemory(size_t size) {
+ self()->clearer_factory_.RevokeAll();
+
+ SharedMemory* mem = self()->GetSharedMemFromCache(size);
+ if (mem)
+ return mem;
+
+ // Round-up size to allocation granularity
+ SYSTEM_INFO info;
+ GetSystemInfo(&info);
+
+ size = size / info.dwAllocationGranularity + 1;
+ size = size * info.dwAllocationGranularity;
+
+ mem = new SharedMemory();
+ if (!mem)
+ return NULL;
+ if (!mem->Create(L"", false, true, size)) {
+ delete mem;
+ return NULL;
+ }
+
+ return mem;
+}
+
+// static
+void RenderProcess::FreeSharedMemory(SharedMemory* mem) {
+ if (self()->PutSharedMemInCache(mem)) {
+ self()->ScheduleCacheClearer();
+ return;
+ }
+ DeleteSharedMem(mem);
+}
+
+// static
+void RenderProcess::DeleteSharedMem(SharedMemory* mem) {
+ delete mem;
+}
+
+SharedMemory* RenderProcess::GetSharedMemFromCache(size_t size) {
+ // look for a cached object that is suitable for the requested size.
+ for (int i = 0; i < arraysize(shared_mem_cache_); ++i) {
+ SharedMemory* mem = shared_mem_cache_[i];
+ if (mem && mem->max_size() >= size) {
+ shared_mem_cache_[i] = NULL;
+ return mem;
+ }
+ }
+ return NULL;
+}
+
+bool RenderProcess::PutSharedMemInCache(SharedMemory* mem) {
+ // simple algorithm:
+ // - look for an empty slot to store mem, or
+ // - if full, then replace any existing cache entry that is smaller than the
+ // given shared memory object.
+ for (int i = 0; i < arraysize(shared_mem_cache_); ++i) {
+ if (!shared_mem_cache_[i]) {
+ shared_mem_cache_[i] = mem;
+ return true;
+ }
+ }
+ for (int i = 0; i < arraysize(shared_mem_cache_); ++i) {
+ SharedMemory* cached_mem = shared_mem_cache_[i];
+ if (cached_mem->max_size() < mem->max_size()) {
+ shared_mem_cache_[i] = mem;
+ DeleteSharedMem(cached_mem);
+ return true;
+ }
+ }
+ return false;
+}
+
+void RenderProcess::ClearSharedMemCache() {
+ for (int i = 0; i < arraysize(shared_mem_cache_); ++i) {
+ if (shared_mem_cache_[i]) {
+ DeleteSharedMem(shared_mem_cache_[i]);
+ shared_mem_cache_[i] = NULL;
+ }
+ }
+}
+
+void RenderProcess::ScheduleCacheClearer() {
+ // If we already have a deferred clearer, then revoke it so we effectively
+ // delay cache clearing until idle for our desired interval.
+ clearer_factory_.RevokeAll();
+
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ clearer_factory_.NewRunnableMethod(&RenderProcess::ClearSharedMemCache),
+ 5000 /* 5 seconds */);
+}
+
+void RenderProcess::Cleanup() {
+#ifndef NDEBUG
+ // log important leaked objects
+ webkit_glue::CheckForLeaks();
+#endif
+}
diff --git a/chrome/renderer/render_process.h b/chrome/renderer/render_process.h
new file mode 100644
index 0000000..49f43e2
--- /dev/null
+++ b/chrome/renderer/render_process.h
@@ -0,0 +1,126 @@
+// Copyright 2008, 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 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.
+
+#ifndef CHROME_RENDERER_RENDER_PROCESS_H__
+#define CHROME_RENDERER_RENDER_PROCESS_H__
+
+#include <objidl.h>
+#include <mlang.h>
+
+#include "base/shared_memory.h"
+#include "chrome/common/child_process.h"
+#include "chrome/renderer/render_thread.h"
+
+class RenderView;
+
+// Represents the renderer end of the browser<->renderer connection. The
+// opposite end is the RenderProcessHost. This is a singleton object for
+// each renderer.
+class RenderProcess : public ChildProcess {
+ public:
+ static bool GlobalInit(const std::wstring& channel_name);
+ static void GlobalCleanup();
+
+ // Returns true if plugins should be loaded in-process.
+ static bool ShouldLoadPluginsInProcess();
+
+ static IMLangFontLink2* GetLangFontLink();
+
+ // Allocates shared memory. When no longer needed, you should pass the
+ // SharedMemory pointer to FreeSharedMemory so it can be recycled. The size
+ // reported in the resulting SharedMemory object will be greater than or
+ // equal to the requested size. This method returns NULL if unable to
+ // allocate memory for some reason.
+ static SharedMemory* AllocSharedMemory(size_t size);
+
+ // Frees shared memory allocated by AllocSharedMemory. You should only use
+ // this function to free the SharedMemory object.
+ static void FreeSharedMemory(SharedMemory* mem);
+
+ private:
+ friend class ChildProcessFactory<RenderProcess>;
+ RenderProcess(const std::wstring& channel_name);
+ ~RenderProcess();
+
+ // Initializes the LangFontLink object. This function cannot be called
+ // while the process is restricted by the sandbox or it will fail.
+ static void InitializeLangFontLink();
+
+ // Releases the LangFontLink object if already created.
+ static void ReleaseLangFontLink();
+
+ // Returns a pointer to the RenderProcess singleton instance. This is
+ // guaranteed to be non-NULL between calls to GlobalInit and GlobalCleanup.
+ static RenderProcess* self() {
+ return static_cast<RenderProcess*>(child_process_);
+ }
+
+ static ChildProcess* ClassFactory(const std::wstring& channel_name);
+
+ // This is here so consumers will use FreeSharedMemory instead. A destructor
+ // on SharedMemory would be too tempting.
+ static void DeleteSharedMem(SharedMemory* mem);
+
+ // Look in the shared memory cache for a suitable object to reuse. Returns
+ // NULL if there is none.
+ SharedMemory* GetSharedMemFromCache(size_t size);
+
+ // Maybe put the given shared memory into the shared memory cache. Returns
+ // true if the SharedMemory object was stored in the cache; otherwise, false
+ // is returned.
+ bool PutSharedMemInCache(SharedMemory* mem);
+
+ void ClearSharedMemCache();
+
+ // We want to lazily clear the shared memory cache if no one has requested
+ // memory. This methods are used to schedule a deferred call to
+ // RenderProcess::ClearSharedMemCache.
+ void ScheduleCacheClearer();
+
+ // ChildProcess implementation
+ virtual void Cleanup();
+
+ // The one render thread (to be replaced with a set of render threads).
+ RenderThread render_thread_;
+
+ // A very simplistic and small cache. If an entry in this array is non-null,
+ // then it points to a SharedMemory object that is available for reuse.
+ SharedMemory* shared_mem_cache_[2];
+
+ // This factory is used to lazily invoke ClearSharedMemCache.
+ ScopedRunnableMethodFactory<RenderProcess> clearer_factory_;
+
+ static IMLangFontLink2* lang_font_link_;
+
+ static bool load_plugins_in_process_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(RenderProcess);
+};
+
+#endif // CHROME_RENDERER_RENDER_PROCESS_H__
diff --git a/chrome/renderer/render_thread.cc b/chrome/renderer/render_thread.cc
new file mode 100644
index 0000000..4288377
--- /dev/null
+++ b/chrome/renderer/render_thread.cc
@@ -0,0 +1,220 @@
+// Copyright 2008, 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 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.
+
+#include <windows.h>
+#include <algorithm>
+
+#include "chrome/renderer/render_thread.h"
+
+#include "base/shared_memory.h"
+#include "chrome/common/ipc_logging.h"
+#include "chrome/plugin/plugin_channel.h"
+#include "chrome/renderer/net/render_dns_master.h"
+#include "chrome/renderer/render_process.h"
+#include "chrome/renderer/render_view.h"
+#include "chrome/renderer/visitedlink_slave.h"
+#include "webkit/glue/cache_manager.h"
+
+static const unsigned int kCacheStatsDelayMS = 2000 /* milliseconds */;
+
+// V8 needs a 1MB stack size.
+static const size_t kStackSize = 1024 * 1024;
+
+/*static*/
+DWORD RenderThread::tls_index_ = ThreadLocalStorage::Alloc();
+
+//-----------------------------------------------------------------------------
+// Methods below are only called on the owner's thread:
+
+RenderThread::RenderThread(const std::wstring& channel_name)
+ : Thread("Chrome_RenderThread"),
+ channel_name_(channel_name),
+ owner_loop_(MessageLoop::current()),
+ visited_link_slave_(NULL),
+ render_dns_master_(NULL),
+ in_send_(0) {
+ DCHECK(owner_loop_);
+ StartWithStackSize(kStackSize);
+}
+
+RenderThread::~RenderThread() {
+ Stop();
+}
+
+void RenderThread::OnChannelError() {
+ // XXX(darin): is this really correct/sufficient?
+ owner_loop_->Quit();
+}
+
+bool RenderThread::Send(IPC::Message* msg) {
+ in_send_++;
+ bool rv = channel_->Send(msg);
+ in_send_--;
+ return rv;
+}
+
+void RenderThread::AddFilter(IPC::ChannelProxy::MessageFilter* filter) {
+ channel_->AddFilter(filter);
+}
+
+void RenderThread::RemoveFilter(IPC::ChannelProxy::MessageFilter* filter) {
+ channel_->RemoveFilter(filter);
+}
+
+void RenderThread::Resolve(const char* name, size_t length) {
+ return render_dns_master_->Resolve(name, length);
+ }
+
+void RenderThread::AddRoute(int32 routing_id,
+ IPC::Channel::Listener* listener) {
+ DCHECK(MessageLoop::current() == message_loop());
+
+ // This corresponds to the AddRoute call done in CreateView.
+ router_.AddRoute(routing_id, listener);
+}
+
+void RenderThread::RemoveRoute(int32 routing_id) {
+ DCHECK(MessageLoop::current() == message_loop());
+
+ router_.RemoveRoute(routing_id);
+}
+
+void RenderThread::Init() {
+ DCHECK(tls_index_) << "static initializer failed";
+ DCHECK(!current()) << "should only have one RenderThread per thread";
+
+ cache_stats_factory_.reset(
+ new ScopedRunnableMethodFactory<RenderThread>(this));
+
+ channel_.reset(new IPC::SyncChannel(channel_name_,
+ IPC::Channel::MODE_CLIENT, this, owner_loop_, true));
+
+ ThreadLocalStorage::Set(tls_index_, this);
+
+ // The renderer thread should wind-up COM.
+ CoInitialize(0);
+
+ // TODO(darin): We should actually try to share this object between
+ // RenderThread instances.
+ visited_link_slave_ = new VisitedLinkSlave();
+
+ render_dns_master_.reset(new RenderDnsMaster());
+
+#ifdef IPC_MESSAGE_LOG_ENABLED
+ IPC::Logging::current()->SetIPCSender(this);
+#endif
+}
+
+void RenderThread::CleanUp() {
+ DCHECK(current() == this);
+
+ // Clean up plugin channels before this thread goes away.
+ PluginChannelBase::CleanupChannels();
+
+#ifdef IPC_MESSAGE_LOG_ENABLED
+ IPC::Logging::current()->SetIPCSender(NULL);
+#endif
+
+ delete visited_link_slave_;
+ visited_link_slave_ = NULL;
+
+ CoUninitialize();
+}
+
+void RenderThread::OnUpdateVisitedLinks(SharedMemoryHandle table) {
+ DCHECK(table) << "Bad table handle";
+ visited_link_slave_->Init(table);
+}
+
+void RenderThread::OnMessageReceived(const IPC::Message& msg) {
+ // NOTE: We could subclass router_ to intercept OnControlMessageReceived, but
+ // it seems simpler to just process any control messages that we care about
+ // up-front and then send the rest of the messages onto router_.
+
+ if (msg.routing_id() == MSG_ROUTING_CONTROL) {
+ IPC_BEGIN_MESSAGE_MAP(RenderThread, msg)
+ IPC_MESSAGE_HANDLER(ViewMsg_VisitedLink_NewTable, OnUpdateVisitedLinks)
+ IPC_MESSAGE_HANDLER(ViewMsg_SetNextPageID, OnSetNextPageID)
+ IPC_MESSAGE_HANDLER(ViewMsg_New, OnCreateNewView)
+ IPC_MESSAGE_HANDLER(ViewMsg_SetCacheCapacities, OnSetCacheCapacities)
+ IPC_MESSAGE_HANDLER(ViewMsg_GetCacheResourceStats,
+ OnGetCacheResourceStats)
+ // send the rest to the router
+ IPC_MESSAGE_UNHANDLED(router_.OnMessageReceived(msg))
+ IPC_END_MESSAGE_MAP()
+ } else {
+ router_.OnMessageReceived(msg);
+ }
+}
+
+void RenderThread::OnSetNextPageID(int32 next_page_id) {
+ // This should only be called at process initialization time, so we shouldn't
+ // have to worry about thread-safety.
+ RenderView::SetNextPageID(next_page_id);
+}
+
+void RenderThread::OnCreateNewView(HWND parent_hwnd,
+ HANDLE modal_dialog_event,
+ const WebPreferences& webkit_prefs,
+ int32 view_id) {
+ // TODO(darin): once we have a RenderThread per RenderView, this will need to
+ // change to assert that we are not creating more than one view.
+
+ RenderView::Create(
+ parent_hwnd, modal_dialog_event, MSG_ROUTING_NONE, webkit_prefs, view_id);
+}
+
+void RenderThread::OnSetCacheCapacities(size_t min_dead_capacity,
+ size_t max_dead_capacity,
+ size_t capacity) {
+ CacheManager::SetCapacities(min_dead_capacity, max_dead_capacity, capacity);
+}
+
+void RenderThread::OnGetCacheResourceStats() {
+ CacheManager::ResourceTypeStats stats;
+ CacheManager::GetResourceTypeStats(&stats);
+ Send(new ViewHostMsg_ResourceTypeStats(stats));
+}
+
+void RenderThread::InformHostOfCacheStats() {
+ CacheManager::UsageStats stats;
+ CacheManager::GetUsageStats(&stats);
+ Send(new ViewHostMsg_UpdatedCacheStats(stats));
+}
+
+void RenderThread::InformHostOfCacheStatsLater() {
+ // Rate limit informing the host of our cache stats.
+ if (!cache_stats_factory_->empty())
+ return;
+
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ cache_stats_factory_->NewRunnableMethod(
+ &RenderThread::InformHostOfCacheStats),
+ kCacheStatsDelayMS);
+}
diff --git a/chrome/renderer/render_thread.h b/chrome/renderer/render_thread.h
new file mode 100644
index 0000000..ca022671
--- /dev/null
+++ b/chrome/renderer/render_thread.h
@@ -0,0 +1,145 @@
+// Copyright 2008, 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 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.
+
+#ifndef CHROME_RENDERER_RENDER_THREAD_H__
+#define CHROME_RENDERER_RENDER_THREAD_H__
+
+#include "base/ref_counted.h"
+#include "base/shared_memory.h"
+#include "base/task.h"
+#include "base/thread.h"
+#include "base/thread_local_storage.h"
+#include "chrome/common/ipc_sync_channel.h"
+#include "chrome/common/message_router.h"
+
+class SkBitmap;
+class Task;
+class VisitedLinkSlave;
+struct WebPreferences;
+class RenderDnsMaster;
+
+// The RenderThread class represents a background thread where RenderView
+// instances live. The RenderThread supports an API that is used by its
+// consumer to talk indirectly to the RenderViews and supporting objects.
+// Likewise, it provides an API for the RenderViews to talk back to the main
+// process (i.e., their corresponding WebContents).
+//
+// Most of the communication occurs in the form of IPC messages. They are
+// routed to the RenderThread according to the routing IDs of the messages.
+// The routing IDs correspond to RenderView instances.
+
+class RenderThread : public IPC::Channel::Listener,
+ public IPC::Message::Sender,
+ public Thread {
+ public:
+ RenderThread(const std::wstring& channel_name);
+ ~RenderThread();
+
+ // IPC::Channel::Listener implementation:
+ virtual void OnMessageReceived(const IPC::Message& msg);
+ virtual void OnChannelError();
+
+ // IPC::Message::Sender implementation:
+ virtual bool Send(IPC::Message* msg);
+
+ void AddFilter(IPC::ChannelProxy::MessageFilter* filter);
+ void RemoveFilter(IPC::ChannelProxy::MessageFilter* filter);
+
+ // The RenderThread instance for the current thread.
+ static RenderThread* current() {
+ return static_cast<RenderThread*>(ThreadLocalStorage::Get(tls_index_));
+ }
+
+ VisitedLinkSlave* visited_link_slave() const { return visited_link_slave_; }
+
+ // Do DNS prefetch resolution of a hostname.
+ void Resolve(const char* name, size_t length);
+
+ // See documentation on MessageRouter for AddRoute and RemoveRoute
+ void AddRoute(int32 routing_id, IPC::Channel::Listener* listener);
+ void RemoveRoute(int32 routing_id);
+
+ // Invokes InformHostOfCacheStats after a short delay. Used to move this
+ // bookkeeping operation off the critical latency path.
+ void InformHostOfCacheStatsLater();
+
+ MessageLoop* owner_loop() { return owner_loop_; }
+
+ // Indicates if RenderThread::Send() is on the call stack.
+ bool in_send() const { return in_send_ != 0; }
+
+ protected:
+ // Called by the thread base class
+ virtual void Init();
+ virtual void CleanUp();
+
+ private:
+ void OnUpdateVisitedLinks(SharedMemoryHandle table);
+
+ void OnSetNextPageID(int32 next_page_id);
+ void OnCreateNewView(HWND parent_hwnd,
+ HANDLE modal_dialog_event,
+ const WebPreferences& webkit_prefs,
+ int32 view_id);
+ void OnTransferBitmap(const SkBitmap& bitmap, int resource_id);
+ void OnSetCacheCapacities(size_t min_dead_capacity,
+ size_t max_dead_capacity,
+ size_t capacity);
+ void OnGetCacheResourceStats();
+
+ // Gather usage statistics from the in-memory cache and inform our host.
+ // These functions should be call periodically so that the host can make
+ // decisions about how to allocation resources using current information.
+ void InformHostOfCacheStats();
+
+ static DWORD tls_index_;
+
+ // The message loop used to run tasks on the thread that started this thread.
+ MessageLoop* owner_loop_;
+
+ // Used only on the background render thread to implement message routing
+ // functionality to the consumers of the RenderThread.
+ MessageRouter router_;
+
+ std::wstring channel_name_;
+ scoped_ptr<IPC::SyncChannel> channel_;
+
+ // These objects live solely on the render thread.
+ VisitedLinkSlave* visited_link_slave_;
+
+ scoped_ptr<RenderDnsMaster> render_dns_master_;
+
+ scoped_ptr<ScopedRunnableMethodFactory<RenderThread> > cache_stats_factory_;
+
+ int in_send_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(RenderThread);
+};
+
+#endif // CHROME_RENDERER_RENDER_THREAD_H__
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
new file mode 100644
index 0000000..519e37d
--- /dev/null
+++ b/chrome/renderer/render_view.cc
@@ -0,0 +1,2469 @@
+// Copyright 2008, 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 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.
+
+#include "chrome/renderer/render_view.h"
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/gfx/bitmap_header.h"
+#include "base/gfx/bitmap_platform_device.h"
+#include "base/gfx/image_operations.h"
+#include "base/gfx/native_theme.h"
+#include "base/gfx/vector_canvas.h"
+#include "base/gfx/png_encoder.h"
+#include "base/string_piece.h"
+#include "base/string_util.h"
+#include "chrome/app/theme/theme_resources.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/gfx/emf.h"
+#include "chrome/common/gfx/favicon_size.h"
+#include "chrome/common/gfx/color_utils.h"
+#include "chrome/common/jstemplate_builder.h"
+#include "chrome/common/l10n_util.h"
+#include "chrome/common/resource_bundle.h"
+#include "chrome/common/text_zoom.h"
+#include "chrome/common/thumbnail_score.h"
+#include "chrome/renderer/about_handler.h"
+#include "chrome/renderer/debug_message_handler.h"
+#include "chrome/renderer/localized_error.h"
+#include "chrome/renderer/renderer_resources.h"
+#include "chrome/renderer/visitedlink_slave.h"
+#include "chrome/renderer/webplugin_delegate_proxy.h"
+#include "chrome/views/message_box_view.h"
+#include "net/base/escape.h"
+#include "net/base/net_errors.h"
+#include "webkit/default_plugin/default_plugin_shared.h"
+#include "webkit/glue/dom_operations.h"
+#include "webkit/glue/dom_serializer.h"
+#include "webkit/glue/password_form.h"
+#include "webkit/glue/plugins/plugin_list.h"
+#include "webkit/glue/searchable_form_data.h"
+#include "webkit/glue/webdatasource.h"
+#include "webkit/glue/webdropdata.h"
+#include "webkit/glue/weberror.h"
+#include "webkit/glue/webframe.h"
+#include "webkit/glue/webhistoryitem.h"
+#include "webkit/glue/webinputevent.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/webpreferences.h"
+#include "webkit/glue/webresponse.h"
+#include "webkit/glue/weburlrequest.h"
+#include "webkit/glue/webview.h"
+#include "webkit/glue/plugins/webplugin_delegate_impl.h"
+#include "webkit/port/platform/graphics/PlatformContextSkia.h"
+
+#include "generated_resources.h"
+
+//-----------------------------------------------------------------------------
+
+// define to write the time necessary for thumbnail/DOM text retrieval,
+// respectively, into the system debug log
+// #define TIME_BITMAP_RETRIEVAL
+// #define TIME_TEXT_RETRIEVAL
+
+// maximum number of characters in the document to index, any text beyond this
+// point will be clipped
+static const int kMaxIndexChars = 65535;
+
+// Size of the thumbnails that we'll generate
+static const int kThumbnailWidth = 196;
+static const int kThumbnailHeight = 136;
+
+// Delay in milliseconds that we'll wait before capturing the page contents
+// and thumbnail.
+static const int kDelayForCaptureMs = 500;
+
+// Typically, we capture the page data once the page is loaded.
+// Sometimes, the page never finishes to load, preventing the page capture
+// To workaround this problem, we always perform a capture after the following
+// delay.
+static const int kDelayForForcedCaptureMs = 6000;
+
+// How often we will sync the navigation state when the user is changing form
+// elements or scroll position.
+const TimeDelta kDelayForNavigationSync = TimeDelta::FromSeconds(5);
+
+// The next available page ID to use. This ensures that the page IDs are
+// globally unique in the renderer.
+static int32 next_page_id_ = 1;
+
+static const char* const kUnreachableWebDataURL =
+ "chrome-resource://chromewebdata/";
+
+namespace {
+
+// Associated with browser-initiated navigations to hold tracking data.
+class RenderViewExtraRequestData : public WebRequest::ExtraData {
+ public:
+ RenderViewExtraRequestData(int32 pending_page_id,
+ PageTransition::Type transition,
+ const GURL& url)
+ : pending_page_id_(pending_page_id),
+ transition_type(transition),
+ request_committed(false) {
+ }
+
+ // Contains the page_id for this navigation or -1 if there is none yet.
+ int32 pending_page_id() const { return pending_page_id_; }
+
+ // Is this a new navigation?
+ bool is_new_navigation() const { return pending_page_id_ == -1; }
+
+ // Contains the transition type that the browser specified when it
+ // initiated the load.
+ PageTransition::Type transition_type;
+
+ // True if we have already processed the "DidCommitLoad" event for this
+ // request. Used by session history.
+ bool request_committed;
+
+ private:
+ int32 pending_page_id_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(RenderViewExtraRequestData);
+};
+
+} // namespace
+
+///////////////////////////////////////////////////////////////////////////////
+
+RenderView::RenderView()
+ : RenderWidget(),
+ is_loading_(false),
+ page_id_(-1),
+ last_page_id_sent_to_browser_(-1),
+ last_indexed_page_id_(-1),
+ method_factory_(this),
+ nav_state_sync_timer_(kDelayForNavigationSync),
+ opened_by_user_gesture_(true),
+ enable_dom_automation_(false),
+ enable_dom_ui_bindings_(false),
+ target_url_status_(TARGET_NONE),
+ printed_document_width_(0),
+ first_default_plugin_(NULL),
+ navigation_gesture_(NavigationGestureUnknown),
+ history_back_list_count_(0),
+ history_forward_list_count_(0),
+ disable_popup_blocking_(false),
+ has_unload_listener_(false) {
+ resource_dispatcher_ = new ResourceDispatcher(this);
+ nav_state_sync_timer_.set_task(
+ method_factory_.NewRunnableMethod(&RenderView::SyncNavigationState));
+}
+
+RenderView::~RenderView() {
+ resource_dispatcher_->ClearMessageSender();
+ // Clear any back-pointers that might still be held by plugins.
+ PluginDelegateList::iterator it = plugin_delegates_.begin();
+ while (it != plugin_delegates_.end()) {
+ (*it)->DropRenderView();
+ it = plugin_delegates_.erase(it);
+ }
+
+ RenderThread::current()->RemoveFilter(debug_message_handler_);
+}
+
+/*static*/
+RenderView* RenderView::Create(HWND parent_hwnd,
+ HANDLE modal_dialog_event,
+ int32 opener_id,
+ const WebPreferences& webkit_prefs,
+ int32 routing_id) {
+ DCHECK(routing_id != MSG_ROUTING_NONE);
+ scoped_refptr<RenderView> view = new RenderView();
+ view->Init(parent_hwnd,
+ modal_dialog_event,
+ opener_id,
+ webkit_prefs,
+ routing_id); // adds reference
+ return view;
+}
+
+/*static*/
+void RenderView::SetNextPageID(int32 next_page_id) {
+ // This method should only be called during process startup, and the given
+ // page id had better not exceed our current next page id!
+ DCHECK(next_page_id_ == 1);
+ DCHECK(next_page_id >= next_page_id_);
+ next_page_id_ = next_page_id;
+}
+
+void RenderView::PluginDestroyed(WebPluginDelegateProxy* proxy) {
+ PluginDelegateList::iterator it =
+ std::find(plugin_delegates_.begin(), plugin_delegates_.end(), proxy);
+ DCHECK(it != plugin_delegates_.end());
+ plugin_delegates_.erase(it);
+ // If the plugin is deleted, we need to clear our reference in case user
+ // clicks the info bar to install. Unfortunately we are getting
+ // PluginDestroyed in single process mode. However, that is not a huge
+ // concern.
+ if (proxy == first_default_plugin_)
+ first_default_plugin_ = NULL;
+}
+
+void RenderView::PluginCrashed(const std::wstring& plugin_path) {
+ Send(new ViewHostMsg_CrashedPlugin(routing_id_, plugin_path));
+}
+
+
+void RenderView::JSOutOfMemory() {
+ Send(new ViewHostMsg_JSOutOfMemory(routing_id_));
+}
+
+void RenderView::Init(HWND parent_hwnd,
+ HANDLE modal_dialog_event,
+ int32 opener_id,
+ const WebPreferences& webkit_prefs,
+ int32 routing_id) {
+ DCHECK(!webview());
+
+ if (opener_id != MSG_ROUTING_NONE)
+ opener_id_ = opener_id;
+
+ // Avoid a leak here by not assigning, since WebView::Create addrefs for us.
+ WebWidget* view = WebView::Create(this, webkit_prefs);
+ webwidget_.swap(&view);
+
+ // Don't let WebCore keep a B/F list - we have our own.
+ // We let it keep 1 entry because FrameLoader::goToItem expects an item in the
+ // backForwardList, which is used only in ASSERTs.
+ webview()->SetBackForwardListSize(1);
+
+ routing_id_ = routing_id;
+ RenderThread::current()->AddRoute(routing_id_, this);
+ // Take a reference on behalf of the RenderThread. This will be balanced
+ // when we receive ViewMsg_Close.
+ AddRef();
+
+ // If this is a popup, we must wait for the CreatingNew_ACK message before
+ // completing initialization. Otherwise, we can finish it now.
+ if (opener_id == MSG_ROUTING_NONE) {
+ did_show_ = true;
+ CompleteInit(parent_hwnd);
+ }
+
+ host_window_ = parent_hwnd;
+ modal_dialog_event_.Set(modal_dialog_event);
+
+ CommandLine command_line;
+ enable_dom_automation_ =
+ command_line.HasSwitch(switches::kDomAutomationController);
+ disable_popup_blocking_ =
+ command_line.HasSwitch(switches::kDisablePopupBlocking);
+
+ debug_message_handler_ = new DebugMessageHandler(this);
+ RenderThread::current()->AddFilter(debug_message_handler_);
+}
+
+void RenderView::OnMessageReceived(const IPC::Message& message) {
+ // Let the resource dispatcher intercept resource messages first.
+ if (resource_dispatcher_->OnMessageReceived(message))
+ return;
+ IPC_BEGIN_MESSAGE_MAP(RenderView, message)
+ IPC_MESSAGE_HANDLER(ViewMsg_CreatingNew_ACK, OnCreatingNewAck)
+ IPC_MESSAGE_HANDLER(ViewMsg_CaptureThumbnail, SendThumbnail)
+ IPC_MESSAGE_HANDLER(ViewMsg_GetPrintedPagesCount, OnGetPrintedPagesCount)
+ IPC_MESSAGE_HANDLER(ViewMsg_PrintPages, OnPrintPages)
+ IPC_MESSAGE_HANDLER(ViewMsg_Navigate, OnNavigate)
+ IPC_MESSAGE_HANDLER(ViewMsg_Stop, OnStop)
+ IPC_MESSAGE_HANDLER(ViewMsg_LoadAlternateHTMLText, OnLoadAlternateHTMLText)
+ IPC_MESSAGE_HANDLER(ViewMsg_StopFinding, OnStopFinding)
+ IPC_MESSAGE_HANDLER(ViewMsg_Undo, OnUndo)
+ IPC_MESSAGE_HANDLER(ViewMsg_Redo, OnRedo)
+ IPC_MESSAGE_HANDLER(ViewMsg_Cut, OnCut)
+ IPC_MESSAGE_HANDLER(ViewMsg_Copy, OnCopy)
+ IPC_MESSAGE_HANDLER(ViewMsg_Paste, OnPaste)
+ IPC_MESSAGE_HANDLER(ViewMsg_Replace, OnReplace)
+ IPC_MESSAGE_HANDLER(ViewMsg_Delete, OnDelete)
+ IPC_MESSAGE_HANDLER(ViewMsg_SelectAll, OnSelectAll)
+ IPC_MESSAGE_HANDLER(ViewMsg_CopyImageAt, OnCopyImageAt)
+ IPC_MESSAGE_HANDLER(ViewMsg_Find, OnFind)
+ IPC_MESSAGE_HANDLER(ViewMsg_AlterTextSize, OnAlterTextSize)
+ IPC_MESSAGE_HANDLER(ViewMsg_SetPageEncoding, OnSetPageEncoding)
+ IPC_MESSAGE_HANDLER(ViewMsg_InspectElement, OnInspectElement)
+ IPC_MESSAGE_HANDLER(ViewMsg_ShowJavaScriptConsole, OnShowJavaScriptConsole)
+ IPC_MESSAGE_HANDLER(ViewMsg_DownloadImage, OnDownloadImage)
+ IPC_MESSAGE_HANDLER(ViewMsg_ScriptEvalRequest, OnScriptEvalRequest)
+ IPC_MESSAGE_HANDLER(ViewMsg_AddMessageToConsole, OnAddMessageToConsole)
+ IPC_MESSAGE_HANDLER(ViewMsg_DebugAttach, OnDebugAttach)
+ IPC_MESSAGE_HANDLER(ViewMsg_ReservePageIDRange, OnReservePageIDRange)
+ IPC_MESSAGE_HANDLER(ViewMsg_UploadFile, OnUploadFileRequest)
+ IPC_MESSAGE_HANDLER(ViewMsg_FormFill, OnFormFill)
+ IPC_MESSAGE_HANDLER(ViewMsg_FillPasswordForm, OnFillPasswordForm)
+ IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDragEnter, OnDragTargetDragEnter)
+ IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDragOver, OnDragTargetDragOver)
+ IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDragLeave, OnDragTargetDragLeave)
+ IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDrop, OnDragTargetDrop)
+ IPC_MESSAGE_HANDLER(ViewMsg_AllowDomAutomationBindings,
+ OnAllowDomAutomationBindings)
+ IPC_MESSAGE_HANDLER(ViewMsg_AllowDOMUIBindings, OnAllowDOMUIBindings)
+ IPC_MESSAGE_HANDLER(ViewMsg_SetDOMUIProperty, OnSetDOMUIProperty)
+ IPC_MESSAGE_HANDLER(ViewMsg_DragSourceEndedOrMoved, OnDragSourceEndedOrMoved)
+ IPC_MESSAGE_HANDLER(ViewMsg_DragSourceSystemDragEnded,
+ OnDragSourceSystemDragEnded)
+ IPC_MESSAGE_HANDLER(ViewMsg_SetInitialFocus, OnSetInitialFocus)
+ IPC_MESSAGE_HANDLER(ViewMsg_FindReplyACK, OnFindReplyAck)
+ IPC_MESSAGE_HANDLER(ViewMsg_UpdateTargetURL_ACK, OnUpdateTargetURLAck)
+ IPC_MESSAGE_HANDLER(ViewMsg_UpdateWebPreferences, OnUpdateWebPreferences)
+ IPC_MESSAGE_HANDLER(ViewMsg_SetAltErrorPageURL, OnSetAltErrorPageURL)
+ IPC_MESSAGE_HANDLER(ViewMsg_InstallMissingPlugin, OnInstallMissingPlugin)
+ IPC_MESSAGE_HANDLER(ViewMsg_RunFileChooserResponse, OnFileChooserResponse)
+ IPC_MESSAGE_HANDLER(ViewMsg_EnableViewSourceMode, OnEnableViewSourceMode)
+ IPC_MESSAGE_HANDLER(ViewMsg_UpdateBackForwardListCount,
+ OnUpdateBackForwardListCount)
+ IPC_MESSAGE_HANDLER(ViewMsg_GetAllSavableResourceLinksForCurrentPage,
+ OnGetAllSavableResourceLinksForCurrentPage)
+ IPC_MESSAGE_HANDLER(ViewMsg_GetSerializedHtmlDataForCurrentPageWithLocalLinks,
+ OnGetSerializedHtmlDataForCurrentPageWithLocalLinks)
+ IPC_MESSAGE_HANDLER(ViewMsg_GetApplicationInfo, OnGetApplicationInfo)
+ IPC_MESSAGE_HANDLER(ViewMsg_ShouldClose, OnMsgShouldClose)
+ IPC_MESSAGE_HANDLER(ViewMsg_ClosePage, OnClosePage)
+ IPC_MESSAGE_HANDLER(ViewMsg_ThemeChanged, OnThemeChanged)
+ // Have the super handle all other messages.
+ IPC_MESSAGE_UNHANDLED(RenderWidget::OnMessageReceived(message))
+ IPC_END_MESSAGE_MAP()
+}
+
+// Got a response from the browser after the renderer decided to create a new
+// view.
+void RenderView::OnCreatingNewAck(HWND parent) {
+ CompleteInit(parent);
+}
+
+void RenderView::SendThumbnail() {
+ WebFrame* main_frame = webview()->GetMainFrame();
+ if (!main_frame)
+ return;
+
+ // get the URL for this page
+ GURL url(main_frame->GetURL());
+ if (url.is_empty())
+ return;
+
+ if (size_.IsEmpty())
+ return; // Don't create an empty thumbnail!
+
+ ThumbnailScore score;
+ SkBitmap thumbnail;
+ CaptureThumbnail(main_frame, kThumbnailWidth, kThumbnailHeight, &thumbnail,
+ &score);
+ // send the thumbnail message to the browser process
+ IPC::Message* thumbnail_msg = new IPC::Message(routing_id_,
+ ViewHostMsg_Thumbnail::ID, IPC::Message::PRIORITY_NORMAL);
+ IPC::ParamTraits<GURL>::Write(thumbnail_msg, url);
+ IPC::ParamTraits<ThumbnailScore>::Write(thumbnail_msg, score);
+ IPC::ParamTraits<SkBitmap>::Write(thumbnail_msg, thumbnail);
+ Send(thumbnail_msg);
+}
+
+int RenderView::SwitchFrameToPrintMediaType(const ViewMsg_Print_Params& params,
+ WebFrame* frame) {
+ float ratio = static_cast<float>(params.desired_dpi / params.dpi);
+ float paper_width = params.printable_size.width() * ratio;
+ float paper_height = params.printable_size.height() * ratio;
+ float minLayoutWidth = static_cast<float>(paper_width * params.min_shrink);
+ float maxLayoutWidth = static_cast<float>(paper_width * params.max_shrink);
+
+ // Safari uses: 765 & 1224. Margins aren't exactly the same either.
+ // Scale = 2.222 for MDI printer.
+ int pages;
+ if (!frame->SetPrintingMode(true,
+ minLayoutWidth,
+ maxLayoutWidth,
+ &printed_document_width_)) {
+ NOTREACHED();
+ pages = 0;
+ } else {
+ // Force to recalculate the height, otherwise it reuse the current window
+ // height as the default.
+ float effective_shrink = printed_document_width_ / paper_width;
+ gfx::Size page_size(printed_document_width_,
+ static_cast<int>(paper_height * effective_shrink) - 1);
+ WebView* view = frame->GetView();
+ if (view) {
+ // Hack around an issue where if the current view height is higher than
+ // the page height, empty pages will be printed even if the bottom of the
+ // web page is empty.
+ printing_view_size_ = view->GetSize();
+ view->Resize(page_size);
+ view->Layout();
+ }
+ pages = frame->ComputePageRects(params.printable_size);
+ DCHECK(pages);
+ }
+ return pages;
+}
+
+void RenderView::SwitchFrameToDisplayMediaType(WebFrame* frame) {
+ // Set the layout back to "normal" document; i.e. CSS media type = "screen".
+ frame->SetPrintingMode(false, 0, 0, NULL);
+ WebView* view = frame->GetView();
+ if (view) {
+ // Restore from the hack described at SwitchFrameToPrintMediaType().
+ view->Resize(printing_view_size_);
+ view->Layout();
+ printing_view_size_.SetSize(0, 0);
+ }
+ printed_document_width_ = 0;
+}
+
+void RenderView::OnPrintPage(const ViewMsg_PrintPage_Params& params) {
+ DCHECK(webview());
+ if (webview())
+ PrintPage(params, webview()->GetMainFrame());
+}
+
+void RenderView::PrintPage(const ViewMsg_PrintPage_Params& params,
+ WebFrame* frame) {
+ if (printed_document_width_ <= 0) {
+ NOTREACHED();
+ return;
+ }
+
+ // Generate a memory-based EMF file. The EMF will use the current screen's
+ // DPI.
+ gfx::Emf emf;
+
+ emf.CreateDc(NULL, NULL);
+ HDC hdc = emf.hdc();
+ DCHECK(hdc);
+ gfx::PlatformDevice::InitializeDC(hdc);
+
+ gfx::Rect rect;
+ frame->GetPageRect(params.page_number, &rect);
+ DCHECK(rect.height());
+ DCHECK(rect.width());
+ double shrink = static_cast<double>(printed_document_width_) /
+ params.params.printable_size.width();
+ // This check would fire each time the page would get truncated on the
+ // right. This is not worth a DCHECK() but should be looked into, for
+ // example, wouldn't be worth trying in landscape?
+ // DCHECK_LE(rect.width(), printed_document_width_);
+
+ // Buffer one page at a time.
+ int src_size_x = printed_document_width_;
+ int src_size_y =
+ static_cast<int>(ceil(params.params.printable_size.height() *
+ shrink));
+#if 0
+ // TODO(maruel): This code is kept for testing until the 100% GDI drawing
+ // code is stable. maruels use this code's output as a reference when the
+ // GDI drawing code fails.
+
+ // Mix of Skia and GDI based.
+ gfx::PlatformCanvas canvas(src_size_x, src_size_y, true);
+ canvas.drawARGB(255, 255, 255, 255, SkPorterDuff::kSrc_Mode);
+ PlatformContextSkia context(&canvas);
+ if (!frame->SpoolPage(params.page_number, &context)) {
+ NOTREACHED() << "Printing page " << params.page_number << " failed.";
+ return;
+ }
+
+ // Create a BMP v4 header that we can serialize.
+ BITMAPV4HEADER bitmap_header;
+ gfx::CreateBitmapV4Header(src_size_x, src_size_y, &bitmap_header);
+ const SkBitmap& src_bmp = canvas.getDevice()->accessBitmap(true);
+ SkAutoLockPixels src_lock(src_bmp);
+ int retval = StretchDIBits(hdc,
+ 0,
+ 0,
+ src_size_x, src_size_y,
+ 0, 0,
+ src_size_x, src_size_y,
+ src_bmp.getPixels(),
+ reinterpret_cast<BITMAPINFO*>(&bitmap_header),
+ DIB_RGB_COLORS,
+ SRCCOPY);
+ DCHECK(retval != GDI_ERROR);
+#else
+ // 100% GDI based.
+ gfx::VectorCanvas canvas(hdc, src_size_x, src_size_y);
+ PlatformContextSkia context(&canvas);
+ // Set the clipping region to be sure to not overflow.
+ SkRect clip_rect;
+ clip_rect.set(0, 0, SkIntToScalar(src_size_x), SkIntToScalar(src_size_y));
+ canvas.clipRect(clip_rect);
+ if (!frame->SpoolPage(params.page_number, &context)) {
+ NOTREACHED() << "Printing page " << params.page_number << " failed.";
+ return;
+ }
+#endif
+
+ // Done printing. Close the device context to retrieve the compiled EMF.
+ if (!emf.CloseDc()) {
+ NOTREACHED() << "EMF failed";
+ }
+
+ // Get the size of the compiled EMF.
+ unsigned buf_size = emf.GetDataSize();
+ DCHECK(buf_size > 128);
+ ViewHostMsg_DidPrintPage_Params page_params;
+ page_params.data_size = 0;
+ page_params.emf_data_handle = NULL;
+ page_params.page_number = params.page_number;
+ page_params.document_cookie = params.params.document_cookie;
+ page_params.actual_shrink = shrink;
+ SharedMemory shared_buf;
+
+ // http://msdn2.microsoft.com/en-us/library/ms535522.aspx
+ // Windows 2000/XP: When a page in a spooled file exceeds approximately 350
+ // MB, it can fail to print and not send an error message.
+ if (buf_size < 350*1024*1024) {
+ // Allocate a shared memory buffer to hold the generated EMF data.
+ if (shared_buf.Create(L"", false, false, buf_size) &&
+ shared_buf.Map(buf_size)) {
+ // Copy the bits into shared memory.
+ if (emf.GetData(shared_buf.memory(), buf_size)) {
+ page_params.emf_data_handle = shared_buf.handle();
+ page_params.data_size = buf_size;
+ } else {
+ NOTREACHED() << "GetData() failed";
+ }
+ shared_buf.Unmap();
+ } else {
+ NOTREACHED() << "Buffer allocation failed";
+ }
+ } else {
+ NOTREACHED() << "Buffer too large: " << buf_size;
+ }
+ emf.CloseEmf();
+ if (Send(new ViewHostMsg_DuplicateSection(routing_id_,
+ page_params.emf_data_handle,
+ &page_params.emf_data_handle))) {
+ Send(new ViewHostMsg_DidPrintPage(routing_id_, page_params));
+ }
+}
+
+void RenderView::OnGetPrintedPagesCount(const ViewMsg_Print_Params& params) {
+ DCHECK(webview());
+ if (!webview()) {
+ Send(new ViewHostMsg_DidGetPrintedPagesCount(routing_id_,
+ params.document_cookie,
+ 0));
+ return;
+ }
+ WebFrame* frame = webview()->GetMainFrame();
+ int expected_pages = SwitchFrameToPrintMediaType(params, frame);
+ Send(new ViewHostMsg_DidGetPrintedPagesCount(routing_id_,
+ params.document_cookie,
+ expected_pages));
+ SwitchFrameToDisplayMediaType(frame);
+}
+
+void RenderView::OnPrintPages(const ViewMsg_PrintPages_Params& params) {
+ DCHECK(webview());
+ if (webview())
+ PrintPages(params, webview()->GetMainFrame());
+}
+
+void RenderView::PrintPages(const ViewMsg_PrintPages_Params& params,
+ WebFrame* frame) {
+ int pages = SwitchFrameToPrintMediaType(params.params, frame);
+ Send(new ViewHostMsg_DidGetPrintedPagesCount(routing_id_,
+ params.params.document_cookie,
+ pages));
+ if (pages) {
+ ViewMsg_PrintPage_Params page_params;
+ page_params.params = params.params;
+ if (params.pages.empty()) {
+ for (int i = 0; i < pages; ++i) {
+ page_params.page_number = i;
+ PrintPage(page_params, frame);
+ }
+ } else {
+ for (size_t i = 0; i < params.pages.size(); ++i) {
+ page_params.page_number = params.pages[i];
+ PrintPage(page_params, frame);
+ }
+ }
+ }
+ SwitchFrameToDisplayMediaType(frame);
+}
+
+void RenderView::CapturePageInfo(int load_id, bool preliminary_capture) {
+ if (load_id != page_id_)
+ return; // this capture call is no longer relevant due to navigation
+ if (load_id == last_indexed_page_id_)
+ return; // we already indexed this page
+
+ if (!webview())
+ return;
+
+ WebFrame* main_frame = webview()->GetMainFrame();
+ if (!main_frame)
+ return;
+
+ // Don't index/capture pages that are in view source mode.
+ if (main_frame->GetInViewSourceMode())
+ return;
+
+ // Don't index/capture pages that failed to load. This only checks the top
+ // level frame so the thumbnail may contain a frame that failed to load.
+ WebDataSource* ds = main_frame->GetDataSource();
+ if (ds && ds->HasUnreachableURL())
+ return;
+
+ if (!preliminary_capture)
+ last_indexed_page_id_ = load_id;
+
+ // get the URL for this page
+ GURL url(main_frame->GetURL());
+ if (url.is_empty())
+ return;
+
+ // full text
+ std::wstring contents;
+ CaptureText(main_frame, &contents);
+ if (contents.size()) {
+ // Send the text to the browser for indexing.
+ Send(new ViewHostMsg_PageContents(url, load_id, contents));
+ }
+
+ // thumbnail
+ SendThumbnail();
+}
+
+void RenderView::CaptureText(WebFrame* frame, std::wstring* contents) {
+ contents->clear();
+ if (!frame)
+ return;
+
+#ifdef TIME_TEXT_RETRIEVAL
+ double begin = time_util::GetHighResolutionTimeNow();
+#endif
+
+ // get the contents of the frame
+ frame->GetContentAsPlainText(kMaxIndexChars, contents);
+
+#ifdef TIME_TEXT_RETRIEVAL
+ double end = time_util::GetHighResolutionTimeNow();
+ char buf[128];
+ sprintf_s(buf, "%d chars retrieved for indexing in %gms\n",
+ contents.size(), (end - begin)*1000);
+ OutputDebugStringA(buf);
+#endif
+
+ // When the contents are clipped to the maximum, we don't want to have a
+ // partial word indexed at the end that might have been clipped. Therefore,
+ // terminate the string at the last space to ensure no words are clipped.
+ if (contents->size() == kMaxIndexChars) {
+ size_t last_space_index = contents->find_last_of(kWhitespaceWide);
+ if (last_space_index == std::wstring::npos)
+ return; // don't index if we got a huge block of text with no spaces
+ contents->resize(last_space_index);
+ }
+}
+
+void RenderView::CaptureThumbnail(WebFrame* frame,
+ int w,
+ int h,
+ SkBitmap* thumbnail,
+ ThumbnailScore* score) {
+#ifdef TIME_BITMAP_RETRIEVAL
+ double begin = time_util::GetHighResolutionTimeNow();
+#endif
+
+ gfx::BitmapPlatformDevice device(frame->CaptureImage(true));
+ const SkBitmap& src_bmp = device.accessBitmap(false);
+
+ SkRect dest_rect;
+ dest_rect.set(0, 0, SkIntToScalar(w), SkIntToScalar(h));
+ float dest_aspect = dest_rect.width() / dest_rect.height();
+
+ // Get the src rect so that we can preserve the aspect ratio while filling
+ // the destination.
+ SkIRect src_rect;
+ if (src_bmp.width() < dest_rect.width() ||
+ src_bmp.height() < dest_rect.height()) {
+ // Source image is smaller: we clip the part of source image within the
+ // dest rect, and then stretch it to fill the dest rect. We don't respect
+ // the aspect ratio in this case.
+ src_rect.set(0, 0, static_cast<S16CPU>(dest_rect.width()),
+ static_cast<S16CPU>(dest_rect.height()));
+ score->good_clipping = false;
+ } else {
+ float src_aspect = static_cast<float>(src_bmp.width()) / src_bmp.height();
+ if (src_aspect > dest_aspect) {
+ // Wider than tall, clip horizontally: we center the smaller thumbnail in
+ // the wider screen.
+ S16CPU new_width = static_cast<S16CPU>(src_bmp.height() * dest_aspect);
+ S16CPU x_offset = (src_bmp.width() - new_width) / 2;
+ src_rect.set(x_offset, 0, new_width + x_offset, src_bmp.height());
+ score->good_clipping = false;
+ } else {
+ src_rect.set(0, 0, src_bmp.width(),
+ static_cast<S16CPU>(src_bmp.width() / dest_aspect));
+ score->good_clipping = true;
+ }
+ }
+
+ score->at_top = (frame->ScrollOffset().height() == 0);
+
+ SkBitmap subset;
+ device.accessBitmap(false).extractSubset(&subset, src_rect);
+
+ // Resample the subset that we want to get it the right size.
+ *thumbnail = gfx::ImageOperations::Resize(
+ subset, gfx::ImageOperations::RESIZE_LANCZOS3, gfx::Size(w, h));
+
+ score->boring_score = CalculateBoringScore(thumbnail);
+
+#ifdef TIME_BITMAP_RETRIEVAL
+ double end = time_util::GetHighResolutionTimeNow();
+ char buf[128];
+ sprintf_s(buf, "thumbnail in %gms\n", (end - begin) * 1000);
+ OutputDebugStringA(buf);
+#endif
+}
+
+double RenderView::CalculateBoringScore(SkBitmap* bitmap) {
+ int histogram[256] = {0};
+ color_utils::BuildLumaHistogram(bitmap, histogram);
+
+ int color_count = *std::max_element(histogram, histogram + 256);
+ int pixel_count = bitmap->width() * bitmap->height();
+ return static_cast<double>(color_count) / pixel_count;
+}
+
+void RenderView::OnNavigate(const ViewMsg_Navigate_Params& params) {
+ if (!webview())
+ return;
+
+ AboutHandler::MaybeHandle(params.url);
+
+ bool is_reload = params.reload;
+
+ WebFrame* main_frame = webview()->GetMainFrame();
+ if (is_reload && !main_frame->HasCurrentState()) {
+ // We cannot reload if we do not have any history state. This happens, for
+ // example, when recovering from a crash. Our workaround here is a bit of
+ // a hack since it means that reload after a crashed tab does not cause an
+ // end-to-end cache validation.
+ is_reload = false;
+ }
+
+ WebRequestCachePolicy cache_policy;
+ if (is_reload) {
+ cache_policy = WebRequestReloadIgnoringCacheData;
+ } else if (params.page_id != -1 || main_frame->GetInViewSourceMode()) {
+ cache_policy = WebRequestReturnCacheDataElseLoad;
+ } else {
+ cache_policy = WebRequestUseProtocolCachePolicy;
+ }
+
+ scoped_ptr<WebRequest> request(WebRequest::Create(params.url));
+ request->SetCachePolicy(cache_policy);
+ request->SetExtraData(new RenderViewExtraRequestData(
+ params.page_id, params.transition, params.url));
+
+ // If we are reloading, then WebKit will use the state of the current page.
+ // Otherwise, we give it the state to navigate to.
+ if (!is_reload)
+ request->SetHistoryState(params.state);
+
+ main_frame->LoadRequest(request.get());
+}
+
+// Stop loading the current page
+void RenderView::OnStop() {
+ if (webview())
+ webview()->StopLoading();
+}
+
+void RenderView::OnLoadAlternateHTMLText(const std::string& html_contents,
+ bool new_navigation,
+ const GURL& display_url,
+ const std::string& security_info) {
+ if (!webview())
+ return;
+
+ scoped_ptr<WebRequest> request(WebRequest::Create(
+ GURL(kUnreachableWebDataURL)));
+ request->SetSecurityInfo(security_info);
+
+ webview()->GetMainFrame()->LoadAlternateHTMLString(request.get(),
+ html_contents,
+ display_url,
+ !new_navigation);
+}
+
+void RenderView::OnCopyImageAt(int x, int y) {
+ webview()->CopyImageAt(x, y);
+}
+
+void RenderView::OnInspectElement(int x, int y) {
+ webview()->InspectElement(x, y);
+}
+
+void RenderView::OnShowJavaScriptConsole() {
+ webview()->ShowJavaScriptConsole();
+}
+
+void RenderView::OnStopFinding(bool clear_selection) {
+ WebView* view = webview();
+ if (!view)
+ return;
+
+ if (clear_selection)
+ view->GetFocusedFrame()->ClearSelection();
+
+ WebFrame* frame = view->GetMainFrame();
+ while (frame) {
+ frame->StopFinding();
+ frame = view->GetNextFrameAfter(frame, false);
+ }
+}
+
+void RenderView::OnFindReplyAck() {
+ // Check if there is any queued up request waiting to be sent.
+ if (queued_find_reply_message_.get()) {
+ // Send the search result over to the browser process.
+ Send(queued_find_reply_message_.get());
+ queued_find_reply_message_.release();
+ }
+}
+
+void RenderView::OnUpdateTargetURLAck() {
+ // Check if there is a targeturl waiting to be sent.
+ if (target_url_status_ == TARGET_PENDING) {
+ Send(new ViewHostMsg_UpdateTargetURL(routing_id_, page_id_,
+ pending_target_url_));
+ }
+
+ target_url_status_ = TARGET_NONE;
+}
+
+void RenderView::OnUndo() {
+ if (!webview())
+ return;
+
+ webview()->GetFocusedFrame()->Undo();
+}
+
+void RenderView::OnRedo() {
+ if (!webview())
+ return;
+
+ webview()->GetFocusedFrame()->Redo();
+}
+
+void RenderView::OnCut() {
+ if (!webview())
+ return;
+
+ webview()->GetFocusedFrame()->Cut();
+}
+
+void RenderView::OnCopy() {
+ if (!webview())
+ return;
+
+ webview()->GetFocusedFrame()->Copy();
+}
+
+void RenderView::OnPaste() {
+ if (!webview())
+ return;
+
+ webview()->GetFocusedFrame()->Paste();
+}
+
+void RenderView::OnReplace(const std::wstring& text) {
+ if (!webview())
+ return;
+
+ webview()->GetFocusedFrame()->Replace(text);
+}
+
+void RenderView::OnDelete() {
+ if (!webview())
+ return;
+
+ webview()->GetFocusedFrame()->Delete();
+}
+
+void RenderView::OnSelectAll() {
+ if (!webview())
+ return;
+
+ webview()->GetFocusedFrame()->SelectAll();
+}
+
+void RenderView::OnSetInitialFocus(bool reverse) {
+ if (!webview())
+ return;
+ webview()->SetInitialFocus(reverse);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+// Tell the embedding application that the URL of the active page has changed
+void RenderView::UpdateURL(WebFrame* frame) {
+ WebDataSource* ds = frame->GetDataSource();
+ DCHECK(ds);
+
+ const WebRequest& request = ds->GetRequest();
+ const WebRequest& initial_request = ds->GetInitialRequest();
+ const WebResponse& response = ds->GetResponse();
+
+ // We don't hold a reference to the extra data. The request's reference will
+ // be sufficient because we won't modify it during our call. MAY BE NULL.
+ RenderViewExtraRequestData* extra_data =
+ static_cast<RenderViewExtraRequestData*>(request.GetExtraData());
+
+ ViewHostMsg_FrameNavigate_Params params;
+ params.is_post = false;
+ params.page_id = page_id_;
+ if (!request.GetSecurityInfo().empty()) {
+ // SSL state specified in the request takes precedence over the one in the
+ // response.
+ // So far this is only intended for error pages that are not expected to be
+ // over ssl, so we should not get any clash.
+ DCHECK(response.GetSecurityInfo().empty());
+ params.security_info = request.GetSecurityInfo();
+ } else {
+ params.security_info = response.GetSecurityInfo();
+ }
+
+ // Set the URL to be displayed in the browser UI to the user.
+ if (ds->HasUnreachableURL()) {
+ params.url = ds->GetUnreachableURL();
+ } else {
+ params.url = request.GetURL();
+ }
+
+ params.redirects = ds->GetRedirectChain();
+ params.should_update_history = !ds->HasUnreachableURL();
+
+ const SearchableFormData* searchable_form_data =
+ frame->GetDataSource()->GetSearchableFormData();
+ if (searchable_form_data) {
+ params.searchable_form_url = searchable_form_data->url();
+ params.searchable_form_element_name = searchable_form_data->element_name();
+ params.searchable_form_encoding = searchable_form_data->encoding();
+ }
+
+ const PasswordForm* password_form_data =
+ frame->GetDataSource()->GetPasswordFormData();
+ if (password_form_data)
+ params.password_form = *password_form_data;
+
+ params.gesture = navigation_gesture_;
+ navigation_gesture_ = NavigationGestureUnknown;
+
+ if (webview()->GetMainFrame() == frame) {
+ // Top-level navigation.
+
+ // Update contents MIME type for main frame.
+ std::wstring mime_type = ds->GetResponseMimeType();
+ params.contents_mime_type = WideToASCII(mime_type);
+
+ // We assume top level navigations initiated by the renderer are link
+ // clicks.
+ params.transition = extra_data ?
+ extra_data->transition_type : PageTransition::LINK;
+ if (!PageTransition::IsMainFrame(params.transition)) {
+ // If the main frame does a load, it should not be reported as a subframe
+ // navigation. This can occur in the following case:
+ // 1. You're on a site with frames.
+ // 2. You do a subframe navigation. This is stored with transition type
+ // MANUAL_SUBFRAME.
+ // 3. You navigate to some non-frame site, say, google.com.
+ // 4. You navigate back to the page from step 2. Since it was initially
+ // MANUAL_SUBFRAME, it will be that same transition type here.
+ // We don't want that, because any navigation that changes the toplevel
+ // frame should be tracked as a toplevel navigation (this allows us to
+ // update the URL bar, etc).
+ params.transition = PageTransition::LINK;
+ }
+
+ if (params.transition == PageTransition::LINK &&
+ frame->GetDataSource()->IsFormSubmit()) {
+ params.transition = PageTransition::FORM_SUBMIT;
+ }
+
+ // If we have a valid consumed client redirect source,
+ // the page contained a client redirect (meta refresh, document.loc...),
+ // so we set the referrer and transition to match.
+ if (completed_client_redirect_src_.is_valid()) {
+ params.referrer = completed_client_redirect_src_;
+ params.transition = static_cast<PageTransition::Type>(
+ params.transition | PageTransition::CLIENT_REDIRECT);
+ } else {
+ // Bug 654101: the referrer will be empty on https->http transitions. It
+ // would be nice if we could get the real referrer from somewhere.
+ params.referrer = GURL(initial_request.GetHttpReferrer());
+ }
+
+ std::wstring method = request.GetHttpMethod();
+ if (method == L"POST")
+ params.is_post = true;
+
+ Send(new ViewHostMsg_FrameNavigate(routing_id_, params));
+ } else {
+ // Subframe navigation: the type depends on whether this navigation
+ // generated a new session history entry. When they do generate a session
+ // history entry, it means the user initiated the navigation and we should
+ // mark it as such. This test checks if this is the first time UpdateURL
+ // has been called since WillNavigateToURL was called to initiate the load.
+ if (page_id_ > last_page_id_sent_to_browser_)
+ params.transition = PageTransition::MANUAL_SUBFRAME;
+ else
+ params.transition = PageTransition::AUTO_SUBFRAME;
+
+ // The browser should never initiate a subframe navigation.
+ DCHECK(!extra_data);
+ Send(new ViewHostMsg_FrameNavigate(routing_id_, params));
+ }
+
+ last_page_id_sent_to_browser_ =
+ std::max(last_page_id_sent_to_browser_, page_id_);
+
+ // If we end up reusing this WebRequest (for example, due to a #ref click),
+ // we don't want the transition type to persist.
+ if (extra_data)
+ extra_data->transition_type = PageTransition::LINK; // Just clear it.
+}
+
+// Tell the embedding application that the title of the active page has changed
+void RenderView::UpdateTitle(WebFrame* frame, const std::wstring& title) {
+ // Ignore all but top level navigations...
+ if (webview()->GetMainFrame() == frame)
+ Send(new ViewHostMsg_UpdateTitle(routing_id_, page_id_, title));
+}
+
+void RenderView::UpdateEncoding(WebFrame* frame,
+ const std::wstring& encoding_name) {
+ // Only update main frame's encoding_name.
+ if (webview()->GetMainFrame() == frame &&
+ last_encoding_name_ != encoding_name) {
+ // save the encoding name for later comparing.
+ last_encoding_name_ = encoding_name;
+
+ Send(new ViewHostMsg_UpdateEncoding(routing_id_,
+ last_encoding_name_));
+ }
+}
+
+void RenderView::UpdateSessionHistory(WebFrame* frame) {
+ // If we have a valid page ID at this point, then it corresponds to the page
+ // we are navigating away from. Otherwise, this is the first navigation, so
+ // there is no past session history to record.
+ if (page_id_ == -1)
+ return;
+
+ GURL url;
+ std::wstring title;
+ std::string state;
+ if (!webview()->GetMainFrame()->GetPreviousState(&url, &title, &state))
+ return;
+
+ Send(new ViewHostMsg_UpdateState(routing_id_, page_id_, url, title, state));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// WebViewDelegate
+
+void RenderView::DidStartLoading(WebView* webview) {
+ if (is_loading_) {
+ DLOG(WARNING) << "DidStartLoading called while loading";
+ return;
+ }
+
+ is_loading_ = true;
+ // Clear the pointer so that we can assign it only when there is an unknown
+ // plugin on a page.
+ first_default_plugin_ = NULL;
+
+ Send(new ViewHostMsg_DidStartLoading(routing_id_, page_id_));
+}
+
+void RenderView::DidStopLoading(WebView* webview) {
+ if (!is_loading_) {
+ DLOG(WARNING) << "DidStopLoading called while not loading";
+ return;
+ }
+
+ is_loading_ = false;
+
+ // NOTE: For now we're doing the safest thing, and sending out notification
+ // when done loading. This currently isn't an issue as the favicon is only
+ // displayed when done loading. Ideally we would send notification when
+ // finished parsing the head, but webkit doesn't support that yet.
+ // The feed discovery code would also benefit from access to the head.
+ GURL favicon_url(webview->GetMainFrame()->GetFavIconURL());
+ if (!favicon_url.is_empty())
+ Send(new ViewHostMsg_UpdateFavIconURL(routing_id_, page_id_, favicon_url));
+
+ AddGURLSearchProvider(webview->GetMainFrame()->GetOSDDURL(),
+ true); // autodetected
+
+ Send(new ViewHostMsg_DidStopLoading(routing_id_, page_id_));
+
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ method_factory_.NewRunnableMethod(&RenderView::CapturePageInfo, page_id_,
+ false),
+ kDelayForCaptureMs);
+
+ // The page is loaded. Try to process the file we need to upload if any.
+ ProcessPendingUpload();
+
+ // Since the page is done loading, we are sure we don't need to try
+ // again.
+ ResetPendingUpload();
+}
+
+void RenderView::DidStartProvisionalLoadForFrame(
+ WebView* webview,
+ WebFrame* frame,
+ NavigationGesture gesture) {
+ if (webview->GetMainFrame() == frame)
+ navigation_gesture_ = gesture;
+
+ Send(new ViewHostMsg_DidStartProvisionalLoadForFrame(
+ routing_id_, webview->GetMainFrame() == frame,
+ frame->GetProvisionalDataSource()->GetRequest().GetURL()));
+}
+
+bool RenderView::DidLoadResourceFromMemoryCache(WebView* webview,
+ const WebRequest& request,
+ const WebResponse& response,
+ WebFrame* frame) {
+ // Let the browser know we loaded a resource from the memory cache. This
+ // message is needed to display the correct SSL indicators.
+ Send(new ViewHostMsg_DidLoadResourceFromMemoryCache(routing_id_,
+ request.GetURL(), response.GetSecurityInfo()));
+
+ return false;
+}
+
+void RenderView::DidReceiveProvisionalLoadServerRedirect(WebView* webview,
+ WebFrame* frame) {
+ if (frame == webview->GetMainFrame()) {
+ // Received a redirect on the main frame.
+ WebDataSource* data_source =
+ webview->GetMainFrame()->GetProvisionalDataSource();
+ if (!data_source) {
+ // Should only be invoked when we have a data source.
+ NOTREACHED();
+ return;
+ }
+ const std::vector<GURL>& redirects = data_source->GetRedirectChain();
+ if (redirects.size() >= 2) {
+ Send(new ViewHostMsg_DidRedirectProvisionalLoad(
+ routing_id_, page_id_, redirects[redirects.size() - 2],
+ redirects[redirects.size() - 1]));
+ }
+ }
+}
+
+void RenderView::DidFailProvisionalLoadWithError(WebView* webview,
+ const WebError& error,
+ WebFrame* frame) {
+ // Notify the browser that we failed a provisional load with an error.
+ //
+ // Note: It is important this notification occur before DidStopLoading so the
+ // SSL manager can react to the provisional load failure before being
+ // notified the load stopped.
+ //
+ WebDataSource* ds = frame->GetProvisionalDataSource();
+ DCHECK(ds);
+
+ const WebRequest& failed_request = ds->GetRequest();
+
+ bool show_repost_interstitial =
+ (error.GetErrorCode() == net::ERR_CACHE_MISS &&
+ LowerCaseEqualsASCII(failed_request.GetHttpMethod(), "post"));
+ Send(new ViewHostMsg_DidFailProvisionalLoadWithError(
+ routing_id_, frame == webview->GetMainFrame(),
+ error.GetErrorCode(), error.GetFailedURL(),
+ show_repost_interstitial));
+
+ // TODO(darin): This should not be necessary!
+ if (is_loading_)
+ DidStopLoading(webview);
+
+ // Don't display an error page if this is simply a cancelled load. Aside
+ // from being dumb, WebCore doesn't expect it and it will cause a crash.
+ if (error.GetErrorCode() == net::ERR_ABORTED)
+ return;
+
+ // If this is a failed back/forward/reload navigation, then we need to do a
+ // 'replace' load. This is necessary to avoid messing up session history.
+ // Otherwise, we do a normal load, which simulates a 'go' navigation as far
+ // as session history is concerned.
+ RenderViewExtraRequestData* extra_data =
+ static_cast<RenderViewExtraRequestData*>(failed_request.GetExtraData());
+ bool replace = extra_data && !extra_data->is_new_navigation();
+
+ const GURL& failed_url = error.GetFailedURL();
+ const GURL& error_page_url = GetAlternateErrorPageURL(failed_url,
+ WebViewDelegate::DNS_ERROR);
+ if (error.GetErrorCode() == net::ERR_NAME_NOT_RESOLVED &&
+ error_page_url.is_valid()) {
+ // Ask the WebFrame to fetch the alternate error page for us.
+ frame->LoadAlternateHTMLErrorPage(&failed_request, error, error_page_url,
+ replace, GURL(kUnreachableWebDataURL));
+ } else {
+ LoadNavigationErrorPage(frame, &failed_request, error, std::string(),
+ replace);
+ }
+}
+
+void RenderView::LoadNavigationErrorPage(WebFrame* frame,
+ const WebRequest* failed_request,
+ const WebError& error,
+ const std::string& html,
+ bool replace) {
+ const GURL& failed_url = error.GetFailedURL();
+
+ std::string alt_html;
+ if (html.empty()) {
+ // Use a local error page.
+ int resource_id;
+ DictionaryValue error_strings;
+ if (error.GetErrorCode() == net::ERR_CACHE_MISS &&
+ LowerCaseEqualsASCII(failed_request->GetHttpMethod(), "post")) {
+ GetFormRepostErrorValues(failed_url, &error_strings);
+ resource_id = IDR_ERROR_NO_DETAILS_HTML;
+ } else {
+ GetLocalizedErrorValues(error, &error_strings);
+ resource_id = IDR_NET_ERROR_HTML;
+ }
+ error_strings.SetString(L"textdirection",
+ (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) ?
+ L"rtl" : L"ltr");
+
+ alt_html = GetAltHTMLForTemplate(error_strings, resource_id);
+ } else {
+ alt_html = html;
+ }
+
+ // Use a data: URL as the site URL to prevent against XSS attacks.
+ scoped_ptr<WebRequest> request(failed_request->Clone());
+ request->SetURL(GURL(kUnreachableWebDataURL));
+
+ frame->LoadAlternateHTMLString(request.get(), alt_html, failed_url,
+ replace);
+}
+
+void RenderView::DidCommitLoadForFrame(WebView *webview, WebFrame* frame,
+ bool is_new_navigation) {
+ const WebRequest& request =
+ webview->GetMainFrame()->GetDataSource()->GetRequest();
+ RenderViewExtraRequestData* extra_data =
+ static_cast<RenderViewExtraRequestData*>(request.GetExtraData());
+
+ if (is_new_navigation) {
+ // When we perform a new navigation, we need to update the previous session
+ // history entry with state for the page we are leaving.
+ UpdateSessionHistory(frame);
+
+ // We bump our Page ID to correspond with the new session history entry.
+ page_id_ = next_page_id_++;
+
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ method_factory_.NewRunnableMethod(&RenderView::CapturePageInfo,
+ page_id_, true),
+ kDelayForForcedCaptureMs);
+ } else {
+ // Inspect the extra_data on the main frame (set in our Navigate method) to
+ // see if the navigation corresponds to a session history navigation...
+ // Note: |frame| may or may not be the toplevel frame, but for the case
+ // of capturing session history, the first committed frame suffices. We
+ // keep track of whether we've seen this commit before so that only capture
+ // session history once per navigation.
+ if (extra_data && !extra_data->is_new_navigation() &&
+ !extra_data->request_committed) {
+ // This is a successful session history navigation!
+ UpdateSessionHistory(frame);
+
+ page_id_ = extra_data->pending_page_id();
+ }
+ }
+
+ // Remember that we've already processed this request, so we don't update
+ // the session history again. We do this regardless of whether this is
+ // a session history navigation, because if we attempted a session history
+ // navigation without valid HistoryItem state, WebCore will think it is a
+ // new navigation.
+ if (extra_data)
+ extra_data->request_committed = true;
+
+ UpdateURL(frame);
+
+ // If this committed load was initiated by a client redirect, we're
+ // at the last stop now, so clear it.
+ completed_client_redirect_src_ = GURL();
+
+ // Check whether we have new encoding name.
+ UpdateEncoding(frame, webview->GetMainFrameEncodingName());
+}
+
+void RenderView::DidReceiveTitle(WebView* webview,
+ const std::wstring& title,
+ WebFrame* frame) {
+ UpdateTitle(frame, title);
+
+ // Also check whether we have new encoding name.
+ UpdateEncoding(frame, webview->GetMainFrameEncodingName());
+}
+
+void RenderView::DidFinishLoadForFrame(WebView* webview, WebFrame* frame) {
+}
+
+void RenderView::DidFailLoadWithError(WebView* webview,
+ const WebError& error,
+ WebFrame* frame) {
+}
+
+void RenderView::DidFinishDocumentLoadForFrame(WebView* webview,
+ WebFrame* frame) {
+ // Check whether we have new encoding name.
+ UpdateEncoding(frame, webview->GetMainFrameEncodingName());
+}
+
+void RenderView::DidHandleOnloadEventsForFrame(WebView* webview,
+ WebFrame* frame) {
+}
+
+void RenderView::DidChangeLocationWithinPageForFrame(WebView* webview,
+ WebFrame* frame,
+ bool is_new_navigation) {
+ DidCommitLoadForFrame(webview, frame, is_new_navigation);
+}
+
+void RenderView::DidReceiveIconForFrame(WebView* webview,
+ WebFrame* frame) {
+}
+
+void RenderView::WillPerformClientRedirect(WebView* webview,
+ WebFrame* frame,
+ const GURL& src_url,
+ const GURL& dest_url,
+ unsigned int delay_seconds,
+ unsigned int fire_date) {
+}
+
+void RenderView::DidCancelClientRedirect(WebView* webview,
+ WebFrame* frame) {
+}
+
+void RenderView::DidCompleteClientRedirect(WebView* webview,
+ WebFrame* frame,
+ const GURL& source) {
+ if (webview->GetMainFrame() == frame)
+ completed_client_redirect_src_ = source;
+}
+
+void RenderView::BindDOMAutomationController(WebFrame* webframe) {
+ dom_automation_controller_.set_message_sender(this);
+ dom_automation_controller_.set_routing_id(routing_id_);
+ dom_automation_controller_.BindToJavascript(webframe,
+ L"domAutomationController");
+}
+
+void RenderView::WindowObjectCleared(WebFrame* webframe) {
+ external_js_object_.set_render_view(this);
+ external_js_object_.BindToJavascript(webframe, L"external");
+ if (enable_dom_automation_)
+ BindDOMAutomationController(webframe);
+ if (enable_dom_ui_bindings_) {
+ dom_ui_bindings_.set_message_sender(this);
+ dom_ui_bindings_.set_routing_id(routing_id_);
+ dom_ui_bindings_.BindToJavascript(webframe, L"chrome");
+ }
+}
+
+WindowOpenDisposition RenderView::DispositionForNavigationAction(
+ WebView* webview,
+ WebFrame* frame,
+ const WebRequest* request,
+ WebNavigationType type,
+ WindowOpenDisposition disposition,
+ bool is_redirect) {
+ // Webkit is asking whether to navigate to a new URL.
+ // This is fine normally, except if we're showing UI from one security
+ // context and they're trying to navigate to a different context.
+ const GURL& url = request->GetURL();
+ // We only care about navigations that are within the current tab (as opposed
+ // to, for example, opening a new window).
+ // But we sometimes navigate to about:blank to clear a tab, and we want to
+ // still allow that.
+ if (disposition == CURRENT_TAB && !(url.SchemeIs("about"))) {
+ // GetExtraData is NULL when we did not issue the request ourselves (see
+ // OnNavigate), and so such a request may correspond to a link-click,
+ // script, or drag-n-drop initiated navigation.
+ if (frame == webview->GetMainFrame() && !request->GetExtraData()) {
+ // When we received such unsolicited navigations, we sometimes want to
+ // punt them up to the browser to handle.
+ if (enable_dom_ui_bindings_ ||
+ frame->GetInViewSourceMode() ||
+ url.SchemeIs("view-source")) {
+ OpenURL(webview, url, disposition);
+ return IGNORE_ACTION; // Suppress the load here.
+ }
+ }
+ }
+
+ // Detect when a page is "forking" a new tab that can be safely rendered in
+ // its own process. This is done by sites like Gmail that try to open links
+ // in new windows without script connections back to the original page. We
+ // treat such cases as browser navigations (in which we will create a new
+ // renderer for a cross-site navigation), rather than WebKit navigations.
+ //
+ // We use the following heuristic to decide whether to fork a new page in its
+ // own process:
+ // The parent page must open a new tab to about:blank, set the new tab's
+ // window.opener to null, and then redirect the tab to a cross-site URL using
+ // JavaScript.
+ bool is_fork =
+ // Must start from a tab showing about:blank, which is later redirected.
+ frame->GetURL() == GURL("about:blank") &&
+ // Must be the first real navigation of the tab.
+ GetHistoryBackListCount() < 1 &&
+ GetHistoryForwardListCount() < 1 &&
+ // The parent page must have set the child's window.opener to null before
+ // redirecting to the desired URL.
+ frame->GetOpener() == NULL &&
+ // Must be a top-level frame.
+ frame->GetParent() == NULL &&
+ // Must not have issued the request from this page. GetExtraData is NULL
+ // when the navigation is being done by something outside the page.
+ !request->GetExtraData() &&
+ // Must be targeted at the current tab.
+ disposition == CURRENT_TAB &&
+ // Must be a JavaScript navigation, which appears as "other".
+ type == WebNavigationTypeOther;
+ if (is_fork) {
+ // Open the URL via the browser, not via WebKit.
+ OpenURL(webview, url, disposition);
+ return IGNORE_ACTION;
+ }
+
+ return disposition;
+}
+
+void RenderView::RunJavaScriptAlert(WebView* webview,
+ const std::wstring& message) {
+ RunJavaScriptMessage(MessageBoxView::kIsJavascriptAlert,
+ message,
+ std::wstring(),
+ NULL);
+}
+
+bool RenderView::RunJavaScriptConfirm(WebView* webview,
+ const std::wstring& message) {
+ return RunJavaScriptMessage(MessageBoxView::kIsJavascriptConfirm,
+ message,
+ std::wstring(),
+ NULL);
+}
+
+bool RenderView::RunJavaScriptPrompt(WebView* webview,
+ const std::wstring& message,
+ const std::wstring& default_value,
+ std::wstring* result) {
+ return RunJavaScriptMessage(MessageBoxView::kIsJavascriptPrompt,
+ message,
+ default_value,
+ result);
+}
+
+bool RenderView::RunJavaScriptMessage(int type,
+ const std::wstring& message,
+ const std::wstring& default_value,
+ std::wstring* result) {
+ bool success = false;
+ std::wstring result_temp;
+ if (!result)
+ result = &result_temp;
+ IPC::SyncMessage* msg = new ViewHostMsg_RunJavaScriptMessage(
+ routing_id_, message, default_value, type, &success, result);
+
+ msg->set_pump_messages_event(modal_dialog_event_);
+ Send(msg);
+
+ return success;
+}
+
+void RenderView::AddGURLSearchProvider(const GURL& osd_url, bool autodetected) {
+ if (!osd_url.is_empty())
+ Send(new ViewHostMsg_PageHasOSDD(routing_id_, page_id_, osd_url,
+ autodetected));
+}
+
+bool RenderView::RunBeforeUnloadConfirm(WebView* webview,
+ const std::wstring& message) {
+ bool success = false;
+ // This is an ignored return value, but is included so we can accept the same
+ // response as RunJavaScriptMessage.
+ std::wstring ignored_result;
+ IPC::SyncMessage* msg = new ViewHostMsg_RunBeforeUnloadConfirm(
+ routing_id_, message, &success, &ignored_result);
+
+ msg->set_pump_messages_event(modal_dialog_event_);
+ Send(msg);
+
+ return success;
+}
+
+void RenderView::OnUnloadListenerChanged(WebView* webview, WebFrame* webframe) {
+ bool has_listener = false;
+ if (!has_unload_listener_) {
+ has_listener = webframe->HasUnloadListener();
+ } else {
+ WebFrame* frame = webview->GetMainFrame();
+ while (frame != NULL) {
+ if (frame->HasUnloadListener()) {
+ has_listener = true;
+ break;
+ }
+ frame = webview->GetNextFrameAfter(frame, false);
+ }
+ }
+ if (has_listener != has_unload_listener_) {
+ has_unload_listener_ = has_listener;
+ Send(new ViewHostMsg_UnloadListenerChanged(routing_id_, has_listener));
+ }
+}
+
+void RenderView::ShowModalHTMLDialog(const GURL& url, int width, int height,
+ const std::string& json_arguments,
+ std::string* json_retval) {
+ IPC::SyncMessage* msg = new ViewHostMsg_ShowModalHTMLDialog(
+ routing_id_, url, width, height, json_arguments, json_retval);
+
+ msg->set_pump_messages_event(modal_dialog_event_);
+ Send(msg);
+}
+
+uint32 RenderView::GetCPBrowsingContext() {
+ uint32 context = 0;
+ Send(new ViewHostMsg_GetCPBrowsingContext(&context));
+ return context;
+}
+
+// Tell the browser to display a destination link.
+void RenderView::UpdateTargetURL(WebView* webview, const GURL& url) {
+ if (url != target_url_) {
+ if (target_url_status_ == TARGET_INFLIGHT ||
+ target_url_status_ == TARGET_PENDING) {
+ // If we have a request in-flight, save the URL to be sent when we
+ // receive an ACK to the in-flight request. We can happily overwrite
+ // any existing pending sends.
+ pending_target_url_ = url;
+ target_url_status_ = TARGET_PENDING;
+ } else {
+ Send(new ViewHostMsg_UpdateTargetURL(routing_id_, page_id_, url));
+ target_url_ = url;
+ target_url_status_ = TARGET_INFLIGHT;
+ }
+ }
+}
+
+void RenderView::RunFileChooser(const std::wstring& default_filename,
+ WebFileChooserCallback* file_chooser) {
+ if (file_chooser_.get()) {
+ // TODO(brettw): bug 1235154: This should be a synchronous message to deal
+ // with the fact that web pages can programatically trigger this. With the
+ // asnychronous messages, we can get an additional call when one is pending,
+ // which this test is for. For now, we just ignore the additional file
+ // chooser request. WebKit doesn't do anything to expect the callback, so
+ // we can just ignore calling it.
+ delete file_chooser;
+ return;
+ }
+ file_chooser_.reset(file_chooser);
+ Send(new ViewHostMsg_RunFileChooser(routing_id_, default_filename));
+}
+
+void RenderView::AddMessageToConsole(WebView* webview,
+ const std::wstring& message,
+ unsigned int line_no,
+ const std::wstring& source_id) {
+ Send(new ViewHostMsg_AddMessageToConsole(routing_id_, message,
+ static_cast<int32>(line_no),
+ source_id));
+}
+
+void RenderView::AddSearchProvider(const std::string& url) {
+ AddGURLSearchProvider(GURL(url),
+ false); // not autodetected
+}
+
+void RenderView::DebuggerOutput(const std::wstring& out) {
+ Send(new ViewHostMsg_DebuggerOutput(routing_id_, out));
+}
+
+WebView* RenderView::CreateWebView(WebView* webview, bool user_gesture) {
+ int32 routing_id = MSG_ROUTING_NONE;
+ HANDLE modal_dialog_event;
+ bool result = RenderThread::current()->Send(
+ new ViewHostMsg_CreateView(routing_id_, user_gesture, &routing_id,
+ &modal_dialog_event));
+ if (routing_id == MSG_ROUTING_NONE) {
+ DCHECK(modal_dialog_event == NULL);
+ return NULL;
+ }
+
+ // The WebView holds a reference to this new RenderView
+ const WebPreferences& prefs = webview->GetPreferences();
+ RenderView* view = RenderView::Create(NULL, modal_dialog_event, routing_id_,
+ prefs, routing_id);
+ view->set_opened_by_user_gesture(user_gesture);
+
+ // Copy over the alternate error page URL so we can have alt error pages in
+ // the new render view (we don't need the browser to send the URL back down).
+ view->alternate_error_page_url_ = alternate_error_page_url_;
+
+ return view->webview();
+}
+
+WebWidget* RenderView::CreatePopupWidget(WebView* webview) {
+ RenderWidget* widget = RenderWidget::Create(routing_id_);
+ return widget->webwidget();
+}
+
+WebPluginDelegate* RenderView::CreatePluginDelegate(
+ WebView* webview,
+ const GURL& url,
+ const std::string& mime_type,
+ const std::string& clsid,
+ std::string* actual_mime_type) {
+ if (RenderProcess::ShouldLoadPluginsInProcess()) {
+ std::wstring path;
+ RenderThread::current()->Send(
+ new ViewHostMsg_GetPluginPath(url, mime_type, clsid, &path,
+ actual_mime_type));
+ if (path.empty())
+ return NULL;
+
+ std::string mime_type_to_use;
+ if (actual_mime_type && !actual_mime_type->empty())
+ mime_type_to_use = *actual_mime_type;
+ else
+ mime_type_to_use = mime_type;
+
+ return WebPluginDelegateImpl::Create(path, mime_type_to_use, host_window_);
+ }
+
+ WebPluginDelegateProxy* proxy =
+ WebPluginDelegateProxy::Create(url, mime_type, clsid, this);
+ if (!proxy)
+ return NULL;
+
+ // We hold onto the proxy so we can poke it when we are painting. See our
+ // DidPaint implementation below.
+ plugin_delegates_.push_back(proxy);
+
+ return proxy;
+}
+
+void RenderView::OnMissingPluginStatus(WebPluginDelegate* delegate,
+ int status) {
+ if (first_default_plugin_ == NULL) {
+ // Show the InfoBar for the first available plugin.
+ if (status == default_plugin::MISSING_PLUGIN_AVAILABLE) {
+ first_default_plugin_ = delegate;
+ Send(new ViewHostMsg_MissingPluginStatus(routing_id_, status));
+ }
+ } else {
+ // Closes the InfoBar if user clicks on the plugin (instead of the InfoBar)
+ // to start the download/install.
+ if (status == default_plugin::MISSING_PLUGIN_USER_STARTED_DOWNLOAD) {
+ Send(new ViewHostMsg_MissingPluginStatus(routing_id_, status));
+ }
+ }
+}
+
+void RenderView::OpenURL(WebView* webview, const GURL& url,
+ WindowOpenDisposition disposition) {
+ Send(new ViewHostMsg_OpenURL(routing_id_, url, disposition));
+}
+
+// We are supposed to get a single call to Show for a newly created RenderView
+// that was created via RenderView::CreateWebView. So, we wait until this
+// point to dispatch the ShowView message.
+//
+// This method provides us with the information about how to display the newly
+// created RenderView (i.e., as a constrained popup or as a new tab).
+//
+void RenderView::Show(WebWidget* webwidget, WindowOpenDisposition disposition) {
+ DCHECK(!did_show_) << "received extraneous Show call";
+ DCHECK(opener_id_ != MSG_ROUTING_NONE);
+
+ if (did_show_)
+ return;
+ did_show_ = true;
+
+ // NOTE: initial_pos_ may still have its default values at this point, but
+ // that's okay. It'll be ignored if disposition is not NEW_POPUP, or the
+ // browser process will impose a default position otherwise.
+ Send(new ViewHostMsg_ShowView(
+ opener_id_, routing_id_, disposition, initial_pos_,
+ WasOpenedByUserGestureHelper()));
+}
+
+void RenderView::RunModal(WebWidget* webwidget) {
+ DCHECK(did_show_) << "should already have shown the view";
+
+ IPC::SyncMessage* msg = new ViewHostMsg_RunModal(routing_id_);
+
+ msg->set_pump_messages_event(modal_dialog_event_);
+ Send(msg);
+}
+
+void RenderView::SyncNavigationState() {
+ if (!webview())
+ return;
+
+ GURL url;
+ std::wstring title;
+ std::string state;
+ if (!webview()->GetMainFrame()->GetCurrentState(&url, &title, &state))
+ return;
+
+ Send(new ViewHostMsg_UpdateState(routing_id_, page_id_, url, title, state));
+}
+
+void RenderView::ShowContextMenu(WebView* webview,
+ ContextNode::Type type,
+ int x,
+ int y,
+ const GURL& link_url,
+ const GURL& image_url,
+ const GURL& page_url,
+ const GURL& frame_url,
+ const std::wstring& selection_text,
+ const std::wstring& misspelled_word,
+ int edit_flags) {
+ ViewHostMsg_ContextMenu_Params params;
+ params.type = type;
+ params.x = x;
+ params.y = y;
+ params.image_url = image_url;
+ params.link_url = link_url;
+ params.page_url = page_url;
+ params.frame_url = frame_url;
+ params.selection_text = selection_text;
+ params.misspelled_word = misspelled_word;
+ params.edit_flags = edit_flags;
+ Send(new ViewHostMsg_ContextMenu(routing_id_, params));
+}
+
+void RenderView::StartDragging(WebView* webview, const WebDropData& drop_data) {
+ Send(new ViewHostMsg_StartDragging(routing_id_, drop_data));
+}
+
+void RenderView::TakeFocus(WebView* webview, bool reverse) {
+ Send(new ViewHostMsg_TakeFocus(routing_id_, reverse));
+}
+
+void RenderView::DidDownloadImage(int id,
+ const GURL& image_url,
+ bool errored,
+ const SkBitmap& image) {
+ Send(new ViewHostMsg_DidDownloadImage(routing_id_, id, image_url, errored,
+ image));
+}
+
+
+void RenderView::OnDownloadImage(int id,
+ const GURL& image_url,
+ int image_size) {
+ if (!webview()->DownloadImage(id, image_url, image_size))
+ Send(new ViewHostMsg_DidDownloadImage(routing_id_, id, image_url, true,
+ SkBitmap()));
+}
+
+void RenderView::OnGetApplicationInfo(int page_id) {
+ webkit_glue::WebApplicationInfo app_info;
+ if (page_id == page_id_)
+ webkit_glue::GetApplicationInfo(webview(), &app_info);
+
+ // Prune out any data URLs in the set of icons. The browser process expects
+ // any icon with a data URL to have originated from a favicon. We don't want
+ // to decode arbitrary data URLs in the browser process. See
+ // http://b/issue?id=1162972
+ for (size_t i = 0; i < app_info.icons.size(); ++i) {
+ if (app_info.icons[i].url.SchemeIs("data")) {
+ app_info.icons.erase(app_info.icons.begin() + i);
+ --i;
+ }
+ }
+
+ Send(new ViewHostMsg_DidGetApplicationInfo(routing_id_, page_id, app_info));
+}
+
+GURL RenderView::GetAlternateErrorPageURL(const GURL& failedURL,
+ ErrorPageType error_type) {
+ if (failedURL.SchemeIsSecure()) {
+ // If the URL that failed was secure, then the embedding web page was not
+ // expecting a network attacker to be able to manipulate its contents. As
+ // we fetch alternate error pages over HTTP, we would be allowing a network
+ // attacker to manipulate the contents of the response if we tried to use
+ // the link doctor here.
+ return GURL::EmptyGURL();
+ }
+
+ // Grab the base URL from the browser process.
+ if (!alternate_error_page_url_.is_valid())
+ return GURL::EmptyGURL();
+
+ // Strip query params from the failed URL.
+ GURL::Replacements remove_params;
+ remove_params.ClearUsername();
+ remove_params.ClearPassword();
+ remove_params.ClearQuery();
+ remove_params.ClearRef();
+ const GURL url_to_send = failedURL.ReplaceComponents(remove_params);
+
+ // Construct the query params to send to link doctor.
+ std::string params(alternate_error_page_url_.query());
+ params.append("&url=");
+ params.append(EscapeQueryParamValue(url_to_send.spec()));
+ params.append("&sourceid=chrome");
+ params.append("&error=");
+ switch (error_type) {
+ case DNS_ERROR:
+ params.append("dnserror");
+ break;
+
+ case HTTP_404:
+ params.append("http404");
+ break;
+
+ default:
+ NOTREACHED() << "unknown ErrorPageType";
+ }
+
+ // OK, build the final url to return.
+ GURL::Replacements link_doctor_params;
+ link_doctor_params.SetQueryStr(params);
+ GURL url = alternate_error_page_url_.ReplaceComponents(link_doctor_params);
+ return url;
+}
+
+void RenderView::OnFind(const FindInPageRequest& request) {
+ WebFrame* main_frame = webview()->GetMainFrame();
+ WebFrame* frame_after_main = webview()->GetNextFrameAfter(main_frame, true);
+ WebFrame* focused_frame = webview()->GetFocusedFrame();
+ WebFrame* search_frame = focused_frame; // start searching focused frame.
+
+ bool multi_frame = (frame_after_main != main_frame);
+
+ // If we have multiple frames, we don't want to wrap the search within the
+ // frame, so we check here if we only have main_frame in the chain.
+ bool wrap_within_frame = !multi_frame;
+
+ gfx::Rect selection_rect;
+ bool result = false;
+
+ do {
+ if (request.find_next)
+ result = search_frame->FindNext(request, wrap_within_frame);
+ else
+ result = search_frame->Find(request, wrap_within_frame, &selection_rect);
+
+ if (!result) {
+ // don't leave text selected as you move to the next frame.
+ search_frame->ClearSelection();
+
+ // Find the next frame, but skip the invisible ones.
+ do {
+ // What is the next frame to search? (we might be going backwards). Note
+ // that we specify wrap=true so that search_frame never becomes NULL.
+ search_frame = request.forward ?
+ webview()->GetNextFrameAfter(search_frame, true) :
+ webview()->GetPreviousFrameBefore(search_frame, true);
+ } while (!search_frame->Visible() && search_frame != focused_frame);
+
+ // make sure selection doesn't affect the search operation in new frame.
+ search_frame->ClearSelection();
+
+ // If we have multiple frames and we have wrapped back around to the
+ // focused frame, we need to search it once more allowing wrap within
+ // the frame, otherwise it will report 'no match' if the focused frame has
+ // reported matches, but no frames after the focused_frame contain a
+ // match for the search word(s).
+ if (multi_frame && search_frame == focused_frame) {
+ if (request.find_next)
+ result = search_frame->FindNext(request, true); // Force wrapping.
+ else
+ result = search_frame->Find(request, true, // Force wrapping.
+ &selection_rect);
+ }
+ }
+
+ // TODO(jcampan): http://b/issue?id=1157486 Remove StoreForFocus call once
+ // we have the fix for 792423.
+ search_frame->GetView()->StoreFocusForFrame(search_frame);
+ webview()->SetFocusedFrame(search_frame);
+ } while (!result && search_frame != focused_frame);
+
+ // Make sure we don't leave any frame focused or the focus won't be restored
+ // properly in WebViewImpl::SetFocus(). Note that we are talking here about
+ // focused on the SelectionController, not FocusController.
+ // webview()->GetFocusedFrame() will still return the last focused frame (as
+ // it queries the FocusController).
+ // TODO(jcampan): http://b/issue?id=1157486 Remove next line once we have the
+ // fix for 792423.
+ webview()->SetFocusedFrame(NULL);
+
+ // We send back word that we found some matches, because we don't want to lag
+ // when notifying the user that we found something. At this point we only know
+ // that we found 1 match, but the scoping effort will tell us more. However,
+ // if this is a FindNext request, the scoping effort is already under way, or
+ // done already, so we have partial results. In that case we set it to -1 so
+ // that it gets ignored by the FindInPageController.
+ int match_count = result ? 1 : 0; // 1 here means possibly more coming.
+ if (request.find_next)
+ match_count = -1;
+
+ // If we find no matches (or if this is Find Next) then this will be our last
+ // status update. Otherwise the scoping effort will send more results.
+ bool final_status_update = !result || request.find_next;
+
+ // Send the search result over to the browser process.
+ Send(new ViewHostMsg_Find_Reply(routing_id_, request.request_id,
+ match_count,
+ selection_rect,
+ -1, // Don't update active match ordinal.
+ final_status_update));
+
+ if (!request.find_next) {
+ // Scoping effort begins, starting with the mainframe.
+ search_frame = main_frame;
+
+ main_frame->ResetMatchCount();
+
+ do {
+ // Cancel all old scoping requests before starting a new one.
+ search_frame->CancelPendingScopingEffort();
+
+ // We don't start another scoping effort unless at least one match has
+ // been found.
+ if (result) {
+ // Start new scoping request. If the scoping function determines that it
+ // needs to scope, it will defer until later.
+ search_frame->ScopeStringMatches(request,
+ true); // reset the tickmarks
+ }
+
+ // Iterate to the next frame. The frame will not necessarily scope, for
+ // example if it is not visible.
+ search_frame = webview()->GetNextFrameAfter(search_frame, true);
+ } while (search_frame != main_frame);
+ }
+}
+
+void RenderView::ReportFindInPageMatchCount(int count, int request_id,
+ bool final_update) {
+ // If we have a message that has been queued up, then we should just replace
+ // it. The ACK from the browser will make sure it gets sent when the browser
+ // wants it.
+ if (queued_find_reply_message_.get()) {
+ IPC::Message* msg = new ViewHostMsg_Find_Reply(
+ routing_id_,
+ request_id,
+ count,
+ gfx::Rect(0, 0, 0, 0),
+ -1, // Don't update active match ordinal.
+ final_update);
+ queued_find_reply_message_.reset(msg);
+ } else {
+ // Send the search result over to the browser process.
+ Send(new ViewHostMsg_Find_Reply(
+ routing_id_,
+ request_id,
+ count,
+ gfx::Rect(0, 0, 0, 0),
+ -1, // // Don't update active match ordinal.
+ final_update));
+ }
+}
+
+void RenderView::ReportFindInPageSelection(int request_id,
+ int active_match_ordinal,
+ const gfx::Rect& selection_rect) {
+ // Send the search result over to the browser process.
+ Send(new ViewHostMsg_Find_Reply(routing_id_,
+ request_id,
+ -1,
+ selection_rect,
+ active_match_ordinal,
+ false));
+}
+
+bool RenderView::WasOpenedByUserGesture(WebView* webview) const {
+ return WasOpenedByUserGestureHelper();
+}
+
+bool RenderView::WasOpenedByUserGestureHelper() const {
+ // If pop-up blocking has been disabled, then treat all new windows as if
+ // they were opened by a user gesture. This will prevent them from being
+ // blocked. This is a bit of a hack, there should be a more straightforward
+ // way to disable pop-up blocking.
+ if (disable_popup_blocking_)
+ return true;
+
+ return opened_by_user_gesture_;
+}
+
+void RenderView::SpellCheck(const std::wstring& word, int& misspell_location,
+ int& misspell_length) {
+ Send(new ViewHostMsg_SpellCheck(routing_id_, word, &misspell_location,
+ &misspell_length));
+}
+
+void RenderView::SetInputMethodState(bool enabled) {
+ // Save the updated IME status and mark the input focus has been updated.
+ // The IME status is to be sent to a browser process next time when
+ // the input caret is rendered.
+ ime_control_updated_ = true;
+ ime_control_new_state_ = enabled;
+}
+
+void RenderView::ScriptedPrint(WebFrame* frame) {
+ // Retrieve the default print settings to calculate the expected number of
+ // pages.
+ ViewMsg_Print_Params default_settings;
+ IPC::SyncMessage* msg =
+ new ViewHostMsg_GetDefaultPrintSettings(routing_id_, &default_settings);
+ if (Send(msg)) {
+ msg = NULL;
+ // Continue only if the settings are valid.
+ if (default_settings.dpi && default_settings.document_cookie) {
+ int expected_pages_count = SwitchFrameToPrintMediaType(default_settings,
+ frame);
+ DCHECK(expected_pages_count);
+ SwitchFrameToDisplayMediaType(frame);
+
+ // Ask the browser to show UI to retrieve the final print settings.
+ ViewMsg_PrintPages_Params print_settings;
+ // host_window_ may be NULL at this point if the current window is a popup
+ // and the print() command has been issued from the parent. The receiver
+ // of this message has to deal with this.
+ msg = new ViewHostMsg_ScriptedPrint(routing_id_,
+ host_window_,
+ default_settings.document_cookie,
+ expected_pages_count,
+ &print_settings);
+ if (Send(msg)) {
+ msg = NULL;
+
+ // If the settings are invalid, early quit.
+ if (print_settings.params.dpi &&
+ print_settings.params.document_cookie) {
+ // Render the printed pages. It will implicitly revert the document to
+ // display CSS media type.
+ PrintPages(print_settings, frame);
+ // All went well.
+ return;
+ } else {
+ // The user cancelled.
+ }
+ } else {
+ // Send() failed.
+ NOTREACHED();
+ }
+ } else {
+ // The user cancelled.
+ }
+ } else {
+ // Send() failed.
+ NOTREACHED();
+ }
+ // TODO(maruel): bug 1123882 Alert the user that printing failed.
+}
+
+void RenderView::WebInspectorOpened(int num_resources) {
+ Send(new ViewHostMsg_InspectElement_Reply(routing_id_, num_resources));
+}
+
+void RenderView::UserMetricsRecordAction(const std::wstring& action) {
+ Send(new ViewHostMsg_UserMetricsRecordAction(routing_id_, action));
+}
+
+void RenderView::DnsPrefetch(const std::vector<std::string>& host_names) {
+ Send(new ViewHostMsg_DnsPrefetch(host_names));
+}
+
+void RenderView::OnAlterTextSize(int size) {
+ switch (size) {
+ case text_zoom::TEXT_SMALLER:
+ webview()->MakeTextSmaller();
+ break;
+ case text_zoom::TEXT_STANDARD:
+ webview()->MakeTextStandardSize();
+ break;
+ case text_zoom::TEXT_LARGER:
+ webview()->MakeTextLarger();
+ break;
+ default:
+ NOTREACHED();
+ }
+}
+
+void RenderView::OnSetPageEncoding(const std::wstring& encoding_name) {
+ webview()->SetPageEncoding(encoding_name);
+}
+
+void RenderView::OnPasswordFormsSeen(WebView* webview,
+ const std::vector<PasswordForm>& forms) {
+ Send(new ViewHostMsg_PasswordFormsSeen(routing_id_, forms));
+}
+
+WebHistoryItem* RenderView::GetHistoryEntryAtOffset(int offset) {
+ // This doesn't work in the multi-process case because we don't want to
+ // hang, as it might lead to deadlocks. Use GoToEntryAtOffsetAsync.
+ return NULL;
+}
+
+void RenderView::GoToEntryAtOffsetAsync(int offset) {
+ Send(new ViewHostMsg_GoToEntryAtOffset(routing_id_, offset));
+}
+
+int RenderView::GetHistoryBackListCount() {
+ return history_back_list_count_;
+}
+
+int RenderView::GetHistoryForwardListCount() {
+ return history_forward_list_count_;
+}
+
+void RenderView::OnNavStateChanged(WebView* webview) {
+ nav_state_sync_timer_.Start();
+}
+
+void RenderView::SetTooltipText(WebView* webview,
+ const std::wstring& tooltip_text) {
+ Send(new ViewHostMsg_SetTooltipText(routing_id_, tooltip_text));
+}
+
+void RenderView::DownloadUrl(const GURL& url, const GURL& referrer) {
+ Send(new ViewHostMsg_DownloadUrl(routing_id_, url, referrer));
+}
+
+WebFrame* RenderView::GetChildFrame(const std::wstring& frame_xpath) const {
+ WebFrame* web_frame;
+ if (frame_xpath.empty()) {
+ web_frame = webview()->GetMainFrame();
+ } else {
+ web_frame = webview()->GetMainFrame()->GetChildFrame(frame_xpath);
+ }
+
+ return web_frame;
+}
+
+void RenderView::EvaluateScriptUrl(const std::wstring& frame_xpath,
+ const std::wstring& js_url) {
+ WebFrame* web_frame = GetChildFrame(frame_xpath);
+ if (!web_frame)
+ return;
+
+ scoped_ptr<WebRequest> request(WebRequest::Create(GURL(js_url)));
+ web_frame->LoadRequest(request.get());
+}
+
+void RenderView::OnScriptEvalRequest(const std::wstring& frame_xpath,
+ const std::wstring& jscript) {
+ EvaluateScriptUrl(frame_xpath, jscript);
+}
+
+void RenderView::OnAddMessageToConsole(const std::wstring& frame_xpath,
+ const std::wstring& msg,
+ ConsoleMessageLevel level) {
+ WebFrame* web_frame = GetChildFrame(frame_xpath);
+ if (!web_frame)
+ return;
+
+ web_frame->AddMessageToConsole(msg, level);
+}
+
+void RenderView::OnDebugAttach() {
+ EvaluateScriptUrl(L"", L"javascript:void(0)");
+ Send(new ViewHostMsg_DidDebugAttach(routing_id_));
+ // Tell the plugin host to stop accepting messages in order to avoid
+ // hangs while the renderer is paused.
+ // TODO(1243929): It might be an improvement to add more plumbing to do this
+ // when the renderer is actually paused vs. just the debugger being attached.
+ PluginChannelHost::SetListening(false);
+}
+
+void RenderView::OnDebugDetach() {
+ // Tell the plugin host to start accepting plugin messages again.
+ PluginChannelHost::SetListening(true);
+}
+
+void RenderView::OnAllowDomAutomationBindings(bool allow_bindings) {
+ enable_dom_automation_ = allow_bindings;
+}
+
+void RenderView::OnAllowDOMUIBindings() {
+ enable_dom_ui_bindings_ = true;
+}
+
+void RenderView::OnSetDOMUIProperty(const std::string& name,
+ const std::string& value) {
+ DCHECK(enable_dom_ui_bindings_);
+ dom_ui_bindings_.SetProperty(name, value);
+}
+
+void RenderView::OnReservePageIDRange(int size_of_range) {
+ next_page_id_ += size_of_range + 1;
+}
+
+void RenderView::OnDragSourceEndedOrMoved(int client_x,
+ int client_y,
+ int screen_x,
+ int screen_y,
+ bool ended) {
+ if (ended)
+ webview()->DragSourceEndedAt(client_x, client_y, screen_x, screen_y);
+ else
+ webview()->DragSourceMovedTo(client_x, client_y, screen_x, screen_y);
+}
+
+void RenderView::OnDragSourceSystemDragEnded() {
+ webview()->DragSourceSystemDragEnded();
+}
+
+void RenderView::OnUploadFileRequest(const ViewMsg_UploadFile_Params& p) {
+ webkit_glue::FileUploadData* f = new webkit_glue::FileUploadData;
+ f->file_path = p.file_path;
+ f->form_name = p.form;
+ f->file_name = p.file;
+ f->submit_name = p.submit;
+
+ // Build the other form values map.
+ if (!p.other_values.empty()) {
+ std::vector<std::wstring> e;
+ std::vector<std::wstring> kvp;
+ std::vector<std::wstring>::iterator i;
+
+ SplitString(p.other_values, L'\n', &e);
+ for (i = e.begin(); i != e.end(); ++i) {
+ SplitString(*i, L'=', &kvp);
+ if (kvp.size() == 2)
+ f->other_form_values[kvp[0]] = kvp[1];
+ kvp.clear();
+ }
+ }
+
+ pending_upload_data_.reset(f);
+ ProcessPendingUpload();
+}
+
+void RenderView::ProcessPendingUpload() {
+ webkit_glue::FileUploadData* f = pending_upload_data_.get();
+ if (f && webview() && webkit_glue::FillFormToUploadFile(webview(), *f))
+ ResetPendingUpload();
+}
+
+void RenderView::ResetPendingUpload() {
+ pending_upload_data_.reset();
+}
+
+void RenderView::OnFormFill(const FormData& form) {
+ webkit_glue::FillForm(this->webview(), form);
+}
+
+void RenderView::OnFillPasswordForm(
+ const PasswordFormDomManager::FillData& form_data) {
+ webkit_glue::FillPasswordForm(this->webview(), form_data);
+}
+
+void RenderView::OnDragTargetDragEnter(const WebDropData& drop_data,
+ const gfx::Point& client_pt, const gfx::Point& screen_pt) {
+ bool is_drop_target = webview()->DragTargetDragEnter(drop_data,
+ client_pt.x(), client_pt.y(), screen_pt.x(), screen_pt.y());
+
+ Send(new ViewHostMsg_UpdateDragCursor(routing_id_, is_drop_target));
+}
+
+void RenderView::OnDragTargetDragOver(const gfx::Point& client_pt,
+ const gfx::Point& screen_pt) {
+ bool is_drop_target = webview()->DragTargetDragOver(client_pt.x(),
+ client_pt.y(), screen_pt.x(), screen_pt.y());
+
+ Send(new ViewHostMsg_UpdateDragCursor(routing_id_, is_drop_target));
+}
+
+void RenderView::OnDragTargetDragLeave() {
+ webview()->DragTargetDragLeave();
+}
+
+void RenderView::OnDragTargetDrop(const gfx::Point& client_pt,
+ const gfx::Point& screen_pt) {
+ webview()->DragTargetDrop(client_pt.x(), client_pt.y(), screen_pt.x(),
+ screen_pt.y());
+}
+
+void RenderView::OnUpdateWebPreferences(const WebPreferences& prefs) {
+ webview()->SetPreferences(prefs);
+}
+
+void RenderView::OnSetAltErrorPageURL(const GURL& url) {
+ alternate_error_page_url_ = url;
+}
+
+void RenderView::DidPaint() {
+ PluginDelegateList::iterator it = plugin_delegates_.begin();
+ while (it != plugin_delegates_.end()) {
+ (*it)->FlushGeometryUpdates();
+ ++it;
+ }
+}
+
+void RenderView::OnInstallMissingPlugin() {
+ // This could happen when the first default plugin is deleted.
+ if (first_default_plugin_ == NULL)
+ return;
+ first_default_plugin_->InstallMissingPlugin();
+}
+
+void RenderView::OnFileChooserResponse(const std::wstring& file_name) {
+ file_chooser_->OnFileChoose(file_name);
+ file_chooser_.reset();
+}
+
+void RenderView::OnEnableViewSourceMode() {
+ if (!webview())
+ return;
+ WebFrame* main_frame = webview()->GetMainFrame();
+ if (!main_frame)
+ return;
+
+ main_frame->SetInViewSourceMode(true);
+}
+
+void RenderView::OnUpdateBackForwardListCount(int back_list_count,
+ int forward_list_count) {
+ history_back_list_count_ = back_list_count;
+ history_forward_list_count_ = forward_list_count;
+}
+
+void RenderView::OnGetAllSavableResourceLinksForCurrentPage(
+ const GURL& page_url) {
+ // Prepare list to storage all savable resource links.
+ std::vector<GURL> resources_list;
+ std::vector<GURL> referrers_list;
+ std::vector<GURL> frames_list;
+ webkit_glue::SavableResourcesResult result(&resources_list,
+ &referrers_list,
+ &frames_list);
+
+ if (!webkit_glue::GetAllSavableResourceLinksForCurrentPage(webview(),
+ page_url,
+ &result)) {
+ // If something is wrong when collecting all savable resource links,
+ // send empty list to embedder(browser) to tell it failed.
+ referrers_list.clear();
+ resources_list.clear();
+ frames_list.clear();
+ }
+
+ // Send result of all savable resource links to embedder.
+ Send(new ViewHostMsg_SendCurrentPageAllSavableResourceLinks(routing_id_,
+ resources_list,
+ referrers_list,
+ frames_list));
+}
+
+void RenderView::OnGetSerializedHtmlDataForCurrentPageWithLocalLinks(
+ const std::vector<std::wstring>& links,
+ const std::vector<std::wstring>& local_paths,
+ const std::wstring& local_directory_name) {
+ webkit_glue::DomSerializer dom_serializer(webview()->GetMainFrame(),
+ true,
+ this,
+ links,
+ local_paths,
+ local_directory_name);
+ dom_serializer.SerializeDom();
+}
+
+void RenderView::DidSerializeDataForFrame(const GURL& frame_url,
+ const std::string& data, PageSavingSerializationStatus status) {
+ Send(new ViewHostMsg_SendSerializedHtmlData(routing_id_,
+ frame_url, data, static_cast<int32>(status)));
+}
+
+void RenderView::OnMsgShouldClose(bool is_closing_browser) {
+ bool should_close = webview()->ShouldClose();
+
+ Send(new ViewHostMsg_ShouldClose_ACK(routing_id_, should_close,
+ is_closing_browser));
+}
+
+void RenderView::OnClosePage(int new_render_process_host_id,
+ int new_request_id,
+ bool is_closing_browser) {
+ // TODO(creis): We'd rather use webview()->Close() here, but that currently
+ // sets the WebView's delegate_ to NULL, preventing any JavaScript dialogs
+ // in the onunload handler from appearing. For now, we're bypassing that and
+ // calling the FrameLoader's CloseURL method directly. This should be
+ // revisited to avoid having two ways to close a page. Having a single way
+ // to close that can run onunload is also useful for fixing
+ // http://b/issue?id=753080.
+ WebFrame* main_frame = webview()->GetMainFrame();
+ if (main_frame)
+ main_frame->ClosePage();
+
+ Send(new ViewHostMsg_ClosePage_ACK(routing_id_,
+ new_render_process_host_id,
+ new_request_id,
+ is_closing_browser));
+}
+
+void RenderView::OnThemeChanged() {
+ gfx::NativeTheme::instance()->CloseHandles();
+ gfx::Rect view_rect(0, 0, size_.width(), size_.height());
+ DidInvalidateRect(webwidget_, view_rect);
+}
+
+std::string RenderView::GetAltHTMLForTemplate(
+ const DictionaryValue& error_strings, int template_resource_id) const {
+ const StringPiece template_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ template_resource_id));
+
+ if (template_html.empty()) {
+ NOTREACHED() << "unable to load template. ID: " << template_resource_id;
+ return "";
+ }
+ // "t" is the id of the templates root node.
+ return jstemplate_builder::GetTemplateHtml(
+ template_html, &error_strings, "t");
+}
diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h
new file mode 100644
index 0000000..844d877
--- /dev/null
+++ b/chrome/renderer/render_view.h
@@ -0,0 +1,623 @@
+// Copyright 2008, 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 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.
+
+#ifndef CHROME_RENDERER_RENDER_VIEW_H__
+#define CHROME_RENDERER_RENDER_VIEW_H__
+
+#include <hash_map>
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/scoped_handle.h"
+#include "base/gfx/point.h"
+#include "base/gfx/rect.h"
+#include "base/timer.h"
+#include "base/values.h"
+#include "chrome/common/resource_dispatcher.h"
+#include "chrome/renderer/automation/dom_automation_controller.h"
+#include "chrome/renderer/dom_ui_bindings.h"
+#include "chrome/renderer/external_js_object.h"
+#include "chrome/renderer/render_process.h"
+#include "chrome/renderer/render_widget.h"
+#include "webkit/glue/console_message_level.h"
+#include "webkit/glue/dom_serializer_delegate.h"
+#include "webkit/glue/webview_delegate.h"
+#include "webkit/glue/webview.h"
+
+// RenderView is a diamond-shaped hierarchy, with WebWidgetDelegate at the root.
+// VS warns when we inherit the WebWidgetDelegate method implementations from
+// RenderWidget. It's safe to ignore that warning.
+#pragma warning(disable: 4250)
+
+class DebugMessageHandler;
+class GURL;
+class SharedMemory;
+class SkBitmap;
+struct ThumbnailScore;
+class WebError;
+class WebFrame;
+class WebPluginDelegate;
+class WebPluginDelegateProxy;
+enum WebRequestCachePolicy;
+
+namespace webkit_glue {
+ struct FileUploadData;
+}
+
+//
+// RenderView is an object that manages a WebView object, and provides a
+// communication interface with an embedding application process
+//
+class RenderView : public RenderWidget, public WebViewDelegate,
+ public webkit_glue::DomSerializerDelegate {
+ public:
+ // Creates a new RenderView. The parent_hwnd specifies a HWND to use as the
+ // parent of the WebView HWND that will be created. The modal_dialog_event
+ // is set by the RenderView whenever a modal dialog alert is shown, so that
+ // the renderer and plugin processes know to pump window messages. If this
+ // is a constrained popup or as a new tab, opener_id is the routing ID of the
+ // RenderView responsible for creating this RenderView (corresponding to the
+ // parent_hwnd).
+ static RenderView* Create(HWND parent_hwnd,
+ HANDLE modal_dialog_event,
+ int32 opener_id,
+ const WebPreferences& webkit_prefs,
+ int32 routing_id);
+
+ // Sets the "next page id" counter.
+ static void SetNextPageID(int32 next_page_id);
+
+ // The resource dispatcher used to fetch resources for this view.
+ ResourceDispatcher* resource_dispatcher() {
+ return resource_dispatcher_;
+ }
+
+ // May return NULL when the view is closing.
+ WebView* webview() const {
+ return static_cast<WebView*>(webwidget());
+ }
+
+ HWND host_window() const {
+ return host_window_;
+ }
+
+ HANDLE modal_dialog_event() {
+ return modal_dialog_event_.Get();
+ }
+
+ // IPC::Channel::Listener
+ virtual void OnMessageReceived(const IPC::Message& msg);
+
+ // WebViewDelegate
+ virtual void RunJavaScriptAlert(WebView* webview,
+ const std::wstring& message);
+ virtual bool RunJavaScriptConfirm(WebView* webview,
+ const std::wstring& message);
+ virtual bool RunJavaScriptPrompt(WebView* webview,
+ const std::wstring& message,
+ const std::wstring& default_value,
+ std::wstring* result);
+ virtual bool RunBeforeUnloadConfirm(WebView* webview,
+ const std::wstring& message);
+ virtual void OnUnloadListenerChanged(WebView* webview, WebFrame* webframe);
+ virtual void UpdateTargetURL(WebView* webview,
+ const GURL& url);
+ virtual void RunFileChooser(const std::wstring& default_filename,
+ WebFileChooserCallback* file_chooser);
+ virtual void AddMessageToConsole(WebView* webview,
+ const std::wstring& message,
+ unsigned int line_no,
+ const std::wstring& source_id);
+
+ virtual void DebuggerOutput(const std::wstring& out);
+
+ virtual void DidStartLoading(WebView* webview);
+ virtual void DidStopLoading(WebView* webview);
+ virtual void DidStartProvisionalLoadForFrame(
+ WebView* webview,
+ WebFrame* frame,
+ NavigationGesture gesture);
+ virtual void DidReceiveProvisionalLoadServerRedirect(WebView* webview,
+ WebFrame* frame);
+ virtual void DidFailProvisionalLoadWithError(WebView* webview,
+ const WebError& error,
+ WebFrame* frame);
+ virtual void LoadNavigationErrorPage(WebFrame* frame,
+ const WebRequest* failed_request,
+ const WebError& error,
+ const std::string& html,
+ bool replace);
+ virtual void DidCommitLoadForFrame(WebView* webview, WebFrame* frame,
+ bool is_new_navigation);
+ virtual void DidReceiveTitle(WebView* webview,
+ const std::wstring& title,
+ WebFrame* frame);
+ virtual void DidFinishLoadForFrame(WebView* webview,
+ WebFrame* frame);
+ virtual void DidFailLoadWithError(WebView* webview,
+ const WebError& error,
+ WebFrame* forFrame);
+ virtual void DidFinishDocumentLoadForFrame(WebView* webview, WebFrame* frame);
+ virtual bool DidLoadResourceFromMemoryCache(WebView* webview,
+ const WebRequest& request,
+ const WebResponse& response,
+ WebFrame* frame);
+ virtual void DidHandleOnloadEventsForFrame(WebView* webview, WebFrame* frame);
+ virtual void DidChangeLocationWithinPageForFrame(WebView* webview,
+ WebFrame* frame,
+ bool is_new_navigation);
+ virtual void DidReceiveIconForFrame(WebView* webview, WebFrame* frame);
+
+ virtual void WillPerformClientRedirect(WebView* webview,
+ WebFrame* frame,
+ const GURL& src_url,
+ const GURL& dest_url,
+ unsigned int delay_seconds,
+ unsigned int fire_date);
+ virtual void DidCancelClientRedirect(WebView* webview,
+ WebFrame* frame);
+ virtual void DidCompleteClientRedirect(WebView* webview,
+ WebFrame* frame,
+ const GURL& source);
+
+ virtual void WindowObjectCleared(WebFrame* webframe);
+ virtual WindowOpenDisposition DispositionForNavigationAction(
+ WebView* webview,
+ WebFrame* frame,
+ const WebRequest* request,
+ WebNavigationType type,
+ WindowOpenDisposition disposition,
+ bool is_redirect);
+
+ virtual WebView* CreateWebView(WebView* webview, bool user_gesture);
+ virtual WebWidget* CreatePopupWidget(WebView* webview);
+ virtual WebPluginDelegate* CreatePluginDelegate(
+ WebView* webview,
+ const GURL& url,
+ const std::string& mime_type,
+ const std::string& clsid,
+ std::string* actual_mime_type);
+ virtual void OnMissingPluginStatus(WebPluginDelegate* delegate, int status);
+ virtual void OpenURL(WebView* webview, const GURL& url,
+ WindowOpenDisposition disposition);
+ virtual void DidDownloadImage(int id,
+ const GURL& image_url,
+ bool errored,
+ const SkBitmap& image);
+ virtual GURL GetAlternateErrorPageURL(const GURL& failedURL,
+ ErrorPageType error_type);
+
+ virtual void ShowContextMenu(WebView* webview,
+ ContextNode::Type type,
+ int x,
+ int y,
+ const GURL& link_url,
+ const GURL& image_url,
+ const GURL& page_url,
+ const GURL& frame_url,
+ const std::wstring& selection_text,
+ const std::wstring& misspelled_word,
+ int edit_flags);
+ virtual void StartDragging(WebView* webview,
+ const WebDropData& drag_data);
+
+ virtual void TakeFocus(WebView* webview, bool reverse);
+ virtual void JSOutOfMemory();
+
+ virtual WebHistoryItem* GetHistoryEntryAtOffset(int offset);
+ virtual void GoToEntryAtOffsetAsync(int offset);
+ virtual int GetHistoryBackListCount();
+ virtual int GetHistoryForwardListCount();
+ virtual void OnNavStateChanged(WebView* webview);
+ virtual void SetTooltipText(WebView* webview,
+ const std::wstring& tooltip_text);
+
+ virtual void DownloadUrl(const GURL& url, const GURL& referrer);
+
+ virtual void OnPasswordFormsSeen(WebView* webview,
+ const std::vector<PasswordForm>& forms);
+
+ virtual void ReportFindInPageMatchCount(int count, int request_id,
+ bool final_update);
+ virtual void ReportFindInPageSelection(int request_id,
+ int active_match_ordinal,
+ const gfx::Rect& selection_rect);
+ virtual bool WasOpenedByUserGesture(WebView* webview) const;
+ virtual void SpellCheck(const std::wstring& word, int& misspell_location,
+ int& misspell_length);
+ virtual void SetInputMethodState(bool enabled);
+ virtual void ScriptedPrint(WebFrame* frame);
+ virtual void WebInspectorOpened(int num_resources);
+ virtual void UserMetricsRecordAction(const std::wstring& action);
+ virtual void DnsPrefetch(const std::vector<std::string>& host_names);
+
+ // DomSerializerDelegate
+ virtual void DidSerializeDataForFrame(const GURL& frame_url,
+ const std::string& data, PageSavingSerializationStatus status);
+
+ // WebWidgetDelegate
+ // Most methods are handled by RenderWidget.
+ virtual void Show(WebWidget* webwidget, WindowOpenDisposition disposition);
+ virtual void RunModal(WebWidget* webwidget);
+
+ // Do not delete directly. This class is reference counted.
+ virtual ~RenderView();
+
+ // Called when a plugin is destroyed.
+ void PluginDestroyed(WebPluginDelegateProxy* proxy);
+
+ // Called when a plugin is crashed.
+ void PluginCrashed(const std::wstring& plugin_path);
+
+ // Shows a modal HTML dialog.
+ void ShowModalHTMLDialog(const GURL& url, int width, int height,
+ const std::string& json_arguments,
+ std::string* json_retval);
+
+ // Called from JavaScript window.external.AddSearchProvider() to add a
+ // keyword for a provider described in the given OpenSearch document.
+ void AddSearchProvider(const std::string& url);
+
+ // Asks the browser for the CPBrowsingContext associated with this renderer.
+ uint32 GetCPBrowsingContext();
+
+ // Dispatches the current navigation state to the browser. Called on a
+ // periodic timer so we don't send too many messages.
+ void SyncNavigationState();
+
+ // Evaluates a javascript: URL
+ void EvaluateScriptUrl(const std::wstring& frame_xpath,
+ const std::wstring& jscript);
+
+ // Called when the Javascript debugger is no longer attached.
+ // This is called from within the renderer, not via an IPC message.
+ void OnDebugDetach();
+
+ private:
+ RenderView();
+
+ // When we are created from window.open from an already existing view, this
+ // constructor stores that view ID.
+ explicit RenderView(int32 opener_id);
+
+ // Initializes this view with the given parent and ID. The |routing_id| can be
+ // set to 'MSG_ROUTING_NONE' if the true ID is not yet known. In this case,
+ // CompleteInit must be called later with the true ID.
+ void Init(HWND parent,
+ HANDLE modal_dialog_event,
+ int32 opener_id,
+ const WebPreferences& webkit_prefs,
+ int32 routing_id);
+
+ void UpdateURL(WebFrame* frame);
+ void UpdateTitle(WebFrame* frame, const std::wstring& title);
+ void UpdateSessionHistory(WebFrame* frame);
+
+ // Update current main frame's encoding and send it to browser window.
+ // Since we want to let users see the right encoding info from menu
+ // before finishing loading, we call the UpdateEncoding in
+ // a) function:DidCommitLoadForFrame. When this function is called,
+ // that means we have got first data. In here we try to get encoding
+ // of page if it has been specified in http header.
+ // b) function:DidReceiveTitle. When this function is called,
+ // that means we have got specified title. Because in most of webpages,
+ // title tags will follow meta tags. In here we try to get encoding of
+ // page if it has been specified in meta tag.
+ // c) function:DidFinishDocumentLoadForFrame. When this function is
+ // called, that means we have got whole html page. In here we should
+ // finally get right encoding of page.
+ void UpdateEncoding(WebFrame* frame, const std::wstring& encoding_name);
+
+ // Captures the thumbnail and text contents for indexing for the given load
+ // ID. If the view's load ID is different than the parameter, this call is
+ // a NOP. Typically called on a timer, so the load ID may have changed in the
+ // meantime.
+ void CapturePageInfo(int load_id, bool preliminary_capture);
+
+ // Called to retrieve the text from the given frame contents, the page text
+ // up to the maximum amount will be placed into the given buffer
+ void CaptureText(WebFrame* frame, std::wstring* contents);
+
+ // Creates a thumbnail of |frame|'s contents resized to (|w|, |h|)
+ // and puts that in |thumbnail|. Thumbnail metadata goes in |score|.
+ void CaptureThumbnail(WebFrame* frame, int w, int h,
+ SkBitmap* thumbnail,
+ ThumbnailScore* score);
+
+ // Calculates how "boring" a thumbnail is. The boring score is the
+ // 0,1 ranged percentage of pixels that are the most common
+ // luma. Higher boring scores indicate that a higher percentage of a
+ // bitmap are all the same brightness.
+ double CalculateBoringScore(SkBitmap* bitmap);
+
+ bool RunJavaScriptMessage(int type,
+ const std::wstring& message,
+ const std::wstring& default_value,
+ std::wstring* result);
+
+ // Adds search provider from the given OpenSearch description URL as a
+ // keyword search.
+ void AddGURLSearchProvider(const GURL& osd_url, bool autodetected);
+
+ // RenderView IPC message handlers
+ void OnCreatingNewAck(HWND parent);
+ void SendThumbnail();
+ void OnPrintPage(const ViewMsg_PrintPage_Params& params);
+ void OnGetPrintedPagesCount(const ViewMsg_Print_Params& params);
+ void OnPrintPages(const ViewMsg_PrintPages_Params& params);
+ void OnNavigate(const ViewMsg_Navigate_Params& params);
+ void OnStop();
+ void OnLoadAlternateHTMLText(const std::string& html_contents,
+ bool new_navigation,
+ const GURL& display_url,
+ const std::string& security_info);
+ void OnStopFinding(bool clear_selection);
+ void OnFindReplyAck();
+ void OnUpdateTargetURLAck();
+ void OnUndo();
+ void OnRedo();
+ void OnCut();
+ void OnCopy();
+ void OnPaste();
+ void OnReplace(const std::wstring& text);
+ void OnDelete();
+ void OnSelectAll();
+ void OnCopyImageAt(int x, int y);
+ void OnInspectElement(int x, int y);
+ void OnShowJavaScriptConsole();
+ void OnCancelDownload(int32 download_id);
+ void OnFind(const FindInPageRequest& request);
+ void OnAlterTextSize(int size);
+ void OnSetPageEncoding(const std::wstring& encoding_name);
+ void OnGetAllSavableResourceLinksForCurrentPage(const GURL& page_url);
+ void OnGetSerializedHtmlDataForCurrentPageWithLocalLinks(
+ const std::vector<std::wstring>& links,
+ const std::vector<std::wstring>& local_paths,
+ const std::wstring& local_directory_name);
+ void OnUploadFileRequest(const ViewMsg_UploadFile_Params& p);
+ void OnFormFill(const FormData& form);
+ void OnFillPasswordForm(const PasswordFormDomManager::FillData& form_data);
+ void OnDragTargetDragEnter(const WebDropData& drop_data,
+ const gfx::Point& client_pt,
+ const gfx::Point& screen_pt);
+ void OnDragTargetDragOver(const gfx::Point& client_pt,
+ const gfx::Point& screen_pt);
+ void OnDragTargetDragLeave();
+ void OnDragTargetDrop(const gfx::Point& client_pt,
+ const gfx::Point& screen_pt);
+ void OnAllowDomAutomationBindings(bool allow_binding);
+ void OnAllowDOMUIBindings();
+ void OnSetDOMUIProperty(const std::string& name, const std::string& value);
+ void OnSetInitialFocus(bool reverse);
+ void OnUpdateWebPreferences(const WebPreferences& prefs);
+ void OnSetAltErrorPageURL(const GURL& gurl);
+
+ void OnDownloadImage(int id, const GURL& image_url, int image_size);
+
+ void OnGetApplicationInfo(int page_id);
+
+ void OnScriptEvalRequest(const std::wstring& frame_xpath,
+ const std::wstring& jscript);
+ void OnAddMessageToConsole(const std::wstring& frame_xpath,
+ const std::wstring& msg,
+ ConsoleMessageLevel level);
+ void OnDebugAttach();
+
+ void OnReservePageIDRange(int size_of_range);
+
+ void OnDragSourceEndedOrMoved(
+ int client_x, int client_y, int screen_x, int screen_y, bool ended);
+ void OnDragSourceSystemDragEnded();
+ void OnInstallMissingPlugin();
+ void OnFileChooserResponse(const std::wstring& file_name);
+ void OnEnableViewSourceMode();
+ void OnUpdateBackForwardListCount(int back_list_count,
+ int forward_list_count);
+
+ // Checks if the RenderView should close, runs the beforeunload handler and
+ // sends ViewMsg_ShouldClose to the browser.
+ void OnMsgShouldClose(bool is_closing_browser);
+
+ // Runs the onunload handler and closes the page, replying with ClosePage_ACK
+ // (with the given RPH and request IDs, to help track the request).
+ void OnClosePage(int new_render_process_host_id, int new_request_id,
+ bool is_closing_browser);
+
+ // Notification about ui theme changes.
+ void OnThemeChanged();
+
+ // Switches the frame's CSS media type to "print" and calculate the number of
+ // printed pages that are to be expected. |frame| will be used to calculate
+ // the number of expected pages for this frame only.
+ int SwitchFrameToPrintMediaType(const ViewMsg_Print_Params& params,
+ WebFrame* frame);
+
+ // Switches the frame's CSS media type to "display".
+ void SwitchFrameToDisplayMediaType(WebFrame* frame);
+
+ // Prints the page listed in |params|.
+ void PrintPage(const ViewMsg_PrintPage_Params& params, WebFrame* frame);
+
+ // Prints all the pages listed in |params|.
+ void PrintPages(const ViewMsg_PrintPages_Params& params, WebFrame* frame);
+
+ // Attempt to upload the file that we are trying to process if any.
+ // Reset the pending file upload data if the form was successfully
+ // posted.
+ void ProcessPendingUpload();
+
+ // Reset the pending file upload.
+ void ResetPendingUpload();
+
+ // Exposes the DOMAutomationController object that allows JS to send
+ // information to the browser process.
+ void BindDOMAutomationController(WebFrame* webframe);
+
+ void set_opened_by_user_gesture(bool value) {
+ opened_by_user_gesture_ = value;
+ }
+
+ // Called by RenderWidget after it paints.
+ virtual void DidPaint();
+
+ // Locates a sub frame with given xpath
+ WebFrame* GetChildFrame(const std::wstring& frame_xpath) const;
+
+ std::string GetAltHTMLForTemplate(const DictionaryValue& error_strings,
+ int template_resource_id) const;
+
+ // A helper method used by WasOpenedByUserGesture.
+ bool WasOpenedByUserGestureHelper() const;
+
+ // Handles resource loads for this view.
+ scoped_refptr<ResourceDispatcher> resource_dispatcher_;
+
+ // DOM Automation Controller CppBoundClass
+ bool enable_dom_automation_;
+ DomAutomationController dom_automation_controller_;
+
+ // Chrome page<->browser messaging CppBoundClass
+ bool enable_dom_ui_bindings_;
+ DOMUIBindings dom_ui_bindings_;
+
+ // window.external object for "built-in" JS extensions
+ ExternalJSObject external_js_object_;
+
+ // The last gotten main frame's encoding.
+ std::wstring last_encoding_name_;
+
+ // The URL we think the user's mouse is hovering over. We use this to
+ // determine if we want to send a new one (we do not need to send
+ // duplicates).
+ GURL target_url_;
+
+ // The state of our target_url transmissions. When we receive a request to
+ // send a URL to the browser, we set this to TARGET_INFLIGHT until an ACK
+ // comes back - if a new request comes in before the ACK, we store the new
+ // URL in pending_target_url_ and set the status to TARGET_PENDING. If an
+ // ACK comes back and we are in TARGET_PENDING, we send the stored URL and
+ // revert to TARGET_INFLIGHT.
+ //
+ // We don't need a queue of URLs to send, as only the latest is useful.
+ enum {
+ TARGET_NONE,
+ TARGET_INFLIGHT, // We have a request in-flight, waiting for an ACK
+ TARGET_PENDING // INFLIGHT + we have a URL waiting to be sent
+ } target_url_status_;
+
+ // The next target URL we want to send to the browser.
+ GURL pending_target_url_;
+
+ // Are we loading our top level frame
+ bool is_loading_;
+
+ // If we are handling a top-level client-side redirect, this tracks the URL
+ // of the page that initiated it. Specifically, when a load is committed this
+ // is used to determine if that load originated from a client-side redirect.
+ // It is empty if there is no top-level client-side redirect.
+ GURL completed_client_redirect_src_;
+
+ // The gesture that initiated the current navigation.
+ NavigationGesture navigation_gesture_;
+
+ // Unique id to identify the current page between browser and renderer.
+ //
+ // Note that this is NOT updated for every main frame navigation, only for
+ // "regular" navigations that go into session history. In particular, client
+ // redirects, like the page cycler uses (document.location.href="foo") do not
+ // count as regular navigations and do not increment the page id.
+ int32 page_id_;
+
+ // Indicates the ID of the last page that we sent a FrameNavigate to the
+ // browser for. This is used to determine if the most recent transition
+ // generated a history entry (less than page_id_), or not (equal to or
+ // greater than). Note that this will be greater than page_id_ if the user
+ // goes back.
+ int32 last_page_id_sent_to_browser_;
+
+ // Page_id from the last page we indexed. This prevents us from indexing the
+ // same page twice in a row.
+ int32 last_indexed_page_id_;
+
+ // Used for popups.
+ bool opened_by_user_gesture_;
+
+ // The alternate error page URL, if one exists.
+ GURL alternate_error_page_url_;
+
+ // The pending file upload.
+ scoped_ptr<webkit_glue::FileUploadData> pending_upload_data_;
+
+ ScopedRunnableMethodFactory<RenderView> method_factory_;
+
+ // Timer used to delay the updating of nav state (see SyncNavigationState).
+ OneShotTimer nav_state_sync_timer_;
+
+ typedef std::vector<WebPluginDelegateProxy*> PluginDelegateList;
+ PluginDelegateList plugin_delegates_;
+
+ // Remember the first uninstalled plugin, so that we can ask the plugin
+ // to install itself when user clicks on the info bar.
+ WebPluginDelegate* first_default_plugin_;
+
+ // If the browser hasn't sent us an ACK for the last FindReply we sent
+ // to it, then we need to queue up the message (keeping only the most
+ // recent message if new ones come in).
+ scoped_ptr<IPC::Message> queued_find_reply_message_;
+
+ // Handle to an event that's set when the page is showing a modal dialog (or
+ // equivalent constrained window). The renderer and any plugin processes
+ // check this to know if they should pump messages/tasks then.
+ ScopedHandle modal_dialog_event_;
+
+ // Document width when in print CSS media type. 0 otherwise.
+ int printed_document_width_;
+
+ // Backup the view size before printing since it needs to be overriden. This
+ // value is set to restore the view size when printing is done.
+ gfx::Size printing_view_size_;
+
+ scoped_refptr<DebugMessageHandler> debug_message_handler_;
+
+ scoped_ptr<WebFileChooserCallback> file_chooser_;
+
+ int history_back_list_count_;
+ int history_forward_list_count_;
+
+ // True if pop-up blocking is disabled. False by default.
+ bool disable_popup_blocking_;
+
+ // True if the page has any frame-level unload or beforeunload listeners.
+ bool has_unload_listener_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(RenderView);
+};
+
+#endif // CHROME_RENDERER_RENDER_VIEW_H__
diff --git a/chrome/renderer/render_widget.cc b/chrome/renderer/render_widget.cc
new file mode 100644
index 0000000..c5db805
--- /dev/null
+++ b/chrome/renderer/render_widget.cc
@@ -0,0 +1,769 @@
+// Copyright 2008, 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 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.
+
+#include "chrome/renderer/render_widget.h"
+
+#include <windows.h>
+
+#include "base/gfx/point.h"
+#include "base/gfx/size.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/gfx/platform_canvas.h"
+#include "base/scoped_ptr.h"
+#include "webkit/glue/webinputevent.h"
+#include "webkit/glue/webwidget.h"
+
+///////////////////////////////////////////////////////////////////////////////
+
+namespace {
+
+// This class is used to defer calling RenderWidget::Close() while the current
+// thread is inside RenderThread::Send(), which in some cases can result in a
+// nested MessageLoop being run.
+class DeferredCloses : public Task {
+ public:
+ // Called to queue a deferred close for the given widget.
+ static void Push(RenderWidget* widget) {
+ if (!current_)
+ current_ = new DeferredCloses();
+ current_->queue_.push(widget);
+ }
+
+ // Called to trigger any deferred closes to be run.
+ static void Post() {
+ DCHECK(!RenderThread::current()->in_send());
+ if (current_) {
+ MessageLoop::current()->PostTask(FROM_HERE, current_);
+ current_ = NULL;
+ }
+ }
+
+ private:
+ virtual void Run() {
+ // Maybe we are being run from within another RenderWidget::Send call. If
+ // that is true, then we need to re-queue the widgets to be closed and try
+ // again later.
+ while (!queue_.empty()) {
+ if (RenderThread::current()->in_send()) {
+ Push(queue_.front());
+ } else {
+ queue_.front()->Close();
+ }
+ queue_.pop();
+ }
+ }
+
+ // The current DeferredCloses object.
+ static DeferredCloses* current_;
+
+ typedef std::queue< scoped_refptr<RenderWidget> > WidgetQueue;
+ WidgetQueue queue_;
+};
+
+DeferredCloses* DeferredCloses::current_ = NULL;
+
+} // namespace
+
+///////////////////////////////////////////////////////////////////////////////
+
+RenderWidget::RenderWidget()
+ : routing_id_(MSG_ROUTING_NONE),
+ opener_id_(MSG_ROUTING_NONE),
+ host_window_(NULL),
+ current_paint_buf_(NULL),
+ current_scroll_buf_(NULL),
+ next_paint_flags_(0),
+ paint_reply_pending_(false),
+ did_show_(false),
+ closing_(false),
+ is_hidden_(false),
+ needs_repainting_on_restore_(false),
+ has_focus_(false),
+ ime_is_active_(false),
+ ime_control_enable_ime_(true),
+ ime_control_x_(-1),
+ ime_control_y_(-1),
+ ime_control_new_state_(false),
+ ime_control_updated_(false) {
+ RenderProcess::AddRefProcess();
+}
+
+RenderWidget::~RenderWidget() {
+ if (current_paint_buf_) {
+ RenderProcess::FreeSharedMemory(current_paint_buf_);
+ current_paint_buf_ = NULL;
+ }
+ if (current_scroll_buf_) {
+ RenderProcess::FreeSharedMemory(current_scroll_buf_);
+ current_scroll_buf_ = NULL;
+ }
+ RenderProcess::ReleaseProcess();
+}
+
+/*static*/
+RenderWidget* RenderWidget::Create(int32 opener_id) {
+ DCHECK(opener_id != MSG_ROUTING_NONE);
+ scoped_refptr<RenderWidget> widget = new RenderWidget();
+ widget->Init(opener_id); // adds reference
+ return widget;
+}
+
+void RenderWidget::Init(int32 opener_id) {
+ DCHECK(!webwidget_);
+
+ if (opener_id != MSG_ROUTING_NONE)
+ opener_id_ = opener_id;
+
+ // Avoid a leak here by not assigning, since WebWidget::Create addrefs for us.
+ WebWidget* webwidget = WebWidget::Create(this);
+ webwidget_.swap(&webwidget);
+
+ bool result = RenderThread::current()->Send(
+ new ViewHostMsg_CreateWidget(opener_id, &routing_id_));
+ if (result) {
+ RenderThread::current()->AddRoute(routing_id_, this);
+ // Take a reference on behalf of the RenderThread. This will be balanced
+ // when we receive ViewMsg_Close.
+ AddRef();
+ } else {
+ DCHECK(false);
+ }
+}
+
+// This is used to complete pending inits and non-pending inits. For non-
+// pending cases, the parent will be the same as the current parent. This
+// indicates we do not need to reparent or anything.
+void RenderWidget::CompleteInit(HWND parent_hwnd) {
+ DCHECK(routing_id_ != MSG_ROUTING_NONE);
+ DCHECK(parent_hwnd);
+
+ host_window_ = parent_hwnd;
+
+ Send(new ViewHostMsg_RendererReady(routing_id_));
+}
+
+IPC_DEFINE_MESSAGE_MAP(RenderWidget)
+ IPC_MESSAGE_HANDLER(ViewMsg_Close, OnClose)
+ IPC_MESSAGE_HANDLER(ViewMsg_CreatingNew_ACK, OnCreatingNewAck)
+ IPC_MESSAGE_HANDLER(ViewMsg_Resize, OnResize)
+ IPC_MESSAGE_HANDLER(ViewMsg_WasHidden, OnWasHidden)
+ IPC_MESSAGE_HANDLER(ViewMsg_WasRestored, OnWasRestored)
+ IPC_MESSAGE_HANDLER(ViewMsg_PaintRect_ACK, OnPaintRectAck)
+ IPC_MESSAGE_HANDLER(ViewMsg_ScrollRect_ACK, OnScrollRectAck)
+ IPC_MESSAGE_HANDLER(ViewMsg_HandleInputEvent, OnHandleInputEvent)
+ IPC_MESSAGE_HANDLER(ViewMsg_MouseCaptureLost, OnMouseCaptureLost)
+ IPC_MESSAGE_HANDLER(ViewMsg_SetFocus, OnSetFocus)
+ IPC_MESSAGE_HANDLER(ViewMsg_ImeSetInputMode, OnImeSetInputMode)
+ IPC_MESSAGE_HANDLER(ViewMsg_ImeSetComposition, OnImeSetComposition)
+ IPC_MESSAGE_UNHANDLED_ERROR()
+IPC_END_MESSAGE_MAP()
+
+bool RenderWidget::Send(IPC::Message* message) {
+ // Don't send any messages after the browser has told us to close.
+ if (closing_) {
+ delete message;
+ return false;
+ }
+
+ // If given a messsage without a routing ID, then assign our routing ID.
+ if (message->routing_id() == MSG_ROUTING_NONE)
+ message->set_routing_id(routing_id_);
+
+ bool rv = RenderThread::current()->Send(message);
+
+ // If there aren't any more RenderThread::Send calls on the stack, then we
+ // can go ahead and schedule Close to be called on any RenderWidget objects
+ // that received a ViewMsg_Close while we were inside Send.
+ if (!RenderThread::current()->in_send())
+ DeferredCloses::Post();
+
+ return rv;
+}
+
+// Got a response from the browser after the renderer decided to create a new
+// view.
+void RenderWidget::OnCreatingNewAck(HWND parent) {
+ DCHECK(routing_id_ != MSG_ROUTING_NONE);
+
+ CompleteInit(parent);
+}
+
+void RenderWidget::OnClose() {
+ if (closing_)
+ return;
+ closing_ = true;
+
+ // Browser correspondence is no longer needed at this point.
+ if (routing_id_ != MSG_ROUTING_NONE)
+ RenderThread::current()->RemoveRoute(routing_id_);
+
+ // Balances the AddRef taken when we called AddRoute. This release happens
+ // via the MessageLoop since it may cause our destruction.
+ MessageLoop::current()->ReleaseSoon(FROM_HERE, this);
+
+ // If there is a Send call on the stack, then it could be dangerous to close
+ // now. Instead, we wait until we get out of Send.
+ if (RenderThread::current()->in_send()) {
+ DeferredCloses::Push(this);
+ } else {
+ Close();
+ }
+}
+
+void RenderWidget::OnResize(const gfx::Size& new_size) {
+ // During shutdown we can just ignore this message.
+ if (!webwidget_)
+ return;
+
+ // TODO(darin): We should not need to reset this here.
+ is_hidden_ = false;
+ needs_repainting_on_restore_ = false;
+
+ // We shouldn't be asked to resize to our current size.
+ DCHECK(size_ != new_size);
+ size_ = new_size;
+
+ // We should not be sent a Resize message if we have not ACK'd the previous
+ DCHECK(!next_paint_is_resize_ack());
+
+ // When resizing, we want to wait to paint before ACK'ing the resize. This
+ // ensures that we only resize as fast as we can paint. We only need to send
+ // an ACK if we are resized to a non-empty rect.
+ webwidget_->Resize(new_size);
+ if (!new_size.IsEmpty()) {
+ DCHECK(!paint_rect_.IsEmpty());
+
+ // This should have caused an invalidation of the entire view. The damaged
+ // rect could be larger than new_size if we are being made smaller.
+ DCHECK_GE(paint_rect_.width(), new_size.width());
+ DCHECK_GE(paint_rect_.height(), new_size.height());
+
+ // We will send the Resize_ACK flag once we paint again.
+ set_next_paint_is_resize_ack();
+ }
+}
+
+void RenderWidget::OnWasHidden() {
+ // Go into a mode where we stop generating paint and scrolling events.
+ is_hidden_ = true;
+}
+
+void RenderWidget::OnWasRestored(bool needs_repainting) {
+ // During shutdown we can just ignore this message.
+ if (!webwidget_)
+ return;
+
+ // See OnWasHidden
+ is_hidden_ = false;
+
+ if (!needs_repainting && !needs_repainting_on_restore_)
+ return;
+ needs_repainting_on_restore_ = false;
+
+ // Tag the next paint as a restore ack, which is picked up by DoDeferredPaint
+ // when it sends out the next PaintRect message.
+ set_next_paint_is_restore_ack();
+
+ // Generate a full repaint.
+ DidInvalidateRect(webwidget_, gfx::Rect(size_.width(), size_.height()));
+}
+
+void RenderWidget::OnPaintRectAck() {
+ DCHECK(paint_reply_pending());
+ paint_reply_pending_ = false;
+
+ // If we sent a PaintRect message with a zero-sized bitmap, then
+ // we should have no current paint buf.
+ if (current_paint_buf_) {
+ RenderProcess::FreeSharedMemory(current_paint_buf_);
+ current_paint_buf_ = NULL;
+ }
+
+ // Continue painting if necessary...
+ DoDeferredPaint();
+}
+
+void RenderWidget::OnScrollRectAck() {
+ DCHECK(scroll_reply_pending());
+
+ RenderProcess::FreeSharedMemory(current_scroll_buf_);
+ current_scroll_buf_ = NULL;
+
+ // Continue scrolling if necessary...
+ DoDeferredScroll();
+}
+
+void RenderWidget::OnHandleInputEvent(const IPC::Message& message) {
+ void* iter = NULL;
+
+ const char* data;
+ int data_length;
+ if (!message.ReadData(&iter, &data, &data_length))
+ return;
+
+ const WebInputEvent* input_event =
+ reinterpret_cast<const WebInputEvent*>(data);
+ bool processed = false;
+ if (webwidget_)
+ processed = webwidget_->HandleInputEvent(input_event);
+
+ IPC::Message* response = new ViewHostMsg_HandleInputEvent_ACK(routing_id_);
+ response->WriteInt(input_event->type);
+ if (!processed) {
+ // If the event was not processed we send it back.
+ response->WriteData(data, data_length);
+ }
+ Send(response);
+}
+
+void RenderWidget::OnMouseCaptureLost() {
+ if (webwidget_)
+ webwidget_->MouseCaptureLost();
+}
+
+void RenderWidget::OnSetFocus(bool enable) {
+ has_focus_ = enable;
+ if (webwidget_)
+ webwidget_->SetFocus(enable);
+ if (enable) {
+ // Force to retrieve the state of the focused widget to determine if we
+ // should activate IMEs next time when this process calls the UpdateIME()
+ // function.
+ ime_control_updated_ = true;
+ ime_control_new_state_ = true;
+ }
+}
+
+void RenderWidget::ClearFocus() {
+ // We may have got the focus from the browser before this gets processed, in
+ // which case we do not want to unfocus ourself.
+ if (!has_focus_ && webwidget_)
+ webwidget_->SetFocus(false);
+}
+
+void RenderWidget::PaintRect(const gfx::Rect& rect, SharedMemory* paint_buf) {
+ gfx::PlatformCanvas canvas(rect.width(), rect.height(), true,
+ paint_buf->handle());
+ // Bring the canvas into the coordinate system of the paint rect
+ canvas.translate(static_cast<SkScalar>(-rect.x()),
+ static_cast<SkScalar>(-rect.y()));
+
+ webwidget_->Paint(&canvas, rect);
+
+ // Flush to underlying bitmap. TODO(darin): is this needed?
+ canvas.getTopPlatformDevice().accessBitmap(false);
+
+ // Let the subclass observe this paint operations.
+ DidPaint();
+}
+
+size_t RenderWidget::GetPaintBufSize(const gfx::Rect& rect) {
+ // TODO(darin): protect against overflow
+ return 4 * rect.width() * rect.height();
+}
+
+void RenderWidget::DoDeferredPaint() {
+ if (!webwidget_ || paint_reply_pending() || paint_rect_.IsEmpty())
+ return;
+
+ // When we are hidden, we want to suppress painting, but we still need to
+ // mark this DoDeferredPaint as complete.
+ if (is_hidden_ || size_.IsEmpty()) {
+ paint_rect_ = gfx::Rect();
+ needs_repainting_on_restore_ = true;
+ return;
+ }
+
+ // Layout may generate more invalidation...
+ webwidget_->Layout();
+
+ // OK, save the current paint_rect to a local since painting may cause more
+ // invalidation. Some WebCore rendering objects only layout when painted.
+ gfx::Rect damaged_rect = paint_rect_;
+ paint_rect_ = gfx::Rect();
+
+ // Compute a buffer for painting and cache it.
+ current_paint_buf_ =
+ RenderProcess::AllocSharedMemory(GetPaintBufSize(damaged_rect));
+ if (!current_paint_buf_) {
+ NOTREACHED();
+ return;
+ }
+
+ PaintRect(damaged_rect, current_paint_buf_);
+
+ ViewHostMsg_PaintRect_Params params;
+ params.bitmap = current_paint_buf_->handle();
+ params.bitmap_rect = damaged_rect;
+ params.view_size = size_;
+ params.plugin_window_moves = plugin_window_moves_;
+ params.flags = next_paint_flags_;
+
+ plugin_window_moves_.clear();
+
+ paint_reply_pending_ = true;
+ Send(new ViewHostMsg_PaintRect(routing_id_, params));
+ next_paint_flags_ = 0;
+
+ UpdateIME();
+}
+
+void RenderWidget::DoDeferredScroll() {
+ if (!webwidget_ || scroll_reply_pending() || scroll_rect_.IsEmpty())
+ return;
+
+ // When we are hidden, we want to suppress scrolling, but we still need to
+ // mark this DoDeferredScroll as complete.
+ if (is_hidden_ || size_.IsEmpty()) {
+ scroll_rect_ = gfx::Rect();
+ needs_repainting_on_restore_ = true;
+ return;
+ }
+
+ // Layout may generate more invalidation, so we might have to bail on
+ // optimized scrolling...
+ webwidget_->Layout();
+
+ if (scroll_rect_.IsEmpty())
+ return;
+
+ gfx::Rect damaged_rect;
+
+ // Compute the region we will expose by scrolling, and paint that into a
+ // shared memory section.
+ if (scroll_delta_.x()) {
+ int dx = scroll_delta_.x();
+ damaged_rect.set_y(scroll_rect_.y());
+ damaged_rect.set_height(scroll_rect_.height());
+ if (dx > 0) {
+ damaged_rect.set_x(scroll_rect_.x());
+ damaged_rect.set_width(dx);
+ } else {
+ damaged_rect.set_x(scroll_rect_.right() + dx);
+ damaged_rect.set_width(-dx);
+ }
+ } else {
+ int dy = scroll_delta_.y();
+ damaged_rect.set_x(scroll_rect_.x());
+ damaged_rect.set_width(scroll_rect_.width());
+ if (dy > 0) {
+ damaged_rect.set_y(scroll_rect_.y());
+ damaged_rect.set_height(dy);
+ } else {
+ damaged_rect.set_y(scroll_rect_.bottom() + dy);
+ damaged_rect.set_height(-dy);
+ }
+ }
+
+ // In case the scroll offset exceeds the width/height of the scroll rect
+ damaged_rect = scroll_rect_.Intersect(damaged_rect);
+
+ current_scroll_buf_ =
+ RenderProcess::AllocSharedMemory(GetPaintBufSize(damaged_rect));
+ if (!current_scroll_buf_) {
+ NOTREACHED();
+ return;
+ }
+
+ // Set these parameters before calling Paint, since that could result in
+ // further invalidates (uncommon).
+ ViewHostMsg_ScrollRect_Params params;
+ params.bitmap = current_scroll_buf_->handle();
+ params.bitmap_rect = damaged_rect;
+ params.dx = scroll_delta_.x();
+ params.dy = scroll_delta_.y();
+ params.clip_rect = scroll_rect_;
+ params.view_size = size_;
+ params.plugin_window_moves = plugin_window_moves_;
+
+ plugin_window_moves_.clear();
+
+ // Mark the scroll operation as no longer pending.
+ scroll_rect_ = gfx::Rect();
+
+ PaintRect(damaged_rect, current_scroll_buf_);
+ Send(new ViewHostMsg_ScrollRect(routing_id_, params));
+ UpdateIME();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// WebWidgetDelegate
+
+HWND RenderWidget::GetContainingWindow(WebWidget* webwidget) {
+ return host_window_;
+}
+
+void RenderWidget::DidInvalidateRect(WebWidget* webwidget,
+ const gfx::Rect& rect) {
+ // We only want one pending DoDeferredPaint call at any time...
+ bool paint_pending = !paint_rect_.IsEmpty();
+
+ // If this invalidate overlaps with a pending scroll, then we have to
+ // downgrade to invalidating the scroll rect.
+ if (rect.Intersects(scroll_rect_)) {
+ paint_rect_ = paint_rect_.Union(scroll_rect_);
+ scroll_rect_ = gfx::Rect();
+ }
+
+ gfx::Rect view_rect(0, 0, size_.width(), size_.height());
+ // TODO(iyengar) Investigate why we have painting issues when
+ // we ignore invalid regions outside the view.
+ // Ignore invalidates that occur outside the bounds of the view
+ // TODO(darin): maybe this should move into the paint code?
+ // paint_rect_ = view_rect.Intersect(paint_rect_.Union(rect));
+ paint_rect_ = paint_rect_.Union(view_rect.Intersect(rect));
+
+ if (paint_rect_.IsEmpty() || paint_reply_pending() || paint_pending)
+ return;
+
+ // Perform painting asynchronously. This serves two purposes:
+ // 1) Ensures that we call WebView::Paint without a bunch of other junk
+ // on the call stack.
+ // 2) Allows us to collect more damage rects before painting to help coalesce
+ // the work that we will need to do.
+ MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &RenderWidget::DoDeferredPaint));
+}
+
+void RenderWidget::DidScrollRect(WebWidget* webwidget, int dx, int dy,
+ const gfx::Rect& clip_rect) {
+ // We only support scrolling along one axis at a time.
+ DCHECK((dx && !dy) || (!dx && dy));
+
+ bool intersects_with_painting = paint_rect_.Intersects(clip_rect);
+
+ // If we already have a pending scroll operation or if this scroll operation
+ // intersects the existing paint region, then just failover to invalidating.
+ if (!scroll_rect_.IsEmpty() || intersects_with_painting) {
+ if (!intersects_with_painting && scroll_rect_ == clip_rect) {
+ // OK, we can just update the scroll delta (requires same scrolling axis)
+ if (!dx && !scroll_delta_.x()) {
+ scroll_delta_.set_y(scroll_delta_.y() + dy);
+ return;
+ }
+ if (!dy && !scroll_delta_.y()) {
+ scroll_delta_.set_x(scroll_delta_.x() + dx);
+ return;
+ }
+ }
+ DidInvalidateRect(webwidget_, scroll_rect_);
+ DCHECK(scroll_rect_.IsEmpty());
+ DidInvalidateRect(webwidget_, clip_rect);
+ return;
+ }
+
+ // We only want one pending DoDeferredScroll call at any time...
+ bool scroll_pending = !scroll_rect_.IsEmpty();
+
+ scroll_rect_ = clip_rect;
+ scroll_delta_.SetPoint(dx, dy);
+
+ if (scroll_pending)
+ return;
+
+ // Perform scrolling asynchronously since we need to call WebView::Paint
+ MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &RenderWidget::DoDeferredScroll));
+}
+
+void RenderWidget::SetCursor(WebWidget* webwidget, const WebCursor& cursor) {
+ // Only send a SetCursor message if we need to make a change.
+ if (!current_cursor_.IsEqual(cursor)) {
+ current_cursor_ = cursor;
+ Send(new ViewHostMsg_SetCursor(routing_id_, cursor));
+ }
+}
+
+// We are supposed to get a single call to Show for a newly created RenderWidget
+// that was created via RenderWidget::CreateWebView. So, we wait until this
+// point to dispatch the ShowWidget message.
+//
+// This method provides us with the information about how to display the newly
+// created RenderWidget (i.e., as a constrained popup or as a new tab).
+//
+void RenderWidget::Show(WebWidget* webwidget,
+ WindowOpenDisposition disposition) {
+ DCHECK(!did_show_) << "received extraneous Show call";
+ DCHECK(routing_id_ != MSG_ROUTING_NONE);
+ DCHECK(opener_id_ != MSG_ROUTING_NONE);
+
+ if (!did_show_) {
+ did_show_ = true;
+ // NOTE: initial_pos_ may still have its default values at this point, but
+ // that's okay. It'll be ignored if as_popup is false, or the browser
+ // process will impose a default position otherwise.
+ RenderThread::current()->Send(new ViewHostMsg_ShowWidget(
+ opener_id_, routing_id_, initial_pos_));
+ }
+}
+
+void RenderWidget::Focus(WebWidget* webwidget) {
+ // Prevent the widget from stealing the focus if it does not have focus
+ // already. We do this by explicitely setting the focus to false again.
+ // We only let the browser focus the renderer.
+ if (!has_focus_ && webwidget_) {
+ MessageLoop::current()->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &RenderWidget::ClearFocus));
+ }
+}
+
+void RenderWidget::Blur(WebWidget* webwidget) {
+ Send(new ViewHostMsg_Blur(routing_id_));
+}
+
+void RenderWidget::CloseWidgetSoon(WebWidget* webwidget) {
+ // If a page calls window.close() twice, we'll end up here twice, but that's
+ // OK. It is safe to send multiple Close messages.
+
+ // Ask the RenderWidgetHost to initiate close.
+ Send(new ViewHostMsg_Close(routing_id_));
+}
+
+void RenderWidget::Close() {
+ if (webwidget_) {
+ webwidget_->Close();
+ webwidget_ = NULL;
+ }
+}
+
+void RenderWidget::GetWindowLocation(WebWidget* webwidget, gfx::Point* origin) {
+ gfx::Rect rect;
+ Send(new ViewHostMsg_GetWindowRect(routing_id_, host_window_, &rect));
+ *origin = rect.origin();
+}
+
+void RenderWidget::SetWindowRect(WebWidget* webwidget, const gfx::Rect& pos) {
+ if (did_show_) {
+ Send(new ViewHostMsg_RequestMove(routing_id_, pos));
+ } else {
+ initial_pos_ = pos;
+ }
+}
+
+void RenderWidget::OnImeSetInputMode(bool is_active) {
+ // A renderer process may move its input focus and the caret position
+ // while a browser process stop receiving IPC messages.
+ // Thus, when a browser process requests for a renderer process to send
+ // IPC messages, it has to check whether or not a renderer process moves
+ // its input focus and send an IPC message if they are updated.
+ ime_is_active_ = is_active;
+ ime_control_updated_ = true;
+ ime_control_new_state_ = true;
+}
+
+void RenderWidget::OnImeSetComposition(int string_type,
+ int cursor_position,
+ int target_start, int target_end,
+ const std::wstring& ime_string) {
+ if (webwidget_) {
+ int string_length = static_cast<int>(ime_string.length());
+ const wchar_t* string_data = ime_string.data();
+ webwidget_->ImeSetComposition(string_type, cursor_position,
+ target_start, target_end,
+ string_length, string_data);
+ }
+}
+
+void RenderWidget::UpdateIME() {
+ // If a browser process does not have IMEs, its IMEs are not active, or there
+ // are not any attached widgets.
+ // a renderer process does not have to retrieve information of the focused
+ // control or send notification messages to a browser process.
+ if (!ime_is_active_) {
+ return;
+ }
+ // Retrieve the caret position from the focused widget.
+ bool enable_ime;
+ int x, y;
+ const void *id;
+ if (!webwidget_ || !webwidget_->ImeUpdateStatus(&enable_ime, &id, &x, &y)) {
+ // There are not any editable widgets attached to this process.
+ // We should disable the IME to prevent it from sending CJK strings to
+ // non-editable widgets.
+ ime_control_updated_ = true;
+ ime_control_new_state_ = false;
+ }
+ if (ime_control_updated_) {
+ // The input focus has been changed.
+ // Compare the current state with the updated state and choose actions.
+ if (ime_control_enable_ime_) {
+ if (ime_control_new_state_) {
+ // Case 1: a text input -> another text input
+ // Complete the current composition and notify the caret position.
+ enum ViewHostMsg_ImeControl control = IME_COMPLETE_COMPOSITION;
+ Send(new ViewHostMsg_ImeUpdateStatus(routing_id(), control, x, y));
+ } else {
+ // Case 2: a text input -> a password input (or a static control)
+ // Complete the current composition and disable the IME.
+ enum ViewHostMsg_ImeControl control = IME_DISABLE;
+ Send(new ViewHostMsg_ImeUpdateStatus(routing_id(), control, x, y));
+ }
+ } else {
+ if (ime_control_new_state_) {
+ // Case 3: a password input (or a static control) -> a text input
+ // Enable the IME and notify the caret position.
+ enum ViewHostMsg_ImeControl control = IME_COMPLETE_COMPOSITION;
+ Send(new ViewHostMsg_ImeUpdateStatus(routing_id(), control, x, y));
+ } else {
+ // Case 4: a password input (or a static contol) -> another password
+ // input (or another static control).
+ // The IME has been already disabled and we don't have to do anything.
+ }
+ }
+ } else {
+ // The input focus is not changed.
+ // Notify the caret position to a browser process only if it is changed.
+ if (ime_control_enable_ime_) {
+ if (x != ime_control_x_ || y != ime_control_y_) {
+ enum ViewHostMsg_ImeControl control = IME_MOVE_WINDOWS;
+ Send(new ViewHostMsg_ImeUpdateStatus(routing_id(), control, x, y));
+ }
+ }
+ }
+ // Save the updated IME status to prevent from sending the same IPC messages.
+ ime_control_updated_ = false;
+ ime_control_enable_ime_ = ime_control_new_state_;
+ ime_control_x_ = x;
+ ime_control_y_ = y;
+}
+
+void RenderWidget::DidMove(WebWidget* webwidget,
+ const WebPluginGeometry& move) {
+ size_t i = 0;
+ for (; i < plugin_window_moves_.size(); ++i) {
+ if (plugin_window_moves_[i].window == move.window) {
+ plugin_window_moves_[i] = move;
+ break;
+ }
+ }
+
+ if (i == plugin_window_moves_.size())
+ plugin_window_moves_.push_back(move);
+}
diff --git a/chrome/renderer/render_widget.h b/chrome/renderer/render_widget.h
new file mode 100644
index 0000000..720df07
--- /dev/null
+++ b/chrome/renderer/render_widget.h
@@ -0,0 +1,277 @@
+// Copyright 2008, 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 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.
+
+#ifndef CHROME_RENDERER_RENDER_WIDGET_H__
+#define CHROME_RENDERER_RENDER_WIDGET_H__
+
+#include <vector>
+#include "base/basictypes.h"
+#include "base/gfx/point.h"
+#include "base/gfx/rect.h"
+#include "base/gfx/size.h"
+#include "base/ref_counted.h"
+#include "chrome/common/ipc_channel.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/renderer/render_process.h"
+#include "webkit/glue/webwidget_delegate.h"
+#include "webkit/glue/webcursor.h"
+#include "webkit/glue/webplugin.h"
+
+// RenderWidget provides a communication bridge between a WebWidget and
+// a RenderWidgetHost, the latter of which lives in a different process.
+class RenderWidget : public IPC::Channel::Listener,
+ public IPC::Message::Sender,
+ virtual public WebWidgetDelegate,
+ public base::RefCounted<RenderWidget> {
+ public:
+ // Creates a new RenderWidget. The opener_id is the routing ID of the
+ // RenderView that this widget lives inside.
+ static RenderWidget* Create(int32 opener_id);
+
+ // The routing ID assigned by the RenderProcess. Will be MSG_ROUTING_NONE if
+ // not yet assigned a view ID, in which case, the process MUST NOT send
+ // messages with this ID to the parent.
+ int32 routing_id() const {
+ return routing_id_;
+ }
+
+ // May return NULL when the window is closing.
+ WebWidget* webwidget() const {
+ return webwidget_;
+ }
+
+ // Implementing RefCounting required for WebWidgetDelegate
+ virtual void AddRef() {
+ RefCounted<RenderWidget>::AddRef();
+ }
+ virtual void Release() {
+ RefCounted<RenderWidget>::Release();
+ }
+
+ // IPC::Channel::Listener
+ virtual void OnMessageReceived(const IPC::Message& msg);
+
+ // IPC::Message::Sender
+ virtual bool Send(IPC::Message* msg);
+
+ // WebWidgetDelegate
+ virtual HWND GetContainingWindow(WebWidget* webwidget);
+ virtual void DidInvalidateRect(WebWidget* webwidget, const gfx::Rect& rect);
+ virtual void DidScrollRect(WebWidget* webwidget, int dx, int dy,
+ const gfx::Rect& clip_rect);
+ virtual void SetCursor(WebWidget* webwidget, const WebCursor& cursor);
+ virtual void Show(WebWidget* webwidget, WindowOpenDisposition disposition);
+ virtual void CloseWidgetSoon(WebWidget* webwidget);
+ virtual void Focus(WebWidget* webwidget);
+ virtual void Blur(WebWidget* webwidget);
+ virtual void GetWindowLocation(WebWidget* webwidget, gfx::Point* origin);
+ virtual void SetWindowRect(WebWidget* webwidget, const gfx::Rect& rect);
+ virtual void DidMove(WebWidget* webwidget, const WebPluginGeometry& move);
+ virtual void RunModal(WebWidget* webwidget) {}
+
+ // Do not delete directly. This class is reference counted.
+ virtual ~RenderWidget();
+
+ // Close the underlying WebWidget.
+ void Close();
+
+ protected:
+ RenderWidget();
+
+ // Initializes this view with the given opener. CompleteInit must be called
+ // later.
+ void Init(int32 opener_id);
+
+ // Finishes creation of a pending view started with Init.
+ void CompleteInit(HWND parent);
+
+ // Paints the given rectangular region of the WebWidget into paint_buf (a
+ // shared memory segment returned by AllocPaintBuf). The caller must ensure
+ // that the given rect fits within the bounds of the WebWidget.
+ void PaintRect(const gfx::Rect& rect, SharedMemory* paint_buf);
+
+ // Get the size of the paint buffer for the given rectangle, rounding up to
+ // the allocation granularity of the system.
+ size_t GetPaintBufSize(const gfx::Rect& rect);
+
+ void DoDeferredPaint();
+ void DoDeferredScroll();
+
+ // This method is called immediately after PaintRect but before the
+ // corresponding paint or scroll message is send to the widget host.
+ virtual void DidPaint() {}
+
+ // RenderWidget IPC message handlers
+ void OnClose();
+ void OnCreatingNewAck(HWND parent);
+ void OnResize(const gfx::Size& new_size);
+ void OnWasHidden();
+ void OnWasRestored(bool needs_repainting);
+ void OnPaintRectAck();
+ void OnScrollRectAck();
+ void OnHandleInputEvent(const IPC::Message& message);
+ void OnMouseCaptureLost();
+ void OnSetFocus(bool enable);
+ void OnImeSetInputMode(bool is_active);
+ void OnImeSetComposition(int string_type, int cursor_position,
+ int target_start, int target_end,
+ const std::wstring& ime_string);
+
+ // True if a PaintRect_ACK message is pending.
+ bool paint_reply_pending() const {
+ return paint_reply_pending_;
+ }
+
+ // True if a ScrollRect_ACK message is pending.
+ bool scroll_reply_pending() const {
+ return current_scroll_buf_ != NULL;
+ }
+
+ bool next_paint_is_resize_ack() const {
+ return ViewHostMsg_PaintRect_Flags::is_resize_ack(next_paint_flags_);
+ }
+
+ bool next_paint_is_restore_ack() const {
+ return ViewHostMsg_PaintRect_Flags::is_restore_ack(next_paint_flags_);
+ }
+
+ void set_next_paint_is_resize_ack() {
+ next_paint_flags_ |= ViewHostMsg_PaintRect_Flags::IS_RESIZE_ACK;
+ }
+
+ void set_next_paint_is_restore_ack() {
+ next_paint_flags_ |= ViewHostMsg_PaintRect_Flags::IS_RESTORE_ACK;
+ }
+
+ // Called when a renderer process moves an input focus or updates the
+ // position of its caret.
+ // This function compares them with the previous values, and send them to
+ // the browser process only if they are updated.
+ // The browser process moves IME windows and context.
+ void UpdateIME();
+
+ // Tells the renderer it does not have focus. Used to prevent us from getting
+ // the focus on our own when the browser did not focus us.
+ void ClearFocus();
+
+ // Routing ID that allows us to communicate to the parent browser process
+ // RenderWidgetHost. When MSG_ROUTING_NONE, no messages may be sent.
+ int32 routing_id_;
+
+ scoped_refptr<WebWidget> webwidget_;
+
+ // Set to the ID of the view that initiated creating this view, if any. When
+ // the view was initiated by the browser (the common case), this will be
+ // MSG_ROUTING_NONE. This is used in determining ownership when opening
+ // child tabs. See RenderWidget::createWebViewWithRequest.
+ //
+ // This ID may refer to an invalid view if that view is closed before this
+ // view is.
+ int32 opener_id_;
+
+ // The position where this view should be initially shown.
+ gfx::Rect initial_pos_;
+
+ // The window we are embedded within. TODO(darin): kill this.
+ HWND host_window_;
+
+ // We store the current cursor object so we can avoid spamming SetCursor
+ // messages.
+ WebCursor current_cursor_;
+ // The size of the RenderWidget.
+ gfx::Size size_;
+
+ // Shared memory handles that are currently in use to transfer an image to
+ // the browser.
+ SharedMemory* current_paint_buf_;
+ SharedMemory* current_scroll_buf_;
+
+ // The smallest bounding rectangle that needs to be re-painted. This is non-
+ // empty if a paint event is pending.
+ gfx::Rect paint_rect_;
+
+ // The clip rect for the pending scroll event. This is non-empty if a
+ // scroll event is pending.
+ gfx::Rect scroll_rect_;
+
+ // The scroll delta for a pending scroll event.
+ gfx::Point scroll_delta_;
+
+ // Flags for the next ViewHostMsg_PaintRect message.
+ int next_paint_flags_;
+
+ // True if we are expecting a PaintRect_ACK message (i.e., that a PaintRect
+ // message has been sent).
+ bool paint_reply_pending_;
+
+ // Set to true if we should ignore RenderWidget::Show calls.
+ bool did_show_;
+
+ // Indicates that we shouldn't bother generated paint events.
+ bool is_hidden_;
+
+ // Indicates that we should be repainted when restored. This flag is set to
+ // true if we receive an invalidation / scroll event from webkit while our
+ // is_hidden_ flag is set to true. This is used to force a repaint once we
+ // restore to account for the fact that our host would not know about the
+ // invalidation / scroll event(s) from webkit while we are hidden.
+ bool needs_repainting_on_restore_;
+
+ // Indicates whether we have been focused/unfocused by the browser.
+ bool has_focus_;
+
+ // True if we have requested this widget be closed. No more messages will
+ // be sent, except for a Close.
+ bool closing_;
+
+ // Represents whether or not the IME of a browser process is active.
+ bool ime_is_active_;
+
+ // Represents the status of the selected edit control sent to a browser
+ // process last time.
+ // When a renderer process finishes rendering a region, it retrieves:
+ // * The identifier of the selected edit control;
+ // * Whether or not the selected edit control requires IME, and;
+ // * The position of the caret (or cursor).
+ // If the above values is updated, a renderer process sends an IPC message
+ // to a browser process. A browser process uses these values to
+ // activate/deactivate IME and set the position of IME windows.
+ bool ime_control_enable_ime_;
+ int ime_control_x_;
+ int ime_control_y_;
+ bool ime_control_new_state_;
+ bool ime_control_updated_;
+
+ // Holds all the needed plugin window moves for a scroll.
+ std::vector<WebPluginGeometry> plugin_window_moves_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(RenderWidget);
+};
+
+#endif // CHROME_RENDERER_RENDER_WIDGET_H__
diff --git a/chrome/renderer/renderer.vcproj b/chrome/renderer/renderer.vcproj
new file mode 100644
index 0000000..7f867bd
--- /dev/null
+++ b/chrome/renderer/renderer.vcproj
@@ -0,0 +1,283 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="renderer"
+ ProjectGUID="{9301A569-5D2B-4D11-9332-B1E30AEACB8D}"
+ RootNamespace="renderer"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="4"
+ InheritedPropertySheets=".\renderer.vsprops;$(SolutionDir)..\build\debug.vsprops;..\tools\build\win\precompiled_wtl.vsprops"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ ConfigurationType="4"
+ InheritedPropertySheets=".\renderer.vsprops;$(SolutionDir)..\build\release.vsprops"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="automation"
+ >
+ <File
+ RelativePath=".\automation\dom_automation_controller.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\automation\dom_automation_controller.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="net"
+ >
+ <File
+ RelativePath=".\net\render_dns_master.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\net\render_dns_master.h"
+ >
+ </File>
+ <File
+ RelativePath=".\net\render_dns_queue.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\net\render_dns_queue.h"
+ >
+ </File>
+ </Filter>
+ <File
+ RelativePath=".\about_handler.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\about_handler.h"
+ >
+ </File>
+ <File
+ RelativePath=".\debug_message_handler.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\debug_message_handler.h"
+ >
+ </File>
+ <File
+ RelativePath=".\dom_ui_bindings.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\dom_ui_bindings.h"
+ >
+ </File>
+ <File
+ RelativePath=".\external_js_object.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\external_js_object.h"
+ >
+ </File>
+ <File
+ RelativePath=".\localized_error.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\localized_error.h"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_channel_host.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_channel_host.h"
+ >
+ </File>
+ <File
+ RelativePath="..\tools\build\win\precompiled_wtl.cc"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\tools\build\win\precompiled_wtl.h"
+ >
+ </File>
+ <File
+ RelativePath=".\render_process.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\render_process.h"
+ >
+ </File>
+ <File
+ RelativePath=".\render_thread.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\render_thread.h"
+ >
+ </File>
+ <File
+ RelativePath=".\render_view.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\render_view.h"
+ >
+ </File>
+ <File
+ RelativePath=".\render_widget.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\render_widget.h"
+ >
+ </File>
+ <File
+ RelativePath=".\renderer_glue.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\renderer_main.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\renderer_resources.h"
+ >
+ </File>
+ <File
+ RelativePath=".\visitedlink_slave.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\visitedlink_slave.h"
+ >
+ </File>
+ <File
+ RelativePath=".\webplugin_delegate_proxy.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\webplugin_delegate_proxy.h"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/chrome/renderer/renderer.vsprops b/chrome/renderer/renderer.vsprops
new file mode 100644
index 0000000..19eda36
--- /dev/null
+++ b/chrome/renderer/renderer.vsprops
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="renderer"
+ InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\skia\using_skia.vsprops;$(SolutionDir)..\third_party\npapi\using_npapi.vsprops;..\tools\build\win\using_generated_strings.vsprops;..\..\third_party\icu38\build\using_icu.vsprops;$(SolutionDir)third_party\wtl\using_wtl.vsprops"
+ >
+ <Tool
+ Name="VCResourceCompilerTool"
+ AdditionalIncludeDirectories="$(IntDir)"
+ />
+</VisualStudioPropertySheet>
diff --git a/chrome/renderer/renderer_glue.cc b/chrome/renderer/renderer_glue.cc
new file mode 100644
index 0000000..cfe1d9c
--- /dev/null
+++ b/chrome/renderer/renderer_glue.cc
@@ -0,0 +1,407 @@
+// Copyright 2008, 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 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 provides the embedder's side of random webkit glue functions.
+
+#include <windows.h>
+#include <wininet.h>
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/string_util.h"
+#include "chrome/renderer/net/render_dns_master.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/common/resource_bundle.h"
+#include "chrome/common/resource_dispatcher.h"
+#include "chrome/plugin/npobject_util.h"
+#include "chrome/renderer/render_process.h"
+#include "chrome/renderer/render_thread.h"
+#include "chrome/renderer/render_view.h"
+#include "chrome/renderer/visitedlink_slave.h"
+#include "googleurl/src/gurl.h"
+#include "googleurl/src/url_util.h"
+#include "net/base/mime_util.h"
+#include "webkit/glue/resource_type.h"
+#include "webkit/glue/webframe.h"
+#include "webkit/glue/webview.h"
+#include "webkit/glue/webkit_glue.h"
+
+#include "SkBitmap.h"
+
+#include <strsafe.h> // note: per msdn docs, this must *follow* other includes
+
+template <typename T, size_t stack_capacity>
+class ResizableStackArray {
+ public:
+ ResizableStackArray()
+ : cur_buffer_(stack_buffer_), cur_capacity_(stack_capacity) {
+ }
+ ~ResizableStackArray() {
+ FreeHeap();
+ }
+
+ T* get() const {
+ return cur_buffer_;
+ }
+
+ T& operator[](size_t i) {
+ return cur_buffer_[i];
+ }
+
+ size_t capacity() const {
+ return cur_capacity_;
+ }
+
+ void Resize(size_t new_size) {
+ if (new_size < cur_capacity_)
+ return; // already big enough
+ FreeHeap();
+ cur_capacity_ = new_size;
+ cur_buffer_ = new T[new_size];
+ }
+
+ private:
+ // Resets the heap buffer, if any
+ void FreeHeap() {
+ if (cur_buffer_ != stack_buffer_) {
+ delete[] cur_buffer_;
+ cur_buffer_ = stack_buffer_;
+ cur_capacity_ = stack_capacity;
+ }
+ }
+
+ T stack_buffer_[stack_capacity];
+ T* cur_buffer_;
+ size_t cur_capacity_;
+};
+
+namespace webkit_glue {
+
+bool HistoryContains(const wchar_t* url, int url_length,
+ const char* document_host, int document_host_length,
+ bool is_dns_prefetch_enabled) {
+ if (url_length == 0)
+ return false; // Empty URLs are not visited.
+
+ // Use big stack buffer to avoid allocation when possible.
+ url_parse::Parsed parsed;
+ url_canon::RawCanonOutput<2048> canon;
+
+ if (!url_util::Canonicalize(url, url_length, NULL, &canon, &parsed))
+ return false; // Invalid URLs are not visited.
+
+ char* parsed_host = canon.data() + parsed.host.begin;
+
+ // If the hostnames match or is_dns_prefetch_enabled is true, do the prefetch.
+ if (parsed.host.is_nonempty()) {
+ if (is_dns_prefetch_enabled ||
+ (document_host_length > 0 && parsed.host.len == document_host_length &&
+ strncmp(parsed_host, document_host, parsed.host.len) == 0))
+ DnsPrefetchCString(parsed_host, parsed.host.len);
+ }
+
+ return RenderThread::current()->visited_link_slave()->
+ IsVisited(canon.data(), canon.length());
+}
+
+void DnsPrefetchUrl(const wchar_t* url, int url_length) {
+ if (url_length == 0)
+ return; // Empty URLs have no hostnames.
+
+ // Use big stack buffer to avoid allocation when possible.
+ url_parse::Parsed parsed;
+ url_canon::RawCanonOutput<2048> canon;
+
+ if (!url_util::Canonicalize(url, url_length, NULL, &canon, &parsed))
+ return; // Invalid URLs don't have hostnames.
+
+ // Call for prefetching without creating a std::string().
+ if (parsed.host.is_nonempty())
+ DnsPrefetchCString(canon.data() + parsed.host.begin, parsed.host.len);
+}
+
+void PrecacheUrl(const wchar_t* url, int url_length) {
+ // TBD: jar: Need implementation that loads the targetted URL into our cache.
+ // For now, at least prefetch DNS lookup
+ DnsPrefetchUrl(url, url_length);
+}
+
+void webkit_glue::AppendToLog(const char* file, int line, const char* msg) {
+ logging::LogMessage(file, line).stream() << msg;
+}
+
+bool webkit_glue::GetMimeTypeFromExtension(std::wstring &ext,
+ std::string *mime_type) {
+ if (IsPluginProcess())
+ return mime_util::GetMimeTypeFromExtension(ext, mime_type);
+
+ // The sandbox restricts our access to the registry, so we need to proxy
+ // these calls over to the browser process.
+ DCHECK(mime_type->empty());
+ RenderThread::current()->Send(
+ new ViewHostMsg_GetMimeTypeFromExtension(ext, mime_type));
+ return !mime_type->empty();
+}
+
+bool webkit_glue::GetMimeTypeFromFile(const std::wstring &file_path,
+ std::string *mime_type) {
+ if (IsPluginProcess())
+ return mime_util::GetMimeTypeFromFile(file_path, mime_type);
+
+ // The sandbox restricts our access to the registry, so we need to proxy
+ // these calls over to the browser process.
+ DCHECK(mime_type->empty());
+ RenderThread::current()->Send(
+ new ViewHostMsg_GetMimeTypeFromFile(file_path, mime_type));
+ return !mime_type->empty();
+}
+
+bool webkit_glue::GetPreferredExtensionForMimeType(const std::string& mime_type,
+ std::wstring* ext) {
+ if (IsPluginProcess())
+ return mime_util::GetPreferredExtensionForMimeType(mime_type, ext);
+
+ // The sandbox restricts our access to the registry, so we need to proxy
+ // these calls over to the browser process.
+ DCHECK(ext->empty());
+ RenderThread::current()->Send(
+ new ViewHostMsg_GetPreferredExtensionForMimeType(mime_type, ext));
+ return !ext->empty();
+}
+
+IMLangFontLink2* webkit_glue::GetLangFontLink() {
+ return RenderProcess::GetLangFontLink();
+}
+
+std::wstring webkit_glue::GetLocalizedString(int message_id) {
+ return ResourceBundle::GetSharedInstance().GetLocalizedString(message_id);
+}
+
+std::string webkit_glue::GetDataResource(int resource_id) {
+ return ResourceBundle::GetSharedInstance().GetDataResource(resource_id);
+}
+
+HCURSOR webkit_glue::LoadCursor(int cursor_id) {
+ return ResourceBundle::GetSharedInstance().LoadCursor(cursor_id);
+}
+
+// Clipboard glue
+
+void webkit_glue::ClipboardClear() {
+ RenderThread::current()->Send(new ViewHostMsg_ClipboardClear());
+}
+
+void webkit_glue::ClipboardWriteText(const std::wstring& text) {
+ RenderThread::current()->Send(new ViewHostMsg_ClipboardWriteText(text));
+}
+
+void webkit_glue::ClipboardWriteHTML(const std::wstring& html,
+ const GURL& url) {
+ RenderThread::current()->Send(new ViewHostMsg_ClipboardWriteHTML(html, url));
+}
+
+void webkit_glue::ClipboardWriteBookmark(const std::wstring& title,
+ const GURL& url) {
+ RenderThread::current()->Send(
+ new ViewHostMsg_ClipboardWriteBookmark(title, url));
+}
+
+// Here we need to do some work to marshal the bitmap through shared memory
+void webkit_glue::ClipboardWriteBitmap(const SkBitmap& bitmap) {
+ size_t buf_size = bitmap.getSize();
+ gfx::Size size(bitmap.width(), bitmap.height());
+
+ // Allocate a shared memory buffer to hold the bitmap bits
+ SharedMemory* shared_buf =
+ RenderProcess::AllocSharedMemory(buf_size);
+ if (!shared_buf) {
+ NOTREACHED();
+ return;
+ }
+ if (!shared_buf->Map(buf_size)) {
+ NOTREACHED();
+ return;
+ }
+
+ // Copy the bits into shared memory
+ SkAutoLockPixels bitmap_lock(bitmap);
+ memcpy(shared_buf->memory(), bitmap.getPixels(), buf_size);
+ shared_buf->Unmap();
+
+ // Send the handle over synchronous IPC
+ RenderThread::current()->Send(
+ new ViewHostMsg_ClipboardWriteBitmap(shared_buf->handle(), size));
+
+ // The browser should be done with the bitmap now. It's our job to free
+ // the shared memory.
+ RenderProcess::FreeSharedMemory(shared_buf);
+}
+
+void webkit_glue::ClipboardWriteWebSmartPaste() {
+ RenderThread::current()->Send(new ViewHostMsg_ClipboardWriteWebSmartPaste());
+}
+
+bool webkit_glue::ClipboardIsFormatAvailable(unsigned int format) {
+ bool result;
+ RenderThread::current()->Send(
+ new ViewHostMsg_ClipboardIsFormatAvailable(format, &result));
+ return result;
+}
+
+void webkit_glue::ClipboardReadText(std::wstring* result) {
+ RenderThread::current()->Send(new ViewHostMsg_ClipboardReadText(result));
+}
+
+void webkit_glue::ClipboardReadAsciiText(std::string* result) {
+ RenderThread::current()->Send(new ViewHostMsg_ClipboardReadAsciiText(result));
+}
+
+void webkit_glue::ClipboardReadHTML(std::wstring* markup, GURL* url) {
+ RenderThread::current()->Send(new ViewHostMsg_ClipboardReadHTML(markup, url));
+}
+
+
+bool webkit_glue::GetApplicationDirectory(std::wstring *path) {
+ return PathService::Get(chrome::DIR_APP, path);
+}
+
+GURL webkit_glue::GetInspectorURL() {
+ return GURL("chrome-resource://inspector/inspector.html");
+}
+
+std::string webkit_glue::GetUIResourceProtocol() {
+ return "chrome-resource";
+}
+
+bool webkit_glue::GetExeDirectory(std::wstring *path) {
+ return PathService::Get(base::DIR_EXE, path);
+}
+
+bool webkit_glue::GetPlugins(bool refresh,
+ std::vector<WebPluginInfo>* plugins) {
+ return RenderThread::current()->Send(
+ new ViewHostMsg_GetPlugins(refresh, plugins));
+}
+
+bool webkit_glue::IsPluginRunningInRendererProcess() {
+ return !IsPluginProcess();
+}
+
+bool webkit_glue::EnsureFontLoaded(HFONT font) {
+ LOGFONT logfont;
+ GetObject(font, sizeof(LOGFONT), &logfont);
+ return RenderThread::current()->Send(new ViewHostMsg_LoadFont(logfont));
+}
+
+MONITORINFOEX webkit_glue::GetMonitorInfoForWindow(HWND window) {
+ MONITORINFOEX monitor_info;
+ RenderThread::current()->Send(
+ new ViewHostMsg_GetMonitorInfoForWindow(window, &monitor_info));
+ return monitor_info;
+}
+
+std::wstring webkit_glue::GetWebKitLocale() {
+ // The browser process should have passed the locale to the renderer via the
+ // --lang command line flag.
+ CommandLine parsed_command_line;
+ const std::wstring& lang =
+ parsed_command_line.GetSwitchValue(switches::kLang);
+ DCHECK(!lang.empty());
+ return lang;
+}
+
+#ifndef USING_SIMPLE_RESOURCE_LOADER_BRIDGE
+
+// Each RenderView has a ResourceDispatcher. In unit tests, this function may
+// not work properly since there may be a ResourceDispatcher w/o a RenderView.
+// The WebView's delegate may be null, which typically happens as a WebView is
+// being closed (but it is also possible that it could be null at other times
+// since WebView has a SetDelegate method).
+static ResourceDispatcher* GetResourceDispatcher(WebFrame* frame) {
+ WebViewDelegate* d = frame->GetView()->GetDelegate();
+ return d ? static_cast<RenderView*>(d)->resource_dispatcher() : NULL;
+}
+
+// static factory function
+ResourceLoaderBridge* ResourceLoaderBridge::Create(
+ WebFrame* webframe,
+ const std::string& method,
+ const GURL& url,
+ const GURL& policy_url,
+ const GURL& referrer,
+ const std::string& headers,
+ int load_flags,
+ int origin_pid,
+ ResourceType::Type resource_type,
+ bool mixed_content) {
+ // TODO(darin): we need to eliminate the webframe parameter because webkit
+ // does not always supply it (see ResourceHandle::loadResourceSynchronously).
+ // Instead we should add context to ResourceRequest, which will be easy to do
+ // once we merge to the latest WebKit (r23806 at least).
+ if (!webframe) {
+ NOTREACHED() << "no webframe";
+ return NULL;
+ }
+ ResourceDispatcher* dispatcher = GetResourceDispatcher(webframe);
+ if (!dispatcher) {
+ DLOG(WARNING) << "no resource dispatcher";
+ return NULL;
+ }
+ return dispatcher->CreateBridge(method, url, policy_url, referrer, headers,
+ load_flags, origin_pid, resource_type,
+ mixed_content, 0);
+}
+
+void SetCookie(const GURL& url, const GURL& policy_url,
+ const std::string& cookie) {
+ RenderThread::current()->Send(new ViewHostMsg_SetCookie(url, policy_url,
+ cookie));
+}
+
+std::string GetCookies(const GURL& url, const GURL& policy_url) {
+ std::string cookies;
+ RenderThread::current()->Send(new ViewHostMsg_GetCookies(url, policy_url,
+ &cookies));
+ return cookies;
+}
+
+void NotifyCacheStats() {
+ // Update the browser about our cache
+ // NOTE: Since this can be called from the plugin process, we might not have
+ // a RenderThread. Do nothing in that case.
+ if (RenderThread::current())
+ RenderThread::current()->InformHostOfCacheStatsLater();
+}
+
+#endif // !USING_SIMPLE_RESOURCE_LOADER_BRIDGE
+
+} // namespace webkit_glue
diff --git a/chrome/renderer/renderer_main.cc b/chrome/renderer/renderer_main.cc
new file mode 100644
index 0000000..b47b1ff
--- /dev/null
+++ b/chrome/renderer/renderer_main.cc
@@ -0,0 +1,136 @@
+// Copyright 2008, 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 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.
+
+#include "base/command_line.h"
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_counters.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/env_util.h"
+#include "chrome/common/l10n_util.h"
+#include "chrome/common/logging_chrome.h"
+#include "chrome/common/resource_bundle.h"
+#include "chrome/renderer/render_process.h"
+#include "chrome/test/injection_test_dll.h"
+#include "sandbox/src/sandbox.h"
+
+#include "generated_resources.h"
+
+// This function provides some ways to test crash and assertion handling
+// behavior of the renderer.
+static void HandleRendererErrorTestParameters(const CommandLine& command_line) {
+ // This parameter causes an assertion.
+ if (command_line.HasSwitch(switches::kRendererAssertTest)) {
+ DCHECK(false);
+ }
+
+ // This parameter causes a null pointer crash (crash reporter trigger).
+ if (command_line.HasSwitch(switches::kRendererCrashTest)) {
+ int* bad_pointer = NULL;
+ *bad_pointer = 0;
+ }
+
+ if (command_line.HasSwitch(switches::kRendererStartupDialog)) {
+ std::wstring title = l10n_util::GetString(IDS_PRODUCT_NAME);
+ title += L" renderer"; // makes attaching to process easier
+ MessageBox(NULL, L"renderer starting...", title.c_str(),
+ MB_OK | MB_SETFOREGROUND);
+ }
+}
+
+// mainline routine for running as the Rendererer process
+int RendererMain(CommandLine &parsed_command_line, int show_command,
+ sandbox::TargetServices* target_services)
+{
+ StatsScope<StatsCounterTimer>
+ startup_timer(chrome::Counters::renderer_main());
+
+ Thread::SetThreadName("Chrome_RendererMain", GetCurrentThreadId());
+
+ CoInitialize(NULL);
+
+ DLOG(INFO) << "Started renderer with " <<
+ parsed_command_line.command_line_string();
+
+ HMODULE sandbox_test_module = NULL;
+ bool no_sandbox = parsed_command_line.HasSwitch(switches::kNoSandbox);
+ if (target_services && !no_sandbox) {
+ // The command line might specify a test dll to load.
+ if (parsed_command_line.HasSwitch(switches::kTestSandbox)) {
+ std::wstring test_dll_name =
+ parsed_command_line.GetSwitchValue(switches::kTestSandbox);
+ sandbox_test_module = LoadLibrary(test_dll_name.c_str());
+ DCHECK(sandbox_test_module);
+ }
+ }
+
+ HandleRendererErrorTestParameters(parsed_command_line);
+
+ std::wstring channel_name =
+ parsed_command_line.GetSwitchValue(switches::kProcessChannelID);
+ if (RenderProcess::GlobalInit(channel_name)) {
+ bool run_loop = true;
+ if (!no_sandbox) {
+ if (target_services) {
+ target_services->LowerToken();
+ } else {
+ run_loop = false;
+ }
+ }
+
+ if (sandbox_test_module) {
+ RunRendererTests run_security_tests =
+ reinterpret_cast<RunRendererTests>(GetProcAddress(sandbox_test_module,
+ kRenderTestCall));
+ DCHECK(run_security_tests);
+ if (run_security_tests) {
+ int test_count = 0;
+ DLOG(INFO) << "Running renderer security tests";
+ BOOL result = run_security_tests(&test_count);
+ DCHECK(result) << "Test number " << test_count << " has failed.";
+ // If we are in release mode, debug or crash the process.
+ if (!result)
+ __debugbreak();
+ }
+ }
+
+ startup_timer.Stop(); // End of Startup Time Measurement.
+
+ if (run_loop) {
+ // Load the accelerator table from the browser executable and tell the
+ // message loop to use it when translating messages.
+ MessageLoop::current()->Run();
+ }
+ }
+ RenderProcess::GlobalCleanup();
+
+ CoUninitialize();
+ return 0;
+}
diff --git a/chrome/renderer/renderer_resources.h b/chrome/renderer/renderer_resources.h
new file mode 100644
index 0000000..21cc7be
--- /dev/null
+++ b/chrome/renderer/renderer_resources.h
@@ -0,0 +1,5 @@
+// TODO(tc): Come up with a way to automate the generation of these
+// IDs so they don't collide with other rc files.
+#define IDR_NET_ERROR_HTML 500
+#define IDR_INSECURE_CONTENT_STAMP 501
+#define IDR_ERROR_NO_DETAILS_HTML 502
diff --git a/chrome/renderer/renderer_resources.rc b/chrome/renderer/renderer_resources.rc
new file mode 100644
index 0000000..55bcd0b
--- /dev/null
+++ b/chrome/renderer/renderer_resources.rc
@@ -0,0 +1,18 @@
+// Resources used by renderer/*.
+//
+// Paths in this file are relative to SolutionDir.
+
+#ifdef APSTUDIO_INVOKED
+ #error // Don't open in the Visual Studio resource editor!
+#endif //APSTUDIO_INVOKED
+
+#include "renderer\\renderer_resources.h"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// data resources
+//
+
+IDR_NET_ERROR_HTML BINDATA "renderer\\resources\\neterror.html"
+IDR_INSECURE_CONTENT_STAMP BINDATA "renderer\\resources\\insecure_content_stamp.png"
+IDR_ERROR_NO_DETAILS_HTML BINDATA "renderer\\resources\\error_no_details.html" \ No newline at end of file
diff --git a/chrome/renderer/resources/error_no_details.html b/chrome/renderer/resources/error_no_details.html
new file mode 100644
index 0000000..7264142a
--- /dev/null
+++ b/chrome/renderer/resources/error_no_details.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html id="t" jsvalues="dir:textdirection">
+<head>
+<title jscontent="title">
+</title>
+<style type="text/css"><!--
+body {
+ background-color: #fff;
+ color: #000;
+ font-family: arial,sans-serif;
+ font-size: 83%;
+ line-height: 120%;
+ max-width: 35em;
+ padding: 0.5em 1em;
+}
+li {
+ padding-bottom: .3em;
+}
+ul {
+ margin: .5em 0 0;
+ padding-bottom: 0;
+}
+h1 {
+ font-size: 1.5em;
+ margin-bottom: 1.5em;
+}
+h2 {
+ font-size: 1em;
+ font-weight: bold;
+ margin: 0 0 .5em;
+ padding: 0;
+}
+a {
+ color: #00c;
+}
+a:active {
+ color: #f00;
+}
+a:visited {
+ color: #551a8b;
+}
+#errorSummary, #suggestions, #search {
+ margin-bottom: 2.5em;
+}
+//-->
+</style>
+</head>
+
+<body>
+
+<h1 jscontent="heading"></h1>
+
+<div id="errorSummary" jsselect="summary">
+ <p jseval="this.innerHTML = $this.msg;"></p>
+</div>
+
+<div id="suggestions">
+ <h2 jscontent="suggestionsHeading"></h2>
+ <ul>
+ <li jsselect="suggestionsReload">
+ <span jseval="this.innerHTML = $this.msg;"></span>
+ </li>
+ <li jsselect="suggestionsCache">
+ <span jseval="this.innerHTML = $this.msg;"></span>
+ </li>
+ <li jsselect="suggestionsHomepage">
+ <span jscontent="suggestionsHomepageMsg"></span>
+ <a jscontent="hostName" jsvalues="href:homePage"></a>
+ </li>
+ </ul>
+</div>
+
+</body>
+</html>
diff --git a/chrome/renderer/resources/insecure_content_stamp.png b/chrome/renderer/resources/insecure_content_stamp.png
new file mode 100644
index 0000000..1eb8dcb
--- /dev/null
+++ b/chrome/renderer/resources/insecure_content_stamp.png
Binary files differ
diff --git a/chrome/renderer/resources/neterror.html b/chrome/renderer/resources/neterror.html
new file mode 100644
index 0000000..bf234f0
--- /dev/null
+++ b/chrome/renderer/resources/neterror.html
@@ -0,0 +1,104 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html id="t" jsvalues="dir:textdirection">
+<head>
+<title jscontent="title">
+</title>
+<style type="text/css"><!--
+body {
+ background-color: #fff;
+ color: #000;
+ font-family: arial,sans-serif;
+ font-size: 83%;
+ line-height: 120%;
+ max-width: 35em;
+ padding: 0.5em 1em;
+}
+li {
+ padding-bottom: .3em;
+}
+ul {
+ margin: .5em 0 0;
+ padding-bottom: 0;
+}
+h1 {
+ font-size: 1.5em;
+ margin-bottom: 1.5em;
+}
+h2 {
+ font-size: 1em;
+ font-weight: bold;
+ margin: 0 0 .5em;
+ padding: 0;
+}
+a {
+ color: #00c;
+}
+a:active {
+ color: #f00;
+}
+a:visited {
+ color: #551a8b;
+}
+#errorSummary, #suggestions, #search {
+ margin-bottom: 2.5em;
+}
+#zipInfo {
+ display: none;
+ padding-left: 16px;
+}
+#plus {
+ border: 0;
+ cursor: pointer;
+ vertical-align: baseline;
+}
+#details {
+ background-color: #e0e0e0;
+ max-width: 30em;
+ padding: 1em;
+}
+//-->
+</style>
+<script>
+function toggleDiv(id) {
+ var elt = document.getElementById(id);
+ elt.style.display = (elt.style.display == 'block') ? 'none' : 'block';
+}
+</script>
+</head>
+
+<body>
+
+<h1 jscontent="heading"></h1>
+
+<div id="errorSummary" jsselect="summary">
+ <p jseval="this.innerHTML = $this.msg;"></p>
+</div>
+
+<div id="suggestions">
+ <h2 jscontent="suggestionsHeading"></h2>
+ <ul>
+ <li jsselect="suggestionsReload">
+ <span jseval="this.innerHTML = $this.msg;"></span>
+ </li>
+ <li jsselect="suggestionsCache">
+ <span jseval="this.innerHTML = $this.msg;"></span>
+ </li>
+ <li jsselect="suggestionsHomepage">
+ <span jscontent="suggestionsHomepageMsg"></span>
+ <a jscontent="hostName" jsvalues="href:homePage"></a>
+ </li>
+ </ul>
+</div>
+
+<div>
+ <a href="javascript:void(0);" style="text-decoration:none" onclick="toggleDiv('zipInfo')">
+ <img id="plus" src="data:image/png;base64,R0lGODlhDAAMAMQAAAAAzOjp7lVmrezt8Zmlztja4c/R2Gx9te/x9srN1PHz9+7w9Ofp7eHj5/f4+vDx89bZ3t3g5eTn6/P19/v8+/////39/fj4+P///wAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABgALAAAAAAMAAwAAAVFYEUIZEkSolCt7CocKgsALdnOrGXLdEVdJMdsOHyQJkTigLRAKBQzxWIQIDGugRlD0miQIoXwDEKGCEaGhHqdeKVMJVQIADs=">
+ <span id="errorExpander" jscontent="detailsLink" style="text-decoration:underline"></span>
+ </a>
+ <div id="zipInfo">
+ <p jscontent="detailsHeading"></p>
+ <div id="details" jscontent="details"></div>
+ </div>
+</div>
+</body>
+</html>
diff --git a/chrome/renderer/spellcheck_unittest.cc b/chrome/renderer/spellcheck_unittest.cc
new file mode 100644
index 0000000..3ef6c08
--- /dev/null
+++ b/chrome/renderer/spellcheck_unittest.cc
@@ -0,0 +1,360 @@
+// Copyright 2008, 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 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.
+
+#include "webkit/glue/webkit_glue.h"
+
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "chrome/browser/spellchecker.h"
+#include "chrome/common/chrome_paths.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+class SpellCheckTest : public testing::Test {
+};
+} // namespace
+
+// Represents a special initialization function used only for the unit tests
+// in this file.
+extern void InitHunspellWithFiles(FILE* file_aff_hunspell,
+ FILE* file_dic_hunspell);
+
+// Operates unit tests for the webkit_glue::SpellCheckWord() function
+// with the US English dictionary.
+// The unit tests in this function consist of:
+// * Tests for the function with empty strings;
+// * Tests for the function with a valid English word;
+// * Tests for the function with a valid non-English word;
+// * Tests for the function with a valid English word with a preceding
+// space character;
+// * Tests for the function with a valid English word with a preceding
+// non-English word;
+// * Tests for the function with a valid English word with a following
+// space character;
+// * Tests for the function with a valid English word with a following
+// non-English word;
+// * Tests for the function with two valid English words concatenated
+// with space characters or non-English words;
+// * Tests for the function with an invalid English word;
+// * Tests for the function with an invalid English word with a preceding
+// space character;
+// * Tests for the function with an invalid English word with a preceding
+// non-English word;
+// * Tests for the function with2 an invalid English word with a following
+// space character;
+// * Tests for the function with an invalid English word with a following
+// non-English word, and;
+// * Tests for the function with two invalid English words concatenated
+// with space characters or non-English words.
+// A test with a "[ROBUSTNESS]" mark shows it is a robustness test and it uses
+// grammartically incorrect string.
+// TODO(hbono): Please feel free to add more tests.
+TEST(SpellCheckTest, SpellCheckStrings_EN_US) {
+ static const struct {
+ // A string to be tested.
+ const wchar_t* input;
+ // An expected result for this test case.
+ // * true: the input string does not have any invalid words.
+ // * false: the input string has one or more invalid words.
+ bool expected_result;
+ // The position and the length of the first invalid word.
+ int misspelling_start;
+ int misspelling_length;
+ } kTestCases[] = {
+ // Empty strings.
+ {NULL, true, 0, 0},
+ {L"", true, 0, 0},
+ {L" ", true, 0, 0},
+ {L"\xA0", true, 0, 0},
+ {L"\x3000", true, 0, 0},
+
+ // A valid English word "hello".
+ {L"hello", true, 0, 0},
+ // A valid Chinese word (meaning "hello") consisiting of two CJKV
+ // ideographs
+ {L"\x4F60\x597D", true, 0, 0},
+ // A valid Korean word (meaning "hello") consisting of five hangul
+ // syllables
+ {L"\xC548\xB155\xD558\xC138\xC694", true, 0, 0},
+ // A valid Japanese word (meaning "hello") consisting of five Hiragana
+ // letters
+ {L"\x3053\x3093\x306B\x3061\x306F", true, 0, 0},
+ // A valid Hindi word (meaning ?) consisting of six Devanagari letters
+ // (This word is copied from "http://b/issue?id=857583".)
+ {L"\x0930\x093E\x091C\x0927\x093E\x0928", true, 0, 0},
+ // A valid English word "affix" using a Latin ligature 'ffi'
+ {L"a\xFB03x", true, 0, 0},
+ // A valid English word "hello" (fullwidth version)
+ {L"\xFF28\xFF45\xFF4C\xFF4C\xFF4F", true, 0, 0},
+ // Two valid Greek words (meaning "hello") consisting of seven Greek
+ // letters
+ {L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5", true, 0, 0},
+ // A valid Russian word (meainng "hello") consisting of twelve Cyrillic
+ // letters
+ {L"\x0437\x0434\x0440\x0430\x0432\x0441"
+ L"\x0442\x0432\x0443\x0439\x0442\x0435", true, 0, 0},
+ // A valid English contraction
+ {L"isn't", true, 0, 0},
+ // A valid English word enclosed with underscores.
+ {L"_hello_", true, 0, 0},
+
+ // A valid English word with a preceding whitespace
+ {L" " L"hello", true, 0, 0},
+ // A valid English word with a preceding no-break space
+ {L"\xA0" L"hello", true, 0, 0},
+ // A valid English word with a preceding ideographic space
+ {L"\x3000" L"hello", true, 0, 0},
+ // A valid English word with a preceding Chinese word
+ {L"\x4F60\x597D" L"hello", true, 0, 0},
+ // [ROBUSTNESS] A valid English word with a preceding Korean word
+ {L"\xC548\xB155\xD558\xC138\xC694" L"hello", true, 0, 0},
+ // A valid English word with a preceding Japanese word
+ {L"\x3053\x3093\x306B\x3061\x306F" L"hello", true, 0, 0},
+ // [ROBUSTNESS] A valid English word with a preceding Hindi word
+ {L"\x0930\x093E\x091C\x0927\x093E\x0928" L"hello", true, 0, 0},
+ // [ROBUSTNESS] A valid English word with two preceding Greek words
+ {L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5"
+ L"hello", true, 0, 0},
+ // [ROBUSTNESS] A valid English word with a preceding Russian word
+ {L"\x0437\x0434\x0440\x0430\x0432\x0441"
+ L"\x0442\x0432\x0443\x0439\x0442\x0435" L"hello", true, 0, 0},
+
+ // A valid English word with a following whitespace
+ {L"hello" L" ", true, 0, 0},
+ // A valid English word with a following no-break space
+ {L"hello" L"\xA0", true, 0, 0},
+ // A valid English word with a following ideographic space
+ {L"hello" L"\x3000", true, 0, 0},
+ // A valid English word with a following Chinese word
+ {L"hello" L"\x4F60\x597D", true, 0, 0},
+ // [ROBUSTNESS] A valid English word with a following Korean word
+ {L"hello" L"\xC548\xB155\xD558\xC138\xC694", true, 0, 0},
+ // A valid English word with a following Japanese word
+ {L"hello" L"\x3053\x3093\x306B\x3061\x306F", true, 0, 0},
+ // [ROBUSTNESS] A valid English word with a following Hindi word
+ {L"hello" L"\x0930\x093E\x091C\x0927\x093E\x0928", true, 0, 0},
+ // [ROBUSTNESS] A valid English word with two following Greek words
+ {L"hello"
+ L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5", true, 0, 0},
+ // [ROBUSTNESS] A valid English word with a following Russian word
+ {L"hello" L"\x0437\x0434\x0440\x0430\x0432\x0441"
+ L"\x0442\x0432\x0443\x0439\x0442\x0435", true, 0, 0},
+
+ // Two valid English words concatenated with a whitespace
+ {L"hello" L" " L"hello", true, 0, 0},
+ // Two valid English words concatenated with a no-break space
+ {L"hello" L"\xA0" L"hello", true, 0, 0},
+ // Two valid English words concatenated with an ideographic space
+ {L"hello" L"\x3000" L"hello", true, 0, 0},
+ // Two valid English words concatenated with a Chinese word
+ {L"hello" L"\x4F60\x597D" L"hello", true, 0, 0},
+ // [ROBUSTNESS] Two valid English words concatenated with a Korean word
+ {L"hello" L"\xC548\xB155\xD558\xC138\xC694" L"hello", true, 0, 0},
+ // Two valid English words concatenated with a Japanese word
+ {L"hello" L"\x3053\x3093\x306B\x3061\x306F" L"hello", true, 0, 0},
+ // [ROBUSTNESS] Two valid English words concatenated with a Hindi word
+ {L"hello" L"\x0930\x093E\x091C\x0927\x093E\x0928" L"hello" , true, 0, 0},
+ // [ROBUSTNESS] Two valid English words concatenated with two Greek words
+ {L"hello" L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5"
+ L"hello", true, 0, 0},
+ // [ROBUSTNESS] Two valid English words concatenated with a Russian word
+ {L"hello" L"\x0437\x0434\x0440\x0430\x0432\x0441"
+ L"\x0442\x0432\x0443\x0439\x0442\x0435" L"hello", true, 0, 0},
+ // [ROBUSTNESS] Two valid English words concatenated with a contraction
+ // character.
+ {L"hello:hello", true, 0, 0},
+
+ // An invalid English word
+ {L"ifmmp", false, 0, 5},
+ // An invalid English word "bffly" containing a Latin ligature 'ffl'
+ {L"b\xFB04y", false, 0, 3},
+ // An invalid English word "ifmmp" (fullwidth version)
+ {L"\xFF29\xFF46\xFF4D\xFF4D\xFF50", false, 0, 5},
+ // An invalid English contraction
+ {L"jtm'u", false, 0, 5},
+ // An invalid English word enclosed with underscores.
+ {L"_ifmmp_", false, 1, 5},
+
+ // An invalid English word with a preceding whitespace
+ {L" " L"ifmmp", false, 1, 5},
+ // An invalid English word with a preceding no-break space
+ {L"\xA0" L"ifmmp", false, 1, 5},
+ // An invalid English word with a preceding ideographic space
+ {L"\x3000" L"ifmmp", false, 1, 5},
+ // An invalid English word with a preceding Chinese word
+ {L"\x4F60\x597D" L"ifmmp", false, 2, 5},
+ // [ROBUSTNESS] An invalid English word with a preceding Korean word
+ {L"\xC548\xB155\xD558\xC138\xC694" L"ifmmp", false, 5, 5},
+ // An invalid English word with a preceding Japanese word
+ {L"\x3053\x3093\x306B\x3061\x306F" L"ifmmp", false, 5, 5},
+ // [ROBUSTNESS] An invalid English word with a preceding Hindi word
+ {L"\x0930\x093E\x091C\x0927\x093E\x0928" L"ifmmp", false, 6, 5},
+ // [ROBUSTNESS] An invalid English word with two preceding Greek words
+ {L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5"
+ L"ifmmp", false, 8, 5},
+ // [ROBUSTNESS] An invalid English word with a preceding Russian word
+ {L"\x0437\x0434\x0440\x0430\x0432\x0441"
+ L"\x0442\x0432\x0443\x0439\x0442\x0435" L"ifmmp", false, 12, 5},
+
+ // An invalid English word with a following whitespace
+ {L"ifmmp" L" ", false, 0, 5},
+ // An invalid English word with a following no-break space
+ {L"ifmmp" L"\xA0", false, 0, 5},
+ // An invalid English word with a following ideographic space
+ {L"ifmmp" L"\x3000", false, 0, 5},
+ // An invalid English word with a following Chinese word
+ {L"ifmmp" L"\x4F60\x597D", false, 0, 5},
+ // [ROBUSTNESS] An invalid English word with a following Korean word
+ {L"ifmmp" L"\xC548\xB155\xD558\xC138\xC694", false, 0, 5},
+ // An invalid English word with a following Japanese word
+ {L"ifmmp" L"\x3053\x3093\x306B\x3061\x306F", false, 0, 5},
+ // [ROBUSTNESS] An invalid English word with a following Hindi word
+ {L"ifmmp" L"\x0930\x093E\x091C\x0927\x093E\x0928", false, 0, 5},
+ // [ROBUSTNESS] An invalid English word with two following Greek words
+ {L"ifmmp"
+ L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5", false, 0, 5},
+ // [ROBUSTNESS] An invalid English word with a following Russian word
+ {L"ifmmp" L"\x0437\x0434\x0440\x0430\x0432\x0441"
+ L"\x0442\x0432\x0443\x0439\x0442\x0435", false, 0, 5},
+
+ // Two invalid English words concatenated with a whitespace
+ {L"ifmmp" L" " L"ifmmp", false, 0, 5},
+ // Two invalid English words concatenated with a no-break space
+ {L"ifmmp" L"\xA0" L"ifmmp", false, 0, 5},
+ // Two invalid English words concatenated with an ideographic space
+ {L"ifmmp" L"\x3000" L"ifmmp", false, 0, 5},
+ // Two invalid English words concatenated with a Chinese word
+ {L"ifmmp" L"\x4F60\x597D" L"ifmmp", false, 0, 5},
+ // [ROBUSTNESS] Two invalid English words concatenated with a Korean word
+ {L"ifmmp" L"\xC548\xB155\xD558\xC138\xC694" L"ifmmp", false, 0, 5},
+ // Two invalid English words concatenated with a Japanese word
+ {L"ifmmp" L"\x3053\x3093\x306B\x3061\x306F" L"ifmmp", false, 0, 5},
+ // [ROBUSTNESS] Two invalid English words concatenated with a Hindi word
+ {L"ifmmp" L"\x0930\x093E\x091C\x0927\x093E\x0928" L"ifmmp" , false, 0, 5},
+ // [ROBUSTNESS] Two invalid English words concatenated with two Greek words
+ {L"ifmmp" L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5"
+ L"ifmmp", false, 0, 5},
+ // [ROBUSTNESS] Two invalid English words concatenated with a Russian word
+ {L"ifmmp" L"\x0437\x0434\x0440\x0430\x0432\x0441"
+ L"\x0442\x0432\x0443\x0439\x0442\x0435" L"ifmmp", false, 0, 5},
+ // [ROBUSTNESS] Two invalid English words concatenated with a contraction
+ // character.
+ {L"ifmmp:ifmmp", false, 0, 11},
+ };
+
+ std::wstring hunspell_directory;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_APP_DICTIONARIES,
+ &hunspell_directory));
+
+ scoped_refptr<SpellChecker> spell_checker(new SpellChecker(
+ hunspell_directory, L"en-US", NULL));
+
+ for (int i = 0; i < arraysize(kTestCases); i++) {
+ size_t input_length = 0;
+ if (kTestCases[i].input != NULL) {
+ input_length = wcslen(kTestCases[i].input);
+ }
+ int misspelling_start;
+ int misspelling_length;
+ bool result = spell_checker->SpellCheckWord(kTestCases[i].input,
+ static_cast<int>(input_length),
+ &misspelling_start,
+ &misspelling_length, NULL);
+
+ EXPECT_EQ(result, kTestCases[i].expected_result);
+ EXPECT_EQ(misspelling_start, kTestCases[i].misspelling_start);
+ EXPECT_EQ(misspelling_length, kTestCases[i].misspelling_length);
+ }
+}
+
+
+TEST(SpellCheckTest, SpellCheckSuggestions_EN_US) {
+ static const struct {
+ // A string to be tested.
+ const wchar_t* input;
+ // An expected result for this test case.
+ // * true: the input string does not have any invalid words.
+ // * false: the input string has one or more invalid words.
+ bool expected_result;
+ // The position and the length of the first invalid word.
+ int misspelling_start;
+ int misspelling_length;
+
+ // A suggested word that should occur.
+ const wchar_t* suggested_word;
+ } kTestCases[] = { // A valid English word with a preceding whitespace
+ {L"ello", false, 0, 0, L"hello"},
+ {L"ello", false, 0, 0, L"cello"},
+ {L"wate", false, 0, 0, L"water"},
+ {L"wate", false, 0, 0, L"waste"},
+ {L"wate", false, 0, 0, L"sate"},
+ {L"wate", false, 0, 0, L"rate"},
+ {L"jum", false, 0, 0, L"jump"},
+ {L"jum", false, 0, 0, L"rum"},
+ {L"jum", false, 0, 0, L"sum"},
+ {L"jum", false, 0, 0, L"tum"},
+ // TODO (Sidchat): add many more examples.
+ };
+
+ std::wstring hunspell_directory;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_APP_DICTIONARIES,
+ &hunspell_directory));
+
+ scoped_refptr<SpellChecker> spell_checker(new SpellChecker(
+ hunspell_directory, L"en-US", NULL));
+
+ for (int i = 0; i < arraysize(kTestCases); i++) {
+ std::vector<std::wstring> suggestions;
+ size_t input_length = 0;
+ if (kTestCases[i].input != NULL) {
+ input_length = wcslen(kTestCases[i].input);
+ }
+ int misspelling_start;
+ int misspelling_length;
+ bool result = spell_checker->SpellCheckWord(kTestCases[i].input,
+ static_cast<int>(input_length),
+ &misspelling_start,
+ &misspelling_length,
+ &suggestions);
+
+ // Check for spelling.
+ EXPECT_EQ(result, kTestCases[i].expected_result);
+
+ // Check if the suggested words occur.
+ bool suggested_word_is_present = false;
+ for (int j=0; j < static_cast<int>(suggestions.size()); j++) {
+ if (suggestions.at(j).compare(kTestCases[i].suggested_word) == 0) {
+ suggested_word_is_present = true;
+ break;
+ }
+ }
+
+ EXPECT_TRUE(suggested_word_is_present);
+ }
+}
diff --git a/chrome/renderer/visitedlink_slave.cc b/chrome/renderer/visitedlink_slave.cc
new file mode 100644
index 0000000..80741e0
--- /dev/null
+++ b/chrome/renderer/visitedlink_slave.cc
@@ -0,0 +1,88 @@
+// Copyright 2008, 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 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.
+
+#include <windows.h>
+#include "base/logging.h"
+#include "base/shared_memory.h"
+#include "chrome/common/win_util.h"
+#include "chrome/renderer/visitedlink_slave.h"
+
+VisitedLinkSlave::VisitedLinkSlave() : shared_memory_(NULL) {
+}
+VisitedLinkSlave::~VisitedLinkSlave() {
+ FreeTable();
+}
+
+// This function's job is to initialize the table with the given
+// shared memory handle. This memory is mappend into the process.
+bool VisitedLinkSlave::Init(SharedMemoryHandle shared_memory) {
+ // since this function may be called again to change the table, we may need
+ // to free old objects
+ FreeTable();
+ DCHECK(shared_memory_ == NULL && hash_table_ == NULL);
+
+ // create the shared memory object
+ shared_memory_ = new SharedMemory(shared_memory, true);
+ if (!shared_memory_)
+ return false;
+
+ // map the header into our process so we can see how long the rest is,
+ // and set the salt
+ if (!shared_memory_->Map(sizeof(SharedHeader)))
+ return false;
+ SharedHeader* header =
+ static_cast<SharedHeader*>(shared_memory_->memory());
+ DCHECK(header);
+ int32 table_len = header->length;
+ memcpy(salt_, header->salt, sizeof(salt_));
+ shared_memory_->Unmap();
+
+ // now do the whole table because we know the length
+ if (!shared_memory_->Map(sizeof(SharedHeader) +
+ table_len * sizeof(Fingerprint))) {
+ shared_memory_->Close();
+ return false;
+ }
+
+ // commit the data
+ DCHECK(shared_memory_->memory());
+ hash_table_ = reinterpret_cast<Fingerprint*>(
+ static_cast<char*>(shared_memory_->memory()) + sizeof(SharedHeader));
+ table_length_ = table_len;
+ return true;
+}
+
+void VisitedLinkSlave::FreeTable() {
+ if (shared_memory_ ) {
+ delete shared_memory_;
+ shared_memory_ = NULL;
+ }
+ hash_table_ = NULL;
+ table_length_ = 0;
+}
diff --git a/chrome/renderer/visitedlink_slave.h b/chrome/renderer/visitedlink_slave.h
new file mode 100644
index 0000000..24c708e
--- /dev/null
+++ b/chrome/renderer/visitedlink_slave.h
@@ -0,0 +1,62 @@
+// Copyright 2008, 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 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.
+
+#ifndef CHROME_WIN_RENDERER_VISITEDLINK_SLAVE_H__
+#define CHROME_WIN_RENDERER_VISITEDLINK_SLAVE_H__
+
+#include <string>
+#include <windows.h>
+
+#include "base/shared_memory.h"
+#include "chrome/common/visitedlink_common.h"
+
+// Reads the link coloring database provided by the master. There can be any
+// number of slaves reading the same database.
+class VisitedLinkSlave : public VisitedLinkCommon
+{
+ public:
+ VisitedLinkSlave();
+ virtual ~VisitedLinkSlave();
+
+ // Called to initialize this object, nothing will work until this is called.
+ // It can also be called again at any time to update the table that we're
+ // using. The handle should be the handle generated by the VisitedLinkMaster.
+ // Returns true on success.
+ bool Init(SharedMemoryHandle shared_memory);
+
+ private:
+ void FreeTable();
+
+ // shared memory consists of a SharedHeader followed by the table
+ SharedMemory* shared_memory_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(VisitedLinkSlave);
+};
+
+#endif // WIN_RENDERER_VISITEDLINK_SLAVE_H__ \ No newline at end of file
diff --git a/chrome/renderer/webplugin_delegate_proxy.cc b/chrome/renderer/webplugin_delegate_proxy.cc
new file mode 100644
index 0000000..0dc1436
--- /dev/null
+++ b/chrome/renderer/webplugin_delegate_proxy.cc
@@ -0,0 +1,696 @@
+// Copyright 2008, 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 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.
+
+#include "chrome/renderer/webplugin_delegate_proxy.h"
+
+#include <atlbase.h>
+
+#include "generated_resources.h"
+
+#include "base/logging.h"
+#include "base/ref_counted.h"
+#include "base/string_util.h"
+#include "base/gfx/size.h"
+
+#include "chrome/app/chrome_dll_resource.h"
+#include "chrome/common/gfx/chrome_canvas.h"
+#include "chrome/common/gfx/emf.h"
+#include "chrome/common/l10n_util.h"
+#include "chrome/common/resource_bundle.h"
+#include "chrome/common/win_util.h"
+#include "chrome/plugin/npobject_proxy.h"
+#include "chrome/plugin/npobject_stub.h"
+#include "chrome/renderer/render_thread.h"
+#include "chrome/renderer/render_view.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/mime_util.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/webframe.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/webplugin.h"
+#include "webkit/glue/webview.h"
+
+// Proxy for WebPluginResourceClient. The object owns itself after creation,
+// deleting itself after its callback has been called.
+class ResourceClientProxy : public WebPluginResourceClient {
+ public:
+ ResourceClientProxy(PluginChannelHost* channel, int instance_id)
+ : channel_(channel), instance_id_(instance_id), resource_id_(0),
+ notify_needed_(false), notify_data_(NULL) {
+ }
+
+ ~ResourceClientProxy() {
+ }
+
+ void Initialize(int resource_id, const std::string &url, bool notify_needed,
+ void *notify_data) {
+ resource_id_ = resource_id;
+ url_ = url;
+ notify_needed_ = notify_needed;
+ notify_data_ = notify_data;
+
+ PluginMsg_URLRequestReply_Params params;
+ params.resource_id = resource_id;
+ params.url = url_;
+ params.notify_needed = notify_needed_;
+ params.notify_data = notify_data_;
+
+ channel_->Send(new PluginMsg_HandleURLRequestReply(instance_id_, params));
+ }
+
+ // PluginResourceClient implementation:
+ void WillSendRequest(const GURL& url) {
+ DCHECK(channel_ != NULL);
+ channel_->Send(new PluginMsg_WillSendRequest(instance_id_, resource_id_,
+ url));
+ }
+
+ void DidReceiveResponse(const std::string& mime_type,
+ const std::string& headers,
+ uint32 expected_length,
+ uint32 last_modified,
+ bool* cancel) {
+ DCHECK(channel_ != NULL);
+ PluginMsg_DidReceiveResponseParams params;
+ params.id = resource_id_;
+ params.mime_type = mime_type;
+ params.headers = headers;
+ params.expected_length = expected_length;
+ params.last_modified = last_modified;
+ // Grab a reference on the underlying channel so it does not get
+ // deleted from under us.
+ scoped_refptr<PluginChannelHost> channel_ref(channel_);
+ channel_->Send(new PluginMsg_DidReceiveResponse(instance_id_, params,
+ cancel));
+ }
+
+ void DidReceiveData(const char* buffer, int length) {
+ DCHECK(channel_ != NULL);
+ DCHECK(length > 0);
+ std::vector<char> data;
+ data.resize(static_cast<size_t>(length));
+ memcpy(&data.front(), buffer, length);
+ // Grab a reference on the underlying channel so it does not get
+ // deleted from under us.
+ scoped_refptr<PluginChannelHost> channel_ref(channel_);
+ channel_->Send(new PluginMsg_DidReceiveData(instance_id_, resource_id_,
+ data));
+ }
+
+ void DidFinishLoading() {
+ DCHECK(channel_ != NULL);
+ channel_->Send(new PluginMsg_DidFinishLoading(instance_id_, resource_id_));
+ channel_ = NULL;
+ MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+ }
+
+ void DidFail() {
+ DCHECK(channel_ != NULL);
+ channel_->Send(new PluginMsg_DidFail(instance_id_, resource_id_));
+ channel_ = NULL;
+ MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+ }
+
+ private:
+ int resource_id_;
+ int instance_id_;
+ scoped_refptr<PluginChannelHost> channel_;
+ std::string url_;
+ bool notify_needed_;
+ void* notify_data_;
+};
+
+WebPluginDelegateProxy* WebPluginDelegateProxy::Create(
+ const GURL& url,
+ const std::string& mime_type,
+ const std::string& clsid,
+ RenderView* render_view) {
+ return new WebPluginDelegateProxy(mime_type, clsid, render_view);
+}
+
+WebPluginDelegateProxy::WebPluginDelegateProxy(const std::string& mime_type,
+ const std::string& clsid,
+ RenderView* render_view)
+ : render_view_(render_view),
+ mime_type_(mime_type),
+ clsid_(clsid),
+ plugin_(NULL),
+ windowless_(false),
+ first_paint_(true),
+ npobject_(NULL),
+ send_deferred_update_geometry_(false),
+ visible_(false),
+ sad_plugin_(NULL),
+ window_script_object_(NULL),
+ modal_loop_pump_messages_event_(NULL) {
+}
+
+WebPluginDelegateProxy::~WebPluginDelegateProxy() {
+ if (npobject_)
+ NPN_ReleaseObject(npobject_);
+
+ if (window_script_object_) {
+ window_script_object_->set_proxy(NULL);
+ window_script_object_->set_invalid();
+ }
+
+ if (modal_loop_pump_messages_event_) {
+ CloseHandle(modal_loop_pump_messages_event_);
+ }
+}
+
+void WebPluginDelegateProxy::PluginDestroyed() {
+ plugin_ = NULL;
+
+ if (channel_host_) {
+ if (npobject_) {
+ // When we destroy the plugin instance, the NPObjectStub NULLs out its
+ // pointer to the npobject (see NPObjectStub::OnChannelError). Therefore,
+ // we release the object before destroying the instance to avoid leaking.
+ NPN_ReleaseObject(npobject_);
+ npobject_ = NULL;
+ }
+
+ channel_host_->RemoveRoute(instance_id_);
+ Send(new PluginMsg_DestroyInstance(instance_id_));
+ channel_host_ = NULL;
+ }
+ render_view_->PluginDestroyed(this);
+ delete this;
+}
+
+void WebPluginDelegateProxy::FlushGeometryUpdates() {
+ if (send_deferred_update_geometry_) {
+ send_deferred_update_geometry_ = false;
+ Send(new PluginMsg_UpdateGeometry(instance_id_,
+ plugin_rect_,
+ deferred_clip_rect_,
+ visible_));
+ }
+}
+
+bool WebPluginDelegateProxy::Initialize(const GURL& url, char** argn,
+ char** argv, int argc,
+ WebPlugin* plugin,
+ bool load_manually) {
+ std::wstring channel_name, plugin_path;
+ if (!RenderThread::current()->Send(new ViewHostMsg_OpenChannelToPlugin(
+ url, mime_type_, clsid_, webkit_glue::GetWebKitLocale(),
+ &channel_name, &plugin_path)))
+ return false;
+
+ MessageLoop* ipc_message_loop = RenderThread::current()->owner_loop();
+ scoped_refptr<PluginChannelHost> channel_host =
+ PluginChannelHost::GetPluginChannelHost(channel_name, ipc_message_loop);
+ if (!channel_host.get())
+ return false;
+
+ int instance_id;
+ bool result = channel_host->Send(new PluginMsg_CreateInstance(
+ mime_type_, &instance_id));
+ if (!result)
+ return false;
+
+ plugin_path_ = plugin_path;
+ channel_host_ = channel_host;
+ instance_id_ = instance_id;
+
+ channel_host_->AddRoute(instance_id_, this, false);
+
+ // Now tell the PluginInstance in the plugin process to initialize.
+ PluginMsg_Init_Params params;
+ params.containing_window = render_view_->host_window();
+ params.url = url;
+ for (int i = 0; i < argc; ++i) {
+ params.arg_names.push_back(argn[i]);
+ params.arg_values.push_back(argv[i]);
+ }
+ params.load_manually = load_manually;
+ params.modal_dialog_event = render_view_->modal_dialog_event();
+
+ plugin_ = plugin;
+
+ result = false;
+ IPC::Message* msg = new PluginMsg_Init(instance_id_, params, &result);
+ Send(msg);
+
+ return result;
+}
+
+bool WebPluginDelegateProxy::Send(IPC::Message* msg) {
+ if (!channel_host_) {
+ DLOG(WARNING) << "dropping message because channel host is null";
+ delete msg;
+ return false;
+ }
+
+ return channel_host_->Send(msg);
+}
+
+void WebPluginDelegateProxy::SendJavaScriptStream(const std::string& url,
+ const std::wstring& result,
+ bool success,
+ bool notify_needed,
+ int notify_data) {
+ PluginMsg_SendJavaScriptStream* msg =
+ new PluginMsg_SendJavaScriptStream(instance_id_, url, result,
+ success, notify_needed,
+ notify_data);
+ Send(msg);
+}
+
+void WebPluginDelegateProxy::DidReceiveManualResponse(
+ const std::string& url, const std::string& mime_type,
+ const std::string& headers, uint32 expected_length,
+ uint32 last_modified) {
+ PluginMsg_DidReceiveResponseParams params;
+ params.id = 0;
+ params.mime_type = mime_type;
+ params.headers = headers;
+ params.expected_length = expected_length;
+ params.last_modified = last_modified;
+ Send(new PluginMsg_DidReceiveManualResponse(instance_id_, url, params));
+}
+
+void WebPluginDelegateProxy::DidReceiveManualData(const char* buffer,
+ int length) {
+ DCHECK(length > 0);
+ std::vector<char> data;
+ data.resize(static_cast<size_t>(length));
+ memcpy(&data.front(), buffer, length);
+ Send(new PluginMsg_DidReceiveManualData(instance_id_, data));
+}
+
+void WebPluginDelegateProxy::DidFinishManualLoading() {
+ Send(new PluginMsg_DidFinishManualLoading(instance_id_));
+}
+
+void WebPluginDelegateProxy::DidManualLoadFail() {
+ Send(new PluginMsg_DidManualLoadFail(instance_id_));
+}
+
+std::wstring WebPluginDelegateProxy::GetPluginPath() {
+ return plugin_path_;
+}
+
+void WebPluginDelegateProxy::InstallMissingPlugin() {
+ Send(new PluginMsg_InstallMissingPlugin(instance_id_));
+}
+
+void WebPluginDelegateProxy::OnMessageReceived(const IPC::Message& msg) {
+ IPC_BEGIN_MESSAGE_MAP(WebPluginDelegateProxy, msg)
+ IPC_MESSAGE_HANDLER(PluginHostMsg_SetWindow, OnSetWindow)
+ IPC_MESSAGE_HANDLER(PluginHostMsg_CancelResource, OnCancelResource)
+ IPC_MESSAGE_HANDLER(PluginHostMsg_Invalidate, OnInvalidate)
+ IPC_MESSAGE_HANDLER(PluginHostMsg_InvalidateRect, OnInvalidateRect)
+ IPC_MESSAGE_HANDLER(PluginHostMsg_GetWindowScriptNPObject,
+ OnGetWindowScriptNPObject)
+ IPC_MESSAGE_HANDLER(PluginHostMsg_GetPluginElement,
+ OnGetPluginElement)
+ IPC_MESSAGE_HANDLER(PluginHostMsg_SetCookie, OnSetCookie)
+ IPC_MESSAGE_HANDLER(PluginHostMsg_GetCookies, OnGetCookies)
+ IPC_MESSAGE_HANDLER(PluginHostMsg_ShowModalHTMLDialog,
+ OnShowModalHTMLDialog)
+ IPC_MESSAGE_HANDLER(PluginHostMsg_MissingPluginStatus,
+ OnMissingPluginStatus)
+ IPC_MESSAGE_HANDLER(PluginHostMsg_URLRequest, OnHandleURLRequest)
+ IPC_MESSAGE_HANDLER(PluginHostMsg_GetCPBrowsingContext,
+ OnGetCPBrowsingContext)
+ IPC_MESSAGE_UNHANDLED_ERROR()
+ IPC_END_MESSAGE_MAP()
+}
+
+void WebPluginDelegateProxy::OnChannelError() {
+ OnInvalidate();
+ render_view_->PluginCrashed(plugin_path_);
+}
+
+void WebPluginDelegateProxy::UpdateGeometry(const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect,
+ bool visible) {
+ plugin_rect_ = window_rect;
+
+ if (windowless_) {
+ IPC::Message* msg = new PluginMsg_UpdateGeometry(
+ instance_id_, window_rect, clip_rect, visible);
+ msg->set_unblock(true);
+ Send(msg);
+ } else {
+ deferred_clip_rect_ = clip_rect;
+ visible_ = visible;
+ send_deferred_update_geometry_ = true;
+ }
+}
+
+void WebPluginDelegateProxy::Paint(HDC hdc, const gfx::Rect& damaged_rect) {
+ // If the plugin is no longer connected (channel crashed) draw a crashed
+ // plugin bitmap
+ if (!channel_host_->channel_valid()) {
+ PaintSadPlugin(hdc, damaged_rect);
+ return;
+ }
+
+ // Can't duplicate an HDC handle, so get all the parameters we need in
+ // order to recreate the same HDC in the plugin process.
+ PluginMsg_Paint_Params params;
+ HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
+ if (bitmap == NULL) {
+ NOTREACHED();
+ return;
+ }
+
+ DIBSECTION dibsection = { 0 };
+ int result = GetObject(bitmap, sizeof(dibsection), &dibsection);
+ if (!result) {
+ NOTREACHED();
+ return;
+ }
+
+ win_util::ScopedHRGN hrgn(CreateRectRgn(0, 0, 0, 0));
+ result = GetClipRgn(hdc, hrgn);
+ if (result == -1) {
+ NOTREACHED();
+ return;
+ }
+
+ params.size.SetSize(dibsection.dsBmih.biWidth, dibsection.dsBmih.biHeight);
+ if (result == 0) {
+ // No clipping region.
+ params.clip_rect.set_width(params.size.width());
+ params.clip_rect.set_height(params.size.height());
+ } else {
+ RECT clip_rect;
+ result = GetRgnBox(hrgn, &clip_rect);
+ DCHECK_NE(result, 0);
+ params.clip_rect = clip_rect;
+ }
+
+ if (!GetWorldTransform(hdc, &params.xf)) {
+ NOTREACHED();
+ return;
+ }
+
+ params.damaged_rect = damaged_rect;
+ params.shared_memory = dibsection.dshSection;
+
+ // Normal painting code path.
+ if (dibsection.dshSection) {
+ // No paint events for windowed plugins. However, if it is the first paint
+ // we don't know yet whether the plugin is windowless or not, so we have to
+ // send the event.
+ if (!windowless_ && !first_paint_) {
+ // TODO(maruel): That's not true for printing and thumbnail capture.
+ // We shall use PrintWindow() to draw the window.
+ return;
+ }
+ first_paint_ = false;
+
+ DCHECK(params.size.width());
+ DCHECK(params.size.height());
+ Send(new PluginMsg_Paint(instance_id_, params));
+ return;
+ }
+
+ params.size.SetSize(damaged_rect.width(), damaged_rect.height());
+ // Pass the window size instead.
+ if (!windowless_)
+ params.damaged_rect = plugin_rect_;
+
+ // When the thumbnail is painted or during printing, a shared memory handle
+ // isn't given to CreateDIBSection so we don't get one now.
+ size_t bytes = 0;
+ SharedMemoryHandle emf_buffer = NULL;
+ PluginMsg_PaintIntoSharedMemory* msg =
+ new PluginMsg_PaintIntoSharedMemory(instance_id_, params, &emf_buffer,
+ &bytes);
+ if (!Send(msg))
+ return;
+
+ if (!emf_buffer) {
+ NOTREACHED();
+ return;
+ }
+
+ // memory's destructor will automatically close emf_buffer.
+ SharedMemory memory(emf_buffer, true);
+ if (!memory.Map(bytes)) {
+ NOTREACHED();
+ return;
+ }
+
+ gfx::Emf emf;
+ if (!emf.CreateFromData(memory.memory(), bytes)) {
+ NOTREACHED();
+ return;
+ }
+ emf.Playback(hdc, NULL);
+}
+
+void WebPluginDelegateProxy::Print(HDC hdc) {
+ PluginMsg_PrintResponse_Params params = { 0 };
+ Send(new PluginMsg_Print(instance_id_, &params));
+
+ SharedMemory memory(params.shared_memory, true);
+ if (!memory.Map(params.size)) {
+ NOTREACHED();
+ return;
+ }
+
+ gfx::Emf emf;
+ if (!emf.CreateFromData(memory.memory(), params.size)) {
+ NOTREACHED();
+ return;
+ }
+ // Playback the buffer.
+ emf.Playback(hdc, NULL);
+}
+
+NPObject* WebPluginDelegateProxy::GetPluginScriptableObject() {
+ if (npobject_)
+ return NPN_RetainObject(npobject_);
+
+ int route_id = MSG_ROUTING_NONE;
+ void* npobject_ptr;
+ Send(new PluginMsg_GetPluginScriptableObject(
+ instance_id_, &route_id, &npobject_ptr));
+ if (route_id == MSG_ROUTING_NONE)
+ return NULL;
+
+ npobject_ = NPObjectProxy::Create(
+ channel_host_.get(), route_id, npobject_ptr, NULL);
+
+ return NPN_RetainObject(npobject_);
+}
+
+void WebPluginDelegateProxy::DidFinishLoadWithReason(NPReason reason) {
+ Send(new PluginMsg_DidFinishLoadWithReason(instance_id_, reason));
+}
+
+void WebPluginDelegateProxy::SetFocus() {
+ Send(new PluginMsg_SetFocus(instance_id_));
+}
+
+bool WebPluginDelegateProxy::HandleEvent(NPEvent* event, WebCursor* cursor) {
+ bool handled;
+ // A windowless plugin can enter a modal loop in the context of a
+ // NPP_HandleEvent call, in which case we need to pump messages to
+ // the plugin. We pass of the corresponding event handle to the
+ // plugin process, which is set if the plugin does enter a modal loop.
+ IPC::SyncMessage* message = new PluginMsg_HandleEvent(instance_id_,
+ *event, &handled,
+ cursor);
+ message->set_pump_messages_event(modal_loop_pump_messages_event_);
+ Send(message);
+ return handled;
+}
+
+int WebPluginDelegateProxy::GetProcessId() {
+ return channel_host_->peer_pid();
+}
+
+HWND WebPluginDelegateProxy::GetWindowHandle() {
+ NOTREACHED() << "GetWindowHandle can't be called on the proxy.";
+ return NULL;
+}
+
+void WebPluginDelegateProxy::OnSetWindow(
+ HWND window, HANDLE modal_loop_pump_messages_event) {
+ windowless_ = window == NULL;
+ if (plugin_)
+ plugin_->SetWindow(window, modal_loop_pump_messages_event);
+
+ modal_loop_pump_messages_event_ = modal_loop_pump_messages_event;
+}
+
+void WebPluginDelegateProxy::OnCancelResource(int id) {
+ if (plugin_)
+ plugin_->CancelResource(id);
+}
+
+void WebPluginDelegateProxy::OnInvalidate() {
+ if (plugin_)
+ plugin_->Invalidate();
+}
+
+void WebPluginDelegateProxy::OnInvalidateRect(const gfx::Rect& rect) {
+ if (plugin_)
+ plugin_->InvalidateRect(rect);
+}
+
+void WebPluginDelegateProxy::OnGetWindowScriptNPObject(
+ int route_id, bool* success, void** npobject_ptr) {
+ *success = false;
+ NPObject* npobject = NULL;
+ if (plugin_)
+ npobject = plugin_->GetWindowScriptNPObject();
+
+ if (!npobject)
+ return;
+
+ // The stub will delete itself when the proxy tells it that it's released, or
+ // otherwise when the channel is closed.
+ NPObjectStub* stub = new NPObjectStub(npobject, channel_host_.get(),
+ route_id);
+ window_script_object_ = stub;
+ window_script_object_->set_proxy(this);
+ *success = true;
+ *npobject_ptr = npobject;
+}
+
+void WebPluginDelegateProxy::OnGetPluginElement(
+ int route_id, bool* success, void** npobject_ptr) {
+ *success = false;
+ NPObject* npobject = NULL;
+ if (plugin_)
+ npobject = plugin_->GetPluginElement();
+ if (!npobject)
+ return;
+
+ // The stub will delete itself when the proxy tells it that it's released, or
+ // otherwise when the channel is closed.
+ NPObjectStub* stub = new NPObjectStub(npobject, channel_host_.get(),
+ route_id);
+ *success = true;
+ *npobject_ptr = npobject;
+}
+
+void WebPluginDelegateProxy::OnSetCookie(const GURL& url,
+ const GURL& policy_url,
+ const std::string& cookie) {
+ if (plugin_)
+ plugin_->SetCookie(url, policy_url, cookie);
+}
+
+void WebPluginDelegateProxy::OnGetCookies(const GURL& url,
+ const GURL& policy_url,
+ std::string* cookies) {
+ DCHECK(cookies);
+ if (plugin_)
+ *cookies = plugin_->GetCookies(url, policy_url);
+}
+
+void WebPluginDelegateProxy::OnShowModalHTMLDialog(
+ const GURL& url, int width, int height, const std::string& json_arguments,
+ std::string* json_retval) {
+ DCHECK(json_retval);
+ if (render_view_)
+ render_view_->ShowModalHTMLDialog(url, width, height, json_arguments,
+ json_retval);
+}
+
+void WebPluginDelegateProxy::OnMissingPluginStatus(int status) {
+ if (render_view_)
+ render_view_->OnMissingPluginStatus(this, status);
+}
+
+void WebPluginDelegateProxy::OnGetCPBrowsingContext(uint32* context) {
+ *context = render_view_ ? render_view_->GetCPBrowsingContext() : 0;
+}
+
+void WebPluginDelegateProxy::PaintSadPlugin(HDC hdc, const gfx::Rect& rect) {
+ const int width = plugin_rect_.width();
+ const int height = plugin_rect_.height();
+
+ ChromeCanvas canvas(width, height, false);
+ SkPaint paint;
+
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setColor(SK_ColorBLACK);
+ canvas.drawRectCoords(0, 0, SkIntToScalar(width), SkIntToScalar(height),
+ paint);
+
+ if (!sad_plugin_) {
+ sad_plugin_ = ResourceBundle::LoadBitmap(
+ _AtlBaseModule.GetResourceInstance(), IDR_CRASHED_PLUGIN);
+ }
+
+ if (sad_plugin_) {
+ canvas.DrawBitmapInt(*sad_plugin_,
+ std::max(0, (width - sad_plugin_->width())/2),
+ std::max(0, (height - sad_plugin_->height())/2));
+ }
+
+ canvas.getTopPlatformDevice().drawToHDC(
+ hdc, plugin_rect_.x(), plugin_rect_.y(), NULL);
+ return;
+}
+
+void WebPluginDelegateProxy::OnHandleURLRequest(
+ const PluginHostMsg_URLRequest_Params& params) {
+ const char* data = NULL;
+ if (params.buffer.size())
+ data = &params.buffer[0];
+
+ const char* target = NULL;
+ if (params.target.length())
+ target = params.target.c_str();
+
+ plugin_->HandleURLRequest(params.method.c_str(),
+ params.is_javascript_url, target,
+ static_cast<unsigned int>(params.buffer.size()),
+ data, params.is_file_data, params.notify,
+ params.url.c_str(), params.notify_data,
+ params.popups_allowed);
+}
+
+WebPluginResourceClient* WebPluginDelegateProxy::CreateResourceClient(
+ int resource_id, const std::string &url, bool notify_needed,
+ void *notify_data) {
+ ResourceClientProxy* proxy = new ResourceClientProxy(channel_host_,
+ instance_id_);
+ proxy->Initialize(resource_id, url, notify_needed, notify_data);
+ return proxy;
+}
+
+void WebPluginDelegateProxy::URLRequestRouted(const std::string& url,
+ bool notify_needed,
+ void* notify_data) {
+ Send(new PluginMsg_URLRequestRouted(instance_id_, url, notify_needed,
+ notify_data));
+}
diff --git a/chrome/renderer/webplugin_delegate_proxy.h b/chrome/renderer/webplugin_delegate_proxy.h
new file mode 100644
index 0000000..b13cc76
--- /dev/null
+++ b/chrome/renderer/webplugin_delegate_proxy.h
@@ -0,0 +1,175 @@
+// Copyright 2008, 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 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.
+
+#ifndef CHROME_RENDERER_WEBPLUGIN_DELEGATE_PROXY_H__
+#define CHROME_RENDERER_WEBPLUGIN_DELEGATE_PROXY_H__
+
+#include <set>
+#include <string>
+
+#include "base/gfx/rect.h"
+#include "base/ref_counted.h"
+#include "chrome/common/ipc_message.h"
+#include "chrome/common/plugin_messages.h"
+#include "chrome/plugin/npobject_stub.h"
+#include "chrome/renderer/plugin_channel_host.h"
+#include "webkit/glue/webplugin.h"
+#include "webkit/glue/webplugin_delegate.h"
+
+class GURL;
+struct PluginHostMsg_RouteToFrame_Params;
+class RenderView;
+class SkBitmap;
+
+// An implementation of WebPluginDelegate that proxies all calls to
+// the plugin process.
+class WebPluginDelegateProxy : public WebPluginDelegate,
+ public IPC::Channel::Listener,
+ public IPC::Message::Sender {
+ public:
+ static WebPluginDelegateProxy* Create(const GURL& url,
+ const std::string& mime_type,
+ const std::string& clsid,
+ RenderView* render_view);
+
+ // Called to drop our back-pointer to the containing RenderView.
+ void DropRenderView() { render_view_ = NULL; }
+
+ // Called to drop our pointer to the window script object.
+ void DropWindowScriptObject() { window_script_object_ = NULL; }
+
+ // Called to flush any deferred geometry changes to the plugin process.
+ virtual void FlushGeometryUpdates();
+
+ // WebPluginDelegate implementation:
+ virtual void PluginDestroyed();
+ virtual bool Initialize(const GURL& url, char** argn, char** argv, int argc,
+ WebPlugin* plugin, bool load_manually);
+ virtual void UpdateGeometry(const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect, bool visible);
+ virtual void Paint(HDC hdc, const gfx::Rect& rect);
+ virtual void Print(HDC hdc);
+ virtual NPObject* GetPluginScriptableObject();
+ virtual void DidFinishLoadWithReason(NPReason reason);
+ virtual void SetFocus();
+ virtual bool HandleEvent(NPEvent* event, WebCursor* cursor);
+ virtual int GetProcessId();
+ virtual HWND GetWindowHandle();
+
+ // IPC::Channel::Listener implementation:
+ virtual void OnMessageReceived(const IPC::Message& msg);
+ void OnChannelError();
+
+ // IPC::Message::Sender implementation:
+ virtual bool Send(IPC::Message* msg);
+
+ virtual void SendJavaScriptStream(const std::string& url,
+ const std::wstring& result,
+ bool success, bool notify_needed,
+ int notify_data);
+
+ virtual void DidReceiveManualResponse(const std::string& url,
+ const std::string& mime_type,
+ const std::string& headers,
+ uint32 expected_length,
+ uint32 last_modified);
+ virtual void DidReceiveManualData(const char* buffer, int length);
+ virtual void DidFinishManualLoading();
+ virtual void DidManualLoadFail();
+ virtual std::wstring GetPluginPath();
+ virtual void InstallMissingPlugin();
+ virtual WebPluginResourceClient* CreateResourceClient(int resource_id,
+ const std::string &url,
+ bool notify_needed,
+ void *notify_data);
+
+ // Notifies the delegate about a Get/Post URL request getting routed
+ virtual void URLRequestRouted(const std::string&url, bool notify_needed,
+ void* notify_data);
+
+ private:
+ WebPluginDelegateProxy(const std::string& mime_type,
+ const std::string& clsid,
+ RenderView* render_view);
+ ~WebPluginDelegateProxy();
+
+ // Message handlers for messages that proxy WebPlugin methods, which
+ // we translate into calls to the real WebPlugin.
+ void OnSetWindow(HWND window, HANDLE modal_loop_pump_messages_event);
+ void OnCompleteURL(const std::string& url_in, std::string* url_out,
+ bool* result);
+ void OnHandleURLRequest(const PluginHostMsg_URLRequest_Params& params);
+ void OnCancelResource(int id);
+ void OnInvalidate();
+ void OnInvalidateRect(const gfx::Rect& rect);
+ void OnGetWindowScriptNPObject(int route_id, bool* success, void** npobject_ptr);
+ void OnGetPluginElement(int route_id, bool* success, void** npobject_ptr);
+ void OnSetCookie(const GURL& url,
+ const GURL& policy_url,
+ const std::string& cookie);
+ void OnGetCookies(const GURL& url, const GURL& policy_url,
+ std::string* cookies);
+ void OnShowModalHTMLDialog(const GURL& url, int width, int height,
+ const std::string& json_arguments,
+ std::string* json_retval);
+ void OnMissingPluginStatus(int status);
+ void OnGetCPBrowsingContext(uint32* context);
+
+ // Draw a graphic indicating a crashed plugin.
+ void PaintSadPlugin(HDC hdc, const gfx::Rect& rect);
+
+ RenderView* render_view_;
+ WebPlugin* plugin_;
+ bool windowless_;
+ bool first_paint_;
+ scoped_refptr<PluginChannelHost> channel_host_;
+ std::string mime_type_;
+ std::string clsid_;
+ int instance_id_;
+ std::wstring plugin_path_;
+
+ gfx::Rect plugin_rect_;
+ gfx::Rect deferred_clip_rect_;
+ bool send_deferred_update_geometry_;
+ bool visible_;
+
+ NPObject* npobject_;
+ NPObjectStub* window_script_object_;
+
+ // Event passed in by the plugin process and is used to decide if
+ // messages need to be pumped in the NPP_HandleEvent sync call.
+ HANDLE modal_loop_pump_messages_event_;
+
+ // Bitmap for crashed plugin
+ SkBitmap* sad_plugin_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(WebPluginDelegateProxy);
+};
+
+#endif // #ifndef CHROME_RENDERER_WEBPLUGIN_DELEGATE_PROXY_H__