summaryrefslogtreecommitdiffstats
path: root/webkit/glue
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-27 00:20:51 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-27 00:20:51 +0000
commitf5b16fed647e941aa66933178da85db2860d639b (patch)
treef00e9856c04aad3b558a140955e7674add33f051 /webkit/glue
parent920c091ac3ee15079194c82ae8a7a18215f3f23c (diff)
downloadchromium_src-f5b16fed647e941aa66933178da85db2860d639b.zip
chromium_src-f5b16fed647e941aa66933178da85db2860d639b.tar.gz
chromium_src-f5b16fed647e941aa66933178da85db2860d639b.tar.bz2
Add webkit to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/glue')
-rw-r--r--webkit/glue/SConscript108
-rw-r--r--webkit/glue/alt_404_page_resource_fetcher.cc70
-rw-r--r--webkit/glue/alt_404_page_resource_fetcher.h79
-rw-r--r--webkit/glue/alt_error_page_resource_fetcher.cc78
-rw-r--r--webkit/glue/alt_error_page_resource_fetcher.h74
-rw-r--r--webkit/glue/autocomplete_input_listener.cc222
-rw-r--r--webkit/glue/autocomplete_input_listener.h241
-rw-r--r--webkit/glue/autocomplete_input_listener_unittest.cc200
-rw-r--r--webkit/glue/bookmarklet_unittest.cc84
-rw-r--r--webkit/glue/cache_manager.cc115
-rw-r--r--webkit/glue/cache_manager.h88
-rw-r--r--webkit/glue/chrome_client_impl.cc441
-rw-r--r--webkit/glue/chrome_client_impl.h137
-rw-r--r--webkit/glue/console_message_level.h40
-rw-r--r--webkit/glue/context_menu_client_impl.cc276
-rw-r--r--webkit/glue/context_menu_client_impl.h65
-rw-r--r--webkit/glue/context_menu_unittest.cc91
-rw-r--r--webkit/glue/context_node_types.h87
-rw-r--r--webkit/glue/cpp_binding_example.cc119
-rw-r--r--webkit/glue/cpp_binding_example.h100
-rw-r--r--webkit/glue/cpp_bound_class.cc279
-rw-r--r--webkit/glue/cpp_bound_class.h164
-rw-r--r--webkit/glue/cpp_bound_class_unittest.cc267
-rw-r--r--webkit/glue/cpp_variant.cc276
-rw-r--r--webkit/glue/cpp_variant.h128
-rw-r--r--webkit/glue/cpp_variant_unittest.cc457
-rw-r--r--webkit/glue/debugger.cc86
-rw-r--r--webkit/glue/debugger.h84
-rw-r--r--webkit/glue/dom_operations.cc791
-rw-r--r--webkit/glue/dom_operations.h205
-rw-r--r--webkit/glue/dom_operations_unittest.cc207
-rw-r--r--webkit/glue/dom_serializer.cc649
-rw-r--r--webkit/glue/dom_serializer.h196
-rw-r--r--webkit/glue/dom_serializer_delegate.h77
-rw-r--r--webkit/glue/dom_serializer_unittest.cc702
-rw-r--r--webkit/glue/dragclient_impl.cc107
-rw-r--r--webkit/glue/dragclient_impl.h79
-rw-r--r--webkit/glue/editor_client_impl.cc786
-rw-r--r--webkit/glue/editor_client_impl.h164
-rw-r--r--webkit/glue/entity_map.cc118
-rw-r--r--webkit/glue/entity_map.h53
-rw-r--r--webkit/glue/event_conversion.cc199
-rw-r--r--webkit/glue/event_conversion.h75
-rw-r--r--webkit/glue/feed_preview.cc105
-rw-r--r--webkit/glue/feed_preview.h79
-rw-r--r--webkit/glue/find_in_page_request.h55
-rw-r--r--webkit/glue/form_data.h51
-rw-r--r--webkit/glue/glue_serialize.cc385
-rw-r--r--webkit/glue/glue_serialize.h61
-rw-r--r--webkit/glue/glue_serialize_unittest.cc202
-rw-r--r--webkit/glue/glue_util.cc107
-rw-r--r--webkit/glue/glue_util.h59
-rw-r--r--webkit/glue/iframe_redirect_unittest.cc67
-rw-r--r--webkit/glue/image_decoder.cc71
-rw-r--r--webkit/glue/image_decoder.h63
-rw-r--r--webkit/glue/image_resource_fetcher.cc81
-rw-r--r--webkit/glue/image_resource_fetcher.h86
-rw-r--r--webkit/glue/inspector_client_impl.cc192
-rw-r--r--webkit/glue/inspector_client_impl.h70
-rw-r--r--webkit/glue/localized_strings.cc158
-rw-r--r--webkit/glue/mimetype_unittest.cc111
-rw-r--r--webkit/glue/multipart_response_delegate.cc255
-rw-r--r--webkit/glue/multipart_response_delegate.h139
-rw-r--r--webkit/glue/multipart_response_delegate_unittest.cc401
-rw-r--r--webkit/glue/password_autocomplete_listener.cc110
-rw-r--r--webkit/glue/password_autocomplete_listener.h73
-rw-r--r--webkit/glue/password_autocomplete_listener_unittest.cc274
-rw-r--r--webkit/glue/password_form.h171
-rw-r--r--webkit/glue/password_form_dom_manager.cc302
-rw-r--r--webkit/glue/password_form_dom_manager.h158
-rw-r--r--webkit/glue/plugins/mozilla_extensions.cc395
-rw-r--r--webkit/glue/plugins/mozilla_extensions.h124
-rw-r--r--webkit/glue/plugins/nphostapi.h302
-rw-r--r--webkit/glue/plugins/plugin_data_stream.cc68
-rw-r--r--webkit/glue/plugins/plugin_data_stream.h66
-rw-r--r--webkit/glue/plugins/plugin_host.cc877
-rw-r--r--webkit/glue/plugins/plugin_host.h107
-rw-r--r--webkit/glue/plugins/plugin_instance.cc463
-rw-r--r--webkit/glue/plugins/plugin_instance.h288
-rw-r--r--webkit/glue/plugins/plugin_lib.cc433
-rw-r--r--webkit/glue/plugins/plugin_lib.h163
-rw-r--r--webkit/glue/plugins/plugin_list.cc500
-rw-r--r--webkit/glue/plugins/plugin_list.h197
-rw-r--r--webkit/glue/plugins/plugin_stream.cc323
-rw-r--r--webkit/glue/plugins/plugin_stream.h136
-rw-r--r--webkit/glue/plugins/plugin_stream_url.cc104
-rw-r--r--webkit/glue/plugins/plugin_stream_url.h84
-rw-r--r--webkit/glue/plugins/plugin_string_stream.cc56
-rw-r--r--webkit/glue/plugins/plugin_string_stream.h62
-rw-r--r--webkit/glue/plugins/test/SConscript109
-rw-r--r--webkit/glue/plugins/test/npapi_constants.cc35
-rw-r--r--webkit/glue/plugins/test/npapi_constants.h44
-rw-r--r--webkit/glue/plugins/test/npapi_test.cc92
-rw-r--r--webkit/glue/plugins/test/npapi_test.def6
-rw-r--r--webkit/glue/plugins/test/npapi_test.rc102
-rw-r--r--webkit/glue/plugins/test/npapi_test_plugin.vcproj256
-rw-r--r--webkit/glue/plugins/test/plugin_arguments_test.cc92
-rw-r--r--webkit/glue/plugins/test/plugin_arguments_test.h69
-rw-r--r--webkit/glue/plugins/test/plugin_client.cc300
-rw-r--r--webkit/glue/plugins/test/plugin_client.h71
-rw-r--r--webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.cc67
-rw-r--r--webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.h56
-rw-r--r--webkit/glue/plugins/test/plugin_execute_script_delete_test.cc53
-rw-r--r--webkit/glue/plugins/test/plugin_execute_script_delete_test.h50
-rw-r--r--webkit/glue/plugins/test/plugin_get_javascript_url_test.cc134
-rw-r--r--webkit/glue/plugins/test/plugin_get_javascript_url_test.h63
-rw-r--r--webkit/glue/plugins/test/plugin_geturl_test.cc253
-rw-r--r--webkit/glue/plugins/test/plugin_geturl_test.h71
-rw-r--r--webkit/glue/plugins/test/plugin_new_fails_test.cc43
-rw-r--r--webkit/glue/plugins/test/plugin_new_fails_test.h46
-rw-r--r--webkit/glue/plugins/test/plugin_npobject_lifetime_test.cc189
-rw-r--r--webkit/glue/plugins/test/plugin_npobject_lifetime_test.h96
-rw-r--r--webkit/glue/plugins/test/plugin_npobject_proxy_test.cc68
-rw-r--r--webkit/glue/plugins/test/plugin_npobject_proxy_test.h53
-rw-r--r--webkit/glue/plugins/test/plugin_test.cc160
-rw-r--r--webkit/glue/plugins/test/plugin_test.h153
-rw-r--r--webkit/glue/plugins/test/plugin_window_size_test.cc67
-rw-r--r--webkit/glue/plugins/test/plugin_window_size_test.h50
-rw-r--r--webkit/glue/plugins/test/resource.h14
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl.cc1081
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl.h287
-rw-r--r--webkit/glue/regular_expression_unittest.cc118
-rw-r--r--webkit/glue/resource_fetcher.cc146
-rw-r--r--webkit/glue/resource_fetcher.h142
-rw-r--r--webkit/glue/resource_fetcher_unittest.cc210
-rw-r--r--webkit/glue/resource_handle_win.cc764
-rw-r--r--webkit/glue/resource_loader_bridge.h225
-rw-r--r--webkit/glue/resource_type.h61
-rw-r--r--webkit/glue/resources/README.txt50
-rw-r--r--webkit/glue/resources/aliasb.curbin0 -> 326 bytes
-rw-r--r--webkit/glue/resources/broken-image.gifbin0 -> 165 bytes
-rw-r--r--webkit/glue/resources/cell.curbin0 -> 326 bytes
-rw-r--r--webkit/glue/resources/col_resize.curbin0 -> 326 bytes
-rw-r--r--webkit/glue/resources/copy.curbin0 -> 326 bytes
-rw-r--r--webkit/glue/resources/dash.pngbin0 -> 122 bytes
-rw-r--r--webkit/glue/resources/feed.html18
-rw-r--r--webkit/glue/resources/row_resize.curbin0 -> 326 bytes
-rw-r--r--webkit/glue/resources/vertical_text.curbin0 -> 326 bytes
-rw-r--r--webkit/glue/resources/webkit_strings_ar.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_bg.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_ca.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_cs.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_da.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_de.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_el.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_en-GB.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_es-419.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_es.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_et.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_fi.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_fil.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_fr.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_he.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_hi.xtb36
-rw-r--r--webkit/glue/resources/webkit_strings_hr.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_hu.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_id.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_it.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_ja.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_ko.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_lt.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_lv.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_nl.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_no.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_pl.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_pt-BR.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_pt-PT.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_ro.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_ru.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_sk.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_sl.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_sr.xtb41
-rw-r--r--webkit/glue/resources/webkit_strings_sv.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_th.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_tr.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_uk.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_vi.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_zh-CN.xtb42
-rw-r--r--webkit/glue/resources/webkit_strings_zh-TW.xtb42
-rw-r--r--webkit/glue/resources/zoom_in.curbin0 -> 326 bytes
-rw-r--r--webkit/glue/resources/zoom_out.curbin0 -> 326 bytes
-rw-r--r--webkit/glue/searchable_form_data.cc420
-rw-r--r--webkit/glue/searchable_form_data.h84
-rw-r--r--webkit/glue/simple_clipboard_impl.cc93
-rw-r--r--webkit/glue/unittest_test_server.h72
-rw-r--r--webkit/glue/webcursor.cc168
-rw-r--r--webkit/glue/webcursor.h124
-rw-r--r--webkit/glue/webdatasource.h219
-rw-r--r--webkit/glue/webdatasource_impl.cc180
-rw-r--r--webkit/glue/webdatasource_impl.h95
-rw-r--r--webkit/glue/webdocumentloader_impl.cc67
-rw-r--r--webkit/glue/webdocumentloader_impl.h101
-rw-r--r--webkit/glue/webdropdata.cc55
-rw-r--r--webkit/glue/webdropdata.h74
-rw-r--r--webkit/glue/weberror.h44
-rw-r--r--webkit/glue/weberror_impl.cc55
-rw-r--r--webkit/glue/weberror_impl.h59
-rw-r--r--webkit/glue/webframe.h377
-rw-r--r--webkit/glue/webframe_impl.cc1723
-rw-r--r--webkit/glue/webframe_impl.h431
-rw-r--r--webkit/glue/webframeloaderclient_impl.cc1502
-rw-r--r--webkit/glue/webframeloaderclient_impl.h287
-rw-r--r--webkit/glue/webhistoryitem.h68
-rw-r--r--webkit/glue/webhistoryitem_impl.cc79
-rw-r--r--webkit/glue/webhistoryitem_impl.h73
-rw-r--r--webkit/glue/webinputevent.cc328
-rw-r--r--webkit/glue/webinputevent.h135
-rw-r--r--webkit/glue/webkit_glue.cc399
-rw-r--r--webkit/glue/webkit_glue.h303
-rw-r--r--webkit/glue/webkit_resources.h25
-rw-r--r--webkit/glue/webkit_resources.rc55
-rw-r--r--webkit/glue/webkit_strings.grd284
-rw-r--r--webkit/glue/webplugin.h170
-rw-r--r--webkit/glue/webplugin_delegate.h145
-rw-r--r--webkit/glue/webplugin_impl.cc1059
-rw-r--r--webkit/glue/webplugin_impl.h282
-rw-r--r--webkit/glue/webplugin_impl_unittest.cc225
-rw-r--r--webkit/glue/webpreferences.h103
-rw-r--r--webkit/glue/webresponse.h57
-rw-r--r--webkit/glue/webresponse_impl.h72
-rw-r--r--webkit/glue/webtextinput.h87
-rw-r--r--webkit/glue/webtextinput_impl.cc178
-rw-r--r--webkit/glue/webtextinput_impl.h81
-rw-r--r--webkit/glue/weburlrequest.h128
-rw-r--r--webkit/glue/weburlrequest_impl.cc145
-rw-r--r--webkit/glue/weburlrequest_impl.h87
-rw-r--r--webkit/glue/webview.h219
-rw-r--r--webkit/glue/webview_delegate.h731
-rw-r--r--webkit/glue/webview_impl.cc1468
-rw-r--r--webkit/glue/webview_impl.h331
-rw-r--r--webkit/glue/webwidget.h100
-rw-r--r--webkit/glue/webwidget_delegate.h111
-rw-r--r--webkit/glue/webwidget_impl.cc275
-rw-r--r--webkit/glue/webwidget_impl.h126
-rw-r--r--webkit/glue/window_open_disposition.h45
235 files changed, 39381 insertions, 0 deletions
diff --git a/webkit/glue/SConscript b/webkit/glue/SConscript
new file mode 100644
index 0000000..15f0557
--- /dev/null
+++ b/webkit/glue/SConscript
@@ -0,0 +1,108 @@
+# 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()
+
+env.Append(
+ CCFLAGS = [
+ '/TP',
+
+ '/WX',
+
+ '/wd4800',
+ '/wd4503',
+ '/wd4819',
+ ],
+)
+
+input_files = [
+ 'alt_404_page_resource_fetcher.cc',
+ 'autocomplete_input_listener.cc',
+ 'plugins/webplugin_delegate_impl.cc',
+ 'plugins/plugin_string_stream.cc',
+ 'plugins/plugin_stream_url.cc',
+ 'plugins/plugin_stream.cc',
+ 'plugins/plugin_list.cc',
+ 'plugins/plugin_lib.cc',
+ 'plugins/plugin_instance.cc',
+ 'plugins/plugin_host.cc',
+ 'plugins/plugin_data_stream.cc',
+ 'plugins/mozilla_extensions.cc',
+ 'webwidget_impl.cc',
+ 'webview_impl.cc',
+ 'weburlrequest_impl.cc',
+ 'webtextinput_impl.cc',
+ 'webplugin_impl.cc',
+ 'webkit_glue.cc',
+ 'webinputevent.cc',
+ 'webhistoryitem_impl.cc',
+ 'webframeloaderclient_impl.cc',
+ 'webframe_impl.cc',
+ 'weberror_impl.cc',
+ 'webdropdata.cc',
+ 'webdocumentloader_impl.cc',
+ 'webdatasource_impl.cc',
+ 'webcursor.cc',
+ 'simple_clipboard_impl.cc',
+ 'searchable_form_data.cc',
+ 'resource_handle_win.cc',
+ 'resource_fetcher.cc',
+ 'password_form_dom_manager.cc',
+ 'password_autocomplete_listener.cc',
+ 'multipart_response_delegate.cc',
+ 'localized_strings.cc',
+ 'inspector_client_impl.cc',
+ 'glue_util.cc',
+ 'glue_serialize.cc',
+ 'feed_preview.cc',
+ 'image_resource_fetcher.cc',
+ 'image_decoder.cc',
+ 'event_conversion.cc',
+ 'editor_client_impl.cc',
+ 'entity_map.cc',
+ 'dragclient_impl.cc',
+ 'dom_operations.cc',
+ 'dom_serializer.cc',
+ 'debugger.cc',
+ 'cpp_variant.cc',
+ 'cpp_bound_class.cc',
+ 'cpp_binding_example.cc',
+ 'context_menu_client_impl.cc',
+ 'chrome_client_impl.cc',
+ 'cache_manager.cc',
+ 'alt_error_page_resource_fetcher.cc',
+ '$PENDING_DIR/AccessibleBase.cpp',
+ '$PENDING_DIR/AccessibleDocument.cpp',
+]
+
+env.StaticLibrary('Glue', input_files)
+
+
diff --git a/webkit/glue/alt_404_page_resource_fetcher.cc b/webkit/glue/alt_404_page_resource_fetcher.cc
new file mode 100644
index 0000000..5b20187
--- /dev/null
+++ b/webkit/glue/alt_404_page_resource_fetcher.cc
@@ -0,0 +1,70 @@
+// 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 "config.h"
+
+#pragma warning(push, 0)
+#include "DocumentLoader.h"
+#pragma warning(pop)
+#undef LOG
+
+#include "webkit/glue/alt_404_page_resource_fetcher.h"
+
+#include "googleurl/src/gurl.h"
+#include "webkit/glue/webframeloaderclient_impl.h"
+
+using WebCore::DocumentLoader;
+
+// Number of seconds to wait for the alternate 404 page server. If it takes
+// too long, just show the original 404 page.
+static const double kDownloadTimeoutSec = 3.0;
+
+Alt404PageResourceFetcher::Alt404PageResourceFetcher(
+ WebFrameLoaderClient* webframeloaderclient,
+ WebCore::Frame* frame,
+ DocumentLoader* doc_loader,
+ const GURL& url)
+ : webframeloaderclient_(webframeloaderclient),
+ doc_loader_(doc_loader) {
+
+ fetcher_.reset(new ResourceFetcherWithTimeout(url, frame,
+ kDownloadTimeoutSec, this));
+}
+
+void Alt404PageResourceFetcher::OnURLFetchComplete(
+ const WebCore::ResourceResponse& response,
+ const std::string& data) {
+ if (response.httpStatusCode() == 200) {
+ // Only show server response if we got a 200.
+ webframeloaderclient_->Alt404PageFinished(doc_loader_.get(), data);
+ } else {
+ webframeloaderclient_->Alt404PageFinished(doc_loader_.get(), std::string());
+ }
+ doc_loader_ = NULL;
+}
diff --git a/webkit/glue/alt_404_page_resource_fetcher.h b/webkit/glue/alt_404_page_resource_fetcher.h
new file mode 100644
index 0000000..a30b294
--- /dev/null
+++ b/webkit/glue/alt_404_page_resource_fetcher.h
@@ -0,0 +1,79 @@
+// 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 WEBKIT_GLUE_ALT_404_PAGE_RESOURCE_HANDLE_CLIENT_H__
+#define WEBKIT_GLUE_ALT_404_PAGE_RESOURCE_HANDLE_CLIENT_H__
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+
+#include "webkit/glue/resource_fetcher.h"
+
+class WebFrameLoaderClient;
+class WebCore::DocumentLoader;
+class WebCore::Frame;
+class WebCore::ResourceResponse;
+
+// ResourceHandleClient implementation that is used for downloading alternate
+// 404 pages. Once downloading is done (or fails), the WebFrameLoaderClient is
+// notified.
+class Alt404PageResourceFetcher : public ResourceFetcher::Delegate {
+ public:
+ Alt404PageResourceFetcher(WebFrameLoaderClient* webframeloaderclient,
+ WebCore::Frame* frame,
+ WebCore::DocumentLoader* doc_loader,
+ const GURL& url);
+
+ virtual void OnURLFetchComplete(const WebCore::ResourceResponse& response,
+ const std::string& data);
+
+ // Stop any pending loads.
+ void Cancel() {
+ if (fetcher_.get())
+ fetcher_->Cancel();
+ }
+
+ private:
+ // Does the actual fetching.
+ scoped_ptr<ResourceFetcherWithTimeout> fetcher_;
+
+ // References to our owner which we call when finished.
+ WebFrameLoaderClient* webframeloaderclient_;
+
+ // The DocumentLoader associated with this load. If there's an error
+ // talking with the alt 404 page server, we need this to complete the
+ // original load.
+ RefPtr<WebCore::DocumentLoader> doc_loader_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(Alt404PageResourceFetcher);
+};
+
+#endif // WEBKIT_GLUE_ALT_404_PAGE_RESOURCE_HANDLE_CLIENT_H__
diff --git a/webkit/glue/alt_error_page_resource_fetcher.cc b/webkit/glue/alt_error_page_resource_fetcher.cc
new file mode 100644
index 0000000..b7b6c32
--- /dev/null
+++ b/webkit/glue/alt_error_page_resource_fetcher.cc
@@ -0,0 +1,78 @@
+// 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 "config.h"
+
+#pragma warning(push, 0)
+#include "ResourceResponse.h"
+#pragma warning(pop)
+#undef LOG
+
+#include "webkit/glue/alt_error_page_resource_fetcher.h"
+
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/webframe_impl.h"
+#include "webkit/glue/webview_delegate.h"
+#include "webkit/glue/webview.h"
+
+// Number of seconds to wait for the alternate error page server. If it takes
+// too long, just use the local error page.
+static const double kDownloadTimeoutSec = 3.0;
+
+AltErrorPageResourceFetcher::AltErrorPageResourceFetcher(
+ WebView* web_view,
+ const WebErrorImpl& web_error,
+ WebFrameImpl* web_frame,
+ const GURL& url)
+ : web_view_(web_view),
+ web_error_(web_error),
+ web_frame_(web_frame) {
+ failed_request_.reset(web_frame_->GetProvisionalDataSource()->
+ GetRequest().Clone());
+ fetcher_.reset(new ResourceFetcherWithTimeout(url, web_frame->frame(),
+ kDownloadTimeoutSec, this));
+}
+
+void AltErrorPageResourceFetcher::OnURLFetchComplete(
+ const WebCore::ResourceResponse& response,
+ const std::string& data) {
+ WebViewDelegate* delegate = web_view_->GetDelegate();
+ if (!delegate)
+ return;
+
+ if (response.httpStatusCode() == 200) {
+ // We successfully got a response from the alternate error page server, so
+ // load it.
+ delegate->LoadNavigationErrorPage(web_frame_, failed_request_.get(),
+ web_error_, data, true);
+ } else {
+ delegate->LoadNavigationErrorPage(web_frame_, failed_request_.get(),
+ web_error_, std::string(), true);
+ }
+}
diff --git a/webkit/glue/alt_error_page_resource_fetcher.h b/webkit/glue/alt_error_page_resource_fetcher.h
new file mode 100644
index 0000000..093f22b
--- /dev/null
+++ b/webkit/glue/alt_error_page_resource_fetcher.h
@@ -0,0 +1,74 @@
+// 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 WEBKIT_GLUE_ALT_ERROR_PAGE_RESOURCE_FETCHER_H__
+#define WEBKIT_GLUE_ALT_ERROR_PAGE_RESOURCE_FETCHER_H__
+
+#include <string>
+
+#pragma warning(push, 0)
+#include "Timer.h"
+#pragma warning(pop)
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "webkit/glue/resource_fetcher.h"
+#include "webkit/glue/weberror_impl.h"
+#include "webkit/glue/weburlrequest.h"
+
+class WebCore::ResourceResponse;
+class WebFrameImpl;
+class WebView;
+
+// Used for downloading alternate dns error pages. Once downloading is done
+// (or fails), the webview delegate is notified.
+class AltErrorPageResourceFetcher : public ResourceFetcher::Delegate {
+ public:
+ AltErrorPageResourceFetcher(WebView* web_view,
+ const WebErrorImpl& web_error,
+ WebFrameImpl* web_frame,
+ const GURL& url);
+
+ virtual void OnURLFetchComplete(const WebCore::ResourceResponse& response,
+ const std::string& data);
+
+ private:
+ // References to our owners
+ WebView* web_view_;
+ WebErrorImpl web_error_;
+ WebFrameImpl* web_frame_;
+ scoped_ptr<WebRequest> failed_request_;
+
+ // Does the actual fetching.
+ scoped_ptr<ResourceFetcherWithTimeout> fetcher_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(AltErrorPageResourceFetcher);
+};
+
+#endif // WEBKIT_GLUE_ALT_ERROR_PAGE_RESOURCE_FETCHER_H__
diff --git a/webkit/glue/autocomplete_input_listener.cc b/webkit/glue/autocomplete_input_listener.cc
new file mode 100644
index 0000000..508a461
--- /dev/null
+++ b/webkit/glue/autocomplete_input_listener.cc
@@ -0,0 +1,222 @@
+// 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 an abstract implementation of the inline autocomplete
+// infrastructure defined in autocomplete_input_listener.h.
+
+#include "webkit/glue/autocomplete_input_listener.h"
+
+#pragma warning(push, 0)
+#include "HTMLInputElement.h"
+#include "HTMLFormElement.h"
+#include "Document.h"
+#include "Frame.h"
+#include "Editor.h"
+#include "EventNames.h"
+#include "Event.h"
+#pragma warning(pop)
+
+#undef LOG
+
+#include "base/logging.h"
+#include "webkit/glue/editor_client_impl.h"
+#include "webkit/glue/glue_util.h"
+
+namespace webkit_glue {
+
+// Hack (1 of 2) for http://bugs.webkit.org/show_bug.cgi?id=16976. This bug
+// causes the caret position to be set after handling input events, which
+// trumps our modifications, so for now we tell the EditorClient to preserve
+// whatever selection set by our code.
+// TODO(timsteele): Remove this function altogether once bug is fixed.
+static void PreserveSelection(WebCore::HTMLInputElement* element) {
+ WebCore::EditorClient* ec =
+ element->form()->document()->frame()->editor()->client();
+ EditorClientImpl* client = static_cast<EditorClientImpl*>(ec);
+ client->PreserveSelection();
+}
+
+HTMLInputDelegate::HTMLInputDelegate(WebCore::HTMLInputElement* element)
+ : element_(element) {
+ // Reference the element for the lifetime of this delegate.
+ // e is NULL when testing.
+ if (element_)
+ element_->ref();
+}
+
+HTMLInputDelegate::~HTMLInputDelegate() {
+ if (element_)
+ element_->deref();
+}
+
+bool HTMLInputDelegate::IsCaretAtEndOfText(size_t input_length,
+ size_t previous_length) const {
+ // Hack 2 of 2 for http://bugs.webkit.org/show_bug.cgi?id=16976.
+ // TODO(timsteele): This check should only return early if
+ // !(selectionEnd == selectionStart == user_input.length()).
+ // However, because of webkit bug #16976 the caret is not properly moved
+ // until after the handlers have executed, so for now we do the following
+ // several checks. The first check handles the case webkit sets the End
+ // selection but not the Start selection correctly, and the second is for
+ // when webcore sets neither. This won't be perfect if the user moves the
+ // selection around during inline autocomplete, but for now its the
+ // friendliest behavior we can offer. Once the bug is fixed this method
+ // should no longer need the previous_length parameter.
+ if (((element_->selectionEnd() != element_->selectionStart() + 1) ||
+ (element_->selectionEnd() != input_length)) &&
+ ((element_->selectionEnd() != element_->selectionStart()) ||
+ (element_->selectionEnd() != previous_length))) {
+ return false;
+ }
+ return true;
+}
+
+void HTMLInputDelegate::SetValue(const std::wstring& value) {
+ element_->setValue(StdWStringToString(value));
+}
+
+std::wstring HTMLInputDelegate::GetValue() const {
+ return StringToStdWString(element_->value());
+}
+
+void HTMLInputDelegate::SetSelectionRange(size_t start, size_t end) {
+ element_->setSelectionRange(start, end);
+ // Hack, see comments for PreserveSelection().
+ PreserveSelection(element_);
+}
+
+void HTMLInputDelegate::OnFinishedAutocompleting() {
+ // This sets the input element to an autofilled state which will result in it
+ // having a yellow background.
+ element_->setAutofilled(true);
+ // Notify any changeEvent listeners.
+ element_->onChange();
+}
+
+AutocompleteInputListener::AutocompleteInputListener(
+ AutocompleteEditDelegate* edit_delegate)
+ : edit_delegate_(edit_delegate) {
+ previous_text_ = edit_delegate->GetValue();
+}
+// The following method is based on Firefox2 code in
+// toolkit/components/autocomplete/src/nsAutoCompleteController.cpp
+// Its license block is
+//
+ /* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Joe Hewitt <hewitt@netscape.com> (Original Author)
+ * Dean Tessman <dean_tessman@hotmail.com>
+ * Johnny Stenback <jst@mozilla.jstenback.com>
+ * Masayuki Nakano <masayuki@d-toybox.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+bool AutocompleteInputListener::ShouldInlineAutocomplete(
+ const std::wstring& user_input) {
+ size_t prev_length = previous_text_.length();
+ // The following are a bunch of early returns in cases we don't want to
+ // go through with inline autocomplete.
+
+ // Don't bother doing AC if nothing changed.
+ if (user_input.length() > 0 && (user_input == previous_text_))
+ return false;
+
+ // Did user backspace?
+ if ((user_input.length() < previous_text_.length()) &&
+ previous_text_.substr(0, user_input.length()) == user_input) {
+ previous_text_ = user_input;
+ return false;
+ }
+
+ // Remember the current input.
+ previous_text_ = user_input;
+
+ // Is search string empty?
+ if (user_input.empty())
+ return false;
+ return edit_delegate_->IsCaretAtEndOfText(user_input.length(), prev_length);
+}
+
+void AutocompleteInputListener::handleEvent(WebCore::Event* event,
+ bool /*is_window_event*/) {
+ const WebCore::AtomicString& webcore_type = event->type();
+ const std::wstring& user_input = edit_delegate_->GetValue();
+ if (webcore_type == WebCore::EventNames::DOMFocusOutEvent) {
+ OnBlur(user_input);
+ } else if (webcore_type == WebCore::EventNames::inputEvent) {
+ // Perform inline autocomplete if it is safe to do so.
+ if (ShouldInlineAutocomplete(user_input))
+ OnInlineAutocompleteNeeded(user_input);
+ } else {
+ NOTREACHED() << "unexpected EventName for autocomplete listener";
+ }
+}
+
+void AttachForInlineAutocomplete(
+ WebCore::HTMLInputElement* target,
+ AutocompleteInputListener* listener) {
+ target->addEventListener(WebCore::EventNames::DOMFocusOutEvent,
+ listener,
+ false);
+ target->addEventListener(WebCore::EventNames::inputEvent,
+ listener,
+ false);
+}
+
+} // webkit_glue
diff --git a/webkit/glue/autocomplete_input_listener.h b/webkit/glue/autocomplete_input_listener.h
new file mode 100644
index 0000000..72c2d16
--- /dev/null
+++ b/webkit/glue/autocomplete_input_listener.h
@@ -0,0 +1,241 @@
+// 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 defines some infrastructure to handle inline autocomplete of DOM
+// input elements.
+
+#ifndef WEBKIT_GLUE_AUTOCOMPLETE_INPUT_LISTENER_H__
+#define WEBKIT_GLUE_AUTOCOMPLETE_INPUT_LISTENER_H__
+
+#include <string>
+#include "config.h"
+
+#pragma warning(push, 0)
+#include "EventListener.h"
+#pragma warning(pop)
+#undef LOG
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+
+namespace WebCore {
+class AtomicString;
+class Event;
+class HTMLInputElement;
+}
+
+namespace webkit_glue {
+
+// This interface exposes all required functionality to perform inline
+// autocomplete on an edit field.
+class AutocompleteEditDelegate {
+ public:
+ // Virtual destructor so it is safe to delete through AutocompleteEditDelegate
+ // pointers.
+ virtual ~AutocompleteEditDelegate() {
+ }
+
+ // Whether or not the caret/selection is at the end of input.
+ // input_length gives the length of the user-typed input.
+ // previous_length is the length of the previously typed input.
+ virtual bool IsCaretAtEndOfText(size_t input_length,
+ size_t previous_length) const = 0;
+
+ // Set the selected range of text that should be displayed to the user
+ // to [start,end] (inclusive).
+ virtual void SetSelectionRange(size_t start, size_t end) = 0;
+
+ // Accessor/Mutator for the text value.
+ virtual void SetValue(const std::wstring& value) = 0;
+ virtual std::wstring GetValue() const = 0;
+
+ // Called when processing is finished.
+ virtual void OnFinishedAutocompleting() = 0;
+};
+
+// A proxy interface to a WebCore::HTMLInputElement for inline autocomplete.
+// This class is NOT used directly by the AutocompleteInputListener but
+// is included here since it is likely most listener implementations will
+// want to interface with an HTMLInputElement (see PasswordACListener).
+// The delegate does not own the WebCore element; it only interfaces it.
+class HTMLInputDelegate : public AutocompleteEditDelegate {
+ public:
+ explicit HTMLInputDelegate(WebCore::HTMLInputElement* element);
+ virtual ~HTMLInputDelegate();
+
+ // AutocompleteEditDelegate implementation.
+ virtual bool IsCaretAtEndOfText(size_t input_length,
+ size_t previous_length) const;
+ virtual void SetValue(const std::wstring& value);
+ virtual std::wstring GetValue() const;
+ virtual void SetSelectionRange(size_t start, size_t end);
+ virtual void OnFinishedAutocompleting();
+
+ private:
+ // The underlying DOM element we're wrapping. We reference the
+ // underlying HTMLInputElement for its lifetime to ensure it does not get
+ // freed by WebCore while in use by the delegate instance.
+ WebCore::HTMLInputElement* element_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(HTMLInputDelegate);
+};
+
+// Reasons for attaching to DOM directly rather than using EditorClient API:
+// 1. Since we don't need to stop listening until the DOM node is unloaded,
+// it makes sense to use an object owned by the DOM node itself. Attaching
+// as a listener gives you this for free (nodes cleanup their listeners
+// upon destruction).
+// 2. It allows fine-grained control when the popup/down is implemented
+// in handling key events / selecting elements.
+//
+// Note: The element an AutocompleteInputListener is attached to is kept
+// separate from the element it explicitly interacts with (via the
+// AutocompleteEditDelegate API) so that the listeners are effectively
+// decoupled from HTMLInputElement; which is great when it comes time
+// for testing. The listeners can be constructed using only the delegates,
+// and events can be manually fired to test specific behaviour.
+//
+class AutocompleteInputListener : public WebCore::EventListener {
+ public:
+ // Construct a listener with access to an edit field (i.e an HTMLInputElement)
+ // through a delegate, so that it can obtain and set values needed for
+ // autocomplete. See the above Note which explains why the edit_delegate it
+ // is handed here is not necessarily the node it is attached to as an
+ // EventListener. This object takes ownership of its edit_delegate.
+ explicit AutocompleteInputListener(AutocompleteEditDelegate* edit_delegate);
+
+ virtual ~AutocompleteInputListener() {
+ }
+
+ // EventListener implementation. Code that is common to inline autocomplete,
+ // such as deciding whether or not it is safe to perform it, is refactored
+ // into this method and the appropriate delegate method is invoked.
+ virtual void handleEvent(WebCore::Event* event, bool is_window_event);
+
+ // Subclasses need only implement the following two methods. They could
+ // be declared protected but are left public to be invoked by testing.
+
+ // OnBlur: DOMFocusOutEvent occured, means one of two things.
+ // 1. The user removed focus from the text field
+ // either by tabbing out or clicking;
+ // 2. The page is being destroyed (e.g user closed the tab)
+ virtual void OnBlur(const std::wstring& user_input) = 0;
+
+ // This method is called when there was a user-initiated text delta in
+ // the edit field that now needs some inline autocompletion.
+ // ShouldInlineAutocomplete gives the precondition for invoking this method.
+ virtual void OnInlineAutocompleteNeeded(const std::wstring& user_input) = 0;
+
+ protected:
+ // Access and modify the edit field only via the AutocompleteEditDelegate API.
+ AutocompleteEditDelegate* edit_delegate() { return edit_delegate_.get(); }
+
+ private:
+ // Determines, based on current state (previous_text_) and user input,
+ // whether or not it is a good idea to attempt inline autocomplete.
+ //
+ // This method is based on firefox2 code in
+ // toolkit/components/autocomplete/src/nsAutoCompleteController.cpp
+ // Its license block is:
+ /* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Joe Hewitt <hewitt@netscape.com> (Original Author)
+ * Dean Tessman <dean_tessman@hotmail.com>
+ * Johnny Stenback <jst@mozilla.jstenback.com>
+ * Masayuki Nakano <masayuki@d-toybox.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+ // The semantics of deciding whether or not the field is in a inline-
+ // autocomplete-healthy state are summarized:
+ // 1. The text is not identical to the text on the previous input event.
+ // 2. This is not the result of a backspace.
+ // 3. The text is not empty.
+ // 4. The caret is at the end of the textbox.
+ // TODO(timsteele): Examine autocomplete_edit.cc in the browser/ code and
+ // make sure to capture all common exclusion cases here.
+ bool ShouldInlineAutocomplete(const std::wstring& user_input);
+
+ // For testability, the AutocompleteEditDelegate API is used to decouple
+ // AutocompleteInputListeners from underlying HTMLInputElements. This
+ // allows testcases to mock delegates and test the autocomplete code without
+ // a real underlying DOM.
+ scoped_ptr<AutocompleteEditDelegate> edit_delegate_;
+
+ // Stores the text across input events during inline autocomplete.
+ std::wstring previous_text_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(AutocompleteInputListener);
+};
+
+// Attach the listener as an EventListener to basic events required
+// to handle inline autocomplete (and blur events for tab/click-out).
+// Attaching to the WebCore element effectively transfers ownership of
+// the listener objects. When WebCore is tearing down the document,
+// any attached listeners are destroyed.
+// See Document::removeAllEventListenersFromAllNodes which is called by
+// FrameLoader::stopLoading. Also, there is no need for matching calls to
+// removeEventListener because the simplest and most convienient thing to do
+// for autocompletion is to stop listening once the element is destroyed.
+void AttachForInlineAutocomplete(WebCore::HTMLInputElement* target,
+ AutocompleteInputListener* listener);
+
+} // webkit_glue
+
+#endif // WEBKIT_GLUE_AUTOCOMPLETE_INPUT_LISTENER_H__
diff --git a/webkit/glue/autocomplete_input_listener_unittest.cc b/webkit/glue/autocomplete_input_listener_unittest.cc
new file mode 100644
index 0000000..6c699a2
--- /dev/null
+++ b/webkit/glue/autocomplete_input_listener_unittest.cc
@@ -0,0 +1,200 @@
+// 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.
+//
+// The DomAutocompleteTests in this file are responsible for ensuring the
+// abstract dom autocomplete framework is correctly responding to events and
+// delegating to appropriate places. This means concrete implementations should
+// focus only on testing the code actually written for that implementation and
+// those tests should be completely decoupled from WebCore::Event.
+
+#include <string>
+
+#include "config.h"
+#pragma warning(push, 0)
+#include "HTMLInputElement.h"
+#include "HTMLFormElement.h"
+#include "Document.h"
+#include "Frame.h"
+#include "Editor.h"
+#include "EventNames.h"
+#include "Event.h"
+#include "EventListener.h"
+#pragma warning(pop)
+
+#undef LOG
+
+#include "webkit/glue/autocomplete_input_listener.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using webkit_glue::AutocompleteInputListener;
+using webkit_glue::AutocompleteEditDelegate;
+
+class TestAutocompleteEditDelegate : public AutocompleteEditDelegate {
+ public:
+ TestAutocompleteEditDelegate() : caret_at_end_(false) {
+ }
+
+ virtual bool IsCaretAtEndOfText(size_t input_length,
+ size_t prev_length) const {
+ return caret_at_end_;
+ }
+
+ void SetCaretAtEnd(bool caret_at_end) {
+ caret_at_end_ = caret_at_end;
+ }
+
+ virtual void SetSelectionRange(size_t start, size_t end) {
+ }
+
+ virtual void SetValue(const std::wstring& value) {
+ value_ = value;
+ }
+
+ virtual std::wstring GetValue() const {
+ return value_;
+ }
+
+ virtual void OnFinishedAutocompleting() {
+ }
+
+ void ResetTestState() {
+ caret_at_end_ = false;
+ value_.clear();
+ }
+
+ private:
+ bool caret_at_end_;
+ std::wstring value_;
+};
+
+class TestAutocompleteInputListener : public AutocompleteInputListener {
+ public:
+ TestAutocompleteInputListener(AutocompleteEditDelegate* d)
+ : blurred_(false),
+ did_request_inline_autocomplete_(false),
+ AutocompleteInputListener(d) {
+ }
+
+ void ResetTestState() {
+ blurred_ = false;
+ did_request_inline_autocomplete_ = false;
+ }
+
+ bool blurred() const { return blurred_; }
+ bool did_request_inline_autocomplete() const {
+ return did_request_inline_autocomplete_;
+ }
+
+ virtual void OnBlur(const std::wstring& user_input) {
+ blurred_ = true;
+ }
+ virtual void OnInlineAutocompleteNeeded(const std::wstring& user_input) {
+ did_request_inline_autocomplete_ = true;
+ }
+
+ private:
+ bool blurred_;
+ bool did_request_inline_autocomplete_;
+};
+
+namespace {
+class DomAutocompleteTests : public testing::Test {
+ public:
+ void SetUp() {
+ WebCore::EventNames::init();
+ }
+
+ void FireAndHandleInputEvent(AutocompleteInputListener* listener) {
+ WebCore::Event event(WebCore::EventNames::inputEvent, false, false);
+ listener->handleEvent(&event, false);
+ }
+
+ void SimulateTypedInput(TestAutocompleteEditDelegate* delegate,
+ AutocompleteInputListener* listener,
+ const std::wstring& new_input) {
+ delegate->SetValue(new_input);
+ delegate->SetCaretAtEnd(true);
+ FireAndHandleInputEvent(listener);
+ }
+};
+} // namespace
+
+TEST_F(DomAutocompleteTests, OnBlur) {
+ // Simulate a blur event and ensure it is properly dispatched.
+ // Listener takes ownership of its delegate.
+ TestAutocompleteInputListener listener(new TestAutocompleteEditDelegate());
+ WebCore::Event event(WebCore::EventNames::DOMFocusOutEvent, false, false);
+ listener.handleEvent(&event, false);
+ EXPECT_TRUE(listener.blurred());
+}
+
+TEST_F(DomAutocompleteTests, InlineAutocompleteTriggeredByInputEvent) {
+ // Set up the edit delegate, assuming the field was initially empty.
+ TestAutocompleteEditDelegate* delegate = new TestAutocompleteEditDelegate();
+ TestAutocompleteInputListener listener(delegate);
+
+ // Simulate an inputEvent by setting the value and artificially firing evt.
+ // The user typed 'g'.
+ SimulateTypedInput(delegate, &listener, L"g");
+ EXPECT_TRUE(listener.did_request_inline_autocomplete());
+}
+
+TEST_F(DomAutocompleteTests, InlineAutocompleteHeuristics) {
+ TestAutocompleteEditDelegate* delegate = new TestAutocompleteEditDelegate();
+ TestAutocompleteInputListener listener(delegate);
+
+ // Simulate a user entering some text, and then backspacing to remove
+ // a character.
+ SimulateTypedInput(delegate, &listener, L"g");
+ EXPECT_TRUE(listener.did_request_inline_autocomplete());
+ listener.ResetTestState();
+
+ SimulateTypedInput(delegate, &listener, L"go");
+ EXPECT_TRUE(listener.did_request_inline_autocomplete());
+ listener.ResetTestState();
+
+ SimulateTypedInput(delegate, &listener, L"g");
+ EXPECT_FALSE(listener.did_request_inline_autocomplete());
+ listener.ResetTestState();
+
+ // Now simulate the user moving the cursor to a position other than the end,
+ // and adding text.
+ delegate->SetCaretAtEnd(false);
+ delegate->SetValue(L"og");
+ FireAndHandleInputEvent(&listener);
+ EXPECT_FALSE(listener.did_request_inline_autocomplete());
+ listener.ResetTestState();
+
+ // Test that same input doesn't trigger autocomplete.
+ delegate->SetCaretAtEnd(true);
+ delegate->SetValue(L"og");
+ FireAndHandleInputEvent(&listener);
+ EXPECT_FALSE(listener.did_request_inline_autocomplete());
+ listener.ResetTestState();
+}
diff --git a/webkit/glue/bookmarklet_unittest.cc b/webkit/glue/bookmarklet_unittest.cc
new file mode 100644
index 0000000..cadff00
--- /dev/null
+++ b/webkit/glue/bookmarklet_unittest.cc
@@ -0,0 +1,84 @@
+// 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 "config.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "base/file_util.h"
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "base/string_util.h"
+#include "webkit/tools/test_shell/test_shell_test.h"
+
+namespace {
+
+class BookmarkletTest : public TestShellTest {
+ public:
+ virtual void SetUp() {
+ TestShellTest::SetUp();
+
+ test_shell_->LoadURL(L"data:text/html,start page");
+ test_shell_->WaitTestFinished();
+ }
+};
+
+}
+
+TEST_F(BookmarkletTest, Redirect) {
+ test_shell_->LoadURL(L"javascript:location.href='data:text/plain,SUCCESS'");
+ test_shell_->WaitTestFinished();
+ std::wstring text = test_shell_->GetDocumentText();
+ EXPECT_EQ(L"SUCCESS", text);
+}
+
+TEST_F(BookmarkletTest, NonEmptyResult) {
+ test_shell_->LoadURL(L"javascript:false");
+ MessageLoop::current()->Quit();
+ MessageLoop::current()->Run();
+ std::wstring text = test_shell_->GetDocumentText();
+ EXPECT_EQ(L"false", text);
+
+ test_shell_->LoadURL(L"javascript:'hello world'");
+ MessageLoop::current()->Quit();
+ MessageLoop::current()->Run();
+ text = test_shell_->GetDocumentText();
+ EXPECT_EQ(L"hello world", text);
+}
+
+TEST_F(BookmarkletTest, DocumentWrite) {
+ test_shell_->LoadURL(
+ L"javascript:document.open();"
+ L"document.write('hello world');"
+ L"document.close()");
+ MessageLoop::current()->Quit();
+ MessageLoop::current()->Run();
+ std::wstring text = test_shell_->GetDocumentText();
+ EXPECT_EQ(L"hello world", text);
+}
diff --git a/webkit/glue/cache_manager.cc b/webkit/glue/cache_manager.cc
new file mode 100644
index 0000000..df35b03
--- /dev/null
+++ b/webkit/glue/cache_manager.cc
@@ -0,0 +1,115 @@
+// 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 "config.h"
+
+#pragma warning(push, 0)
+// Instead of providing accessors, we make all members of Cache public.
+// This will make it easier to track WebKit changes to the Cache class.
+#define private public
+#include "Cache.h"
+#undef private
+#pragma warning(pop)
+
+#undef LOG
+#include "base/logging.h"
+#include "webkit/glue/cache_manager.h"
+
+namespace {
+
+// A helper method for coverting a WebCore::Cache::TypeStatistic to a
+// CacheManager::ResourceTypeStat.
+CacheManager::ResourceTypeStat TypeStatisticToResourceTypeStat(
+ const WebCore::Cache::TypeStatistic& in_stat) {
+ CacheManager::ResourceTypeStat stat;
+ stat.count = static_cast<size_t>(in_stat.count);
+ stat.size = static_cast<size_t>(in_stat.size);
+ stat.live_size = static_cast<size_t>(in_stat.liveSize);
+ stat.decoded_size = static_cast<size_t>(in_stat.decodedSize);
+ return stat;
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+// CacheManager implementation
+
+CacheManager::CacheManager() {
+}
+
+CacheManager::~CacheManager() {
+}
+
+// static
+void CacheManager::GetUsageStats(UsageStats* result) {
+ DCHECK(result);
+
+ WebCore::Cache* cache = WebCore::cache();
+
+ if (cache) {
+ result->min_dead_capacity = cache->m_minDeadCapacity;
+ result->max_dead_capacity = cache->m_maxDeadCapacity;
+ result->capacity = cache->m_capacity;
+ result->live_size = cache->m_liveSize;
+ result->dead_size = cache->m_deadSize;
+ } else {
+ memset(result, 0, sizeof(UsageStats));
+ }
+}
+
+// static
+void CacheManager::SetCapacities(size_t min_dead_capacity,
+ size_t max_dead_capacity,
+ size_t capacity) {
+ WebCore::Cache* cache = WebCore::cache();
+
+ if (cache) {
+ cache->setCapacities(static_cast<unsigned int>(min_dead_capacity),
+ static_cast<unsigned int>(max_dead_capacity),
+ static_cast<unsigned int>(capacity));
+ }
+}
+
+// static
+void CacheManager::GetResourceTypeStats(
+ CacheManager::ResourceTypeStats* result) {
+ WebCore::Cache* cache = WebCore::cache();
+ if (cache) {
+ WebCore::Cache::Statistics in_stats = cache->getStatistics();
+ result->images = TypeStatisticToResourceTypeStat(in_stats.images);
+ result->css_stylesheets = TypeStatisticToResourceTypeStat(
+ in_stats.cssStyleSheets);
+ result->scripts = TypeStatisticToResourceTypeStat(in_stats.scripts);
+ result->xsl_stylesheets = TypeStatisticToResourceTypeStat(
+ in_stats.xslStyleSheets);
+ result->fonts = TypeStatisticToResourceTypeStat(in_stats.fonts);
+ } else {
+ memset(result, 0, sizeof(CacheManager::ResourceTypeStats));
+ }
+}
diff --git a/webkit/glue/cache_manager.h b/webkit/glue/cache_manager.h
new file mode 100644
index 0000000..643b40a
--- /dev/null
+++ b/webkit/glue/cache_manager.h
@@ -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.
+
+#ifndef WEBKIT_GLUE_CACHE_MANAGER_H__
+#define WEBKIT_GLUE_CACHE_MANAGER_H__
+
+#include <stddef.h>
+
+class CacheManager {
+ public:
+ struct UsageStats {
+ public:
+ // Capacities.
+ size_t min_dead_capacity;
+ size_t max_dead_capacity;
+ size_t capacity;
+ // Utilization.
+ size_t live_size;
+ size_t dead_size;
+ };
+
+ // A struct mirroring WebCore::Cache::TypeStatistic that we can send to the
+ // browser process.
+ struct ResourceTypeStat {
+ size_t count;
+ size_t size;
+ size_t live_size;
+ size_t decoded_size;
+ ResourceTypeStat()
+ : count(0), size(0), live_size(0), decoded_size(0) {}
+ };
+
+ // A struct mirroring WebCore::Cache::Statistics that we can send to the
+ // browser process.
+ struct ResourceTypeStats {
+ ResourceTypeStat images;
+ ResourceTypeStat css_stylesheets;
+ ResourceTypeStat scripts;
+ ResourceTypeStat xsl_stylesheets;
+ ResourceTypeStat fonts;
+ };
+
+ // Gets the usage statistics from the WebCore cache
+ static void GetUsageStats(UsageStats* result);
+
+ // Sets the capacities of the WebCore cache, evicting objects as necessary
+ static void SetCapacities(size_t min_dead_capacity,
+ size_t max_dead_capacity,
+ size_t capacity);
+
+ // Get usage stats about the WebCore cache.
+ static void GetResourceTypeStats(ResourceTypeStats* result);
+
+ private:
+ // This class only has static methods. It can't be instantiated
+ CacheManager();
+ ~CacheManager();
+
+ DISALLOW_EVIL_CONSTRUCTORS(CacheManager);
+};
+
+#endif // WEBKIT_GLUE_CACHE_MANAGER_H__
diff --git a/webkit/glue/chrome_client_impl.cc b/webkit/glue/chrome_client_impl.cc
new file mode 100644
index 0000000..20109b9
--- /dev/null
+++ b/webkit/glue/chrome_client_impl.cc
@@ -0,0 +1,441 @@
+// 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 "config.h"
+
+#pragma warning(push, 0)
+#include "FloatRect.h"
+#include "FileChooser.h"
+#include "FrameLoadRequest.h"
+#include "FrameView.h"
+#include "HitTestResult.h"
+#include "IntRect.h"
+#include "Page.h"
+#include "WindowFeatures.h"
+#pragma warning(pop)
+#undef LOG
+
+#include "webkit/glue/chrome_client_impl.h"
+
+#include "base/gfx/rect.h"
+#include "googleurl/src/gurl.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/webframe_impl.h"
+#include "webkit/glue/webinputevent.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/webview_delegate.h"
+#include "webkit/glue/webview_impl.h"
+
+struct IWebURLResponse;
+
+// Callback class that's given to the WebViewDelegate during a file choose
+// operation.
+class WebFileChooserCallbackImpl : public WebFileChooserCallback {
+ public:
+ WebFileChooserCallbackImpl(PassRefPtr<WebCore::FileChooser> file_chooser)
+ : file_chooser_(file_chooser) {
+ }
+
+ void OnFileChoose(const std::wstring& file_name) {
+ file_chooser_->chooseFile(webkit_glue::StdWStringToString(file_name));
+ }
+
+ private:
+ RefPtr<WebCore::FileChooser> file_chooser_;
+ DISALLOW_EVIL_CONSTRUCTORS(WebFileChooserCallbackImpl);
+};
+
+ChromeClientImpl::ChromeClientImpl(WebViewImpl* webview)
+ : webview_(webview),
+ toolbars_visible_(true),
+ statusbar_visible_(true),
+ scrollbars_visible_(true),
+ menubar_visible_(true),
+ resizable_(true) {
+}
+
+ChromeClientImpl::~ChromeClientImpl() {
+}
+
+void ChromeClientImpl::chromeDestroyed() {
+ delete this;
+}
+
+void ChromeClientImpl::setWindowRect(const WebCore::FloatRect& r) {
+ WebViewDelegate* d = webview_->delegate();
+ if (d) {
+ WebCore::IntRect ir(r);
+ d->SetWindowRect(webview_,
+ gfx::Rect(ir.x(), ir.y(), ir.width(), ir.height()));
+ }
+}
+
+WebCore::FloatRect ChromeClientImpl::windowRect() {
+ gfx::Point origin;
+ if (webview_->delegate())
+ webview_->delegate()->GetWindowLocation(webview_, &origin);
+ const gfx::Size size = webview_->size();
+
+ return WebCore::FloatRect(
+ static_cast<float>(origin.x()),
+ static_cast<float>(origin.y()),
+ static_cast<float>(size.width()),
+ static_cast<float>(size.height()));
+}
+
+WebCore::FloatRect ChromeClientImpl::pageRect() {
+ // We hide the details of the window's border thickness from the web page by
+ // simple re-using the window position here. So, from the point-of-view of
+ // the web page, the window has no border.
+ return windowRect();
+}
+
+float ChromeClientImpl::scaleFactor() {
+ // This is supposed to return the scale factor of the web page. It looks like
+ // the implementor of the graphics layer is responsible for doing most of the
+ // operations associated with scaling. However, this value is used ins some
+ // cases by WebCore. For example, this is used as a scaling factor in canvas
+ // so that things drawn in it are scaled just like the web page is.
+ //
+ // We don't currently implement scaling, so just return 1.0 (no scaling).
+ return 1.0;
+}
+
+void ChromeClientImpl::focus() {
+ WebViewDelegate* d = webview_->delegate();
+ if (d)
+ d->Focus(webview_);
+}
+
+void ChromeClientImpl::unfocus() {
+ WebViewDelegate* d = webview_->delegate();
+ if (d)
+ d->Blur(webview_);
+}
+
+bool ChromeClientImpl::canTakeFocus(WebCore::FocusDirection) {
+ // For now the browser can always take focus if we're not running layout
+ // tests.
+ return !webkit_glue::IsLayoutTestMode();
+}
+
+void ChromeClientImpl::takeFocus(WebCore::FocusDirection direction) {
+ WebViewDelegate* d = webview_->delegate();
+ if (d) {
+ d->TakeFocus(webview_,
+ direction == WebCore::FocusDirectionBackward);
+ }
+}
+
+WebCore::Page* ChromeClientImpl::createWindow(
+ WebCore::Frame* frame, const WebCore::FrameLoadRequest& r,
+ const WebCore::WindowFeatures& features) {
+ WebViewDelegate* d = webview_->delegate();
+ if (!d)
+ return NULL;
+
+ bool userGesture = frame->scriptBridge()->wasRunByUserGesture();
+ WebViewImpl* new_view = static_cast<WebViewImpl*>(
+ d->CreateWebView(webview_, userGesture));
+ if (!new_view)
+ return NULL;
+
+ // The request is empty when we are just being asked to open a blank window.
+ // This corresponds to window.open(""), for example.
+ if (!r.resourceRequest().isEmpty()) {
+ WebRequestImpl request(r);
+ new_view->main_frame()->LoadRequest(&request);
+ }
+
+ WebViewImpl* new_view_impl = static_cast<WebViewImpl*>(new_view);
+ return new_view_impl->page();
+}
+
+static inline bool CurrentEventShouldCauseBackgroundTab(
+ const WebInputEvent* input_event) {
+ if (!input_event)
+ return false;
+
+ if (input_event->type != WebInputEvent::MOUSE_UP)
+ return false;
+
+ const WebMouseEvent* mouse_event = static_cast<const WebMouseEvent*>(input_event);
+ return (mouse_event->button == WebMouseEvent::BUTTON_MIDDLE);
+}
+
+void ChromeClientImpl::show() {
+ WebViewDelegate* d = webview_->delegate();
+ if (d) {
+ // If our default configuration was modified by a script or wasn't
+ // created by a user gesture, then show as a popup. Else, let this
+ // new window be opened as a toplevel window.
+ //
+ bool as_popup =
+ !toolbars_visible_ ||
+ !statusbar_visible_ ||
+ !scrollbars_visible_ ||
+ !menubar_visible_ ||
+ !resizable_ ||
+ !d->WasOpenedByUserGesture(webview_);
+
+ WindowOpenDisposition disposition = NEW_FOREGROUND_TAB;
+ if (as_popup)
+ disposition = NEW_POPUP;
+ if (CurrentEventShouldCauseBackgroundTab(WebViewImpl::current_input_event()))
+ disposition = NEW_BACKGROUND_TAB;
+
+ d->Show(webview_, disposition);
+ }
+}
+
+bool ChromeClientImpl::canRunModal() {
+ return webview_->delegate() != NULL;
+}
+
+void ChromeClientImpl::runModal() {
+ WebViewDelegate* d = webview_->delegate();
+ if (d)
+ d->RunModal(webview_);
+}
+
+void ChromeClientImpl::setToolbarsVisible(bool value) {
+ toolbars_visible_ = value;
+}
+
+bool ChromeClientImpl::toolbarsVisible() {
+ return toolbars_visible_;
+}
+
+void ChromeClientImpl::setStatusbarVisible(bool value) {
+ statusbar_visible_ = value;
+}
+
+bool ChromeClientImpl::statusbarVisible() {
+ return statusbar_visible_;
+}
+
+void ChromeClientImpl::setScrollbarsVisible(bool value) {
+ scrollbars_visible_ = value;
+ WebFrameImpl* web_frame =
+ static_cast<WebFrameImpl*>(webview_->GetMainFrame());
+ if (web_frame)
+ web_frame->SetAllowsScrolling(value);
+}
+
+bool ChromeClientImpl::scrollbarsVisible() {
+ return scrollbars_visible_;
+}
+
+void ChromeClientImpl::setMenubarVisible(bool value) {
+ menubar_visible_ = value;
+}
+
+bool ChromeClientImpl::menubarVisible() {
+ return menubar_visible_;
+}
+
+void ChromeClientImpl::setResizable(bool value) {
+ resizable_ = value;
+}
+
+void ChromeClientImpl::addMessageToConsole(const WebCore::String& message,
+ unsigned int line_no,
+ const WebCore::String& source_id) {
+ WebViewDelegate* d = webview_->delegate();
+ if (d) {
+ std::wstring wstr_message = webkit_glue::StringToStdWString(message);
+ std::wstring wstr_source_id = webkit_glue::StringToStdWString(source_id);
+ d->AddMessageToConsole(webview_, wstr_message, line_no, wstr_source_id);
+ }
+}
+
+bool ChromeClientImpl::canRunBeforeUnloadConfirmPanel() {
+ return webview_->delegate() != NULL;
+}
+
+bool ChromeClientImpl::runBeforeUnloadConfirmPanel(const WebCore::String& message,
+ WebCore::Frame* frame) {
+ WebViewDelegate* d = webview_->delegate();
+ if (d) {
+ std::wstring wstr = webkit_glue::StringToStdWString(message);
+ return d->RunBeforeUnloadConfirm(webview_, wstr);
+ }
+ return false;
+}
+
+void ChromeClientImpl::closeWindowSoon() {
+ // Make sure this Page can no longer be found by JS.
+ webview_->page()->setGroupName(WebCore::String());
+
+ // Make sure that all loading is stopped. Ensures that JS stops executing!
+ webview_->StopLoading();
+
+ WebViewDelegate* d = webview_->delegate();
+ if (d)
+ d->CloseWidgetSoon(webview_);
+}
+
+// Although a WebCore::Frame is passed in, we don't actually use it, since we
+// already know our own webview_.
+void ChromeClientImpl::runJavaScriptAlert(WebCore::Frame* frame,
+ const WebCore::String& message) {
+ // Pass the request on to the WebView delegate, for more control.
+ WebViewDelegate* d = webview_->delegate();
+ if (d) {
+ std::wstring wstr = webkit_glue::StringToStdWString(message);
+ d->RunJavaScriptAlert(webview_, wstr);
+ }
+}
+
+// See comments for runJavaScriptAlert().
+bool ChromeClientImpl::runJavaScriptConfirm(WebCore::Frame* frame,
+ const WebCore::String& message) {
+ WebViewDelegate* d = webview_->delegate();
+ if (d) {
+ std::wstring wstr = webkit_glue::StringToStdWString(message);
+ return d->RunJavaScriptConfirm(webview_, wstr);
+ }
+ return false;
+}
+
+// See comments for runJavaScriptAlert().
+bool ChromeClientImpl::runJavaScriptPrompt(WebCore::Frame* frame,
+ const WebCore::String& message,
+ const WebCore::String& defaultValue,
+ WebCore::String& result) {
+ WebViewDelegate* d = webview_->delegate();
+ if (d) {
+ std::wstring wstr_message = webkit_glue::StringToStdWString(message);
+ std::wstring wstr_default = webkit_glue::StringToStdWString(defaultValue);
+ std::wstring wstr_result;
+ bool ok = d->RunJavaScriptPrompt(webview_,
+ wstr_message,
+ wstr_default,
+ &wstr_result);
+ if (ok)
+ result = webkit_glue::StdWStringToString(wstr_result);
+ return ok;
+ }
+ return false;
+}
+
+void ChromeClientImpl::setStatusbarText(const WebCore::String&) {
+ // TODO(mbelshe): implement me
+}
+
+bool ChromeClientImpl::shouldInterruptJavaScript() {
+ // TODO(mbelshe): implement me
+ return false;
+}
+
+bool ChromeClientImpl::tabsToLinks() const {
+ // TODO(pamg): Consider controlling this with a user preference, when we have
+ // a preference system in place.
+ // For now Chrome will allow link to take focus if we're not running layout
+ // tests.
+ return !webkit_glue::IsLayoutTestMode();
+}
+
+WebCore::IntRect ChromeClientImpl::windowResizerRect() const {
+ // TODO(mbelshe): implement me
+ WebCore::IntRect rv;
+ return rv;
+}
+
+void ChromeClientImpl::addToDirtyRegion(const WebCore::IntRect& damaged_rect) {
+ ASSERT_NOT_REACHED();
+}
+
+void ChromeClientImpl::scrollBackingStore(int dx, int dy,
+ const WebCore::IntRect& scroll_rect,
+ const WebCore::IntRect& clip_rect) {
+ ASSERT_NOT_REACHED();
+}
+
+void ChromeClientImpl::updateBackingStore() {
+ ASSERT_NOT_REACHED();
+}
+
+void ChromeClientImpl::mouseDidMoveOverElement(const WebCore::HitTestResult& result,
+ unsigned modifierFlags) {
+
+ // Find out if the mouse is over a link, and if so, let our UI know... somehow
+ WebViewDelegate* d = webview_->delegate();
+ if (d) {
+ if (result.isLiveLink() && !result.absoluteLinkURL().string().isEmpty()) {
+ d->UpdateTargetURL(webview_, webkit_glue::KURLToGURL(result.absoluteLinkURL()));
+ } else {
+ d->UpdateTargetURL(webview_, GURL());
+ }
+ }
+}
+
+void ChromeClientImpl::setToolTip(const WebCore::String& tooltip_text) {
+ if (webview_->delegate()) {
+ std::wstring tooltip_text_as_wstring =
+ webkit_glue::StringToStdWString(tooltip_text);
+ webview_->delegate()->SetTooltipText(webview_, tooltip_text_as_wstring);
+ }
+}
+
+void ChromeClientImpl::runFileChooser(const WebCore::String& default_path,
+ PassRefPtr<WebCore::FileChooser> fileChooser) {
+ WebViewDelegate* delegate = webview_->delegate();
+ if (!delegate)
+ return;
+
+ std::wstring suggestion = webkit_glue::StringToStdWString(default_path);
+ WebFileChooserCallbackImpl* chooser = new WebFileChooserCallbackImpl(fileChooser);
+ delegate->RunFileChooser(suggestion, chooser);
+}
+
+WebCore::IntRect ChromeClientImpl::windowToScreen(const WebCore::IntRect& rect) {
+ WebCore::IntRect screen_rect(rect);
+
+ WebViewDelegate* d = webview_->delegate();
+ if (d) {
+ gfx::Point window_pos;
+ d->GetWindowLocation(webview_, &window_pos);
+ screen_rect.move(window_pos.x(), window_pos.y());
+ }
+
+ return screen_rect;
+}
+
+void ChromeClientImpl::print(WebCore::Frame* frame) {
+ WebViewDelegate* d = webview_->delegate();
+ if (d) {
+ d->ScriptedPrint(WebFrameImpl::FromFrame(frame));
+ }
+}
+
+void ChromeClientImpl::exceededDatabaseQuota(WebCore::Frame* frame,
+ const WebCore::String& databaseName) {
+ // TODO(tc): If we enable the storage API, we need to implement this function.
+}
diff --git a/webkit/glue/chrome_client_impl.h b/webkit/glue/chrome_client_impl.h
new file mode 100644
index 0000000..8515f15
--- /dev/null
+++ b/webkit/glue/chrome_client_impl.h
@@ -0,0 +1,137 @@
+// 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 WEBKIT_GLUE_CHROME_CLIENT_IMPL_H__
+#define WEBKIT_GLUE_CHROME_CLIENT_IMPL_H__
+
+#pragma warning(push, 0)
+#include "ChromeClientWin.h"
+#pragma warning(pop)
+
+class WebViewImpl;
+namespace WebCore {
+ class SecurityOrigin;
+ struct WindowFeatures;
+}
+
+// Handles window-level notifications from WebCore on behalf of a WebView.
+class ChromeClientImpl : public WebCore::ChromeClientWin {
+public:
+ ChromeClientImpl(WebViewImpl* webview);
+ virtual ~ChromeClientImpl();
+
+ virtual void chromeDestroyed();
+
+ virtual void setWindowRect(const WebCore::FloatRect&);
+ virtual WebCore::FloatRect windowRect();
+
+ virtual WebCore::FloatRect pageRect();
+
+ virtual float scaleFactor();
+
+ virtual void focus();
+ virtual void unfocus();
+
+ virtual bool canTakeFocus(WebCore::FocusDirection);
+ virtual void takeFocus(WebCore::FocusDirection);
+
+ virtual WebCore::Page* createWindow(WebCore::Frame*,
+ const WebCore::FrameLoadRequest&,
+ const WebCore::WindowFeatures&);
+ virtual void show();
+
+ virtual bool canRunModal();
+ virtual void runModal();
+
+ virtual void setToolbarsVisible(bool);
+ virtual bool toolbarsVisible();
+
+ virtual void setStatusbarVisible(bool);
+ virtual bool statusbarVisible();
+
+ virtual void setScrollbarsVisible(bool);
+ virtual bool scrollbarsVisible();
+
+ virtual void setMenubarVisible(bool);
+ virtual bool menubarVisible();
+
+ virtual void setResizable(bool);
+
+ virtual void addMessageToConsole(const WebCore::String& message,
+ unsigned int lineNumber,
+ const WebCore::String& sourceID);
+
+ virtual bool canRunBeforeUnloadConfirmPanel();
+ virtual bool runBeforeUnloadConfirmPanel(const WebCore::String& message,
+ WebCore::Frame* frame);
+
+ virtual void closeWindowSoon();
+
+ virtual void runJavaScriptAlert(WebCore::Frame*, const WebCore::String&);
+ virtual bool runJavaScriptConfirm(WebCore::Frame*, const WebCore::String&);
+ virtual bool runJavaScriptPrompt(WebCore::Frame*, const WebCore::String& message, const WebCore::String& defaultValue, WebCore::String& result);
+
+ virtual void setStatusbarText(const WebCore::String&);
+ virtual bool shouldInterruptJavaScript();
+
+ // Returns true if anchors should accept keyboard focus with the tab key.
+ // This method is used in a convoluted fashion by EventHandler::tabsToLinks.
+ // It's a twisted path (self-evident, but more complicated than seems
+ // necessary), but the net result is that returning true from here, on a
+ // platform other than MAC or QT, lets anchors get keyboard focus.
+ virtual bool tabsToLinks() const;
+
+ virtual WebCore::IntRect windowResizerRect() const;
+ virtual void addToDirtyRegion(const WebCore::IntRect&);
+ virtual void scrollBackingStore(int dx, int dy, const WebCore::IntRect& scrollViewRect, const WebCore::IntRect& clipRect);
+ virtual void updateBackingStore();
+
+ virtual void mouseDidMoveOverElement(const WebCore::HitTestResult& result, unsigned modifierFlags);
+
+ virtual void setToolTip(const WebCore::String& tooltip_text);
+
+ virtual void runFileChooser(const WebCore::String&,
+ PassRefPtr<WebCore::FileChooser>);
+ virtual WebCore::IntRect windowToScreen(const WebCore::IntRect& rect);
+
+ virtual void print(WebCore::Frame*);
+
+ virtual void exceededDatabaseQuota(WebCore::Frame*,
+ const WebCore::String& databaseName);
+
+private:
+ WebViewImpl* webview_; // weak pointer
+ bool toolbars_visible_;
+ bool statusbar_visible_;
+ bool scrollbars_visible_;
+ bool menubar_visible_;
+ bool resizable_;
+};
+
+#endif // WEBKIT_GLUE_CHROME_CLIENT_IMPL_H__
diff --git a/webkit/glue/console_message_level.h b/webkit/glue/console_message_level.h
new file mode 100644
index 0000000..aae95fa
--- /dev/null
+++ b/webkit/glue/console_message_level.h
@@ -0,0 +1,40 @@
+// 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 WEBKIT_GLUE_CONSOLE_MESSAGE_LEVEL_H__
+#define WEBKIT_GLUE_CONSOLE_MESSAGE_LEVEL_H__
+
+enum ConsoleMessageLevel {
+ MESSAGE_LEVEL_TIP,
+ MESSAGE_LEVEL_LOG,
+ MESSAGE_LEVEL_WARNING,
+ MESSAGE_LEVEL_ERROR
+};
+
+#endif // WEBKIT_GLUE_CONSOLE_MESSAGE_LEVEL_H__
diff --git a/webkit/glue/context_menu_client_impl.cc b/webkit/glue/context_menu_client_impl.cc
new file mode 100644
index 0000000..c5227676
--- /dev/null
+++ b/webkit/glue/context_menu_client_impl.cc
@@ -0,0 +1,276 @@
+// 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 "config.h"
+
+#pragma warning(push, 0)
+#include "ContextMenu.h"
+#include "Document.h"
+#include "DocumentLoader.h"
+#include "Editor.h"
+#include "FrameLoader.h"
+#include "FrameView.h"
+#include "HitTestResult.h"
+#include "KURL.h"
+#include "Widget.h"
+#pragma warning(pop)
+#undef LOG
+
+#include "webkit/glue/context_menu_client_impl.h"
+
+#include "base/string_util.h"
+#include "webkit/glue/context_node_types.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/webdocumentloader_impl.h"
+#include "webkit/glue/webview_impl.h"
+
+#include "base/word_iterator.h"
+
+// Helper function to determine whether text is a single word or a sentence.
+static bool IsASingleWord(const std::wstring& text) {
+ WordIterator iter(text, WordIterator::BREAK_WORD);
+ int word_count = 0;
+ if (!iter.Init()) return false;
+ while (iter.Advance()) {
+ if (iter.IsWord()) {
+ word_count++;
+ if (word_count > 1) // More than one word.
+ return false;
+ }
+ }
+
+ // Check for 0 words.
+ if (!word_count)
+ return false;
+
+ // Has a single word.
+ return true;
+}
+
+// Helper function to get misspelled word on which context menu
+// is to be evolked. This function also sets the word on which context menu
+// has been evoked to be the selected word, as required.
+static std::wstring GetMisspelledWord(WebCore::ContextMenu* default_menu,
+ WebCore::Frame* selected_frame) {
+ std::wstring misspelled_word_string;
+
+ // First select from selectedText to check for multiple word selection.
+ misspelled_word_string = CollapseWhitespace(
+ webkit_glue::StringToStdWString(selected_frame->selectedText()),
+ false);
+
+ // Don't provide suggestions for multiple words.
+ if (!misspelled_word_string.empty() &&
+ !IsASingleWord(misspelled_word_string))
+ return L"";
+
+ // Expand around the click to see if we clicked a word.
+ WebCore::Selection selection;
+ WebCore::VisiblePosition pos(default_menu->hitTestResult().innerNode()->
+ renderer()->positionForPoint(default_menu->hitTestResult().
+ localPoint()));
+
+ if (pos.isNotNull()) {
+ selection = WebCore::Selection(pos);
+ selection.expandUsingGranularity(WebCore::WordGranularity);
+ }
+
+ if (selection.isRange()) {
+ selected_frame->setSelectionGranularity(WebCore::WordGranularity);
+ }
+
+ if (selected_frame->shouldChangeSelection(selection))
+ selected_frame->selectionController()->setSelection(selection);
+
+ misspelled_word_string = CollapseWhitespace(
+ webkit_glue::StringToStdWString(selected_frame->selectedText()),
+ false);
+
+ return misspelled_word_string;
+}
+
+ContextMenuClientImpl::~ContextMenuClientImpl() {
+}
+
+void ContextMenuClientImpl::contextMenuDestroyed() {
+ delete this;
+}
+
+// Figure out the URL of a page or subframe. Returns |page_type| as the type,
+// which indicates page or subframe, or ContextNode::NONE if the URL could not
+// be determined for some reason.
+static ContextNode::Type GetTypeAndURLFromFrame(WebCore::Frame* frame,
+ GURL* url,
+ ContextNode::Type page_type) {
+ ContextNode::Type type = ContextNode::NONE;
+ if (frame) {
+ WebCore::DocumentLoader* dl = frame->loader()->documentLoader();
+ if (dl) {
+ WebDataSource* ds = static_cast<WebDocumentLoaderImpl*>(dl)->
+ GetDataSource();
+ if (ds) {
+ type = page_type;
+ *url = ds->HasUnreachableURL() ? ds->GetUnreachableURL()
+ : ds->GetRequest().GetURL();
+ }
+ }
+ }
+ return type;
+}
+
+WebCore::PlatformMenuDescription
+ ContextMenuClientImpl::getCustomMenuFromDefaultItems(
+ WebCore::ContextMenu* default_menu) {
+ // Displaying the context menu in this function is a big hack as we don't
+ // have context, i.e. whether this is being invoked via a script or in
+ // response to user input (Mouse event WM_RBUTTONDOWN,
+ // Keyboard events KeyVK_APPS, Shift+F10). Check if this is being invoked
+ // in response to the above input events before popping up the context menu.
+ if (!webview_->context_menu_allowed())
+ return NULL;
+
+ WebCore::HitTestResult r = default_menu->hitTestResult();
+ WebCore::Frame* selected_frame = r.innerNonSharedNode()->document()->frame();
+
+ WebCore::IntPoint menu_point =
+ selected_frame->view()->contentsToWindow(r.point());
+
+ ContextNode::Type type = ContextNode::NONE;
+
+ // Links, Images and Image-Links take preference over all else.
+ WebCore::KURL link_url = r.absoluteLinkURL();
+ std::wstring link_url_string;
+ if (!link_url.isEmpty()) {
+ type = ContextNode::LINK;
+ }
+ WebCore::KURL image_url = r.absoluteImageURL();
+ std::wstring image_url_string;
+ if (!image_url.isEmpty()) {
+ type = ContextNode::IMAGE;
+ }
+ if (!image_url.isEmpty() && !link_url.isEmpty())
+ type = ContextNode::IMAGE_LINK;
+
+ // If it's not a link, an image or an image link, show a selection menu or a
+ // more generic page menu.
+ std::wstring selection_text_string;
+ std::wstring misspelled_word_string;
+ GURL frame_url;
+ GURL page_url;
+
+ // Send the frame and page URLs in any case.
+ ContextNode::Type frame_type = ContextNode::NONE;
+ ContextNode::Type page_type =
+ GetTypeAndURLFromFrame(webview_->main_frame()->frame(),
+ &page_url,
+ ContextNode::PAGE);
+ if (selected_frame != webview_->main_frame()->frame()) {
+ frame_type = GetTypeAndURLFromFrame(selected_frame,
+ &frame_url,
+ ContextNode::FRAME);
+ }
+
+ if (type == ContextNode::NONE) {
+ if (r.isContentEditable()) {
+ type = ContextNode::EDITABLE;
+ if (webview_->FocusedFrameNeedsSpellchecking()) {
+ misspelled_word_string = GetMisspelledWord(default_menu,
+ selected_frame);
+ }
+ } else if (r.isSelected()) {
+ type = ContextNode::SELECTION;
+ selection_text_string =
+ CollapseWhitespace(
+ webkit_glue::StringToStdWString(selected_frame->selectedText()),
+ false);
+ } else if (selected_frame != webview_->main_frame()->frame()) {
+ type = frame_type;
+ } else {
+ type = page_type;
+ }
+ }
+
+ int edit_flags = ContextNode::CAN_DO_NONE;
+ if (webview_->GetFocusedWebCoreFrame()->editor()->canUndo())
+ edit_flags |= ContextNode::CAN_UNDO;
+ if (webview_->GetFocusedWebCoreFrame()->editor()->canRedo())
+ edit_flags |= ContextNode::CAN_REDO;
+ if (webview_->GetFocusedWebCoreFrame()->editor()->canCut())
+ edit_flags |= ContextNode::CAN_CUT;
+ if (webview_->GetFocusedWebCoreFrame()->editor()->canCopy())
+ edit_flags |= ContextNode::CAN_COPY;
+ if (webview_->GetFocusedWebCoreFrame()->editor()->canPaste())
+ edit_flags |= ContextNode::CAN_PASTE;
+ if (webview_->GetFocusedWebCoreFrame()->editor()->canDelete())
+ edit_flags |= ContextNode::CAN_DELETE;
+ // We can always select all...
+ edit_flags |= ContextNode::CAN_SELECT_ALL;
+
+ WebViewDelegate* d = webview_->delegate();
+ if (d) {
+ d->ShowContextMenu(webview_,
+ type,
+ menu_point.x(),
+ menu_point.y(),
+ webkit_glue::KURLToGURL(link_url),
+ webkit_glue::KURLToGURL(image_url),
+ page_url,
+ frame_url,
+ selection_text_string,
+ misspelled_word_string,
+ edit_flags);
+ }
+ return NULL;
+}
+
+void ContextMenuClientImpl::contextMenuItemSelected(
+ WebCore::ContextMenuItem*, const WebCore::ContextMenu*) {
+}
+
+void ContextMenuClientImpl::downloadURL(const WebCore::KURL&) {
+}
+
+void ContextMenuClientImpl::copyImageToClipboard(const WebCore::HitTestResult&) {
+}
+
+void ContextMenuClientImpl::searchWithGoogle(const WebCore::Frame*) {
+}
+
+void ContextMenuClientImpl::lookUpInDictionary(WebCore::Frame*) {
+}
+
+void ContextMenuClientImpl::speak(const WebCore::String&) {
+}
+
+void ContextMenuClientImpl::stopSpeaking() {
+}
+
+bool ContextMenuClientImpl::shouldIncludeInspectElementItem() {
+ return false; // TODO(jackson): Eventually include the inspector context menu item
+}
diff --git a/webkit/glue/context_menu_client_impl.h b/webkit/glue/context_menu_client_impl.h
new file mode 100644
index 0000000..fd64068
--- /dev/null
+++ b/webkit/glue/context_menu_client_impl.h
@@ -0,0 +1,65 @@
+// 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 WEBKIT_GLUE_CONTEXT_MENU_CLIENT_IMPL_H__
+#define WEBKIT_GLUE_CONTEXT_MENU_CLIENT_IMPL_H__
+
+#pragma warning(push, 0)
+#include "ContextMenuClient.h"
+#pragma warning(pop)
+
+class WebViewImpl;
+
+// Handles window-level notifications from WebCore on behalf of a WebView.
+class ContextMenuClientImpl : public WebCore::ContextMenuClient {
+public:
+ ContextMenuClientImpl(WebViewImpl* webview) : webview_(webview) {
+ }
+
+ virtual ~ContextMenuClientImpl();
+ virtual void contextMenuDestroyed();
+
+ virtual WebCore::PlatformMenuDescription getCustomMenuFromDefaultItems(
+ WebCore::ContextMenu*);
+ virtual void contextMenuItemSelected(WebCore::ContextMenuItem*,
+ const WebCore::ContextMenu*);
+
+ virtual void downloadURL(const WebCore::KURL&);
+ virtual void copyImageToClipboard(const WebCore::HitTestResult&);
+ virtual void searchWithGoogle(const WebCore::Frame*);
+ virtual void lookUpInDictionary(WebCore::Frame*);
+ virtual void speak(const WebCore::String&);
+ virtual void stopSpeaking();
+ virtual bool shouldIncludeInspectElementItem();
+
+private:
+ WebViewImpl* webview_; // weak pointer
+};
+
+#endif // WEBKIT_GLUE_CONTEXT_MENU_CLIENT_IMPL_H__
diff --git a/webkit/glue/context_menu_unittest.cc b/webkit/glue/context_menu_unittest.cc
new file mode 100644
index 0000000..5e78eb6
--- /dev/null
+++ b/webkit/glue/context_menu_unittest.cc
@@ -0,0 +1,91 @@
+// 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.
+
+// Tests for displaying context menus in corner cases (and swallowing context
+// menu events when appropriate)
+
+#include <vector>
+
+#include "base/file_util.h"
+#include "base/message_loop.h"
+#include "webkit/glue/webframe.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/webview.h"
+#include "webkit/tools/test_shell/test_shell_test.h"
+
+
+// Right clicking inside on an iframe should produce a context menu
+class ContextMenuCapturing : public TestShellTest {
+ protected:
+ void SetUp() {
+ TestShellTest::SetUp();
+
+ iframes_data_dir_ = data_dir_;
+ file_util::AppendToPath(&iframes_data_dir_, L"test_shell");
+ file_util::AppendToPath(&iframes_data_dir_, L"iframes");
+ ASSERT_TRUE(file_util::PathExists(iframes_data_dir_));
+ }
+
+ std::wstring iframes_data_dir_;
+};
+
+
+TEST_F(ContextMenuCapturing, ContextMenuCapturing) {
+ // Make sure we have no stored mouse event state
+ WebViewDelegate* raw_delegate = test_shell_->webView()->GetDelegate();
+ TestWebViewDelegate* test_delegate = static_cast<TestWebViewDelegate*>(raw_delegate);
+ test_delegate->clear_captured_context_menu_events();
+ EXPECT_EQ(0, test_delegate->captured_context_menu_events().size());
+
+ std::wstring test_url = GetTestURL(iframes_data_dir_, L"testiframe.html");
+ test_shell_->LoadURL(test_url.c_str());
+ test_shell_->WaitTestFinished();
+
+ // Create a right click in the center of the iframe. (I'm hoping this will
+ // make this a bit more robust in case of some other formatting or other bug.)
+ WebMouseEvent mouse_event;
+ mouse_event.type = WebInputEvent::MOUSE_DOWN;
+ mouse_event.modifiers = 0;
+ mouse_event.button = WebMouseEvent::BUTTON_RIGHT;
+ mouse_event.x = 250;
+ mouse_event.y = 250;
+ mouse_event.global_x = 250;
+ mouse_event.global_y = 250;
+ mouse_event.timestamp_sec = 0;
+ mouse_event.layout_test_click_count = 0;
+
+ WebView* webview = test_shell_->webView();
+ webview->HandleInputEvent(&mouse_event);
+
+ // Now simulate the corresponding up event which should display the menu
+ mouse_event.type = WebInputEvent::MOUSE_UP;
+ webview->HandleInputEvent(&mouse_event);
+
+ EXPECT_EQ(1, test_delegate->captured_context_menu_events().size());
+}
diff --git a/webkit/glue/context_node_types.h b/webkit/glue/context_node_types.h
new file mode 100644
index 0000000..e3c86f3
--- /dev/null
+++ b/webkit/glue/context_node_types.h
@@ -0,0 +1,87 @@
+// 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 WEBKIT_GLUE_CONTEXT_NODE_TYPES_H__
+#define WEBKIT_GLUE_CONTEXT_NODE_TYPES_H__
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+// This class is for scoping only.
+class ContextNode {
+ public:
+ // This enumeration defines the type of node that the user may perform a
+ // contextual action on in the WebView.
+ enum Type {
+
+ // No node is selected
+ NONE = 0,
+
+ // The top page is selected
+ PAGE = 1,
+
+ // A subframe page is selected
+ FRAME = 2,
+
+ // A link is selected
+ LINK = 3,
+
+ // An image is selected
+ IMAGE = 4,
+
+ // An image that is also a link is selected
+ IMAGE_LINK = 5,
+
+ // There is a textual or mixed selection that is selected
+ SELECTION = 6,
+
+ // An editiable element is selected
+ EDITABLE = 7,
+
+ // A misspelled word is selected
+ MISPELLED_WORD = 8
+ };
+
+ static Type FromInt(int32 type) {
+ return static_cast<Type>(type);
+ }
+
+ enum Capability {
+ CAN_DO_NONE = 0x0,
+ CAN_UNDO = 0x1,
+ CAN_REDO = 0x2,
+ CAN_CUT = 0x4,
+ CAN_COPY = 0x8,
+ CAN_PASTE = 0x10,
+ CAN_DELETE = 0x20,
+ CAN_SELECT_ALL = 0x40,
+ };
+};
+
+#endif // WEBKIT_GLUE_CONTEXT_NODE_TYPES_H__
diff --git a/webkit/glue/cpp_binding_example.cc b/webkit/glue/cpp_binding_example.cc
new file mode 100644
index 0000000..25616d4828
--- /dev/null
+++ b/webkit/glue/cpp_binding_example.cc
@@ -0,0 +1,119 @@
+// 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 contains the definition for CppBindingExample, a usage example
+// that is not actually used anywhere. See cpp_binding_example.h.
+
+#include "cpp_binding_example.h"
+
+CppBindingExample::CppBindingExample() {
+ // Map properties. It's recommended, but not required, that the JavaScript
+ // names (used as the keys in this map) match the names of the member
+ // variables exposed through those names.
+ BindProperty("my_value", &my_value);
+ BindProperty("my_other_value", &my_other_value);
+
+ // Map methods. See comment above about names.
+ BindMethod("echoValue", &CppBindingExample::echoValue);
+ BindMethod("echoType", &CppBindingExample::echoType);
+ BindMethod("plus", &CppBindingExample::plus);
+
+ // The fallback method is called when a nonexistent method is called on an
+ // object. If none is specified, calling a nonexistent method causes an
+ // exception to be thrown and the JavaScript execution is stopped.
+ BindFallbackMethod(&CppBindingExample::fallbackMethod);
+
+ my_value.Set(10);
+ my_other_value.Set("Reinitialized!");
+}
+
+void CppBindingExample::echoValue(const CppArgumentList& args,
+ CppVariant* result) {
+ if (args.size() < 1) {
+ result->SetNull();
+ return;
+ }
+ result->Set(args[0]);
+}
+
+void CppBindingExample::echoType(const CppArgumentList& args,
+ CppVariant* result) {
+ if (args.size() < 1) {
+ result->SetNull();
+ return;
+ }
+ // Note that if args[0] is a string, the following assignment implicitly
+ // makes a copy of that string, which may have an undesirable impact on
+ // performance.
+ CppVariant arg1 = args[0];
+ if (arg1.isBool())
+ result->Set(true);
+ else if (arg1.isInt32())
+ result->Set(7);
+ else if (arg1.isDouble())
+ result->Set(3.14159);
+ else if (arg1.isString())
+ result->Set("Success!");
+}
+
+void CppBindingExample::plus(const CppArgumentList& args,
+ CppVariant* result) {
+ if (args.size() < 2) {
+ result->SetNull();
+ return;
+ }
+
+ CppVariant arg1 = args[0];
+ CppVariant arg2 = args[1];
+
+ if (!arg1.isNumber() || !arg2.isNumber()) {
+ result->SetNull();
+ return;
+ }
+
+ // The value of a CppVariant may be read directly from its NPVariant struct.
+ // (However, it should only be set using one of the Set() functions.)
+ double sum = 0.;
+ if (arg1.isDouble())
+ sum += arg1.value.doubleValue;
+ else if (arg1.isInt32())
+ sum += arg1.value.intValue;
+
+ if (arg2.isDouble())
+ sum += arg2.value.doubleValue;
+ else if (arg2.isInt32())
+ sum += arg2.value.intValue;
+
+ result->Set(sum);
+}
+
+void CppBindingExample::fallbackMethod(const CppArgumentList& args,
+ CppVariant* result) {
+ printf("Error: unknown JavaScript method invoked.\n");
+}
diff --git a/webkit/glue/cpp_binding_example.h b/webkit/glue/cpp_binding_example.h
new file mode 100644
index 0000000..940618b
--- /dev/null
+++ b/webkit/glue/cpp_binding_example.h
@@ -0,0 +1,100 @@
+// 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.
+
+/*
+ CppBindingExample class:
+ This provides an example of how to use the CppBoundClass to create methods
+ and properties that can be exposed to JavaScript by an appropriately built
+ embedding client. It is also used by the CppBoundClass unit test.
+
+ Typically, a class intended to be bound to JavaScript will define a
+ constructor, any methods and properties to be exposed, and optionally a
+ destructor. An embedding client can then bind the class to a JavaScript
+ object in a frame's window using the CppBoundClass::BindToJavascript() method,
+ generally called from the WebView delegate's WindowObjectCleared().
+
+ Once this class has been bound, say to the name "example", it might be called
+ from JavaScript in the following way:
+
+ <script>
+ if (window.example) {
+ document.writeln(example.echoValue(false));
+ document.writeln(example.echoType("Hello world!"));
+ document.writeln(example.plus(2, 3.1));
+
+ example.my_value = 15;
+ example.my_other_value = 2.1;
+ document.writeln(example.plus(example.my_value, example.my_other_value));
+ }
+ </script>
+*/
+
+#ifndef CPP_BINDING_EXAMPLE_H__
+#define CPP_BINDING_EXAMPLE_H__
+
+#include "webkit/glue/cpp_bound_class.h"
+
+class CppBindingExample : public CppBoundClass {
+ public:
+ // The default constructor initializes the property and method lists needed
+ // to bind this class to a JS object.
+ CppBindingExample();
+
+ //
+ // These public member variables and methods implement the methods and
+ // properties that will be exposed to JavaScript. If needed, the class could
+ // also contain other methods or variables, which will be hidden from JS
+ // as long as they're not mapped in the property and method lists created in
+ // the constructor.
+ //
+ // The signatures of any methods to be bound must match
+ // CppBoundClass::Callback.
+ //
+
+ // Returns the value that was passed in as its first (only) argument.
+ void echoValue(const CppArgumentList& args, CppVariant* result);
+
+ // Returns a hard-coded value of the same type (bool, number (double),
+ // string, or null) that was passed in as an argument.
+ void echoType(const CppArgumentList& args, CppVariant* result);
+
+ // Returns the sum of the (first) two arguments as a double, if they are both
+ // numbers (integers or doubles). Otherwise returns null.
+ void plus(const CppArgumentList& args, CppVariant* result);
+
+ // Invoked when a nonexistent method is called on this example object, this
+ // prints an error message.
+ void fallbackMethod(const CppArgumentList& args, CppVariant* result);
+
+ // These properties will also be exposed to JavaScript.
+ CppVariant my_value;
+ CppVariant my_other_value;
+};
+
+#endif // CPP_BINDING_EXAMPLE_H__
diff --git a/webkit/glue/cpp_bound_class.cc b/webkit/glue/cpp_bound_class.cc
new file mode 100644
index 0000000..66244b5
--- /dev/null
+++ b/webkit/glue/cpp_bound_class.cc
@@ -0,0 +1,279 @@
+// 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 contains definitions for CppBoundClass
+
+// Here's the control flow of a JS method getting forwarded to a class.
+// - Something calls our NPObject with a function like "Invoke".
+// - CppNPObject's static invoke() function forwards it to its attached
+// CppBoundClass's Invoke() method.
+// - CppBoundClass has then overridden Invoke() to look up the function
+// name in its internal map of methods, and then calls the appropriate
+// method.
+
+#include "webkit/glue/cpp_bound_class.h"
+
+#include "config.h"
+#include "webkit/glue/webframe.h"
+
+// This is required for the KJS build due to an artifact of the
+// npruntime_priv.h file from JavaScriptCore/bindings.
+#pragma warning(disable:4067)
+#include "npruntime_priv.h"
+
+#if USE(JAVASCRIPTCORE_BINDINGS)
+#pragma warning(push, 0)
+#include "JSLock.h"
+#pragma warning(pop)
+#endif
+
+// Our special NPObject type. We extend an NPObject with a pointer to a
+// CppBoundClass, which is just a C++ interface that we forward all NPObject
+// callbacks to.
+struct CppNPObject {
+ NPObject parent; // This must be the first field in the struct.
+ CppBoundClass* bound_class;
+
+ //
+ // All following objects and functions are static, and just used to interface
+ // with NPObject/NPClass.
+ //
+
+ // An NPClass associates static functions of CppNPObject with the
+ // function pointers used by the JS runtime.
+ static NPClass np_class_;
+
+ // Allocate a new NPObject with the specified class.
+ static NPObject* allocate(NPP npp, NPClass* aClass);
+
+ // Free an object.
+ static void deallocate(NPObject* obj);
+
+ // Returns true if the C++ class associated with this NPObject exposes the
+ // given property. Called by the JS runtime.
+ static bool hasProperty(NPObject *obj, NPIdentifier ident);
+
+ // Returns true if the C++ class associated with this NPObject exposes the
+ // given method. Called by the JS runtime.
+ static bool hasMethod(NPObject *obj, NPIdentifier ident);
+
+ // If the given method is exposed by the C++ class associated with this
+ // NPObject, invokes it with the given args and returns a result. Otherwise,
+ // returns "undefined" (in the JavaScript sense). Called by the JS runtime.
+ static bool invoke(NPObject *obj, NPIdentifier ident,
+ const NPVariant *args, uint32_t arg_count,
+ NPVariant *result);
+
+ // If the given property is exposed by the C++ class associated with this
+ // NPObject, returns its value. Otherwise, returns "undefined" (in the
+ // JavaScript sense). Called by the JS runtime.
+ static bool getProperty(NPObject *obj, NPIdentifier ident,
+ NPVariant *result);
+
+ // If the given property is exposed by the C++ class associated with this
+ // NPObject, sets its value. Otherwise, does nothing. Called by the JS
+ // runtime.
+ static bool setProperty(NPObject *obj, NPIdentifier ident,
+ const NPVariant *value);
+};
+
+// Build CppNPObject's static function pointers into an NPClass, for use
+// in constructing NPObjects for the C++ classes.
+NPClass CppNPObject::np_class_ = {
+ NP_CLASS_STRUCT_VERSION,
+ CppNPObject::allocate,
+ CppNPObject::deallocate,
+ /* NPInvalidateFunctionPtr */ NULL,
+ CppNPObject::hasMethod,
+ CppNPObject::invoke,
+ /* NPInvokeDefaultFunctionPtr */ NULL,
+ CppNPObject::hasProperty,
+ CppNPObject::getProperty,
+ CppNPObject::setProperty,
+ /* NPRemovePropertyFunctionPtr */ NULL
+};
+
+/* static */ NPObject* CppNPObject::allocate(NPP npp, NPClass* aClass) {
+ CppNPObject* obj = new CppNPObject;
+ // obj->parent will be initialized by the NPObject code calling this.
+ obj->bound_class = NULL;
+ return &obj->parent;
+}
+
+/* static */ void CppNPObject::deallocate(NPObject* np_obj) {
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
+ delete obj;
+}
+
+/* static */ bool CppNPObject::hasMethod(NPObject* np_obj,
+ NPIdentifier ident) {
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
+ return obj->bound_class->HasMethod(ident);
+}
+
+/* static */ bool CppNPObject::hasProperty(NPObject* np_obj,
+ NPIdentifier ident) {
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
+ return obj->bound_class->HasProperty(ident);
+}
+
+/* static */ bool CppNPObject::invoke(NPObject* np_obj, NPIdentifier ident,
+ const NPVariant* args, uint32_t arg_count,
+ NPVariant* result) {
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
+ return obj->bound_class->Invoke(ident, args, arg_count, result);
+}
+
+/* static */ bool CppNPObject::getProperty(NPObject* np_obj,
+ NPIdentifier ident,
+ NPVariant* result) {
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
+ return obj->bound_class->GetProperty(ident, result);
+}
+
+/* static */ bool CppNPObject::setProperty(NPObject* np_obj,
+ NPIdentifier ident,
+ const NPVariant* value) {
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
+ return obj->bound_class->SetProperty(ident, value);
+}
+
+CppBoundClass::~CppBoundClass() {
+ for (MethodList::iterator i = methods_.begin(); i != methods_.end(); ++i)
+ delete i->second;
+
+ // Unregister objects we created and bound to a frame.
+ for (BoundObjectList::iterator i = bound_objects_.begin();
+ i != bound_objects_.end(); ++i) {
+#if USE(V8_BINDING)
+ _NPN_UnregisterObject(*i);
+#endif
+ NPN_ReleaseObject(*i);
+ }
+}
+
+bool CppBoundClass::HasMethod(NPIdentifier ident) {
+ return (methods_.find(ident) != methods_.end());
+}
+
+bool CppBoundClass::HasProperty(NPIdentifier ident) {
+ return (properties_.find(ident) != properties_.end());
+}
+
+bool CppBoundClass::Invoke(NPIdentifier ident,
+ const NPVariant* args,
+ size_t arg_count,
+ NPVariant* result) {
+ MethodList::const_iterator method = methods_.find(ident);
+ Callback* callback;
+ if (method == methods_.end()) {
+ if (fallback_callback_.get()) {
+ callback = fallback_callback_.get();
+ } else {
+ VOID_TO_NPVARIANT(*result);
+ return false;
+ }
+ } else {
+ callback = (*method).second;
+ }
+
+ // Build a CppArgumentList argument vector from the NPVariants coming in.
+ CppArgumentList cpp_args(arg_count);
+ for (size_t i = 0; i < arg_count; i++)
+ cpp_args[i].Set(args[i]);
+
+ CppVariant cpp_result;
+ callback->Run(cpp_args, &cpp_result);
+
+ cpp_result.CopyToNPVariant(result);
+ return true;
+}
+
+bool CppBoundClass::GetProperty(NPIdentifier ident, NPVariant* result) {
+ PropertyList::const_iterator prop = properties_.find(ident);
+ if (prop == properties_.end()) {
+ VOID_TO_NPVARIANT(*result);
+ return false;
+ }
+
+ const CppVariant* cpp_value = (*prop).second;
+ cpp_value->CopyToNPVariant(result);
+ return true;
+}
+
+bool CppBoundClass::SetProperty(NPIdentifier ident,
+ const NPVariant* value) {
+ PropertyList::iterator prop = properties_.find(ident);
+ if (prop == properties_.end())
+ return false;
+
+ (*prop).second->Set(*value);
+ return true;
+}
+
+void CppBoundClass::BindCallback(std::string name, Callback* callback) {
+ // NPUTF8 is a typedef for char, so this cast is safe.
+ NPIdentifier ident = NPN_GetStringIdentifier((const NPUTF8*)name.c_str());
+ MethodList::iterator old_callback = methods_.find(ident);
+ if (old_callback != methods_.end())
+ delete old_callback->second;
+ methods_[ident] = callback;
+}
+
+void CppBoundClass::BindProperty(std::string name, CppVariant* prop) {
+ // NPUTF8 is a typedef for char, so this cast is safe.
+ NPIdentifier ident = NPN_GetStringIdentifier((const NPUTF8*)name.c_str());
+ properties_[ident] = prop;
+}
+
+bool CppBoundClass::IsMethodRegistered(std::string name) {
+ // NPUTF8 is a typedef for char, so this cast is safe.
+ NPIdentifier ident = NPN_GetStringIdentifier((const NPUTF8*)name.c_str());
+ MethodList::iterator callback = methods_.find(ident);
+ return (callback != methods_.end());
+}
+
+void CppBoundClass::BindToJavascript(WebFrame* frame,
+ const std::wstring& classname) {
+#if USE(JAVASCRIPTCORE_BINDINGS)
+ KJS::JSLock lock;
+#endif
+
+ // Create an NPObject using our static NPClass. The first argument (a
+ // plugin's instance handle) is passed through to the allocate function
+ // directly, and we don't use it, so it's ok to be 0.
+ NPObject* np_obj = NPN_CreateObject(0, &CppNPObject::np_class_);
+ CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
+ obj->bound_class = this;
+
+ // BindToWindowObject will (indirectly) retain the np_object. We save it
+ // so we can release it when we're destroyed.
+ frame->BindToWindowObject(classname, np_obj);
+ bound_objects_.push_back(np_obj);
+}
diff --git a/webkit/glue/cpp_bound_class.h b/webkit/glue/cpp_bound_class.h
new file mode 100644
index 0000000..56b4b8e
--- /dev/null
+++ b/webkit/glue/cpp_bound_class.h
@@ -0,0 +1,164 @@
+// 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.
+
+/*
+ CppBoundClass class:
+ This base class serves as a parent for C++ classes designed to be bound to
+ JavaScript objects.
+
+ Subclasses should define the constructor to build the property and method
+ lists needed to bind this class to a JS object. They should also declare
+ and define member variables and methods to be exposed to JS through
+ that object.
+
+ See cpp_binding_example.{h|cc} for an example.
+*/
+
+#ifndef WEBKIT_GLUE_CPP_BOUNDCLASS_H__
+#define WEBKIT_GLUE_CPP_BOUNDCLASS_H__
+
+#include <map>
+#include <vector>
+
+#include "webkit/glue/cpp_variant.h"
+
+#include "base/task.h"
+
+class WebFrame;
+
+typedef std::vector<const CppVariant> CppArgumentList;
+
+// CppBoundClass lets you map Javascript method calls and property accesses
+// directly to C++ method calls and CppVariant* variable access.
+class CppBoundClass {
+ public:
+ // The constructor should call BindMethod, BindProperty, and
+ // SetFallbackMethod as needed to set up the methods, properties, and
+ // fallback method.
+ CppBoundClass() { }
+ virtual ~CppBoundClass();
+
+ // Given a WebFrame, BindToJavascript builds the NPObject that will represent
+ // the class and binds it to the frame's window under the given name. This
+ // should generally be called from the WebView delegate's
+ // WindowObjectCleared(). A class so bound will be accessible to JavaScript
+ // as window.<classname>. The owner of the CppBoundObject is responsible for
+ // keeping the object around while the frame is alive, and for destroying it
+ // afterwards.
+ void BindToJavascript(WebFrame* frame, const std::wstring& classname);
+
+ // The type of callbacks.
+ typedef Callback2<const CppArgumentList&, CppVariant*>::Type Callback;
+
+ // Used by a test. Returns true if a method with name |name| exists,
+ // regardless of whether a fallback is registered.
+ bool IsMethodRegistered(std::string name);
+
+ protected:
+ // Bind the Javascript method called |name| to the C++ callback |callback|.
+ void BindCallback(std::string name, Callback* callback);
+
+ // A wrapper for BindCallback, to simplify the common case of binding a
+ // method on the current object. Though not verified here, |method|
+ // must be a method of this CppBoundClass subclass.
+ template<typename T>
+ void BindMethod(std::string name,
+ void (T::*method)(const CppArgumentList&, CppVariant*)) {
+ Callback* callback =
+ NewCallback<T, const CppArgumentList&, CppVariant*>(
+ static_cast<T*>(this), method);
+ BindCallback(name, callback);
+ }
+
+ // Bind the Javascript property called |name| to a CppVariant |prop|.
+ void BindProperty(std::string name, CppVariant* prop);
+
+ // Set the fallback callback, which is called when when a callback is
+ // invoked that isn't bound.
+ // If it is NULL (its default value), a JavaScript exception is thrown in
+ // that case (as normally expected). If non NULL, the fallback method is
+ // invoked and the script continues its execution.
+ // Passing NULL for |callback| clears out any existing binding.
+ // It is used for tests and should probably only be used in such cases
+ // as it may cause unexpected behaviors (a JavaScript object with a
+ // fallback always returns true when checked for a method's
+ // existence).
+ void BindFallbackCallback(Callback* fallback_callback) {
+ fallback_callback_.reset(fallback_callback);
+ }
+
+ // A wrapper for BindFallbackCallback, to simplify the common case of
+ // binding a method on the current object. Though not verified here,
+ // |method| must be a method of this CppBoundClass subclass.
+ // Passing NULL for |method| clears out any existing binding.
+ template<typename T>
+ void BindFallbackMethod(
+ void (T::*method)(const CppArgumentList&, CppVariant*)) {
+ if (method) {
+ Callback* callback =
+ NewCallback<T, const CppArgumentList&, CppVariant*>(
+ static_cast<T*>(this), method);
+ BindFallbackCallback(callback);
+ } else {
+ BindFallbackCallback(NULL);
+ }
+ }
+
+ // Some fields are protected because some tests depend on accessing them,
+ // but otherwise they should be considered private.
+
+ typedef std::map<NPIdentifier, CppVariant*> PropertyList;
+ typedef std::map<NPIdentifier, Callback*> MethodList;
+ // These maps associate names with property and method pointers to be
+ // exposed to JavaScript.
+ PropertyList properties_;
+ MethodList methods_;
+
+ // The callback gets invoked when a call is made to an nonexistent method.
+ scoped_ptr<Callback> fallback_callback_;
+
+ private:
+ // NPObject callbacks.
+ friend struct CppNPObject;
+ bool HasMethod(NPIdentifier ident);
+ bool Invoke(NPIdentifier ident, const NPVariant* args, size_t arg_count,
+ NPVariant* result);
+ bool HasProperty(NPIdentifier ident);
+ bool GetProperty(NPIdentifier ident, NPVariant* result);
+ bool SetProperty(NPIdentifier ident, const NPVariant* value);
+
+ // A list of all NPObjects we created and bound in BindToJavascript(), so we
+ // can clean them up when we're destroyed.
+ typedef std::vector<NPObject*> BoundObjectList;
+ BoundObjectList bound_objects_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(CppBoundClass);
+};
+
+#endif // CPP_BOUNDCLASS_H__
diff --git a/webkit/glue/cpp_bound_class_unittest.cc b/webkit/glue/cpp_bound_class_unittest.cc
new file mode 100644
index 0000000..c47131aa
--- /dev/null
+++ b/webkit/glue/cpp_bound_class_unittest.cc
@@ -0,0 +1,267 @@
+// 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.
+
+// Tests for CppBoundClass, in conjunction with CppBindingExample. Binds
+// a CppBindingExample class into JavaScript in a custom test shell and tests
+// the binding from the outside by loading JS into the shell.
+
+#include <vector>
+
+#include "base/message_loop.h"
+#include "webkit/glue/cpp_binding_example.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/webframe.h"
+#include "webkit/glue/webview.h"
+#include "webkit/tools/test_shell/test_shell_test.h"
+
+namespace {
+
+class CppBindingExampleWithOptionalFallback : public CppBindingExample {
+ public:
+ CppBindingExampleWithOptionalFallback() {
+ }
+
+ void set_fallback_method_enabled(bool state) {
+ BindFallbackMethod(state ?
+ &CppBindingExampleWithOptionalFallback::fallbackMethod
+ : NULL);
+ }
+
+ // The fallback method does nothing, but because of it the JavaScript keeps
+ // running when a nonexistent method is called on an object.
+ void fallbackMethod(const CppArgumentList& args,
+ CppVariant* result) {
+ }
+};
+
+class ExampleTestShell : public TestShell {
+ public:
+
+ ExampleTestShell(bool use_fallback_method) {
+ example_bound_class_.set_fallback_method_enabled(use_fallback_method);
+ }
+
+ // When called by WebViewDelegate::WindowObjectCleared method, this binds a
+ // CppExampleObject to window.example.
+ virtual void BindJSObjectsToWindow(WebFrame* frame) {
+ example_bound_class_.BindToJavascript(frame, L"example");
+ // We use the layoutTestController binding for notifyDone.
+ TestShell::BindJSObjectsToWindow(frame);
+ }
+
+ // This is a public interface to TestShell's protected method, so it
+ // can be called by our CreateEmptyWindow.
+ bool PublicInitialize(const std::wstring& startingURL) {
+ return Initialize(startingURL);
+ }
+
+ CppBindingExampleWithOptionalFallback example_bound_class_;
+};
+
+class CppBoundClassTest : public TestShellTest {
+ protected:
+ // Adapted from TestShell::CreateNewWindow, this creates an
+ // ExampleTestShellWindow rather than a regular TestShell.
+ virtual void CreateEmptyWindow() {
+ ExampleTestShell* host = new ExampleTestShell(useFallback());
+ ASSERT_TRUE(host != NULL);
+ bool rv = host->PublicInitialize(L"about:blank");
+ if (rv) {
+ test_shell_ = host;
+ TestShell::windowList()->push_back(host->mainWnd());
+ webframe_ = test_shell_->webView()->GetMainFrame();
+ ASSERT_TRUE(webframe_ != NULL);
+ } else {
+ delete host;
+ }
+ }
+
+ // Wraps the given JavaScript snippet in <html><body><script> tags, then
+ // loads it into a webframe so it is executed.
+ void ExecuteJavaScript(const std::string& javascript) {
+ std::string html = "<html><body>";
+ html.append(TestShellTest::kJavascriptDelayExitScript);
+ html.append("<script>");
+ html.append(javascript);
+ html.append("</script></body></html>");
+ // The base URL doesn't matter.
+ webframe_->LoadHTMLString(html, GURL("about:blank"));
+
+ test_shell_->WaitTestFinished();
+ }
+
+ // Executes the specified JavaScript and checks to be sure that the resulting
+ // document text is exactly "SUCCESS".
+ void CheckJavaScriptSuccess(const std::string& javascript) {
+ ExecuteJavaScript(javascript);
+ EXPECT_EQ(L"SUCCESS", webkit_glue::DumpDocumentText(webframe_));
+ }
+
+ // Executes the specified JavaScript and checks that the resulting document
+ // text is empty.
+ void CheckJavaScriptFailure(const std::string& javascript) {
+ ExecuteJavaScript(javascript);
+ EXPECT_EQ(L"", webkit_glue::DumpDocumentText(webframe_));
+ }
+
+ // Constructs a JavaScript snippet that evaluates and compares the left and
+ // right expressions, printing "SUCCESS" to the page if they are equal and
+ // printing their actual values if they are not. Any strings in the
+ // expressions should be enclosed in single quotes, and no double quotes
+ // should appear in either expression (even if escaped). (If a test case
+ // is added that needs fancier quoting, Json::valueToQuotedString could be
+ // used here. For now, it's not worth adding the dependency.)
+ std::string BuildJSCondition(std::string left, std::string right) {
+ return "var leftval = " + left + ";" +
+ "var rightval = " + right + ";" +
+ "if (leftval == rightval) {" +
+ " document.writeln('SUCCESS');" +
+ "} else {" +
+ " document.writeln(\"" +
+ left + " [\" + leftval + \"] != " +
+ right + " [\" + rightval + \"]\");" +
+ "}";
+ }
+
+protected:
+ virtual bool useFallback() {
+ return false;
+ }
+
+private:
+ WebFrame* webframe_;
+};
+
+class CppBoundClassWithFallbackMethodTest : public CppBoundClassTest {
+protected:
+ virtual bool useFallback() {
+ return true;
+ }
+};
+
+} // namespace
+
+// Ensures that the example object has been bound to JS.
+TEST_F(CppBoundClassTest, ObjectExists) {
+ std::string js = BuildJSCondition("typeof window.example", "'object'");
+ CheckJavaScriptSuccess(js);
+
+ // An additional check to test our test.
+ js = BuildJSCondition("typeof window.invalid_object", "'undefined'");
+ CheckJavaScriptSuccess(js);
+}
+
+TEST_F(CppBoundClassTest, PropertiesAreInitialized) {
+ std::string js = BuildJSCondition("example.my_value", "10");
+ CheckJavaScriptSuccess(js);
+
+ js = BuildJSCondition("example.my_other_value", "'Reinitialized!'");
+ CheckJavaScriptSuccess(js);
+}
+
+TEST_F(CppBoundClassTest, SetAndGetProperties) {
+ // The property on the left will be set to the value on the right, then
+ // checked to make sure it holds that same value.
+ static const std::string tests[] = {
+ "example.my_value", "7",
+ "example.my_value", "'test'",
+ "example.my_other_value", "3.14",
+ "example.my_other_value", "false",
+ "" // Array end marker: insert additional test pairs before this.
+ };
+
+ for (int i = 0; tests[i] != ""; i += 2) {
+ std::string left = tests[i];
+ std::string right = tests[i + 1];
+ // left = right;
+ std::string js = left;
+ js.append(" = ");
+ js.append(right);
+ js.append(";");
+ js.append(BuildJSCondition(left, right));
+ CheckJavaScriptSuccess(js);
+ }
+}
+
+TEST_F(CppBoundClassTest, InvokeMethods) {
+ // The expression on the left is expected to return the value on the right.
+ static const std::string tests[] = {
+ "example.echoValue(true)", "true",
+ "example.echoValue(13)", "13",
+ "example.echoValue(2.718)", "2.718",
+ "example.echoValue('yes')", "'yes'",
+ "example.echoValue()", "null", // Too few arguments
+
+ "example.echoType(false)", "true",
+ "example.echoType(19)", "3.14159",
+ "example.echoType(9.876)", "3.14159",
+ "example.echoType('test string')", "'Success!'",
+ "example.echoType()", "null", // Too few arguments
+
+ // Comparing floats that aren't integer-valued is usually problematic due
+ // to rounding, but exact powers of 2 should also be safe.
+ "example.plus(2.5, 18.0)", "20.5",
+ "example.plus(2, 3.25)", "5.25",
+ "example.plus(2, 3)", "5",
+ "example.plus()", "null", // Too few arguments
+ "example.plus(1)", "null", // Too few arguments
+ "example.plus(1, 'test')", "null", // Wrong argument type
+ "example.plus('test', 2)", "null", // Wrong argument type
+ "example.plus('one', 'two')", "null", // Wrong argument type
+ "" // Array end marker: insert additional test pairs before this.
+ };
+
+ for (int i = 0; tests[i] != ""; i+= 2) {
+ std::string left = tests[i];
+ std::string right = tests[i + 1];
+ std::string js = BuildJSCondition(left, right);
+ CheckJavaScriptSuccess(js);
+ }
+
+ std::string js = "example.my_value = 3.25; example.my_other_value = 1.25;";
+ js.append(BuildJSCondition(
+ "example.plus(example.my_value, example.my_other_value)", "4.5"));
+ CheckJavaScriptSuccess(js);
+}
+
+// Tests that invoking a nonexistent method with no fallback method stops the
+// script's execution
+TEST_F(CppBoundClassTest,
+ InvokeNonexistentMethodNoFallback) {
+ std::string js = "example.nonExistentMethod();document.writeln('SUCCESS');";
+ CheckJavaScriptFailure(js);
+}
+
+// Ensures existent methods can be invoked successfully when the fallback method
+// is used
+TEST_F(CppBoundClassWithFallbackMethodTest,
+ InvokeExistentMethodsWithFallback) {
+ std::string js = BuildJSCondition("example.echoValue(34)", "34");
+ CheckJavaScriptSuccess(js);
+}
diff --git a/webkit/glue/cpp_variant.cc b/webkit/glue/cpp_variant.cc
new file mode 100644
index 0000000..0fb43e1
--- /dev/null
+++ b/webkit/glue/cpp_variant.cc
@@ -0,0 +1,276 @@
+// 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 contains definitions for CppVariant.
+
+#include <limits>
+#include "config.h"
+#include "webkit/glue/cpp_variant.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+
+#include "npruntime_priv.h" // for NPN_InitializeVariantWithStringCopy
+
+#if USE(JAVASCRIPTCORE_BINDINGS)
+#define _NPN_InitializeVariantWithStringCopy NPN_InitializeVariantWithStringCopy
+#endif
+
+CppVariant::CppVariant() {
+ type = NPVariantType_Null;
+}
+
+// Note that Set() performs a deep copy, which is necessary to safely
+// call FreeData() on the value in the destructor.
+CppVariant::CppVariant(const CppVariant& original) {
+ type = NPVariantType_Null;
+ Set(original);
+}
+
+// See comment for copy constructor, above.
+CppVariant& CppVariant::operator=(const CppVariant& original) {
+ if (&original != this)
+ Set(original);
+ return *this;
+}
+
+CppVariant::~CppVariant() {
+ FreeData();
+}
+
+void CppVariant::FreeData() {
+ NPN_ReleaseVariantValue(this);
+}
+
+bool CppVariant::isEqual(const CppVariant& other) const {
+ if (type != other.type)
+ return false;
+
+ switch (type) {
+ case NPVariantType_Bool: {
+ return (value.boolValue == other.value.boolValue);
+ }
+ case NPVariantType_Int32: {
+ return (value.intValue == other.value.intValue);
+ }
+ case NPVariantType_Double: {
+ return (value.doubleValue == other.value.doubleValue);
+ }
+ case NPVariantType_String: {
+ const NPString *this_value = &value.stringValue;
+ const NPString *other_value = &other.value.stringValue;
+ uint32_t len = this_value->UTF8Length;
+ return (len == other_value->UTF8Length &&
+ !strncmp(this_value->UTF8Characters, other_value->UTF8Characters,
+ len));
+ }
+ case NPVariantType_Null:
+ case NPVariantType_Void: {
+ return true;
+ }
+ case NPVariantType_Object: {
+ NPObject *this_value = value.objectValue;
+ NPObject *other_value = other.value.objectValue;
+ return (this_value->_class == other_value->_class &&
+ this_value->referenceCount == other_value->referenceCount);
+ }
+ }
+ return false;
+}
+
+void CppVariant::CopyToNPVariant(NPVariant* result) const {
+ result->type = type;
+ switch (type) {
+ case NPVariantType_Bool:
+ result->value.boolValue = value.boolValue;
+ break;
+ case NPVariantType_Int32:
+ result->value.intValue = value.intValue;
+ break;
+ case NPVariantType_Double:
+ result->value.doubleValue = value.doubleValue;
+ break;
+ case NPVariantType_String:
+ _NPN_InitializeVariantWithStringCopy(result, &value.stringValue);
+ break;
+ case NPVariantType_Null:
+ case NPVariantType_Void:
+ // Nothing to set.
+ break;
+ case NPVariantType_Object:
+ result->type = NPVariantType_Object;
+ result->value.objectValue = NPN_RetainObject(value.objectValue);
+ break;
+ }
+}
+
+void CppVariant::Set(const NPVariant& new_value) {
+ FreeData();
+ switch (new_value.type) {
+ case NPVariantType_Bool:
+ Set(new_value.value.boolValue);
+ break;
+ case NPVariantType_Int32:
+ Set(new_value.value.intValue);
+ break;
+ case NPVariantType_Double:
+ Set(new_value.value.doubleValue);
+ break;
+ case NPVariantType_String:
+ Set(new_value.value.stringValue);
+ break;
+ case NPVariantType_Null:
+ case NPVariantType_Void:
+ type = new_value.type;
+ break;
+ case NPVariantType_Object:
+ Set(new_value.value.objectValue);
+ break;
+ }
+}
+
+void CppVariant::SetNull() {
+ FreeData();
+ type = NPVariantType_Null;
+}
+
+void CppVariant::Set(bool new_value) {
+ FreeData();
+ type = NPVariantType_Bool;
+ value.boolValue = new_value;
+}
+
+void CppVariant::Set(int32_t new_value) {
+ FreeData();
+ type = NPVariantType_Int32;
+ value.intValue = new_value;
+}
+
+void CppVariant::Set(double new_value) {
+ FreeData();
+ type = NPVariantType_Double;
+ value.doubleValue = new_value;
+}
+
+// The new_value must be a null-terminated string.
+void CppVariant::Set(const char* new_value) {
+ FreeData();
+ type = NPVariantType_String;
+ NPString new_string = {new_value,
+ static_cast<uint32_t>(strlen(new_value))};
+ _NPN_InitializeVariantWithStringCopy(this, &new_string);
+}
+
+void CppVariant::Set(const std::string& new_value) {
+ FreeData();
+ type = NPVariantType_String;
+ NPString new_string = {new_value.data(),
+ static_cast<uint32_t>(new_value.size())};
+ _NPN_InitializeVariantWithStringCopy(this, &new_string);
+}
+void CppVariant::Set(const NPString& new_value) {
+ FreeData();
+ type = NPVariantType_String;
+ _NPN_InitializeVariantWithStringCopy(this, &new_value);
+}
+
+void CppVariant::Set(NPObject* new_value) {
+ FreeData();
+ type = NPVariantType_Object;
+ value.objectValue = NPN_RetainObject(new_value);
+}
+
+std::string CppVariant::ToString() const {
+ DCHECK(isString());
+ return std::string(value.stringValue.UTF8Characters,
+ value.stringValue.UTF8Length);
+}
+
+int32_t CppVariant::ToInt32() const {
+ if (isInt32()) {
+ return value.intValue;
+ } else if (isDouble()) {
+ return static_cast<int32_t>(value.doubleValue);
+ } else {
+ NOTREACHED();
+ return 0;
+ }
+}
+
+double CppVariant::ToDouble() const {
+ if (isInt32()) {
+ return static_cast<double>(value.intValue);
+ } else if (isDouble()) {
+ return value.doubleValue;
+ } else {
+ NOTREACHED();
+ return 0.0;
+ }
+}
+
+bool CppVariant::ToBoolean() const {
+ DCHECK(isBool());
+ return value.boolValue;
+}
+
+std::vector<std::wstring> CppVariant::ToStringVector() const {
+
+ DCHECK(isObject());
+ std::vector<std::wstring> wstring_vector;
+ NPObject* np_value = value.objectValue;
+ NPIdentifier length_id = NPN_GetStringIdentifier("length");
+
+ if (NPN_HasProperty(NULL, np_value, length_id)) {
+ NPVariant length_value;
+ if (NPN_GetProperty(NULL, np_value, length_id, &length_value)) {
+ int length = 0;
+ // The length is a double in some cases.
+ if (NPVARIANT_IS_DOUBLE(length_value))
+ length = static_cast<int>(NPVARIANT_TO_DOUBLE(length_value));
+ else if (NPVARIANT_IS_INT32(length_value))
+ length = NPVARIANT_TO_INT32(length_value);
+ // For sanity, only allow 100 items.
+ length = std::min(100, length);
+ for (int i = 0; i < length; ++i) {
+ // Get each of the items.
+ std::string index = StringPrintf("%d", i);
+ NPIdentifier index_id = NPN_GetStringIdentifier(index.c_str());
+ if (NPN_HasProperty(NULL, np_value, index_id)) {
+ NPVariant index_value;
+ if (NPN_GetProperty(NULL, np_value, index_id, &index_value) &&
+ NPVARIANT_IS_STRING(index_value)) {
+ std::string string(NPVARIANT_TO_STRING(index_value).UTF8Characters,
+ NPVARIANT_TO_STRING(index_value).UTF8Length);
+ wstring_vector.push_back(UTF8ToWide(string));
+ }
+ }
+ }
+ }
+ }
+ return wstring_vector;
+}
diff --git a/webkit/glue/cpp_variant.h b/webkit/glue/cpp_variant.h
new file mode 100644
index 0000000..5e57a51
--- /dev/null
+++ b/webkit/glue/cpp_variant.h
@@ -0,0 +1,128 @@
+// 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 contains the declaration for CppVariant, a type used by C++ classes
+ that are to be bound to JavaScript objects.
+
+ CppVariant exists primarily as an interface between C++ callers and the
+ corresponding NPVariant type. CppVariant also provides a number of
+ convenience constructors and accessors, so that the NPVariantType values
+ don't need to be exposed, and a destructor to free any memory allocated for
+ string values.
+
+ For a usage example, see cpp_binding_example.{h|cc}.
+*/
+
+#ifndef WEBKIT_GLUE_CPP_VARIANT_H__
+#define WEBKIT_GLUE_CPP_VARIANT_H__
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "bindings/npruntime.h"
+
+class CppVariant : public NPVariant {
+ public:
+ CppVariant();
+ ~CppVariant();
+ void SetNull();
+ void Set(bool value);
+ void Set(int32_t value);
+ void Set(double value);
+
+ // Note that setting a CppVariant to a string value involves copying the
+ // string data, which must be freed with a call to FreeData() when the
+ // CppVariant is set to a different value or is no longer needed. Normally
+ // this is handled by the other Set() methods and by the destructor.
+ void Set(const char* value); // Must be a null-terminated string.
+ void Set(const std::string& value);
+ void Set(const NPString& new_value);
+ void Set(const NPVariant& new_value);
+
+ // Note that setting a CppVariant to an NPObject involves ref-counting
+ // the actual object. FreeData() should only be called if the CppVariant
+ // is no longer needed. The other Set() methods handle this internally.
+ // Also, the object's NPClass is expected to be a static object: neither
+ // the NP runtime nor CPPVariant will ever free it.
+ void Set(NPObject* new_value);
+
+ // These three methods all perform deep copies of any string data. This
+ // allows local CppVariants to be released by the destructor without
+ // corrupting their sources. In performance-critical code, or when strings
+ // are very long, avoid creating new CppVariants.
+ // In case of NPObject as the data, the copying involves ref-counting
+ // as opposed to deep-copying. The ref-counting ensures that sources don't
+ // get corrupted when the copies get destroyed.
+ void CopyToNPVariant(NPVariant* result) const;
+ CppVariant& operator=(const CppVariant& original);
+ CppVariant(const CppVariant& original);
+
+ // Calls NPN_ReleaseVariantValue, which frees any string data
+ // held by the object and sets its type to null.
+ // In case of NPObject, the NPN_ReleaseVariantValue decrements
+ // the ref-count (releases when ref-count becomes 0)
+ void FreeData();
+
+ // Compares this CppVariant's type and value to another's. They must be
+ // identical in both type and value to be considered equal. For string and
+ // object types, a deep comparison is performed; that is, the contents of the
+ // strings, or the classes and refcounts of the objects, must be the same,
+ // but they need not be the same pointers.
+ bool isEqual(const CppVariant& other) const;
+
+ // The value of a CppVariant may be read directly from its NPVariant (but
+ // should only be set using one of the Set() methods above). Although the
+ // type of a CppVariant is likewise public, it can be accessed through these
+ // functions rather than directly if a caller wishes to avoid dependence on
+ // the NPVariantType values.
+ bool isBool() const { return (type == NPVariantType_Bool); }
+ bool isInt32() const { return (type == NPVariantType_Int32); }
+ bool isDouble() const { return (type == NPVariantType_Double); }
+ bool isNumber() const { return (isInt32() || isDouble()); }
+ bool isString() const { return (type == NPVariantType_String); }
+ bool isVoid() const { return (type == NPVariantType_Void); }
+ bool isNull() const { return (type == NPVariantType_Null); }
+ bool isEmpty() const { return (isVoid() || isNull()); }
+ bool isObject() const { return (type == NPVariantType_Object); }
+
+ // Converters. The CppVariant must be of a type convertible to these values.
+ // For example, ToInteger() works only if isNumber() is true.
+ std::string ToString() const;
+ int32_t ToInt32() const;
+ double ToDouble() const;
+ bool ToBoolean() const;
+ // Returns a vector of strings for the specified argument. This is useful
+ // for converting a JavaScript array of strings into a vector of strings.
+ std::vector<std::wstring> ToStringVector() const;
+
+};
+
+#endif // WEBKIT_GLUE_CPP_VARIANT_H__
diff --git a/webkit/glue/cpp_variant_unittest.cc b/webkit/glue/cpp_variant_unittest.cc
new file mode 100644
index 0000000..bc5f7b7
--- /dev/null
+++ b/webkit/glue/cpp_variant_unittest.cc
@@ -0,0 +1,457 @@
+// 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 "config.h"
+
+#include "webkit/glue/cpp_variant.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#pragma warning(push, 0)
+#include "npruntime_priv.h" // for NPN_InitializeVariantWithStringCopy
+#pragma warning(pop)
+
+#if USE(JAVASCRIPTCORE_BINDINGS)
+#define _NPN_InitializeVariantWithStringCopy NPN_InitializeVariantWithStringCopy
+#endif
+
+// Creates a std::string from an NPVariant of string type. If the NPVariant
+// is not a string, empties the std::string.
+void MakeStdString(const NPVariant& np, std::string* std_string) {
+ if (np.type == NPVariantType_String) {
+ const char* chars =
+ reinterpret_cast<const char*>(np.value.stringValue.UTF8Characters);
+ (*std_string).assign(chars, np.value.stringValue.UTF8Length);
+ } else {
+ (*std_string).clear();
+ }
+}
+
+// Verifies that the actual NPVariant is a string and that its value matches
+// the expected_str.
+void CheckString(const std::string& expected_str, const NPVariant& actual) {
+ EXPECT_EQ(NPVariantType_String, actual.type);
+ std::string actual_str;
+ MakeStdString(actual, &actual_str);
+ EXPECT_EQ(expected_str, actual_str);
+}
+
+// Verifies that both the actual and the expected NPVariants are strings and
+// that their values match.
+void CheckString(const NPVariant& expected, const NPVariant& actual) {
+ EXPECT_EQ(NPVariantType_String, expected.type);
+ std::string expected_str;
+ MakeStdString(expected, &expected_str);
+ CheckString(expected_str, actual);
+}
+
+int g_allocate_call_count = 0;
+int g_deallocate_call_count = 0;
+
+void CheckObject(const NPVariant& actual) {
+ EXPECT_EQ(NPVariantType_Object, actual.type);
+ EXPECT_TRUE(actual.value.objectValue);
+ EXPECT_EQ(1, actual.value.objectValue->referenceCount);
+ EXPECT_EQ(1, g_allocate_call_count);
+ EXPECT_EQ(0, g_deallocate_call_count);
+}
+
+NPObject* MockNPAllocate(NPP npp, NPClass* aClass) {
+ // This is a mock allocate method that mimics the behavior
+ // of NPN_CreateObject when allocate() is NULL
+
+ ++g_allocate_call_count;
+ // Ignore npp and NPClass
+ return reinterpret_cast<NPObject*>(malloc(sizeof(NPObject)));
+}
+
+void MockNPDeallocate(NPObject* npobj) {
+ // This is a mock deallocate method that mimics the behavior
+ // of NPN_DeallocateObject when deallocate() is NULL
+
+ ++g_deallocate_call_count;
+ free(npobj);
+}
+
+static NPClass void_class = { NP_CLASS_STRUCT_VERSION,
+ MockNPAllocate,
+ MockNPDeallocate,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+NPObject* MakeVoidObject() {
+ g_allocate_call_count = 0;
+ g_deallocate_call_count = 0;
+ return NPN_CreateObject(NULL, &void_class);
+}
+
+TEST(CppVariantTest, NewVariantHasNullType) {
+ CppVariant value;
+ EXPECT_EQ(NPVariantType_Null, value.type);
+}
+
+TEST(CppVariantTest, SetNullSetsType) {
+ CppVariant value;
+ value.Set(17);
+ value.SetNull();
+ EXPECT_EQ(NPVariantType_Null, value.type);
+}
+
+TEST(CppVariantTest, CopyConstructorDoesDeepCopy) {
+ CppVariant source;
+ source.Set("test string");
+ CppVariant dest = source;
+ EXPECT_EQ(NPVariantType_String, dest.type);
+ EXPECT_EQ(NPVariantType_String, source.type);
+
+ // Ensure that the string was copied, not just the pointer.
+ EXPECT_NE(source.value.stringValue.UTF8Characters,
+ dest.value.stringValue.UTF8Characters);
+
+ CheckString(source, dest);
+}
+
+TEST(CppVariantTest, CopyConstructorIncrementsRefCount) {
+ CppVariant source;
+ NPObject *object = MakeVoidObject();
+ source.Set(object);
+ // 2 references so far.
+ EXPECT_EQ(2, source.value.objectValue->referenceCount);
+
+ CppVariant dest = source;
+ EXPECT_EQ(3, dest.value.objectValue->referenceCount);
+ EXPECT_EQ(1, g_allocate_call_count);
+ NPN_ReleaseObject(object);
+ source.SetNull();
+ CheckObject(dest);
+}
+
+TEST(CppVariantTest, AssignmentDoesDeepCopy) {
+ CppVariant source;
+ source.Set("test string");
+ CppVariant dest;
+ dest = source;
+ EXPECT_EQ(NPVariantType_String, dest.type);
+ EXPECT_EQ(NPVariantType_String, source.type);
+
+ // Ensure that the string was copied, not just the pointer.
+ EXPECT_NE(source.value.stringValue.UTF8Characters,
+ dest.value.stringValue.UTF8Characters);
+
+ CheckString(source, dest);
+}
+
+TEST(CppVariantTest, AssignmentIncrementsRefCount) {
+ CppVariant source;
+ NPObject *object = MakeVoidObject();
+ source.Set(object);
+ // 2 references so far.
+ EXPECT_EQ(2, source.value.objectValue->referenceCount);
+
+ CppVariant dest;
+ dest = source;
+ EXPECT_EQ(3, dest.value.objectValue->referenceCount);
+ EXPECT_EQ(1, g_allocate_call_count);
+
+ NPN_ReleaseObject(object);
+ source.SetNull();
+ CheckObject(dest);
+}
+
+TEST(CppVariantTest, DestroyingCopyDoesNotCorruptSource) {
+ CppVariant source;
+ source.Set("test string");
+ std::string before;
+ MakeStdString(source, &before);
+ {
+ CppVariant dest = source;
+ }
+ CheckString(before, source);
+
+ NPObject *object = MakeVoidObject();
+ source.Set(object);
+ {
+ CppVariant dest2 = source;
+ }
+ NPN_ReleaseObject(object);
+ CheckObject(source);
+}
+
+TEST(CppVariantTest, CopiesTypeAndValueToNPVariant) {
+ NPVariant np;
+ CppVariant cpp;
+
+ cpp.Set(true);
+ cpp.CopyToNPVariant(&np);
+ EXPECT_EQ(cpp.type, np.type);
+ EXPECT_EQ(cpp.value.boolValue, np.value.boolValue);
+ NPN_ReleaseVariantValue(&np);
+
+ cpp.Set(17);
+ cpp.CopyToNPVariant(&np);
+ EXPECT_EQ(cpp.type, np.type);
+ EXPECT_EQ(cpp.value.intValue, np.value.intValue);
+ NPN_ReleaseVariantValue(&np);
+
+ cpp.Set(3.1415);
+ cpp.CopyToNPVariant(&np);
+ EXPECT_EQ(cpp.type, np.type);
+ EXPECT_EQ(cpp.value.doubleValue, np.value.doubleValue);
+ NPN_ReleaseVariantValue(&np);
+
+ cpp.Set("test value");
+ cpp.CopyToNPVariant(&np);
+ CheckString("test value", np);
+ NPN_ReleaseVariantValue(&np);
+
+ cpp.SetNull();
+ cpp.CopyToNPVariant(&np);
+ EXPECT_EQ(cpp.type, np.type);
+ NPN_ReleaseVariantValue(&np);
+
+ NPObject *object = MakeVoidObject();
+ cpp.Set(object);
+ cpp.CopyToNPVariant(&np);
+ NPN_ReleaseObject(object);
+ cpp.SetNull();
+ CheckObject(np);
+ NPN_ReleaseVariantValue(&np);
+}
+
+TEST(CppVariantTest, SetsTypeAndValueFromNPVariant) {
+ NPVariant np;
+ CppVariant cpp;
+
+ VOID_TO_NPVARIANT(np);
+ cpp.Set(np);
+ EXPECT_EQ(np.type, cpp.type);
+ NPN_ReleaseVariantValue(&np);
+
+ NULL_TO_NPVARIANT(np);
+ cpp.Set(np);
+ EXPECT_EQ(np.type, cpp.type);
+ NPN_ReleaseVariantValue(&np);
+
+ BOOLEAN_TO_NPVARIANT(true, np);
+ cpp.Set(np);
+ EXPECT_EQ(np.type, cpp.type);
+ EXPECT_EQ(np.value.boolValue, cpp.value.boolValue);
+ NPN_ReleaseVariantValue(&np);
+
+ INT32_TO_NPVARIANT(15, np);
+ cpp.Set(np);
+ EXPECT_EQ(np.type, cpp.type);
+ EXPECT_EQ(np.value.intValue, cpp.value.intValue);
+ NPN_ReleaseVariantValue(&np);
+
+ DOUBLE_TO_NPVARIANT(2.71828, np);
+ cpp.Set(np);
+ EXPECT_EQ(np.type, cpp.type);
+ EXPECT_EQ(np.value.doubleValue, cpp.value.doubleValue);
+ NPN_ReleaseVariantValue(&np);
+
+ NPString np_ascii_str = { "1st test value",
+ static_cast<uint32_t>(strlen("1st test value")) };
+ _NPN_InitializeVariantWithStringCopy(&np, &np_ascii_str);
+ cpp.Set(np);
+ CheckString("1st test value", cpp);
+ NPN_ReleaseVariantValue(&np);
+
+ // Test characters represented in 2/3/4 bytes in UTF-8
+ // Greek alpha, Chinese number 1 (horizontal bar),
+ // Deseret letter (similar to 'O')
+ NPString np_intl_str = { "\xce\xb1\xe4\xb8\x80\xf0\x90\x90\x84",
+ static_cast<uint32_t>(strlen(
+ "\xce\xb1\xe4\xb8\x80\xf0\x90\x90\x84")) };
+ _NPN_InitializeVariantWithStringCopy(&np, &np_intl_str);
+ cpp.Set(np);
+ CheckString("\xce\xb1\xe4\xb8\x80\xf0\x90\x90\x84", cpp);
+ NPN_ReleaseVariantValue(&np);
+
+ NPObject *obj = MakeVoidObject();
+ OBJECT_TO_NPVARIANT(obj, np); // Doesn't make a copy.
+ cpp.Set(np);
+ NPN_ReleaseVariantValue(&np); // or NPN_ReleaseObject but NOT both
+ CheckObject(cpp);
+}
+
+TEST(CppVariantTest, SetsSimpleTypesAndValues) {
+ CppVariant cpp;
+ cpp.Set(true);
+ EXPECT_EQ(NPVariantType_Bool, cpp.type);
+ EXPECT_EQ(true, cpp.value.boolValue);
+
+ cpp.Set(5);
+ EXPECT_EQ(NPVariantType_Int32, cpp.type);
+ EXPECT_EQ(5, cpp.value.intValue);
+
+ cpp.Set(1.234);
+ EXPECT_EQ(NPVariantType_Double, cpp.type);
+ EXPECT_EQ(1.234, cpp.value.doubleValue);
+
+ // C string
+ cpp.Set("1st test string");
+ CheckString("1st test string", cpp);
+
+ // std::string
+ std::string source("std test string");
+ cpp.Set(source);
+ CheckString("std test string", cpp);
+
+ // NPString
+ const char *ascii_str = "test NPString";
+ NPString np_ascii_str = { "test NPString",
+ static_cast<uint32_t>(strlen("test NPString")) };
+ cpp.Set(np_ascii_str);
+ std::string expected("test NPString");
+ CheckString(expected, cpp);
+
+ // Test characters represented in 2/3/4 bytes in UTF-8
+ // Greek alpha, Chinese number 1 (horizontal bar),
+ // Deseret letter (similar to 'O')
+ NPString np_intl_str = { "\xce\xb1\xe4\xb8\x80\xf0\x90\x90\x84",
+ static_cast<uint32_t>(strlen(
+ "\xce\xb1\xe4\xb8\x80\xf0\x90\x90\x84")) };
+ cpp.Set(np_intl_str);
+ expected = std::string("\xce\xb1\xe4\xb8\x80\xf0\x90\x90\x84");
+ CheckString(expected, cpp);
+
+ NPObject* obj = MakeVoidObject();
+ cpp.Set(obj);
+ NPN_ReleaseObject(obj);
+ CheckObject(cpp);
+}
+
+TEST(CppVariantTest, FreeDataSetsToVoid) {
+ CppVariant cpp;
+ EXPECT_EQ(NPVariantType_Null, cpp.type);
+ cpp.Set(12);
+ EXPECT_EQ(NPVariantType_Int32, cpp.type);
+ cpp.FreeData();
+ EXPECT_EQ(NPVariantType_Void, cpp.type);
+}
+
+TEST(CppVariantTest, FreeDataReleasesObject) {
+ CppVariant cpp;
+ NPObject* object = MakeVoidObject();
+ cpp.Set(object);
+ EXPECT_EQ(2, object->referenceCount);
+ cpp.FreeData();
+ EXPECT_EQ(1, object->referenceCount);
+ EXPECT_EQ(0, g_deallocate_call_count);
+
+ cpp.Set(object);
+ NPN_ReleaseObject(object);
+ EXPECT_EQ(0, g_deallocate_call_count);
+ cpp.FreeData();
+ EXPECT_EQ(1, g_deallocate_call_count);
+}
+
+TEST(CppVariantTest, IsTypeFunctionsWork) {
+ CppVariant cpp;
+ // These should not happen in practice, since voids are not supported
+ // This test must be first since it just clobbers internal data without
+ // releasing.
+ VOID_TO_NPVARIANT(cpp);
+ EXPECT_FALSE(cpp.isBool());
+ EXPECT_FALSE(cpp.isInt32());
+ EXPECT_FALSE(cpp.isDouble());
+ EXPECT_FALSE(cpp.isNumber());
+ EXPECT_FALSE(cpp.isString());
+ EXPECT_TRUE(cpp.isVoid());
+ EXPECT_FALSE(cpp.isNull());
+ EXPECT_TRUE(cpp.isEmpty());
+
+ cpp.Set(true);
+ EXPECT_TRUE(cpp.isBool());
+ EXPECT_FALSE(cpp.isInt32());
+ EXPECT_FALSE(cpp.isDouble());
+ EXPECT_FALSE(cpp.isNumber());
+ EXPECT_FALSE(cpp.isString());
+ EXPECT_FALSE(cpp.isVoid());
+ EXPECT_FALSE(cpp.isNull());
+ EXPECT_FALSE(cpp.isEmpty());
+ EXPECT_FALSE(cpp.isObject());
+
+ cpp.Set(12);
+ EXPECT_FALSE(cpp.isBool());
+ EXPECT_TRUE(cpp.isInt32());
+ EXPECT_FALSE(cpp.isDouble());
+ EXPECT_TRUE(cpp.isNumber());
+ EXPECT_FALSE(cpp.isString());
+ EXPECT_FALSE(cpp.isVoid());
+ EXPECT_FALSE(cpp.isNull());
+ EXPECT_FALSE(cpp.isEmpty());
+ EXPECT_FALSE(cpp.isObject());
+
+ cpp.Set(3.1415);
+ EXPECT_FALSE(cpp.isBool());
+ EXPECT_FALSE(cpp.isInt32());
+ EXPECT_TRUE(cpp.isDouble());
+ EXPECT_TRUE(cpp.isNumber());
+ EXPECT_FALSE(cpp.isString());
+ EXPECT_FALSE(cpp.isVoid());
+ EXPECT_FALSE(cpp.isNull());
+ EXPECT_FALSE(cpp.isEmpty());
+ EXPECT_FALSE(cpp.isObject());
+
+ cpp.Set("a string");
+ EXPECT_FALSE(cpp.isBool());
+ EXPECT_FALSE(cpp.isInt32());
+ EXPECT_FALSE(cpp.isDouble());
+ EXPECT_FALSE(cpp.isNumber());
+ EXPECT_TRUE(cpp.isString());
+ EXPECT_FALSE(cpp.isVoid());
+ EXPECT_FALSE(cpp.isNull());
+ EXPECT_FALSE(cpp.isEmpty());
+ EXPECT_FALSE(cpp.isObject());
+
+ cpp.SetNull();
+ EXPECT_FALSE(cpp.isBool());
+ EXPECT_FALSE(cpp.isInt32());
+ EXPECT_FALSE(cpp.isDouble());
+ EXPECT_FALSE(cpp.isNumber());
+ EXPECT_FALSE(cpp.isString());
+ EXPECT_FALSE(cpp.isVoid());
+ EXPECT_TRUE(cpp.isNull());
+ EXPECT_TRUE(cpp.isEmpty());
+ EXPECT_FALSE(cpp.isObject());
+
+ NPObject *obj = MakeVoidObject();
+ cpp.Set(obj);
+ EXPECT_FALSE(cpp.isBool());
+ EXPECT_FALSE(cpp.isInt32());
+ EXPECT_FALSE(cpp.isDouble());
+ EXPECT_FALSE(cpp.isNumber());
+ EXPECT_FALSE(cpp.isString());
+ EXPECT_FALSE(cpp.isVoid());
+ EXPECT_FALSE(cpp.isNull());
+ EXPECT_FALSE(cpp.isEmpty());
+ EXPECT_TRUE(cpp.isObject());
+ NPN_ReleaseObject(obj);
+ CheckObject(cpp);
+}
diff --git a/webkit/glue/debugger.cc b/webkit/glue/debugger.cc
new file mode 100644
index 0000000..469870a
--- /dev/null
+++ b/webkit/glue/debugger.cc
@@ -0,0 +1,86 @@
+// 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 "config.h" // webkit config for V8_BINDING
+#include "base/string_util.h"
+#include "webkit/glue/debugger.h"
+
+#if USE(V8_BINDING)
+#define USING_V8
+#include "v8/public/debug.h"
+#endif
+
+void V8DebugMessageHandler(const uint16_t* message, int length, void* data) {
+ std::wstring out(reinterpret_cast<const wchar_t*>(message), length);
+ reinterpret_cast<Debugger*>(data)->OutputLater(out);
+}
+
+Debugger::Debugger(Delegate* del) : delegate_(del), attached_(false) {
+ delegate_loop_ = MessageLoop::current();
+}
+
+Debugger::~Debugger() {
+ DCHECK(!attached_);
+ Detach();
+}
+
+void Debugger::Attach() {
+#ifdef USING_V8
+ if (!attached_) {
+ attached_ = true;
+ v8::Debug::SetMessageHandler(V8DebugMessageHandler, this);
+ }
+#endif
+}
+
+void Debugger::Detach() {
+#ifdef USING_V8
+ if (attached_) {
+ attached_ = false;
+ v8::Debug::SetMessageHandler(NULL);
+ }
+#endif
+}
+
+void Debugger::OutputLater(const std::wstring& out) {
+ delegate_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &Debugger::Output, out));
+}
+
+void Debugger::Output(const std::wstring& out) {
+ delegate_->DebuggerOutput(out);
+}
+
+void Debugger::Command(const std::wstring& cmd) {
+#ifdef USING_V8
+ DCHECK(attached_);
+ v8::Debug::SendCommand(reinterpret_cast<const uint16_t*>(cmd.data()),
+ cmd.length());
+#endif
+}
diff --git a/webkit/glue/debugger.h b/webkit/glue/debugger.h
new file mode 100644
index 0000000..cb10804
--- /dev/null
+++ b/webkit/glue/debugger.h
@@ -0,0 +1,84 @@
+// 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.
+
+// An interface to the V8 debugger. This is in WebKit in order to isolate
+// the renderer from a direct V8 dependency.
+
+#ifndef WEBKIT_GLUE_DEBUGGER_H
+#define WEBKIT_GLUE_DEBUGGER_H
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/message_loop.h"
+
+#include "v8/public/debug.h"
+
+void V8DebugMessageHandler(const uint16_t* message, int length, void* data);
+
+class Debugger : public base::RefCountedThreadSafe<Debugger> {
+public:
+ class Delegate {
+ public:
+ virtual void DebuggerOutput(const std::wstring& data) = 0;
+ };
+ // When constructed, the underlying V8 debugger is initialized and connected
+ // to the internals of this object. The provided delegate received output
+ // from the debugger. This output may be spontaneous (error messages,
+ // exceptions, etc.) or the output from a command.
+ // NOTE: the delegate will be called from another thread
+ Debugger(Debugger::Delegate* del);
+ virtual ~Debugger();
+
+ // Sends a command to the debugger (same as v8 command-line debugger).
+ // Results from the command come asynchronously.
+ // TODO(erikkay): link command output to a particular command
+ void Command(const std::wstring& cmd);
+
+ // Attach and detach from the V8 debug message handler.
+ void Attach();
+ void Detach();
+
+private:
+ friend void V8DebugMessageHandler(const uint16_t* message, int length, void* data);
+
+ // Called by the LocalDebugSession so that the delegate can called in the
+ // appropriate thread.
+ void OutputLater(const std::wstring& cmd);
+ // Calls the delegate. This method is called in the delegate's thread.
+ void Output(const std::wstring& out);
+
+ Delegate* delegate_;
+ MessageLoop* delegate_loop_;
+ bool attached_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(Debugger);
+};
+
+#endif // WEBKIT_GLUE_DEBUGGER_H
diff --git a/webkit/glue/dom_operations.cc b/webkit/glue/dom_operations.cc
new file mode 100644
index 0000000..dd89d84
--- /dev/null
+++ b/webkit/glue/dom_operations.cc
@@ -0,0 +1,791 @@
+// 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 "config.h"
+
+#pragma warning(push, 0)
+#include "FrameLoader.h"
+#include "FrameTree.h"
+#include "Document.h"
+#include "Element.h"
+#include "EventListener.h"
+#include "EventNames.h"
+#include "HTMLCollection.h"
+#include "HTMLElement.h"
+#include "HTMLFormElement.h"
+#include "HTMLFrameOwnerElement.h"
+#include "HTMLHeadElement.h"
+#include "HTMLInputElement.h"
+#include "HTMLLinkElement.h"
+#include "HTMLMetaElement.h"
+#include "HTMLNames.h"
+#include "KURL.h"
+#pragma warning(pop)
+#undef LOG
+
+#include "webkit/glue/dom_operations.h"
+
+#include "base/string_util.h"
+#include "webkit/glue/autocomplete_input_listener.h"
+#include "webkit/glue/form_data.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/password_autocomplete_listener.h"
+#include "webkit/glue/webframe_impl.h"
+#include "webkit/glue/webview_impl.h"
+
+using WebCore::String;
+
+namespace {
+
+// Structure for storage the unique set of all savable resource links for
+// making sure that no duplicated resource link in final result. The consumer
+// of the SavableResourcesUniqueCheck is responsible for keeping these pointers
+// valid for the lifetime of the SavableResourcesUniqueCheck instance.
+struct SavableResourcesUniqueCheck {
+ // Unique set of all sub resource links.
+ std::set<GURL>* resources_set;
+ // Unique set of all frame links.
+ std::set<GURL>* frames_set;
+ // Collection of all frames we go through when getting all savable resource
+ // links.
+ std::vector<WebFrameImpl*>* frames;
+
+ SavableResourcesUniqueCheck()
+ : resources_set(NULL),
+ frames_set(NULL),
+ frames(NULL) {}
+
+ SavableResourcesUniqueCheck(std::set<GURL>* resources_set,
+ std::set<GURL>* frames_set, std::vector<WebFrameImpl*>* frames)
+ : resources_set(resources_set),
+ frames_set(frames_set),
+ frames(frames) {}
+};
+
+// Get all savable resource links from current element. One element might
+// have more than one resource link. It is possible to have some links
+// in one CSS stylesheet.
+void GetSavableResourceLinkForElement(WebCore::Element* element,
+ WebCore::Document* current_doc, SavableResourcesUniqueCheck* unique_check,
+ webkit_glue::SavableResourcesResult* result) {
+ // Handle frame and iframe tag.
+ bool is_frame_element;
+ WebFrameImpl* web_frame =
+ webkit_glue::GetWebFrameImplFromElement(element, &is_frame_element);
+ if (is_frame_element) {
+ if (web_frame)
+ unique_check->frames->push_back(web_frame);
+ return;
+ }
+ // Check whether the node has sub resource URL or not.
+ const WebCore::AtomicString* value =
+ webkit_glue::GetSubResourceLinkFromElement(element);
+ if (!value)
+ return;
+ // Get absolute URL.
+ GURL u(webkit_glue::KURLToGURL(current_doc->completeURL((*value).
+ deprecatedString())));
+ // ignore invalid URL
+ if (!u.is_valid())
+ return;
+ // Ignore those URLs which are not standard protocols. Because FTP
+ // protocol does no have cache mechanism, we will skip all
+ // sub-resources if they use FTP protocol.
+ if (!u.SchemeIs("http") && !u.SchemeIs("https") && !u.SchemeIs("file"))
+ return;
+ // Ignore duplicated resource link.
+ if (!unique_check->resources_set->insert(u).second)
+ return;
+ result->resources_list->push_back(u);
+ // Insert referrer for above new resource link.
+ if (current_doc->frame()) {
+ GURL u(webkit_glue::KURLToGURL(
+ current_doc->frame()->loader()->outgoingReferrer().
+ deprecatedString()));
+ result->referrers_list->push_back(u);
+ } else {
+ // Insert blank referrer.
+ result->referrers_list->push_back(GURL());
+ }
+}
+
+// Get all savable resource links from current WebFrameImpl object pointer.
+void GetAllSavableResourceLinksForFrame(WebFrameImpl* current_frame,
+ SavableResourcesUniqueCheck* unique_check,
+ webkit_glue::SavableResourcesResult* result) {
+ // Get current frame's URL.
+ const WebCore::KURL& current_frame_kurl =
+ current_frame->frame()->loader()->url();
+ GURL current_frame_gurl(webkit_glue::KURLToGURL(current_frame_kurl));
+
+ // If url of current frame is invalid or not standard protocol, ignore it.
+ if (!current_frame_gurl.is_valid())
+ return;
+ if (!current_frame_gurl.SchemeIs("http") &&
+ !current_frame_gurl.SchemeIs("https") &&
+ !current_frame_gurl.SchemeIs("ftp") &&
+ !current_frame_gurl.SchemeIs("file"))
+ return;
+ // If find same frame we have recorded, ignore it.
+ if (!unique_check->frames_set->insert(current_frame_gurl).second)
+ return;
+
+ // Get current using document.
+ WebCore::Document* current_doc = current_frame->frame()->document();
+ // Go through all descent nodes.
+ PassRefPtr<WebCore::HTMLCollection> all = current_doc->all();
+ // Go through all node in this frame.
+ for (WebCore::Node* node = all->firstItem(); node != NULL;
+ node = all->nextItem()) {
+ // We only save HTML resources.
+ if (!node->isHTMLElement())
+ continue;
+ WebCore::Element* element = static_cast<WebCore::Element*>(node);
+ GetSavableResourceLinkForElement(element,
+ current_doc,
+ unique_check,
+ result);
+ }
+}
+
+} // namespace
+
+namespace webkit_glue {
+
+// Map element name to a list of pointers to corresponding elements to simplify
+// form filling.
+typedef std::map<std::wstring, RefPtr<WebCore::HTMLInputElement> >
+ FormElementRefMap;
+
+// Utility struct for form lookup and autofill. When we parse the DOM to lookup
+// a form, in addition to action and origin URL's we have to compare all
+// necessary form elements. To avoid having to look these up again when we want
+// to fill the form, the FindFormElements function stores the pointers
+// in a FormElements* result, referenced to ensure they are safe to use.
+struct FormElements {
+ RefPtr<WebCore::HTMLFormElement> form_element;
+ FormElementRefMap input_elements;
+ FormElements() : form_element(NULL) {
+ }
+};
+
+typedef std::vector<FormElements*> FormElementsList;
+
+static bool FillFormToUploadFileImpl(WebCore::HTMLFormElement* fe,
+ const FileUploadData& data) {
+ std::vector<WebCore::HTMLInputElement*> changed;
+ PassRefPtr<WebCore::HTMLCollection> elements = fe->elements();
+ int i, c;
+
+ bool file_found = false;
+ bool submit_found = false;
+
+ // We reference the form element itself just in case it is destroyed by one
+ // of the onLoad() handler.
+ fe->ref();
+
+ for (i = 0, c = elements->length(); i < c; ++i) {
+ WebCore::HTMLInputElement* ie =
+ static_cast<WebCore::HTMLInputElement*>(elements->item(i));
+
+ std::wstring name = StringToStdWString(ie->name());
+ std::wstring id = StringToStdWString(ie->id());
+
+ if (!file_found &&
+ ie->inputType() == WebCore::HTMLInputElement::FILE &&
+ (name == data.file_name || id == data.file_name)) {
+ ie->setValueFromRenderer(StdWStringToString(data.file_path));
+ ie->ref();
+ changed.push_back(ie);
+ file_found = true;
+ } else if (!submit_found &&
+ ie->inputType() == WebCore::HTMLInputElement::SUBMIT &&
+ (name == data.submit_name || id == data.submit_name)) {
+ ie->setActivatedSubmit(true);
+ submit_found = true;
+ } else {
+ FormValueMap::const_iterator val = data.other_form_values.find(name);
+ if (val != data.other_form_values.end()) {
+ ie->setValueFromRenderer(StdWStringToString(val->second));
+ ie->ref();
+ changed.push_back(ie);
+ } else {
+ val = data.other_form_values.find(id);
+ if (val != data.other_form_values.end()) {
+ ie->setValueFromRenderer(StdWStringToString(val->second));
+ ie->ref();
+ changed.push_back(ie);
+ }
+ }
+ }
+ }
+
+ // Call all the onChange functions.
+ std::vector<WebCore::HTMLInputElement*>::iterator changed_ie;
+ for (changed_ie = changed.begin(); changed_ie != changed.end();
+ ++changed_ie) {
+ (*changed_ie)->onChange();
+ (*changed_ie)->deref();
+ }
+
+ // If we found both the file and the submit button, let's submit.
+ if (file_found && submit_found) {
+ fe->submit();
+ }
+
+ fe->deref();
+
+ // This operation is successful if the file input has been
+ // configured.
+ return file_found;
+}
+
+bool FillFormToUploadFile(WebView* view, const FileUploadData& data) {
+ WebFrame* main_frame = view->GetMainFrame();
+ if (!main_frame)
+ return false;
+ WebFrameImpl* main_frame_impl = static_cast<WebFrameImpl*>(main_frame);
+ WebCore::Frame* frame = main_frame_impl->frame();
+ WebCore::Frame* f;
+ for (f = frame; f; f = f->tree()->traverseNext()) {
+ WebCore::Document* doc = f->document();
+ if (doc->isHTMLDocument()) {
+ PassRefPtr<WebCore::HTMLCollection> forms = doc->forms();
+ int i, c;
+ for (i = 0, c = forms->length(); i < c; ++i) {
+ WebCore::HTMLFormElement* fe =
+ static_cast<WebCore::HTMLFormElement*>(forms->item(i));
+ std::wstring name = StringToStdWString(fe->name());
+ std::wstring id = StringToStdWString(fe->id());
+ if (data.form_name.empty() ||
+ id == data.form_name || name == data.form_name) {
+ if (FillFormToUploadFileImpl(fe, data))
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+// Internal implementation of FillForm API.
+static bool FillFormImpl(FormElements* fe, const FormData& data, bool submit) {
+ if (!fe->form_element->autoComplete())
+ return false;
+
+ FormValueMap data_map;
+ for (unsigned int i = 0; i < data.elements.size(); i++) {
+ data_map[data.elements[i]] = data.values[i];
+ }
+
+ bool submit_found = false;
+ for (FormElementRefMap::iterator it = fe->input_elements.begin();
+ it != fe->input_elements.end(); ++it) {
+ if (it->first == data.submit) {
+ it->second->setActivatedSubmit(true);
+ submit_found = true;
+ continue;
+ }
+ it->second->setValue(StdWStringToString(data_map[it->first]));
+ it->second->setAutofilled(true);
+ it->second->onChange();
+ }
+
+ if (submit && submit_found) {
+ fe->form_element->submit();
+ return true;
+ }
+ return false;
+}
+
+// Helper function to cast a Node as an HTMLInputElement.
+static WebCore::HTMLInputElement* GetNodeAsInputElement(WebCore::Node* node) {
+ DCHECK(node->nodeType() == WebCore::Node::ELEMENT_NODE);
+ DCHECK(static_cast<WebCore::Element*>(node)->hasTagName(
+ WebCore::HTMLNames::inputTag));
+ return static_cast<WebCore::HTMLInputElement*>(node);
+}
+
+// Helper to search the given form element for the specified input elements
+// in |data|, and add results to |result|.
+static bool FindFormInputElements(WebCore::HTMLFormElement* fe,
+ const FormData& data,
+ FormElements* result) {
+ Vector<RefPtr<WebCore::Node> > temp_elements;
+ bool found_elements = true;
+ // Loop through the list of elements we need to find on the form in
+ // order to autofill it. If we don't find any one of them, abort
+ // processing this form; it can't be the right one.
+ for (size_t j = 0; j < data.elements.size(); j++, temp_elements.clear()) {
+ fe->getNamedElements(StdWStringToString(data.elements[j]),
+ temp_elements);
+ if (temp_elements.isEmpty()) {
+ // We didn't find a required element. This is not the right form.
+ // Make sure no input elements from a partially matched form
+ // in this iteration remain in the result set.
+ // Note: clear will remove a reference from each InputElement.
+ result->input_elements.clear();
+ return false;
+ }
+ // This element matched, add it to our temporary result. It's possible
+ // there are multiple matches, but for purposes of identifying the form
+ // one suffices and if some function needs to deal with multiple
+ // matching elements it can get at them through the FormElement*.
+ // Note: This assignment adds a reference to the InputElement.
+ result->input_elements[data.elements[j]] =
+ GetNodeAsInputElement(temp_elements[0].get());
+ }
+ return true;
+}
+
+// Helper to locate form elements identified by |data|.
+static void FindFormElements(WebView* view,
+ const FormData& data,
+ FormElementsList* results) {
+ DCHECK(view);
+ DCHECK(results);
+ WebFrame* main_frame = view->GetMainFrame();
+ if (!main_frame)
+ return;
+
+ GURL::Replacements rep;
+ rep.ClearQuery();
+ rep.ClearRef();
+ WebFrameImpl* main_frame_impl = static_cast<WebFrameImpl*>(main_frame);
+ WebCore::Frame* frame = main_frame_impl->frame();
+
+ // Loop through each frame.
+ for (WebCore::Frame* f = frame; f; f = f->tree()->traverseNext()) {
+ WebCore::Document* doc = f->document();
+ if (!doc->isHTMLDocument())
+ continue;
+
+ GURL full_origin(StringToStdWString(doc->documentURI()));
+ if (data.origin != full_origin.ReplaceComponents(rep))
+ continue;
+
+ WebCore::FrameLoader* loader = f->loader();
+ if (loader == NULL)
+ continue;
+
+ PassRefPtr<WebCore::HTMLCollection> forms = doc->forms();
+ for (size_t i = 0; i < forms->length(); ++i) {
+ WebCore::HTMLFormElement* fe =
+ static_cast<WebCore::HTMLFormElement*>(forms->item(i));
+
+ // Action URL must match.
+ GURL full_action(KURLToGURL(loader->completeURL(fe->action())));
+ if (data.action != full_action.ReplaceComponents(rep))
+ continue;
+
+ scoped_ptr<FormElements> curr_elements(new FormElements);
+ if (!FindFormInputElements(fe, data, curr_elements.get()))
+ continue;
+
+ // We found the right element.
+ // Note: this assignment adds a reference to |fe|.
+ curr_elements->form_element = fe;
+ results->push_back(curr_elements.release());
+ }
+ }
+}
+
+bool FillForm(WebView* view, const FormData& data) {
+ FormElementsList forms;
+ FindFormElements(view, data, &forms);
+ bool success = false;
+ if (!forms.empty())
+ success = FillFormImpl(forms[0], data, false);
+
+ // TODO(timsteele): Move STLDeleteElements to base/ and have FormElementsList
+ // use that.
+ FormElementsList::iterator iter;
+ for (iter = forms.begin(); iter != forms.end(); ++iter)
+ delete *iter;
+ return success;
+}
+
+void FillPasswordForm(WebView* view,
+ const PasswordFormDomManager::FillData& data) {
+ FormElementsList forms;
+ // We own the FormElements* in forms.
+ FindFormElements(view, data.basic_data, &forms);
+ FormElementsList::iterator iter;
+ for (iter = forms.begin(); iter != forms.end(); ++iter) {
+ // TODO(timsteele): Move STLDeleteElements to base/ and have
+ // FormElementsList use that.
+ scoped_ptr<FormElements> form_elements(*iter);
+
+ // False param to FillFormByAction is so we don't auto-submit password
+ // forms. If wait_for_username is true, we don't want to initially fill
+ // the form until the user types in a valid username.
+ if (!data.wait_for_username)
+ FillFormImpl(form_elements.get(), data.basic_data, false);
+
+ // Attach autocomplete listener to enable selecting alternate logins.
+ // First, get pointers to username element.
+ WebCore::HTMLInputElement* username_element =
+ form_elements->input_elements[data.basic_data.elements[0]].get();
+
+ // Get pointer to password element. (We currently only support single
+ // password forms).
+ WebCore::HTMLInputElement* password_element =
+ form_elements->input_elements[data.basic_data.elements[1]].get();
+
+ AttachForInlineAutocomplete(username_element,
+ new PasswordAutocompleteListener(
+ new HTMLInputDelegate(username_element),
+ new HTMLInputDelegate(password_element),
+ data));
+ }
+}
+
+WebFrameImpl* GetWebFrameImplFromElement(WebCore::Element* element,
+ bool* is_frame_element) {
+ *is_frame_element = false;
+ if (element->hasTagName(WebCore::HTMLNames::iframeTag) ||
+ element->hasTagName(WebCore::HTMLNames::frameTag)) {
+ *is_frame_element = true;
+ if (element->isFrameOwnerElement()) {
+ // Check whether this frame has content.
+ WebCore::HTMLFrameOwnerElement* frame_element =
+ static_cast<WebCore::HTMLFrameOwnerElement*>(element);
+ WebCore::Frame* content_frame = frame_element->contentFrame();
+ return content_frame ? WebFrameImpl::FromFrame(content_frame) : NULL;
+ }
+ }
+ return NULL;
+}
+
+const WebCore::AtomicString* GetSubResourceLinkFromElement(
+ const WebCore::Element* element) {
+ const WebCore::QualifiedName* attribute_name = NULL;
+ if (element->hasTagName(WebCore::HTMLNames::imgTag) ||
+ element->hasTagName(WebCore::HTMLNames::scriptTag) ||
+ element->hasTagName(WebCore::HTMLNames::linkTag)) {
+ // Get value.
+ if (element->hasTagName(WebCore::HTMLNames::linkTag)) {
+ // If the link element is not linked to css, ignore it.
+ const WebCore::HTMLLinkElement* link =
+ static_cast<const WebCore::HTMLLinkElement*>(element);
+ if (!link->sheet())
+ return NULL;
+ // TODO(jnd). Add support for extracting links of sub-resources which
+ // are inside style-sheet such as @import, url(), etc.
+ // See bug: http://b/issue?id=1111667.
+ attribute_name = &WebCore::HTMLNames::hrefAttr;
+ } else {
+ attribute_name = &WebCore::HTMLNames::srcAttr;
+ }
+ } else if (element->hasTagName(WebCore::HTMLNames::inputTag)) {
+ const WebCore::HTMLInputElement* input =
+ static_cast<const WebCore::HTMLInputElement*>(element);
+ if (input->inputType() == WebCore::HTMLInputElement::IMAGE) {
+ attribute_name = &WebCore::HTMLNames::srcAttr;
+ }
+ } else if (element->hasTagName(WebCore::HTMLNames::bodyTag) ||
+ element->hasTagName(WebCore::HTMLNames::tableTag) ||
+ element->hasTagName(WebCore::HTMLNames::trTag) ||
+ element->hasTagName(WebCore::HTMLNames::tdTag)) {
+ attribute_name = &WebCore::HTMLNames::backgroundAttr;
+ } else if (element->hasTagName(WebCore::HTMLNames::blockquoteTag) ||
+ element->hasTagName(WebCore::HTMLNames::qTag) ||
+ element->hasTagName(WebCore::HTMLNames::delTag) ||
+ element->hasTagName(WebCore::HTMLNames::insTag)) {
+ attribute_name = &WebCore::HTMLNames::citeAttr;
+ }
+ if (!attribute_name)
+ return NULL;
+ const WebCore::AtomicString* value =
+ &element->getAttribute(*attribute_name);
+ // If value has content and not start with "javascript:" then return it,
+ // otherwise return NULL.
+ if (value && !value->isEmpty() &&
+ !value->domString().startsWith("javascript:", false))
+ return value;
+
+ return NULL;
+}
+
+bool ElementHasLegalLinkAttribute(const WebCore::Element* element,
+ const WebCore::QualifiedName& attr_name) {
+ if (attr_name == WebCore::HTMLNames::srcAttr) {
+ // Check src attribute.
+ if (element->hasTagName(WebCore::HTMLNames::imgTag) ||
+ element->hasTagName(WebCore::HTMLNames::scriptTag) ||
+ element->hasTagName(WebCore::HTMLNames::iframeTag) ||
+ element->hasTagName(WebCore::HTMLNames::frameTag))
+ return true;
+ if (element->hasTagName(WebCore::HTMLNames::inputTag)) {
+ const WebCore::HTMLInputElement* input =
+ static_cast<const WebCore::HTMLInputElement*>(element);
+ if (input->inputType() == WebCore::HTMLInputElement::IMAGE)
+ return true;
+ }
+ } else if (attr_name == WebCore::HTMLNames::hrefAttr) {
+ // Check href attribute.
+ if (element->hasTagName(WebCore::HTMLNames::linkTag) ||
+ element->hasTagName(WebCore::HTMLNames::aTag) ||
+ element->hasTagName(WebCore::HTMLNames::areaTag))
+ return true;
+ } else if (attr_name == WebCore::HTMLNames::actionAttr) {
+ if (element->hasTagName(WebCore::HTMLNames::formTag))
+ return true;
+ } else if (attr_name == WebCore::HTMLNames::backgroundAttr) {
+ if (element->hasTagName(WebCore::HTMLNames::bodyTag) ||
+ element->hasTagName(WebCore::HTMLNames::tableTag) ||
+ element->hasTagName(WebCore::HTMLNames::trTag) ||
+ element->hasTagName(WebCore::HTMLNames::tdTag))
+ return true;
+ } else if (attr_name == WebCore::HTMLNames::citeAttr) {
+ if (element->hasTagName(WebCore::HTMLNames::blockquoteTag) ||
+ element->hasTagName(WebCore::HTMLNames::qTag) ||
+ element->hasTagName(WebCore::HTMLNames::delTag) ||
+ element->hasTagName(WebCore::HTMLNames::insTag))
+ return true;
+ } else if (attr_name == WebCore::HTMLNames::classidAttr ||
+ attr_name == WebCore::HTMLNames::dataAttr) {
+ if (element->hasTagName(WebCore::HTMLNames::objectTag))
+ return true;
+ } else if (attr_name == WebCore::HTMLNames::codebaseAttr) {
+ if (element->hasTagName(WebCore::HTMLNames::objectTag) ||
+ element->hasTagName(WebCore::HTMLNames::appletTag))
+ return true;
+ }
+ return false;
+}
+
+WebFrameImpl* GetWebFrameImplFromWebViewForSpecificURL(WebView* view,
+ const GURL& page_url) {
+ WebFrame* main_frame = view->GetMainFrame();
+ if (!main_frame)
+ return NULL;
+ WebFrameImpl* main_frame_impl = static_cast<WebFrameImpl*>(main_frame);
+
+ std::vector<WebFrameImpl*> frames;
+ // First, process main frame.
+ frames.push_back(main_frame_impl);
+ // Collect all frames inside the specified frame.
+ for (int i = 0; i < static_cast<int>(frames.size()); ++i) {
+ WebFrameImpl* current_frame = frames[i];
+ // Get current using document.
+ WebCore::Document* current_doc = current_frame->frame()->document();
+ // Check whether current frame is target or not.
+ const WebCore::KURL& current_frame_kurl =
+ current_frame->frame()->loader()->url();
+ GURL current_frame_gurl(KURLToGURL(current_frame_kurl));
+ if (page_url == current_frame_gurl)
+ return current_frame;
+ // Go through sub-frames.
+ RefPtr<WebCore::HTMLCollection> all = current_doc->all();
+ for (WebCore::Node* node = all->firstItem(); node != NULL;
+ node = all->nextItem()) {
+ if (!node->isHTMLElement())
+ continue;
+ WebCore::Element* element = static_cast<WebCore::Element*>(node);
+ // Check frame tag and iframe tag.
+ bool is_frame_element;
+ WebFrameImpl* web_frame = GetWebFrameImplFromElement(
+ element, &is_frame_element);
+ if (is_frame_element && web_frame)
+ frames.push_back(web_frame);
+ }
+ }
+
+ return NULL;
+}
+
+// Get all savable resource links from current webview, include main
+// frame and sub-frame
+bool GetAllSavableResourceLinksForCurrentPage(WebView* view,
+ const GURL& page_url, SavableResourcesResult* result) {
+ WebFrame* main_frame = view->GetMainFrame();
+ if (!main_frame)
+ return false;
+ WebFrameImpl* main_frame_impl = static_cast<WebFrameImpl*>(main_frame);
+
+ std::set<GURL> resources_set;
+ std::set<GURL> frames_set;
+ std::vector<WebFrameImpl*> frames;
+ SavableResourcesUniqueCheck unique_check(&resources_set,
+ &frames_set,
+ &frames);
+
+ GURL main_page_gurl(KURLToGURL(main_frame_impl->frame()->loader()->url()));
+
+ // Make sure we are saving same page between embedder and webkit.
+ // If page has being navigated, embedder will get three empty vector,
+ // which will make the saving page job ended.
+ if (page_url != main_page_gurl)
+ return true;
+
+ // First, process main frame.
+ frames.push_back(main_frame_impl);
+
+ // Check all resource in this page, include sub-frame.
+ for (int i = 0; i < static_cast<int>(frames.size()); ++i) {
+ // Get current frame's all savable resource links.
+ GetAllSavableResourceLinksForFrame(frames[i], &unique_check, result);
+ }
+
+ // Since frame's src can also point to sub-resources link, so it is possible
+ // that some URLs in frames_list are also in resources_list. For those
+ // URLs, we will remove it from frame_list, only keep them in resources_list.
+ for (std::set<GURL>::iterator it = frames_set.begin();
+ it != frames_set.end(); ++it) {
+ // Append unique frame source to savable frame list.
+ if (resources_set.find(*it) == resources_set.end())
+ result->frames_list->push_back(*it);
+ }
+
+ return true;
+}
+
+// Sizes a single size (the width or height) from a 'sizes' attribute. A size
+// matches must match the following regex: [1-9][0-9]*.
+static int ParseSingleIconSize(const std::wstring& text) {
+ // Size must not start with 0, and be between 0 and 9.
+ if (text.empty() || !(text[0] >= L'1' && text[0] <= L'9'))
+ return 0;
+ // Make sure all chars are from 0-9.
+ for (size_t i = 1; i < text.length(); ++i) {
+ if (!(text[i] >= L'0' && text[i] <= L'9'))
+ return 0;
+ }
+ return _wtoi(text.c_str());
+}
+
+// Parses an icon size. An icon size must match the following regex:
+// [1-9][0-9]*x[1-9][0-9]*.
+// If the input couldn't be parsed, a size with a width/height < 0 is returned.
+static gfx::Size ParseIconSize(const std::wstring& text) {
+ std::vector<std::wstring> sizes;
+ SplitStringDontTrim(text, L'x', &sizes);
+ if (sizes.size() != 2)
+ return gfx::Size();
+
+ return gfx::Size(ParseSingleIconSize(sizes[0]),
+ ParseSingleIconSize(sizes[1]));
+}
+
+bool ParseIconSizes(const std::wstring& text,
+ std::vector<gfx::Size>* sizes,
+ bool* is_any) {
+ *is_any = false;
+ std::vector<std::wstring> size_strings;
+ SplitStringAlongWhitespace(text, &size_strings);
+ for (size_t i = 0; i < size_strings.size(); ++i) {
+ if (size_strings[i] == L"any") {
+ *is_any = true;
+ } else {
+ gfx::Size size = ParseIconSize(size_strings[i]);
+ if (size.width() <= 0 || size.height() <= 0)
+ return false; // Bogus size.
+ sizes->push_back(size);
+ }
+ }
+ if (*is_any && !sizes->empty()) {
+ // If is_any is true, it must occur by itself.
+ return false;
+ }
+ return (*is_any || !sizes->empty());
+}
+
+static void AddInstallIcon(WebCore::HTMLLinkElement* link,
+ std::vector<WebApplicationInfo::IconInfo>* icons) {
+ String href = link->href();
+ if (href.isEmpty() || href.isNull())
+ return;
+
+ GURL url(webkit_glue::StringToStdWString(href));
+ if (!url.is_valid())
+ return;
+
+ const String sizes_attr = "sizes";
+ if (!link->hasAttribute(sizes_attr))
+ return;
+
+ bool is_any = false;
+ std::vector<gfx::Size> icon_sizes;
+ if (!ParseIconSizes(webkit_glue::StringToStdWString(
+ link->getAttribute(sizes_attr)), &icon_sizes, &is_any) || is_any ||
+ icon_sizes.size() != 1) {
+ return;
+ }
+ WebApplicationInfo::IconInfo icon_info;
+ icon_info.width = icon_sizes[0].width();
+ icon_info.height = icon_sizes[0].height();
+ icon_info.url = url;
+ icons->push_back(icon_info);
+}
+
+void GetApplicationInfo(WebView* view, WebApplicationInfo* app_info) {
+ WebFrame* main_frame = view->GetMainFrame();
+ if (!main_frame)
+ return;
+ WebFrameImpl* main_frame_impl = static_cast<WebFrameImpl*>(main_frame);
+
+ WebCore::HTMLHeadElement* head;
+ if (!main_frame_impl->frame() ||
+ !main_frame_impl->frame()->document() ||
+ !(head = main_frame_impl->frame()->document()->head())) {
+ return;
+ }
+ WTF::PassRefPtr<WebCore::HTMLCollection> children = head->children();
+ for (unsigned i = 0; i < children->length(); ++i) {
+ WebCore::Node* child = children->item(i);
+ WebCore::HTMLLinkElement* link = CastHTMLElement<WebCore::HTMLLinkElement>(
+ child, WebCore::HTMLNames::linkTag);
+ if (link) {
+ if (link->isIcon())
+ AddInstallIcon(link, &app_info->icons);
+ } else {
+ WebCore::HTMLMetaElement* meta =
+ CastHTMLElement<WebCore::HTMLMetaElement>(
+ child, WebCore::HTMLNames::metaTag);
+ if (meta) {
+ if (meta->name() == String("application-name")) {
+ app_info->title = webkit_glue::StringToStdWString(meta->content());
+ } else if (meta->name() == String("description")) {
+ app_info->description =
+ webkit_glue::StringToStdWString(meta->content());
+ } else if (meta->name() == String("application-url")) {
+ std::wstring url = webkit_glue::StringToStdWString(meta->content());
+ GURL main_url = main_frame->GetURL();
+ app_info->app_url = main_url.is_valid() ?
+ main_url.Resolve(url) : GURL(url);
+ if (!app_info->app_url.is_valid())
+ app_info->app_url = GURL();
+ }
+ }
+ }
+ }
+}
+
+} // webkit_glue
diff --git a/webkit/glue/dom_operations.h b/webkit/glue/dom_operations.h
new file mode 100644
index 0000000..777c519
--- /dev/null
+++ b/webkit/glue/dom_operations.h
@@ -0,0 +1,205 @@
+// 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 WEBKIT_GLUE_DOM_OPERATIONS_H__
+#define WEBKIT_GLUE_DOM_OPERATIONS_H__
+
+#include <string>
+#include <map>
+
+#include "base/gfx/size.h"
+#include "googleurl/src/gurl.h"
+#include "webkit/glue/password_form_dom_manager.h"
+
+struct FormData;
+class WebFrameImpl;
+class WebView;
+
+namespace WebCore {
+class AtomicString;
+class Document;
+class Element;
+class Node;
+class QualifiedName;
+class String;
+}
+
+// A collection of operations that access the underlying WebKit DOM directly.
+namespace webkit_glue {
+
+// Automatically fill a form to upload a file.
+//
+// Look in all frames for a form with the name or ID |form_name|. If the form is
+// found, set the input type=file with name or ID equal to |file_name| to
+// |file_path|. If |form_name| is empty, look for any form containing the
+// provided submit button.
+//
+// If |submit_name| is non empty and a submit button with a matching name or ID
+// exists, the form is submitted using that submit button. If any form input
+// has a name or ID matching an |other_form_values| key, it will be set to the
+// corresponding value.
+//
+// Return true if a form was found and processed.
+typedef std::map<std::wstring, std::wstring> FormValueMap;
+struct FileUploadData {
+ std::wstring file_path;
+ std::wstring form_name;
+ std::wstring file_name;
+ std::wstring submit_name;
+ FormValueMap other_form_values;
+};
+
+bool FillFormToUploadFile(WebView* view, const FileUploadData& data);
+
+// Fill in a form identified by form |data|.
+bool FillForm(WebView* view, const FormData& data);
+
+// Fill matching password forms and trigger autocomplete in the case of multiple
+// matching logins.
+void FillPasswordForm(WebView* view,
+ const PasswordFormDomManager::FillData& data);
+
+// If node is an HTML node with a tag name of name it is casted to HTMLNodeType
+// and returned. If node is not an HTML node or the tag name is not name
+// NULL is returned.
+template <class HTMLNodeType>
+HTMLNodeType* CastHTMLElement(WebCore::Node* node,
+ const WebCore::QualifiedName& name) {
+ if (node->isHTMLElement() &&
+ static_cast<WebCore::HTMLElement*>(node)->hasTagName(name)) {
+ return static_cast<HTMLNodeType*>(node);
+ }
+ return NULL;
+}
+
+// If element is HTML:IFrame or HTML:Frame, then return the WebFrameImpl
+// object corresponding to the content frame, otherwise return NULL.
+// The parameter is_frame_element indicates whether the input element
+// is frame/iframe element or not.
+WebFrameImpl* GetWebFrameImplFromElement(WebCore::Element* element,
+ bool* is_frame_element);
+
+
+// If element is img, script or input type=image, then return its link refer
+// to the "src" attribute. If element is link, then return its link refer to
+// the "href" attribute. If element is body, table, tr, td, then return its
+// link refer to the "background" attribute. If element is blockquote, q, del,
+// ins, then return its link refer to the "cite" attribute. Otherwise return
+// NULL.
+const WebCore::AtomicString* GetSubResourceLinkFromElement(
+ const WebCore::Element* element);
+
+// For img, script, iframe, frame element, when attribute name is src,
+// for link, a, area element, when attribute name is href,
+// for form element, when attribute name is action,
+// for input, type=image, when attribute name is src,
+// for body, table, tr, td, when attribute name is background,
+// for blockquote, q, del, ins, when attribute name is cite,
+// we can consider the attribute value has legal link.
+bool ElementHasLegalLinkAttribute(const WebCore::Element* element,
+ const WebCore::QualifiedName& attr_name);
+
+// Get pointer of WebFrameImpl from webview according to specific URL.
+WebFrameImpl* GetWebFrameImplFromWebViewForSpecificURL(WebView* view,
+ const GURL& page_url);
+
+// Structure for storage the result of getting all savable resource links
+// for current page. The consumer of the SavableResourcesResult is responsible
+// for keeping these pointers valid for the lifetime of the
+// SavableResourcesResult instance.
+struct SavableResourcesResult {
+ // vector which contains all savable links of sub resource.
+ std::vector<GURL>* resources_list;
+ // vector which contains corresponding all referral links of sub resource,
+ // it matched with links one by one.
+ std::vector<GURL>* referrers_list;
+ // vector which contains all savable links of main frame and sub frames.
+ std::vector<GURL>* frames_list;
+
+ // Constructor.
+ SavableResourcesResult(std::vector<GURL>* resources_list,
+ std::vector<GURL>* referrers_list,
+ std::vector<GURL>* frames_list)
+ : resources_list(resources_list),
+ referrers_list(referrers_list),
+ frames_list(frames_list) { }
+
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(SavableResourcesResult);
+};
+
+// Get all savable resource links from current webview, include main frame
+// and sub-frame. After collecting all savable resource links, this function
+// will send those links to embedder. Return value indicates whether we get
+// all saved resource links successfully.
+bool GetAllSavableResourceLinksForCurrentPage(WebView* view,
+ const GURL& page_url, SavableResourcesResult* savable_resources_result);
+
+// Structure used when installing a web page as an app. Populated via
+// GetApplicationInfo.
+struct WebApplicationInfo {
+ struct IconInfo {
+ GURL url;
+ int width;
+ int height;
+ };
+
+ // Title of the application. This is set from the meta tag whose name is
+ // 'application-name'.
+ std::wstring title;
+
+ // Description of the application. This is set from the meta tag whose name
+ // is 'description'.
+ std::wstring description;
+
+ // URL for the app. This is set from the meta tag whose name is
+ // 'application-url'.
+ GURL app_url;
+
+ // Set of available icons. This is set for all link tags whose rel=icon. Only
+ // icons that have a non-zero (width and/or height) are added.
+ std::vector<IconInfo> icons;
+};
+
+// Parses the icon's size attribute as defined in the HTML 5 spec. Returns true
+// on success, false on errors. On success either all the sizes specified in
+// the attribute are added to sizes, or is_any is set to true.
+//
+// You shouldn't have a need to invoke this directly, it's public for testing.
+bool ParseIconSizes(const std::wstring& text,
+ std::vector<gfx::Size>* sizes,
+ bool* is_any);
+
+// Gets the application info for the specified page. See the description of
+// WebApplicationInfo for details as to where each field comes from.
+void GetApplicationInfo(WebView* view, WebApplicationInfo* app_info);
+
+} // namespace webkit_glue
+
+#endif // WEBKIT_GLUE_DOM_OPERATIONS_H__
diff --git a/webkit/glue/dom_operations_unittest.cc b/webkit/glue/dom_operations_unittest.cc
new file mode 100644
index 0000000..3865ea7
--- /dev/null
+++ b/webkit/glue/dom_operations_unittest.cc
@@ -0,0 +1,207 @@
+// 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/file_util.h"
+#include "base/path_service.h"
+#include "base/string_util.h"
+#include "net/base/net_util.h"
+#include "net/url_request/url_request_context.h"
+#include "webkit/glue/dom_operations.h"
+#include "webkit/glue/webview.h"
+#include "webkit/glue/webframe.h"
+#include "webkit/tools/test_shell/simple_resource_loader_bridge.h"
+#include "webkit/tools/test_shell/test_shell_test.h"
+
+namespace {
+
+class DomOperationsTests : public TestShellTest {
+ public:
+ // Test function GetAllSavableResourceLinksForCurrentPage with a web page.
+ // We expect result of GetAllSavableResourceLinksForCurrentPage exactly
+ // matches expected_resources_set.
+ void GetSavableResourceLinksForPage(const std::wstring& page_file_path,
+ const std::set<GURL>& expected_resources_set);
+
+ protected:
+ // testing::Test
+ virtual void SetUp() {
+ TestShellTest::SetUp();
+ }
+
+ virtual void TearDown() {
+ TestShellTest::TearDown();
+ }
+};
+
+} // namespace
+
+
+void DomOperationsTests::GetSavableResourceLinksForPage(
+ const std::wstring& page_file_path,
+ const std::set<GURL>& expected_resources_set) {
+ // Convert local file path to file URL.
+ GURL file_url = net_util::FilePathToFileURL(page_file_path);
+ // Load the test file.
+ test_shell_->ResetTestController();
+ std::wstring file_wurl = ASCIIToWide(file_url.spec());
+ test_shell_->LoadURL(file_wurl.c_str());
+ test_shell_->WaitTestFinished();
+ // Get all savable resource links for the page.
+ 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);
+
+ GURL main_page_gurl(file_wurl);
+ ASSERT_TRUE(webkit_glue::GetAllSavableResourceLinksForCurrentPage(
+ test_shell_->webView(), main_page_gurl, &result));
+ // Check all links of sub-resource
+ for (std::vector<GURL>::const_iterator cit = resources_list.begin();
+ cit != resources_list.end(); ++cit) {
+ ASSERT_TRUE(expected_resources_set.find(*cit) !=
+ expected_resources_set.end());
+ }
+ // Check all links of frame.
+ for (std::vector<GURL>::const_iterator cit = frames_list.begin();
+ cit != frames_list.end(); ++cit) {
+ ASSERT_TRUE(expected_resources_set.find(*cit) !=
+ expected_resources_set.end());
+ }
+}
+
+// Test function GetAllSavableResourceLinksForCurrentPage with a web page
+// which has valid savable resource links.
+TEST_F(DomOperationsTests, GetSavableResourceLinksWithPageHasValidLinks) {
+ std::set<GURL> expected_resources_set;
+ // Set directory of test data.
+ std::wstring page_file_path = data_dir_;
+ file_util::AppendToPath(&page_file_path, L"dom_serializer");
+
+ const wchar_t* expected_sub_resource_links[] = {
+ L"file:///c:/yt/css/base_all-vfl36460.css",
+ L"file:///c:/yt/js/base_all_with_bidi-vfl36451.js",
+ L"file:///c:/yt/img/pixel-vfl73.gif"
+ };
+ const wchar_t* expected_frame_links[] = {
+ L"youtube_1.htm",
+ L"youtube_2.htm"
+ };
+ // Add all expected links of sub-resource to expected set.
+ for (int i = 0; i < arraysize(expected_sub_resource_links); ++i)
+ expected_resources_set.insert(GURL(expected_sub_resource_links[i]));
+ // Add all expected links of frame to expected set.
+ for (int i = 0; i < arraysize(expected_frame_links); ++i) {
+ std::wstring expected_frame_url = page_file_path;
+ file_util::AppendToPath(&expected_frame_url, expected_frame_links[i]);
+ expected_resources_set.insert(
+ net_util::FilePathToFileURL(expected_frame_url));
+ }
+
+ file_util::AppendToPath(&page_file_path, std::wstring(L"youtube_1.htm"));
+ GetSavableResourceLinksForPage(page_file_path, expected_resources_set);
+}
+
+// Test function GetAllSavableResourceLinksForCurrentPage with a web page
+// which does not have valid savable resource links.
+TEST_F(DomOperationsTests, GetSavableResourceLinksWithPageHasInvalidLinks) {
+ std::set<GURL> expected_resources_set;
+ // Set directory of test data.
+ std::wstring page_file_path = data_dir_;
+ file_util::AppendToPath(&page_file_path, L"dom_serializer");
+
+ const wchar_t* expected_frame_links[] = {
+ L"youtube_2.htm"
+ };
+ // Add all expected links of frame to expected set.
+ for (int i = 0; i < arraysize(expected_frame_links); ++i) {
+ std::wstring expected_frame_url = page_file_path;
+ file_util::AppendToPath(&expected_frame_url, expected_frame_links[i]);
+ expected_resources_set.insert(
+ net_util::FilePathToFileURL(expected_frame_url));
+ }
+
+ file_util::AppendToPath(&page_file_path, std::wstring(L"youtube_2.htm"));
+ GetSavableResourceLinksForPage(page_file_path, expected_resources_set);
+}
+
+// Tests ParseIconSizes with various input.
+TEST_F(DomOperationsTests, ParseIconSizes) {
+ struct TestData {
+ const std::wstring input;
+ const bool expected_result;
+ const bool is_any;
+ const int expected_size_count;
+ const int width1;
+ const int height1;
+ const int width2;
+ const int height2;
+ } data[] = {
+ // Bogus input cases.
+ { L"10", false, false, 0, 0, 0, 0, 0 },
+ { L"10 10", false, false, 0, 0, 0, 0, 0 },
+ { L"010", false, false, 0, 0, 0, 0, 0 },
+ { L" 010 ", false, false, 0, 0, 0, 0, 0 },
+ { L" 10x ", false, false, 0, 0, 0, 0, 0 },
+ { L" x10 ", false, false, 0, 0, 0, 0, 0 },
+ { L"any 10x10", false, false, 0, 0, 0, 0, 0 },
+ { L"", false, false, 0, 0, 0, 0, 0 },
+ { L"10ax11", false, false, 0, 0, 0, 0, 0 },
+
+ // Any.
+ { L"any", true, true, 0, 0, 0, 0, 0 },
+ { L" any", true, true, 0, 0, 0, 0, 0 },
+ { L" any ", true, true, 0, 0, 0, 0, 0 },
+
+ // Sizes.
+ { L"10x11", true, false, 1, 10, 11, 0, 0 },
+ { L" 10x11 ", true, false, 1, 10, 11, 0, 0 },
+ { L" 10x11 1x2", true, false, 2, 10, 11, 1, 2 },
+ };
+ for (size_t i = 0; i < arraysize(data); ++i) {
+ bool is_any;
+ std::vector<gfx::Size> sizes;
+ const bool result =
+ webkit_glue::ParseIconSizes(data[i].input, &sizes, &is_any);
+ ASSERT_EQ(result, data[i].expected_result);
+ if (result) {
+ ASSERT_EQ(data[i].is_any, is_any);
+ ASSERT_EQ(data[i].expected_size_count, sizes.size());
+ if (sizes.size() > 0) {
+ ASSERT_EQ(data[i].width1, sizes[0].width());
+ ASSERT_EQ(data[i].height1, sizes[0].height());
+ }
+ if (sizes.size() > 1) {
+ ASSERT_EQ(data[i].width2, sizes[1].width());
+ ASSERT_EQ(data[i].height2, sizes[1].height());
+ }
+ }
+ }
+}
diff --git a/webkit/glue/dom_serializer.cc b/webkit/glue/dom_serializer.cc
new file mode 100644
index 0000000..3f75d27
--- /dev/null
+++ b/webkit/glue/dom_serializer.cc
@@ -0,0 +1,649 @@
+// 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.
+//
+// How we handle the base tag better.
+// Current status:
+// At now the normal way we use to handling base tag is
+// a) For those links which have corresponding local saved files, such as
+// savable CSS, JavaScript files, they will be written to relative URLs which
+// point to local saved file. Why those links can not be resolved as absolute
+// file URLs, because if they are resolved as absolute URLs, after moving the
+// file location from one directory to another directory, the file URLs will
+// be dead links.
+// b) For those links which have not corresponding local saved files, such as
+// links in A, AREA tags, they will be resolved as absolute URLs.
+// c) We comment all base tags when serialzing DOM for the page.
+// FireFox also uses above way to handle base tag.
+//
+// Problem:
+// This way can not handle the following situation:
+// the base tag is written by JavaScript.
+// For example. The page "www.yahoo.com" use
+// "document.write('<base href="http://www.yahoo.com/"...');" to setup base URL
+// of page when loading page. So when saving page as completed-HTML, we assume
+// that we save "www.yahoo.com" to "c:\yahoo.htm". After then we load the saved
+// completed-HTML page, then the JavaScript will insert a base tag
+// <base href="http://www.yahoo.com/"...> to DOM, so all URLs which point to
+// local saved resource files will be resolved as
+// "http://www.yahoo.com/yahoo_files/...", which will cause all saved resource
+// files can not be loaded correctly. Also the page will be rendered ugly since
+// all saved sub-resource files (such as CSS, JavaScript files) and sub-frame
+// files can not be fetched.
+// Now FireFox, IE and WebKit based Browser all have this problem.
+//
+// Solution:
+// My solution is that we comment old base tag and write new base tag:
+// <base href="." ...> after the previous commented base tag. In WebKit, it
+// always uses the latest "href" attribute of base tag to set document's base
+// URL. Based on this behavior, when we encounter a base tag, we comment it and
+// write a new base tag <base href="."> after the previous commented base tag.
+// The new added base tag can help engine to locate correct base URL for
+// correctly loading local saved resource files. Also I think we need to inherit
+// the base target value from document object when appending new base tag.
+// If there are multiple base tags in original document, we will comment all old
+// base tags and append new base tag after each old base tag because we do not
+// know those old base tags are original content or added by JavaScript. If
+// they are added by JavaScript, it means when loading saved page, the script(s)
+// will still insert base tag(s) to DOM, so the new added base tag(s) can
+// override the incorrect base URL and make sure we alway load correct local
+// saved resource files.
+
+#include "config.h"
+
+#pragma warning(push, 0)
+#include "DocumentType.h"
+#include "FrameLoader.h"
+#include "Document.h"
+#include "Element.h"
+#include "HTMLCollection.h"
+#include "HTMLElement.h"
+#include "HTMLFormElement.h"
+#include "HTMLMetaElement.h"
+#include "HTMLNames.h"
+#include "KURL.h"
+#include "PlatformString.h"
+#include "TextEncoding.h"
+#pragma warning(pop)
+#undef LOG
+
+#include "webkit/glue/dom_serializer.h"
+
+#include "base/string_util.h"
+#include "webkit/glue/dom_operations.h"
+#include "webkit/glue/dom_serializer_delegate.h"
+#include "webkit/glue/entity_map.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/webframe_impl.h"
+
+namespace {
+
+// Default "mark of the web" declaration
+static const wchar_t* const kDefaultMarkOfTheWeb =
+ L"\n<!-- saved from url=(%04d)%s -->\n";
+
+// Default meat content for writing correct charset declaration.
+static const wchar_t* const kDefaultMetaContent =
+ L"<META http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">";
+
+// Notation of start comment.
+static const wchar_t* const kStartCommentNotation = L"<!-- ";
+
+// Notation of end comment.
+static const wchar_t* const kEndCommentNotation = L" -->";
+
+// Default XML declaration.
+static const wchar_t* const kXMLDeclaration =
+ L"<?xml version=\"%s\" encoding=\"%s\"%s?>\n";
+
+// Default base tag declaration
+static const wchar_t* const kBaseTagDeclaration =
+ L"<BASE href=\".\"%s>";
+
+static const wchar_t* const kBaseTargetDeclaration =
+ L" target=\"%s\"";
+
+// Maximum length of data buffer which is used to temporary save generated
+// html content data.
+static const int kHtmlContentBufferLength = 65536;
+
+// Check whether specified unicode has corresponding html/xml entity name.
+// If yes, replace the character with the returned entity notation, if not
+// then still use original character.
+void ConvertCorrespondingSymbolToEntity(WebCore::String* result,
+ const WebCore::String& value,
+ bool in_html_doc) {
+ unsigned len = value.length();
+ const UChar* start_pos = value.characters();
+ const UChar* cur_pos = start_pos;
+ while (len--) {
+ const char* entity_name =
+ webkit_glue::EntityMap::GetEntityNameByCode(*cur_pos, in_html_doc);
+ if (entity_name) {
+ // Append content before entity code.
+ if (cur_pos > start_pos)
+ result->append(start_pos, cur_pos - start_pos);
+ result->append(entity_name);
+ start_pos = ++cur_pos;
+ } else {
+ cur_pos++;
+ }
+ }
+ // Append the remaining content.
+ if (cur_pos > start_pos)
+ result->append(start_pos, cur_pos - start_pos);
+}
+
+} // namespace
+
+namespace webkit_glue {
+
+// SerializeDomParam Constructor.
+DomSerializer::SerializeDomParam::SerializeDomParam(
+ const GURL& current_frame_gurl,
+ const std::wstring& current_frame_wurl,
+ const WebCore::TextEncoding& text_encoding,
+ WebCore::Document* doc,
+ const std::wstring& directory_name)
+ : current_frame_gurl(current_frame_gurl),
+ current_frame_wurl(current_frame_wurl),
+ text_encoding(text_encoding),
+ doc(doc),
+ directory_name(directory_name),
+ has_doctype(false),
+ has_checked_meta(false),
+ skip_meta_element(NULL),
+ is_in_script_or_style_tag(false),
+ has_doc_declaration(false) {
+ // Cache the value since we check it lots of times.
+ is_html_document = doc->isHTMLDocument();
+}
+
+// Static.
+std::wstring DomSerializer::GenerateMarkOfTheWebDeclaration(
+ const std::wstring& url) {
+ return StringPrintf(kDefaultMarkOfTheWeb, url.size(), url.c_str());
+}
+
+// Static.
+std::wstring DomSerializer::GenerateBaseTagDeclaration(
+ const std::wstring& base_target) {
+ std::wstring target_declaration = base_target.empty() ? L"" :
+ StringPrintf(kBaseTargetDeclaration, base_target.c_str());
+ return StringPrintf(kBaseTagDeclaration, target_declaration.c_str());
+}
+
+WebCore::String DomSerializer::PreActionBeforeSerializeOpenTag(
+ const WebCore::Element* element, SerializeDomParam* param,
+ bool* need_skip) {
+ WebCore::String result;
+
+ *need_skip = false;
+ if (param->is_html_document) {
+ // Skip the open tag of original META tag which declare charset since we
+ // have overrided the META which have correct charset declaration after
+ // serializing open tag of HEAD element.
+ if (element->hasTagName(WebCore::HTMLNames::metaTag)) {
+ const WebCore::HTMLMetaElement* meta =
+ static_cast<const WebCore::HTMLMetaElement*>(element);
+ // Check whether the META tag has declared charset or not.
+ WebCore::String equiv = meta->httpEquiv();
+ if (equalIgnoringCase(equiv, "content-type")) {
+ WebCore::String content = meta->content();
+ if (content.length() && content.contains("charset", false)) {
+ // Find META tag declared charset, we need to skip it when
+ // serializing DOM.
+ param->skip_meta_element = element;
+ *need_skip = true;
+ }
+ }
+ } else if (element->hasTagName(WebCore::HTMLNames::htmlTag)) {
+ // Check something before processing the open tag of HEAD element.
+ // First we add doc type declaration if original doc has it.
+ if (!param->has_doctype) {
+ param->has_doctype = true;
+ WebCore::DocumentType* doc_type = param->doc->doctype();
+ if (doc_type)
+ result += doc_type->toString();
+ }
+
+ // Add MOTW declaration before html tag.
+ // See http://msdn2.microsoft.com/en-us/library/ms537628(VS.85).aspx.
+ result += GenerateMarkOfTheWebDeclaration(param->current_frame_wurl).
+ c_str();
+ } else if (element->hasTagName(WebCore::HTMLNames::baseTag)) {
+ // Comment the BASE tag when serializing dom.
+ result += kStartCommentNotation;
+ }
+ } else {
+ // Write XML declaration.
+ if (!param->has_doc_declaration) {
+ param->has_doc_declaration = true;
+ // Get encoding info.
+ WebCore::String xml_encoding = param->doc->xmlEncoding();
+ if (xml_encoding.isEmpty())
+ xml_encoding = param->doc->frame()->loader()->encoding();
+ if (xml_encoding.isEmpty())
+ xml_encoding = WebCore::UTF8Encoding().name();
+ std::wstring str_xml_declaration =
+ StringPrintf(kXMLDeclaration,
+ param->doc->xmlVersion().charactersWithNullTermination(),
+ xml_encoding.charactersWithNullTermination(),
+ param->doc->xmlStandalone() ? L" standalone=\"yes\"" :
+ L"");
+ result += str_xml_declaration.c_str();
+ }
+ // Add doc type declaration if original doc has it.
+ if (!param->has_doctype) {
+ param->has_doctype = true;
+ WebCore::DocumentType* doc_type = param->doc->doctype();
+ if (doc_type)
+ result += doc_type->toString();
+ }
+ }
+
+ return result;
+}
+
+WebCore::String DomSerializer::PostActionAfterSerializeOpenTag(
+ const WebCore::Element* element, SerializeDomParam* param) {
+ WebCore::String result;
+
+ if (!param->is_html_document)
+ return result;
+ // Check after processing the open tag of HEAD element
+ if (!param->has_checked_meta &&
+ element->hasTagName(WebCore::HTMLNames::headTag)) {
+ param->has_checked_meta = true;
+ // Check meta element. WebKit only pre-parse the first 512 bytes
+ // of the document. If the whole <HEAD> is larger and meta is the
+ // end of head part, then this kind of pages aren't decoded correctly
+ // because of this issue. So when we serialize the DOM, we need to
+ // make sure the meta will in first child of head tag.
+ // See http://bugs.webkit.org/show_bug.cgi?id=16621.
+ // First we generate new content for writing correct META element.
+ std::wstring str_meta =
+ StringPrintf(kDefaultMetaContent,
+ ASCIIToWide(param->text_encoding.name()).c_str());
+ result += str_meta.c_str();
+
+ // Will search each META which has charset declaration, and skip them all
+ // in PreActionBeforeSerializeOpenTag.
+ } else if (element->hasTagName(WebCore::HTMLNames::scriptTag) ||
+ element->hasTagName(WebCore::HTMLNames::styleTag)) {
+ param->is_in_script_or_style_tag = true;
+ }
+
+ return result;
+}
+
+WebCore::String DomSerializer::PreActionBeforeSerializeEndTag(
+ const WebCore::Element* element, SerializeDomParam* param,
+ bool* need_skip) {
+ WebCore::String result;
+
+ *need_skip = false;
+ if (!param->is_html_document)
+ return result;
+ // Skip the end tag of original META tag which declare charset.
+ // Need not to check whether it's META tag since we guarantee
+ // skip_meta_element is definitely META tag if it's not NULL.
+ if (param->skip_meta_element == element) {
+ *need_skip = true;
+ } else if (element->hasTagName(WebCore::HTMLNames::scriptTag) ||
+ element->hasTagName(WebCore::HTMLNames::styleTag)) {
+ DCHECK(param->is_in_script_or_style_tag);
+ param->is_in_script_or_style_tag = false;
+ }
+
+ return result;
+}
+
+// After we finish serializing end tag of a element, we give the target
+// element a chance to do some post work to add some additional data.
+WebCore::String DomSerializer::PostActionAfterSerializeEndTag(
+ const WebCore::Element* element, SerializeDomParam* param) {
+ WebCore::String result;
+
+ if (!param->is_html_document)
+ return result;
+ // Comment the BASE tag when serializing DOM.
+ if (element->hasTagName(WebCore::HTMLNames::baseTag)) {
+ result += kEndCommentNotation;
+ // Append a new base tag declaration.
+ result += GenerateBaseTagDeclaration(
+ webkit_glue::StringToStdWString(param->doc->baseTarget())).c_str();
+ }
+
+ return result;
+}
+
+void DomSerializer::SaveHtmlContentToBuffer(const WebCore::String& result,
+ SerializeDomParam* param) {
+ if (!result.length())
+ return;
+ // Convert the unicode content to target encoding
+ const UChar* ucode = result.characters();
+ // If the text encoding can not convert some unicode character to
+ // corresponding code, we allow using entity notation to replace
+ // the unicode character.
+ WebCore::CString encoding_result = param->text_encoding.encode(ucode,
+ result.length(), true);
+
+ // if the data buffer will be full, then send it out first.
+ if (encoding_result.length() + data_buffer_.size() >
+ data_buffer_.capacity()) {
+ // Send data to delegate, tell it now we are serializing current frame.
+ delegate_->DidSerializeDataForFrame(param->current_frame_gurl,
+ data_buffer_, DomSerializerDelegate::CURRENT_FRAME_IS_NOT_FINISHED);
+ data_buffer_.clear();
+ }
+
+ // Append result to data buffer.
+ data_buffer_.append(CStringToStdString(encoding_result));
+}
+
+void DomSerializer::OpenTagToString(const WebCore::Element* element,
+ SerializeDomParam* param) {
+ bool need_skip;
+ // Do pre action for open tag.
+ WebCore::String result = PreActionBeforeSerializeOpenTag(element,
+ param,
+ &need_skip);
+ if (need_skip)
+ return;
+ // Add open tag
+ result += "<" + element->nodeName();
+ // Go through all attributes and serialize them.
+ const WebCore::NamedAttrMap *attrMap = element->attributes(true);
+ if (attrMap) {
+ unsigned numAttrs = attrMap->length();
+ for (unsigned i = 0; i < numAttrs; i++) {
+ result += " ";
+ // Add attribute pair
+ const WebCore::Attribute *attribute = attrMap->attributeItem(i);
+ result += attribute->name().toString();
+ result += "=\"";
+ if (!attribute->value().isEmpty()) {
+ // Check whether we need to replace some resource links
+ // with local resource paths.
+ const WebCore::QualifiedName& attr_name = attribute->name();
+ // Check whether need to change the attribute which has link
+ bool need_replace_link =
+ ElementHasLegalLinkAttribute(element, attr_name);
+ if (need_replace_link) {
+ // First, get the absolute link
+ const WebCore::String& attr_value = attribute->value();
+ // For links start with "javascript:", we do not change it.
+ if (attr_value.startsWith("javascript:", false)) {
+ result += attr_value;
+ } else {
+ WebCore::String str_value = param->doc->completeURL(attr_value);
+ std::wstring value(str_value.charactersWithNullTermination());
+ // Check whether we local files for those link.
+ LinkLocalPathMap::const_iterator it = local_links_.find(value);
+ if (it != local_links_.end()) {
+ // Replace the link when we have local files.
+ result += param->directory_name.c_str();
+ result += (it->second).c_str();
+ } else {
+ // If not found local path, replace it with absolute link.
+ result += str_value;
+ }
+ }
+ } else {
+ ConvertCorrespondingSymbolToEntity(&result, attribute->value(),
+ param->is_html_document);
+ }
+ }
+ result += "\"";
+ }
+ }
+ // Complete the open tag for element when it has child/children.
+ if (element->hasChildNodes())
+ result += ">";
+ // Do post action for open tag.
+ result += PostActionAfterSerializeOpenTag(element, param);
+ // Save the result to data buffer.
+ SaveHtmlContentToBuffer(result, param);
+}
+
+// Serialize end tag of an specified element.
+void DomSerializer::EndTagToString(const WebCore::Element* element,
+ SerializeDomParam* param) {
+ bool need_skip;
+ // Do pre action for end tag.
+ WebCore::String result = PreActionBeforeSerializeEndTag(element,
+ param,
+ &need_skip);
+ if (need_skip)
+ return;
+ // Write end tag when element has child/children.
+ if (element->hasChildNodes()) {
+ result += "</";
+ result += element->nodeName();
+ result += ">";
+ } else {
+ // Check whether we have to write end tag for empty element.
+ if (param->is_html_document) {
+ result += ">";
+ const WebCore::HTMLElement* html_element =
+ static_cast<const WebCore::HTMLElement*>(element);
+ if (html_element->endTagRequirement() == WebCore::TagStatusRequired) {
+ // We need to write end tag when it is required.
+ result += "</";
+ result += html_element->nodeName();
+ result += ">";
+ }
+ } else {
+ // For xml base document.
+ result += " />";
+ }
+ }
+ // Do post action for end tag.
+ result += PostActionAfterSerializeEndTag(element, param);
+ // Save the result to data buffer.
+ SaveHtmlContentToBuffer(result, param);
+}
+
+void DomSerializer::BuildContentForNode(const WebCore::Node* node,
+ SerializeDomParam* param) {
+ switch (node->nodeType()) {
+ case WebCore::Node::ELEMENT_NODE: {
+ // Process open tag of element.
+ OpenTagToString(static_cast<const WebCore::Element*>(node), param);
+ // Walk through the children nodes and process it.
+ for (const WebCore::Node *child = node->firstChild(); child != NULL;
+ child = child->nextSibling())
+ BuildContentForNode(child, param);
+ // Process end tag of element.
+ EndTagToString(static_cast<const WebCore::Element*>(node), param);
+ break;
+ }
+ case WebCore::Node::TEXT_NODE: {
+ WebCore::String result;
+ WebCore::String s = node->toString();
+ if (param->is_html_document) {
+ // For html document, do not convert entity notation in code
+ // block of style tag and script tag.
+ if (param->is_in_script_or_style_tag)
+ result += s;
+ else
+ ConvertCorrespondingSymbolToEntity(&result, s,
+ param->is_html_document);
+ } else {
+ ConvertCorrespondingSymbolToEntity(&result, s,
+ param->is_html_document);
+ }
+
+ SaveHtmlContentToBuffer(result, param);
+ break;
+ }
+ case WebCore::Node::ATTRIBUTE_NODE:
+ case WebCore::Node::DOCUMENT_NODE:
+ case WebCore::Node::DOCUMENT_FRAGMENT_NODE: {
+ // Should not exist.
+ DCHECK(false);
+ break;
+ }
+ // Document type node can be in DOM?
+ case WebCore::Node::DOCUMENT_TYPE_NODE:
+ param->has_doctype = true;
+ default: {
+ // For other type node, call default action.
+ SaveHtmlContentToBuffer(node->toString(), param);
+ break;
+ }
+ }
+}
+
+DomSerializer::DomSerializer(WebFrame* webframe,
+ bool recursive_serialization,
+ DomSerializerDelegate* delegate,
+ const std::vector<std::wstring>& links,
+ const std::vector<std::wstring>& local_paths,
+ const std::wstring& local_directory_name)
+ : recursive_serialization_(recursive_serialization),
+ delegate_(delegate),
+ local_directory_name_(local_directory_name),
+ frames_collected_(false) {
+ // Must specify available webframe.
+ DCHECK(webframe);
+ specified_webframeimpl_ = static_cast<WebFrameImpl*>(webframe);
+ // Make sure we have not-NULL delegate.
+ DCHECK(delegate);
+ // Build local resources map.
+ DCHECK(links.size() == local_paths.size());
+ for (std::vector<std::wstring>::const_iterator link_it = links.begin(),
+ path_it = local_paths.begin(); link_it != links.end();
+ ++link_it, ++path_it) {
+ bool never_present = local_links_.insert(
+ LinkLocalPathMap::value_type(*link_it, *path_it)).
+ second;
+ DCHECK(never_present);
+ }
+
+ // Init data buffer.
+ data_buffer_.reserve(kHtmlContentBufferLength);
+ DCHECK(data_buffer_.empty());
+}
+
+void DomSerializer::CollectTargetFrames() {
+ DCHECK(!frames_collected_);
+ frames_collected_ = true;
+
+ // First, process main frame.
+ frames_.push_back(specified_webframeimpl_);
+ // Return now if user only needs to serialize specified frame, not including
+ // all sub-frames.
+ if (!recursive_serialization_)
+ return;
+ // Collect all frames inside the specified frame.
+ for (int i = 0; i < static_cast<int>(frames_.size()); ++i) {
+ WebFrameImpl* current_frame = frames_[i];
+ // Get current using document.
+ WebCore::Document* current_doc = current_frame->frame()->document();
+ // Go through sub-frames.
+ RefPtr<WebCore::HTMLCollection> all = current_doc->all();
+ for (WebCore::Node* node = all->firstItem(); node != NULL;
+ node = all->nextItem()) {
+ if (!node->isHTMLElement())
+ continue;
+ WebCore::Element* element = static_cast<WebCore::Element*>(node);
+ // Check frame tag and iframe tag.
+ bool is_frame_element;
+ WebFrameImpl* web_frame = GetWebFrameImplFromElement(
+ element, &is_frame_element);
+ if (is_frame_element && web_frame)
+ frames_.push_back(web_frame);
+ }
+ }
+}
+
+bool DomSerializer::SerializeDom() {
+ // Collect target frames.
+ if (!frames_collected_)
+ CollectTargetFrames();
+ bool did_serialization = false;
+ // Get GURL for main frame.
+ GURL main_page_gurl(KURLToGURL(
+ specified_webframeimpl_->frame()->loader()->url()));
+
+ // Go through all frames for serializing DOM for whole page, include
+ // sub-frames.
+ for (int i = 0; i < static_cast<int>(frames_.size()); ++i) {
+ // Get current serializing frame.
+ WebFrameImpl* current_frame = frames_[i];
+ // Get current using document.
+ WebCore::Document* current_doc = current_frame->frame()->document();
+ // Get current frame's URL.
+ const WebCore::KURL& current_frame_kurl =
+ current_frame->frame()->loader()->url();
+ GURL current_frame_gurl(KURLToGURL(current_frame_kurl));
+ std::wstring current_frame_wurl = ASCIIToWide(current_frame_gurl.spec());
+
+ // Check whether we have done this document.
+ if (local_links_.find(current_frame_wurl) != local_links_.end()) {
+ // A new document, we will serialize it.
+ did_serialization = true;
+ // Get target encoding for current document.
+ WebCore::String encoding = current_frame->frame()->loader()->encoding();
+ // Create the text encoding object with target encoding.
+ WebCore::TextEncoding text_encoding(encoding);
+ // Construct serialize parameter for late processing document.
+ SerializeDomParam param(
+ current_frame_gurl,
+ current_frame_wurl,
+ encoding.length() ? text_encoding : WebCore::UTF8Encoding(),
+ current_doc,
+ current_frame_gurl == main_page_gurl ?
+ local_directory_name_ : L"./");
+
+ // Process current document.
+ WebCore::Element* root_element = current_doc->documentElement();
+ if (root_element)
+ BuildContentForNode(root_element, &param);
+
+ // Sink the remainder data and finish serializing current frame.
+ delegate_->DidSerializeDataForFrame(current_frame_gurl, data_buffer_,
+ DomSerializerDelegate::CURRENT_FRAME_IS_FINISHED);
+ // Clear the buffer.
+ data_buffer_.clear();
+ }
+ }
+
+ // We have done call frames, so we send message to embedder to tell it that
+ // frames are finished serializing.
+ DCHECK(data_buffer_.empty());
+ delegate_->DidSerializeDataForFrame(GURL(), data_buffer_,
+ DomSerializerDelegate::ALL_FRAMES_ARE_FINISHED);
+
+ return did_serialization;
+}
+
+} // namespace webkit_glue
diff --git a/webkit/glue/dom_serializer.h b/webkit/glue/dom_serializer.h
new file mode 100644
index 0000000..d9e667b
--- /dev/null
+++ b/webkit/glue/dom_serializer.h
@@ -0,0 +1,196 @@
+// 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 WEBKIT_GLUE_DOM_SERIALIZER_H__
+#define WEBKIT_GLUE_DOM_SERIALIZER_H__
+
+#include <string>
+#include <hash_map>
+
+#include "googleurl/src/gurl.h"
+
+class WebFrame;
+class WebFrameImpl;
+
+namespace WebCore {
+class Document;
+class Element;
+class Node;
+class String;
+class TextEncoding;
+}
+
+namespace webkit_glue {
+
+class DomSerializerDelegate;
+
+// Get html data by serializing all frames of current page with lists
+// which contain all resource links that have local copy.
+// contain all saved auxiliary files included all sub frames and resources.
+// This function will find out all frames and serialize them to HTML data.
+// We have a data buffer to temporary saving generated html data. We will
+// sequentially call WebViewDelegate::SendSerializedHtmlData once the data
+// buffer is full. See comments of WebViewDelegate::SendSerializedHtmlData
+// for getting more information.
+class DomSerializer {
+ public:
+ // Do serialization action. Return false means no available frame has been
+ // serialized, otherwise return true.
+ bool SerializeDom();
+ // The parameter specifies which frame need to be serialized.
+ // The parameter recursive_serialization specifies whether we need to
+ // serialize all sub frames of the specified frame or not.
+ // The parameter delegate specifies the pointer of interface
+ // DomSerializerDelegate provide sink interface which can receive the
+ // individual chunks of data to be saved.
+ // The parameter links contain original URLs of all saved links.
+ // The parameter local_paths contain corresponding local file paths of all
+ // saved links, which matched with vector:links one by one.
+ // The parameter local_directory_name is relative path of directory which
+ // contain all saved auxiliary files included all sub frames and resources.
+ DomSerializer(WebFrame* webframe,
+ bool recursive_serialization,
+ DomSerializerDelegate* delegate,
+ const std::vector<std::wstring>& links,
+ const std::vector<std::wstring>& local_paths,
+ const std::wstring& local_directory_name);
+
+ // Generate the MOTW declaration.
+ static std::wstring GenerateMarkOfTheWebDeclaration(const std::wstring& url);
+ // Generate the default base tag declaration.
+ static std::wstring GenerateBaseTagDeclaration(
+ const std::wstring& base_target);
+
+ private:
+ // Specified frame which need to be serialized;
+ WebFrameImpl* specified_webframeimpl_;
+ // This hash_map is used to map resource URL of original link to its local
+ // file path.
+ typedef stdext::hash_map<std::wstring, std::wstring> LinkLocalPathMap;
+ // local_links_ include all pair of local resource path and corresponding
+ // original link.
+ LinkLocalPathMap local_links_;
+ // Pointer of DomSerializerDelegate
+ DomSerializerDelegate* delegate_;
+ // Data buffer for saving result of serialized DOM data.
+ std::string data_buffer_;
+ // Passing true to recursive_serialization_ indicates we will serialize not
+ // only the specified frame but also all sub-frames in the specific frame.
+ // Otherwise we only serialize the specified frame excluded all sub-frames.
+ bool recursive_serialization_;
+ // Flag indicates whether we have collected all frames which need to be
+ // serialized or not;
+ bool frames_collected_;
+ // Local directory name of all local resource files.
+ const std::wstring& local_directory_name_;
+ // Vector for saving all frames which need to be serialized.
+ std::vector<WebFrameImpl*> frames_;
+
+ struct SerializeDomParam {
+ // Frame URL of current processing document presented by GURL
+ const GURL& current_frame_gurl;
+ // Frame URL of current processing document presented by std::wstring.
+ const std::wstring& current_frame_wurl;
+ // Current using text encoding object.
+ const WebCore::TextEncoding& text_encoding;
+
+ // Document object of current frame.
+ WebCore::Document* doc;
+ // Local directory name of all local resource files.
+ const std::wstring& directory_name;
+
+ // Flag indicates current doc is html document or not. It's a cache value
+ // of Document.isHTMLDocument().
+ bool is_html_document;
+ // Flag which indicate whether we have met document type declaration.
+ bool has_doctype;
+ // Flag which indicate whether will process meta issue.
+ bool has_checked_meta;
+ // This meta element need to be skipped when serializing DOM.
+ const WebCore::Element* skip_meta_element;
+ // Flag indicates we are in script or style tag.
+ bool is_in_script_or_style_tag;
+ // Flag indicates whether we have written xml document declaration.
+ // It is only used in xml document
+ bool has_doc_declaration;
+
+ // Constructor.
+ SerializeDomParam(
+ const GURL& current_frame_gurl,
+ const std::wstring& current_frame_wurl,
+ const WebCore::TextEncoding& text_encoding,
+ WebCore::Document* doc,
+ const std::wstring& directory_name);
+
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(SerializeDomParam);
+ };
+
+ // Collect all target frames which need to be serialized.
+ void CollectTargetFrames();
+ // Before we begin serializing open tag of a element, we give the target
+ // element a chance to do some work prior to add some additional data.
+ WebCore::String PreActionBeforeSerializeOpenTag(
+ const WebCore::Element* element,
+ SerializeDomParam* param,
+ bool* need_skip);
+ // After we finish serializing open tag of a element, we give the target
+ // element a chance to do some post work to add some additional data.
+ WebCore::String PostActionAfterSerializeOpenTag(
+ const WebCore::Element* element,
+ SerializeDomParam* param);
+ // Before we begin serializing end tag of a element, we give the target
+ // element a chance to do some work prior to add some additional data.
+ WebCore::String PreActionBeforeSerializeEndTag(
+ const WebCore::Element* element,
+ SerializeDomParam* param, bool* need_skip);
+ // After we finish serializing end tag of a element, we give the target
+ // element a chance to do some post work to add some additional data.
+ WebCore::String PostActionAfterSerializeEndTag(
+ const WebCore::Element* element,
+ SerializeDomParam* param);
+ // Save generated html content to data buffer.
+ void SaveHtmlContentToBuffer(const WebCore::String& result,
+ SerializeDomParam* param);
+ // Serialize open tag of an specified element.
+ void OpenTagToString(const WebCore::Element* element,
+ SerializeDomParam* param);
+ // Serialize end tag of an specified element.
+ void EndTagToString(const WebCore::Element* element,
+ SerializeDomParam* param);
+ // Build content for a specified node
+ void BuildContentForNode(const WebCore::Node* node,
+ SerializeDomParam* param);
+
+ DISALLOW_EVIL_CONSTRUCTORS(DomSerializer);
+};
+
+} // namespace webkit_glue
+
+#endif // WEBKIT_GLUE_DOM_SERIALIZER_H__
diff --git a/webkit/glue/dom_serializer_delegate.h b/webkit/glue/dom_serializer_delegate.h
new file mode 100644
index 0000000..1012cd9
--- /dev/null
+++ b/webkit/glue/dom_serializer_delegate.h
@@ -0,0 +1,77 @@
+// 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 WEBKIT_GLUE_DOM_SERIALIZER_DELEGATE_H__
+#define WEBKIT_GLUE_DOM_SERIALIZER_DELEGATE_H__
+
+#include <string>
+
+#include "googleurl/src/gurl.h"
+
+namespace webkit_glue {
+
+// This class is used for providing sink interface that can be used to receive
+// the individual chunks of data to be saved.
+class DomSerializerDelegate {
+ public:
+ // This enum indicates This sink interface can receive the individual chunks
+ // of serialized data to be saved, so we use values of following enum
+ // definition to indicate the serialization status of serializing all html
+ // content. If current frame is not complete serialized, call
+ // DidSerializeDataForFrame with URL of current frame, data, data length and
+ // flag CURRENT_FRAME_IS_NOT_FINISHED.
+ // If current frame is complete serialized, call DidSerializeDataForFrame
+ // with URL of current frame, data, data length and flag
+ // CURRENT_FRAME_IS_FINISHED.
+ // If all frames of page are complete serialized, call
+ // DidSerializeDataForFrame with empty URL, empty data, 0 and flag
+ // ALL_FRAMES_ARE_FINISHED.
+ enum PageSavingSerializationStatus {
+ // Current frame is not finished saving.
+ CURRENT_FRAME_IS_NOT_FINISHED = 0,
+ // Current frame is finished saving.
+ CURRENT_FRAME_IS_FINISHED,
+ // All frame are finished saving.
+ ALL_FRAMES_ARE_FINISHED,
+ };
+
+ // Receive the individual chunks of serialized data to be saved.
+ // The parameter frame_url specifies what frame the data belongs. The
+ // parameter data contains the available data for saving. The parameter
+ // status indicates the status of data serialization.
+ virtual void DidSerializeDataForFrame(const GURL& frame_url,
+ const std::string& data, PageSavingSerializationStatus status) = 0;
+
+ DomSerializerDelegate() { }
+ virtual ~DomSerializerDelegate() { }
+};
+
+} // namespace webkit_glue
+
+#endif // WEBKIT_GLUE_DOM_SERIALIZER_DELEGATE_H__
diff --git a/webkit/glue/dom_serializer_unittest.cc b/webkit/glue/dom_serializer_unittest.cc
new file mode 100644
index 0000000..afc4db0
--- /dev/null
+++ b/webkit/glue/dom_serializer_unittest.cc
@@ -0,0 +1,702 @@
+// 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 <hash_map>
+
+#include "config.h"
+
+#pragma warning(push, 0)
+#include "Document.h"
+#include "DocumentType.h"
+#include "Element.h"
+#include "FrameLoader.h"
+#include "FrameView.h"
+#include "HTMLHeadElement.h"
+#include "HTMLMetaElement.h"
+#include "HTMLNames.h"
+#include "KURL.h"
+#include "SharedBuffer.h"
+#include "SubstituteData.h"
+#pragma warning(pop)
+#undef LOG
+
+#include "base/file_util.h"
+#include "base/string_util.h"
+#include "net/base/net_util.h"
+#include "net/url_request/url_request_context.h"
+#include "webkit/glue/dom_operations.h"
+#include "webkit/glue/dom_serializer.h"
+#include "webkit/glue/dom_serializer_delegate.h"
+#include "webkit/glue/webview.h"
+#include "webkit/glue/webframe.h"
+#include "webkit/glue/webframe_impl.h"
+#include "webkit/tools/test_shell/simple_resource_loader_bridge.h"
+#include "webkit/tools/test_shell/test_shell_test.h"
+
+namespace {
+
+class DomSerializerTests : public TestShellTest,
+ public webkit_glue::DomSerializerDelegate {
+ public:
+ DomSerializerTests()
+ : local_directory_name_(L"./dummy_files/") { }
+
+ // DomSerializerDelegate.
+ void DidSerializeDataForFrame(const GURL& frame_url,
+ const std::string& data, PageSavingSerializationStatus status) {
+ // If the all frames are finished saving, check all finish status
+ if (status == ALL_FRAMES_ARE_FINISHED) {
+ SerializationFinishStatusMap::iterator it =
+ serialization_finish_status_.begin();
+ for (; it != serialization_finish_status_.end(); ++it)
+ ASSERT_TRUE(it->second);
+ serialized_ = true;
+ return;
+ }
+
+ std::wstring current_frame_url = UTF8ToWide(frame_url.spec());
+ // Check finish status of current frame.
+ SerializationFinishStatusMap::iterator it =
+ serialization_finish_status_.find(current_frame_url);
+ // New frame, set initial status as false.
+ if (it == serialization_finish_status_.end())
+ serialization_finish_status_[current_frame_url] = false;
+
+ it = serialization_finish_status_.find(current_frame_url);
+ ASSERT_TRUE(it != serialization_finish_status_.end());
+ // In process frame, finish status should be false.
+ ASSERT_FALSE(it->second);
+
+ // Add data to corresponding frame's content.
+ serialized_frame_map_[current_frame_url] += data;
+
+ // Current frame is completed saving, change the finish status.
+ if (status == CURRENT_FRAME_IS_FINISHED)
+ it->second = true;
+ }
+
+ bool HasSerializedFrame(const std::wstring& frame_url) {
+ return serialized_frame_map_.find(frame_url) !=
+ serialized_frame_map_.end();
+ }
+
+ const std::string& GetSerializedContentForFrame(
+ const std::wstring& frame_url) {
+ return serialized_frame_map_[frame_url];
+ }
+
+ // Load web page according to specific URL.
+ void LoadPageFromURL(const std::wstring& page_url) {
+ // Load the test file.
+ test_shell_->ResetTestController();
+ test_shell_->LoadURL(page_url.c_str());
+ test_shell_->WaitTestFinished();
+ }
+
+ // Load web page according to input content and relative URLs within
+ // the document.
+ void LoadContents(const std::string& contents,
+ const GURL& base_url,
+ const WebCore::String encoding_info) {
+ test_shell_->ResetTestController();
+ // If input encoding is empty, use UTF-8 as default encoding.
+ if (encoding_info.isEmpty()) {
+ test_shell_->webView()->GetMainFrame()->LoadHTMLString(contents,
+ base_url);
+ } else {
+ // Do not use WebFrame.LoadHTMLString because it assumes that input
+ // html contents use UTF-8 encoding.
+ WebFrameImpl* web_frame =
+ static_cast<WebFrameImpl*>(test_shell_->webView()->GetMainFrame());
+ ASSERT_TRUE(web_frame != NULL);
+ int len = static_cast<int>(contents.size());
+ RefPtr<WebCore::SharedBuffer> buf(
+ new WebCore::SharedBuffer(contents.data(), len));
+
+ WebCore::SubstituteData subst_data(
+ buf, WebCore::String("text/html"), encoding_info, WebCore::KURL());
+ WebCore::ResourceRequest request(webkit_glue::GURLToKURL(base_url),
+ WebCore::CString());
+ web_frame->frame()->loader()->load(request, subst_data);
+ }
+
+ test_shell_->WaitTestFinished();
+ }
+
+ // Serialize page DOM according to specific page URL. The parameter
+ // recursive_serialization indicates whether we will serialize all
+ // sub-frames.
+ void SerializeDomForURL(const std::wstring& page_url,
+ bool recursive_serialization) {
+ // Find corresponding WebFrameImpl according to page_url.
+ WebFrameImpl* web_frame =
+ webkit_glue::GetWebFrameImplFromWebViewForSpecificURL(
+ test_shell_->webView(), GURL(page_url));
+ ASSERT_TRUE(web_frame != NULL);
+ // Add input file URl to links_.
+ links_.push_back(page_url);
+ // Add dummy file path to local_path_.
+ local_paths_.push_back(std::wstring(L"c:\\dummy.htm"));
+ // Start serializing DOM.
+ webkit_glue::DomSerializer dom_serializer(web_frame,
+ recursive_serialization, this, links_, local_paths_,
+ local_directory_name_);
+ ASSERT_TRUE(dom_serializer.SerializeDom());
+ ASSERT_TRUE(serialized_);
+ }
+
+ private:
+ // Map frame_url to corresponding serialized_content.
+ typedef stdext::hash_map<std::wstring, std::string> SerializedFrameContentMap;
+ SerializedFrameContentMap serialized_frame_map_;
+ // Map frame_url to corresponding status of serialization finish.
+ typedef stdext::hash_map<std::wstring, bool> SerializationFinishStatusMap;
+ SerializationFinishStatusMap serialization_finish_status_;
+ // Flag indicates whether the process of serializing DOM is finished or not.
+ bool serialized_;
+ // The links_ contain dummy original URLs of all saved links.
+ std::vector<std::wstring> links_;
+ // The local_paths_ contain dummy corresponding local file paths of all saved
+ // links, which matched links_ one by one.
+ std::vector<std::wstring> local_paths_;
+ // The local_directory_name_ is dummy relative path of directory which
+ // contain all saved auxiliary files included all sub frames and resources.
+ const std::wstring local_directory_name_;
+
+ protected:
+ // testing::Test
+ virtual void SetUp() {
+ TestShellTest::SetUp();
+ serialized_ = false;
+ }
+
+ virtual void TearDown() {
+ TestShellTest::TearDown();
+ }
+};
+
+// Helper function for checking whether input node is META tag. Return true
+// means it is META element, otherwise return false. The parameter charset_info
+// return actual charset info if the META tag has charset declaration.
+bool IsMetaElement(const WebCore::Node* node, WebCore::String* charset_info) {
+ if (!node->isHTMLElement())
+ return false;
+ if (!(static_cast<const WebCore::HTMLElement*>(node))->hasTagName(
+ WebCore::HTMLNames::metaTag))
+ return false;
+ charset_info->remove(0, charset_info->length());
+ const WebCore::HTMLMetaElement* meta =
+ static_cast<const WebCore::HTMLMetaElement*>(node);
+ // Check the META charset declaration.
+ WebCore::String equiv = meta->httpEquiv();
+ if (equalIgnoringCase(equiv, "content-type")) {
+ WebCore::String content = meta->content();
+ int pos = content.find("charset", 0, false);
+ if (pos > -1) {
+ // Add a dummy charset declaration to charset_info, which indicates this
+ // META tag has charset declaration although we do not get correct value
+ // yet.
+ charset_info->append("has-charset-declaration");
+ int remaining_length = content.length() - pos - 7;
+ if (!remaining_length)
+ return true;
+ const UChar* start_pos = content.characters() + pos + 7;
+ // Find "=" symbol.
+ while (remaining_length--)
+ if (*start_pos++ == L'=')
+ break;
+ // Skip beginning space.
+ while (remaining_length) {
+ if (*start_pos > 0x0020)
+ break;
+ ++start_pos;
+ --remaining_length;
+ }
+ if (!remaining_length)
+ return true;
+ const UChar* end_pos = start_pos;
+ // Now we find out the start point of charset info. Search the end point.
+ while (remaining_length--) {
+ if (*end_pos <= 0x0020 || *end_pos == L';')
+ break;
+ ++end_pos;
+ }
+ // Get actual charset info.
+ *charset_info = WebCore::String(start_pos,
+ static_cast<unsigned>(end_pos - start_pos));
+ return true;
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+// If original contents have document type, the serialized contents also have
+// document type.
+TEST_F(DomSerializerTests, SerialzeHTMLDOMWithDocType) {
+ std::wstring page_file_path = data_dir_;
+ file_util::AppendToPath(&page_file_path, L"dom_serializer/youtube_1.htm");
+ GURL file_url = net_util::FilePathToFileURL(page_file_path);
+ ASSERT_TRUE(file_url.SchemeIsFile());
+ std::wstring page_url = ASCIIToWide(file_url.spec());
+ // Load the test file.
+ LoadPageFromURL(page_url);
+ // Make sure original contents have document type.
+ WebFrameImpl* web_frame =
+ webkit_glue::GetWebFrameImplFromWebViewForSpecificURL(
+ test_shell_->webView(), file_url);
+ ASSERT_TRUE(web_frame != NULL);
+ WebCore::Document* doc = web_frame->frame()->document();
+ ASSERT_TRUE(doc->doctype() != NULL);
+ // Do serialization.
+ SerializeDomForURL(page_url, false);
+ // Load the serialized contents.
+ ASSERT_TRUE(HasSerializedFrame(page_url));
+ const std::string& serialized_contents =
+ GetSerializedContentForFrame(page_url);
+ LoadContents(serialized_contents, GURL(page_url),
+ web_frame->frame()->loader()->encoding());
+ // Make sure serialized contents still have document type.
+ web_frame =
+ static_cast<WebFrameImpl*>(test_shell_->webView()->GetMainFrame());
+ doc = web_frame->frame()->document();
+ ASSERT_TRUE(doc->doctype() != NULL);
+}
+
+// If original contents do not have document type, the serialized contents
+// also do not have document type.
+TEST_F(DomSerializerTests, SerialzeHTMLDOMWithoutDocType) {
+ std::wstring page_file_path = data_dir_;
+ file_util::AppendToPath(&page_file_path, L"dom_serializer/youtube_2.htm");
+ GURL file_url = net_util::FilePathToFileURL(page_file_path);
+ ASSERT_TRUE(file_url.SchemeIsFile());
+ std::wstring page_url = ASCIIToWide(file_url.spec());
+ // Load the test file.
+ LoadPageFromURL(page_url);
+ // Make sure original contents do not have document type.
+ WebFrameImpl* web_frame =
+ webkit_glue::GetWebFrameImplFromWebViewForSpecificURL(
+ test_shell_->webView(), file_url);
+ ASSERT_TRUE(web_frame != NULL);
+ WebCore::Document* doc = web_frame->frame()->document();
+ ASSERT_TRUE(doc->doctype() == NULL);
+ // Do serialization.
+ SerializeDomForURL(page_url, false);
+ // Load the serialized contents.
+ ASSERT_TRUE(HasSerializedFrame(page_url));
+ const std::string& serialized_contents =
+ GetSerializedContentForFrame(page_url);
+ LoadContents(serialized_contents, GURL(page_url),
+ web_frame->frame()->loader()->encoding());
+ // Make sure serialized contents do not have document type.
+ web_frame =
+ static_cast<WebFrameImpl*>(test_shell_->webView()->GetMainFrame());
+ doc = web_frame->frame()->document();
+ ASSERT_TRUE(doc->doctype() == NULL);
+}
+
+// Serialize XML document which has all 5 built-in entities. After
+// finishing serialization, the serialized contents should be same
+// with original XML document.
+TEST_F(DomSerializerTests, SerialzeXMLDocWithBuiltInEntities) {
+ std::wstring page_file_path = data_dir_;
+ file_util::AppendToPath(&page_file_path, L"dom_serializer/note.xml");
+ // Read original contents for later comparison.
+ std::string orginal_contents;
+ ASSERT_TRUE(file_util::ReadFileToString(page_file_path, &orginal_contents));
+ // Get file URL.
+ GURL file_url = net_util::FilePathToFileURL(page_file_path);
+ ASSERT_TRUE(file_url.SchemeIsFile());
+ std::wstring page_url = ASCIIToWide(file_url.spec());
+ // Load the test file.
+ LoadPageFromURL(page_url);
+ // Do serialization.
+ SerializeDomForURL(page_url, false);
+ // Compare the serialized contents with original contents.
+ ASSERT_TRUE(HasSerializedFrame(page_url));
+ const std::string& serialized_contents =
+ GetSerializedContentForFrame(page_url);
+ ASSERT_EQ(serialized_contents, orginal_contents);
+}
+
+// When serializing DOM, we add MOTW declaration before html tag.
+TEST_F(DomSerializerTests, SerialzeHTMLDOMWithAddingMOTW) {
+ std::wstring page_file_path = data_dir_;
+ file_util::AppendToPath(&page_file_path, L"dom_serializer/youtube_2.htm");
+ // Read original contents for later comparison .
+ std::string orginal_contents;
+ ASSERT_TRUE(file_util::ReadFileToString(page_file_path, &orginal_contents));
+ // Get file URL.
+ GURL file_url = net_util::FilePathToFileURL(page_file_path);
+ ASSERT_TRUE(file_url.SchemeIsFile());
+ std::wstring page_url = ASCIIToWide(file_url.spec());
+ // Make sure original contents does not have MOTW;
+ std::wstring motw_declaration =
+ webkit_glue::DomSerializer::GenerateMarkOfTheWebDeclaration(page_url);
+ ASSERT_FALSE(motw_declaration.empty());
+ // The encoding of original contents is ISO-8859-1, so we convert the MOTW
+ // declaration to ASCII and search whether original contents has it or not.
+ ASSERT_TRUE(std::wstring::npos ==
+ orginal_contents.find(WideToASCII(motw_declaration)));
+ // Load the test file.
+ LoadPageFromURL(page_url);
+ // Do serialization.
+ SerializeDomForURL(page_url, false);
+ // Make sure the serialized contents have MOTW ;
+ ASSERT_TRUE(HasSerializedFrame(page_url));
+ const std::string& serialized_contents =
+ GetSerializedContentForFrame(page_url);
+ ASSERT_TRUE(std::wstring::npos !=
+ serialized_contents.find(WideToUTF8(motw_declaration)));
+}
+
+// When serializing DOM, we will add the META which have correct charset
+// declaration as first child of HEAD element for resolving WebKit bug:
+// http://bugs.webkit.org/show_bug.cgi?id=16621 even the original document
+// does not have META charset declaration.
+TEST_F(DomSerializerTests, SerialzeHTMLDOMWithNoMetaCharsetInOriginalDoc) {
+ std::wstring page_file_path = data_dir_;
+ file_util::AppendToPath(&page_file_path, L"dom_serializer/youtube_1.htm");
+ // Get file URL.
+ GURL file_url = net_util::FilePathToFileURL(page_file_path);
+ ASSERT_TRUE(file_url.SchemeIsFile());
+ std::wstring page_url = ASCIIToWide(file_url.spec());
+ // Load the test file.
+ LoadPageFromURL(page_url);
+
+ // Make sure there is no META charset declaration in original document.
+ WebFrameImpl* web_frame =
+ webkit_glue::GetWebFrameImplFromWebViewForSpecificURL(
+ test_shell_->webView(), file_url);
+ ASSERT_TRUE(web_frame != NULL);
+ WebCore::Document* doc = web_frame->frame()->document();
+ ASSERT_TRUE(doc->isHTMLDocument());
+ WebCore::HTMLHeadElement* head_ele = doc->head();
+ ASSERT_TRUE(head_ele != NULL);
+ // Go through all children of HEAD element.
+ WebCore::String charset_info;
+ for (const WebCore::Node *child = head_ele->firstChild(); child != NULL;
+ child = child->nextSibling())
+ if (IsMetaElement(child, &charset_info))
+ ASSERT_TRUE(charset_info.isEmpty());
+
+ // Do serialization.
+ SerializeDomForURL(page_url, false);
+
+ // Load the serialized contents.
+ ASSERT_TRUE(HasSerializedFrame(page_url));
+ const std::string& serialized_contents =
+ GetSerializedContentForFrame(page_url);
+ LoadContents(serialized_contents, GURL(page_url),
+ web_frame->frame()->loader()->encoding());
+ // Make sure the first child of HEAD element is META which has charset
+ // declaration in serialized contents.
+ web_frame =
+ static_cast<WebFrameImpl*>(test_shell_->webView()->GetMainFrame());
+ ASSERT_TRUE(web_frame != NULL);
+ doc = web_frame->frame()->document();
+ ASSERT_TRUE(doc->isHTMLDocument());
+ head_ele = doc->head();
+ ASSERT_TRUE(head_ele != NULL);
+ WebCore::Node* meta_node = head_ele->firstChild();
+ ASSERT_TRUE(meta_node != NULL);
+ // Get meta charset info.
+ ASSERT_TRUE(IsMetaElement(meta_node, &charset_info));
+ ASSERT_TRUE(!charset_info.isEmpty());
+ ASSERT_TRUE(charset_info == web_frame->frame()->loader()->encoding());
+
+ // Make sure no more additional META tags which have charset declaration.
+ for (const WebCore::Node *child = meta_node->nextSibling(); child != NULL;
+ child = child->nextSibling())
+ if (IsMetaElement(child, &charset_info))
+ ASSERT_TRUE(charset_info.isEmpty());
+}
+
+// When serializing DOM, if the original document has multiple META charset
+// declaration, we will add the META which have correct charset declaration
+// as first child of HEAD element and remove all original META charset
+// declarations.
+TEST_F(DomSerializerTests,
+ SerialzeHTMLDOMWithMultipleMetaCharsetInOriginalDoc) {
+ std::wstring page_file_path = data_dir_;
+ file_util::AppendToPath(&page_file_path, L"dom_serializer/youtube_2.htm");
+ // Get file URL.
+ GURL file_url = net_util::FilePathToFileURL(page_file_path);
+ ASSERT_TRUE(file_url.SchemeIsFile());
+ std::wstring page_url = ASCIIToWide(file_url.spec());
+ // Load the test file.
+ LoadPageFromURL(page_url);
+
+ // Make sure there are multiple META charset declarations in original
+ // document.
+ WebFrameImpl* web_frame =
+ webkit_glue::GetWebFrameImplFromWebViewForSpecificURL(
+ test_shell_->webView(), file_url);
+ ASSERT_TRUE(web_frame != NULL);
+ WebCore::Document* doc = web_frame->frame()->document();
+ ASSERT_TRUE(doc->isHTMLDocument());
+ WebCore::HTMLHeadElement* head_ele = doc->head();
+ ASSERT_TRUE(head_ele != NULL);
+ // Go through all children of HEAD element.
+ int charset_declaration_count = 0;
+ WebCore::String charset_info;
+ for (const WebCore::Node *child = head_ele->firstChild(); child != NULL;
+ child = child->nextSibling()) {
+ if (IsMetaElement(child, &charset_info) && !charset_info.isEmpty())
+ charset_declaration_count++;
+ }
+ // The original doc has more than META tags which have charset declaration.
+ ASSERT(charset_declaration_count > 1);
+
+ // Do serialization.
+ SerializeDomForURL(page_url, false);
+
+ // Load the serialized contents.
+ ASSERT_TRUE(HasSerializedFrame(page_url));
+ const std::string& serialized_contents =
+ GetSerializedContentForFrame(page_url);
+ LoadContents(serialized_contents, GURL(page_url),
+ web_frame->frame()->loader()->encoding());
+ // Make sure only first child of HEAD element is META which has charset
+ // declaration in serialized contents.
+ web_frame =
+ static_cast<WebFrameImpl*>(test_shell_->webView()->GetMainFrame());
+ ASSERT_TRUE(web_frame != NULL);
+ doc = web_frame->frame()->document();
+ ASSERT_TRUE(doc->isHTMLDocument());
+ head_ele = doc->head();
+ ASSERT_TRUE(head_ele != NULL);
+ WebCore::Node* meta_node = head_ele->firstChild();
+ ASSERT_TRUE(meta_node != NULL);
+ // Get meta charset info.
+ ASSERT_TRUE(IsMetaElement(meta_node, &charset_info));
+ ASSERT_TRUE(!charset_info.isEmpty());
+ ASSERT_TRUE(charset_info == web_frame->frame()->loader()->encoding());
+
+ // Make sure no more additional META tags which have charset declaration.
+ for (const WebCore::Node *child = meta_node->nextSibling(); child != NULL;
+ child = child->nextSibling())
+ if (IsMetaElement(child, &charset_info))
+ ASSERT_TRUE(charset_info.isEmpty());
+}
+
+// Test situation of html entities in text when serializing HTML DOM.
+TEST_F(DomSerializerTests, SerialzeHTMLDOMWithEntitiesInText) {
+ std::wstring page_file_path = data_dir_;
+ file_util::AppendToPath(&page_file_path,
+ L"dom_serializer/htmlentities_in_text.htm");
+ // Read original contents for later comparison .
+ std::string orginal_contents;
+ ASSERT_TRUE(file_util::ReadFileToString(page_file_path, &orginal_contents));
+ // Get file URL.
+ GURL file_url = net_util::FilePathToFileURL(page_file_path);
+ ASSERT_TRUE(file_url.SchemeIsFile());
+ std::wstring page_url = ASCIIToWide(file_url.spec());
+ // Load the test file.
+ LoadPageFromURL(page_url);
+ // Get BODY's text content in DOM.
+ WebFrameImpl* web_frame =
+ webkit_glue::GetWebFrameImplFromWebViewForSpecificURL(
+ test_shell_->webView(), file_url);
+ ASSERT_TRUE(web_frame != NULL);
+ WebCore::Document* doc = web_frame->frame()->document();
+ ASSERT_TRUE(doc->isHTMLDocument());
+ WebCore::HTMLElement* body_ele = doc->body();
+ ASSERT_TRUE(body_ele != NULL);
+ WebCore::Node* text_node = body_ele->firstChild();
+ ASSERT_TRUE(text_node->isTextNode());
+ ASSERT_TRUE(text_node->toString() == WebCore::String("&<>\"\'"));
+ // Do serialization.
+ SerializeDomForURL(page_url, false);
+ // Compare the serialized contents with original contents.
+ ASSERT_TRUE(HasSerializedFrame(page_url));
+ const std::string& serialized_contents =
+ GetSerializedContentForFrame(page_url);
+ // Because we add MOTW when serializing DOM, so before comparison, we also
+ // need to add MOTW to original_contents.
+ std::wstring motw_declaration =
+ webkit_glue::DomSerializer::GenerateMarkOfTheWebDeclaration(page_url);
+ orginal_contents = WideToASCII(motw_declaration) + orginal_contents;
+ ASSERT_EQ(serialized_contents, orginal_contents);
+}
+
+// Test situation of html entities in attribute value when serializing
+// HTML DOM.
+TEST_F(DomSerializerTests, SerialzeHTMLDOMWithEntitiesInAttributeValue) {
+ std::wstring page_file_path = data_dir_;
+ file_util::AppendToPath(&page_file_path,
+ L"dom_serializer/htmlentities_in_attribute_value.htm");
+ // Read original contents for later comparison.
+ std::string orginal_contents;
+ ASSERT_TRUE(file_util::ReadFileToString(page_file_path, &orginal_contents));
+ // Get file URL.
+ GURL file_url = net_util::FilePathToFileURL(page_file_path);
+ ASSERT_TRUE(file_url.SchemeIsFile());
+ std::wstring page_url = ASCIIToWide(file_url.spec());
+ // Load the test file.
+ LoadPageFromURL(page_url);
+ // Get value of BODY's title attribute in DOM.
+ WebFrameImpl* web_frame =
+ webkit_glue::GetWebFrameImplFromWebViewForSpecificURL(
+ test_shell_->webView(), file_url);
+ ASSERT_TRUE(web_frame != NULL);
+ WebCore::Document* doc = web_frame->frame()->document();
+ ASSERT_TRUE(doc->isHTMLDocument());
+ WebCore::HTMLElement* body_ele = doc->body();
+ ASSERT_TRUE(body_ele != NULL);
+ const WebCore::String& value = body_ele->getAttribute(
+ WebCore::HTMLNames::titleAttr);
+ ASSERT_TRUE(value == WebCore::String("&<>\"\'"));
+ // Do serialization.
+ SerializeDomForURL(page_url, false);
+ // Compare the serialized contents with original contents.
+ ASSERT_TRUE(HasSerializedFrame(page_url));
+ const std::string& serialized_contents =
+ GetSerializedContentForFrame(page_url);
+ // Because we add MOTW when serializing DOM, so before comparison, we also
+ // need to add MOTW to original_contents.
+ std::wstring motw_declaration =
+ webkit_glue::DomSerializer::GenerateMarkOfTheWebDeclaration(page_url);
+ orginal_contents = WideToASCII(motw_declaration) + orginal_contents;
+ ASSERT_EQ(serialized_contents, orginal_contents);
+}
+
+// Test situation of BASE tag in original document when serializing HTML DOM.
+// When serializing, we should comment the BASE tag, append a new BASE tag.
+// rewrite all the savable URLs to relative local path, and change other URLs
+// to absolute URLs.
+TEST_F(DomSerializerTests, SerialzeHTMLDOMWithBaseTag) {
+ // There are total 2 available base tags in this test file.
+ const int kTotalBaseTagCountInTestFile = 2;
+ std::wstring page_file_path = data_dir_;
+ file_util::AppendToPath(&page_file_path, L"dom_serializer\\");
+ // Get page dir URL which is base URL of this file.
+ GURL path_dir_url = net_util::FilePathToFileURL(page_file_path);
+ // Get file path.
+ file_util::AppendToPath(&page_file_path, L"html_doc_has_base_tag.htm");
+ // Get file URL.
+ GURL file_url = net_util::FilePathToFileURL(page_file_path);
+ ASSERT_TRUE(file_url.SchemeIsFile());
+ std::wstring page_url = ASCIIToWide(file_url.spec());
+ // Load the test file.
+ LoadPageFromURL(page_url);
+ // Since for this test, we assume there is no savable sub-resource links for
+ // this test file, also all links are relative URLs in this test file, so we
+ // need to check those relative URLs and make sure document has BASE tag.
+ WebFrameImpl* web_frame =
+ webkit_glue::GetWebFrameImplFromWebViewForSpecificURL(
+ test_shell_->webView(), file_url);
+ ASSERT_TRUE(web_frame != NULL);
+ WebCore::Document* doc = web_frame->frame()->document();
+ ASSERT_TRUE(doc->isHTMLDocument());
+ // Go through all descent nodes.
+ RefPtr<WebCore::HTMLCollection> all = doc->all();
+ int original_base_tag_count = 0;
+ for (WebCore::Node* node = all->firstItem(); node != NULL;
+ node = all->nextItem()) {
+ if (!node->isHTMLElement())
+ continue;
+ WebCore::Element* element = static_cast<WebCore::Element*>(node);
+ if (element->hasTagName(WebCore::HTMLNames::baseTag)) {
+ original_base_tag_count++;
+ } else {
+ // Get link.
+ const WebCore::AtomicString* value =
+ webkit_glue::GetSubResourceLinkFromElement(element);
+ if (!value && element->hasTagName(WebCore::HTMLNames::aTag)) {
+ value = &element->getAttribute(WebCore::HTMLNames::hrefAttr);
+ if (value->domString().isEmpty())
+ value = NULL;
+ }
+ // Each link is relative link.
+ if (value) {
+ GURL link(webkit_glue::StringToStdWString(value->domString()).c_str());
+ ASSERT_TRUE(link.scheme().empty());
+ }
+ }
+ }
+ ASSERT_TRUE(original_base_tag_count == kTotalBaseTagCountInTestFile);
+ // Make sure in original document, the base URL is not equal with the
+ // |path_dir_url|.
+ GURL original_base_url(
+ webkit_glue::DeprecatedStringToStdWString(doc->baseURL()).c_str());
+ ASSERT_TRUE(original_base_url != path_dir_url);
+
+ // Do serialization.
+ SerializeDomForURL(page_url, false);
+
+ // Load the serialized contents.
+ ASSERT_TRUE(HasSerializedFrame(page_url));
+ const std::string& serialized_contents =
+ GetSerializedContentForFrame(page_url);
+ LoadContents(serialized_contents, GURL(page_url),
+ web_frame->frame()->loader()->encoding());
+
+ // Make sure all links are absolute URLs and doc there are some number of
+ // BASE tags in serialized HTML data. Each of those BASE tags have same base
+ // URL which is as same as URL of current test file.
+ web_frame =
+ static_cast<WebFrameImpl*>(test_shell_->webView()->GetMainFrame());
+ ASSERT_TRUE(web_frame != NULL);
+ doc = web_frame->frame()->document();
+ ASSERT_TRUE(doc->isHTMLDocument());
+ // Go through all descent nodes.
+ all = doc->all();
+ int new_base_tag_count = 0;
+ for (WebCore::Node* node = all->firstItem(); node != NULL;
+ node = all->nextItem()) {
+ if (!node->isHTMLElement())
+ continue;
+ WebCore::Element* element = static_cast<WebCore::Element*>(node);
+ if (element->hasTagName(WebCore::HTMLNames::baseTag)) {
+ new_base_tag_count++;
+ } else {
+ // Get link.
+ const WebCore::AtomicString* value =
+ webkit_glue::GetSubResourceLinkFromElement(element);
+ if (!value && element->hasTagName(WebCore::HTMLNames::aTag)) {
+ value = &element->getAttribute(WebCore::HTMLNames::hrefAttr);
+ if (value->domString().isEmpty())
+ value = NULL;
+ }
+ // Each link is absolute link.
+ if (value) {
+ GURL link(webkit_glue::StringToStdWString(value->domString()).c_str());
+ ASSERT_FALSE(link.scheme().empty());
+ }
+ }
+ }
+ // We have one more added BASE tag which is generated by JavaScript.
+ ASSERT_TRUE(new_base_tag_count == original_base_tag_count + 1);
+ // Make sure in new document, the base URL is equal with the |path_dir_url|.
+ GURL new_base_url(
+ webkit_glue::DeprecatedStringToStdWString(doc->baseURL()).c_str());
+ ASSERT_TRUE(new_base_url == path_dir_url);
+}
diff --git a/webkit/glue/dragclient_impl.cc b/webkit/glue/dragclient_impl.cc
new file mode 100644
index 0000000..f3063fa9
--- /dev/null
+++ b/webkit/glue/dragclient_impl.cc
@@ -0,0 +1,107 @@
+// 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 "config.h"
+
+#include <objidl.h>
+
+#pragma warning(push, 0)
+#include "ClipboardWin.h"
+#include "COMPtr.h"
+#include "DragData.h"
+#include "Frame.h"
+#include "HitTestResult.h"
+#include "Image.h"
+#include "KURL.h"
+#pragma warning(pop)
+#undef LOG
+
+#include "webkit/glue/dragclient_impl.h"
+
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "webkit/glue/context_node_types.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/webdropdata.h"
+#include "webkit/glue/webview_delegate.h"
+#include "webkit/glue/webview_impl.h"
+
+void DragClientImpl::willPerformDragDestinationAction(
+ WebCore::DragDestinationAction,
+ WebCore::DragData*) {
+ // FIXME
+}
+
+void DragClientImpl::willPerformDragSourceAction(
+ WebCore::DragSourceAction,
+ const WebCore::IntPoint&,
+ WebCore::Clipboard*) {
+ // FIXME
+}
+
+WebCore::DragDestinationAction DragClientImpl::actionMaskForDrag(
+ WebCore::DragData*) {
+ return WebCore::DragDestinationActionAny;
+}
+
+WebCore::DragSourceAction DragClientImpl::dragSourceActionMaskForPoint(
+ const WebCore::IntPoint& window_point) {
+ // We want to handle drag operations for all source types.
+ return WebCore::DragSourceActionAny;
+}
+
+void DragClientImpl::startDrag(WebCore::DragImageRef drag_image,
+ const WebCore::IntPoint& drag_image_origin,
+ const WebCore::IntPoint& event_pos,
+ WebCore::Clipboard* clipboard,
+ WebCore::Frame* frame,
+ bool is_link_drag) {
+ // Add a ref to the frame just in case a load occurs mid-drag.
+ RefPtr<WebCore::Frame> frame_protector = frame;
+
+ COMPtr<IDataObject> data_object(
+ static_cast<WebCore::ClipboardWin*>(clipboard)->dataObject());
+ DCHECK(data_object.get());
+ WebDropData drop_data;
+ WebDropData::PopulateWebDropData(data_object.get(), &drop_data);
+
+ webview_->StartDragging(drop_data);
+}
+
+WebCore::DragImageRef DragClientImpl::createDragImageForLink(
+ WebCore::KURL&,
+ const WebCore::String& label,
+ WebCore::Frame*) {
+ // FIXME
+ return 0;
+}
+
+void DragClientImpl::dragControllerDestroyed() {
+ delete this;
+}
diff --git a/webkit/glue/dragclient_impl.h b/webkit/glue/dragclient_impl.h
new file mode 100644
index 0000000..1a2b2a3
--- /dev/null
+++ b/webkit/glue/dragclient_impl.h
@@ -0,0 +1,79 @@
+// 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 WEBKIT_GLUE_DRAGCLIENT_IMPL_H__
+#define WEBKIT_GLUE_DRAGCLIENT_IMPL_H__
+
+#include "base/basictypes.h"
+
+#pragma warning(push, 0)
+#include "DragClient.h"
+#include "DragActions.h"
+#pragma warning(pop)
+
+namespace WebCore {
+class ClipBoard;
+class DragData;
+class IntPoint;
+class KURL;
+}
+
+class WebViewImpl;
+
+class DragClientImpl : public WebCore::DragClient {
+public:
+ DragClientImpl(WebViewImpl* webview) : webview_(webview) {}
+ virtual ~DragClientImpl() {}
+
+ virtual void willPerformDragDestinationAction(WebCore::DragDestinationAction,
+ WebCore::DragData*);
+ virtual void willPerformDragSourceAction(WebCore::DragSourceAction,
+ const WebCore::IntPoint&,
+ WebCore::Clipboard*);
+ virtual WebCore::DragDestinationAction actionMaskForDrag(WebCore::DragData*);
+ virtual WebCore::DragSourceAction dragSourceActionMaskForPoint(
+ const WebCore::IntPoint& window_point);
+
+ virtual void startDrag(WebCore::DragImageRef drag_image,
+ const WebCore::IntPoint& drag_image_origin,
+ const WebCore::IntPoint& event_pos,
+ WebCore::Clipboard* clipboard,
+ WebCore::Frame* frame,
+ bool is_link_drag = false);
+ virtual WebCore::DragImageRef createDragImageForLink(
+ WebCore::KURL&, const WebCore::String& label, WebCore::Frame*);
+
+ virtual void dragControllerDestroyed();
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(DragClientImpl);
+ WebViewImpl* webview_;
+};
+
+#endif // #ifndef WEBKIT_GLUE_DRAGCLIENT_IMPL_H__
diff --git a/webkit/glue/editor_client_impl.cc b/webkit/glue/editor_client_impl.cc
new file mode 100644
index 0000000..50545d6
--- /dev/null
+++ b/webkit/glue/editor_client_impl.cc
@@ -0,0 +1,786 @@
+// 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.
+
+// The Mac interface forwards most of these commands to the application layer,
+// and I'm not really sure what to do about most of them.
+
+#include "config.h"
+#pragma warning(push, 0)
+#include "Document.h"
+#include "EditCommand.h"
+#include "Editor.h"
+#include "EventHandler.h"
+#include "EventNames.h"
+#include "HTMLInputElement.h"
+#include "Frame.h"
+#include "KeyboardEvent.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformString.h"
+#include "WebView.h"
+#pragma warning(pop)
+
+#undef LOG
+
+#include "base/string_util.h"
+#include "webkit/glue/editor_client_impl.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/webview_impl.h"
+
+// The notImplemented() from NotImplemented.h is now being dragged in via
+// webview_impl.h. We want the one from LogWin.h instead.
+#undef notImplemented
+#include "LogWin.h"
+
+// Arbitrary depth limit for the undo stack, to keep it from using
+// unbounded memory. This is the maximum number of distinct undoable
+// actions -- unbroken stretches of typed characters are coalesced
+// into a single action.
+static const int kMaximumUndoStackDepth = 1000;
+
+namespace {
+
+// Record an editor command from the keyDownEntries[] below. We ignore the
+// Move* and Insert* commands because they're not that interesting.
+void MaybeRecordCommand(WebViewDelegate* d, const char* command_name) {
+ if (!d)
+ return;
+
+ const char* move_prefix = "Move";
+ const char* insert_prefix = "Insert";
+ const char* delete_prefix = "Delete";
+ // Ignore all the Move*, Insert*, and Delete* commands.
+ if (0 == strncmp(command_name, move_prefix, sizeof(move_prefix)) ||
+ 0 == strncmp(command_name, insert_prefix, sizeof(insert_prefix)) ||
+ 0 == strncmp(command_name, delete_prefix, sizeof(delete_prefix))) {
+ return;
+ }
+ d->UserMetricsRecordComputedAction(UTF8ToWide(command_name));
+}
+
+}
+
+EditorClientImpl::EditorClientImpl(WebView* web_view)
+ : web_view_(static_cast<WebViewImpl*>(web_view)),
+ use_editor_delegate_(false),
+ in_redo_(false),
+ preserve_(false),
+ pending_inline_autocompleted_element_(NULL) {
+}
+
+EditorClientImpl::~EditorClientImpl() {
+}
+
+void EditorClientImpl::pageDestroyed() {
+ // Called by the Page (which owns the editor client) when the page is going
+ // away. This should cause us to delete ourselves, which is stupid. The page
+ // should just delete us when it's going away. Oh well.
+ delete this;
+}
+
+bool EditorClientImpl::shouldShowDeleteInterface(WebCore::HTMLElement* elem) {
+ // Normally, we don't care to show WebCore's deletion UI, so we only enable
+ // it if in testing mode and the test specifically requests it by using this
+ // magic class name.
+ return webkit_glue::IsLayoutTestMode() &&
+ elem->className() == "needsDeletionUI";
+}
+
+bool EditorClientImpl::smartInsertDeleteEnabled() {
+ if (use_editor_delegate_) {
+ WebViewDelegate* d = web_view_->delegate();
+ if (d)
+ return d->SmartInsertDeleteEnabled();
+ }
+ return true;
+}
+
+bool EditorClientImpl::isContinuousSpellCheckingEnabled() {
+ // Spell check everything if possible.
+ // FIXME(brettw) This should be modified to do reasonable defaults depending
+ // on input type, and probably also allow the user to turn spellchecking on
+ // for individual fields.
+ return true;
+}
+
+void EditorClientImpl::toggleContinuousSpellChecking() {
+ notImplemented();
+}
+
+bool EditorClientImpl::isGrammarCheckingEnabled() {
+ notImplemented();
+ return false;
+}
+
+void EditorClientImpl::toggleGrammarChecking() {
+ notImplemented();
+}
+
+int EditorClientImpl::spellCheckerDocumentTag() {
+ notImplemented();
+ return 0;
+}
+
+bool EditorClientImpl::isEditable() {
+ notImplemented();
+ return false;
+}
+
+bool EditorClientImpl::shouldBeginEditing(WebCore::Range* range) {
+ if (use_editor_delegate_) {
+ WebViewDelegate* d = web_view_->delegate();
+ if (d)
+ return d->ShouldBeginEditing(web_view_, Describe(range));
+ }
+ return true;
+}
+
+bool EditorClientImpl::shouldEndEditing(WebCore::Range* range) {
+ if (use_editor_delegate_) {
+ WebViewDelegate* d = web_view_->delegate();
+ if (d)
+ return d->ShouldEndEditing(web_view_, Describe(range));
+ }
+ return true;
+}
+
+bool EditorClientImpl::shouldInsertNode(WebCore::Node* node,
+ WebCore::Range* range,
+ WebCore::EditorInsertAction action) {
+ if (use_editor_delegate_) {
+ WebViewDelegate* d = web_view_->delegate();
+ if (d) {
+ return d->ShouldInsertNode(web_view_,
+ Describe(node),
+ Describe(range),
+ Describe(action));
+ }
+ }
+ return true;
+}
+
+bool EditorClientImpl::shouldInsertText(WebCore::String text,
+ WebCore::Range* range,
+ WebCore::EditorInsertAction action) {
+ if (use_editor_delegate_) {
+ WebViewDelegate* d = web_view_->delegate();
+ if (d) {
+ std::wstring wstr = webkit_glue::StringToStdWString(text);
+ return d->ShouldInsertText(web_view_,
+ wstr,
+ Describe(range),
+ Describe(action));
+ }
+ }
+ return true;
+}
+
+
+bool EditorClientImpl::shouldDeleteRange(WebCore::Range* range) {
+ if (use_editor_delegate_) {
+ WebViewDelegate* d = web_view_->delegate();
+ if (d)
+ return d->ShouldDeleteRange(web_view_, Describe(range));
+ }
+ return true;
+}
+
+void EditorClientImpl::PreserveSelection() {
+ preserve_ = true;
+}
+
+bool EditorClientImpl::shouldChangeSelectedRange(WebCore::Range* fromRange,
+ WebCore::Range* toRange,
+ WebCore::EAffinity affinity,
+ bool stillSelecting) {
+ if (use_editor_delegate_) {
+ WebViewDelegate* d = web_view_->delegate();
+ if (d) {
+ return d->ShouldChangeSelectedRange(web_view_,
+ Describe(fromRange),
+ Describe(toRange),
+ Describe(affinity),
+ stillSelecting);
+ }
+ }
+ // Have we been told to preserve the selection?
+ // (See comments for PreserveSelection in header).
+ if (preserve_) {
+ preserve_ = false;
+ return false;
+ }
+ return true;
+}
+
+bool EditorClientImpl::shouldApplyStyle(WebCore::CSSStyleDeclaration* style,
+ WebCore::Range* range) {
+ if (use_editor_delegate_) {
+ WebViewDelegate* d = web_view_->delegate();
+ if (d)
+ return d->ShouldApplyStyle(web_view_, Describe(style), Describe(range));
+ }
+ return true;
+}
+
+bool EditorClientImpl::shouldMoveRangeAfterDelete(
+ WebCore::Range* /*range*/,
+ WebCore::Range* /*rangeToBeReplaced*/) {
+ notImplemented();
+ return true;
+}
+
+void EditorClientImpl::didBeginEditing() {
+ if (use_editor_delegate_) {
+ WebViewDelegate* d = web_view_->delegate();
+ if (d)
+ d->DidBeginEditing();
+ }
+}
+
+void EditorClientImpl::respondToChangedSelection() {
+ if (use_editor_delegate_) {
+ WebViewDelegate* d = web_view_->delegate();
+ if (d)
+ d->DidChangeSelection();
+ }
+}
+
+void EditorClientImpl::respondToChangedContents() {
+ // Ugly Hack. (See also webkit bug #16976).
+ // Something is wrong with webcore's focusController in that when selection
+ // is set to a region within a text element when handling an input event, if
+ // you don't re-focus the node then it only _APPEARS_ to have successfully
+ // changed the selection (the UI "looks" right) but in reality there is no
+ // selection of text. And to make matters worse, you can't just re-focus it,
+ // you have to re-focus it in code executed after the entire event listener
+ // loop has finished; and hence here we are. Oh, and to make matters worse,
+ // this sequence of events _doesn't_ happen when you debug through the code
+ // -- in that case it works perfectly fine -- because swapping to the debugger
+ // causes the refocusing we artificially reproduce here.
+ // TODO (timsteele): Clean this up once root webkit problem is identified and
+ // the bug is patched.
+ if (pending_inline_autocompleted_element_) {
+ pending_inline_autocompleted_element_->blur();
+ pending_inline_autocompleted_element_->focus();
+ pending_inline_autocompleted_element_ = NULL;
+ }
+
+ if (use_editor_delegate_) {
+ WebViewDelegate* d = web_view_->delegate();
+ if (d)
+ d->DidChangeContents();
+ }
+}
+
+void EditorClientImpl::didEndEditing() {
+ if (use_editor_delegate_) {
+ WebViewDelegate* d = web_view_->delegate();
+ if (d)
+ d->DidEndEditing();
+ }
+}
+
+void EditorClientImpl::didWriteSelectionToPasteboard() {
+ notImplemented();
+}
+
+void EditorClientImpl::didSetSelectionTypesForPasteboard() {
+ notImplemented();
+}
+
+void EditorClientImpl::registerCommandForUndo(
+ PassRefPtr<WebCore::EditCommand> command) {
+ if (undo_stack_.size() == kMaximumUndoStackDepth)
+ undo_stack_.pop_front(); // drop oldest item off the far end
+ if (!in_redo_)
+ redo_stack_.clear();
+ undo_stack_.push_back(command);
+}
+
+void EditorClientImpl::registerCommandForRedo(
+ PassRefPtr<WebCore::EditCommand> command) {
+ redo_stack_.push_back(command);
+}
+
+void EditorClientImpl::clearUndoRedoOperations() {
+ undo_stack_.clear();
+ redo_stack_.clear();
+}
+
+bool EditorClientImpl::canUndo() const {
+ return !undo_stack_.empty();
+}
+
+bool EditorClientImpl::canRedo() const {
+ return !redo_stack_.empty();
+}
+
+void EditorClientImpl::undo() {
+ if (canUndo()) {
+ RefPtr<WebCore::EditCommand> command(undo_stack_.back());
+ undo_stack_.pop_back();
+ command->unapply();
+ // unapply will call us back to push this command onto the redo stack.
+ }
+}
+
+void EditorClientImpl::redo() {
+ if (canRedo()) {
+ RefPtr<WebCore::EditCommand> command(redo_stack_.back());
+ redo_stack_.pop_back();
+
+ ASSERT(!in_redo_);
+ in_redo_ = true;
+ command->reapply();
+ // reapply will call us back to push this command onto the undo stack.
+ in_redo_ = false;
+ }
+}
+
+// Get the distance we should go (in pixels) when doing a pageup/pagedown.
+static int GetVerticalPageDistance(WebCore::KeyboardEvent* event) {
+ if (event->target()) {
+ WebCore::Node* node = event->target()->toNode();
+ if (node && node->renderer())
+ return node->renderer()->contentHeight();
+ }
+
+ return 0;
+}
+
+// The below code was adapted from the WebKit file webview.cpp
+// provided by Apple, Inc, and is subject to the following copyright
+// notice and disclaimer.
+
+/*
+ * Copyright (C) 2006, 2007 Apple, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+static const unsigned CtrlKey = 1 << 0;
+static const unsigned AltKey = 1 << 1;
+static const unsigned ShiftKey = 1 << 2;
+
+// Keys with special meaning. These will be delegated to the editor using
+// the execCommand() method
+struct KeyDownEntry {
+ unsigned virtualKey;
+ unsigned modifiers;
+ const char* name;
+};
+
+struct KeyPressEntry {
+ unsigned charCode;
+ unsigned modifiers;
+ const char* name;
+};
+
+static const KeyDownEntry keyDownEntries[] = {
+ { VK_LEFT, 0, "MoveLeft" },
+ { VK_LEFT, ShiftKey, "MoveLeftAndModifySelection" },
+ { VK_LEFT, CtrlKey, "MoveWordLeft" },
+ { VK_LEFT, CtrlKey | ShiftKey, "MoveWordLeftAndModifySelection" },
+ { VK_RIGHT, 0, "MoveRight" },
+ { VK_RIGHT, ShiftKey, "MoveRightAndModifySelection" },
+ { VK_RIGHT, CtrlKey, "MoveWordRight" },
+ { VK_RIGHT, CtrlKey | ShiftKey, "MoveWordRightAndModifySelection" },
+ { VK_UP, 0, "MoveUp" },
+ { VK_UP, ShiftKey, "MoveUpAndModifySelection" },
+ { VK_PRIOR, ShiftKey, "MovePageUpAndModifySelection" },
+ { VK_DOWN, 0, "MoveDown" },
+ { VK_DOWN, ShiftKey, "MoveDownAndModifySelection" },
+ { VK_NEXT, ShiftKey, "MovePageDownAndModifySelection" },
+ { VK_PRIOR, 0, "MovePageUp" },
+ { VK_NEXT, 0, "MovePageDown" },
+ { VK_HOME, 0, "MoveToBeginningOfLine" },
+ { VK_HOME, ShiftKey, "MoveToBeginningOfLineAndModifySelection" },
+ { VK_HOME, CtrlKey, "MoveToBeginningOfDocument" },
+ { VK_HOME, CtrlKey | ShiftKey, "MoveToBeginningOfDocumentAndModifySelection" },
+
+ { VK_END, 0, "MoveToEndOfLine" },
+ { VK_END, ShiftKey, "MoveToEndOfLineAndModifySelection" },
+ { VK_END, CtrlKey, "MoveToEndOfDocument" },
+ { VK_END, CtrlKey | ShiftKey, "MoveToEndOfDocumentAndModifySelection" },
+
+ { VK_BACK, 0, "DeleteBackward" },
+ { VK_BACK, ShiftKey, "DeleteBackward" },
+ { VK_DELETE, 0, "DeleteForward" },
+ { VK_BACK, CtrlKey, "DeleteWordBackward" },
+ { VK_DELETE, CtrlKey, "DeleteWordForward" },
+
+ { 'B', CtrlKey, "ToggleBold" },
+ { 'I', CtrlKey, "ToggleItalic" },
+ { 'U', CtrlKey, "ToggleUnderline" },
+
+ { VK_ESCAPE, 0, "Cancel" },
+ { VK_OEM_PERIOD, CtrlKey, "Cancel" },
+ { VK_TAB, 0, "InsertTab" },
+ { VK_TAB, ShiftKey, "InsertBacktab" },
+ { VK_RETURN, 0, "InsertNewline" },
+ { VK_RETURN, CtrlKey, "InsertNewline" },
+ { VK_RETURN, AltKey, "InsertNewline" },
+ { VK_RETURN, AltKey | ShiftKey, "InsertNewline" },
+ { VK_RETURN, ShiftKey, "InsertLineBreak" },
+
+ { 'C', CtrlKey, "Copy" },
+ { VK_INSERT, CtrlKey, "Copy" },
+ { 'V', CtrlKey, "Paste" },
+ { VK_INSERT, ShiftKey, "Paste" },
+ { 'V', CtrlKey | ShiftKey, "PasteAndMatchStyle" },
+ { 'X', CtrlKey, "Cut" },
+ { VK_DELETE, ShiftKey, "Cut" },
+ { 'A', CtrlKey, "SelectAll" },
+ { 'Z', CtrlKey, "Undo" },
+ { 'Z', CtrlKey | ShiftKey, "Redo" },
+ { 'Y', CtrlKey, "Redo" },
+};
+
+static const KeyPressEntry keyPressEntries[] = {
+ { '\t', 0, "InsertTab" },
+ { '\t', ShiftKey, "InsertBacktab" },
+ { '\r', 0, "InsertNewline" },
+ { '\r', CtrlKey, "InsertNewline" },
+ { '\r', ShiftKey, "InsertLineBreak" },
+ { '\r', AltKey, "InsertNewline" },
+ { '\r', AltKey | ShiftKey, "InsertNewline" },
+};
+
+const char* EditorClientImpl::interpretKeyEvent(
+ const WebCore::KeyboardEvent* evt) {
+ const WebCore::PlatformKeyboardEvent* keyEvent = evt->keyEvent();
+ if (!keyEvent)
+ return "";
+
+ static HashMap<int, const char*>* keyDownCommandsMap = 0;
+ static HashMap<int, const char*>* keyPressCommandsMap = 0;
+
+ if (!keyDownCommandsMap) {
+ keyDownCommandsMap = new HashMap<int, const char*>;
+ keyPressCommandsMap = new HashMap<int, const char*>;
+
+ for (unsigned i = 0; i < _countof(keyDownEntries); i++) {
+ keyDownCommandsMap->set(
+ keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey,
+ keyDownEntries[i].name);
+ }
+
+ for (unsigned i = 0; i < _countof(keyPressEntries); i++) {
+ keyPressCommandsMap->set(
+ keyPressEntries[i].modifiers << 16 | keyPressEntries[i].charCode,
+ keyPressEntries[i].name);
+ }
+ }
+
+ unsigned modifiers = 0;
+ if (keyEvent->shiftKey())
+ modifiers |= ShiftKey;
+ if (keyEvent->altKey())
+ modifiers |= AltKey;
+ if (keyEvent->ctrlKey())
+ modifiers |= CtrlKey;
+
+ if (evt->type() == WebCore::EventNames::keydownEvent) {
+ int mapKey = modifiers << 16 | evt->keyCode();
+ return mapKey ? keyDownCommandsMap->get(mapKey) : 0;
+ }
+
+ int mapKey = modifiers << 16 | evt->charCode();
+ return mapKey ? keyPressCommandsMap->get(mapKey) : 0;
+}
+
+bool EditorClientImpl::handleEditingKeyboardEvent(
+ WebCore::KeyboardEvent* evt) {
+ const WebCore::PlatformKeyboardEvent* keyEvent = evt->keyEvent();
+ // do not treat this as text input if it's a system key event
+ if (!keyEvent || keyEvent->isSystemKey())
+ return false;
+
+ WebCore::Frame* frame = evt->target()->toNode()->document()->frame();
+ if (!frame)
+ return false;
+
+ const char* command_name = interpretKeyEvent(evt);
+ WebCore::Editor::Command command = frame->editor()->command(command_name);
+
+ if (keyEvent->type() == WebCore::PlatformKeyboardEvent::RawKeyDown) {
+ // WebKit doesn't have enough information about mode to decide how
+ // commands that just insert text if executed via Editor should be treated,
+ // so we leave it upon WebCore to either handle them immediately
+ // (e.g. Tab that changes focus) or let a keypress event be generated
+ // (e.g. Tab that inserts a Tab character, or Enter).
+ if (command.isTextInsertion() || !command_name)
+ return false;
+ if (command.execute(evt)) {
+ WebViewDelegate* d = web_view_->delegate();
+ MaybeRecordCommand(d, command_name);
+ return true;
+ }
+ return false;
+ }
+
+ if (command.execute(evt)) {
+ WebViewDelegate* d = web_view_->delegate();
+ MaybeRecordCommand(d, command_name);
+ return true;
+ }
+
+ if (evt->keyEvent()->text().length() == 1) {
+ UChar ch = evt->keyEvent()->text()[0];
+
+ // Don't insert null or control characters as they can result in
+ // unexpected behaviour
+ if (ch < ' ')
+ return false;
+ }
+
+ return frame->editor()->insertText(evt->keyEvent()->text(), evt);
+}
+
+//
+// End of code block subject to Apple, Inc. copyright
+//
+
+void EditorClientImpl::handleKeyboardEvent(WebCore::KeyboardEvent* evt) {
+ if (handleEditingKeyboardEvent(evt))
+ evt->setDefaultHandled();
+}
+
+void EditorClientImpl::handleInputMethodKeydown(WebCore::KeyboardEvent* keyEvent) {
+ notImplemented();
+}
+
+void EditorClientImpl::textFieldDidBeginEditing(WebCore::Element*) {
+ notImplemented();
+}
+
+void EditorClientImpl::textFieldDidEndEditing(WebCore::Element*) {
+ // Notification that focus was lost.
+ // Be careful with this, it's also sent when the page is being closed.
+ notImplemented();
+}
+
+void EditorClientImpl::textDidChangeInTextField(WebCore::Element* element) {
+ // Track the element so we can blur/focus it in respondToChangedContents
+ // so that the selected range is properly set. (See respondToChangedContents).
+ if (static_cast<WebCore::HTMLInputElement*>(element)->autofilled())
+ pending_inline_autocompleted_element_ = element;
+}
+
+bool EditorClientImpl::doTextFieldCommandFromEvent(WebCore::Element*,
+ WebCore::KeyboardEvent*) {
+ // The Mac code appears to use this method as a hook to implement special
+ // keyboard commands specific to Safari's auto-fill implementation. We
+ // just return false to allow the default action.
+ return false;
+}
+
+void EditorClientImpl::textWillBeDeletedInTextField(WebCore::Element*) {
+ notImplemented();
+}
+
+void EditorClientImpl::textDidChangeInTextArea(WebCore::Element*) {
+ notImplemented();
+}
+
+void EditorClientImpl::ignoreWordInSpellDocument(const WebCore::String&) {
+ notImplemented();
+}
+
+void EditorClientImpl::learnWord(const WebCore::String&) {
+ notImplemented();
+}
+
+void EditorClientImpl::checkSpellingOfString(const UChar* str, int length,
+ int* misspellingLocation,
+ int* misspellingLength) {
+ // SpellCheckWord will write (0, 0) into the output vars, which is what our
+ // caller expects if the word is spelled correctly.
+ int spell_location = -1;
+ int spell_length = 0;
+ WebViewDelegate* d = web_view_->delegate();
+ if (web_view_->FocusedFrameNeedsSpellchecking() && d) {
+ std::wstring word(str, length);
+ d->SpellCheck(word, spell_location, spell_length);
+ } else {
+ spell_location = 0;
+ spell_length = 0;
+ }
+
+ // Note: the Mac code checks if the pointers are NULL before writing to them,
+ // so we do too.
+ if (misspellingLocation)
+ *misspellingLocation = spell_location;
+ if (misspellingLength)
+ *misspellingLength = spell_length;
+}
+
+void EditorClientImpl::checkGrammarOfString(const UChar*, int length,
+ WTF::Vector<WebCore::GrammarDetail>&,
+ int* badGrammarLocation,
+ int* badGrammarLength) {
+ notImplemented();
+ if (badGrammarLocation)
+ *badGrammarLocation = 0;
+ if (badGrammarLength)
+ *badGrammarLength = 0;
+}
+
+void EditorClientImpl::updateSpellingUIWithGrammarString(const WebCore::String&,
+ const WebCore::GrammarDetail& detail) {
+ notImplemented();
+}
+
+void EditorClientImpl::updateSpellingUIWithMisspelledWord(const WebCore::String&) {
+ notImplemented();
+}
+
+void EditorClientImpl::showSpellingUI(bool show) {
+ notImplemented();
+}
+
+bool EditorClientImpl::spellingUIIsShowing() {
+ return false;
+}
+
+void EditorClientImpl::getGuessesForWord(const WebCore::String&,
+ WTF::Vector<WebCore::String>& guesses) {
+ notImplemented();
+}
+
+void EditorClientImpl::setInputMethodState(bool enabled) {
+ WebViewDelegate* d = web_view_->delegate();
+ if (d) {
+ d->SetInputMethodState(enabled);
+ }
+}
+
+
+std::wstring EditorClientImpl::DescribeOrError(int number,
+ WebCore::ExceptionCode ec) {
+ if (ec)
+ return L"ERROR";
+
+ wchar_t buffer[128];
+ _itow_s(number, buffer, arraysize(buffer), 10);
+ return std::wstring(buffer);
+}
+
+std::wstring EditorClientImpl::DescribeOrError(WebCore::Node* node,
+ WebCore::ExceptionCode ec) {
+ if (ec)
+ return L"ERROR";
+
+ return Describe(node);
+}
+
+// These Describe() functions match the output expected by the layout tests.
+std::wstring EditorClientImpl::Describe(WebCore::Range* range) {
+ if (range) {
+ WebCore::ExceptionCode exception = 0;
+ std::wstring str = L"range from ";
+ int offset = range->startOffset(exception);
+ str.append(DescribeOrError(offset, exception));
+ str.append(L" of ");
+ WebCore::Node* container = range->startContainer(exception);
+ str.append(DescribeOrError(container, exception));
+ str.append(L" to ");
+ offset = range->endOffset(exception);
+ str.append(DescribeOrError(offset, exception));
+ str.append(L" of ");
+ container = range->endContainer(exception);
+ str.append(DescribeOrError(container, exception));
+ return str;
+ }
+ return L"(null)";
+}
+
+// See comment for Describe(), above.
+std::wstring EditorClientImpl::Describe(WebCore::Node* node) {
+ if (node) {
+ std::wstring str = webkit_glue::StringToStdWString(node->nodeName());
+ WebCore::Node* parent = node->parentNode();
+ if (parent) {
+ str.append(L" > ");
+ str.append(Describe(parent));
+ }
+ return str;
+ }
+ return L"(null)";
+}
+
+// See comment for Describe(), above.
+std::wstring EditorClientImpl::Describe(WebCore::EditorInsertAction action) {
+ switch (action) {
+ case WebCore::EditorInsertActionTyped:
+ return L"WebViewInsertActionTyped";
+ case WebCore::EditorInsertActionPasted:
+ return L"WebViewInsertActionPasted";
+ case WebCore::EditorInsertActionDropped:
+ return L"WebViewInsertActionDropped";
+ }
+ return L"(UNKNOWN ACTION)";
+}
+
+// See comment for Describe(), above.
+std::wstring EditorClientImpl::Describe(WebCore::EAffinity affinity) {
+ switch (affinity) {
+ case WebCore::UPSTREAM:
+ return L"NSSelectionAffinityUpstream";
+ case WebCore::DOWNSTREAM:
+ return L"NSSelectionAffinityDownstream";
+ }
+ return L"(UNKNOWN AFFINITY)";
+}
+
+std::wstring EditorClientImpl::Describe(WebCore::CSSStyleDeclaration* style) {
+ // TODO(pamg): Implement me. It's not clear what WebKit produces for this
+ // (their [style description] method), and none of the layout tests provide
+ // an example. But because none of them use it, it's not yet important.
+ return std::wstring();
+}
diff --git a/webkit/glue/editor_client_impl.h b/webkit/glue/editor_client_impl.h
new file mode 100644
index 0000000..23a640a
--- /dev/null
+++ b/webkit/glue/editor_client_impl.h
@@ -0,0 +1,164 @@
+// 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 WEBKIT_GLUE_EDITOR_CLIENT_IMPL_H__
+#define WEBKIT_GLUE_EDITOR_CLIENT_IMPL_H__
+
+#include <deque>
+
+#pragma warning(push, 0)
+#include "EditorClient.h"
+#pragma warning(pop)
+
+namespace WebCore {
+class Frame;
+class Node;
+class PlatformKeyboardEvent;
+}
+
+class WebView;
+class WebViewImpl;
+
+class EditorClientImpl : public WebCore::EditorClient {
+ public:
+ EditorClientImpl(WebView* web_view);
+ virtual ~EditorClientImpl();
+ virtual void pageDestroyed();
+
+ virtual bool shouldShowDeleteInterface(WebCore::HTMLElement*);
+ virtual bool smartInsertDeleteEnabled();
+ virtual bool isContinuousSpellCheckingEnabled();
+ virtual void toggleContinuousSpellChecking();
+ virtual bool isGrammarCheckingEnabled();
+ virtual void toggleGrammarChecking();
+ virtual int spellCheckerDocumentTag();
+
+ virtual bool isEditable();
+
+ virtual bool shouldBeginEditing(WebCore::Range* range);
+ virtual bool shouldEndEditing(WebCore::Range* range);
+ virtual bool shouldInsertNode(WebCore::Node* node, WebCore::Range* range,
+ WebCore::EditorInsertAction action);
+ virtual bool shouldInsertText(WebCore::String text, WebCore::Range* range,
+ WebCore::EditorInsertAction action);
+ virtual bool shouldDeleteRange(WebCore::Range* range);
+ virtual bool shouldChangeSelectedRange(WebCore::Range* fromRange,
+ WebCore::Range* toRange,
+ WebCore::EAffinity affinity,
+ bool stillSelecting);
+ virtual bool shouldApplyStyle(WebCore::CSSStyleDeclaration* style,
+ WebCore::Range* range);
+ virtual bool shouldMoveRangeAfterDelete(WebCore::Range*, WebCore::Range*);
+
+ virtual void didBeginEditing();
+ virtual void respondToChangedContents();
+ virtual void respondToChangedSelection();
+ virtual void didEndEditing();
+ virtual void didWriteSelectionToPasteboard();
+ virtual void didSetSelectionTypesForPasteboard();
+
+ virtual void registerCommandForUndo(PassRefPtr<WebCore::EditCommand>);
+ virtual void registerCommandForRedo(PassRefPtr<WebCore::EditCommand>);
+ virtual void clearUndoRedoOperations();
+
+ virtual bool canUndo() const;
+ virtual bool canRedo() const;
+
+ virtual void undo();
+ virtual void redo();
+
+ virtual const char* interpretKeyEvent(const WebCore::KeyboardEvent*);
+ virtual bool handleEditingKeyboardEvent(WebCore::KeyboardEvent*);
+ virtual void handleKeyboardEvent(WebCore::KeyboardEvent*);
+ virtual void handleInputMethodKeydown(WebCore::KeyboardEvent*);
+
+ virtual void textFieldDidBeginEditing(WebCore::Element*);
+ virtual void textFieldDidEndEditing(WebCore::Element*);
+ virtual void textDidChangeInTextField(WebCore::Element*);
+ virtual bool doTextFieldCommandFromEvent(WebCore::Element*,WebCore::KeyboardEvent*);
+ virtual void textWillBeDeletedInTextField(WebCore::Element*);
+ virtual void textDidChangeInTextArea(WebCore::Element*);
+
+ virtual void ignoreWordInSpellDocument(const WebCore::String&);
+ virtual void learnWord(const WebCore::String&);
+ virtual void checkSpellingOfString(const UChar*, int length,
+ int* misspellingLocation,
+ int* misspellingLength);
+ virtual void checkGrammarOfString(const UChar*, int length,
+ WTF::Vector<WebCore::GrammarDetail>&,
+ int* badGrammarLocation,
+ int* badGrammarLength);
+ virtual void updateSpellingUIWithGrammarString(const WebCore::String&,
+ const WebCore::GrammarDetail& detail);
+ virtual void updateSpellingUIWithMisspelledWord(const WebCore::String&);
+ virtual void showSpellingUI(bool show);
+ virtual bool spellingUIIsShowing();
+ virtual void getGuessesForWord(const WebCore::String&,
+ WTF::Vector<WebCore::String>& guesses);
+ virtual void setInputMethodState(bool enabled);
+
+ void SetUseEditorDelegate(bool value) { use_editor_delegate_ = value; }
+ // HACK for webkit bug #16976.
+ // TODO (timsteele): Clean this up once webkit bug 16976 is fixed.
+ void PreserveSelection();
+
+ // It would be better to add these methods to the objects they describe, but
+ // those are in WebCore and therefore inaccessible.
+ virtual std::wstring DescribeOrError(int number,
+ WebCore::ExceptionCode ec);
+ virtual std::wstring DescribeOrError(WebCore::Node* node,
+ WebCore::ExceptionCode ec);
+ virtual std::wstring Describe(WebCore::Range* range);
+ virtual std::wstring Describe(WebCore::Node* node);
+ virtual std::wstring Describe(WebCore::EditorInsertAction action);
+ virtual std::wstring Describe(WebCore::EAffinity affinity);
+ virtual std::wstring Describe(WebCore::CSSStyleDeclaration* style);
+
+ private:
+ void ModifySelection(WebCore::Frame* frame,
+ WebCore::KeyboardEvent* event);
+
+ protected:
+ WebViewImpl* web_view_;
+ bool use_editor_delegate_;
+ bool in_redo_;
+
+ // Should preserve the selection in next call to shouldChangeSelectedRange.
+ bool preserve_;
+
+ // Points to an HTMLInputElement that was just autocompleted (else NULL),
+ // for use by respondToChangedContents().
+ WebCore::Element* pending_inline_autocompleted_element_;
+
+ typedef std::deque<WTF::RefPtr<WebCore::EditCommand> > EditCommandStack;
+ EditCommandStack undo_stack_;
+ EditCommandStack redo_stack_;
+};
+
+#endif // WEBKIT_GLUE_EDITOR_CLIENT_IMPL_H__
diff --git a/webkit/glue/entity_map.cc b/webkit/glue/entity_map.cc
new file mode 100644
index 0000000..771be72
--- /dev/null
+++ b/webkit/glue/entity_map.cc
@@ -0,0 +1,118 @@
+// 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/entity_map.h"
+
+#include <hash_map>
+
+#include "HTMLEntityCodes.c"
+
+#include "base/string_util.h"
+
+namespace webkit_glue {
+
+typedef stdext::hash_map<wchar_t, const char*> EntityMapType;
+
+class EntityMapData {
+ public:
+ EntityMapData(const EntityCode* entity_codes, int entity_codes_length,
+ bool user_number_entity_apos)
+ : entity_codes_(entity_codes),
+ entity_codes_length_(entity_codes_length),
+ user_number_entity_apos_(user_number_entity_apos),
+ map_(NULL) {
+ }
+ ~EntityMapData() { delete map_; }
+ const EntityMapType* GetEntityMapData();
+
+ private:
+ // Data structure which saves all pairs of Unicode character and its
+ // corresponding entity notation.
+ const EntityCode* entity_codes_;
+ const int entity_codes_length_;
+ // IE does not support '&apos;'(html entity name for symbol ') as HTML entity
+ // (but it does support &apos; as xml entity), so if user_number_entity_apos_
+ // is true, we will use entity number 0x0027 instead of using '&apos;' when
+ // doing serialization work.
+ const bool user_number_entity_apos_;
+ // Map the Unicode character to corresponding entity notation.
+ EntityMapType* map_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(EntityMapData);
+};
+
+const EntityMapType* EntityMapData::GetEntityMapData() {
+ if (!map_) {
+ // lazily create the entity map.
+ map_ = new EntityMapType;
+ const EntityCode* entity_code = &entity_codes_[0];
+ for (int i = 0; i < entity_codes_length_; ++i, ++entity_code)
+ (*map_)[entity_code->code] = entity_code->name;
+ if (user_number_entity_apos_)
+ (*map_)[0x0027] = "&#39;";
+ }
+ return map_;
+}
+
+static const EntityCode xml_built_in_entity_codes[] = {
+ {0x003c, "&lt;"},
+ {0x003e, "&gt;"},
+ {0x0026, "&amp;"},
+ {0x0027, "&apos;"},
+ {0x0022, "&quot;"}
+};
+
+static const int xml_entity_codes_length =
+ arraysize(xml_built_in_entity_codes);
+
+static EntityMapData html_entity_map_singleton(entity_codes,
+ entity_codes_length,
+ true);
+static EntityMapData xml_entity_map_singleton(xml_built_in_entity_codes,
+ xml_entity_codes_length,
+ false);
+
+const char* EntityMap::GetEntityNameByCode(wchar_t code, bool is_html) {
+ const EntityMapType* entity_map;
+ if (is_html)
+ entity_map = html_entity_map_singleton.GetEntityMapData();
+ else
+ entity_map = xml_entity_map_singleton.GetEntityMapData();
+
+ // Check entity name according to unicode.
+ EntityMapType::const_iterator i = entity_map->find(code);
+ if (i == entity_map->end())
+ // Not found, return NULL.
+ return NULL;
+ else
+ // Found, return entity notation.
+ return i->second;
+}
+
+} // namespace webkit_glue
diff --git a/webkit/glue/entity_map.h b/webkit/glue/entity_map.h
new file mode 100644
index 0000000..8dfea5d
--- /dev/null
+++ b/webkit/glue/entity_map.h
@@ -0,0 +1,53 @@
+// 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 WEBKIT_GLUE_ENTITY_MAP_H__
+#define WEBKIT_GLUE_ENTITY_MAP_H__
+
+#include <string>
+
+#include "base/basictypes.h"
+
+namespace webkit_glue {
+
+class EntityMap {
+ public:
+ // Check whether specified unicode has corresponding html or xml built-in
+ // entity name. If yes, return the entity notation, if not then return NULL.
+ // Parameter is_html indicates check the code in html entity map or in xml
+ // entity map. THIS FUNCTION IS NOT THREADSAFE.
+ static const char* GetEntityNameByCode(wchar_t code, bool is_html);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(EntityMap);
+};
+
+} // namespace webkit_glue
+
+#endif // WEBKIT_GLUE_ENTITY_MAP_H__
diff --git a/webkit/glue/event_conversion.cc b/webkit/glue/event_conversion.cc
new file mode 100644
index 0000000..6ec7034
--- /dev/null
+++ b/webkit/glue/event_conversion.cc
@@ -0,0 +1,199 @@
+// 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 "config.h"
+#include <windows.h>
+
+#include "StringImpl.h" // This is so that the KJS build works
+#pragma warning(push, 0)
+// HACK: make it possible to initialize these classes...
+// TODO(darin): send this change to webkit.org
+#define private protected
+#include "PlatformKeyboardEvent.h"
+#include "PlatformMouseEvent.h"
+#include "PlatformWheelEvent.h"
+#undef private
+#include "Widget.h"
+#pragma warning(pop)
+
+#undef LOG
+#include "base/gfx/point.h"
+#include "base/logging.h"
+#include "webkit/glue/event_conversion.h"
+#include "webkit/glue/webinputevent.h"
+#include "webkit/glue/webkit_glue.h"
+
+using namespace WebCore;
+
+// MakePlatformMouseEvent -----------------------------------------------------
+
+int MakePlatformMouseEvent::last_click_count_ = 0;
+long MakePlatformMouseEvent::last_click_time_ = 0;
+
+MakePlatformMouseEvent::MakePlatformMouseEvent(Widget* widget,
+ const WebMouseEvent& e)
+ : PlatformMouseEvent(NULL, 0, 0, 0, false /* TODO(darin): do we care? */) {
+ // TODO(mpcomplete): widget is always toplevel, unless it's a popup. We
+ // may be able to get rid of this once we abstract popups into a WebKit API.
+ m_position = widget->convertFromContainingWindow(IntPoint(e.x, e.y));
+ m_globalPosition = IntPoint(e.global_x, e.global_y);
+ m_button = static_cast<MouseButton>(e.button);
+ m_shiftKey = (e.modifiers & WebInputEvent::SHIFT_KEY) != 0;
+ m_ctrlKey = (e.modifiers & WebInputEvent::CTRL_KEY) != 0;
+ m_altKey = (e.modifiers & WebInputEvent::ALT_KEY) != 0;
+ m_metaKey = (e.modifiers & WebInputEvent::META_KEY) != 0;
+ m_modifierFlags = e.modifiers;
+ m_timestamp = e.timestamp_sec;
+
+ // This differs slightly from the WebKit code in WebKit/win/WebView.cpp where
+ // their original code looks buggy.
+ static IntPoint last_click_position;
+ static MouseButton last_click_button = LeftButton;
+
+ const DWORD current_time = static_cast<DWORD>(m_timestamp * 1000);
+ const bool cancel_previous_click =
+ (abs(last_click_position.x() - m_position.x()) >
+ (GetSystemMetrics(SM_CXDOUBLECLK) / 2)) ||
+ (abs(last_click_position.y() - m_position.y()) >
+ (GetSystemMetrics(SM_CYDOUBLECLK) / 2)) ||
+ ((current_time - last_click_time_) > GetDoubleClickTime());
+
+ switch (e.type) {
+ case WebInputEvent::MOUSE_MOVE:
+ case WebInputEvent::MOUSE_LEAVE: // synthesize a move event
+ if (cancel_previous_click) {
+ last_click_count_ = 0;
+ last_click_position = IntPoint();
+ last_click_time_ = 0;
+ }
+ setClickCount(last_click_count_);
+ m_eventType = MouseEventMoved;
+ break;
+
+ case WebInputEvent::MOUSE_DOWN:
+ case WebInputEvent::MOUSE_DOUBLE_CLICK:
+ if (!cancel_previous_click && (m_button == last_click_button)) {
+ ++last_click_count_;
+ } else {
+ last_click_count_ = 1;
+ last_click_position = m_position;
+ }
+ last_click_time_ = current_time;
+ last_click_button = m_button;
+ setClickCount(last_click_count_);
+ m_eventType = MouseEventPressed;
+ break;
+
+ case WebInputEvent::MOUSE_UP:
+ setClickCount(last_click_count_);
+ m_eventType = MouseEventReleased;
+ break;
+
+ default:
+ NOTREACHED() << "unexpected mouse event type";
+ }
+
+ if (webkit_glue::IsLayoutTestMode()) {
+ setClickCount(e.layout_test_click_count);
+ }
+}
+
+// MakePlatformWheelEvent -----------------------------------------------------
+
+MakePlatformWheelEvent::MakePlatformWheelEvent(Widget* widget,
+ const WebMouseWheelEvent& e)
+ : PlatformWheelEvent(NULL, 0, 0, false) { // TODO(jackson): Check if it's a horizontal event
+ m_position = widget->convertFromContainingWindow(IntPoint(e.x, e.y));
+ m_globalPosition = IntPoint(e.global_x, e.global_y);
+ m_deltaX = static_cast<float>(e.delta_x);
+ m_deltaY = static_cast<float>(e.delta_y);
+ m_shiftKey = (e.modifiers & WebInputEvent::SHIFT_KEY) != 0;
+ m_ctrlKey = (e.modifiers & WebInputEvent::CTRL_KEY) != 0;
+ m_altKey = (e.modifiers & WebInputEvent::ALT_KEY) != 0;
+ m_metaKey = (e.modifiers & WebInputEvent::META_KEY) != 0;
+}
+
+static inline const PlatformKeyboardEvent::Type platformKeyTypeForWebInputEventType(WebInputEvent::Type type) {
+ switch (type) {
+ case WebInputEvent::KEY_UP:
+ return PlatformKeyboardEvent::KeyUp;
+ case WebInputEvent::KEY_DOWN:
+ return PlatformKeyboardEvent::KeyDown;
+ case WebInputEvent::CHAR:
+ return PlatformKeyboardEvent::Char;
+ }
+ ASSERT_NOT_REACHED();
+ return PlatformKeyboardEvent::KeyDown;
+}
+
+// MakePlatformKeyboardEvent --------------------------------------------------
+
+MakePlatformKeyboardEvent::MakePlatformKeyboardEvent(const WebKeyboardEvent& e)
+ : PlatformKeyboardEvent(NULL, e.key_code, e.key_data,
+ platformKeyTypeForWebInputEventType(e.type),
+ e.system_key) {
+ m_autoRepeat = (e.modifiers & WebInputEvent::IS_AUTO_REPEAT) != 0;
+ m_isKeypad = (e.modifiers & WebInputEvent::IS_KEYPAD) != 0;
+ m_shiftKey = (e.modifiers & WebInputEvent::SHIFT_KEY) != 0;
+ m_ctrlKey = (e.modifiers & WebInputEvent::CTRL_KEY) != 0;
+ m_altKey = (e.modifiers & WebInputEvent::ALT_KEY) != 0;
+ m_metaKey = (e.modifiers & WebInputEvent::META_KEY) != 0;
+}
+
+void MakePlatformKeyboardEvent::SetKeyType(Type type) {
+ // According to the behavior of Webkit in Windows platform,
+ // we need to convert KeyDown to RawKeydown and Char events
+ // See WebKit/WebKit/Win/WebView.cpp
+ ASSERT(m_type == KeyDown);
+ ASSERT(type == RawKeyDown || type == Char);
+ m_type = type;
+
+ if (type == RawKeyDown) {
+ m_text = String();
+ m_unmodifiedText = String();
+ } else {
+ m_keyIdentifier = String();
+ m_windowsVirtualKeyCode = 0;
+ }
+}
+
+// Please refer to bug http://b/issue?id=961192, which talks about Webkit
+// keyboard event handling changes. It also mentions the list of keys
+// which don't have associated character events.
+bool MakePlatformKeyboardEvent::IsCharacterKey() const {
+ switch (windowsVirtualKeyCode()) {
+ case VK_BACK:
+ case VK_ESCAPE:
+ return false;
+
+ default:
+ break;
+ }
+ return true;
+}
diff --git a/webkit/glue/event_conversion.h b/webkit/glue/event_conversion.h
new file mode 100644
index 0000000..2c08459
--- /dev/null
+++ b/webkit/glue/event_conversion.h
@@ -0,0 +1,75 @@
+// 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 WEBKIT_GLUE_EVENT_CONVERSION_H__
+#define WEBKIT_GLUE_EVENT_CONVERSION_H__
+
+#pragma warning(push, 0)
+#include "PlatformKeyboardEvent.h"
+#include "PlatformMouseEvent.h"
+#include "PlatformWheelEvent.h"
+#pragma warning(pop)
+
+namespace WebCore {
+ class Widget;
+}
+
+class WebMouseEvent;
+class WebMouseWheelEvent;
+class WebKeyboardEvent;
+
+// These classes are used to convert from WebInputEvent subclasses to
+// corresponding WebCore events.
+
+class MakePlatformMouseEvent : public WebCore::PlatformMouseEvent {
+ public:
+ MakePlatformMouseEvent(WebCore::Widget* widget, const WebMouseEvent& e);
+
+ static void ResetLastClick() {
+ last_click_time_ = last_click_count_ = 0;
+ }
+
+ private:
+ static int last_click_count_;
+ static long last_click_time_;
+};
+
+class MakePlatformWheelEvent : public WebCore::PlatformWheelEvent {
+ public:
+ MakePlatformWheelEvent(WebCore::Widget* widget, const WebMouseWheelEvent& e);
+};
+
+class MakePlatformKeyboardEvent : public WebCore::PlatformKeyboardEvent {
+ public:
+ MakePlatformKeyboardEvent(const WebKeyboardEvent& e);
+ void SetKeyType(Type type);
+ bool IsCharacterKey() const;
+};
+
+#endif // WEBKIT_GLUE_EVENT_CONVERSION_H__
diff --git a/webkit/glue/feed_preview.cc b/webkit/glue/feed_preview.cc
new file mode 100644
index 0000000..82c9270
--- /dev/null
+++ b/webkit/glue/feed_preview.cc
@@ -0,0 +1,105 @@
+// 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 "config.h"
+
+#include "webkit/glue/feed_preview.h"
+
+#pragma warning(push, 0)
+#include "ResourceRequest.h"
+#include "ResourceResponse.h"
+#include "ResourceHandle.h"
+#pragma warning(pop)
+
+#undef LOG
+
+#include "base/logging.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/webkit_resources.h"
+
+namespace WebCore {
+
+// Generate a preview for a feed. |url| is the (http://) URL of the feed,
+// and |data| are the bytes we received in response to the HTTP request.
+// Returns an HTML string.
+static std::string MakeFeedPreview(const std::string& url,
+ const std::string& data) {
+ // TODO(evanm): this is just a placeholder.
+ // Maybe we should make this parse the feed data and display a preview?
+ // Yuck. Seems like a lot of effort for a pretty minor feature.
+
+ // The feed preview template has {{URL}} in place of where the URL should go.
+ const std::string kUrlTemplate = "{{URL}}";
+ std::string feed_template(webkit_glue::GetDataResource(IDR_FEED_PREVIEW));
+ std::string::size_type template_offset = feed_template.find(kUrlTemplate);
+ DCHECK(template_offset != std::string::npos);
+ // TODO(evanm): URL-escape URL!
+ return feed_template.substr(0, template_offset) + url +
+ feed_template.substr(template_offset + kUrlTemplate.size());
+}
+
+FeedClientProxy::FeedClientProxy(ResourceHandleClient* client)
+ : client_(client), do_feed_preview_(false) {
+}
+
+void FeedClientProxy::didReceiveResponse(ResourceHandle* handle,
+ const ResourceResponse& response) {
+ if (response.httpStatusCode() == 200) {
+ ResourceResponse new_response(response);
+ // Our feed preview has mime type text/html.
+ new_response.setMimeType("text/html");
+ do_feed_preview_ = true;
+ client_->didReceiveResponse(handle, new_response);
+ } else {
+ client_->didReceiveResponse(handle, response);
+ }
+}
+
+void FeedClientProxy::didReceiveData(ResourceHandle*, const char* data,
+ int data_len, int length_received) {
+ length_received_ = length_received;
+ data_.append(data, data_len);
+}
+
+void FeedClientProxy::didFinishLoading(ResourceHandle* handle) {
+ const std::string url =
+ webkit_glue::KURLToGURL(handle->request().url()).spec();
+ const std::string& data =
+ do_feed_preview_ ? MakeFeedPreview(url, data_) : data_;
+ client_->didReceiveData(handle, data.data(), data.size(), length_received_);
+ client_->didFinishLoading(handle);
+}
+
+void FeedClientProxy::didFail(ResourceHandle* handle,
+ const ResourceError& error) {
+ client_->didFail(handle, error);
+}
+
+} // namespace WebCore
diff --git a/webkit/glue/feed_preview.h b/webkit/glue/feed_preview.h
new file mode 100644
index 0000000..7b62693
--- /dev/null
+++ b/webkit/glue/feed_preview.h
@@ -0,0 +1,79 @@
+// 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.
+
+// URLs of the form "feed://foo" are implemented by handing an "http://"
+// URL up to the resource fetching code, then generating a preview at this
+// layer and handing that back to WebKit.
+
+#ifndef WEBKIT_GLUE_FEED_PREVIEW_H__
+#define WEBKIT_GLUE_FEED_PREVIEW_H__
+
+#include <string>
+
+#pragma warning(push, 0)
+#include "ResourceHandleClient.h"
+#pragma warning(pop)
+
+namespace WebCore {
+
+// FeedClientProxy serves as a ResourceHandleClient that forwards calls to
+// a "real" ResourceHandleClient, buffering the response so it can provide
+// a feed preview if the underlying resource request succeeds.
+class FeedClientProxy : public ResourceHandleClient {
+ public:
+ FeedClientProxy(ResourceHandleClient* client);
+ virtual ~FeedClientProxy() { }
+
+ // ResourceHandleClient overrides.
+ virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&);
+ virtual void didReceiveData(ResourceHandle*, const char*, int, int);
+ virtual void didFinishLoading(ResourceHandle*);
+ virtual void didFail(ResourceHandle*, const ResourceError&);
+
+ private:
+ // The "real" ResourceHandleClient that we're forwarding responses to.
+ ResourceHandleClient* client_;
+
+ // Whether we should insert a feed preview -- only if the request came
+ // back ok.
+ bool do_feed_preview_;
+
+ // The response data, which we can parse for the feed preview.
+ std::string data_;
+
+ // The value of the mystery lengthReceived parameter. We accept this via
+ // didReceiveData() and forward it along unmodified.
+ // TODO(evanm): do the right thing here, once we know what that is.
+ // (See TODOs in resource_handle_win.cc.)
+ int length_received_;
+};
+
+} // namespace WebCore
+
+#endif // WEBKIT_GLUE_FEED_PREVIEW_H__
diff --git a/webkit/glue/find_in_page_request.h b/webkit/glue/find_in_page_request.h
new file mode 100644
index 0000000..f72a991
--- /dev/null
+++ b/webkit/glue/find_in_page_request.h
@@ -0,0 +1,55 @@
+// 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 WEBKIT_GLUE_FIND_IN_PAGE_REQUEST_H__
+#define WEBKIT_GLUE_FIND_IN_PAGE_REQUEST_H__
+
+#include <string>
+
+// Parameters for a find in page request.
+struct FindInPageRequest {
+ // The id for the request, this message is passed in by the caller and
+ // returned back with the reply so that the caller can start a new search and
+ // choose to ignore packets that belonged to the last search.
+ int request_id;
+
+ // The word(s) to find on the page.
+ std::wstring search_string;
+
+ // Whether to search forward or backward within the page.
+ bool forward;
+
+ // Whether search should be Case sensitive.
+ bool match_case;
+
+ // Whether this operation is first request (Find) or a follow-up (FindNext).
+ bool find_next;
+};
+
+#endif // WEBKIT_GLUE_FIND_IN_PAGE_REQUEST_H__
diff --git a/webkit/glue/form_data.h b/webkit/glue/form_data.h
new file mode 100644
index 0000000..32a7553
--- /dev/null
+++ b/webkit/glue/form_data.h
@@ -0,0 +1,51 @@
+// 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 WEBKIT_GLUE_FORM_DATA_H__
+#define WEBKIT_GLUE_FORM_DATA_H__
+
+#include <vector>
+
+#include "googleurl/src/gurl.h"
+
+// Holds information about a form to be filled and/or submitted.
+struct FormData {
+ // The URL (minus query parameters) containing the form
+ GURL origin;
+ // The action target of the form
+ GURL action;
+ // A list of element names to be filled
+ std::vector<std::wstring> elements;
+ // A list of element values to be filled
+ std::vector<std::wstring> values;
+ // The name of the submit button to be used to submit (optional)
+ std::wstring submit;
+};
+
+#endif // WEBKIT_GLUE_FORM_DATA_H__
diff --git a/webkit/glue/glue_serialize.cc b/webkit/glue/glue_serialize.cc
new file mode 100644
index 0000000..8ea4286
--- /dev/null
+++ b/webkit/glue/glue_serialize.cc
@@ -0,0 +1,385 @@
+// 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 "config.h"
+#include <string>
+
+#pragma warning(push, 0)
+#include "HistoryItem.h"
+#include "PlatformString.h"
+#include "ResourceRequest.h"
+#pragma warning(pop)
+#undef LOG
+
+#include "webkit/glue/glue_serialize.h"
+
+#include "base/pickle.h"
+#include "base/scoped_ptr.h"
+#include "base/string_util.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/webkit_glue.h"
+
+using namespace WebCore;
+
+namespace webkit_glue {
+
+struct SerializeObject {
+ SerializeObject() : iter(NULL) {}
+ SerializeObject(const char* data, int len) : pickle(data, len), iter(NULL) {}
+
+ std::string GetAsString() {
+ return std::string(static_cast<const char*>(pickle.data()), pickle.size());
+ }
+
+ Pickle pickle;
+ mutable void* iter;
+ mutable int version;
+};
+
+// TODO(mpcomplete): obsolete versions 1 and 2 after 1/1/2008.
+// Version ID used in reading/writing history items.
+// 1: Initial revision.
+// 2: Added case for NULL string versus "". Version 2 code can read Version 1
+// data, but not vice versa.
+// 3: Version 2 was broken, it stored number of UChars, not number of bytes.
+// This version checks and reads v1 and v2 correctly.
+// Should be const, but unit tests may modify it.
+int kVersion = 3;
+
+// A bunch of convenience functions to read/write to SerializeObjects.
+// The serializers assume the input data is in the correct format and so does
+// no error checking.
+inline void WriteData(const void* data, int length, SerializeObject* obj) {
+ obj->pickle.WriteData(static_cast<const char*>(data), length);
+}
+
+inline void ReadData(const SerializeObject* obj, const void** data,
+ int* length) {
+ const char* tmp;
+ obj->pickle.ReadData(&obj->iter, &tmp, length);
+ *data = tmp;
+}
+
+inline bool ReadBytes(const SerializeObject* obj, const void** data,
+ int length) {
+ const char *tmp;
+ if (!obj->pickle.ReadBytes(&obj->iter, &tmp, length))
+ return false;
+ *data = tmp;
+ return true;
+}
+
+inline void WriteInteger(int data, SerializeObject* obj) {
+ obj->pickle.WriteInt(data);
+}
+
+inline int ReadInteger(const SerializeObject* obj) {
+ int tmp;
+ obj->pickle.ReadInt(&obj->iter, &tmp);
+ return tmp;
+}
+
+inline void WriteReal(double data, SerializeObject* obj) {
+ WriteData(&data, sizeof(double), obj);
+}
+
+inline double ReadReal(const SerializeObject* obj) {
+ const void* tmp;
+ int length;
+ ReadData(obj, &tmp, &length);
+ return *static_cast<const double*>(tmp);
+}
+
+inline void WriteBoolean(bool data, SerializeObject* obj) {
+ obj->pickle.WriteInt(data ? 1 : 0);
+}
+
+inline bool ReadBoolean(const SerializeObject* obj) {
+ bool tmp;
+ obj->pickle.ReadBool(&obj->iter, &tmp);
+ return tmp;
+}
+
+// Read/WriteString pickle the String as <int length><UChar* data>.
+// If length == -1, then the String itself is NULL (String()).
+// Otherwise the length is the number of UChars (not bytes) in the String.
+inline void WriteString(const String& data, SerializeObject* obj) {
+ switch (kVersion) {
+ case 1:
+ // Version 1 writes <length in bytes><string data>.
+ // It saves String() and "" as "".
+ obj->pickle.WriteInt(data.length() * sizeof(UChar));
+ obj->pickle.WriteBytes(data.characters(), data.length() * sizeof(UChar));
+ break;
+ case 2:
+ // Version 2 writes <length in UChars><string data>.
+ // It uses -1 in the length field to mean String().
+ if (data.isNull()) {
+ obj->pickle.WriteInt(-1);
+ } else {
+ obj->pickle.WriteInt(data.length());
+ obj->pickle.WriteBytes(data.characters(),
+ data.length() * sizeof(UChar));
+ }
+ break;
+ case 3:
+ // Version 3 writes <length in bytes><string data>.
+ // It uses -1 in the length field to mean String().
+ if (data.isNull()) {
+ obj->pickle.WriteInt(-1);
+ } else {
+ obj->pickle.WriteInt(data.length() * sizeof(UChar));
+ obj->pickle.WriteBytes(data.characters(),
+ data.length() * sizeof(UChar));
+ }
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+// This reads a serialized String from obj. If a string can't be read,
+// String() is returned.
+inline String ReadString(const SerializeObject* obj) {
+ int length;
+
+ // Versions 1, 2, and 3 all start with an integer.
+ if (!obj->pickle.ReadInt(&obj->iter, &length))
+ return String();
+
+ // Starting with version 2, -1 means String().
+ if (length == -1)
+ return String();
+
+ // In version 2, the length field was the length in UChars.
+ // In version 1 and 3 it is the length in bytes.
+ int bytes = ((obj->version == 2) ? length * sizeof(UChar) : length);
+
+ const void* data;
+ if (!ReadBytes(obj, &data, bytes))
+ return String();
+ return String(static_cast<const UChar*>(data), bytes / sizeof(UChar));
+}
+
+// Writes a Vector of Strings into a SerializeObject for serialization.
+static void WriteStringVector(const Vector<String>& data, SerializeObject* obj) {
+ WriteInteger(static_cast<int>(data.size()), obj);
+ for (size_t i = 0, c = data.size(); i < c; ++i) {
+ unsigned ui = static_cast<unsigned>(i); // sigh
+ WriteString(data[ui], obj);
+ }
+}
+
+static void ReadStringVector(const SerializeObject* obj, Vector<String>* data) {
+ int num_elements = ReadInteger(obj);
+ data->reserveCapacity(num_elements);
+ for (int i = 0; i < num_elements; ++i) {
+ data->append(ReadString(obj));
+ }
+}
+
+// Writes a FormData object into a SerializeObject for serialization.
+static void WriteFormData(const FormData* form_data, SerializeObject* obj) {
+ if (form_data == NULL) {
+ WriteInteger(0, obj);
+ return;
+ }
+
+ WriteInteger(static_cast<int>(form_data->elements().size()), obj);
+ for (size_t i = 0, c = form_data->elements().size(); i < c; ++i) {
+ const FormDataElement& e = form_data->elements().at(i);
+ WriteInteger(e.m_type, obj);
+
+ if (e.m_type == FormDataElement::data) {
+ WriteData(e.m_data.data(), static_cast<int>(e.m_data.size()), obj);
+ } else {
+ WriteString(e.m_filename, obj);
+ }
+ }
+}
+
+static FormData* ReadFormData(const SerializeObject* obj) {
+ int num_elements = ReadInteger(obj);
+ if (num_elements == 0)
+ return NULL;
+
+ FormData* form_data = new FormData();
+
+ for (int i = 0; i < num_elements; ++i) {
+ int type = ReadInteger(obj);
+ if (type == FormDataElement::data) {
+ const void* data;
+ int length;
+ ReadData(obj, &data, &length);
+ form_data->appendData(static_cast<const char*>(data), length);
+ } else {
+ form_data->appendFile(ReadString(obj));
+ }
+ }
+
+ return form_data;
+}
+
+// Writes the HistoryItem data into the SerializeObject object for
+// serialization.
+static void WriteHistoryItem(const HistoryItem* item, SerializeObject* obj) {
+ // WARNING: This data may be persisted for later use. As such, care must be
+ // taken when changing the serialized format. If a new field needs to be
+ // written, only adding at the end will make it easier to deal with loading
+ // older versions. Similarly, this should NOT save fields with sensitive
+ // data, such as password fields.
+ WriteInteger(kVersion, obj);
+ WriteString(item->urlString(), obj);
+ WriteString(item->originalURLString(), obj);
+ WriteString(item->target(), obj);
+ WriteString(item->parent(), obj);
+ WriteString(item->title(), obj);
+ WriteString(item->alternateTitle(), obj);
+ WriteReal(item->lastVisitedTime(), obj);
+ WriteInteger(item->scrollPoint().x(), obj);
+ WriteInteger(item->scrollPoint().y(), obj);
+ WriteBoolean(item->isTargetItem(), obj);
+ WriteInteger(item->visitCount(), obj);
+ WriteString(item->rssFeedReferrer(), obj);
+
+ WriteStringVector(item->documentState(), obj);
+
+ // No access to formData through a const HistoryItem = lame.
+ WriteFormData(const_cast<HistoryItem*>(item)->formData(), obj);
+ WriteString(item->formContentType(), obj);
+ WriteString(item->formReferrer(), obj);
+
+ // Subitems
+ WriteInteger(static_cast<int>(item->children().size()), obj);
+ for (size_t i = 0, c = item->children().size(); i < c; ++i)
+ WriteHistoryItem(item->children().at(i).get(), obj);
+}
+
+// Creates a new HistoryItem tree based on the serialized string.
+// Assumes the data is in the format returned by WriteHistoryItem.
+static HistoryItem* ReadHistoryItem(const SerializeObject* obj) {
+ // See note in WriteHistoryItem. on this.
+ obj->version = ReadInteger(obj);
+
+ if (obj->version > kVersion)
+ return NULL;
+
+ HistoryItem* item = new HistoryItem();
+
+ item->setURLString(ReadString(obj));
+ item->setOriginalURLString(ReadString(obj));
+ item->setTarget(ReadString(obj));
+ item->setParent(ReadString(obj));
+ item->setTitle(ReadString(obj));
+ item->setAlternateTitle(ReadString(obj));
+ item->setLastVisitedTime(ReadReal(obj));
+ int x = ReadInteger(obj);
+ int y = ReadInteger(obj);
+ item->setScrollPoint(IntPoint(x, y));
+ item->setIsTargetItem(ReadBoolean(obj));
+ item->setVisitCount(ReadInteger(obj));
+ item->setRSSFeedReferrer(ReadString(obj));
+
+ Vector<String> document_state;
+ ReadStringVector(obj, &document_state);
+ item->setDocumentState(document_state);
+
+ // Form data. If there is any form data, we assume POST, otherwise GET.
+ // ResourceRequest takes ownership of the new FormData, then gives it to
+ // HistoryItem.
+ ResourceRequest dummy_request; // only way to initialize HistoryItem
+ dummy_request.setHTTPBody(ReadFormData(obj));
+ dummy_request.setHTTPContentType(ReadString(obj));
+ dummy_request.setHTTPReferrer(ReadString(obj));
+ if (dummy_request.httpBody())
+ dummy_request.setHTTPMethod("POST");
+ item->setFormInfoFromRequest(dummy_request);
+
+ // Subitems
+ int num_children = ReadInteger(obj);
+ for (int i = 0; i < num_children; ++i)
+ item->addChildItem(ReadHistoryItem(obj));
+
+ return item;
+}
+
+// Serialize a HistoryItem to a string, using our JSON Value serializer.
+void HistoryItemToString(PassRefPtr<HistoryItem> item,
+ std::string* serialized_item) {
+ if (!item) {
+ serialized_item->clear();
+ return;
+ }
+
+ SerializeObject obj;
+ WriteHistoryItem(item.get(), &obj);
+ *serialized_item = obj.GetAsString();
+}
+
+// Reconstruct a HistoryItem from a string, using our JSON Value deserializer.
+// This assumes that the given serialized string has all the required key,value
+// pairs, and does minimal error checking.
+PassRefPtr<HistoryItem> HistoryItemFromString(
+ const std::string& serialized_item) {
+ if (serialized_item.empty())
+ return NULL;
+
+ SerializeObject obj(serialized_item.data(),
+ static_cast<int>(serialized_item.length()));
+ return ReadHistoryItem(&obj);
+}
+
+// For testing purposes only.
+void HistoryItemToVersionedString(PassRefPtr<HistoryItem> item, int version,
+ std::string* serialized_item) {
+ if (!item) {
+ serialized_item->clear();
+ return;
+ }
+
+ // Temporarily change the version.
+ int real_version = kVersion;
+ kVersion = version;
+
+ SerializeObject obj;
+ WriteHistoryItem(item.get(), &obj);
+ *serialized_item = obj.GetAsString();
+
+ kVersion = real_version;
+}
+
+std::string CreateHistoryStateForURL(const GURL& url) {
+ RefPtr<HistoryItem> item(new HistoryItem(GURLToKURL(url), String()));
+ std::string data;
+ HistoryItemToString(item, &data);
+ return data;
+}
+
+} // namespace webkit_glue
diff --git a/webkit/glue/glue_serialize.h b/webkit/glue/glue_serialize.h
new file mode 100644
index 0000000..dd1bddc
--- /dev/null
+++ b/webkit/glue/glue_serialize.h
@@ -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.
+//
+// This file contains (de)serialization (or if you like python, pickling)
+// methods for various objects that we want to persist.
+// In serialization, we write an object's state to a string in some opaque
+// format. Deserialization reconstructs the object's state from such a string.
+
+#ifndef WEBKIT_GLUE_GLUE_SERIALIZE_H__
+#define WEBKIT_GLUE_GLUE_SERIALIZE_H__
+
+#include "PassRefPtr.h"
+#include "RefPtr.h"
+
+namespace WebCore {
+class String;
+class HistoryItem;
+}
+
+namespace webkit_glue {
+// HistoryItem serialization. The returned HistoryItem will have a ref count
+// of 0, so the first RefPtr it is assigned to will take ownership. The empty
+// string corresponds with a NULL HistoryItem.
+void HistoryItemToString(
+ PassRefPtr<WebCore::HistoryItem> item, std::string* serialized_item);
+PassRefPtr<WebCore::HistoryItem> HistoryItemFromString(
+ const std::string& serialized_item);
+
+// For testing purposes only.
+void HistoryItemToVersionedString(
+ PassRefPtr<WebCore::HistoryItem> item, int version,
+ std::string* serialized_item);
+}
+
+#endif // #ifndef WEBKIT_GLUE_GLUE_SERIALIZE_H__
diff --git a/webkit/glue/glue_serialize_unittest.cc b/webkit/glue/glue_serialize_unittest.cc
new file mode 100644
index 0000000..a71f9b2
--- /dev/null
+++ b/webkit/glue/glue_serialize_unittest.cc
@@ -0,0 +1,202 @@
+// 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 "config.h"
+#include <string>
+
+#include "webkit/glue/glue_serialize.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "base/pickle.h"
+
+#pragma warning(push, 0)
+#include "CString.h"
+#include "FormData.h"
+#include "HistoryItem.h"
+#include "PlatformString.h"
+#include "ResourceRequest.h"
+#pragma warning(pop)
+
+using namespace std;
+using namespace WebCore;
+using namespace webkit_glue;
+
+// These exist only to support the gTest assertion macros, and
+// shouldn't be used in normal program code.
+static std::ostream& operator<<(std::ostream& out, const String& str)
+{
+ return out << str.latin1().data();
+}
+
+static std::ostream& operator<<(std::ostream& out, const FormDataElement& e)
+{
+ return out << e.m_type << ": " <<
+ e.m_data.size() <<
+ " <" << string(e.m_data.data() ? e.m_data.data() : "", e.m_data.size()) << "> " <<
+ e.m_filename;
+}
+
+template<typename T>
+static std::ostream& operator<<(std::ostream& out, const Vector<T>& v)
+{
+ for (size_t i = 0; i < v.size(); ++i)
+ out << "[" << v[i] << "] ";
+
+ return out;
+}
+
+static std::ostream& operator<<(std::ostream& out, const FormData& data)
+{
+ return out << data.elements();
+}
+
+static std::ostream& operator<<(std::ostream& out, const IntPoint& pt)
+{
+ return out << "(" << pt.x() << "," << pt.y() << ")";
+}
+
+namespace {
+class GlueSerializeTest : public testing::Test {
+ public:
+ // Makes a FormData with some random data.
+ FormData* MakeFormData() {
+ FormData* form_data = new FormData();
+
+ char d1[] = "first data block";
+ form_data->appendData(d1, sizeof(d1)-1);
+
+ form_data->appendFile("file.txt");
+
+ char d2[] = "data the second";
+ form_data->appendData(d2, sizeof(d2)-1);
+
+ return form_data;
+ }
+
+ // Constructs a HistoryItem with some random data and an optional child.
+ PassRefPtr<HistoryItem> MakeHistoryItem(bool with_form_data, bool pregnant) {
+ RefPtr<HistoryItem> item = new HistoryItem();
+
+ item->setURLString("urlString");
+ item->setOriginalURLString("originalURLString");
+ item->setTarget("target");
+ item->setParent("parent");
+ item->setTitle("title");
+ item->setAlternateTitle("alternateTitle");
+ item->setLastVisitedTime(13.37);
+ item->setScrollPoint(IntPoint(42, -42));
+ item->setIsTargetItem(true);
+ item->setVisitCount(42*42);
+ item->setRSSFeedReferrer("rssFeedReferrer");
+
+ Vector<String> document_state;
+ document_state.append("state1");
+ document_state.append("state2");
+ document_state.append("state AWESOME");
+ item->setDocumentState(document_state);
+
+ // Form Data
+ ResourceRequest dummy_request; // only way to initialize HistoryItem
+ if (with_form_data) {
+ FormData* form_data = MakeFormData();
+ dummy_request.setHTTPBody(form_data);
+ dummy_request.setHTTPContentType("formContentType");
+ dummy_request.setHTTPReferrer("formReferrer");
+ dummy_request.setHTTPMethod("POST");
+ }
+ item->setFormInfoFromRequest(dummy_request);
+
+ // Children
+ if (pregnant)
+ item->addChildItem(MakeHistoryItem(false, false));
+
+ return item;
+ }
+
+ // Checks that a == b.
+ void HistoryItemExpectEqual(HistoryItem* a, HistoryItem* b) {
+ EXPECT_EQ(a->urlString(), b->urlString());
+ EXPECT_EQ(a->originalURLString(), b->originalURLString());
+ EXPECT_EQ(a->target(), b->target());
+ EXPECT_EQ(a->parent(), b->parent());
+ EXPECT_EQ(a->title(), b->title());
+ EXPECT_EQ(a->alternateTitle(), b->alternateTitle());
+ EXPECT_EQ(a->lastVisitedTime(), b->lastVisitedTime());
+ EXPECT_EQ(a->scrollPoint(), b->scrollPoint());
+ EXPECT_EQ(a->isTargetItem(), b->isTargetItem());
+ EXPECT_EQ(a->visitCount(), b->visitCount());
+ EXPECT_EQ(a->rssFeedReferrer(), b->rssFeedReferrer());
+ EXPECT_EQ(a->documentState(), b->documentState());
+
+ // Form Data
+ EXPECT_EQ(a->formData() != NULL, b->formData() != NULL);
+ if (a->formData() && b->formData())
+ EXPECT_EQ(*a->formData(), *b->formData());
+ EXPECT_EQ(a->formReferrer(), b->formReferrer());
+ EXPECT_EQ(a->formContentType(), b->formContentType());
+
+ // Children
+ EXPECT_EQ(a->children().size(), b->children().size());
+ for (size_t i = 0, c = a->children().size(); i < c; ++i) {
+ HistoryItemExpectEqual(a->children().at(i).get(),
+ b->children().at(i).get());
+ }
+ }
+};
+
+// Test old versions of serialized data to ensure that newer versions of code
+// can still read history items written by previous versions.
+TEST_F(GlueSerializeTest, BackwardsCompatibleTest) {
+ RefPtr<HistoryItem> item = MakeHistoryItem(false, false);
+
+ // Make sure version 3 (current version) can read versions 1 and 2.
+ for (int i = 1; i <= 2; i++) {
+ string serialized_item;
+ HistoryItemToVersionedString(item.get(), i, &serialized_item);
+ RefPtr<HistoryItem> deserialized_item = HistoryItemFromString(serialized_item);
+ ASSERT_FALSE(item == NULL);
+ ASSERT_FALSE(deserialized_item == NULL);
+ HistoryItemExpectEqual(item.get(), deserialized_item.get());
+ }
+}
+
+// Makes sure that a HistoryItem remains intact after being serialized and
+// deserialized.
+TEST_F(GlueSerializeTest, HistoryItemSerializeTest) {
+ RefPtr<HistoryItem> item = MakeHistoryItem(true, true);
+ string serialized_item;
+ HistoryItemToString(item, &serialized_item);
+ RefPtr<HistoryItem> deserialized_item = HistoryItemFromString(serialized_item);
+
+ ASSERT_FALSE(item == NULL);
+ ASSERT_FALSE(deserialized_item == NULL);
+ HistoryItemExpectEqual(item.get(), deserialized_item.get());
+}
+
+
+} // namespace \ No newline at end of file
diff --git a/webkit/glue/glue_util.cc b/webkit/glue/glue_util.cc
new file mode 100644
index 0000000..b2eebb3
--- /dev/null
+++ b/webkit/glue/glue_util.cc
@@ -0,0 +1,107 @@
+// 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 "config.h"
+#include <string>
+
+#include "webkit/glue/glue_util.h"
+#include "base/string_util.h"
+
+#pragma warning(push, 0)
+#include "CString.h"
+#include "DeprecatedString.h"
+#include "PlatformString.h"
+#pragma warning(pop)
+
+#include "KURL.h"
+
+namespace webkit_glue {
+
+// String conversions ----------------------------------------------------------
+
+std::string CStringToStdString(const WebCore::CString& str) {
+ const char* chars = str.data();
+ return std::string(chars ? chars : "", str.length());
+}
+
+WebCore::CString StdStringToCString(const std::string& str) {
+ return WebCore::CString(str.data(), str.size());
+}
+
+std::wstring StringToStdWString(const WebCore::String& str) {
+ const UChar* chars = str.characters();
+ return std::wstring(chars ? chars : L"", str.length());
+}
+
+WebCore::String StdWStringToString(const std::wstring& str) {
+ return WebCore::String(str.data(), static_cast<unsigned>(str.length()));
+}
+
+WebCore::String StdStringToString(const std::string& str) {
+ return WebCore::String(str.data(), static_cast<unsigned>(str.length()));
+}
+
+WebCore::DeprecatedString StdWStringToDeprecatedString(
+ const std::wstring& str) {
+ return WebCore::DeprecatedString(
+ reinterpret_cast<const WebCore::DeprecatedChar*>(str.c_str()),
+ static_cast<int>(str.size()));
+}
+
+std::wstring DeprecatedStringToStdWString(
+ const WebCore::DeprecatedString& dep) {
+ return std::wstring(reinterpret_cast<const wchar_t*>(dep.unicode()),
+ dep.length());
+}
+
+// URL conversions -------------------------------------------------------------
+
+GURL KURLToGURL(const WebCore::KURL& url) {
+#ifdef USE_GOOGLE_URL_LIBRARY
+ const WebCore::CString& spec = url.utf8String();
+ if (spec.isNull())
+ return GURL();
+ return GURL(spec.data(), spec.length(), url.parsed(), url.isValid());
+#else
+ return GURL(WideToUTF8(DeprecatedStringToStdWString(spec)));
+#endif
+}
+
+WebCore::KURL GURLToKURL(const GURL& url) {
+ const std::string& spec = url.possibly_invalid_spec();
+#ifdef USE_GOOGLE_URL_LIBRARY
+ // Convert using the internal structures to avoid re-parsing.
+ return WebCore::KURL(spec.c_str(), static_cast<int>(spec.length()),
+ url.parsed_for_possibly_invalid_spec(), url.is_valid());
+#else
+ return WebCore::KURL(StdWStringToDeprecatedString(UTF8ToWide(spec)));
+#endif
+}
+
+} // namespace webkit_glue
diff --git a/webkit/glue/glue_util.h b/webkit/glue/glue_util.h
new file mode 100644
index 0000000..f4de7a4
--- /dev/null
+++ b/webkit/glue/glue_util.h
@@ -0,0 +1,59 @@
+// 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 WEBKIT_GLUE_GLUE_UTIL_H__
+#define WEBKIT_GLUE_GLUE_UTIL_H__
+
+#include <string>
+
+#include "googleurl/src/gurl.h"
+
+namespace WebCore {
+ class CString;
+ class DeprecatedString;
+ class KURL;
+ class String;
+}
+
+namespace webkit_glue {
+ std::string CStringToStdString(const WebCore::CString& str);
+ WebCore::CString StdStringToCString(const std::string& str);
+ std::wstring StringToStdWString(const WebCore::String& str);
+
+ WebCore::String StdWStringToString(const std::wstring& str);
+ WebCore::String StdStringToString(const std::string& str);
+
+ WebCore::DeprecatedString StdWStringToDeprecatedString(const std::wstring& str);
+ std::wstring DeprecatedStringToStdWString(const WebCore::DeprecatedString& dep);
+
+ GURL KURLToGURL(const WebCore::KURL& url);
+ WebCore::KURL GURLToKURL(const GURL& url);
+}
+
+#endif // #ifndef WEBKIT_GLUE_GLUE_UTIL_H__
diff --git a/webkit/glue/iframe_redirect_unittest.cc b/webkit/glue/iframe_redirect_unittest.cc
new file mode 100644
index 0000000..e10198e
--- /dev/null
+++ b/webkit/glue/iframe_redirect_unittest.cc
@@ -0,0 +1,67 @@
+// 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 "config.h"
+
+#include <string>
+
+#undef LOG
+
+#include "base/file_util.h"
+#include "base/string_util.h"
+#include "webkit/glue/webdatasource.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/webframe.h"
+#include "webkit/glue/webview.h"
+#include "webkit/tools/test_shell/test_shell_test.h"
+
+typedef TestShellTest IFrameRedirectTest;
+
+// Tests that loading a page in an iframe from javascript results in
+// a redirect from about:blank.
+TEST_F(IFrameRedirectTest, Test) {
+ std::wstring iframes_data_dir_ = data_dir_;
+
+ file_util::AppendToPath(&iframes_data_dir_, L"test_shell");
+ file_util::AppendToPath(&iframes_data_dir_, L"iframe_redirect");
+ ASSERT_TRUE(file_util::PathExists(iframes_data_dir_));
+
+ std::wstring test_url = GetTestURL(iframes_data_dir_, L"main.html");
+
+ test_shell_->LoadURL(test_url.c_str());
+ test_shell_->WaitTestFinished();
+
+ WebFrame* iframe = test_shell_->webView()->GetFrameWithName(L"ifr");
+ ASSERT_TRUE(iframe != NULL);
+ WebDataSource* iframe_ds = iframe->GetDataSource();
+ ASSERT_TRUE(iframe_ds != NULL);
+ const std::vector<GURL>& redirects = iframe_ds->GetRedirectChain();
+ ASSERT_FALSE(redirects.empty());
+ ASSERT_TRUE(redirects[0] == GURL("about:blank"));
+}
diff --git a/webkit/glue/image_decoder.cc b/webkit/glue/image_decoder.cc
new file mode 100644
index 0000000..34a56b8
--- /dev/null
+++ b/webkit/glue/image_decoder.cc
@@ -0,0 +1,71 @@
+// 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/image_decoder.h"
+
+#pragma warning(push, 0)
+#include "ImageSourceSkia.h"
+#include "IntSize.h"
+#include "RefPtr.h"
+#include "SharedBuffer.h"
+#pragma warning(pop)
+
+#include "SkBitmap.h"
+
+namespace webkit_glue {
+
+ImageDecoder::ImageDecoder() : desired_icon_size_(0, 0) {
+}
+
+ImageDecoder::ImageDecoder(const gfx::Size& desired_icon_size)
+ : desired_icon_size_(desired_icon_size) {
+}
+
+ImageDecoder::~ImageDecoder() {
+}
+
+SkBitmap ImageDecoder::Decode(const unsigned char* data, size_t size) {
+ WebCore::ImageSourceSkia source;
+ WTF::RefPtr<WebCore::SharedBuffer> buffer(new WebCore::SharedBuffer(
+ data, static_cast<int>(size)));
+ source.setData(buffer.get(), true,
+ WebCore::IntSize(desired_icon_size_.width(),
+ desired_icon_size_.height()));
+
+ if (!source.isSizeAvailable())
+ return SkBitmap();
+
+ WebCore::NativeImagePtr frame0 = source.createFrameAtIndex(0);
+ if (!frame0)
+ return SkBitmap();
+
+ return *reinterpret_cast<SkBitmap*>(frame0);
+}
+
+} // namespace webkit_glue
diff --git a/webkit/glue/image_decoder.h b/webkit/glue/image_decoder.h
new file mode 100644
index 0000000..e81e9da
--- /dev/null
+++ b/webkit/glue/image_decoder.h
@@ -0,0 +1,63 @@
+// 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/basictypes.h"
+#include "base/gfx/size.h"
+#include "base/scoped_ptr.h"
+
+class SkBitmap;
+
+namespace webkit_glue {
+
+// Provides an interface to WebKit's image decoders.
+//
+// Note to future: This class should be deleted. We should have our own nice
+// image decoders in base/gfx, and our port should use those. Currently, it's
+// the other way around.
+class ImageDecoder {
+ public:
+ // Use the constructor with desired_size when you think you may have an .ico
+ // format and care about which size you get back. Otherwise, use the 0-arg
+ // constructor.
+ ImageDecoder();
+ ImageDecoder(const gfx::Size& desired_icon_size);
+ ~ImageDecoder();
+
+ // Call this function to decode the image. If successful, the decoded image
+ // will be returned. Otherwise, an empty bitmap will be returned.
+ SkBitmap Decode(const unsigned char* data, size_t size);
+
+ private:
+ // Size will be empty to get the largest possible size.
+ gfx::Size desired_icon_size_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(ImageDecoder);
+};
+
+} // namespace webkit_glue
diff --git a/webkit/glue/image_resource_fetcher.cc b/webkit/glue/image_resource_fetcher.cc
new file mode 100644
index 0000000..1279206
--- /dev/null
+++ b/webkit/glue/image_resource_fetcher.cc
@@ -0,0 +1,81 @@
+// 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 "config.h"
+
+#pragma warning(push, 0)
+#include "ImageSourceSkia.h"
+#pragma warning(pop)
+#undef LOG
+
+#include "webkit/glue/image_resource_fetcher.h"
+
+#include "base/gfx/size.h"
+#include "webkit/glue/image_decoder.h"
+#include "webkit/glue/webview_impl.h"
+#include "skia/include/SkBitmap.h"
+
+ImageResourceFetcher::ImageResourceFetcher(
+ WebViewImpl* web_view,
+ int id,
+ const GURL& image_url,
+ int image_size)
+ : web_view_(web_view),
+ id_(id),
+ image_url_(image_url),
+ image_size_(image_size) {
+ fetcher_.reset(new ResourceFetcher(image_url,
+ web_view->main_frame()->frame(),
+ this));
+}
+
+ImageResourceFetcher::~ImageResourceFetcher() {
+ if (!fetcher_->completed())
+ fetcher_->Cancel();
+}
+
+void ImageResourceFetcher::OnURLFetchComplete(
+ const WebCore::ResourceResponse& response,
+ const std::string& data) {
+ SkBitmap image;
+ bool errored = false;
+ if (response.isNull()) {
+ errored = true;
+ } else if (response.httpStatusCode() == 200) {
+ // Request succeeded, try to convert it to an image.
+ webkit_glue::ImageDecoder decoder(gfx::Size(image_size_, image_size_));
+ image = decoder.Decode(
+ reinterpret_cast<const unsigned char*>(data.data()), data.size());
+ } // else case:
+ // If we get here, it means no image from server or couldn't decode the
+ // response as an image. Need to notify the webview though, otherwise the
+ // browser will keep trying to download favicon (when this is used to
+ // download the favicon).
+ web_view_->ImageResourceDownloadDone(this, errored, image);
+}
diff --git a/webkit/glue/image_resource_fetcher.h b/webkit/glue/image_resource_fetcher.h
new file mode 100644
index 0000000..66c7bcb
--- /dev/null
+++ b/webkit/glue/image_resource_fetcher.h
@@ -0,0 +1,86 @@
+// 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 WEBKIT_GLUE_IMAGE_RESOURCE_FETCHER_H__
+#define WEBKIT_GLUE_IMAGE_RESOURCE_FETCHER_H__
+
+#include "base/basictypes.h"
+#include "webkit/glue/resource_fetcher.h"
+
+class SkBitmap;
+class WebCore::ResourceResponse;
+class WebViewImpl;
+
+// ImageResourceFetcher handles downloading an image for a webview. Once
+// downloading is done the hosting WebViewImpl is notified. ImageResourceFetcher
+// is used to download the favicon and images for web apps.
+class ImageResourceFetcher : public ResourceFetcher::Delegate {
+ public:
+ ImageResourceFetcher(WebViewImpl* web_view,
+ int id,
+ const GURL& image_url,
+ int image_size);
+
+ virtual ~ImageResourceFetcher();
+
+ // ResourceFetcher::Delegate method. Decodes the image and invokes one of
+ // DownloadFailed or DownloadedImage.
+ virtual void OnURLFetchComplete(const WebCore::ResourceResponse& response,
+ const std::string& data);
+
+ // URL of the image we're downloading.
+ const GURL& image_url() const { return image_url_; }
+
+ // Hosting WebView.
+ WebViewImpl* web_view() const { return web_view_; }
+
+ // Unique identifier for the request.
+ int id() const { return id_; }
+
+ private:
+ WebViewImpl* web_view_;
+
+ // Unique identifier for the request.
+ const int id_;
+
+ // URL of the image.
+ const GURL image_url_;
+
+ // The size of the image. This is only a hint that is used if the image
+ // contains multiple sizes. A value of 0 results in using the first frame
+ // of the image.
+ const int image_size_;
+
+ // Does the actual download.
+ scoped_ptr<ResourceFetcher> fetcher_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(ImageResourceFetcher);
+};
+
+#endif // WEBKIT_GLUE_IMAGE_RESOURCE_FETCHER_H__
diff --git a/webkit/glue/inspector_client_impl.cc b/webkit/glue/inspector_client_impl.cc
new file mode 100644
index 0000000..9aeb981
--- /dev/null
+++ b/webkit/glue/inspector_client_impl.cc
@@ -0,0 +1,192 @@
+// 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 "config.h"
+
+#pragma warning(push, 0)
+#include "FloatRect.h"
+#include "InspectorController.h"
+#include "Page.h"
+#include "Settings.h"
+#pragma warning(pop)
+
+#undef LOG
+#include "webkit/glue/inspector_client_impl.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/webview_impl.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/net_util.h"
+
+using namespace WebCore;
+
+static const float kDefaultInspectorXPos = 10;
+static const float kDefaultInspectorYPos = 50;
+static const float kDefaultInspectorHeight = 640;
+static const float kDefaultInspectorWidth = 480;
+
+WebInspectorClient::WebInspectorClient(WebView* webView)
+ : inspected_web_view_(webView)
+ , inspector_web_view_(0) {
+ ASSERT(inspected_web_view_);
+}
+
+WebInspectorClient::~WebInspectorClient() {
+}
+
+void WebInspectorClient::inspectorDestroyed() {
+ delete this;
+}
+
+Page* WebInspectorClient::createPage() {
+ WebCore::Page* page;
+
+ if (inspector_web_view_ != NULL) {
+ page = static_cast<WebViewImpl*>(inspector_web_view_)->page();
+ ASSERT(page != NULL);
+ if (page != NULL)
+ return page;
+ }
+
+ WebViewDelegate* delegate = inspected_web_view_->GetDelegate();
+ if (!delegate)
+ return NULL;
+ inspector_web_view_ = delegate->CreateWebView(inspected_web_view_, true);
+ if (!inspector_web_view_)
+ return NULL;
+
+ GURL inspector_url(webkit_glue::GetInspectorURL());
+ scoped_ptr<WebRequest> request(WebRequest::Create(inspector_url));
+ WebViewImpl* inspector_web_view_impl =
+ static_cast<WebViewImpl*>(inspector_web_view_);
+ inspector_web_view_impl->main_frame()->LoadRequest(request.get());
+
+ page = inspector_web_view_impl->page();
+
+ page->chrome()->setToolbarsVisible(false);
+ page->chrome()->setStatusbarVisible(false);
+ page->chrome()->setScrollbarsVisible(false);
+ page->chrome()->setMenubarVisible(false);
+ page->chrome()->setResizable(true);
+
+ // Don't allow inspection of inspector.
+ page->settings()->setDeveloperExtrasEnabled(false);
+ page->settings()->setPrivateBrowsingEnabled(true);
+ page->settings()->setPluginsEnabled(false);
+ page->settings()->setJavaEnabled(false);
+
+ FloatRect windowRect = page->chrome()->windowRect();
+ FloatSize pageSize = page->chrome()->pageRect().size();
+ windowRect.setX(kDefaultInspectorXPos);
+ windowRect.setY(kDefaultInspectorYPos);
+ windowRect.setWidth(kDefaultInspectorHeight);
+ windowRect.setHeight(kDefaultInspectorWidth);
+ page->chrome()->setWindowRect(windowRect);
+
+ page->chrome()->show();
+
+ return page;
+}
+
+void WebInspectorClient::showWindow() {
+ WebViewImpl* impl = static_cast<WebViewImpl*>(inspected_web_view_.get());
+ InspectorController* inspector = impl->page()->inspectorController();
+ inspector->setWindowVisible(true);
+
+ // Notify the webview delegate of how many resources we're inspecting.
+ WebViewDelegate* d = impl->delegate();
+ DCHECK(d);
+ d->WebInspectorOpened(inspector->resources().size());
+}
+
+void WebInspectorClient::closeWindow() {
+ inspector_web_view_ = NULL;
+ WebViewImpl* impl = static_cast<WebViewImpl*>(inspected_web_view_.get());
+ WebFrameImpl* frame = static_cast<WebFrameImpl*>(impl->GetMainFrame());
+
+ if (frame && frame->inspected_node())
+ hideHighlight();
+
+ if (impl->page())
+ impl->page()->inspectorController()->setWindowVisible(false);
+}
+
+bool WebInspectorClient::windowVisible() {
+ if (inspector_web_view_ != NULL) {
+ Page* page = static_cast<WebViewImpl*>(inspector_web_view_)->page();
+ ASSERT(page != NULL);
+ if (page != NULL)
+ return true;
+ }
+ return false;
+}
+
+void WebInspectorClient::attachWindow() {
+ // TODO(jackson): Implement this
+}
+
+void WebInspectorClient::detachWindow() {
+ // TODO(jackson): Implement this
+}
+
+static void invalidateNodeBoundingRect(WebViewImpl* web_view) {
+ // TODO(ojan): http://b/1143996 Is it important to just invalidate the rect
+ // of the node region given that this is not on a critical codepath?
+ // In order to do so, we'd have to take scrolling into account.
+ gfx::Size size = web_view->size();
+ gfx::Rect damaged_rect(0, 0, size.width(), size.height());
+ web_view->GetDelegate()->DidInvalidateRect(web_view, damaged_rect);
+}
+
+void WebInspectorClient::highlight(Node* node) {
+ WebViewImpl* web_view = static_cast<WebViewImpl*>(inspected_web_view_.get());
+ WebFrameImpl* frame = static_cast<WebFrameImpl*>(web_view->GetMainFrame());
+
+ if (frame->inspected_node())
+ hideHighlight();
+
+ invalidateNodeBoundingRect(web_view);
+ frame->selectNodeFromInspector(node);
+}
+
+void WebInspectorClient::hideHighlight() {
+ WebViewImpl* web_view = static_cast<WebViewImpl*>(inspected_web_view_.get());
+ WebFrameImpl* frame = static_cast<WebFrameImpl*>(web_view->GetMainFrame());
+
+ invalidateNodeBoundingRect(web_view);
+ frame->selectNodeFromInspector(NULL);
+}
+
+void WebInspectorClient::inspectedURLChanged(const String& newURL) {
+ // TODO(jackson): Implement this
+}
+
+String WebInspectorClient::localizedStringsURL() {
+ notImplemented();
+ return String();
+}
diff --git a/webkit/glue/inspector_client_impl.h b/webkit/glue/inspector_client_impl.h
new file mode 100644
index 0000000..e2135c7
--- /dev/null
+++ b/webkit/glue/inspector_client_impl.h
@@ -0,0 +1,70 @@
+// 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 WEBKIT_GLUE_INSPECTOR_CLIENT_IMPL_H__
+#define WEBKIT_GLUE_INSPECTOR_CLIENT_IMPL_H__
+
+#include "InspectorClient.h"
+#include "base/ref_counted.h"
+
+class WebNodeHighlight;
+class WebView;
+
+class WebInspectorClient : public WebCore::InspectorClient {
+public:
+ WebInspectorClient(WebView*);
+
+ // InspectorClient
+ virtual void inspectorDestroyed();
+
+ virtual WebCore::Page* createPage();
+ virtual WebCore::String localizedStringsURL();
+ virtual void showWindow();
+ virtual void closeWindow();
+ virtual bool windowVisible();
+
+ virtual void attachWindow();
+ virtual void detachWindow();
+
+ virtual void highlight(WebCore::Node*);
+ virtual void hideHighlight();
+
+ virtual void inspectedURLChanged(const WebCore::String& newURL);
+
+private:
+ ~WebInspectorClient();
+
+ // The WebView of the page being inspected; gets passed to the constructor
+ scoped_refptr<WebView> inspected_web_view_;
+
+ // The WebView of the Inspector popup window
+ WebView* inspector_web_view_;
+};
+
+#endif // WEBKIT_GLUE_INSPECTOR_CLIENT_IMPL_H__
diff --git a/webkit/glue/localized_strings.cc b/webkit/glue/localized_strings.cc
new file mode 100644
index 0000000..094e9c1
--- /dev/null
+++ b/webkit/glue/localized_strings.cc
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2007 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 "config.h"
+#include "LocalizedStrings.h"
+#include "PlatformString.h"
+#include "IntSize.h"
+
+#undef LOG
+#include "webkit/glue/webkit_glue.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+
+#include "webkit_strings.h"
+
+using namespace WebCore;
+
+inline String GetLocalizedString(int message_id) {
+ const std::wstring& str(webkit_glue::GetLocalizedString(message_id));
+ return String(str.c_str());
+}
+
+String WebCore::searchableIndexIntroduction() {
+ return GetLocalizedString(IDS_SEARCHABLE_INDEX_INTRO);
+}
+String WebCore::submitButtonDefaultLabel() {
+ return GetLocalizedString(IDS_FORM_SUBMIT_LABEL);
+}
+String WebCore::inputElementAltText() {
+ return GetLocalizedString(IDS_FORM_INPUT_ALT);
+}
+String WebCore::resetButtonDefaultLabel() {
+ return GetLocalizedString(IDS_FORM_RESET_LABEL);
+}
+String WebCore::fileButtonChooseFileLabel() {
+ return GetLocalizedString(IDS_FORM_FILE_BUTTON_LABEL);
+}
+String WebCore::fileButtonNoFileSelectedLabel() {
+ return GetLocalizedString(IDS_FORM_FILE_NO_FILE_LABEL);
+}
+
+// TODO(tc): Do we actually plan on implementing search menu items?
+String WebCore::searchMenuNoRecentSearchesText() {
+ return GetLocalizedString(IDS_RECENT_SEARCHES_NONE);
+}
+String WebCore::searchMenuRecentSearchesText() {
+ return GetLocalizedString(IDS_RECENT_SEARCHES);
+}
+String WebCore::searchMenuClearRecentSearchesText() {
+ return GetLocalizedString(IDS_RECENT_SEARCHES_CLEAR);
+}
+
+// A11y strings.
+String WebCore::AXWebAreaText() {
+ return GetLocalizedString(IDS_AX_ROLE_WEB_AREA);
+}
+String WebCore::AXLinkText() {
+ return GetLocalizedString(IDS_AX_ROLE_LINK);
+}
+String WebCore::AXListMarkerText() {
+ return GetLocalizedString(IDS_AX_ROLE_LIST_MARKER);
+}
+String WebCore::AXImageMapText() {
+ return GetLocalizedString(IDS_AX_ROLE_IMAGE_MAP);
+}
+String WebCore::AXHeadingText() {
+ return GetLocalizedString(IDS_AX_ROLE_HEADING);
+}
+String WebCore::AXButtonActionVerb() {
+ return GetLocalizedString(IDS_AX_BUTTON_ACTION_VERB);
+}
+String WebCore::AXRadioButtonActionVerb() {
+ return GetLocalizedString(IDS_AX_RADIO_BUTTON_ACTION_VERB);
+}
+String WebCore::AXTextFieldActionVerb() {
+ return GetLocalizedString(IDS_AX_TEXT_FIELD_ACTION_VERB);
+}
+String WebCore::AXCheckedCheckBoxActionVerb() {
+ return GetLocalizedString(IDS_AX_CHECKED_CHECK_BOX_ACTION_VERB);
+}
+String WebCore::AXUncheckedCheckBoxActionVerb() {
+ return GetLocalizedString(IDS_AX_UNCHECKED_CHECK_BOX_ACTION_VERB);
+}
+String WebCore::AXLinkActionVerb() {
+ return GetLocalizedString(IDS_AX_LINK_ACTION_VERB);
+}
+
+// The following two functions are not declared in LocalizedStrings.h.
+// They are used by the menu for the HTML keygen tag.
+namespace WebCore {
+String keygenMenuHighGradeKeySize() {
+ return GetLocalizedString(IDS_KEYGEN_HIGH_GRADE_KEY);
+}
+String keygenMenuMediumGradeKeySize() {
+ return GetLocalizedString(IDS_KEYGEN_MED_GRADE_KEY);
+}
+} //namespace WebCore
+
+// We don't use these strings, so they return an empty String. We can't just
+// make them asserts because webcore still calls them.
+String WebCore::contextMenuItemTagOpenLinkInNewWindow() { return String(); }
+String WebCore::contextMenuItemTagDownloadLinkToDisk() { return String(); }
+String WebCore::contextMenuItemTagCopyLinkToClipboard() { return String(); }
+String WebCore::contextMenuItemTagOpenImageInNewWindow() { return String(); }
+String WebCore::contextMenuItemTagDownloadImageToDisk() { return String(); }
+String WebCore::contextMenuItemTagCopyImageToClipboard() { return String(); }
+String WebCore::contextMenuItemTagOpenFrameInNewWindow() { return String(); }
+String WebCore::contextMenuItemTagCopy() { return String(); }
+String WebCore::contextMenuItemTagGoBack() { return String(); }
+String WebCore::contextMenuItemTagGoForward() { return String(); }
+String WebCore::contextMenuItemTagStop() { return String(); }
+String WebCore::contextMenuItemTagReload() { return String(); }
+String WebCore::contextMenuItemTagCut() { return String(); }
+String WebCore::contextMenuItemTagPaste() { return String(); }
+String WebCore::contextMenuItemTagNoGuessesFound() { return String(); }
+String WebCore::contextMenuItemTagIgnoreSpelling() { return String(); }
+String WebCore::contextMenuItemTagLearnSpelling() { return String(); }
+String WebCore::contextMenuItemTagSearchWeb() { return String(); }
+String WebCore::contextMenuItemTagLookUpInDictionary() { return String(); }
+String WebCore::contextMenuItemTagOpenLink() { return String(); }
+String WebCore::contextMenuItemTagIgnoreGrammar() { return String(); }
+String WebCore::contextMenuItemTagSpellingMenu() { return String(); }
+String WebCore::contextMenuItemTagCheckSpelling() { return String(); }
+String WebCore::contextMenuItemTagCheckSpellingWhileTyping() { return String(); }
+String WebCore::contextMenuItemTagCheckGrammarWithSpelling() { return String(); }
+String WebCore::contextMenuItemTagFontMenu() { return String(); }
+String WebCore::contextMenuItemTagBold() { return String(); }
+String WebCore::contextMenuItemTagItalic() { return String(); }
+String WebCore::contextMenuItemTagUnderline() { return String(); }
+String WebCore::contextMenuItemTagOutline() { return String(); }
+String WebCore::contextMenuItemTagWritingDirectionMenu() { return String(); }
+String WebCore::contextMenuItemTagDefaultDirection() { return String(); }
+String WebCore::contextMenuItemTagLeftToRight() { return String(); }
+String WebCore::contextMenuItemTagRightToLeft() { return String(); }
+String WebCore::contextMenuItemTagInspectElement() { return String(); }
+String WebCore::contextMenuItemTagShowSpellingPanel(bool show) { return String(); }
diff --git a/webkit/glue/mimetype_unittest.cc b/webkit/glue/mimetype_unittest.cc
new file mode 100644
index 0000000..e9eb394
--- /dev/null
+++ b/webkit/glue/mimetype_unittest.cc
@@ -0,0 +1,111 @@
+// 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 "config.h"
+
+#include <string>
+
+#undef LOG
+
+#include "base/string_util.h"
+#include "net/url_request/url_request_unittest.h"
+#include "webkit/glue/unittest_test_server.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/webview.h"
+#include "webkit/tools/test_shell/test_shell_test.h"
+
+namespace {
+
+class MimeTypeTests : public TestShellTest {
+ public:
+ void LoadURL(const GURL& url) {
+ test_shell_->LoadURL(UTF8ToWide(url.spec()).c_str());
+ test_shell_->WaitTestFinished();
+ }
+
+ void CheckMimeType(const char* mimetype, const std::wstring& expected) {
+ std::string path("contenttype?");
+ GURL url = server_->TestServerPage(path + mimetype);
+ LoadURL(url);
+ WebFrame* frame = test_shell_->webView()->GetMainFrame();
+ EXPECT_EQ(expected, webkit_glue::DumpDocumentText(frame));
+ }
+
+ scoped_ptr<UnittestTestServer> server_;
+};
+
+TEST_F(MimeTypeTests, MimeTypeTests) {
+ server_.reset(new UnittestTestServer);
+
+ std::wstring expected_src(L"<html>\n<body>\n"
+ L"<p>HTML text</p>\n</body>\n</html>\n");
+
+ // These files should all be displayed as plain text.
+ const char* plain_text[] = {
+ "text/css",
+ "text/foo",
+ "text/richext",
+ "text/rtf",
+ "application/x-javascript",
+ };
+ for (int i = 0; i < arraysize(plain_text); ++i) {
+ CheckMimeType(plain_text[i], expected_src);
+ }
+
+ // These should all be displayed as html content.
+ const char* html_src[] = {
+ "text/html",
+ "text/xml",
+ "text/xsl",
+ "application/xhtml+xml",
+ };
+ for (int i = 0; i < arraysize(html_src); ++i) {
+ CheckMimeType(html_src[i], L"HTML text");
+ }
+
+ // These shouldn't be rendered as text or HTML, but shouldn't download
+ // either.
+ const char* not_text[] = {
+ "image/png",
+ "image/gif",
+ "image/jpeg",
+ "image/bmp",
+ };
+ for (int i = 0; i < arraysize(not_text); ++i) {
+ CheckMimeType(not_text[i], L"");
+ test_shell_->webView()->StopLoading();
+ }
+
+ // TODO(tc): make sure other mime types properly go to download (e.g.,
+ // image/foo).
+
+ server_.reset(NULL);
+}
+
+} // namespace
diff --git a/webkit/glue/multipart_response_delegate.cc b/webkit/glue/multipart_response_delegate.cc
new file mode 100644
index 0000000..e9cc258
--- /dev/null
+++ b/webkit/glue/multipart_response_delegate.cc
@@ -0,0 +1,255 @@
+// 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 <string>
+
+#include "config.h"
+#pragma warning(push, 0)
+#include "HTTPHeaderMap.h"
+#include "ResourceHandle.h"
+#include "ResourceHandleClient.h"
+#include "String.h"
+#pragma warning(pop)
+
+#undef LOG
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "webkit/glue/multipart_response_delegate.h"
+#include "webkit/glue/glue_util.h"
+#include "net/base/net_util.h"
+
+MultipartResponseDelegate::MultipartResponseDelegate(
+ WebCore::ResourceHandleClient* client,
+ WebCore::ResourceHandle* job,
+ const WebCore::ResourceResponse& response,
+ const std::string& boundary)
+ : client_(client),
+ job_(job),
+ original_response_(response),
+ boundary_("--"),
+ first_received_data_(true),
+ processing_headers_(false),
+ stop_sending_(false) {
+ boundary_.append(boundary);
+}
+
+void MultipartResponseDelegate::OnReceivedData(const char* data, int data_len) {
+ // stop_sending_ means that we've already received the final boundary token.
+ // The server should stop sending us data at this point, but if it does, we
+ // just throw it away.
+ if (stop_sending_)
+ return;
+
+ // TODO(tc): Figure out what to use for length_received. Maybe we can just
+ // pass the value on from our caller. See note in
+ // resource_handle_win.cc:ResourceHandleInternal::OnReceivedData.
+ int length_received = -1;
+
+ data_.append(data, data_len);
+ if (first_received_data_) {
+ // Some servers don't send a boundary token before the first chunk of
+ // data. We handle this case anyway (Gecko does too).
+ first_received_data_ = false;
+
+ // Eat leading \r\n
+ int pos = PushOverLine(data_, 0);
+ if (pos)
+ data_ = data_.substr(pos);
+
+ if (data_.length() < boundary_.length() + 2) {
+ // We don't have enough data yet to make a boundary token. Just wait
+ // until the next chunk of data arrives.
+ first_received_data_ = true;
+ return;
+ }
+
+ if (data_.substr(0, boundary_.length()) != boundary_) {
+ data_ = boundary_ + "\n" + data_;
+ }
+ }
+ DCHECK(!first_received_data_);
+
+ // Headers
+ if (processing_headers_) {
+ if (ParseHeaders()) {
+ // Successfully parsed headers.
+ processing_headers_ = false;
+ } else {
+ // Get more data before trying again.
+ return;
+ }
+ }
+ DCHECK(!processing_headers_);
+
+ int token_line_feed = 1;
+ size_t boundary_pos;
+ while ((boundary_pos = FindBoundary()) != std::string::npos) {
+ if (boundary_pos > 0) {
+ // Send the last data chunk.
+ client_->didReceiveData(job_, data_.substr(0, boundary_pos).data(),
+ static_cast<int>(boundary_pos), length_received);
+ }
+ size_t boundary_end_pos = boundary_pos + boundary_.length();
+ if (boundary_end_pos < data_.length() && '-' == data_[boundary_end_pos]) {
+ // This was the last boundary so we can stop processing.
+ stop_sending_ = true;
+ data_.clear();
+ return;
+ }
+
+ // We can now throw out data up through the boundary
+ int offset = PushOverLine(data_, boundary_end_pos);
+ data_ = data_.substr(boundary_end_pos + offset);
+
+ // Ok, back to parsing headers
+ if (!ParseHeaders()) {
+ processing_headers_ = true;
+ break;
+ }
+ }
+}
+
+void MultipartResponseDelegate::OnCompletedRequest() {
+ // If we have any pending data and we're not in a header, go ahead and send
+ // it to WebCore.
+ if (!processing_headers_ && !data_.empty()) {
+ // TODO(tc): Figure out what to use for length_received. Maybe we can just
+ // pass the value on from our caller.
+ int length_received = -1;
+ client_->didReceiveData(job_, data_.data(),
+ static_cast<int>(data_.length()), length_received);
+ }
+}
+
+int MultipartResponseDelegate::PushOverLine(const std::string& data, size_t pos) {
+ int offset = 0;
+ if (pos < data.length() && (data[pos] == '\r' || data[pos] == '\n')) {
+ ++offset;
+ if (pos + 1 < data.length() && data[pos + 1] == '\n')
+ ++offset;
+ }
+ return offset;
+}
+
+bool MultipartResponseDelegate::ParseHeaders() {
+ int line_feed_increment = 1;
+
+ // Grab the headers being liberal about line endings.
+ size_t line_start_pos = 0;
+ size_t line_end_pos = data_.find('\n');
+ while (line_end_pos != std::string::npos) {
+ // Handle CRLF
+ if (line_end_pos > line_start_pos && data_[line_end_pos - 1] == '\r') {
+ line_feed_increment = 2;
+ --line_end_pos;
+ } else {
+ line_feed_increment = 1;
+ }
+ if (line_start_pos == line_end_pos) {
+ // A blank line, end of headers
+ line_end_pos += line_feed_increment;
+ break;
+ }
+ // Find the next header line.
+ line_start_pos = line_end_pos + line_feed_increment;
+ line_end_pos = data_.find('\n', line_start_pos);
+ }
+ // Truncated in the middle of a header, stop parsing.
+ if (line_end_pos == std::string::npos)
+ return false;
+
+ // Eat headers
+ std::string headers("\n");
+ headers.append(data_.substr(0, line_end_pos));
+ data_ = data_.substr(line_end_pos);
+
+ // Create a ResourceResponse based on the original set of headers + the
+ // replacement headers. We only replace the same few headers that gecko
+ // does. See netwerk/streamconv/converters/nsMultiMixedConv.cpp.
+ std::string mime_type = net_util::GetSpecificHeader(headers,
+ "content-type");
+ std::string charset = net_util::GetHeaderParamValue(mime_type,
+ "charset");
+ WebCore::ResourceResponse response(original_response_.url(),
+ webkit_glue::StdStringToString(mime_type.c_str()),
+ -1,
+ charset.c_str(),
+ WebCore::String());
+ const WebCore::HTTPHeaderMap& orig_headers =
+ original_response_.httpHeaderFields();
+ for (WebCore::HTTPHeaderMap::const_iterator it = orig_headers.begin();
+ it != orig_headers.end(); ++it) {
+ if (!(equalIgnoringCase("content-type", it->first) ||
+ equalIgnoringCase("content-length", it->first) ||
+ equalIgnoringCase("content-disposition", it->first) ||
+ equalIgnoringCase("content-range", it->first) ||
+ equalIgnoringCase("range", it->first) ||
+ equalIgnoringCase("set-cookie", it->first))) {
+ response.setHTTPHeaderField(it->first, it->second);
+ }
+ }
+ static const char* replace_headers[] = {
+ "Content-Type",
+ "Content-Length",
+ "Content-Disposition",
+ "Content-Range",
+ "Range",
+ "Set-Cookie"
+ };
+ for (int i = 0; i < arraysize(replace_headers); ++i) {
+ std::string name(replace_headers[i]);
+ std::string value = net_util::GetSpecificHeader(headers, name);
+ if (!value.empty()) {
+ response.setHTTPHeaderField(webkit_glue::StdStringToString(name.c_str()),
+ webkit_glue::StdStringToString(value.c_str()));
+ }
+ }
+ // Send the response!
+ client_->didReceiveResponse(job_, response);
+
+ return true;
+}
+
+// Boundaries are supposed to be preceeded with --, but it looks like gecko
+// doesn't require the dashes to exist. See nsMultiMixedConv::FindToken.
+size_t MultipartResponseDelegate::FindBoundary() {
+ size_t boundary_pos = data_.find(boundary_);
+ if (boundary_pos != std::string::npos) {
+ // Back up over -- for backwards compat
+ // TODO(tc): Don't we only want to do this once? Gecko code doesn't seem
+ // to care.
+ if (boundary_pos >= 2) {
+ if ('-' == data_[boundary_pos - 1] && '-' == data_[boundary_pos - 2]) {
+ boundary_pos -= 2;
+ boundary_ = "--" + boundary_;
+ }
+ }
+ }
+ return boundary_pos;
+}
diff --git a/webkit/glue/multipart_response_delegate.h b/webkit/glue/multipart_response_delegate.h
new file mode 100644
index 0000000..9b7c084
--- /dev/null
+++ b/webkit/glue/multipart_response_delegate.h
@@ -0,0 +1,139 @@
+// 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 delegate class of ResourceHandleInternal (resource_handle_win) that
+// handles multipart/x-mixed-replace data. We special case
+// multipart/x-mixed-replace because WebCore expects a separate
+// didReceiveResponse for each new message part.
+//
+// Most of the logic and edge case handling are based on the Mozilla's
+// implementation in netwerk/streamconv/converters/nsMultiMixedConv.cpp.
+// This seems like a derivative work, so here's the original license:
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <string>
+
+#include "config.h"
+#pragma warning(push, 0)
+#include "ResourceResponse.h"
+#pragma warning(pop)
+
+namespace WebCore {
+ class ResourceHandle;
+ class ResourceHandleClient;
+}
+
+class MultipartResponseDelegate {
+ friend class MultipartResponseTest_Functions_Test; // For unittests.
+
+ public:
+ MultipartResponseDelegate(WebCore::ResourceHandleClient* client,
+ WebCore::ResourceHandle* job,
+ const WebCore::ResourceResponse& response,
+ const std::string& boundary);
+
+ // Passed through from ResourceHandleInternal
+ void OnReceivedData(const char* data, int data_len);
+ void OnCompletedRequest();
+
+ private:
+ // Pointers back to our owning object so we can make callbacks as we parse
+ // pieces of data.
+ WebCore::ResourceHandleClient* client_;
+ WebCore::ResourceHandle* job_;
+
+ // The original resource response for this request. We use this as a
+ // starting point for each parts response.
+ WebCore::ResourceResponse original_response_;
+
+ // Checks to see if data[pos] character is a line break; handles crlf, lflf,
+ // lf, or cr. Returns the number of characters to skip over (0, 1 or 2).
+ int PushOverLine(const std::string& data, size_t pos);
+
+ // Tries to parse http headers from the start of data_. Returns true if it
+ // succeeds and sends a didReceiveResponse to m_client. Returns false if
+ // the header is incomplete (in which case we just wait for more data).
+ bool ParseHeaders();
+
+ // Find the next boundary in data_. Returns std::string::npos if there's no
+ // full token.
+ size_t FindBoundary();
+
+ // A temporary buffer to hold data between reads for multipart data that
+ // gets split in the middle of a header.
+ std::string data_;
+
+ // Multipart boundary token
+ std::string boundary_;
+
+ // true until we get our first on received data call
+ bool first_received_data_;
+
+ // true if we're truncated in the middle of a header
+ bool processing_headers_;
+
+ // true when we're done sending information. At that point, we stop
+ // processing AddData requests.
+ bool stop_sending_;
+};
diff --git a/webkit/glue/multipart_response_delegate_unittest.cc b/webkit/glue/multipart_response_delegate_unittest.cc
new file mode 100644
index 0000000..d810dc0
--- /dev/null
+++ b/webkit/glue/multipart_response_delegate_unittest.cc
@@ -0,0 +1,401 @@
+// 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 <vector>
+
+#include "config.h"
+
+#pragma warning(push, 0)
+#include "KURL.h"
+#include "ResourceResponse.h"
+#include "ResourceHandle.h"
+#include "ResourceHandleClient.h"
+#include "String.h"
+#pragma warning(pop)
+
+#include "base/basictypes.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/multipart_response_delegate.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using namespace WebCore;
+using namespace std;
+
+namespace {
+
+class MultipartResponseTest : public testing::Test {
+};
+
+class MockResourceHandleClient : public ResourceHandleClient {
+ public:
+ MockResourceHandleClient() { Reset(); }
+
+ virtual void didReceiveResponse(ResourceHandle* handle,
+ const ResourceResponse& response) {
+ ++received_response_;
+ resource_response_ = response;
+ data_.clear();
+ }
+ virtual void didReceiveData(ResourceHandle* handle,
+ const char* data, int data_length,
+ int length_received) {
+ ++received_data_;
+ data_.append(data, data_length);
+ }
+
+ void Reset() {
+ received_response_ = received_data_ = 0;
+ data_.clear();
+ resource_response_ = ResourceResponse();
+ }
+
+ int received_response_, received_data_;
+ string data_;
+ ResourceResponse resource_response_;
+};
+
+} // namespace
+
+// We can't put this in an anonymous function because it's a friend class for
+// access to private members.
+TEST(MultipartResponseTest, Functions) {
+ // PushOverLine tests
+
+ ResourceResponse response(KURL(), "multipart/x-mixed-replace", 0, "en-US",
+ String());
+ response.setHTTPHeaderField(String("Foo"), String("Bar"));
+ response.setHTTPHeaderField(String("Content-type"), String("text/plain"));
+ MockResourceHandleClient client;
+ MultipartResponseDelegate delegate(&client, NULL, response, "bound");
+
+ struct {
+ const char* input;
+ const int position;
+ const int expected;
+ } line_tests[] = {
+ { "Line", 0, 0 },
+ { "Line", 2, 0 },
+ { "Line", 10, 0 },
+ { "\r\nLine", 0, 2 },
+ { "\nLine", 0, 1 },
+ { "\n\nLine", 0, 2 },
+ { "\rLine", 0, 1 },
+ { "Line\r\nLine", 4, 2 },
+ { "Line\nLine", 4, 1 },
+ { "Line\n\nLine", 4, 2 },
+ { "Line\rLine", 4, 1 },
+ { "Line\r\rLine", 4, 1 },
+ };
+ for (int i = 0; i < arraysize(line_tests); ++i) {
+ EXPECT_EQ(line_tests[i].expected,
+ delegate.PushOverLine(line_tests[i].input,
+ line_tests[i].position));
+ }
+
+ // ParseHeaders tests
+ struct {
+ const char* data;
+ const bool rv;
+ const int received_response_calls;
+ const char* newdata;
+ } header_tests[] = {
+ { "This is junk", false, 0, "This is junk" },
+ { "Foo: bar\nBaz:\n\nAfter:\n", true, 1, "After:\n" },
+ { "Foo: bar\nBaz:\n", false, 0, "Foo: bar\nBaz:\n" },
+ { "Foo: bar\r\nBaz:\r\n\r\nAfter:\r\n", true, 1, "After:\r\n" },
+ { "Foo: bar\r\nBaz:\r\n", false, 0, "Foo: bar\r\nBaz:\r\n" },
+ { "Foo: bar\nBaz:\r\n\r\nAfter:\n\n", true, 1, "After:\n\n" },
+ { "Foo: bar\r\nBaz:\n", false, 0, "Foo: bar\r\nBaz:\n" },
+ { "\r\n", true, 1, "" },
+ };
+ for (int i = 0; i < arraysize(header_tests); ++i) {
+ client.Reset();
+ delegate.data_.assign(header_tests[i].data);
+ EXPECT_EQ(header_tests[i].rv,
+ delegate.ParseHeaders());
+ EXPECT_EQ(header_tests[i].received_response_calls,
+ client.received_response_);
+ EXPECT_EQ(string(header_tests[i].newdata),
+ delegate.data_);
+ }
+ // Test that the resource response is filled in correctly when parsing
+ // headers.
+ client.Reset();
+ string test_header("content-type: image/png\ncontent-length: 10\n\n");
+ delegate.data_.assign(test_header);
+ EXPECT_TRUE(delegate.ParseHeaders());
+ EXPECT_TRUE(delegate.data_.length() == 0);
+ EXPECT_EQ(webkit_glue::StringToStdWString(
+ client.resource_response_.httpHeaderField(
+ String("Content-Type"))),
+ wstring(L"image/png"));
+ EXPECT_EQ(webkit_glue::StringToStdWString(
+ client.resource_response_.httpHeaderField(
+ String("content-length"))),
+ wstring(L"10"));
+ // This header is passed from the original request.
+ EXPECT_EQ(webkit_glue::StringToStdWString(
+ client.resource_response_.httpHeaderField(String("foo"))),
+ wstring(L"Bar"));
+
+ // FindBoundary tests
+ struct {
+ const char* boundary;
+ const char* data;
+ const size_t position;
+ } boundary_tests[] = {
+ { "bound", "bound", 0 },
+ { "bound", "--bound", 0 },
+ { "bound", "junkbound", 4 },
+ { "bound", "junk--bound", 4 },
+ { "foo", "bound", string::npos },
+ { "bound", "--boundbound", 0 },
+ };
+ for (int i = 0; i < arraysize(boundary_tests); ++i) {
+ delegate.boundary_.assign(boundary_tests[i].boundary);
+ delegate.data_.assign(boundary_tests[i].data);
+ EXPECT_EQ(boundary_tests[i].position,
+ delegate.FindBoundary());
+ }
+}
+
+namespace {
+
+TEST(MultipartResponseTest, MissingBoundaries) {
+ ResourceResponse response(KURL(), "multipart/x-mixed-replace", 0, "en-US",
+ String());
+ response.setHTTPHeaderField(String("Foo"), String("Bar"));
+ response.setHTTPHeaderField(String("Content-type"), String("text/plain"));
+ MockResourceHandleClient client;
+ MultipartResponseDelegate delegate(&client, NULL, response, "bound");
+
+ // No start boundary
+ string no_start_boundary(
+ "Content-type: text/plain\n\n"
+ "This is a sample response\n"
+ "--bound--"
+ "ignore junk after end token --bound\n\nTest2\n");
+ delegate.OnReceivedData(no_start_boundary.c_str(),
+ static_cast<int>(no_start_boundary.length()));
+ EXPECT_EQ(1, client.received_response_);
+ EXPECT_EQ(1, client.received_data_);
+ EXPECT_EQ(string("This is a sample response\n"),
+ client.data_);
+
+ delegate.OnCompletedRequest();
+ EXPECT_EQ(1, client.received_response_);
+ EXPECT_EQ(1, client.received_data_);
+
+ // No end boundary
+ client.Reset();
+ MultipartResponseDelegate delegate2(&client, NULL, response, "bound");
+ string no_end_boundary(
+ "bound\nContent-type: text/plain\n\n"
+ "This is a sample response\n");
+ delegate2.OnReceivedData(no_end_boundary.c_str(),
+ static_cast<int>(no_end_boundary.length()));
+ EXPECT_EQ(1, client.received_response_);
+ EXPECT_EQ(0, client.received_data_);
+ EXPECT_EQ(string(), client.data_);
+
+ delegate2.OnCompletedRequest();
+ EXPECT_EQ(1, client.received_response_);
+ EXPECT_EQ(1, client.received_data_);
+ EXPECT_EQ(string("This is a sample response\n"),
+ client.data_);
+
+ // Neither boundary
+ client.Reset();
+ MultipartResponseDelegate delegate3(&client, NULL, response, "bound");
+ string no_boundaries(
+ "Content-type: text/plain\n\n"
+ "This is a sample response\n");
+ delegate3.OnReceivedData(no_boundaries.c_str(),
+ static_cast<int>(no_boundaries.length()));
+ EXPECT_EQ(1, client.received_response_);
+ EXPECT_EQ(0, client.received_data_);
+ EXPECT_EQ(string(), client.data_);
+
+ delegate3.OnCompletedRequest();
+ EXPECT_EQ(1, client.received_response_);
+ EXPECT_EQ(1, client.received_data_);
+ EXPECT_EQ(string("This is a sample response\n"),
+ client.data_);
+}
+
+
+// Used in for tests that break the data in various places.
+struct TestChunk {
+ const int start_pos; // offset in data
+ const int end_pos; // end offset in data
+ const int expected_responses;
+ const int expected_received_data;
+ const char* expected_data;
+};
+
+void VariousChunkSizesTest(const TestChunk chunks[], int chunks_size, int responses,
+ int received_data, const char* completed_data) {
+ const string data(
+ "--bound\n" // 0-7
+ "Content-type: image/png\n\n" // 8-32
+ "datadatadatadatadata" // 33-52
+ "--bound\n" // 53-60
+ "Content-type: image/jpg\n\n" // 61-85
+ "foofoofoofoofoo" // 86-100
+ "--bound--"); // 101-109
+
+ ResourceResponse response(KURL(), "multipart/x-mixed-replace", 0, "en-US",
+ String());
+ MockResourceHandleClient client;
+ MultipartResponseDelegate delegate(&client, NULL, response, "bound");
+
+ for (int i = 0; i < chunks_size; ++i) {
+ ASSERT(chunks[i].start_pos < chunks[i].end_pos);
+ string chunk = data.substr(chunks[i].start_pos,
+ chunks[i].end_pos - chunks[i].start_pos);
+ delegate.OnReceivedData(chunk.c_str(), static_cast<int>(chunk.length()));
+ EXPECT_EQ(chunks[i].expected_responses,
+ client.received_response_);
+ EXPECT_EQ(chunks[i].expected_received_data,
+ client.received_data_);
+ EXPECT_EQ(string(chunks[i].expected_data),
+ client.data_);
+ }
+ // Check final state
+ delegate.OnCompletedRequest();
+ EXPECT_EQ(responses,
+ client.received_response_);
+ EXPECT_EQ(received_data,
+ client.received_data_);
+ EXPECT_EQ(string(completed_data),
+ client.data_);
+}
+
+TEST(MultipartResponseTest, BreakInBoundary) {
+ // Break in the first boundary
+ const TestChunk bound1[] = {
+ { 0, 4, 0, 0, ""},
+ { 4, 110, 2, 2, "foofoofoofoofoo" },
+ };
+ VariousChunkSizesTest(bound1, arraysize(bound1),
+ 2, 2, "foofoofoofoofoo");
+
+ // Break in first and second
+ const TestChunk bound2[] = {
+ { 0, 4, 0, 0, ""},
+ { 4, 55, 1, 0, "" },
+ { 55, 65, 1, 1, "datadatadatadatadata" },
+ { 65, 110, 2, 2, "foofoofoofoofoo" },
+ };
+ VariousChunkSizesTest(bound2, arraysize(bound2),
+ 2, 2, "foofoofoofoofoo");
+
+ // Break in second only
+ const TestChunk bound3[] = {
+ { 0, 55, 1, 0, "" },
+ { 55, 110, 2, 2, "foofoofoofoofoo" },
+ };
+ VariousChunkSizesTest(bound3, arraysize(bound3),
+ 2, 2, "foofoofoofoofoo");
+}
+
+TEST(MultipartResponseTest, BreakInHeaders) {
+ // Break in first header
+ const TestChunk header1[] = {
+ { 0, 10, 0, 0, "" },
+ { 10, 35, 1, 0, "" },
+ { 35, 110, 2, 2, "foofoofoofoofoo" },
+ };
+ VariousChunkSizesTest(header1, arraysize(header1),
+ 2, 2, "foofoofoofoofoo");
+
+ // Break in both headers
+ const TestChunk header2[] = {
+ { 0, 10, 0, 0, "" },
+ { 10, 65, 1, 1, "datadatadatadatadata" },
+ { 65, 110, 2, 2, "foofoofoofoofoo" },
+ };
+ VariousChunkSizesTest(header2, arraysize(header2),
+ 2, 2, "foofoofoofoofoo");
+
+ // Break at end of a header
+ const TestChunk header3[] = {
+ { 0, 33, 1, 0, "" },
+ { 33, 65, 1, 1, "datadatadatadatadata" },
+ { 65, 110, 2, 2, "foofoofoofoofoo" },
+ };
+ VariousChunkSizesTest(header3, arraysize(header3),
+ 2, 2, "foofoofoofoofoo");
+}
+
+TEST(MultipartResponseTest, BreakInData) {
+ // All data as one chunk
+ const TestChunk data1[] = {
+ { 0, 110, 2, 2, "foofoofoofoofoo" },
+ };
+ VariousChunkSizesTest(data1, arraysize(data1),
+ 2, 2, "foofoofoofoofoo");
+
+ // breaks in data segment
+ const TestChunk data2[] = {
+ { 0, 35, 1, 0, "" },
+ { 35, 65, 1, 1, "datadatadatadatadata" },
+ { 65, 90, 2, 1, "" },
+ { 90, 110, 2, 2, "foofoofoofoofoo" },
+ };
+ VariousChunkSizesTest(data2, arraysize(data2),
+ 2, 2, "foofoofoofoofoo");
+
+ // Incomplete send
+ const TestChunk data3[] = {
+ { 0, 35, 1, 0, "" },
+ { 35, 90, 2, 1, "" },
+ };
+ VariousChunkSizesTest(data3, arraysize(data3),
+ 2, 2, "foof");
+}
+
+TEST(MultipartResponseTest, MultipleBoundaries) {
+ // Test multiple boundaries back to back
+ ResourceResponse response(KURL(), "multipart/x-mixed-replace", 0, "en-US",
+ String());
+ MockResourceHandleClient client;
+ MultipartResponseDelegate delegate(&client, NULL, response, "bound");
+
+ string data("--bound\r\n\r\n--bound\r\n\r\nfoofoo--bound--");
+ delegate.OnReceivedData(data.c_str(), static_cast<int>(data.length()));
+ EXPECT_EQ(2,
+ client.received_response_);
+ EXPECT_EQ(1,
+ client.received_data_);
+ EXPECT_EQ(string("foofoo"),
+ client.data_);
+}
+
+} // namespace
diff --git a/webkit/glue/password_autocomplete_listener.cc b/webkit/glue/password_autocomplete_listener.cc
new file mode 100644
index 0000000..7270618
--- /dev/null
+++ b/webkit/glue/password_autocomplete_listener.cc
@@ -0,0 +1,110 @@
+// 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 implementaiton of the password manager's autocomplete
+// component.
+
+#include "webkit/glue/password_autocomplete_listener.h"
+#include "base/logging.h"
+
+namespace webkit_glue {
+
+PasswordAutocompleteListener::PasswordAutocompleteListener(
+ AutocompleteEditDelegate* username_delegate,
+ HTMLInputDelegate* password_delegate,
+ const PasswordFormDomManager::FillData& data)
+ : AutocompleteInputListener(username_delegate),
+ password_delegate_(password_delegate),
+ data_(data) {
+}
+
+void PasswordAutocompleteListener::OnBlur(const std::wstring& user_input) {
+ // If this listener exists, its because the password manager had more than
+ // one match for the password form, which implies it had at least one
+ // [preferred] username/password pair.
+ DCHECK(data_.basic_data.values.size() == 2);
+
+ // Set the password field to match the current username.
+ if (data_.basic_data.values[0] == user_input) {
+ // Preferred username/login is selected.
+ password_delegate_->SetValue(data_.basic_data.values[1]);
+ } else if (data_.additional_logins.find(user_input) !=
+ data_.additional_logins.end()) {
+ // One of the extra username/logins is selected.
+ password_delegate_->SetValue(data_.additional_logins[user_input]);
+ }
+ password_delegate_->OnFinishedAutocompleting();
+}
+
+void PasswordAutocompleteListener::OnInlineAutocompleteNeeded(
+ const std::wstring& user_input) {
+ // If wait_for_username is true, we only autofill the password when
+ // the username field is blurred (i.e not inline) with a matching
+ // username string entered.
+ if (data_.wait_for_username)
+ return;
+ // Look for any suitable matches to current field text.
+ // TODO(timsteele): The preferred login (in basic_data.values) and
+ // additional logins could be bundled into the same data structure
+ // (possibly even as WebCore strings) upon construction of the
+ // PasswordAutocompleteListener to simplify lookup and save string
+ // conversions (see SetValue) on each successful call to
+ // OnInlineAutocompleteNeeded.
+ if (TryToMatch(user_input,
+ data_.basic_data.values[0],
+ data_.basic_data.values[1])) {
+ return;
+ }
+
+ // Scan additional logins for a match.
+ for (PasswordFormDomManager::LoginCollection::iterator it =
+ data_.additional_logins.begin();
+ it != data_.additional_logins.end();
+ ++it) {
+ if (TryToMatch(user_input, it->first, it->second))
+ return;
+ }
+}
+
+bool PasswordAutocompleteListener::TryToMatch(const std::wstring& input,
+ const std::wstring& username,
+ const std::wstring& password) {
+ if (input.compare(0, input.length(), username, 0, input.length()) != 0)
+ return false;
+
+ // Input matches the username, fill in required values.
+ edit_delegate()->SetValue(username);
+ edit_delegate()->SetSelectionRange(input.length(), username.length());
+ edit_delegate()->OnFinishedAutocompleting();
+ password_delegate_->SetValue(password);
+ password_delegate_->OnFinishedAutocompleting();
+ return true;
+}
+
+} // webkit_glue
diff --git a/webkit/glue/password_autocomplete_listener.h b/webkit/glue/password_autocomplete_listener.h
new file mode 100644
index 0000000..9ee51c0
--- /dev/null
+++ b/webkit/glue/password_autocomplete_listener.h
@@ -0,0 +1,73 @@
+// 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 concrete definition of the DOM autocomplete framework defined by
+// autocomplete_input_listener.h, for the password manager.
+
+#ifndef WEBKIT_GLUE_PASSWORD_AUTOCOMPLETE_LISTENER_H__
+#define WEBKIT_GLUE_PASSWORD_AUTOCOMPLETE_LISTENER_H__
+
+#include "base/basictypes.h"
+#include "webkit/glue/autocomplete_input_listener.h"
+#include "webkit/glue/password_form_dom_manager.h"
+
+namespace webkit_glue {
+
+class PasswordAutocompleteListener : public AutocompleteInputListener {
+ public:
+ PasswordAutocompleteListener(AutocompleteEditDelegate* username_delegate,
+ HTMLInputDelegate* password_delegate,
+ const PasswordFormDomManager::FillData& data);
+ virtual ~PasswordAutocompleteListener() {
+ }
+
+ // AutocompleteInputListener implementation.
+ virtual void OnBlur(const std::wstring& user_input);
+ virtual void OnInlineAutocompleteNeeded(const std::wstring& user_input);
+
+ private:
+ // Check if the input string resembles a potential matching login
+ // (username/password) and if so, match them up by autocompleting
+ // the edit delegates.
+ bool TryToMatch(const std::wstring& input,
+ const std::wstring& username,
+ const std::wstring& password);
+
+ // Access to password field to autocomplete on blur/username updates.
+ scoped_ptr<HTMLInputDelegate> password_delegate_;
+
+ // Contains the extra logins for matching on delta/blur.
+ PasswordFormDomManager::FillData data_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(PasswordAutocompleteListener);
+};
+
+} // webkit_glue
+
+#endif // WEBKIT_GLUE_PASSWORD_AUTOCOMPLETE_LISTENER_H__
diff --git a/webkit/glue/password_autocomplete_listener_unittest.cc b/webkit/glue/password_autocomplete_listener_unittest.cc
new file mode 100644
index 0000000..4929f25
--- /dev/null
+++ b/webkit/glue/password_autocomplete_listener_unittest.cc
@@ -0,0 +1,274 @@
+// 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.
+//
+// The PasswordManagerAutocompleteTests in this file test only the
+// PasswordAutocompleteListener class implementation (and not any of the
+// higher level dom autocomplete framework).
+
+#include <string>
+#include "config.h"
+#pragma warning(push, 0)
+#include "HTMLInputElement.h"
+#include "HTMLFormElement.h"
+#include "Document.h"
+#include "Frame.h"
+#include "Editor.h"
+#include "EventNames.h"
+#include "Event.h"
+#include "EventListener.h"
+#pragma warning(pop)
+
+#undef LOG
+
+#include "webkit/glue/autocomplete_input_listener.h"
+#include "webkit/glue/password_autocomplete_listener.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using webkit_glue::AutocompleteInputListener;
+using webkit_glue::PasswordAutocompleteListener;
+using webkit_glue::AutocompleteEditDelegate;
+using webkit_glue::HTMLInputDelegate;
+
+class TestHTMLInputDelegate : public HTMLInputDelegate {
+ public:
+ TestHTMLInputDelegate() : did_call_on_finish_(false),
+ did_set_value_(false),
+ did_set_selection_(false),
+ selection_start_(0),
+ selection_end_(0),
+ HTMLInputDelegate(NULL) {
+ }
+
+ // Override those methods we implicitly invoke in the tests.
+ virtual std::wstring GetValue() const {
+ return value_;
+ }
+
+ virtual void SetValue(const std::wstring& value) {
+ value_ = value;
+ did_set_value_ = true;
+ }
+
+ virtual void OnFinishedAutocompleting() {
+ did_call_on_finish_ = true;
+ }
+
+ virtual void SetSelectionRange(size_t start, size_t end) {
+ selection_start_ = start;
+ selection_end_ = end;
+ did_set_selection_ = true;
+ }
+
+ // Testing-only methods.
+ void ResetTestState() {
+ did_call_on_finish_ = false;
+ did_set_value_ = false;
+ did_set_selection_ = false;
+ }
+
+ bool did_call_on_finish() const {
+ return did_call_on_finish_;
+ }
+
+ bool did_set_value() const {
+ return did_set_value_;
+ }
+
+ bool did_set_selection() const {
+ return did_set_selection_;
+ }
+
+ size_t selection_start() const {
+ return selection_start_;
+ }
+
+ size_t selection_end() const {
+ return selection_end_;
+ }
+
+ private:
+ bool did_call_on_finish_;
+ bool did_set_value_;
+ bool did_set_selection_;
+ std::wstring value_;
+ size_t selection_start_;
+ size_t selection_end_;
+};
+
+namespace {
+class PasswordManagerAutocompleteTests : public testing::Test {
+ public:
+ virtual void SetUp() {
+ // Add a preferred login and an additional login to the FillData.
+ username1_ = L"alice";
+ password1_ = L"password";
+ username2_ = L"bob";
+ password2_ = L"bobsyouruncle";
+ data_.basic_data.values.push_back(username1_);
+ data_.basic_data.values.push_back(password1_);
+ data_.additional_logins[username2_] = password2_;
+ testing::Test::SetUp();
+ }
+
+ std::wstring username1_;
+ std::wstring password1_;
+ std::wstring username2_;
+ std::wstring password2_;
+ PasswordFormDomManager::FillData data_;
+};
+} // namespace
+
+TEST_F(PasswordManagerAutocompleteTests, OnBlur) {
+ TestHTMLInputDelegate* username_delegate = new TestHTMLInputDelegate();
+ TestHTMLInputDelegate* password_delegate = new TestHTMLInputDelegate();
+
+ PasswordAutocompleteListener* listener = new PasswordAutocompleteListener(
+ username_delegate, password_delegate, data_);
+
+ // Clear the password field.
+ password_delegate->SetValue(std::wstring());
+ // Simulate a blur event on the username field and expect a password autofill.
+ listener->OnBlur(username1_);
+ EXPECT_EQ(password1_, password_delegate->GetValue());
+
+ // Now the user goes back and changes the username to something we don't
+ // have saved. The password should remain unchanged.
+ listener->OnBlur(L"blahblahblah");
+ EXPECT_EQ(password1_, password_delegate->GetValue());
+
+ // Now they type in the additional login username.
+ listener->OnBlur(username2_);
+ EXPECT_EQ(password2_, password_delegate->GetValue());
+
+ // Now they submit and the listener is destroyed.
+ delete listener;
+}
+
+TEST_F(PasswordManagerAutocompleteTests, OnInlineAutocompleteNeeded) {
+ TestHTMLInputDelegate* username_delegate = new TestHTMLInputDelegate();
+ TestHTMLInputDelegate* password_delegate = new TestHTMLInputDelegate();
+
+ PasswordAutocompleteListener* listener = new PasswordAutocompleteListener(
+ username_delegate, password_delegate, data_);
+
+ password_delegate->SetValue(std::wstring());
+ // Simulate the user typing in the first letter of 'alice', a stored username.
+ listener->OnInlineAutocompleteNeeded(L"a");
+ // Both the username and password delegates should reflect selection
+ // of the stored login.
+ EXPECT_EQ(username1_, username_delegate->GetValue());
+ EXPECT_EQ(password1_, password_delegate->GetValue());
+ // And the selection should have been set to 'lice', the last 4 letters.
+ EXPECT_EQ(1, username_delegate->selection_start());
+ EXPECT_EQ(username1_.length(), username_delegate->selection_end());
+ // And both fields should have observed OnFinishedAutocompleting.
+ EXPECT_TRUE(username_delegate->did_call_on_finish());
+ EXPECT_TRUE(password_delegate->did_call_on_finish());
+
+ // Now the user types the next letter of the same username, 'l'.
+ listener->OnInlineAutocompleteNeeded(L"al");
+ // Now the fields should have the same value, but the selection should have a
+ // different start value.
+ EXPECT_EQ(username1_, username_delegate->GetValue());
+ EXPECT_EQ(password1_, password_delegate->GetValue());
+ EXPECT_EQ(2, username_delegate->selection_start());
+ EXPECT_EQ(username1_.length(), username_delegate->selection_end());
+
+ // Now lets say the user goes astray from the stored username and types
+ // the letter 'f', spelling 'alf'. We don't know alf (that's just sad),
+ // so in practice the username should no longer be 'alice' and the selected
+ // range should be empty. In our case, when the autocomplete code doesn't
+ // know the text, it won't set the value or the selection and hence our
+ // delegate methods won't get called. The WebCore::HTMLInputElement's value
+ // and selection would be set directly by WebCore in practice.
+
+ // Reset the delegate's test state so we can determine what, if anything,
+ // was invoked during OnInlineAutocompleteNeeded.
+ username_delegate->ResetTestState();
+ password_delegate->ResetTestState();
+ listener->OnInlineAutocompleteNeeded(L"alf");
+ EXPECT_FALSE(username_delegate->did_set_selection());
+ EXPECT_FALSE(username_delegate->did_set_value());
+ EXPECT_FALSE(username_delegate->did_call_on_finish());
+ EXPECT_FALSE(password_delegate->did_set_value());
+ EXPECT_FALSE(password_delegate->did_call_on_finish());
+
+ // Ok, so now the user removes all the text and enters the letter 'b'.
+ listener->OnInlineAutocompleteNeeded(L"b");
+ // The username and password fields should match the 'bob' entry.
+ EXPECT_EQ(username2_, username_delegate->GetValue());
+ EXPECT_EQ(password2_, password_delegate->GetValue());
+ EXPECT_EQ(1, username_delegate->selection_start());
+ EXPECT_EQ(username2_.length(), username_delegate->selection_end());
+
+ // The End.
+ delete listener;
+}
+
+TEST_F(PasswordManagerAutocompleteTests, TestWaitUsername) {
+ TestHTMLInputDelegate* username_delegate = new TestHTMLInputDelegate();
+ TestHTMLInputDelegate* password_delegate = new TestHTMLInputDelegate();
+
+ // If we had an action authority mismatch (for example), we don't want to
+ // automatically autofill anything without some user interaction first.
+ // We require an explicit blur on the username field, and that a valid
+ // matching username is in the field, before we autofill passwords.
+ data_.wait_for_username = true;
+ PasswordAutocompleteListener* listener = new PasswordAutocompleteListener(
+ username_delegate, password_delegate, data_);
+
+ std::wstring empty;
+ // In all cases, username_delegate should remain empty because we should
+ // never modify it when wait_for_username is true; only the user can by
+ // typing into (in real life) the HTMLInputElement.
+ password_delegate->SetValue(std::wstring());
+ listener->OnInlineAutocompleteNeeded(L"a");
+ EXPECT_EQ(empty, username_delegate->GetValue());
+ EXPECT_EQ(empty, password_delegate->GetValue());
+ listener->OnInlineAutocompleteNeeded(L"al");
+ EXPECT_EQ(empty, username_delegate->GetValue());
+ EXPECT_EQ(empty, password_delegate->GetValue());
+ listener->OnInlineAutocompleteNeeded(L"alice");
+ EXPECT_EQ(empty, username_delegate->GetValue());
+ EXPECT_EQ(empty, password_delegate->GetValue());
+
+ listener->OnBlur(L"a");
+ EXPECT_EQ(empty, username_delegate->GetValue());
+ EXPECT_EQ(empty, password_delegate->GetValue());
+ listener->OnBlur(L"ali");
+ EXPECT_EQ(empty, username_delegate->GetValue());
+ EXPECT_EQ(empty, password_delegate->GetValue());
+
+ // Blur with 'alice' should allow password autofill.
+ listener->OnBlur(L"alice");
+ EXPECT_EQ(empty, username_delegate->GetValue());
+ EXPECT_EQ(password1_, password_delegate->GetValue());
+
+ delete listener;
+}
diff --git a/webkit/glue/password_form.h b/webkit/glue/password_form.h
new file mode 100644
index 0000000..cae102c
--- /dev/null
+++ b/webkit/glue/password_form.h
@@ -0,0 +1,171 @@
+// 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 WEBKIT_GLUE_PASSWORD_FORM_H__
+#define WEBKIT_GLUE_PASSWORD_FORM_H__
+
+#include <string>
+#include <map>
+
+#include "base/time.h"
+#include "googleurl/src/gurl.h"
+
+// The PasswordForm struct encapsulates information about a login form,
+// which can be an HTML form or a dialog with username/password text fields.
+//
+// The Web Data database stores saved username/passwords and associated form
+// metdata using a PasswordForm struct, typically one that was created from
+// a parsed HTMLFormElement or LoginDialog, but the saved entries could have
+// also been created by imported data from another browser.
+//
+// The PasswordManager implements a fuzzy-matching algorithm to compare saved
+// PasswordForm entries against PasswordForms that were created from a parsed
+// HTML or dialog form. As one might expect, the more data contained in one
+// of the saved PasswordForms, the better the job the PasswordManager can do
+// in matching it against the actual form it was saved on, and autofill
+// accurately. But it is not always possible, especially when importing from
+// other browsers with different data models, to copy over all the information
+// about a particular "saved password entry" to our PasswordForm
+// representation.
+//
+// The field descriptions in the struct specification below are
+// intended to describe which fields are not strictly required when adding a saved
+// password entry to the database and how they can affect the matching process.
+
+struct PasswordForm {
+ // Enum to differentiate between HTML form based authentication, and dialogs
+ // using basic or digest schemes. Default is SCHEME_HTML. Only PasswordForms
+ // of the same Scheme will be matched/autofilled against each other.
+ enum Scheme {
+ SCHEME_HTML,
+ SCHEME_BASIC,
+ SCHEME_DIGEST,
+ SCHEME_OTHER
+ } scheme;
+
+ // The "Realm" for the sign-on (scheme, host, port for SCHEME_HTML, and
+ // contains the HTTP realm for dialog-based forms).
+ // The signon_realm is effectively the primary key used for retrieving
+ // data from the database, so it must not be empty.
+ std::string signon_realm;
+
+ // The URL (minus query parameters) containing the form. This is the primary
+ // data used by the PasswordManager to decide (in longest matching prefix
+ // fashion) whether or not a given PasswordForm result from the database is a
+ // good fit for a particular form on a page, so it must not be empty.
+ GURL origin;
+
+ // The action target of the form. This is the primary data used by the
+ // PasswordManager for form autofill; that is, the action of the saved
+ // credentials must match the action of the form on the page to be autofilled.
+ // If this is empty / not available, it will result in a "restricted"
+ // IE-like autofill policy, where we wait for the user to type in his
+ // username before autofilling the password. In these cases, after successful
+ // login the action URL will automatically be assigned by the
+ // PasswordManager.
+ //
+ // When parsing an HTML form, this must always be set.
+ GURL action;
+
+ // The name of the submit button used. Optional; only used in scoring
+ // of PasswordForm results from the database to make matches as tight as
+ // possible.
+ //
+ // When parsing an HTML form, this must always be set.
+ std::wstring submit_element;
+
+ // The name of the username input element. Optional (improves scoring).
+ //
+ // When parsing an HTML form, this must always be set.
+ std::wstring username_element;
+
+ // The username. Optional.
+ //
+ // When parsing an HTML form, this is typically empty unless the site
+ // has implemented some form of autofill.
+ std::wstring username_value;
+
+ // The name of the password input element, Optional (improves scoring).
+ //
+ // When parsing an HTML form, this must always be set.
+ std::wstring password_element;
+
+ // The password. Required.
+ //
+ // When parsing an HTML form, this is typically empty.
+ std::wstring password_value;
+
+ // If the form was a change password form, the name of the
+ // 'old password' input element. Optional.
+ std::wstring old_password_element;
+
+ // The old password. Optional.
+ std::wstring old_password_value;
+
+ // Whether or not this login was saved under an HTTPS session with a valid
+ // SSL cert. We will never match or autofill a PasswordForm where
+ // ssl_valid == true with a PasswordForm where ssl_valid == false. This means
+ // passwords saved under HTTPS will never get autofilled onto an HTTP page.
+ // When importing, this should be set to true if the page URL is HTTPS, thus
+ // giving it "the benefit of the doubt" that the SSL cert was valid when it
+ // was saved. Default to false.
+ bool ssl_valid;
+
+ // True if this PasswordForm represents the last username/password login the
+ // user selected to log in to the site. If there is only one saved entry for
+ // the site, this will always be true, but when there are multiple entries
+ // the PasswordManager ensures that only one of them has a preferred bit set
+ // to true. Default to false.
+ //
+ // When parsing an HTML form, this is not used.
+ bool preferred;
+
+ // When the login was saved (by chrome).
+ //
+ // When parsing an HTML form, this is not used.
+ Time date_created;
+
+ // Tracks if the user opted to never remember passwords for this form. Default
+ // to false.
+ //
+ // When parsing an HTML form, this is not used.
+ bool blacklisted_by_user;
+
+ PasswordForm()
+ : scheme(SCHEME_HTML),
+ ssl_valid(false),
+ preferred(false),
+ blacklisted_by_user(false) {
+ }
+};
+
+// Map username to PasswordForm* for convenience. See password_form_manager.h.
+typedef std::map<std::wstring, PasswordForm*> PasswordFormMap;
+
+#endif // WEBKIT_GLUE_PASSWORD_FORM_H__
diff --git a/webkit/glue/password_form_dom_manager.cc b/webkit/glue/password_form_dom_manager.cc
new file mode 100644
index 0000000..0a3ed7c
--- /dev/null
+++ b/webkit/glue/password_form_dom_manager.cc
@@ -0,0 +1,302 @@
+// 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 "config.h"
+
+#pragma warning(push, 0)
+#include "csshelper.h"
+#include "Document.h"
+#include "DocumentLoader.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "HTMLFormElement.h"
+#include "HTMLInputElement.h"
+#include "HTMLNames.h"
+#include "KURL.h"
+#pragma warning(pop)
+
+#undef LOG
+
+#include "base/logging.h"
+#include "base/basictypes.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/password_form_dom_manager.h"
+
+// Maximum number of password fields we will observe before throwing our
+// hands in the air and giving up with a given form.
+static const int kMaxPasswords = 3;
+
+PasswordForm* PasswordFormDomManager::CreatePasswordForm(
+ WebCore::HTMLFormElement* form) {
+ WebCore::Frame* frame = form->document()->frame();
+ if (frame == NULL)
+ return NULL;
+
+ WebCore::FrameLoader* loader = frame->loader();
+ if (loader == NULL)
+ return NULL;
+
+ PasswordFormFields fields;
+ FindPasswordFormFields(form, &fields);
+
+ // Get the document URL
+ WebCore::String origin_string = form->document()->documentURI();
+ GURL full_origin(webkit_glue::StringToStdWString(origin_string));
+
+ // Calculate the canonical action URL
+ GURL full_action(webkit_glue::KURLToGURL(loader->completeURL(form->action())));
+ if (!full_action.is_valid())
+ return NULL;
+
+ // Determine the types of the password fields
+ WebCore::HTMLInputElement* password = NULL;
+ WebCore::HTMLInputElement* old_password = NULL;
+ if (!LocateSpecificPasswords(&fields, &password, &old_password))
+ return NULL;
+
+ return AssemblePasswordFormResult(full_origin, full_action,
+ fields.submit, fields.username,
+ old_password, password);
+}
+
+// static
+PasswordFormDomManager::FillData* PasswordFormDomManager::CreateFillData(
+ const PasswordForm& form_on_page,
+ const PasswordFormMap& matches,
+ const PasswordForm* const preferred_match,
+ bool wait_for_username_before_autofill) {
+ DCHECK(preferred_match);
+ PasswordFormDomManager::FillData* result =
+ new PasswordFormDomManager::FillData();
+
+ // Fill basic form data.
+ result->basic_data.origin = form_on_page.origin;
+ result->basic_data.action = form_on_page.action;
+ result->basic_data.elements.push_back(form_on_page.username_element);
+ result->basic_data.values.push_back(preferred_match->username_value);
+ result->basic_data.elements.push_back(form_on_page.password_element);
+ result->basic_data.values.push_back(preferred_match->password_value);
+ result->basic_data.submit = form_on_page.submit_element;
+ result->wait_for_username = wait_for_username_before_autofill;
+
+ // Copy additional username/value pairs.
+ PasswordFormMap::const_iterator iter;
+ for (iter = matches.begin(); iter != matches.end(); iter++) {
+ if (iter->second != preferred_match)
+ result->additional_logins[iter->first] = iter->second->password_value;
+ }
+ return result;
+}
+
+// static
+bool PasswordFormDomManager::LocateSpecificPasswords(
+ PasswordFormFields* fields,
+ WebCore::HTMLInputElement** password,
+ WebCore::HTMLInputElement** old_password) {
+ DCHECK(fields && password && old_password);
+ switch (fields->passwords.size()) {
+ case 1:
+ // Single password, easy.
+ *password = fields->passwords[0];
+ break;
+ case 2:
+ if (fields->passwords[0]->value() == fields->passwords[1]->value())
+ // Treat two identical passwords as a single password.
+ *password = fields->passwords[0];
+ else {
+ // Assume first is old password, second is new (no choice but to guess).
+ *old_password = fields->passwords[0];
+ *password = fields->passwords[1];
+ }
+ break;
+ case 3:
+ if (fields->passwords[0]->value() == fields->passwords[1]->value() &&
+ fields->passwords[0]->value() == fields->passwords[2]->value()) {
+ // All three passwords the same? Just treat as one and hope.
+ *password = fields->passwords[0];
+ } else if (fields->passwords[0]->value() ==
+ fields->passwords[1]->value()) {
+ // Two the same and one different -> old password is duplicated one.
+ *old_password = fields->passwords[0];
+ *password = fields->passwords[2];
+ } else if (fields->passwords[1]->value() ==
+ fields->passwords[2]->value()) {
+ *old_password = fields->passwords[0];
+ *password = fields->passwords[1];
+ } else {
+ // Three different passwords, or first and last match with middle
+ // different. No idea which is which, so no luck.
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+ // This method based on Firefox2 code in
+ // toolkit/components/passwordmgr/base/nsPasswordManager.cpp
+ // Its license block is
+ //
+ /* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Password Manager.
+ *
+ * The Initial Developer of the Original Code is
+ * Brian Ryner.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Brian Ryner <bryner@brianryner.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+// static
+void PasswordFormDomManager::FindPasswordFormFields(
+ WebCore::HTMLFormElement* form,
+ PasswordFormFields* fields) {
+ DCHECK(form && fields);
+ int first_password_index = 0;
+ // First, find the password fields and activated submit button
+ const WTF::Vector<WebCore::HTMLGenericFormElement*>& form_elements =
+ form->formElements;
+ for (size_t i = 0; i < form_elements.size(); i++) {
+ WebCore::HTMLGenericFormElement* form_element = form_elements[i];
+ if (form_element->isActivatedSubmit())
+ fields->submit = form_element;
+
+ if (!form_element->hasLocalName(WebCore::HTMLNames::inputTag))
+ continue;
+
+ WebCore::HTMLInputElement* input_element =
+ static_cast<WebCore::HTMLInputElement*>(form_element);
+ if (!input_element->isEnabled())
+ continue;
+
+ if ((fields->passwords.size() < kMaxPasswords) &&
+ (input_element->inputType() == WebCore::HTMLInputElement::PASSWORD) &&
+ (input_element->autoComplete())) {
+ if (fields->passwords.empty())
+ first_password_index = i;
+ fields->passwords.push_back(input_element);
+ }
+ }
+
+ if (!fields->passwords.empty()) {
+ // Then, search backwards for the username field
+ for (int i = first_password_index - 1; i >= 0; i--) {
+ WebCore::HTMLGenericFormElement* form_element = form_elements[i];
+ if (!form_element->hasLocalName(WebCore::HTMLNames::inputTag))
+ continue;
+
+ WebCore::HTMLInputElement* input_element =
+ static_cast<WebCore::HTMLInputElement*>(form_element);
+ if (!input_element->isEnabled())
+ continue;
+
+ if ((input_element->inputType() == WebCore::HTMLInputElement::TEXT) &&
+ (input_element->autoComplete())) {
+ fields->username = input_element;
+ break;
+ }
+ }
+ }
+}
+
+// static
+PasswordForm* PasswordFormDomManager::AssemblePasswordFormResult(
+ const GURL& full_origin,
+ const GURL& full_action,
+ WebCore::HTMLGenericFormElement* submit,
+ WebCore::HTMLInputElement* username,
+ WebCore::HTMLInputElement* old_password,
+ WebCore::HTMLInputElement* password) {
+ std::wstring empty;
+ PasswordForm* result = new PasswordForm();
+ // Ignore the query and ref components
+ GURL::Replacements rep;
+ rep.ClearUsername();
+ rep.ClearPassword();
+ rep.ClearQuery();
+ rep.ClearRef();
+ // We want to keep the path but strip any authentication data, as well as
+ // query and ref portions of URL, for the form action and form origin.
+ result->action = full_action.ReplaceComponents(rep);
+ result->origin = full_origin.ReplaceComponents(rep);
+
+ // Naming is confusing here because we have both the HTML form origin URL
+ // the page where the form was seen), and the "origin" components of the url
+ // (scheme, host, and port).
+ result->signon_realm = full_origin.GetOrigin().spec();
+ // Note PasswordManager sets ssl_valid by asking the WebContents' SSLManager.
+ result->submit_element =
+ submit == NULL ? empty : webkit_glue::StringToStdWString(submit->name());
+ result->username_element =
+ username == NULL ? empty
+ : webkit_glue::StringToStdWString(username->name());
+ result->username_value =
+ username == NULL ? empty
+ : webkit_glue::StringToStdWString(username->value());
+ result->password_element =
+ password == NULL ? empty
+ : webkit_glue::StringToStdWString(password->name());
+ result->password_value =
+ password == NULL ? empty
+ : webkit_glue::StringToStdWString(password->value());
+ result->old_password_element =
+ old_password == NULL ? empty
+ : webkit_glue::StringToStdWString(old_password->name());
+ result->old_password_value =
+ old_password == NULL ? empty
+ : webkit_glue::StringToStdWString(old_password->value());
+ return result;
+}
diff --git a/webkit/glue/password_form_dom_manager.h b/webkit/glue/password_form_dom_manager.h
new file mode 100644
index 0000000..3e0b22c
--- /dev/null
+++ b/webkit/glue/password_form_dom_manager.h
@@ -0,0 +1,158 @@
+// 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 WEBKIT_GLUE_PASSWORD_FORM_DOM_MANAGER_H__
+#define WEBKIT_GLUE_PASSWORD_FORM_DOM_MANAGER_H__
+
+#include "webkit/glue/form_data.h"
+#include "webkit/glue/password_form.h"
+
+#include <map>
+#include <vector>
+
+namespace WebCore {
+class HTMLFormElement;
+class HTMLInputElement;
+class HTMLGenericFormElement;
+}
+
+class GURL;
+
+class PasswordFormDomManager {
+ public:
+ typedef std::map<std::wstring, std::wstring> LoginCollection;
+
+ // Structure used for autofilling password forms.
+ // basic_data identifies the HTML form on the page and preferred username/
+ // password for login, while
+ // additional_logins is a list of other matching user/pass pairs for the form.
+ // wait_for_username tells us whether we need to wait for the user to enter
+ // a valid username before we autofill the password. By default, this is off
+ // unless the PasswordManager determined there is an additional risk
+ // associated with this form. This can happen, for example, if action URI's
+ // of the observed form and our saved representation don't match up.
+ struct FillData {
+ FormData basic_data;
+ LoginCollection additional_logins;
+ bool wait_for_username;
+ FillData() : wait_for_username(false) {
+ }
+ };
+
+ // Create a PasswordForm from DOM form. Webkit doesn't allow storing
+ // custom metadata to DOM nodes, so we have to do this every time an event
+ // happens with a given form and compare against previously Create'd forms
+ // to identify..which sucks.
+ static PasswordForm* CreatePasswordForm(WebCore::HTMLFormElement* form);
+
+ // Create a FillData structure in preparation for autofilling a form,
+ // from basic_data identifying which form to fill, and a collection of
+ // matching stored logins to use as username/password values.
+ // preferred_match should equal (address) one of matches.
+ // wait_for_username_before_autofill is true if we should not autofill
+ // anything until the user typed in a valid username and blurred the field.
+ static FillData* CreateFillData(const PasswordForm& form_on_page,
+ const PasswordFormMap& matches,
+ const PasswordForm* const preferred_match,
+ bool wait_for_username_before_autofill);
+ private:
+ // Helper structure to locate username, passwords and submit fields.
+ struct PasswordFormFields {
+ WebCore::HTMLInputElement* username;
+ std::vector<WebCore::HTMLInputElement*> passwords;
+ WebCore::HTMLGenericFormElement* submit;
+ PasswordFormFields() : username(NULL), submit(NULL) {
+ }
+ };
+
+ // Helper to CreatePasswordForm to do the locating of username/password
+ // fields.
+ // This method based on Firefox2 code in
+ // toolkit/components/passwordmgr/base/nsPasswordManager.cpp
+ // Its license block is
+
+ /* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Password Manager.
+ *
+ * The Initial Developer of the Original Code is
+ * Brian Ryner.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Brian Ryner <bryner@brianryner.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+ static void FindPasswordFormFields(WebCore::HTMLFormElement* form,
+ PasswordFormFields* fields);
+ // Helper to determine which password is the main one, and which is
+ // an old password (e.g on a "make new password" form), if any.
+ static bool LocateSpecificPasswords(
+ PasswordFormFields* fields,
+ WebCore::HTMLInputElement** password,
+ WebCore::HTMLInputElement** old_password_index);
+
+ // Helper to gather up the final form data and create a PasswordForm.
+ static PasswordForm* AssemblePasswordFormResult(
+ const GURL& full_origin,
+ const GURL& full_action,
+ WebCore::HTMLGenericFormElement* submit,
+ WebCore::HTMLInputElement* username,
+ WebCore::HTMLInputElement* old_password,
+ WebCore::HTMLInputElement* password);
+
+ // This class can't be instantiated.
+ DISALLOW_IMPLICIT_CONSTRUCTORS(PasswordFormDomManager);
+};
+
+#endif // WEBKIT_GLUE_PASSWORD_FORM_DOM_MANAGER_H__
diff --git a/webkit/glue/plugins/mozilla_extensions.cc b/webkit/glue/plugins/mozilla_extensions.cc
new file mode 100644
index 0000000..efda1df
--- /dev/null
+++ b/webkit/glue/plugins/mozilla_extensions.cc
@@ -0,0 +1,395 @@
+// 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 <Winhttp.h>
+
+#include <algorithm>
+
+#include "webkit/glue/plugins/mozilla_extensions.h"
+
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_proxy_service.h"
+#include "net/http/http_proxy_resolver_winhttp.h"
+#include "third_party/npapi/bindings/npapi.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/plugins/plugin_instance.h"
+
+#define QI_SUPPORTS_IID(iid, iface) \
+ QI_SUPPORTS_IID_(iid, iface::GetIID(), iface)
+
+#define QI_SUPPORTS_IID_(src_iid, iface_iid, iface) \
+ if (iid.Equals(iface_iid)) { \
+ AddRef(); \
+ *result = static_cast<iface*>(this); \
+ return NS_OK; \
+ }
+
+namespace NPAPI
+{
+
+void MozillaExtensionApi::DetachFromInstance() {
+ plugin_instance_ = NULL;
+}
+
+bool MozillaExtensionApi::FindProxyForUrl(const char* url,
+ std::string* proxy) {
+ bool result = false;
+
+ if ((!url) || (!proxy)) {
+ NOTREACHED();
+ return result;
+ }
+
+ net::HttpProxyResolverWinHttp proxy_resolver;
+ net::HttpProxyService proxy_service(&proxy_resolver);
+ net::HttpProxyInfo proxy_info;
+
+ if (proxy_service.ResolveProxy(GURL(std::string(url)),
+ &proxy_info,
+ NULL,
+ NULL) == net::OK) {
+ if (!proxy_info.is_direct()) {
+ std::wstring winhttp_proxy = proxy_info.proxy_server();
+
+ // Winhttp returns proxy in the the following format:
+ // - HTTP proxy: "111.111.111.111:11"
+ // -.SOCKS proxy: "socks=111.111.111.111:11"
+ // - Mixed proxy: "http=111.111.111.111:11; socks=222.222.222.222:22"
+ //
+ // We need to translate this into the following format:
+ // i) "DIRECT" -- no proxy
+ // ii) "PROXY xxx.xxx.xxx.xxx" -- use proxy
+ // iii) "SOCKS xxx.xxx.xxx.xxx" -- use SOCKS
+ // iv) Mixed. e.g. "PROXY 111.111.111.111;PROXY 112.112.112.112",
+ // "PROXY 111.111.111.111;SOCKS 112.112.112.112"....
+ StringToLowerASCII(winhttp_proxy);
+ if (std::wstring::npos == winhttp_proxy.find(L'=')) {
+ // Proxy is in the form: "111.111.111.111:11"
+ winhttp_proxy.insert(0, L"http ");
+ } else {
+ // Proxy is in the following form.
+ // -.SOCKS proxy: "socks=111.111.111.111:11"
+ // - Mixed proxy: "http=111.111.111.111:11; socks=222.222.222.222:22"
+ // in this case just replace the '=' with a space
+ std::replace_if(winhttp_proxy.begin(),
+ winhttp_proxy.end(),
+ std::bind2nd(std::equal_to<wchar_t>(), L'='), L' ');
+ }
+
+ *proxy = WideToASCII(std::wstring(winhttp_proxy));
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+// nsISupports implementation
+NS_IMETHODIMP MozillaExtensionApi::QueryInterface(REFNSIID iid,
+ void** result) {
+ static const nsIID knsISupportsIID = NS_ISUPPORTS_IID;
+ QI_SUPPORTS_IID_(iid, knsISupportsIID, nsIServiceManager)
+ QI_SUPPORTS_IID(iid, nsIServiceManager)
+ QI_SUPPORTS_IID(iid, nsIPluginManager)
+ QI_SUPPORTS_IID(iid, nsIPluginManager2)
+ QI_SUPPORTS_IID(iid, nsICookieStorage)
+
+ NOTREACHED();
+ return NS_ERROR_NO_INTERFACE;
+}
+
+NS_IMETHODIMP_(nsrefcnt) MozillaExtensionApi::AddRef(void) {
+ return InterlockedIncrement(reinterpret_cast<LONG*>(&ref_count_));
+}
+
+NS_IMETHODIMP_(nsrefcnt) MozillaExtensionApi::Release(void) {
+ DCHECK(static_cast<int>(ref_count_) > 0);
+ if (InterlockedDecrement(reinterpret_cast<LONG*>(&ref_count_)) == 0) {
+ delete this;
+ return 0;
+ }
+
+ return ref_count_;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::GetService(REFNSIID class_guid,
+ REFNSIID iid,
+ void** result) {
+
+ static const nsIID kPluginManagerCID = NS_PLUGINMANAGER_CID;
+ static const nsIID kCookieStorageCID = NS_COOKIESTORAGE_CID;
+
+ nsresult rv = NS_ERROR_FAILURE;
+
+ if ((class_guid.Equals(kPluginManagerCID)) ||
+ (class_guid.Equals(kCookieStorageCID))) {
+ rv = QueryInterface(iid, result);
+ }
+
+ DCHECK(rv == NS_OK);
+ return rv;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::GetServiceByContractID(
+ const char* contract_id,
+ REFNSIID iid,
+ void** result) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::IsServiceInstantiated(REFNSIID class_guid,
+ REFNSIID iid,
+ PRBool* result) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::IsServiceInstantiatedByContractID(
+ const char* contract_id,
+ REFNSIID iid,
+ PRBool* result) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+
+NS_IMETHODIMP MozillaExtensionApi::GetValue(nsPluginManagerVariable variable,
+ void * value) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::ReloadPlugins(PRBool reloadPages) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::UserAgent(
+ const char** resultingAgentString) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::GetURL(
+ nsISupports* pluginInst,
+ const char* url,
+ const char* target,
+ nsIPluginStreamListener* streamListener,
+ const char* altHost,
+ const char* referrer,
+ PRBool forceJSEnabled) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::PostURL(
+ nsISupports* pluginInst,
+ const char* url,
+ unsigned int postDataLen,
+ const char* postData,
+ PRBool isFile,
+ const char* target,
+ nsIPluginStreamListener* streamListener,
+ const char* altHost,
+ const char* referrer,
+ PRBool forceJSEnabled ,
+ unsigned int postHeadersLength,
+ const char* postHeaders) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::RegisterPlugin(
+ REFNSIID aCID,
+ const char *aPluginName,
+ const char *aDescription,
+ const char * * aMimeTypes,
+ const char * * aMimeDescriptions,
+ const char * * aFileExtensions,
+ PRInt32 aCount) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::UnregisterPlugin(REFNSIID aCID) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::GetURLWithHeaders(
+ nsISupports* pluginInst,
+ const char* url,
+ const char* target /* = NULL */,
+ nsIPluginStreamListener* streamListener /* = NULL */,
+ const char* altHost /* = NULL */,
+ const char* referrer /* = NULL */,
+ PRBool forceJSEnabled /* = PR_FALSE */,
+ PRUint32 getHeadersLength /* = 0 */,
+ const char* getHeaders /* = NULL */){
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+// nsIPluginManager2
+NS_IMETHODIMP MozillaExtensionApi::BeginWaitCursor() {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::EndWaitCursor() {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::SupportsURLProtocol(const char* aProtocol,
+ PRBool* aResult) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::NotifyStatusChange(nsIPlugin* aPlugin,
+ nsresult aStatus) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::FindProxyForURL(
+ const char* aURL,
+ char** aResult) {
+ std::string proxy = "DIRECT";
+ FindProxyForUrl(aURL, &proxy);
+
+ // Allocate this using the NPAPI allocator. The plugin will call
+ // NPN_Free to free this.
+ char* result = static_cast<char*>(NPN_MemAlloc(proxy.length() + 1));
+ strncpy(result, proxy.c_str(), proxy.length() + 1);
+
+ *aResult = result;
+ return NS_OK;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::RegisterWindow(
+ nsIEventHandler* handler,
+ nsPluginPlatformWindowRef window) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::UnregisterWindow(
+ nsIEventHandler* handler,
+ nsPluginPlatformWindowRef win) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::AllocateMenuID(nsIEventHandler* aHandler,
+ PRBool aIsSubmenu,
+ PRInt16 *aResult) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::DeallocateMenuID(nsIEventHandler* aHandler,
+ PRInt16 aMenuID) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::HasAllocatedMenuID(nsIEventHandler* aHandler,
+ PRInt16 aMenuID,
+ PRBool* aResult) {
+ NOTREACHED();
+ return NS_ERROR_FAILURE;
+}
+
+// nsICookieStorage
+NS_IMETHODIMP MozillaExtensionApi::GetCookie(
+ const char* url,
+ void* cookie_buffer,
+ PRUint32& buffer_size) {
+ if ((!url) || (!cookie_buffer)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ if (!plugin_instance_)
+ return NS_ERROR_FAILURE;
+
+ WebPlugin* webplugin = plugin_instance_->webplugin();
+ if (!webplugin)
+ return NS_ERROR_FAILURE;
+
+ // Bypass third-party cookie blocking by using the url as the policy_url.
+ GURL cookies_url((std::string(url)));
+ std::string cookies = webplugin->GetCookies(cookies_url, cookies_url);
+
+ if (cookies.empty())
+ return NS_ERROR_FAILURE;
+
+ if(cookies.length() >= buffer_size)
+ return NS_ERROR_FAILURE;
+
+ strncpy(static_cast<char*>(cookie_buffer),
+ cookies.c_str(),
+ cookies.length() + 1);
+
+ buffer_size = cookies.length();
+ return NS_OK;
+}
+
+NS_IMETHODIMP MozillaExtensionApi::SetCookie(
+ const char* url,
+ const void* cookie_buffer,
+ PRUint32 buffer_size){
+ if ((!url) || (!cookie_buffer) || (!buffer_size)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ if (!plugin_instance_)
+ return NS_ERROR_FAILURE;
+
+ WebPlugin* webplugin = plugin_instance_->webplugin();
+ if (!webplugin)
+ return NS_ERROR_FAILURE;
+
+ std::string cookie(static_cast<const char*>(cookie_buffer),
+ buffer_size);
+ GURL cookies_url((std::string(url)));
+ webplugin->SetCookie(cookies_url,
+ cookies_url,
+ cookie);
+ return NS_OK;
+}
+
+
+} // namespace NPAPI
diff --git a/webkit/glue/plugins/mozilla_extensions.h b/webkit/glue/plugins/mozilla_extensions.h
new file mode 100644
index 0000000..737f9fe9
--- /dev/null
+++ b/webkit/glue/plugins/mozilla_extensions.h
@@ -0,0 +1,124 @@
+// 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 WEBKIT_GLUE_PLUGINS_MOZILLA_EXTENSIONS_H__
+#define WEBKIT_GLUE_PLUGINS_MOZILLA_EXTENSIONS_H__
+
+#include <windows.h>
+
+// Include npapi first to avoid definition clashes due to
+// XP_WIN
+#include "third_party/npapi/bindings/npapi.h"
+
+#include "third_party/mozilla/include/nsIServiceManager.h"
+#include "third_party/mozilla/include/nsIPluginManager2.h"
+#include "third_party/mozilla/include/nsICookieStorage.h"
+#include "third_party/mozilla/include/nsError.h"
+
+#include "base/ref_counted.h"
+
+// NS_DECL_NSIPLUGINMANAGER doesn't include methods described as "C++" in the
+// nsIPluginManager.idl.
+#define NS_DECL_NSIPLUGINMANAGER_FIXED \
+ NS_DECL_NSIPLUGINMANAGER \
+ NS_IMETHOD \
+ GetURL(nsISupports* pluginInst, \
+ const char* url, \
+ const char* target = NULL, \
+ nsIPluginStreamListener* streamListener = NULL, \
+ const char* altHost = NULL, \
+ const char* referrer = NULL, \
+ PRBool forceJSEnabled = PR_FALSE); \
+ NS_IMETHOD \
+ PostURL(nsISupports* pluginInst, \
+ const char* url, \
+ PRUint32 postDataLen, \
+ const char* postData, \
+ PRBool isFile = PR_FALSE, \
+ const char* target = NULL, \
+ nsIPluginStreamListener* streamListener = NULL, \
+ const char* altHost = NULL, \
+ const char* referrer = NULL, \
+ PRBool forceJSEnabled = PR_FALSE, \
+ PRUint32 postHeadersLength = 0, \
+ const char* postHeaders = NULL); \
+ NS_IMETHOD \
+ GetURLWithHeaders(nsISupports* pluginInst, \
+ const char* url, \
+ const char* target = NULL, \
+ nsIPluginStreamListener* streamListener = NULL, \
+ const char* altHost = NULL, \
+ const char* referrer = NULL, \
+ PRBool forceJSEnabled = PR_FALSE, \
+ PRUint32 getHeadersLength = 0, \
+ const char* getHeaders = NULL);
+
+// Avoid dependence on the nsIsupportsImpl.h and so on.
+#ifndef NS_DECL_ISUPPORTS
+#define NS_DECL_ISUPPORTS \
+ NS_IMETHOD QueryInterface(REFNSIID aIID, \
+ void** aInstancePtr); \
+ NS_IMETHOD_(nsrefcnt) AddRef(void); \
+ NS_IMETHOD_(nsrefcnt) Release(void);
+#endif // NS_DECL_ISUPPORTS
+
+namespace NPAPI
+{
+
+class PluginInstance;
+
+// Implementation of extended Mozilla interfaces needed to support
+// Sun's new Java plugin.
+class MozillaExtensionApi : public nsIServiceManager,
+ public nsIPluginManager2,
+ public nsICookieStorage {
+ public:
+ MozillaExtensionApi(PluginInstance* plugin_instance) :
+ plugin_instance_(plugin_instance), ref_count_(0) {
+ }
+
+ void DetachFromInstance();
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSISERVICEMANAGER
+ NS_DECL_NSIPLUGINMANAGER_FIXED
+ NS_DECL_NSIPLUGINMANAGER2
+ NS_DECL_NSICOOKIESTORAGE
+
+ protected:
+ bool FindProxyForUrl(const char* url, std::string* proxy);
+
+ protected:
+ scoped_refptr<NPAPI::PluginInstance> plugin_instance_;
+ unsigned long ref_count_;
+};
+
+} // namespace NPAPI
+
+#endif // WEBKIT_GLUE_PLUGINS_MOZILLA_EXTENSIONS_H__
diff --git a/webkit/glue/plugins/nphostapi.h b/webkit/glue/plugins/nphostapi.h
new file mode 100644
index 0000000..a248fd6
--- /dev/null
+++ b/webkit/glue/plugins/nphostapi.h
@@ -0,0 +1,302 @@
+// 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.
+
+// TODO: Did not implement JRIGlobalRef function yet. Not sure if this is used?
+
+#ifndef WEBKIT_GLUE_PLUGIN_NPHOSTAPI_H__
+#define WEBKIT_GLUE_PLUGIN_NPHOSTAPI_H__
+
+#include "bindings/npapi.h"
+#include "bindings/npruntime.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//
+// NPAPI NPP Function Pointers
+//
+typedef NPError (*NPP_NewProcPtr)(NPMIMEType pluginType,
+ NPP instance,
+ uint16 mode,
+ int16 argc,
+ char* argn[],
+ char* argv[],
+ NPSavedData* saved);
+typedef NPError (*NPP_DestroyProcPtr)(NPP instance,
+ NPSavedData** save);
+typedef NPError (*NPP_SetWindowProcPtr)(NPP instance,
+ NPWindow* window);
+typedef NPError (*NPP_NewStreamProcPtr)(NPP instance,
+ NPMIMEType type,
+ NPStream* stream,
+ NPBool seekable,
+ uint16* stype);
+typedef NPError (*NPP_DestroyStreamProcPtr)(NPP instance,
+ NPStream* stream,
+ NPReason reason);
+typedef int32 (*NPP_WriteReadyProcPtr)(NPP instance,
+ NPStream* stream);
+typedef int32 (*NPP_WriteProcPtr)(NPP instance,
+ NPStream* stream,
+ int32 offset,
+ int32 len,
+ void* buffer);
+typedef void (*NPP_StreamAsFileProcPtr)(NPP instance,
+ NPStream* stream,
+ const char* fname);
+typedef void (*NPP_PrintProcPtr)(NPP instance,
+ NPPrint* platformPrint);
+typedef int16 (*NPP_HandleEventProcPtr)(NPP instance,
+ void* event);
+typedef void (*NPP_URLNotifyProcPtr)(NPP instance,
+ const char* url,
+ NPReason reason,
+ void* notifyData);
+typedef void* JRIGlobalRef; //not using this right now
+typedef NPError (*NPP_GetValueProcPtr)(NPP instance,
+ NPPVariable variable,
+ void *ret_alue);
+typedef NPError (*NPP_SetValueProcPtr)(NPP instance,
+ NPNVariable variable,
+ void *ret_alue);
+
+//
+// NPAPI NPN Function Pointers
+//
+typedef NPError (*NPN_GetURLProcPtr)(NPP instance,
+ const char* URL,
+ const char* window);
+typedef NPError (*NPN_PostURLProcPtr)(NPP instance,
+ const char* URL,
+ const char* window,
+ uint32 len,
+ const char* buf,
+ NPBool file);
+typedef NPError (*NPN_RequestReadProcPtr)(NPStream* stream,
+ NPByteRange* rangeList);
+typedef NPError (*NPN_NewStreamProcPtr)(NPP instance,
+ NPMIMEType type,
+ const char* window,
+ NPStream** stream);
+typedef int32 (*NPN_WriteProcPtr)(NPP instance,
+ NPStream* stream,
+ int32 len,
+ void* buffer);
+typedef NPError (*NPN_DestroyStreamProcPtr)(NPP instance,
+ NPStream* stream,
+ NPReason reason);
+typedef void (*NPN_StatusProcPtr)(NPP instance,
+ const char* message);
+typedef const char* (*NPN_UserAgentProcPtr)(NPP instance);
+typedef void* (*NPN_MemAllocProcPtr)(uint32 size);
+typedef void (*NPN_MemFreeProcPtr)(void* ptr);
+typedef uint32 (*NPN_MemFlushProcPtr)(uint32 size);
+typedef void (*NPN_ReloadPluginsProcPtr)(NPBool reloadPages);
+
+typedef void* (*NPN_GetJavaEnvProcPtr)(void);
+typedef void* (*NPN_GetJavaPeerProcPtr)(NPP instance);
+
+typedef NPError (*NPN_GetURLNotifyProcPtr)(NPP instance,
+ const char* URL,
+ const char* window,
+ void* notifyData);
+typedef NPError (*NPN_PostURLNotifyProcPtr)(NPP instance,
+ const char* URL,
+ const char* window,
+ uint32 len,
+ const char* buf,
+ NPBool file,
+ void* notifyData);
+typedef NPError (*NPN_GetValueProcPtr)(NPP instance,
+ NPNVariable variable,
+ void *ret_value);
+typedef NPError (*NPN_SetValueProcPtr)(NPP instance,
+ NPPVariable variable,
+ void *value);
+typedef void (*NPN_InvalidateRectProcPtr)(NPP instance,
+ NPRect *rect);
+typedef void (*NPN_InvalidateRegionProcPtr)(NPP instance,
+ NPRegion region);
+typedef void (*NPN_ForceRedrawProcPtr)(NPP instance);
+
+typedef void (*NPN_ReleaseVariantValueProcPtr) (NPVariant *variant);
+
+typedef NPIdentifier (*NPN_GetStringIdentifierProcPtr) (const NPUTF8 *name);
+typedef void (*NPN_GetStringIdentifiersProcPtr) (const NPUTF8 **names,
+ int32_t nameCount,
+ NPIdentifier *identifiers);
+typedef NPIdentifier (*NPN_GetIntIdentifierProcPtr) (int32_t intid);
+typedef int32_t (*NPN_IntFromIdentifierProcPtr) (NPIdentifier identifier);
+typedef bool (*NPN_IdentifierIsStringProcPtr) (NPIdentifier identifier);
+typedef NPUTF8 * (*NPN_UTF8FromIdentifierProcPtr) (NPIdentifier identifier);
+
+typedef NPObject* (*NPN_CreateObjectProcPtr) (NPP,
+ NPClass *aClass);
+typedef NPObject* (*NPN_RetainObjectProcPtr) (NPObject *obj);
+typedef void (*NPN_ReleaseObjectProcPtr) (NPObject *obj);
+typedef bool (*NPN_InvokeProcPtr) (NPP npp,
+ NPObject *obj,
+ NPIdentifier methodName,
+ const NPVariant *args,
+ unsigned argCount,
+ NPVariant *result);
+typedef bool (*NPN_InvokeDefaultProcPtr) (NPP npp,
+ NPObject *obj,
+ const NPVariant *args,
+ unsigned argCount,
+ NPVariant *result);
+typedef bool (*NPN_EvaluateProcPtr) (NPP npp,
+ NPObject *obj,
+ NPString *script,
+ NPVariant *result);
+typedef bool (*NPN_GetPropertyProcPtr) (NPP npp,
+ NPObject *obj,
+ NPIdentifier propertyName,
+ NPVariant *result);
+typedef bool (*NPN_SetPropertyProcPtr) (NPP npp,
+ NPObject *obj,
+ NPIdentifier propertyName,
+ const NPVariant *value);
+typedef bool (*NPN_HasPropertyProcPtr) (NPP,
+ NPObject *npobj,
+ NPIdentifier propertyName);
+typedef bool (*NPN_HasMethodProcPtr) (NPP npp,
+ NPObject *npobj,
+ NPIdentifier methodName);
+typedef bool (*NPN_RemovePropertyProcPtr) (NPP npp,
+ NPObject *obj,
+ NPIdentifier propertyName);
+typedef void (*NPN_SetExceptionProcPtr) (NPObject *obj,
+ const NPUTF8 *message);
+typedef void (*NPN_PushPopupsEnabledStateProcPtr)(NPP npp,
+ NPBool enabled);
+typedef void (*NPN_PopPopupsEnabledStateProcPtr)(NPP npp);
+typedef bool (*NPN_EnumerateProcPtr)(NPP npp,
+ NPObject *obj,
+ NPIdentifier **identifier,
+ uint32_t *count);
+typedef void (*NPN_PluginThreadAsyncCallProcPtr)(NPP instance,
+ void (*func)(void *),
+ void *userData);
+typedef bool (*NPN_ConstructProcPtr)(NPP npp,
+ NPObject* obj,
+ const NPVariant *args,
+ uint32_t argCount,
+ NPVariant *result);
+
+//
+// NPAPI Function table of NPP functions (functions provided by plugin to host)
+//
+typedef struct _NPPluginFuncs {
+ unsigned short size;
+ unsigned short version;
+ NPP_NewProcPtr newp;
+ NPP_DestroyProcPtr destroy;
+ NPP_SetWindowProcPtr setwindow;
+ NPP_NewStreamProcPtr newstream;
+ NPP_DestroyStreamProcPtr destroystream;
+ NPP_StreamAsFileProcPtr asfile;
+ NPP_WriteReadyProcPtr writeready;
+ NPP_WriteProcPtr write;
+ NPP_PrintProcPtr print;
+ NPP_HandleEventProcPtr event;
+ NPP_URLNotifyProcPtr urlnotify;
+ JRIGlobalRef javaClass;
+ NPP_GetValueProcPtr getvalue;
+ NPP_SetValueProcPtr setvalue;
+} NPPluginFuncs;
+
+//
+// NPAPI Function table NPN functions (functions provided by host to plugin)
+//
+typedef struct _NPNetscapeFuncs {
+ uint16 size;
+ uint16 version;
+ NPN_GetURLProcPtr geturl;
+ NPN_PostURLProcPtr posturl;
+ NPN_RequestReadProcPtr requestread;
+ NPN_NewStreamProcPtr newstream;
+ NPN_WriteProcPtr write;
+ NPN_DestroyStreamProcPtr destroystream;
+ NPN_StatusProcPtr status;
+ NPN_UserAgentProcPtr uagent;
+ NPN_MemAllocProcPtr memalloc;
+ NPN_MemFreeProcPtr memfree;
+ NPN_MemFlushProcPtr memflush;
+ NPN_ReloadPluginsProcPtr reloadplugins;
+ NPN_GetJavaEnvProcPtr getJavaEnv;
+ NPN_GetJavaPeerProcPtr getJavaPeer;
+ NPN_GetURLNotifyProcPtr geturlnotify;
+ NPN_PostURLNotifyProcPtr posturlnotify;
+ NPN_GetValueProcPtr getvalue;
+ NPN_SetValueProcPtr setvalue;
+ NPN_InvalidateRectProcPtr invalidaterect;
+ NPN_InvalidateRegionProcPtr invalidateregion;
+ NPN_ForceRedrawProcPtr forceredraw;
+
+ NPN_GetStringIdentifierProcPtr getstringidentifier;
+ NPN_GetStringIdentifiersProcPtr getstringidentifiers;
+ NPN_GetIntIdentifierProcPtr getintidentifier;
+ NPN_IdentifierIsStringProcPtr identifierisstring;
+ NPN_UTF8FromIdentifierProcPtr utf8fromidentifier;
+ NPN_IntFromIdentifierProcPtr intfromidentifier;
+ NPN_CreateObjectProcPtr createobject;
+ NPN_RetainObjectProcPtr retainobject;
+ NPN_ReleaseObjectProcPtr releaseobject;
+ NPN_InvokeProcPtr invoke;
+ NPN_InvokeDefaultProcPtr invokeDefault;
+ NPN_EvaluateProcPtr evaluate;
+ NPN_GetPropertyProcPtr getproperty;
+ NPN_SetPropertyProcPtr setproperty;
+ NPN_RemovePropertyProcPtr removeproperty;
+ NPN_HasPropertyProcPtr hasproperty;
+ NPN_HasMethodProcPtr hasmethod;
+ NPN_ReleaseVariantValueProcPtr releasevariantvalue;
+ NPN_SetExceptionProcPtr setexception;
+ NPN_PushPopupsEnabledStateProcPtr pushpopupsenabledstate;
+ NPN_PopPopupsEnabledStateProcPtr poppopupsenabledstate;
+ NPN_EnumerateProcPtr enumerate;
+ NPN_PluginThreadAsyncCallProcPtr pluginthreadasynccall;
+ NPN_ConstructProcPtr construct;
+} NPNetscapeFuncs;
+
+//
+// NPAPI DLL entry points
+//
+typedef NPError (__stdcall * NP_InitializeFunc)(NPNetscapeFuncs* pFuncs);
+typedef NPError (__stdcall * NP_GetEntryPointsFunc)(NPPluginFuncs* pFuncs);
+typedef NPError (__stdcall * NP_ShutdownFunc)(void);
+
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBKIT_GLUE_PLUGIN_NPHOSTAPI_H__
diff --git a/webkit/glue/plugins/plugin_data_stream.cc b/webkit/glue/plugins/plugin_data_stream.cc
new file mode 100644
index 0000000..bb7ee0b
--- /dev/null
+++ b/webkit/glue/plugins/plugin_data_stream.cc
@@ -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.
+
+#include "webkit/glue/plugins/plugin_data_stream.h"
+
+namespace NPAPI {
+
+PluginDataStream::PluginDataStream(PluginInstance *instance,
+ const std::string& url,
+ const std::string& mime_type,
+ const std::string& headers,
+ uint32 expected_length,
+ uint32 last_modified)
+ : PluginStream(instance, url.c_str(), false, 0),
+ mime_type_(mime_type),
+ headers_(headers),
+ expected_length_(expected_length),
+ last_modified_(last_modified),
+ stream_open_failed_(false) {
+}
+
+PluginDataStream::~PluginDataStream() {
+}
+
+void PluginDataStream::SendToPlugin(const char* buffer, int length) {
+ if (stream_open_failed_)
+ return;
+
+ if (!open()) {
+ if (!Open(mime_type_, headers_, expected_length_, last_modified_)) {
+ stream_open_failed_ = true;
+ return;
+ }
+ }
+
+ // TODO(iyengar) - check if it was not fully sent, and figure out a
+ // backup plan.
+ int written = Write(buffer, length);
+ DCHECK(written == length);
+}
+
+} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_data_stream.h b/webkit/glue/plugins/plugin_data_stream.h
new file mode 100644
index 0000000..64cc3b1
--- /dev/null
+++ b/webkit/glue/plugins/plugin_data_stream.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.
+
+#ifndef WEBKIT_GLUE_PLUGIN_PLUGIN_DATA_STREAM_H__
+#define WEBKIT_GLUE_PLUGIN_PLUGIN_DATA_STREAM_H__
+
+#include "webkit/glue/plugins/plugin_stream.h"
+
+namespace NPAPI {
+
+class PluginInstance;
+
+// A NPAPI stream based on data received from the renderer.
+class PluginDataStream : public PluginStream {
+ public:
+ // Create a new stream for sending to the plugin.
+ PluginDataStream(PluginInstance *instance, const std::string& url,
+ const std::string& mime_type, const std::string& headers,
+ uint32 expected_length, uint32 last_modified);
+ virtual ~PluginDataStream();
+
+ // Initiates the sending of data to the plugin.
+ void SendToPlugin(const char* buffer, int length);
+
+ private:
+ std::string mime_type_;
+ std::string headers_;
+ uint32 expected_length_;
+ uint32 last_modified_;
+ // This flag when set serves as an indicator that subsequent
+ // data coming from the renderer should not be handed off to the plugin.
+ bool stream_open_failed_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(PluginDataStream);
+};
+
+} // namespace NPAPI
+
+#endif // WEBKIT_GLUE_PLUGIN_PLUGIN_DATA_STREAM_H__
+
diff --git a/webkit/glue/plugins/plugin_host.cc b/webkit/glue/plugins/plugin_host.cc
new file mode 100644
index 0000000..63cd6ca
--- /dev/null
+++ b/webkit/glue/plugins/plugin_host.cc
@@ -0,0 +1,877 @@
+// 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/plugins/plugin_host.h"
+
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/string_util.h"
+#include "webkit/default_plugin/default_plugin_shared.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/webplugin.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/plugins/plugin_instance.h"
+#include "webkit/glue/plugins/plugin_lib.h"
+#include "webkit/glue/plugins/plugin_list.h"
+#include "webkit/glue/plugins/plugin_stream_url.h"
+#include "third_party/npapi/bindings/npruntime.h"
+
+extern "C" {
+
+// FindInstance()
+// Finds a PluginInstance from an NPP.
+// The caller must take a reference if needed.
+NPAPI::PluginInstance* FindInstance(NPP id) {
+ if (id == NULL) {
+ NOTREACHED();
+ return NULL;
+ }
+
+ return (NPAPI::PluginInstance *)id->ndata;
+}
+
+namespace NPAPI
+{
+scoped_refptr<PluginHost> PluginHost::singleton_;
+
+static const int kFlashMessageThrottleDelayMs = 10;
+
+PluginHost::PluginHost()
+#pragma warning(suppress: 4355) // can use this
+ : throttle_factory_(this) {
+ InitializeHostFuncs();
+}
+
+PluginHost::~PluginHost() {
+}
+
+PluginHost *PluginHost::Singleton() {
+ if (singleton_.get() == NULL) {
+ singleton_ = new PluginHost();
+ }
+
+ DCHECK(singleton_.get() != NULL);
+ return singleton_;
+}
+
+void PluginHost::InitializeHostFuncs() {
+ memset(&host_funcs_, 0, sizeof(host_funcs_));
+ host_funcs_.size = sizeof(host_funcs_);
+ host_funcs_.version = (NP_VERSION_MAJOR << 8) | (NP_VERSION_MINOR);
+
+ // The "basic" functions
+ host_funcs_.geturl = &NPN_GetURL;
+ host_funcs_.posturl = &NPN_PostURL;
+ host_funcs_.requestread = &NPN_RequestRead;
+ host_funcs_.newstream = &NPN_NewStream;
+ host_funcs_.write = &NPN_Write;
+ host_funcs_.destroystream = &NPN_DestroyStream;
+ host_funcs_.status = &NPN_Status;
+ host_funcs_.uagent = &NPN_UserAgent;
+ host_funcs_.memalloc = &NPN_MemAlloc;
+ host_funcs_.memfree = &NPN_MemFree;
+ host_funcs_.memflush = &NPN_MemFlush;
+ host_funcs_.reloadplugins = &NPN_ReloadPlugins;
+
+ // We don't implement java yet
+ host_funcs_.getJavaEnv = &NPN_GetJavaEnv;
+ host_funcs_.getJavaPeer = &NPN_GetJavaPeer;
+
+ // Advanced functions we implement
+ host_funcs_.geturlnotify = &NPN_GetURLNotify;
+ host_funcs_.posturlnotify = &NPN_PostURLNotify;
+ host_funcs_.getvalue = &NPN_GetValue;
+ host_funcs_.setvalue = &NPN_SetValue;
+ host_funcs_.invalidaterect = &NPN_InvalidateRect;
+ host_funcs_.invalidateregion = &NPN_InvalidateRegion;
+ host_funcs_.forceredraw = &NPN_ForceRedraw;
+
+ // These come from the Javascript Engine
+ host_funcs_.getstringidentifier = NPN_GetStringIdentifier;
+ host_funcs_.getstringidentifiers = NPN_GetStringIdentifiers;
+ host_funcs_.getintidentifier = NPN_GetIntIdentifier;
+ host_funcs_.identifierisstring = NPN_IdentifierIsString;
+ host_funcs_.utf8fromidentifier = NPN_UTF8FromIdentifier;
+ host_funcs_.intfromidentifier = NPN_IntFromIdentifier;
+ host_funcs_.createobject = NPN_CreateObject;
+ host_funcs_.retainobject = NPN_RetainObject;
+ host_funcs_.releaseobject = NPN_ReleaseObject;
+ host_funcs_.invoke = NPN_Invoke;
+ host_funcs_.invokeDefault = NPN_InvokeDefault;
+ host_funcs_.evaluate = NPN_Evaluate;
+ host_funcs_.getproperty = NPN_GetProperty;
+ host_funcs_.setproperty = NPN_SetProperty;
+ host_funcs_.removeproperty = NPN_RemoveProperty;
+ host_funcs_.hasproperty = NPN_HasProperty;
+ host_funcs_.hasmethod = NPN_HasMethod;
+ host_funcs_.releasevariantvalue = NPN_ReleaseVariantValue;
+ host_funcs_.setexception = NPN_SetException;
+ host_funcs_.pushpopupsenabledstate = &NPN_PushPopupsEnabledState;
+ host_funcs_.poppopupsenabledstate = &NPN_PopPopupsEnabledState;
+ host_funcs_.enumerate = &NPN_Enumerate;
+ host_funcs_.pluginthreadasynccall = &NPN_PluginThreadAsyncCall;
+ host_funcs_.construct = &NPN_Construct;
+
+}
+
+void PluginHost::PatchNPNetscapeFuncs(NPNetscapeFuncs* overrides) {
+ // When running in the plugin process, we need to patch the NPN functions
+ // that the plugin calls to interact with NPObjects that we give. Otherwise
+ // the plugin will call the v8 NPN functions, which won't work since we have
+ // an NPObjectProxy and not a real v8 implementation.
+ if (overrides->invoke)
+ host_funcs_.invoke = overrides->invoke;
+
+ if (overrides->invokeDefault)
+ host_funcs_.invokeDefault = overrides->invokeDefault;
+
+ if (overrides->evaluate)
+ host_funcs_.evaluate = overrides->evaluate;
+
+ if (overrides->getproperty)
+ host_funcs_.getproperty = overrides->getproperty;
+
+ if (overrides->setproperty)
+ host_funcs_.setproperty = overrides->setproperty;
+
+ if (overrides->removeproperty)
+ host_funcs_.removeproperty = overrides->removeproperty;
+
+ if (overrides->hasproperty)
+ host_funcs_.hasproperty = overrides->hasproperty;
+
+ if (overrides->hasmethod)
+ host_funcs_.hasmethod = overrides->hasmethod;
+
+ if (overrides->setexception)
+ host_funcs_.setexception = overrides->setexception;
+
+ if (overrides->enumerate)
+ host_funcs_.enumerate = overrides->enumerate;
+}
+
+void PluginHost::InvalidateRect(NPP id, NPRect* invalidRect) {
+ if (!invalidRect) {
+ NOTREACHED();
+ return;
+ }
+
+ // Invalidates specified drawing area prior to repainting or refreshing a
+ // windowless plugin
+
+ // Before a windowless plugin can refresh part of its drawing area, it must
+ // first invalidate it. This function causes the NPP_HandleEvent method to
+ // pass an update event or a paint message to the plug-in. After calling
+ // this method, the plug-in recieves a paint message asynchronously.
+
+ // The browser redraws invalid areas of the document and any windowless
+ // plug-ins at regularly timed intervals. To force a paint message, the
+ // plug-in can call NPN_ForceRedraw after calling this method.
+
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ DCHECK(plugin.get() != NULL);
+
+ if (plugin.get() && plugin->webplugin()) {
+ if (plugin->throttle_invalidate()) {
+ // We need to track plugin invalidates on a per instance basis.
+ ThrottledInvalidates plugin_instance_invalidates;
+ InstanceThrottledInvalidatesMap::iterator invalidate_index =
+ instance_throttled_invalidates_.find(id);
+ if (invalidate_index != instance_throttled_invalidates_.end()) {
+ plugin_instance_invalidates = (*invalidate_index).second;
+ }
+
+ bool throttle_active =
+ (plugin_instance_invalidates.throttled_invalidates.size() > 0);
+
+ gfx::Rect rect(invalidRect->left,
+ invalidRect->top,
+ invalidRect->right - invalidRect->left,
+ invalidRect->bottom - invalidRect->top);
+
+ plugin_instance_invalidates.throttled_invalidates.push_back(rect);
+
+ if (!throttle_active) {
+ // We hold a reference to the plugin instance to avoid race conditions
+ // due to the instance being released before the OnInvalidateRect
+ // function is invoked.
+ plugin->AddRef();
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ throttle_factory_.NewRunnableMethod(&PluginHost::OnInvalidateRect,
+ id, plugin.get()),
+ kFlashMessageThrottleDelayMs);
+ }
+ instance_throttled_invalidates_[id] = plugin_instance_invalidates;
+ } else {
+ gfx::Rect rect(invalidRect->left,
+ invalidRect->top,
+ invalidRect->right - invalidRect->left,
+ invalidRect->bottom - invalidRect->top);
+ plugin->webplugin()->InvalidateRect(rect);
+ }
+ }
+}
+
+bool PluginHost::SetPostData(const char *buf,
+ uint32 length,
+ std::vector<std::string>* names,
+ std::vector<std::string>* values,
+ std::vector<char>* body) {
+ // Use a state table to do the parsing. Whitespace must be
+ // trimmed after the fact if desired. In our case, we actually
+ // don't care about the whitespace, because we're just going to
+ // pass this back into another POST. This function strips out the
+ // "Content-length" header and does not append it to the request.
+
+ //
+ // This parser takes action only on state changes.
+ //
+ // Transition table:
+ // : \n NULL Other
+ // 0 GetHeader 1 2 4 0
+ // 1 GetValue 1 0 3 1
+ // 2 GetData 2 2 3 2
+ // 3 DONE
+ // 4 ERR
+ //
+ enum { INPUT_COLON=0, INPUT_NEWLINE, INPUT_NULL, INPUT_OTHER };
+ enum { GETNAME, GETVALUE, GETDATA, DONE, ERR };
+ int statemachine[3][4] = { { GETVALUE, GETDATA, ERR, GETNAME },
+ { GETVALUE, GETNAME, DONE, GETVALUE },
+ { GETDATA, GETDATA, DONE, GETDATA } };
+ std::string name, value;
+ char *ptr = (char*)buf;
+ char *start = ptr;
+ int state = GETNAME; // initial state
+ bool done = false;
+ bool err = false;
+ do {
+ int input;
+
+ // Translate the current character into an input
+ // for the state table.
+ switch (*ptr) {
+ case ':' :
+ input = INPUT_COLON;
+ break;
+ case '\n':
+ input = INPUT_NEWLINE;
+ break;
+ case 0 :
+ input = INPUT_NULL;
+ break;
+ default :
+ input = INPUT_OTHER;
+ break;
+ }
+
+ int newstate = statemachine[state][input];
+
+ // Take action based on the new state.
+ if (state != newstate) {
+ switch (newstate) {
+ case GETNAME:
+ // Got a value.
+ value = std::string(start, ptr - start);
+ TrimWhitespace(value, TRIM_ALL, &value);
+ // If the name field is empty, we'll skip this header
+ // but we won't error out.
+ if (!name.empty() && name != "content-length") {
+ names->push_back(name);
+ values->push_back(value);
+ }
+ start = ptr + 1;
+ break;
+ case GETVALUE:
+ // Got a header.
+ name = StringToLowerASCII(std::string(start, ptr - start));
+ TrimWhitespace(name, TRIM_ALL, &name);
+ start = ptr + 1;
+ break;
+ case GETDATA:
+ {
+ // Finished headers, now get body.
+ start = ptr + 1;
+ size_t previous_size = body->size();
+ size_t new_body_size = length - static_cast<int>(start - buf);
+ body->resize(previous_size + new_body_size);
+ if (!body->empty())
+ memcpy(&body->front() + previous_size, start, new_body_size);
+ done = true;
+ break;
+ }
+ case ERR:
+ // error
+ err = true;
+ done = true;
+ break;
+ }
+ }
+ state = newstate;
+ ptr++;
+ } while (!done);
+
+ return !err;
+}
+
+void PluginHost::OnInvalidateRect(NPP id, PluginInstance* instance) {
+ if (!instance) {
+ NOTREACHED();
+ return;
+ }
+
+ InstanceThrottledInvalidatesMap::iterator invalidate_index =
+ instance_throttled_invalidates_.find(id);
+ if (invalidate_index == instance_throttled_invalidates_.end()) {
+ NOTREACHED();
+ instance->Release();
+ return;
+ }
+
+ ThrottledInvalidates plugin_instance_invalidates =
+ (*invalidate_index).second;
+
+ if (instance->webplugin()) {
+ for (unsigned int throttle_index = 0;
+ throttle_index <
+ plugin_instance_invalidates.throttled_invalidates.size();
+ throttle_index++) {
+ instance->webplugin()->InvalidateRect(
+ plugin_instance_invalidates.throttled_invalidates[throttle_index]);
+ }
+ }
+
+ instance->Release();
+ instance_throttled_invalidates_.erase(invalidate_index);
+}
+
+} // namespace NPAPI
+
+// Allocates memory from the host's memory space.
+void* NPN_MemAlloc(uint32 size) {
+ scoped_refptr<NPAPI::PluginHost> host = NPAPI::PluginHost::Singleton();
+ if (host != NULL) {
+ // Note: We must use the same allocator/deallocator
+ // that is used by the javascript library, as some of the
+ // JS APIs will pass memory to the plugin which the plugin
+ // will attempt to free.
+ return malloc(size);
+ }
+ return NULL;
+}
+
+// Deallocates memory from the host's memory space
+void NPN_MemFree(void* ptr) {
+ scoped_refptr<NPAPI::PluginHost> host = NPAPI::PluginHost::Singleton();
+ if (host != NULL) {
+ if (ptr != NULL && ptr != (void*)-1) {
+ free(ptr);
+ }
+ }
+}
+
+// Requests that the host free a specified amount of memory.
+uint32 NPN_MemFlush(uint32 size) {
+ // This is not relevant on Windows; MAC specific
+ return size;
+}
+
+// This is for dynamic discovery of new plugins.
+// Should force a re-scan of the plugins directory to load new ones.
+void NPN_ReloadPlugins(NPBool reloadPages) {
+ // TODO: implement me
+}
+
+// Requests a range of bytes for a seekable stream.
+NPError NPN_RequestRead(NPStream* stream, NPByteRange* rangeList) {
+ // TODO: implement me
+ return NPERR_GENERIC_ERROR;
+}
+
+static bool IsJavaScriptUrl(const std::string& url) {
+ return StartsWithASCII(url, "javascript:", false);
+}
+
+// Generic form of GetURL for common code between
+// GetURL() and GetURLNotify().
+static NPError GetURLNotify(NPP id,
+ const char* url,
+ const char* target,
+ bool notify,
+ void* notify_data) {
+ if (!url)
+ return NPERR_INVALID_URL;
+
+ bool is_javascript_url = IsJavaScriptUrl(url);
+
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin.get()) {
+ plugin->webplugin()->HandleURLRequest("GET",
+ is_javascript_url,
+ target,
+ 0,
+ 0,
+ false,
+ notify,
+ url,
+ notify_data,
+ plugin->popups_allowed());
+ } else {
+ NOTREACHED();
+ return NPERR_GENERIC_ERROR;
+ }
+ return NPERR_NO_ERROR;
+}
+
+// Requests creation of a new stream with the contents of the
+// specified URL; gets notification of the result.
+NPError NPN_GetURLNotify(NPP id,
+ const char* url,
+ const char* target,
+ void* notify_data) {
+ // This is identical to NPN_GetURL, but after finishing, the
+ // browser will call NPP_URLNotify to inform the plugin that
+ // it has completed.
+
+ // According to the NPAPI documentation, if target == _self
+ // or a parent to _self, the browser should return NPERR_INVALID_PARAM,
+ // because it can't notify the plugin once deleted. This is
+ // absolutely false; firefox doesn't do this, and Flash relies on
+ // being able to use this.
+
+ // Also according to the NPAPI documentation, we should return
+ // NPERR_INVALID_URL if the url requested is not valid. However,
+ // this would require that we synchronously start fetching the
+ // URL. That just isn't practical. As such, there really is
+ // no way to return this error. From looking at the Firefox
+ // implementation, it doesn't look like Firefox does this either.
+
+ return GetURLNotify(id, url, target, true, notify_data);
+}
+
+NPError NPN_GetURL(NPP id, const char* url, const char* target) {
+ // Notes:
+ // Request from the Plugin to fetch content either for the plugin
+ // or to be placed into a browser window.
+ //
+ // If target == null, the browser fetches content and streams to plugin.
+ // otherwise, the browser loads content into an existing browser frame.
+ // If the target is the window/frame containing the plugin, the plugin
+ // may be destroyed.
+ // If the target is _blank, a mailto: or news: url open content in a new
+ // browser window
+ // If the target is _self, no other instance of the plugin is created. The
+ // plugin continues to operate in its own window
+
+ return GetURLNotify(id, url, target, false, 0);
+}
+
+// Generic form of PostURL for common code between
+// PostURL() and PostURLNotify().
+static NPError PostURLNotify(NPP id,
+ const char* url,
+ const char* target,
+ uint32 len,
+ const char* buf,
+ NPBool file,
+ bool notify,
+ void* notify_data) {
+ if (!url)
+ return NPERR_INVALID_URL;
+
+ if (file) {
+ // Unfortunately, our WebKit requests can support files which
+ // contain *only* data. But the files from NPAPI contain
+ // headers + data! So, we need to read the file, extract
+ // the headers, write the data back to a new file, and then
+ // finally we can post the file. TODO: Implement me!
+ // TODO: implement me
+ NOTREACHED();
+ return NPERR_GENERIC_ERROR;
+ }
+
+ bool is_javascript_url = IsJavaScriptUrl(url);
+
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin.get()) {
+ // The post data sent by a plugin contains both headers
+ // and post data. Example:
+ // Content-type: text/html
+ // Content-length: 200
+ //
+ // <200 bytes of content here>
+ //
+ // Unfortunately, our stream needs these broken apart,
+ // so we need to parse the data and set headers and data
+ // separately.
+ plugin->webplugin()->HandleURLRequest("POST",
+ is_javascript_url,
+ target,
+ len,
+ buf,
+ file ? true : false,
+ notify,
+ url,
+ notify_data,
+ plugin->popups_allowed());
+ return NPERR_NO_ERROR;
+ } else {
+ NOTREACHED();
+ }
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError NPN_PostURLNotify(NPP id,
+ const char* url,
+ const char* target,
+ uint32 len,
+ const char* buf,
+ NPBool file,
+ void* notify_data) {
+ return PostURLNotify(id, url, target, len, buf, file, true, notify_data);
+}
+
+NPError NPN_PostURL(NPP id,
+ const char* url,
+ const char* target,
+ uint32 len,
+ const char* buf,
+ NPBool file) {
+ // POSTs data to an URL, either from a temp file or a buffer.
+ // If file is true, buf contains a temp file (which host will delete after
+ // completing), and len contains the length of the filename.
+ // If file is false, buf contains the data to send, and len contains the
+ // length of the buffer
+ //
+ // If target is null,
+ // server response is returned to the plugin
+ // If target is _current, _self, or _top,
+ // server response is written to the plugin window and plugin is unloaded.
+ // If target is _new or _blank,
+ // server response is written to a new browser window
+ // If target is an existing frame,
+ // server response goes to that frame.
+ //
+ // For protocols other than FTP
+ // file uploads must be line-end converted from \r\n to \n
+ //
+ // Note: you cannot specify headers (even a blank line) in a memory buffer,
+ // use NPN_PostURLNotify
+
+ return PostURLNotify(id, url, target, len, buf, file, false, 0);
+}
+
+NPError NPN_NewStream(NPP id,
+ NPMIMEType type,
+ const char* target,
+ NPStream** stream) {
+ // Requests creation of a new data stream produced by the plugin,
+ // consumed by the browser.
+ //
+ // Browser should put this stream into a window target.
+ //
+
+ // TODO: implement me
+ return NPERR_GENERIC_ERROR;
+}
+
+int32 NPN_Write(NPP id, NPStream* stream, int32 len, void* buffer) {
+ // Writes data to an existing Plugin-created stream.
+
+ // TODO: implement me
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError NPN_DestroyStream(NPP id, NPStream* stream, NPReason reason) {
+ // Destroys a stream (could be created by plugin or browser).
+ //
+ // Reasons:
+ // NPRES_DONE - normal completion
+ // NPRES_USER_BREAK - user terminated
+ // NPRES_NETWORK_ERROR - network error (all errors fit here?)
+ //
+ //
+
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin.get() == NULL) {
+ NOTREACHED();
+ return NPERR_GENERIC_ERROR;
+ }
+
+ return plugin->NPP_DestroyStream(stream, reason);
+}
+
+const char* NPN_UserAgent(NPP id) {
+ // Flash passes in a null id during the NP_initialize call. We need to
+ // default to the Mozilla user agent if we don't have an NPP instance or
+ // else Flash won't request windowless mode.
+ if (id) {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin.get() && !plugin->use_mozilla_user_agent())
+ return webkit_glue::GetDefaultUserAgent().c_str();
+ }
+
+ static const char *UA = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) Gecko/20061103 Firefox/2.0a1";
+ return UA;
+}
+
+void NPN_Status(NPP id, const char* message) {
+ // Displays a message on the status line of the browser window.
+
+ // TODO: implement me
+}
+
+void NPN_InvalidateRect(NPP id, NPRect *invalidRect) {
+ scoped_refptr<NPAPI::PluginHost> host = NPAPI::PluginHost::Singleton();
+ if (host != NULL) {
+ host->InvalidateRect(id, invalidRect);
+ }
+}
+
+void NPN_InvalidateRegion(NPP id, NPRegion invalidRegion) {
+ // Invalidates a specified drawing region prior to repainting
+ // or refreshing a window-less plugin.
+ //
+ // Similar to NPN_InvalidateRect.
+
+ // TODO: implement me
+}
+
+void NPN_ForceRedraw(NPP id) {
+ // Forces repaint for a windowless plug-in.
+ //
+ // Once a value has been invalidated with NPN_InvalidateRect/
+ // NPN_InvalidateRegion, ForceRedraw can be used to force a paint message.
+ //
+ // The plugin will receive a WM_PAINT message, the lParam of the WM_PAINT
+ // message holds a pointer to an NPRect that is the bounding box of the
+ // update area.
+ // Since the plugin and browser share the same HDC, before drawing, the
+ // plugin is responsible fro saving the current HDC settings, setting up
+ // its own environment, drawing, and restoring the HDC to the previous
+ // settings. The HDC settings must be restored whenever control returns
+ // back to the browser, either before returning from NPP_HandleEvent or
+ // before calling a drawing-related netscape method.
+ //
+
+ // TODO: implement me
+}
+
+NPError NPN_GetValue(NPP id, NPNVariable variable, void *value) {
+ // Allows the plugin to query the browser for information
+ //
+ // Variables:
+ // NPNVxDisplay (unix only)
+ // NPNVxtAppContext (unix only)
+ // NPNVnetscapeWindow (win only) - Gets the native window on which the
+ // plug-in drawing occurs, returns HWND
+ // NPNVjavascriptEnabledBool: tells whether Javascript is enabled
+ // NPNVasdEnabledBool: tells whether SmartUpdate is enabled
+ // NPNVOfflineBool: tells whether offline-mode is enabled
+
+ NPError rv = NPERR_GENERIC_ERROR;
+
+ switch (variable) {
+ case NPNVWindowNPObject:
+ {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ NPObject *np_object = plugin->webplugin()->GetWindowScriptNPObject();
+ // Return value is expected to be retained, as
+ // described here:
+ // <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess>
+ if (np_object) {
+ NPN_RetainObject(np_object);
+ void **v = (void **)value;
+ *v = np_object;
+ rv = NPERR_NO_ERROR;
+ } else {
+ NOTREACHED();
+ }
+ break;
+ }
+ case NPNVPluginElementNPObject:
+ {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ NPObject *np_object = plugin->webplugin()->GetPluginElement();
+ // Return value is expected to be retained, as
+ // described here:
+ // <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess>
+ if (np_object) {
+ NPN_RetainObject(np_object);
+ void **v = (void **)value;
+ *v = np_object;
+ rv = NPERR_NO_ERROR;
+ } else {
+ NOTREACHED();
+ }
+ break;
+ }
+ case NPNVnetscapeWindow:
+ {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ HWND handle = plugin->window_handle();
+ *((void**)value) = (void*)handle;
+ rv = NPERR_NO_ERROR;
+ break;
+ }
+ case NPNVjavascriptEnabledBool:
+ {
+ // yes, JS is enabled.
+ *((void**)value) = (void*)1;
+ rv = NPERR_NO_ERROR;
+ break;
+ }
+ case NPNVserviceManager:
+ {
+ NPAPI::PluginInstance* instance =
+ NPAPI::PluginInstance::GetInitializingInstance();
+ if (instance) {
+ instance->GetServiceManager(reinterpret_cast<void**>(value));
+ } else {
+ NOTREACHED();
+ }
+
+ rv = NPERR_NO_ERROR;
+ break;
+ }
+ case default_plugin::kMissingPluginStatusStart +
+ default_plugin::MISSING_PLUGIN_AVAILABLE:
+ // fall through
+ case default_plugin::kMissingPluginStatusStart +
+ default_plugin::MISSING_PLUGIN_USER_STARTED_DOWNLOAD:
+ {
+ // This is a hack for the default plugin to send notification to renderer.
+ // Because we will check if the plugin is default plugin, we don't need
+ // to worry about future standard change that may conflict with the
+ // variable definition.
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin->plugin_lib()->plugin_info().file == kDefaultPluginDllName)
+ plugin->webplugin()->OnMissingPluginStatus(
+ variable - default_plugin::kMissingPluginStatusStart);
+ break;
+ }
+ default:
+ {
+ // TODO: implement me
+ break;
+ }
+ }
+ return rv;
+}
+
+NPError NPN_SetValue(NPP id, NPPVariable variable, void *value) {
+ // Allows the plugin to set various modes
+
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ switch(variable)
+ {
+ case NPPVpluginWindowBool:
+ {
+ // Sets windowless mode for display of the plugin
+ // Note: the documentation at http://developer.mozilla.org/en/docs/NPN_SetValue
+ // is wrong. When value is NULL, the mode is set to true. This is the same
+ // way Mozilla works.
+ bool mode = (value == 0);
+ plugin->set_windowless(mode);
+ return NPERR_NO_ERROR;
+ }
+ case NPPVpluginTransparentBool:
+ {
+ // Sets transparent mode for display of the plugin
+ //
+ // Transparent plugins require the browser to paint the background
+ // before having the plugin paint. By default, windowless plugins
+ // are transparent. Making a windowless plugin opaque means that
+ // the plugin does not require the browser to paint the background.
+ //
+ bool mode = (value != 0);
+ plugin->set_transparent(mode);
+ return NPERR_NO_ERROR;
+ }
+ case NPPVjavascriptPushCallerBool:
+ // Specifies whether you are pushing or popping the JSContext off
+ // the stack
+ // TODO: implement me
+ return NPERR_GENERIC_ERROR;
+ case NPPVpluginKeepLibraryInMemory:
+ // Tells browser that plugin dll should live longer than usual.
+ // TODO: implement me
+ return NPERR_GENERIC_ERROR;
+ default:
+ // TODO: implement me
+ break;
+ }
+
+ NOTREACHED();
+ return NPERR_GENERIC_ERROR;
+}
+
+void *NPN_GetJavaEnv() {
+ // TODO: implement me
+ return NULL;
+}
+
+void *NPN_GetJavaPeer(NPP) {
+ // TODO: implement me
+ return NULL;
+}
+
+void NPN_PushPopupsEnabledState(NPP id, NPBool enabled) {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin) {
+ plugin->PushPopupsEnabledState(enabled);
+ }
+}
+
+void NPN_PopPopupsEnabledState(NPP id) {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin) {
+ plugin->PopPopupsEnabledState();
+ }
+}
+
+void NPN_PluginThreadAsyncCall(NPP id,
+ void (*func)(void *),
+ void *userData) {
+ scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
+ if (plugin) {
+ plugin->PluginThreadAsyncCall(func, userData);
+ }
+}
+
+bool NPN_Construct(NPP npp,
+ NPObject* obj,
+ const NPVariant *args,
+ uint32_t argCount,
+ NPVariant *result) {
+ NOTREACHED();
+ return false;
+}
+
+} // extern "C"
diff --git a/webkit/glue/plugins/plugin_host.h b/webkit/glue/plugins/plugin_host.h
new file mode 100644
index 0000000..61f03c5
--- /dev/null
+++ b/webkit/glue/plugins/plugin_host.h
@@ -0,0 +1,107 @@
+// 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.
+
+// TODO: Need mechanism to cleanup the static instance
+
+#ifndef WEBKIT_GLUE_PLUGIN_PLUGIN_HOST_H__
+#define WEBKIT_GLUE_PLUGIN_PLUGIN_HOST_H__
+
+#include <string>
+#include <vector>
+#include <map>
+
+#include "base/ref_counted.h"
+#include "base/gfx/rect.h"
+#include "base/task.h"
+#include "webkit/glue/plugins/nphostapi.h"
+#include "third_party/npapi/bindings/npapi.h"
+
+namespace NPAPI
+{
+class PluginInstance;
+
+// The Plugin Host implements the NPN_xxx functions for NPAPI plugins.
+// These are the functions exposed from the Plugin Host for use
+// by the Plugin.
+//
+// The PluginHost is managed as a singleton. This isn't strictly
+// necessary, but since the callback functions are all global C
+// functions, there is really no point in having per-instance PluginHosts.
+class PluginHost : public base::RefCounted<PluginHost> {
+ public:
+ // Access the single PluginHost instance. Callers
+ // must call deref() when finished with the object.
+ static PluginHost *Singleton();
+ virtual ~PluginHost();
+
+ // The table of functions provided to the plugin.
+ NPNetscapeFuncs *host_functions() { return &host_funcs_; }
+
+ // Helper function for parsing post headers, and applying attributes
+ // to the stream. NPAPI post data include headers + data combined.
+ // This function parses it out and adds it to the stream in a WebKit
+ // style.
+ static bool SetPostData(const char *buf,
+ uint32 length,
+ std::vector<std::string>* names,
+ std::vector<std::string>* values,
+ std::vector<char>* body);
+
+ void PatchNPNetscapeFuncs(NPNetscapeFuncs* overrides);
+
+ // Handles invalidateRect requests for windowless plugins.
+ void InvalidateRect(NPP id, NPRect* invalidRect);
+
+ private:
+ PluginHost();
+ void InitializeHostFuncs();
+ // For certain plugins like flash we need to throttle invalidateRect
+ // requests as they are made at a high frequency.
+ void OnInvalidateRect(NPP id, PluginInstance* instance);
+
+ static scoped_refptr<PluginHost> singleton_;
+ NPNetscapeFuncs host_funcs_;
+ DISALLOW_EVIL_CONSTRUCTORS(PluginHost);
+
+ // This structure keeps track of individual plugin instance invalidates.
+ struct ThrottledInvalidates {
+ std::vector<gfx::Rect> throttled_invalidates;
+ };
+
+ // We need to track throttled invalidate rects on a per plugin instance
+ // basis.
+ typedef std::map<NPP, ThrottledInvalidates> InstanceThrottledInvalidatesMap;
+ InstanceThrottledInvalidatesMap instance_throttled_invalidates_;
+
+ ScopedRunnableMethodFactory<PluginHost> throttle_factory_;
+};
+
+} // namespace NPAPI
+
+#endif // WEBKIT_GLUE_PLUGIN_PLUGIN_HOST_H__
diff --git a/webkit/glue/plugins/plugin_instance.cc b/webkit/glue/plugins/plugin_instance.cc
new file mode 100644
index 0000000..62e1357
--- /dev/null
+++ b/webkit/glue/plugins/plugin_instance.cc
@@ -0,0 +1,463 @@
+// 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/plugins/plugin_instance.h"
+
+#include "base/message_loop.h"
+#include "base/string_util.h"
+#include "base/thread_local_storage.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/webplugin.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/plugins/plugin_data_stream.h"
+#include "webkit/glue/plugins/plugin_host.h"
+#include "webkit/glue/plugins/plugin_lib.h"
+#include "webkit/glue/plugins/plugin_stream_url.h"
+#include "webkit/glue/plugins/plugin_string_stream.h"
+#include "webkit/glue/plugins/mozilla_extensions.h"
+#include "net/base/escape.h"
+
+namespace NPAPI
+{
+int PluginInstance::plugin_instance_tls_index_ = ThreadLocalStorage::Alloc();
+
+PluginInstance::PluginInstance(PluginLib *plugin, const std::string &mime_type)
+ : plugin_(plugin),
+ npp_(0),
+ host_(PluginHost::Singleton()),
+ npp_functions_(plugin->functions()),
+ hwnd_(0),
+ windowless_(false),
+ transparent_(true),
+ mime_type_(mime_type),
+ webplugin_(0),
+ use_mozilla_user_agent_(false),
+ message_loop_(MessageLoop::current()),
+ load_manually_(false),
+ throttle_invalidate_(false),
+ get_notify_data_(NULL),
+ in_close_streams_(false) {
+ npp_ = new NPP_t();
+ npp_->ndata = 0;
+ npp_->pdata = 0;
+
+ memset(&zero_padding_, 0, sizeof(zero_padding_));
+ DCHECK(message_loop_);
+}
+
+PluginInstance::~PluginInstance() {
+ CloseStreams();
+
+ if (npp_ != 0) {
+ delete npp_;
+ npp_ = 0;
+ }
+
+ if (plugin_)
+ plugin_->CloseInstance();
+}
+
+PluginStreamUrl *PluginInstance::CreateStream(int resource_id,
+ const std::string &url,
+ const std::string &mime_type,
+ bool notify_needed,
+ void *notify_data) {
+ PluginStreamUrl *stream = new PluginStreamUrl(
+ resource_id, GURL(url), this, notify_needed, notify_data);
+
+ AddStream(stream);
+ return stream;
+}
+
+void PluginInstance::SendStream(const std::string &url,
+ bool notify_needed,
+ void *notify_data) {
+ if (notify_needed) {
+ host_->host_functions()->geturlnotify(npp(), url.c_str(), NULL,
+ notify_data);
+ } else {
+ host_->host_functions()->geturl(npp(), url.c_str(), NULL);
+ }
+}
+
+void PluginInstance::AddStream(PluginStream* stream) {
+ open_streams_.push_back(stream);
+}
+
+void PluginInstance::RemoveStream(PluginStream* stream) {
+ if (in_close_streams_)
+ return;
+
+ std::vector<scoped_refptr<PluginStream> >::iterator stream_index;
+ for (stream_index = open_streams_.begin();
+ stream_index != open_streams_.end(); ++stream_index) {
+ if (*stream_index == stream) {
+ open_streams_.erase(stream_index);
+ break;
+ }
+ }
+}
+
+bool PluginInstance::IsValidStream(const NPStream* stream) {
+ std::vector<scoped_refptr<PluginStream> >::iterator stream_index;
+ for (stream_index = open_streams_.begin();
+ stream_index != open_streams_.end(); ++stream_index) {
+ if ((*stream_index)->stream() == stream)
+ return true;
+ }
+
+ return false;
+}
+
+void PluginInstance::CloseStreams() {
+ in_close_streams_ = true;
+ for (unsigned int index = 0; index < open_streams_.size(); ++index) {
+ // Close all streams on the way down.
+ open_streams_[index]->Close(NPRES_USER_BREAK);
+ }
+ open_streams_.clear();
+ in_close_streams_ = false;
+}
+
+bool PluginInstance::HandleEvent(UINT message, WPARAM wParam, LPARAM lParam) {
+ if (!windowless_)
+ return false;
+
+ NPEvent windowEvent;
+ windowEvent.event = message;
+ windowEvent.lParam = static_cast<uint32>(lParam);
+ windowEvent.wParam = static_cast<uint32>(wParam);
+ return NPP_HandleEvent(&windowEvent) != 0;
+}
+
+bool PluginInstance::Start(const GURL& url,
+ char** const param_names,
+ char** const param_values,
+ int param_count,
+ bool load_manually) {
+ load_manually_ = load_manually;
+ instance_url_ = url;
+ unsigned short mode = load_manually_ ? NP_FULL : NP_EMBED;
+ npp_->ndata = this;
+
+ NPError err = NPP_New(mode, param_count,
+ const_cast<char **>(param_names), const_cast<char **>(param_values));
+ return err == NPERR_NO_ERROR;
+}
+
+NPObject *PluginInstance::GetPluginScriptableObject() {
+ NPObject *value;
+ NPError error = NPP_GetValue(NPPVpluginScriptableNPObject, &value);
+ if (error != NPERR_NO_ERROR)
+ return NULL;
+ return value;
+}
+
+void PluginInstance::SetURLLoadData(const GURL& url,
+ void* notify_data) {
+ get_url_ = url;
+ get_notify_data_ = notify_data;
+}
+
+// WebPluginLoadDelegate methods
+void PluginInstance::DidFinishLoadWithReason(NPReason reason) {
+ if (!get_url_.is_empty()) {
+ NPP_URLNotify(get_url_.spec().c_str(), reason, get_notify_data_);
+ }
+
+ get_url_ = GURL();
+ get_notify_data_ = NULL;
+}
+
+// NPAPI methods
+NPError PluginInstance::NPP_New(unsigned short mode,
+ short argc,
+ char *argn[],
+ char *argv[]) {
+ DCHECK(npp_functions_ != 0);
+ DCHECK(npp_functions_->newp != 0);
+ DCHECK(argc >= 0);
+
+ if (npp_functions_->newp != 0) {
+ return npp_functions_->newp(
+ (NPMIMEType)mime_type_.c_str(), npp_, mode, argc, argn, argv, NULL);
+ }
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+}
+
+void PluginInstance::NPP_Destroy() {
+ DCHECK(npp_functions_ != 0);
+ DCHECK(npp_functions_->newp != 0);
+
+ if (npp_functions_->destroy != 0) {
+ NPSavedData *savedData = 0;
+ npp_functions_->destroy(npp_, &savedData);
+
+ // TODO: Support savedData. Technically, these need to be
+ // saved on a per-URL basis, and then only passed
+ // to new instances of the plugin at the same URL.
+ // Sounds like a huge security risk. When we do support
+ // these, we should pass them back to the PluginLib
+ // to be stored there.
+ DCHECK(savedData == 0);
+ }
+
+ // Clean up back references to this instance if any
+ if (mozilla_extenstions_) {
+ mozilla_extenstions_->DetachFromInstance();
+ mozilla_extenstions_ = NULL;
+ }
+}
+
+NPError PluginInstance::NPP_SetWindow(NPWindow *window) {
+ DCHECK(npp_functions_ != 0);
+ DCHECK(npp_functions_->setwindow != 0);
+
+ if (npp_functions_->setwindow != 0) {
+ return npp_functions_->setwindow(npp_, window);
+ }
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+}
+
+NPError PluginInstance::NPP_NewStream(NPMIMEType type,
+ NPStream *stream,
+ NPBool seekable,
+ unsigned short *stype) {
+ DCHECK(npp_functions_ != 0);
+ DCHECK(npp_functions_->newstream != 0);
+ if (npp_functions_->newstream != 0) {
+ return npp_functions_->newstream(npp_, type, stream, seekable, stype);
+ }
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+}
+
+NPError PluginInstance::NPP_DestroyStream(NPStream *stream, NPReason reason) {
+ DCHECK(npp_functions_ != 0);
+ DCHECK(npp_functions_->destroystream != 0);
+
+ if (stream == NULL || (stream->ndata == NULL) ||
+ !IsValidStream(stream))
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ if (npp_functions_->destroystream != 0) {
+ NPError result = npp_functions_->destroystream(npp_, stream, reason);
+ stream->ndata = NULL;
+ return result;
+ }
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+}
+
+int PluginInstance::NPP_WriteReady(NPStream *stream) {
+ DCHECK(npp_functions_ != 0);
+ DCHECK(npp_functions_->writeready != 0);
+ if (npp_functions_->writeready != 0) {
+ return npp_functions_->writeready(npp_, stream);
+ }
+ return NULL;
+}
+
+int PluginInstance::NPP_Write(NPStream *stream,
+ int offset,
+ int len,
+ void *buffer) {
+ DCHECK(npp_functions_ != 0);
+ DCHECK(npp_functions_->write != 0);
+ if (npp_functions_->write != 0) {
+ return npp_functions_->write(npp_, stream, offset, len, buffer);
+ }
+ return NULL;
+}
+
+void PluginInstance::NPP_StreamAsFile(NPStream *stream, const char *fname) {
+ DCHECK(npp_functions_ != 0);
+ DCHECK(npp_functions_->asfile != 0);
+ if (npp_functions_->asfile != 0) {
+ npp_functions_->asfile(npp_, stream, fname);
+ }
+}
+
+void PluginInstance::NPP_URLNotify(const char *url,
+ NPReason reason,
+ void *notifyData) {
+ DCHECK(npp_functions_ != 0);
+ DCHECK(npp_functions_->urlnotify != 0);
+ if (npp_functions_->urlnotify != 0) {
+ npp_functions_->urlnotify(npp_, url, reason, notifyData);
+ }
+}
+
+NPError PluginInstance::NPP_GetValue(NPPVariable variable, void *value) {
+ DCHECK(npp_functions_ != 0);
+ // getvalue is NULL for Shockwave
+ if (npp_functions_->getvalue != 0) {
+ return npp_functions_->getvalue(npp_, variable, value);
+ }
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+}
+
+NPError PluginInstance::NPP_SetValue(NPNVariable variable, void *value) {
+ DCHECK(npp_functions_ != 0);
+ if (npp_functions_->setvalue != 0) {
+ return npp_functions_->setvalue(npp_, variable, value);
+ }
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+}
+
+short PluginInstance::NPP_HandleEvent(NPEvent *event) {
+ DCHECK(npp_functions_ != 0);
+ DCHECK(npp_functions_->event != 0);
+ if (npp_functions_->event != 0) {
+ return npp_functions_->event(npp_, (void*)event);
+ }
+ return false;
+}
+
+bool PluginInstance::NPP_Print(NPPrint* platform_print) {
+ DCHECK(npp_functions_ != 0);
+ if (npp_functions_->print != 0) {
+ npp_functions_->print(npp_, platform_print);
+ return true;
+ }
+ return false;
+}
+
+void PluginInstance::SendJavaScriptStream(const std::string& url,
+ const std::wstring& result,
+ bool success,
+ bool notify_needed,
+ int notify_data) {
+ if (success) {
+ PluginStringStream *stream =
+ new PluginStringStream(this, url, notify_needed,
+ reinterpret_cast<void*>(notify_data));
+ AddStream(stream);
+ stream->SendToPlugin(WideToUTF8(result), "text/html");
+ } else {
+ // NOTE: Sending an empty stream here will crash MacroMedia
+ // Flash 9. Just send the URL Notify.
+ if (notify_needed) {
+ this->NPP_URLNotify(url.c_str(), NPRES_DONE,
+ reinterpret_cast<void*>(notify_data));
+ }
+ }
+}
+
+void PluginInstance::DidReceiveManualResponse(const std::string& url,
+ const std::string& mime_type,
+ const std::string& headers,
+ uint32 expected_length,
+ uint32 last_modified) {
+ DCHECK(load_manually_);
+ std::string response_url = url;
+ if (response_url.empty()) {
+ response_url = instance_url_.spec();
+ }
+
+ plugin_data_stream_ = new PluginDataStream(this, response_url, mime_type,
+ headers, expected_length,
+ last_modified);
+ AddStream(plugin_data_stream_.get());
+}
+
+void PluginInstance::DidReceiveManualData(const char* buffer, int length) {
+ DCHECK(load_manually_);
+ DCHECK(plugin_data_stream_.get() != NULL);
+ plugin_data_stream_->SendToPlugin(buffer, length);
+}
+
+void PluginInstance::DidFinishManualLoading() {
+ DCHECK(load_manually_);
+ DCHECK(plugin_data_stream_);
+ plugin_data_stream_->Close(NPRES_DONE);
+ RemoveStream(plugin_data_stream_.get());
+ plugin_data_stream_ = NULL;
+}
+
+void PluginInstance::DidManualLoadFail() {
+ DCHECK(load_manually_);
+ DCHECK(plugin_data_stream_);
+ plugin_data_stream_->Close(NPRES_NETWORK_ERR);
+ RemoveStream(plugin_data_stream_.get());
+ plugin_data_stream_ = NULL;
+}
+
+void PluginInstance::PluginThreadAsyncCall(void (*func)(void *),
+ void *userData) {
+ message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &PluginInstance::OnPluginThreadAsyncCall, func, userData));
+}
+
+void PluginInstance::OnPluginThreadAsyncCall(void (*func)(void *),
+ void *userData) {
+ // We are invoking an arbitrary callback provided by a third
+ // party plugin. It's better to wrap this into an exception
+ // block to protect us from crashes.
+ __try {
+ func(userData);
+ } __except(EXCEPTION_EXECUTE_HANDLER) {
+ // Maybe we can disable a crashing plugin.
+ // But for now, just continue.
+ }
+}
+
+PluginInstance* PluginInstance::SetInitializingInstance(
+ PluginInstance* instance) {
+ PluginInstance* old_instance =
+ static_cast<PluginInstance*>(
+ ThreadLocalStorage::Get(plugin_instance_tls_index_));
+ ThreadLocalStorage::Set(plugin_instance_tls_index_, instance);
+ return old_instance;
+}
+
+PluginInstance* PluginInstance::GetInitializingInstance() {
+ PluginInstance* instance =
+ static_cast<PluginInstance*>(
+ ThreadLocalStorage::Get(plugin_instance_tls_index_));
+ return instance;}
+
+NPError PluginInstance::GetServiceManager(void** service_manager) {
+ if (!mozilla_extenstions_) {
+ mozilla_extenstions_ = new MozillaExtensionApi(this);
+ }
+
+ DCHECK(mozilla_extenstions_);
+ mozilla_extenstions_->QueryInterface(nsIServiceManager::GetIID(),
+ service_manager);
+ return NPERR_NO_ERROR;
+}
+
+void PluginInstance::PushPopupsEnabledState(bool enabled) {
+ popups_enabled_stack_.push(enabled);
+}
+
+void PluginInstance::PopPopupsEnabledState() {
+ popups_enabled_stack_.pop();
+}
+
+} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_instance.h b/webkit/glue/plugins/plugin_instance.h
new file mode 100644
index 0000000..5743c24
--- /dev/null
+++ b/webkit/glue/plugins/plugin_instance.h
@@ -0,0 +1,288 @@
+// 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.
+
+// TODO: Need to deal with NPAPI's NPSavedData.
+// I haven't seen plugins use it yet.
+
+#ifndef WEBKIT_GLUE_PLUGIN_PLUGIN_INSTANCE_H__
+#define WEBKIT_GLUE_PLUGIN_PLUGIN_INSTANCE_H__
+
+#include <string>
+#include <vector>
+#include <stack>
+
+#include "base/basictypes.h"
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+#include "webkit/glue/plugins/nphostapi.h"
+#include "googleurl/src/gurl.h"
+#include "third_party/npapi/bindings/npapi.h"
+
+class WebPlugin;
+class MessageLoop;
+
+namespace NPAPI
+{
+class PluginLib;
+class PluginHost;
+class PluginStream;
+class PluginStreamUrl;
+class PluginDataStream;
+class MozillaExtensionApi;
+
+// A PluginInstance is an active, running instance of a Plugin.
+// A single plugin may have many PluginInstances.
+class PluginInstance : public base::RefCounted<PluginInstance> {
+ public:
+ // Create a new instance of a plugin. The PluginInstance
+ // will hold a reference to the plugin.
+ PluginInstance(PluginLib *plugin, const std::string &mime_type);
+ virtual ~PluginInstance();
+
+ // Activates the instance by calling NPP_New.
+ // This should be called after our instance is all
+ // setup from the host side and we are ready to receive
+ // requests from the plugin. We must not call any
+ // functions on the plugin instance until start has
+ // been called.
+ //
+ // url: The instance URL.
+ // param_names: the list of names of attributes passed via the
+ // element.
+ // param_values: the list of values corresponding to param_names
+ // param_count: number of attributes
+ // load_manually: if true indicates that the plugin data would be passed
+ // from webkit. if false indicates that the plugin should
+ // download the data.
+ // This also controls whether the plugin is instantiated as
+ // a full page plugin (NP_FULL) or embedded (NP_EMBED)
+ //
+ bool Start(const GURL& url,
+ char** const param_names,
+ char** const param_values,
+ int param_count,
+ bool load_manually);
+
+ // NPAPI's instance identifier for this instance
+ NPP npp() { return npp_; }
+
+ // Get/Set for the instance's HWND.
+ HWND window_handle() { return hwnd_; }
+ void set_window_handle(HWND value) { hwnd_ = value; }
+
+ // Get/Set whether this instance is in Windowless mode.
+ // Default is false.
+ bool windowless() { return windowless_; }
+ void set_windowless(bool value) { windowless_ = value; }
+
+ // Get/Set whether this instance is transparent.
+ // This only applies to windowless plugins. Transparent
+ // plugins require that webkit paint the background.
+ // Default is true.
+ bool transparent() { return transparent_; }
+ void set_transparent(bool value) { transparent_ = value; }
+
+ // Get/Set the WebPlugin associated with this instance
+ WebPlugin* webplugin() { return webplugin_; }
+ void set_web_plugin(WebPlugin* webplugin) { webplugin_ = webplugin; }
+
+ // Get the mimeType for this plugin stream
+ const std::string &mime_type() { return mime_type_; }
+
+ NPAPI::PluginLib* plugin_lib() { return plugin_; }
+
+ // Handles a windows native message which this PluginInstance should deal
+ // with. Returns true if the event is handled, false otherwise.
+ bool HandleEvent(UINT message, WPARAM wParam, LPARAM lParam);
+
+ // Creates a stream for sending an URL. If notify_needed
+ // is true, it will send a notification to the plugin
+ // when the stream is complete; otherwise it will not.
+ // Set object_url to true if the load is for the object tag's
+ // url, or false if it's for a url that the plugin
+ // fetched through NPN_GetUrl[Notify].
+ PluginStreamUrl *CreateStream(int resource_id,
+ const std::string &url,
+ const std::string &mime_type,
+ bool notify_needed,
+ void *notify_data);
+
+ // Convenience function for sending a stream from a URL to this instance.
+ // URL can be a relative or a fully qualified url.
+ void SendStream(const std::string& url, bool notify_needed,
+ void* notify_data);
+ // For each instance, we track all streams. When the
+ // instance closes, all remaining streams are also
+ // closed. All streams associated with this instance
+ // should call AddStream so that they can be cleaned
+ // up when the instance shuts down.
+ void AddStream(PluginStream* stream);
+
+ // This is called when a stream is closed. We remove the stream from the
+ // list, which releases the reference maintained to the stream.
+ void RemoveStream(PluginStream* stream);
+
+ // Closes all open streams on this instance.
+ void CloseStreams();
+
+ // Have the plugin create it's script object.
+ NPObject *GetPluginScriptableObject();
+
+ // WebViewDelegate methods that we implement. This is for handling
+ // callbacks during getURLNotify.
+ virtual void DidFinishLoadWithReason(NPReason reason);
+
+ // Helper method to set some persistent data for getURLNotify since
+ // resource fetches happen async.
+ void SetURLLoadData(const GURL& url, void* notify_data);
+
+ // If true, send the Mozilla user agent instead of Chrome's to the plugin.
+ bool use_mozilla_user_agent() { return use_mozilla_user_agent_; }
+ void set_use_mozilla_user_agent() { use_mozilla_user_agent_ = true; }
+
+ bool throttle_invalidate() const { return throttle_invalidate_; }
+ void set_throttle_invalidate(bool throttle_invalidate) {
+ throttle_invalidate_ = throttle_invalidate;
+ }
+
+ // Helper that implements NPN_PluginThreadAsyncCall semantics
+ void PluginThreadAsyncCall(void (*func)(void *),
+ void *userData);
+
+ //
+ // NPAPI methods for calling the Plugin Instance
+ //
+ NPError NPP_New(unsigned short, short, char *[], char *[]);
+ NPError NPP_SetWindow(NPWindow *);
+ NPError NPP_NewStream(NPMIMEType, NPStream *, NPBool, unsigned short *);
+ NPError NPP_DestroyStream(NPStream *, NPReason);
+ int NPP_WriteReady(NPStream *);
+ int NPP_Write(NPStream *, int, int, void *);
+ void NPP_StreamAsFile(NPStream *, const char *);
+ void NPP_URLNotify(const char *, NPReason, void *);
+ NPError NPP_GetValue(NPPVariable, void *);
+ NPError NPP_SetValue(NPNVariable, void *);
+ short NPP_HandleEvent(NPEvent *);
+ void NPP_Destroy();
+ bool NPP_Print(NPPrint* platform_print);
+
+ void SendJavaScriptStream(const std::string& url, const std::wstring& result,
+ bool success, bool notify_needed, int notify_data);
+
+ void DidReceiveManualResponse(const std::string& url,
+ const std::string& mime_type,
+ const std::string& headers,
+ uint32 expected_length,
+ uint32 last_modified);
+ void DidReceiveManualData(const char* buffer, int length);
+ void DidFinishManualLoading();
+ void DidManualLoadFail();
+
+ NPError GetServiceManager(void** service_manager);
+
+ static PluginInstance* SetInitializingInstance(PluginInstance* instance);
+ static PluginInstance* GetInitializingInstance();
+
+ void PushPopupsEnabledState(bool enabled);
+ void PopPopupsEnabledState();
+
+ bool popups_allowed() const {
+ return popups_enabled_stack_.empty() ? false : popups_enabled_stack_.top();
+ }
+
+ private:
+ void OnPluginThreadAsyncCall(void (*func)(void *),
+ void *userData);
+ bool IsValidStream(const NPStream* stream);
+
+ // This is a hack to get the real player plugin to work with chrome
+ // The real player plugin dll(nppl3260) when loaded by firefox is loaded via
+ // the NS COM API which is analogous to win32 COM. So the NPAPI functions in
+ // the plugin are invoked via an interface by firefox. The plugin instance
+ // handle which is passed to every NPAPI method is owned by the real player
+ // plugin, i.e. it expects the ndata member to point to a structure which
+ // it knows about. Eventually it dereferences this structure and compares
+ // a member variable at offset 0x24(Version 6.0.11.2888) /2D (Version
+ // 6.0.11.3088) with 0 and on failing this check, takes a different code
+ // path which causes a crash. Safari and Opera work with version 6.0.11.2888
+ // by chance as their ndata structure contains a 0 at the location which real
+ // player checks:(. They crash with version 6.0.11.3088 as well. The
+ // following member just adds a 96 byte padding to our PluginInstance class
+ // which is passed in the ndata member. This magic number works correctly on
+ // Vista with UAC on or off :(.
+ // NOTE: Please dont change the ordering of the member variables
+ // New members should be added after this padding array.
+ // TODO(iyengar) : Disassemble the Realplayer ndata structure and look into
+ // the possiblity of conforming to it (http://b/issue?id=936667). We
+ // could also log a bug with Real, which would save the effort.
+ uint8 zero_padding_[96];
+ scoped_refptr<NPAPI::PluginLib> plugin_;
+ NPP npp_;
+ scoped_refptr<PluginHost> host_;
+ NPPluginFuncs* npp_functions_;
+ std::vector<scoped_refptr<PluginStream> > open_streams_;
+ HWND hwnd_;
+ bool windowless_;
+ bool transparent_;
+ WebPlugin* webplugin_;
+ std::string mime_type_;
+ GURL get_url_;
+ void* get_notify_data_;
+ bool use_mozilla_user_agent_;
+ scoped_refptr<MozillaExtensionApi> mozilla_extenstions_;
+ MessageLoop* message_loop_;
+ // Using TLS to store PluginInstance object during its creation.
+ // We need to pass this instance to the service manager
+ // (MozillaExtensionApi) created as a result of NPN_GetValue
+ // in the context of NP_Initialize.
+ static int plugin_instance_tls_index_;
+ scoped_refptr<PluginDataStream> plugin_data_stream_;
+ GURL instance_url_;
+
+ // This flag if true indicates that the plugin data would be passed from
+ // webkit. if false indicates that the plugin should download the data.
+ bool load_manually_;
+
+ // This flag indicates if the NPN_InvalidateRect calls made by the
+ // plugin need to be throttled.
+ bool throttle_invalidate_;
+
+ // Stack indicating if popups are to be enabled for the outgoing
+ // NPN_GetURL/NPN_GetURLNotify calls.
+ std::stack<bool> popups_enabled_stack_;
+
+ // True if in CloseStreams().
+ bool in_close_streams_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(PluginInstance);
+};
+
+} // namespace NPAPI
+
+#endif // WEBKIT_GLUE_PLUGIN_PLUGIN_INSTANCE_H__ \ No newline at end of file
diff --git a/webkit/glue/plugins/plugin_lib.cc b/webkit/glue/plugins/plugin_lib.cc
new file mode 100644
index 0000000..bf36152
--- /dev/null
+++ b/webkit/glue/plugins/plugin_lib.cc
@@ -0,0 +1,433 @@
+// 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 "config.h"
+
+#include "webkit/glue/plugins/plugin_lib.h"
+
+#include "base/file_util.h"
+#include "base/file_version_info.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "base/stats_counters.h"
+#include "base/string_util.h"
+#include "base/task.h"
+#include "webkit/activex_shim/npp_impl.h"
+#include "webkit/default_plugin/plugin_main.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/webplugin.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/plugins/plugin_instance.h"
+#include "webkit/glue/plugins/plugin_host.h"
+#include "webkit/glue/plugins/plugin_list.h"
+#include "net/base/mime_util.h"
+
+
+namespace NPAPI
+{
+
+const wchar_t kPluginLibrariesLoadedCounter[] = L"PluginLibrariesLoaded";
+const wchar_t kPluginInstancesActiveCounter[] = L"PluginInstancesActive";
+
+PluginLib::PluginMap* PluginLib::loaded_libs_;
+
+PluginLib* PluginLib::CreatePluginLib(const std::wstring& filename) {
+ // We can only have one PluginLib object per plugin as it controls the per
+ // instance function calls (i.e. NP_Initialize and NP_Shutdown). So we keep
+ // a (non-ref counted) map of PluginLib objects.
+ if (!loaded_libs_)
+ loaded_libs_ = new PluginMap();
+
+ PluginMap::const_iterator iter = loaded_libs_->find(filename);
+ if (iter != loaded_libs_->end())
+ return iter->second;
+
+ static const InternalPluginInfo activex_shim_info = {
+ {kActiveXShimFileName,
+ L"ActiveX Plug-in",
+ L"ActiveX Plug-in provides a shim to support ActiveX controls",
+ L"1, 0, 0, 1",
+ L"application/x-oleobject|application/oleobject|"
+ L"application/x-ms-wmp|application/asx|video/x-ms-asf-plugin|"
+ L"application/x-mplayer2|video/x-ms-asf|video/x-ms-wm|audio/x-ms-wma|"
+ L"audio/x-ms-wax|video/x-ms-wmv|video/x-ms-wvx",
+ L"*|*|*|*|*|*|asf,asx,*|wm,*|wma,*|wax,*|wmv,*|wvx,*",
+ L""
+ },
+ activex_shim::ActiveX_Shim_NP_GetEntryPoints,
+ activex_shim::ActiveX_Shim_NP_Initialize,
+ activex_shim::ActiveX_Shim_NP_Shutdown
+ };
+
+ static const InternalPluginInfo default_null_plugin_info = {
+ {kDefaultPluginDllName,
+ L"Default Plug-in",
+ L"Provides functionality for installing third-party plug-ins",
+ L"1, 0, 0, 1",
+ L"*",
+ L"",
+ L""
+ },
+ default_plugin::NP_GetEntryPoints,
+ default_plugin::NP_Initialize,
+ default_plugin::NP_Shutdown
+ };
+
+ WebPluginInfo* info = NULL;
+ const InternalPluginInfo* internal_plugin_info = NULL;
+ if (filename == activex_shim_info.version_info.file_name) {
+ info = CreateWebPluginInfo(activex_shim_info.version_info);
+ internal_plugin_info = &activex_shim_info;
+ } else if (filename == default_null_plugin_info.version_info.file_name) {
+ info = CreateWebPluginInfo(default_null_plugin_info.version_info);
+ internal_plugin_info = &default_null_plugin_info;
+ } else {
+ info = ReadWebPluginInfo(filename);
+ if (!info) {
+ DLOG(INFO) << "This file isn't a valid NPAPI plugin: " << filename;
+ return NULL;
+ }
+ }
+
+ return new PluginLib(info, internal_plugin_info);
+}
+
+void PluginLib::UnloadAllPlugins() {
+ if (loaded_libs_) {
+ PluginMap::iterator lib_index;
+ for (lib_index = loaded_libs_->begin(); lib_index != loaded_libs_->end();
+ ++lib_index) {
+ lib_index->second->Unload();
+ }
+ delete loaded_libs_;
+ loaded_libs_ = NULL;
+ }
+}
+
+void PluginLib::ShutdownAllPlugins() {
+ if (loaded_libs_) {
+ PluginMap::iterator lib_index;
+ for (lib_index = loaded_libs_->begin(); lib_index != loaded_libs_->end();
+ ++lib_index) {
+ lib_index->second->Shutdown();
+ }
+ }
+}
+
+PluginLib::PluginLib(WebPluginInfo* info,
+ const InternalPluginInfo* internal_plugin_info)
+ : web_plugin_info_(info),
+ module_(0),
+ initialized_(false),
+ saved_data_(0),
+ instance_count_(0) {
+ StatsCounter(kPluginLibrariesLoadedCounter).Increment();
+ memset((void*)&plugin_funcs_, 0, sizeof(plugin_funcs_));
+
+ (*loaded_libs_)[info->file] = this;
+ if (internal_plugin_info) {
+ internal_ = true;
+ NP_Initialize_ = internal_plugin_info->np_initialize;
+ NP_GetEntryPoints_ = internal_plugin_info->np_getentrypoints;
+ NP_Shutdown_ = internal_plugin_info->np_shutdown;
+ } else {
+ internal_ = false;
+ }
+}
+
+PluginLib::~PluginLib() {
+ StatsCounter(kPluginLibrariesLoadedCounter).Decrement();
+ if (saved_data_ != 0) {
+ // TODO - delete the savedData object here
+ }
+}
+
+NPPluginFuncs *PluginLib::functions() {
+ return &plugin_funcs_;
+}
+
+bool PluginLib::SupportsType(const std::string &mime_type,
+ bool allow_wildcard) {
+ // Webkit will ask for a plugin to handle empty mime types.
+ if (mime_type.empty())
+ return false;
+
+ for (size_t i = 0; i < web_plugin_info_->mime_types.size(); ++i) {
+ const WebPluginMimeType& mime_info = web_plugin_info_->mime_types[i];
+ if (mime_util::MatchesMimeType(mime_info.mime_type, mime_type)) {
+ if (!allow_wildcard && (mime_info.mime_type == "*")) {
+ continue;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+NPError PluginLib::NP_Initialize() {
+ if (initialized_)
+ return NPERR_NO_ERROR;
+
+ if (!Load())
+ return NPERR_MODULE_LOAD_FAILED_ERROR;
+
+ PluginHost *host = PluginHost::Singleton();
+ if (host == 0)
+ return NPERR_GENERIC_ERROR;
+
+ NPError rv = NP_Initialize_(host->host_functions());
+ initialized_ = (rv == NPERR_NO_ERROR);
+ return rv;
+}
+
+void PluginLib::NP_Shutdown(void) {
+ DCHECK(initialized_);
+ NP_Shutdown_();
+}
+
+PluginInstance *PluginLib::CreateInstance(const std::string &mime_type) {
+ PluginInstance *new_instance = new PluginInstance(this, mime_type);
+ instance_count_++;
+ StatsCounter(kPluginInstancesActiveCounter).Increment();
+ DCHECK(new_instance != 0);
+ return new_instance;
+}
+
+void PluginLib::CloseInstance() {
+ StatsCounter(kPluginInstancesActiveCounter).Decrement();
+ instance_count_--;
+ // If a plugin is running in its own process it will get unloaded on process
+ // shutdown.
+ if ((instance_count_ == 0) &&
+ webkit_glue::IsPluginRunningInRendererProcess()) {
+ Unload();
+ loaded_libs_->erase(web_plugin_info_->file);
+ if (loaded_libs_->empty()) {
+ delete loaded_libs_;
+ loaded_libs_ = NULL;
+ }
+ }
+}
+
+bool PluginLib::Load() {
+ bool rv = false;
+ HMODULE module = 0;
+
+ if (!internal_) {
+ if (module_ != 0)
+ return rv;
+
+ module = LoadPluginHelper(web_plugin_info_->file);
+ if (module == 0)
+ return rv;
+
+ rv = true; // assume success now
+
+ NP_Initialize_ = (NP_InitializeFunc)GetProcAddress(
+ module, "NP_Initialize");
+ if (NP_Initialize_ == 0)
+ rv = false;
+
+ NP_GetEntryPoints_ = (NP_GetEntryPointsFunc)GetProcAddress(
+ module, "NP_GetEntryPoints");
+ if (NP_GetEntryPoints_ == 0)
+ rv = false;
+
+ NP_Shutdown_ = (NP_ShutdownFunc)GetProcAddress(
+ module, "NP_Shutdown");
+ if (NP_Shutdown_ == 0)
+ rv = false;
+ } else {
+ rv = true;
+ }
+
+ if (rv) {
+ plugin_funcs_.size = sizeof(plugin_funcs_);
+ plugin_funcs_.version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
+ if (NP_GetEntryPoints_(&plugin_funcs_) != NPERR_NO_ERROR)
+ rv = false;
+ }
+
+ if (!internal_) {
+ if (rv)
+ module_ = module;
+ else
+ FreeLibrary(module);
+ }
+
+ return rv;
+}
+
+HMODULE PluginLib::LoadPluginHelper(const std::wstring plugin_file) {
+ // Switch the current directory to the plugin directory as the plugin
+ // may have dependencies on dlls in this directory.
+ bool restore_directory = false;
+ std::wstring current_directory;
+ if (PathService::Get(base::DIR_CURRENT, &current_directory)) {
+ std::wstring plugin_path = file_util::GetDirectoryFromPath(
+ plugin_file);
+ if (!plugin_path.empty()) {
+ PathService::SetCurrentDirectory(plugin_path);
+ restore_directory = true;
+ }
+ }
+
+ HMODULE module = LoadLibrary(plugin_file.c_str());
+ if (restore_directory)
+ PathService::SetCurrentDirectory(current_directory);
+
+ return module;
+}
+
+// This class implements delayed NP_Shutdown and FreeLibrary on the plugin dll.
+class FreePluginLibraryTask : public Task {
+ public:
+ FreePluginLibraryTask(HMODULE module, NP_ShutdownFunc shutdown_func)
+ : module_(module),
+ NP_Shutdown_(shutdown_func) {
+ }
+
+ ~FreePluginLibraryTask() {}
+
+ void Run() {
+ if (NP_Shutdown_)
+ NP_Shutdown_();
+
+ if (module_) {
+ FreeLibrary(module_);
+ module_ = NULL;
+ }
+ }
+
+ private:
+ HMODULE module_;
+ NP_ShutdownFunc NP_Shutdown_;
+ DISALLOW_EVIL_CONSTRUCTORS(FreePluginLibraryTask);
+};
+
+void PluginLib::Unload() {
+ if (!internal_ && module_) {
+ // In case of single process mode, a plugin can delete itself
+ // by executing a script. So delay the unloading of the DLL
+ // so that the plugin will have a chance to unwind.
+ bool defer_unload = webkit_glue::IsPluginRunningInRendererProcess();
+
+#if USE(JAVASCRIPTCORE_BINDINGS)
+ // The plugin NPAPI instances may still be around. Delay the
+ // NP_Shutdown and FreeLibrary calls at least till the next
+ // peek message.
+ defer_unload = true;
+#endif
+
+ if (defer_unload) {
+ FreePluginLibraryTask* free_library_task =
+ new FreePluginLibraryTask(module_, NP_Shutdown_);
+ MessageLoop::current()->PostTask(FROM_HERE, free_library_task);
+ } else {
+ Shutdown();
+ FreeLibrary(module_);
+ }
+
+ module_ = 0;
+ }
+}
+
+void PluginLib::Shutdown() {
+ if (initialized_ && !internal_) {
+ NP_Shutdown();
+ initialized_ = false;
+ }
+}
+
+WebPluginInfo* PluginLib::CreateWebPluginInfo(const PluginVersionInfo& pvi) {
+ std::vector<std::string> mime_types, file_extensions;
+ std::vector<std::wstring> descriptions;
+ SplitString(WideToNativeMB(pvi.mime_types), '|', &mime_types);
+ SplitString(WideToNativeMB(pvi.file_extents), '|', &file_extensions);
+ SplitString(pvi.file_open_names, '|', &descriptions);
+
+ if (mime_types.empty())
+ return NULL;
+
+ WebPluginInfo *info = new WebPluginInfo();
+ info->name = pvi.product_name;
+ info->desc = pvi.file_description;
+ info->version = pvi.file_version;
+ info->file = StringToLowerASCII(pvi.file_name);
+
+ for (size_t i = 0; i < mime_types.size(); ++i) {
+ WebPluginMimeType mime_type;
+ mime_type.mime_type = StringToLowerASCII(mime_types[i]);
+ if (file_extensions.size() > i)
+ SplitString(file_extensions[i], ',', &mime_type.file_extensions);
+
+ if (descriptions.size() > i) {
+ mime_type.description = descriptions[i];
+
+ // Remove the extension list from the description.
+ size_t ext = mime_type.description.find(L"(*");
+ if (ext != std::wstring::npos) {
+ if (ext > 1 && mime_type.description[ext -1] == ' ')
+ ext--;
+
+ mime_type.description.erase(ext);
+ }
+ }
+
+ info->mime_types.push_back(mime_type);
+ }
+
+ return info;
+}
+
+WebPluginInfo* PluginLib::ReadWebPluginInfo(const std::wstring &filename) {
+ // On windows, the way we get the mime types for the library is
+ // to check the version information in the DLL itself. This
+ // will be a string of the format: <type1>|<type2>|<type3>|...
+ // For example:
+ // video/quicktime|audio/aiff|image/jpeg
+ scoped_ptr<FileVersionInfo> version_info(
+ FileVersionInfo::CreateFileVersionInfo(filename));
+ if (!version_info.get())
+ return NULL;
+
+ PluginVersionInfo pvi;
+ version_info->GetValue(L"MIMEType", &pvi.mime_types);
+ version_info->GetValue(L"FileExtents", &pvi.file_extents);
+ version_info->GetValue(L"FileOpenName", &pvi.file_open_names);
+ pvi.product_name = version_info->product_name();
+ pvi.file_description = version_info->file_description();
+ pvi.file_version = version_info->file_version();
+ pvi.file_name = filename;
+
+ return CreateWebPluginInfo(pvi);
+}
+
+} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_lib.h b/webkit/glue/plugins/plugin_lib.h
new file mode 100644
index 0000000..798b2ea
--- /dev/null
+++ b/webkit/glue/plugins/plugin_lib.h
@@ -0,0 +1,163 @@
+// 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 WEBKIT_GLUE_PLUGIN_PLUGIN_LIB_H__
+#define WEBKIT_GLUE_PLUGIN_PLUGIN_LIB_H__
+
+#include <hash_map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+#include "webkit/glue/plugins/nphostapi.h"
+#include "third_party/npapi/bindings/npapi.h"
+
+struct WebPluginInfo;
+
+namespace NPAPI
+{
+
+class PluginInstance;
+
+// This struct fully describes a plugin. For dll plugins, it's read in from
+// the version info of the dll; For internal plugins, it's predefined.
+struct PluginVersionInfo {
+ std::wstring file_name;
+ std::wstring product_name;
+ std::wstring file_description;
+ std::wstring file_version;
+ std::wstring mime_types;
+ std::wstring file_extents;
+ std::wstring file_open_names;
+};
+
+// This struct contains information of an internal plugin and addresses of
+// entry functions.
+struct InternalPluginInfo {
+ PluginVersionInfo version_info;
+ NP_GetEntryPointsFunc np_getentrypoints;
+ NP_InitializeFunc np_initialize;
+ NP_ShutdownFunc np_shutdown;
+};
+
+// A PluginLib is a single NPAPI Plugin Library, and is the lifecycle
+// manager for new PluginInstances.
+class PluginLib : public base::RefCounted<PluginLib> {
+ public:
+ virtual ~PluginLib();
+ static PluginLib* CreatePluginLib(const std::wstring& filename);
+
+ // Unloads all the loaded plugin dlls and cleans up the plugin map.
+ static void UnloadAllPlugins();
+
+ // Shuts down all loaded plugin instances.
+ static void ShutdownAllPlugins();
+
+ // Get the Plugin's function pointer table.
+ NPPluginFuncs *functions();
+
+ // Returns true if this Plugin supports a given mime-type.
+ // mime_type should be all lower case.
+ bool SupportsType(const std::string &mime_type, bool allow_wildcard);
+
+ // Creates a new instance of this plugin.
+ PluginInstance *CreateInstance(const std::string &mime_type);
+
+ // Called by the instance when the instance is tearing down.
+ void CloseInstance();
+
+ // Gets information about this plugin and the mime types that it
+ // supports.
+ const WebPluginInfo& plugin_info() { return *web_plugin_info_; }
+
+ //
+ // NPAPI functions
+ //
+
+ // NPAPI method to initialize a Plugin.
+ // Initialize can be safely called multiple times
+ NPError NP_Initialize();
+
+ // NPAPI method to shutdown a Plugin.
+ void NP_Shutdown(void);
+
+ // Helper function to load a plugin.
+ // Returns the module handle on success.
+ static HMODULE LoadPluginHelper(const std::wstring plugin_file);
+
+ int instance_count() const { return instance_count_; }
+
+ private:
+ // Creates a new PluginLib. The WebPluginInfo object is owned by this
+ // object. If internal_plugin_info is not NULL, this Lib is an internal
+ // plugin thus doesn't need to load dll.
+ PluginLib(WebPluginInfo* info,
+ const InternalPluginInfo* internal_plugin_info);
+
+ // Attempts to load the plugin from the DLL.
+ // Returns true if it is a legitimate plugin, false otherwise
+ bool Load();
+
+ // Unloading the plugin DLL.
+ void Unload();
+
+ // Shutdown the plugin DLL.
+ void Shutdown();
+
+ // Returns a WebPluginInfo structure given a plugin's path. Returns NULL if
+ // the dll couldn't be found, or if it's not a plugin.
+ static WebPluginInfo* ReadWebPluginInfo(const std::wstring &filename);
+ // Creates WebPluginInfo structure based on read in or built in
+ // PluginVersionInfo.
+ static WebPluginInfo* CreateWebPluginInfo(const PluginVersionInfo& info);
+
+ bool internal_; // Whether this an internal plugin.
+ scoped_ptr<WebPluginInfo> web_plugin_info_; // supported mime types, description
+ HMODULE module_; // the opened DLL handle
+ NPPluginFuncs plugin_funcs_; // the struct of plugin side functions
+ bool initialized_; // is the plugin initialized
+ NPSavedData *saved_data_; // persisted plugin info for NPAPI
+ int instance_count_; // count of plugins in use
+
+ // A map of all the insantiated plugins.
+ typedef stdext::hash_map<std::wstring, scoped_refptr<PluginLib> > PluginMap;
+ static PluginMap* loaded_libs_;
+
+ // C-style function pointers
+ NP_InitializeFunc NP_Initialize_;
+ NP_GetEntryPointsFunc NP_GetEntryPoints_;
+ NP_ShutdownFunc NP_Shutdown_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(PluginLib);
+};
+
+} // namespace NPAPI
+
+#endif // WEBKIT_GLUE_PLUGIN_PLUGIN_LIB_H__
diff --git a/webkit/glue/plugins/plugin_list.cc b/webkit/glue/plugins/plugin_list.cc
new file mode 100644
index 0000000..8c8deef
--- /dev/null
+++ b/webkit/glue/plugins/plugin_list.cc
@@ -0,0 +1,500 @@
+// 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 <algorithm>
+#include <tchar.h>
+
+#include "webkit/glue/plugins/plugin_list.h"
+
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/registry.h"
+#include "base/scoped_ptr.h"
+#include "base/string_util.h"
+#include "base/time.h"
+#include "webkit/activex_shim/activex_shared.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/webplugin.h"
+#include "webkit/glue/plugins/plugin_lib.h"
+#include "googleurl/src/gurl.h"
+
+namespace NPAPI
+{
+
+scoped_refptr<PluginList> PluginList::singleton_;
+
+static const TCHAR kRegistryApps[] =
+ _T("Software\\Microsoft\\Windows\\CurrentVersion\\App Paths");
+static const TCHAR kRegistryFirefox[] = _T("firefox.exe");
+static const TCHAR kRegistryAcrobat[] = _T("AcroRd32.exe");
+static const TCHAR kRegistryWindowsMedia[] = _T("wmplayer.exe");
+static const TCHAR kRegistryQuickTime[] = _T("QuickTimePlayer.exe");
+static const TCHAR kRegistryPath[] = _T("Path");
+static const TCHAR kRegistryMozillaPlugins[] = _T("SOFTWARE\\MozillaPlugins");
+static const TCHAR kRegistryFirefoxInstalled[] =
+ _T("SOFTWARE\\Mozilla\\Mozilla Firefox");
+static const TCHAR kMozillaActiveXPlugin[] = _T("npmozax.dll");
+static const TCHAR kNewWMPPlugin[] = _T("np-mswmp.dll");
+static const TCHAR kOldWMPPlugin[] = _T("npdsplay.dll");
+static const TCHAR kRegistryJava[] =
+ _T("Software\\JavaSoft\\Java Runtime Environment");
+static const TCHAR kRegistryBrowserJavaVersion[] = _T("BrowserJavaVersion");
+static const TCHAR kRegistryCurrentJavaVersion[] = _T("CurrentVersion");
+static const TCHAR kRegistryJavaHome[] = _T("JavaHome");
+
+// Extra registry paths to search.
+static std::vector<std::wstring>* extra_plugin_paths_ = NULL;
+
+PluginList* PluginList::Singleton() {
+ if (singleton_.get() == NULL) {
+ singleton_ = new PluginList();
+ singleton_->LoadPlugins(false);
+ }
+
+ return singleton_;
+}
+
+void PluginList::AddExtraPluginPath(const std::wstring& plugin_path) {
+ DCHECK(!singleton_.get() || !singleton_->plugins_loaded_);
+
+ if (!extra_plugin_paths_)
+ extra_plugin_paths_ = new std::vector<std::wstring>;
+ extra_plugin_paths_->push_back(plugin_path);
+}
+
+PluginList::PluginList() :
+ plugins_loaded_(false) {
+ CommandLine command_line;
+ dont_load_new_wmp_ = command_line.HasSwitch(kUseOldWMPPluginSwitch);
+ use_internal_activex_shim_ =
+ !command_line.HasSwitch(kNoNativeActiveXShimSwitch);
+}
+
+PluginList::~PluginList() {
+ plugins_.clear();
+}
+
+void PluginList::LoadPlugins(bool refresh) {
+ if (plugins_loaded_ && !refresh)
+ return;
+
+ plugins_.clear();
+ plugins_loaded_ = true;
+
+ TimeTicks start_time = TimeTicks::Now();
+
+ LoadInternalPlugins();
+
+ // Load any plugins listed in the registry
+ if (extra_plugin_paths_) {
+ for (size_t i = 0; i < extra_plugin_paths_->size(); ++i) {
+ LoadPlugin((*extra_plugin_paths_)[i]);
+ }
+ }
+
+ // Load from the application-specific area
+ LoadPlugins(GetPluginAppDirectory());
+
+ // Load from the executable area
+ LoadPlugins(GetPluginExeDirectory());
+
+ // Load Java
+ LoadJavaPlugin();
+
+ // Load firefox plugins too. This is mainly to try to locate
+ // a pre-installed Flash player.
+ LoadFirefoxPlugins();
+
+ // Firefox hard-codes the paths of some popular plugins to ensure that
+ // the plugins are found. We are going to copy this as well.
+ LoadAcrobatPlugins();
+ LoadQuicktimePlugins();
+ LoadWindowsMediaPlugins();
+
+ if (webkit_glue::IsDefaultPluginEnabled()) {
+ scoped_refptr<PluginLib> default_plugin = PluginLib::CreatePluginLib(
+ kDefaultPluginDllName);
+ plugins_.push_back(default_plugin);
+ }
+
+ TimeTicks end_time = TimeTicks::Now();
+ TimeDelta elapsed = end_time - start_time;
+ DLOG(INFO) << "Loaded plugin list in " << elapsed.InMilliseconds() << " ms.";
+}
+
+void PluginList::LoadPlugins(const std::wstring &path) {
+ WIN32_FIND_DATA find_file_data;
+ HANDLE find_handle;
+
+ std::wstring dir = path;
+ // FindFirstFile requires that you specify a wildcard for directories.
+ dir.append(L"\\NP*.DLL");
+
+ find_handle = FindFirstFile(dir.c_str(), &find_file_data);
+ if (find_handle == INVALID_HANDLE_VALUE)
+ return;
+
+ do {
+ if (!(find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ std::wstring filename = path;
+ filename.append(L"\\");
+ filename.append(find_file_data.cFileName);
+
+ LoadPlugin(filename);
+ }
+ } while (FindNextFile(find_handle, &find_file_data) != 0);
+
+ DCHECK(GetLastError() == ERROR_NO_MORE_FILES);
+ FindClose(find_handle);
+}
+
+void PluginList::LoadPlugin(const std::wstring &path) {
+ std::wstring path_lc = StringToLowerASCII(path);
+ if (!ShouldLoadPlugin(file_util::GetFilenameFromPath(path_lc)))
+ return;
+
+ scoped_refptr<PluginLib> new_plugin = PluginLib::CreatePluginLib(path_lc);
+ if (!new_plugin.get())
+ return;
+
+ const WebPluginInfo& plugin_info = new_plugin->plugin_info();
+ for (size_t i = 0; i < plugin_info.mime_types.size(); ++i) {
+ // TODO: don't load global handlers for now.
+ // WebKit hands to the Plugin before it tries
+ // to handle mimeTypes on its own.
+ const std::string &mime_type = plugin_info.mime_types[i].mime_type;
+ if (mime_type == "*" ) {
+#ifndef NDEBUG
+ // Make an exception for NPSPY.
+ if (plugin_info.file.find(L"npspy.dll") != std::wstring::npos) {
+ // Put it at the beginning so it's used before the real plugin.
+ plugins_.insert(plugins_.begin(), new_plugin.get());
+ }
+#endif
+ continue;
+ }
+
+ if (!SupportsType(mime_type))
+ plugins_.push_back(new_plugin);
+ }
+}
+
+bool PluginList::ShouldLoadPlugin(const std::wstring& filename) {
+ // Depends on XPCOM.
+ if (filename == kMozillaActiveXPlugin)
+ return false;
+
+ // We will use activex shim to handle embeded wmp media.
+ if (use_internal_activex_shim_) {
+ if (filename == kNewWMPPlugin || filename == kOldWMPPlugin)
+ return false;
+ } else {
+ // If both the new and old WMP plugins exist, only load the new one.
+ if (filename == kNewWMPPlugin) {
+ if (dont_load_new_wmp_)
+ return false;
+
+ int old_plugin = FindPluginFile(kOldWMPPlugin);
+ if (old_plugin != -1)
+ plugins_.erase(plugins_.begin() + old_plugin);
+ } else if (filename == kOldWMPPlugin) {
+ if (FindPluginFile(kNewWMPPlugin) != -1)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void PluginList::LoadInternalPlugins() {
+ if (use_internal_activex_shim_) {
+ scoped_refptr<PluginLib> new_plugin = PluginLib::CreatePluginLib(
+ kActiveXShimFileName);
+ plugins_.push_back(new_plugin);
+ }
+}
+
+int PluginList::FindPluginFile(const std::wstring& filename) {
+ for (size_t i = 0; i < plugins_.size(); ++i) {
+ if (file_util::GetFilenameFromPath(plugins_[i]->plugin_info().file) ==
+ filename) {
+ return static_cast<int>(i);
+ }
+ }
+
+ return -1;
+}
+
+PluginLib* PluginList::FindPlugin(const std::string& mime_type,
+ const std::string& clsid,
+ bool allow_wildcard) {
+ DCHECK(mime_type == StringToLowerASCII(mime_type));
+
+ for (size_t idx = 0; idx < plugins_.size(); ++idx) {
+ if (plugins_[idx]->SupportsType(mime_type, allow_wildcard)) {
+ if (!clsid.empty() &&
+ plugins_[idx]->plugin_info().file == kActiveXShimFileName) {
+ // Special handling for ActiveX shim. If ActiveX is not installed, we
+ // should use the default plugin to show the installation UI.
+ if (!activex_shim::IsActiveXInstalled(clsid))
+ continue;
+ }
+ return plugins_[idx];
+ }
+ }
+
+ return NULL;
+}
+
+PluginLib* PluginList::FindPlugin(const GURL &url, std::string* actual_mime_type) {
+ std::wstring path = NativeMBToWide(url.path());
+ std::wstring extension_wide = file_util::GetFileExtensionFromPath(path);
+ if (extension_wide.empty())
+ return NULL;;
+
+ std::string extension = StringToLowerASCII(WideToNativeMB(extension_wide));
+
+ for (size_t idx = 0; idx < plugins_.size(); ++idx) {
+ if (SupportsExtension(plugins_[idx]->plugin_info(), extension, actual_mime_type)) {
+ return plugins_[idx];
+ }
+ }
+
+ return NULL;
+}
+
+bool PluginList::SupportsType(const std::string &mime_type) {
+ DCHECK(mime_type == StringToLowerASCII(mime_type));
+ bool allow_wildcard = true;
+ return (FindPlugin(mime_type, "", allow_wildcard ) != 0);
+}
+
+bool PluginList::SupportsExtension(const WebPluginInfo& info,
+ const std::string &extension,
+ std::string* actual_mime_type) {
+ for (size_t i = 0; i < info.mime_types.size(); ++i) {
+ const WebPluginMimeType& mime_type = info.mime_types[i];
+ for (size_t j = 0; j < mime_type.file_extensions.size(); ++j) {
+ if (mime_type.file_extensions[j] == extension) {
+ if (actual_mime_type)
+ *actual_mime_type = mime_type.mime_type;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+
+bool PluginList::GetPlugins(bool refresh, std::vector<WebPluginInfo>* plugins) {
+ if (refresh)
+ LoadPlugins(true);
+
+ plugins->resize(plugins_.size());
+ for (size_t i = 0; i < plugins->size(); ++i)
+ (*plugins)[i] = plugins_[i]->plugin_info();
+
+ return true;
+}
+
+bool PluginList::GetPluginInfo(const GURL& url,
+ const std::string& mime_type,
+ const std::string& clsid,
+ bool allow_wildcard,
+ WebPluginInfo* info,
+ std::string* actual_mime_type) {
+ scoped_refptr<PluginLib> plugin = FindPlugin(mime_type, clsid,
+ allow_wildcard);
+
+ if (plugin.get() == NULL ||
+ (plugin->plugin_info().file == kDefaultPluginDllName && clsid.empty())) {
+ scoped_refptr<PluginLib> default_plugin = plugin;
+ plugin = FindPlugin(url, actual_mime_type);
+ // url matches may not return the default plugin if no match is found.
+ if (plugin.get() == NULL && default_plugin.get() != NULL)
+ plugin = default_plugin;
+ }
+
+ if (plugin.get() == NULL)
+ return false;
+
+ *info = plugin->plugin_info();
+ return true;
+}
+
+bool PluginList::GetPluginInfoByDllPath(const std::wstring& dll_path,
+ WebPluginInfo* info) {
+ for (size_t i = 0; i < plugins_.size(); ++i) {
+ if (wcsicmp(plugins_[i]->plugin_info().file.c_str(),
+ dll_path.c_str()) == 0) {
+ *info = plugins_[i]->plugin_info();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void PluginList::Shutdown() {
+ // TODO
+}
+
+std::wstring PluginList::GetPluginAppDirectory() {
+ std::wstring app_path;
+ if (webkit_glue::GetApplicationDirectory(&app_path))
+ app_path.append(L"\\plugins");
+
+ return app_path;
+}
+
+std::wstring PluginList::GetPluginExeDirectory() {
+ std::wstring exe_path;
+ if (webkit_glue::GetExeDirectory(&exe_path))
+ exe_path.append(L"\\plugins");
+
+ return exe_path;
+}
+
+// Gets the installed path for a registered app.
+static bool GetInstalledPath(const TCHAR* app, std::wstring* out) {
+ std::wstring reg_path(kRegistryApps);
+ reg_path.append(L"\\");
+ reg_path.append(app);
+
+ RegKey key(HKEY_LOCAL_MACHINE, reg_path.c_str());
+ return key.ReadValue(kRegistryPath, out);
+}
+
+// Enumerate through the registry key to find all installed FireFox paths.
+// FireFox 3 beta and version 2 can coexist. See bug: 1025003
+static void GetFirefoxInstalledPaths(std::vector<std::wstring>* out) {
+ RegistryKeyIterator it(HKEY_LOCAL_MACHINE, kRegistryFirefoxInstalled);
+ for (; it.Valid(); ++it) {
+ std::wstring full_path = std::wstring(kRegistryFirefoxInstalled) + L"\\" +
+ it.Name() + L"\\Main";
+ RegKey key(HKEY_LOCAL_MACHINE, full_path.c_str(), KEY_READ);
+ std::wstring install_dir;
+ if (!key.ReadValue(L"Install Directory", &install_dir))
+ continue;
+ out->push_back(install_dir);
+ }
+}
+
+void PluginList::LoadFirefoxPlugins() {
+ std::vector<std::wstring> paths;
+ GetFirefoxInstalledPaths(&paths);
+ for (unsigned int i = 0; i < paths.size(); ++i) {
+ std::wstring path = paths[i] + L"\\plugins";
+ LoadPlugins(path);
+ }
+
+ LoadPluginsInRegistryFolder(HKEY_CURRENT_USER, kRegistryMozillaPlugins);
+ LoadPluginsInRegistryFolder(HKEY_LOCAL_MACHINE, kRegistryMozillaPlugins);
+
+ std::wstring firefox_app_data_plugin_path;
+ if (PathService::Get(base::DIR_APP_DATA, &firefox_app_data_plugin_path)) {
+ firefox_app_data_plugin_path += L"\\Mozilla\\plugins";
+ LoadPlugins(firefox_app_data_plugin_path);
+ }
+}
+
+void PluginList::LoadAcrobatPlugins() {
+ std::wstring path;
+ if (GetInstalledPath(kRegistryAcrobat, &path)) {
+ path.append(L"\\Browser");
+ LoadPlugins(path);
+ }
+}
+
+void PluginList::LoadQuicktimePlugins() {
+ std::wstring path;
+ if (GetInstalledPath(kRegistryQuickTime, &path)) {
+ path.append(L"\\plugins");
+ LoadPlugins(path);
+ }
+}
+
+void PluginList::LoadWindowsMediaPlugins() {
+ std::wstring path;
+ if (GetInstalledPath(kRegistryWindowsMedia, &path)) {
+ LoadPlugins(path);
+ }
+}
+
+void PluginList::LoadJavaPlugin() {
+ // Load the new NPAPI Java plugin
+ // 1. Open the main JRE key under HKLM
+ RegKey java_key(HKEY_LOCAL_MACHINE, kRegistryJava, KEY_QUERY_VALUE);
+
+ // 2. Read the current Java version
+ std::wstring java_version;
+ if (!java_key.ReadValue(kRegistryBrowserJavaVersion, &java_version))
+ java_key.ReadValue(kRegistryCurrentJavaVersion, &java_version);
+
+ if (!java_version.empty()) {
+ java_key.OpenKey(java_version.c_str(), KEY_QUERY_VALUE);
+
+ // 3. Install path of the JRE binaries is specified in "JavaHome"
+ // value under the Java version key.
+ std::wstring java_plugin_directory;
+ if (java_key.ReadValue(kRegistryJavaHome, &java_plugin_directory)) {
+
+ // 4. The new plugin resides under the 'bin/new_plugin'
+ // subdirectory.
+ DCHECK(!java_plugin_directory.empty());
+ java_plugin_directory.append(L"\\bin\\new_plugin");
+
+ // 5. We don't know the exact name of the DLL but it's in the form
+ // NP*.dll so just invoke LoadPlugins on this path.
+ LoadPlugins(java_plugin_directory);
+ }
+ }
+}
+
+void PluginList::LoadPluginsInRegistryFolder(
+ HKEY root_key,
+ const std::wstring& registry_folder) {
+ for (RegistryKeyIterator iter(root_key, registry_folder.c_str());
+ iter.Valid(); ++iter) {
+ // Use the registry to gather plugin across the file system.
+ std::wstring reg_path = registry_folder;
+ reg_path.append(L"\\");
+ reg_path.append(iter.Name());
+ RegKey key(root_key, reg_path.c_str());
+
+ std::wstring path;
+ if (key.ReadValue(kRegistryPath, &path))
+ LoadPlugin(path);
+ }
+}
+
+} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_list.h b/webkit/glue/plugins/plugin_list.h
new file mode 100644
index 0000000..1176ad8
--- /dev/null
+++ b/webkit/glue/plugins/plugin_list.h
@@ -0,0 +1,197 @@
+// 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.
+
+// TODO: Need mechanism to cleanup the static instance
+
+#ifndef WEBKIT_GLUE_PLUGIN_PLUGIN_LIST_H__
+#define WEBKIT_GLUE_PLUGIN_PLUGIN_LIST_H__
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/ref_counted.h"
+#include "webkit/glue/webplugin.h"
+
+class GURL;
+
+namespace NPAPI
+{
+
+// Used by plugins_test when testing the older WMP plugin to force the new
+// plugin to not get loaded.
+#define kUseOldWMPPluginSwitch L"use-old-wmp"
+// Used for testing ActiveX shim. By default it's off. If this flag is specified
+// we will use the native ActiveX shim.
+#define kNoNativeActiveXShimSwitch L"no-activex"
+// Internal file name for activex shim, used as a unique identifier.
+#define kActiveXShimFileName L"activex-shim"
+
+#define kDefaultPluginDllName L"default_plugin"
+
+class PluginLib;
+class PluginInstance;
+
+// The PluginList is responsible for loading our NPAPI based plugins.
+// It loads plugins from a known directory by looking for DLLs
+// which start with "NP", and checking to see if they are valid
+// NPAPI libraries.
+class PluginList : public base::RefCounted<PluginList> {
+ public:
+ // Gets the one instance of the PluginList.
+ //
+ // Accessing the singleton causes the PluginList to look on
+ // disk for existing plugins. It does not actually load
+ // libraries, that will only happen when you initialize
+ // the plugin for the first time.
+ static PluginList* Singleton();
+
+ // Add an extra plugin to load when we actually do the loading. This is
+ // static because we want to be able to add to it without searching the disk
+ // for plugins. Must be called before the plugins have been loaded.
+ static void AddExtraPluginPath(const std::wstring& plugin_path);
+
+ virtual ~PluginList();
+
+ // Find a plugin to by mime type, and clsid.
+ // If clsid is empty, we will just find the plugin that supports mime type.
+ // Otherwise, if mime_type is application/x-oleobject etc that supported by
+ // by our activex shim, we need to check if the specified ActiveX exists.
+ // If not we will not return the activex shim, instead we will let the
+ // default plugin handle activex installation.
+ // The allow_wildcard parameter controls whether this function returns
+ // plugins which support wildcard mime types (* as the mime type)
+ PluginLib* FindPlugin(const std::string &mime_type, const std::string& clsid,
+ bool allow_wildcard);
+
+ // Find a plugin to by extension. Returns the corresponding mime type
+ PluginLib* FindPlugin(const GURL &url, std::string* actual_mime_type);
+
+ // Check if we have any plugin for a given type.
+ // mime_type must be all lowercase.
+ bool SupportsType(const std::string &mime_type);
+
+ // Returns true if the given WebPluginInfo supports a given file extension.
+ // extension should be all lower case.
+ // If mime_type is not NULL, it will be set to the mime type if found.
+ // The mime type which corresponds to the extension is optionally returned
+ // back.
+ static bool SupportsExtension(const WebPluginInfo& info,
+ const std::string &extension,
+ std::string* actual_mime_type);
+
+ // Shutdown all plugins. Should be called at process teardown.
+ void Shutdown();
+
+ // Get all the plugins
+ bool GetPlugins(bool refresh, std::vector<WebPluginInfo>* plugins);
+
+ // Returns true if a plugin is found for the given url and mime type.
+ // The mime type which corresponds to the URL is optionally returned
+ // back.
+ // The allow_wildcard parameter controls whether this function returns
+ // plugins which support wildcard mime types (* as the mime type)
+ bool GetPluginInfo(const GURL& url,
+ const std::string& mime_type,
+ const std::string& clsid,
+ bool allow_wildcard,
+ WebPluginInfo* info,
+ std::string* actual_mime_type);
+
+ // Get plugin info by plugin dll path. Returns true if the plugin is found and
+ // WebPluginInfo has been filled in |info|
+ bool GetPluginInfoByDllPath(const std::wstring& dll_path,
+ WebPluginInfo* info);
+ private:
+ // Constructors are private for singletons
+ PluginList();
+
+ // Load all plugins from the default plugins directory
+ void LoadPlugins(bool refresh);
+
+ // Load all plugins from a specific directory
+ void LoadPlugins(const std::wstring &path);
+
+ // Load a specific plugin with full path. filename can be mixed case.
+ void LoadPlugin(const std::wstring &filename);
+
+ // Returns true if we should load the given plugin, or false otherwise.
+ // filename must be lower case.
+ bool ShouldLoadPlugin(const std::wstring& filename);
+
+ // Load internal plugins. Right now there is only one: activex_shim.
+ void LoadInternalPlugins();
+
+ // Find a plugin by filename. Returns -1 if it's not found, otherwise its
+ // index in plugins_. filename needs to be lower case.
+ int FindPluginFile(const std::wstring& filename);
+
+ // The application path where we expect to find plugins.
+ static std::wstring GetPluginAppDirectory();
+
+ // The executable path where we expect to find plugins.
+ static std::wstring GetPluginExeDirectory();
+
+ // Load plugins from the Firefox install path. This is kind of
+ // a kludge, but it helps us locate the flash player for users that
+ // already have it for firefox. Not having to download yet-another-plugin
+ // is a good thing.
+ void LoadFirefoxPlugins();
+
+ // Hardcoded logic to detect and load acrobat plugins
+ void LoadAcrobatPlugins();
+
+ // Hardcoded logic to detect and load quicktime plugins
+ void LoadQuicktimePlugins();
+
+ // Hardcoded logic to detect and load Windows Media Player plugins
+ void LoadWindowsMediaPlugins();
+
+ // Hardcoded logic to detect and load Java plugins
+ void LoadJavaPlugin();
+
+ // Search the registry at the given path and load plugins listed there.
+ void LoadPluginsInRegistryFolder(HKEY root_key,
+ const std::wstring& registry_folder);
+
+ // true if we shouldn't load the new WMP plugin.
+ bool dont_load_new_wmp_;
+
+ bool use_internal_activex_shim_;
+
+ static scoped_refptr<PluginList> singleton_;
+ bool plugins_loaded_;
+ std::vector<scoped_refptr<PluginLib> > plugins_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(PluginList);
+};
+
+} // namespace NPAPI
+
+#endif // WEBKIT_GLUE_PLUGIN_PLUGIN_LIST_H__
diff --git a/webkit/glue/plugins/plugin_stream.cc b/webkit/glue/plugins/plugin_stream.cc
new file mode 100644
index 0000000..9f41ac9
--- /dev/null
+++ b/webkit/glue/plugins/plugin_stream.cc
@@ -0,0 +1,323 @@
+// 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.
+
+// TODO : Support NP_ASFILEONLY mode
+// TODO : Support NP_SEEK mode
+// TODO : Support SEEKABLE=true in NewStream
+
+#include "webkit/glue/plugins/plugin_stream.h"
+
+#include "base/string_util.h"
+#include "base/message_loop.h"
+#include "webkit/glue/plugins/plugin_instance.h"
+#include "webkit/glue/webkit_glue.h"
+#include "googleurl/src/gurl.h"
+
+namespace NPAPI {
+
+PluginStream::PluginStream(
+ PluginInstance *instance,
+ const char *url,
+ bool need_notify,
+ void *notify_data)
+ : instance_(instance),
+ bytes_sent_(0),
+ notify_needed_(need_notify),
+ notify_data_(notify_data),
+ close_on_write_data_(false),
+ opened_(false),
+ requested_plugin_mode_(NP_NORMAL),
+ temp_file_handle_(INVALID_HANDLE_VALUE) {
+ memset(&stream_, 0, sizeof(stream_));
+ stream_.url = _strdup(url);
+ temp_file_name_[0] = '\0';
+}
+
+PluginStream::~PluginStream() {
+ // always cleanup our temporary files.
+ CleanupTempFile();
+
+ free(const_cast<char*>(stream_.url));
+}
+
+void PluginStream::UpdateUrl(const char* url) {
+ DCHECK(!opened_);
+ free(const_cast<char*>(stream_.url));
+ stream_.url = _strdup(url);
+}
+
+bool PluginStream::Open(const std::string &mime_type,
+ const std::string &headers,
+ uint32 length,
+ uint32 last_modified) {
+ headers_ = headers;
+ NPP id = instance_->npp();
+ stream_.end = length;
+ stream_.lastmodified = last_modified;
+ stream_.pdata = 0;
+ stream_.ndata = id->ndata;
+ stream_.notifyData = notify_data_;
+ if (!headers_.empty())
+ stream_.headers = headers_.c_str();
+
+ const char *char_mime_type = "application/x-unknown-content-type";
+ std::string temp_mime_type;
+ if (!mime_type.empty()) {
+ char_mime_type = mime_type.c_str();
+ } else {
+ GURL gurl(stream_.url);
+ std::wstring path(UTF8ToWide(gurl.path()));
+ if (webkit_glue::GetMimeTypeFromFile(path, &temp_mime_type))
+ char_mime_type = temp_mime_type.c_str();
+ }
+
+ // Silverlight expects a valid mime type
+ DCHECK(strlen(char_mime_type) != 0);
+ NPError err = instance_->NPP_NewStream((NPMIMEType)char_mime_type,
+ &stream_, false,
+ &requested_plugin_mode_);
+ if (err != NPERR_NO_ERROR)
+ return false;
+
+ opened_ = true;
+
+ // If the plugin has requested certain modes, then we need a copy
+ // of this file on disk. Open it and save it as we go.
+ if (requested_plugin_mode_ == NP_ASFILEONLY ||
+ requested_plugin_mode_ == NP_ASFILE ||
+ requested_plugin_mode_ == NP_SEEK) {
+ if (OpenTempFile() == false)
+ return false;
+ }
+
+ return true;
+}
+
+int PluginStream::Write(const char *buffer, const int length) {
+ // There may be two streams to write to - the plugin and the file.
+ // It is unclear what to do if we cannot write to both. The rules of
+ // this function are that the plugin must consume at least as many
+ // bytes as returned by the WriteReady call. So, we will attempt to
+ // write that many to both streams. If we can't write that many bytes
+ // to each stream, we'll return failure.
+
+ DCHECK(opened_);
+ if (WriteToFile(buffer, length) && WriteToPlugin(buffer, length))
+ return length;
+
+ return -1;
+}
+
+bool PluginStream::WriteToFile(const char *buf, const int length) {
+ // For ASFILEONLY, ASFILE, and SEEK modes, we need to write
+ // to the disk
+ if (temp_file_handle_ != INVALID_HANDLE_VALUE &&
+ (requested_plugin_mode_ == NP_SEEK ||
+ requested_plugin_mode_ == NP_ASFILE ||
+ requested_plugin_mode_ == NP_ASFILEONLY) ) {
+ int totalBytesWritten = 0;
+ DWORD bytes;
+ do {
+ if (WriteFile(temp_file_handle_, buf, length, &bytes, 0) == FALSE)
+ break;
+ totalBytesWritten += bytes;
+ } while (bytes > 0 && totalBytesWritten < length);
+
+ if (totalBytesWritten != length)
+ return false;
+ }
+
+ return true;
+}
+
+bool PluginStream::WriteToPlugin(const char *buf, const int length) {
+ // For NORMAL and ASFILE modes, we send the data to the plugin now
+ if (requested_plugin_mode_ != NP_NORMAL &&
+ requested_plugin_mode_ != NP_ASFILE)
+ return true;
+
+ int written = TryWriteToPlugin(buf, length);
+ if (written == -1)
+ return false;
+
+ if (written < length) {
+ // Buffer the remaining data.
+ size_t remaining = length - written;
+ size_t previous_size = delivery_data_.size();
+ delivery_data_.resize(previous_size + remaining);
+ memcpy(&delivery_data_[previous_size], buf + written, remaining);
+ MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &PluginStream::OnDelayDelivery));
+ }
+
+ return true;
+}
+
+void PluginStream::OnDelayDelivery() {
+ // It is possible that the plugin stream may have closed before the task
+ // was hit.
+ if (!opened_) {
+ return;
+ }
+
+ int size = static_cast<int>(delivery_data_.size());
+ int written = TryWriteToPlugin(&delivery_data_.front(), size);
+ if (written > 0) {
+ // Remove the data that we already wrote.
+ delivery_data_.erase(delivery_data_.begin(),
+ delivery_data_.begin() + written);
+ }
+}
+
+int PluginStream::TryWriteToPlugin(const char *buf, const int length) {
+ bool result = true;
+ int byte_offset = 0;
+
+ while (byte_offset < length) {
+ int bytes_remaining = length - byte_offset;
+ int bytes_to_write = instance_->NPP_WriteReady(&stream_);
+ if (bytes_to_write > bytes_remaining)
+ bytes_to_write = bytes_remaining;
+
+ if (bytes_to_write == 0)
+ return byte_offset;
+
+ int bytesSent = instance_->NPP_Write(&stream_,
+ bytes_sent_,
+ bytes_to_write,
+ const_cast<char*>(buf + byte_offset));
+ if (bytesSent < bytes_to_write) {
+ // We couldn't write all the bytes. This is an error.
+ return -1;
+ }
+ bytes_sent_ += bytesSent;
+ byte_offset += bytesSent;
+ }
+
+ if (close_on_write_data_)
+ Close(NPRES_DONE);
+
+ return length;
+}
+
+void PluginStream::WriteAsFile() {
+ if (requested_plugin_mode_ == NP_ASFILE ||
+ requested_plugin_mode_ == NP_ASFILEONLY)
+ instance_->NPP_StreamAsFile(&stream_, temp_file_name_);
+}
+
+bool PluginStream::Close(NPReason reason) {
+ if (opened_ == true) {
+ opened_ = false;
+
+ if (delivery_data_.size()) {
+ if (reason == NPRES_DONE) {
+ // There is more data to be streamed, don't destroy the stream now.
+ close_on_write_data_ = true;
+ return true;
+ } else {
+ // Stop any pending data from being streamed
+ delivery_data_.resize(0);
+ }
+ }
+
+ // If we have a temp file, be sure to close it.
+ // Also, allow the plugin to access it now.
+ if (temp_file_handle_ != INVALID_HANDLE_VALUE) {
+ CloseTempFile();
+ WriteAsFile();
+ }
+
+ if (stream_.ndata != NULL) {
+ // Stream hasn't been closed yet.
+ NPError err = instance_->NPP_DestroyStream(&stream_, reason);
+ DCHECK(err == NPERR_NO_ERROR);
+ }
+ }
+
+ Notify(reason);
+ return true;
+}
+
+bool PluginStream::OpenTempFile() {
+ DCHECK(temp_file_handle_ == INVALID_HANDLE_VALUE);
+
+ // The reason for using all the Ascii versions of these filesystem
+ // calls is that the filename which we pass back to the plugin
+ // via NPAPI is an ascii filename. Otherwise, we'd use wide-chars.
+ //
+ // TODO:
+ // This is a bug in NPAPI itself, and it needs to be fixed.
+ // The case which will fail is if a user has a multibyte name,
+ // but has the system locale set to english. GetTempPathA will
+ // return junk in this case, causing us to be unable to open the
+ // file.
+
+ char temp_directory[MAX_PATH];
+ if (GetTempPathA(MAX_PATH, temp_directory) == 0)
+ return false;
+ if (GetTempFileNameA(temp_directory, "npstream", 0, temp_file_name_) == 0)
+ return false;
+ temp_file_handle_ = CreateFileA(temp_file_name_,
+ FILE_ALL_ACCESS,
+ FILE_SHARE_READ,
+ 0,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ 0);
+ if (temp_file_handle_ == INVALID_HANDLE_VALUE) {
+ temp_file_name_[0] = '\0';
+ return false;
+ }
+ return true;
+}
+
+void PluginStream::CloseTempFile() {
+ if (temp_file_handle_ != INVALID_HANDLE_VALUE) {
+ CloseHandle(temp_file_handle_);
+ temp_file_handle_ = INVALID_HANDLE_VALUE;
+ }
+}
+
+void PluginStream::CleanupTempFile() {
+ CloseTempFile();
+ if (temp_file_name_[0] != '\0') {
+ DeleteFileA(temp_file_name_);
+ temp_file_name_[0] = '\0';
+ }
+}
+
+void PluginStream::Notify(NPReason reason) {
+ if (notify_needed_) {
+ instance_->NPP_URLNotify(stream_.url, reason, notify_data_);
+ notify_needed_ = false;
+ }
+}
+
+} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_stream.h b/webkit/glue/plugins/plugin_stream.h
new file mode 100644
index 0000000..e4b99ba
--- /dev/null
+++ b/webkit/glue/plugins/plugin_stream.h
@@ -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.
+
+#ifndef WEBKIT_GLUE_PLUGIN_PLUGIN_STREAM_H__
+#define WEBKIT_GLUE_PLUGIN_PLUGIN_STREAM_H__
+
+#include <string>
+#include <vector>
+
+#include "base/ref_counted.h"
+#include "third_party/npapi/bindings/npapi.h"
+
+
+namespace NPAPI {
+
+class PluginInstance;
+
+// Base class for a NPAPI stream. Tracks basic elements
+// of a stream for NPAPI notifications and stream position.
+class PluginStream : public base::RefCounted<PluginStream> {
+ public:
+ // Create a new PluginStream object. If needNotify is true, then the
+ // plugin will be notified when the stream has been fully sent.
+ PluginStream(PluginInstance *instance,
+ const char *url,
+ bool need_notify,
+ void *notify_data);
+ virtual ~PluginStream();
+
+ // In case of a redirect, this can be called to update the url. But it must
+ // be called before Open().
+ void UpdateUrl(const char* url);
+
+ // Opens the stream to the Plugin.
+ // If the mime-type is not specified, we'll try to find one based on the
+ // mime-types table and the extension (if any) in the URL.
+ // If the size of the stream is known, use length to set the size. If
+ // not known, set length to 0.
+ bool Open(const std::string &mime_type,
+ const std::string &headers,
+ uint32 length,
+ uint32 last_modified);
+
+ // Writes to the stream.
+ int Write(const char *buf, const int len);
+
+ // Write the result as a file.
+ void WriteAsFile();
+
+ // Notify the plugin that a stream is complete.
+ void Notify(NPReason reason);
+
+ // Close the stream.
+ virtual bool Close(NPReason reason);
+
+ const NPStream* stream() const {
+ return &stream_;
+ }
+
+ protected:
+ PluginInstance* instance() { return instance_.get(); }
+ // Check if the stream is open.
+ bool open() { return opened_; }
+
+ private:
+ // Open a temporary file for this stream.
+ // If successful, will set temp_file_name_, temp_file_handle_, and
+ // return true.
+ bool OpenTempFile();
+
+ // Closes the temporary file if it is open.
+ void CloseTempFile();
+
+ // Closes the temporary file if it is open and deletes the file.
+ void CleanupTempFile();
+
+ // Sends the data to the file if it's open.
+ bool WriteToFile(const char *buf, const int length);
+
+ // Sends the data to the plugin. If it's not ready, handles buffering it
+ // and retrying later.
+ bool WriteToPlugin(const char *buf, const int length);
+
+ // Send the data to the plugin, returning how many bytes it accepted, or -1
+ // if an error occurred.
+ int TryWriteToPlugin(const char *buf, const int length);
+
+ // The callback which calls TryWriteToPlugin.
+ void OnDelayDelivery();
+
+ private:
+ NPStream stream_;
+ std::string headers_;
+ scoped_refptr<PluginInstance> instance_;
+ int bytes_sent_;
+ bool notify_needed_;
+ void * notify_data_;
+ bool close_on_write_data_;
+ uint16 requested_plugin_mode_;
+ bool opened_;
+ char temp_file_name_[MAX_PATH];
+ HANDLE temp_file_handle_;
+ std::vector<char> delivery_data_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(PluginStream);
+};
+
+} // namespace NPAPI
+
+#endif // WEBKIT_GLUE_PLUGIN_PLUGIN_STREAM_H__
diff --git a/webkit/glue/plugins/plugin_stream_url.cc b/webkit/glue/plugins/plugin_stream_url.cc
new file mode 100644
index 0000000..9400f2c
--- /dev/null
+++ b/webkit/glue/plugins/plugin_stream_url.cc
@@ -0,0 +1,104 @@
+// 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/plugins/plugin_stream_url.h"
+
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/webplugin.h"
+#include "webkit/glue/plugins/plugin_host.h"
+#include "webkit/glue/plugins/plugin_instance.h"
+
+namespace NPAPI {
+
+PluginStreamUrl::PluginStreamUrl(
+ int resource_id,
+ const GURL &url,
+ PluginInstance *instance,
+ bool notify_needed,
+ void *notify_data)
+ : PluginStream(instance, url.spec().c_str(), notify_needed, notify_data),
+ url_(url),
+ id_(resource_id) {
+}
+
+PluginStreamUrl::~PluginStreamUrl() {
+}
+
+bool PluginStreamUrl::Close(NPReason reason) {
+ if (id_ != 0) {
+ if (instance()->webplugin()) {
+ instance()->webplugin()->CancelResource(id_);
+ }
+
+ id_ = 0;
+ }
+
+ bool result = PluginStream::Close(reason);
+ instance()->RemoveStream(this);
+ return result;
+}
+
+void PluginStreamUrl::WillSendRequest(const GURL& url) {
+ url_ = url;
+ UpdateUrl(url.spec().c_str());
+}
+
+void PluginStreamUrl::DidReceiveResponse(const std::string& mime_type,
+ const std::string& headers,
+ uint32 expected_length,
+ uint32 last_modified,
+ bool* cancel) {
+
+ bool opened = Open(mime_type,
+ headers,
+ expected_length,
+ last_modified);
+ if (!opened) {
+ instance()->RemoveStream(this);
+ *cancel = true;
+ }
+}
+
+void PluginStreamUrl::DidReceiveData(const char* buffer, int length) {
+ if (!open())
+ return;
+
+ if (length > 0)
+ Write(const_cast<char*>(buffer), length);
+}
+
+void PluginStreamUrl::DidFinishLoading() {
+ Close(NPRES_DONE);
+}
+
+void PluginStreamUrl::DidFail() {
+ Close(NPRES_NETWORK_ERR);
+}
+
+} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_stream_url.h b/webkit/glue/plugins/plugin_stream_url.h
new file mode 100644
index 0000000..b6b5b3b
--- /dev/null
+++ b/webkit/glue/plugins/plugin_stream_url.h
@@ -0,0 +1,84 @@
+// 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 WEBKIT_GLUE_PLUGIN_PLUGIN_STREAM_URL_H__
+#define WEBKIT_GLUE_PLUGIN_PLUGIN_STREAM_URL_H__
+
+
+#include "webkit/glue/webplugin.h"
+#include "webkit/glue/plugins/plugin_stream.h"
+#include "googleurl/src/gurl.h"
+
+namespace NPAPI {
+
+class PluginInstance;
+
+// A NPAPI Stream based on a URL.
+class PluginStreamUrl : public PluginStream,
+ public WebPluginResourceClient {
+ public:
+ // Create a new stream for sending to the plugin by fetching
+ // a URL. If notifyNeeded is set, then the plugin will be notified
+ // when the stream has been fully sent to the plugin. Initialize
+ // must be called before the object is used.
+ PluginStreamUrl(int resource_id,
+ const GURL &url,
+ PluginInstance *instance,
+ bool notify_needed,
+ void *notify_data);
+ virtual ~PluginStreamUrl();
+
+ // Stop sending the stream to the client.
+ // Overrides the base Close so we can cancel our fetching the URL if
+ // it is still loading.
+ bool Close(NPReason reason);
+
+ //
+ // WebPluginResourceClient methods
+ //
+ void WillSendRequest(const GURL& url);
+ void DidReceiveResponse(const std::string& mime_type,
+ const std::string& headers,
+ uint32 expected_length,
+ uint32 last_modified,
+ bool* cancel);
+ void DidReceiveData(const char* buffer, int length);
+ void DidFinishLoading();
+ void DidFail();
+
+ private:
+ GURL url_;
+ int id_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(PluginStreamUrl);
+};
+
+} // namespace NPAPI
+
+#endif // WEBKIT_GLUE_PLUGIN_PLUGIN_STREAM_URL_H__ \ No newline at end of file
diff --git a/webkit/glue/plugins/plugin_string_stream.cc b/webkit/glue/plugins/plugin_string_stream.cc
new file mode 100644
index 0000000..c32f5ab
--- /dev/null
+++ b/webkit/glue/plugins/plugin_string_stream.cc
@@ -0,0 +1,56 @@
+// 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/plugins/plugin_string_stream.h"
+
+namespace NPAPI {
+
+PluginStringStream::PluginStringStream(
+ PluginInstance *instance,
+ const std::string &url,
+ bool notify_needed,
+ void *notify_data)
+ : PluginStream(instance, url.c_str(), notify_needed, notify_data) {
+}
+
+PluginStringStream::~PluginStringStream() {
+}
+
+void PluginStringStream::SendToPlugin(const std::string &data,
+ const std::string &mime_type) {
+ int length = static_cast<int>(data.length());
+ if (Open(mime_type, std::string(), length, 0)) {
+ // TODO - check if it was not fully sent, and figure out a backup plan.
+ int written = Write(data.c_str(), length);
+ NPReason reason = written == length ? NPRES_DONE : NPRES_NETWORK_ERR;
+ Close(reason);
+ }
+}
+
+}
diff --git a/webkit/glue/plugins/plugin_string_stream.h b/webkit/glue/plugins/plugin_string_stream.h
new file mode 100644
index 0000000..8c2e2c6
--- /dev/null
+++ b/webkit/glue/plugins/plugin_string_stream.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 WEBKIT_GLUE_PLUGIN_PLUGIN_STRING_STREAM_H__
+#define WEBKIT_GLUE_PLUGIN_PLUGIN_STRING_STREAM_H__
+
+#include "webkit/glue/plugins/plugin_stream.h"
+
+namespace NPAPI {
+
+class PluginInstance;
+
+// An NPAPI stream from a string.
+class PluginStringStream : public PluginStream {
+ public:
+ // Create a new stream for sending to the plugin.
+ // If notify_needed, will notify the plugin after the data has
+ // all been sent.
+ PluginStringStream(PluginInstance *instance,
+ const std::string &url,
+ bool notify_needed,
+ void *notify_data);
+ virtual ~PluginStringStream();
+
+ // Initiates the sending of data to the plugin.
+ void SendToPlugin(const std::string &data,
+ const std::string &mime_type);
+
+ private:
+
+ DISALLOW_EVIL_CONSTRUCTORS(PluginStringStream);
+};
+
+} // namespace NPAPI
+
+#endif // WEBKIT_GLUE_PLUGIN_PLUGIN_STRING_STREAM_H__
diff --git a/webkit/glue/plugins/test/SConscript b/webkit/glue/plugins/test/SConscript
new file mode 100644
index 0000000..f8113f6
--- /dev/null
+++ b/webkit/glue/plugins/test/SConscript
@@ -0,0 +1,109 @@
+# 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_res')
+
+env = env.Clone()
+env_res = env_res.Clone()
+
+input_files = [
+ 'npapi_constants.cc',
+ 'npapi_test.cc',
+ env_res.RES('npapi_test.rc'),
+ 'plugin_arguments_test.cc',
+ 'plugin_client.cc',
+ 'plugin_delete_plugin_in_stream_test.cc',
+ 'plugin_execute_script_delete_test.cc',
+ 'plugin_get_javascript_url_test.cc',
+ 'plugin_geturl_test.cc',
+ 'plugin_new_fails_test.cc',
+ 'plugin_npobject_lifetime_test.cc',
+ 'plugin_npobject_proxy_test.cc',
+ 'plugin_test.cc',
+ 'plugin_window_size_test.cc',
+ 'npapi_test.def',
+
+ env.File('$BASE_DIR/base.lib'),
+]
+
+env.Append(
+ CCFLAGS = [
+ '/TP',
+ '/wd4800',
+ '/wd4503',
+ '/wd4819',
+ ],
+
+ LIBS = [
+ 'comctl32.lib',
+ 'shlwapi.lib',
+ 'rpcrt4.lib',
+ 'winmm.lib',
+ 'wininet.lib',
+ 'version.lib',
+ 'msimg32.lib',
+ 'ws2_32.lib',
+ 'usp10.lib',
+ 'psapi.lib',
+ 'kernel32.lib',
+ 'user32.lib',
+ 'gdi32.lib',
+ 'winspool.lib',
+ 'comdlg32.lib',
+ 'advapi32.lib',
+ 'shell32.lib',
+ 'ole32.lib',
+ 'oleaut32.lib',
+ 'uuid.lib',
+ 'odbc32.lib',
+ 'odbccp32.lib',
+
+ 'delayimp.lib',
+ ],
+
+ LINKFLAGS = [
+ '/DELAYLOAD:"dwmapi.dll"',
+ '/DELAYLOAD:"uxtheme.dll"',
+ '/FIXED:No',
+ '/SUBSYSTEM:CONSOLE',
+ '/MACHINE:X86',
+ '/safeseh',
+ '/dynamicbase',
+ '/ignore:4199',
+ '/nxcompat',
+ ],
+)
+
+dll = env.SharedLibrary(['npapi_test_plugin',
+ 'npapi_test_plugin.ilk',
+ 'npapi_test_plugin.pdb'],
+ input_files)
+
+i = env.Install('$TARGET_ROOT', dll)
+env.Alias('webkit', i)
diff --git a/webkit/glue/plugins/test/npapi_constants.cc b/webkit/glue/plugins/test/npapi_constants.cc
new file mode 100644
index 0000000..eadd9e0
--- /dev/null
+++ b/webkit/glue/plugins/test/npapi_constants.cc
@@ -0,0 +1,35 @@
+// 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/plugins/test/npapi_constants.h"
+
+namespace NPAPIClient {
+const char kTestCompleteCookie[] = "status";
+const char kTestCompleteSuccess[] = "OK";
+}
diff --git a/webkit/glue/plugins/test/npapi_constants.h b/webkit/glue/plugins/test/npapi_constants.h
new file mode 100644
index 0000000..0894e7a
--- /dev/null
+++ b/webkit/glue/plugins/test/npapi_constants.h
@@ -0,0 +1,44 @@
+// 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.
+
+// Constants for the NPAPI test
+
+#ifndef WEBKIT_PORT_PLUGINS_TEST_NPAPI_CONSTANTS_H__
+#define WEBKIT_PORT_PLUGINS_TEST_NPAPI_CONSTANTS_H__
+
+namespace NPAPIClient {
+// The name of the cookie which will be used to communicate between
+// the plugin and the test harness.
+extern const char kTestCompleteCookie[];
+
+// The cookie value which will be sent to the client upon successful
+// test.
+extern const char kTestCompleteSuccess[];
+}
+#endif // WEBKIT_PORT_PLUGINS_TEST_NPAPI_CONSTANTS_H__
diff --git a/webkit/glue/plugins/test/npapi_test.cc b/webkit/glue/plugins/test/npapi_test.cc
new file mode 100644
index 0000000..4272dd4
--- /dev/null
+++ b/webkit/glue/plugins/test/npapi_test.cc
@@ -0,0 +1,92 @@
+// 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.
+
+//
+// npapitest
+//
+// This is a NPAPI Plugin Program which is used to test the Browser's NPAPI
+// host implementation. It is used in conjunction with the npapi_unittest.
+//
+// As a NPAPI Plugin, you can invoke it by creating a web page of the following
+// type:
+//
+// <embed src="content-to-load" type="application/vnd.npapi-test"
+// name="test-name">
+//
+// arguments:
+// src: This is the initial content which will be sent to the plugin.
+// type: Must be "application/vnd.npapi-test"
+// name: The testcase to run when invoked
+// id: The id of the test being run (for testing concurrent plugins)
+//
+// The Plugin drives the actual test, calling host functions and validating the
+// Host callbacks which it receives. It is the duty of the plugin to record
+// all errors.
+//
+// To indicate test completion, the plugin expects the containing HTML page to
+// implement two javascript functions:
+// onSuccess(string testname);
+// onFailure(string testname, string results);
+// The HTML host pages used in this test will then set a document cookie
+// which the automated test framework can poll for and discover that the
+// test has completed.
+//
+//
+// TESTS
+// When the PluginClient receives a NPP_New callback from the browser,
+// it looks at the "name" argument which is passed in. It verifies that
+// the name matches a known test, and instantiates that test. The test is
+// a subclass of PluginTest.
+//
+//
+
+#include <windows.h>
+#include "webkit/glue/plugins/test/plugin_client.h"
+
+BOOL WINAPI DllMain(HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved) {
+ return TRUE;
+}
+
+extern "C" {
+NPError WINAPI NP_GetEntryPoints(NPPluginFuncs* pFuncs) {
+ return NPAPIClient::PluginClient::GetEntryPoints(pFuncs);
+}
+
+NPError WINAPI NP_Initialize(NPNetscapeFuncs* pFuncs) {
+ return NPAPIClient::PluginClient::Initialize(pFuncs);
+}
+
+NPError WINAPI NP_Shutdown() {
+ return NPAPIClient::PluginClient::Shutdown();
+}
+} // extern "C"
+
+namespace WebCore {
+ const char* currentTextBreakLocaleID() { return "en_us"; }
+} \ No newline at end of file
diff --git a/webkit/glue/plugins/test/npapi_test.def b/webkit/glue/plugins/test/npapi_test.def
new file mode 100644
index 0000000..4481c16
--- /dev/null
+++ b/webkit/glue/plugins/test/npapi_test.def
@@ -0,0 +1,6 @@
+LIBRARY npapi_test_plugin
+
+EXPORTS
+ NP_GetEntryPoints @1
+ NP_Initialize @2
+ NP_Shutdown @3
diff --git a/webkit/glue/plugins/test/npapi_test.rc b/webkit/glue/plugins/test/npapi_test.rc
new file mode 100644
index 0000000..a337ce6
--- /dev/null
+++ b/webkit/glue/plugins/test/npapi_test.rc
@@ -0,0 +1,102 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4"
+ BEGIN
+ VALUE "FileDescription", "npapites Dynamic Link Library"
+ VALUE "FileVersion", "1, 0, 0, 1"
+ VALUE "InternalName", "npapites"
+ VALUE "LegalCopyright", "Copyright (C) 2007"
+ VALUE "OriginalFilename", "npapites.dll"
+ VALUE "ProductName", " npapites Dynamic Link Library"
+ VALUE "ProductVersion", "1, 0, 0, 1"
+ VALUE "MIMEType", "application/vnd.npapi-test\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/webkit/glue/plugins/test/npapi_test_plugin.vcproj b/webkit/glue/plugins/test/npapi_test_plugin.vcproj
new file mode 100644
index 0000000..ffcd76c
--- /dev/null
+++ b/webkit/glue/plugins/test/npapi_test_plugin.vcproj
@@ -0,0 +1,256 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="npapi_test_plugin"
+ ProjectGUID="{0D04AEC1-6B68-492C-BCCF-808DFD69ABC6}"
+ RootNamespace="npapi_test"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\build\debug.vsprops;..\..\..\build\webkit_common.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="VCLinkerTool"
+ AdditionalDependencies="winmm.lib"
+ ModuleDefinitionFile="npapi_test.def"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\build\release.vsprops;..\..\..\build\webkit_common.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="VCLinkerTool"
+ AdditionalDependencies="winmm.lib"
+ ModuleDefinitionFile="npapi_test.def"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath=".\npapi_constants.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\npapi_constants.h"
+ >
+ </File>
+ <File
+ RelativePath=".\npapi_test.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\npapi_test.rc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_arguments_test.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_arguments_test.h"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_client.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_client.h"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_delete_plugin_in_stream_test.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_delete_plugin_in_stream_test.h"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_execute_script_delete_test.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_execute_script_delete_test.h"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_get_javascript_url_test.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_get_javascript_url_test.h"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_geturl_test.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_geturl_test.h"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_new_fails_test.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_new_fails_test.h"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_npobject_lifetime_test.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_npobject_lifetime_test.h"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_npobject_proxy_test.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_npobject_proxy_test.h"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_test.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_test.h"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_window_size_test.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\plugin_window_size_test.h"
+ >
+ </File>
+ <File
+ RelativePath=".\resource.h"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/webkit/glue/plugins/test/plugin_arguments_test.cc b/webkit/glue/plugins/test/plugin_arguments_test.cc
new file mode 100644
index 0000000..dfd34e4
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_arguments_test.cc
@@ -0,0 +1,92 @@
+// 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.
+
+#define STRSAFE_NO_DEPRECATE
+#include <strsafe.h>
+#include "webkit/glue/plugins/test/plugin_arguments_test.h"
+
+namespace NPAPIClient {
+
+PluginArgumentsTest::PluginArgumentsTest(NPP id,
+ NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions) {
+}
+
+NPError PluginArgumentsTest::New(uint16 mode, int16 argc,
+ const char* argn[], const char* argv[],
+ NPSavedData* saved) {
+ // mode: should be the string either "NP_EMBED" or "NP_FULL",
+ // depending on the mode passed in.
+ // count: the count of "val" arguments. If the value is
+ // 2, then we'll find arguments "val1" and "val2". If
+ // the value is 0, then there will be no "val" arguments.
+ // size: each val string will be this size * the value's
+ // index. E.g if size is "10", val1 will be 10bytes,
+ // and val2 will be 20bytes.
+ const char *mode_string = GetArgValue("mode", argc, argn, argv);
+ ExpectAsciiStringNotEqual(mode_string, (const char *)NULL);
+ if (mode_string != NULL) {
+ std::string mode_dep_string = mode_string;
+ if (mode == NP_EMBED)
+ ExpectStringLowerCaseEqual(mode_dep_string, "np_embed");
+ else if (mode == NP_FULL)
+ ExpectStringLowerCaseEqual(mode_dep_string, "np_full");
+ }
+
+ const char *count_string = GetArgValue("count", argc, argn, argv);
+ if (count_string != NULL) {
+ int max_args = atoi(count_string);
+
+ const char *size_string = GetArgValue("size", argc, argn, argv);
+ ExpectAsciiStringNotEqual(size_string, (const char *)NULL);
+ if (size_string != NULL) {
+ int size = atoi(size_string);
+
+ for (int index = 1; index <= max_args; index++) {
+ char arg_name[MAX_PATH]; // Use MAX_PATH for Max Name Length
+ StringCchPrintfA(arg_name, sizeof(arg_name), "%s%d", "val", index);
+ const char *val_string = GetArgValue(arg_name, argc, argn, argv);
+ ExpectAsciiStringNotEqual(val_string, (const char*)NULL);
+ if (val_string != NULL)
+ ExpectIntegerEqual((int)strlen(val_string), (index*size));
+ }
+ }
+ }
+
+ return PluginTest::New(mode, argc, argn, argv, saved);
+}
+
+NPError PluginArgumentsTest::SetWindow(NPWindow* pNPWindow) {
+ // This test just tests the arguments. We're done now.
+ this->SignalTestCompleted();
+
+ return NPERR_NO_ERROR;
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_arguments_test.h b/webkit/glue/plugins/test/plugin_arguments_test.h
new file mode 100644
index 0000000..57d9e6f
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_arguments_test.h
@@ -0,0 +1,69 @@
+// 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 WEBKIT_PORT_PLUGINS_TEST_PLUGIN_ARGUMENTS_TEST_H__
+#define WEBKIT_PORT_PLUGINS_TEST_PLUGIN_ARGUMENTS_TEST_H__
+
+#include "webkit/glue/plugins/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// The PluginArgumentsTest test that we properly receive arguments
+// intended for the plugin.
+//
+// This is basically overkill for testing that the arguments passed
+// to the plugin match what we expect.
+//
+// We expect to find the following arguments:
+// mode: should be the string either "NP_EMBED" or "NP_FULL",
+// depending on the mode passed in.
+// count: the count of "val" arguments. If the value is
+// 2, then we'll find arguments "val1" and "val2". If
+// the value is 0, then there will be no "val" arguments.
+// size: each val string will be this size * the value's
+// index. E.g if size is "10", val1 will be 10bytes,
+// and val2 will be 20bytes.
+//
+class PluginArgumentsTest : public PluginTest {
+ public:
+ // Constructor.
+ PluginArgumentsTest(NPP id, NPNetscapeFuncs *host_functions);
+
+ // Initialize this PluginTest based on the arguments from NPP_New.
+ virtual NPError New(uint16 mode, int16 argc, const char* argn[],
+ const char* argv[], NPSavedData* saved);
+
+ // NPAPI SetWindow handler.
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PORT_PLUGINS_TEST_PLUGIN_ARGUMENTS_TEST_H__
+
diff --git a/webkit/glue/plugins/test/plugin_client.cc b/webkit/glue/plugins/test/plugin_client.cc
new file mode 100644
index 0000000..d8d409e
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_client.cc
@@ -0,0 +1,300 @@
+// 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/plugins/test/plugin_client.h"
+#include "webkit/glue/plugins/test/plugin_arguments_test.h"
+#include "webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.h"
+#include "webkit/glue/plugins/test/plugin_execute_script_delete_test.h"
+#include "webkit/glue/plugins/test/plugin_get_javascript_url_test.h"
+#include "webkit/glue/plugins/test/plugin_geturl_test.h"
+#include "webkit/glue/plugins/test/plugin_new_fails_test.h"
+#include "webkit/glue/plugins/test/plugin_npobject_lifetime_test.h"
+#include "webkit/glue/plugins/test/plugin_npobject_proxy_test.h"
+#include "webkit/glue/plugins/test/plugin_window_size_test.h"
+#include "third_party/npapi/bindings/npapi.h"
+#include "third_party/npapi/bindings/npruntime.h"
+
+namespace NPAPIClient {
+
+NPNetscapeFuncs* PluginClient::host_functions_;
+
+NPError PluginClient::GetEntryPoints(NPPluginFuncs* pFuncs) {
+ if (pFuncs == NULL)
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+
+ if (pFuncs->size < sizeof(NPPluginFuncs))
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+
+ pFuncs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
+ pFuncs->newp = NPP_New;
+ pFuncs->destroy = NPP_Destroy;
+ pFuncs->setwindow = NPP_SetWindow;
+ pFuncs->newstream = NPP_NewStream;
+ pFuncs->destroystream = NPP_DestroyStream;
+ pFuncs->asfile = NPP_StreamAsFile;
+ pFuncs->writeready = NPP_WriteReady;
+ pFuncs->write = NPP_Write;
+ pFuncs->print = NPP_Print;
+ pFuncs->event = NPP_HandleEvent;
+ pFuncs->urlnotify = NPP_URLNotify;
+ pFuncs->getvalue = NPP_GetValue;
+ pFuncs->setvalue = NPP_SetValue;
+ pFuncs->javaClass = NPP_GetJavaClass;
+
+ return NPERR_NO_ERROR;
+}
+
+NPError PluginClient::Initialize(NPNetscapeFuncs* pFuncs) {
+ if (pFuncs == NULL) {
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+ }
+
+ if (HIBYTE(pFuncs->version) > NP_VERSION_MAJOR) {
+ return NPERR_INCOMPATIBLE_VERSION_ERROR;
+ }
+
+ host_functions_ = pFuncs;
+
+ return NPERR_NO_ERROR;
+}
+
+NPError PluginClient::Shutdown() {
+ return NPERR_NO_ERROR;
+}
+
+} // namespace NPAPIClient
+
+extern "C" {
+NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode,
+ int16 argc, char* argn[], char* argv[], NPSavedData* saved) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ // We look at the test name requested via the plugin arguments. We match
+ // that against a given test and try to instantiate it.
+
+ // lookup the name parameter
+ int name_index = 0;
+ for (name_index = 0; name_index < argc; name_index++)
+ if (_stricmp(argn[name_index], "name") == 0)
+ break;
+
+ if (name_index >= argc)
+ return NPERR_GENERIC_ERROR; // no name found
+
+ NPError ret = NPERR_GENERIC_ERROR;
+ bool windowless_plugin = false;
+
+ NPAPIClient::PluginTest *new_test = NULL;
+ if (_stricmp(argv[name_index], "arguments") == 0) {
+ new_test = new NPAPIClient::PluginArgumentsTest(instance,
+ NPAPIClient::PluginClient::HostFunctions());
+ } else if (_stricmp(argv[name_index], "geturl") == 0) {
+ new_test = new NPAPIClient::PluginGetURLTest(instance,
+ NPAPIClient::PluginClient::HostFunctions());
+ } else if (_stricmp(argv[name_index], "npobject_proxy") == 0) {
+ new_test = new NPAPIClient::NPObjectProxyTest(instance,
+ NPAPIClient::PluginClient::HostFunctions());
+ } else if (_stricmp(argv[name_index], "execute_script_delete_in_paint") == 0) {
+ new_test = new NPAPIClient::ExecuteScriptDeleteTest(instance,
+ NPAPIClient::PluginClient::HostFunctions());
+ windowless_plugin = true;
+ } else if (_stricmp(argv[name_index], "getjavascripturl") == 0) {
+ new_test = new NPAPIClient::ExecuteGetJavascriptUrlTest(instance,
+ NPAPIClient::PluginClient::HostFunctions());
+ } else if (_stricmp(argv[name_index], "checkwindowrect") == 0) {
+ new_test = new NPAPIClient::PluginWindowSizeTest(instance,
+ NPAPIClient::PluginClient::HostFunctions());
+ } else if (_stricmp(argv[name_index], "self_delete_plugin_stream") == 0) {
+ new_test = new NPAPIClient::DeletePluginInStreamTest(instance,
+ NPAPIClient::PluginClient::HostFunctions());
+ } else if (_stricmp(argv[name_index], "npobject_lifetime_test") == 0) {
+ new_test = new NPAPIClient::NPObjectLifetimeTest(instance,
+ NPAPIClient::PluginClient::HostFunctions());
+ } else if (_stricmp(argv[name_index],
+ "npobject_lifetime_test_second_instance") == 0) {
+ new_test = new NPAPIClient::NPObjectLifetimeTestInstance2(instance,
+ NPAPIClient::PluginClient::HostFunctions());
+ } else if (_stricmp(argv[name_index], "new_fails") == 0) {
+ new_test = new NPAPIClient::NewFailsTest(instance,
+ NPAPIClient::PluginClient::HostFunctions());
+ } else if (_stricmp(argv[name_index],
+ "npobject_delete_plugin_in_evaluate") == 0) {
+ new_test = new NPAPIClient::NPObjectDeletePluginInNPN_Evaluate(instance,
+ NPAPIClient::PluginClient::HostFunctions());
+ } else {
+ // If we don't have a test case for this, create a
+ // generic one which basically never fails.
+ new_test = new NPAPIClient::PluginTest(instance,
+ NPAPIClient::PluginClient::HostFunctions());
+ }
+
+ if (new_test) {
+ ret = new_test->New(mode, argc, (const char**)argn,
+ (const char**)argv, saved);
+ if ((ret == NPERR_NO_ERROR) && windowless_plugin) {
+ NPAPIClient::PluginClient::HostFunctions()->setvalue(
+ instance, NPPVpluginWindowBool, NULL);
+ }
+ }
+
+ return ret;
+}
+
+NPError NPP_Destroy(NPP instance, NPSavedData** save) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ NPAPIClient::PluginTest *plugin =
+ (NPAPIClient::PluginTest*)instance->pdata;
+ delete plugin;
+
+ // XXXMB - do work here.
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError NPP_SetWindow(NPP instance, NPWindow* pNPWindow) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ if (pNPWindow->window == NULL) {
+ return NPERR_NO_ERROR;
+ }
+
+ NPAPIClient::PluginTest *plugin =
+ (NPAPIClient::PluginTest*)instance->pdata;
+
+ return plugin->SetWindow(pNPWindow);
+}
+
+NPError NPP_NewStream(NPP instance, NPMIMEType type,
+ NPStream* stream, NPBool seekable, uint16* stype) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ NPAPIClient::PluginTest *plugin =
+ (NPAPIClient::PluginTest*)instance->pdata;
+
+ return plugin->NewStream(type, stream, seekable, stype);
+}
+
+int32 NPP_WriteReady(NPP instance, NPStream *stream) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ NPAPIClient::PluginTest *plugin =
+ (NPAPIClient::PluginTest*)instance->pdata;
+
+ return plugin->WriteReady(stream);
+}
+
+int32 NPP_Write(NPP instance, NPStream *stream, int32 offset,
+ int32 len, void *buffer) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ NPAPIClient::PluginTest *plugin =
+ (NPAPIClient::PluginTest*)instance->pdata;
+
+ return plugin->Write(stream, offset, len, buffer);
+}
+
+NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPError reason) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ NPAPIClient::PluginTest *plugin =
+ (NPAPIClient::PluginTest*)instance->pdata;
+
+ return plugin->DestroyStream(stream, reason);
+}
+
+void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname) {
+ if (instance == NULL)
+ return;
+
+ NPAPIClient::PluginTest *plugin =
+ (NPAPIClient::PluginTest*)instance->pdata;
+
+ return plugin->StreamAsFile(stream, fname);
+}
+
+void NPP_Print(NPP instance, NPPrint* printInfo) {
+ if (instance == NULL)
+ return;
+
+ // XXXMB - do work here.
+}
+
+void NPP_URLNotify(NPP instance, const char* url, NPReason reason,
+ void* notifyData) {
+ if (instance == NULL)
+ return;
+
+ NPAPIClient::PluginTest *plugin =
+ (NPAPIClient::PluginTest*)instance->pdata;
+
+ return plugin->URLNotify(url, reason, notifyData);
+}
+
+NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ // XXXMB - do work here.
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ // XXXMB - do work here.
+ return NPERR_GENERIC_ERROR;
+}
+
+int16 NPP_HandleEvent(NPP instance, void* event) {
+ if (instance == NULL)
+ return 0;
+
+ NPAPIClient::PluginTest *plugin =
+ (NPAPIClient::PluginTest*)instance->pdata;
+
+ return plugin->HandleEvent(event);
+}
+
+void* NPP_GetJavaClass(void) {
+ // XXXMB - do work here.
+ return NULL;
+}
+} // extern "C"
+
+
+
+
diff --git a/webkit/glue/plugins/test/plugin_client.h b/webkit/glue/plugins/test/plugin_client.h
new file mode 100644
index 0000000..70df0fe
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_client.h
@@ -0,0 +1,71 @@
+// 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 WEBKIT_PORT_PLUGINS_TEST_PLUGIN_CLIENT_H__
+#define WEBKIT_PORT_PLUGINS_TEST_PLUGIN_CLIENT_H__
+
+#include "webkit/glue/plugins/nphostapi.h"
+#include "third_party/npapi/bindings/npapi.h"
+
+namespace NPAPIClient {
+
+// A PluginClient is a NPAPI Plugin. This class contains
+// the bootstrapping functions used by the browser to load
+// the plugin.
+class PluginClient {
+ public:
+ // Although not documented in the NPAPI specification, this function
+ // gets the list of entry points in the NPAPI Plugin (client) for the
+ // NPAPI Host to call.
+ static NPError GetEntryPoints(NPPluginFuncs* pFuncs);
+
+ // The browser calls this function only once: when a plug-in is loaded,
+ // before the first instance is created. This is the first function that
+ // the browser calls. NP_Initialize tells the plug-in that the browser has
+ // loaded it and provides global initialization. Allocate any memory or
+ // resources shared by all instances of your plug-in at this time.
+ static NPError Initialize(NPNetscapeFuncs* pFuncs);
+
+ // The browser calls this function once after the last instance of your
+ // plug-in is destroyed, before unloading the plug-in library itself. Use
+ // NP_Shutdown to delete any data allocated in NP_Initialize to be shared
+ // by all instances of a plug-in.
+ static NPError Shutdown();
+
+ // The table of functions provided by the host.
+ static NPNetscapeFuncs *HostFunctions() { return host_functions_; }
+
+ private:
+ static NPNetscapeFuncs* host_functions_;
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PORT_PLUGINS_TEST_PLUGIN_CLIENT_H__
+
diff --git a/webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.cc b/webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.cc
new file mode 100644
index 0000000..86fd917
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.cc
@@ -0,0 +1,67 @@
+// 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/plugins/test/plugin_delete_plugin_in_stream_test.h"
+
+#include "webkit/glue/plugins/test/plugin_client.h"
+
+namespace NPAPIClient {
+
+#define kUrl "javascript:window.location+\"\""
+#define kUrlStreamId 1
+
+DeletePluginInStreamTest::DeletePluginInStreamTest(NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions),
+ test_started_(false) {
+}
+
+NPError DeletePluginInStreamTest::SetWindow(NPWindow* pNPWindow) {
+ if (!test_started_) {
+ std::string url = "self_delete_plugin_stream.html";
+ HostFunctions()->geturlnotify(id(), url.c_str(), NULL,
+ reinterpret_cast<void*>(kUrlStreamId));
+ test_started_ = true;
+ }
+ return NPERR_NO_ERROR;
+}
+
+NPError DeletePluginInStreamTest::NewStream(NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype) {
+ NPIdentifier delete_id = HostFunctions()->getstringidentifier("DeletePluginWithinScript");
+
+ NPObject *window_obj = NULL;
+ HostFunctions()->getvalue(id(), NPNVWindowNPObject, &window_obj);
+
+ NPVariant rv;
+ HostFunctions()->invoke(id(), window_obj, delete_id, NULL, 0, &rv);
+
+ return NPERR_NO_ERROR;
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.h b/webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.h
new file mode 100644
index 0000000..8eeaefb
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.h
@@ -0,0 +1,56 @@
+// 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 WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_DELETE_PLUGIN_IN_STREAM_TEST_H
+#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_DELETE_PLUGIN_IN_STREAM_TEST_H
+
+#include "webkit/glue/plugins/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// This class tests
+class DeletePluginInStreamTest : public PluginTest {
+ public:
+ // Constructor.
+ DeletePluginInStreamTest(NPP id, NPNetscapeFuncs *host_functions);
+ //
+ // NPAPI functions
+ //
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+ virtual NPError NewStream(NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype);
+ private:
+ bool test_started_;
+ std::string self_url_;
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_DELETE_PLUGIN_IN_STREAM_TEST_H
+
diff --git a/webkit/glue/plugins/test/plugin_execute_script_delete_test.cc b/webkit/glue/plugins/test/plugin_execute_script_delete_test.cc
new file mode 100644
index 0000000..c18c91c
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_execute_script_delete_test.cc
@@ -0,0 +1,53 @@
+// 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.
+
+#define STRSAFE_NO_DEPRECATE
+#include "webkit/glue/plugins/test/plugin_execute_script_delete_test.h"
+#include "webkit/glue/plugins/test/plugin_client.h"
+
+namespace NPAPIClient {
+
+ExecuteScriptDeleteTest::ExecuteScriptDeleteTest(NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions) {
+}
+
+int16 ExecuteScriptDeleteTest::HandleEvent(void* event) {
+ NPEvent* np_event = reinterpret_cast<NPEvent*>(event);
+ if (WM_PAINT == np_event->event ) {
+ NPNetscapeFuncs* browser = NPAPIClient::PluginClient::HostFunctions();
+ NPUTF8* urlString = "javascript:DeletePluginWithinScript()";
+ NPUTF8* targetString = NULL;
+ browser->geturl(id(), urlString, targetString);
+ SignalTestCompleted();
+ }
+ // If this test failed, then we'd have crashed by now.
+ return PluginTest::HandleEvent(event);
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_execute_script_delete_test.h b/webkit/glue/plugins/test/plugin_execute_script_delete_test.h
new file mode 100644
index 0000000..fe3c6ecf
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_execute_script_delete_test.h
@@ -0,0 +1,50 @@
+// 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 WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_EXECUTE_SCRIPT_DELETE_TEST_H
+#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_EXECUTE_SCRIPT_DELETE_TEST_H
+
+#include "webkit/glue/plugins/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// This class tests the case where a plugin instance is deleted by invoking
+// a javascript function in the context of a paint event.
+class ExecuteScriptDeleteTest : public PluginTest {
+ public:
+ // Constructor.
+ ExecuteScriptDeleteTest(NPP id, NPNetscapeFuncs *host_functions);
+ // NPAPI HandleEvent handler
+ virtual int16 HandleEvent(void* event);
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_EXECUTE_SCRIPT_DELETE_TEST_H
+
diff --git a/webkit/glue/plugins/test/plugin_get_javascript_url_test.cc b/webkit/glue/plugins/test/plugin_get_javascript_url_test.cc
new file mode 100644
index 0000000..1b6f1bd
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_get_javascript_url_test.cc
@@ -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.
+
+#include "webkit/glue/plugins/test/plugin_get_javascript_url_test.h"
+
+
+// url for "self".
+#define SELF_URL "javascript:window.location+\"\""
+// The identifier for the self url stream.
+#define SELF_URL_STREAM_ID 1
+
+// The identifier for the fetched url stream.
+#define FETCHED_URL_STREAM_ID 2
+
+// The maximum chunk size of stream data.
+#define STREAM_CHUNK 197
+
+namespace NPAPIClient {
+
+ExecuteGetJavascriptUrlTest::ExecuteGetJavascriptUrlTest(NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions),
+ test_started_(false) {
+}
+
+NPError ExecuteGetJavascriptUrlTest::SetWindow(NPWindow* pNPWindow) {
+ if (!test_started_) {
+ std::string url = SELF_URL;
+ HostFunctions()->geturlnotify(id(), url.c_str(), "_top",
+ reinterpret_cast<void*>(SELF_URL_STREAM_ID));
+ test_started_ = true;
+ }
+ return NPERR_NO_ERROR;
+}
+
+NPError ExecuteGetJavascriptUrlTest::NewStream(NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype) {
+ if (stream == NULL)
+ SetError("NewStream got null stream");
+
+ unsigned long stream_id = PtrToUlong(stream->notifyData);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ break;
+ default:
+ SetError("Unexpected NewStream callback");
+ break;
+ }
+ return NPERR_NO_ERROR;
+}
+
+int32 ExecuteGetJavascriptUrlTest::WriteReady(NPStream *stream) {
+ return STREAM_CHUNK;
+}
+
+int32 ExecuteGetJavascriptUrlTest::Write(NPStream *stream, int32 offset, int32 len,
+ void *buffer) {
+ if (stream == NULL)
+ SetError("Write got null stream");
+ if (len < 0 || len > STREAM_CHUNK)
+ SetError("Write got bogus stream chunk size");
+
+ unsigned long stream_id = PtrToUlong(stream->notifyData);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ self_url_.append(static_cast<char*>(buffer), len);
+ break;
+ default:
+ SetError("Unexpected write callback");
+ break;
+ }
+ // Pretend that we took all the data.
+ return len;
+}
+
+
+NPError ExecuteGetJavascriptUrlTest::DestroyStream(NPStream *stream, NPError reason) {
+ if (stream == NULL)
+ SetError("NewStream got null stream");
+
+ unsigned long stream_id = PtrToUlong(stream->notifyData);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ // don't care
+ break;
+ default:
+ SetError("Unexpected NewStream callback");
+ break;
+ }
+ return NPERR_NO_ERROR;
+}
+
+void ExecuteGetJavascriptUrlTest::URLNotify(const char* url, NPReason reason, void* data) {
+ unsigned long stream_id = PtrToUlong(data);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ if (strcmp(url, SELF_URL) != 0)
+ SetError("URLNotify reported incorrect url for SELF_URL");
+ if (self_url_.empty())
+ SetError("Failed to obtain window location.");
+ SignalTestCompleted();
+ break;
+ default:
+ SetError("Unexpected NewStream callback");
+ break;
+ }
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_get_javascript_url_test.h b/webkit/glue/plugins/test/plugin_get_javascript_url_test.h
new file mode 100644
index 0000000..33b627e
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_get_javascript_url_test.h
@@ -0,0 +1,63 @@
+// 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 WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_GET_JAVASCRIPT_URL_H
+#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_GET_JAVASCRIPT_URL_H
+
+#include "webkit/glue/plugins/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// This class tests NPP_GetURLNotify for a javascript URL with _top
+// as the target frame.
+class ExecuteGetJavascriptUrlTest : public PluginTest {
+ public:
+ // Constructor.
+ ExecuteGetJavascriptUrlTest(NPP id, NPNetscapeFuncs *host_functions);
+ //
+ // NPAPI functions
+ //
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+ virtual NPError NewStream(NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype);
+ virtual int32 WriteReady(NPStream *stream);
+ virtual int32 Write(NPStream *stream, int32 offset, int32 len,
+ void *buffer);
+ virtual NPError DestroyStream(NPStream *stream, NPError reason);
+ virtual void URLNotify(const char* url, NPReason reason, void* data);
+
+ private:
+ bool test_started_;
+ std::string self_url_;
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_GET_JAVASCRIPT_URL_H
+
diff --git a/webkit/glue/plugins/test/plugin_geturl_test.cc b/webkit/glue/plugins/test/plugin_geturl_test.cc
new file mode 100644
index 0000000..33a2f17
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_geturl_test.cc
@@ -0,0 +1,253 @@
+// 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/plugins/test/plugin_geturl_test.h"
+
+// url for "self". The %22%22 is to make a statement for javascript to
+// evaluate and return.
+#define SELF_URL "javascript:window.location+\"\""
+
+// The identifier for the self url stream.
+#define SELF_URL_STREAM_ID 1
+
+// The identifier for the fetched url stream.
+#define FETCHED_URL_STREAM_ID 2
+
+// url for testing GetURL with a bogus URL.
+#define BOGUS_URL "bogoproto:///x:/asdf.xysdhffieasdf.asdhj/"
+
+// The identifier for the bogus url stream.
+#define BOGUS_URL_STREAM_ID 3
+
+// The maximum chunk size of stream data.
+#define STREAM_CHUNK 197
+
+namespace NPAPIClient {
+
+PluginGetURLTest::PluginGetURLTest(NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions),
+ tests_started_(false),
+ tests_in_progress_(0),
+ test_file_handle_(INVALID_HANDLE_VALUE) {
+}
+
+NPError PluginGetURLTest::SetWindow(NPWindow* pNPWindow) {
+ if (!tests_started_) {
+ tests_started_ = true;
+
+ tests_in_progress_++;
+
+ std::string url = SELF_URL;
+ HostFunctions()->geturlnotify(id(), url.c_str(), NULL,
+ reinterpret_cast<void*>(SELF_URL_STREAM_ID));
+
+ tests_in_progress_++;
+ std::string bogus_url = BOGUS_URL;
+ HostFunctions()->geturlnotify(id(), bogus_url.c_str(), NULL,
+ reinterpret_cast<void*>(BOGUS_URL_STREAM_ID));
+ }
+ return NPERR_NO_ERROR;
+}
+
+NPError PluginGetURLTest::NewStream(NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype) {
+ if (stream == NULL)
+ SetError("NewStream got null stream");
+
+ unsigned long stream_id = PtrToUlong(stream->notifyData);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ break;
+ case FETCHED_URL_STREAM_ID:
+ {
+ std::string filename = self_url_;
+ if (filename.find("file:///", 0) != 0) {
+ SetError("Test expects a file-url.");
+ break;
+ }
+
+ filename = filename.substr(8); // remove "file:///"
+
+ test_file_handle_ = CreateFileA(filename.c_str(),
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL);
+ if (test_file_handle_ == INVALID_HANDLE_VALUE)
+ SetError("Could not open source file");
+ }
+ break;
+ case BOGUS_URL_STREAM_ID:
+ SetError("Unexpected NewStream for BOGUS_URL");
+ break;
+ default:
+ SetError("Unexpected NewStream callback");
+ break;
+ }
+ return NPERR_NO_ERROR;
+}
+
+int32 PluginGetURLTest::WriteReady(NPStream *stream) {
+ unsigned long stream_id = PtrToUlong(stream->notifyData);
+ if (stream_id == BOGUS_URL_STREAM_ID)
+ SetError("Received WriteReady for BOGUS_URL");
+
+ return STREAM_CHUNK;
+}
+
+int32 PluginGetURLTest::Write(NPStream *stream, int32 offset, int32 len,
+ void *buffer) {
+ if (stream == NULL)
+ SetError("Write got null stream");
+ if (len < 0 || len > STREAM_CHUNK)
+ SetError("Write got bogus stream chunk size");
+
+ unsigned long stream_id = PtrToUlong(stream->notifyData);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ self_url_.append(static_cast<char*>(buffer), len);
+ break;
+ case FETCHED_URL_STREAM_ID:
+ {
+ char read_buffer[STREAM_CHUNK];
+ DWORD bytes = 0;
+ if (!ReadFile(test_file_handle_, read_buffer, len,
+ &bytes, NULL))
+ SetError("Could not read data from source file");
+ // Technically, readfile could return fewer than len
+ // bytes. But this is not likely.
+ if (bytes != len)
+ SetError("Did not read correct bytelength from source file");
+ if (memcmp(read_buffer, buffer, len))
+ SetError("Content mismatch between data and source!");
+ }
+ break;
+ case BOGUS_URL_STREAM_ID:
+ SetError("Unexpected write callback for BOGUS_URL");
+ break;
+ default:
+ SetError("Unexpected write callback");
+ break;
+ }
+ // Pretend that we took all the data.
+ return len;
+}
+
+
+NPError PluginGetURLTest::DestroyStream(NPStream *stream, NPError reason) {
+ if (stream == NULL)
+ SetError("NewStream got null stream");
+
+ unsigned long stream_id = PtrToUlong(stream->notifyData);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ // don't care
+ break;
+ case FETCHED_URL_STREAM_ID:
+ {
+ char read_buffer[STREAM_CHUNK];
+ DWORD bytes = 0;
+ if (!ReadFile(test_file_handle_, read_buffer, sizeof(read_buffer),
+ &bytes, NULL))
+ SetError("Could not read data from source file");
+ if (bytes != 0)
+ SetError("Data and source mismatch on length");
+ CloseHandle(test_file_handle_);
+ }
+ break;
+ default:
+ SetError("Unexpected NewStream callback");
+ break;
+ }
+ return NPERR_NO_ERROR;
+}
+
+void PluginGetURLTest::StreamAsFile(NPStream* stream, const char* fname) {
+ if (stream == NULL)
+ SetError("NewStream got null stream");
+
+ unsigned long stream_id = PtrToUlong(stream->notifyData);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ // don't care
+ break;
+ default:
+ SetError("Unexpected NewStream callback");
+ break;
+ }
+}
+
+void PluginGetURLTest::URLNotify(const char* url, NPReason reason, void* data) {
+ if (!tests_in_progress_) {
+ SetError("URLNotify received after tests completed");
+ return;
+ }
+
+ if (!url) {
+ SetError("URLNotify received NULL url");
+ return;
+ }
+
+ unsigned long stream_id = PtrToUlong(data);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ if (strcmp(url, SELF_URL) != 0)
+ SetError("URLNotify reported incorrect url for SELF_URL");
+
+ // We have our stream url. Go fetch it.
+ HostFunctions()->geturlnotify(id(), self_url_.c_str(), NULL,
+ reinterpret_cast<void*>(FETCHED_URL_STREAM_ID));
+ break;
+ case FETCHED_URL_STREAM_ID:
+ if (!url || strcmp(url, self_url_.c_str()) != 0)
+ SetError("URLNotify reported incorrect url for FETCHED_URL");
+ tests_in_progress_--;
+ break;
+ case BOGUS_URL_STREAM_ID:
+ if (reason != NPRES_NETWORK_ERR) {
+ std::string err = "BOGUS_URL received unexpected URLNotify status: ";
+ char buf[10];
+ _itoa_s(reason, buf, 10, 10);
+ err.append(buf);
+ SetError(err);
+ }
+ tests_in_progress_--;
+ break;
+ default:
+ SetError("Unexpected NewStream callback");
+ break;
+ }
+
+ if (tests_in_progress_ == 0)
+ SignalTestCompleted();
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_geturl_test.h b/webkit/glue/plugins/test/plugin_geturl_test.h
new file mode 100644
index 0000000..07e41aa
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_geturl_test.h
@@ -0,0 +1,71 @@
+// 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 WEBKIT_PORT_PLUGINS_TEST_PLUGIN_GETURL_TEST_H__
+#define WEBKIT_PORT_PLUGINS_TEST_PLUGIN_GETURL_TEST_H__
+
+#include "webkit/glue/plugins/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// The PluginGetURLTest test functionality of the NPN_GetURL
+// and NPN_GetURLNotify methods.
+//
+// This test first discovers it's URL by sending a GetURL request
+// for 'javascript:top.location'. After receiving that, the
+// test will request the url itself (again via GetURL).
+class PluginGetURLTest : public PluginTest {
+ public:
+ // Constructor.
+ PluginGetURLTest(NPP id, NPNetscapeFuncs *host_functions);
+
+ //
+ // NPAPI functions
+ //
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+ virtual NPError NewStream(NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype);
+ virtual int32 WriteReady(NPStream *stream);
+ virtual int32 Write(NPStream *stream, int32 offset, int32 len,
+ void *buffer);
+ virtual NPError DestroyStream(NPStream *stream, NPError reason);
+ virtual void StreamAsFile(NPStream* stream, const char* fname);
+ virtual void URLNotify(const char* url, NPReason reason, void* data);
+
+ private:
+ bool tests_started_;
+ int tests_in_progress_;
+ std::string self_url_;
+ HANDLE test_file_handle_;
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PORT_PLUGINS_TEST_PLUGIN_GETURL_TEST_H__
+
diff --git a/webkit/glue/plugins/test/plugin_new_fails_test.cc b/webkit/glue/plugins/test/plugin_new_fails_test.cc
new file mode 100644
index 0000000..382bf4e
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_new_fails_test.cc
@@ -0,0 +1,43 @@
+// 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/plugins/test/plugin_new_fails_test.h"
+
+namespace NPAPIClient {
+
+NewFailsTest::NewFailsTest(NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions) {
+}
+
+NPError NewFailsTest::New(uint16 mode, int16 argc, const char* argn[],
+ const char* argv[], NPSavedData* saved) {
+ return NPERR_GENERIC_ERROR;
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_new_fails_test.h b/webkit/glue/plugins/test/plugin_new_fails_test.h
new file mode 100644
index 0000000..e864553
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_new_fails_test.h
@@ -0,0 +1,46 @@
+// 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 WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_PLUGIN_NEW_FAILS_TEST_H__
+#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_PLUGIN_NEW_FAILS_TEST_H__
+
+#include "webkit/glue/plugins/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+class NewFailsTest : public PluginTest {
+ public:
+ NewFailsTest(NPP id, NPNetscapeFuncs *host_functions);
+ virtual NPError New(uint16 mode, int16 argc, const char* argn[],
+ const char* argv[], NPSavedData* saved);
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_PLUGIN_NPP_NEW_FAILS_TEST_H__
diff --git a/webkit/glue/plugins/test/plugin_npobject_lifetime_test.cc b/webkit/glue/plugins/test/plugin_npobject_lifetime_test.cc
new file mode 100644
index 0000000..24cc9e9
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_npobject_lifetime_test.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.
+
+#include "webkit/glue/plugins/test/plugin_npobject_lifetime_test.h"
+
+namespace NPAPIClient {
+
+const int kNPObjectLifetimeTimer = 100;
+const int kNPObjectLifetimeTimerElapse = 2000;
+
+NPObject* NPObjectLifetimeTestInstance2::plugin_instance_object_ = NULL;
+
+NPObjectDeletePluginInNPN_Evaluate*
+ NPObjectDeletePluginInNPN_Evaluate::g_npn_evaluate_test_instance_ = NULL;
+
+NPObjectLifetimeTest::NPObjectLifetimeTest(NPP id,
+ NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions),
+ other_plugin_instance_object_(NULL) {
+}
+
+NPError NPObjectLifetimeTest::SetWindow(NPWindow* pNPWindow) {
+ HWND window_handle = reinterpret_cast<HWND>(pNPWindow->window);
+ if (!::GetProp(window_handle, L"Plugin_Instance")) {
+ ::SetProp(window_handle, L"Plugin_Instance", this);
+ // We attempt to retreive the NPObject for the plugin instance identified
+ // by the NPObjectLifetimeTestInstance2 class as it may not have been
+ // instantiated yet.
+ SetTimer(window_handle, kNPObjectLifetimeTimer, kNPObjectLifetimeTimerElapse,
+ TimerProc);
+ }
+ return NPERR_NO_ERROR;
+}
+
+void CALLBACK NPObjectLifetimeTest::TimerProc(
+ HWND window, UINT message, UINT timer_id,
+ unsigned long elapsed_milli_seconds) {
+
+ KillTimer(window, kNPObjectLifetimeTimer);
+ NPObjectLifetimeTest* this_instance =
+ reinterpret_cast<NPObjectLifetimeTest*>
+ (::GetProp(window, L"Plugin_Instance"));
+
+ this_instance->other_plugin_instance_object_ =
+ NPObjectLifetimeTestInstance2::plugin_instance_object_;
+ this_instance->HostFunctions()->retainobject(
+ this_instance->other_plugin_instance_object_);
+
+ NPString script;
+ script.UTF8Characters = "javascript:DeleteSecondPluginInstance()";
+ script.UTF8Length = static_cast<uint32_t>(strlen(script.UTF8Characters));
+
+ this_instance->HostFunctions()->geturlnotify(
+ this_instance->id(), "javascript:DeleteSecondPluginInstance()", NULL,
+ reinterpret_cast<void*>(1));
+}
+
+void NPObjectLifetimeTest::URLNotify(const char* url, NPReason reason,
+ void* data) {
+ // Create a "location" identifier.
+ NPIdentifier identifier = HostFunctions()->getstringidentifier("location");
+ // Declare a local variant value.
+ NPVariant variantValue;
+ // Get the location property from the window object (which is another object).
+ bool b1 = HostFunctions()->getproperty(id(), other_plugin_instance_object_,
+ identifier, &variantValue );
+ HostFunctions()->releaseobject(other_plugin_instance_object_);
+ other_plugin_instance_object_ = NULL;
+ // If this test failed, then we'd have crashed by now.
+ SignalTestCompleted();
+}
+
+NPObjectLifetimeTestInstance2::NPObjectLifetimeTestInstance2(
+ NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions) {
+}
+
+NPObjectLifetimeTestInstance2::~NPObjectLifetimeTestInstance2() {
+ if (plugin_instance_object_) {
+ HostFunctions()->releaseobject(plugin_instance_object_);
+ plugin_instance_object_ = NULL;
+ }
+}
+
+NPError NPObjectLifetimeTestInstance2::SetWindow(NPWindow* pNPWindow) {
+ if (!plugin_instance_object_) {
+ if (!HostFunctions()->getvalue(id(), NPNVWindowNPObject,
+ &plugin_instance_object_)) {
+ SetError("Failed to get NPObject for plugin instance2");
+ SignalTestCompleted();
+ return NPERR_GENERIC_ERROR;
+ }
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+
+NPObjectDeletePluginInNPN_Evaluate::NPObjectDeletePluginInNPN_Evaluate(
+ NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions),
+ plugin_instance_object_(NULL),
+ npn_evaluate_timer_proc_set_(false) {
+ g_npn_evaluate_test_instance_ = this;
+}
+
+NPObjectDeletePluginInNPN_Evaluate::~NPObjectDeletePluginInNPN_Evaluate() {
+ if (plugin_instance_object_) {
+ HostFunctions()->releaseobject(plugin_instance_object_);
+ plugin_instance_object_ = NULL;
+ }
+}
+
+NPError NPObjectDeletePluginInNPN_Evaluate::SetWindow(NPWindow* np_window) {
+ if (!::IsWindowVisible(reinterpret_cast<HWND>(np_window->window)))
+ return NPERR_NO_ERROR;
+
+ HWND window_handle = reinterpret_cast<HWND>(np_window->window);
+ // We setup a timerproc to invoke NPN_Evaluate to destroy this plugin
+ // instance. This is to ensure that we don't destroy the plugin instance
+ // while it is being used in webkit as this leads to crashes and is a
+ // more accurate representation of the renderer crash as described in
+ // http://b/issue?id=1134683.
+ if (!npn_evaluate_timer_proc_set_) {
+ npn_evaluate_timer_proc_set_ = true;
+ SetTimer(window_handle, kNPObjectLifetimeTimer, kNPObjectLifetimeTimerElapse,
+ TimerProc);
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+void CALLBACK NPObjectDeletePluginInNPN_Evaluate::TimerProc(
+ HWND window, UINT message, UINT timer_id,
+ unsigned long elapsed_milli_seconds) {
+
+ KillTimer(window, kNPObjectLifetimeTimer);
+ NPObject *window_obj = NULL;
+ g_npn_evaluate_test_instance_->HostFunctions()->getvalue(
+ g_npn_evaluate_test_instance_->id(), NPNVWindowNPObject,
+ &window_obj);
+
+ if (!window_obj) {
+ g_npn_evaluate_test_instance_->SetError(
+ "Failed to get NPObject for plugin instance2");
+ g_npn_evaluate_test_instance_->SignalTestCompleted();
+ return;
+ }
+
+ std::string script = "javascript:DeletePluginWithinScript()";
+ NPString script_string;
+ script_string.UTF8Characters = script.c_str();
+ script_string.UTF8Length =
+ static_cast<unsigned int>(script.length());
+
+ NPVariant result_var;
+ NPError result = g_npn_evaluate_test_instance_->HostFunctions()->evaluate(
+ g_npn_evaluate_test_instance_->id(), window_obj,
+ &script_string, &result_var);
+ // If this test failed we would have crashed by now.
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_npobject_lifetime_test.h b/webkit/glue/plugins/test/plugin_npobject_lifetime_test.h
new file mode 100644
index 0000000..2a5d808
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_npobject_lifetime_test.h
@@ -0,0 +1,96 @@
+// 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 WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_NPOBJECT_LIFETIME_TEST_H__
+#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_NPOBJECT_LIFETIME_TEST_H__
+
+#include "webkit/glue/plugins/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// The NPObjectLifeTime class tests the case where a plugin has an NPObject
+// which points to a different plugin instance on a different frame in the
+// page and whether refcounts on this npobject are valid when the source frame
+// is destroyed.
+class NPObjectLifetimeTest : public PluginTest {
+ public:
+ // Constructor.
+ NPObjectLifetimeTest(NPP id, NPNetscapeFuncs *host_functions);
+
+ // NPAPI SetWindow handler.
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+
+ virtual void URLNotify(const char* url, NPReason reason, void* data);
+
+ protected:
+ NPObject* other_plugin_instance_object_;
+ static void CALLBACK TimerProc(HWND window, UINT message, UINT timer_id,
+ unsigned long elapsed_milli_seconds);
+};
+
+// The NPObjectLifetimeTestInstance2 class represents the plugin instance
+// which is deleted by the NPObjectLifeTime class via a javascript function.
+class NPObjectLifetimeTestInstance2 : public PluginTest {
+ public:
+ // Constructor.
+ NPObjectLifetimeTestInstance2(NPP id, NPNetscapeFuncs *host_functions);
+ ~NPObjectLifetimeTestInstance2();
+
+ // NPAPI SetWindow handler.
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+ protected:
+ static NPObject* plugin_instance_object_;
+ friend class NPObjectLifetimeTest;
+
+};
+
+// The NPObjectLifeTime class tests the case where a plugin instance is
+// destroyed in NPN_Evaluate
+class NPObjectDeletePluginInNPN_Evaluate : public PluginTest {
+ public:
+ // Constructor.
+ NPObjectDeletePluginInNPN_Evaluate(NPP id, NPNetscapeFuncs *host_functions);
+ ~NPObjectDeletePluginInNPN_Evaluate();
+
+ // NPAPI SetWindow handler.
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+
+ protected:
+ NPObject* plugin_instance_object_;
+ static void CALLBACK TimerProc(HWND window, UINT message, UINT timer_id,
+ unsigned long elapsed_milli_seconds);
+ private:
+ bool npn_evaluate_timer_proc_set_;
+ static NPObjectDeletePluginInNPN_Evaluate* g_npn_evaluate_test_instance_;
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_NPOBJECT_LIFETIME_TEST_H__
+
diff --git a/webkit/glue/plugins/test/plugin_npobject_proxy_test.cc b/webkit/glue/plugins/test/plugin_npobject_proxy_test.cc
new file mode 100644
index 0000000..e7fa2fb
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_npobject_proxy_test.cc
@@ -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.
+
+#define STRSAFE_NO_DEPRECATE
+#include <strsafe.h>
+#include "webkit/glue/plugins/test/plugin_npobject_proxy_test.h"
+
+namespace NPAPIClient {
+
+NPObjectProxyTest::NPObjectProxyTest(NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions) {
+}
+
+NPError NPObjectProxyTest::SetWindow(NPWindow* pNPWindow) {
+ NPIdentifier document_id = HostFunctions()->getstringidentifier("document");
+ NPIdentifier create_text_node_id = HostFunctions()->getstringidentifier("createTextNode");
+ NPIdentifier append_child_id = HostFunctions()->getstringidentifier("appendChild");
+
+ NPVariant docv;
+ NPObject *window_obj = NULL;
+ HostFunctions()->getvalue(id(), NPNVWindowNPObject, &window_obj);
+
+ HostFunctions()->getproperty(id(), window_obj, document_id, &docv);
+ NPObject *doc = NPVARIANT_TO_OBJECT(docv);
+
+ NPVariant strv;
+#pragma warning(suppress: 4267)
+ STRINGZ_TO_NPVARIANT("div", strv);
+
+ NPVariant textv;
+ HostFunctions()->invoke(id(), doc, create_text_node_id, &strv, 1, &textv);
+
+ NPVariant v;
+ HostFunctions()->invoke(id(), doc, append_child_id, &textv, 1, &v);
+
+ // If this test failed, then we'd have crashed by now.
+ SignalTestCompleted();
+
+ return NPERR_NO_ERROR;
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_npobject_proxy_test.h b/webkit/glue/plugins/test/plugin_npobject_proxy_test.h
new file mode 100644
index 0000000..e5c94d4
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_npobject_proxy_test.h
@@ -0,0 +1,53 @@
+// 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 WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_NPOBJECT_PROXY_TEST_H__
+#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_NPOBJECT_PROXY_TEST_H__
+
+#include "webkit/glue/plugins/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// The NPObjectProxyTest tests that when we proxy an NPObject that is itself
+// a proxy, we don't create a new proxy but instead just use the original
+// pointer.
+
+class NPObjectProxyTest : public PluginTest {
+ public:
+ // Constructor.
+ NPObjectProxyTest(NPP id, NPNetscapeFuncs *host_functions);
+
+ // NPAPI SetWindow handler.
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_NPOBJECT_PROXY_TEST_H__
+
diff --git a/webkit/glue/plugins/test/plugin_test.cc b/webkit/glue/plugins/test/plugin_test.cc
new file mode 100644
index 0000000..043fef9
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_test.cc
@@ -0,0 +1,160 @@
+// 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/plugins/test/plugin_test.h"
+#include "webkit/glue/plugins/test/npapi_constants.h"
+
+namespace NPAPIClient {
+
+PluginTest::PluginTest(NPP id, NPNetscapeFuncs *host_functions) {
+ id_ = id;
+ id_->pdata = this;
+ host_functions_ = host_functions;
+}
+
+NPError PluginTest::New(uint16 mode, int16 argc, const char* argn[],
+ const char* argv[], NPSavedData* saved) {
+ test_name_ = this->GetArgValue("name", argc, argn, argv);
+ test_id_ = this->GetArgValue("id", argc, argn, argv);
+ return NPERR_NO_ERROR;
+}
+
+NPError PluginTest::SetWindow(NPWindow* pNPWindow) {
+ return NPERR_NO_ERROR;
+}
+
+// It's a shame I have to implement URLEncode. But, using webkit's
+// or using chrome's means a ball of string of dlls and dependencies that
+// is very very long. After spending far too much time on it,
+// I'll just encode it myself. Too bad Microsoft doesn't implement
+// this in a reusable way either. Both webkit and chrome will
+// end up using libicu, which is a string of dependencies we don't
+// want.
+
+inline BYTE toHex(const BYTE &x) {
+ return x > 9 ? x + 55: x + 48;
+}
+
+std::string URLEncode(const std::string &sIn) {
+ std::string sOut;
+
+ const size_t length = sIn.length();
+ for (size_t idx = 0; idx < length;) {
+ const char ch = sIn.at(idx);
+ if (isalnum(ch)) {
+ sOut.append(1, ch);
+ } else if (isspace(ch) && ((ch != '\n') && (ch != '\r'))) {
+ sOut.append(1, '+');
+ } else {
+ sOut.append(1, '%');
+ sOut.append(1, toHex(ch>>4));
+ sOut.append(1, toHex(ch%16));
+ }
+ idx++;
+ }
+ return sOut;
+}
+
+void PluginTest::SignalTestCompleted() {
+ // To signal test completion, we expect a couple of
+ // javascript functions to be defined in the webpage
+ // which hosts this plugin:
+ // onSuccess(test_name, test_id)
+ // onFailure(test_name, test_id, error_message)
+ std::string script_result;
+ std::string script_url;
+ if (Succeeded()) {
+ script_url.append("onSuccess(\"");
+ script_url.append(test_name_);
+ script_url.append("\",\"");
+ script_url.append(test_id_);
+ script_url.append("\");");
+ } else {
+ script_url.append("onFailure(\"");
+ script_url.append(test_name_);
+ script_url.append("\",\"");
+ script_url.append(test_id_);
+ script_url.append("\",\"");
+ script_url.append(test_status_);
+ script_url.append("\");");
+ }
+ script_url = URLEncode(script_url);
+ script_result.append("javascript:");
+ script_result.append(script_url);
+ host_functions_->geturl(id_, script_result.c_str(), "_self");
+}
+
+const char *PluginTest::GetArgValue(const char *name, const int16 argc,
+ const char *argn[], const char *argv[]) {
+ for (int idx = 0; idx < argc; idx++)
+ if (_stricmp(argn[idx], name) == 0)
+ return argv[idx];
+ return NULL;
+}
+
+void PluginTest::SetError(const std::string &msg) {
+ test_status_.append(msg);
+}
+
+NPError PluginTest::NewStream(NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype) {
+ // There is no default action here.
+ return NPERR_NO_ERROR;
+}
+
+int32 PluginTest::WriteReady(NPStream *stream) {
+ // Take data in small chunks
+ return 4096;
+}
+
+int32 PluginTest::Write(NPStream *stream, int32 offset, int32 len,
+ void *buffer) {
+ // Pretend that we took all the data.
+ return len;
+}
+
+NPError PluginTest::DestroyStream(NPStream *stream, NPError reason) {
+ // There is no default action.
+ return NPERR_NO_ERROR;
+}
+
+void PluginTest::StreamAsFile(NPStream* stream, const char* fname) {
+ // There is no default action.
+}
+
+void PluginTest::URLNotify(const char* url, NPReason reason, void* data) {
+ // There is no default action
+}
+
+int16 PluginTest::HandleEvent(void* event) {
+ // There is no default action
+ return 0;
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_test.h b/webkit/glue/plugins/test/plugin_test.h
new file mode 100644
index 0000000..0cdc1b7
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_test.h
@@ -0,0 +1,153 @@
+// 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 WEBKIT_PORT_PLUGINS_TEST_PLUGIN_TEST_H__
+#define WEBKIT_PORT_PLUGINS_TEST_PLUGIN_TEST_H__
+
+#include <string>
+
+#include "base/string_util.h"
+#include "webkit/glue/plugins/nphostapi.h"
+#include "third_party/npapi/bindings/npapi.h"
+
+namespace NPAPIClient {
+
+// A PluginTest represents an instance of the plugin, which in
+// our case is a test case.
+class PluginTest {
+ public:
+ // Constructor.
+ PluginTest(NPP id, NPNetscapeFuncs *host_functions);
+
+ // Destructor
+ virtual ~PluginTest() {}
+
+ //
+ // NPAPI Functions
+ //
+ virtual NPError New(uint16 mode, int16 argc, const char* argn[],
+ const char* argv[], NPSavedData* saved);
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+ virtual NPError NewStream(NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype);
+ virtual int32 WriteReady(NPStream *stream);
+ virtual int32 Write(NPStream *stream, int32 offset, int32 len,
+ void *buffer);
+ virtual NPError DestroyStream(NPStream *stream, NPError reason);
+ virtual void StreamAsFile(NPStream* stream, const char* fname);
+ virtual void URLNotify(const char* url, NPReason reason, void* data);
+ virtual int16 HandleEvent(void* event);
+ // Returns true if the test has not had any errors.
+ bool Succeeded() { return test_status_.length() == 0; }
+
+ // Sets an error for the test case. Appends the msg to the
+ // error that will be returned from the test.
+ void SetError(const std::string &msg);
+
+ // Expect two string values are equal, and if not, logs an
+ // appropriate error about it.
+ void ExpectStringLowerCaseEqual(const std::string &val1, const std::string &val2) {
+ if (!LowerCaseEqualsASCII(val1, val2.c_str())) {
+ std::string err;
+ err = "Expected Equal for '";
+ err.append(val1);
+ err.append("' and '");
+ err.append(val2);
+ err.append("'");
+ SetError(err);
+ }
+ };
+
+ // Expect two values to not be equal, and if they are
+ // logs an appropriate error about it.
+ void ExpectAsciiStringNotEqual(const char *val1, const char *val2) {
+ if (val1 == val2) {
+ std::string err;
+ err = "Expected Not Equal for '";
+ err.append(val1);
+ err.append("' and '");
+ err.append(val2);
+ err.append("'");
+ SetError(err);
+ }
+ }
+ // Expect two integer values are equal, and if not, logs an
+ // appropriate error about it.
+ void ExpectIntegerEqual(int val1, int val2) {
+ if (val1 != val2) {
+ std::string err;
+ char buf[64]; // what's the right size?
+ err = "Expected Equal for '";
+ sprintf_s(buf, "%d", val1);
+ err.append(buf);
+ err.append("' and '");
+ sprintf_s(buf, "%d", val2);
+ err.append(buf);
+ err.append("'");
+ SetError(err);
+ }
+ }
+
+
+ protected:
+ // Signals to the Test that invoked us that the test is
+ // completed. This is done by forcing the plugin to
+ // set a cookie in the browser window, which the test program
+ // is waiting for. Note - because this is done by
+ // using javascript, the browser must have the frame
+ // setup before the plugin calls this function. So plugin
+ // tests MUST NOT call this function prior to having
+ // received the SetWindow() callback from the browser.
+ void SignalTestCompleted();
+
+ // Helper function to lookup names in the input array.
+ // If the name is found, returns the value, otherwise
+ // returns NULL.
+ const char *GetArgValue(const char *name, const int16 argc,
+ const char *argn[], const char *argv[]);
+
+ // Access to the list of functions provided
+ // by the NPAPI host.
+ NPNetscapeFuncs *HostFunctions() { return host_functions_; }
+
+ // The NPP Identifier for this plugin instance.
+ NPP id() { return id_; }
+
+ private:
+ NPP id_;
+ NPNetscapeFuncs * host_functions_;
+ std::string test_name_;
+ std::string test_id_;
+ std::string test_status_;
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PORT_PLUGINS_TEST_PLUGIN_TEST_H__
+
diff --git a/webkit/glue/plugins/test/plugin_window_size_test.cc b/webkit/glue/plugins/test/plugin_window_size_test.cc
new file mode 100644
index 0000000..33aeafa
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_window_size_test.cc
@@ -0,0 +1,67 @@
+// 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/plugins/test/plugin_window_size_test.h"
+#include "webkit/glue/plugins/test/plugin_client.h"
+
+namespace NPAPIClient {
+
+PluginWindowSizeTest::PluginWindowSizeTest(NPP id,
+ NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions) {
+}
+
+NPError PluginWindowSizeTest::SetWindow(NPWindow* pNPWindow) {
+ if (!pNPWindow ||
+ !::IsWindow(reinterpret_cast<HWND>(pNPWindow->window))) {
+ SetError("Invalid arguments passed in");
+ return NPERR_INVALID_PARAM;
+ }
+
+ RECT window_rect = {0};
+ window_rect.left = pNPWindow->x;
+ window_rect.top = pNPWindow->y;
+ window_rect.right = pNPWindow->width;
+ window_rect.bottom = pNPWindow->height;
+
+ if (!::IsRectEmpty(&window_rect)) {
+ RECT client_rect = {0};
+ ::GetClientRect(reinterpret_cast<HWND>(pNPWindow->window),
+ &client_rect);
+ if (::IsRectEmpty(&client_rect)) {
+ SetError("The client rect of the plugin window is empty. Test failed");
+ }
+
+ SignalTestCompleted();
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_window_size_test.h b/webkit/glue/plugins/test/plugin_window_size_test.h
new file mode 100644
index 0000000..13b50aa
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_window_size_test.h
@@ -0,0 +1,50 @@
+// 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 WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_WINDOW_SIZE_TEST_H
+#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_WINDOW_SIZE_TEST_H
+
+#include "webkit/glue/plugins/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// This class tests whether the plugin window has a non zero rect
+// on the second SetWindow call.
+class PluginWindowSizeTest : public PluginTest {
+ public:
+ // Constructor.
+ PluginWindowSizeTest(NPP id, NPNetscapeFuncs *host_functions);
+ // NPAPI SetWindow handler
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_WINDOW_SIZE_TEST_H
+
diff --git a/webkit/glue/plugins/test/resource.h b/webkit/glue/plugins/test/resource.h
new file mode 100644
index 0000000..2f2bf3b
--- /dev/null
+++ b/webkit/glue/plugins/test/resource.h
@@ -0,0 +1,14 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by npapitest.rc
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/webkit/glue/plugins/webplugin_delegate_impl.cc b/webkit/glue/plugins/webplugin_delegate_impl.cc
new file mode 100644
index 0000000..774cad7
--- /dev/null
+++ b/webkit/glue/plugins/webplugin_delegate_impl.cc
@@ -0,0 +1,1081 @@
+// 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/plugins/webplugin_delegate_impl.h"
+
+#include "base/file_util.h"
+#include "base/message_loop.h"
+#include "base/gfx/point.h"
+#include "base/stats_counters.h"
+#include "webkit/default_plugin/plugin_impl.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/webplugin.h"
+#include "webkit/glue/plugins/plugin_instance.h"
+#include "webkit/glue/plugins/plugin_lib.h"
+#include "webkit/glue/plugins/plugin_list.h"
+#include "webkit/glue/plugins/plugin_stream_url.h"
+
+static StatsCounter windowless_queue(L"Plugin.ThrottleQueue");
+
+static const wchar_t kNativeWindowClassName[] = L"NativeWindowClass";
+static const wchar_t kWebPluginDelegateProperty[] =
+ L"WebPluginDelegateProperty";
+static const wchar_t kPluginNameAtomProperty[] = L"PluginNameAtom";
+static const wchar_t kDummyActivationWindowName[] = L"DummyWindowForActivation";
+static const wchar_t kPluginOrigProc[] = L"OriginalPtr";
+static const wchar_t kPluginFlashThrottle[] = L"FlashThrottle";
+
+// The fastest we are willing to process WM_USER+1 events for Flash.
+// Flash can easily exceed the limits of our CPU if we don't throttle it.
+// The throttle has been chosen by testing various delays and compromising
+// on acceptable Flash performance and reasonable CPU consumption.
+//
+// I'd like to make the throttle delay variable, based on the amount of
+// time currently required to paint Flash plugins. There isn't a good
+// way to count the time spent in aggregate plugin painting, however, so
+// this seems to work well enough.
+static const int kFlashWMUSERMessageThrottleDelayMs = 5;
+
+std::list<MSG> WebPluginDelegateImpl::throttle_queue_;
+
+WebPluginDelegateImpl* WebPluginDelegateImpl::current_plugin_instance_ = NULL;
+
+WebPluginDelegateImpl* WebPluginDelegateImpl::Create(
+ const std::wstring& filename,
+ const std::string& mime_type,
+ HWND containing_window) {
+ scoped_refptr<NPAPI::PluginLib> plugin =
+ NPAPI::PluginLib::CreatePluginLib(filename);
+ if (plugin.get() == NULL)
+ return NULL;
+
+ NPError err = plugin->NP_Initialize();
+ if (err != NPERR_NO_ERROR)
+ return NULL;
+
+ scoped_refptr<NPAPI::PluginInstance> instance =
+ plugin->CreateInstance(mime_type);
+ return new WebPluginDelegateImpl(containing_window, instance.get());
+}
+
+bool WebPluginDelegateImpl::IsPluginDelegateWindow(HWND window) {
+ // We use a buffer that is one char longer than we need to detect cases where
+ // kNativeWindowClassName is a prefix of the given window's class name. It
+ // happens that GetClassNameW will just silently truncate the class name to
+ // fit into the given buffer.
+ wchar_t class_name[arraysize(kNativeWindowClassName) + 1];
+ if (!GetClassNameW(window, class_name, arraysize(class_name)))
+ return false;
+ return wcscmp(class_name, kNativeWindowClassName) == 0;
+}
+
+bool WebPluginDelegateImpl::GetPluginNameFromWindow(
+ HWND window, std::wstring *plugin_name) {
+ if (NULL == plugin_name) {
+ return false;
+ }
+ if (!IsPluginDelegateWindow(window)) {
+ return false;
+ }
+ ATOM plugin_name_atom = reinterpret_cast<ATOM>(
+ GetPropW(window, kPluginNameAtomProperty));
+ if (plugin_name_atom != 0) {
+ WCHAR plugin_name_local[MAX_PATH] = {0};
+ GlobalGetAtomNameW(plugin_name_atom,
+ plugin_name_local,
+ ARRAYSIZE(plugin_name_local));
+ *plugin_name = plugin_name_local;
+ return true;
+ }
+ return false;
+}
+
+bool WebPluginDelegateImpl::IsDummyActivationWindow(HWND window) {
+ if (!IsWindow(window))
+ return false;
+
+ wchar_t window_title[MAX_PATH + 1] = {0};
+ if (GetWindowText(window, window_title, arraysize(window_title))) {
+ return (0 == lstrcmpiW(window_title, kDummyActivationWindowName));
+ }
+ return false;
+}
+
+LRESULT CALLBACK WebPluginDelegateImpl::HandleEventMessageFilterHook(
+ int code, WPARAM wParam, LPARAM lParam) {
+
+ DCHECK(current_plugin_instance_);
+ current_plugin_instance_->OnModalLoopEntered();
+ return CallNextHookEx(NULL, code, wParam, lParam);
+}
+
+WebPluginDelegateImpl::WebPluginDelegateImpl(
+ HWND containing_window,
+ NPAPI::PluginInstance *instance)
+ : parent_(containing_window),
+ instance_(instance),
+ quirks_(0),
+ plugin_(NULL),
+ windowless_(false),
+ windowed_handle_(NULL),
+ windowed_did_set_window_(false),
+ windowless_needs_set_window_(true),
+ plugin_wnd_proc_(NULL),
+ last_message_(0),
+ is_calling_wndproc(false),
+ initial_plugin_resize_done_(false),
+ dummy_window_for_activation_(NULL),
+ handle_event_message_filter_hook_(NULL),
+ handle_event_pump_messages_event_(NULL),
+ handle_event_depth_(0),
+ user_gesture_message_posted_(false),
+#pragma warning(suppress: 4355) // can use this
+ user_gesture_msg_factory_(this),
+ load_manually_(false),
+ first_geometry_update_(true) {
+ memset(&window_, 0, sizeof(window_));
+
+ const WebPluginInfo& plugin_info = instance_->plugin_lib()->plugin_info();
+ std::wstring filename = file_util::GetFilenameFromPath(plugin_info.file);
+
+ if (instance_->mime_type() == "application/x-shockwave-flash" ||
+ filename == L"npswf32.dll") {
+ // Flash only requests windowless plugins if we return a Mozilla user
+ // agent.
+ instance_->set_use_mozilla_user_agent();
+ instance_->set_throttle_invalidate(true);
+ quirks_ |= PLUGIN_QUIRK_THROTTLE_WM_USER_PLUS_ONE;
+ } else if (plugin_info.name.find(L"Windows Media Player") !=
+ std::wstring::npos) {
+ // Windows Media Player needs two NPP_SetWindow calls.
+ quirks_ |= PLUGIN_QUIRK_SETWINDOW_TWICE;
+ } else if (instance_->mime_type() == "audio/x-pn-realaudio-plugin" ||
+ filename == L"nppl3260.dll") {
+ quirks_ |= PLUGIN_QUIRK_DONT_CALL_WND_PROC_RECURSIVELY;
+ } else if (plugin_info.name.find(L"VLC Multimedia Plugin") !=
+ std::wstring::npos) {
+ // VLC hangs on NPP_Destroy if we call NPP_SetWindow with a null window
+ // handle
+ quirks_ |= PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY;
+ // VLC 0.8.6d and 0.8.6e crash if multiple instances are created.
+ quirks_ |= PLUGIN_QUIRK_DONT_ALLOW_MULTIPLE_INSTANCES;
+ }
+}
+
+WebPluginDelegateImpl::~WebPluginDelegateImpl() {
+ if (::IsWindow(dummy_window_for_activation_)) {
+ ::DestroyWindow(dummy_window_for_activation_);
+ }
+
+ DestroyInstance();
+
+ if (!windowless_)
+ WindowedDestroyWindow();
+
+ if (handle_event_pump_messages_event_) {
+ CloseHandle(handle_event_pump_messages_event_);
+ }
+}
+
+void WebPluginDelegateImpl::PluginDestroyed() {
+ delete this;
+}
+
+bool WebPluginDelegateImpl::Initialize(const GURL& url,
+ char** argn,
+ char** argv,
+ int argc,
+ WebPlugin* plugin,
+ bool load_manually) {
+ plugin_ = plugin;
+
+ instance_->set_web_plugin(plugin);
+ NPAPI::PluginInstance* old_instance =
+ NPAPI::PluginInstance::SetInitializingInstance(instance_);
+
+ if (quirks_ & PLUGIN_QUIRK_DONT_ALLOW_MULTIPLE_INSTANCES) {
+ NPAPI::PluginLib* plugin_lib = instance()->plugin_lib();
+ if (plugin_lib->instance_count() > 1) {
+ return false;
+ }
+ }
+
+ bool start_result = instance_->Start(url, argn, argv, argc, load_manually);
+
+ NPAPI::PluginInstance::SetInitializingInstance(old_instance);
+
+ if (!start_result)
+ return false;
+
+ windowless_ = instance_->windowless();
+ if (windowless_) {
+ // For windowless plugins we should set the containing window handle
+ // as the instance window handle. This is what Safari does. Not having
+ // a valid window handle causes subtle bugs with plugins which retreive
+ // the window handle and validate the same. The window handle can be
+ // retreived via NPN_GetValue of NPNVnetscapeWindow.
+ instance_->set_window_handle(parent_);
+ CreateDummyWindowForActivation();
+ handle_event_pump_messages_event_ = CreateEvent(NULL, TRUE, FALSE, NULL);
+ } else {
+ if (!WindowedCreatePlugin())
+ return false;
+ }
+
+ plugin->SetWindow(windowed_handle_, handle_event_pump_messages_event_);
+
+ load_manually_ = load_manually;
+ plugin_url_ = url.spec();
+ return true;
+}
+
+void WebPluginDelegateImpl::DestroyInstance() {
+ if (instance_ && (instance_->npp()->ndata != NULL)) {
+ // Shutdown all streams before destroying so that
+ // no streams are left "in progress". Need to do
+ // this before calling set_web_plugin(NULL) because the
+ // instance uses the helper to do the download.
+ instance_->CloseStreams();
+
+ window_.window = NULL;
+ if (!(quirks_ & PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY)) {
+ instance_->NPP_SetWindow(&window_);
+ }
+
+ instance_->NPP_Destroy();
+
+ instance_->set_web_plugin(NULL);
+
+ instance_ = 0;
+ }
+}
+
+void WebPluginDelegateImpl::UpdateGeometry(const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect,
+ bool visible) {
+ if (windowless_) {
+ window_.window =
+ reinterpret_cast<void *>(::GetDC(instance_->window_handle()));
+ WindowlessUpdateGeometry(window_rect, clip_rect);
+ ::ReleaseDC(instance_->window_handle(),
+ reinterpret_cast<HDC>(window_.window));
+ } else {
+ WindowedUpdateGeometry(window_rect, clip_rect, visible);
+ }
+
+ // Initiate a download on the plugin url. This should be done for the
+ // first update geometry sequence.
+ if (first_geometry_update_) {
+ first_geometry_update_ = false;
+ // An empty url corresponds to an EMBED tag with no src attribute.
+ if (!load_manually_ && !plugin_url_.empty()) {
+ instance_->SendStream(plugin_url_.c_str(), false, NULL);
+ }
+ }
+}
+
+void WebPluginDelegateImpl::Paint(HDC hdc, const gfx::Rect& rect) {
+ if (windowless_)
+ WindowlessPaint(hdc, rect);
+}
+
+void WebPluginDelegateImpl::Print(HDC hdc) {
+ // Disabling the call to NPP_Print as it causes a crash in
+ // flash in some cases. In any case this does not work as expected
+ // as the EMF meta file dc passed in needs to be created with the
+ // the plugin window dc as its sibling dc and the window rect
+ // in .01 mm units.
+#if 0
+ NPPrint npprint;
+ npprint.mode = NP_EMBED;
+ npprint.print.embedPrint.platformPrint = reinterpret_cast<void*>(hdc);
+ npprint.print.embedPrint.window = window_;
+ instance()->NPP_Print(&npprint);
+#endif
+}
+
+NPObject* WebPluginDelegateImpl::GetPluginScriptableObject() {
+ return instance_->GetPluginScriptableObject();
+}
+
+void WebPluginDelegateImpl::DidFinishLoadWithReason(NPReason reason) {
+ instance()->DidFinishLoadWithReason(reason);
+}
+
+int WebPluginDelegateImpl::GetProcessId() {
+ // We are in process, so the plugin pid is this current process pid.
+ return ::GetCurrentProcessId();
+}
+
+HWND WebPluginDelegateImpl::GetWindowHandle() {
+ return instance()->window_handle();
+}
+
+void WebPluginDelegateImpl::SendJavaScriptStream(const std::string& url,
+ const std::wstring& result,
+ bool success,
+ bool notify_needed,
+ int notify_data) {
+ instance()->SendJavaScriptStream(url, result, success, notify_needed,
+ notify_data);
+}
+
+void WebPluginDelegateImpl::DidReceiveManualResponse(
+ const std::string& url, const std::string& mime_type,
+ const std::string& headers, uint32 expected_length, uint32 last_modified) {
+ instance()->DidReceiveManualResponse(url, mime_type, headers,
+ expected_length, last_modified);
+}
+
+void WebPluginDelegateImpl::DidReceiveManualData(const char* buffer,
+ int length) {
+ instance()->DidReceiveManualData(buffer, length);
+}
+
+void WebPluginDelegateImpl::DidFinishManualLoading() {
+ instance()->DidFinishManualLoading();
+}
+
+void WebPluginDelegateImpl::DidManualLoadFail() {
+ instance()->DidManualLoadFail();
+}
+
+std::wstring WebPluginDelegateImpl::GetPluginPath() {
+ return instance()->plugin_lib()->plugin_info().file;
+}
+
+void WebPluginDelegateImpl::InstallMissingPlugin() {
+ NPEvent evt;
+ evt.event = PluginInstallerImpl::kInstallMissingPluginMessage;
+ evt.lParam = 0;
+ evt.wParam = 0;
+ instance()->NPP_HandleEvent(&evt);
+}
+
+void WebPluginDelegateImpl::WindowedUpdateGeometry(const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect,
+ bool visible) {
+ if (WindowedReposition(window_rect, clip_rect, visible) ||
+ !windowed_did_set_window_) {
+ // Let the plugin know that it has been moved
+ WindowedSetWindow();
+ }
+}
+
+bool WebPluginDelegateImpl::WindowedCreatePlugin() {
+ DCHECK(!windowed_handle_);
+
+ RegisterNativeWindowClass();
+
+ // The window will be sized and shown later.
+ windowed_handle_ = CreateWindowEx(
+ WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR,
+ kNativeWindowClassName,
+ 0,
+ WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
+ 0,
+ 0,
+ 0,
+ 0,
+ parent_,
+ 0,
+ GetModuleHandle(NULL),
+ 0);
+ if (windowed_handle_ == 0)
+ return false;
+
+ BOOL result = SetProp(windowed_handle_, kWebPluginDelegateProperty, this);
+ DCHECK(result == TRUE) << "SetProp failed, last error = " << GetLastError();
+ // Get the name of the plugin, create an atom and set that in a window
+ // property. Use an atom so that other processes can access the name of
+ // the plugin that this window is hosting
+ if (instance_ != NULL) {
+ NPAPI::PluginLib* plugin_lib = instance()->plugin_lib();
+ if (plugin_lib != NULL) {
+ std::wstring plugin_name = plugin_lib->plugin_info().name;
+ if (!plugin_name.empty()) {
+ ATOM plugin_name_atom = GlobalAddAtomW(plugin_name.c_str());
+ DCHECK(0 != plugin_name_atom);
+ result = SetProp(windowed_handle_,
+ kPluginNameAtomProperty,
+ reinterpret_cast<HANDLE>(plugin_name_atom));
+ DCHECK(result == TRUE) << "SetProp failed, last error = " <<
+ GetLastError();
+ }
+ }
+ }
+
+ // Calling SetWindowLongPtrA here makes the window proc ASCII, which is
+ // required by at least the Shockwave Director plug-in.
+ SetWindowLongPtrA(
+ windowed_handle_, GWL_WNDPROC, reinterpret_cast<LONG>(DefWindowProcA));
+
+ return true;
+}
+
+void WebPluginDelegateImpl::WindowedDestroyWindow() {
+ if (windowed_handle_ != NULL) {
+ // Unsubclass the window.
+ WNDPROC current_wnd_proc = reinterpret_cast<WNDPROC>(
+ GetWindowLongPtr(windowed_handle_, GWLP_WNDPROC));
+ if (current_wnd_proc == NativeWndProc) {
+ SetWindowLongPtr(windowed_handle_,
+ GWLP_WNDPROC,
+ reinterpret_cast<LONG>(plugin_wnd_proc_));
+ }
+
+ DestroyWindow(windowed_handle_);
+ windowed_handle_ = 0;
+ }
+}
+
+// Erase all messages in the queue destined for a particular window.
+// When windows are closing, callers should use this function to clear
+// the queue.
+// static
+void WebPluginDelegateImpl::ClearThrottleQueueForWindow(HWND window) {
+ std::list<MSG>::iterator it;
+ for (it = throttle_queue_.begin(); it != throttle_queue_.end(); ) {
+ if (it->hwnd == window) {
+ it = throttle_queue_.erase(it);
+ windowless_queue.Decrement();
+ } else {
+ it++;
+ }
+ }
+}
+
+// Delayed callback for processing throttled messages.
+// Throttled messages are aggregated globally across all plugins.
+// static
+void WebPluginDelegateImpl::OnThrottleMessage() {
+ // The current algorithm walks the list and processes the first
+ // message it finds for each plugin. It is important to service
+ // all active plugins with each pass through the throttle, otherwise
+ // we see video jankiness.
+ std::map<HWND, int> processed;
+
+ std::list<MSG>::iterator it = throttle_queue_.begin();
+ while (it != throttle_queue_.end()) {
+ const MSG& msg = *it;
+ if (processed.find(msg.hwnd) == processed.end()) {
+ WNDPROC proc = reinterpret_cast<WNDPROC>(msg.time);
+ CallWindowProc(proc, msg.hwnd, msg.message, msg.wParam, msg.lParam);
+ processed[msg.hwnd] = 1;
+ it = throttle_queue_.erase(it);
+ windowless_queue.Decrement();
+ } else {
+ it++;
+ }
+ }
+
+ if (throttle_queue_.size() > 0)
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ NewRunnableFunction(&WebPluginDelegateImpl::OnThrottleMessage),
+ kFlashWMUSERMessageThrottleDelayMs);
+}
+
+// Schedule a windows message for delivery later.
+// static
+void WebPluginDelegateImpl::ThrottleMessage(WNDPROC proc, HWND hwnd,
+ UINT message, WPARAM wParam,
+ LPARAM lParam) {
+ MSG msg;
+ msg.time = reinterpret_cast<DWORD>(proc);
+ msg.hwnd = hwnd;
+ msg.message = message;
+ msg.wParam = wParam;
+ msg.lParam = lParam;
+ throttle_queue_.push_back(msg);
+ windowless_queue.Increment();
+
+ if (throttle_queue_.size() == 1) {
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ NewRunnableFunction(&WebPluginDelegateImpl::OnThrottleMessage),
+ kFlashWMUSERMessageThrottleDelayMs);
+ }
+}
+
+// We go out of our way to find the hidden windows created by Flash for
+// windowless plugins. We throttle the rate at which they deliver messages
+// so that they will not consume outrageous amounts of CPU.
+// static
+LRESULT CALLBACK WebPluginDelegateImpl::FlashWindowlessWndProc(HWND hwnd,
+ UINT message, WPARAM wparam, LPARAM lparam) {
+ WNDPROC old_proc = reinterpret_cast<WNDPROC>(GetProp(hwnd, kPluginOrigProc));
+ DCHECK(old_proc);
+
+ switch (message) {
+ case WM_NCDESTROY: {
+ WebPluginDelegateImpl::ClearThrottleQueueForWindow(hwnd);
+ break;
+ }
+ // Flash may flood the message queue with WM_USER+1 message causing 100% CPU
+ // usage. See https://bugzilla.mozilla.org/show_bug.cgi?id=132759. We
+ // prevent this by throttling the messages.
+ case WM_USER + 1: {
+ WebPluginDelegateImpl::ThrottleMessage(old_proc, hwnd, message, wparam,
+ lparam);
+ return TRUE;
+ }
+ default: {
+ break;
+ }
+ }
+ return CallWindowProc(old_proc, hwnd, message, wparam, lparam);
+}
+
+// Callback for enumerating the Flash windows.
+BOOL CALLBACK EnumFlashWindows(HWND window, LPARAM arg) {
+ WNDPROC wnd_proc = reinterpret_cast<WNDPROC>(arg);
+ TCHAR class_name[1024];
+ if (!RealGetWindowClass(window, class_name,
+ sizeof(class_name)/sizeof(TCHAR))) {
+ LOG(ERROR) << "RealGetWindowClass failure: " << GetLastError();
+ return FALSE;
+ }
+
+ if (wcscmp(class_name, L"SWFlash_PlaceholderX"))
+ return TRUE;
+
+ WNDPROC current_wnd_proc = reinterpret_cast<WNDPROC>(
+ GetWindowLongPtr(window, GWLP_WNDPROC));
+ if (current_wnd_proc != wnd_proc) {
+ WNDPROC old_flash_proc = reinterpret_cast<WNDPROC>(SetWindowLongPtr(
+ window, GWLP_WNDPROC,
+ reinterpret_cast<LONG>(wnd_proc)));
+ DCHECK(old_flash_proc);
+ BOOL result = SetProp(window, kPluginOrigProc, old_flash_proc);
+ if (!result) {
+ LOG(ERROR) << "SetProp failed, last error = " << GetLastError();
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+bool WebPluginDelegateImpl::CreateDummyWindowForActivation() {
+ DCHECK(!dummy_window_for_activation_);
+ dummy_window_for_activation_ = CreateWindowEx(
+ 0,
+ L"Static",
+ kDummyActivationWindowName,
+ WS_CHILD,
+ 0,
+ 0,
+ 0,
+ 0,
+ parent_,
+ 0,
+ GetModuleHandle(NULL),
+ 0);
+
+ if (dummy_window_for_activation_ == 0)
+ return false;
+
+ // Flash creates background windows which use excessive CPU in our
+ // environment; we wrap these windows and throttle them so that they don't
+ // get out of hand.
+ if (!EnumThreadWindows(::GetCurrentThreadId(), EnumFlashWindows,
+ reinterpret_cast<LPARAM>(
+ &WebPluginDelegateImpl::FlashWindowlessWndProc))) {
+ // Log that this happened. Flash will still work; it just means the
+ // throttle isn't installed (and Flash will use more CPU).
+ NOTREACHED();
+ LOG(ERROR) << "Failed to wrap all windowless Flash windows";
+ }
+ return true;
+}
+
+void WebPluginDelegateImpl::MoveWindow(HWND window,
+ const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect,
+ bool visible) {
+ HRGN hrgn = ::CreateRectRgn(clip_rect.x(),
+ clip_rect.y(),
+ clip_rect.right(),
+ clip_rect.bottom());
+
+ // Note: System will own the hrgn after we call SetWindowRgn,
+ // so we don't need to call DeleteObject(hrgn)
+ ::SetWindowRgn(window, hrgn, FALSE);
+
+ // Move the window now, but do not paint it. We expect to be painted later,
+ // when our parent window paints.
+ unsigned long flags = SWP_NOREDRAW;
+ if (visible)
+ flags |= SWP_SHOWWINDOW;
+ else
+ flags |= SWP_HIDEWINDOW;
+
+ ::SetWindowPos(window,
+ NULL,
+ window_rect.x(),
+ window_rect.y(),
+ window_rect.width(),
+ window_rect.height(),
+ flags);
+}
+
+bool WebPluginDelegateImpl::WindowedReposition(const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect,
+ bool visible) {
+ if (!windowed_handle_) {
+ NOTREACHED();
+ return false;
+ }
+
+ if (window_rect_ == window_rect && clip_rect_ == clip_rect &&
+ initial_plugin_resize_done_)
+ return false;
+
+ window_rect_ = window_rect;
+ clip_rect_ = clip_rect;
+
+ if (!initial_plugin_resize_done_) {
+ // We need to ensure that the plugin process continues to reposition
+ // the plugin window until we receive an indication that it is now visible.
+ // Subsequent repositions will be done by the browser.
+ if (visible)
+ initial_plugin_resize_done_ = true;
+ // We created the window with 0 width and height since we didn't know it
+ // at the time. Now that we know the geometry, we we can update its size
+ // since the browser only calls SetWindowPos when scrolling occurs.
+ MoveWindow(windowed_handle_, window_rect, clip_rect, visible);
+ // Ensure that the entire window gets repainted.
+ ::InvalidateRect(windowed_handle_, NULL, FALSE);
+ }
+
+ return true;
+}
+
+void WebPluginDelegateImpl::WindowedSetWindow() {
+ if (!instance_)
+ return;
+
+ if (!windowed_handle_) {
+ NOTREACHED();
+ return;
+ }
+
+ instance()->set_window_handle(windowed_handle_);
+
+ DCHECK(!instance()->windowless());
+
+ window_.clipRect.top = clip_rect_.y();
+ window_.clipRect.left = clip_rect_.x();
+ window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height();
+ window_.clipRect.right = clip_rect_.x() + clip_rect_.width();
+ window_.height = window_rect_.height();
+ window_.width = window_rect_.width();
+ window_.x = window_rect_.x();
+ window_.y = window_rect_.y();
+
+ window_.window = windowed_handle_;
+ window_.type = NPWindowTypeWindow;
+
+ // Reset this flag before entering the instance in case of side-effects.
+ windowed_did_set_window_ = true;
+
+ NPError err = instance()->NPP_SetWindow(&window_);
+ if (quirks_ & PLUGIN_QUIRK_SETWINDOW_TWICE)
+ instance()->NPP_SetWindow(&window_);
+
+ WNDPROC current_wnd_proc = reinterpret_cast<WNDPROC>(
+ GetWindowLongPtr(windowed_handle_, GWLP_WNDPROC));
+ if (current_wnd_proc != NativeWndProc) {
+ plugin_wnd_proc_ = reinterpret_cast<WNDPROC>(SetWindowLongPtr(
+ windowed_handle_, GWLP_WNDPROC, reinterpret_cast<LONG>(NativeWndProc)));
+ }
+}
+
+ATOM WebPluginDelegateImpl::RegisterNativeWindowClass() {
+ static bool have_registered_window_class = false;
+ if (have_registered_window_class == true)
+ return true;
+
+ have_registered_window_class = true;
+
+ WNDCLASSEX wcex;
+ wcex.cbSize = sizeof(WNDCLASSEX);
+ wcex.style = CS_DBLCLKS;
+ wcex.lpfnWndProc = DefWindowProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = GetModuleHandle(NULL);
+ wcex.hIcon = 0;
+ wcex.hCursor = 0;
+ // Some plugins like windows media player 11 create child windows parented
+ // by our plugin window, where the media content is rendered. These plugins
+ // dont implement WM_ERASEBKGND, which causes painting issues, when the
+ // window where the media is rendered is moved around. DefWindowProc does
+ // implement WM_ERASEBKGND correctly if we have a valid background brush.
+ wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW+1);
+ wcex.lpszMenuName = 0;
+ wcex.lpszClassName = kNativeWindowClassName;
+ wcex.hIconSm = 0;
+
+ return RegisterClassEx(&wcex);
+}
+
+LRESULT CALLBACK WebPluginDelegateImpl::NativeWndProc(
+ HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
+ WebPluginDelegateImpl* delegate = reinterpret_cast<WebPluginDelegateImpl*>(
+ GetProp(hwnd, kWebPluginDelegateProperty));
+ if (!delegate) {
+ NOTREACHED();
+ return 0;
+ }
+
+ if (message == delegate->last_message_ &&
+ delegate->quirks() & PLUGIN_QUIRK_DONT_CALL_WND_PROC_RECURSIVELY &&
+ delegate->is_calling_wndproc) {
+ // Real may go into a state where it recursively dispatches the same event
+ // when subclassed. See https://bugzilla.mozilla.org/show_bug.cgi?id=192914
+ // We only do the recursive check for Real because it's possible and valid
+ // for a plugin to synchronously dispatch a message to itself such that it
+ // looks like it's in recursion.
+ return TRUE;
+ }
+
+ switch (message) {
+ case WM_NCDESTROY: {
+ RemoveProp(hwnd, kWebPluginDelegateProperty);
+ ATOM plugin_name_atom = reinterpret_cast <ATOM>(
+ RemoveProp(hwnd, kPluginNameAtomProperty));
+ if (plugin_name_atom != 0)
+ GlobalDeleteAtom(plugin_name_atom);
+ ClearThrottleQueueForWindow(hwnd);
+ break;
+ }
+ // Flash may flood the message queue with WM_USER+1 message causing 100% CPU
+ // usage. See https://bugzilla.mozilla.org/show_bug.cgi?id=132759. We
+ // prevent this by throttling the messages.
+ case WM_USER + 1: {
+ if (delegate->quirks() & PLUGIN_QUIRK_THROTTLE_WM_USER_PLUS_ONE) {
+ WebPluginDelegateImpl::ThrottleMessage(delegate->plugin_wnd_proc_, hwnd,
+ message, wparam, lparam);
+ return FALSE;
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+
+ delegate->last_message_ = message;
+ delegate->is_calling_wndproc = true;
+
+ if (!delegate->user_gesture_message_posted_ &&
+ IsUserGestureMessage(message)) {
+ delegate->user_gesture_message_posted_ = true;
+
+ delegate->instance()->PushPopupsEnabledState(true);
+
+ MessageLoop::current()->PostTask(FROM_HERE,
+ delegate->user_gesture_msg_factory_.NewRunnableMethod(
+ &WebPluginDelegateImpl::OnUserGestureEnd));
+ }
+
+ LRESULT result = CallWindowProc(delegate->plugin_wnd_proc_, hwnd, message,
+ wparam, lparam);
+ delegate->is_calling_wndproc = false;
+ return result;
+}
+
+void WebPluginDelegateImpl::WindowlessUpdateGeometry(
+ const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect) {
+ // Only resend to the instance if the geometry has changed.
+ if (window_rect == window_rect_ && clip_rect == clip_rect_)
+ return;
+
+ // Set this flag before entering the instance in case of side-effects.
+ windowless_needs_set_window_ = true;
+
+ // We will inform the instance of this change when we call NPP_SetWindow.
+ clip_rect_ = clip_rect;
+
+ if (window_rect_ != window_rect) {
+ window_rect_ = window_rect;
+
+ WindowlessSetWindow(true);
+
+ WINDOWPOS win_pos = {0};
+ win_pos.x = window_rect_.x();
+ win_pos.y = window_rect_.y();
+ win_pos.cx = window_rect_.width();
+ win_pos.cy = window_rect_.height();
+
+ NPEvent pos_changed_event;
+ pos_changed_event.event = WM_WINDOWPOSCHANGED;
+ pos_changed_event.wParam = 0;
+ pos_changed_event.lParam = PtrToUlong(&win_pos);
+
+ instance()->NPP_HandleEvent(&pos_changed_event);
+ }
+}
+
+void WebPluginDelegateImpl::WindowlessPaint(HDC hdc,
+ const gfx::Rect& damage_rect) {
+ DCHECK(hdc);
+
+ RECT damage_rect_win;
+ damage_rect_win.left = damage_rect.x(); // + window_rect_.x();
+ damage_rect_win.top = damage_rect.y(); // + window_rect_.y();
+ damage_rect_win.right = damage_rect_win.left + damage_rect.width();
+ damage_rect_win.bottom = damage_rect_win.top + damage_rect.height();
+
+ window_.window = (void*)hdc;
+
+ // TODO(darin): we should avoid calling NPP_SetWindow here since it may
+ // cause page layout to be invalidated.
+
+ // We really don't need to continually call SetWindow.
+ // m_needsSetWindow flags when the geometry has changed.
+ if (windowless_needs_set_window_)
+ WindowlessSetWindow(false);
+
+ NPEvent paint_event;
+ paint_event.event = WM_PAINT;
+ // NOTE: NPAPI is not 64bit safe. It puts pointers into 32bit values.
+ paint_event.wParam = PtrToUlong(hdc);
+ paint_event.lParam = PtrToUlong(&damage_rect_win);
+ static StatsRate plugin_paint(L"Plugin.Paint");
+ StatsScope<StatsRate> scope(plugin_paint);
+ instance()->NPP_HandleEvent(&paint_event);
+}
+
+void WebPluginDelegateImpl::WindowlessSetWindow(bool force_set_window) {
+ if (!instance())
+ return;
+
+ if (window_rect_.IsEmpty()) // wait for geometry to be set.
+ return;
+
+ DCHECK(instance()->windowless());
+
+ window_.clipRect.top = clip_rect_.y();
+ window_.clipRect.left = clip_rect_.x();
+ window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height();
+ window_.clipRect.right = clip_rect_.x() + clip_rect_.width();
+ window_.height = window_rect_.height();
+ window_.width = window_rect_.width();
+ window_.x = window_rect_.x();
+ window_.y = window_rect_.y();
+ window_.type = NPWindowTypeDrawable;
+
+ if (!force_set_window)
+ // Reset this flag before entering the instance in case of side-effects.
+ windowless_needs_set_window_ = false;
+
+ NPError err = instance()->NPP_SetWindow(&window_);
+ DCHECK(err == NPERR_NO_ERROR);
+}
+
+void WebPluginDelegateImpl::SetFocus() {
+ DCHECK(instance()->windowless());
+
+ NPEvent focus_event;
+ focus_event.event = WM_SETFOCUS;
+ focus_event.wParam = 0;
+ focus_event.lParam = 0;
+
+ instance()->NPP_HandleEvent(&focus_event);
+}
+
+bool WebPluginDelegateImpl::HandleEvent(NPEvent* event,
+ WebCursor* cursor) {
+ DCHECK(windowless_) << "events should only be received in windowless mode";
+ DCHECK(cursor != NULL);
+
+ // To ensure that the plugin receives keyboard events we set focus to the
+ // dummy window.
+ // TODO(iyengar) We need a framework in the renderer to identify which
+ // windowless plugin is under the mouse and to handle this. This would
+ // also require some changes in RenderWidgetHost to detect this in the
+ // WM_MOUSEACTIVATE handler and inform the renderer accordingly.
+ HWND prev_focus_window = NULL;
+ if (event->event == WM_RBUTTONDOWN) {
+ prev_focus_window = ::SetFocus(dummy_window_for_activation_);
+ }
+
+ if (ShouldTrackEventForModalLoops(event)) {
+ // A windowless plugin can enter a modal loop in a NPP_HandleEvent call.
+ // For e.g. Flash puts up a context menu when we right click on the
+ // windowless plugin area. We detect this by setting up a message filter
+ // hook pror to calling NPP_HandleEvent on the plugin and unhook on
+ // return from NPP_HandleEvent. If the plugin does enter a modal loop
+ // in that context we unhook on receiving the first notification in
+ // the message filter hook.
+ handle_event_message_filter_hook_ =
+ SetWindowsHookEx(WH_MSGFILTER, HandleEventMessageFilterHook, NULL,
+ GetCurrentThreadId());
+ }
+
+ bool old_task_reentrancy_state =
+ MessageLoop::current()->NestableTasksAllowed();
+
+ current_plugin_instance_ = this;
+
+ handle_event_depth_++;
+
+ bool pop_user_gesture = false;
+
+ if (IsUserGestureMessage(event->event)) {
+ pop_user_gesture = true;
+ instance()->PushPopupsEnabledState(true);
+ }
+
+ bool ret = instance()->NPP_HandleEvent(event) != 0;
+
+ if (pop_user_gesture) {
+ instance()->PopPopupsEnabledState();
+ }
+
+ handle_event_depth_--;
+
+ current_plugin_instance_ = NULL;
+
+ MessageLoop::current()->SetNestableTasksAllowed(old_task_reentrancy_state);
+
+ if (handle_event_message_filter_hook_) {
+ UnhookWindowsHookEx(handle_event_message_filter_hook_);
+ handle_event_message_filter_hook_ = NULL;
+ }
+
+ // We could have multiple NPP_HandleEvent calls nested together in case
+ // the plugin enters a modal loop. Reset the pump messages event when
+ // the outermost NPP_HandleEvent call unwinds.
+ if (handle_event_depth_ == 0) {
+ ResetEvent(handle_event_pump_messages_event_);
+ }
+
+ if (::IsWindow(prev_focus_window)) {
+ ::SetFocus(prev_focus_window);
+ }
+
+ if (WM_MOUSEMOVE == event->event) {
+ HCURSOR actual_cursor = ::GetCursor();
+ *cursor = GetCursorType(actual_cursor);
+ }
+
+ return ret;
+}
+
+WebCursor::Type WebPluginDelegateImpl::GetCursorType(
+ HCURSOR cursor) const {
+ static HCURSOR standard_cursors[] = {
+ LoadCursor(NULL, IDC_ARROW),
+ LoadCursor(NULL, IDC_IBEAM),
+ LoadCursor(NULL, IDC_WAIT),
+ LoadCursor(NULL, IDC_CROSS),
+ LoadCursor(NULL, IDC_UPARROW),
+ LoadCursor(NULL, IDC_SIZE),
+ LoadCursor(NULL, IDC_ICON),
+ LoadCursor(NULL, IDC_SIZENWSE),
+ LoadCursor(NULL, IDC_SIZENESW),
+ LoadCursor(NULL, IDC_SIZEWE),
+ LoadCursor(NULL, IDC_SIZENS),
+ LoadCursor(NULL, IDC_SIZEALL),
+ LoadCursor(NULL, IDC_NO),
+ LoadCursor(NULL, IDC_HAND),
+ LoadCursor(NULL, IDC_APPSTARTING),
+ LoadCursor(NULL, IDC_HELP),
+ };
+
+ for (int cursor_index = 0; cursor_index < arraysize(standard_cursors);
+ cursor_index++) {
+ if (cursor == standard_cursors[cursor_index])
+ return static_cast<WebCursor::Type>(cursor_index);
+ }
+
+ return WebCursor::ARROW;
+}
+
+WebPluginResourceClient* WebPluginDelegateImpl::CreateResourceClient(
+ int resource_id, const std::string &url, bool notify_needed,
+ void *notify_data) {
+ if (notify_needed) {
+ instance()->SetURLLoadData(GURL(url.c_str()), notify_data);
+ }
+ std::string mime_type;
+ NPAPI::PluginStreamUrl *stream = instance()->CreateStream(resource_id,
+ url,
+ mime_type,
+ notify_needed,
+ notify_data);
+ return stream;
+}
+
+void WebPluginDelegateImpl::URLRequestRouted(const std::string&url,
+ bool notify_needed,
+ void* notify_data) {
+ if (notify_needed) {
+ instance()->SetURLLoadData(GURL(url.c_str()), notify_data);
+ }
+}
+
+void WebPluginDelegateImpl::OnModalLoopEntered() {
+ DCHECK(handle_event_pump_messages_event_ != NULL);
+ SetEvent(handle_event_pump_messages_event_);
+
+ MessageLoop::current()->SetNestableTasksAllowed(true);
+
+ UnhookWindowsHookEx(handle_event_message_filter_hook_);
+ handle_event_message_filter_hook_ = NULL;
+}
+
+bool WebPluginDelegateImpl::ShouldTrackEventForModalLoops(NPEvent* event) {
+ if (event->event == WM_RBUTTONDOWN)
+ return true;
+ return false;
+}
+
+bool WebPluginDelegateImpl::IsUserGestureMessage(unsigned int message) {
+ switch (message) {
+ case WM_LBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_KEYUP:
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+void WebPluginDelegateImpl::OnUserGestureEnd() {
+ user_gesture_message_posted_ = false;
+ instance()->PopPopupsEnabledState();
+}
diff --git a/webkit/glue/plugins/webplugin_delegate_impl.h b/webkit/glue/plugins/webplugin_delegate_impl.h
new file mode 100644
index 0000000..3b774e8
--- /dev/null
+++ b/webkit/glue/plugins/webplugin_delegate_impl.h
@@ -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.
+
+#ifndef WEBKIT_GLUE_PLUGIN_WEBPLUGIN_DELEGATE_IMPL_H__
+#define WEBKIT_GLUE_PLUGIN_WEBPLUGIN_DELEGATE_IMPL_H__
+
+#include <string>
+#include <list>
+
+#include "base/ref_counted.h"
+#include "base/task.h"
+#include "webkit/glue/webplugin_delegate.h"
+#include "third_party/npapi/bindings/npapi.h"
+#include "webkit/glue/webcursor.h"
+
+namespace NPAPI {
+ class PluginInstance;
+};
+
+// An implementation of WebPluginDelegate that proxies all calls to
+// the plugin process.
+class WebPluginDelegateImpl : public WebPluginDelegate {
+ public:
+ static WebPluginDelegateImpl* Create(const std::wstring& filename,
+ const std::string& mime_type,
+ HWND containing_window);
+ static bool IsPluginDelegateWindow(HWND window);
+ static bool GetPluginNameFromWindow(HWND window, std::wstring *plugin_name);
+
+ // Returns true if the window handle passed in is that of the dummy
+ // activation window for windowless plugins.
+ static bool IsDummyActivationWindow(HWND window);
+
+ // 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 void SetFocus(); // only called when windowless
+// only called when windowless
+ virtual bool HandleEvent(NPEvent* event,
+ WebCursor* cursor);
+ virtual NPObject* GetPluginScriptableObject();
+ virtual void DidFinishLoadWithReason(NPReason reason);
+ virtual int GetProcessId();
+ virtual HWND GetWindowHandle();
+
+ virtual void FlushGeometryUpdates() {
+ }
+ 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);
+
+ virtual void URLRequestRouted(const std::string&url, bool notify_needed,
+ void* notify_data);
+ bool windowless() const {
+ return windowless_;
+ }
+
+ enum PluginQuirks {
+ PLUGIN_QUIRK_SETWINDOW_TWICE = 1,
+ PLUGIN_QUIRK_THROTTLE_WM_USER_PLUS_ONE = 2,
+ PLUGIN_QUIRK_DONT_CALL_WND_PROC_RECURSIVELY = 4,
+ PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY = 8,
+ PLUGIN_QUIRK_DONT_ALLOW_MULTIPLE_INSTANCES = 16,
+ };
+
+ int quirks() { return quirks_; }
+
+ static void MoveWindow(HWND window,
+ const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect,
+ bool visible);
+
+ private:
+ WebPluginDelegateImpl(HWND containing_window,
+ NPAPI::PluginInstance *instance);
+ ~WebPluginDelegateImpl();
+
+ //--------------------------
+ // used for windowed plugins
+ void WindowedUpdateGeometry(const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect, bool visible);
+ // Create the native window.
+ // Returns true if the window is created (or already exists).
+ // Returns false if unable to create the window.
+ bool WindowedCreatePlugin();
+
+ // Destroy the native window.
+ void WindowedDestroyWindow();
+
+ // Reposition the native window to be in sync with the given geometry.
+ // Returns true if the native window has moved or been clipped differently.
+ bool WindowedReposition(const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect, bool visible);
+
+ // Tells the plugin about the current state of the window.
+ // See NPAPI NPP_SetWindow for more information.
+ void WindowedSetWindow();
+
+ // Registers the window class for our window
+ ATOM RegisterNativeWindowClass();
+
+ // Our WndProc functions.
+ static LRESULT CALLBACK NativeWndProc(
+ HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
+ static LRESULT CALLBACK FlashWindowlessWndProc(
+ HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
+
+ // Used for throttling Flash messages.
+ static void ClearThrottleQueueForWindow(HWND window);
+ static void OnThrottleMessage();
+ static void ThrottleMessage(WNDPROC proc, HWND hwnd, UINT message,
+ WPARAM wParam, LPARAM lParam);
+
+ //----------------------------
+ // used for windowless plugins
+ void WindowlessUpdateGeometry(const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect);
+ void WindowlessPaint(HDC hdc, const gfx::Rect& rect);
+
+ // Tells the plugin about the current state of the window.
+ // See NPAPI NPP_SetWindow for more information.
+ void WindowlessSetWindow(bool force_set_window);
+
+
+ //-----------------------------------------
+ // used for windowed and windowless plugins
+
+ NPAPI::PluginInstance* instance() { return instance_.get(); }
+
+ // Closes down and destroys our plugin instance.
+ void DestroyInstance();
+
+ // Returns the cursor type.
+ // TODO(iyengar) Add support for custom cursors.
+ WebCursor::Type GetCursorType(HCURSOR cursor) const;
+
+ // used for windowed plugins
+ HWND windowed_handle_;
+ bool windowed_did_set_window_;
+ gfx::Rect windowed_last_pos_;
+
+ // this is an optimization to avoid calling SetWindow to the plugin
+ // when it is not necessary. Initially, we need to call SetWindow,
+ // and after that we only need to call it when the geometry changes.
+ // use this flag to indicate whether we really need it or not.
+ bool windowless_needs_set_window_;
+
+ // used by windowed and windowless plugins
+ bool windowless_;
+
+ WebPlugin* plugin_;
+ scoped_refptr<NPAPI::PluginInstance> instance_;
+
+ // Original wndproc before we subclassed.
+ WNDPROC plugin_wnd_proc_;
+
+ // Used to throttle WM_USER+1 messages in Flash.
+ uint32 last_message_;
+ bool is_calling_wndproc;
+
+ HWND parent_;
+ NPWindow window_;
+ gfx::Rect window_rect_;
+ gfx::Rect clip_rect_;
+ int quirks_;
+
+ // We only move/size the plugin window once after its creation. The
+ // rest of the moves are controlled by the browser. This flag controls
+ // this behaviour.
+ bool initial_plugin_resize_done_;
+
+ // Windowless plugins don't have keyboard focus causing issues with the
+ // plugin not receiving keyboard events if the plugin enters a modal
+ // loop like TrackPopupMenuEx or MessageBox, etc.
+ // This is a basic issue with windows activation and focus arising due to
+ // the fact that these windows are created by different threads. Activation
+ // and focus are thread specific states, and if the browser has focus,
+ // the plugin may not have focus.
+ // To fix a majority of these activation issues we create a dummy visible
+ // child window to which we set focus whenever the windowless plugin
+ // receives a WM_LBUTTONDOWN/WM_RBUTTONDOWN message via NPP_HandleEvent.
+ HWND dummy_window_for_activation_;
+ bool CreateDummyWindowForActivation();
+
+ static std::list<MSG> throttle_queue_;
+
+ // Returns true if the event passed in needs to be tracked for a potential
+ // modal loop.
+ static bool ShouldTrackEventForModalLoops(NPEvent* event);
+
+ // The message filter hook procedure, which tracks modal loops entered by
+ // a plugin in the course of a NPP_HandleEvent call.
+ static LRESULT CALLBACK HandleEventMessageFilterHook(int code, WPARAM wParam,
+ LPARAM lParam);
+
+ // Called by the message filter hook when the plugin enters a modal loop.
+ void OnModalLoopEntered();
+
+ // Returns true if the message passed in corresponds to a user gesture.
+ static bool IsUserGestureMessage(unsigned int message);
+
+ // Indicates the end of a user gesture period.
+ void OnUserGestureEnd();
+
+ // Handle to the message filter hook
+ HHOOK handle_event_message_filter_hook_;
+
+ // The current instance of the plugin which entered the modal loop.
+ static WebPluginDelegateImpl* current_plugin_instance_;
+
+ // Event which is set when the plugin enters a modal loop in the course
+ // of a NPP_HandleEvent call.
+ HANDLE handle_event_pump_messages_event_;
+
+ // Holds the depth of the HandleEvent callstack.
+ int handle_event_depth_;
+
+ // This flag indicates whether we started tracking a user gesture message.
+ bool user_gesture_message_posted_;
+
+ // Runnable Method Factory used to invoke the OnUserGestureEnd method
+ // asynchronously.
+ ScopedRunnableMethodFactory<WebPluginDelegateImpl> user_gesture_msg_factory_;
+
+ // The url with which the plugin was instantiated.
+ std::string plugin_url_;
+
+ // Indicates if the download would be initiated by the plugin or us.
+ bool load_manually_;
+
+ // Indicates whether a geometry update sequence is the first.
+ bool first_geometry_update_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(WebPluginDelegateImpl);
+};
+
+#endif // #ifndef WEBKIT_GLUE_PLUGIN_WEBPLUGIN_DELEGATE_IMPL_H__
diff --git a/webkit/glue/regular_expression_unittest.cc b/webkit/glue/regular_expression_unittest.cc
new file mode 100644
index 0000000..a9e1cfa
--- /dev/null
+++ b/webkit/glue/regular_expression_unittest.cc
@@ -0,0 +1,118 @@
+// 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 "config.h"
+
+#pragma warning(push, 0)
+#include "PlatformString.h"
+#include "RegularExpression.h"
+#pragma warning(pop)
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/glue/glue_util.h"
+
+using std::wstring;
+using webkit_glue::StdWStringToDeprecatedString;
+using WebCore::DeprecatedString;
+using WebCore::RegularExpression;
+
+namespace {
+
+class RegexTest : public testing::Test {
+};
+
+struct Match {
+ const std::wstring text;
+ const int position;
+ const int length;
+};
+
+} // namespace
+
+TEST(RegexTest, Basic) {
+ // Just make sure we're not completely broken.
+ const DeprecatedString pattern("the quick brown fox");
+ RegularExpression regex(pattern, /* case sensitive */ true);
+ EXPECT_EQ(0, regex.match(DeprecatedString("the quick brown fox")));
+ EXPECT_EQ(1, regex.match(DeprecatedString(" the quick brown fox")));
+ EXPECT_EQ(3, regex.match(DeprecatedString("foothe quick brown foxbar")));
+
+ EXPECT_EQ(-1, regex.match(DeprecatedString("The quick brown FOX")));
+ EXPECT_EQ(-1, regex.match(DeprecatedString("the quick brown fo")));
+}
+
+TEST(RegexTest, Unicode) {
+ // Make sure we get the right offsets for unicode strings.
+
+ // Test 1
+ wstring wstr_pattern(L"\x6240\x6709\x7f51\x9875");
+ DeprecatedString pattern = StdWStringToDeprecatedString(wstr_pattern);
+ RegularExpression regex(pattern, /* case sensitive */ false);
+
+ EXPECT_EQ(0, regex.match(StdWStringToDeprecatedString(wstr_pattern)));
+ EXPECT_EQ(1, regex.match(StdWStringToDeprecatedString(
+ wstring(L" ") + wstr_pattern)));
+ EXPECT_EQ(3, regex.match(StdWStringToDeprecatedString(
+ wstring(L"foo") + wstr_pattern + wstring(L"bar"))));
+ EXPECT_EQ(4, regex.match(StdWStringToDeprecatedString(
+ wstring(L"\x4e2d\x6587\x7f51\x9875") + wstr_pattern)));
+
+ // Test 2, mixed length
+ wstr_pattern = L":[ \x2000]+:";
+ pattern = StdWStringToDeprecatedString(wstr_pattern);
+ regex = RegularExpression(pattern, /* case sensitive */ false);
+
+ const Match matches[] = {
+ { L": :", 0, 4 },
+ { L" : : ", 2, 6 },
+ { L" : \x2000 : ", 1, 5 },
+ { L"\x6240\x6709\x7f51\x9875 : \x2000 \x2000 : ", 5, 7 },
+ { L"", -1, -1 },
+ { L"::", -1, -1 },
+ };
+ for (size_t i = 0; i < arraysize(matches); ++i) {
+ EXPECT_EQ(matches[i].position, regex.match(StdWStringToDeprecatedString(
+ wstring(matches[i].text))));
+ EXPECT_EQ(matches[i].length, regex.matchedLength());
+ }
+
+ // Test 3, empty match
+ wstr_pattern = L"|x";
+ pattern = StdWStringToDeprecatedString(wstr_pattern);
+ regex = RegularExpression(pattern, /* case sensitive */ false);
+
+ const Match matches2[] = {
+ { L"", 0, 0 },
+ };
+ for (size_t i = 0; i < arraysize(matches2); ++i) {
+ EXPECT_EQ(matches2[i].position, regex.match(StdWStringToDeprecatedString(
+ wstring(matches2[i].text))));
+ EXPECT_EQ(matches2[i].length, regex.matchedLength());
+ }
+}
diff --git a/webkit/glue/resource_fetcher.cc b/webkit/glue/resource_fetcher.cc
new file mode 100644
index 0000000..1a4bbd4
--- /dev/null
+++ b/webkit/glue/resource_fetcher.cc
@@ -0,0 +1,146 @@
+// 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 "config.h"
+#include "webkit/glue/resource_fetcher.h"
+
+#pragma warning(push, 0)
+#include "FrameLoader.h"
+#include "ResourceHandle.h"
+#include "ResourceRequest.h"
+#pragma warning(pop)
+
+#undef LOG
+#include "base/logging.h"
+#include "webkit/glue/glue_util.h"
+#include "net/url_request/url_request_status.h"
+
+using WebCore::ResourceError;
+using WebCore::ResourceHandle;
+using WebCore::ResourceResponse;
+
+ResourceFetcher::ResourceFetcher(const GURL& url, WebCore::Frame* frame,
+ Delegate* d)
+ : url_(url), delegate_(d), completed_(false) {
+ // Can't do anything without a frame. However, delegate can be NULL (so we
+ // can do a http request and ignore the results).
+ DCHECK(frame);
+ Start(frame);
+}
+
+ResourceFetcher::~ResourceFetcher() {
+ if (!completed_)
+ loader_->cancel();
+ loader_ = NULL;
+}
+
+void ResourceFetcher::Cancel() {
+ if (!completed_) {
+ loader_->cancel();
+ completed_ = true;
+ }
+}
+
+void ResourceFetcher::Start(WebCore::Frame* frame) {
+ WebCore::FrameLoader* frame_loader = frame->loader();
+ if (!frame_loader) {
+ // We put this on a 0 timer so the callback happens async (consistent with
+ // regular fetches).
+ start_failed_timer_.reset(new StartFailedTimer(this,
+ &ResourceFetcher::StartFailed));
+ start_failed_timer_->startOneShot(0);
+ return;
+ }
+
+ WebCore::ResourceRequest request(webkit_glue::GURLToKURL(url_));
+ request.setFrame(frame);
+
+ loader_ = ResourceHandle::create(request, this, NULL, false, false);
+}
+
+void ResourceFetcher::StartFailed(StartFailedTimer* timer) {
+ didFail(NULL, ResourceError());
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// ResourceHandleClient methods
+void ResourceFetcher::didReceiveResponse(ResourceHandle* resource_handle,
+ const ResourceResponse& response) {
+ ASSERT(!completed_);
+ // It's safe to use the ResourceResponse copy constructor
+ // (xmlhttprequest.cpp uses it).
+ response_ = response;
+}
+
+void ResourceFetcher::didReceiveData(ResourceHandle* resource_handle,
+ const char* data, int length,
+ int total_length) {
+ ASSERT(!completed_);
+ if (length <= 0)
+ return;
+
+ data_.append(data, length);
+}
+
+void ResourceFetcher::didFinishLoading(ResourceHandle* resource_handle) {
+ ASSERT(!completed_);
+ completed_ = true;
+
+ if (delegate_)
+ delegate_->OnURLFetchComplete(response_, data_);
+}
+
+void ResourceFetcher::didFail(ResourceHandle* resource_handle,
+ const ResourceError& error) {
+ ASSERT(!completed_);
+ completed_ = true;
+
+ // Go ahead and tell our delegate that we're done. Send an empty
+ // ResourceResponse and string.
+ if (delegate_)
+ delegate_->OnURLFetchComplete(ResourceResponse(), std::string());
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// A resource fetcher with a timeout
+
+ResourceFetcherWithTimeout::ResourceFetcherWithTimeout(
+ const GURL& url, WebCore::Frame* frame, double timeout_secs, Delegate* d)
+ : ResourceFetcher(url, frame, d) {
+ timeout_timer_.reset(new FetchTimer(this,
+ &ResourceFetcherWithTimeout::TimeoutFired));
+ timeout_timer_->startOneShot(timeout_secs);
+}
+
+void ResourceFetcherWithTimeout::TimeoutFired(FetchTimer* timer) {
+ if (!completed_) {
+ loader_->cancel();
+ didFail(NULL, ResourceError());
+ }
+}
diff --git a/webkit/glue/resource_fetcher.h b/webkit/glue/resource_fetcher.h
new file mode 100644
index 0000000..57f038a
--- /dev/null
+++ b/webkit/glue/resource_fetcher.h
@@ -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.
+//
+// A wrapper around ResourceHandle and ResourceHandleClient that simplifies
+// the download of an HTTP object. The interface is modeled after URLFetcher
+// in the /chrome/browser.
+//
+// ResourceFetcher::Delegate::OnURLFetchComplete will be called async after
+// the ResourceFetcher object is created.
+
+#ifndef WEBKIT_GLUE_RESOURCE_FETCHER_H__
+#define WEBKIT_GLUE_RESOURCE_FETCHER_H__
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "googleurl/src/gurl.h"
+
+#pragma warning(push, 0)
+#include "Frame.h"
+#include "Timer.h"
+#include "ResourceHandleClient.h"
+#include "ResourceResponse.h"
+#pragma warning(pop)
+
+class GURL;
+class WebCore::ResourceHandle;
+
+class ResourceFetcher : public WebCore::ResourceHandleClient {
+ public:
+ class Delegate {
+ public:
+ // This will be called when the URL has been fetched, successfully or not.
+ // If there is a failure, response and data will both be empty.
+ // |response| and |data| are both valid until the URLFetcher instance is
+ // destroyed.
+ virtual void OnURLFetchComplete(const WebCore::ResourceResponse& response,
+ const std::string& data) = 0;
+ };
+
+ // We need a frame and frame loader to make requests.
+ ResourceFetcher(const GURL& url, WebCore::Frame* frame, Delegate* d);
+ ~ResourceFetcher();
+
+ // Stop the request and don't call the callback.
+ void Cancel();
+
+ bool completed() { return completed_; }
+
+ // ResourceHandleClient methods
+ virtual void didReceiveResponse(WebCore::ResourceHandle* resource_handle,
+ const WebCore::ResourceResponse& response);
+
+ virtual void didReceiveData(WebCore::ResourceHandle* resource_handle,
+ const char* data, int length, int total_length);
+
+ virtual void didFinishLoading(WebCore::ResourceHandle* resource_handle);
+
+ virtual void didFail(WebCore::ResourceHandle* resource_handle,
+ const WebCore::ResourceError& error);
+
+ protected:
+ // The parent ResourceHandle
+ RefPtr<WebCore::ResourceHandle> loader_;
+
+ // URL we're fetching
+ GURL url_;
+
+ // Callback when we're done
+ Delegate* delegate_;
+
+ // A copy of the original resource response
+ WebCore::ResourceResponse response_;
+
+ // Set to true once the request is compelte.
+ bool completed_;
+
+ private:
+ // If we fail to start the request, we still want to finish async.
+ typedef WebCore::Timer<ResourceFetcher> StartFailedTimer;
+
+ // Start the actual download.
+ void Start(WebCore::Frame* frame);
+
+ // Callback function if Start fails.
+ void StartFailed(StartFailedTimer* timer);
+
+ // Timer for calling StartFailed async.
+ scoped_ptr<StartFailedTimer> start_failed_timer_;
+
+ // Buffer to hold the content from the server.
+ std::string data_;
+};
+
+/////////////////////////////////////////////////////////////////////////////
+// A resource fetcher with a timeout
+class ResourceFetcherWithTimeout : public ResourceFetcher {
+ public:
+ ResourceFetcherWithTimeout(const GURL& url, WebCore::Frame* frame, double
+ timeout_secs, Delegate* d);
+ virtual ~ResourceFetcherWithTimeout() {}
+
+ private:
+ typedef WebCore::Timer<ResourceFetcherWithTimeout> FetchTimer;
+
+ // Callback for timer that limits how long we wait for the alternate error
+ // page server. If this timer fires and the request hasn't completed, we
+ // kill the request.
+ void TimeoutFired(FetchTimer* timer);
+
+ // Limit how long we wait for the alternate error page server.
+ scoped_ptr<FetchTimer> timeout_timer_;
+};
+
+#endif // WEBKIT_GLUE_RESOURCE_FETCHER_H__
diff --git a/webkit/glue/resource_fetcher_unittest.cc b/webkit/glue/resource_fetcher_unittest.cc
new file mode 100644
index 0000000..c9eef1f
--- /dev/null
+++ b/webkit/glue/resource_fetcher_unittest.cc
@@ -0,0 +1,210 @@
+// 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 "config.h"
+
+#pragma warning(push, 0)
+#include "ResourceResponse.h"
+#pragma warning(pop)
+#undef LOG
+
+#include "webkit/glue/unittest_test_server.h"
+#include "webkit/glue/webview.h"
+#include "webkit/glue/webframe_impl.h"
+#include "webkit/glue/resource_fetcher.h"
+#include "webkit/tools/test_shell/simple_resource_loader_bridge.h"
+#include "webkit/tools/test_shell/test_shell_test.h"
+
+using WebCore::ResourceResponse;
+
+namespace {
+
+
+class ResourceFetcherTests : public TestShellTest {
+ public:
+ void SetUp() {
+ TestShellTest::SetUp();
+ }
+ void TearDown() {
+ TestShellTest::TearDown();
+ }
+};
+
+static const int kMaxWaitTimeMs = 5000;
+static const int kWaitIntervalMs = 100;
+
+class FetcherDelegate : public ResourceFetcher::Delegate {
+ public:
+ FetcherDelegate()
+ : timer_id_(0), completed_(false), time_elapsed_ms_(0) {
+ // Start a repeating timer waiting for the download to complete. The
+ // callback has to be a static function, so we hold on to our instance.
+ FetcherDelegate::instance_ = this;
+ timer_id_ = SetTimer(NULL, NULL, kWaitIntervalMs,
+ &FetcherDelegate::TimerCallback);
+ }
+
+ virtual void OnURLFetchComplete(const ResourceResponse& response,
+ const std::string& data) {
+ response_ = response;
+ data_ = data;
+ completed_ = true;
+ KillTimer(NULL, timer_id_);
+ MessageLoop::current()->Quit();
+ }
+
+ bool completed() const { return completed_; }
+ bool timed_out() const { return time_elapsed_ms_ > kMaxWaitTimeMs; }
+
+ int time_elapsed_ms() const { return time_elapsed_ms_; }
+ std::string data() const { return data_; }
+ ResourceResponse response() const { return response_; }
+
+ // Wait for the request to complete or timeout. We use a loop here b/c the
+ // testing infrastructure (test_shell) can generate spurious calls to the
+ // MessageLoop's Quit method.
+ void WaitForResponse() {
+ while (!completed() && !timed_out())
+ MessageLoop::current()->Run();
+ }
+
+ // Static timer callback, just passes through to instance version.
+ static VOID CALLBACK TimerCallback(HWND hwnd, UINT msg, UINT_PTR timer_id,
+ DWORD ms) {
+ instance_->TimerFired(hwnd, timer_id);
+ }
+
+ void TimerFired(HWND hwnd, UINT_PTR timer_id) {
+ ASSERT_FALSE(completed_);
+
+ if (timed_out()) {
+ printf("timer fired\n");
+ KillTimer(hwnd, timer_id);
+ MessageLoop::current()->Quit();
+ FAIL() << "fetch timed out";
+ return;
+ }
+
+ time_elapsed_ms_ += kWaitIntervalMs;
+ }
+
+ static FetcherDelegate* instance_;
+
+ private:
+ UINT_PTR timer_id_;
+ bool completed_;
+ int time_elapsed_ms_;
+ ResourceResponse response_;
+ std::string data_;
+};
+
+FetcherDelegate* FetcherDelegate::instance_ = NULL;
+
+} // namespace
+
+// Test a fetch from the test server.
+TEST_F(ResourceFetcherTests, ResourceFetcherDownload) {
+ UnittestTestServer server;
+
+ WebFrame* web_frame = test_shell_->webView()->GetMainFrame();
+ // Not safe, but this is a unittest, so whatever.
+ WebFrameImpl* web_frame_impl = reinterpret_cast<WebFrameImpl*>(web_frame);
+ WebCore::Frame* frame = web_frame_impl->frame();
+
+ GURL url = server.TestServerPage("files/test_shell/index.html");
+ scoped_ptr<FetcherDelegate> delegate(new FetcherDelegate);
+ scoped_ptr<ResourceFetcher> fetcher(new ResourceFetcher(
+ url, frame, delegate.get()));
+
+ delegate->WaitForResponse();
+
+ ASSERT_TRUE(delegate->completed());
+ EXPECT_EQ(delegate->response().httpStatusCode(), 200);
+ std::string text = delegate->data();
+ EXPECT_TRUE(text.find("What is this page?") != std::string::npos);
+
+ // Test 404 response.
+ url = server.TestServerPage("files/thisfiledoesntexist.html");
+ delegate.reset(new FetcherDelegate);
+ fetcher.reset(new ResourceFetcher(url, frame, delegate.get()));
+
+ delegate->WaitForResponse();
+
+ ASSERT_TRUE(delegate->completed());
+ EXPECT_EQ(delegate->response().httpStatusCode(), 404);
+ EXPECT_TRUE(delegate->data().find("Not Found.") != std::string::npos);
+}
+
+TEST_F(ResourceFetcherTests, ResourceFetcherDidFail) {
+ UnittestTestServer server;
+ WebFrame* web_frame = test_shell_->webView()->GetMainFrame();
+ // Not safe, but this is a unittest, so whatever.
+ WebFrameImpl* web_frame_impl = reinterpret_cast<WebFrameImpl*>(web_frame);
+ WebCore::Frame* frame = web_frame_impl->frame();
+
+ // Try to fetch a page on a site that doesn't exist.
+ GURL url("http://localhost:1339/doesnotexist");
+ scoped_ptr<FetcherDelegate> delegate(new FetcherDelegate);
+ scoped_ptr<ResourceFetcher> fetcher(new ResourceFetcher(
+ url, frame, delegate.get()));
+
+ delegate->WaitForResponse();
+
+ // When we fail, we still call the Delegate callback but we pass in empty
+ // values.
+ EXPECT_TRUE(delegate->completed());
+ EXPECT_TRUE(delegate->response().isNull());
+ EXPECT_EQ(delegate->data(), std::string());
+ EXPECT_TRUE(delegate->time_elapsed_ms() < kMaxWaitTimeMs);
+}
+
+TEST_F(ResourceFetcherTests, ResourceFetcherTimeout) {
+ UnittestTestServer server;
+
+ WebFrame* web_frame = test_shell_->webView()->GetMainFrame();
+ // Not safe, but this is a unittest, so whatever.
+ WebFrameImpl* web_frame_impl = reinterpret_cast<WebFrameImpl*>(web_frame);
+ WebCore::Frame* frame = web_frame_impl->frame();
+
+ // Grab a page that takes at least 1 sec to respond, but set the fetcher to
+ // timeout in 0 sec.
+ GURL url = server.TestServerPage("slow?1");
+ scoped_ptr<FetcherDelegate> delegate(new FetcherDelegate);
+ scoped_ptr<ResourceFetcher> fetcher(new ResourceFetcherWithTimeout(
+ url, frame, 0, delegate.get()));
+
+ delegate->WaitForResponse();
+
+ // When we timeout, we still call the Delegate callback but we pass in empty
+ // values.
+ EXPECT_TRUE(delegate->completed());
+ EXPECT_TRUE(delegate->response().isNull());
+ EXPECT_EQ(delegate->data(), std::string());
+ EXPECT_TRUE(delegate->time_elapsed_ms() < kMaxWaitTimeMs);
+}
diff --git a/webkit/glue/resource_handle_win.cc b/webkit/glue/resource_handle_win.cc
new file mode 100644
index 0000000..1646f0a
--- /dev/null
+++ b/webkit/glue/resource_handle_win.cc
@@ -0,0 +1,764 @@
+// 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 replaces WebCore/platform/network/win/ResourceHandleWin.cpp with a
+// platform-neutral implementation that simply defers almost entirely to
+// ResouceLoaderBridge.
+//
+// This uses the same ResourceHandle.h header file that the rest of WebKit
+// uses, allowing us to avoid complicated changes. Our specific things are
+// added on ResourceHandleInternal. The ResourceHandle owns the
+// ResourceHandleInternal and passes off almost all processing to it.
+//
+// The WebKit version of this code keeps the ResourceHandle AddRef'd when
+// there are any callbacks. This prevents the callbacks from occuring into
+// destroyed objects. However, our destructors should always stop callbacks
+// from happening, making this (hopefully) unnecessary.
+//
+// We preserve this behavior for safety. A client could count on this behavior
+// and fire off a request, release it, and wait for callbacks to get the data
+// as long as it doesn't care about canceling the request. Although this is
+// dumb, we support it. We use pending_ to indicate this extra AddRef, which
+// is done in start() and released in OnCompletedRequest.
+
+#include "config.h"
+
+#pragma warning(push, 0)
+#include "CString.h"
+#include "DocLoader.h"
+#include "FormData.h"
+#include "FrameLoader.h"
+#include "LogWin.h"
+#include "Page.h"
+#include "ResourceError.h"
+#include "ResourceHandle.h"
+#include "ResourceHandleClient.h"
+#include "ResourceHandleWin.h" // for Platform{Response,Data}Struct
+#include "ResourceRequest.h"
+#include "ResourceResponse.h"
+#pragma warning(pop)
+
+#undef LOG
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/time.h"
+#include "base/string_util.h"
+#include "base/string_tokenizer.h"
+#include "webkit/glue/feed_preview.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/multipart_response_delegate.h"
+#include "webkit/glue/resource_loader_bridge.h"
+#include "webkit/glue/webframe_impl.h"
+#include "net/base/data_url.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_util.h"
+#include "net/base/load_flags.h"
+
+using webkit_glue::ResourceLoaderBridge;
+using net::HttpResponseHeaders;
+
+namespace {
+
+// Extracts the information from a data: url.
+bool GetInfoFromDataUrl(const GURL& url,
+ ResourceLoaderBridge::ResponseInfo* info,
+ std::string* data, URLRequestStatus* status) {
+ std::string mime_type;
+ std::string charset;
+ if (DataURL::Parse(url, &mime_type, &charset, data)) {
+ info->request_time = Time::Now();
+ info->response_time = Time::Now();
+ info->mime_type.swap(mime_type);
+ info->charset.swap(charset);
+ *status = URLRequestStatus(URLRequestStatus::SUCCESS, 0);
+ return true;
+ }
+
+ *status = URLRequestStatus(URLRequestStatus::FAILED, net::ERR_INVALID_URL);
+ return false;
+}
+
+} // namespace
+
+namespace WebCore {
+
+static void ExtractInfoFromHeaders(const HttpResponseHeaders* headers,
+ HTTPHeaderMap* header_map,
+ int* status_code,
+ String* status_text,
+ long long* expected_content_length) {
+ *status_code = headers->response_code();
+
+ // Set the status text (the returned status line is normalized).
+ const std::string& status = headers->GetStatusLine();
+ StringTokenizer status_tokenizer(status, " ");
+ if (status_tokenizer.GetNext() && // identifies "HTTP/1.1"
+ status_tokenizer.GetNext() && // identifies "200"
+ status_tokenizer.GetNext()) // identifies first word of status text
+ *status_text = webkit_glue::StdStringToString(
+ std::string(status_tokenizer.token_begin(), status.end()));
+
+ // Set the content length.
+ std::string length_val;
+ if (headers->EnumerateHeader(NULL, "content-length", &length_val))
+ *expected_content_length = StringToInt64(length_val);
+
+ // Build up the header map. Take care with duplicate headers.
+ void* iter = NULL;
+ std::string name, value;
+ while (headers->EnumerateHeaderLines(&iter, &name, &value)) {
+ String name_str = webkit_glue::StdStringToString(name);
+ String value_str = webkit_glue::StdStringToString(value);
+
+ pair<HTTPHeaderMap::iterator, bool> result =
+ header_map->add(name_str, value_str);
+ if (!result.second)
+ result.first->second += ", " + value_str;
+ }
+}
+
+static ResourceResponse MakeResourceResponse(
+ const KURL& kurl,
+ const ResourceLoaderBridge::ResponseInfo& info) {
+ int status_code = 0;
+ long long expected_content_length = info.content_length;
+ String status_text;
+ HTTPHeaderMap header_map;
+
+ // It's okay if there are no headers
+ if (info.headers)
+ ExtractInfoFromHeaders(info.headers,
+ &header_map,
+ &status_code,
+ &status_text,
+ &expected_content_length);
+
+ // TODO(darin): We should leverage HttpResponseHeaders for this, and this
+ // should be using the same code as ResourceDispatcherHost.
+ std::wstring suggested_filename;
+ if (info.headers) {
+ std::string disp_val;
+ if (info.headers->EnumerateHeader(NULL, "content-disposition", &disp_val)) {
+ suggested_filename = net_util::GetSuggestedFilename(
+ webkit_glue::KURLToGURL(kurl), disp_val, std::wstring());
+ }
+ }
+
+ ResourceResponse response(kurl,
+ webkit_glue::StdStringToString(info.mime_type),
+ expected_content_length,
+ webkit_glue::StdStringToString(info.charset),
+ webkit_glue::StdWStringToString(suggested_filename));
+
+ if (info.headers) {
+ Time time_val;
+ if (info.headers->GetLastModifiedValue(&time_val))
+ response.setLastModifiedDate(time_val.ToTimeT());
+
+ // Compute expiration date
+ TimeDelta freshness_lifetime =
+ info.headers->GetFreshnessLifetime(info.response_time);
+ if (freshness_lifetime != TimeDelta()) {
+ Time now = Time::Now();
+ TimeDelta current_age =
+ info.headers->GetCurrentAge(info.request_time, info.response_time,
+ now);
+ time_val = now + freshness_lifetime - current_age;
+
+ response.setExpirationDate(time_val.ToTimeT());
+ } else {
+ // WebKit uses 0 as a special expiration date that means never expire.
+ // 1 is a small enough value to let it always expire.
+ response.setExpirationDate(1);
+ }
+ }
+
+ response.setHTTPStatusCode(status_code);
+ response.setHTTPStatusText(status_text);
+ response.setSecurityInfo(webkit_glue::StdStringToCString(info.security_info));
+
+ // WebKit doesn't provide a way for us to set expected content length after
+ // calling the constructor, so we parse the headers first and then swap in
+ // our HTTP header map. Ideally we would like a setter for expected content
+ // length (perhaps by abstracting ResourceResponse interface into
+ // ResourceResponseBase) but that would require forking.
+ const_cast<HTTPHeaderMap*>(&response.httpHeaderFields())->swap(header_map);
+
+ return response;
+}
+
+class ResourceHandleInternal : public ResourceLoaderBridge::Peer {
+ public:
+ ResourceHandleInternal(ResourceHandle* job, const ResourceRequest& r,
+ ResourceHandleClient* c);
+ ~ResourceHandleInternal();
+
+ // If the response parameter is null, then an asynchronous load is started.
+ bool Start(ResourceLoaderBridge::SyncLoadResponse* response);
+
+ // Used to cancel an asynchronous load.
+ void Cancel();
+
+ // Used to suspend/resume an asynchronous load.
+ void SetDefersLoading(bool value);
+
+ // ResourceLoaderBridge::Peer implementation
+ virtual void OnReceivedRedirect(const GURL& new_url);
+ virtual void OnReceivedResponse(
+ const ResourceLoaderBridge::ResponseInfo& info);
+ virtual void OnReceivedData(const char* data, int len);
+ virtual void OnCompletedRequest(const URLRequestStatus& status);
+ virtual std::string GetURLForDebugging();
+
+ // Handles a data: url internally instead of calling the bridge.
+ void HandleDataUrl();
+
+ // This is the bridge implemented by the embedder.
+ // The bridge is kept alive as long as the request is valid and we
+ // are ready for callbacks.
+ scoped_ptr<ResourceLoaderBridge> bridge_;
+
+ // The resource loader that owns us
+ ResourceHandle* job_;
+
+ // This is the object that receives various status messages (such as when the
+ // loader has received data). See definition for the exact messages that are
+ // sent to it.
+ ResourceHandleClient* client_;
+
+ ResourceRequest request_;
+
+ // Runnable Method Factory used to invoke later HandleDataUrl().
+ ScopedRunnableMethodFactory<ResourceHandleInternal> data_url_factory_;
+
+ int load_flags_;
+
+ private:
+ // Set to true when we're waiting for data from the bridge, also indicating
+ // we have addrefed our job.
+ bool pending_;
+
+ // Expected content length of the response
+ long long expected_content_length_;
+
+ // NULL unless we are handling a multipart/x-mixed-replace request
+ scoped_ptr<MultipartResponseDelegate> multipart_delegate_;
+
+ // NULL unless we are handling a feed:// request.
+ scoped_ptr<FeedClientProxy> feed_client_proxy_;
+};
+
+ResourceHandleInternal::ResourceHandleInternal(ResourceHandle* job,
+ const ResourceRequest& r,
+ ResourceHandleClient* c)
+ : job_(job),
+ client_(c),
+ request_(r),
+ load_flags_(net::LOAD_NORMAL),
+ pending_(false),
+ expected_content_length_(-1),
+ multipart_delegate_(NULL),
+#pragma warning(suppress: 4355) // can use this
+ data_url_factory_(this) {
+}
+
+ResourceHandleInternal::~ResourceHandleInternal() {
+ DCHECK(!pending_);
+}
+
+void ResourceHandleInternal::HandleDataUrl() {
+ ResourceLoaderBridge::ResponseInfo info;
+ URLRequestStatus status;
+ std::string data;
+
+ if (GetInfoFromDataUrl(webkit_glue::KURLToGURL(request_.url()), &info, &data,
+ &status)) {
+ OnReceivedResponse(info);
+
+ if (data.size())
+ OnReceivedData(data.c_str(), data.size());
+ }
+
+ OnCompletedRequest(status);
+
+ // We are done using the object. ResourceHandle and ResourceHandleInternal
+ // might be destroyed now.
+ job_->deref();
+}
+
+bool ResourceHandleInternal::Start(
+ ResourceLoaderBridge::SyncLoadResponse* sync_load_response) {
+ DCHECK(!bridge_.get());
+
+ // The WebFrame is the Frame's FrameWinClient
+ WebFrameImpl* webframe =
+ request_.frame() ? WebFrameImpl::FromFrame(request_.frame()) : NULL;
+
+ CString method = request_.httpMethod().latin1();
+ GURL referrer(webkit_glue::StringToStdWString(request_.httpReferrer()));
+
+ // Compute the URL of the load.
+ GURL url = webkit_glue::KURLToGURL(request_.url());
+ if (url.SchemeIs("feed:")) {
+ // Feed URLs are special, they actually mean "http".
+ url_canon::Replacements<char> replacements;
+ replacements.SetScheme("http", url_parse::Component(0, 4));
+ url = url.ReplaceComponents(replacements);
+
+ // Replace our client with a client that understands previewing feeds
+ // and forwards the feeds along to the original client.
+ feed_client_proxy_.reset(new FeedClientProxy(client_));
+ client_ = feed_client_proxy_.get();
+ }
+
+ // Inherit the policy URL from the request's frame. However, if the request
+ // is for a main frame, the current document's policyBaseURL is the old
+ // document, so we leave policyURL empty to indicate that the request is a
+ // first-party request.
+ GURL policy_url;
+ if (request_.resourceType() != ResourceType::MAIN_FRAME &&
+ request_.frame() && request_.frame()->document()) {
+ policy_url = GURL(webkit_glue::StringToStdWString(
+ request_.frame()->document()->policyBaseURL()));
+ }
+
+ // Translate the table of request headers to a formatted string blob
+ String headerBuf;
+ const HTTPHeaderMap& headerMap = request_.httpHeaderFields();
+
+ // In some cases, WebCore doesn't add an Accept header, but not having the
+ // header confuses some web servers. See bug 808613.
+ // Note: headerMap uses case-insenstive keys, so this will find Accept as
+ // as well.
+ if (!headerMap.contains("accept"))
+ request_.addHTTPHeaderField("Accept", "*/*");
+
+ const String crlf(L"\r\n");
+ const String sep(L": ");
+ for (HTTPHeaderMap::const_iterator it = headerMap.begin();
+ it != headerMap.end(); ++it) {
+ // Skip over referrer headers found in the header map because we already
+ // pulled it out as a separate parameter. We likewise prune the UA since
+ // that will be added back by the network layer.
+ if (equalIgnoringCase((*it).first, "referer") ||
+ equalIgnoringCase((*it).first, "user-agent"))
+ continue;
+ // WinInet dies if blank headers are set. TODO(darin): Is this still an
+ // issue now that we are using WinHTTP?
+ if ((*it).first.isEmpty()) {
+ webframe->frame()->page()->chrome()->addMessageToConsole(
+ JSMessageSource,
+ ErrorMessageLevel,
+ "Refused to set blank header",
+ 1,
+ String());
+ continue;
+ }
+ if (!headerBuf.isEmpty())
+ headerBuf.append(crlf);
+ headerBuf.append((*it).first + sep + (*it).second);
+ }
+
+ switch (request_.cachePolicy()) {
+ case ReloadIgnoringCacheData:
+ // Required by LayoutTests/http/tests/misc/refresh-headers.php
+ load_flags_ |= net::LOAD_VALIDATE_CACHE;
+ break;
+ case ReturnCacheDataElseLoad:
+ load_flags_ |= net::LOAD_PREFERRING_CACHE;
+ break;
+ case ReturnCacheDataDontLoad:
+ load_flags_ |= net::LOAD_ONLY_FROM_CACHE;
+ break;
+ }
+
+ // TODO(jcampan): in the non out-of-process plugin case the request does not
+ // have a origin_pid. Find a better place to set this.
+ int origin_pid = request_.originPid();
+ if (origin_pid == 0)
+ origin_pid = ::GetCurrentProcessId();
+
+ bool mixed_content =
+ webkit_glue::KURLToGURL(request_.mainDocumentURL()).SchemeIsSecure() &&
+ !url.SchemeIsSecure();
+
+ if (url.SchemeIs("data")) {
+ if (sync_load_response) {
+ // This is a sync load. Do the work now.
+ sync_load_response->url = url;
+ std::string data;
+ GetInfoFromDataUrl(sync_load_response->url, sync_load_response,
+ &sync_load_response->data,
+ &sync_load_response->status);
+ } else {
+ pending_ = true;
+ job_->ref(); // to be released when we get a OnCompletedRequest.
+ job_->ref(); // to be released when HandleDataUrl is completed.
+ MessageLoop::current()->PostTask(FROM_HERE,
+ data_url_factory_.NewRunnableMethod(
+ &ResourceHandleInternal::HandleDataUrl));
+ }
+ return true;
+ }
+
+ // TODO(darin): is latin1 really correct here? It is if the strings are
+ // already ASCII (i.e., if they are already escaped properly).
+ // TODO(brettw) this should take parameter encoding into account when
+ // creating the GURLs.
+ bridge_.reset(ResourceLoaderBridge::Create(
+ webframe,
+ webkit_glue::CStringToStdString(method),
+ url,
+ policy_url,
+ referrer,
+ webkit_glue::CStringToStdString(headerBuf.latin1()),
+ load_flags_,
+ origin_pid,
+ request_.resourceType(),
+ mixed_content));
+ if (!bridge_.get())
+ return false;
+
+ if (request_.httpBody()) {
+ // GET and HEAD requests shouldn't have http bodies.
+ DCHECK(method != "GET" && method != "HEAD");
+ const Vector<FormDataElement>& elements = request_.httpBody()->elements();
+ size_t n = elements.size();
+ for (size_t i = 0; i < n; ++i) {
+ const FormDataElement& e = elements[static_cast<unsigned>(i)];
+ if (e.m_type == FormDataElement::data) {
+ if (e.m_data.size() > 0) {
+ // WebKit sometimes gives up empty data to append. These aren't
+ // necessary so we just optimize those out here.
+ bridge_->AppendDataToUpload(e.m_data.data(),
+ static_cast<int>(e.m_data.size()));
+ }
+ } else {
+ bridge_->AppendFileToUpload(
+ webkit_glue::StringToStdWString(e.m_filename));
+ }
+ }
+ }
+
+ if (sync_load_response) {
+ bridge_->SyncLoad(sync_load_response);
+ return true;
+ }
+
+ bool rv = bridge_->Start(this);
+ if (rv) {
+ pending_ = true;
+ job_->ref(); // to be released when we get a OnCompletedRequest.
+ } else {
+ bridge_.reset();
+ }
+
+ return rv;
+}
+
+void ResourceHandleInternal::Cancel() {
+ // The bridge will still send OnCompletedRequest, which will deref() us,
+ // so we don't do that here.
+ if (bridge_.get())
+ bridge_->Cancel();
+
+ // Ensure that we do not notify the multipart delegate anymore as it has
+ // its own pointer to the client.
+ multipart_delegate_.reset();
+
+ // Do not make any further calls to the client.
+ client_ = NULL;
+}
+
+void ResourceHandleInternal::SetDefersLoading(bool value) {
+ if (bridge_.get())
+ bridge_->SetDefersLoading(value);
+}
+
+// ResourceLoaderBridge::Peer impl --------------------------------------------
+
+void ResourceHandleInternal::OnReceivedRedirect(const GURL& new_url) {
+ DCHECK(pending_);
+
+ KURL url = webkit_glue::GURLToKURL(new_url);
+
+ // TODO(darin): need a way to properly initialize a ResourceResponse
+ ResourceResponse response(request_.url(), String(), -1, String(), String());
+
+ ResourceRequest new_request(url);
+
+ // TODO(darin): we need to setup new_request to reflect the fact that we
+ // for example drop the httpBody when following a POST request that is
+ // redirected to a GET request.
+
+ if (client_)
+ client_->willSendRequest(job_, new_request, response);
+
+ //
+ // TODO(darin): since new_request is sent as a mutable reference, it is
+ // possible that willSendRequest may expect to be able to modify it.
+ //
+ // andresca on #webkit confirms that that is intentional, so we'll need
+ // to rework the ResourceLoaderBridge to give us control over what URL
+ // is really loaded (and with what headers) when a redirect is encountered.
+ //
+
+ request_ = new_request;
+}
+
+void ResourceHandleInternal::OnReceivedResponse(
+ const ResourceLoaderBridge::ResponseInfo& info) {
+ DCHECK(pending_);
+
+ // TODO(darin): need a way to properly initialize a ResourceResponse
+ ResourceResponse response = MakeResourceResponse(request_.url(), info);
+
+ expected_content_length_ = response.expectedContentLength();
+
+ if (client_)
+ client_->didReceiveResponse(job_, response);
+
+ // we may have been cancelled after didReceiveResponse, which would leave us
+ // without a client and therefore without much need to do multipart handling.
+
+ DCHECK(!multipart_delegate_.get());
+ if (client_ && info.headers && response.isMultipart()) {
+ std::string content_type;
+ info.headers->EnumerateHeader(NULL, "content-type", &content_type);
+
+ std::string boundary = net_util::GetHeaderParamValue(content_type,
+ "boundary");
+ TrimString(boundary, " \"", &boundary);
+ // If there's no boundary, just handle the request normally. In the gecko
+ // code, nsMultiMixedConv::OnStartRequest throws an exception.
+ if (!boundary.empty()) {
+ multipart_delegate_.reset(new MultipartResponseDelegate(client_, job_,
+ response, boundary));
+ }
+ }
+
+ // TODO(darin): generate willCacheResponse callback. debug mac webkit to
+ // determine when it should be called.
+}
+
+void ResourceHandleInternal::OnReceivedData(const char* data, int data_len) {
+ DCHECK(pending_);
+
+ if (client_) {
+ // TODO(darin): figure out what to pass for lengthReceived. from reading
+ // the loader code, it looks like this is supposed to be the content-length
+ // value, but it seems really wacky to include that here! we have to debug
+ // webkit on mac to figure out what this should be.
+
+ // TODO(jackson): didReceiveData expects an int, but an expected content
+ // length is an int64, so we do our best to fit it inside an int. The only
+ // code that cares currently about this value is the Inspector, so beware
+ // that the Inspector's network panel might under-represent the size of
+ // some resources if they're larger than a gigabyte.
+ int lengthReceived = static_cast<int>(expected_content_length_);
+ if (lengthReceived != expected_content_length_) // overflow occurred
+ lengthReceived = -1;
+
+ if (!multipart_delegate_.get()) {
+ client_->didReceiveData(job_, data, data_len, lengthReceived);
+ } else {
+ // AddData will make the appropriate calls to client_->didReceiveData
+ // and client_->didReceiveResponse
+ multipart_delegate_->OnReceivedData(data, data_len);
+ }
+ }
+}
+
+void ResourceHandleInternal::OnCompletedRequest(
+ const URLRequestStatus& status) {
+ if (multipart_delegate_.get()) {
+ multipart_delegate_->OnCompletedRequest();
+ multipart_delegate_.reset(NULL);
+ }
+
+ pending_ = false;
+
+ if (client_) {
+ if (status.status() != URLRequestStatus::SUCCESS) {
+ int error_code;
+ if (status.status() == URLRequestStatus::HANDLED_EXTERNALLY) {
+ // By marking this request as aborted we insure that we don't navigate
+ // to an error page.
+ error_code = net::ERR_ABORTED;
+ } else {
+ error_code = status.os_error();
+ }
+ // TODO(tc): fill in these fields properly
+ ResourceError error(net::kErrorDomain,
+ error_code,
+ request_.url().string(),
+ String() /*localized description*/);
+ client_->didFail(job_, error);
+ } else {
+ client_->didFinishLoading(job_);
+ }
+ }
+
+ job_->deref(); // may destroy our owner and hence |this|
+}
+
+std::string ResourceHandleInternal::GetURLForDebugging() {
+ return webkit_glue::CStringToStdString(request_.url().string().latin1());
+}
+
+// ResourceHandle -------------------------------------------------------------
+
+ResourceHandle::ResourceHandle(const ResourceRequest& request,
+ ResourceHandleClient* client,
+ bool defersLoading,
+ bool shouldContentSniff,
+ bool mightDownloadFromHandle)
+#pragma warning(suppress: 4355) // it's okay to pass |this| here!
+ : d(new ResourceHandleInternal(this, request, client)) {
+ // TODO(darin): figure out what to do with the two bool params
+}
+
+PassRefPtr<ResourceHandle> ResourceHandle::create(const ResourceRequest& request,
+ ResourceHandleClient* client,
+ Frame* deprecated,
+ bool defersLoading,
+ bool shouldContentSniff,
+ bool mightDownloadFromHandle) {
+ RefPtr<ResourceHandle> newHandle(
+ new ResourceHandle(request, client, defersLoading, shouldContentSniff,
+ mightDownloadFromHandle));
+
+ if (newHandle->start(NULL))
+ return newHandle.release();
+
+ return NULL;
+}
+
+const ResourceRequest& ResourceHandle::request() const {
+ return d->request_;
+}
+
+ResourceHandleClient* ResourceHandle::client() const {
+ return d->client_;
+}
+
+void ResourceHandle::setClient(ResourceHandleClient* client) {
+ d->client_ = client;
+}
+
+void ResourceHandle::setDefersLoading(bool value) {
+ d->SetDefersLoading(value);
+}
+
+bool ResourceHandle::start(Frame* deprecated) {
+ return d->Start(NULL);
+}
+
+void ResourceHandle::clearAuthentication() {
+ // TODO(darin): do something here. it looks like the ResourceLoader calls
+ // this method when it is canceled. i have no idea why it does this.
+}
+
+void ResourceHandle::cancel() {
+ d->Cancel();
+}
+
+ResourceHandle::~ResourceHandle() {
+}
+
+PassRefPtr<SharedBuffer> ResourceHandle::bufferedData() {
+ return NULL;
+}
+
+/*static*/ bool ResourceHandle::loadsBlocked() {
+ return false; // this seems to be related to sync XMLHttpRequest...
+}
+
+/*static*/ bool ResourceHandle::supportsBufferedData() {
+ return false; // the loader will buffer manually if it needs to
+}
+
+/*static*/ void ResourceHandle::loadResourceSynchronously(
+ const ResourceRequest& request, ResourceError& error,
+ ResourceResponse& response, Vector<char>& data, Frame*) {
+
+ RefPtr<ResourceHandle> handle =
+ new ResourceHandle(request, NULL, false, false, false);
+
+ ResourceLoaderBridge::SyncLoadResponse sync_load_response;
+ if (!handle->d->Start(&sync_load_response)) {
+ // TODO(darin): what should the error code really be?
+ error = ResourceError(net::kErrorDomain,
+ net::ERR_FAILED,
+ request.url().string(),
+ String() /* localized description */);
+ return;
+ }
+
+ KURL kurl = webkit_glue::GURLToKURL(sync_load_response.url);
+
+ // TODO(tc): If there's an error during the load, we don't set the response.
+ // For file loads, we may want to include a more descriptive status code or
+ // status text.
+ const URLRequestStatus::Status& status = sync_load_response.status.status();
+ if (status != URLRequestStatus::SUCCESS &&
+ status != URLRequestStatus::HANDLED_EXTERNALLY) {
+ error = ResourceError(net::kErrorDomain,
+ sync_load_response.status.os_error(),
+ kurl.string(),
+ String() /* localized description */);
+ return;
+ }
+
+ response = MakeResourceResponse(kurl, sync_load_response);
+
+ data.clear();
+ data.append(sync_load_response.data.data(),
+ sync_load_response.data.size());
+}
+
+// static
+bool ResourceHandle::willLoadFromCache(ResourceRequest& request) {
+ //
+ // This method is used to determine if a POST request can be repeated from
+ // cache, but you cannot really know until you actually try to read from the
+ // cache. Even if we checked now, something else could come along and wipe
+ // out the cache entry by the time we fetch it.
+ //
+ // So, we always say yes here, which allows us to generate an ERR_CACHE_MISS
+ // if the request cannot be serviced from cache. We force the 'DontLoad'
+ // cache policy at this point to ensure that we never hit the network for
+ // this request.
+ //
+ DCHECK(request.httpMethod() == "POST");
+ request.setCachePolicy(ReturnCacheDataDontLoad);
+ return true;
+}
+
+} // namespace WebCore
diff --git a/webkit/glue/resource_loader_bridge.h b/webkit/glue/resource_loader_bridge.h
new file mode 100644
index 0000000..ba2fd0c
--- /dev/null
+++ b/webkit/glue/resource_loader_bridge.h
@@ -0,0 +1,225 @@
+// 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.
+//
+// The intent of this file is to provide a type-neutral abstraction between
+// Chrome and WebKit for resource loading. This pure-virtual interface is
+// implemented by the embedder, which also provides a factory method Create
+// to instantiate this object.
+//
+// One of these objects will be created by WebKit for each request. WebKit
+// will own the pointer to the bridge, and will delete it when the request is
+// no longer needed.
+//
+// In turn, the bridge's owner on the WebKit end will implement the Peer
+// interface, which we will use to communicate notifications back.
+
+#ifndef RESOURCE_LOADER_BRIDGE_H__
+#define RESOURCE_LOADER_BRIDGE_H__
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/ref_counted.h"
+#include "base/time.h"
+#include "googleurl/src/gurl.h"
+#include "net/http/http_response_headers.h"
+#include "net/url_request/url_request_status.h"
+#include "webkit/glue/resource_type.h"
+
+class WebFrame;
+
+namespace webkit_glue {
+
+class ResourceLoaderBridge {
+ public:
+ struct ResponseInfo {
+ // The time at which the request was made that resulted in this response.
+ // For cached responses, this time could be "far" in the past.
+ Time request_time;
+
+ // The time at which the response headers were received. For cached
+ // responses, this time could be "far" in the past.
+ Time response_time;
+
+ // The response headers or NULL if the URL type does not support headers.
+ scoped_refptr<net::HttpResponseHeaders> headers;
+
+ // The mime type of the response. This may be a derived value.
+ std::string mime_type;
+
+ // The character encoding of the response or none if not applicable to the
+ // response's mime type. This may be a derived value.
+ std::string charset;
+
+ // An opaque string carrying security information pertaining to this
+ // response. This may include information about the SSL connection used.
+ std::string security_info;
+
+ // Content length if available. -1 if not available
+ int64 content_length;
+ };
+
+ // generated by the bridge. This is implemented by our custom resource loader
+ // within webkit. The Peer and it's bridge should have identical lifetimes
+ // as they represent each end of a communication channel.
+ //
+ // These callbacks mirror URLRequest::Delegate and the order and conditions
+ // in which they will be called are identical. See url_request.h for more
+ // information.
+ class Peer {
+ public:
+ // Called as upload progress is made.
+ // note: only for requests with LOAD_ENABLE_UPLOAD_PROGRESS set
+ virtual void OnUploadProgress(uint64 position, uint64 size) {};
+
+ // Called when a redirect occurs.
+ virtual void OnReceivedRedirect(const GURL& new_url) = 0;
+
+ // Called when response headers are available (after all redirects have
+ // been followed).
+ virtual void OnReceivedResponse(const ResponseInfo& info) = 0;
+
+ // Called when a chunk of response data is available. This method may
+ // be called multiple times or not at all if an error occurs.
+ virtual void OnReceivedData(const char* data, int len) = 0;
+
+ // Called when the response is complete. This method signals completion of
+ // the resource load.
+ virtual void OnCompletedRequest(const URLRequestStatus& status) = 0;
+
+ // Returns the URL of the request, which allows us to display it in
+ // debugging situations.
+ virtual std::string GetURLForDebugging() = 0;
+ };
+
+ // use Create() for construction, but anybody can delete at any time,
+ // INCLUDING during processing of callbacks.
+ virtual ~ResourceLoaderBridge() {}
+
+ // Call this method to make a new instance. The method name is a HTTP-style
+ // method name (e.g., "GET" or "POST"). The URL should be an absolute URL
+ // encoded in ASCII per the rules of RFC-2396. The referrer parameter is
+ // optional (may be NULL) and is a URL with similar constraints in how it
+ // must be encoded.
+ //
+ // For HTTP(S) POST requests, the AppendDataToUpload and AppendFileToUpload
+ // methods may be called to construct the body of the request.
+ //
+ // For HTTP(S) requests, the headers parameter can be a \r\n-delimited and
+ // \r\n-terminated list of MIME headers. They should be ASCII-encoded using
+ // the standard MIME header encoding rules. The headers parameter can also
+ // be null if no extra request headers need to be set.
+ //
+ // The WebFrame passed to this function provides context about the origin
+ // of the resource request.
+ //
+ // policy_url is the URL of the document in the top-level window, which may be
+ // checked by the third-party cookie blocking policy.
+ //
+ // load_flags is composed of the values defined in url_request_load_flags.h
+ //
+ // mixed_content when true indicates that the resource associated with this
+ // request is over HTTP when the main page was loaded over HTTPS.
+ //
+ // request_type indicates if the current request is the main frame load, a
+ // sub-frame load, or a sub objects load.
+ static ResourceLoaderBridge* Create(WebFrame* frame,
+ 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 request_type,
+ bool mixed_content);
+
+ // Call this method before calling Start() to append a chunk of binary data
+ // to the request body. May only be used with HTTP(S) POST requests.
+ virtual void AppendDataToUpload(const char* data, int data_len) = 0;
+
+ // Call this method before calling Start() to append the contents of a file
+ // to the request body. May only be used with HTTP(S) POST requests.
+ void AppendFileToUpload(const std::wstring& file_path) {
+ AppendFileRangeToUpload(file_path, 0, kuint64max);
+ }
+
+ // Call this method before calling Start() to append the contents of a file
+ // to the request body. May only be used with HTTP(S) POST requests.
+ virtual void AppendFileRangeToUpload(const std::wstring& file_path,
+ uint64 offset, uint64 length) = 0;
+
+ // Call this method to initiate the request. If this method succeeds, then
+ // the peer's methods will be called asynchronously to report various events.
+ virtual bool Start(Peer* peer) = 0;
+
+ // Call this method to cancel a request that is in progress. This method
+ // causes the request to immediately transition into the 'done' state. The
+ // OnCompletedRequest method will be called asynchronously; this assumes
+ // the peer is still valid.
+ virtual void Cancel() = 0;
+
+ // Call this method to suspend or resume a load that is in progress. This
+ // method may only be called after a successful call to the Start method.
+ virtual void SetDefersLoading(bool value) = 0;
+
+ // See the SyncLoad method declared below. (The name of this struct is not
+ // suffixed with "Info" because it also contains the response data.)
+ struct SyncLoadResponse : ResponseInfo {
+ // The response status.
+ URLRequestStatus status;
+
+ // The final URL of the response. This may differ from the request URL in
+ // the case of a server redirect.
+ GURL url;
+
+ // The response data.
+ std::string data;
+ };
+
+ // Call this method to load the resource synchronously (i.e., in one shot).
+ // This is an alternative to the Start method. Be warned that this method
+ // will block the calling thread until the resource is fully downloaded or an
+ // error occurs. It could block the calling thread for a long time, so only
+ // use this if you really need it! There is also no way for the caller to
+ // interrupt this method. Errors are reported via the status field of the
+ // response parameter.
+ virtual void SyncLoad(SyncLoadResponse* response) = 0;
+
+ protected:
+ // construction must go through Create()
+ ResourceLoaderBridge() {}
+
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(ResourceLoaderBridge);
+};
+
+} // namespace webkit_glue
+
+#endif // RESOURCE_LOADER_BRIDGE__
diff --git a/webkit/glue/resource_type.h b/webkit/glue/resource_type.h
new file mode 100644
index 0000000..d426bcf
--- /dev/null
+++ b/webkit/glue/resource_type.h
@@ -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.
+
+#ifndef WEBKIT_GLUE_RESOURCE_TYPE_H__
+#define WEBKIT_GLUE_RESOURCE_TYPE_H__
+
+
+class ResourceType {
+ public:
+ enum Type {
+ MAIN_FRAME = 0, // top level page
+ SUB_FRAME, // frame or iframe
+ SUB_RESOURCE, // a resource like images, js, css
+ OBJECT, // an object (or embed) tag for a plugin,
+ // or a resource that a plugin requested.
+ };
+
+ static bool ValidType(int32 type) {
+ return type >= MAIN_FRAME && type <= OBJECT;
+ }
+
+ static Type FromInt(int32 type) {
+ return static_cast<Type>(type);
+ }
+
+ static bool IsFrame(ResourceType::Type type) {
+ return type == MAIN_FRAME || type == SUB_FRAME;
+ }
+
+ private:
+ // Don't instantiate this class.
+ ResourceType();
+ ~ResourceType();
+};
+#endif // WEBKIT_GLUE_RESOURCE_TYPE_H__
diff --git a/webkit/glue/resources/README.txt b/webkit/glue/resources/README.txt
new file mode 100644
index 0000000..678a136
--- /dev/null
+++ b/webkit/glue/resources/README.txt
@@ -0,0 +1,50 @@
+The following files in this directory are copied from the Mozilla source tree,
+where they are licensed under the MPL/GPL/LGPL. While binary files do not
+contain a license block, I have pasted the relevant Mozilla license block at
+the bottom of this file.
+
+aliasb.cur
+broken-image.gif
+cell.cur
+col_resize.cur
+copy.cur
+grab.cur
+grabbing.cur
+row_resize.cur
+vertical_text.cur
+zoom_in.cur
+zoom_out.cur
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
diff --git a/webkit/glue/resources/aliasb.cur b/webkit/glue/resources/aliasb.cur
new file mode 100644
index 0000000..8d9ac94
--- /dev/null
+++ b/webkit/glue/resources/aliasb.cur
Binary files differ
diff --git a/webkit/glue/resources/broken-image.gif b/webkit/glue/resources/broken-image.gif
new file mode 100644
index 0000000..735e10c
--- /dev/null
+++ b/webkit/glue/resources/broken-image.gif
Binary files differ
diff --git a/webkit/glue/resources/cell.cur b/webkit/glue/resources/cell.cur
new file mode 100644
index 0000000..decfbdc
--- /dev/null
+++ b/webkit/glue/resources/cell.cur
Binary files differ
diff --git a/webkit/glue/resources/col_resize.cur b/webkit/glue/resources/col_resize.cur
new file mode 100644
index 0000000..8f7f675
--- /dev/null
+++ b/webkit/glue/resources/col_resize.cur
Binary files differ
diff --git a/webkit/glue/resources/copy.cur b/webkit/glue/resources/copy.cur
new file mode 100644
index 0000000..87f1519c
--- /dev/null
+++ b/webkit/glue/resources/copy.cur
Binary files differ
diff --git a/webkit/glue/resources/dash.png b/webkit/glue/resources/dash.png
new file mode 100644
index 0000000..1747604
--- /dev/null
+++ b/webkit/glue/resources/dash.png
Binary files differ
diff --git a/webkit/glue/resources/feed.html b/webkit/glue/resources/feed.html
new file mode 100644
index 0000000..c6a5747d
--- /dev/null
+++ b/webkit/glue/resources/feed.html
@@ -0,0 +1,18 @@
+<html>
+ <head>
+ <title>Feed Content</title>
+ <style type='text/css'>
+ body {
+ margin: 5ex 7ex;
+ font-family: sans-serif;
+ }
+ </style>
+ </head>
+ <body>
+ <p>This is a <a href="http://en.wikipedia.org/wiki/Web_feed">feed</a> that
+ can be displayed in a feed reader.</p>
+
+ <p><a href="http://www.google.com/ig/add?feedurl={{URL}}">Subscribe via
+ Google</a>.</p>
+ </body>
+</html>
diff --git a/webkit/glue/resources/row_resize.cur b/webkit/glue/resources/row_resize.cur
new file mode 100644
index 0000000..a7369d3
--- /dev/null
+++ b/webkit/glue/resources/row_resize.cur
Binary files differ
diff --git a/webkit/glue/resources/vertical_text.cur b/webkit/glue/resources/vertical_text.cur
new file mode 100644
index 0000000..3de04eb
--- /dev/null
+++ b/webkit/glue/resources/vertical_text.cur
Binary files differ
diff --git a/webkit/glue/resources/webkit_strings_ar.xtb b/webkit/glue/resources/webkit_strings_ar.xtb
new file mode 100644
index 0000000..f348455
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_ar.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ar">
+<translation id="7658239707568436148">إلغاء</translation>
+<translation id="3789841737615482174">تثبيت</translation>
+<translation id="8141602879876242471">هذا فهرس يمكن البحث فيه. أدخل كلمات البحث الرئيسية:</translation>
+<translation id="2653659639078652383">تقديم</translation>
+<translation id="5939518447894949180">إعادة تعيين</translation>
+<translation id="7364796246159120393">اختيار ملف</translation>
+<translation id="2548326553472216322">لا توجد عمليات بحث جرت مؤخرًا</translation>
+<translation id="6663448176199120256">عمليات البحث الأخيرة</translation>
+<translation id="1235745349614807883">مسح عمليات البحث الأخيرة</translation>
+<translation id="6807599807928161586">منطقة الويب</translation>
+<translation id="3040011195152428237">رابط</translation>
+<translation id="5048533449481078685">محدِد القائمة</translation>
+<translation id="8244226242650769279">مخطط صورة</translation>
+<translation id="8597182159515967513">العنوان</translation>
+<translation id="5944544982112848342">2048 (درجة عالية)</translation>
+<translation id="2846343701378493991">1024 (درجة متوسطة)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436">لم يتم تثبيت المكون الإضافي <ph name="PLUGIN"/></translation>
+<translation id="4838490908464673667">لم يتم تثبيت المكون الإضافي المطلوب</translation>
+<translation id="3600343118165084788">انقر هنا لتنزيل مكون إضافي</translation>
+<translation id="8281246460978372009">بعد تثبيت المكون الإضافي، انقر هنا للتحديث</translation>
+<translation id="679352192834563463">لا يتوفر أي مكون إضافي لعرض هذا المحتوى</translation>
+<translation id="8662565117025751661">جارٍ تنزيل مكون إضافي...</translation>
+<translation id="3771786644471114952">الحصول على مكون إضافي</translation>
+<translation id="1275511093094545429">يلزم توفر مكون <ph name="PLUGIN"/> الإضافي</translation>
+<translation id="3825324228893189080">يلزم توفر مكون إضافي آخر</translation>
+<translation id="4420062214988137980">فشل تثبيت المكون الإضافي</translation>
+<translation id="4317653869502688143">يُرجى تأكيد رغبتك في تثبيت المكون الإضافي <ph name="PLUGIN"/>. يجب تثبيت المكونات الإضافية التي تثق فيها فقط.</translation>
+<translation id="3926627843712816530">يُرجى تأكيد رغبتك في تثبيت هذا المكون الإضافي. يجب تثبيت المكونات الإضافية التي تثق فيها فقط.</translation>
+<translation id="1383141426028388991">فشل تثبيت مكون إضافي من <ph name="URL"/></translation>
+<translation id="6845533974506654842">اضغط</translation>
+<translation id="1842960171412779397">تحديد</translation>
+<translation id="6119846243427417423">تنشيط</translation>
+<translation id="5476505524087279545">عدم تحديد</translation>
+<translation id="838869780401515933">تحديد</translation>
+<translation id="4202807286478387388">انتقال</translation>
+<translation id="795667975304826397">لم يتم اختيار أي ملف</translation>
+<translation id="8964020114565522021">سحب ملف إلى هنا</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_bg.xtb b/webkit/glue/resources/webkit_strings_bg.xtb
new file mode 100644
index 0000000..79558b7
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_bg.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="bg">
+<translation id="7658239707568436148">Отказ</translation>
+<translation id="3789841737615482174">Инсталиране</translation>
+<translation id="8141602879876242471">В този индекс може да се търси. Въведете ключови думи за търсене:</translation>
+<translation id="2653659639078652383">Изпращане</translation>
+<translation id="5939518447894949180">Повторно задаване</translation>
+<translation id="7364796246159120393">Избор на файл</translation>
+<translation id="2548326553472216322">Няма скорошни търсения</translation>
+<translation id="6663448176199120256">Скорошни търсения</translation>
+<translation id="1235745349614807883">Изчистване на скорошните търсения</translation>
+<translation id="6807599807928161586">уеб зона</translation>
+<translation id="3040011195152428237">връзка</translation>
+<translation id="5048533449481078685">списъчен показалец</translation>
+<translation id="8244226242650769279">карта с изображения</translation>
+<translation id="8597182159515967513">заглавие</translation>
+<translation id="5944544982112848342">2048 (висока степен на сложност)</translation>
+<translation id="2846343701378493991">1024 (средна степен на сложност)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436">Приставката за <ph name="PLUGIN"/> не е инсталирана</translation>
+<translation id="4838490908464673667">Необходимата приставка не е инсталирана</translation>
+<translation id="3600343118165084788">Кликнете тук, за да изтеглите приставката</translation>
+<translation id="8281246460978372009">След като инсталирате приставката, кликнете тук, за да опресните прозореца</translation>
+<translation id="679352192834563463">Няма приставка, с която може да се покаже това съдържание</translation>
+<translation id="8662565117025751661">Приставката се изтегля...</translation>
+<translation id="3771786644471114952">Изтегляне на приставката</translation>
+<translation id="1275511093094545429">Необходима е приставка за <ph name="PLUGIN"/></translation>
+<translation id="3825324228893189080">Изисква се допълнителна приставка</translation>
+<translation id="4420062214988137980">Инсталирането на приставката не бе успешно</translation>
+<translation id="4317653869502688143">Моля, потвърдете, че искате да инсталирате приставката за <ph name="PLUGIN"/>. Инсталирайте само тези приставки, които считате за надеждни.</translation>
+<translation id="3926627843712816530">Моля, потвърдете, че искате да инсталирате тази приставка. Инсталирайте само тези приставки, които считате за надеждни.</translation>
+<translation id="1383141426028388991">Инсталирането на приставката от <ph name="URL"/> не бе успешно</translation>
+<translation id="6845533974506654842">натискане</translation>
+<translation id="1842960171412779397">Избиране</translation>
+<translation id="6119846243427417423">активиране</translation>
+<translation id="5476505524087279545">премахване на отметката</translation>
+<translation id="838869780401515933">отмятане</translation>
+<translation id="4202807286478387388">преминаване</translation>
+<translation id="795667975304826397">Няма избран файл</translation>
+<translation id="8964020114565522021">Плъзнете файла тук</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_ca.xtb b/webkit/glue/resources/webkit_strings_ca.xtb
new file mode 100644
index 0000000..4b8a689
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_ca.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ca">
+<translation id="7658239707568436148">Cancel·la</translation>
+<translation id="3789841737615482174">Instal·la</translation>
+<translation id="8141602879876242471">És un índex on es poden realitzar cerques. Introdueix els termes de cerca:</translation>
+<translation id="2653659639078652383">Envia</translation>
+<translation id="5939518447894949180">Restablir</translation>
+<translation id="7364796246159120393">Selecciona el fitxer</translation>
+<translation id="2548326553472216322">No hi ha cerques recents</translation>
+<translation id="6663448176199120256">Cerques recents</translation>
+<translation id="1235745349614807883">Esborra les cerques recents</translation>
+<translation id="6807599807928161586">àrea web</translation>
+<translation id="3040011195152428237">enllaç</translation>
+<translation id="5048533449481078685">marcador de llistes</translation>
+<translation id="8244226242650769279">mapa d'imatges</translation>
+<translation id="8597182159515967513">Capçalera</translation>
+<translation id="5944544982112848342">2048 (Gran)</translation>
+<translation id="2846343701378493991">1024 (Mitjà)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436">El complement <ph name="PLUGIN"/> no està instal·lat</translation>
+<translation id="4838490908464673667">El complement necessari no està instal·lat</translation>
+<translation id="3600343118165084788">Fes clic aquí per baixar el complement</translation>
+<translation id="8281246460978372009">Després d'instal·lar el complement, fes clic aquí per actualitzar.</translation>
+<translation id="679352192834563463">No hi ha cap complement disponible per mostrar aquest contingut</translation>
+<translation id="8662565117025751661">S'està baixant el complement...</translation>
+<translation id="3771786644471114952">Obtén el complement</translation>
+<translation id="1275511093094545429">Es necessita el complement <ph name="PLUGIN"/></translation>
+<translation id="3825324228893189080">Es necessita un complement addicional</translation>
+<translation id="4420062214988137980">Error en la instal·lació del complement</translation>
+<translation id="4317653869502688143">Confirma que vols instal·lar el complement <ph name="PLUGIN"/>. Només hauries d'instal·lar complements fiables.</translation>
+<translation id="3926627843712816530">Confirma que vols instal·lar aquest complement. Només hauries d'instal·lar complements fiables.</translation>
+<translation id="1383141426028388991">Error en instal·lar el complement des de <ph name="URL"/></translation>
+<translation id="6845533974506654842">prem</translation>
+<translation id="1842960171412779397">selecciona</translation>
+<translation id="6119846243427417423">activa</translation>
+<translation id="5476505524087279545">desmarca</translation>
+<translation id="838869780401515933">marca</translation>
+<translation id="4202807286478387388">salta</translation>
+<translation id="795667975304826397">No heu seleccionat cap fitxer.</translation>
+<translation id="8964020114565522021">Arrossegueu el fitxer aquí.</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_cs.xtb b/webkit/glue/resources/webkit_strings_cs.xtb
new file mode 100644
index 0000000..92b2e91
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_cs.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="cs">
+<translation id="7658239707568436148">Zrušit</translation>
+<translation id="3789841737615482174">Instalovat</translation>
+<translation id="8141602879876242471">Toto je prohledávatelný index. Zadejte hledaná klíčová slova:</translation>
+<translation id="2653659639078652383">Odeslat</translation>
+<translation id="5939518447894949180">Resetovat</translation>
+<translation id="7364796246159120393">Vybrat soubor</translation>
+<translation id="2548326553472216322">Žádná nedávná vyhledávání</translation>
+<translation id="6663448176199120256">Nedávná vyhledávání</translation>
+<translation id="1235745349614807883">Smazat nedávná vyhledávání</translation>
+<translation id="6807599807928161586">oblast webu</translation>
+<translation id="3040011195152428237">odkaz</translation>
+<translation id="5048533449481078685">značka seznamu</translation>
+<translation id="8244226242650769279">obrázková mapa</translation>
+<translation id="8597182159515967513">záhlaví</translation>
+<translation id="5944544982112848342">2048 (vysoká kvalita)</translation>
+<translation id="2846343701378493991">1024 (Střední kvalita)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436">Není nainstalován plugin <ph name="PLUGIN"/></translation>
+<translation id="4838490908464673667">Požadovaný plugin není nainstalován</translation>
+<translation id="3600343118165084788">Pro stažení pluginu klikněte sem</translation>
+<translation id="8281246460978372009">Po instalaci pluginu klikněte sem pro obnovení</translation>
+<translation id="679352192834563463">Není k dispozici žádný plugin pro zobrazení tohoto obsahu</translation>
+<translation id="8662565117025751661">Probíhá stahování pluginu...</translation>
+<translation id="3771786644471114952">Získat plugin</translation>
+<translation id="1275511093094545429">Je potřeba plugin <ph name="PLUGIN"/></translation>
+<translation id="3825324228893189080">Je potřeba další plugin</translation>
+<translation id="4420062214988137980">Nepodařilo se nainstalovat plugin</translation>
+<translation id="4317653869502688143">Potvrďte prosím, že si přejete instalovat plugin <ph name="PLUGIN"/>. Měli byste instalovat pouze takové pluginy, kterým důvěřujete.</translation>
+<translation id="3926627843712816530">Potvrďte, prosím, že si přejete instalovat tento plugin. Měli byste instalovat pouze takové pluginy, kterým důvěřujete.</translation>
+<translation id="1383141426028388991">Nepodařilo se nainstalovat plugin z <ph name="URL"/></translation>
+<translation id="6845533974506654842">zmáčknout</translation>
+<translation id="1842960171412779397">zvolit</translation>
+<translation id="6119846243427417423">aktivovat</translation>
+<translation id="5476505524087279545">odstranit zaškrtnutí</translation>
+<translation id="838869780401515933">zaškrtnout</translation>
+<translation id="4202807286478387388">přejít</translation>
+<translation id="795667975304826397">Nebyl zvolen žádný soubor</translation>
+<translation id="8964020114565522021">Přetáhnout soubor sem</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_da.xtb b/webkit/glue/resources/webkit_strings_da.xtb
new file mode 100644
index 0000000..30f2494
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_da.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="da">
+<translation id="7658239707568436148">Annuller</translation>
+<translation id="3789841737615482174">Installer</translation>
+<translation id="8141602879876242471">Der kan søges i dette indeks. Indtast søge-nøgleord:</translation>
+<translation id="2653659639078652383">Indsend</translation>
+<translation id="5939518447894949180">Nulstil</translation>
+<translation id="7364796246159120393">Vælg fil</translation>
+<translation id="2548326553472216322">Ingen nylige søgninger</translation>
+<translation id="6663448176199120256">Nylige søgninger</translation>
+<translation id="1235745349614807883">Slet nylige søgninger</translation>
+<translation id="6807599807928161586">webområde</translation>
+<translation id="3040011195152428237">link</translation>
+<translation id="5048533449481078685">listemarkering</translation>
+<translation id="8244226242650769279">billedekort</translation>
+<translation id="8597182159515967513">overskrift</translation>
+<translation id="5944544982112848342">2048 (Høj klasse)</translation>
+<translation id="2846343701378493991">1024 (Mellemklasse)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436"><ph name="PLUGIN"/> plugin er ikke installeret</translation>
+<translation id="4838490908464673667">Det krævede plugin er ikke installeret</translation>
+<translation id="3600343118165084788">Klik her for at downloade plugin</translation>
+<translation id="8281246460978372009">Når du har installeret plugin'et, skal du klikke her for at opdatere</translation>
+<translation id="679352192834563463">Intet tilgængeligt plugin kan vise dette indhold</translation>
+<translation id="8662565117025751661">Downloader plugin ...</translation>
+<translation id="3771786644471114952">Hent plugin</translation>
+<translation id="1275511093094545429"><ph name="PLUGIN"/> Plugin påkrævet</translation>
+<translation id="3825324228893189080">Ekstra plugin påkrævet</translation>
+<translation id="4420062214988137980">Installation af plugin mislykkedes</translation>
+<translation id="4317653869502688143">Bekræft venligst, at du ønsker at installere plugin'et <ph name="PLUGIN"/>. Du bør udelukkende installere plugins, som du stoler på.</translation>
+<translation id="3926627843712816530">Bekræft venligst, at du gerne vil installere dette plugin. Du bør udelukkende installere plugins, som du stoler på.</translation>
+<translation id="1383141426028388991">Mislykket installation af plugin fra <ph name="URL"/></translation>
+<translation id="6845533974506654842">tryk</translation>
+<translation id="1842960171412779397">vælg</translation>
+<translation id="6119846243427417423">aktiver</translation>
+<translation id="5476505524087279545">fjern markering</translation>
+<translation id="838869780401515933">marker</translation>
+<translation id="4202807286478387388">hop</translation>
+<translation id="795667975304826397">Der er ikke valgt nogen fil</translation>
+<translation id="8964020114565522021">Træk filer hertil</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_de.xtb b/webkit/glue/resources/webkit_strings_de.xtb
new file mode 100644
index 0000000..48a5f68
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_de.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="de">
+<translation id="7658239707568436148">Abbrechen</translation>
+<translation id="3789841737615482174">Installieren</translation>
+<translation id="8141602879876242471">Dieser Index kann durchsucht werden. Geben Sie Suchbegriffe ein:</translation>
+<translation id="2653659639078652383">Senden</translation>
+<translation id="5939518447894949180">Zurücksetzen</translation>
+<translation id="7364796246159120393">Datei auswählen</translation>
+<translation id="2548326553472216322">Keine vor kurzem durchgeführte Suchanfragen</translation>
+<translation id="6663448176199120256">Vor kurzem durchgeführte Suchanfragen</translation>
+<translation id="1235745349614807883">Vor kurzem durchgeführte Suchanfragen löschen</translation>
+<translation id="6807599807928161586">Webbereich</translation>
+<translation id="3040011195152428237">Link</translation>
+<translation id="5048533449481078685">Listenmarkierung</translation>
+<translation id="8244226242650769279">Imagemap</translation>
+<translation id="8597182159515967513">Kopfzeile</translation>
+<translation id="5944544982112848342">2048 (High Grade)</translation>
+<translation id="2846343701378493991">1024 (mittlere Stufe)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436">Plug-in <ph name="PLUGIN"/> nicht installiert</translation>
+<translation id="4838490908464673667">Das erforderliche Plug-in ist nicht installiert</translation>
+<translation id="3600343118165084788">Klicken Sie hier, um das Plug-in herunterzuladen.</translation>
+<translation id="8281246460978372009">Klicken Sie nach der Installation des Plug-ins hier, um eine Aktualisierung durchzuführen.</translation>
+<translation id="679352192834563463">Kein Plug-in zum Anzeigen dieses Contents verfügbar</translation>
+<translation id="8662565117025751661">Plug-in wird heruntergeladen...</translation>
+<translation id="3771786644471114952">Plug-in abrufen</translation>
+<translation id="1275511093094545429">Plug-in <ph name="PLUGIN"/> erforderlich</translation>
+<translation id="3825324228893189080">Zusätzliches Plug-in erforderlich</translation>
+<translation id="4420062214988137980">Plug-in-Installation fehlgeschlagen</translation>
+<translation id="4317653869502688143">Bestätigen Sie, dass Sie das Plug-in <ph name="PLUGIN"/> installieren möchten. Sie sollten nur vertrauenswürdige Plug-ins installieren.</translation>
+<translation id="3926627843712816530">Bestätigen Sie, dass Sie dieses Plug-in installieren möchten. Sie sollten nur vertrauenswürdige Plug-ins installieren.</translation>
+<translation id="1383141426028388991">Installieren des Plug-ins von <ph name="URL"/> fehlgeschlagen</translation>
+<translation id="6845533974506654842">klicken</translation>
+<translation id="1842960171412779397">auswählen</translation>
+<translation id="6119846243427417423">aktivieren</translation>
+<translation id="5476505524087279545">Auswahl aufheben</translation>
+<translation id="838869780401515933">auswählen</translation>
+<translation id="4202807286478387388">springen</translation>
+<translation id="795667975304826397">Keine Datei ausgewählt</translation>
+<translation id="8964020114565522021">Datei hier ablegen</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_el.xtb b/webkit/glue/resources/webkit_strings_el.xtb
new file mode 100644
index 0000000..aca3a3c
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_el.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="el">
+<translation id="7658239707568436148">Ακύρωση</translation>
+<translation id="3789841737615482174">Εγκατάσταση</translation>
+<translation id="8141602879876242471">Πρόκειται για ευρετήριο με δυνατότητα αναζήτησης. Πληκτρολογήστε λέξεις-κλειδιά αναζήτησης:</translation>
+<translation id="2653659639078652383">Υποβολή</translation>
+<translation id="5939518447894949180">Επαναφορά</translation>
+<translation id="7364796246159120393">Επιλογή αρχείου</translation>
+<translation id="2548326553472216322">Δεν υπάρχουν πρόσφατες αναζητήσεις</translation>
+<translation id="6663448176199120256">Πρόσφατες αναζητήσεις</translation>
+<translation id="1235745349614807883">Εκκαθάριση πρόσφατων αναζητήσεων</translation>
+<translation id="6807599807928161586">περιοχή ιστού</translation>
+<translation id="3040011195152428237">σύνδεσμος</translation>
+<translation id="5048533449481078685">δείκτης λίστας</translation>
+<translation id="8244226242650769279">χάρτης εικόνας</translation>
+<translation id="8597182159515967513">επικεφαλίδα</translation>
+<translation id="5944544982112848342">2048 (Υψηλός βαθμός)</translation>
+<translation id="2846343701378493991">1024 (Μέτριος βαθμός)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436">Η προσθήκη <ph name="PLUGIN"/> δεν έχει εγκατασταθεί</translation>
+<translation id="4838490908464673667">Η απαιτούμενη προσθήκη δεν έχει εγκατασταθεί</translation>
+<translation id="3600343118165084788">Κάντε κλικ εδώ για να κατεβάσετε την προσθήκη</translation>
+<translation id="8281246460978372009">Μετά την εγκατάσταση της προσθήκης, κάντε κλικ εδώ για ανανέωση</translation>
+<translation id="679352192834563463">Δεν υπάρχει διαθέσιμη προσθήκη για την εμφάνιση του περιεχομένου</translation>
+<translation id="8662565117025751661">Λήψη προσθήκης...</translation>
+<translation id="3771786644471114952">Λήψη προσθήκης</translation>
+<translation id="1275511093094545429">Χρειάζεται η προσθήκη <ph name="PLUGIN"/></translation>
+<translation id="3825324228893189080">Απαιτείται επιπλέον προσθήκη</translation>
+<translation id="4420062214988137980">Η εγκατάσταση της προσθήκης απέτυχε</translation>
+<translation id="4317653869502688143">Επιβεβαιώστε ότι θέλετε να εγκαταστήσετε την προσθήκη <ph name="PLUGIN"/>. Πρέπει να εγκαθιστάτε μόνο προσθήκες που θεωρείτε αξιόπιστες.</translation>
+<translation id="3926627843712816530">Επιβεβαιώστε ότι θέλετε να εγκαταστήσετε αυτή την προσθήκη. Πρέπει να εγκαθιστάτε μόνο προσθήκες που θεωρείτε αξιόπιστες.</translation>
+<translation id="1383141426028388991">Η εγκατάσταση της προσθήκης από τη διεύθυνση <ph name="URL"/> απέτυχε</translation>
+<translation id="6845533974506654842">πατήστε</translation>
+<translation id="1842960171412779397">επιλογή</translation>
+<translation id="6119846243427417423">ενεργοποίηση</translation>
+<translation id="5476505524087279545">απενεργοποίηση</translation>
+<translation id="838869780401515933">ενεργοποίηση</translation>
+<translation id="4202807286478387388">μεταπήδηση</translation>
+<translation id="795667975304826397">Δεν έχει επιλεγεί κανένα αρχείο</translation>
+<translation id="8964020114565522021">Σύρετε το αρχείο εδώ</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_en-GB.xtb b/webkit/glue/resources/webkit_strings_en-GB.xtb
new file mode 100644
index 0000000..c06499c
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_en-GB.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="en-GB">
+<translation id="7658239707568436148">Cancel</translation>
+<translation id="3789841737615482174">Install</translation>
+<translation id="8141602879876242471">This is a searchable index. Enter search keywords:</translation>
+<translation id="2653659639078652383">Submit</translation>
+<translation id="5939518447894949180">Reset</translation>
+<translation id="7364796246159120393">Choose File</translation>
+<translation id="2548326553472216322">No recent searches</translation>
+<translation id="6663448176199120256">Recent Searches</translation>
+<translation id="1235745349614807883">Clear Recent Searches</translation>
+<translation id="6807599807928161586">web area</translation>
+<translation id="3040011195152428237">link</translation>
+<translation id="5048533449481078685">list marker</translation>
+<translation id="8244226242650769279">image map</translation>
+<translation id="8597182159515967513">heading</translation>
+<translation id="5944544982112848342">2048 (High Grade)</translation>
+<translation id="2846343701378493991">1024 (Medium Grade)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436"><ph name="PLUGIN"/> plug-in is not installed</translation>
+<translation id="4838490908464673667">The required plug-in is not installed</translation>
+<translation id="3600343118165084788">Click here to download plug-in</translation>
+<translation id="8281246460978372009">After installing the plug-in, click here to refresh</translation>
+<translation id="679352192834563463">No plug-in available to display this content</translation>
+<translation id="8662565117025751661">Downloading plug-in...</translation>
+<translation id="3771786644471114952">Get Plug-in</translation>
+<translation id="1275511093094545429"><ph name="PLUGIN"/> plug-in needed</translation>
+<translation id="3825324228893189080">Additional plug-in needed</translation>
+<translation id="4420062214988137980">Plug-in installation failed</translation>
+<translation id="4317653869502688143">Please confirm that you would like to install the <ph name="PLUGIN"/> plug-in. You should only install plug-ins that you trust.</translation>
+<translation id="3926627843712816530">Please confirm that you would like to install this plug-in. You should only install plug-ins that you trust.</translation>
+<translation id="1383141426028388991">Failed to install plug-in from <ph name="URL"/></translation>
+<translation id="6845533974506654842">press</translation>
+<translation id="1842960171412779397">select</translation>
+<translation id="6119846243427417423">activate</translation>
+<translation id="5476505524087279545">untick</translation>
+<translation id="838869780401515933">tick</translation>
+<translation id="4202807286478387388">jump</translation>
+<translation id="795667975304826397">No file chosen</translation>
+<translation id="8964020114565522021">Drag file here</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_es-419.xtb b/webkit/glue/resources/webkit_strings_es-419.xtb
new file mode 100644
index 0000000..c6f1f60
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_es-419.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="es-419">
+<translation id="7658239707568436148">Cancelar</translation>
+<translation id="3789841737615482174">Instalar</translation>
+<translation id="8141602879876242471">Se trata de un índice que admite búsquedas. Escribe las palabras clave de búsqueda:</translation>
+<translation id="2653659639078652383">Enviar</translation>
+<translation id="5939518447894949180">Restablecer</translation>
+<translation id="7364796246159120393">Seleccionar archivo</translation>
+<translation id="2548326553472216322">No hay búsquedas recientes</translation>
+<translation id="6663448176199120256">Búsquedas recientes</translation>
+<translation id="1235745349614807883">Eliminar búsquedas recientes</translation>
+<translation id="6807599807928161586">área web</translation>
+<translation id="3040011195152428237">enlace</translation>
+<translation id="5048533449481078685">marcador de listas</translation>
+<translation id="8244226242650769279">mapa de imágenes</translation>
+<translation id="8597182159515967513">cabecera</translation>
+<translation id="5944544982112848342">2048 (Grado elevado)</translation>
+<translation id="2846343701378493991">1024 (Mediano)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436">El plug-in <ph name="PLUGIN"/> no está instalado</translation>
+<translation id="4838490908464673667">El plug-in necesario no está instalado.</translation>
+<translation id="3600343118165084788">Haz clic aquí para descargar el plug-in.</translation>
+<translation id="8281246460978372009">Tras instalar el complemento, haz clic aquí para actualizar.</translation>
+<translation id="679352192834563463">No hay ningún plug-in disponible para mostrar este contenido</translation>
+<translation id="8662565117025751661">Descargando plug-in...</translation>
+<translation id="3771786644471114952">Obtener plug-in</translation>
+<translation id="1275511093094545429">Se requiere el plug-in <ph name="PLUGIN"/></translation>
+<translation id="3825324228893189080">Se necesita un plug-in adicional</translation>
+<translation id="4420062214988137980">Error en la instalación del plug-in</translation>
+<translation id="4317653869502688143">Confirma que deseas instalar el plug-in <ph name="PLUGIN"/>. Solo debes instalar plug-in fiables.</translation>
+<translation id="3926627843712816530">Confirma que deseas instalar este plug-in. Solo debes instalar plug-in fiables.</translation>
+<translation id="1383141426028388991">Error al instalar el plug-in desde <ph name="URL"/></translation>
+<translation id="6845533974506654842">hacer clic</translation>
+<translation id="1842960171412779397">seleccionar</translation>
+<translation id="6119846243427417423">activar</translation>
+<translation id="5476505524087279545">desmarcar</translation>
+<translation id="838869780401515933">marcar</translation>
+<translation id="4202807286478387388">saltar</translation>
+<translation id="795667975304826397">No se eligió ningún archivo</translation>
+<translation id="8964020114565522021">Arrastre el archivo hasta aquí</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_es.xtb b/webkit/glue/resources/webkit_strings_es.xtb
new file mode 100644
index 0000000..39bc5f0
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_es.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="es">
+<translation id="7658239707568436148">Cancelar</translation>
+<translation id="3789841737615482174">Instalar</translation>
+<translation id="8141602879876242471">Se trata de un índice que admite búsquedas. Introduce las palabras clave de búsqueda:</translation>
+<translation id="2653659639078652383">Enviar</translation>
+<translation id="5939518447894949180">Restablecer</translation>
+<translation id="7364796246159120393">Seleccionar archivo</translation>
+<translation id="2548326553472216322">No hay búsquedas recientes</translation>
+<translation id="6663448176199120256">Búsquedas recientes</translation>
+<translation id="1235745349614807883">Eliminar búsquedas recientes</translation>
+<translation id="6807599807928161586">área web</translation>
+<translation id="3040011195152428237">enlace</translation>
+<translation id="5048533449481078685">marcador de listas</translation>
+<translation id="8244226242650769279">mapa de imágenes</translation>
+<translation id="8597182159515967513">cabecera</translation>
+<translation id="5944544982112848342">2048 (Grado elevado)</translation>
+<translation id="2846343701378493991">1024 (Mediano)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436">El plug-in <ph name="PLUGIN"/> no está instalado</translation>
+<translation id="4838490908464673667">El plug-in necesario no está instalado.</translation>
+<translation id="3600343118165084788">Haz clic aquí para descargar el plug-in.</translation>
+<translation id="8281246460978372009">Tras instalar el complemento, haz clic aquí para actualizar.</translation>
+<translation id="679352192834563463">No hay ningún plug-in disponible para mostrar este contenido</translation>
+<translation id="8662565117025751661">Descargando plug-in...</translation>
+<translation id="3771786644471114952">Obtener plug-in</translation>
+<translation id="1275511093094545429">Se requiere el plug-in <ph name="PLUGIN"/></translation>
+<translation id="3825324228893189080">Se necesita un plug-in adicional</translation>
+<translation id="4420062214988137980">Error en la instalación del plug-in</translation>
+<translation id="4317653869502688143">Confirma que deseas instalar el plug-in <ph name="PLUGIN"/>. Solo debes instalar plug-in fiables.</translation>
+<translation id="3926627843712816530">Confirma que deseas instalar este plug-in. Solo debes instalar plug-in fiables.</translation>
+<translation id="1383141426028388991">Error al instalar el plug-in desde <ph name="URL"/></translation>
+<translation id="6845533974506654842">pulsar</translation>
+<translation id="1842960171412779397">seleccionar</translation>
+<translation id="6119846243427417423">activar</translation>
+<translation id="5476505524087279545">desmarcar</translation>
+<translation id="838869780401515933">marcar</translation>
+<translation id="4202807286478387388">saltar</translation>
+<translation id="795667975304826397">No se ha seleccionado ningun archivo</translation>
+<translation id="8964020114565522021">Arrastrar archivo hasta aquí</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_et.xtb b/webkit/glue/resources/webkit_strings_et.xtb
new file mode 100644
index 0000000..4b4c10e
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_et.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="et">
+<translation id="7658239707568436148">Loobu</translation>
+<translation id="3789841737615482174">Installi</translation>
+<translation id="8141602879876242471">See on otsitav indeks. Sisestage otsingu jaoks märksõnad:</translation>
+<translation id="2653659639078652383">Esita</translation>
+<translation id="5939518447894949180">Lähtesta</translation>
+<translation id="7364796246159120393">Vali fail</translation>
+<translation id="2548326553472216322">Pole viimaseid otsingud</translation>
+<translation id="6663448176199120256">Viimased otsingud</translation>
+<translation id="1235745349614807883">Kustuta viimased otsingud</translation>
+<translation id="6807599807928161586">veebiala</translation>
+<translation id="3040011195152428237">link</translation>
+<translation id="5048533449481078685">loendilooja</translation>
+<translation id="8244226242650769279">hüperpilt</translation>
+<translation id="8597182159515967513">pealkiri</translation>
+<translation id="5944544982112848342">2048 (kõrge)</translation>
+<translation id="2846343701378493991">1024 (keskmine)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436"><ph name="PLUGIN"/> lisandmoodulit ei installita</translation>
+<translation id="4838490908464673667">Nõutav lisandmoodul pole installitud</translation>
+<translation id="3600343118165084788">Lisandmooduli allalaadimiseks klõpsake siia.</translation>
+<translation id="8281246460978372009">Pärast lisandmooduli installimist klõpsake värskendamiseks siia</translation>
+<translation id="679352192834563463">Selle sisu kuvamiseks pole saadaval lisandmoodulit</translation>
+<translation id="8662565117025751661">Lisandmooduli allalaadimine...</translation>
+<translation id="3771786644471114952">Hangi lisandmoodul</translation>
+<translation id="1275511093094545429"><ph name="PLUGIN"/> vajalik lisandmoodul</translation>
+<translation id="3825324228893189080">Vajalik täiendav lisandmoodul</translation>
+<translation id="4420062214988137980">Lisandmooduli install ebaõnnestus</translation>
+<translation id="4317653869502688143">Palun kinnitage, et soovite installida selle lisandmooduli <ph name="PLUGIN"/>. Te peaksite installima lisandmooduleid, mida usaldate.</translation>
+<translation id="3926627843712816530">Palun kinnitage, et soovite installida selle lisandmooduli. Te peaksite installima lisandmooduleid, mida usaldate.</translation>
+<translation id="1383141426028388991">Lisandmooduli installimine asukohast <ph name="URL"/> ebaõnnestus.</translation>
+<translation id="6845533974506654842">vajuta</translation>
+<translation id="1842960171412779397">vali</translation>
+<translation id="6119846243427417423">aktiveeri</translation>
+<translation id="5476505524087279545">eemalda mrgistus</translation>
+<translation id="838869780401515933">mrgista</translation>
+<translation id="4202807286478387388">liigu</translation>
+<translation id="795667975304826397">Ühtegi faili pole valitud</translation>
+<translation id="8964020114565522021">Lohistage fail siia</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_fi.xtb b/webkit/glue/resources/webkit_strings_fi.xtb
new file mode 100644
index 0000000..040bded
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_fi.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="fi">
+<translation id="7658239707568436148">Peruuta</translation>
+<translation id="3789841737615482174">Asenna</translation>
+<translation id="8141602879876242471">Tämä on haettavissa oleva hakemisto. Anna hakusanat:</translation>
+<translation id="2653659639078652383">Lähetä</translation>
+<translation id="5939518447894949180">Tyhjennä</translation>
+<translation id="7364796246159120393">Valitse tiedosto</translation>
+<translation id="2548326553472216322">Ei viimeisimpiä hakuja</translation>
+<translation id="6663448176199120256">Viimeisimmät haut</translation>
+<translation id="1235745349614807883">Poista viimeisimmät haut</translation>
+<translation id="6807599807928161586">verkkoalue</translation>
+<translation id="3040011195152428237">linkki</translation>
+<translation id="5048533449481078685">luettelon merkitsijä</translation>
+<translation id="8244226242650769279">kuvakartta</translation>
+<translation id="8597182159515967513">otsikko</translation>
+<translation id="5944544982112848342">2048 (korkea taso)</translation>
+<translation id="2846343701378493991">1024 (keskitaso)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436">Laajennusta <ph name="PLUGIN"/> ei asennettu</translation>
+<translation id="4838490908464673667">Vaadittua laajennusta ei ole asennettu</translation>
+<translation id="3600343118165084788">Lataa laajennus napsauttamalla tätä</translation>
+<translation id="8281246460978372009">Päivitä laajennuksen asennuksen jälkeen napsauttamalla tästä</translation>
+<translation id="679352192834563463">Tämän sisällön näyttämiseen ei ole saatavissa laajennusta</translation>
+<translation id="8662565117025751661">Ladataan laajennusta...</translation>
+<translation id="3771786644471114952">Hae laajennus</translation>
+<translation id="1275511093094545429"><ph name="PLUGIN"/> laajennus tarvitaan</translation>
+<translation id="3825324228893189080">Lisälaajennus tarvitaan</translation>
+<translation id="4420062214988137980">Laajennuksen asennus epäonnistui</translation>
+<translation id="4317653869502688143">Vahvista, että haluat asentaa laajennuksen <ph name="PLUGIN"/>. Sinun tulee asentaa vain luotettavia laajennuksia.</translation>
+<translation id="3926627843712816530">Vahvista, että haluat asentaa tämän laajennuksen. Sinun tulee asentaa vain luotettavia laajennuksia.</translation>
+<translation id="1383141426028388991">Laajennuksen asennus osoitteesta <ph name="URL"/> epäonnistui</translation>
+<translation id="6845533974506654842">paina</translation>
+<translation id="1842960171412779397">Valitse</translation>
+<translation id="6119846243427417423">aktivoi</translation>
+<translation id="5476505524087279545">poista valinta</translation>
+<translation id="838869780401515933">valitse</translation>
+<translation id="4202807286478387388">siirry</translation>
+<translation id="795667975304826397">Ei valittua tiedostoa</translation>
+<translation id="8964020114565522021">Vedä tiedosto tähän</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_fil.xtb b/webkit/glue/resources/webkit_strings_fil.xtb
new file mode 100644
index 0000000..cf13799
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_fil.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="fil">
+<translation id="7658239707568436148">Ikansela</translation>
+<translation id="3789841737615482174">Install</translation>
+<translation id="8141602879876242471">Isa itong paghahanap ng index. Ipasok ang paghahanap sa mga keyword:</translation>
+<translation id="2653659639078652383">Isumite</translation>
+<translation id="5939518447894949180">I-reset</translation>
+<translation id="7364796246159120393">Pumili ng File</translation>
+<translation id="2548326553472216322">Walang kamakailang mga paghahanap</translation>
+<translation id="6663448176199120256">Kasalukuyang Mga Paghahanap</translation>
+<translation id="1235745349614807883">Lisiman ang Kasalukuyang Mga Paghahanap</translation>
+<translation id="6807599807928161586">web area</translation>
+<translation id="3040011195152428237">link</translation>
+<translation id="5048533449481078685">Ilista ang marker</translation>
+<translation id="8244226242650769279">mapa ng imahe</translation>
+<translation id="8597182159515967513">heading</translation>
+<translation id="5944544982112848342">2048 (Pinakamataas na Marka)</translation>
+<translation id="2846343701378493991">1024 (Katamtamang Grado)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436"><ph name="PLUGIN"/> hindi na-install ang plugin</translation>
+<translation id="4838490908464673667">Ang kinakailangan na plugin ay hindi na-install</translation>
+<translation id="3600343118165084788">Mag-click dito upagn mai-download ang plugin</translation>
+<translation id="8281246460978372009">Matapos ang pag-install ng plugin, mag-click dito upang mag-refresh</translation>
+<translation id="679352192834563463">Walang magagamit na plugin na ipapakita sa nilalaman nito</translation>
+<translation id="8662565117025751661">Nagda-download ng plugin...</translation>
+<translation id="3771786644471114952">Kunin ang Plugin</translation>
+<translation id="1275511093094545429"><ph name="PLUGIN"/> kinakailangang plugin</translation>
+<translation id="3825324228893189080">Kailangan ng karagdagang plugin</translation>
+<translation id="4420062214988137980">Nabigong pag-install sa plugin</translation>
+<translation id="4317653869502688143">Mangyaring kumpirmahin na nais mong i-install ang <ph name="PLUGIN"/> plugin. Dapat mo lamang i-install ang mga plugin na pinagkakatiwalaan mo.</translation>
+<translation id="3926627843712816530">Mangyaring kumpirmahin na dapat gusto mong i-install sa plugin na ito. Dapat mo lamang i-install ang mga plugin na pinagkakatiwalaan mo.</translation>
+<translation id="1383141426028388991">Nabigong na-install ang plugin mula sa <ph name="URL"/></translation>
+<translation id="6845533974506654842">pindutin</translation>
+<translation id="1842960171412779397">piliin</translation>
+<translation id="6119846243427417423">isaaktibo</translation>
+<translation id="5476505524087279545">i-uncheck</translation>
+<translation id="838869780401515933">I-tsek</translation>
+<translation id="4202807286478387388">tumalon</translation>
+<translation id="795667975304826397">Walang napiling file</translation>
+<translation id="8964020114565522021">Kaldkarin dito ang file</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_fr.xtb b/webkit/glue/resources/webkit_strings_fr.xtb
new file mode 100644
index 0000000..0af3156
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_fr.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="fr">
+<translation id="7658239707568436148">Annuler</translation>
+<translation id="3789841737615482174">Installer</translation>
+<translation id="8141602879876242471">Vous pouvez lancer des recherches dans cet index. Pour cela, entrez des mots clés de recherche :</translation>
+<translation id="2653659639078652383">Valider</translation>
+<translation id="5939518447894949180">Réinitialiser</translation>
+<translation id="7364796246159120393">Choisissez un fichier</translation>
+<translation id="2548326553472216322">Aucune recherche récente</translation>
+<translation id="6663448176199120256">Recherches récentes</translation>
+<translation id="1235745349614807883">Effacer les recherches récentes</translation>
+<translation id="6807599807928161586">Zone Web</translation>
+<translation id="3040011195152428237">Lien</translation>
+<translation id="5048533449481078685">marqueur de liste</translation>
+<translation id="8244226242650769279">image map</translation>
+<translation id="8597182159515967513">en-tête</translation>
+<translation id="5944544982112848342">2048 (haute sécurité)</translation>
+<translation id="2846343701378493991">1024 (sécurité moyenne)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/> × <ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436">Le plug-in <ph name="PLUGIN"/> n'est pas installé.</translation>
+<translation id="4838490908464673667">Le plug-in requis n'est pas installé.</translation>
+<translation id="3600343118165084788">Cliquez ici pour télécharger le plug-in</translation>
+<translation id="8281246460978372009">Après l'installation du plug-in, cliquez ici pour actualiser.</translation>
+<translation id="679352192834563463">Aucun plug-in disponible pour afficher ce contenu</translation>
+<translation id="8662565117025751661">Téléchargement du plug-in...</translation>
+<translation id="3771786644471114952">Ajouter le plug-in</translation>
+<translation id="1275511093094545429">Plug-in <ph name="PLUGIN"/> requis</translation>
+<translation id="3825324228893189080">Plug-in supplémentaire requis</translation>
+<translation id="4420062214988137980">Échec de l'installation du plug-in</translation>
+<translation id="4317653869502688143">Veuillez confirmer que vous souhaitez installer le plug-in <ph name="PLUGIN"/>. Veillez à installer uniquement des plug-ins approuvés.</translation>
+<translation id="3926627843712816530">Veuillez confirmer que vous souhaitez installer ce plug-in. Vous devez uniquement installer des plug-ins approuvés.</translation>
+<translation id="1383141426028388991">Échec de l'installation du plug-in depuis <ph name="URL"/></translation>
+<translation id="6845533974506654842">appuyer</translation>
+<translation id="1842960171412779397">sélectionner</translation>
+<translation id="6119846243427417423">activer</translation>
+<translation id="5476505524087279545">décocher</translation>
+<translation id="838869780401515933">cocher</translation>
+<translation id="4202807286478387388">accéder</translation>
+<translation id="795667975304826397">Aucun fichier choisi</translation>
+<translation id="8964020114565522021">Placer le fichier ici</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_he.xtb b/webkit/glue/resources/webkit_strings_he.xtb
new file mode 100644
index 0000000..f6cc4ac
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_he.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="he">
+<translation id="4317653869502688143">אשר שברצונך להתקין את התוסף <ph name="PLUGIN"/>. עליך להתקין רק תוספים אתה בוטח.</translation>
+<translation id="3926627843712816530">אנא אשר שברצונך להתקין תוסף זה. עליך להתקין רק תוספים שבהם אתה בוטח.</translation>
+<translation id="1383141426028388991">התקנת התוסף מ-<ph name="URL"/> נכשלה</translation>
+<translation id="7658239707568436148">ביטול</translation>
+<translation id="6119846243427417423">הפעל</translation>
+<translation id="6845533974506654842">לחץ</translation>
+<translation id="838869780401515933">סמן</translation>
+<translation id="7364796246159120393">בחר קובץ</translation>
+<translation id="1235745349614807883">הסר חיפושים אחרונים</translation>
+<translation id="3600343118165084788">לחץ כאן להורדת התוסף</translation>
+<translation id="8597182159515967513">כותרת</translation>
+<translation id="2965480764085142436"><ph name="PLUGIN"/> אינו מותקן</translation>
+<translation id="2846343701378493991">1024 (Medium Grade)</translation>
+<translation id="8141602879876242471">זהו אינדקס שניתן לבצע בו חיפוש. הזן מילות מפתח לחיפוש:</translation>
+<translation id="3771786644471114952">קבל תוסף</translation>
+<translation id="4202807286478387388">קפוץ</translation>
+<translation id="679352192834563463">אין תוסף זמין להצגת תוכן זה</translation>
+<translation id="3825324228893189080">דרוש תוסף נוסף</translation>
+<translation id="3789841737615482174">התקן</translation>
+<translation id="795667975304826397">לא נבחר קובץ</translation>
+<translation id="8244226242650769279">מפת תמונות</translation>
+<translation id="6663448176199120256">חיפושים אחרונים</translation>
+<translation id="2653659639078652383">שלח</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="4838490908464673667">התוסף המבוקש אינו מותקן</translation>
+<translation id="1275511093094545429">נדרש plugin <ph name="PLUGIN"/></translation>
+<translation id="8964020114565522021">גרור את הקובץ לכאן</translation>
+<translation id="5939518447894949180">אפס</translation>
+<translation id="8281246460978372009">לאחר התקנת התוסף, לחץ כאן לרענון</translation>
+<translation id="6807599807928161586">אזור אינטרנט</translation>
+<translation id="3040011195152428237">קישור</translation>
+<translation id="4420062214988137980">התקנת פלגא-אין נכשלה</translation>
+<translation id="5944544982112848342">2048 (High Grade)</translation>
+<translation id="5048533449481078685">סמן רשימה</translation>
+<translation id="2548326553472216322">אין חיפושים אחרונים</translation>
+<translation id="5476505524087279545">בטל סימון</translation>
+<translation id="1842960171412779397">בחר</translation>
+<translation id="8662565117025751661">מוריד תוסף...</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_hi.xtb b/webkit/glue/resources/webkit_strings_hi.xtb
new file mode 100644
index 0000000..3ee472c
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_hi.xtb
@@ -0,0 +1,36 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="hi">
+<translation id="7658239707568436148">रद्द करें</translation>
+<translation id="3789841737615482174">स्थापित करें</translation>
+<translation id="8141602879876242471">यह एक खोजने योग्य इंडेक्स है. खोज कुंजीशब्द प्रविष्ट करें :</translation>
+<translation id="2653659639078652383">जमा करें</translation>
+<translation id="5939518447894949180">पुन: सेट करें</translation>
+<translation id="7364796246159120393">फ़ाइल चुनें</translation>
+<translation id="2548326553472216322">हाल ही में कोई खोज नहीं</translation>
+<translation id="6663448176199120256">हाल ही में की गई खोजें</translation>
+<translation id="1235745349614807883">हाल ही की खोजें साफ़ करें</translation>
+<translation id="6807599807928161586">वेब क्षेत्र</translation>
+<translation id="3040011195152428237">लिंक</translation>
+<translation id="5048533449481078685">सूची चिन्हक</translation>
+<translation id="8244226242650769279">चित्र मैप</translation>
+<translation id="8597182159515967513">हेडिंग</translation>
+<translation id="5944544982112848342">2048 (उच्च ग्रेड)</translation>
+<translation id="2846343701378493991">1024 (मध्यम ग्रेड)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436"><ph name="PLUGIN"/> प्लगइन स्थापित नहीं किया गया है</translation>
+<translation id="4838490908464673667">आवश्यक प्लगइन स्थापित नहीं है</translation>
+<translation id="3600343118165084788">प्लगइन डाउनलोड करने के लिए यहाँ क्लिक करें</translation>
+<translation id="8281246460978372009">प्लगइन स्थापित करने के बाद, पुन: ताज़ा करने के लिए यहाँ क्लिक करें</translation>
+<translation id="679352192834563463">इस सामग्री को प्रदर्शित करने के लिए कोई प्लगइन उपलब्ध नहीं है</translation>
+<translation id="8662565117025751661">प्लगइन डाउनलोड कर रहा है ...</translation>
+<translation id="3771786644471114952">प्लगइन प्राप्त करें</translation>
+<translation id="1275511093094545429"><ph name="PLUGIN"/> प्लगइन आवश्यक</translation>
+<translation id="3825324228893189080">अतिरिक्त प्लगइन आवश्यक</translation>
+<translation id="4420062214988137980">प्लगइन स्थापना असफ़ल रही</translation>
+<translation id="4317653869502688143">कृपया पुष्टि करें कि आप <ph name="PLUGIN"/> प्लगइन स्थापित करना चाहते हैं. आपके केवल वे प्लगइन स्थापित करने चाहिए जिनपर आप भरोसा करते हों.</translation>
+<translation id="3926627843712816530">कृपया पुष्टि करें कि आप यह प्लगइन स्थापित करना चाहते हैं. आपके केवल वे प्लगइन स्थापित करने चाहिए जिनपर आप भरोसा करते हों.</translation>
+<translation id="1383141426028388991"><ph name="URL"/> से प्लगइन स्थापित करने में असफ़ल रहा</translation>
+<translation id="795667975304826397">कोई फाइल नहीं चुनी गई</translation>
+<translation id="8964020114565522021">फाइल खींचकर यहाँ लाएं</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_hr.xtb b/webkit/glue/resources/webkit_strings_hr.xtb
new file mode 100644
index 0000000..4c1cfb8
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_hr.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="hr">
+<translation id="7658239707568436148">Odustani</translation>
+<translation id="3789841737615482174">Instaliraj</translation>
+<translation id="8141602879876242471">Ovaj je indeks moguće pretraživati. Unesite ključne riječi za pretraživanje:</translation>
+<translation id="2653659639078652383">Pošalji</translation>
+<translation id="5939518447894949180">Ponovno postavi</translation>
+<translation id="7364796246159120393">Odaberi datoteku</translation>
+<translation id="2548326553472216322">Nema najnovijih pretraživanja</translation>
+<translation id="6663448176199120256">Najnovija pretraživanja</translation>
+<translation id="1235745349614807883">Obriši najnovija pretraživanja</translation>
+<translation id="6807599807928161586">web područje</translation>
+<translation id="3040011195152428237">veza</translation>
+<translation id="5048533449481078685">oznaka popisa</translation>
+<translation id="8244226242650769279">karta slika</translation>
+<translation id="8597182159515967513">naslov</translation>
+<translation id="5944544982112848342">2048 (visoki stupanj)</translation>
+<translation id="2846343701378493991">1024 (srednji)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436">Nije instaliran dodatak za <ph name="PLUGIN"/></translation>
+<translation id="4838490908464673667">Potreban dodatak nije instaliran</translation>
+<translation id="3600343118165084788">Kliknite ovdje za preuzimanje dodatka</translation>
+<translation id="8281246460978372009">Nakon instalacije dodatka, kliknite ovdje za osvježenje stranice</translation>
+<translation id="679352192834563463">Nema dostupnog dodatka za prikaz ovog sadržaja</translation>
+<translation id="8662565117025751661">Preuzimanje dodatka...</translation>
+<translation id="3771786644471114952">Dohvati dodatak</translation>
+<translation id="1275511093094545429">Potreban je dodatak za <ph name="PLUGIN"/></translation>
+<translation id="3825324228893189080">Potreban je dodatak</translation>
+<translation id="4420062214988137980">Nije uspjela instalacija dodatka</translation>
+<translation id="4317653869502688143">Potvrdite da želite instalirati dodatak za <ph name="PLUGIN"/> Instalirajte samo one dodatke kojima vjerujete.</translation>
+<translation id="3926627843712816530">Potvrdite da želite instalirati ovaj dodatak. Instalirajte samo one dodatke kojima vjerujete.</translation>
+<translation id="1383141426028388991">Nije uspjela instalacija dodatka s <ph name="URL"/></translation>
+<translation id="6845533974506654842">pritisni</translation>
+<translation id="1842960171412779397">odaberi</translation>
+<translation id="6119846243427417423">aktiviraj</translation>
+<translation id="5476505524087279545">ukloni oznaku</translation>
+<translation id="838869780401515933">označi</translation>
+<translation id="4202807286478387388">skoči</translation>
+<translation id="795667975304826397">Nije odabrana niti jedna datoteka.</translation>
+<translation id="8964020114565522021">Povucite datoteku ovamo</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_hu.xtb b/webkit/glue/resources/webkit_strings_hu.xtb
new file mode 100644
index 0000000..9d467c8
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_hu.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="hu">
+<translation id="7658239707568436148">Mégse</translation>
+<translation id="3789841737615482174">Telepítés</translation>
+<translation id="8141602879876242471">Ez egy kereshető index. Írjon be keresési kulcsszavakat:</translation>
+<translation id="2653659639078652383">Elküldés</translation>
+<translation id="5939518447894949180">Visszaállítás</translation>
+<translation id="7364796246159120393">Fájl kiválasztása</translation>
+<translation id="2548326553472216322">Nincsenek friss keresések</translation>
+<translation id="6663448176199120256">Friss keresések</translation>
+<translation id="1235745349614807883">Friss keresések törlése</translation>
+<translation id="6807599807928161586">internetes terület</translation>
+<translation id="3040011195152428237">link</translation>
+<translation id="5048533449481078685">listajelölő</translation>
+<translation id="8244226242650769279">képtérkép</translation>
+<translation id="8597182159515967513">fejléc</translation>
+<translation id="5944544982112848342">2048 (magasfokú)</translation>
+<translation id="2846343701378493991">1024 (Közepes)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436">A(z) <ph name="PLUGIN"/> plugin nem lett telepítve</translation>
+<translation id="4838490908464673667">A szükséges plugin nem lett telepítve</translation>
+<translation id="3600343118165084788">Ha ide kattint, letöltheti a plugint</translation>
+<translation id="8281246460978372009">A plugin telepítését követően ide kattintson a frissítéshez</translation>
+<translation id="679352192834563463">Nincs elérhető plugin a tartalom megjelenítéséhez</translation>
+<translation id="8662565117025751661">Plugin letöltése...</translation>
+<translation id="3771786644471114952">Plugin beszerzése</translation>
+<translation id="1275511093094545429"><ph name="PLUGIN"/> plugin szükséges</translation>
+<translation id="3825324228893189080">További plugin szükséges</translation>
+<translation id="4420062214988137980">A plugin telepítése nem sikerült</translation>
+<translation id="4317653869502688143">Kérjük, erősítse meg, hogy telepíteni szeretné a(z) <ph name="PLUGIN"/> plugint. Csak azokat a plugineket telepítse, amelyekben megbízik.</translation>
+<translation id="3926627843712816530">Kérjük, erősítse meg, hogy telepíteni szeretné ezt a plugint. Csak azokat a plugineket telepítse, amelyekben megbízik.</translation>
+<translation id="1383141426028388991">A plugin telepítése nem sikerült a következő helyről: <ph name="URL"/></translation>
+<translation id="6845533974506654842">Gomb lenyomása</translation>
+<translation id="1842960171412779397">Kiválasztás</translation>
+<translation id="6119846243427417423">Aktiválás</translation>
+<translation id="5476505524087279545">Megjelölés eltávolítása</translation>
+<translation id="838869780401515933">Megjelölés</translation>
+<translation id="4202807286478387388">Mehet</translation>
+<translation id="795667975304826397">Nem lett fájl kiválasztva</translation>
+<translation id="8964020114565522021">Húzza át ide a fájlt</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_id.xtb b/webkit/glue/resources/webkit_strings_id.xtb
new file mode 100644
index 0000000..5b68dce
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_id.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="id">
+<translation id="7658239707568436148">Batal</translation>
+<translation id="3789841737615482174">Instal</translation>
+<translation id="8141602879876242471">Terdapat indeks yang dapat dicari. Masukkan kata kunci penelusuran:</translation>
+<translation id="2653659639078652383">Kirim</translation>
+<translation id="5939518447894949180">Atur ulang</translation>
+<translation id="7364796246159120393">Pilih Berkas</translation>
+<translation id="2548326553472216322">Tidak ada penelusuran terkini</translation>
+<translation id="6663448176199120256">Penelusuran Barusan</translation>
+<translation id="1235745349614807883">Hapus Penelusuran Barusan</translation>
+<translation id="6807599807928161586">area Web</translation>
+<translation id="3040011195152428237">tautan</translation>
+<translation id="5048533449481078685">penanda daftar</translation>
+<translation id="8244226242650769279">gambar peta</translation>
+<translation id="8597182159515967513">kepala</translation>
+<translation id="5944544982112848342">2048 (Tingkat Tinggi)</translation>
+<translation id="2846343701378493991">1024 (Tingkat Menengah)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/> - <ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436"><ph name="PLUGIN"/> plug-in belum terinstal</translation>
+<translation id="4838490908464673667">Plug-in yang diperlukan belum terinstal</translation>
+<translation id="3600343118165084788">Klik di sini untuk mengunduh plug-in</translation>
+<translation id="8281246460978372009">Setelah menginstal plug-in, klik di sini untuk me-refresh</translation>
+<translation id="679352192834563463">Tidak tersedia plug-in untuk menampilkan konten ini</translation>
+<translation id="8662565117025751661">Mengunduh plug-in...</translation>
+<translation id="3771786644471114952">Dapatkan Plug-in</translation>
+<translation id="1275511093094545429"><ph name="PLUGIN"/> diperlukan plug-in</translation>
+<translation id="3825324228893189080">Diperlukan plug-in tambahan</translation>
+<translation id="4420062214988137980">Penginstalan plug-in gagal</translation>
+<translation id="4317653869502688143">Konfirmasikan bahwa Anda ingin menginstal plug-in<ph name="PLUGIN"/>. Sebaiknya hanya instal plug-in yang Anda percaya.</translation>
+<translation id="3926627843712816530">Konfirmasikan bahwa Anda ingin menginstal plug-in ini. Sebaiknya hanya instal plug-in yang Anda percaya.</translation>
+<translation id="1383141426028388991">Gagal menginstal plug-in dari <ph name="URL"/></translation>
+<translation id="6845533974506654842">tekan</translation>
+<translation id="1842960171412779397">pilih</translation>
+<translation id="6119846243427417423">aktifkan</translation>
+<translation id="5476505524087279545">batalkan centang</translation>
+<translation id="838869780401515933">centangi</translation>
+<translation id="4202807286478387388">lompati</translation>
+<translation id="795667975304826397">Tidak ada file yang dipilih</translation>
+<translation id="8964020114565522021">Tarik file ke sini</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_it.xtb b/webkit/glue/resources/webkit_strings_it.xtb
new file mode 100644
index 0000000..4cce7eb
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_it.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="it">
+<translation id="7658239707568436148">Annulla</translation>
+<translation id="3789841737615482174">Installa</translation>
+<translation id="8141602879876242471">Questo è un indice di ricerca. Inserisci le parole chiave di ricerca:</translation>
+<translation id="2653659639078652383">Invia</translation>
+<translation id="5939518447894949180">Ripristina</translation>
+<translation id="7364796246159120393">Scegli file</translation>
+<translation id="2548326553472216322">Nessuna ricerca recente</translation>
+<translation id="6663448176199120256">Ricerche recenti</translation>
+<translation id="1235745349614807883">Cancella ricerche recenti</translation>
+<translation id="6807599807928161586">area web</translation>
+<translation id="3040011195152428237">link</translation>
+<translation id="5048533449481078685">indicatore elenco</translation>
+<translation id="8244226242650769279">image map</translation>
+<translation id="8597182159515967513">intestazione</translation>
+<translation id="5944544982112848342">2048 (alta qualità)</translation>
+<translation id="2846343701378493991">1024 (Medium Grade)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436">Plug-in <ph name="PLUGIN"/> non installato</translation>
+<translation id="4838490908464673667">Il plug-in richiesto non è installato</translation>
+<translation id="3600343118165084788">Fai clic qui per scaricare il plug-in</translation>
+<translation id="8281246460978372009">Dopo aver installato il plug-in, fai clic qui per aggiornare</translation>
+<translation id="679352192834563463">Nessun plug-in disponibile per visualizzare il contenuto</translation>
+<translation id="8662565117025751661">Download del plugin in corso...</translation>
+<translation id="3771786644471114952">Aggiungi plug-in</translation>
+<translation id="1275511093094545429">Plugin <ph name="PLUGIN"/> necessario</translation>
+<translation id="3825324228893189080">Plug-in aggiuntivo necessario</translation>
+<translation id="4420062214988137980">Installazione plug-in non riuscita</translation>
+<translation id="4317653869502688143">Conferma l'installazione del plug-in <ph name="PLUGIN"/>. Ti invitiamo a installare solo i plug-in che ritieni affidabili.</translation>
+<translation id="3926627843712816530">Conferma l'installazione del plug-in. Ti invitiamo a installare solo i plug-in che ritieni affidabili.</translation>
+<translation id="1383141426028388991">Installazione plug-in da <ph name="URL"/> non riuscita</translation>
+<translation id="6845533974506654842">premi</translation>
+<translation id="1842960171412779397">seleziona</translation>
+<translation id="6119846243427417423">attiva</translation>
+<translation id="5476505524087279545">deseleziona</translation>
+<translation id="838869780401515933">seleziona</translation>
+<translation id="4202807286478387388">vai</translation>
+<translation id="795667975304826397">Nessun file selezionato</translation>
+<translation id="8964020114565522021">Trascina il file qui</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_ja.xtb b/webkit/glue/resources/webkit_strings_ja.xtb
new file mode 100644
index 0000000..6bc856e
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_ja.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ja">
+<translation id="7658239707568436148">キャンセル</translation>
+<translation id="3789841737615482174">インストール</translation>
+<translation id="8141602879876242471">このインデックスは検索できます。キーワードを入力してください:</translation>
+<translation id="2653659639078652383">送信</translation>
+<translation id="5939518447894949180">リセット</translation>
+<translation id="7364796246159120393">ファイルを選択</translation>
+<translation id="2548326553472216322">最近の検索はありません</translation>
+<translation id="6663448176199120256">最近の検索</translation>
+<translation id="1235745349614807883">最近の検索履歴を消去</translation>
+<translation id="6807599807928161586">ウェブ領域</translation>
+<translation id="3040011195152428237">リンク</translation>
+<translation id="5048533449481078685">リスト マーカー</translation>
+<translation id="8244226242650769279">イメージ マップ</translation>
+<translation id="8597182159515967513">見出し</translation>
+<translation id="5944544982112848342">2048 (高)</translation>
+<translation id="2846343701378493991">1024 (中)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436"><ph name="PLUGIN"/> プラグインはインストールされていません</translation>
+<translation id="4838490908464673667">必要なプラグインがインストールされていません</translation>
+<translation id="3600343118165084788">ここをクリックしてプラグインをダウンロード</translation>
+<translation id="8281246460978372009">プラグインをインストールした後は、ここをクリックして更新してください</translation>
+<translation id="679352192834563463">このコンテンツの表示に使用できるプラグインはありません</translation>
+<translation id="8662565117025751661">プラグインをダウンロードしています...</translation>
+<translation id="3771786644471114952">プラグインの取得</translation>
+<translation id="1275511093094545429"><ph name="PLUGIN"/> プラグインが必要です</translation>
+<translation id="3825324228893189080">追加の必要なプラグイン</translation>
+<translation id="4420062214988137980">プラグインのインストールが失敗しました</translation>
+<translation id="4317653869502688143"><ph name="PLUGIN"/> プラグインのインストールを確認してください。信頼できるプラグインだけインストールしてください。</translation>
+<translation id="3926627843712816530">このプラグインのインストールを確認してください。信頼できるプラグインだけインストールしてください。</translation>
+<translation id="1383141426028388991"><ph name="URL"/> からのプラグインのインストールに失敗しました</translation>
+<translation id="6845533974506654842">押す</translation>
+<translation id="1842960171412779397">選択</translation>
+<translation id="6119846243427417423">アクティブにする</translation>
+<translation id="5476505524087279545">チェックを外す</translation>
+<translation id="838869780401515933">チェックを付ける</translation>
+<translation id="4202807286478387388">ジャンプ</translation>
+<translation id="795667975304826397">ファイルが選択されていません</translation>
+<translation id="8964020114565522021">ファイルをここにドラッグ</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_ko.xtb b/webkit/glue/resources/webkit_strings_ko.xtb
new file mode 100644
index 0000000..b688b9d
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_ko.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ko">
+<translation id="7658239707568436148">취소</translation>
+<translation id="3789841737615482174">설치</translation>
+<translation id="8141602879876242471">이것은 검색 색인합니다. 검색 키워드 입력:</translation>
+<translation id="2653659639078652383">제출</translation>
+<translation id="5939518447894949180">재설정</translation>
+<translation id="7364796246159120393">파일 선택</translation>
+<translation id="2548326553472216322">최근 수행된 검색 없음</translation>
+<translation id="6663448176199120256">최근 수행된 검색</translation>
+<translation id="1235745349614807883">최근 검색 삭제</translation>
+<translation id="6807599807928161586">웹 영역</translation>
+<translation id="3040011195152428237">링크</translation>
+<translation id="5048533449481078685">목록 표시기</translation>
+<translation id="8244226242650769279">이미지 지도</translation>
+<translation id="8597182159515967513">항목</translation>
+<translation id="5944544982112848342">2048(높은 등급)</translation>
+<translation id="2846343701378493991">1024(중간 등급)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436"><ph name="PLUGIN"/> 플러그인이 설치되지 않음</translation>
+<translation id="4838490908464673667">필수 플러그인이 설치되지 않음</translation>
+<translation id="3600343118165084788">여기를 클릭하여 플러그인을 다운로드합니다.</translation>
+<translation id="8281246460978372009">플러그인 설치 후 여기를 클릭하여 새로고침</translation>
+<translation id="679352192834563463">이 콘텐츠를 표시하는 데 사용할 플러그인 없음</translation>
+<translation id="8662565117025751661">플러그인 다운로드 중...</translation>
+<translation id="3771786644471114952">플러그인 가져오기</translation>
+<translation id="1275511093094545429"><ph name="PLUGIN"/> 플러그인 필요</translation>
+<translation id="3825324228893189080">추가 플러그인 필요</translation>
+<translation id="4420062214988137980">플러그인 설치 실패</translation>
+<translation id="4317653869502688143"><ph name="PLUGIN"/> 플러그인을 설치할 것인지 확인해 주세요. 신뢰하는 플러그인만 설치해야 합니다.</translation>
+<translation id="3926627843712816530">해당 플러그인을 설치할 것인지 확인해 주세요. 신뢰하는 플러그인만 설치해야 합니다.</translation>
+<translation id="1383141426028388991"><ph name="URL"/>의 플러그인 설치 실패</translation>
+<translation id="6845533974506654842">누르기</translation>
+<translation id="1842960171412779397">선택</translation>
+<translation id="6119846243427417423">활성화</translation>
+<translation id="5476505524087279545">선택취소</translation>
+<translation id="838869780401515933">선택</translation>
+<translation id="4202807286478387388">건너뛰기</translation>
+<translation id="795667975304826397">선택된 파일 없음</translation>
+<translation id="8964020114565522021">여기로 파일 드래그</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_lt.xtb b/webkit/glue/resources/webkit_strings_lt.xtb
new file mode 100644
index 0000000..4d88715
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_lt.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="lt">
+<translation id="7658239707568436148">Atšaukti</translation>
+<translation id="3789841737615482174">Diegti</translation>
+<translation id="8141602879876242471">Tai yra ieškotinas indeksas. Įveskite paieškos raktinių žodžių:</translation>
+<translation id="2653659639078652383">Pateikti</translation>
+<translation id="5939518447894949180">Nustatyti iš naujo</translation>
+<translation id="7364796246159120393">Pasirinkti failą</translation>
+<translation id="2548326553472216322">Pastaruoju metu paieškų nevykdyta</translation>
+<translation id="6663448176199120256">Naujausios paieškos</translation>
+<translation id="1235745349614807883">Išvalyti pastarąsias paieškas</translation>
+<translation id="6807599807928161586">interneto sritis</translation>
+<translation id="3040011195152428237">nuoroda</translation>
+<translation id="5048533449481078685">sąrašo žymeklis</translation>
+<translation id="8244226242650769279">paveikslėlio žemėlapis</translation>
+<translation id="8597182159515967513">antraštė</translation>
+<translation id="5944544982112848342">2048 (Aukšto laipsnio)</translation>
+<translation id="2846343701378493991">1024 (vidutinio lygio)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436"><ph name="PLUGIN"/> papildinys neįdiegtas</translation>
+<translation id="4838490908464673667">Neįdiegtas reikalingas papildinys</translation>
+<translation id="3600343118165084788">Spustelėkite čia, kad atsisiųstumėte papildinį</translation>
+<translation id="8281246460978372009">Įdiegę papildinį paspauskite čia, kad būtų perkrautas puslapis</translation>
+<translation id="679352192834563463">Nėra papildinio, galinčio parodyti šį turinį</translation>
+<translation id="8662565117025751661">Siunčiamas papildinys...</translation>
+<translation id="3771786644471114952">Siųsti papildinį</translation>
+<translation id="1275511093094545429">Reikia <ph name="PLUGIN"/> papildinio (-ių)</translation>
+<translation id="3825324228893189080">Reikia papidomo papildinio</translation>
+<translation id="4420062214988137980">Papildinio įdiegti nepavyko</translation>
+<translation id="4317653869502688143">Patvirtinkite, kad norite diegti <ph name="PLUGIN"/> papildinį. Diekite tik tuos papildinius, kuriais tikrai pasitikite.</translation>
+<translation id="3926627843712816530">Patvirtinkite, kad norite diegti šį papildinį. Diekite tik tuos papildinius, kuriais tikrai pasitikite.</translation>
+<translation id="1383141426028388991">Nepavyko įdiegti papildinio iš <ph name="URL"/></translation>
+<translation id="6845533974506654842">paspausti</translation>
+<translation id="1842960171412779397">pasirinkti</translation>
+<translation id="6119846243427417423">aktyvinti</translation>
+<translation id="5476505524087279545">Nuimti žymėjimą</translation>
+<translation id="838869780401515933">tikrinti</translation>
+<translation id="4202807286478387388">peršokti</translation>
+<translation id="795667975304826397">Nepasirinktas joks failas</translation>
+<translation id="8964020114565522021">Vilkite failą čia</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_lv.xtb b/webkit/glue/resources/webkit_strings_lv.xtb
new file mode 100644
index 0000000..ce2afd5
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_lv.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="lv">
+<translation id="7658239707568436148">Atcelt</translation>
+<translation id="3789841737615482174">Iestatīt</translation>
+<translation id="8141602879876242471">Šis ir indekss ar meklēšanas iespējām. Ievadīt meklēšanas atslēgvārdus:</translation>
+<translation id="2653659639078652383">Iesniegt</translation>
+<translation id="5939518447894949180">Atiestatīt</translation>
+<translation id="7364796246159120393">Izvēlieties failu</translation>
+<translation id="2548326553472216322">Nav nesenu meklējumu</translation>
+<translation id="6663448176199120256">Neseni meklējumi</translation>
+<translation id="1235745349614807883">Dzēst nesenos meklējumus</translation>
+<translation id="6807599807928161586">tīmekļa apgabals</translation>
+<translation id="3040011195152428237">saite</translation>
+<translation id="5048533449481078685">sarakstu marķieris</translation>
+<translation id="8244226242650769279">attēlu karte</translation>
+<translation id="8597182159515967513">Virsraksts</translation>
+<translation id="5944544982112848342">2048 (Augsta Atzīme)</translation>
+<translation id="2846343701378493991">1024 (Vidēja Atzīme)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436"><ph name="PLUGIN"/> spraudnis nav iestatīts</translation>
+<translation id="4838490908464673667">Nepieciešamais spraudnis nav iestatīts</translation>
+<translation id="3600343118165084788">Klikšķiniet šeit, lai lejupielādētu spraudni</translation>
+<translation id="8281246460978372009">Pēc spraudņa iestatīšanas, nospiediet šeit, lai atsvaidzinātu</translation>
+<translation id="679352192834563463">Nav pieejamu spraudņu, lai attēlotu saturu</translation>
+<translation id="8662565117025751661">Spraudņu lejupielāde...</translation>
+<translation id="3771786644471114952">Iegūt spraudni</translation>
+<translation id="1275511093094545429"><ph name="PLUGIN"/> nepieciešams spraudnis</translation>
+<translation id="3825324228893189080">Nepieciešams papildus spraudnis</translation>
+<translation id="4420062214988137980">Spraudņa iestatīšana neizdevās</translation>
+<translation id="4317653869502688143">Lūdzu, apstipriniet, ka vēlaties iestatīt <ph name="PLUGIN"/> spraudni. Jums vajadzētu iestatīt tikai tos spraudņus, kuriem uzticaties.</translation>
+<translation id="3926627843712816530">Lūdzu, apstipriniet, ka vēlaties iestatīt šo spraudni. Jums vajadzētu iestatīt tikai tos spraudņus, kuriem uzticaties.</translation>
+<translation id="1383141426028388991">Neizdevās iestatīt spraudni no <ph name="URL"/></translation>
+<translation id="6845533974506654842">nospiest</translation>
+<translation id="1842960171412779397">Atlasiet</translation>
+<translation id="6119846243427417423">aktivizt</translation>
+<translation id="5476505524087279545">neprbaudt</translation>
+<translation id="838869780401515933">prbaudt</translation>
+<translation id="4202807286478387388">lekt</translation>
+<translation id="795667975304826397">Nav izvēlēts neviens fails</translation>
+<translation id="8964020114565522021">Ievelciet failu šeit</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_nl.xtb b/webkit/glue/resources/webkit_strings_nl.xtb
new file mode 100644
index 0000000..b0bd112
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_nl.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="nl">
+<translation id="7658239707568436148">Annuleren</translation>
+<translation id="3789841737615482174">Installeren</translation>
+<translation id="8141602879876242471">Dit is een doorzoekbare index. Geef zoekwoorden op:</translation>
+<translation id="2653659639078652383">Verzenden</translation>
+<translation id="5939518447894949180">Herstellen</translation>
+<translation id="7364796246159120393">Bestand kiezen</translation>
+<translation id="2548326553472216322">Geen recente zoekopdrachten</translation>
+<translation id="6663448176199120256">Recente zoekopdrachten</translation>
+<translation id="1235745349614807883">Recente zoekopdrachten wissen</translation>
+<translation id="6807599807928161586">webgedeelte</translation>
+<translation id="3040011195152428237">link</translation>
+<translation id="5048533449481078685">lijstmarkering</translation>
+<translation id="8244226242650769279">image map</translation>
+<translation id="8597182159515967513">kop</translation>
+<translation id="5944544982112848342">2048 (hoog niveau)</translation>
+<translation id="2846343701378493991">1024 (gemiddeld niveau)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436">De plug-in <ph name="PLUGIN"/> is niet geïnstalleerd</translation>
+<translation id="4838490908464673667">De vereiste plug-in is niet geïnstalleerd</translation>
+<translation id="3600343118165084788">Klik hier om de plug-in te downloaden</translation>
+<translation id="8281246460978372009">Klik hier na het installeren van de invoegtoepassing om te vernieuwen</translation>
+<translation id="679352192834563463">Er is geen plug-in beschikbaar om deze inhoud weer te geven</translation>
+<translation id="8662565117025751661">Plug-in downloaden...</translation>
+<translation id="3771786644471114952">Plug-in ophalen</translation>
+<translation id="1275511093094545429">Plug-in <ph name="PLUGIN"/> vereist</translation>
+<translation id="3825324228893189080">Aanvullende plug-in vereist</translation>
+<translation id="4420062214988137980">Installatie van plug-in mislukt</translation>
+<translation id="4317653869502688143">Bevestig dat u de plugin <ph name="PLUGIN"/> wilt installeren. Installeer alleen plug-ins die u vertrouwt.</translation>
+<translation id="3926627843712816530">Bevestig dat u deze plug-in wilt installeren. Installeer alleen plug-ins die u vertrouwt.</translation>
+<translation id="1383141426028388991">Kan plug-in niet installeren van <ph name="URL"/></translation>
+<translation id="6845533974506654842">Indrukken</translation>
+<translation id="1842960171412779397">Selecteren</translation>
+<translation id="6119846243427417423">Activeren</translation>
+<translation id="5476505524087279545">Deselecteren</translation>
+<translation id="838869780401515933">Selecteren</translation>
+<translation id="4202807286478387388">Gaan naar</translation>
+<translation id="795667975304826397">Geen bestand gekozen</translation>
+<translation id="8964020114565522021">Sleep bestand hier naartoe</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_no.xtb b/webkit/glue/resources/webkit_strings_no.xtb
new file mode 100644
index 0000000..a36b0c4
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_no.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="no">
+<translation id="7658239707568436148">Avbryt</translation>
+<translation id="3789841737615482174">Installer</translation>
+<translation id="8141602879876242471">Dette er en søkbar indeks. Angi søkeordene:</translation>
+<translation id="2653659639078652383">Send</translation>
+<translation id="5939518447894949180">Tilbakestill</translation>
+<translation id="7364796246159120393">Velg fil</translation>
+<translation id="2548326553472216322">Ingen nylige søk</translation>
+<translation id="6663448176199120256">Nylige søk</translation>
+<translation id="1235745349614807883">Fjern nylige søk</translation>
+<translation id="6807599807928161586">nettområde</translation>
+<translation id="3040011195152428237">kobling</translation>
+<translation id="5048533449481078685">listemarkør</translation>
+<translation id="8244226242650769279">bildekart</translation>
+<translation id="8597182159515967513">overskrift</translation>
+<translation id="5944544982112848342">2048 (sterk)</translation>
+<translation id="2846343701378493991">1024 (middels)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436">Tilleggsmodulen <ph name="PLUGIN"/> er ikke installert</translation>
+<translation id="4838490908464673667">Den nødvendige tilleggsmodulen er ikke installert</translation>
+<translation id="3600343118165084788">Klikk her for å laste ned tilleggsmodulen</translation>
+<translation id="8281246460978372009">Når tilleggsmodulen er installert, klikker du her for å oppdatere</translation>
+<translation id="679352192834563463">Ingen tilleggsmodul tilgjengelig for å vise dette innholdet</translation>
+<translation id="8662565117025751661">Laster ned tilleggsmodul...</translation>
+<translation id="3771786644471114952">Få tilleggsmodul</translation>
+<translation id="1275511093094545429">Tilleggsmodulen <ph name="PLUGIN"/> kreves</translation>
+<translation id="3825324228893189080">Ytterligere tilleggsmodul kreves</translation>
+<translation id="4420062214988137980">Installasjon av tilleggsmodul mislyktes</translation>
+<translation id="4317653869502688143">Du må bekrefte om du vil installere tilleggsmodulen <ph name="PLUGIN"/>. Du bør bare installere moduler som du stoler på.</translation>
+<translation id="3926627843712816530">Du må bekrefte om du vil installere tilleggsmodulen. Du bør bare installere tilleggsmoduler som du stoler på.</translation>
+<translation id="1383141426028388991">Fikk ikke installert tilleggsmodulen fra <ph name="URL"/></translation>
+<translation id="6845533974506654842">trykk</translation>
+<translation id="1842960171412779397">velg</translation>
+<translation id="6119846243427417423">aktiver</translation>
+<translation id="5476505524087279545">fjern merke</translation>
+<translation id="838869780401515933">merk av</translation>
+<translation id="4202807286478387388">hopp</translation>
+<translation id="795667975304826397">Ingen fil valgt</translation>
+<translation id="8964020114565522021">Dra filen hit</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_pl.xtb b/webkit/glue/resources/webkit_strings_pl.xtb
new file mode 100644
index 0000000..0acd58a
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_pl.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="pl">
+<translation id="7658239707568436148">Anuluj</translation>
+<translation id="3789841737615482174">Zainstaluj</translation>
+<translation id="8141602879876242471">Ten indeks można przeszukiwać. Wprowadź wyszukiwane słowa kluczowe:</translation>
+<translation id="2653659639078652383">Prześlij</translation>
+<translation id="5939518447894949180">Resetuj</translation>
+<translation id="7364796246159120393">Wybierz plik</translation>
+<translation id="2548326553472216322">Brak ostatnich wyszukiwań</translation>
+<translation id="6663448176199120256">Ostatnie wyszukiwania</translation>
+<translation id="1235745349614807883">Wyczyść ostatnie wyszukiwania</translation>
+<translation id="6807599807928161586">obszar sieci</translation>
+<translation id="3040011195152428237">link</translation>
+<translation id="5048533449481078685">znacznik listy</translation>
+<translation id="8244226242650769279">mapa grafiki</translation>
+<translation id="8597182159515967513">nagłówek</translation>
+<translation id="5944544982112848342">2048 (wysoki poziom)</translation>
+<translation id="2846343701378493991">1024 (średni poziom)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436">Dodatek plug-in <ph name="PLUGIN"/> nie został zainstalowany</translation>
+<translation id="4838490908464673667">Wymagany dodatek plug-in nie został zainstalowany</translation>
+<translation id="3600343118165084788">Kliknij tutaj, aby pobrać dodatek plug-in</translation>
+<translation id="8281246460978372009">Po zainstalowaniu dodatku plug-in kliknij tutaj, aby odświeżyć</translation>
+<translation id="679352192834563463">Brak dostępnego dodatku plug-in umożliwiającego wyświetlenie tej treści</translation>
+<translation id="8662565117025751661">Pobieranie dodatku plug-in...</translation>
+<translation id="3771786644471114952">Pobierz dodatek plug-in</translation>
+<translation id="1275511093094545429">Wymagany dodatek plug-in <ph name="PLUGIN"/></translation>
+<translation id="3825324228893189080">Wymagany dodatkowy dodatek plug-in</translation>
+<translation id="4420062214988137980">Instalacja dodatku plug-in nie powiodła się</translation>
+<translation id="4317653869502688143">Potwierdź instalację dodatku plug-in <ph name="PLUGIN"/>. Należy instalować wyłącznie zaufane dodatki plug-in.</translation>
+<translation id="3926627843712816530">Potwierdź instalację tego dodatku plug-in. Należy instalować wyłącznie zaufane dodatki plug-in.</translation>
+<translation id="1383141426028388991">Nie można zainstalować dodatku plug-in z <ph name="URL"/></translation>
+<translation id="6845533974506654842">naciśnij</translation>
+<translation id="1842960171412779397">wybierz</translation>
+<translation id="6119846243427417423">aktywuj</translation>
+<translation id="5476505524087279545">odznacz</translation>
+<translation id="838869780401515933">zaznacz</translation>
+<translation id="4202807286478387388">przejdź</translation>
+<translation id="795667975304826397">Nie wybrano pliku</translation>
+<translation id="8964020114565522021">Przeciągnij plik tutaj</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_pt-BR.xtb b/webkit/glue/resources/webkit_strings_pt-BR.xtb
new file mode 100644
index 0000000..8466b83
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_pt-BR.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="pt-BR">
+<translation id="7658239707568436148">Cancelar</translation>
+<translation id="3789841737615482174">Instalar</translation>
+<translation id="8141602879876242471">Este é um índice pesquisável. Insira palavras-chave de pesquisa:</translation>
+<translation id="2653659639078652383">Enviar</translation>
+<translation id="5939518447894949180">Redefinir</translation>
+<translation id="7364796246159120393">Escolher arquivo</translation>
+<translation id="2548326553472216322">Nenhuma pesquisa recente</translation>
+<translation id="6663448176199120256">Pesquisas recentes</translation>
+<translation id="1235745349614807883">Limpar pesquisas recentes</translation>
+<translation id="6807599807928161586">área da web</translation>
+<translation id="3040011195152428237">link</translation>
+<translation id="5048533449481078685">marcador de lista</translation>
+<translation id="8244226242650769279">mapa da imagem</translation>
+<translation id="8597182159515967513">cabeçalho</translation>
+<translation id="5944544982112848342">2048 (Nota alta)</translation>
+<translation id="2846343701378493991">1024 (Nota média)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436">O plug-in <ph name="PLUGIN"/> não está instalado</translation>
+<translation id="4838490908464673667">O plug-in necessário não está instalado</translation>
+<translation id="3600343118165084788">Clique aqui para fazer download do plug-in</translation>
+<translation id="8281246460978372009">Depois de instalar o plug-in, clique aqui para atualizar</translation>
+<translation id="679352192834563463">Nenhum plug-in disponível para exibir este conteúdo</translation>
+<translation id="8662565117025751661">Fazendo download do plug-in...</translation>
+<translation id="3771786644471114952">Obter plug-in</translation>
+<translation id="1275511093094545429"><ph name="PLUGIN"/> plug-in necessário</translation>
+<translation id="3825324228893189080">Plug-in adicional necessário</translation>
+<translation id="4420062214988137980">Falha de instalação de plug-in</translation>
+<translation id="4317653869502688143">Confirme se deseja instalar este plug-in <ph name="PLUGIN"/>. Instale somente plug-ins confiáveis.</translation>
+<translation id="3926627843712816530">Confirme se deseja instalar este plug-in. Instale somente plug-ins confiáveis.</translation>
+<translation id="1383141426028388991">Falha ao instalar plug-in a partir de <ph name="URL"/></translation>
+<translation id="6845533974506654842">pressione</translation>
+<translation id="1842960171412779397">selecione</translation>
+<translation id="6119846243427417423">ativar</translation>
+<translation id="5476505524087279545">desmarcar</translation>
+<translation id="838869780401515933">marcar</translation>
+<translation id="4202807286478387388">pular</translation>
+<translation id="795667975304826397">Nenhum arquivo selecionado</translation>
+<translation id="8964020114565522021">Arraste o arquivo até aquil</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_pt-PT.xtb b/webkit/glue/resources/webkit_strings_pt-PT.xtb
new file mode 100644
index 0000000..afc7d4b1
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_pt-PT.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="pt-PT">
+<translation id="7658239707568436148">Cancelar</translation>
+<translation id="3789841737615482174">Instalar</translation>
+<translation id="8141602879876242471">Este índice é pesquisável. Introduza palavras-chave de pesquisa:</translation>
+<translation id="2653659639078652383">Submeter</translation>
+<translation id="5939518447894949180">Repor</translation>
+<translation id="7364796246159120393">Escolher ficheiro</translation>
+<translation id="2548326553472216322">Nenhuma pesquisa recente</translation>
+<translation id="6663448176199120256">Pesquisas recentes</translation>
+<translation id="1235745349614807883">Limpar pesquisas recentes</translation>
+<translation id="6807599807928161586">Área Web</translation>
+<translation id="3040011195152428237">link</translation>
+<translation id="5048533449481078685">marcador de lista</translation>
+<translation id="8244226242650769279">mapa de imagem</translation>
+<translation id="8597182159515967513">cabeçalho</translation>
+<translation id="5944544982112848342">2048 (Tamanho grande)</translation>
+<translation id="2846343701378493991">1024 (Tamanho médio)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436">O plug-in <ph name="PLUGIN"/> não está instalado</translation>
+<translation id="4838490908464673667">O plug-in necessário não está instalado</translation>
+<translation id="3600343118165084788">Clique aqui para transferir o plug-in</translation>
+<translation id="8281246460978372009">Após instalar o plug-in, clique aqui para actualizar</translation>
+<translation id="679352192834563463">Nenhum plug-in disponível para apresentar este conteúdo</translation>
+<translation id="8662565117025751661">A transferir o plug-in…</translation>
+<translation id="3771786644471114952">Obter plug-in</translation>
+<translation id="1275511093094545429">Plug-in <ph name="PLUGIN"/> necessário</translation>
+<translation id="3825324228893189080">Plug-in adicional necessário</translation>
+<translation id="4420062214988137980">A instalação do plug-in falhou</translation>
+<translation id="4317653869502688143">Confirme que pretende instalar o plug-in <ph name="PLUGIN"/>. Apenas deverá instalar plug-ins fidedignos.</translation>
+<translation id="3926627843712816530">Confirme que pretende instalar este plug-in. Apenas deverá instalar plug-ins fidedignos.</translation>
+<translation id="1383141426028388991">Falha ao instalar plug-in de <ph name="URL"/></translation>
+<translation id="6845533974506654842">premir</translation>
+<translation id="1842960171412779397">seleccionar</translation>
+<translation id="6119846243427417423">activar</translation>
+<translation id="5476505524087279545">desmarcar</translation>
+<translation id="838869780401515933">verificar</translation>
+<translation id="4202807286478387388">ir para</translation>
+<translation id="795667975304826397">Nenhum ficheiro seleccionado</translation>
+<translation id="8964020114565522021">Arraste o ficheiro para aqui</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_ro.xtb b/webkit/glue/resources/webkit_strings_ro.xtb
new file mode 100644
index 0000000..04e57ab
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_ro.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ro">
+<translation id="7658239707568436148">Anulaţi</translation>
+<translation id="3789841737615482174">Instalaţi</translation>
+<translation id="8141602879876242471">Acesta este un index în care se poate căuta. Introduceţi cuvintele cheie pentru căutare:</translation>
+<translation id="2653659639078652383">Trimiteţi</translation>
+<translation id="5939518447894949180">Resetaţi</translation>
+<translation id="7364796246159120393">Alegeţi fişierul</translation>
+<translation id="2548326553472216322">Nicio căutare recentă</translation>
+<translation id="6663448176199120256">Căutări recente</translation>
+<translation id="1235745349614807883">Ştergeţi căutările recente</translation>
+<translation id="6807599807928161586">zona Web</translation>
+<translation id="3040011195152428237">link</translation>
+<translation id="5048533449481078685">marcator listă</translation>
+<translation id="8244226242650769279">hartă cu imagini</translation>
+<translation id="8597182159515967513">titlu</translation>
+<translation id="5944544982112848342">2048 (Grad înalt)</translation>
+<translation id="2846343701378493991">1024 (Grad mediu)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436">Plug-in-ul <ph name="PLUGIN"/> nu este instalat</translation>
+<translation id="4838490908464673667">Plug-in-ul necesar nu este instalat</translation>
+<translation id="3600343118165084788">Faceţi clic aici pentru a descărca plug-in-ul</translation>
+<translation id="8281246460978372009">După instalarea plug-in-ului, faceţi clic aici pentru a reactualiza</translation>
+<translation id="679352192834563463">Niciun plug-in disponibil pentru a afişa acest conţinut</translation>
+<translation id="8662565117025751661">Descărcare plug-in...</translation>
+<translation id="3771786644471114952">Obţineţi plug-in-ul</translation>
+<translation id="1275511093094545429">Este necesar plug-in-ul <ph name="PLUGIN"/></translation>
+<translation id="3825324228893189080">Este necesar un plug-in suplimentar</translation>
+<translation id="4420062214988137980">Instalarea plug-in-ului a eşuat</translation>
+<translation id="4317653869502688143">Confirmaţi că doriţi să instalaţi plug-in-ul <ph name="PLUGIN"/>. Ar trebui să instalaţi numai plug-in-uri în care aveţi încredere.</translation>
+<translation id="3926627843712816530">Confirmaţi că doriţi să instalaţi acest plug-in. Ar trebui să instalaţi numai plug-in-uri în care aveţi încredere.</translation>
+<translation id="1383141426028388991">Instalarea plug-in-ului de la <ph name="URL"/> a eşuat</translation>
+<translation id="6845533974506654842">Apăsaţi</translation>
+<translation id="1842960171412779397">Selectaţi</translation>
+<translation id="6119846243427417423">Activaţi</translation>
+<translation id="5476505524087279545">Debifaţi</translation>
+<translation id="838869780401515933">Bifaţi</translation>
+<translation id="4202807286478387388">Salt</translation>
+<translation id="795667975304826397">Nu s-au ales fişiere</translation>
+<translation id="8964020114565522021">Trageţi fişierul aici</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_ru.xtb b/webkit/glue/resources/webkit_strings_ru.xtb
new file mode 100644
index 0000000..6e29a72
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_ru.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="ru">
+<translation id="7658239707568436148">Отмена</translation>
+<translation id="3789841737615482174">Установить</translation>
+<translation id="8141602879876242471">Это индекс с возможностью поиска. Введите ключевые слова для поиска:</translation>
+<translation id="2653659639078652383">Отправить</translation>
+<translation id="5939518447894949180">Изменить</translation>
+<translation id="7364796246159120393">Выберите файл</translation>
+<translation id="2548326553472216322">Нет недавних поисков</translation>
+<translation id="6663448176199120256">Недавние поиски</translation>
+<translation id="1235745349614807883">Очистить недавние поиски</translation>
+<translation id="6807599807928161586">область Интернетеа</translation>
+<translation id="3040011195152428237">ссылка</translation>
+<translation id="5048533449481078685">маркер списка</translation>
+<translation id="8244226242650769279">графическая карта</translation>
+<translation id="8597182159515967513">заголовок</translation>
+<translation id="5944544982112848342">2048 (Крупный размер)</translation>
+<translation id="2846343701378493991">1024 (Средний размер)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436">Плагин <ph name="PLUGIN"/> не установлен</translation>
+<translation id="4838490908464673667">Не установлен необходимый плагин.</translation>
+<translation id="3600343118165084788">Нажмите здесь, чтобы загрузить плагин</translation>
+<translation id="8281246460978372009">После установки подключаемого модуля нажмите здесь для обновления</translation>
+<translation id="679352192834563463">Недоступен плагин для отображения этого содержания</translation>
+<translation id="8662565117025751661">Загрузка подключаемого модуля...</translation>
+<translation id="3771786644471114952">Получить плагин</translation>
+<translation id="1275511093094545429">Необходим плагин <ph name="PLUGIN"/></translation>
+<translation id="3825324228893189080">Необходим дополнительный плагин</translation>
+<translation id="4420062214988137980">Ошибка при установке плагина</translation>
+<translation id="4317653869502688143">Подтвердите, что хотите установить плагин <ph name="PLUGIN"/>. Устанавливать следует модули только тех издателей, которым вы доверяете.</translation>
+<translation id="3926627843712816530">Подтвердите, что хотите установить этот плагин. Устанавливать следует модули только тех издателей, которым вы доверяете.</translation>
+<translation id="1383141426028388991">Не удалось установить плагин с <ph name="URL"/></translation>
+<translation id="6845533974506654842">нажать</translation>
+<translation id="1842960171412779397">выбрать</translation>
+<translation id="6119846243427417423">активировать</translation>
+<translation id="5476505524087279545">снять галочку</translation>
+<translation id="838869780401515933">поставить галочку</translation>
+<translation id="4202807286478387388">перейти</translation>
+<translation id="795667975304826397">Файл не выбран</translation>
+<translation id="8964020114565522021">Перетащите файл сюда</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_sk.xtb b/webkit/glue/resources/webkit_strings_sk.xtb
new file mode 100644
index 0000000..c429d1a
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_sk.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sk">
+<translation id="7658239707568436148">Zrušiť</translation>
+<translation id="3789841737615482174">Inštalovať</translation>
+<translation id="8141602879876242471">Tento index sa dá prehľadávať. Zadajte kľúčové slová na vyhľadanie:</translation>
+<translation id="2653659639078652383">Odoslať</translation>
+<translation id="5939518447894949180">Vynulovať</translation>
+<translation id="7364796246159120393">Vybrať súbor</translation>
+<translation id="2548326553472216322">Žiadne posledné vyhľadávania</translation>
+<translation id="6663448176199120256">Posledné vyhľadávania</translation>
+<translation id="1235745349614807883">Vyčistiť posledné vyhľadávania</translation>
+<translation id="6807599807928161586">webová oblasť</translation>
+<translation id="3040011195152428237">odkaz</translation>
+<translation id="5048533449481078685">ukazovateľ v zozname</translation>
+<translation id="8244226242650769279">mapa obrázka</translation>
+<translation id="8597182159515967513">nadpis</translation>
+<translation id="5944544982112848342">2048 (vysoký stupeň)</translation>
+<translation id="2846343701378493991">1024 (stredný stupeň)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/> <ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436">Nie je nainštalovaný doplnkový modul <ph name="PLUGIN"/></translation>
+<translation id="4838490908464673667">Nie je nainštalovaný vyžadovaný doplnkový modul.</translation>
+<translation id="3600343118165084788">Kliknite sem, ak chcete prevziať doplnkový modul</translation>
+<translation id="8281246460978372009">Po inštalácii doplnkového modulu kliknite sem kvôli obnoveniu obsahu</translation>
+<translation id="679352192834563463">Na zobrazenie tohto obsahu nie je k dispozícii žiadny doplnkový modul</translation>
+<translation id="8662565117025751661">Preberá sa doplnkový modul...</translation>
+<translation id="3771786644471114952">Získať doplnkový modul</translation>
+<translation id="1275511093094545429">Vyžaduje sa doplnkový modul <ph name="PLUGIN"/></translation>
+<translation id="3825324228893189080">Vyžaduje sa ďalší doplnkový modul</translation>
+<translation id="4420062214988137980">Nedal sa nainštalovať doplnkový modul</translation>
+<translation id="4317653869502688143">Potvrďte, že naozaj chcete nainštalovať doplnkový modul <ph name="PLUGIN"/>. Mali by ste inštalovať len doplnkové moduly, ktorým dôverujete.</translation>
+<translation id="3926627843712816530">Potvrďte, že naozaj chcete nainštalovať tento doplnkový modul. Mali by ste inštalovať len doplnkové moduly, ktorým dôverujete.</translation>
+<translation id="1383141426028388991">Nedal sa nainštalovať doplnkový modul z adresy <ph name="URL"/></translation>
+<translation id="6845533974506654842">stlačiť</translation>
+<translation id="1842960171412779397">vybrať</translation>
+<translation id="6119846243427417423">aktivovať</translation>
+<translation id="5476505524087279545">zrušiť označenie</translation>
+<translation id="838869780401515933">označiť</translation>
+<translation id="4202807286478387388">skok</translation>
+<translation id="795667975304826397">Nie je vybratý žiadny súbor</translation>
+<translation id="8964020114565522021">Súbor presunúť sem</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_sl.xtb b/webkit/glue/resources/webkit_strings_sl.xtb
new file mode 100644
index 0000000..dd0e2ed
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_sl.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sl">
+<translation id="7658239707568436148">Prekliči</translation>
+<translation id="3789841737615482174">Namesti</translation>
+<translation id="8141602879876242471">To je kazalo, ki omogoča iskanje. Vnesite ključne besede za iskanje:</translation>
+<translation id="2653659639078652383">Pošlji</translation>
+<translation id="5939518447894949180">Ponastavi</translation>
+<translation id="7364796246159120393">Izberi datoteko</translation>
+<translation id="2548326553472216322">Ni zadnjih iskanj</translation>
+<translation id="6663448176199120256">Zadnja iskanja</translation>
+<translation id="1235745349614807883">Počisti zadnja iskanja</translation>
+<translation id="6807599807928161586">spletno področje</translation>
+<translation id="3040011195152428237">povezava</translation>
+<translation id="5048533449481078685">označevalnik seznama</translation>
+<translation id="8244226242650769279">slikovni zemljevid</translation>
+<translation id="8597182159515967513">naslov</translation>
+<translation id="5944544982112848342">2048 (visoka stopnja)</translation>
+<translation id="2846343701378493991">1024 (srednja stopnja)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436">Vtičnik <ph name="PLUGIN"/> ni nameščen</translation>
+<translation id="4838490908464673667">Potrebni vtičnik ni nameščen</translation>
+<translation id="3600343118165084788">Za prenos vtičnika kliknite tukaj</translation>
+<translation id="8281246460978372009">Po namestitvi vtičnika za osvežitev kliknite tu</translation>
+<translation id="679352192834563463">Za prikaz te vsebine ni na voljo noben vtičnik</translation>
+<translation id="8662565117025751661">Prenos vtičnika ...</translation>
+<translation id="3771786644471114952">Dobite vtičnik</translation>
+<translation id="1275511093094545429">Potreben je vtičnik <ph name="PLUGIN"/></translation>
+<translation id="3825324228893189080">Potreben je dodatni vtičnik</translation>
+<translation id="4420062214988137980">Namestitev vtičnika ni bila uspešna</translation>
+<translation id="4317653869502688143">Prosimo potrdite, da želite namestiti vtičnik <ph name="PLUGIN"/>. Priporočamo vam, da namestite le vtičnike, ki so vredni zaupanja.</translation>
+<translation id="3926627843712816530">Potrdite, da želite namestiti ta vtičnik. Priporočamo vam, da namestite le vtičnike, ki so vredni zaupanja.</translation>
+<translation id="1383141426028388991">Namestitev vtičnika z naslova <ph name="URL"/> ni bila uspešna.</translation>
+<translation id="6845533974506654842">pritisni</translation>
+<translation id="1842960171412779397">izberi</translation>
+<translation id="6119846243427417423">aktiviraj</translation>
+<translation id="5476505524087279545">počisti izbor</translation>
+<translation id="838869780401515933">potrdi</translation>
+<translation id="4202807286478387388">skoči</translation>
+<translation id="795667975304826397">Nobena datoteka ni izbrana</translation>
+<translation id="8964020114565522021">Datoteko povleci sem</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_sr.xtb b/webkit/glue/resources/webkit_strings_sr.xtb
new file mode 100644
index 0000000..bdbca13e
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_sr.xtb
@@ -0,0 +1,41 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sr">
+<translation id="7658239707568436148">Откажи</translation>
+<translation id="3789841737615482174">Инсталирај</translation>
+<translation id="8141602879876242471">Ово је индекс који може да се претражује. Унесите кључне речи за претрагу:</translation>
+<translation id="2653659639078652383">Пошаљи</translation>
+<translation id="5939518447894949180">Ресетуј</translation>
+<translation id="7364796246159120393">Одаберите датотеку</translation>
+<translation id="2548326553472216322">Нема недавних претрага</translation>
+<translation id="6663448176199120256">Недавне претраге</translation>
+<translation id="1235745349614807883">Обриши недавне претраге</translation>
+<translation id="6807599807928161586">веб област</translation>
+<translation id="3040011195152428237">веза</translation>
+<translation id="5048533449481078685">означивач листе</translation>
+<translation id="8244226242650769279">мапа слике</translation>
+<translation id="8597182159515967513">наслов</translation>
+<translation id="5944544982112848342">2048 (високи степен)</translation>
+<translation id="2846343701378493991">1024 (средњи степен)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436">Додатна компонента <ph name="PLUGIN"/> није инсталирана</translation>
+<translation id="4838490908464673667">Потребна додатна компонента није инсталирана</translation>
+<translation id="3600343118165084788">Кликните овде да бисте преузели додатну компоненту</translation>
+<translation id="8281246460978372009">Након инсталирања додатне компоненте, кликните овде да бисте освежили</translation>
+<translation id="679352192834563463">Нема доступне додатне компоненте за приказивање овог садржаја</translation>
+<translation id="8662565117025751661">Преузимање додатне компоненте...</translation>
+<translation id="3771786644471114952">Набави додатну компоненту</translation>
+<translation id="1275511093094545429">Потребна је додатна компонента <ph name="PLUGIN"/></translation>
+<translation id="3825324228893189080">Потребна је додатна компонента</translation>
+<translation id="4420062214988137980">Инсталирање додатне компоненте није успело</translation>
+<translation id="4317653869502688143">Потврдите да желите да инсталирате додатну компоненту <ph name="PLUGIN"/>. Требало би да инсталирате само додатне компоненте које сматрате поузданима.</translation>
+<translation id="3926627843712816530">Потврдите да желите да инсталирате ову додатну компоненту. Требало би да инсталирате само додатне компоненте које сматрате поузданима.</translation>
+<translation id="6845533974506654842">притисни</translation>
+<translation id="1842960171412779397">изабери</translation>
+<translation id="6119846243427417423">активирај</translation>
+<translation id="5476505524087279545">опозови избор</translation>
+<translation id="838869780401515933">изабери</translation>
+<translation id="4202807286478387388">прескочи</translation>
+<translation id="795667975304826397">Није одабрана ниједна датотека</translation>
+<translation id="8964020114565522021">Превуците датотеку овде</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_sv.xtb b/webkit/glue/resources/webkit_strings_sv.xtb
new file mode 100644
index 0000000..6dc3a1b9
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_sv.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="sv">
+<translation id="7658239707568436148">Avbryt</translation>
+<translation id="3789841737615482174">Installera</translation>
+<translation id="8141602879876242471">Det här är ett sökbart index. Skriv sökord:</translation>
+<translation id="2653659639078652383">Skicka</translation>
+<translation id="5939518447894949180">Återställ</translation>
+<translation id="7364796246159120393">Välj fil</translation>
+<translation id="2548326553472216322">Inga nya sökningar</translation>
+<translation id="6663448176199120256">Senaste sökningar</translation>
+<translation id="1235745349614807883">Rensa senaste sökningar</translation>
+<translation id="6807599807928161586">webbområde</translation>
+<translation id="3040011195152428237">länk</translation>
+<translation id="5048533449481078685">listmarkör</translation>
+<translation id="8244226242650769279">bildkarta</translation>
+<translation id="8597182159515967513">rubrik</translation>
+<translation id="5944544982112848342">2048 (hög)</translation>
+<translation id="2846343701378493991">1024 (medel)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436"><ph name="PLUGIN"/>-plugin-programmet har inte installerats</translation>
+<translation id="4838490908464673667">De begärda plugin-programmen har inte installerats</translation>
+<translation id="3600343118165084788">Klicka här för att ladda ned plugin-program</translation>
+<translation id="8281246460978372009">Klicka här för att uppdatera när du har installerat plugin-programmet</translation>
+<translation id="679352192834563463">Det finns inget plugin-program för att visa det här innehållet</translation>
+<translation id="8662565117025751661">Laddar ned plugin-program...</translation>
+<translation id="3771786644471114952">Hämta plugin-program</translation>
+<translation id="1275511093094545429"><ph name="PLUGIN"/>-pluginprogram krävs</translation>
+<translation id="3825324228893189080">Ytterligare plugin-program krävs</translation>
+<translation id="4420062214988137980">Installationen av plugin-programmet misslyckades</translation>
+<translation id="4317653869502688143">Bekräfta att du vill installera <ph name="PLUGIN"/>-plugin-programmet. Installera bara tillförlitliga plugin-program.</translation>
+<translation id="3926627843712816530">Bekräfta att du vill installera det här plugin-programmet. Installera bara tillförlitliga plugin-program.</translation>
+<translation id="1383141426028388991">Kunde inte installera plugin-program från <ph name="URL"/></translation>
+<translation id="6845533974506654842">tryck</translation>
+<translation id="1842960171412779397">välj</translation>
+<translation id="6119846243427417423">aktivera</translation>
+<translation id="5476505524087279545">kryssa av</translation>
+<translation id="838869780401515933">kryssa för</translation>
+<translation id="4202807286478387388">fortsätta</translation>
+<translation id="795667975304826397">Ingen fil har valts</translation>
+<translation id="8964020114565522021">Dra filen hit</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_th.xtb b/webkit/glue/resources/webkit_strings_th.xtb
new file mode 100644
index 0000000..8f1059f
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_th.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="th">
+<translation id="7658239707568436148">ยกเลิก</translation>
+<translation id="3789841737615482174">ติดตั้ง</translation>
+<translation id="8141602879876242471">นี่คือดัชนีที่สามารถค้นหาได้ ป้อนคำหลักในการค้นหา:</translation>
+<translation id="2653659639078652383">ส่ง</translation>
+<translation id="5939518447894949180">ตั้งค่าใหม่</translation>
+<translation id="7364796246159120393">ปิดไฟล์</translation>
+<translation id="2548326553472216322">ไม่พบการค้นหาล่าสุด</translation>
+<translation id="6663448176199120256">การค้นหาล่าสุด</translation>
+<translation id="1235745349614807883">ลบการค้นหาล่าสุด</translation>
+<translation id="6807599807928161586">พื้นที่เว็บ</translation>
+<translation id="3040011195152428237">ลิงก์</translation>
+<translation id="5048533449481078685">ผู้สร้างรายการ</translation>
+<translation id="8244226242650769279">แผนที่รูปภาพ</translation>
+<translation id="8597182159515967513">ส่วนหัว</translation>
+<translation id="5944544982112848342">2048 (เกรดสูง)</translation>
+<translation id="2846343701378493991">1024 (เกรดปานกลาง)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436"><ph name="PLUGIN"/> ไม่ได้ติดตั้งปลั๊กอิน</translation>
+<translation id="4838490908464673667">ไม่ได้ติดตั้งปลั๊กอินที่จำเป็น</translation>
+<translation id="3600343118165084788">คลิกที่นี่เพื่อดาวน์โหลดปลั๊กอิน</translation>
+<translation id="8281246460978372009">หลังจากติดตั้งปลั๊กอิน คลิกที่นี่เพื่อรีเฟรซ</translation>
+<translation id="679352192834563463">ไม่มีปลั๊กอินที่จะแสดงเนื้อหานี้</translation>
+<translation id="8662565117025751661">กำลังดาวน์โหลดปลั๊กอิน...</translation>
+<translation id="3771786644471114952">ติดตั้งปลั๊กอิน</translation>
+<translation id="1275511093094545429">ต้องใช้ปลั๊กอิน <ph name="PLUGIN"/></translation>
+<translation id="3825324228893189080">ต้องการปลั๊กอินเพิ่มเติม</translation>
+<translation id="4420062214988137980">การติดตั้งปลั๊กอินล้มเหลว</translation>
+<translation id="4317653869502688143">โปรดยืนยันว่าคุณต้องการที่จะติดตั้ง <ph name="PLUGIN"/> ปลั๊กอิน คุณควรติดตั้งปลั๊กอินที่คุณเชื่อถือเท่านั้น</translation>
+<translation id="3926627843712816530">โปรดยืนยันว่าคุณต้องการติดตั้งปลั๊กอินนี้ คุณควรติดตั้งปลั๊กอินที่คุณเชื่อถือเท่านั้น</translation>
+<translation id="1383141426028388991">การติดตั้งปลั๊กอินจาก <ph name="URL"/> ล้มเหลว</translation>
+<translation id="6845533974506654842">กด</translation>
+<translation id="1842960171412779397">เลือก</translation>
+<translation id="6119846243427417423">เปิดใช้งาน</translation>
+<translation id="5476505524087279545">ยกเลิกการทำเครื่องหมาย</translation>
+<translation id="838869780401515933">ทำเครื่องหมาย</translation>
+<translation id="4202807286478387388">ข้าม</translation>
+<translation id="795667975304826397">ไม่ได้เลือกไฟล์ใด</translation>
+<translation id="8964020114565522021">ลากไฟล์มาที่นี่</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_tr.xtb b/webkit/glue/resources/webkit_strings_tr.xtb
new file mode 100644
index 0000000..f9c8c66
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_tr.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="tr">
+<translation id="7658239707568436148">İptal</translation>
+<translation id="3789841737615482174">Yükle</translation>
+<translation id="8141602879876242471">Bu dizinde arama yapılabilir. Arama anahtar kelimeleri girin:</translation>
+<translation id="2653659639078652383">Gönder</translation>
+<translation id="5939518447894949180">Sıfırla</translation>
+<translation id="7364796246159120393">Dosya Seç</translation>
+<translation id="2548326553472216322">Yeni arama yok</translation>
+<translation id="6663448176199120256">Son Aramalar</translation>
+<translation id="1235745349614807883">Son Aramaları Temizle</translation>
+<translation id="6807599807928161586">web alanı</translation>
+<translation id="3040011195152428237">bağlantı</translation>
+<translation id="5048533449481078685">liste işaretçisi</translation>
+<translation id="8244226242650769279">resim haritası</translation>
+<translation id="8597182159515967513">başlık</translation>
+<translation id="5944544982112848342">2048 (Yüksek Düzey)</translation>
+<translation id="2846343701378493991">1024 (Orta Düzey)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436"><ph name="PLUGIN"/> eklentisi yüklü değil</translation>
+<translation id="4838490908464673667">Gereken eklenti yüklü değil</translation>
+<translation id="3600343118165084788">Eklentiyi indirmek için burayı tıklayın</translation>
+<translation id="8281246460978372009">Eklentiyi yükledikten sonra yenilemek için burayı tıklayın</translation>
+<translation id="679352192834563463">Bu içeriği görüntüleyecek eklenti yok</translation>
+<translation id="8662565117025751661">Eklenti indiriliyor...</translation>
+<translation id="3771786644471114952">Eklenti Al</translation>
+<translation id="1275511093094545429"><ph name="PLUGIN"/> eklentisi gerekiyor</translation>
+<translation id="3825324228893189080">Ek eklenti gerekiyor</translation>
+<translation id="4420062214988137980">Eklenti kurulumu başarısız oldu</translation>
+<translation id="4317653869502688143">Lütfen <ph name="PLUGIN"/> eklentisini yüklemek istediğinizi onaylayın. Yalnızca güvendiğiniz eklentileri yüklemelisiniz.</translation>
+<translation id="3926627843712816530">Lütfen bu eklentiyi yüklemek istediğinizi onaylayın. Yalnızca güvendiğiniz eklentileri yüklemelisiniz.</translation>
+<translation id="1383141426028388991">Eklenti, <ph name="URL"/> kaynağından kaldırılamadı</translation>
+<translation id="6845533974506654842">bas</translation>
+<translation id="1842960171412779397">seç</translation>
+<translation id="6119846243427417423">etkinleştir</translation>
+<translation id="5476505524087279545">işareti kaldır</translation>
+<translation id="838869780401515933">işaretle</translation>
+<translation id="4202807286478387388">git</translation>
+<translation id="795667975304826397">Dosya seçilmedi</translation>
+<translation id="8964020114565522021">Dosyayı buraya sürükleyin</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_uk.xtb b/webkit/glue/resources/webkit_strings_uk.xtb
new file mode 100644
index 0000000..37c5540
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_uk.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="uk">
+<translation id="7658239707568436148">Скасувати</translation>
+<translation id="3789841737615482174">Інсталювати</translation>
+<translation id="8141602879876242471">Цей доступний для пошуку індекс. Введіть ключові слова пошуку:</translation>
+<translation id="2653659639078652383">Надіслати</translation>
+<translation id="5939518447894949180">Скинути</translation>
+<translation id="7364796246159120393">Вибрати файл</translation>
+<translation id="2548326553472216322">Немає останніх пошуків</translation>
+<translation id="6663448176199120256">Останні пошуки</translation>
+<translation id="1235745349614807883">Очистити останні пошуки</translation>
+<translation id="6807599807928161586">область Інтернету</translation>
+<translation id="3040011195152428237">посилання</translation>
+<translation id="5048533449481078685">маркер списку</translation>
+<translation id="8244226242650769279">мапа зображення</translation>
+<translation id="8597182159515967513">заголовок</translation>
+<translation id="5944544982112848342">2048 (Високий рівень)</translation>
+<translation id="2846343701378493991">1024 (Середній рівень)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436">Модуль <ph name="PLUGIN"/> не інстальовано</translation>
+<translation id="4838490908464673667">Потрібний модуль не інстальовано</translation>
+<translation id="3600343118165084788">Натисніть тут, щоб завантажити модуль</translation>
+<translation id="8281246460978372009">Після інсталяції модуля натисніть тут, щоб оновити</translation>
+<translation id="679352192834563463">Немає доступного модуля для відображення цього вмісту</translation>
+<translation id="8662565117025751661">Завантаження модуля...</translation>
+<translation id="3771786644471114952">Отримати модуль</translation>
+<translation id="1275511093094545429">Потрібен модуль <ph name="PLUGIN"/></translation>
+<translation id="3825324228893189080">Потрібен додатковий модуль.</translation>
+<translation id="4420062214988137980">Не вдалось інсталювати модуль</translation>
+<translation id="4317653869502688143">Підтвердьте інсталяцію модуля <ph name="PLUGIN"/>. Слід інсталювати лише модулі, які вважаєте надійними.</translation>
+<translation id="3926627843712816530">Підтвердьте інсталяцію цього модуля. Слід інсталювати лише модулі, які вважаєте надійними.</translation>
+<translation id="1383141426028388991">Не вдалось інсталювати модуль із <ph name="URL"/></translation>
+<translation id="6845533974506654842">натиснути</translation>
+<translation id="1842960171412779397">вибрати</translation>
+<translation id="6119846243427417423">активувати</translation>
+<translation id="5476505524087279545">зняти прапорець</translation>
+<translation id="838869780401515933">установити прапорець</translation>
+<translation id="4202807286478387388">перейти</translation>
+<translation id="795667975304826397">Файл не вибрано</translation>
+<translation id="8964020114565522021">Перетягніть файл сюди</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_vi.xtb b/webkit/glue/resources/webkit_strings_vi.xtb
new file mode 100644
index 0000000..2d60a93
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_vi.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="vi">
+<translation id="7658239707568436148">Huỷ</translation>
+<translation id="3789841737615482174">Cài đặt</translation>
+<translation id="8141602879876242471">Đây là chỉ mục có thể tìm kiếm. Nhập từ khoá tìm kiếm vào:</translation>
+<translation id="2653659639078652383">Gửi</translation>
+<translation id="5939518447894949180">Đặt lại</translation>
+<translation id="7364796246159120393">Chọn Tệp tin</translation>
+<translation id="2548326553472216322">Không có tìm kiếm nào gần đây</translation>
+<translation id="6663448176199120256">Tìm kiếm Gần đây</translation>
+<translation id="1235745349614807883">Xoá Tìm kiếm Gần đây</translation>
+<translation id="6807599807928161586">khu vực web</translation>
+<translation id="3040011195152428237">liên kết</translation>
+<translation id="5048533449481078685">đánh dấu danh sách</translation>
+<translation id="8244226242650769279">bản đồ hình ảnh</translation>
+<translation id="8597182159515967513">đầu đề</translation>
+<translation id="5944544982112848342">2048 (Cấp độ cao)</translation>
+<translation id="2846343701378493991">1024 (Loại Trung bình)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436"><ph name="PLUGIN"/> plgin không được cài đặt</translation>
+<translation id="4838490908464673667">Plugin yêu cầu không được cài đặt</translation>
+<translation id="3600343118165084788">Nhấp vào đây để tải plugin xuống</translation>
+<translation id="8281246460978372009">Sau khi cài đặt plugin, nhấp vào đây để làm mới</translation>
+<translation id="679352192834563463">Không plugin nào có sẵn để hiển thị nội dung này</translation>
+<translation id="8662565117025751661">Đang tải xuống plugin...</translation>
+<translation id="3771786644471114952">Lấy Plugin</translation>
+<translation id="1275511093094545429"><ph name="PLUGIN"/> plugin cần</translation>
+<translation id="3825324228893189080">Cần plugin bổ sung</translation>
+<translation id="4420062214988137980">Không cài đặt plugin được</translation>
+<translation id="4317653869502688143">Vui lòng xác nhận rằng bạn muốn cài đặt plugin <ph name="PLUGIN"/>. Bạn chỉ nên cài đặt plugin mà mình tin cậy.</translation>
+<translation id="3926627843712816530">Hãy xác nhận rằng bạn muốn cài đặt plugin này. Bạn chỉ nên cài đặt plugin mà mình tin cậy.</translation>
+<translation id="1383141426028388991">Lỗi cài đặt plugin từ <ph name="URL"/></translation>
+<translation id="6845533974506654842">nhấn</translation>
+<translation id="1842960171412779397">chọn</translation>
+<translation id="6119846243427417423">kích hoạt</translation>
+<translation id="5476505524087279545">bỏ chọn</translation>
+<translation id="838869780401515933">chọn</translation>
+<translation id="4202807286478387388">chuyển</translation>
+<translation id="795667975304826397">Không có tệp tin nào được chọn</translation>
+<translation id="8964020114565522021">Kéo tệp tin tại đây</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_zh-CN.xtb b/webkit/glue/resources/webkit_strings_zh-CN.xtb
new file mode 100644
index 0000000..e93fb4d
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_zh-CN.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="zh-CN">
+<translation id="7658239707568436148">取消</translation>
+<translation id="3789841737615482174">安装</translation>
+<translation id="8141602879876242471">这是一个可搜索的索引。 输入搜索关键字:</translation>
+<translation id="2653659639078652383">提交</translation>
+<translation id="5939518447894949180">重置</translation>
+<translation id="7364796246159120393">选择文件</translation>
+<translation id="2548326553472216322">近期无搜索</translation>
+<translation id="6663448176199120256">近期搜索</translation>
+<translation id="1235745349614807883">清除最近的搜索</translation>
+<translation id="6807599807928161586">网络区域</translation>
+<translation id="3040011195152428237">链接</translation>
+<translation id="5048533449481078685">列表标记</translation>
+<translation id="8244226242650769279">影像地图</translation>
+<translation id="8597182159515967513">标题</translation>
+<translation id="5944544982112848342">2048(高强度)</translation>
+<translation id="2846343701378493991">1024(中等强度)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436"><ph name="PLUGIN"/></translation>
+<translation id="4838490908464673667">未安装所需插件</translation>
+<translation id="3600343118165084788">点击此处下载插件。</translation>
+<translation id="8281246460978372009">安装插件后,点击此处刷新</translation>
+<translation id="679352192834563463">未找到显示此内容的插件</translation>
+<translation id="8662565117025751661">正在下载插件...</translation>
+<translation id="3771786644471114952">获取插件</translation>
+<translation id="1275511093094545429"><ph name="PLUGIN"/></translation>
+<translation id="3825324228893189080">需要其他插件</translation>
+<translation id="4420062214988137980">插件安装失败</translation>
+<translation id="4317653869502688143"><ph name="PLUGIN"/> 只应安装自己信任的插件。</translation>
+<translation id="3926627843712816530">请确认要安装此插件。 只应安装自己信任的插件。</translation>
+<translation id="1383141426028388991"><ph name="URL"/></translation>
+<translation id="6845533974506654842">按下</translation>
+<translation id="1842960171412779397">选择</translation>
+<translation id="6119846243427417423">启动</translation>
+<translation id="5476505524087279545">取消选中</translation>
+<translation id="838869780401515933">选中</translation>
+<translation id="4202807286478387388">跳转</translation>
+<translation id="795667975304826397">没有选择文件</translation>
+<translation id="8964020114565522021">将文件拖动到此处</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_zh-TW.xtb b/webkit/glue/resources/webkit_strings_zh-TW.xtb
new file mode 100644
index 0000000..a2955d4
--- /dev/null
+++ b/webkit/glue/resources/webkit_strings_zh-TW.xtb
@@ -0,0 +1,42 @@
+<?xml version="1.0" ?>
+<!DOCTYPE translationbundle>
+<translationbundle lang="zh-TW">
+<translation id="7658239707568436148">取消</translation>
+<translation id="3789841737615482174">安裝</translation>
+<translation id="8141602879876242471">這是可搜尋的索引,輸入搜尋關鍵字:</translation>
+<translation id="2653659639078652383">提交</translation>
+<translation id="5939518447894949180">重設</translation>
+<translation id="7364796246159120393">選擇檔案</translation>
+<translation id="2548326553472216322">沒有近期的搜尋</translation>
+<translation id="6663448176199120256">最近的搜尋</translation>
+<translation id="1235745349614807883">清除最近的搜尋記錄</translation>
+<translation id="6807599807928161586">網頁範圍</translation>
+<translation id="3040011195152428237">連結</translation>
+<translation id="5048533449481078685">清單標記</translation>
+<translation id="8244226242650769279">影像地圖</translation>
+<translation id="8597182159515967513">標題</translation>
+<translation id="5944544982112848342">2048 (高級)</translation>
+<translation id="2846343701378493991">1024 (中等)</translation>
+<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
+<translation id="2965480764085142436"><ph name="PLUGIN"/> 外掛程式尚未安裝</translation>
+<translation id="4838490908464673667">未安裝要求的外掛程式</translation>
+<translation id="3600343118165084788">按一下這裡以下載掛程式</translation>
+<translation id="8281246460978372009">安裝外掛程式後,請按一下這裡更新</translation>
+<translation id="679352192834563463">沒有外掛程式可供顯示目前內容</translation>
+<translation id="8662565117025751661">正在下載外掛程式...</translation>
+<translation id="3771786644471114952">取得外掛程式</translation>
+<translation id="1275511093094545429">需要 <ph name="PLUGIN"/> 外掛程式</translation>
+<translation id="3825324228893189080">需要額外的外掛程式</translation>
+<translation id="4420062214988137980">外掛程式安裝失敗</translation>
+<translation id="4317653869502688143">請確定您想要安裝 <ph name="PLUGIN"/> 外掛程式。建議您僅安裝可靠的外掛程式。</translation>
+<translation id="3926627843712816530">請確定您想要安裝此外掛程式。建議您僅安裝可靠的外掛程式。</translation>
+<translation id="1383141426028388991">無法從 <ph name="URL"/> 安裝外掛程式</translation>
+<translation id="6845533974506654842">按下</translation>
+<translation id="1842960171412779397">選取</translation>
+<translation id="6119846243427417423">啟動</translation>
+<translation id="5476505524087279545">取消選取</translation>
+<translation id="838869780401515933">選取</translation>
+<translation id="4202807286478387388">跳至另一頁</translation>
+<translation id="795667975304826397">未選擇檔案</translation>
+<translation id="8964020114565522021">拖曳檔案至此</translation>
+</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/zoom_in.cur b/webkit/glue/resources/zoom_in.cur
new file mode 100644
index 0000000..b594d79
--- /dev/null
+++ b/webkit/glue/resources/zoom_in.cur
Binary files differ
diff --git a/webkit/glue/resources/zoom_out.cur b/webkit/glue/resources/zoom_out.cur
new file mode 100644
index 0000000..7e495fb
--- /dev/null
+++ b/webkit/glue/resources/zoom_out.cur
Binary files differ
diff --git a/webkit/glue/searchable_form_data.cc b/webkit/glue/searchable_form_data.cc
new file mode 100644
index 0000000..3d024e6
--- /dev/null
+++ b/webkit/glue/searchable_form_data.cc
@@ -0,0 +1,420 @@
+// 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 "config.h"
+
+#pragma warning(push, 0)
+#include "csshelper.h"
+#include "CString.h"
+#include "Document.h"
+#include "DocumentLoader.h"
+#include "FormData.h"
+#include "FormDataList.h"
+#include "FrameLoader.h"
+#include "HTMLFormElement.h"
+#include "HTMLOptionElement.h"
+#include "HTMLGenericFormElement.h"
+#include "HTMLInputElement.h"
+#include "HTMLNames.h"
+#include "HTMLOptionsCollection.h"
+#include "HTMLSelectElement.h"
+#include "ResourceRequest.h"
+#include "String.h"
+#include "TextEncoding.h"
+#pragma warning(pop)
+
+#undef LOG
+
+#include "base/basictypes.h"
+#include "webkit/glue/dom_operations.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/searchable_form_data.h"
+#include "webkit/glue/webframe_impl.h"
+
+using WebCore::HTMLInputElement;
+using WebCore::HTMLOptionElement;
+
+namespace {
+
+// TODO (sky): This comes straight out of HTMLFormElement, will work with
+// WebKit folks to make public.
+WebCore::DeprecatedCString encodeCString(const WebCore::CString& cstr) {
+ WebCore::DeprecatedCString e = cstr.deprecatedCString();
+
+ // http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1
+ // same safe characters as Netscape for compatibility
+ static const char *safe = "-._*";
+ int elen = e.length();
+ WebCore::DeprecatedCString encoded((elen + e.contains('\n')) * 3 + 1);
+ int enclen = 0;
+
+ for (int pos = 0; pos < elen; pos++) {
+ unsigned char c = e[pos];
+
+ if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || strchr(safe, c))
+ encoded[enclen++] = c;
+ else if (c == ' ')
+ encoded[enclen++] = '+';
+ else if (c == '\n' || (c == '\r' && e[pos + 1] != '\n')) {
+ encoded[enclen++] = '%';
+ encoded[enclen++] = '0';
+ encoded[enclen++] = 'D';
+ encoded[enclen++] = '%';
+ encoded[enclen++] = '0';
+ encoded[enclen++] = 'A';
+ } else if (c != '\r') {
+ encoded[enclen++] = '%';
+ unsigned int h = c / 16;
+ h += (h > 9) ? ('A' - 10) : '0';
+ encoded[enclen++] = h;
+
+ unsigned int l = c % 16;
+ l += (l > 9) ? ('A' - 10) : '0';
+ encoded[enclen++] = l;
+ }
+ }
+ encoded[enclen++] = '\0';
+ encoded.truncate(enclen);
+
+ return encoded;
+}
+
+// Returns true if the form element has an 'onsubmit' attribute.
+bool FormHasOnSubmit(WebCore::HTMLFormElement* form) {
+ const WebCore::AtomicString& attribute_value =
+ form->getAttribute(WebCore::HTMLNames::onsubmitAttr);
+ return (!attribute_value.isNull() && !attribute_value.isEmpty());
+}
+
+// Returns true if the form element will submit the data using a GET.
+bool IsFormMethodGet(WebCore::HTMLFormElement* form) {
+ const WebCore::AtomicString& attribute_value =
+ form->getAttribute(WebCore::HTMLNames::methodAttr);
+ return !equalIgnoringCase(attribute_value, "post");
+}
+
+// Gets the encoding for the form.
+void GetFormEncoding(WebCore::HTMLFormElement* form,
+ WebCore::TextEncoding* encoding) {
+ WebCore::String str =
+ form->getAttribute(WebCore::HTMLNames::accept_charsetAttr);
+ str.replace(',', ' ');
+ Vector<WebCore::String> charsets = str.split(' ');
+ Vector<WebCore::String>::const_iterator end = charsets.end();
+ for (Vector<WebCore::String>::const_iterator it = charsets.begin(); it != end;
+ ++it) {
+ *encoding = WebCore::TextEncoding(*it);
+ if (encoding->isValid())
+ return;
+ }
+ if (!encoding->isValid()) {
+ WebCore::Frame* frame = form->document()->frame();
+ if (frame)
+ *encoding = WebCore::TextEncoding(frame->loader()->encoding());
+ else
+ *encoding = WebCore::Latin1Encoding();
+ }
+}
+
+// Returns true if the submit request results in an HTTP URL.
+bool IsHTTPFormSubmit(WebCore::HTMLFormElement* form) {
+ WebCore::Frame* frame = form->document()->frame();
+ WebCore::String action = WebCore::parseURL(form->action());
+ WebCore::FrameLoader* loader = frame->loader();
+ WebCore::KURL url = loader->completeURL(action.isNull() ? "" : action);
+ return (url.protocol() == "http");
+}
+
+// If the form does not have an activated submit button, the first submit
+// button is returned.
+WebCore::HTMLGenericFormElement* GetButtonToActivate(
+ WebCore::HTMLFormElement* form) {
+ WTF::Vector<WebCore::HTMLGenericFormElement*> form_elements =
+ form->formElements;
+ WebCore::HTMLGenericFormElement* first_submit_button = NULL;
+
+ for (unsigned i = 0; i < form_elements.size(); ++i) {
+ WebCore::HTMLGenericFormElement* current = form_elements[i];
+ if (current->isActivatedSubmit()) {
+ // There's a button that is already activated for submit, return NULL.
+ return NULL;
+ } else if (first_submit_button == NULL &&
+ current->isSuccessfulSubmitButton()) {
+ first_submit_button = current;
+ }
+ }
+ return first_submit_button;
+}
+
+// Returns true if the selected state of all the options matches the default
+// selected state.
+bool IsSelectInDefaultState(WebCore::HTMLSelectElement* select) {
+ RefPtr<WebCore::HTMLOptionsCollection> options = select->options();
+ WebCore::Node* node = options->firstItem();
+
+ if (!select->multiple() && select->size() <= 1) {
+ // The select is rendered as a combobox (called menulist in WebKit). At
+ // least one item is selected, determine which one.
+ HTMLOptionElement* initial_selected = NULL;
+ while (node) {
+ HTMLOptionElement* option_element =
+ webkit_glue::CastHTMLElement<HTMLOptionElement>(
+ node, WebCore::HTMLNames::optionTag);
+ if (option_element) {
+ if (!initial_selected)
+ initial_selected = option_element;
+ if (option_element->defaultSelected()) {
+ // The page specified the option to select.
+ initial_selected = option_element;
+ break;
+ }
+ }
+ node = options->nextItem();
+ }
+ if (initial_selected)
+ return initial_selected->selected();
+ } else {
+ while (node) {
+ HTMLOptionElement* option_element =
+ webkit_glue::CastHTMLElement<HTMLOptionElement>(
+ node, WebCore::HTMLNames::optionTag);
+ if (option_element &&
+ option_element->selected() != option_element->defaultSelected()) {
+ return false;
+ }
+ node = options->nextItem();
+ }
+ }
+ return true;
+}
+
+bool IsCheckBoxOrRadioInDefaultState(HTMLInputElement* element) {
+ return (element->checked() == element->defaultChecked());
+}
+
+// Returns true if the form element is in its default state, false otherwise.
+// The default state is the state of the form element on initial load of the
+// page, and varies depending upon the form element. For example, a checkbox is
+// in its default state if the checked state matches the defaultChecked state.
+bool IsInDefaultState(WebCore::HTMLGenericFormElement* form_element) {
+ if (form_element->hasTagName(WebCore::HTMLNames::inputTag)) {
+ HTMLInputElement* input_element =
+ static_cast<HTMLInputElement*>(form_element);
+ if (input_element->inputType() == HTMLInputElement::CHECKBOX ||
+ input_element->inputType() == HTMLInputElement::RADIO) {
+ return IsCheckBoxOrRadioInDefaultState(input_element);
+ }
+ } else if (form_element->hasTagName(WebCore::HTMLNames::selectTag)) {
+ return IsSelectInDefaultState(
+ static_cast<WebCore::HTMLSelectElement*>(form_element));
+ }
+ return true;
+}
+
+// If form has only one text input element, it is returned. If a valid input
+// element is not found, NULL is returned. Additionally, the form data for all
+// elements is added to enc_string and the encoding used is set in
+// encoding_name.
+WebCore::HTMLInputElement* GetTextElement(
+ WebCore::HTMLFormElement* form,
+ WebCore::DeprecatedCString* enc_string,
+ std::string* encoding_name) {
+ WebCore::TextEncoding encoding;
+ GetFormEncoding(form, &encoding);
+ if (!encoding.isValid()) {
+ // Need a valid encoding to encode the form elements.
+ // If the encoding isn't found webkit ends up replacing the params with
+ // empty strings. So, we don't try to do anything here.
+ return NULL;
+ }
+ *encoding_name = encoding.name();
+ WebCore::HTMLInputElement* text_element = NULL;
+ WTF::Vector<WebCore::HTMLGenericFormElement*> form_elements =
+ form->formElements;
+ for (unsigned i = 0; i < form_elements.size(); ++i) {
+ WebCore::HTMLGenericFormElement* form_element = form_elements[i];
+ if (!form_element->disabled() && !form_element->name().isNull()) {
+ bool is_text_element = false;
+ if (!IsInDefaultState(form_element)) {
+ return NULL;
+ }
+ if (form_element->hasTagName(WebCore::HTMLNames::inputTag)) {
+ WebCore::HTMLInputElement* input_element =
+ static_cast<WebCore::HTMLInputElement*>(form_element);
+ switch (input_element->inputType()) {
+ case WebCore::HTMLInputElement::TEXT:
+ case WebCore::HTMLInputElement::ISINDEX:
+ is_text_element = true;
+ break;
+ case WebCore::HTMLInputElement::PASSWORD:
+ // Don't store passwords! This is most likely an https anyway.
+ // Fall through.
+ case WebCore::HTMLInputElement::FILE:
+ // Too big, don't try to index this.
+ return NULL;
+ break;
+ default:
+ // All other input types are indexable.
+ break;
+ }
+ } else if (form_element->hasTagName(WebCore::HTMLNames::textareaTag)) {
+ // TextArea aren't use for search.
+ return NULL;
+ }
+ WebCore::FormDataList lst(encoding);
+ if (form_element->appendFormData(lst, false)) {
+ if (is_text_element && lst.list().size() > 0) {
+ if (text_element != NULL) {
+ // The auto-complete bar only knows how to fill in one value.
+ // This form has multiple fields; don't treat it as searchable.
+ return NULL;
+ }
+ text_element = static_cast<WebCore::HTMLInputElement*>(form_element);
+ }
+ for (int j = 0, max = static_cast<int>(lst.list().size()); j < max; ++j) {
+ const WebCore::FormDataListItem& item = lst.list()[j];
+ // handle ISINDEX / <input name=isindex> special
+ // but only if its the first entry
+ if (enc_string->isEmpty() && item.m_data == "isindex") {
+ if (form_element == text_element)
+ *enc_string += "{searchTerms}";
+ else
+ *enc_string += encodeCString(lst.list()[j + 1].m_data);
+ ++j;
+ } else {
+ if (!enc_string->isEmpty())
+ *enc_string += '&';
+ *enc_string += encodeCString(item.m_data);
+ *enc_string += "=";
+ if (form_element == text_element)
+ *enc_string += "{searchTerms}";
+ else
+ *enc_string += encodeCString(lst.list()[j + 1].m_data);
+ ++j;
+ }
+ }
+ }
+ }
+ }
+ return text_element;
+}
+
+} // namespace
+
+SearchableFormData* SearchableFormData::Create(WebCore::Element* element) {
+ if (!element->isHTMLElement() ||
+ !static_cast<WebCore::HTMLElement*>(element)->isGenericFormElement()) {
+ return NULL;
+ }
+
+ WebCore::Frame* frame = element->document()->frame();
+ if (frame == NULL)
+ return NULL;
+
+ WebCore::HTMLGenericFormElement* input_element =
+ static_cast<WebCore::HTMLGenericFormElement*>(element);
+
+ WebCore::HTMLFormElement* form = input_element->form();
+ if (form == NULL)
+ return NULL;
+
+ return Create(form);
+}
+
+SearchableFormData* SearchableFormData::Create(WebCore::HTMLFormElement* form) {
+ WebCore::Frame* frame = form->document()->frame();
+ if (frame == NULL)
+ return NULL;
+
+ // Only consider forms that GET data, do not have script for onsubmit, and
+ // the action targets an http page.
+ if (!IsFormMethodGet(form) || FormHasOnSubmit(form) ||
+ !IsHTTPFormSubmit(form))
+ return NULL;
+
+ WebCore::DeprecatedCString enc_string = "";
+ WebCore::HTMLGenericFormElement* first_submit_button =
+ GetButtonToActivate(form);
+
+ if (first_submit_button) {
+ // The form does not have an active submit button, make the first button
+ // active. We need to do this, otherwise the URL will not contain the
+ // name of the submit button.
+ first_submit_button->setActivatedSubmit(true);
+ }
+
+ std::string encoding;
+ WebCore::HTMLInputElement* text_element =
+ GetTextElement(form, &enc_string, &encoding);
+
+ if (first_submit_button)
+ first_submit_button->setActivatedSubmit(false);
+
+ if (text_element == NULL) {
+ // Not a searchable form.
+ return NULL;
+ }
+
+ // It's a valid form.
+ // Generate the URL and create a new SearchableFormData.
+ RefPtr<WebCore::FormData> form_data = new WebCore::FormData;
+ form_data->appendData(enc_string.data(), enc_string.length());
+ WebCore::String action = WebCore::parseURL(form->action());
+ WebCore::FrameLoader* loader = frame->loader();
+ WebCore::KURL url = loader->completeURL(action.isNull() ? "" : action);
+ url.setQuery(form_data->flattenToString().deprecatedString());
+ std::wstring url_wstring = webkit_glue::StringToStdWString(url.string());
+ std::wstring current_value = webkit_glue::StringToStdWString(
+ static_cast<WebCore::HTMLInputElement*>(text_element)->value());
+ std::wstring text_name =
+ webkit_glue::StringToStdWString(text_element->name());
+ return
+ new SearchableFormData(url_wstring, text_name, current_value, encoding);
+}
+
+// static
+bool SearchableFormData::Equals(const SearchableFormData* a,
+ const SearchableFormData* b) {
+ return ((a == b) ||
+ (a != NULL && b != NULL &&
+ a->url().spec() == b->url().spec() &&
+ a->element_name() == b->element_name() &&
+ a->element_value() == b->element_value() &&
+ a->encoding() == b->encoding()));
+}
+
+SearchableFormData::SearchableFormData(const std::wstring& url,
+ const std::wstring& element_name,
+ const std::wstring& element_value,
+ const std::string& encoding)
+ : url_(url),
+ element_name_(element_name),
+ element_value_(element_value),
+ encoding_(encoding) {
+}
diff --git a/webkit/glue/searchable_form_data.h b/webkit/glue/searchable_form_data.h
new file mode 100644
index 0000000..61891e8
--- /dev/null
+++ b/webkit/glue/searchable_form_data.h
@@ -0,0 +1,84 @@
+// 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 WEBKIT_GLUE_SEARCHABLE_FORM_DATA_H__
+#define WEBKIT_GLUE_SEARCHABLE_FORM_DATA_H__
+
+#include <string>
+
+#include "googleurl/src/gurl.h"
+
+namespace WebCore {
+class Element;
+class HTMLFormElement;
+}
+
+// SearchableFormData encapsulates a URL and class name of an INPUT field
+// that correspond to a searchable form request.
+class SearchableFormData {
+ public:
+ // If form contains elements that constitutes a valid searchable form
+ // request, a SearchableFormData is created and returned.
+ static SearchableFormData* Create(WebCore::HTMLFormElement* form);
+
+ // If the element is contained in a form that constitutes a valid searchable
+ // form, a SearchableFormData is created and returned.
+ static SearchableFormData* Create(WebCore::Element* element);
+
+ // Returns true if the two SearchableFormData are equal, false otherwise.
+ // Either argument may be NULL. If both elements are NULL, true is returned.
+ static bool Equals(const SearchableFormData* a, const SearchableFormData* b);
+
+ // URL for the searchable form request.
+ const GURL& url() const { return url_; }
+
+ // Class name of the INPUT element the user input text into.
+ const std::wstring element_name() const { return element_name_; }
+
+ // Value of the text field in the form.
+ const std::wstring element_value() const { return element_value_; }
+
+ // Encoding used to encode the form parameters; never empty.
+ const std::string& encoding() const { return encoding_; }
+
+ private:
+ SearchableFormData(const std::wstring& url,
+ const std::wstring& element_name,
+ const std::wstring& element_value,
+ const std::string& encoding);
+
+ const GURL url_;
+ const std::wstring element_name_;
+ const std::wstring element_value_;
+ const std::string encoding_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(SearchableFormData);
+};
+
+#endif // WEBKIT_GLUE_SEARCHABLE_FORM_H__
diff --git a/webkit/glue/simple_clipboard_impl.cc b/webkit/glue/simple_clipboard_impl.cc
new file mode 100644
index 0000000..9f26b52
--- /dev/null
+++ b/webkit/glue/simple_clipboard_impl.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 "webkit/glue/webkit_glue.h"
+
+#include <string>
+
+#include "base/clipboard.h"
+#include "googleurl/src/gurl.h"
+
+#include "SkBitmap.h"
+
+// Clipboard glue
+// Basically just proxy the calls off to the clipboard
+
+namespace webkit_glue {
+
+Clipboard clipboard;
+
+void webkit_glue::ClipboardClear() {
+ clipboard.Clear();
+}
+
+void webkit_glue::ClipboardWriteText(const std::wstring& text) {
+ clipboard.WriteText(text);
+}
+
+void webkit_glue::ClipboardWriteHTML(const std::wstring& html,
+ const GURL& url) {
+ clipboard.WriteHTML(html, url.spec());
+}
+
+void webkit_glue::ClipboardWriteBookmark(const std::wstring& title,
+ const GURL& url) {
+ clipboard.WriteBookmark(title, url.spec());
+}
+
+void webkit_glue::ClipboardWriteBitmap(const SkBitmap& bitmap) {
+ SkAutoLockPixels bitmap_lock(bitmap);
+ clipboard.WriteBitmap(bitmap.getPixels(),
+ gfx::Size(bitmap.width(), bitmap.height()));
+}
+
+void webkit_glue::ClipboardWriteWebSmartPaste() {
+ clipboard.WriteWebSmartPaste();
+}
+
+bool webkit_glue::ClipboardIsFormatAvailable(unsigned int format) {
+ return clipboard.IsFormatAvailable(format);
+}
+
+void webkit_glue::ClipboardReadText(std::wstring* result) {
+ clipboard.ReadText(result);
+}
+
+void webkit_glue::ClipboardReadAsciiText(std::string* result) {
+ clipboard.ReadAsciiText(result);
+}
+
+void webkit_glue::ClipboardReadHTML(std::wstring* markup, GURL* url) {
+ std::string url_str;
+ clipboard.ReadHTML(markup, url ? &url_str : NULL);
+ if (url)
+ *url = GURL(url_str);
+}
+
+} // namespace webkit_glue
diff --git a/webkit/glue/unittest_test_server.h b/webkit/glue/unittest_test_server.h
new file mode 100644
index 0000000..4a8156d
--- /dev/null
+++ b/webkit/glue/unittest_test_server.h
@@ -0,0 +1,72 @@
+// 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 WEBKIT_GLUE_UNITTEST_TEST_SERVER_H__
+#define WEBKIT_GLUE_UNITTEST_TEST_SERVER_H__
+
+#include "webkit/glue/resource_loader_bridge.h"
+#include "net/base/load_flags.h"
+#include "net/url_request/url_request_unittest.h"
+
+using webkit_glue::ResourceLoaderBridge;
+
+// We need to use ResourceLoaderBridge to communicate with the testserver
+// instead of using URLRequest directly because URLRequests need to be run on
+// the test_shell's IO thread.
+class UnittestTestServer : public TestServer {
+ public:
+ UnittestTestServer() : TestServer(TestServer::ManualInit()) {
+ Init("localhost", 1337, L"webkit/data", std::wstring());
+ }
+
+ ~UnittestTestServer() {
+ Shutdown();
+ }
+
+ virtual bool MakeGETRequest(const std::string& page_name) {
+ GURL url(TestServerPage(page_name));
+ scoped_ptr<ResourceLoaderBridge> loader(
+ ResourceLoaderBridge::Create(NULL, "GET",
+ url,
+ url, // policy_url
+ GURL(), // no referrer
+ std::string(), // no extra headers
+ net::LOAD_NORMAL,
+ 0,
+ ResourceType::SUB_RESOURCE,
+ false));
+ EXPECT_TRUE(loader.get());
+
+ ResourceLoaderBridge::SyncLoadResponse resp;
+ loader->SyncLoad(&resp);
+ return resp.status.is_success();
+ }
+};
+
+#endif // WEBKIT_GLUE_UNITTEST_TEST_SERVER_H__
diff --git a/webkit/glue/webcursor.cc b/webkit/glue/webcursor.cc
new file mode 100644
index 0000000..8bd5744
--- /dev/null
+++ b/webkit/glue/webcursor.cc
@@ -0,0 +1,168 @@
+// 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/gfx/bitmap_header.h"
+#include "webkit/glue/webcursor.h"
+#include "webkit/glue/webkit_resources.h"
+
+WebCursor::WebCursor()
+ : type_(ARROW),
+ hotspot_x_(0),
+ hotspot_y_(0) {
+ memset(&bitmap_, 0, sizeof(bitmap_));
+}
+
+WebCursor::WebCursor(Type cursor_type)
+ : type_(cursor_type),
+ hotspot_x_(0),
+ hotspot_y_(0) {
+ memset(&bitmap_, 0, sizeof(bitmap_));
+}
+
+WebCursor::WebCursor(const SkBitmap* bitmap, int hotspot_x, int hotspot_y)
+ : type_(CUSTOM) {
+ hotspot_x_ = hotspot_x;
+ hotspot_y_ = hotspot_y;
+ bitmap_ = *bitmap;
+}
+
+WebCursor::~WebCursor() {
+}
+
+WebCursor::WebCursor(const WebCursor& other) {
+ type_ = other.type_;
+ hotspot_x_ = other.hotspot_x_;
+ hotspot_y_ = other.hotspot_y_;
+ bitmap_ = other.bitmap_;
+}
+
+WebCursor& WebCursor::operator=(const WebCursor& other) {
+ if (this != &other) {
+ type_ = other.type_;
+ hotspot_x_ = other.hotspot_x_;
+ hotspot_y_ = other.hotspot_y_;
+ bitmap_ = other.bitmap_;
+ }
+ return *this;
+}
+
+HCURSOR WebCursor::GetCursor(HINSTANCE module_handle) const {
+ if (type_ == CUSTOM)
+ return NULL;
+
+ static LPCWSTR cursor_resources[] = {
+ IDC_ARROW,
+ IDC_IBEAM,
+ IDC_WAIT,
+ IDC_CROSS,
+ IDC_UPARROW,
+ IDC_SIZE,
+ IDC_ICON,
+ IDC_SIZENWSE,
+ IDC_SIZENESW,
+ IDC_SIZEWE,
+ IDC_SIZENS,
+ IDC_SIZEALL,
+ IDC_NO,
+ IDC_HAND,
+ IDC_APPSTARTING,
+ IDC_HELP,
+ // webkit resources
+ MAKEINTRESOURCE(IDC_ALIAS),
+ MAKEINTRESOURCE(IDC_CELL),
+ MAKEINTRESOURCE(IDC_COLRESIZE),
+ MAKEINTRESOURCE(IDC_COPYCUR),
+ MAKEINTRESOURCE(IDC_ROWRESIZE),
+ MAKEINTRESOURCE(IDC_VERTICALTEXT),
+ MAKEINTRESOURCE(IDC_ZOOMIN),
+ MAKEINTRESOURCE(IDC_ZOOMOUT)
+ };
+
+ HINSTANCE instance_to_use = NULL;
+ if (type_ > HELP)
+ instance_to_use = module_handle;
+
+ HCURSOR cursor_handle = LoadCursor(instance_to_use,
+ cursor_resources[type_]);
+ return cursor_handle;
+}
+
+HCURSOR WebCursor::GetCustomCursor() const {
+ if (type_ != CUSTOM)
+ return NULL;
+
+ BITMAPINFO cursor_bitmap_info = {0};
+ gfx::CreateBitmapHeader(bitmap_.width(), bitmap_.height(),
+ reinterpret_cast<BITMAPINFOHEADER*>(&cursor_bitmap_info));
+ HDC dc = ::GetDC(0);
+ HDC workingDC = CreateCompatibleDC(dc);
+ HBITMAP bitmap_handle = CreateDIBSection(dc, &cursor_bitmap_info,
+ DIB_RGB_COLORS, 0, 0, 0);
+ SkAutoLockPixels bitmap_lock(bitmap_);
+ SetDIBits(0, bitmap_handle, 0, bitmap_.width(),
+ bitmap_.getPixels(), &cursor_bitmap_info, DIB_RGB_COLORS);
+
+ HBITMAP old_bitmap = reinterpret_cast<HBITMAP>(SelectObject(workingDC,
+ bitmap_handle));
+ SetBkMode(workingDC, TRANSPARENT);
+ SelectObject(workingDC, old_bitmap);
+
+ HBITMAP mask = CreateBitmap(bitmap_.width(), bitmap_.height(),
+ 1, 1, NULL);
+ ICONINFO ii = {0};
+ ii.fIcon = FALSE;
+ ii.xHotspot = hotspot_x_;
+ ii.yHotspot = hotspot_y_;
+ ii.hbmMask = mask;
+ ii.hbmColor = bitmap_handle;
+
+ HCURSOR cursor_handle = CreateIconIndirect(&ii);
+
+ DeleteObject(mask);
+ DeleteObject(bitmap_handle);
+ DeleteDC(workingDC);
+ ::ReleaseDC(0, dc);
+ return cursor_handle;
+}
+
+bool WebCursor::IsSameBitmap(const SkBitmap& bitmap) const {
+ SkAutoLockPixels new_bitmap_lock(bitmap);
+ SkAutoLockPixels bitmap_lock(bitmap_);
+ return (memcmp(bitmap_.getPixels(), bitmap.getPixels(),
+ bitmap_.getSize()) == 0);
+}
+
+bool WebCursor::IsEqual(const WebCursor& other) const {
+ if (type_ != other.type_)
+ return false;
+
+ if(type_ == CUSTOM)
+ return IsSameBitmap(other.bitmap_);
+ return true;
+}
diff --git a/webkit/glue/webcursor.h b/webkit/glue/webcursor.h
new file mode 100644
index 0000000..fd693f8
--- /dev/null
+++ b/webkit/glue/webcursor.h
@@ -0,0 +1,124 @@
+// 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 WEBCURSOR_H__
+#define WEBCURSOR_H__
+
+#include "skia/include/SkBitmap.h"
+
+// This class provides the functionality of a generic cursor type. The intent
+// is to stay away from platform specific code here. We do have win32 specific
+// functionality to retreive a HCURSOR from a cursor type.
+// TODO(iyengar) : Win32 specific functionality needs to be taken out of this
+// object
+class WebCursor
+{
+public:
+ // Supported cursor types.
+ enum Type {
+ ARROW,
+ IBEAM,
+ WAIT,
+ CROSS,
+ UPARROW,
+ SIZE,
+ ICON,
+ SIZENWSE,
+ SIZENESW,
+ SIZEWE,
+ SIZENS,
+ SIZEALL,
+ NO,
+ HAND,
+ APPSTARTING,
+ HELP,
+ ALIAS,
+ CELL,
+ COLRESIZE,
+ COPYCUR,
+ ROWRESIZE,
+ VERTICALTEXT,
+ ZOOMIN,
+ ZOOMOUT,
+ CUSTOM
+ };
+
+ WebCursor();
+ WebCursor(Type cursor_type);
+ WebCursor(const SkBitmap* bitmap, int hotspot_x, int hotspot_y);
+ ~WebCursor();
+
+ WebCursor(const WebCursor& other);
+ WebCursor& operator = (const WebCursor&);
+
+ Type type() const { return type_; };
+ int hotspot_x() const { return hotspot_x_; }
+ int hotspot_y() const { return hotspot_y_; }
+ const SkBitmap& bitmap() const { return bitmap_; }
+
+ void set_type(Type cursor_type) {
+ type_ = cursor_type;
+ }
+
+ void set_bitmap(const SkBitmap& bitmap) {
+ bitmap_ = bitmap;
+ }
+
+ void set_hotspot(int hotspot_x, int hotspot_y) {
+ hotspot_x_ = hotspot_x;
+ hotspot_y_ = hotspot_x;
+ }
+
+ // Returns the cursor handle. If the cursor type is a win32 or safari
+ // cursor, we use LoadCursor to load the cursor.
+ // Returns NULL on error.
+ HCURSOR GetCursor(HINSTANCE module_handle) const;
+ // If the underlying cursor type is a custom cursor, this function converts
+ // the SkBitmap to a cursor and returns the same. The responsiblity of
+ // freeing the cursor handle lies with the caller.
+ // Returns NULL on error.
+ HCURSOR GetCustomCursor() const;
+ // Returns true if the passed in SkBitmap is the same as the the
+ // current SkBitmap. We use memcmp to compare the two bitmaps.
+ bool IsSameBitmap(const SkBitmap& bitmap) const;
+
+ // Returns true if the current cursor object contains the same
+ // cursor as the cursor object passed in. If the current cursor
+ // is a custom cursor, we also compare the bitmaps to verify
+ // whether they are equal.
+ bool IsEqual(const WebCursor& other) const;
+
+protected:
+ Type type_;
+ int hotspot_x_;
+ int hotspot_y_;
+ SkBitmap bitmap_;
+};
+
+#endif // WEBCURSOR_H__
diff --git a/webkit/glue/webdatasource.h b/webkit/glue/webdatasource.h
new file mode 100644
index 0000000..232e21a
--- /dev/null
+++ b/webkit/glue/webdatasource.h
@@ -0,0 +1,219 @@
+// 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 WEBKIT_GLUE_WEBDATASOURCE_H__
+#define WEBKIT_GLUE_WEBDATASOURCE_H__
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "googleurl/src/gurl.h"
+
+struct PasswordForm;
+class SearchableFormData;
+class WebFrame;
+class WebRequest;
+class WebResponse;
+
+class WebDataSource {
+ public:
+ //
+ // @method webFrame
+ // @result Return the frame that represents this data source.
+ // - (WebFrame *)webFrame;
+ virtual WebFrame* GetWebFrame() = 0;
+
+ // Returns a reference to the original request data that created the
+ // datasource. This request will be unmodified by WebKit.
+ //
+ // Note that this will be a different physical object than the WebRequest
+ // that was specified in the load request initiated by the embedder, but the
+ // data members will be copied.
+ //
+ // This call will update the request with the latest information from WebKit,
+ // so it is important that the caller not cache the result or keep the
+ // reference across entries into WebKit.
+ virtual const WebRequest& GetInitialRequest() const = 0;
+
+ // Returns the request that was used to create this datasource. This may
+ // be modified by WebKit.
+ //
+ // Note that this will be a different physical object than the WebRequest
+ // that was specified in the load request initiated by the embedder.
+ //
+ // This call will update the request with the latest information from WebKit,
+ // so it is important that the caller not cache the result or keep the
+ // reference across entries into WebKit.
+ virtual const WebRequest& GetRequest() const = 0;
+
+ // Returns the response associated to this datasource.
+ virtual const WebResponse& GetResponse() const = 0;
+
+ virtual std::wstring GetResponseMimeType() const = 0;
+
+ //
+ // @method unreachableURL
+ // @discussion This will be non-nil only for dataSources created by calls to the
+ // WebFrame method loadAlternateHTMLString:baseURL:forUnreachableURL:.
+ // @result returns the unreachableURL for which this dataSource is showing alternate content, or nil
+ // - (NSURL *)unreachableURL;
+ virtual GURL GetUnreachableURL() const = 0;
+
+ // Returns true if there is a non-null unreachable URL.
+ virtual bool HasUnreachableURL() const = 0;
+
+ // Returns all redirects that occurred (both client and server) before at
+ // last committing the current page. This will contain one entry for each
+ // intermediate URL, and one entry for the last URL (so if there are no
+ // redirects, it will contain exactly the current URL, and if there is one
+ // redirect, it will contain the source and destination URL).
+ virtual const std::vector<GURL>& GetRedirectChain() const = 0;
+
+ // Returns the SearchableFormData, or NULL if the request wasn't a search
+ // request. The returned object is owned by the WebDataSource (actually
+ // the WebDocumentLoader) and shouldn't be freed.
+ virtual const SearchableFormData* GetSearchableFormData() const = 0;
+
+ // Returns the PasswordFormData, or NULL if the request isn't a form submission
+ // or doesn't have any password fields. The returned object is owned by the
+ // WebDataSource (actually the WebDocumentLoader) and shouldn't be freed.
+ virtual const PasswordForm* GetPasswordFormData() const = 0;
+
+ // Returns true if this request was the result of submitting a form.
+ // NOTE: this returns false if the user submitted a form, but the form used
+ // script to do the actuall submission.
+ virtual bool IsFormSubmit() const = 0;
+
+ /*
+ These functions are not implemented yet, and we are not yet sure whether or not
+ we need them, so we have commented them out both here and in the
+ webdatasource_impl.cc file.
+
+ //
+ // @method data
+ // @discussion The data will be incomplete until the datasource has completely loaded.
+ // @result Returns the raw data associated with the datasource. Returns nil
+ // if the datasource hasn't loaded any data.
+ // - (NSData *)data;
+ virtual void GetData(IStream** data) = 0;
+
+ //
+ // @method representation
+ // @discussion A representation holds a type specific representation
+ // of the datasource's data. The representation class is determined by mapping
+ // a MIME type to a class. The representation is created once the MIME type
+ // of the datasource content has been determined.
+ // @result Returns the representation associated with this datasource.
+ // Returns nil if the datasource hasn't created it's representation.
+ // - (id <WebDocumentRepresentation>)representation;
+ virtual void GetRepresentation(IWebDocumentRepresentation** rep) = 0;
+
+ //
+ // @method response
+ // @result returns the WebResourceResponse for the data source.
+ // - (NSURLResponse *)response;
+ virtual void GetResponse(IWebURLResponse** response) = 0;
+
+ //
+ // @method textEncodingName
+ // @result Returns either the override encoding, as set on the WebView for this
+ // dataSource or the encoding from the response.
+ // - (NSString *)textEncodingName;
+ virtual void GetTextEncodingName(std::wstring* name) = 0;
+
+ //
+ // @method isLoading
+ // @discussion Returns YES if there are any pending loads.
+ // - (BOOL)isLoading;
+ virtual bool IsLoading() = 0;
+
+ //
+ // @method pageTitle
+ // @result Returns nil or the page title.
+ // - (NSString *)pageTitle;
+ virtual void GetPageTitle(std::wstring* title) = 0;
+
+ //
+ // @method webArchive
+ // @result A WebArchive representing the data source, its subresources and child frames.
+ // @description This method constructs a WebArchive using the original downloaded data.
+ // In the case of HTML, if the current state of the document is preferred, webArchive should be
+ // called on the DOM document instead.
+ // - (WebArchive *)webArchive;
+ virtual void GetWebArchive(IWebArchive** archive) = 0;
+
+ //
+ // @method mainResource
+ // @result A WebResource representing the data source.
+ // @description This method constructs a WebResource using the original downloaded data.
+ // This method can be used to construct a WebArchive in case the archive returned by
+ // WebDataSource's webArchive isn't sufficient.
+ // - (WebResource *)mainResource;
+ virtual void GetMainResource(IWebResource** resource) = 0;
+
+ //
+ // @method subresources
+ // @abstract Returns all the subresources associated with the data source.
+ // @description The returned array only contains subresources that have fully downloaded.
+ // - (NSArray *)subresources;
+ virtual void GetSubresources(int* count, IWebResource*** resources);
+
+ //
+ // method subresourceForURL:
+ // @abstract Returns a subresource for a given URL.
+ // @param URL The URL of the subresource.
+ // @description Returns non-nil if the data source has fully downloaded a subresource with the given URL.
+ // - (WebResource *)subresourceForURL:(NSURL *)URL;
+ virtual void GetSubresourceForURL(const std::wstring& url,
+ IWebResource** resource) = 0;
+
+ //
+ // @method addSubresource:
+ // @abstract Adds a subresource to the data source.
+ // @param subresource The subresource to be added.
+ // @description addSubresource: adds a subresource to the data source's list of subresources.
+ // Later, if something causes the data source to load the URL of the subresource, the data source
+ // will load the data from the subresource instead of from the network. For example, if one wants to add
+ // an image that is already downloaded to a web page, addSubresource: can be called so that the data source
+ // uses the downloaded image rather than accessing the network. NOTE: If the data source already has a
+ // subresource with the same URL, addSubresource: will replace it.
+ // - (void)addSubresource:(WebResource *)subresource;
+ virtual void AddSubresource(IWebResource* subresource) = 0;
+ */
+
+ WebDataSource() { }
+ virtual ~WebDataSource() { }
+
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(WebDataSource);
+};
+
+
+
+#endif // #ifndef WEBKIT_GLUE_WEBDATASOURCE_H__
diff --git a/webkit/glue/webdatasource_impl.cc b/webkit/glue/webdatasource_impl.cc
new file mode 100644
index 0000000..7f018b2
--- /dev/null
+++ b/webkit/glue/webdatasource_impl.cc
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 "config.h"
+
+#pragma warning(push, 0)
+#include "KURL.h"
+#include "FrameLoadRequest.h"
+#include "ResourceRequest.h"
+#pragma warning(pop)
+#undef LOG
+
+#include "base/string_util.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/password_form.h"
+#include "webkit/glue/webdatasource_impl.h"
+#include "webkit/glue/webdocumentloader_impl.h"
+#include "webkit/glue/webframe_impl.h"
+#include "webkit/glue/weburlrequest_impl.h"
+
+// WebDataSource ----------------------------------------------------------------
+
+WebDataSourceImpl::WebDataSourceImpl(WebFrameImpl* frame,
+ WebDocumentLoaderImpl* loader) :
+ frame_(frame),
+ loader_(loader),
+ initial_request_(loader->initialRequest()),
+ request_(loader->request()) {
+}
+
+WebDataSourceImpl::~WebDataSourceImpl() {
+}
+
+// static
+WebDataSourceImpl* WebDataSourceImpl::CreateInstance(
+ WebFrameImpl* frame, WebDocumentLoaderImpl* loader) {
+ return new WebDataSourceImpl(frame, loader);
+}
+
+// WebDataSource
+WebFrame* WebDataSourceImpl::GetWebFrame() {
+ return frame_;
+}
+
+const WebRequest& WebDataSourceImpl::GetInitialRequest() const {
+ // WebKit may change the frame load request as it sees fit, so we must sync
+ // our request object.
+ initial_request_.set_frame_load_request(
+ WebCore::FrameLoadRequest(loader_->initialRequest()));
+ return initial_request_;
+}
+
+const WebRequest& WebDataSourceImpl::GetRequest() const {
+ // WebKit may change the frame load request as it sees fit, so we must sync
+ // our request object.
+ request_.set_frame_load_request(
+ WebCore::FrameLoadRequest(loader_->request()));
+ return request_;
+}
+
+const WebResponse& WebDataSourceImpl::GetResponse() const {
+ response_.set_resource_response(loader_->response());
+ return response_;
+}
+
+void WebDataSourceImpl::SetExtraData(WebRequest::ExtraData* extra) {
+ initial_request_.SetExtraData(extra);
+ request_.SetExtraData(extra);
+}
+
+std::wstring WebDataSourceImpl::GetResponseMimeType() const {
+ return webkit_glue::StringToStdWString(loader_->responseMIMEType());
+}
+
+GURL WebDataSourceImpl::GetUnreachableURL() const {
+ const WebCore::KURL& url = loader_->unreachableURL();
+ return url.isEmpty() ? GURL() : webkit_glue::KURLToGURL(url);
+}
+
+bool WebDataSourceImpl::HasUnreachableURL() const {
+ const WebCore::KURL& url = loader_->unreachableURL();
+ return !url.isEmpty();
+}
+
+const std::vector<GURL>& WebDataSourceImpl::GetRedirectChain() const {
+ return redirect_chain_;
+}
+
+void WebDataSourceImpl::ClearRedirectChain() {
+ redirect_chain_.clear();
+}
+
+void WebDataSourceImpl::AppendRedirect(const GURL& url) {
+ redirect_chain_.push_back(url);
+}
+
+const SearchableFormData* WebDataSourceImpl::GetSearchableFormData() const {
+ return loader_->searchable_form_data();
+}
+
+const PasswordForm* WebDataSourceImpl::GetPasswordFormData() const {
+ return loader_->password_form_data();
+}
+
+bool WebDataSourceImpl::IsFormSubmit() const {
+ return loader_->is_form_submit();
+}
+
+/*
+See comment in webdatasource.h
+
+void WebDataSourceImpl::GetData(IStream** data) {
+ DebugBreak();
+}
+
+void WebDataSourceImpl::GetRepresentation(IWebDocumentRepresentation** rep) {
+ DebugBreak();
+}
+
+void WebDataSourceImpl::GetResponse(IWebURLResponse** response) {
+ DebugBreak();
+}
+
+std::wstring WebDataSourceImpl::GetTextEncodingName() {
+ DebugBreak();
+ return L"";
+}
+
+bool WebDataSourceImpl::IsLoading() {
+ DebugBreak();
+}
+
+std::wstring WebDataSourceImpl::GetPageTitle() {
+ DebugBreak();
+ return L"";
+}
+
+void WebDataSourceImpl::GetWebArchive(IWebArchive** archive) {
+ DebugBreak();
+}
+
+void WebDataSourceImpl::GetMainResource(IWebResource** resource) {
+ DebugBreak();
+}
+
+void WebDataSourceImpl::GetSubresources(int* count, IWebResource*** resources) {
+ DebugBreak();
+}
+
+void WebDataSourceImpl::GetSubresourceForURL(const std::wstring& url,
+ IWebResource** resource) {
+ DebugBreak();
+}
+
+void WebDataSourceImpl::AddSubresource(IWebResource* subresource) {
+ DebugBreak();
+}
+*/
diff --git a/webkit/glue/webdatasource_impl.h b/webkit/glue/webdatasource_impl.h
new file mode 100644
index 0000000..baa476b
--- /dev/null
+++ b/webkit/glue/webdatasource_impl.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 WEBKIT_GLUE_WEBDATASOURCE_IMPL_H__
+#define WEBKIT_GLUE_WEBDATASOURCE_IMPL_H__
+
+#include "webkit/glue/webdatasource.h"
+#include "webkit/glue/webresponse_impl.h"
+#include "webkit/glue/weburlrequest_impl.h"
+#include "base/basictypes.h"
+
+struct PasswordForm;
+class SearchableFormData;
+class WebFrameImpl;
+class WebDocumentLoaderImpl;
+
+class WebDataSourceImpl : public WebDataSource {
+ public:
+ static WebDataSourceImpl* CreateInstance(WebFrameImpl* frame,
+ WebDocumentLoaderImpl* loader);
+
+ protected:
+ WebDataSourceImpl(WebFrameImpl* frame, WebDocumentLoaderImpl* loader);
+ ~WebDataSourceImpl();
+
+ public:
+ // WebDataSource
+ virtual WebFrame* GetWebFrame();
+ virtual const WebRequest& GetInitialRequest() const;
+ virtual const WebRequest& GetRequest() const;
+ virtual const WebResponse& GetResponse() const;
+ virtual std::wstring GetResponseMimeType() const;
+ virtual GURL GetUnreachableURL() const;
+ virtual bool HasUnreachableURL() const;
+ virtual const std::vector<GURL>& GetRedirectChain() const;
+
+ // WebDataSourceImpl
+
+ // Called after creating a new data source if there is request info
+ // available. Since we store copies of the WebRequests, the original
+ // WebRequest that the embedder created was lost, and the exra data would
+ // go with it. This preserves the request info so retrieving the requests
+ // later will have the same data.
+ void SetExtraData(WebRequest::ExtraData* extra);
+
+ void ClearRedirectChain();
+ void AppendRedirect(const GURL& url);
+
+ virtual const SearchableFormData* GetSearchableFormData() const;
+ virtual const PasswordForm* GetPasswordFormData() const;
+
+ virtual bool IsFormSubmit() const;
+
+private:
+ WebFrameImpl* frame_;
+ WebDocumentLoaderImpl* loader_;
+
+ // Mutable because the const getters will magically sync these to the
+ // latest version from WebKit.
+ mutable WebRequestImpl initial_request_;
+ mutable WebRequestImpl request_;
+ mutable WebResponseImpl response_;
+
+ // Lists all intermediate URLs that have redirected for the current
+ // provisional load. See WebFrameLoaderClient::
+ // dispatchDidReceiveServerRedirectForProvisionalLoad for a description of
+ // who modifies this when to keep it up to date.
+ std::vector<GURL> redirect_chain_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(WebDataSourceImpl);
+};
+
+#endif // #ifndef WEBKIT_GLUE_WEBDATASOURCE_IMPL_H__
diff --git a/webkit/glue/webdocumentloader_impl.cc b/webkit/glue/webdocumentloader_impl.cc
new file mode 100644
index 0000000..b33896f
--- /dev/null
+++ b/webkit/glue/webdocumentloader_impl.cc
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "config.h"
+
+#include "webkit/glue/webdocumentloader_impl.h"
+#undef LOG
+
+#include "base/logging.h"
+
+using WebCore::DocumentLoader;
+using WebCore::ResourceRequest;
+using WebCore::SubstituteData;
+
+WebDocumentLoaderImpl::WebDocumentLoaderImpl(const ResourceRequest& request,
+ const SubstituteData& data)
+ : DocumentLoader(request, data),
+ lock_history_(false),
+ form_submit_(false) {
+}
+
+void WebDocumentLoaderImpl::SetDataSource(WebDataSource* datasource) {
+ datasource_.reset(datasource);
+}
+
+WebDataSource* WebDocumentLoaderImpl::GetDataSource() const {
+ return datasource_.get();
+}
+
+// DocumentLoader
+void WebDocumentLoaderImpl::attachToFrame() {
+ DocumentLoader::attachToFrame();
+ if (detached_datasource_.get()) {
+ DCHECK(datasource_.get());
+ datasource_.reset(detached_datasource_.release());
+ }
+}
+
+void WebDocumentLoaderImpl::detachFromFrame() {
+ DocumentLoader::detachFromFrame();
+ detached_datasource_.reset(datasource_.release());
+}
diff --git a/webkit/glue/webdocumentloader_impl.h b/webkit/glue/webdocumentloader_impl.h
new file mode 100644
index 0000000..9ad3ee3
--- /dev/null
+++ b/webkit/glue/webdocumentloader_impl.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 WEBKIT_GLUE_WEBDOCUMENTLOADER_IMPL_H__
+#define WEBKIT_GLUE_WEBDOCUMENTLOADER_IMPL_H__
+
+#pragma warning(push, 0)
+#include "DocumentLoader.h"
+#pragma warning(pop)
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "webkit/glue/password_form.h"
+#include "webkit/glue/searchable_form_data.h"
+#include "webkit/glue/webdatasource.h"
+
+class WebDataSource;
+
+class WebDocumentLoaderImpl : public WebCore::DocumentLoader
+{
+ public:
+ WebDocumentLoaderImpl(const WebCore::ResourceRequest&, const WebCore::SubstituteData&);
+
+ void SetDataSource(WebDataSource*);
+ WebDataSource* GetDataSource() const;
+
+ void SetLockHistory(bool lock_history) { lock_history_ = lock_history; }
+ bool GetLockHistory() const { return lock_history_; }
+
+ // DocumentLoader
+ virtual void attachToFrame();
+ virtual void detachFromFrame();
+
+ // Sets the SearchableFormData for this DocumentLoader.
+ // WebDocumentLoaderImpl will own the SearchableFormData.
+ void set_searchable_form_data(SearchableFormData* searchable_form_data) {
+ searchable_form_data_.reset(searchable_form_data);
+ }
+ // Returns the SearchableFormData for this DocumentLoader.
+ // WebDocumentLoaderImpl owns the returned SearchableFormData.
+ const SearchableFormData* searchable_form_data() const {
+ return searchable_form_data_.get();
+ }
+
+ // Sets the PasswordFormData for this DocumentLoader.
+ // WebDocumentLoaderImpl will own the PasswordFormData.
+ void set_password_form_data(PasswordForm* password_form_data) {
+ password_form_data_.reset(password_form_data);
+ }
+ // Returns the PasswordFormData for this DocumentLoader.
+ // WebDocumentLoaderImpl owns the returned PasswordFormData.
+ const PasswordForm* password_form_data() const {
+ return password_form_data_.get();
+ }
+
+ void set_form_submit(bool value) {
+ form_submit_ = value;
+ }
+ bool is_form_submit() const {
+ return form_submit_;
+ }
+
+ private:
+ scoped_ptr<WebDataSource> datasource_;
+ scoped_ptr<WebDataSource> detached_datasource_;
+ scoped_ptr<const SearchableFormData> searchable_form_data_;
+ scoped_ptr<const PasswordForm> password_form_data_;
+
+ bool lock_history_;
+
+ bool form_submit_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(WebDocumentLoaderImpl);
+};
+
+#endif // #ifndef WEBKIT_GLUE_WEBDOCUMENTLOADER_IMPL_H__
diff --git a/webkit/glue/webdropdata.cc b/webkit/glue/webdropdata.cc
new file mode 100644
index 0000000..d8cb4ecf
--- /dev/null
+++ b/webkit/glue/webdropdata.cc
@@ -0,0 +1,55 @@
+// 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/webdropdata.h"
+
+#include "base/clipboard_util.h"
+#include "googleurl/src/gurl.h"
+#include <shellapi.h>
+#include <shlobj.h>
+
+/* static */
+void WebDropData::PopulateWebDropData(IDataObject* data_object,
+ WebDropData* drop_data) {
+ std::wstring url_str;
+ if (ClipboardUtil::GetUrl(data_object, &url_str, &drop_data->url_title)) {
+ GURL test_url(url_str);
+ if (test_url.is_valid())
+ drop_data->url = test_url;
+ }
+ ClipboardUtil::GetFilenames(data_object, &drop_data->filenames);
+ ClipboardUtil::GetPlainText(data_object, &drop_data->plain_text);
+ ClipboardUtil::GetCFHtml(data_object, &drop_data->cf_html);
+ ClipboardUtil::GetTextHtml(data_object, &drop_data->text_html);
+ ClipboardUtil::GetFileContents(data_object,
+ &drop_data->file_description_filename, &drop_data->file_contents);
+
+ // data_object used by the test_shell.
+ drop_data->data_object = data_object;
+}
diff --git a/webkit/glue/webdropdata.h b/webkit/glue/webdropdata.h
new file mode 100644
index 0000000..dbc1f8b
--- /dev/null
+++ b/webkit/glue/webdropdata.h
@@ -0,0 +1,74 @@
+// 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 struct for managing data being dropped on a webview. This represents a
+// union of all the types of data that can be dropped in a platform neutral
+// way.
+
+#ifndef WEBKIT_GLUE_WEBDROPDATA_H__
+#define WEBKIT_GLUE_WEBDROPDATA_H__
+
+#include <string>
+#include <vector>
+#include "googleurl/src/gurl.h"
+
+struct IDataObject;
+
+struct WebDropData {
+ // User is dropping a link on the webview.
+ GURL url;
+ std::wstring url_title; // The title associated with |url|.
+
+ // User is dropping one or more files on the webview.
+ std::vector<std::wstring> filenames;
+
+ // User is dragging plain text into the webview.
+ std::wstring plain_text;
+
+ // User is dragging MS HTML into the webview (e.g., out of IE).
+ std::wstring cf_html;
+
+ // User is dragging text/html into the webview (e.g., out of Firefox).
+ std::wstring text_html;
+
+ // User is dragging data from the webview (e.g., an image).
+ std::wstring file_description_filename;
+ std::string file_contents;
+
+ // A reference to the underlying IDataObject. This is a Windows drag and
+ // drop specific object. This should only be used by the test shell.
+ IDataObject* data_object;
+
+ // Helper method for converting Window's specific IDataObject to a WebDropData
+ // object.
+ static void PopulateWebDropData(IDataObject* data_object,
+ WebDropData* drop_data);
+};
+
+#endif // WEBKIT_GLUE_WEBDROPDATA_H__
diff --git a/webkit/glue/weberror.h b/webkit/glue/weberror.h
new file mode 100644
index 0000000..4540d8d
--- /dev/null
+++ b/webkit/glue/weberror.h
@@ -0,0 +1,44 @@
+// 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 WEBKIT_GLUE_WEBERROR_H__
+#define WEBKIT_GLUE_WEBERROR_H__
+
+class GURL;
+
+class WebError {
+ public:
+ // The network error code.
+ virtual int GetErrorCode() const = 0;
+
+ // The URL that failed.
+ virtual const GURL& GetFailedURL() const = 0;
+};
+
+#endif // WEBKIT_GLUE_WEBERROR_H__
diff --git a/webkit/glue/weberror_impl.cc b/webkit/glue/weberror_impl.cc
new file mode 100644
index 0000000..54e2830
--- /dev/null
+++ b/webkit/glue/weberror_impl.cc
@@ -0,0 +1,55 @@
+// 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 "config.h"
+#include "ResourceError.h"
+
+#undef LOG
+#include "webkit/glue/weberror_impl.h"
+
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/webkit_glue.h"
+
+WebErrorImpl::WebErrorImpl(const WebCore::ResourceError& e)
+ : error_code_(e.errorCode()),
+ failed_url_(webkit_glue::StringToStdWString(e.failingURL())) {
+}
+
+WebErrorImpl::WebErrorImpl(const WebError& e)
+ : error_code_(e.GetErrorCode()),
+ failed_url_(e.GetFailedURL()) {
+}
+
+int WebErrorImpl::GetErrorCode() const {
+ return error_code_;
+}
+
+const GURL& WebErrorImpl::GetFailedURL() const {
+ return failed_url_;
+}
diff --git a/webkit/glue/weberror_impl.h b/webkit/glue/weberror_impl.h
new file mode 100644
index 0000000..79013b1
--- /dev/null
+++ b/webkit/glue/weberror_impl.h
@@ -0,0 +1,59 @@
+// 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 WEBKIT_GLUE_WEBERROR_IMPL_H__
+#define WEBKIT_GLUE_WEBERROR_IMPL_H__
+
+#include "base/basictypes.h"
+#include "webkit/glue/weberror.h"
+#include "googleurl/src/gurl.h"
+
+namespace WebCore {
+class ResourceError;
+};
+
+class WebErrorImpl : public WebError {
+ public:
+ explicit WebErrorImpl(const WebCore::ResourceError& error);
+ explicit WebErrorImpl(const WebError& error);
+ ~WebErrorImpl() {}
+
+ // WebError implementation:
+ virtual int GetErrorCode() const;
+ virtual const GURL& GetFailedURL() const;
+
+ private:
+ int error_code_;
+ GURL failed_url_;
+
+ // Disallow assignment operator
+ void operator=(const WebErrorImpl&);
+};
+
+#endif // WEBKIT_GLUE_WEBERROR_IMPL_H__
diff --git a/webkit/glue/webframe.h b/webkit/glue/webframe.h
new file mode 100644
index 0000000..996d0db
--- /dev/null
+++ b/webkit/glue/webframe.h
@@ -0,0 +1,377 @@
+// 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 WEBKIT_GLUE_WEBFRAME_H__
+#define WEBKIT_GLUE_WEBFRAME_H__
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/ref_counted.h"
+#include "base/gfx/size.h"
+#include "webkit/glue/console_message_level.h"
+#include "webkit/glue/find_in_page_request.h"
+
+class GURL;
+class PlatformContextSkia;
+class WebDataSource;
+class WebError;
+class WebRequest;
+class WebView;
+class WebTextInput;
+struct NPObject;
+
+namespace gfx {
+class BitmapPlatformDevice;
+class Size;
+class Rect;
+}
+
+// TODO(darin): use GURL everywhere a URL string appears
+
+// Every frame in a web page is represented by one WebFrame, including the
+// outermost frame.
+class WebFrame : public base::RefCounted<WebFrame> {
+ public:
+ WebFrame() {}
+ virtual ~WebFrame() {}
+
+ // Binds a C++ class to a JavaScript property of the window object. This
+ // should generally be used via CppBoundClass::BindToJavascript() instead of
+ // calling it directly.
+ virtual void BindToWindowObject(const std::wstring& name,
+ NPObject* object) = 0;
+
+ virtual void CallJSGC() = 0;
+
+ // WARNING: DON'T USE THIS METHOD unless you know what it is doing.
+ //
+ // Returns a pointer to the underlying implementation WebCore::Frame.
+ // Currently it is a hack to avoid including "Frame.h". The caller
+ // casts the return value to WebCore::Frame.
+ // TODO(fqian): Remove this method when V8 supports NP runtime.
+ virtual void* GetFrameImplementation() = 0;
+
+ // Loads the given WebRequest.
+ virtual void LoadRequest(WebRequest* request) = 0;
+
+ // This method is short-hand for calling LoadAlternateHTMLString with a dummy
+ // request for the given base_url.
+ virtual void LoadHTMLString(const std::string& html_text,
+ const GURL& base_url) = 0;
+
+ // Loads alternative HTML text in place of a particular URL. This method is
+ // designed with error pages in mind, in which case it would typically be
+ // called in response to WebViewDelegate's didFailProvisionalLoadWithError
+ // method.
+ //
+ // |html_text| is a utf8 string to load in the frame. |display_url| is the
+ // URL that the content will appear to have been loaded from. The |replace|
+ // parameter controls how this affects session history. If |replace| is
+ // true, then the current session history entry is replaced with the given
+ // HTML text. Otherwise, a new navigation is produced.
+ //
+ // In either case, when the corresponding session history entry is revisited,
+ // it is the given request /w the |display_url| substituted for the request's
+ // URL, which is repeated. The |html_text| is not stored in session history.
+ //
+ virtual void LoadAlternateHTMLString(const WebRequest* request,
+ const std::string& html_text,
+ const GURL& display_url,
+ bool replace) = 0;
+
+ // Asks the WebFrame to try and download the alternate error page. We notify
+ // the WebViewDelegate of the results so it can decide whether or not to show
+ // something to the user (e.g., a local error page or the alternate error
+ // page).
+ virtual void LoadAlternateHTMLErrorPage(const WebRequest* request,
+ const WebError& error,
+ const GURL& error_page_url,
+ bool replace,
+ const GURL& fake_url) = 0;
+
+ // Returns a string representing the state of the previous page load for
+ // later use when loading as well as the uri and title of the page. The
+ // previous page is the page that was loaded before DidCommitLoadForFrame was
+ // received. Returns false if there is no state.
+ virtual bool GetPreviousState(GURL* url, std::wstring* title,
+ std::string* history_state) const = 0;
+
+ // Returns a string representing the state of the current page load for later
+ // use when loading as well as the url and title of the page. Returns false
+ // if there is no state.
+ virtual bool GetCurrentState(GURL* url, std::wstring* title,
+ std::string* history_state) const = 0;
+
+ // Returns true if there is a current history item. A newly created WebFrame
+ // lacks a history item. Otherwise, this will always be true.
+ virtual bool HasCurrentState() const = 0;
+
+ // Returns the current URL of the frame, or the empty string if there is no
+ // URL to retrieve (for example, the frame may never have had any content).
+ virtual GURL GetURL() const = 0;
+
+ // Returns the URL to the favorite icon for the frame. An empty string is
+ // returned if the frame has not finished loading, or the frame's URL
+ // protocol is not http or https.
+ virtual GURL GetFavIconURL() const = 0;
+
+ // Returns the URL to the OpenSearch description document for the frame. If
+ // the page does not have a valid document, an empty GURL is returned.
+ virtual GURL GetOSDDURL() const = 0;
+
+ // Returns the committed data source, which is the last data source that has
+ // successfully started loading. Will return NULL if no provisional data
+ // has been committed.
+ virtual WebDataSource* GetDataSource() const = 0;
+
+ // Returns the provisional data source, which is a data source where a
+ // request has been made, but we are not sure if we will use data from it
+ // (for example, it may be an invalid URL). When the provisional load is
+ // "committed," it will become the "real" data source (see GetDataSource
+ // above) and the provisional data source will be NULL.
+ virtual WebDataSource* GetProvisionalDataSource() const = 0;
+
+ //
+ // @method stopLoading
+ // @discussion Stop any pending loads on the frame's data source,
+ // and its children.
+ // - (void)stopLoading;
+ virtual void StopLoading() = 0;
+
+ // Returns the frame that opened this frame, or NULL if this window has no
+ // opener.
+ virtual WebFrame* GetOpener() const = 0;
+
+ // Returns the frame containing this frame, or NULL of this is a top level
+ // frame with no parent.
+ virtual WebFrame* GetParent() const = 0;
+
+ // Returns the child frame with the given xpath.
+ // The document of this frame is used as the context node.
+ // The xpath may need a recursive traversal if non-trivial
+ // A non-trivial xpath will contain a combination of xpaths
+ // (delimited by '\n') leading to an inner subframe.
+ //
+ // Example: /html/body/iframe/\n/html/body/div/iframe/\n/frameset/frame[0]
+ // can be broken into 3 xpaths
+ // /html/body/iframe evaluates to an iframe within the root frame
+ // /html/body/div/iframe evaluates to an iframe within the level-1 iframe
+ // /frameset/frame[0] evaluates to first frame within the level-2 iframe
+ virtual WebFrame* GetChildFrame(const std::wstring& xpath) const = 0;
+
+ // Returns a pointer to the WebView that contains this WebFrame. This
+ // pointer is not AddRef'd and is only valid for the lifetime of the WebFrame
+ // unless it is AddRef'd separately by the caller.
+ virtual WebView* GetView() const = 0;
+
+ // Fills the contents of this frame into the given string. If the text is
+ // longer than max_chars, it will be clipped to that length. Warning: this
+ // function may be slow depending on the number of characters retrieved and
+ // page complexity. For a typically sized page, expect it to take on the
+ // order of milliseconds.
+ //
+ // If there is room, subframe text will be recursively appended. Each frame
+ // will be separated by an empty line.
+ virtual void GetContentAsPlainText(int max_chars,
+ std::wstring* text) const = 0;
+
+ // Searches a frame for a given string.
+ //
+ // If a match is found, this function will select it (scrolling down to make
+ // it visible if needed) and fill in the IntRect (selection_rect) with the
+ // location of where the match was found (in screen coordinates).
+ //
+ // If no match is found, this function clears all tickmarks and highlighting.
+ //
+ // Returns true if the search string was found, false otherwise.
+ virtual bool Find(const FindInPageRequest& request,
+ bool wrap_within_frame,
+ gfx::Rect* selection_rect) = 0;
+
+ // Searches a frame for the next (or previous occurrence of a given string.
+ //
+ // This function works similarly to Find (documented above), except that it
+ // uses an index into the tick-mark vector to figure out what the next
+ // match is, alleviating the need to call findString on the content again.
+ //
+ // Returns true if the search string was found, false otherwise.
+ virtual bool FindNext(const FindInPageRequest& request,
+ bool wrap_within_frame) = 0;
+
+ // Notifies the frame that we are no longer interested in searching. This will
+ // abort any asynchronous scoping effort already under way (see the function
+ // ScopeStringMatches for details) and erase all tick-marks and highlighting
+ // from the previous search.
+ virtual void StopFinding() = 0;
+
+ // Counts how many times a particular string occurs within the frame. It
+ // also retrieves the location of the string and updates a vector in the frame
+ // so that tick-marks and highlighting can be drawn. This function does its
+ // work asynchronously, by running for a certain time-slice and then
+ // scheduling itself (co-operative multitasking) to be invoked later
+ // (repeating the process until all matches have been found). This allows
+ // multiple frames to be searched at the same time and provides a way to
+ // cancel at any time (see CancelPendingScopingEffort). The parameter Request
+ // specifies what to look for and Reset signals whether this is a brand new
+ // request or a continuation of the last scoping effort.
+ virtual void ScopeStringMatches(FindInPageRequest request,
+ bool reset) = 0;
+
+ // Cancels any outstanding requests for scoping string matches on a frame.
+ virtual void CancelPendingScopingEffort() = 0;
+
+ // This function is called on the mainframe during the scoping effort to keep
+ // a running tally of the accumulated total match-count for all frames. After
+ // updating the count it will notify the render-view about the new count.
+ virtual void IncreaseMatchCount(int count, int request_id) = 0;
+
+ // Notifies the webview-delegate about a new selection rect. This will result
+ // in the browser getting notified. For more information see WebViewDelegate.
+ virtual void ReportFindInPageSelection(const gfx::Rect& selection_rect,
+ int active_match_ordinal,
+ int request_id) = 0;
+
+ // This function is called on the mainframe to reset the total number of
+ // matches found during the scoping effort.
+ virtual void ResetMatchCount() = 0;
+
+ // Returns true if the frame is visible (defined as width > 0 and height > 0).
+ virtual bool Visible() = 0;
+
+ // Selects all the text in the frame.
+ virtual void SelectAll() = 0;
+
+ //
+ // - (void)copy:(id)sender;
+ virtual void Copy() = 0;
+
+ //
+ // - (void)cut:(id)sender;
+ virtual void Cut() = 0;
+
+ //
+ // - (void)paste:(id)sender;
+ virtual void Paste() = 0;
+
+ // Replace the selection text by a given text.
+ virtual void Replace(const std::wstring& text) = 0;
+
+ //
+ // - (void)delete:(id)sender;
+ // Delete as in similar to Cut, not as in teardown
+ virtual void Delete() = 0;
+
+ // Undo the last text editing command.
+ virtual void Undo() = 0;
+
+ // Redo the last undone text editing command.
+ virtual void Redo() = 0;
+
+ // Clear any text selection in the frame.
+ virtual void ClearSelection() = 0;
+
+ // Paints the contents of this web view in a bitmapped image. This image
+ // will not have plugins drawn. Devices are cheap to copy because the data is
+ // internally refcounted, so we return by value.
+ //
+ // Set scroll_to_zero to force all frames to be scrolled to 0,0 before
+ // being painted into the image. This will not send DOM events because it
+ // just draws the contents at a different place, but it does mean the
+ // scrollbars in the resulting image will appear to be wrong (they'll be
+ // painted as if the content was scrolled).
+ virtual gfx::BitmapPlatformDevice CaptureImage(bool scroll_to_zero) = 0;
+
+ // This function sets a flag within WebKit to instruct it to render the page
+ // as View-Source (showing the HTML source for the page).
+ virtual void SetInViewSourceMode(bool enable) = 0;
+
+ // This function returns whether this frame is in "view-source" mode.
+ virtual bool GetInViewSourceMode() const = 0;
+
+ // Returns the frame name.
+ virtual std::wstring GetName() = 0;
+
+ // Returns a pointer to the WebTextInput object associated with the frame.
+ // The caller does not own the object returned.
+ virtual WebTextInput* GetTextInput() = 0;
+
+ // Executes a webkit editor command. The supported commands are a
+ // superset of those accepted by javascript:document.execCommand().
+ // This method is exposed in order to implement
+ // javascript:layoutTestController.execCommand()
+ virtual bool ExecuteCoreCommandByName(const std::string& name, const std::string& value) = 0;
+
+ // Adds a message to the frame's console.
+ virtual void AddMessageToConsole(const std::wstring& msg,
+ ConsoleMessageLevel level) = 0;
+
+ // Tells the current page to close, running the onunload handler.
+ // TODO(creis): We'd rather use WebView::Close(), but that sets its delegate_
+ // to NULL, preventing any JavaScript dialogs in the onunload handler from
+ // appearing. This lets us shortcut that for now, but we should refactor
+ // close messages so that this isn't necessary.
+ virtual void ClosePage() = 0;
+
+ // The current scroll offset from the top of frame in pixels.
+ virtual gfx::Size ScrollOffset() const = 0;
+
+ // Reformats the web page, i.e. the main frame and its subframes, for printing
+ // or for screen display, depending on |printing| argument. |page_width_min|
+ // and |page_width_max| are the minimum and maximum width, in pixels, that the
+ // layout can try to fit the whole content. |width| is the resulted choosen
+ // document width in pixel.
+ // Note: It fails if the main frame failed to load. It will succeed even if a
+ // child frame failed to load.
+ virtual bool SetPrintingMode(bool printing,
+ float page_width_min,
+ float page_width_max,
+ int* width) = 0;
+
+ // Layouts the web page on paper. Calculates the rectangle of the web page
+ // each pages will "see". Then you can retrieve the exact view of a paper page
+ // with GetPageRect.
+ // Returns the number of printed pages computed.
+ virtual int ComputePageRects(const gfx::Size& page_size_px) = 0;
+
+ // Retrieves the paper page's view of the web page.
+ virtual void GetPageRect(int page, gfx::Rect* page_size) const = 0;
+
+ // Prints one page. |page| is 0-based.
+ virtual bool SpoolPage(int page,
+ PlatformContextSkia* context) = 0;
+
+ // Does this frame have an onunload or unbeforeunload event listener?
+ virtual bool HasUnloadListener() = 0;
+
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(WebFrame);
+};
+
+#endif // WEBKIT_GLUE_WEBFRAME_H__
diff --git a/webkit/glue/webframe_impl.cc b/webkit/glue/webframe_impl.cc
new file mode 100644
index 0000000..d6288ed
--- /dev/null
+++ b/webkit/glue/webframe_impl.cc
@@ -0,0 +1,1723 @@
+/*
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+// How ownership works
+// -------------------
+//
+// Big oh represents a refcounted relationship: owner O--- ownee
+//
+// WebView (for the toplevel frame only)
+// O
+// |
+// O
+// WebFrame <-------------------------- FrameLoader
+// O (via WebFrameLoaderClient) ||
+// | ||
+// +------------------------------+ ||
+// | ||
+// FrameView O-------------------------O Frame
+//
+// FrameLoader and Frame are formerly one object that was split apart because
+// it got too big. They basically have the same lifetime, hence the double line.
+//
+// WebFrame is refcounted and has one ref on behalf of the FrameLoader/Frame
+// and, in the case of the toplevel frame, one more for the WebView. This is
+// not a normal reference counted pointer because that would require changing
+// WebKit code that we don't control. Instead, it is created with this ref
+// initially and it is removed when the FrameLoader is getting destroyed.
+//
+// WebFrames are created in two places, first in WebViewImpl when the root
+// frame is created, and second in WebFrame::CreateChildFrame when sub-frames
+// are created. WebKit will hook up this object to the FrameLoader/Frame
+// and the refcount will be correct.
+//
+// How frames are destroyed
+// ------------------------
+//
+// The main frame is never destroyed and is re-used. The FrameLoader is
+// re-used and a reference is also kept by the WebView, so the root frame will
+// generally have a refcount of 2.
+//
+// When frame content is replaced, all subframes are destroyed. This happens
+// in FrameLoader::detachFromParent for each suframe. Here, we first clear
+// the view in the Frame, breaking the circular cycle between Frame and
+// FrameView. Then it calls detachedFromParent4 on the FrameLoaderClient.
+//
+// The FrameLoaderClient is implemented by WebFrameLoaderClient, which is
+// an object owned by WebFrame. It calls WebFrame::Closing which causes
+// WebFrame to release its references to Frame, generally releasing it.
+//
+// Frame going away causes the FrameLoader to get deleted. In FrameLoader's
+// destructor it notifies its client with frameLoaderDestroyed. This derefs
+// WebView and will cause it to be deleted (unless an external someone is also
+// holding a reference).
+
+#include "config.h"
+
+#include <algorithm>
+#include <string>
+
+#pragma warning(push, 0)
+#include "HTMLFormElement.h" // need this before Document.h
+#include "Chrome.h"
+#include "Document.h"
+#include "DocumentFragment.h" // Only needed for ReplaceSelectionCommand.h :(
+#include "DocumentLoader.h"
+#include "Editor.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameLoadRequest.h"
+#include "FrameTree.h"
+#include "FrameView.h"
+#include "FrameWin.h"
+#include "graphics/SkiaUtils.h"
+#include "GraphicsContext.h"
+#include "HTMLHeadElement.h"
+#include "HTMLLinkElement.h"
+#include "HTMLNames.h"
+#include "HistoryItem.h"
+#include "markup.h"
+#include "Page.h"
+#include "PlatformScrollBar.h"
+#include "RenderFrame.h"
+#include "RenderWidget.h"
+#include "ReplaceSelectionCommand.h"
+#include "ResourceHandle.h"
+#include "ResourceHandleWin.h"
+#include "ResourceRequest.h"
+#include "SelectionController.h"
+#include "Settings.h"
+#include "SubstituteData.h"
+#include "TextIterator.h"
+#include "TextAffinity.h"
+#include "xml/XPathResult.h"
+
+#pragma warning(pop)
+
+#undef LOG
+#include "base/gfx/bitmap_platform_device.h"
+#include "base/gfx/rect.h"
+#include "base/gfx/platform_canvas.h"
+#include "base/message_loop.h"
+#include "base/stats_counters.h"
+#include "base/string_util.h"
+#include "base/time.h"
+#include "net/base/net_errors.h"
+#include "webkit/glue/dom_operations.h"
+#include "webkit/glue/glue_serialize.h"
+#include "webkit/glue/alt_error_page_resource_fetcher.h"
+#include "webkit/glue/webdocumentloader_impl.h"
+#include "webkit/glue/weberror_impl.h"
+#include "webkit/glue/webframe_impl.h"
+#include "webkit/glue/webhistoryitem_impl.h"
+#include "webkit/glue/webtextinput_impl.h"
+#include "webkit/glue/webview_impl.h"
+#include "webkit/port/page/ChromeClientWin.h"
+#include "webkit/port/platform/WidgetClientWin.h"
+
+using WebCore::ChromeClientWin;
+using WebCore::Color;
+using WebCore::DeprecatedString;
+using WebCore::Document;
+using WebCore::DocumentLoader;
+using WebCore::ExceptionCode;
+using WebCore::GraphicsContext;
+using WebCore::HTMLFrameOwnerElement;
+using WebCore::Frame;
+using WebCore::FrameLoader;
+using WebCore::FrameLoadRequest;
+using WebCore::FrameLoadType;
+using WebCore::FrameTree;
+using WebCore::FrameView;
+using WebCore::HistoryItem;
+using WebCore::HTMLFrameElementBase;
+using WebCore::IntRect;
+using WebCore::KURL;
+using WebCore::Node;
+using WebCore::PlatformScrollbar;
+using WebCore::Range;
+using WebCore::ReloadIgnoringCacheData;
+using WebCore::RenderObject;
+using WebCore::ResourceError;
+using WebCore::ResourceHandle;
+using WebCore::ResourceRequest;
+using WebCore::Selection;
+using WebCore::SharedBuffer;
+using WebCore::String;
+using WebCore::SubstituteData;
+using WebCore::TextIterator;
+using WebCore::VisiblePosition;
+using WebCore::WidgetClientWin;
+using WebCore::XPathResult;
+
+static const wchar_t* const kWebFrameActiveCount = L"WebFrameActiveCount";
+
+static const char* const kOSDType = "application/opensearchdescription+xml";
+static const char* const kOSDRel = "search";
+
+// The separator between frames when the frames are converted to plain text.
+static const wchar_t kFrameSeparator[] = L"\n\n";
+static const int kFrameSeparatorLen = arraysize(kFrameSeparator) - 1;
+
+// Backend for GetContentAsPlainText, this is a recursive function that gets
+// the text for the current frame and all of its subframes. It will append
+// the text of each frame in turn to the |output| up to |max_chars| length.
+//
+// The |frame| must be non-NULL.
+static void FrameContentAsPlainText(int max_chars, Frame* frame,
+ std::wstring* output) {
+ Document* doc = frame->document();
+ if (!doc)
+ return;
+
+ // Select the document body.
+ RefPtr<Range> range(doc->createRange());
+ ExceptionCode exception = 0;
+ range->selectNodeContents(doc->body(), exception);
+
+ if (exception == 0) {
+ // The text iterator will walk nodes giving us text. This is similar to
+ // the plainText() function in TextIterator.h, but we implement the maximum
+ // size and also copy the results directly into a wstring, avoiding the
+ // string conversion.
+ for (TextIterator it(range.get()); !it.atEnd(); it.advance()) {
+ const wchar_t* chars = reinterpret_cast<const wchar_t*>(it.characters());
+ if (chars) {
+ int to_append = std::min(it.length(),
+ max_chars - static_cast<int>(output->size()));
+ output->append(chars, to_append);
+ if (output->size() >= static_cast<size_t>(max_chars))
+ return; // Filled up the buffer.
+ }
+ }
+ }
+
+ // Recursively walk the children.
+ FrameTree* frame_tree = frame->tree();
+ Frame* cur_child = frame_tree->firstChild();
+ for (Frame* cur_child = frame_tree->firstChild(); cur_child;
+ cur_child = cur_child->tree()->nextSibling()) {
+ // Make sure the frame separator won't fill up the buffer, and give up if
+ // it will. The danger is if the separator will make the buffer longer than
+ // max_chars. This will cause the computation above:
+ // max_chars - output->size()
+ // to be a negative number which will crash when the subframe is added.
+ if (static_cast<int>(output->size()) >= max_chars - kFrameSeparatorLen)
+ return;
+
+ output->append(kFrameSeparator, kFrameSeparatorLen);
+ FrameContentAsPlainText(max_chars, cur_child, output);
+ if (output->size() >= static_cast<size_t>(max_chars))
+ return; // Filled up the buffer.
+ }
+}
+
+// WebFrameImpl ----------------------------------------------------------------
+
+int WebFrameImpl::live_object_count_ = 0;
+
+WebFrameImpl::WebFrameImpl()
+// Don't complain about using "this" in initializer list.
+#pragma warning(disable: 4355)
+ : frame_loader_client_(this),
+ scope_matches_factory_(this),
+#pragma warning(default: 4355)
+ currently_loading_request_(NULL),
+ plugin_delegate_(NULL),
+ allows_scrolling_(true),
+ margin_width_(-1),
+ margin_height_(-1),
+ last_match_count_(-1),
+ total_matchcount_(-1),
+ inspected_node_(NULL),
+ active_tickmark_frame_(NULL),
+ active_tickmark_(WidgetClientWin::kNoTickmark),
+ last_active_range_(NULL),
+ frames_scoping_count_(-1),
+ scoping_complete_(false),
+ next_invalidate_after_(0),
+ printing_(false) {
+ StatsCounter(kWebFrameActiveCount).Increment();
+ live_object_count_++;
+}
+
+WebFrameImpl::~WebFrameImpl() {
+ StatsCounter(kWebFrameActiveCount).Decrement();
+ live_object_count_--;
+
+ CancelPendingScopingEffort();
+}
+
+// WebFrame -------------------------------------------------------------------
+
+void WebFrameImpl::InitMainFrame(WebViewImpl* webview_impl) {
+ webview_impl_ = webview_impl; // owning ref
+
+ Frame* frame = new Frame(webview_impl_->page(), 0, &frame_loader_client_);
+
+ // Add reference on behalf of FrameLoader. See comments in
+ // WebFrameLoaderClient::frameLoaderDestroyed for more info.
+ AddRef();
+
+ frame_ = frame;
+
+ // We must call init() after frame_ is assigned because it is referenced
+ // during init().
+ frame_->init();
+}
+
+void WebFrameImpl::LoadRequest(WebRequest* request) {
+ SubstituteData data;
+ InternalLoadRequest(request, data, false);
+}
+
+void WebFrameImpl::InternalLoadRequest(const WebRequest* request,
+ const SubstituteData& data,
+ bool replace) {
+ const WebRequestImpl* request_impl =
+ static_cast<const WebRequestImpl*>(request);
+
+ const ResourceRequest& resource_request =
+ request_impl->frame_load_request().resourceRequest();
+
+ // Special-case javascript URLs. Do not interrupt the existing load when
+ // asked to load a javascript URL unless the script generates a result.
+ // We can't just use FrameLoader::executeIfJavaScriptURL because it doesn't
+ // handle redirects properly.
+ const KURL& kurl = resource_request.url();
+ if (!data.isValid() && kurl.protocol() == "javascript") {
+ // Don't attempt to reload javascript URLs.
+ if (resource_request.cachePolicy() == ReloadIgnoringCacheData)
+ return;
+
+ // We can't load a javascript: URL if there is no Document!
+ if (!frame_->document())
+ return;
+
+ // TODO(darin): Is this the best API to use here? It works and seems good,
+ // but will it change out from under us?
+ DeprecatedString script =
+ KURL::decode_string(kurl.deprecatedString().mid(sizeof("javascript:")-1));
+ bool succ = false;
+ WebCore::String value =
+ frame_->loader()->executeScript(script, &succ, true);
+ if (succ && !frame_->loader()->isScheduledLocationChangePending()) {
+ // TODO(darin): We need to figure out how to represent this in session
+ // history. Hint: don't re-eval script when the user or script navigates
+ // back-n-forth (instead store the script result somewhere).
+ LoadDocumentData(kurl, value, String("text/html"), String());
+ }
+ return;
+ }
+
+ StopLoading(); // make sure existing activity stops
+
+ // Keep track of the request temporarily. This is effectively a way of
+ // passing the request to callbacks that may need it. See
+ // WebFrameLoaderClient::createDocumentLoader.
+ currently_loading_request_ = request;
+
+ // If we have a current datasource, save the request info on it immediately.
+ // This is because WebCore may not actually initiate a load on the toplevel
+ // frame for some subframe navigations, so we want to update its request.
+ WebDataSourceImpl* datasource = GetDataSourceImpl();
+ if (datasource)
+ CacheCurrentRequestInfo(datasource);
+
+ if (data.isValid()) {
+ frame_->loader()->load(resource_request, data);
+ if (replace) {
+ // Do this to force WebKit to treat the load as replacing the currently
+ // loaded page.
+ frame_->loader()->setReplacing();
+ }
+ } else if (request_impl->history_item()) {
+ // Use the history item if we have one, otherwise fall back to standard
+ // load.
+ RefPtr<HistoryItem> current_item = frame_->loader()->currentHistoryItem();
+
+ // If there is no current_item, which happens when we are navigating in
+ // session history after a crash, we need to manufacture one otherwise
+ // WebKit hoarks. This is probably the wrong thing to do, but it seems to
+ // work.
+ if (!current_item) {
+ current_item = new HistoryItem(KURL("about:blank"), "");
+ frame_->loader()->setCurrentHistoryItem(current_item);
+ frame_->page()->backForwardList()->setCurrentItem(current_item.get());
+
+ // Mark the item as fake, so that we don't attempt to save its state and
+ // end up with about:blank in the navigation history.
+ frame_->page()->backForwardList()->setCurrentItemFake(true);
+ }
+
+ frame_->loader()->goToItem(request_impl->history_item().get(),
+ WebCore::FrameLoadTypeIndexedBackForward);
+ } else if (resource_request.cachePolicy() == ReloadIgnoringCacheData) {
+ frame_->loader()->reload();
+ } else {
+ frame_->loader()->load(resource_request);
+ }
+
+ currently_loading_request_ = NULL;
+}
+
+void WebFrameImpl::LoadHTMLString(const std::string& html_text,
+ const GURL& base_url) {
+ WebRequestImpl request(base_url);
+ LoadAlternateHTMLString(&request, html_text, GURL(), false);
+}
+
+void WebFrameImpl::LoadAlternateHTMLString(const WebRequest* request,
+ const std::string& html_text,
+ const GURL& display_url,
+ bool replace) {
+ int len = static_cast<int>(html_text.size());
+ RefPtr<SharedBuffer> buf(new SharedBuffer(html_text.data(), len));
+
+ SubstituteData subst_data(
+ buf, String("text/html"), String("UTF-8"),
+ webkit_glue::GURLToKURL(display_url));
+ DCHECK(subst_data.isValid());
+
+ InternalLoadRequest(request, subst_data, replace);
+}
+
+GURL WebFrameImpl::GetURL() const {
+ const WebDataSource* ds = GetDataSource();
+ if (!ds)
+ return GURL();
+ return ds->GetRequest().GetURL();
+}
+
+GURL WebFrameImpl::GetFavIconURL() const {
+ WebCore::FrameLoader* frame_loader = frame_->loader();
+ // The URL to the favicon may be in the header. As such, only
+ // ask the loader for the favicon if it's finished loading.
+ if (frame_loader->state() == WebCore::FrameStateComplete) {
+ const KURL& url = frame_loader->iconURL();
+ if (!url.isEmpty()) {
+ return webkit_glue::KURLToGURL(url);
+ }
+ }
+ return GURL();
+}
+
+GURL WebFrameImpl::GetOSDDURL() const {
+ WebCore::FrameLoader* frame_loader = frame_->loader();
+ if (frame_loader->state() == WebCore::FrameStateComplete &&
+ frame_->document() && frame_->document()->head() &&
+ !frame_->tree()->parent()) {
+ WebCore::HTMLHeadElement* head = frame_->document()->head();
+ if (head) {
+ RefPtr<WebCore::HTMLCollection> children = head->children();
+ for (Node* child = children->firstItem(); child != NULL;
+ child = children->nextItem()) {
+ WebCore::HTMLLinkElement* link_element =
+ webkit_glue::CastHTMLElement<WebCore::HTMLLinkElement>(
+ child, WebCore::HTMLNames::linkTag);
+ if (link_element && link_element->type() == kOSDType &&
+ link_element->rel() == kOSDRel && !link_element->href().isEmpty()) {
+ return GURL(link_element->href().charactersWithNullTermination());
+ }
+ }
+ }
+ }
+ return GURL();
+}
+
+bool WebFrameImpl::GetPreviousState(GURL* url, std::wstring* title,
+ std::string* history_state) const {
+ // We use the previous item here because documentState (filled-out forms)
+ // only get saved to history when it becomes the previous item. The caller
+ // is expected to query the history state after a navigation occurs, after
+ // the desired history item has become the previous entry.
+ if (frame_->page()->backForwardList()->isPreviousItemFake())
+ return false;
+
+ RefPtr<HistoryItem> item = frame_->page()->backForwardList()->previousItem();
+ if (!item)
+ return false;
+
+ static StatsCounterTimer history_timer(L"GetHistoryTimer");
+ StatsScope<StatsCounterTimer> history_scope(history_timer);
+
+ webkit_glue::HistoryItemToString(item, history_state);
+ *url = webkit_glue::KURLToGURL(item->url());
+ *title = webkit_glue::StringToStdWString(item->title());
+
+ return true;
+}
+
+bool WebFrameImpl::GetCurrentState(GURL* url, std::wstring* title,
+ std::string* state) const {
+ if (frame_->loader())
+ frame_->loader()->saveDocumentAndScrollState();
+ RefPtr<HistoryItem> item = frame_->page()->backForwardList()->currentItem();
+ if (!item)
+ return false;
+
+ webkit_glue::HistoryItemToString(item, state);
+ *url = webkit_glue::KURLToGURL(item->url());
+ *title = webkit_glue::StringToStdWString(item->title());
+
+ return true;
+}
+
+bool WebFrameImpl::HasCurrentState() const {
+ return frame_->page()->backForwardList()->currentItem() != NULL;
+}
+
+void WebFrameImpl::LoadDocumentData(const KURL& base_url,
+ const String& data,
+ const String& mime_type,
+ const String& charset) {
+ // TODO(darin): This is wrong. We need to re-cast this in terms of a call to
+ // one of the FrameLoader::load(...) methods. Else, WebCore will be angry!!
+
+ // Requiring a base_url here seems like a good idea for security reasons.
+ ASSERT(!base_url.isEmpty());
+ ASSERT(!mime_type.isEmpty());
+
+ StopLoading();
+
+ // Reset any pre-existing scroll offset
+ frameview()->setContentsPos(0, 0);
+
+ // Make sure the correct document type is constructed.
+ frame_->loader()->setResponseMIMEType(mime_type);
+
+ // TODO(darin): Inform the FrameLoader of the charset somehow.
+
+ frame_->loader()->begin(base_url);
+ frame_->loader()->write(data);
+ frame_->loader()->end();
+}
+
+void WebFrameImpl::set_currently_loading_history_item(
+ WebHistoryItemImpl* item) {
+ currently_loading_history_item_ = item;
+}
+
+
+static WebDataSource* DataSourceForDocLoader(DocumentLoader* loader) {
+ return (loader ?
+ static_cast<WebDocumentLoaderImpl*>(loader)->GetDataSource() : NULL);
+}
+
+WebDataSource* WebFrameImpl::GetDataSource() const {
+ if (!frame_->loader())
+ return NULL;
+ return DataSourceForDocLoader(frame_->loader()->documentLoader());
+}
+
+WebDataSourceImpl* WebFrameImpl::GetDataSourceImpl() const {
+ return static_cast<WebDataSourceImpl*>(GetDataSource());
+}
+
+WebDataSource* WebFrameImpl::GetProvisionalDataSource() const {
+ FrameLoader* frame_loader = frame_->loader();
+ if (!frame_loader)
+ return NULL;
+
+ // We regard the policy document loader as still provisional.
+ DocumentLoader* doc_loader = frame_loader->provisionalDocumentLoader();
+ if (!doc_loader)
+ doc_loader = frame_loader->policyDocumentLoader();
+
+ return DataSourceForDocLoader(doc_loader);
+}
+
+WebDataSourceImpl* WebFrameImpl::GetProvisionalDataSourceImpl() const {
+ return static_cast<WebDataSourceImpl*>(GetProvisionalDataSource());
+}
+
+void WebFrameImpl::CacheCurrentRequestInfo(WebDataSourceImpl* datasource) {
+ // Cache our current request info on the data source. It contains its
+ // own requests, so the extra data needs to be transferred.
+ scoped_refptr<WebRequest::ExtraData> extra;
+
+ // Our extra data may come from a request issued via LoadRequest, or a
+ // history navigation from WebCore.
+ if (currently_loading_request_) {
+ extra = currently_loading_request_->GetExtraData();
+ } else if (currently_loading_history_item_) {
+ extra = currently_loading_history_item_->GetExtraData();
+ currently_loading_history_item_ = 0;
+ }
+
+ // We must only update this if it is valid, or the valid state will be lost.
+ if (extra)
+ datasource->SetExtraData(extra);
+}
+
+void WebFrameImpl::StopLoading() {
+ if (!frame_)
+ return;
+
+ // TODO(darin): Figure out what we should really do here. It seems like a
+ // bug that FrameLoader::stopLoading doesn't call stopAllLoaders.
+ frame_->loader()->stopAllLoaders();
+ frame_->loader()->stopLoading(false);
+}
+
+WebFrame* WebFrameImpl::GetOpener() const {
+ if (frame_) {
+ Frame* opener = frame_->loader()->opener();
+ if (opener)
+ return FromFrame(opener);
+ }
+ return NULL;
+}
+
+WebFrame* WebFrameImpl::GetParent() const {
+ if (frame_) {
+ Frame *parent = frame_->tree()->parent();
+ if (parent)
+ return FromFrame(parent);
+ }
+ return NULL;
+}
+
+WebFrame* WebFrameImpl::GetChildFrame(const std::wstring& xpath) const {
+ // xpath string can represent a frame deep down the tree (across multiple
+ // frame DOMs).
+ // Example, /html/body/table/tbody/tr/td/iframe\n/frameset/frame[0]
+ // should break into 2 xpaths
+ // /html/body/table/tbody/tr/td/iframe & /frameset/frame[0]
+
+ if (xpath.empty())
+ return NULL;
+
+ std::wstring secondary;
+ String xpath_str;
+
+ std::wstring::size_type delim_pos = xpath.find_first_of(L'\n');
+ if (delim_pos != std::wstring::npos) {
+ std::wstring primary = xpath.substr(0, delim_pos);
+ secondary = xpath.substr(delim_pos + 1);
+ xpath_str = webkit_glue::StdWStringToString(primary);
+ } else {
+ xpath_str = webkit_glue::StdWStringToString(xpath);
+ }
+
+ Document* document = frame_->document();
+
+ ExceptionCode ec = 0;
+ PassRefPtr<XPathResult> xpath_result =
+ document->evaluate(xpath_str,
+ document,
+ NULL, /* namespace */
+ XPathResult::ORDERED_NODE_ITERATOR_TYPE,
+ NULL, /* XPathResult object */
+ ec);
+
+ if (!xpath_result.get())
+ return NULL;
+
+ Node* node = xpath_result->iterateNext(ec);
+
+ if (!node || !node->isFrameOwnerElement())
+ return NULL;
+ HTMLFrameOwnerElement* frame_element =
+ static_cast<HTMLFrameOwnerElement*>(node);
+ WebFrame* web_frame = FromFrame(frame_element->contentFrame());
+
+ if (secondary.empty())
+ return web_frame;
+ else
+ return web_frame->GetChildFrame(secondary);
+}
+
+void WebFrameImpl::SetInViewSourceMode(bool enable) {
+ if (frame_)
+ frame_->setInViewSourceMode(enable);
+}
+
+bool WebFrameImpl::GetInViewSourceMode() const {
+ if (frame_)
+ return frame_->inViewSourceMode();
+
+ return false;
+}
+
+WebView* WebFrameImpl::GetView() const {
+ return webview_impl_;
+}
+
+void WebFrameImpl::BindToWindowObject(const std::wstring& name,
+ NPObject* object) {
+ assert(frame_);
+ if (!frame_ || !frame_->scriptBridge()->isEnabled())
+ return;
+
+ String key = webkit_glue::StdWStringToString(name);
+ frame_->scriptBridge()->BindToWindowObject(frame_.get(), key, object);
+}
+
+
+// Call JavaScript garbage collection.
+void WebFrameImpl::CallJSGC() {
+ if (!frame_) return;
+ if (!frame_->settings()->isJavaScriptEnabled()) return;
+ frame_->scriptBridge()->CollectGarbage();
+}
+
+
+void WebFrameImpl::GetContentAsPlainText(int max_chars,
+ std::wstring* text) const {
+ text->clear();
+ if (!frame_)
+ return;
+
+ FrameContentAsPlainText(max_chars, frame_.get(), text);
+}
+
+void WebFrameImpl::InvalidateArea(AreaToInvalidate area) {
+ ASSERT(frame() && frame()->view());
+ FrameView* view = frame()->view();
+
+ if ((area & INVALIDATE_ALL) == INVALIDATE_ALL) {
+ view->addToDirtyRegion(view->frameGeometry());
+ } else {
+ if ((area & INVALIDATE_CONTENT_AREA) == INVALIDATE_CONTENT_AREA) {
+ IntRect content_area(view->x(),
+ view->y(),
+ view->visibleWidth(),
+ view->visibleHeight());
+ view->addToDirtyRegion(content_area);
+ }
+
+ if ((area & INVALIDATE_SCROLLBAR) == INVALIDATE_SCROLLBAR) {
+ // Invalidate the vertical scroll bar region for the view.
+ IntRect scroll_bar_vert(view->x() + view->visibleWidth(),
+ view->y(),
+ PlatformScrollbar::verticalScrollbarWidth(),
+ view->visibleHeight());
+ view->addToDirtyRegion(scroll_bar_vert);
+ }
+ }
+}
+
+void WebFrameImpl::InvalidateTickmark(RefPtr<WebCore::Range> tickmark) {
+ ASSERT(frame() && frame()->view());
+ FrameView* view = frame()->view();
+
+ IntRect pos = tickmark->boundingBox();
+ pos.move(-view->contentsX(), -view->contentsY());
+ view->addToDirtyRegion(pos);
+}
+
+void WebFrameImpl::IncreaseMatchCount(int count, int request_id) {
+ total_matchcount_ += count;
+
+ // Update the UI with the latest findings.
+ WebViewDelegate* webview_delegate = GetView()->GetDelegate();
+ DCHECK(webview_delegate);
+ if (webview_delegate)
+ webview_delegate->ReportFindInPageMatchCount(total_matchcount_, request_id,
+ frames_scoping_count_ == 0);
+}
+
+void WebFrameImpl::ReportFindInPageSelection(const gfx::Rect& selection_rect,
+ int active_match_ordinal,
+ int request_id) {
+ // Update the UI with the latest selection rect.
+ WebViewDelegate* webview_delegate = GetView()->GetDelegate();
+ DCHECK(webview_delegate);
+ if (webview_delegate) {
+ webview_delegate->ReportFindInPageSelection(
+ request_id,
+ OrdinalOfFirstMatchForFrame(this) + active_match_ordinal,
+ selection_rect);
+ }
+}
+
+void WebFrameImpl::ResetMatchCount() {
+ total_matchcount_ = 0;
+ frames_scoping_count_ = 0;
+}
+
+bool WebFrameImpl::Find(const FindInPageRequest& request,
+ bool wrap_within_frame,
+ gfx::Rect* selection_rect) {
+ WebCore::String webcore_string =
+ webkit_glue::StdWStringToString(request.search_string);
+
+ // Starts the search from the current selection.
+ bool start_in_selection = true; // Policy. Can it be made configurable?
+
+ // If the user has selected something since the last Find operation we want
+ // to start from there. Otherwise, we start searching from where the last Find
+ // operation left off (either a Find or a FindNext operation).
+ Selection selection(frame()->selectionController()->selection());
+ if (selection.isNone() && last_active_range_) {
+ selection = Selection(last_active_range_.get());
+ frame()->selectionController()->setSelection(selection);
+ }
+
+ DCHECK(frame() && frame()->view());
+ bool found = frame()->findString(webcore_string, request.forward,
+ request.match_case, wrap_within_frame,
+ start_in_selection);
+ if (found) {
+ // We found something, so we can now query the selection for its position.
+ Selection new_selection(frame()->selectionController()->selection());
+
+ // If we thought we found something, but it couldn't be selected (perhaps
+ // because it was marked -webkit-user-select: none), call it not-found so
+ // we don't crash. See http://b/1169294. This matches Safari's behavior,
+ // including some oddities when selectable and un-selectable text are mixed
+ // on a page: see http://b/1180007.
+ if (new_selection.isNone()) {
+ // Fall through to clean up selection and tickmarks.
+ found = false;
+ } else {
+ last_active_range_ = new_selection.toRange();
+ active_selection_rect_ = new_selection.toRange()->boundingBox();
+ ClearSelection(); // We'll draw our own highlight for the active item.
+
+ if (selection_rect) {
+ gfx::Rect rect(
+ frame()->view()->convertToContainingWindow(active_selection_rect_));
+ rect.Offset(-frameview()->scrollOffset().width(),
+ -frameview()->scrollOffset().height());
+ *selection_rect = rect;
+ }
+ }
+ }
+
+ if (!found) {
+ active_selection_rect_ = IntRect();
+ last_active_range_ = NULL;
+
+ if (!tickmarks_.isEmpty()) {
+ // Let the frame know that we found no matches.
+ tickmarks_.clear();
+ // Erase all previous tickmarks and highlighting.
+ InvalidateArea(INVALIDATE_ALL);
+ }
+ }
+
+ return found;
+}
+
+bool WebFrameImpl::FindNext(const FindInPageRequest& request,
+ bool wrap_within_frame) {
+ if (tickmarks_.isEmpty())
+ return false;
+
+ // Save the old tickmark (if any). We will use this to invalidate the area
+ // of the tickmark that becomes unselected.
+ WebFrameImpl* const main_frame_impl =
+ static_cast<WebFrameImpl*>(GetView()->GetMainFrame());
+ WebFrameImpl* const active_frame = main_frame_impl->active_tickmark_frame_;
+ RefPtr<WebCore::Range> old_tickmark = NULL;
+ if (active_frame &&
+ (active_frame->active_tickmark_ != WidgetClientWin::kNoTickmark)) {
+ // When we get a reference to |old_tickmark| we can be in a state where
+ // the |active_tickmark_| points outside the tickmark vector, possibly
+ // during teardown of the frame. This doesn't reproduce normally, so if you
+ // hit this during debugging, update issue http://b/1277569 with
+ // reproduction steps - or contact the assignee. In release, we can ignore
+ // this and continue on (and let |old_tickmark| be null).
+ if (active_frame->active_tickmark_ >= active_frame->tickmarks_.size())
+ NOTREACHED() << L"Active tickmark points outside the tickmark vector!";
+ else
+ old_tickmark = active_frame->tickmarks_[active_frame->active_tickmark_];
+ }
+
+ // See if we have another match to select, and select it.
+ if (request.forward) {
+ const bool at_end = (active_tickmark_ == (tickmarks_.size() - 1));
+ if ((active_tickmark_ == WidgetClientWin::kNoTickmark) ||
+ (at_end && wrap_within_frame)) {
+ // Wrapping within a frame is only done for single frame pages. So when we
+ // reach the end we go back to the beginning (or back to the end if
+ // searching backwards).
+ active_tickmark_ = 0;
+ } else if (at_end) {
+ return false;
+ } else {
+ ++active_tickmark_;
+ DCHECK(active_tickmark_ < tickmarks_.size());
+ }
+ } else {
+ const bool at_end = (active_tickmark_ == 0);
+ if ((active_tickmark_ == WidgetClientWin::kNoTickmark) ||
+ (at_end && wrap_within_frame)) {
+ // Wrapping within a frame is not done for multi-frame pages, but if no
+ // tickmark is active we still need to set the index to the end so that
+ // we don't skip the frame during FindNext when searching backwards.
+ active_tickmark_ = tickmarks_.size() - 1;
+ } else if (at_end) {
+ return false;
+ } else {
+ --active_tickmark_;
+ DCHECK(active_tickmark_ < tickmarks_.size());
+ }
+ }
+
+ if (active_frame != this) {
+ // If we are jumping between frames, reset the active tickmark in the old
+ // frame and invalidate the area.
+ active_frame->active_tickmark_ = WidgetClientWin::kNoTickmark;
+ active_frame->InvalidateArea(INVALIDATE_CONTENT_AREA);
+ main_frame_impl->active_tickmark_frame_ = this;
+ } else {
+ // Invalidate the old tickmark.
+ if (old_tickmark)
+ active_frame->InvalidateTickmark(old_tickmark);
+ }
+
+ Selection selection(tickmarks_[active_tickmark_].get());
+ frame()->selectionController()->setSelection(selection);
+ frame()->revealSelection(); // Scroll the selection into view if necessary.
+ // Make sure we save where the selection was after the operation so that
+ // we can set the selection to it for the next Find operation (if needed).
+ last_active_range_ = tickmarks_[active_tickmark_];
+ ClearSelection(); // We will draw our own highlighting.
+
+ // Notify browser of new location for the selected rectangle.
+ IntRect pos = tickmarks_[active_tickmark_]->boundingBox();
+ pos.move(-frameview()->scrollOffset().width(),
+ -frameview()->scrollOffset().height());
+ ReportFindInPageSelection(
+ gfx::Rect(frame()->view()->convertToContainingWindow(pos)),
+ active_tickmark_ + 1,
+ request.request_id);
+
+ return true; // Found a match.
+}
+
+int WebFrameImpl::OrdinalOfFirstMatchForFrame(WebFrameImpl* frame) const {
+ int ordinal = 0;
+ WebFrameImpl* const main_frame_impl =
+ static_cast<WebFrameImpl*>(GetView()->GetMainFrame());
+ // Iterate from the main frame up to (but not including) this frame and
+ // add up the number of tickmarks.
+ for (WebFrameImpl* frame = main_frame_impl;
+ frame != this;
+ frame = static_cast<WebFrameImpl*>(
+ webview_impl_->GetNextFrameAfter(frame, true))) {
+ ordinal += frame->tickmarks().size();
+ }
+
+ return ordinal;
+}
+
+bool WebFrameImpl::ShouldScopeMatches(FindInPageRequest request) {
+ // Don't scope if we can't find a frame or if the frame is not visible.
+ // The user may have closed the tab/application, so abort.
+ if (!frame() || !Visible())
+ return false;
+
+ DCHECK(frame()->document() && frame()->view());
+
+ // If the frame completed the scoping operation and found 0 matches the last
+ // time it was searched, then we don't have to search it again if the user is
+ // just adding to the search string or sending the same search string again.
+ if (scoping_complete_ &&
+ last_search_string_ != std::wstring(L"") && last_match_count_ == 0) {
+ // Check to see if the search string prefixes match.
+ std::wstring previous_search_prefix =
+ request.search_string.substr(0, last_search_string_.length());
+
+ if (previous_search_prefix == last_search_string_) {
+ return false; // Don't search this frame, it will be fruitless.
+ }
+ }
+
+ return true;
+}
+
+void WebFrameImpl::InvalidateIfNecessary() {
+ if (last_match_count_ > next_invalidate_after_) {
+ // TODO(finnur): (http://b/1088165) Optimize the drawing of the
+ // tickmarks and remove this. This calculation sets a milestone for when
+ // next to invalidate the scrollbar and the content area. We do this so that
+ // we don't spend too much time drawing the scrollbar over and over again.
+ // Basically, up until the first 500 matches there is no throttle. After the
+ // first 500 matches, we set set the milestone further and further out (750,
+ // 1125, 1688, 2K, 3K).
+ static const int start_slowing_down_after = 500;
+ static const int slowdown = 750;
+ int i = (last_match_count_ / start_slowing_down_after);
+ next_invalidate_after_ += i * slowdown;
+
+ // Invalidating content area draws both highlighting and in-page
+ // tickmarks, but not the scrollbar.
+ // TODO(finnur): (http://b/1088165) invalidate content area only if
+ // match found on-screen.
+ InvalidateArea(INVALIDATE_CONTENT_AREA);
+ InvalidateArea(INVALIDATE_SCROLLBAR);
+ }
+}
+
+// static
+bool WebFrameImpl::RangeShouldBeHighlighted(Range* range) {
+ ExceptionCode exception = 0;
+ Node* common_ancestor_container = range->commonAncestorContainer(exception);
+
+ if (exception)
+ return false;
+
+ RenderObject* renderer = common_ancestor_container->renderer();
+
+ if (!renderer)
+ return false;
+
+ IntRect overflow_clip_rect = renderer->absoluteClippedOverflowRect();
+ return range->boundingBox().intersects(overflow_clip_rect);
+}
+
+void WebFrameImpl::selectNodeFromInspector(WebCore::Node* node) {
+ inspected_node_ = node;
+}
+
+void WebFrameImpl::ScopeStringMatches(FindInPageRequest request,
+ bool reset) {
+ if (!ShouldScopeMatches(request))
+ return;
+
+ WebFrameImpl* main_frame_impl =
+ static_cast<WebFrameImpl*>(GetView()->GetMainFrame());
+
+ if (reset) {
+ // This is a brand new search, so we need to reset everything.
+ // Scoping is just about to begin.
+ scoping_complete_ = false;
+ // First of all, all previous tickmarks need to be erased.
+ tickmarks_.clear();
+ // Clear the counters from last operation.
+ last_match_count_ = 0;
+ next_invalidate_after_ = 0;
+
+ main_frame_impl->frames_scoping_count_++;
+
+ // Now, defer scoping until later to allow find operation to finish quickly.
+ MessageLoop::current()->PostTask(FROM_HERE,
+ scope_matches_factory_.NewRunnableMethod(
+ &WebFrameImpl::ScopeStringMatches,
+ request,
+ false)); // false=we just reset, so don't do it again.
+ return;
+ }
+
+ WebCore::String webcore_string =
+ webkit_glue::StdWStringToString(request.search_string);
+
+ RefPtr<Range> searchRange(rangeOfContents(frame()->document()));
+
+ ExceptionCode ec = 0, ec2 = 0;
+ if (!reset && !tickmarks_.isEmpty()) {
+ // This is a continuation of a scoping operation that timed out and didn't
+ // complete last time around, so we should start from where we left off.
+ RefPtr<Range> start_range = tickmarks_.last();
+ searchRange->setStart(start_range->startNode(),
+ start_range->startOffset(ec2) + 1, ec);
+ if (ec != 0 || ec2 != 0) {
+ NOTREACHED();
+ return;
+ }
+ }
+
+ // This timeout controls how long we scope (in ms) before releasing control.
+ // This value does not prevent us from running for longer than this, but it
+ // is periodically checked to see if we have exceeded our allocated time.
+ static const int kTimeout = 100; // ms
+
+ int matchCount = 0;
+ bool timeout = false;
+ Time start_time = Time::Now();
+ do {
+ // Find next occurrence of the search string.
+ // TODO(finnur): (http://b/1088245) This WebKit operation may run
+ // for longer than the timeout value, and is not interruptible as it is
+ // currently written. We may need to rewrite it with interruptibility in
+ // mind, or find an alternative.
+ RefPtr<Range> resultRange(findPlainText(searchRange.get(),
+ webcore_string,
+ true,
+ request.match_case));
+ if (resultRange->collapsed(ec))
+ break; // no further matches.
+
+ // A non-collapsed result range can in some funky whitespace cases still not
+ // advance the range's start position (4509328). Break to avoid infinite
+ // loop. (This function is based on the implementation of Frame::FindString,
+ // which is where this safeguard comes from).
+ VisiblePosition newStart =
+ endVisiblePosition(resultRange.get(), WebCore::DOWNSTREAM);
+ if (newStart ==
+ startVisiblePosition(searchRange.get(), WebCore::DOWNSTREAM))
+ break;
+
+ ++matchCount;
+
+ // Add the location we just found to the tickmarks collection.
+ tickmarks_.append(resultRange);
+
+ setStart(searchRange.get(), newStart);
+
+ // If the Find function found a match it will have stored where the
+ // match was found in active_selection_rect_ on the current frame. If we
+ // find this rect during scoping it means we have found the active
+ // tickmark.
+ if (!active_selection_rect_.isEmpty() &&
+ active_selection_rect_ == resultRange->boundingBox()) {
+ // We have found the active tickmark frame.
+ main_frame_impl->active_tickmark_frame_ = this;
+ // We also know which tickmark is active now.
+ active_tickmark_ = tickmarks_.size() - 1;
+ // To stop looking for the active tickmark, we clear this rectangle.
+ active_selection_rect_ = IntRect();
+
+ // Notify browser of new location for the selected rectangle.
+ IntRect pos = tickmarks_[active_tickmark_]->boundingBox();
+ pos.move(-frameview()->scrollOffset().width(),
+ -frameview()->scrollOffset().height());
+ ReportFindInPageSelection(
+ gfx::Rect(frame()->view()->convertToContainingWindow(pos)),
+ active_tickmark_ + 1,
+ request.request_id);
+ }
+
+ timeout = (Time::Now() - start_time).InMilliseconds() >= kTimeout;
+ } while (!timeout);
+
+ // Remember what we search for last time, so we can skip searching if more
+ // letters are added to the search string (and last outcome was 0).
+ last_search_string_ = request.search_string;
+
+ if (matchCount > 0) {
+ last_match_count_ += matchCount;
+
+ // Let the mainframe know how much we found during this pass.
+ main_frame_impl->IncreaseMatchCount(matchCount, request.request_id);
+ }
+
+ if (timeout) {
+ // If we found anything during this pass, we should redraw. However, we
+ // don't want to spam too much if the page is extremely long, so if we
+ // reach a certain point we start throttling the redraw requests.
+ if (matchCount > 0)
+ InvalidateIfNecessary();
+
+ // Scoping effort ran out of time, lets ask for another time-slice.
+ MessageLoop::current()->PostTask(FROM_HERE,
+ scope_matches_factory_.NewRunnableMethod(
+ &WebFrameImpl::ScopeStringMatches,
+ request,
+ false)); // don't reset.
+
+ return; // Done for now, resume work later.
+ }
+
+ // This frame has no further scoping left, so it is done. Other frames might,
+ // of course, continue to scope matches.
+ scoping_complete_ = true;
+ main_frame_impl->frames_scoping_count_--;
+
+ // If this is the last frame to finish scoping we need to trigger the final
+ // update to be sent.
+ if (main_frame_impl->frames_scoping_count_ == 0)
+ main_frame_impl->IncreaseMatchCount(0, request.request_id);
+
+ // This frame is done, so show any tickmark/highlight we haven't drawn yet.
+ InvalidateArea(INVALIDATE_ALL);
+
+ return;
+}
+
+void WebFrameImpl::CancelPendingScopingEffort() {
+ scope_matches_factory_.RevokeAll();
+ active_tickmark_ = WidgetClientWin::kNoTickmark;
+}
+
+void WebFrameImpl::StopFinding() {
+ CancelPendingScopingEffort();
+
+ // Let the frame know that we don't want tickmarks or highlighting anymore.
+ tickmarks_.clear();
+ InvalidateArea(INVALIDATE_ALL);
+}
+
+void WebFrameImpl::SelectAll() {
+ frame()->selectionController()->selectAll();
+
+ WebViewDelegate* d = GetView()->GetDelegate();
+ if (d)
+ d->UserMetricsRecordAction(L"SelectAll");
+}
+
+void WebFrameImpl::Copy() {
+ frame()->editor()->copy();
+
+ WebViewDelegate* d = GetView()->GetDelegate();
+ if (d)
+ d->UserMetricsRecordAction(L"Copy");
+}
+
+void WebFrameImpl::Cut() {
+ frame()->editor()->cut();
+
+ WebViewDelegate* d = GetView()->GetDelegate();
+ if (d)
+ d->UserMetricsRecordAction(L"Cut");
+}
+
+// Returns a copy of data from a data handle retrieved from the clipboard. The
+// data is decoded according to the format that it is in. The caller is
+// responsible for freeing the data.
+static wchar_t* GetDataFromHandle(HGLOBAL data_handle,
+ unsigned int clipboard_format) {
+ switch (clipboard_format) {
+ case CF_TEXT: {
+ char* string_data = static_cast<char*>(::GlobalLock(data_handle));
+ int n_chars = ::MultiByteToWideChar(CP_ACP, 0, string_data, -1, NULL, 0);
+ wchar_t* wcs_data =
+ static_cast<wchar_t*>(malloc((n_chars * sizeof(wchar_t)) +
+ sizeof(wchar_t)));
+ if (!wcs_data) {
+ ::GlobalUnlock(data_handle);
+ return NULL;
+ }
+
+ ::MultiByteToWideChar(CP_ACP, 0, string_data, -1, wcs_data, n_chars);
+ ::GlobalUnlock(data_handle);
+ wcs_data[n_chars] = '\0';
+ return wcs_data;
+ }
+ case CF_UNICODETEXT: {
+ wchar_t* string_data = static_cast<wchar_t*>(::GlobalLock(data_handle));
+ size_t data_size_in_bytes = ::GlobalSize(data_handle);
+ wchar_t* wcs_data =
+ static_cast<wchar_t*>(malloc(data_size_in_bytes + sizeof(wchar_t)));
+ if (!wcs_data) {
+ ::GlobalUnlock(data_handle);
+ return NULL;
+ }
+
+ size_t n_chars = static_cast<int>(data_size_in_bytes / sizeof(wchar_t));
+ wmemcpy_s(wcs_data, n_chars, string_data, n_chars);
+ ::GlobalUnlock(data_handle);
+ wcs_data[n_chars] = '\0';
+ return wcs_data;
+ }
+ }
+ return NULL;
+}
+
+void WebFrameImpl::Paste() {
+ frame()->editor()->paste();
+
+ WebViewDelegate* d = GetView()->GetDelegate();
+ if (d)
+ d->UserMetricsRecordAction(L"Paste");
+}
+
+void WebFrameImpl::Replace(const std::wstring& wtext) {
+ String text = webkit_glue::StdWStringToString(wtext);
+ frame()->editor()->replaceSelectionWithText(text, false, true);
+}
+
+void WebFrameImpl::Delete() {
+ frame()->editor()->command("Delete").execute();
+
+ WebViewDelegate* d = GetView()->GetDelegate();
+ if (d)
+ d->UserMetricsRecordAction(L"DeleteSelection");
+}
+
+void WebFrameImpl::Undo() {
+ frame()->editor()->undo();
+
+ WebViewDelegate* d = GetView()->GetDelegate();
+ if (d)
+ d->UserMetricsRecordAction(L"Undo");
+}
+
+void WebFrameImpl::Redo() {
+ frame()->editor()->redo();
+
+ WebViewDelegate* d = GetView()->GetDelegate();
+ if (d)
+ d->UserMetricsRecordAction(L"Redo");
+}
+
+void WebFrameImpl::ClearSelection() {
+ frame()->selectionController()->clear();
+}
+
+void WebFrameImpl::CreateFrameView() {
+ ASSERT(frame_); // If frame_ doesn't exist, we probably didn't init properly.
+
+ WebCore::Page* page = frame_->page();
+ DCHECK(page);
+
+ DCHECK(page->mainFrame() != NULL);
+
+ // Detach the current view. This ensures that UI widgets like plugins,
+ // etc are detached(hidden)
+ if (frame_->view())
+ frame_->view()->detachFromWindow();
+
+ frame_->setView(0);
+
+ WebCore::FrameView* view = new FrameView(frame_.get());
+
+ frame_->setView(view);
+
+ // Attaching the view ensures that UI widgets like plugins, display/hide
+ // correctly.
+ frame_->view()->attachToWindow();
+
+ if (margin_width_ >= 0)
+ view->setMarginWidth(margin_width_);
+ if (margin_height_ >= 0)
+ view->setMarginHeight(margin_height_);
+ if (!allows_scrolling_)
+ view->setScrollbarsMode(WebCore::ScrollbarAlwaysOff);
+
+ // TODO(darin): The Mac code has a comment about this possibly being
+ // unnecessary. See installInFrame in WebCoreFrameBridge.mm
+ if (frame_->ownerRenderer())
+ frame_->ownerRenderer()->setWidget(view);
+
+ view->initScrollbars();
+
+ // FrameViews are created with a refcount of 1 so it needs releasing after we
+ // assign it to a RefPtr.
+ view->deref();
+
+ WebFrameImpl* parent = static_cast<WebFrameImpl*>(GetParent());
+ if (parent) {
+ parent->frameview()->addChild(view);
+ } else {
+ view->setClient(webview_impl_);
+
+ IntRect geom(0, 0, webview_impl_->size().width(),
+ webview_impl_->size().height());
+ view->setFrameGeometry(geom);
+ }
+}
+
+// static
+WebFrameImpl* WebFrameImpl::FromFrame(WebCore::Frame* frame) {
+ return static_cast<WebFrameLoaderClient*>(
+ frame->loader()->client())->webframe();
+}
+
+// WebFrame --------------------------------------------------------------------
+
+void WebFrameImpl::Layout() {
+ // layout this frame
+ if (frame_->document())
+ frame_->document()->updateLayout();
+ // layout child frames
+ Frame* child = frame_->tree()->firstChild();
+ for (; child; child = child->tree()->nextSibling())
+ FromFrame(child)->Layout();
+}
+
+void WebFrameImpl::Paint(gfx::PlatformCanvas* canvas, const gfx::Rect& rect) {
+ static StatsRate rendering(L"WebFramePaintTime");
+ StatsScope<StatsRate> rendering_scope(rendering);
+
+ if (!rect.IsEmpty()) {
+ PlatformContextSkia context(canvas);
+
+ // PlatformGraphicsContext is actually a pointer to PlatformContextSkia
+ GraphicsContext gc(reinterpret_cast<PlatformGraphicsContext*>(&context));
+ IntRect dirty_rect(rect.x(), rect.y(), rect.width(), rect.height());
+
+ if (frame_->document() && frameview()) {
+ frameview()->paint(&gc, dirty_rect);
+ } else {
+ gc.fillRect(dirty_rect, Color::white);
+ }
+ }
+}
+
+gfx::BitmapPlatformDevice WebFrameImpl::CaptureImage(bool scroll_to_zero) {
+ // Must layout before painting.
+ Layout();
+
+ gfx::PlatformCanvas canvas(frameview()->width(), frameview()->height(), true);
+ PlatformContextSkia context(&canvas);
+
+ GraphicsContext gc(reinterpret_cast<PlatformGraphicsContext*>(&context));
+ frameview()->paint(&gc, IntRect(0, 0, frameview()->width(),
+ frameview()->height()));
+
+ gfx::BitmapPlatformDevice& device =
+ static_cast<gfx::BitmapPlatformDevice&>(canvas.getTopPlatformDevice());
+ device.fixupAlphaBeforeCompositing();
+ return device;
+}
+
+bool WebFrameImpl::IsLoading() {
+ // I'm assuming this does what we want.
+ return frame_->loader()->isLoading();
+}
+
+void WebFrameImpl::Closing() {
+ // let go of our references, this breaks reference cycles and will
+ // usually eventually lead to us being destroyed.
+ if (frameview())
+ frameview()->clear();
+ if (frame_) {
+ StopLoading();
+ frame_ = NULL;
+ }
+ alt_error_page_fetcher_.reset();
+ webview_impl_ = NULL;
+}
+
+void WebFrameImpl::DidReceiveData(DocumentLoader* loader,
+ const char* data, int length) {
+ // Set the text encoding. This calls begin() for us. It is safe to call
+ // this multiple times (Mac does: page/mac/WebCoreFrameBridge.mm).
+ bool user_chosen = true;
+ String encoding = frame_->loader()->documentLoader()->overrideEncoding();
+ if (encoding.isNull()) {
+ user_chosen = false;
+ encoding = loader->response().textEncodingName();
+ }
+ frame_->loader()->setEncoding(encoding, user_chosen);
+
+ // NOTE: mac only does this if there is a document
+ frame_->loader()->addData(data, length);
+
+ // It's possible that we get a DNS failure followed by a second load that
+ // succeeds before we hear back from the alternate error page server. In
+ // that case, cancel the alt error page download.
+ alt_error_page_fetcher_.reset();
+}
+
+void WebFrameImpl::DidFail(const ResourceError& error, bool was_provisional) {
+ // Make sure we never show errors in view source mode.
+ SetInViewSourceMode(false);
+
+ WebViewDelegate* delegate = webview_impl_->delegate();
+ if (delegate) {
+ WebErrorImpl web_error(error);
+ if (was_provisional) {
+ delegate->DidFailProvisionalLoadWithError(webview_impl_, web_error,
+ this);
+ } else {
+ delegate->DidFailLoadWithError(webview_impl_, web_error, this);
+ }
+ }
+}
+
+void WebFrameImpl::LoadAlternateHTMLErrorPage(const WebRequest* request,
+ const WebError& error,
+ const GURL& error_page_url,
+ bool replace,
+ const GURL& fake_url) {
+ // Load alternate HTML in place of the previous request. We create a copy of
+ // the original request so we can replace its URL with a dummy URL. That
+ // prevents other web content from the same origin as the failed URL to
+ // script the error page.
+ scoped_ptr<WebRequest> failed_request(request->Clone());
+ failed_request->SetURL(fake_url);
+
+ LoadAlternateHTMLString(failed_request.get(), std::string(),
+ error.GetFailedURL(), replace);
+
+ WebErrorImpl weberror_impl(error);
+ alt_error_page_fetcher_.reset(
+ new AltErrorPageResourceFetcher(webview_impl_, weberror_impl, this,
+ error_page_url));
+}
+
+std::wstring WebFrameImpl::GetName() {
+ return webkit_glue::StringToStdWString(frame_->tree()->name());
+}
+
+WebTextInput* WebFrameImpl::GetTextInput() {
+ if (!webtextinput_impl_.get()) {
+ webtextinput_impl_.reset(new WebTextInputImpl(this));
+ }
+ return webtextinput_impl_.get();
+}
+
+void WebFrameImpl::SetPrinting(bool printing,
+ float page_width_min,
+ float page_width_max) {
+ frame_->setPrinting(printing,
+ page_width_min,
+ page_width_max,
+ true);
+}
+
+bool WebFrameImpl::Visible() {
+ return frame()->view()->visibleWidth() > 0 &&
+ frame()->view()->visibleHeight() > 0;
+}
+
+void WebFrameImpl::CreateChildFrame(const FrameLoadRequest& r,
+ HTMLFrameOwnerElement* owner_element,
+ bool allows_scrolling,
+ int margin_height,
+ int margin_width,
+ Frame*& result) {
+ // TODO(darin): share code with initWithName()
+
+ scoped_refptr<WebFrameImpl> webframe = new WebFrameImpl();
+
+ // Add an extra ref on behalf of the Frame/FrameLoader, which references the
+ // WebFrame via the FrameLoaderClient interface. See the comment at the top
+ // of this file for more info.
+ webframe->AddRef();
+
+ webframe->allows_scrolling_ = allows_scrolling;
+ webframe->margin_width_ = margin_width;
+ webframe->margin_height_ = margin_height;
+
+ webframe->frame_ =
+ new Frame(frame_->page(), owner_element, &webframe->frame_loader_client_);
+ webframe->frame_->tree()->setName(r.frameName());
+
+ webframe->webview_impl_ = webview_impl_; // owning ref
+
+
+ // Note that Frames already start out with a refcount of 1.
+ // We wait until loader()->load() returns before deref-ing the Frame.
+ // Otherwise the danger is that the onload handler can cause
+ // the Frame to be dealloc-ed, and subsequently trash memory.
+ // (b:1055700)
+ WTF::RefPtr<Frame> protector(WTF::adoptRef(webframe->frame_.get()));
+
+ frame_->tree()->appendChild(webframe->frame_);
+
+ // Frame::init() can trigger onload event in the parent frame,
+ // which may detach this frame and trigger a null-pointer access
+ // in FrameTree::removeChild. Move init() after appendChild call
+ // so that webframe->frame_ is in the tree before triggering
+ // onload event handler.
+ // Because the event handler may set webframe->frame_ to null,
+ // it is necessary to check the value after calling init() and
+ // return without loading URL.
+ // (b:791612)
+ webframe->frame_->init(); // create an empty document
+ if (!webframe->frame_.get())
+ return;
+
+ // The following code was pulled from WebFrame.mm:_loadURL, with minor
+ // modifications. The purpose is to ensure we load the right HistoryItem for
+ // this child frame.
+ HistoryItem* parentItem = frame_->loader()->currentHistoryItem();
+ FrameLoadType loadType = frame_->loader()->loadType();
+ FrameLoadType childLoadType = WebCore::FrameLoadTypeRedirectWithLockedHistory;
+ KURL new_url = r.resourceRequest().url();
+
+ // If we're moving in the backforward list, we might want to replace the
+ // content of this child frame with whatever was there at that point.
+ // Reload will maintain the frame contents, LoadSame will not.
+ if (parentItem && parentItem->children().size() != 0 &&
+ (isBackForwardLoadType(loadType) ||
+ loadType == WebCore::FrameLoadTypeReload ||
+ loadType == WebCore::FrameLoadTypeReloadAllowingStaleData)) {
+ HistoryItem* childItem = parentItem->childItemWithName(r.frameName());
+ if (childItem) {
+ // Use the original URL to ensure we get all the side-effects, such as
+ // onLoad handlers, of any redirects that happened. An example of where
+ // this is needed is Radar 3213556.
+ new_url = KURL(KURL(""),
+ childItem->originalURLString().deprecatedString());
+
+ // These behaviors implied by these loadTypes should apply to the child
+ // frames
+ childLoadType = loadType;
+
+ if (isBackForwardLoadType(loadType)) {
+ // For back/forward, remember this item so we can traverse any child
+ // items as child frames load.
+ webframe->frame_->loader()->setProvisionalHistoryItem(childItem);
+ } else {
+ // For reload, just reinstall the current item, since a new child frame
+ // was created but we won't be creating a new BF item
+ webframe->frame_->loader()->setCurrentHistoryItem(childItem);
+ }
+ }
+ }
+
+ webframe->frame_->loader()->load(new_url,
+ r.resourceRequest().httpReferrer(),
+ childLoadType,
+ String(), NULL, NULL);
+
+ // A synchronous navigation (about:blank) would have already processed
+ // onload, so it is possible for the frame to have already been destroyed by
+ // script in the page.
+ result = webframe->frame_.get();
+}
+
+bool WebFrameImpl::ExecuteCoreCommandByName(const std::string& name,
+ const std::string& value) {
+ ASSERT(frame());
+ return frame()->editor()->command(webkit_glue::StdStringToString(name))
+ .execute(webkit_glue::StdStringToString(value));
+}
+
+void WebFrameImpl::AddMessageToConsole(const std::wstring& msg,
+ ConsoleMessageLevel level) {
+ ASSERT(frame());
+
+ WebCore::MessageLevel webcore_message_level;
+ switch (level) {
+ case MESSAGE_LEVEL_TIP:
+ webcore_message_level = WebCore::TipMessageLevel;
+ break;
+ case MESSAGE_LEVEL_LOG:
+ webcore_message_level = WebCore::LogMessageLevel;
+ break;
+ case MESSAGE_LEVEL_WARNING:
+ webcore_message_level = WebCore::WarningMessageLevel;
+ break;
+ case MESSAGE_LEVEL_ERROR:
+ webcore_message_level = WebCore::ErrorMessageLevel;
+ break;
+ default:
+ NOTREACHED();
+ return;
+ }
+
+ frame()->page()->chrome()->addMessageToConsole(
+ WebCore::OtherMessageSource, webcore_message_level,
+ webkit_glue::StdWStringToString(msg), 1, String());
+}
+
+void WebFrameImpl::ClosePage() {
+ // TODO(creis): Find a way to use WebView::Close() instead. (See comments in
+ // webframe.h and RenderView::OnClosePage.)
+ frame_->loader()->closeURL();
+}
+
+gfx::Size WebFrameImpl::ScrollOffset() const {
+ WebCore::FrameView* view = frameview();
+ if (view) {
+ WebCore::IntSize s = view->scrollOffset();
+ return gfx::Size(s.width(), s.height());
+ }
+
+ return gfx::Size();
+}
+
+void WebFrameImpl::SetAllowsScrolling(bool flag) {
+ allows_scrolling_ = flag;
+ frame_->view()->setAllowsScrolling(flag);
+}
+
+bool WebFrameImpl::SetPrintingMode(bool printing,
+ float page_width_min,
+ float page_width_max,
+ int* width) {
+ // Make sure main frame is loaded.
+ WebCore::FrameView* view = frameview();
+ if (!view) {
+ NOTREACHED();
+ return false;
+ }
+ printing_ = printing;
+ if (printing) {
+ view->setScrollbarsMode(WebCore::ScrollbarAlwaysOff);
+ } else {
+ view->setScrollbarsMode(WebCore::ScrollbarAuto);
+ }
+ DCHECK_EQ(frame()->isFrameSet(), false);
+
+ SetPrinting(printing, page_width_min, page_width_max);
+ if (!printing)
+ pages_.clear();
+
+ // The document width is well hidden.
+ if (width)
+ *width = frame()->document()->renderer()->width();
+ return true;
+}
+
+int WebFrameImpl::ComputePageRects(const gfx::Size& page_size_px) {
+ if (!printing_ ||
+ !frame() ||
+ !frame()->document()) {
+ NOTREACHED();
+ return 0;
+ }
+ // In Safari, they are using:
+ // (0,0) + soft margins top/left
+ // (phys width, phys height) - hard margins -
+ // soft margins top/left - soft margins right/bottom
+ // TODO(maruel): Weird. We don't do that.
+ // Everything is in pixels :(
+ // pages_ and page_height are actually output parameters.
+ int page_height;
+ WebCore::IntRect rect(0, 0, page_size_px.width(), page_size_px.height());
+ computePageRectsForFrame(frame(), rect, 0, 0, 1.0, pages_, page_height);
+ return pages_.size();
+}
+
+void WebFrameImpl::GetPageRect(int page, gfx::Rect* page_size) const {
+ if (page < 0 || page >= static_cast<int>(pages_.size())) {
+ NOTREACHED();
+ return;
+ }
+ *page_size = pages_[page];
+}
+
+bool WebFrameImpl::SpoolPage(int page,
+ PlatformContextSkia* context) {
+ // Ensure correct state.
+ if (!context ||
+ !printing_ ||
+ page < 0 ||
+ page >= static_cast<int>(pages_.size())) {
+ NOTREACHED();
+ return false;
+ }
+
+ if (!frame() || !frame()->document()) {
+ NOTREACHED();
+ return false;
+ }
+
+ GraphicsContext spool(reinterpret_cast<PlatformGraphicsContext*>(context));
+ DCHECK(pages_[page].x() == 0);
+ // Offset to get the right square.
+ spool.translate(0, -static_cast<float>(pages_[page].y()));
+ frame()->paint(&spool, pages_[page]);
+ return true;
+}
+
+bool WebFrameImpl::HasUnloadListener() {
+ if (frame() && frame()->document()) {
+ Document* doc = frame()->document();
+ return doc->hasUnloadEventListener();
+ }
+ return false;
+}
diff --git a/webkit/glue/webframe_impl.h b/webkit/glue/webframe_impl.h
new file mode 100644
index 0000000..2b974b7
--- /dev/null
+++ b/webkit/glue/webframe_impl.h
@@ -0,0 +1,431 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 WEBKIT_GLUE_WEBFRAME_IMPL_H__
+#define WEBKIT_GLUE_WEBFRAME_IMPL_H__
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "base/task.h"
+#include "webkit/glue/webdatasource_impl.h"
+#include "webkit/glue/webframe.h"
+#include "webkit/glue/webframeloaderclient_impl.h"
+#include "webkit/glue/webplugin_delegate.h"
+#include "webkit/glue/webview_delegate.h"
+
+#pragma warning(push, 0)
+#include "ResourceHandleClient.h"
+#include "Frame.h"
+#include "PlatformString.h"
+#pragma warning(pop)
+
+class AltErrorPageResourceFetcher;
+class WebErrorImpl;
+class WebHistoryItemImpl;
+class WebRequest;
+class WebView;
+class WebViewImpl;
+class WebTextInput;
+class WebTextInputImpl;
+
+namespace WebCore {
+class Frame;
+class FrameView;
+class HistoryItem;
+class Node;
+class Range;
+class SubstituteData;
+struct WindowFeatures;
+}
+
+namespace gfx {
+class PlatformCanvas;
+class BitmapPlatformDevice;
+}
+
+// Implementation of WebFrame, note that this is a reference counted object.
+class WebFrameImpl : public WebFrame {
+ public:
+ WebFrameImpl();
+ ~WebFrameImpl();
+
+ static int live_object_count() {
+ return live_object_count_;
+ }
+
+ // Called by the WebViewImpl to initialize its main frame:
+ void InitMainFrame(WebViewImpl* webview_impl);
+
+ // WebFrame
+ virtual void LoadRequest(WebRequest* request);
+ virtual void LoadHTMLString(const std::string& html_text,
+ const GURL& base_url);
+ virtual void LoadAlternateHTMLString(const WebRequest* request,
+ const std::string& html_text,
+ const GURL& display_url,
+ bool replace);
+ virtual void LoadAlternateHTMLErrorPage(const WebRequest* request,
+ const WebError& error,
+ const GURL& error_page_url,
+ bool replace,
+ const GURL& fake_url);
+ virtual bool GetPreviousState(GURL* url, std::wstring* title,
+ std::string* history_state) const;
+ virtual bool GetCurrentState(GURL* url, std::wstring* title,
+ std::string* history_state) const;
+ virtual bool HasCurrentState() const;
+ virtual GURL GetURL() const;
+ virtual GURL GetFavIconURL() const;
+ virtual GURL GetOSDDURL() const;
+ virtual WebDataSource* GetDataSource() const;
+ virtual WebDataSource* GetProvisionalDataSource() const;
+ virtual void StopLoading();
+ virtual WebFrame* GetOpener() const;
+ virtual WebFrame* GetParent() const;
+ virtual WebFrame* GetChildFrame(const std::wstring& xpath) const;
+ virtual WebView* GetView() const;
+ virtual gfx::BitmapPlatformDevice CaptureImage(bool scroll_to_zero);
+
+ // This method calls createRuntimeObject (in KJS::Bindings::Instance), which
+ // increments the refcount of the NPObject passed in.
+ virtual void BindToWindowObject(const std::wstring& name, NPObject* object);
+ virtual void CallJSGC();
+
+ virtual void* GetFrameImplementation() { return frame(); }
+
+ virtual void GetContentAsPlainText(int max_chars, std::wstring* text) const;
+ virtual bool Find(const FindInPageRequest& request,
+ bool wrap_within_frame,
+ gfx::Rect* selection_rect);
+ virtual bool FindNext(const FindInPageRequest& request,
+ bool wrap_within_frame);
+ virtual void StopFinding();
+ virtual void ScopeStringMatches(FindInPageRequest request, bool reset);
+ virtual void CancelPendingScopingEffort();
+ virtual void ResetMatchCount();
+ virtual bool Visible();
+ virtual void SelectAll();
+ virtual void Copy();
+ virtual void Cut();
+ virtual void Paste();
+ virtual void Replace(const std::wstring& text);
+ virtual void Delete();
+ virtual void Undo();
+ virtual void Redo();
+ virtual void ClearSelection();
+
+ virtual void SetInViewSourceMode(bool);
+
+ virtual bool GetInViewSourceMode() const;
+
+ virtual void DidReceiveData(WebCore::DocumentLoader* loader,
+ const char* data,
+ int length);
+ virtual void DidFail(const WebCore::ResourceError&, bool was_provisional);
+
+ virtual std::wstring GetName();
+
+ virtual WebTextInput* GetTextInput();
+
+ virtual bool ExecuteCoreCommandByName(const std::string& name, const std::string& value);
+
+ virtual void AddMessageToConsole(const std::wstring& msg,
+ ConsoleMessageLevel level);
+
+ virtual void ClosePage();
+
+ virtual gfx::Size ScrollOffset() const;
+
+ virtual bool SetPrintingMode(bool printing,
+ float page_width_min,
+ float page_width_max,
+ int* width);
+ virtual int ComputePageRects(const gfx::Size& page_size_px);
+ virtual void GetPageRect(int page, gfx::Rect* page_size) const;
+ virtual bool SpoolPage(int page,
+ PlatformContextSkia* context);
+
+ // Reformats this frame for printing or for screen display, depending on
+ // |printing| flag. Acts recursively on inner frames.
+ // Note: It fails if the main frame failed to load. It will succeed even if a
+ // child frame failed to load.
+ void SetPrinting(bool printing, float page_width_min, float page_width_max);
+
+ void CreateChildFrame(const WebCore::FrameLoadRequest&,
+ WebCore::HTMLFrameOwnerElement* owner_element,
+ bool allows_scrolling, int margin_width,
+ int margin_height, WebCore::Frame*& new_frame);
+
+ // WebFrameImpl
+ void Layout();
+ void Paint(gfx::PlatformCanvas* canvas, const gfx::Rect& rect);
+
+ bool IsLoading();
+
+ void CreateFrameView();
+
+ // The plugin delegate is used to get notifications when downloads complete.
+ // This is used by the NPAPI method getURLNotify. plugin_delegate() may
+ // return NULL. TODO(darin): how come there is only one per frame?!?
+ WebPluginDelegate* plugin_delegate() const {
+ return plugin_delegate_;
+ }
+ void set_plugin_delegate(WebPluginDelegate* plugin_delegate) {
+ plugin_delegate_ = plugin_delegate;
+ }
+
+ WebCore::Frame* frame() {
+ return frame_.get();
+ }
+
+ static WebFrameImpl* FromFrame(WebCore::Frame* frame);
+
+ WebViewImpl* webview_impl() const {
+ return webview_impl_;
+ }
+
+ WebCore::FrameView* frameview() const {
+ return frame_ ? frame_->view() : NULL;
+ }
+
+ // Update the given datasource with currently_loading_request's info.
+ // If currently_loading_request is NULL, does nothing.
+ void CacheCurrentRequestInfo(WebDataSourceImpl* datasource);
+
+ void set_currently_loading_history_item(WebHistoryItemImpl* item);
+
+ // Getters for the impls corresponding to Get(Provisional)DataSource. They
+ // may return NULL if there is no corresponding data source.
+ WebDataSourceImpl* GetDataSourceImpl() const;
+ WebDataSourceImpl* GetProvisionalDataSourceImpl() const;
+
+ // Gets the tickmarks for drawing on the scrollbars of a particular frame.
+ const Vector<RefPtr<WebCore::Range> >& tickmarks() const {
+ return tickmarks_;
+ }
+
+ // Returns whether a range representing a tickmark should be highlighted.
+ // We use this to avoid highlighting ranges that are currently hidden.
+ static bool RangeShouldBeHighlighted(WebCore::Range* range);
+
+ const WebCore::Node* inspected_node() const {
+ return inspected_node_;
+ }
+
+ void WebFrameImpl::selectNodeFromInspector(WebCore::Node* node);
+
+ // Returns which frame has an active tickmark. This function should only be
+ // called on the main frame, as it is the only frame keeping track. Returned
+ // value can be NULL if no frame has an active tickmark.
+ const WebFrameImpl* active_tickmark_frame() const {
+ return active_tickmark_frame_;
+ }
+
+ // Returns the index of the active tickmark for this frame.
+ size_t active_tickmark_index() const {
+ return active_tickmark_;
+ }
+
+ // Sets whether the WebFrameImpl allows its document to be scrolled.
+ // If the parameter is true, allow the document to be scrolled.
+ // Otherwise, disallow scrolling
+ void SetAllowsScrolling(bool flag);
+
+ // Returns true if the frame CSS is in "printing" mode.
+ bool printing() const { return printing_; }
+
+ virtual bool HasUnloadListener();
+
+ protected:
+ friend class WebFrameLoaderClient;
+
+ // Informs the WebFrame that the Frame is being closed, called by the
+ // WebFrameLoaderClient
+ void Closing();
+
+ // A helper function for loading some document, given all of its data, into
+ // this frame. The charset may be empty if unknown, but a mime type must be
+ // specified. TODO(darin): Add option for storing this in session history.
+ void LoadDocumentData(const WebCore::KURL& base_url,
+ const WebCore::String& data,
+ const WebCore::String& mime_type,
+ const WebCore::String& charset);
+
+ // See WebFrame.h for details.
+ virtual void IncreaseMatchCount(int count, int request_id);
+ virtual void ReportFindInPageSelection(const gfx::Rect& selection_rect,
+ int active_match_ordinal,
+ int request_id);
+
+ // Resource fetcher for downloading an alternate DNS error page.
+ scoped_ptr<AltErrorPageResourceFetcher> alt_error_page_fetcher_;
+
+ // Used to check for leaks of this object.
+ static int live_object_count_;
+
+ WebFrameLoaderClient frame_loader_client_;
+
+ // Holding a reference back to the WebViewImpl is necessary to ensure that
+ // its HWND is not destroyed before all of the WebCore::Widgets, which refer
+ // to the WebViewImpl's HWND as their containingWindow. However, this ref
+ // creates a cycle between the WebViewImpl and the top-most WebFrameImpl. We
+ // break this cycle in our Closing method.
+ scoped_refptr<WebViewImpl> webview_impl_;
+
+ // The WebCore frame associated with this frame. MAY BE NULL if the frame
+ // has been detached from the DOM.
+ WTF::RefPtr<WebCore::Frame> frame_;
+
+ // This holds the request passed to LoadRequest, for access by the
+ // WebFrameLoaderClient. Unfortunately we have no other way to pass this
+ // information to him. Only non-NULL during a call to LoadRequest.
+ const WebRequest* currently_loading_request_;
+
+ // Similar to currently_loading_request_, except this will be set when
+ // WebCore initiates a history navigation (probably via javascript).
+ scoped_refptr<WebHistoryItemImpl> currently_loading_history_item_;
+
+ // Plugins sometimes need to be notified when loads are complete so we keep
+ // a pointer back to the appropriate plugin.
+ WebPluginDelegate* plugin_delegate_;
+
+ // Frame construction parameters
+ bool allows_scrolling_;
+ int margin_width_;
+ int margin_height_;
+
+ // Handling requests from TextInputController on this frame.
+ scoped_ptr<WebTextInputImpl> webtextinput_impl_;
+
+ // This vector maintains a list of Ranges representing locations for search
+ // string matches that were found in the frame during a FindInPage operation.
+ Vector<RefPtr<WebCore::Range> > tickmarks_;
+
+ // The node selected in the web inspector. Used for highlighting it on the page.
+ WebCore::Node* inspected_node_;
+
+ // The index of the active tickmark for the current frame.
+ size_t active_tickmark_;
+
+ // This rectangle is used during the scoping effort to figure out what rect
+ // got selected during the Find operation. In other words, first the Find
+ // operation iterates to the next match and then scoping will happen for all
+ // matches. When we encounter this rectangle during scoping we mark that
+ // tickmark as active (see active_tickmark_). This avoids having to iterate
+ // through a potentially very large tickmark vector to see which hit is
+ // active. Once we find the active rectangle we clear this rectangle to
+ // indicate that we are done determining what the active match is.
+ WebCore::IntRect active_selection_rect_;
+
+ // This range represents the range that got selected during the Find or
+ // FindNext operation. We will set this range as the selection (unless the
+ // user selects something between Find/FindNext operations) so that we can
+ // continue from where we left off.
+ RefPtr<WebCore::Range> last_active_range_;
+
+ // Keeps track of the last string this frame searched for. This is used for
+ // short-circuiting searches in the following scenarios: When a frame has
+ // been searched and returned 0 results, we don't need to search that frame
+ // again if the user is just adding to the search (making it more specific).
+ std::wstring last_search_string_;
+
+ // Keeps track of how many matches this frame has found so far, so that we
+ // don't loose count between scoping efforts, and is also used (in conjunction
+ // with last_search_string_ and scoping_complete_) to figure out if we need to
+ // search the frame again.
+ int last_match_count_;
+
+ // This variable keeps a cumulative total of matches found so far for ALL the
+ // frames on the page, and is only incremented by calling IncreaseMatchCount
+ // (on the main frame only). It should be -1 for all other frames.
+ int total_matchcount_;
+
+ // A way for the main frame to keep track of which frame has an active
+ // tickmark. Should be NULL for all other frames.
+ WebFrameImpl* active_tickmark_frame_;
+
+ // This variable keeps a cumulative total of how many frames are currently
+ // scoping, and is incremented/decremented on the main frame only.
+ // It should be -1 for all other frames.
+ int frames_scoping_count_;
+
+ // Keeps track of whether the scoping effort was completed (the user may
+ // interrupt it before it completes by submitting a new search).
+ bool scoping_complete_;
+
+ // Keeps track of when the scoping effort should next invalidate the scrollbar
+ // and the frame area.
+ int next_invalidate_after_;
+
+ // This is a factory for creating cancelable tasks for this frame that run
+ // asynchronously in order to scope string matches during a find operation.
+ ScopedRunnableMethodFactory<WebFrameImpl> scope_matches_factory_;
+
+ private:
+ // A bit mask specifying area of the frame to invalidate.
+ typedef enum AreaToInvalidate {
+ INVALIDATE_NOTHING = 0,
+ INVALIDATE_CONTENT_AREA = 1,
+ INVALIDATE_SCROLLBAR = 2, // vertical scrollbar only.
+ INVALIDATE_ALL = 3 // both content area and the scrollbar.
+ };
+
+ // Invalidates a certain area within the frame.
+ void InvalidateArea(AreaToInvalidate area);
+
+ // Invalidates the tickmark area represented by the range passed in.
+ void InvalidateTickmark(RefPtr<WebCore::Range> tickmark);
+
+ // Returns the ordinal of the first match in the frame specified. This
+ // function enumerates the frames, starting with the main frame and up to (but
+ // not including) the frame passed in as a parameter and counts how many
+ // tickmarks there are.
+ int OrdinalOfFirstMatchForFrame(WebFrameImpl* frame) const;
+
+ // Determines whether the scoping effort is required for a particular frame.
+ // It is not necessary if the frame is invisible, for example, or if this
+ // is a repeat search that already returned nothing last time the same prefix
+ // was searched.
+ bool ShouldScopeMatches(FindInPageRequest request);
+
+ // Determines whether to invalidate the content area and scrollbar.
+ void InvalidateIfNecessary();
+
+ void InternalLoadRequest(const WebRequest* request,
+ const WebCore::SubstituteData& data,
+ bool replace);
+
+ // In "printing" mode. Used as a state check.
+ bool printing_;
+
+ // For each printed page, the view of the document in pixels.
+ Vector<WebCore::IntRect> pages_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(WebFrameImpl);
+};
+
+#endif // WEBKIT_GLUE_WEBFRAME_IMPL_H__
diff --git a/webkit/glue/webframeloaderclient_impl.cc b/webkit/glue/webframeloaderclient_impl.cc
new file mode 100644
index 0000000..b1056d8
--- /dev/null
+++ b/webkit/glue/webframeloaderclient_impl.cc
@@ -0,0 +1,1502 @@
+// 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 "config.h"
+#include <string>
+#include <vector>
+
+#pragma warning(push, 0)
+#include "Chrome.h"
+#include "CString.h"
+#include "Document.h"
+#include "DocumentLoader.h"
+#include "Element.h"
+#include "HistoryItem.h"
+#include "HTMLFormElement.h" // needed by FormState.h
+#include "FormState.h"
+#include "FrameLoader.h"
+#include "FrameLoadRequest.h"
+#include "FrameView.h"
+#include "MIMETypeRegistry.h"
+#include "MouseEvent.h"
+#include "Page.h"
+#include "PlatformString.h"
+#include "PluginInfoStore.h"
+#include "RefPtr.h"
+#include "WindowFeatures.h"
+#pragma warning(pop)
+
+#undef LOG
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "net/base/mime_util.h"
+#include "net/base/net_errors.h"
+#include "webkit/activex_shim/activex_shared.h"
+#include "webkit/glue/webframeloaderclient_impl.h"
+#include "webkit/glue/alt_404_page_resource_fetcher.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/password_form_dom_manager.h"
+#include "webkit/glue/plugins/plugin_list.h"
+#include "webkit/glue/searchable_form_data.h"
+#include "webkit/glue/webdatasource_impl.h"
+#include "webkit/glue/webdocumentloader_impl.h"
+#include "webkit/glue/weberror_impl.h"
+#include "webkit/glue/webhistoryitem_impl.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/webplugin_impl.h"
+#include "webkit/glue/webresponse_impl.h"
+#include "webkit/glue/webview_delegate.h"
+#include "webkit/glue/webview_impl.h"
+#include "webkit/glue/weburlrequest.h"
+
+using namespace WebCore;
+
+// Domain for internal error codes.
+static const char kInternalErrorDomain[] = "webkit_glue";
+
+// An internal error code. Used to note a policy change error resulting from
+// dispatchDecidePolicyForMIMEType not passing the PolicyUse option.
+enum {
+ ERR_POLICY_CHANGE = -10000,
+};
+
+WebFrameLoaderClient::WebFrameLoaderClient(WebFrameImpl* frame) :
+ webframe_(frame),
+ postpone_loading_data_(false),
+ has_representation_(false),
+ plugin_widget_(NULL),
+ sent_initial_response_to_plugin_(false),
+ next_window_open_disposition_(IGNORE_ACTION) {
+}
+
+WebFrameLoaderClient::~WebFrameLoaderClient() {
+}
+
+void WebFrameLoaderClient::frameLoaderDestroyed() {
+ // When the WebFrame was created, it had an extra ref() given to it on behalf
+ // of the FrameWin, which accesses it via the FrameWinClient interface.
+ // Since the WebFrame owns us, this extra ref also serves to keep us alive
+ // until the FrameLoader is done with us. The FrameLoader calls this method
+ // when it's going away. Therefore, we balance out that extra ref.
+ //
+ // May delete 'this'
+ webframe_->Release();
+}
+
+void WebFrameLoaderClient::windowObjectCleared() {
+ WebViewImpl* webview = webframe_->webview_impl();
+ WebViewDelegate* d = webview->delegate();
+ if (d)
+ d->WindowObjectCleared(webframe_);
+}
+
+void WebFrameLoaderClient::didPerformFirstNavigation() const {
+}
+
+void WebFrameLoaderClient::registerForIconNotification(bool listen){
+}
+
+void WebFrameLoaderClient::unloadListenerChanged() {
+ WebViewImpl* webview = webframe_->webview_impl();
+ WebViewDelegate* d = webview->delegate();
+ if (d)
+ d->OnUnloadListenerChanged(webview, webframe_);
+}
+
+bool WebFrameLoaderClient::hasWebView() const {
+ return webframe_->webview_impl() != NULL;
+}
+
+bool WebFrameLoaderClient::hasFrameView() const {
+ // The Mac port has this notion of a WebFrameView, which seems to be
+ // some wrapper around an NSView. Since our equivalent is HWND, I guess
+ // we have a "frameview" whenever we have the toplevel HWND.
+ return webframe_->webview_impl() != NULL;
+}
+
+bool WebFrameLoaderClient::privateBrowsingEnabled() const {
+ // FIXME
+ return false;
+}
+
+void WebFrameLoaderClient::makeDocumentView() {
+ webframe_->CreateFrameView();
+}
+
+void WebFrameLoaderClient::makeRepresentation(DocumentLoader*) {
+ has_representation_ = true;
+}
+
+void WebFrameLoaderClient::setDocumentViewFromCachedPage(CachedPage*) {
+ // FIXME
+}
+void WebFrameLoaderClient::forceLayout() {
+ // FIXME
+}
+void WebFrameLoaderClient::forceLayoutForNonHTML() {
+ // FIXME
+}
+
+void WebFrameLoaderClient::setCopiesOnScroll() {
+ // FIXME
+}
+
+void WebFrameLoaderClient::detachedFromParent2() {
+ // FIXME
+}
+void WebFrameLoaderClient::detachedFromParent3() {
+ // FIXME
+}
+
+void WebFrameLoaderClient::detachedFromParent4() {
+ // Called during the last part of frame detaching, to indicate that we should
+ // destroy various objects (including the FrameWin).
+ webframe_->Closing();
+}
+
+void WebFrameLoaderClient::loadedFromCachedPage() {
+ // FIXME
+}
+
+// This function is responsible for associating the |identifier| with a given
+// subresource load. The following functions that accept an |identifier| are
+// called for each subresource, so they should not be dispatched to the
+// WebFrame.
+void WebFrameLoaderClient::assignIdentifierToInitialRequest(
+ unsigned long identifier, DocumentLoader* loader,
+ const ResourceRequest& request) {
+ WebViewImpl* webview = webframe_->webview_impl();
+ WebViewDelegate* d = webview->delegate();
+ if (d) {
+ WebRequestImpl webreq(request);
+ d->AssignIdentifierToRequest(webview, identifier, webreq);
+ }
+}
+
+// Determines whether the request being loaded by |loader| is a frame
+// or a subresource. A subresource in this context is anything other
+// than a frame -- this includes images and xmlhttp requests.
+// It is important to note that a subresource is NOT limited to stuff
+// loaded through the frame's subresource loader. Synchronous xmlhttp
+// requests for example, do not go through the subresource loader,
+// but we still label them as SUB_RESOURCE.
+//
+// The important edge cases to consider when modifying this function are
+// how synchronous resource loads are treated during load/unload threshold.
+static ResourceType::Type DetermineResourceTypeFromLoader(DocumentLoader* loader) {
+ if (loader == loader->frameLoader()->provisionalDocumentLoader()) {
+ if (loader->frameLoader()->isLoadingMainFrame()) {
+ return ResourceType::MAIN_FRAME;
+ } else {
+ return ResourceType::SUB_FRAME;
+ }
+ }
+ return ResourceType::SUB_RESOURCE;
+}
+
+void WebFrameLoaderClient::dispatchWillSendRequest(
+ DocumentLoader* loader, unsigned long identifier, ResourceRequest& request,
+ const ResourceResponse& redirectResponse) {
+ // We set the Frame on the ResourceRequest to provide load context to the
+ // ResourceHandle implementation.
+ request.setFrame(webframe_->frame());
+
+ // We want to distinguish between a request for a document to be loaded into
+ // the main frame, a sub-frame, or the sub-objects in that document.
+ request.setResourceType(DetermineResourceTypeFromLoader(loader));
+
+ // FrameLoader::loadEmptyDocumentSynchronously() creates an empty document
+ // with no URL. We don't like that, so we'll rename it to about:blank.
+ if (request.url().isEmpty())
+ request.setURL(KURL("about:blank"));
+ if (request.mainDocumentURL().isEmpty())
+ request.setMainDocumentURL(KURL("about:blank"));
+
+ // Give the delegate a crack at the request.
+ WebViewImpl* webview = webframe_->webview_impl();
+ WebViewDelegate* d = webview->delegate();
+ if (d) {
+ WebRequestImpl webreq(request);
+ d->WillSendRequest(webview, identifier, &webreq);
+ request = webreq.frame_load_request().resourceRequest();
+ }
+}
+
+void WebFrameLoaderClient::dispatchDidReceiveAuthenticationChallenge(
+ DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&) {
+ // FIXME
+}
+
+void WebFrameLoaderClient::dispatchDidCancelAuthenticationChallenge(
+ DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&) {
+ // FIXME
+}
+
+void WebFrameLoaderClient::dispatchDidReceiveResponse(DocumentLoader* loader,
+ unsigned long identifier,
+ const ResourceResponse& response) {
+
+ // True if the request was for the page's main frame, or a subframe.
+ bool is_frame = ResourceType::IsFrame(DetermineResourceTypeFromLoader(loader));
+
+ /* TODO(evanm): reenable this once we properly sniff XHTML from text/xml documents.
+ if (is_frame &&
+ response.httpStatusCode() == 200 &&
+ mime_util::IsViewSourceMimeType(
+ webkit_glue::CStringToStdString(response.mimeType().latin1()).c_str())) {
+ loader->frame()->setInViewSourceMode();
+ }*/
+
+ // When the frame request first 404's, chrome may replace it with the alternate
+ // 404 page's contents. It does this using substitute data in the document
+ // loader, so the original response and url of the request can be preserved.
+ // We need to avoid replacing the current page, if it has already been
+ // replaced (otherwise could loop on setting alt-404 page!)
+ bool is_substitute_data = loader->substituteData().isValid();
+
+ // If it's a 404 page, we wait until we get 512 bytes of data before trying
+ // to load the document. This allows us to put up an alternate 404 page if
+ // there's short text.
+ postpone_loading_data_ = is_frame &&
+ !is_substitute_data &&
+ response.httpStatusCode() == 404 &&
+ GetAlt404PageUrl(loader).is_valid();
+ if (postpone_loading_data_)
+ postponed_data_.clear();
+
+ // Cancel any pending loads.
+ alt_404_page_fetcher_.reset(NULL);
+}
+
+void WebFrameLoaderClient::dispatchDidReceiveContentLength(DocumentLoader* loader,
+ unsigned long identifier,
+ int lengthReceived) {
+ // FIXME
+}
+
+// Called when a particular resource load completes
+void WebFrameLoaderClient::dispatchDidFinishLoading(DocumentLoader* loader,
+ unsigned long identifier) {
+ if (postpone_loading_data_) {
+ // The server returned a 404 and the content was < 512 bytes (which we
+ // suppressed). Go ahead and fetch the alternate page content.
+ const GURL& url = GetAlt404PageUrl(loader);
+ DCHECK(url.is_valid()) <<
+ "URL changed? It was valid in dispatchDidReceiveResponse.";
+ alt_404_page_fetcher_.reset(new Alt404PageResourceFetcher(this,
+ webframe_->frame(), loader, url));
+ }
+
+ WebViewImpl* webview = webframe_->webview_impl();
+ WebViewDelegate* d = webview->delegate();
+ if (d)
+ d->DidFinishLoading(webview, identifier);
+}
+
+GURL WebFrameLoaderClient::GetAlt404PageUrl(DocumentLoader* loader) {
+ WebViewImpl* webview = webframe_->webview_impl();
+ WebViewDelegate* d = webview->delegate();
+ if (!d)
+ return GURL();
+
+ const GURL& failedURL = webkit_glue::KURLToGURL(loader->url());
+
+ // If trying to view source on a 404 page, just show the original page
+ // content.
+ if (webframe_->frame()->inViewSourceMode())
+ return GURL();
+
+ // Construct the URL to fetch from the alt error page server. "html404"
+ // is understood by the link doctor server.
+ return d->GetAlternateErrorPageURL(failedURL, WebViewDelegate::HTTP_404);
+}
+
+void WebFrameLoaderClient::Alt404PageFinished(DocumentLoader* loader,
+ const std::string& html) {
+ if (html.length() > 0) {
+ // TODO(tc): Handle backoff on so we don't hammer the alt error page
+ // servers.
+ webframe_->LoadHTMLString(html, webkit_glue::KURLToGURL(loader->url()));
+ } else {
+ // Fall back on original text
+ webframe_->LoadHTMLString(postponed_data_,
+ webkit_glue::KURLToGURL(loader->url()));
+ }
+}
+
+void WebFrameLoaderClient::dispatchDidFailLoading(DocumentLoader* loader,
+ unsigned long identifier,
+ const ResourceError& error) {
+ WebViewImpl* webview = webframe_->webview_impl();
+ if (webview && webview->delegate()) {
+ webview->delegate()->DidFailLoadingWithError(webview, identifier,
+ WebErrorImpl(error));
+ }
+}
+
+void WebFrameLoaderClient::dispatchDidFinishDocumentLoad() {
+ WebViewImpl* webview = webframe_->webview_impl();
+ WebViewDelegate* d = webview->delegate();
+ // The document has now been fully loaded.
+ // Scan for password forms to be sent to the browser
+ PassRefPtr<WebCore::HTMLCollection> forms =
+ webframe_->frame()->document()->forms();
+
+ std::vector<PasswordForm> actions;
+ unsigned int form_count = forms->length();
+ for (unsigned int i = 0; i < form_count; ++i) {
+ // Strange but true, sometimes item can be NULL.
+ WebCore::Node* item = forms->item(i);
+ if (item) {
+ WebCore::HTMLFormElement* form =
+ static_cast<WebCore::HTMLFormElement*>(item);
+
+ // Honour autocomplete=off.
+ if (!form->autoComplete())
+ continue;
+
+ scoped_ptr<PasswordForm> data(
+ PasswordFormDomManager::CreatePasswordForm(form));
+ if (data.get())
+ actions.push_back(*data);
+ }
+ }
+ if (d && (actions.size() > 0))
+ d->OnPasswordFormsSeen(webview, actions);
+ if (d)
+ d->DidFinishDocumentLoadForFrame(webview, webframe_);
+}
+
+bool WebFrameLoaderClient::dispatchDidLoadResourceFromMemoryCache(
+ DocumentLoader* loader,
+ const ResourceRequest& request,
+ const ResourceResponse& response,
+ int length) {
+ WebViewImpl* webview = webframe_->webview_impl();
+ WebViewDelegate* d = webview->delegate();
+ if (d) {
+ WebRequestImpl webreq(request);
+ WebResponseImpl webresp(response);
+ return d->DidLoadResourceFromMemoryCache(webview, webreq, webresp,
+ webframe_);
+ }
+
+ return false;
+}
+
+void WebFrameLoaderClient::dispatchDidHandleOnloadEvents() {
+ WebViewImpl* webview = webframe_->webview_impl();
+ WebViewDelegate* d = webview->delegate();
+
+ if (d)
+ d->DidHandleOnloadEventsForFrame(webview, webframe_);
+}
+
+// Redirect Tracking
+// =================
+// We want to keep track of the chain of redirects that occur during page
+// loading. There are two types of redirects, server redirects which are HTTP
+// response codes, and client redirects which are document.location= and meta
+// refreshes.
+//
+// This outlines the callbacks that we get in different redirect situations,
+// and how each call modifies the redirect chain.
+//
+// Normal page load
+// ----------------
+// dispatchDidStartProvisionalLoad() -> adds URL to the redirect list
+// dispatchDidCommitLoad() -> DISPATCHES & clears list
+//
+// Server redirect (success)
+// -------------------------
+// dispatchDidStartProvisionalLoad() -> adds source URL
+// dispatchDidReceiveServerRedirectForProvisionalLoad() -> adds dest URL
+// dispatchDidCommitLoad() -> DISPATCHES
+//
+// Client redirect (success)
+// -------------------------
+// (on page)
+// dispatchWillPerformClientRedirect() -> saves expected redirect
+// dispatchDidStartProvisionalLoad() -> appends redirect source (since
+// it matches the expected redirect)
+// and the current page as the dest)
+// dispatchDidCancelClientRedirect() -> clears expected redirect
+// dispatchDidCommitLoad() -> DISPATCHES
+//
+// Client redirect (cancelled)
+// (e.g meta-refresh trumped by manual doc.location change, or just cancelled
+// because a link was clicked that requires the meta refresh to be rescheduled
+// (the SOURCE URL may have changed).
+// ---------------------------
+// dispatchDidCancelClientRedirect() -> clears expected redirect
+// dispatchDidStartProvisionalLoad() -> adds only URL to redirect list
+// dispatchDidCommitLoad() -> DISPATCHES & clears list
+// rescheduled ? dispatchWillPerformClientRedirect() -> saves expected redirect
+// : nothing
+
+// Client redirect (failure)
+// -------------------------
+// (on page)
+// dispatchWillPerformClientRedirect() -> saves expected redirect
+// dispatchDidStartProvisionalLoad() -> appends redirect source (since
+// it matches the expected redirect)
+// and the current page as the dest)
+// dispatchDidCancelClientRedirect()
+// dispatchDidFailProvisionalLoad()
+//
+// Load 1 -> Server redirect to 2 -> client redirect to 3 -> server redirect to 4
+// ------------------------------------------------------------------------------
+// dispatchDidStartProvisionalLoad() -> adds source URL 1
+// dispatchDidReceiveServerRedirectForProvisionalLoad() -> adds dest URL 2
+// dispatchDidCommitLoad() -> DISPATCHES 1+2
+// -- begin client redirect and NEW DATA SOURCE
+// dispatchWillPerformClientRedirect() -> saves expected redirect
+// dispatchDidStartProvisionalLoad() -> appends URL 2 and URL 3
+// dispatchDidReceiveServerRedirectForProvisionalLoad() -> appends destination URL 4
+// dispatchDidCancelClientRedirect() -> clears expected redirect
+// dispatchDidCommitLoad() -> DISPATCHES
+//
+// Interesting case with multiple location changes involving anchors.
+// Load page 1 containing future client-redirect (back to 1, e.g meta refresh) > Click
+// on a link back to the same page (i.e an anchor href) >
+// client-redirect finally fires (with new source, set to 1#anchor)
+// -----------------------------------------------------------------------------
+// dispatchWillPerformClientRedirect(non-zero 'interval' param) -> saves expected redirect
+// -- click on anchor href
+// dispatchDidCancelClientRedirect() -> clears expected redirect
+// dispatchDidStartProvisionalLoad() -> adds 1#anchor source
+// dispatchDidCommitLoad() -> DISPATCHES 1#anchor
+// dispatchWillPerformClientRedirect() -> saves exp. source (1#anchor)
+// -- redirect timer fires
+// dispatchDidStartProvisionalLoad() -> appends 1#anchor (src) and 1 (dest)
+// dispatchDidCancelClientRedirect() -> clears expected redirect
+// dispatchDidCommitLoad() -> DISPATCHES 1#anchor + 1
+//
+void WebFrameLoaderClient::dispatchDidReceiveServerRedirectForProvisionalLoad() {
+ WebDataSourceImpl* ds = webframe_->GetProvisionalDataSourceImpl();
+ if (!ds) {
+ NOTREACHED() << "Got a server redirect when there is no provisional DS";
+ return;
+ }
+
+ // A provisional load should have started already, which should have put an
+ // entry in our redirect chain.
+ DCHECK(!ds->GetRedirectChain().empty());
+
+ // The URL of the destination is on the provisional data source. We also need
+ // to update the redirect chain to account for this addition (we do this
+ // before the callback so the callback can look at the redirect chain to see
+ // what happened).
+ ds->AppendRedirect(ds->GetRequest().GetURL());
+
+ // Dispatch callback
+ WebViewImpl* webview = webframe_->webview_impl();
+ WebViewDelegate* d = webview->delegate();
+ if (d)
+ d->DidReceiveProvisionalLoadServerRedirect(webview, webframe_);
+}
+
+// Called on both success and failure of a client redirect.
+void WebFrameLoaderClient::dispatchDidCancelClientRedirect() {
+ // No longer expecting a client redirect.
+ WebViewImpl* webview = webframe_->webview_impl();
+ WebViewDelegate* d = webview ? webview->delegate() : NULL;
+ if (d) {
+ expected_client_redirect_src_ = GURL();
+ expected_client_redirect_dest_ = GURL();
+
+ d->DidCancelClientRedirect(webview, webframe_);
+ }
+
+ // No need to clear the redirect chain, since that data source has already
+ // been deleted by the time this function is called.
+}
+
+void WebFrameLoaderClient::dispatchWillPerformClientRedirect(const KURL& url,
+ double interval,
+ double fire_date) {
+ // Tells dispatchDidStartProvisionalLoad that if it sees this item it is a
+ // redirect and the source item should be added as the start of the chain.
+ WebViewImpl* webview = webframe_->webview_impl();
+ WebViewDelegate* d = webview ? webview->delegate() : NULL;
+ if (d) {
+ expected_client_redirect_src_ = webframe_->GetURL();
+ expected_client_redirect_dest_ = webkit_glue::KURLToGURL(url);
+
+ // TODO(timsteele): bug 1135512. Webkit does not properly notify us of
+ // cancelling http > file client redirects. Since the FrameLoader's policy
+ // is to never carry out such a navigation anyway, the best thing we can do
+ // for now to not get confused is ignore this notification.
+ if (expected_client_redirect_dest_.SchemeIsFile() &&
+ (expected_client_redirect_src_.SchemeIs("http") ||
+ expected_client_redirect_src_.SchemeIsSecure())) {
+ expected_client_redirect_src_ = GURL();
+ expected_client_redirect_dest_ = GURL();
+ return;
+ }
+
+ d->WillPerformClientRedirect(webview,
+ webframe_,
+ expected_client_redirect_src_,
+ expected_client_redirect_dest_,
+ static_cast<unsigned int>(interval),
+ static_cast<unsigned int>(fire_date));
+ }
+}
+
+void WebFrameLoaderClient::dispatchDidChangeLocationWithinPage() {
+ // Anchor fragment navigations are not normal loads, so we need to synthesize
+ // some events for our delegate.
+ WebViewImpl* webview = webframe_->webview_impl();
+ WebViewDelegate* d = webview->delegate();
+ if (d)
+ d->DidStartLoading(webview);
+
+ WebDataSourceImpl* ds = webframe_->GetDataSourceImpl();
+ DCHECK(ds) << "DataSource NULL when navigating to reference fragment";
+ if (ds) {
+ GURL url = ds->GetRequest().GetURL();
+ GURL chain_end = ds->GetRedirectChain().back();
+ ds->ClearRedirectChain();
+
+ // Figure out if this location change is because of a JS-initiated client
+ // redirect (e.g onload/setTimeout document.location.href=).
+ // TODO(timsteele): (bugs 1085325, 1046841) We don't get proper redirect
+ // performed/cancelled notifications across anchor navigations, so the
+ // other redirect-tracking code in this class (see dispatch*ClientRedirect()
+ // and dispatchDidStartProvisionalLoad) is insufficient to catch and
+ // properly flag these transitions. Once a proper fix for this bug is
+ // identified and applied the following block may no longer be required.
+ bool was_client_redirect =
+ ((url == expected_client_redirect_dest_) &&
+ (chain_end == expected_client_redirect_src_)) ||
+ (NavigationGestureForLastLoad() == NavigationGestureAuto);
+
+ if (was_client_redirect) {
+ if (d)
+ d->DidCompleteClientRedirect(webview, webframe_, chain_end);
+ ds->AppendRedirect(chain_end);
+ // Make sure we clear the expected redirect since we just effectively
+ // completed it.
+ expected_client_redirect_src_ = GURL();
+ expected_client_redirect_dest_ = GURL();
+ }
+
+ // Regardless of how we got here, we are navigating to a URL so we need to
+ // add it to the redirect chain.
+ ds->AppendRedirect(url);
+
+ // WebKit will re-use requests for in-page navigations, but we want to
+ // think of it as a new request that has a page ID in session history.
+ // This will set the proper page ID, etc. on the request so that the
+ // browser will treat it properly.
+ webframe_->CacheCurrentRequestInfo(ds);
+ }
+
+ bool is_new_navigation;
+ webview->DidCommitLoad(&is_new_navigation);
+ if (d) {
+ d->DidChangeLocationWithinPageForFrame(webview, webframe_,
+ is_new_navigation);
+ }
+
+ if (d)
+ d->DidStopLoading(webview);
+}
+
+void WebFrameLoaderClient::dispatchWillClose() {
+ WebViewImpl* webview = webframe_->webview_impl();
+ // Make sure WebViewImpl releases the references it uses to restore focus.
+ // If we didn't do this, WebViewImpl might try to restore focus to an invalid
+ // element.
+ webview->ReleaseFocusReferences();
+ WebViewDelegate* d = webview->delegate();
+ if (d)
+ d->WillCloseFrame(webview, webframe_);
+}
+
+void WebFrameLoaderClient::dispatchDidReceiveIcon() {
+ WebViewImpl* webview = webframe_->webview_impl();
+ WebViewDelegate* d = webview->delegate();
+ if (d)
+ d->DidReceiveIconForFrame(webview, webframe_);
+}
+
+void WebFrameLoaderClient::dispatchDidStartProvisionalLoad() {
+ // In case a redirect occurs, we need this to be set so that the redirect
+ // handling code can tell where the redirect came from. Server redirects
+ // will occur on the provisional load, so we need to keep track of the most
+ // recent provisional load URL.
+ // See dispatchDidReceiveServerRedirectForProvisionalLoad.
+ WebDataSourceImpl* ds = webframe_->GetProvisionalDataSourceImpl();
+ if (!ds) {
+ NOTREACHED() << "Attempting to provisional load but there isn't one";
+ return;
+ }
+ const GURL& url = ds->GetRequest().GetURL();
+
+ // Since the provisional load just started, we should have not gotten
+ // any redirects yet.
+ DCHECK(ds->GetRedirectChain().empty());
+
+ WebViewImpl* webview = webframe_->webview_impl();
+ WebViewDelegate* d = webview->delegate();
+ // If this load is what we expected from a client redirect, treat it as a
+ // redirect from that original page. The expected redirect urls will be
+ // cleared by DidCancelClientRedirect.
+ if (expected_client_redirect_src_.is_valid()) {
+ // expected_client_redirect_dest_ could be something like
+ // "javascript:history.go(-1)" thus we need to exclude url starts with
+ // "javascript:". See bug: 1080873
+ DCHECK(expected_client_redirect_dest_.SchemeIs("javascript") ||
+ expected_client_redirect_dest_ == url);
+ ds->AppendRedirect(expected_client_redirect_src_);
+ if (d)
+ d->DidCompleteClientRedirect(webview, webframe_,
+ expected_client_redirect_src_);
+ }
+ ds->AppendRedirect(url);
+
+ if (d)
+ d->DidStartProvisionalLoadForFrame(webview, webframe_,
+ NavigationGestureForLastLoad());
+
+ // Cancel any pending loads.
+ if (alt_404_page_fetcher_.get())
+ alt_404_page_fetcher_->Cancel();
+}
+
+NavigationGesture WebFrameLoaderClient::NavigationGestureForLastLoad() {
+ // TODO(timsteele): userGestureHint returns too many false positives
+ // (see bug 1051891) to trust it and assign NavigationGestureUser, so
+ // for now we assign Unknown in those cases and Auto otherwise.
+ // (Issue 874811 known false negative as well).
+ return webframe_->frame()->loader()->userGestureHint() ?
+ NavigationGestureUnknown :
+ NavigationGestureAuto;
+}
+
+void WebFrameLoaderClient::dispatchDidReceiveTitle(const String& title) {
+ WebViewImpl* webview = webframe_->webview_impl();
+ WebViewDelegate* d = webview->delegate();
+ if (d) {
+ d->DidReceiveTitle(webview, webkit_glue::StringToStdWString(title),
+ webframe_);
+ }
+}
+
+void WebFrameLoaderClient::dispatchDidCommitLoad() {
+ WebViewImpl* webview = webframe_->webview_impl();
+
+ bool is_new_navigation;
+ webview->DidCommitLoad(&is_new_navigation);
+ WebViewDelegate* d = webview->delegate();
+ if (d)
+ d->DidCommitLoadForFrame(webview, webframe_, is_new_navigation);
+}
+
+void WebFrameLoaderClient::dispatchDidFailProvisionalLoad(
+ const ResourceError& error) {
+ // If a policy change occured, then we do not want to inform the plugin
+ // delegate. See bug 907789 for details.
+ if (error.domain() == kInternalErrorDomain &&
+ error.errorCode() == ERR_POLICY_CHANGE) {
+ webframe_->DidFail(cancelledError(error.failingURL()), true);
+ } else {
+ webframe_->DidFail(error, true);
+ WebPluginDelegate* plg_delegate = webframe_->plugin_delegate();
+ if (plg_delegate)
+ plg_delegate->DidFinishLoadWithReason(NPRES_NETWORK_ERR);
+ }
+}
+
+void WebFrameLoaderClient::dispatchDidFailLoad(const ResourceError& error) {
+ webframe_->DidFail(error, false);
+
+ WebPluginDelegate* plg_delegate = webframe_->plugin_delegate();
+ if (plg_delegate)
+ plg_delegate->DidFinishLoadWithReason(NPRES_NETWORK_ERR);
+
+ // Don't clear the redirect chain, this will happen in the middle of client
+ // redirects, and we need the context. The chain will be cleared when the
+ // provisional load succeeds or fails, not the "real" one.
+}
+
+void WebFrameLoaderClient::dispatchDidFinishLoad() {
+ WebViewImpl* webview = webframe_->webview_impl();
+ WebViewDelegate* d = webview->delegate();
+ if (d)
+ d->DidFinishLoadForFrame(webview, webframe_);
+ WebPluginDelegate* plg_delegate = webframe_->plugin_delegate();
+ if (plg_delegate)
+ plg_delegate->DidFinishLoadWithReason(NPRES_DONE);
+
+ // Don't clear the redirect chain, this will happen in the middle of client
+ // redirects, and we need the context. The chain will be cleared when the
+ // provisional load succeeds or fails, not the "real" one.
+}
+
+void WebFrameLoaderClient::dispatchDidFirstLayout() {
+ // FIXME: called when webkit finished layout of page.
+ // All resources have not necessarily finished loading.
+}
+
+Frame* WebFrameLoaderClient::dispatchCreatePage() {
+ struct WebCore::WindowFeatures features;
+ Page* new_page = webframe_->frame()->page()->chrome()->createWindow(
+ webframe_->frame(), FrameLoadRequest(), features);
+
+ // Make sure that we have a valid disposition. This should have been set in
+ // the preceeding call to dispatchDecidePolicyForNewWindowAction.
+ DCHECK(next_window_open_disposition_ != IGNORE_ACTION);
+ WindowOpenDisposition disp = next_window_open_disposition_;
+ next_window_open_disposition_ = IGNORE_ACTION;
+
+ // createWindow can return NULL (e.g., popup blocker denies the window).
+ if (!new_page)
+ return NULL;
+
+ WebViewImpl::FromPage(new_page)->set_window_open_disposition(disp);
+ return new_page->mainFrame();
+}
+
+void WebFrameLoaderClient::dispatchShow() {
+ WebViewImpl* webview = webframe_->webview_impl();
+ WebViewDelegate* d = webview->delegate();
+ if (d)
+ d->Show(webview, webview->window_open_disposition());
+}
+
+static bool TreatAsAttachment(const ResourceResponse& response) {
+ const String& content_disposition =
+ response.httpHeaderField("Content-Disposition");
+ if (content_disposition.isEmpty())
+ return false;
+
+ // Some broken sites just send
+ // Content-Disposition: ; filename="file"
+ // screen those out here.
+ if (content_disposition.startsWith(";"))
+ return false;
+
+ if (content_disposition.startsWith("inline", false))
+ return false;
+
+ // Some broken sites just send
+ // Content-Disposition: filename="file"
+ // without a disposition token... screen those out.
+ if (content_disposition.startsWith("filename", false))
+ return false;
+
+ // Also in use is Content-Disposition: name="file"
+ if (content_disposition.startsWith("name", false))
+ return false;
+
+ // We have a content-disposition of "attachment" or unknown.
+ // RFC 2183, section 2.8 says that an unknown disposition
+ // value should be treated as "attachment"
+ return true;
+}
+
+void WebFrameLoaderClient::dispatchDecidePolicyForMIMEType(
+ FramePolicyFunction function,
+ const String& mime_type,
+ const ResourceRequest&) {
+ const ResourceResponse& response =
+ webframe_->frame()->loader()->activeDocumentLoader()->response();
+
+ PolicyAction action;
+
+ int status_code = response.httpStatusCode();
+ if (status_code == 204 || status_code == 205) {
+ // The server does not want us to replace the page contents.
+ action = PolicyIgnore;
+ } else if (TreatAsAttachment(response)) {
+ // The server wants us to download instead of replacing the page contents.
+ // Downloading is handled by the embedder, but we still get the initial
+ // response so that we can ignore it and clean up properly.
+ action = PolicyIgnore;
+ } else if (!canShowMIMEType(mime_type)) {
+ // Make sure that we can actually handle this type internally.
+ action = PolicyIgnore;
+ } else {
+ // OK, we will render this page.
+ action = PolicyUse;
+ }
+
+ // NOTE: ERR_POLICY_CHANGE will be generated when action is not PolicyUse.
+ (webframe_->frame()->loader()->*function)(action);
+}
+
+void WebFrameLoaderClient::dispatchDecidePolicyForNewWindowAction(
+ WebCore::FramePolicyFunction function,
+ const WebCore::NavigationAction& action,
+ const WebCore::ResourceRequest& request,
+ const WebCore::String& frame_name) {
+ WindowOpenDisposition disposition;
+ if (!ActionSpecifiesDisposition(action, &disposition))
+ disposition = NEW_FOREGROUND_TAB;
+
+ PolicyAction policy_action;
+ if (disposition == SAVE_TO_DISK) {
+ policy_action = PolicyDownload;
+ } else {
+ policy_action = PolicyUse;
+
+ // Remember the disposition for when dispatchCreatePage is called. It is
+ // unfortunate that WebCore does not provide us with any context when
+ // creating or showing the new window that would allow us to avoid having
+ // to keep this state.
+ next_window_open_disposition_ = disposition;
+ }
+ (webframe_->frame()->loader()->*function)(policy_action);
+}
+
+// Conversion.
+static WebNavigationType NavigationTypeToWebNavigationType(
+ WebCore::NavigationType t) {
+ switch (t) {
+ case WebCore::NavigationTypeLinkClicked:
+ return WebNavigationTypeLinkClicked;
+ case WebCore::NavigationTypeFormSubmitted:
+ return WebNavigationTypeFormSubmitted;
+ case WebCore::NavigationTypeBackForward:
+ return WebNavigationTypeBackForward;
+ case WebCore::NavigationTypeReload:
+ return WebNavigationTypeReload;
+ case WebCore::NavigationTypeFormResubmitted:
+ return WebNavigationTypeFormResubmitted;
+ default:
+ case WebCore::NavigationTypeOther:
+ return WebNavigationTypeOther;
+ }
+}
+
+void WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction(
+ WebCore::FramePolicyFunction function,
+ const WebCore::NavigationAction& action,
+ const WebCore::ResourceRequest& request) {
+ PolicyAction policy_action = PolicyUse;
+
+ WebViewImpl* wv = webframe_->webview_impl();
+ WebViewDelegate* d = wv->delegate();
+ // It is valid for this function to be invoked in code paths where the
+ // the webview is closed.
+ if (d) {
+ WindowOpenDisposition disposition = CURRENT_TAB;
+ ActionSpecifiesDisposition(action, &disposition);
+
+ // Give the delegate a chance to change the disposition. When we do not
+ // have a provisional data source here, it means that we are scrolling to
+ // an anchor in the page. We don't need to ask the WebViewDelegate about
+ // such navigations.
+ const WebDataSourceImpl* ds = webframe_->GetProvisionalDataSourceImpl();
+ if (ds) {
+ bool is_redirect = !ds->GetRedirectChain().empty();
+
+ WebNavigationType webnav_type =
+ NavigationTypeToWebNavigationType(action.type());
+
+ disposition = d->DispositionForNavigationAction(
+ wv, webframe_, &ds->GetRequest(), webnav_type, disposition, is_redirect);
+
+ if (disposition != IGNORE_ACTION) {
+ if (disposition == CURRENT_TAB) {
+ policy_action = PolicyUse;
+ } else if (disposition == SAVE_TO_DISK) {
+ policy_action = PolicyDownload;
+ } else {
+ d->OpenURL(webframe_->webview_impl(),
+ webkit_glue::KURLToGURL(request.url()),
+ disposition);
+ policy_action = PolicyIgnore;
+ }
+ } else {
+ policy_action = PolicyIgnore;
+ }
+ }
+ } else {
+ policy_action = PolicyIgnore;
+ }
+
+ (webframe_->frame()->loader()->*function)(policy_action);
+}
+
+void WebFrameLoaderClient::cancelPolicyCheck() {
+ // FIXME
+}
+
+void WebFrameLoaderClient::dispatchUnableToImplementPolicy(const ResourceError&) {
+ // FIXME
+}
+
+void WebFrameLoaderClient::dispatchWillSubmitForm(FramePolicyFunction function,
+ PassRefPtr<FormState> form_ref) {
+ SearchableFormData* form_data = SearchableFormData::Create(form_ref->form());
+ WebDocumentLoaderImpl* loader = static_cast<WebDocumentLoaderImpl*>(
+ webframe_->frame()->loader()->provisionalDocumentLoader());
+ // Don't free the SearchableFormData, the loader will do that.
+ loader->set_searchable_form_data(form_data);
+
+ PasswordForm* pass_data =
+ PasswordFormDomManager::CreatePasswordForm(form_ref->form());
+ // Don't free the PasswordFormData, the loader will do that.
+ loader->set_password_form_data(pass_data);
+
+ loader->set_form_submit(true);
+
+ (webframe_->frame()->loader()->*function)(PolicyUse);
+}
+
+void WebFrameLoaderClient::dispatchDidLoadMainResource(DocumentLoader*) {
+ // FIXME
+}
+
+void WebFrameLoaderClient::revertToProvisionalState(DocumentLoader*) {
+ has_representation_ = true;
+}
+
+void WebFrameLoaderClient::setMainDocumentError(DocumentLoader*,
+ const ResourceError& error) {
+ if (plugin_widget_) {
+ if (sent_initial_response_to_plugin_) {
+ plugin_widget_->didFail(error);
+ sent_initial_response_to_plugin_ = false;
+ }
+ plugin_widget_ = NULL;
+ }
+}
+
+void WebFrameLoaderClient::clearUnarchivingState(DocumentLoader*) {
+ // FIXME
+}
+
+void WebFrameLoaderClient::postProgressStartedNotification() {
+ if (hasWebView()) {
+ WebViewDelegate* d = webframe_->webview_impl()->delegate();
+ if (d)
+ d->DidStartLoading(webframe_->webview_impl());
+ }
+}
+
+void WebFrameLoaderClient::postProgressEstimateChangedNotification() {
+ // FIXME
+}
+
+void WebFrameLoaderClient::postProgressFinishedNotification() {
+ // TODO(ericroman): why might webframe_->webview_impl be null?
+ // http://b/1234461
+ if (hasWebView()) {
+ WebViewDelegate* d = webframe_->webview_impl()->delegate();
+
+ if (d)
+ d->DidStopLoading(webframe_->webview_impl());
+ }
+}
+
+void WebFrameLoaderClient::setMainFrameDocumentReady(bool ready) {
+ // FIXME
+}
+
+// Creates a new connection and begins downloading from that (contrast this
+// with |download|).
+void WebFrameLoaderClient::startDownload(const ResourceRequest& request) {
+ WebViewDelegate* d = webframe_->webview_impl()->delegate();
+ if (d) {
+ const GURL url(webkit_glue::KURLToGURL(request.url()));
+ const GURL referrer(webkit_glue::StringToStdWString(request.httpReferrer()));
+ d->DownloadUrl(url, referrer);
+ }
+}
+
+void WebFrameLoaderClient::willChangeTitle(DocumentLoader*) {
+ // FIXME
+}
+void WebFrameLoaderClient::didChangeTitle(DocumentLoader*) {
+ // FIXME
+}
+
+// Called whenever data is received.
+void WebFrameLoaderClient::committedLoad(DocumentLoader* loader, const char* data, int length) {
+ if (!plugin_widget_) {
+ if (postpone_loading_data_) {
+ postponed_data_.append(data, length);
+ if (postponed_data_.length() >= 512) {
+ postpone_loading_data_ = false;
+ webframe_->DidReceiveData(loader, postponed_data_.c_str(),
+ static_cast<int>(postponed_data_.length()));
+ }
+ return;
+ }
+ webframe_->DidReceiveData(loader, data, length);
+ }
+
+ // The plugin widget could have been created in the webframe_->DidReceiveData
+ // function.
+ if (plugin_widget_) {
+ if (!sent_initial_response_to_plugin_) {
+ sent_initial_response_to_plugin_ = true;
+ plugin_widget_->didReceiveResponse(
+ webframe_->frame()->loader()->activeDocumentLoader()->response());
+ }
+ plugin_widget_->didReceiveData(data, length);
+ }
+}
+
+void WebFrameLoaderClient::finishedLoading(DocumentLoader* dl) {
+ if (plugin_widget_) {
+ plugin_widget_->didFinishLoading();
+ plugin_widget_ = NULL;
+ sent_initial_response_to_plugin_ = false;
+ } else {
+ // This is necessary to create an empty document. See bug 634004.
+ // However, we only want to do this if makeRepresentation has been called, to
+ // match the behavior on the Mac.
+ if (has_representation_)
+ dl->frameLoader()->setEncoding("", false);
+ }
+}
+
+void WebFrameLoaderClient::finalSetupForReplace(DocumentLoader*) {
+ // FIXME
+}
+
+void WebFrameLoaderClient::updateGlobalHistoryForStandardLoad(const KURL& kurl) {
+}
+
+void WebFrameLoaderClient::updateGlobalHistoryForReload(const KURL&) {
+ // FIXME: this is for updating the visit time.
+}
+
+bool WebFrameLoaderClient::shouldGoToHistoryItem(HistoryItem*) const {
+ // FIXME
+ return true;
+}
+
+ResourceError WebFrameLoaderClient::blockedError(const WebCore::ResourceRequest&) {
+ // FIXME
+ return ResourceError();
+}
+
+ResourceError WebFrameLoaderClient::cancelledError(
+ const ResourceRequest& request) {
+ return ResourceError(net::kErrorDomain, net::ERR_ABORTED,
+ request.url().string(), String());
+}
+ResourceError WebFrameLoaderClient::cannotShowURLError(const ResourceRequest&) {
+ // FIXME
+ return ResourceError();
+}
+ResourceError WebFrameLoaderClient::interruptForPolicyChangeError(
+ const ResourceRequest& request) {
+ return ResourceError(kInternalErrorDomain, ERR_POLICY_CHANGE,
+ request.url().string(), String());
+}
+
+ResourceError WebFrameLoaderClient::cannotShowMIMETypeError(const ResourceResponse&) {
+ // FIXME
+ return ResourceError();
+}
+ResourceError WebFrameLoaderClient::fileDoesNotExistError(const ResourceResponse&) {
+ // FIXME
+ return ResourceError();
+}
+
+bool WebFrameLoaderClient::shouldFallBack(const ResourceError& error) {
+ // This method is called when we fail to load the URL for an <object> tag
+ // that has fallback content (child elements) and is being loaded as a frame.
+ // The error parameter indicates the reason for the load failure.
+ // We should let the fallback content load only if this wasn't a cancelled
+ // request.
+ // Note: The mac version also has a case for "WebKitErrorPluginWillHandleLoad"
+ return error.errorCode() != net::ERR_ABORTED;
+}
+
+void WebFrameLoaderClient::setDefersLoading(bool) {
+ // FIXME
+}
+
+bool WebFrameLoaderClient::willUseArchive(ResourceLoader*, const ResourceRequest&, const KURL& originalURL) const {
+ // FIXME
+ return false;
+}
+bool WebFrameLoaderClient::isArchiveLoadPending(ResourceLoader*) const {
+ // FIXME
+ return false;
+}
+void WebFrameLoaderClient::cancelPendingArchiveLoad(ResourceLoader*) {
+ // FIXME
+}
+void WebFrameLoaderClient::clearArchivedResources() {
+ // FIXME
+}
+
+bool WebFrameLoaderClient::canHandleRequest(const ResourceRequest&) const {
+ // FIXME: this appears to be used only by the context menu code to determine
+ // if "open" should be displayed in the menu when clicking on a link.
+ return true;
+}
+
+bool WebFrameLoaderClient::canShowMIMEType(const String& mime_type) const {
+ // This method is called to determine if the media type can be shown
+ // "internally" (i.e. inside the browser) regardless of whether or not the
+ // browser or a plugin is doing the rendering.
+
+ if (mime_util::IsSupportedMimeType(
+ WideToASCII(webkit_glue::StringToStdWString(mime_type))))
+ return true;
+
+ // See if the type is handled by an installed plugin, if so, we can show it.
+ // TODO(beng): (http://b/1085524) This is the place to stick a preference to
+ // disable full page plugins (optionally for certain types!)
+ return PluginInfoStore::supportsMIMEType(mime_type);
+}
+
+bool WebFrameLoaderClient::representationExistsForURLScheme(const String& URLScheme) const {
+ // FIXME
+ return false;
+}
+
+String WebFrameLoaderClient::generatedMIMETypeForURLScheme(const String& URLScheme) const {
+ // This appears to generate MIME types for protocol handlers that are handled
+ // internally. The only place I can find in the WebKit code that uses this
+ // function is WebView::registerViewClass, where it is used as part of the
+ // process by which custom view classes for certain document representations
+ // are registered.
+ String mimetype(L"x-apple-web-kit/");
+ mimetype.append(URLScheme.lower());
+ return mimetype;
+}
+
+void WebFrameLoaderClient::frameLoadCompleted() {
+ // FIXME: the mac port also conditionally calls setDrawsBackground:YES on
+ // it's ScrollView here.
+
+ // This comment from the Mac port:
+ // Note: Can be called multiple times.
+ // Even if already complete, we might have set a previous item on a frame that
+ // didn't do any data loading on the past transaction. Make sure to clear these out.
+ webframe_->frame()->loader()->setPreviousHistoryItem(0);
+}
+
+void WebFrameLoaderClient::saveViewStateToItem(HistoryItem*) {
+ // FIXME
+}
+
+
+void WebFrameLoaderClient::restoreViewState() {
+ // FIXME: probably scrolls to last position when you go back or forward
+}
+
+void WebFrameLoaderClient::provisionalLoadStarted() {
+ // FIXME: On mac, this does various caching stuff
+}
+
+void WebFrameLoaderClient::didFinishLoad() {
+ WebPluginDelegate* plg_delegate = webframe_->plugin_delegate();
+ if (plg_delegate)
+ plg_delegate->DidFinishLoadWithReason(NPRES_DONE);
+}
+void WebFrameLoaderClient::prepareForDataSourceReplacement() {
+ // FIXME
+}
+
+PassRefPtr<DocumentLoader> WebFrameLoaderClient::createDocumentLoader(
+ const ResourceRequest& request,
+ const SubstituteData& data) {
+ WebDocumentLoaderImpl* loader = new WebDocumentLoaderImpl(request, data);
+
+ // Attach a datasource to the loader as a way of accessing requests.
+ WebDataSourceImpl* datasource =
+ WebDataSourceImpl::CreateInstance(webframe_, loader);
+ loader->SetDataSource(datasource);
+
+ webframe_->CacheCurrentRequestInfo(datasource);
+
+ return loader;
+}
+
+void WebFrameLoaderClient::setTitle(const String& title, const KURL& url) {
+ // FIXME: monitor for changes in WebFrameLoaderClient.mm
+ // FIXME: Set the title of the current history item. HistoryItemImpl's setter
+ // will notify its clients (e.g. the history database) that the title
+ // has changed.
+ //
+ // e.g.:
+ // WebHistoryItem* item =
+ // webframe_->webview_impl()->GetBackForwardList()->GetCurrentItem();
+ // WebHistoryItemImpl* item_impl = static_cast<WebHistoryItemImpl*>(item);
+ //
+ // item_impl->SetTitle(webkit_glue::StringToStdWString(title));
+}
+
+String WebFrameLoaderClient::userAgent(const KURL& url) {
+ return webkit_glue::StdStringToString(
+ webframe_->webview_impl()->GetPreferences().user_agent);
+}
+
+void WebFrameLoaderClient::savePlatformDataToCachedPage(WebCore::CachedPage*) {
+ NOTREACHED() << "Page cache should be disabled";
+}
+
+void WebFrameLoaderClient::transitionToCommittedFromCachedPage(WebCore::CachedPage*) {
+ ASSERT_NOT_REACHED();
+}
+
+void WebFrameLoaderClient::transitionToCommittedForNewPage() {
+ makeDocumentView();
+}
+
+bool WebFrameLoaderClient::canCachePage() const {
+ NOTREACHED() << "Page cache should be disabled";
+ return false;
+}
+
+// Downloading is handled in the browser process, not WebKit. If we get to this
+// point, our download detection code in the ResourceDispatcherHost is broken!
+void WebFrameLoaderClient::download(ResourceHandle* handle,
+ const ResourceRequest& request,
+ const ResourceRequest& initialRequest,
+ const ResourceResponse& response) {
+ NOTREACHED();
+}
+
+PassRefPtr<Frame> WebFrameLoaderClient::createFrame(
+ const KURL& url,
+ const String& name,
+ HTMLFrameOwnerElement* owner_element,
+ const String& referrer,
+ bool allows_scrolling,
+ int margin_width,
+ int margin_height) {
+ FrameLoadRequest frame_request(ResourceRequest(url, referrer), name);
+
+ Frame* new_frame = NULL;
+ if (webframe_)
+ webframe_->CreateChildFrame(frame_request, owner_element, allows_scrolling,
+ margin_width, margin_height, new_frame);
+ return new_frame;
+}
+
+// Utility function to convert a vector to an array of char*'s.
+// Caller is responsible to free memory with DeleteToArray().
+static char** ToArray(const Vector<WebCore::String> &vector) {
+ char **rv = new char *[vector.size()+1];
+ unsigned int index = 0;
+ for (index = 0; index < vector.size(); ++index) {
+ WebCore::CString src = vector[index].utf8();
+ rv[index] = new char[src.length() + 1];
+ strncpy_s(rv[index], src.length() + 1, src.data(), _TRUNCATE);
+ rv[index][src.length()] = '\0';
+ }
+ rv[index] = 0;
+ return rv;
+}
+
+static void DeleteToArray(char** arr) {
+ char **ptr = arr;
+ while (*ptr != 0) {
+ delete [] *ptr;
+ ++ptr;
+ }
+ delete [] arr;
+}
+
+Widget* WebFrameLoaderClient::createPlugin(const IntSize& size, // TODO(erikkay): how do we use this?
+ Element *element, const KURL &url,
+ const Vector<String> &param_names,
+ const Vector<String> &param_values,
+ const String &mime_type,
+ bool load_manually) {
+ WebViewImpl* webview = webframe_->webview_impl();
+ WebViewDelegate* d = webview->delegate();
+ if (!d)
+ return NULL;
+
+ GURL gurl = webkit_glue::KURLToGURL(url);
+ std::string my_mime_type =
+ webkit_glue::CStringToStdString(mime_type.latin1());
+ StringToLowerASCII(&my_mime_type);
+
+ // Get the classid and version from attributes of the object.
+ std::string clsid, version, combined_clsid;
+ if (activex_shim::IsMimeTypeActiveX(my_mime_type)) {
+ GURL url = webframe_->GetURL();
+ for (unsigned int i = 0; i < param_names.size(); i++) {
+ String lowercase_param_name = param_names[i].lower();
+ if (lowercase_param_name == "classid") {
+ activex_shim::GetClsidFromClassidAttribute(
+ webkit_glue::CStringToStdString(param_values[i].latin1()), &clsid);
+ } else if (lowercase_param_name == "codebase") {
+ version = activex_shim::GetVersionFromCodebaseAttribute(
+ webkit_glue::CStringToStdString(param_values[i].latin1()));
+ }
+ }
+ // We only allowed specific ActiveX controls to run from certain websites.
+ if (!activex_shim::IsActiveXAllowed(clsid, url))
+ return NULL;
+ // We need to pass the combined clsid + version to PluginsList, so that it
+ // would detect if the requested version is installed. If not, it needs
+ // to use the default plugin to update the control.
+ if (!version.empty())
+ combined_clsid = clsid + "#" + version;
+ else
+ combined_clsid = clsid;
+ }
+
+ std::string actual_mime_type;
+ WebPluginDelegate* plugin_delegate =
+ d->CreatePluginDelegate(webframe_->webview_impl(), gurl, my_mime_type,
+ combined_clsid, &actual_mime_type);
+ if (!plugin_delegate)
+ return NULL;
+
+ if (!actual_mime_type.empty())
+ my_mime_type = actual_mime_type;
+
+ DCHECK(param_names.size() == param_values.size());
+
+ char **argn = NULL;
+ char **argv = NULL;
+ int argc = 0;
+ // There is a bug in Webkit which occurs when a plugin instance is defined
+ // with an OBJECT tag containing the "DATA" attribute". Please refer to the
+ // webkit issue http://bugs.webkit.org/show_bug.cgi?id=15457 for more info.
+ // The code below is a patch which should be taken out when a fix is
+ // available in webkit. The logic is to add the "src" attribute to the list
+ // of params if the "data" attribute exists.
+ // TODO(iyengar) : remove this when a fix is available in webkit.
+ int data_attr_index = -1;
+ int src_attr_index = -1;
+ for (unsigned int i = 0; i < param_names.size(); i++) {
+ String param_name = param_names[i].lower();
+ if (param_name == "data")
+ data_attr_index = i;
+ else if (param_name == "src")
+ src_attr_index = i;
+ }
+ if ((data_attr_index != -1) && (src_attr_index == -1)) {
+ Vector<String> updated_param_names = param_names;
+ Vector<String> updated_param_values = param_values;
+ updated_param_names.append("src");
+ updated_param_values.append(param_values[data_attr_index]);
+
+ argn = ToArray(updated_param_names);
+ argv = ToArray(updated_param_values);
+ argc = static_cast<int>(updated_param_names.size());
+ } else {
+ argn = ToArray(param_names);
+ argv = ToArray(param_values);
+ argc = static_cast<int>(param_names.size());
+ }
+
+ Widget* result = WebPluginImpl::Create(gurl, argn, argv, argc, element,
+ webframe_, plugin_delegate,
+ load_manually);
+
+ DeleteToArray(argn);
+ DeleteToArray(argv);
+
+ return result;
+}
+
+// This method gets called when a plugin is put in place of html content
+// (e.g., acrobat reader).
+void WebFrameLoaderClient::redirectDataToPlugin(Widget* pluginWidget) {
+ plugin_widget_ = static_cast<WebPluginContainer*>(pluginWidget);
+ DCHECK(plugin_widget_ != NULL);
+}
+
+Widget* WebFrameLoaderClient::createJavaAppletWidget(
+ const IntSize& size,
+ Element *element, const KURL &url,
+ const Vector<String> &param_names,
+ const Vector<String> &param_values) {
+ return createPlugin(size, element, url, param_names, param_values,
+ "application/x-java-applet", false);
+}
+
+ObjectContentType WebFrameLoaderClient::objectContentType(
+ const KURL& url,
+ const String& explicit_mime_type) {
+ // This code is based on Apple's implementation from
+ // WebCoreSupport/WebFrameBridge.mm.
+
+ String mime_type = explicit_mime_type;
+ if (mime_type.isEmpty()) {
+ // Try to guess the MIME type based off the extension.
+ String filename = url.lastPathComponent();
+ int extension_pos = filename.reverseFind('.');
+ if (extension_pos >= 0)
+ mime_type = MIMETypeRegistry::getMIMETypeForPath(url.path());
+
+ if (mime_type.isEmpty())
+ return ObjectContentFrame;
+ }
+
+ if (MIMETypeRegistry::isSupportedImageMIMEType(mime_type))
+ return ObjectContentImage;
+
+ if (PluginInfoStore::supportsMIMEType(mime_type))
+ return ObjectContentNetscapePlugin;
+
+ if (MIMETypeRegistry::isSupportedNonImageMIMEType(mime_type))
+ return ObjectContentFrame;
+
+ return ObjectContentNone;
+}
+
+String WebFrameLoaderClient::overrideMediaType() const {
+ // FIXME
+ String rv;
+ return rv;
+}
+
+bool WebFrameLoaderClient::ActionSpecifiesDisposition(
+ const WebCore::NavigationAction& action,
+ WindowOpenDisposition* disposition) {
+ if ((action.type() != NavigationTypeLinkClicked) ||
+ !action.event()->isMouseEvent())
+ return false;
+
+ const MouseEvent* event = static_cast<const MouseEvent*>(action.event());
+ const bool middle_or_ctrl = (event->button() == 1) || event->ctrlKey();
+ const bool shift = event->shiftKey();
+ const bool alt = event->altKey();
+ if (!middle_or_ctrl && !shift && !alt)
+ return false;
+
+ DCHECK(disposition);
+ if (middle_or_ctrl)
+ *disposition = shift ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB;
+ else
+ *disposition = shift ? NEW_WINDOW : SAVE_TO_DISK;
+ return true;
+}
diff --git a/webkit/glue/webframeloaderclient_impl.h b/webkit/glue/webframeloaderclient_impl.h
new file mode 100644
index 0000000..2c2eb78
--- /dev/null
+++ b/webkit/glue/webframeloaderclient_impl.h
@@ -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.
+
+#ifndef WEBKIT_GLUE_WEBFRAMELOADERCLIENT_IMPL_H__
+#define WEBKIT_GLUE_WEBFRAMELOADERCLIENT_IMPL_H__
+
+#pragma warning(push, 0)
+#include "FrameLoaderClient.h"
+#pragma warning(pop)
+
+#include "googleurl/src/gurl.h"
+#include "webkit/glue/window_open_disposition.h"
+
+namespace WebCore {
+class Frame;
+class Widget;
+}
+
+enum NavigationGesture;
+class Alt404PageResourceFetcher;
+class WebFrameImpl;
+class WebPluginContainer;
+
+class WebFrameLoaderClient : public WebCore::FrameLoaderClient {
+ public:
+ WebFrameLoaderClient(WebFrameImpl* webframe);
+ virtual ~WebFrameLoaderClient();
+
+ WebFrameImpl* webframe() const { return webframe_; }
+
+ // WebCore::FrameLoaderClient ----------------------------------------------
+
+ virtual void frameLoaderDestroyed();
+
+ // Notifies the WebView delegate that the JS window object has been cleared,
+ // giving it a chance to bind native objects to the window before script
+ // parsing begins.
+ virtual void windowObjectCleared();
+
+ virtual bool hasWebView() const; // mainly for assertions
+ virtual bool hasFrameView() const; // ditto
+
+ virtual bool privateBrowsingEnabled() const;
+
+ virtual void makeDocumentView();
+ virtual void makeRepresentation(WebCore::DocumentLoader*);
+ virtual void setDocumentViewFromCachedPage(WebCore::CachedPage*);
+ virtual void forceLayout();
+ virtual void forceLayoutForNonHTML();
+
+ virtual void setCopiesOnScroll();
+
+ virtual void detachedFromParent2();
+ virtual void detachedFromParent3();
+ virtual void detachedFromParent4();
+
+ virtual void loadedFromCachedPage();
+
+ virtual void assignIdentifierToInitialRequest(unsigned long identifier, WebCore::DocumentLoader*, const WebCore::ResourceRequest&);
+
+ virtual void dispatchWillSendRequest(WebCore::DocumentLoader*, unsigned long identifier, WebCore::ResourceRequest&, const WebCore::ResourceResponse& redirectResponse);
+ virtual void dispatchDidReceiveAuthenticationChallenge(WebCore::DocumentLoader*, unsigned long identifier, const WebCore::AuthenticationChallenge&);
+ virtual void dispatchDidCancelAuthenticationChallenge(WebCore::DocumentLoader*, unsigned long identifier, const WebCore::AuthenticationChallenge&);
+ virtual void dispatchDidReceiveResponse(WebCore::DocumentLoader*, unsigned long identifier, const WebCore::ResourceResponse&);
+ virtual void dispatchDidReceiveContentLength(WebCore::DocumentLoader*, unsigned long identifier, int lengthReceived);
+ virtual void dispatchDidFinishLoading(WebCore::DocumentLoader*, unsigned long identifier);
+ virtual void dispatchDidFailLoading(WebCore::DocumentLoader*, unsigned long identifier, const WebCore::ResourceError&);
+ virtual bool dispatchDidLoadResourceFromMemoryCache(WebCore::DocumentLoader*, const WebCore::ResourceRequest&, const WebCore::ResourceResponse&, int length);
+
+ virtual void dispatchDidHandleOnloadEvents();
+ virtual void dispatchDidReceiveServerRedirectForProvisionalLoad();
+ virtual void dispatchDidCancelClientRedirect();
+ virtual void dispatchWillPerformClientRedirect(const WebCore::KURL&, double interval, double fireDate);
+ virtual void dispatchDidChangeLocationWithinPage();
+ virtual void dispatchWillClose();
+ virtual void dispatchDidReceiveIcon();
+ virtual void dispatchDidStartProvisionalLoad();
+ virtual void dispatchDidReceiveTitle(const WebCore::String& title);
+ virtual void dispatchDidCommitLoad();
+ virtual void dispatchDidFailProvisionalLoad(const WebCore::ResourceError&);
+ virtual void dispatchDidFailLoad(const WebCore::ResourceError&);
+ virtual void dispatchDidFinishDocumentLoad();
+ virtual void dispatchDidFinishLoad();
+ virtual void dispatchDidFirstLayout();
+
+ virtual WebCore::Frame* dispatchCreatePage();
+ virtual void dispatchShow();
+
+ virtual void dispatchDecidePolicyForMIMEType(WebCore::FramePolicyFunction function, const WebCore::String& mime_type, const WebCore::ResourceRequest&);
+ virtual void dispatchDecidePolicyForNewWindowAction(WebCore::FramePolicyFunction function, const WebCore::NavigationAction& action, const WebCore::ResourceRequest& request, const WebCore::String& frame_name);
+ virtual void dispatchDecidePolicyForNavigationAction(WebCore::FramePolicyFunction function, const WebCore::NavigationAction& action, const WebCore::ResourceRequest& request);
+ virtual void cancelPolicyCheck();
+
+ virtual void dispatchUnableToImplementPolicy(const WebCore::ResourceError&);
+
+ virtual void dispatchWillSubmitForm(WebCore::FramePolicyFunction, PassRefPtr<WebCore::FormState>);
+
+ virtual void dispatchDidLoadMainResource(WebCore::DocumentLoader*);
+ virtual void revertToProvisionalState(WebCore::DocumentLoader*);
+ virtual void setMainDocumentError(WebCore::DocumentLoader*, const WebCore::ResourceError&);
+ virtual void clearUnarchivingState(WebCore::DocumentLoader*);
+
+ // Maybe these should go into a ProgressTrackerClient some day
+ virtual void willChangeEstimatedProgress() { }
+ virtual void didChangeEstimatedProgress() { }
+ virtual void postProgressStartedNotification();
+ virtual void postProgressEstimateChangedNotification();
+ virtual void postProgressFinishedNotification();
+
+ virtual void setMainFrameDocumentReady(bool);
+
+ virtual void startDownload(const WebCore::ResourceRequest&);
+
+ virtual void willChangeTitle(WebCore::DocumentLoader*);
+ virtual void didChangeTitle(WebCore::DocumentLoader*);
+
+ virtual void committedLoad(WebCore::DocumentLoader*, const char*, int);
+ virtual void finishedLoading(WebCore::DocumentLoader*);
+ virtual void finalSetupForReplace(WebCore::DocumentLoader*);
+
+ virtual void updateGlobalHistoryForStandardLoad(const WebCore::KURL&);
+ virtual void updateGlobalHistoryForReload(const WebCore::KURL&);
+ virtual bool shouldGoToHistoryItem(WebCore::HistoryItem*) const;
+
+ virtual WebCore::ResourceError blockedError(const WebCore::ResourceRequest&);
+ virtual WebCore::ResourceError cancelledError(const WebCore::ResourceRequest&);
+ virtual WebCore::ResourceError cannotShowURLError(const WebCore::ResourceRequest&);
+ virtual WebCore::ResourceError interruptForPolicyChangeError(const WebCore::ResourceRequest&);
+
+ virtual WebCore::ResourceError cannotShowMIMETypeError(const WebCore::ResourceResponse&);
+ virtual WebCore::ResourceError fileDoesNotExistError(const WebCore::ResourceResponse&);
+
+ virtual bool shouldFallBack(const WebCore::ResourceError&);
+
+ virtual void setDefersLoading(bool);
+
+ virtual bool willUseArchive(WebCore::ResourceLoader*, const WebCore::ResourceRequest&, const WebCore::KURL& originalURL) const;
+ virtual bool isArchiveLoadPending(WebCore::ResourceLoader*) const;
+ virtual void cancelPendingArchiveLoad(WebCore::ResourceLoader*);
+ virtual void clearArchivedResources();
+
+ virtual bool canHandleRequest(const WebCore::ResourceRequest&) const;
+ virtual bool canShowMIMEType(const WebCore::String& MIMEType) const;
+ virtual bool representationExistsForURLScheme(const WebCore::String& URLScheme) const;
+ virtual WebCore::String generatedMIMETypeForURLScheme(const WebCore::String& URLScheme) const;
+
+ virtual void frameLoadCompleted();
+ virtual void saveViewStateToItem(WebCore::HistoryItem*);
+ virtual void restoreViewState();
+ virtual void provisionalLoadStarted();
+ virtual void didFinishLoad();
+ virtual void prepareForDataSourceReplacement();
+
+ virtual PassRefPtr<WebCore::DocumentLoader> createDocumentLoader(
+ const WebCore::ResourceRequest&,
+ const WebCore::SubstituteData&);
+ virtual void setTitle(const WebCore::String& title, const WebCore::KURL&);
+
+ virtual WebCore::String userAgent(const WebCore::KURL&);
+
+ virtual void savePlatformDataToCachedPage(WebCore::CachedPage*);
+ virtual void transitionToCommittedFromCachedPage(WebCore::CachedPage*);
+ virtual void transitionToCommittedForNewPage();
+
+ virtual bool canCachePage() const;
+ virtual void download(WebCore::ResourceHandle* handle,
+ const WebCore::ResourceRequest& request,
+ const WebCore::ResourceRequest& initialRequest,
+ const WebCore::ResourceResponse& response);
+ virtual PassRefPtr<WebCore::Frame> createFrame(
+ const WebCore::KURL& url,
+ const WebCore::String& name,
+ WebCore::HTMLFrameOwnerElement* ownerElement,
+ const WebCore::String& referrer,
+ bool allowsScrolling, int marginWidth,
+ int marginHeight);
+ virtual WebCore::Widget* createPlugin(const WebCore::IntSize&,
+ WebCore::Element*,
+ const WebCore::KURL&,
+ const WTF::Vector<WebCore::String>&,
+ const WTF::Vector<WebCore::String>&,
+ const WebCore::String&,
+ bool loadManually);
+ virtual void redirectDataToPlugin(WebCore::Widget* pluginWidget);
+
+ virtual WebCore::Widget* createJavaAppletWidget(const WebCore::IntSize&,
+ WebCore::Element*, const WebCore::KURL& baseURL,
+ const WTF::Vector<WebCore::String>& paramNames,
+ const WTF::Vector<WebCore::String>& paramValues);
+
+ virtual WebCore::ObjectContentType objectContentType(const WebCore::KURL& url,
+ const WebCore::String& mimeType);
+ virtual WebCore::String overrideMediaType() const;
+
+ virtual void didPerformFirstNavigation() const;
+
+ virtual void registerForIconNotification(bool listen = true);
+
+ virtual void unloadListenerChanged();
+
+#if defined(__APPLE__)
+ virtual NSCachedURLResponse* willCacheResponse(WebCore::DocumentLoader*,
+ unsigned long identifier,
+ NSCachedURLResponse*) const;
+#endif
+
+ // Callback function for download of alternate 404 pages. If the server is
+ // down or we take more than 1s to download the page, html will be an empty
+ // string.
+ void Alt404PageFinished(WebCore::DocumentLoader* loader,
+ const std::string& html);
+
+ private:
+ // Given a NavigationAction, determine the associated window opening
+ // disposition. For example, a middle click means "open in background tab".
+ static bool ActionSpecifiesDisposition(
+ const WebCore::NavigationAction& action,
+ WindowOpenDisposition* disposition);
+
+ // Returns a valid GURL if we have an alt 404 server URL.
+ GURL GetAlt404PageUrl(WebCore::DocumentLoader* loader);
+
+ // Returns NavigationGestureAuto if the last load was not user initiated,
+ // otherwise returns NavigationGestureUnknown.
+ NavigationGesture NavigationGestureForLastLoad();
+
+ // The WebFrame that owns this object and manages its lifetime. Therefore,
+ // the web frame object is guaranteed to exist.
+ WebFrameImpl* webframe_;
+
+ // Resource fetcher for downloading an alternate 404 page.
+ scoped_ptr<Alt404PageResourceFetcher> alt_404_page_fetcher_;
+
+ bool postpone_loading_data_;
+ std::string postponed_data_;
+
+ // True if makeRepresentation was called. We don't actually have a concept
+ // of a "representation", but we need to know when we're expected to have one.
+ // See finishedLoading().
+ bool has_representation_;
+
+ // Used to help track client redirects. When a provisional load starts, it
+ // has no redirects in its chain. But in the case of client redirects, we want
+ // to add that initial load as a redirect. When we get a new provisional load
+ // and the dest URL matches that load, we know that it was the result of a
+ // previous client redirect and the source should be added as a redirect.
+ // Both should be empty if unused.
+ GURL expected_client_redirect_src_;
+ GURL expected_client_redirect_dest_;
+
+ // Contains a pointer to the plugin widget.
+ WebPluginContainer* plugin_widget_;
+ // Indicates if we need to send over the initial notification to the plugin
+ // which specifies that the plugin should be ready to accept data.
+ bool sent_initial_response_to_plugin_;
+
+ // The disposition to use for the next call to dispatchCreatePage.
+ WindowOpenDisposition next_window_open_disposition_;
+};
+
+#endif // #ifndef WEBKIT_GLUE_WEBFRAMELOADERCLIENT_IMPL_H__
diff --git a/webkit/glue/webhistoryitem.h b/webkit/glue/webhistoryitem.h
new file mode 100644
index 0000000..3a2f0df
--- /dev/null
+++ b/webkit/glue/webhistoryitem.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.
+
+#ifndef WEBKIT_GLUE_WEBHISTORYITEM_H__
+#define WEBKIT_GLUE_WEBHISTORYITEM_H__
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/ref_counted.h"
+#include "webkit/glue/weburlrequest.h" // for WebRequest::ExtraData
+
+class GURL;
+
+class WebHistoryItem : public base::RefCounted<WebHistoryItem> {
+ public:
+ // Create a new history item.
+ static WebHistoryItem* Create(const GURL& url,
+ const std::wstring& title,
+ const std::string& history_state,
+ WebRequest::ExtraData* extra_data);
+
+ WebHistoryItem() { }
+ virtual ~WebHistoryItem() { }
+
+ // Returns the URL.
+ virtual const GURL& GetURL() const = 0;
+
+ // Returns the title.
+ virtual const std::wstring& GetTitle() const = 0;
+
+ // Returns the string representation of the history state for this entry.
+ virtual const std::string& GetHistoryState() const = 0;
+
+ // Returns any ExtraData associated with this history entry.
+ virtual WebRequest::ExtraData* GetExtraData() const = 0;
+
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(WebHistoryItem);
+};
+
+#endif // #ifndef WEBKIT_GLUE_WEBHISTORYITEM_H__
diff --git a/webkit/glue/webhistoryitem_impl.cc b/webkit/glue/webhistoryitem_impl.cc
new file mode 100644
index 0000000..7ee880d
--- /dev/null
+++ b/webkit/glue/webhistoryitem_impl.cc
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 "config.h"
+#include "webkit/glue/webhistoryitem_impl.h"
+
+#include "webkit/glue/glue_serialize.h"
+
+#pragma warning(push, 0)
+#include "HistoryItem.h"
+#pragma warning(pop)
+
+
+WebHistoryItem* WebHistoryItem::Create(const GURL& url,
+ const std::wstring& title,
+ const std::string& history_state,
+ WebRequest::ExtraData* extra_data) {
+ return new WebHistoryItemImpl(url, title, history_state, extra_data);
+}
+
+WebHistoryItemImpl::WebHistoryItemImpl(const GURL& url,
+ const std::wstring& title,
+ const std::string& history_state,
+ WebRequest::ExtraData* extra_data) :
+ url_(url),
+ title_(title),
+ history_state_(history_state),
+ history_item_(NULL),
+ extra_data_(extra_data) {
+}
+
+WebHistoryItemImpl::~WebHistoryItemImpl() {
+}
+
+const std::wstring& WebHistoryItemImpl::GetTitle() const {
+ return title_;
+}
+
+const std::string& WebHistoryItemImpl::GetHistoryState() const {
+ return history_state_;
+}
+
+WebRequest::ExtraData* WebHistoryItemImpl::GetExtraData() const {
+ return extra_data_.get();
+}
+
+WebCore::HistoryItem* WebHistoryItemImpl::GetHistoryItem() const {
+ if (history_item_)
+ return history_item_.get();
+
+ history_item_ = webkit_glue::HistoryItemFromString(history_state_);
+ return history_item_.get();
+}
+
+const GURL& WebHistoryItemImpl::GetURL() const {
+ return url_;
+}
diff --git a/webkit/glue/webhistoryitem_impl.h b/webkit/glue/webhistoryitem_impl.h
new file mode 100644
index 0000000..312b82e
--- /dev/null
+++ b/webkit/glue/webhistoryitem_impl.h
@@ -0,0 +1,73 @@
+// 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 WEBKIT_GLUE_WEBHISTORYITEM_IMPL_H__
+#define WEBKIT_GLUE_WEBHISTORYITEM_IMPL_H__
+
+#include "base/basictypes.h"
+#include "webkit/glue/webhistoryitem.h"
+#include "googleurl/src/gurl.h"
+
+#include "RefPtr.h"
+
+namespace WebCore {
+ class HistoryItem;
+}
+
+class WebHistoryItemImpl : public WebHistoryItem {
+ public:
+ WebHistoryItemImpl(const GURL& url,
+ const std::wstring& title,
+ const std::string& history_state,
+ WebRequest::ExtraData* extra_data);
+ virtual ~WebHistoryItemImpl();
+
+ // WebHistoryItem
+ virtual const GURL& GetURL() const;
+ virtual const std::wstring& GetTitle() const;
+ virtual const std::string& GetHistoryState() const;
+ virtual WebRequest::ExtraData* GetExtraData() const;
+
+ // WebHistoryItemImpl
+ // Returns a WebCore::HistoryItem based on the history_state. This is
+ // lazily-created and cached.
+ WebCore::HistoryItem* GetHistoryItem() const;
+
+ protected:
+ GURL url_;
+ std::wstring title_;
+ std::string history_state_;
+ mutable RefPtr<WebCore::HistoryItem> history_item_;
+ scoped_refptr<WebRequest::ExtraData> extra_data_;
+
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(WebHistoryItemImpl);
+};
+
+#endif // #ifndef WEBKIT_GLUE_WEBHISTORYITEM_IMPL_H__
diff --git a/webkit/glue/webinputevent.cc b/webkit/glue/webinputevent.cc
new file mode 100644
index 0000000..79f8afbe
--- /dev/null
+++ b/webkit/glue/webinputevent.cc
@@ -0,0 +1,328 @@
+// 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 "config.h"
+
+#include "webkit/glue/webinputevent.h"
+
+#include "webkit/glue/event_conversion.h"
+
+#undef LOG
+#include "base/logging.h"
+
+static const unsigned long kDefaultScrollLinesPerWheelDelta = 3;
+
+// WebMouseEvent --------------------------------------------------------------
+
+static LPARAM GetRelativeCursorPos(HWND hwnd) {
+ POINT pos = {-1, -1};
+ GetCursorPos(&pos);
+ ScreenToClient(hwnd, &pos);
+ return MAKELPARAM(pos.x, pos.y);
+}
+
+WebMouseEvent::WebMouseEvent(HWND hwnd, UINT message, WPARAM wparam,
+ LPARAM lparam) {
+ switch (message) {
+ case WM_MOUSEMOVE:
+ type = MOUSE_MOVE;
+ if (wparam & MK_LBUTTON)
+ button = BUTTON_LEFT;
+ else if (wparam & MK_MBUTTON)
+ button = BUTTON_MIDDLE;
+ else if (wparam & MK_RBUTTON)
+ button = BUTTON_MIDDLE;
+ else
+ button = BUTTON_NONE;
+ break;
+ case WM_MOUSELEAVE:
+ type = MOUSE_LEAVE;
+ button = BUTTON_NONE;
+ // set the current mouse position (relative to the client area of the
+ // current window) since none is specified for this event
+ lparam = GetRelativeCursorPos(hwnd);
+ break;
+ case WM_LBUTTONDOWN:
+ type = MOUSE_DOWN;
+ button = BUTTON_LEFT;
+ break;
+ case WM_MBUTTONDOWN:
+ type = MOUSE_DOWN;
+ button = BUTTON_MIDDLE;
+ break;
+ case WM_RBUTTONDOWN:
+ type = MOUSE_DOWN;
+ button = BUTTON_RIGHT;
+ break;
+ case WM_LBUTTONUP:
+ type = MOUSE_UP;
+ button = BUTTON_LEFT;
+ break;
+ case WM_MBUTTONUP:
+ type = MOUSE_UP;
+ button = BUTTON_MIDDLE;
+ break;
+ case WM_RBUTTONUP:
+ type = MOUSE_UP;
+ button = BUTTON_RIGHT;
+ break;
+ case WM_LBUTTONDBLCLK:
+ type = MOUSE_DOUBLE_CLICK;
+ button = BUTTON_LEFT;
+ break;
+ case WM_MBUTTONDBLCLK:
+ type = MOUSE_DOUBLE_CLICK;
+ button = BUTTON_MIDDLE;
+ break;
+ case WM_RBUTTONDBLCLK:
+ type = MOUSE_DOUBLE_CLICK;
+ button = BUTTON_RIGHT;
+ break;
+ default:
+ NOTREACHED() << "unexpected native message";
+ }
+
+ // set position fields:
+
+ x = static_cast<short>(LOWORD(lparam));
+ y = static_cast<short>(HIWORD(lparam));
+
+ POINT global_point = { x, y };
+ ClientToScreen(hwnd, &global_point);
+
+ global_x = global_point.x;
+ global_y = global_point.y;
+
+ // set modifiers:
+
+ modifiers = 0;
+ if (wparam & MK_CONTROL)
+ modifiers |= CTRL_KEY;
+ if (wparam & MK_SHIFT)
+ modifiers |= SHIFT_KEY;
+ if (GetKeyState(VK_MENU) & 0x8000)
+ modifiers |= (ALT_KEY | META_KEY); // TODO(darin): set META properly
+
+ // TODO(pkasting): http://b/1117926 Instead of using GetTickCount() here, we
+ // should use GetMessageTime() on the original Windows message in the browser
+ // process, and pass that in the WebMouseEvent.
+ timestamp_sec = GetTickCount() / 1000.0;
+
+ layout_test_click_count = 0;
+}
+
+// WebMouseWheelEvent ---------------------------------------------------------
+
+WebMouseWheelEvent::WebMouseWheelEvent(HWND hwnd, UINT message, WPARAM wparam,
+ LPARAM lparam) {
+ type = MOUSE_WHEEL;
+ button = BUTTON_NONE;
+
+ UINT key_state = GET_KEYSTATE_WPARAM(wparam);
+ int wheel_delta = static_cast<int>(GET_WHEEL_DELTA_WPARAM(wparam));
+
+ typedef SHORT (WINAPI *GetKeyStateFunction)(int key);
+ GetKeyStateFunction get_key_state = GetKeyState;
+
+ // Synthesize mousewheel event from a scroll event.
+ // This is needed to simulate middle mouse scrolling in some
+ // laptops (Thinkpads)
+ if ((WM_VSCROLL == message) || (WM_HSCROLL == message)) {
+
+ POINT cursor_position = {0};
+ GetCursorPos(&cursor_position);
+
+ global_x = cursor_position.x;
+ global_y = cursor_position.y;
+
+ key_state = 0;
+
+ // Since we are synthesizing the wheel event, we have to
+ // use GetAsyncKeyState
+ if (GetAsyncKeyState(VK_SHIFT))
+ key_state |= MK_SHIFT;
+
+ if (GetAsyncKeyState(VK_CONTROL))
+ key_state |= MK_CONTROL;
+
+ // Add a simple workaround to scroll multiples units per page.
+ // The right fix needs to extend webkit's implementation of
+ // wheel events and that's not something we want to do at
+ // this time. See bug# 928509
+ // TODO(joshia): Implement the right fix for bug# 928509
+ const int kPageScroll = 10; // 10 times wheel scroll
+ switch (LOWORD(wparam)) {
+ case SB_LINEUP: // == SB_LINELEFT
+ wheel_delta = WHEEL_DELTA;
+ break;
+ case SB_LINEDOWN: // == SB_LINERIGHT
+ wheel_delta = -WHEEL_DELTA;
+ break;
+ case SB_PAGEUP:
+ wheel_delta = kPageScroll * WHEEL_DELTA;
+ break;
+ case SB_PAGEDOWN:
+ wheel_delta = -kPageScroll * WHEEL_DELTA;
+ break;
+ // TODO(joshia): Handle SB_THUMBPOSITION and SB_THUMBTRACK
+ // for compeleteness
+ default:
+ break;
+ }
+
+ // Windows sends the following messages for tilt-wheel events.
+ // * Tilt a mousewheel (left)
+ // message == WM_HSCROLL, wparam == SB_LINELEFT (== SB_LINEUP).
+ // * Tilt a mousewheel (right)
+ // message == WM_HSCROLL, wparam == SB_LINERIGHT (== SB_LINEDOWN).
+ // To convert these events to the shift + mousewheel ones, we do not only
+ // add a shift but also change the signs of their |wheel_delta| values.
+ if (WM_HSCROLL == message) {
+ key_state |= MK_SHIFT;
+ wheel_delta = -wheel_delta;
+ }
+
+ // Use GetAsyncKeyState for key state since we are synthesizing
+ // the input
+ get_key_state = GetAsyncKeyState;
+ } else {
+
+ global_x = static_cast<short>(LOWORD(lparam));
+ global_y = static_cast<short>(HIWORD(lparam));
+ }
+
+ POINT client_point = { global_x, global_y };
+ ScreenToClient(hwnd, &client_point);
+ x = client_point.x;
+ y = client_point.y;
+
+ // compute the scroll delta based on Raymond Chen's algorithm:
+ // http://blogs.msdn.com/oldnewthing/archive/2003/08/07/54615.aspx
+
+ static int carryover = 0;
+ static HWND last_window = NULL;
+
+ if (hwnd != last_window) {
+ last_window = hwnd;
+ carryover = 0;
+ }
+
+ unsigned long scroll_lines = kDefaultScrollLinesPerWheelDelta;
+ SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &scroll_lines, 0);
+
+ // TODO(darin): handle the case where scroll_lines is WHEEL_PAGESIZE
+ int delta_lines = 0;
+ if (scroll_lines == 0) {
+ carryover = 0;
+ } else {
+ const int delta = carryover + wheel_delta;
+
+ // see how many lines we should scroll. relies on round-toward-zero.
+ delta_lines = delta * static_cast<int>(scroll_lines) / WHEEL_DELTA;
+
+ // record the unused portion as the next carryover.
+ carryover =
+ delta - delta_lines * WHEEL_DELTA / static_cast<int>(scroll_lines);
+ }
+
+ // Scroll horizontally if shift is held. WebKit's WebKit/win/WebView.cpp
+ // does the equivalent.
+ // TODO(jackson): Support WM_MOUSEHWHEEL = 0x020E event as well.
+ // (Need a mouse with horizontal scrolling capabilities to test it.)
+ if (key_state & MK_SHIFT) {
+ // Scrolling up should move left, scrolling down should move right
+ delta_x = -delta_lines;
+ delta_y = 0;
+ } else {
+ delta_x = 0;
+ delta_y = delta_lines;
+ }
+
+ if (key_state & MK_SHIFT)
+ modifiers |= SHIFT_KEY;
+ if (key_state & MK_CONTROL)
+ modifiers |= CTRL_KEY;
+
+ // Get any additional key states needed
+ if (get_key_state(VK_MENU) & 0x8000)
+ modifiers |= (ALT_KEY | META_KEY);
+}
+
+// WebKeyboardEvent -----------------------------------------------------------
+
+WebKeyboardEvent::WebKeyboardEvent(HWND hwnd, UINT message, WPARAM wparam,
+ LPARAM lparam) {
+ modifiers = 0;
+ system_key = false;
+
+ actual_message.hwnd = hwnd;
+ actual_message.message = message;
+ actual_message.wParam = wparam;
+ actual_message.lParam = lparam;
+
+ key_code = static_cast<int>(wparam);
+ key_data = static_cast<int>(lparam);
+
+ switch (message) {
+ case WM_SYSKEYDOWN:
+ system_key = true;
+ case WM_KEYDOWN:
+ type = KEY_DOWN;
+ break;
+ case WM_SYSKEYUP:
+ system_key = true;
+ case WM_KEYUP:
+ type = KEY_UP;
+ break;
+ case WM_IME_CHAR:
+ key_data = static_cast<int>(wparam);
+ type = CHAR;
+ break;
+ case WM_SYSCHAR:
+ system_key = true;
+ type = CHAR;
+ case WM_CHAR:
+ type = CHAR;
+ break;
+ default:
+ NOTREACHED() << "unexpected native message";
+ }
+
+ if (GetKeyState(VK_SHIFT) & 0x8000)
+ modifiers |= SHIFT_KEY;
+ if (GetKeyState(VK_CONTROL) & 0x8000)
+ modifiers |= CTRL_KEY;
+ if (GetKeyState(VK_MENU) & 0x8000)
+ modifiers |= (ALT_KEY | META_KEY);
+
+ if (LOWORD(lparam) > 1)
+ modifiers |= IS_AUTO_REPEAT;
+
+ // TODO(darin): figure out if we should set IS_KEYPAD
+}
diff --git a/webkit/glue/webinputevent.h b/webkit/glue/webinputevent.h
new file mode 100644
index 0000000..fad7165
--- /dev/null
+++ b/webkit/glue/webinputevent.h
@@ -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.
+
+#ifndef WEBKIT_GLUE_WEBINPUTEVENT_H__
+#define WEBKIT_GLUE_WEBINPUTEVENT_H__
+
+#include <windows.h>
+#include "base/basictypes.h"
+
+// The classes defined in this file are intended to be used with WebView's
+// HandleInputEvent method. These event types are cross-platform; however,
+// there are platform-specific constructors that accept native UI events.
+//
+// The fields of these event classes roughly correspond to the fields required
+// by WebCore's platform event classes.
+
+// WebInputEvent --------------------------------------------------------------
+
+class WebInputEvent {
+ public:
+ enum Type {
+ // WebMouseEvent
+ MOUSE_DOWN,
+ MOUSE_UP,
+ MOUSE_MOVE,
+ MOUSE_LEAVE,
+ MOUSE_DOUBLE_CLICK,
+
+ // WebMouseWheelEvent
+ MOUSE_WHEEL,
+
+ // WebKeyboardEvent
+ KEY_DOWN,
+ KEY_UP,
+ CHAR
+ };
+
+ enum Modifiers {
+ // modifiers for all events:
+ SHIFT_KEY = 1 << 0,
+ CTRL_KEY = 1 << 1,
+ ALT_KEY = 1 << 2,
+ META_KEY = 1 << 3,
+
+ // modifiers for keyboard events:
+ IS_KEYPAD = 1 << 4,
+ IS_AUTO_REPEAT = 1 << 5
+ };
+
+ Type type;
+ int modifiers;
+};
+
+// WebMouseEvent --------------------------------------------------------------
+
+class WebMouseEvent : public WebInputEvent {
+ public:
+ // These values defined for WebCore::MouseButton
+ enum Button {
+ BUTTON_NONE = -1,
+ BUTTON_LEFT,
+ BUTTON_MIDDLE,
+ BUTTON_RIGHT
+ };
+
+ Button button;
+ int x;
+ int y;
+ int global_x;
+ int global_y;
+ double timestamp_sec; // Seconds since epoch.
+ int layout_test_click_count; // Only used during layout tests.
+
+ WebMouseEvent() {}
+ WebMouseEvent(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
+};
+
+// WebMouseWheelEvent ---------------------------------------------------------
+
+class WebMouseWheelEvent : public WebMouseEvent {
+ public:
+ int delta_x;
+ int delta_y;
+
+ WebMouseWheelEvent() {}
+ WebMouseWheelEvent(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
+};
+
+// WebKeyboardEvent -----------------------------------------------------------
+
+class WebKeyboardEvent : public WebInputEvent {
+ public:
+ bool system_key; // Set if we receive a SYSKEYDOWN/WM_SYSKEYUP message.
+ MSG actual_message; // Set to the current keyboard message.
+ int key_code;
+ int key_data;
+
+ WebKeyboardEvent()
+ : system_key(false),
+ key_code(0),
+ key_data(0) {
+ memset(&actual_message, 0, sizeof(actual_message));
+ }
+
+ WebKeyboardEvent(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
+};
+
+
+#endif // WEBKIT_GLUE_WEBINPUTEVENT_H__
diff --git a/webkit/glue/webkit_glue.cc b/webkit/glue/webkit_glue.cc
new file mode 100644
index 0000000..82de57d
--- /dev/null
+++ b/webkit/glue/webkit_glue.cc
@@ -0,0 +1,399 @@
+// 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 <objidl.h>
+#include <mlang.h>
+
+#include "config.h"
+#pragma warning(push, 0)
+#include "BackForwardList.h"
+#include "Document.h"
+#include "FrameTree.h"
+#include "FrameView.h"
+#include "Frame.h"
+#include "HistoryItem.h"
+#include "ImageSource.h"
+#include "KURL.h"
+#include "LogWin.h"
+#include "Page.h"
+#include "PlatformString.h"
+#include "RenderTreeAsText.h"
+#include "SharedBuffer.h"
+#pragma warning(pop)
+
+#if USE(V8_BINDING) || USE(JAVASCRIPTCORE_BINDINGS)
+#include "JSBridge.h" // for set flags
+#endif
+
+#undef LOG
+#undef notImplemented
+#include "webkit/glue/webkit_glue.h"
+
+#include "base/file_version_info.h"
+#include "base/string_util.h"
+#include "skia/include/SkBitmap.h"
+#include "webkit/glue/event_conversion.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/weburlrequest_impl.h"
+#include "webkit/glue/webframe_impl.h"
+#include "webkit/glue/webview_impl.h"
+
+//------------------------------------------------------------------------------
+// webkit_glue impl:
+
+namespace webkit_glue {
+
+void SetJavaScriptFlags(const std::wstring& str) {
+#if USE(V8_BINDING) || USE(JAVASCRIPTCORE_BINDINGS)
+ std::string utf8_str = WideToUTF8(str);
+ WebCore::JSBridge::setFlags(utf8_str.data(), static_cast<int>(utf8_str.size()));
+#endif
+}
+
+void SetRecordPlaybackMode(bool value) {
+#if USE(V8_BINDING) || USE(JAVASCRIPTCORE_BINDINGS)
+ WebCore::JSBridge::setRecordPlaybackMode(value);
+#endif
+}
+
+static bool layout_test_mode_ = false;
+
+void SetLayoutTestMode(bool enable) {
+ layout_test_mode_ = enable;
+}
+
+bool IsLayoutTestMode() {
+ return layout_test_mode_;
+}
+
+MONITORINFOEX GetMonitorInfoForWindowHelper(HWND window) {
+ HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY);
+ MONITORINFOEX monitorInfo;
+ monitorInfo.cbSize = sizeof(MONITORINFOEX);
+ GetMonitorInfo(monitor, &monitorInfo);
+ return monitorInfo;
+}
+
+IMLangFontLink2* GetLangFontLinkHelper() {
+ // TODO(hbono): http://b/1072298 Experimentally disabled this code to
+ // prevent registry leaks caused by this IMLangFontLink2 interface.
+ // If you find any font-rendering regressions. Please feel free to blame me.
+ // TODO(hbono): http://b/1072298 The test shell does not use our font metrics
+ // but it uses its own font metrics which heavily depend on this
+ // IMLangFontLink2 interface. Even though we should change the test shell to
+ // use out font metrics and re-baseline such tests, we temporarily let the
+ // test shell use this interface until we complete the said change.
+ if (!IsLayoutTestMode())
+ return NULL;
+
+ static IMultiLanguage *multi_language = NULL;
+
+ if (!multi_language) {
+ if (CoCreateInstance(CLSID_CMultiLanguage,
+ 0,
+ CLSCTX_ALL,
+ IID_IMultiLanguage,
+ reinterpret_cast<void**>(&multi_language)) != S_OK) {
+ return 0;
+ }
+ }
+
+ static IMLangFontLink2* lang_font_link;
+ if (!lang_font_link) {
+ if (multi_language->QueryInterface(
+ IID_IMLangFontLink2,
+ reinterpret_cast<void**>(&lang_font_link)) != S_OK) {
+ return 0;
+ }
+ }
+
+ return lang_font_link;
+}
+
+std::wstring DumpDocumentText(WebFrame* web_frame) {
+ WebFrameImpl* webFrameImpl = static_cast<WebFrameImpl*>(web_frame);
+ WebCore::Frame* frame = webFrameImpl->frame();
+
+ // We use the document element's text instead of the body text here because
+ // not all documents have a body, such as XML documents.
+ return StringToStdWString(frame->document()->documentElement()->innerText());
+}
+
+std::wstring DumpFramesAsText(WebFrame* web_frame, bool recursive) {
+ WebFrameImpl* webFrameImpl = static_cast<WebFrameImpl*>(web_frame);
+ std::wstring result;
+
+ // Add header for all but the main frame.
+ if (webFrameImpl->GetParent()) {
+ result.append(L"\n--------\nFrame: '");
+ result.append(webFrameImpl->GetName());
+ result.append(L"'\n--------\n");
+ }
+
+ result.append(DumpDocumentText(web_frame));
+ result.append(L"\n");
+
+ if (recursive) {
+ WebCore::Frame* child = webFrameImpl->frame()->tree()->firstChild();
+ for (; child; child = child->tree()->nextSibling()) {
+ result.append(
+ DumpFramesAsText(WebFrameImpl::FromFrame(child), recursive));
+ }
+ }
+
+ return result;
+}
+
+std::wstring DumpRenderer(WebFrame* web_frame) {
+ WebFrameImpl* webFrameImpl = static_cast<WebFrameImpl*>(web_frame);
+ WebCore::Frame* frame = webFrameImpl->frame();
+
+ // This implicitly converts from a DeprecatedString.
+ return StringToStdWString(WebCore::externalRepresentation(frame->renderer()));
+}
+
+std::wstring DumpFrameScrollPosition(WebFrame* web_frame, bool recursive) {
+ WebFrameImpl* webFrameImpl = static_cast<WebFrameImpl*>(web_frame);
+ WebCore::IntSize offset = webFrameImpl->frameview()->scrollOffset();
+ std::wstring result;
+
+ if (offset.width() > 0 || offset.height() > 0) {
+ if (webFrameImpl->GetParent()) {
+ StringAppendF(&result, L"frame '%s' ", StringToStdWString(
+ webFrameImpl->frame()->tree()->name()).c_str());
+ }
+ StringAppendF(&result, L"scrolled to %d,%d\n",
+ offset.width(), offset.height());
+ }
+
+ if (recursive) {
+ WebCore::Frame* child = webFrameImpl->frame()->tree()->firstChild();
+ for (; child; child = child->tree()->nextSibling()) {
+ result.append(DumpFrameScrollPosition(WebFrameImpl::FromFrame(child),
+ recursive));
+ }
+ }
+
+ return result;
+}
+
+// Returns True if item1 < item2.
+static bool HistoryItemCompareLess(PassRefPtr<WebCore::HistoryItem> item1,
+ PassRefPtr<WebCore::HistoryItem> item2) {
+ std::wstring target1 = StringToStdWString(item1->target());
+ std::wstring target2 = StringToStdWString(item2->target());
+ std::transform(target1.begin(), target1.end(), target1.begin(), tolower);
+ std::transform(target2.begin(), target2.end(), target2.begin(), tolower);
+ return target1 < target2;
+}
+
+// Writes out a HistoryItem into a string in a readable format.
+static void DumpHistoryItem(WebCore::HistoryItem* item, int indent,
+ bool is_current, std::wstring* result) {
+ if (is_current) {
+ result->append(L"curr->");
+ result->append(indent - 6, L' '); // 6 == L"curr->".length()
+ } else {
+ result->append(indent, L' ');
+ }
+
+ result->append(StringToStdWString(item->urlString()));
+ if (!item->target().isEmpty()) {
+ result->append(L" (in frame \"" + StringToStdWString(item->target()) +
+ L"\")");
+ }
+ if (item->isTargetItem())
+ result->append(L" **nav target**");
+ result->append(L"\n");
+
+ if (item->hasChildren()) {
+ WebCore::HistoryItemVector children = item->children();
+ // Must sort to eliminate arbitrary result ordering which defeats
+ // reproducible testing.
+ std::sort(children.begin(), children.end(), HistoryItemCompareLess);
+ for (unsigned i = 0; i < children.size(); i++) {
+ DumpHistoryItem(children[i].get(), indent+4, false, result);
+ }
+ }
+}
+
+void DumpBackForwardList(WebView* view, void* previous_history_item,
+ std::wstring* result) {
+ result->append(L"\n============== Back Forward List ==============\n");
+
+ WebCore::Frame* frame =
+ static_cast<WebFrameImpl*>(view->GetMainFrame())->frame();
+ WebCore::BackForwardList* list = frame->page()->backForwardList();
+
+ // Skip everything before the previous_history_item, if it's in the back list.
+ // If it isn't found, assume it fell off the end, and include everything.
+ int start_index = -list->backListCount();
+ WebCore::HistoryItem* prev_item =
+ static_cast<WebCore::HistoryItem*>(previous_history_item);
+ for (int i = -list->backListCount(); i < 0; ++i) {
+ if (prev_item == list->itemAtIndex(i))
+ start_index = i+1;
+ }
+
+ for (int i = start_index; i < 0; ++i)
+ DumpHistoryItem(list->itemAtIndex(i), 8, false, result);
+
+ DumpHistoryItem(list->currentItem(), 8, true, result);
+
+ for (int i = 1; i <= list->forwardListCount(); ++i)
+ DumpHistoryItem(list->itemAtIndex(i), 8, false, result);
+
+ result->append(L"===============================================\n");
+}
+
+void ResetBeforeTestRun(WebView* view) {
+ WebFrameImpl* webframe = static_cast<WebFrameImpl*>(view->GetMainFrame());
+ WebCore::Frame* frame = webframe->frame();
+
+ // Reset the main frame name since tests always expect it to be empty. It
+ // is normally not reset between page loads (even in IE and FF).
+ if (frame && frame->tree())
+ frame->tree()->setName("");
+
+ // This is papering over b/850700. But it passes a few more tests, so we'll
+ // keep it for now.
+ if (frame && frame->scriptBridge())
+ frame->scriptBridge()->setEventHandlerLineno(0);
+
+ // Reset the last click information so the clicks generated from previous
+ // test aren't inherited (otherwise can mistake single/double/triple clicks)
+ MakePlatformMouseEvent::ResetLastClick();
+}
+
+#ifndef NDEBUG
+// The log macro was having problems due to collisions with WTF, so we just
+// code here what that would have inlined.
+void DumpLeakedObject(const char* file, int line, const char* object, int count) {
+ std::string msg = StringPrintf("%s LEAKED %d TIMES", object, count);
+ AppendToLog(file, line, msg.c_str());
+}
+#endif
+
+void CheckForLeaks() {
+#ifndef NDEBUG
+ int count = WebFrameImpl::live_object_count();
+ if (count)
+ DumpLeakedObject(__FILE__, __LINE__, "WebFrame", count);
+#endif
+}
+
+bool DecodeImage(const std::string& image_data, SkBitmap* image) {
+ RefPtr<WebCore::SharedBuffer> buffer(
+ new WebCore::SharedBuffer(image_data.data(),
+ static_cast<int>(image_data.length())));
+ WebCore::ImageSource image_source;
+ image_source.setData(buffer.get(), true);
+
+ if (image_source.frameCount() > 0) {
+ *image = *reinterpret_cast<SkBitmap*>(image_source.createFrameAtIndex(0));
+ return true;
+ }
+ // We failed to decode the image.
+ return false;
+}
+
+// Convert from WebKit types to Glue types and notify the embedder. This should
+// not perform complex processing since it may be called a lot.
+void NotifyFormStateChanged(const WebCore::Document* document) {
+ if (!document)
+ return;
+
+ WebCore::Frame* frame = document->frame();
+ if (!frame)
+ return;
+
+ // Dispatch to the delegate of the view that owns the frame.
+ WebFrame* webframe = WebFrameImpl::FromFrame(document->frame());
+ WebView* webview = webframe->GetView();
+ if (!webview)
+ return;
+ WebViewDelegate* delegate = webview->GetDelegate();
+ if (!delegate)
+ return;
+ delegate->OnNavStateChanged(webview);
+}
+
+const std::string& GetDefaultUserAgent() {
+ static std::string user_agent;
+ static bool generated_user_agent;
+ if (!generated_user_agent) {
+ OSVERSIONINFO info = {0};
+ info.dwOSVersionInfoSize = sizeof(info);
+ GetVersionEx(&info);
+
+ // Get the product name and version, and replace Safari's Version/X string
+ // with it. This is done to expose our product name in a manner that is
+ // maximally compatible with Safari, we hope!!
+ std::string product;
+#ifdef CHROME_LAST_MINUTE
+ FileVersionInfo* version_info =
+ FileVersionInfo::CreateFileVersionInfoForCurrentModule();
+ if (version_info)
+ product = "Chrome/" + WideToASCII(version_info->product_version());
+#endif
+ if (product.empty())
+ product = "Version/3.1";
+
+ // Derived from Safari's UA string.
+ StringAppendF(
+ &user_agent,
+ "Mozilla/5.0 (Windows; U; Windows NT %d.%d; en-US) AppleWebKit/525.13"
+ " (KHTML, like Gecko) %s Safari/525.13",
+ info.dwMajorVersion,
+ info.dwMinorVersion,
+ product.c_str());
+
+ generated_user_agent = true;
+ }
+
+ return user_agent;
+}
+
+
+void NotifyJSOutOfMemory(WebCore::Frame* frame) {
+ if (!frame)
+ return;
+
+ // Dispatch to the delegate of the view that owns the frame.
+ WebFrame* webframe = WebFrameImpl::FromFrame(frame);
+ WebView* webview = webframe->GetView();
+ if (!webview)
+ return;
+ WebViewDelegate* delegate = webview->GetDelegate();
+ if (!delegate)
+ return;
+ delegate->JSOutOfMemory();
+}
+
+} // namespace webkit_glue
diff --git a/webkit/glue/webkit_glue.h b/webkit/glue/webkit_glue.h
new file mode 100644
index 0000000..80249fb
--- /dev/null
+++ b/webkit/glue/webkit_glue.h
@@ -0,0 +1,303 @@
+// 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 WEBKIT_GLUE_H__
+#define WEBKIT_GLUE_H__
+
+#include <string>
+#include <vector>
+#ifdef _WIN32
+#include <windows.h>
+#endif
+#include "base/string16.h"
+#include "webkit/glue/webplugin.h"
+
+// We do not include the header files for these interfaces since this header
+// file is included by code in webkit/port
+class SharedCursor;
+class WebView;
+class WebViewDelegate;
+class WebRequest;
+class WebFrame;
+class WebFrameImpl;
+class GURL;
+struct _NPNetscapeFuncs;
+typedef _NPNetscapeFuncs NPNetscapeFuncs;
+
+#ifdef _WIN32
+struct IMLangFontLink2;
+#endif
+
+namespace WebCore {
+
+class Document;
+class Frame;
+
+} // namespace WebCore
+
+class SkBitmap;
+
+namespace webkit_glue {
+
+//-----------------------------------------------------------------------------
+// Functions implemented by JS engines.
+void SetJavaScriptFlags(const std::wstring& flags);
+void SetRecordPlaybackMode(bool value);
+
+//-----------------------------------------------------------------------------
+// Functions implemented by WebKit, called by the embedder:
+
+// Turns on "layout test" mode, which tries to mimic the font and widget sizing
+// of the Mac DumpRenderTree.
+void SetLayoutTestMode(bool enable);
+bool IsLayoutTestMode();
+
+#ifdef _WIN32
+// Returns the com object pointer for the FontLink interface. This is the
+// default way to do this operation. It can be called directly from
+// GetLangFontLink.
+IMLangFontLink2* GetLangFontLinkHelper();
+
+// Returns the monitor information corresponding to the window.
+// This is the default implementation.
+MONITORINFOEX GetMonitorInfoForWindowHelper(HWND window);
+#endif
+
+// Returns the text of the document element.
+std::wstring DumpDocumentText(WebFrame* web_frame);
+
+// Returns the text of the document element and optionally its child frames.
+// If recursive is false, this is equivalent to DumpDocumentText followed by
+// a newline. If recursive is true, it recursively dumps all frames as text.
+std::wstring DumpFramesAsText(WebFrame* web_frame, bool recursive);
+
+// Returns the renderer's description of its tree (its externalRepresentation).
+std::wstring DumpRenderer(WebFrame* web_frame);
+
+// Returns a dump of the scroll position of the webframe.
+std::wstring DumpFrameScrollPosition(WebFrame* web_frame, bool recursive);
+
+// Returns a representation of the back/forward list.
+void DumpBackForwardList(WebView* view, void* previous_history_item,
+ std::wstring* result);
+
+// Cleans up state left over from the previous test run.
+void ResetBeforeTestRun(WebView* view);
+
+// Returns the user agent.
+const std::string& GetDefaultUserAgent();
+
+// Creates serialized state for the specified URL. This is a variant of
+// HistoryItemToString (in glue_serialize) that is used during session restore
+// if the saved state is empty.
+std::string CreateHistoryStateForURL(const GURL& url);
+
+#ifndef NDEBUG
+// Checks various important objects to see if there are any in memory, and
+// calls AppendToLog with any leaked objects. Designed to be called on shutdown
+void CheckForLeaks();
+#endif
+
+// Decodes the image from the data in |image_data| into |image|.
+// Returns false if the image could not be decoded.
+bool DecodeImage(const std::string& image_data, SkBitmap* image);
+
+//-----------------------------------------------------------------------------
+// Functions implemented by the embedder, called by WebKit:
+
+// This function is called to check if the given URL string exists in the
+// user's browsing history db. The given URL may NOT be in canonical form and
+// it will NOT be null-terminated; use the length instead. This function also
+// causes the hostnames' DNS record to be prefetched if is_dns_prefetch_enabled
+// is true or document_host matches the URL being checked. The hostname will
+// likewise not be null-terminated; use document_host_length instead.
+bool HistoryContains(const char16* url, int url_length,
+ const char* document_host, int document_host_length,
+ bool is_dns_prefetch_enabled);
+
+// This function is called to request a prefetch of the DNS resolution for the
+// embedded URL's hostname. The given URL may NOT be in canonical form and
+// it will NOT be null-terminated; use the length instead.
+void DnsPrefetchUrl(const char16* url, int url_length);
+
+// This function is called to request a prefetch of the entire URL, loading it
+// into our cache for (expected) future needs. The given URL may NOT be in
+// canonical form and it will NOT be null-terminated; use the length instead.
+void PrecacheUrl(const char16* url, int url_length);
+
+// This function is called to add a line to the application's log file.
+void AppendToLog(const char* filename, int line, const char* message);
+
+// Get the mime type (if any) that is associated with the given file extension.
+// Returns true if a corresponding mime type exists.
+bool GetMimeTypeFromExtension(std::wstring &ext, std::string *mime_type);
+
+// Get the mime type (if any) that is associated with the given file.
+// Returns true if a corresponding mime type exists.
+bool GetMimeTypeFromFile(const std::wstring &file_path, std::string *mime_type);
+
+// Get the preferred extension (if any) associated with the given mime type.
+// Returns true if a corresponding file extension exists.
+bool GetPreferredExtensionForMimeType(const std::string& mime_type,
+ std::wstring *ext);
+
+#ifdef _WIN32
+// Returns the com object pointer for the FontLink interface
+IMLangFontLink2* GetLangFontLink();
+#endif
+
+// Sets a cookie string for the given URL. The policy_url argument indicates
+// the URL of the topmost frame, which may be useful for determining whether or
+// not to allow this cookie setting. NOTE: the cookie string is a standard
+// cookie string of the form "name=value; option1=x; option2=y"
+void SetCookie(const GURL& url, const GURL& policy_url,
+ const std::string& cookie);
+
+// Returns all cookies in the form "a=1; b=2; c=3" for the given URL. NOTE:
+// this string should not include any options that may have been specified when
+// the cookie was set. Semicolons delimit individual cookies in this context.
+std::string GetCookies(const GURL& url, const GURL& policy_url);
+
+// Gather usage statistics from the in-memory cache and inform our host, if
+// applicable.
+void NotifyCacheStats();
+
+// Glue to get resources from the embedder.
+
+// Gets a localized string given a message id. Returns an empty string if the
+// message id is not found.
+std::wstring GetLocalizedString(int message_id);
+
+// Returns the raw data for a resource. This resource must have been
+// specified as BINDATA in the relevant .rc file.
+std::string GetDataResource(int resource_id);
+
+#ifdef _WIN32
+// Loads and returns a cursor.
+HCURSOR LoadCursor(int cursor_id);
+#endif
+
+// Glue to access the clipboard.
+
+// Clear the clipboard. It is usually a good idea to clear the clipboard
+// before writing content to the clipboard.
+void ClipboardClear();
+
+// Adds UNICODE and ASCII text to the clipboard.
+void ClipboardWriteText(const std::wstring& text);
+
+// Adds HTML to the clipboard. The url parameter is optional, but especially
+// useful if the HTML fragment contains relative links
+void ClipboardWriteHTML(const std::wstring& html, const GURL& url);
+
+// Adds a bookmark to the clipboard
+void ClipboardWriteBookmark(const std::wstring& title, const GURL& url);
+
+// Adds a bitmap to the clipboard
+void ClipboardWriteBitmap(const SkBitmap& bitmap);
+
+// Used by WebKit to determine whether WebKit wrote the clipboard last
+void ClipboardWriteWebSmartPaste();
+
+// Tests whether the clipboard contains a certain format
+bool ClipboardIsFormatAvailable(unsigned int format);
+
+// Reads UNICODE text from the clipboard, if available.
+void ClipboardReadText(std::wstring* result);
+
+// Reads ASCII text from the clipboard, if available.
+void ClipboardReadAsciiText(std::string* result);
+
+// Reads HTML from the clipboard, if available.
+void ClipboardReadHTML(std::wstring* markup, GURL* url);
+
+// Gets the directory where the application data and libraries exist. This
+// may be a versioned subdirectory, or it may be the same directory as the
+// GetExeDirectory(), depending on the embedder's implementation.
+// Path is an output parameter to receive the path.
+// Returns true if successful, false otherwise.
+bool GetApplicationDirectory(std::wstring *path);
+
+// Gets the URL where the inspector's HTML file resides. It must use the
+// protocol returned by GetUIResourceProtocol.
+GURL GetInspectorURL();
+
+// Gets the protocol that is used for all user interface resources, including
+// the Inspector. It must end with "-resource".
+std::string GetUIResourceProtocol();
+
+// Gets the directory where the launching executable resides on disk.
+// Path is an output parameter to receive the path.
+// Returns true if successful, false otherwise.
+bool GetExeDirectory(std::wstring *path);
+
+// Embedders implement this function to return the list of plugins to Webkit.
+bool GetPlugins(bool refresh, std::vector<WebPluginInfo>* plugins);
+
+// Returns true if the plugins run in the same process as the renderer, and
+// false otherwise.
+bool IsPluginRunningInRendererProcess();
+
+#ifdef _WIN32
+// Asks the browser to load the font.
+bool EnsureFontLoaded(HFONT font);
+
+// Returns the monitor information corresponding to the window.
+MONITORINFOEX GetMonitorInfoForWindow(HWND window);
+#endif
+
+// Functions implemented by webkit_glue for WebKit ----------------------------
+
+// Notifies the embedder that a form element value has changed. The document
+// pointer, which MAY BE NULL, indicates the document that owns the form
+// element that changed, if any.
+void NotifyFormStateChanged(const WebCore::Document* document);
+
+// Returns a bool indicating if the Null plugin should be enabled or not.
+bool IsDefaultPluginEnabled();
+
+#ifdef _WIN32
+// Downloads the file specified by the URL. On sucess a WM_COPYDATA message
+// will be sent to the caller_window.
+bool DownloadUrl(const std::string& url, HWND caller_window);
+#endif
+
+// Returns the plugin finder URL.
+bool GetPluginFinderURL(std::string* plugin_finder_url);
+
+// Returns the locale that this instance of webkit is running as. This is of
+// the form language-country (e.g., en-US or pt-BR).
+std::wstring GetWebKitLocale();
+
+// Notifies the browser that the current page runs out of JS memory.
+void NotifyJSOutOfMemory(WebCore::Frame* frame);
+
+} // namespace webkit_glue
+
+#endif // WEBKIT_GLUE_H__
diff --git a/webkit/glue/webkit_resources.h b/webkit/glue/webkit_resources.h
new file mode 100644
index 0000000..075d0fd
--- /dev/null
+++ b/webkit/glue/webkit_resources.h
@@ -0,0 +1,25 @@
+// These values shouldn't clash with other values defined in .rc files.
+// 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_BROKENIMAGE 2000
+#define IDR_TICKMARK_DASH 2001
+#define IDR_FEED_PREVIEW 2002
+
+#define IDC_ALIAS 2100
+#define IDC_CELL 2101
+#define IDC_COLRESIZE 2102
+#define IDC_COPYCUR 2103
+#define IDC_ROWRESIZE 2104
+#define IDC_VERTICALTEXT 2105
+#define IDC_ZOOMIN 2106
+#define IDC_ZOOMOUT 2107
+
+#define IDD_DEFAULT_PLUGIN_INSTALL_DIALOG 2108
+#define IDI_DEFAULT_PLUGIN_ICON 2109
+#define IDB_GET_THE_PLUGIN 2110
+#define IDC_PLUGIN_MAIN_LABEL 2111
+#define IDC_PLUGIN_INSTALL_LABEL 2112
+#define IDC_PLUGIN_URL_LABEL 2113
+#define IDC_PLUGIN_INSTALL_CONFIRMATION_LABEL 2114
+#define IDC_PLUGIN_NAME 2115
+#define IDC_PLUGIN_NAME_VALUE 2116
diff --git a/webkit/glue/webkit_resources.rc b/webkit/glue/webkit_resources.rc
new file mode 100644
index 0000000..b71c338
--- /dev/null
+++ b/webkit/glue/webkit_resources.rc
@@ -0,0 +1,55 @@
+// Resources used by webkit/*.
+//
+// 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 <winuser.h>
+#include "webkit\\glue\\webkit_resources.h"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// data resources
+//
+
+IDR_BROKENIMAGE BINDATA "webkit\\glue\\resources\\broken-image.gif"
+IDR_TICKMARK_DASH BINDATA "webkit\\glue\\resources\\dash.png"
+
+IDR_FEED_PREVIEW BINDATA "webkit\\glue\\resources\\feed.html"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Cursor
+//
+
+IDC_ALIAS CURSOR "webkit\\glue\\resources\\aliasb.cur"
+IDC_CELL CURSOR "webkit\\glue\\resources\\cell.cur"
+IDC_COLRESIZE CURSOR "webkit\\glue\\resources\\col_resize.cur"
+IDC_COPYCUR CURSOR "webkit\\glue\\resources\\copy.cur"
+IDC_ROWRESIZE CURSOR "webkit\\glue\\resources\\row_resize.cur"
+IDC_VERTICALTEXT CURSOR "webkit\\glue\\resources\\vertical_text.cur"
+IDC_ZOOMIN CURSOR "webkit\\glue\\resources\\zoom_in.cur"
+IDC_ZOOMOUT CURSOR "webkit\\glue\\resources\\zoom_out.cur"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog template for the plugin installation dialog.
+//
+IDD_DEFAULT_PLUGIN_INSTALL_DIALOG DIALOGEX 0, 0, 240, 130
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Plug-in Needed"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "",IDB_GET_THE_PLUGIN,32,100,81,14
+ PUSHBUTTON "",IDCANCEL,133,100,74,14
+ LTEXT "",IDC_PLUGIN_INSTALL_CONFIRMATION_LABEL,17,50,204,27
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon used by the default plugin window.
+//
+IDI_DEFAULT_PLUGIN_ICON ICON "webkit\\default_plugin\\default_plugin.ico"
diff --git a/webkit/glue/webkit_strings.grd b/webkit/glue/webkit_strings.grd
new file mode 100644
index 0000000..d8efc4a
--- /dev/null
+++ b/webkit/glue/webkit_strings.grd
@@ -0,0 +1,284 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This file contains definitions of resources that will be translated for
+each locale. Specifically, these are UI strings that are used by webkit that
+need to be translated for each locale.-->
+
+<!-- Some of these strings and string descriptions were taken from
+WebKit/win/WebCoreLocalizedStrings.cpp so we include the original license
+below:
+
+/*
+ * Copyright (C) 2007 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+-->
+
+<grit base_dir="." latest_public_release="0" current_release="1"
+ source_lang_id="en" enc_check="möl">
+ <outputs>
+ <!-- TODO add each of your output files. Modify the three below, and add
+ your own for your various languages. See the user's guide
+ (http://wiki/Main/GritUsersGuide) for more details.
+ Note that all output references are relative to the output directory
+ which is specified at build time. -->
+ <output filename="webkit_strings.h" type="rc_header">
+ <emit emit_type='prepend'></emit>
+ </output>
+ <output filename="webkit_strings_ar.rc" type="rc_all" lang="ar" />
+ <output filename="webkit_strings_bg.rc" type="rc_all" lang="bg" />
+ <output filename="webkit_strings_ca.rc" type="rc_all" lang="ca" />
+ <output filename="webkit_strings_cs.rc" type="rc_all" lang="cs" />
+ <output filename="webkit_strings_da.rc" type="rc_all" lang="da" />
+ <output filename="webkit_strings_de.rc" type="rc_all" lang="de" />
+ <output filename="webkit_strings_el.rc" type="rc_all" lang="el" />
+ <output filename="webkit_strings_en-GB.rc" type="rc_all" lang="en-GB" />
+ <output filename="webkit_strings_en-US.rc" type="rc_all" lang="en" />
+ <output filename="webkit_strings_es.rc" type="rc_all" lang="es" />
+ <output filename="webkit_strings_es-419.rc" type="rc_all" lang="es-419" />
+ <output filename="webkit_strings_et.rc" type="rc_all" lang="et" />
+ <output filename="webkit_strings_fi.rc" type="rc_all" lang="fi" />
+ <output filename="webkit_strings_fil.rc" type="rc_all" lang="fil" />
+ <output filename="webkit_strings_fr.rc" type="rc_all" lang="fr" />
+ <output filename="webkit_strings_he.rc" type="rc_all" lang="he" />
+ <output filename="webkit_strings_hi.rc" type="rc_all" lang="hi" />
+ <output filename="webkit_strings_hr.rc" type="rc_all" lang="hr" />
+ <output filename="webkit_strings_hu.rc" type="rc_all" lang="hu" />
+ <output filename="webkit_strings_id.rc" type="rc_all" lang="id" />
+ <output filename="webkit_strings_it.rc" type="rc_all" lang="it" />
+ <output filename="webkit_strings_ja.rc" type="rc_all" lang="ja" />
+ <output filename="webkit_strings_ko.rc" type="rc_all" lang="ko" />
+ <output filename="webkit_strings_lt.rc" type="rc_all" lang="lt" />
+ <output filename="webkit_strings_lv.rc" type="rc_all" lang="lv" />
+ <output filename="webkit_strings_nl.rc" type="rc_all" lang="nl" />
+ <!-- The translation console uses 'no' for Norwegian Bokmål. It should
+ be 'nb'. -->
+ <output filename="webkit_strings_nb.rc" type="rc_all" lang="no" />
+ <output filename="webkit_strings_pl.rc" type="rc_all" lang="pl" />
+ <output filename="webkit_strings_pt-BR.rc" type="rc_all" lang="pt-BR" />
+ <output filename="webkit_strings_pt-PT.rc" type="rc_all" lang="pt-PT" />
+ <output filename="webkit_strings_ro.rc" type="rc_all" lang="ro" />
+ <output filename="webkit_strings_ru.rc" type="rc_all" lang="ru" />
+ <output filename="webkit_strings_sk.rc" type="rc_all" lang="sk" />
+ <output filename="webkit_strings_sl.rc" type="rc_all" lang="sl" />
+ <output filename="webkit_strings_sr.rc" type="rc_all" lang="sr" />
+ <output filename="webkit_strings_sv.rc" type="rc_all" lang="sv" />
+ <output filename="webkit_strings_th.rc" type="rc_all" lang="th" />
+ <output filename="webkit_strings_tr.rc" type="rc_all" lang="tr" />
+ <output filename="webkit_strings_uk.rc" type="rc_all" lang="uk" />
+ <output filename="webkit_strings_vi.rc" type="rc_all" lang="vi" />
+ <output filename="webkit_strings_zh-CN.rc" type="rc_all" lang="zh-CN" />
+ <output filename="webkit_strings_zh-TW.rc" type="rc_all" lang="zh-TW" />
+ </outputs>
+ <translations>
+ <file path="resources/webkit_strings_ar.xtb" lang="ar" />
+ <file path="resources/webkit_strings_bg.xtb" lang="bg" />
+ <file path="resources/webkit_strings_ca.xtb" lang="ca" />
+ <file path="resources/webkit_strings_cs.xtb" lang="cs" />
+ <file path="resources/webkit_strings_da.xtb" lang="da" />
+ <file path="resources/webkit_strings_de.xtb" lang="de" />
+ <file path="resources/webkit_strings_el.xtb" lang="el" />
+ <file path="resources/webkit_strings_en-GB.xtb" lang="en-GB" />
+ <file path="resources/webkit_strings_es.xtb" lang="es" />
+ <file path="resources/webkit_strings_es-419.xtb" lang="es-419" />
+ <file path="resources/webkit_strings_et.xtb" lang="et" />
+ <file path="resources/webkit_strings_fi.xtb" lang="fi" />
+ <file path="resources/webkit_strings_fil.xtb" lang="fil" />
+ <file path="resources/webkit_strings_fr.xtb" lang="fr" />
+ <file path="resources/webkit_strings_he.xtb" lang="he" />
+ <file path="resources/webkit_strings_hi.xtb" lang="hi" />
+ <file path="resources/webkit_strings_hr.xtb" lang="hr" />
+ <file path="resources/webkit_strings_hu.xtb" lang="hu" />
+ <file path="resources/webkit_strings_id.xtb" lang="id" />
+ <file path="resources/webkit_strings_it.xtb" lang="it" />
+ <file path="resources/webkit_strings_ja.xtb" lang="ja" />
+ <file path="resources/webkit_strings_ko.xtb" lang="ko" />
+ <file path="resources/webkit_strings_lt.xtb" lang="lt" />
+ <file path="resources/webkit_strings_lv.xtb" lang="lv" />
+ <file path="resources/webkit_strings_nl.xtb" lang="nl" />
+ <file path="resources/webkit_strings_no.xtb" lang="no" />
+ <file path="resources/webkit_strings_pl.xtb" lang="pl" />
+ <file path="resources/webkit_strings_pt-BR.xtb" lang="pt-BR" />
+ <file path="resources/webkit_strings_pt-PT.xtb" lang="pt-PT" />
+ <file path="resources/webkit_strings_ro.xtb" lang="ro" />
+ <file path="resources/webkit_strings_ru.xtb" lang="ru" />
+ <file path="resources/webkit_strings_sk.xtb" lang="sk" />
+ <file path="resources/webkit_strings_sl.xtb" lang="sl" />
+ <file path="resources/webkit_strings_sr.xtb" lang="sr" />
+ <file path="resources/webkit_strings_sv.xtb" lang="sv" />
+ <file path="resources/webkit_strings_th.xtb" lang="th" />
+ <file path="resources/webkit_strings_tr.xtb" lang="tr" />
+ <file path="resources/webkit_strings_uk.xtb" lang="uk" />
+ <file path="resources/webkit_strings_vi.xtb" lang="vi" />
+ <file path="resources/webkit_strings_zh-CN.xtb" lang="zh-CN" />
+ <file path="resources/webkit_strings_zh-TW.xtb" lang="zh-TW" />
+ </translations>
+ <release seq="1">
+ <messages>
+ <!-- TODO add all of your "string table" messages here. Remember to
+ change nontranslateable parts of the messages into placeholders (using the
+ <ph> element). You can also use the 'grit add' tool to help you identify
+ nontranslateable parts and create placeholders for them. -->
+
+ <message name="IDS_SEARCHABLE_INDEX_INTRO" desc="Text that appears at the start of nearly-obsolete web pages in the form of a 'searchable index'.">
+ This is a searchable index. Enter search keywords: '''
+ </message>
+ <message name="IDS_FORM_SUBMIT_LABEL" desc="Default label for Submit buttons in forms on web pages.">
+ Submit
+ </message>
+ <message name="IDS_FORM_INPUT_ALT" desc="alt text for &lt;input&gt; elements with no alt, title, or value">
+ Submit
+ </message>
+ <message name="IDS_FORM_RESET_LABEL" desc="default label for Reset buttons in forms on web pages">
+ Reset
+ </message>
+ <message name="IDS_FORM_FILE_BUTTON_LABEL" desc="title for file button used in HTML forms">
+ Choose File
+ </message>
+ <message name="IDS_FORM_FILE_NO_FILE_LABEL" desc="text to display in file button used in HTML forms when no file is selected">
+ No file chosen
+ </message>
+ <message name="IDS_FORM_FILE_NO_FILE_DRAG_LABEL" desc="text to display in file button used in HTML forms when no file is selected to indicate that files can be dragged onto the file button">
+ Drag file here
+ </message>
+
+ <message name="IDS_RECENT_SEARCHES_NONE" desc="Label for only item in menu that appears when clicking on the search field image, when no searches have been performed">
+ No recent searches
+ </message>
+ <message name="IDS_RECENT_SEARCHES" desc="label for first item in the menu that appears when clicking on the search field image, used as embedded menu title">
+ Recent Searches
+ </message>
+ <message name="IDS_RECENT_SEARCHES_CLEAR" desc="menu item in Recent Searches menu that empties menu's contents">
+ Clear Recent Searches
+ </message>
+
+ <message name="IDS_IMAGE_TITLE_FOR_FILENAME" desc="window title for a standalone image (uses mutiplication symbol, not x)">
+ <ph name="FILENAME">%s<ex>My Cool Image.gif</ex></ph><ph name="WIDTH">%d<ex>400</ex></ph>×<ph name="HEIGHT">%d<ex>600</ex></ph>
+ </message>
+
+ <message name="IDS_AX_ROLE_WEB_AREA" desc="accessibility role description for web area">
+ web area
+ </message>
+ <message name="IDS_AX_ROLE_LINK" desc="accessibility role description for link">
+ link
+ </message>
+ <message name="IDS_AX_ROLE_LIST_MARKER" desc="accessibility role description for list marker">
+ list marker
+ </message>
+ <message name="IDS_AX_ROLE_IMAGE_MAP" desc="accessibility role description for image map">
+ image map
+ </message>
+ <message name="IDS_AX_ROLE_HEADING" desc="accessibility role description for headings">
+ heading
+ </message>
+
+ <message name="IDS_AX_BUTTON_ACTION_VERB" desc="Verb stating the action that will occur when a button is pressed, as used by accessibility.">
+ press
+ </message>
+ <message name="IDS_AX_RADIO_BUTTON_ACTION_VERB" desc="Verb stating the action that will occur when a radio button is clicked, as used by accessibility.">
+ select
+ </message>
+ <message name="IDS_AX_TEXT_FIELD_ACTION_VERB" desc="Verb stating the action that will occur when a text field is selected, as used by accessibility.">
+ activate
+ </message>
+ <message name="IDS_AX_CHECKED_CHECK_BOX_ACTION_VERB" desc="Verb stating the action that will occur when a checked checkbox is clicked, as used by accessibility.">
+ uncheck
+ </message>
+ <message name="IDS_AX_UNCHECKED_CHECK_BOX_ACTION_VERB" desc="Verb stating the action that will occur when an unchecked checkbox is clicked, as used by accessibility.">
+ check
+ </message>
+ <message name="IDS_AX_LINK_ACTION_VERB" desc="Verb stating the action that will occur when a link is clicked, as used by accessibility.">
+ jump
+ </message>
+
+ <message name="IDS_KEYGEN_HIGH_GRADE_KEY" desc="High-grade cryptographic key size menu item">
+ 2048 (High Grade)
+ </message>
+ <message name="IDS_KEYGEN_MED_GRADE_KEY" desc="Medium-grade cryptographic key size menu item">
+ 1024 (Medium Grade)
+ </message>
+
+ <message name="IDS_DEFAULT_PLUGIN_GET_PLUGIN_MSG" desc="Message displayed by the default plugin in its main window">
+ <ph name="PLUGIN">$1<ex>Realplayer</ex></ph> plugin is not installed
+ </message>
+
+ <message name="IDS_DEFAULT_PLUGIN_GET_PLUGIN_MSG_NO_PLUGIN_NAME" desc="Message displayed by the default plugin in its main window when we don't know the plugin name">
+ The required plugin is not installed
+ </message>
+
+ <message name="IDS_DEFAULT_PLUGIN_GET_PLUGIN_MSG_2" desc="Second Message displayed by the default plugin in its main window">
+ Click here to download plugin
+ </message>
+
+ <message name="IDS_DEFAULT_PLUGIN_REFRESH_PLUGIN_MSG" desc="Message displayed by the default plugin to refresh the window after installing the required plugin">
+ After installing the plugin, click here to refresh
+ </message>
+
+ <message name="IDS_DEFAULT_PLUGIN_NO_PLUGIN_AVAILABLE_MSG" desc="Message displayed by the default plugin when no plugin was found for the page.">
+ No plugin available to display this content
+ </message>
+
+ <message name="IDS_DEFAULT_PLUGIN_DOWNLOADING_PLUGIN_MSG" desc="Message displayed by the default plugin when a download has been initiated for the third party plugin.">
+ Downloading plugin...
+ </message>
+
+ <message name="IDS_DEFAULT_PLUGIN_GET_THE_PLUGIN_BTN_MSG" desc="Message displayed by the default plugin on the button which the user should click to fetch the plugin.">
+ Get Plugin
+ </message>
+
+ <message name="IDS_DEFAULT_PLUGIN_CANCEL_PLUGIN_DOWNLOAD_MSG" desc="Message displayed by the default plugin on the button which the user should click to cancel the plugin download.">
+ Cancel
+ </message>
+
+ <message name="IDS_DEFAULT_PLUGIN_CONFIRMATION_DIALOG_TITLE" desc="Default plugin confirmation dialog title.">
+ <ph name="PLUGIN">$1<ex>Realplayer</ex></ph> plugin needed
+ </message>
+
+ <message name="IDS_DEFAULT_PLUGIN_CONFIRMATION_DIALOG_TITLE_NO_PLUGIN_NAME" desc="Default plugin confirmation dialog title when we don't know the plugin name">
+ Additional plugin needed
+ </message>
+
+ <message name="IDS_DEFAULT_PLUGIN_USER_OPTION_MSG" desc="Message displayed by the default plugin in the install dialog indicating information on the user action.">
+ Please confirm that you would like to install the <ph name="PLUGIN">$1<ex>realplayer</ex></ph> plugin. You should only install plugins that you trust.
+ </message>
+ <message name="IDS_DEFAULT_PLUGIN_USER_OPTION_MSG_NO_PLUGIN_NAME" desc="Message displayed by the default plugin in the install dialog indicating information on the user action when we don't know the plugin name">
+ Please confirm that you would like to install this plugin. You should only install plugins that you trust.
+ </message>
+
+ <message name="IDS_DEFAULT_PLUGIN_USE_OPTION_CONFIRM" desc="Button to confirm installation of plugin">
+ Install
+ </message>
+ <message name="IDS_DEFAULT_PLUGIN_USE_OPTION_CANCEL" desc="Button to cancel installation of plugin">
+ Cancel
+ </message>
+
+ <message name="IDS_DEFAULT_PLUGIN_DOWNLOAD_FAILED_MSG" desc="Message displayed by the default plugin when download is failed.">
+ Failed to install plugin from <ph name="URL">$1<ex>http://www.google.com/blablah.exe</ex></ph>
+ </message>
+
+ <message name="IDS_DEFAULT_PLUGIN_INSTALLATION_FAILED_MSG" desc="Message displayed by the default plugin when installation is failed.">
+ Plugin installation failed
+ </message>
+ </messages>
+ </release>
+</grit>
diff --git a/webkit/glue/webplugin.h b/webkit/glue/webplugin.h
new file mode 100644
index 0000000..c07c08a
--- /dev/null
+++ b/webkit/glue/webplugin.h
@@ -0,0 +1,170 @@
+// 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 WEBKIT_GLUE_WEBPLUGIN_H__
+#define WEBKIT_GLUE_WEBPLUGIN_H__
+
+#include <string>
+#include <vector>
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/gfx/rect.h"
+
+typedef struct HWND__* HWND;
+
+class GURL;
+class WebFrame;
+class WebPluginResourceClient;
+
+struct NPObject;
+
+// Describes a mime type entry for a plugin.
+struct WebPluginMimeType {
+ // The actual mime type.
+ std::string mime_type;
+
+ // A list of all the file extensions for this mime type.
+ std::vector<std::string> file_extensions;
+
+ // Description of the mime type.
+ std::wstring description;
+};
+
+
+// Describes an available NPAPI plugin.
+struct WebPluginInfo {
+ // The name of the plugin (i.e. Flash).
+ std::wstring name;
+
+ // The path to the dll.
+ std::wstring file;
+
+ // The version number of the plugin file (may be OS-specific)
+ std::wstring version;
+
+ // A description of the plugin that we get from it's version info.
+ std::wstring desc;
+
+ // A list of all the mime types that this plugin supports.
+ std::vector<WebPluginMimeType> mime_types;
+};
+
+
+// Describes the new location for a plugin window.
+struct WebPluginGeometry {
+ HWND window;
+ gfx::Rect window_rect;
+ gfx::Rect clip_rect;
+ bool visible;
+};
+
+
+enum RoutingStatus {
+ ROUTED,
+ NOT_ROUTED,
+ INVALID_URL,
+ GENERAL_FAILURE
+};
+
+// The WebKit side of a plugin implementation. It provides wrappers around
+// operations that need to interact with the frame and other WebCore objects.
+class WebPlugin {
+ public:
+ WebPlugin() { }
+ virtual ~WebPlugin() { }
+
+ // Called by the plugin delegate to let the WebPlugin know if the plugin is
+ // windowed (i.e. handle is not NULL) or windowless (handle is NULL). This
+ // tells the WebPlugin to send mouse/keyboard events to the plugin delegate,
+ // as well as the information about the HDC for paint operations.
+ // The pump_messages_event is a event handle which is valid only for
+ // windowless plugins and is used in NPP_HandleEvent calls to pump messages
+ // if the plugin enters a modal loop.
+ virtual void SetWindow(HWND window, HANDLE pump_messages_event) = 0;
+ // Cancels a pending request.
+ virtual void CancelResource(int id) = 0;
+ virtual void Invalidate() = 0;
+ virtual void InvalidateRect(const gfx::Rect& rect) = 0;
+
+ // Returns the NPObject for the browser's window object.
+ virtual NPObject* GetWindowScriptNPObject() = 0;
+
+ // Returns the DOM element that loaded the plugin.
+ virtual NPObject* GetPluginElement() = 0;
+
+ // Cookies
+ virtual void SetCookie(const GURL& url,
+ const GURL& policy_url,
+ const std::string& cookie) = 0;
+ virtual std::string GetCookies(const GURL& url,
+ const GURL& policy_url) = 0;
+
+ // Shows a modal HTML dialog containing the given URL. json_arguments are
+ // passed to the dialog via the DOM 'window.chrome.dialogArguments', and the
+ // retval is the string returned by 'window.chrome.send("DialogClose",
+ // retval)'.
+ virtual void ShowModalHTMLDialog(const GURL& url, int width, int height,
+ const std::string& json_arguments,
+ std::string* json_retval) = 0;
+
+ // When a default plugin has downloaded the plugin list and finds it is
+ // available, it calls this method to notify the renderer. Also it will update
+ // the status when user clicks on the plugin to install.
+ virtual void OnMissingPluginStatus(int status) = 0;
+
+ // Handles GetURL/GetURLNotify/PostURL/PostURLNotify requests initiated
+ // by plugins.
+ virtual void HandleURLRequest(const char *method,
+ bool is_javascript_url,
+ const char* target, unsigned int len,
+ const char* buf, bool is_file_data,
+ bool notify, const char* url,
+ void* notify_data, bool popups_allowed) = 0;
+
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(WebPlugin);
+};
+
+// Simpler version of ResourceHandleClient that lends itself to proxying.
+class WebPluginResourceClient {
+ public:
+ virtual void WillSendRequest(const GURL& url) = 0;
+ virtual void DidReceiveResponse(const std::string& mime_type,
+ const std::string& headers,
+ uint32 expected_length,
+ uint32 last_modified,
+ bool* cancel) = 0;
+ virtual void DidReceiveData(const char* buffer, int length) = 0;
+ virtual void DidFinishLoading() = 0;
+ virtual void DidFail() = 0;
+};
+
+
+#endif // #ifndef WEBKIT_GLUE_WEBPLUGIN_H__
diff --git a/webkit/glue/webplugin_delegate.h b/webkit/glue/webplugin_delegate.h
new file mode 100644
index 0000000..43ab88c
--- /dev/null
+++ b/webkit/glue/webplugin_delegate.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 WEBKIT_GLUE_WEBPLUGIN_DELEGATE_H__
+#define WEBKIT_GLUE_WEBPLUGIN_DELEGATE_H__
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/gfx/rect.h"
+#include "bindings/npapi.h"
+
+typedef struct HDC__* HDC;
+
+class GURL;
+class WebPlugin;
+struct NPObject;
+class WebCursor;
+class WebPluginResourceClient;
+// This is the interface that a plugin implementation needs to provide.
+class WebPluginDelegate {
+ public:
+ WebPluginDelegate() {}
+
+ // Initializes the plugin implementation with the given (UTF8) arguments.
+ // Note that the lifetime of WebPlugin must be longer than this delegate.
+ // If this function returns false the plugin isn't started and shouldn't be
+ // called again. If this method succeeds, then the WebPlugin is valid until
+ // PluginDestroyed is called.
+ // The load_manually parameter if true indicates that the plugin data would
+ // be passed from webkit. if false indicates that the plugin should download
+ // the data. This also controls whether the plugin is instantiated as a full
+ // page plugin (NP_FULL) or embedded (NP_EMBED)
+ virtual bool Initialize(const GURL& url, char** argn, char** argv,
+ int argc, WebPlugin* plugin, bool load_manually) = 0;
+
+ // Called when the WebPlugin is being destroyed. This is a signal to the
+ // delegate that it should tear-down the plugin implementation and not call
+ // methods on the WebPlugin again.
+ virtual void PluginDestroyed() = 0;
+
+ // Update the geometry of the plugin. This is a request to move the plugin,
+ // relative to its containing window, to the coords given by window_rect.
+ // Its contents should be clipped to the coords given by clip_rect, which are
+ // relative to the origin of the plugin window.
+ virtual void UpdateGeometry(const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect, bool visible) = 0;
+
+ // Tells the plugin to paint the damaged rect. The HDC is only used for
+ // windowless plugins.
+ virtual void Paint(HDC hdc, const gfx::Rect& rect) = 0;
+
+ // Tells the plugin to print itself.
+ virtual void Print(HDC hdc) = 0;
+
+ // Informs the plugin that it now has focus.
+ virtual void SetFocus() = 0;
+
+ // For windowless plugins, gives them a user event like mouse/keyboard.
+ // Returns whether the event was handled.
+ virtual bool HandleEvent(NPEvent* event, WebCursor* cursor) = 0;
+
+ // Gets the NPObject associated with the plugin for scripting.
+ virtual NPObject* GetPluginScriptableObject() = 0;
+
+ // Receives notification about a resource load that the plugin initiated
+ // for a frame.
+ virtual void DidFinishLoadWithReason(NPReason reason) = 0;
+
+ // Returns the process id of the process that is running the plugin.
+ virtual int GetProcessId() = 0;
+
+ // Returns the window handle for this plugin if it's a windowed plugin,
+ // or NULL otherwise.
+ virtual HWND GetWindowHandle() = 0;
+
+ virtual void FlushGeometryUpdates() = 0;
+
+ // The result of the script execution is returned via this function.
+ virtual void SendJavaScriptStream(const std::string& url,
+ const std::wstring& result,
+ bool success, bool notify_needed,
+ int notify_data) = 0;
+
+ // Receives notification about data being available.
+ virtual void DidReceiveManualResponse(const std::string& url,
+ const std::string& mime_type,
+ const std::string& headers,
+ uint32 expected_length,
+ uint32 last_modified) = 0;
+
+ // Receives the data.
+ virtual void DidReceiveManualData(const char* buffer, int length) = 0;
+
+ // Indicates end of data load.
+ virtual void DidFinishManualLoading() = 0;
+
+ // Indicates a failure in data receipt.
+ virtual void DidManualLoadFail() = 0;
+
+ // Only Available after Initialize is called.
+ virtual std::wstring GetPluginPath() = 0;
+
+ // Only Supported when the plugin is the default plugin.
+ virtual void InstallMissingPlugin() = 0;
+
+ // Creates a WebPluginResourceClient instance and returns the same.
+ virtual WebPluginResourceClient* CreateResourceClient(int resource_id,
+ const std::string &url,
+ bool notify_needed,
+ void *notify_data) = 0;
+ // Notifies the delegate about a Get/Post URL request getting routed
+ virtual void URLRequestRouted(const std::string&url, bool notify_needed,
+ void* notify_data) = 0;
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(WebPluginDelegate);
+};
+
+#endif // #ifndef WEBKIT_GLUE_WEBPLUGIN_DELEGATE_H__
diff --git a/webkit/glue/webplugin_impl.cc b/webkit/glue/webplugin_impl.cc
new file mode 100644
index 0000000..421c91f
--- /dev/null
+++ b/webkit/glue/webplugin_impl.cc
@@ -0,0 +1,1059 @@
+// 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 "config.h"
+
+#pragma warning(push, 0)
+#include "Document.h"
+#include "Element.h"
+#include "Event.h"
+#include "EventNames.h"
+#include "FormData.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameLoadRequest.h"
+#include "FrameTree.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HTMLPluginElement.h"
+#include "IntRect.h"
+#include "KURL.h"
+#include "KeyboardEvent.h"
+#include "MouseEvent.h"
+#include "Page.h"
+#include "PlatformMouseEvent.h"
+#include "PlatformString.h"
+#include "ResourceHandle.h"
+#include "ResourceHandleClient.h"
+#include "ResourceResponse.h"
+#include "ScrollView.h"
+#include "Widget.h"
+#pragma warning(pop)
+#undef LOG
+
+#include "base/gfx/rect.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/string_util.h"
+#include "net/base/escape.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/webplugin_impl.h"
+#include "webkit/glue/plugins/plugin_host.h"
+#include "webkit/glue/plugins/plugin_instance.h"
+#include "webkit/glue/webview_impl.h"
+#include "googleurl/src/gurl.h"
+#include "webkit/port/platform/cursor.h"
+
+WebPluginContainer::WebPluginContainer(WebPluginImpl* impl) : impl_(impl) { }
+
+WebPluginContainer::~WebPluginContainer() {
+ impl_->SetContainer(NULL);
+ MessageLoop::current()->DeleteSoon(FROM_HERE, impl_);
+}
+
+NPObject* WebPluginContainer::GetPluginScriptableObject() {
+ return impl_->GetPluginScriptableObject();
+}
+
+WebCore::IntRect WebPluginContainer::windowClipRect() const {
+ return impl_->windowClipRect();
+}
+
+void WebPluginContainer::geometryChanged() const {
+ impl_->geometryChanged();
+}
+
+void WebPluginContainer::setFrameGeometry(const WebCore::IntRect& rect) {
+ WebCore::Widget::setFrameGeometry(rect);
+ impl_->setFrameGeometry(rect);
+}
+
+void WebPluginContainer::paint(WebCore::GraphicsContext* gc,
+ const WebCore::IntRect& damage_rect) {
+ // In theory, we should call impl_->print(gc); when
+ // impl_->webframe_->printing() is true but it still has placement issues so
+ // keep that code off for now.
+ impl_->paint(gc, damage_rect);
+}
+
+void WebPluginContainer::setFocus() {
+ WebCore::Widget::setFocus();
+ impl_->setFocus();
+}
+
+void WebPluginContainer::show() {
+ // We don't want to force a geometry update when the plugin widget is
+ // already visible as this involves a geometry update which may lead
+ // to unnecessary window moves in the plugin process. The only case
+ // where this does not apply is if the force_geometry_update_ flag
+ // is set, which occurs when a plugin is created and does not have
+ // a parent. We can send out geometry updates only when the plugin
+ // widget has a parent.
+ if (!impl_->visible_ || impl_->force_geometry_update_) {
+ impl_->show();
+ WebCore::Widget::show();
+ // This is to force an updategeometry call to the plugin process
+ // where the plugin window can be hidden or shown.
+ geometryChanged();
+ }
+}
+
+void WebPluginContainer::hide() {
+ // Please refer to WebPluginContainer::show for the reasoning behind
+ // the if check below.
+ if (impl_->visible_ || impl_->force_geometry_update_) {
+ impl_->hide();
+ WebCore::Widget::hide();
+ // This is to force an updategeometry call to the plugin process
+ // where the plugin window can be hidden or shown.
+ geometryChanged();
+ }
+}
+
+void WebPluginContainer::handleEvent(WebCore::Event* event) {
+ impl_->handleEvent(event);
+}
+
+void WebPluginContainer::attachToWindow() {
+ Widget::attachToWindow();
+ show();
+}
+
+void WebPluginContainer::detachFromWindow() {
+ Widget::detachFromWindow();
+ hide();
+}
+
+void WebPluginContainer::didReceiveResponse(
+ const WebCore::ResourceResponse& response) {
+
+ std::wstring url = webkit_glue::StringToStdWString(response.url().string());
+ std::string ascii_url = WideToASCII(url);
+
+ std::wstring mime_type(webkit_glue::StringToStdWString(response.mimeType()));
+
+ uint32 last_modified = static_cast<uint32>(response.lastModifiedDate());
+ uint32 expected_length =
+ static_cast<uint32>(response.expectedContentLength());
+ WebCore::String content_encoding =
+ response.httpHeaderField("Content-Encoding");
+ if (!content_encoding.isNull() && content_encoding != "identity") {
+ // Don't send the compressed content length to the plugin, which only
+ // cares about the decoded length.
+ expected_length = 0;
+ }
+
+ impl_->delegate_->DidReceiveManualResponse(
+ ascii_url, WideToNativeMB(mime_type),
+ WideToNativeMB(impl_->GetAllHeaders(response)),
+ expected_length, last_modified);
+}
+
+void WebPluginContainer::didReceiveData(const char *buffer, int length) {
+ impl_->delegate_->DidReceiveManualData(buffer, length);
+}
+
+void WebPluginContainer::didFinishLoading() {
+ impl_->delegate_->DidFinishManualLoading();
+}
+
+void WebPluginContainer::didFail(const WebCore::ResourceError&) {
+ impl_->delegate_->DidManualLoadFail();
+}
+
+WebCore::Widget* WebPluginImpl::Create(const GURL& url,
+ char** argn,
+ char** argv,
+ int argc,
+ WebCore::Element *element,
+ WebFrameImpl *frame,
+ WebPluginDelegate* delegate,
+ bool load_manually) {
+ WebPluginImpl* webplugin = new WebPluginImpl(element, frame, delegate);
+
+ if (!delegate->Initialize(url, argn, argv, argc, webplugin, load_manually)) {
+ delegate->PluginDestroyed();
+ delegate = NULL;
+ delete webplugin;
+ return NULL;
+ }
+
+ WebPluginContainer* container = new WebPluginContainer(webplugin);
+ webplugin->SetContainer(container);
+ return container;
+}
+
+WebPluginImpl::WebPluginImpl(WebCore::Element* element,
+ WebFrameImpl* webframe,
+ WebPluginDelegate* delegate)
+ : element_(element),
+ webframe_(webframe),
+ delegate_(delegate),
+ windowless_(false),
+ window_(NULL),
+ force_geometry_update_(false),
+ visible_(false),
+ widget_(NULL),
+ received_first_paint_notification_(false) {
+}
+
+WebPluginImpl::~WebPluginImpl() {
+}
+
+void WebPluginImpl::SetWindow(HWND window, HANDLE pump_messages_event) {
+ if (window) {
+ DCHECK(!windowless_); // Make sure not called twice.
+ window_ = window;
+ } else {
+ DCHECK(!window_); // Make sure not called twice.
+ windowless_ = true;
+ }
+}
+
+bool WebPluginImpl::CompleteURL(const std::string& url_in,
+ std::string* url_out) {
+ if (!frame() || !frame()->document()) {
+ NOTREACHED();
+ return false;
+ }
+
+ WebCore::String str(webkit_glue::StdStringToString(url_in));
+ WebCore::String url = frame()->document()->completeURL(str);
+ std::wstring wurl = webkit_glue::StringToStdWString(url);
+ *url_out = WideToUTF8(wurl);
+ return true;
+}
+
+bool WebPluginImpl::ExecuteScript(const std::string& url,
+ const std::wstring& script,
+ bool notify_needed,
+ int notify_data,
+ bool popups_allowed) {
+ // This could happen if the WebPluginContainer was already deleted.
+ if (!frame())
+ return false;
+
+ // Pending resource fetches should also not trigger a callback.
+ webframe_->set_plugin_delegate(NULL);
+
+ WebCore::String script_str(webkit_glue::StdWStringToString(script));
+
+ // Note: the call to executeScript might result in the frame being
+ // deleted, so add an extra reference to it in this scope.
+ // For KJS, keeping a pointer to the JSBridge is enough, but for V8
+ // we also need to addref the frame.
+ WTF::RefPtr<WebCore::Frame> cur_frame(frame());
+ WebCore::JSBridge* bridge = cur_frame->scriptBridge();
+
+ bool succ = false;
+ WebCore::String result_str = frame()->loader()->executeScript(script_str,
+ &succ,
+ popups_allowed);
+ std::wstring result;
+ if (succ)
+ result = webkit_glue::StringToStdWString(result_str);
+
+ // delegate_ could be NULL because executeScript caused the container to be
+ // deleted.
+ if (delegate_)
+ delegate_->SendJavaScriptStream(url, result, succ, notify_needed,
+ notify_data);
+
+ return succ;
+}
+
+void WebPluginImpl::CancelResource(int id) {
+ for (size_t i = 0; i < clients_.size(); ++i) {
+ if (clients_[i].id == id) {
+ if (clients_[i].handle) {
+ clients_[i].handle->cancel();
+ RemoveClient(i);
+ }
+
+ return;
+ }
+ }
+}
+
+bool WebPluginImpl::SetPostData(WebCore::ResourceRequest* request,
+ const char *buf,
+ uint32 length) {
+ std::vector<std::string> names;
+ std::vector<std::string> values;
+ std::vector<char> body;
+ bool rv = NPAPI::PluginHost::SetPostData(buf, length, &names, &values, &body);
+
+ for (size_t i = 0; i < names.size(); ++i)
+ request->addHTTPHeaderField(webkit_glue::StdStringToString(names[i]),
+ webkit_glue::StdStringToString(values[i]));
+
+ WebCore::FormData *data = new WebCore::FormData();
+ if (body.size())
+ data->appendData(&body.front(), body.size());
+
+ request->setHTTPBody(data); // request refcounts FormData
+
+ return rv;
+}
+
+RoutingStatus WebPluginImpl::RouteToFrame(const char *method,
+ bool is_javascript_url,
+ const char* target, unsigned int len,
+ const char* buf, bool is_file_data,
+ bool notify, const char* url,
+ GURL* completeURL) {
+ // If there is no target, there is nothing to do
+ if (!target)
+ return NOT_ROUTED;
+
+ // This could happen if the WebPluginContainer was already deleted.
+ if (!frame())
+ return NOT_ROUTED;
+
+ // Take special action for javascript URLs
+ WebCore::DeprecatedString str_target = target;
+ if (is_javascript_url) {
+ WebCore::Frame *frameTarget = frame()->tree()->find(str_target);
+ // For security reasons, do not allow javascript on frames
+ // other than this frame.
+ if (frameTarget != frame()) {
+ // FIXME - might be good to log this into a security
+ // log somewhere.
+ return ROUTED;
+ }
+
+ // Route javascript calls back to the plugin.
+ return NOT_ROUTED;
+ }
+
+ // If we got this far, we're routing content to a target frame.
+ // Go fetch the URL.
+
+ WebCore::String complete_url_str = frame()->document()->completeURL(
+ WebCore::String(url));
+
+ WebCore::KURL complete_url_kurl(complete_url_str.deprecatedString());
+
+ if (strcmp(method, "GET") != 0) {
+ const WebCore::DeprecatedString& protocol_scheme =
+ complete_url_kurl.protocol();
+ // We're only going to route HTTP/HTTPS requests
+ if ((protocol_scheme != "http") && (protocol_scheme != "https"))
+ return INVALID_URL;
+ }
+
+ // url.deprecatedString());
+ *completeURL = webkit_glue::KURLToGURL(complete_url_kurl);
+ WebCore::ResourceRequest request(complete_url_kurl);
+ request.setHTTPMethod(method);
+ if (len > 0) {
+ if (!is_file_data) {
+ if (!SetPostData(&request, buf, len)) {
+ // Uhoh - we're in trouble. There isn't a good way
+ // to recover at this point. Break out.
+ ASSERT_NOT_REACHED();
+ return ROUTED;
+ }
+ } else {
+ // TODO: Support "file" mode. For now, just break out
+ // since proceeding may do something unintentional.
+ ASSERT_NOT_REACHED();
+ return ROUTED;
+ }
+ }
+ WebCore::FrameLoadRequest load_request(request);
+ load_request.setFrameName(str_target);
+ WebCore::FrameLoader *loader = frame()->loader();
+ // we actually don't know whether usergesture is true or false,
+ // passing true since all we can do is assume it is okay.
+ loader->load(load_request,
+ false, // lock history
+ true, // user gesture
+ 0, // event
+ 0, // form element
+ HashMap<WebCore::String, WebCore::String>());
+
+ // load() can cause the frame to go away.
+ if (webframe_) {
+ WebPluginDelegate* last_plugin = webframe_->plugin_delegate();
+ if (last_plugin) {
+ last_plugin->DidFinishLoadWithReason(NPRES_USER_BREAK);
+ webframe_->set_plugin_delegate(NULL);
+ }
+
+ if (notify)
+ webframe_->set_plugin_delegate(delegate_);
+ }
+
+ return ROUTED;
+}
+
+NPObject* WebPluginImpl::GetWindowScriptNPObject() {
+ if (!frame()) {
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+
+ return frame()->windowScriptNPObject();
+}
+
+NPObject* WebPluginImpl::GetPluginElement() {
+ // We don't really know that this is a
+ // HTMLPluginElement. Cast to it and hope?
+ WebCore::HTMLPlugInElement *plugin_element =
+ static_cast<WebCore::HTMLPlugInElement*>(element_);
+ return plugin_element->getNPObject();
+}
+
+void WebPluginImpl::SetCookie(const GURL& url,
+ const GURL& policy_url,
+ const std::string& cookie) {
+ webkit_glue::SetCookie(url, policy_url, cookie);
+}
+
+std::string WebPluginImpl::GetCookies(const GURL& url, const GURL& policy_url) {
+ return webkit_glue::GetCookies(url, policy_url);
+}
+
+void WebPluginImpl::ShowModalHTMLDialog(const GURL& url, int width, int height,
+ const std::string& json_arguments,
+ std::string* json_retval) {
+ // TODO(mpcomplete): Figure out how to call out to the RenderView and
+ // implement this. Though, this is never called atm - only the out-of-process
+ // version is used.
+ NOTREACHED();
+}
+
+void WebPluginImpl::OnMissingPluginStatus(int status) {
+ NOTREACHED();
+}
+
+void WebPluginImpl::Invalidate() {
+ if (widget_)
+ widget_->invalidate();
+}
+
+void WebPluginImpl::InvalidateRect(const gfx::Rect& rect) {
+ if (widget_)
+ widget_->invalidateRect(WebCore::IntRect(rect.ToRECT()));
+}
+
+WebCore::IntRect WebPluginImpl::windowClipRect() const {
+ // This is based on the code in WebCore/plugins/win/PluginViewWin.cpp:
+ WebCore::IntRect rect(0, 0, widget_->width(), widget_->height());
+
+ // Start by clipping to our bounds.
+ WebCore::IntRect clip_rect = widget_->convertToContainingWindow(
+ WebCore::IntRect(0, 0, widget_->width(), widget_->height()));
+
+ // Take our element and get the clip rect from the enclosing layer and
+ // frame view.
+ WebCore::RenderLayer* layer = element_->renderer()->enclosingLayer();
+
+ // document()->renderer() can be NULL when we receive messages from the
+ // plugins while we are destroying a frame.
+ if (element_->renderer()->document()->renderer()) {
+ WebCore::FrameView* parent_view = element_->document()->view();
+ clip_rect.intersect(parent_view->windowClipRectForLayer(layer, true));
+ }
+
+ return clip_rect;
+}
+
+void WebPluginImpl::geometryChanged() const {
+ if (!widget_)
+ return;
+
+ // This is a hack to tickle re-positioning of the plugin in the case where
+ // our parent view was scrolled.
+ const_cast<WebPluginImpl*>(this)->widget_->setFrameGeometry(
+ widget_->frameGeometry());
+ }
+
+void WebPluginImpl::setFrameGeometry(const WebCore::IntRect& rect) {
+ // Compute a new position and clip rect for ourselves relative to the
+ // containing window. We ask our delegate to reposition us accordingly.
+
+ // When the plugin is loaded we don't have a parent frame yet. We need
+ // to force the plugin window to get created in the plugin process,
+ // when the plugin widget position is updated. This occurs just after
+ // the plugin is loaded (See http://b/issue?id=892174).
+ if (!parent()) {
+ force_geometry_update_ = true;
+ return;
+ }
+
+ WebCore::Frame* frame = element_->document()->frame();
+ WebFrameImpl* webframe = WebFrameImpl::FromFrame(frame);
+ WebViewImpl* webview = webframe->webview_impl();
+ // It is valid for this function to be invoked in code paths where the
+ // the webview is closed.
+ if (!webview->delegate()) {
+ return;
+ }
+
+ WebCore::IntRect window_rect;
+ WebCore::IntRect clip_rect;
+ CalculateBounds(rect, &window_rect, &clip_rect);
+
+ if (window_ && received_first_paint_notification_) {
+ // Let the WebViewDelegate know that the plugin window needs to be moved,
+ // so that all the HWNDs are moved together.
+ WebPluginGeometry move;
+ move.window = window_;
+ move.window_rect = gfx::Rect(window_rect);
+ move.clip_rect = gfx::Rect(clip_rect);
+ move.visible = visible_;
+ webview->delegate()->DidMove(webview, move);
+ }
+
+ delegate_->UpdateGeometry(
+ gfx::Rect(window_rect), gfx::Rect(clip_rect),
+ received_first_paint_notification_? visible_ : false);
+
+ // delegate_ can go away as a result of above call, so check it first.
+ if (force_geometry_update_ && delegate_) {
+ force_geometry_update_ = false;
+ delegate_->FlushGeometryUpdates();
+ }
+}
+
+void WebPluginImpl::paint(WebCore::GraphicsContext* gc,
+ const WebCore::IntRect& damage_rect) {
+ if (gc->paintingDisabled())
+ return;
+
+ if (!parent())
+ return;
+
+ // Don't paint anything if the plugin doesn't intersect the damage rect.
+ if (!widget_->frameGeometry().intersects(damage_rect))
+ return;
+
+ // A windowed plugin starts out by being invisible regardless of the style
+ // which webkit tells us. The paint notification from webkit indicates that
+ // the plugin widget is being shown and we need to make sure that
+ // it becomes visible.
+ // Please refer to https://bugs.webkit.org/show_bug.cgi?id=18901 for more
+ // details on this issue.
+ // TODO(iyengar): Remove this hack when this issue is fixed in webkit.
+ if (!received_first_paint_notification_) {
+ received_first_paint_notification_ = true;
+
+ if (!windowless_) {
+ WebCore::IntRect window_rect;
+ WebCore::IntRect clip_rect;
+
+ CalculateBounds(widget_->frameGeometry(), &window_rect, &clip_rect);
+
+ delegate_->UpdateGeometry(gfx::Rect(window_rect), gfx::Rect(clip_rect),
+ visible_);
+ delegate_->FlushGeometryUpdates();
+ }
+ }
+
+ gc->save();
+
+ DCHECK(parent()->isFrameView());
+ WebCore::FrameView* view = static_cast<WebCore::FrameView*>(parent());
+
+ // The plugin is positioned in window coordinates, so it needs to be painted
+ // in window coordinates.
+ WebCore::IntPoint origin = view->windowToContents(WebCore::IntPoint(0, 0));
+ gc->translate(static_cast<float>(origin.x()),
+ static_cast<float>(origin.y()));
+
+ // HDC is only used when in windowless mode.
+ HDC hdc = gc->getWindowsContext();
+
+ WebCore::IntRect window_rect =
+ WebCore::IntRect(view->contentsToWindow(damage_rect.location()),
+ damage_rect.size());
+
+ delegate_->Paint(hdc, gfx::Rect(window_rect));
+
+ gc->releaseWindowsContext(hdc);
+ gc->restore();
+}
+
+void WebPluginImpl::print(WebCore::GraphicsContext* gc) {
+ if (gc->paintingDisabled())
+ return;
+
+ if (!parent())
+ return;
+
+ gc->save();
+ HDC hdc = gc->getWindowsContext();
+ delegate_->Print(hdc);
+ gc->releaseWindowsContext(hdc);
+ gc->restore();
+}
+
+void WebPluginImpl::setFocus() {
+ if (windowless_)
+ delegate_->SetFocus();
+}
+
+void WebPluginImpl::show() {
+ visible_ = true;
+}
+
+void WebPluginImpl::hide() {
+ visible_ = false;
+}
+
+void WebPluginImpl::handleEvent(WebCore::Event* event) {
+ if (!windowless_)
+ return;
+
+ // Pass events to the plugin.
+ // The events we pass are defined at:
+ // http://devedge-temp.mozilla.org/library/manuals/2002/plugin/1.0/structures5.html#1000000
+ // Don't take the documentation as truth, however. I've found
+ // many cases where mozilla behaves differently than the spec.
+ if (event->isMouseEvent())
+ handleMouseEvent(static_cast<WebCore::MouseEvent*>(event));
+ else if (event->isKeyboardEvent())
+ handleKeyboardEvent(static_cast<WebCore::KeyboardEvent*>(event));
+}
+
+void WebPluginImpl::handleMouseEvent(WebCore::MouseEvent* event) {
+ DCHECK(parent()->isFrameView());
+ WebCore::IntPoint p =
+ static_cast<WebCore::FrameView*>(parent())->contentsToWindow(
+ WebCore::IntPoint(event->pageX(), event->pageY()));
+ NPEvent np_event;
+ np_event.lParam = static_cast<uint32>(MAKELPARAM(p.x(), p.y()));
+ np_event.wParam = 0;
+
+ if (event->ctrlKey())
+ np_event.wParam |= MK_CONTROL;
+ if (event->shiftKey())
+ np_event.wParam |= MK_SHIFT;
+
+ if ((event->type() == WebCore::EventNames::mousemoveEvent) ||
+ (event->type() == WebCore::EventNames::mouseoutEvent) ||
+ (event->type() == WebCore::EventNames::mouseoverEvent)) {
+ np_event.event = WM_MOUSEMOVE;
+ if (event->buttonDown()) {
+ switch (event->button()) {
+ case WebCore::LeftButton:
+ np_event.wParam |= MK_LBUTTON;
+ break;
+ case WebCore::MiddleButton:
+ np_event.wParam |= MK_MBUTTON;
+ break;
+ case WebCore::RightButton:
+ np_event.wParam |= MK_RBUTTON;
+ break;
+ }
+ }
+ } else if (event->type() == WebCore::EventNames::mousedownEvent) {
+ // Ensure that the frame containing the plugin has focus.
+ WebCore::Frame* containing_frame = webframe_->frame();
+ if (WebCore::Page* current_page = containing_frame->page()) {
+ current_page->focusController()->setFocusedFrame(containing_frame);
+ }
+ // Give focus to our containing HTMLPluginElement.
+ containing_frame->document()->setFocusedNode(element_);
+
+ // Ideally we'd translate to WM_xBUTTONDBLCLK here if the click count were
+ // a multiple of 2. But there seems to be no way to get at the click count
+ // or the original Windows message from the WebCore::Event.
+ switch (event->button()) {
+ case WebCore::LeftButton:
+ np_event.event = WM_LBUTTONDOWN;
+ np_event.wParam |= MK_LBUTTON;
+ break;
+ case WebCore::MiddleButton:
+ np_event.event = WM_MBUTTONDOWN;
+ np_event.wParam |= MK_MBUTTON;
+ break;
+ case WebCore::RightButton:
+ np_event.event = WM_RBUTTONDOWN;
+ np_event.wParam |= MK_RBUTTON;
+ break;
+ }
+ } else if (event->type() == WebCore::EventNames::mouseupEvent) {
+ switch (event->button()) {
+ case WebCore::LeftButton:
+ np_event.event = WM_LBUTTONUP;
+ break;
+ case WebCore::MiddleButton:
+ np_event.event = WM_MBUTTONUP;
+ break;
+ case WebCore::RightButton:
+ np_event.event = WM_RBUTTONUP;
+ break;
+ }
+ } else {
+ // Skip all other mouse events.
+ return;
+ }
+
+ // TODO(pkasting): http://b/1119691 This conditional seems exactly backwards,
+ // but it matches Safari's code, and if I reverse it, giving focus to a
+ // transparent (windowless) plugin fails.
+ WebCursor current_web_cursor;
+ if (!delegate_->HandleEvent(&np_event, &current_web_cursor))
+ event->setDefaultHandled();
+ // A windowless plugin can change the cursor in response to the WM_MOUSEMOVE
+ // event. We need to reflect the changed cursor in the frame view as the
+ // the mouse is moved in the boundaries of the windowless plugin.
+ parent()->setCursor(current_web_cursor);
+}
+
+void WebPluginImpl::handleKeyboardEvent(WebCore::KeyboardEvent* event) {
+ NPEvent np_event;
+ np_event.wParam = event->keyCode();
+
+ if (event->type() == WebCore::EventNames::keydownEvent) {
+ np_event.event = WM_KEYDOWN;
+ np_event.lParam = 0;
+ } else if (event->type() == WebCore::EventNames::keyupEvent) {
+ np_event.event = WM_KEYUP;
+ np_event.lParam = 0x8000;
+ } else {
+ // Skip all other keyboard events.
+ return;
+ }
+
+ // TODO(pkasting): http://b/1119691 See above.
+ WebCursor current_web_cursor;
+ if (!delegate_->HandleEvent(&np_event, &current_web_cursor))
+ event->setDefaultHandled();
+}
+
+NPObject* WebPluginImpl::GetPluginScriptableObject() {
+ return delegate_->GetPluginScriptableObject();
+}
+
+WebPluginResourceClient* WebPluginImpl::GetClientFromHandle(
+ WebCore::ResourceHandle* handle) {
+ for (size_t i = 0; i < clients_.size(); ++i) {
+ if (clients_[i].handle.get() == handle)
+ return clients_[i].client;
+ }
+
+ NOTREACHED();
+ return 0;
+}
+
+
+void WebPluginImpl::willSendRequest(WebCore::ResourceHandle* handle,
+ WebCore::ResourceRequest& request,
+ const WebCore::ResourceResponse&) {
+ WebPluginResourceClient* client = GetClientFromHandle(handle);
+ if (client) {
+ GURL gurl(webkit_glue::KURLToGURL(request.url()));
+ client->WillSendRequest(gurl);
+ }
+}
+
+std::wstring WebPluginImpl::GetAllHeaders(
+ const WebCore::ResourceResponse& response) {
+ std::wstring result;
+ const WebCore::String& status = response.httpStatusText();
+ if (status.isEmpty())
+ return result;
+
+ result.append(L"HTTP ");
+ result.append(FormatNumber(response.httpStatusCode()));
+ result.append(L" ");
+ result.append(status.characters(), status.length());
+ result.append(L"\n");
+
+ WebCore::HTTPHeaderMap::const_iterator it =
+ response.httpHeaderFields().begin();
+ for (; it != response.httpHeaderFields().end(); ++it) {
+ if (!it->first.isEmpty() && !it->second.isEmpty()) {
+ result.append(std::wstring(it->first.characters(), it->first.length()));
+ result.append(L": ");
+ result.append(std::wstring(it->second.characters(), it->second.length()));
+ result.append(L"\n");
+ }
+ }
+
+ return result;
+}
+
+void WebPluginImpl::didReceiveResponse(WebCore::ResourceHandle* handle,
+ const WebCore::ResourceResponse& response) {
+ WebPluginResourceClient* client = GetClientFromHandle(handle);
+ if (!client)
+ return;
+
+ bool cancel = false;
+ std::wstring mime_type(webkit_glue::StringToStdWString(response.mimeType()));
+
+ uint32 last_modified = static_cast<uint32>(response.lastModifiedDate());
+ uint32 expected_length =
+ static_cast<uint32>(response.expectedContentLength());
+ WebCore::String content_encoding =
+ response.httpHeaderField("Content-Encoding");
+ if (!content_encoding.isNull() && content_encoding != "identity") {
+ // Don't send the compressed content length to the plugin, which only
+ // cares about the decoded length.
+ expected_length = 0;
+ }
+
+ client->DidReceiveResponse(WideToNativeMB(mime_type),
+ WideToNativeMB(GetAllHeaders(response)),
+ expected_length,
+ last_modified,
+ &cancel);
+ if (cancel) {
+ handle->cancel();
+ RemoveClient(handle);
+ return;
+ }
+
+ // Bug http://b/issue?id=925559. The flash plugin would not handle the HTTP
+ // error codes in the stream header and as a result, was unaware of the
+ // fate of the HTTP requests issued via NPN_GetURLNotify. Webkit and FF
+ // destroy the stream and invoke the NPP_DestroyStream function on the
+ // plugin if the HTTP request fails.
+ const WebCore::DeprecatedString& protocol_scheme =
+ response.url().protocol();
+ if ((protocol_scheme == "http") || (protocol_scheme == "https")) {
+ if (response.httpStatusCode() < 100 || response.httpStatusCode() >= 400) {
+ // The plugin instance could be in the process of deletion here.
+ // Verify if the WebPluginResourceClient instance still exists before
+ // use.
+ WebPluginResourceClient* resource_client = GetClientFromHandle(handle);
+ if (resource_client) {
+ handle->cancel();
+ resource_client->DidFail();
+ RemoveClient(handle);
+ }
+ }
+ }
+}
+
+void WebPluginImpl::didReceiveData(WebCore::ResourceHandle* handle,
+ const char *buffer,
+ int length, int) {
+ WebPluginResourceClient* client = GetClientFromHandle(handle);
+ if (client)
+ client->DidReceiveData(buffer, length);
+}
+
+void WebPluginImpl::didFinishLoading(WebCore::ResourceHandle* handle) {
+ WebPluginResourceClient* client = GetClientFromHandle(handle);
+ if (client)
+ client->DidFinishLoading();
+
+ RemoveClient(handle);
+}
+
+void WebPluginImpl::didFail(WebCore::ResourceHandle* handle,
+ const WebCore::ResourceError&) {
+ WebPluginResourceClient* client = GetClientFromHandle(handle);
+ if (client)
+ client->DidFail();
+
+ RemoveClient(handle);
+}
+
+void WebPluginImpl::RemoveClient(size_t i) {
+ clients_.erase(clients_.begin() + i);
+}
+
+void WebPluginImpl::RemoveClient(WebCore::ResourceHandle* handle) {
+ for (size_t i = 0; i < clients_.size(); ++i) {
+ if (clients_[i].handle.get() == handle) {
+ RemoveClient(i);
+ return;
+ }
+ }
+}
+
+void WebPluginImpl::SetContainer(WebPluginContainer* container) {
+ if (container == NULL) {
+ // The frame maintains a list of JSObjects which are related to this
+ // plugin. Tell the frame we're gone so that it can invalidate all
+ // of those sub JSObjects.
+ if (frame()) {
+ ASSERT(widget_ != NULL);
+ frame()->cleanupScriptObjectsForPlugin(widget_);
+ }
+
+ // Call PluginDestroyed() first to prevent the plugin from calling us back
+ // in the middle of tearing down the render tree.
+ delegate_->PluginDestroyed();
+ delegate_ = NULL;
+
+ // Cancel any pending requests because otherwise this deleted object will be
+ // called by the ResourceDispatcher.
+ int int_offset = 0;
+ while (!clients_.empty()) {
+ if (clients_[int_offset].handle)
+ clients_[int_offset].handle->cancel();
+ WebPluginResourceClient* resource_client = clients_[int_offset].client;
+ RemoveClient(int_offset);
+ if (resource_client)
+ resource_client->DidFail();
+ }
+
+ // This needs to be called now and not in the destructor since the
+ // webframe_ might not be valid anymore.
+ webframe_->set_plugin_delegate(NULL);
+ webframe_ = NULL;
+ }
+ widget_ = container;
+}
+
+WebCore::ScrollView* WebPluginImpl::parent() const {
+ if (widget_)
+ return widget_->parent();
+
+ return NULL;
+}
+
+void WebPluginImpl::CalculateBounds(const WebCore::IntRect& frame_rect,
+ WebCore::IntRect* window_rect,
+ WebCore::IntRect* clip_rect) {
+ DCHECK(parent()->isFrameView());
+ WebCore::FrameView* view = static_cast<WebCore::FrameView*>(parent());
+
+ *window_rect =
+ WebCore::IntRect(view->contentsToWindow(frame_rect.location()),
+ frame_rect.size());
+ // Calculate a clip-rect so that we don't overlap the scrollbars, etc.
+ *clip_rect = widget_->windowClipRect();
+ clip_rect->move(-window_rect->x(), -window_rect->y());
+}
+
+void WebPluginImpl::HandleURLRequest(const char *method,
+ bool is_javascript_url,
+ const char* target, unsigned int len,
+ const char* buf, bool is_file_data,
+ bool notify, const char* url,
+ void* notify_data, bool popups_allowed) {
+ // For this request, we either route the output to a frame
+ // because a target has been specified, or we handle the request
+ // here, i.e. by executing the script if it is a javascript url
+ // or by initiating a download on the URL, etc. There is one special
+ // case in that the request is a javascript url and the target is "_self",
+ // in which case we route the output to the plugin rather than routing it
+ // to the plugin's frame.
+ GURL complete_url;
+ int routing_status = RouteToFrame(method, is_javascript_url, target, len,
+ buf, is_file_data, notify, url,
+ &complete_url);
+ if (routing_status == ROUTED) {
+ // The delegate could have gone away because of this call.
+ if (delegate_)
+ delegate_->URLRequestRouted(url, notify, notify_data);
+ return;
+ }
+
+ if (is_javascript_url) {
+ std::string original_url = url;
+
+ // Convert the javascript: URL to javascript by unescaping. WebCore uses
+ // decode_string for this, so we do, too.
+ std::string escaped_script = original_url.substr(strlen("javascript:"));
+ WebCore::DeprecatedString script = WebCore::KURL::decode_string(
+ WebCore::DeprecatedString(escaped_script.data(),
+ static_cast<int>(escaped_script.length())));
+
+ ExecuteScript(original_url,
+ webkit_glue::DeprecatedStringToStdWString(script), notify,
+ reinterpret_cast<int>(notify_data), popups_allowed);
+ } else {
+ std::string complete_url_string;
+ CompleteURL(url, &complete_url_string);
+
+ int resource_id = GetNextResourceId();
+ WebPluginResourceClient* resource_client =
+ delegate_->CreateResourceClient(resource_id, complete_url_string,
+ notify, notify_data);
+
+ // If the RouteToFrame call returned a failure then inform the result
+ // back to the plugin asynchronously.
+ if ((routing_status == INVALID_URL) ||
+ (routing_status == GENERAL_FAILURE)) {
+ resource_client->DidFail();
+ return;
+ }
+
+ InitiateHTTPRequest(resource_id, resource_client, method, buf, len,
+ GURL(complete_url_string));
+ }
+}
+
+int WebPluginImpl::GetNextResourceId() {
+ static int next_id = 0;
+ return ++next_id;
+}
+
+bool WebPluginImpl::InitiateHTTPRequest(int resource_id,
+ WebPluginResourceClient* client,
+ const char* method, const char* buf,
+ int buf_len,
+ const GURL& complete_url_string) {
+ if (!client) {
+ NOTREACHED();
+ return false;
+ }
+
+ ClientInfo info;
+ info.id = resource_id;
+ info.client = client;
+ info.request.setFrame(frame());
+ info.request.setURL(webkit_glue::GURLToKURL(complete_url_string));
+ info.request.setOriginPid(delegate_->GetProcessId());
+ info.request.setResourceType(ResourceType::OBJECT);
+ info.request.setHTTPMethod(method);
+
+ const WebCore::String& referrer = frame()->loader()->outgoingReferrer();
+ if (!WebCore::FrameLoader::shouldHideReferrer(
+ complete_url_string.spec().c_str(), referrer)) {
+ info.request.setHTTPReferrer(referrer);
+ }
+
+ if (lstrcmpA(method, "POST") == 0) {
+ // Adds headers or form data to a request. This must be called before
+ // we initiate the actual request.
+ SetPostData(&info.request, buf, buf_len);
+ }
+
+ info.handle = WebCore::ResourceHandle::create(info.request, this, frame(),
+ false, false);
+ if (!info.handle) {
+ return false;
+ }
+
+ clients_.push_back(info);
+ return true;
+}
diff --git a/webkit/glue/webplugin_impl.h b/webkit/glue/webplugin_impl.h
new file mode 100644
index 0000000..dd78d53
--- /dev/null
+++ b/webkit/glue/webplugin_impl.h
@@ -0,0 +1,282 @@
+// 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 WEBKIT_GLUE_WEBPLUGIN_IMPL_H__
+#define WEBKIT_GLUE_WEBPLUGIN_IMPL_H__
+
+#include <string>
+#include <vector>
+
+#include "config.h"
+#pragma warning(push, 0)
+#include "ResourceHandleClient.h"
+#include "ResourceRequest.h"
+#include "Widget.h"
+#pragma warning(pop)
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "webkit/glue/webframe_impl.h"
+#include "webkit/glue/webplugin.h"
+#include "webkit/glue/webplugin_delegate.h"
+
+class WebFrameImpl;
+class WebPluginDelegate;
+class WebPluginImpl;
+
+namespace WebCore {
+ class DeprecatedString;
+ class Element;
+ class Event;
+ class Frame;
+ class IntRect;
+ class KeyboardEvent;
+ class KURL;
+ class MouseEvent;
+ class ResourceHandle;
+ class ResourceError;
+ class ResourceResponse;
+ class String;
+ class Widget;
+}
+
+// Implements WebCore::Widget functions that WebPluginImpl needs. This class
+// exists because it is possible for the plugin widget to be deleted at any
+// time because of a delegate javascript call. However we don't want the
+// WebPluginImpl to be deleted from under us because it could be lower in the
+// call stack.
+class WebPluginContainer : public WebCore::Widget {
+ public:
+ WebPluginContainer(WebPluginImpl* impl);
+ virtual ~WebPluginContainer();
+ NPObject* GetPluginScriptableObject();
+ virtual WebCore::IntRect windowClipRect() const;
+ virtual void geometryChanged() const;
+ virtual void setFrameGeometry(const WebCore::IntRect& rect);
+ virtual void paint(WebCore::GraphicsContext*, const WebCore::IntRect& rect);
+ virtual void setFocus();
+ virtual void show();
+ virtual void hide();
+ virtual void handleEvent(WebCore::Event* event);
+ virtual void attachToWindow();
+ virtual void detachFromWindow();
+
+ // These methods are invoked from webkit when it has data to be sent to the
+ // plugin. The plugin in this case does not initiate a download for the data.
+ void didReceiveResponse(const WebCore::ResourceResponse& response);
+ void didReceiveData(const char *buffer, int length);
+ void didFinishLoading();
+ void didFail(const WebCore::ResourceError&);
+
+ private:
+ WebPluginImpl* impl_;
+};
+
+// This is the WebKit side of the plugin implementation that forwards calls,
+// after changing out of WebCore types, to a delegate. The delegate will
+// be in a different process.
+class WebPluginImpl : public WebPlugin,
+ public WebCore::ResourceHandleClient {
+ public:
+ // Creates a WebPlugin instance, as long as the delegate's initialization
+ // succeeds. If it fails, the delegate is deleted and NULL is returned.
+ // Note that argn and argv are UTF8.
+ static WebCore::Widget* Create(const GURL& url,
+ char** argn,
+ char** argv,
+ int argc,
+ WebCore::Element* element,
+ WebFrameImpl* frame,
+ WebPluginDelegate* delegate,
+ bool load_manually);
+ virtual ~WebPluginImpl();
+
+ virtual NPObject* GetPluginScriptableObject();
+
+ // Helper function for sorting post data.
+ static bool SetPostData(WebCore::ResourceRequest* request,
+ const char *buf,
+ uint32 length);
+
+ private:
+ friend class WebPluginContainer;
+
+ WebPluginImpl(WebCore::Element *element, WebFrameImpl *frame,
+ WebPluginDelegate* delegate);
+
+ // WebPlugin implementation:
+ void SetWindow(HWND window, HANDLE pump_messages_event);
+
+ // Given a (maybe partial) url, completes using the base url.
+ bool CompleteURL(const std::string& url_in, std::string* url_out);
+
+ // Executes the script passed in. The notify_needed and notify_data arguments
+ // are passed in by the plugin process. These indicate whether the plugin
+ // expects a notification on script execution. We pass them back to the
+ // plugin as is. This avoids having to track the notification arguments
+ // in the plugin process.
+ bool ExecuteScript(const std::string& url, const std::wstring& script,
+ bool notify_needed, int notify_data, bool popups_allowed);
+
+ // Given a download request, check if we need to route the output
+ // to a frame. Returns ROUTED if the load is done and routed to
+ // a frame, NOT_ROUTED or corresponding error codes otherwise.
+ RoutingStatus RouteToFrame(const char *method, bool is_javascript_url,
+ const char* target, unsigned int len,
+ const char* buf, bool is_file_data, bool notify,
+ const char* url, GURL* completeURL);
+
+ // Cancels a pending request.
+ void CancelResource(int id);
+
+ // Returns the next avaiable resource id.
+ int GetNextResourceId();
+
+ // Initiates HTTP GET/POST requests.
+ // Returns true on success.
+ bool InitiateHTTPRequest(int resource_id, WebPluginResourceClient* client,
+ const char* method, const char* buf, int buf_len,
+ const GURL& complete_url_string);
+
+ gfx::Rect GetWindowClipRect(const gfx::Rect& rect);
+
+ NPObject* GetWindowScriptNPObject();
+ NPObject* GetPluginElement();
+
+ void SetCookie(const GURL& url,
+ const GURL& policy_url,
+ const std::string& cookie);
+ std::string GetCookies(const GURL& url,
+ const GURL& policy_url);
+
+ void ShowModalHTMLDialog(const GURL& url, int width, int height,
+ const std::string& json_arguments,
+ std::string* json_retval);
+ void OnMissingPluginStatus(int status);
+ void Invalidate();
+ void InvalidateRect(const gfx::Rect& rect);
+
+ // Widget implementation:
+ virtual WebCore::IntRect windowClipRect() const;
+ virtual void geometryChanged() const;
+
+ // Override for when our window changes size or position.
+ // Used to notify the plugin when the size or position changes.
+ virtual void setFrameGeometry(const WebCore::IntRect& rect);
+
+ // Overrides paint so we can notify the underlying widget to repaint.
+ virtual void paint(WebCore::GraphicsContext*, const WebCore::IntRect& rect);
+ virtual void print(WebCore::GraphicsContext*);
+
+ // Override setFocus so we can notify the Plugin.
+ virtual void setFocus();
+
+ // Override show and hide to be able to control the visible state of the
+ // plugin window.
+ virtual void show();
+ virtual void hide();
+
+ // Handle widget events.
+ virtual void handleEvent(WebCore::Event* event);
+ void handleMouseEvent(WebCore::MouseEvent* event);
+ void handleKeyboardEvent(WebCore::KeyboardEvent* event);
+
+ // Sets the actual Widget for the plugin.
+ void SetContainer(WebPluginContainer* container);
+
+ WebCore::ScrollView* parent() const;
+
+ // ResourceHandleClient implementation. We implement this interface in the
+ // renderer process, and then use the simple WebPluginResourceClient interface
+ // to relay the callbacks to the plugin.
+ void willSendRequest(WebCore::ResourceHandle* handle,
+ WebCore::ResourceRequest& request,
+ const WebCore::ResourceResponse&);
+
+ void didReceiveResponse(WebCore::ResourceHandle* handle,
+ const WebCore::ResourceResponse& response);
+ void didReceiveData(WebCore::ResourceHandle* handle, const char *buffer,
+ int length, int);
+ void didFinishLoading(WebCore::ResourceHandle* handle);
+ void didFail(WebCore::ResourceHandle* handle, const WebCore::ResourceError&);
+
+ // Helper function
+ WebPluginResourceClient* GetClientFromHandle(WebCore::ResourceHandle* handle);
+
+ // Helper function to remove the stored information about a resource
+ // request given its index in m_clients.
+ void RemoveClient(size_t i);
+
+ // Helper function to remove the stored information about a resource
+ // request given a handle.
+ void RemoveClient(WebCore::ResourceHandle* handle);
+
+ // Returns all the response headers in one string, including the status code.
+ std::wstring GetAllHeaders(const WebCore::ResourceResponse& response);
+
+ WebCore::Frame* frame() { return webframe_ ? webframe_->frame() : NULL; }
+
+ // Calculates the bounds of the plugin widget based on the frame rect passed in.
+ void CalculateBounds(const WebCore::IntRect& frame_rect,
+ WebCore::IntRect* window_rect,
+ WebCore::IntRect* clip_rect);
+
+ void HandleURLRequest(const char *method,
+ bool is_javascript_url,
+ const char* target, unsigned int len,
+ const char* buf, bool is_file_data,
+ bool notify, const char* url,
+ void* notify_data, bool popups_allowed);
+
+ struct ClientInfo {
+ int id;
+ WebPluginResourceClient* client;
+ WebCore::ResourceRequest request;
+ RefPtr<WebCore::ResourceHandle> handle;
+ };
+
+ std::vector<ClientInfo> clients_;
+
+ bool windowless_;
+ HWND window_;
+ WebCore::Element* element_;
+ WebFrameImpl* webframe_;
+
+ WebPluginDelegate* delegate_;
+ bool force_geometry_update_;
+ bool visible_;
+ // Set when we receive the first paint notification for the plugin widget.
+ bool received_first_paint_notification_;
+
+ WebPluginContainer* widget_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(WebPluginImpl);
+};
+
+#endif // #ifndef WEBKIT_GLUE_WEBPLUGIN_IMPL_H__
diff --git a/webkit/glue/webplugin_impl_unittest.cc b/webkit/glue/webplugin_impl_unittest.cc
new file mode 100644
index 0000000..51a9ea4
--- /dev/null
+++ b/webkit/glue/webplugin_impl_unittest.cc
@@ -0,0 +1,225 @@
+// 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 "config.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+#pragma warning(push, 0)
+#include "ResourceRequest.h"
+#include "CString.h"
+#pragma warning(pop)
+#undef LOG
+
+#include "webkit/glue/webplugin_impl.h"
+
+namespace {
+ class WebPluginImplTest : public testing::Test {
+ };
+}
+
+// These exist only to support the gTest assertion macros, and
+// shouldn't be used in normal program code.
+std::ostream& operator<<(std::ostream& out, const WebCore::String& str)
+{
+ return out << str.latin1().data();
+}
+
+// The Host functions for NPN_PostURL and NPN_PostURLNotify
+// need to parse out some HTTP headers. Make sure it works
+// with the following tests
+
+TEST(WebPluginImplTest, PostParserSimple) {
+ // Test a simple case with headers & data
+ char *ex1 = "foo: bar\nContent-length: 10\n\nabcdefghij";
+ WebCore::ResourceRequest request;
+ bool rv= WebPluginImpl::SetPostData(&request, ex1,
+ static_cast<uint32>(strlen(ex1)));
+ EXPECT_EQ(true, rv);
+ EXPECT_EQ("bar", request.httpHeaderField("foo").stripWhiteSpace());
+ EXPECT_EQ(0, request.httpHeaderField("bar").length());
+ EXPECT_EQ(0, request.httpHeaderField("Content-length").length());
+ EXPECT_EQ("abcdefghij", request.httpBody()->flattenToString());
+}
+
+TEST(WebPluginImplTest, PostParserLongHeader) {
+ // Test a simple case with long headers
+ char *ex1 = "foo: 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n\nabcdefghij";
+ WebCore::ResourceRequest request;
+ bool rv= WebPluginImpl::SetPostData(&request, ex1,
+ static_cast<uint32>(strlen(ex1)));
+ EXPECT_EQ(true, rv);
+ EXPECT_EQ(100, request.httpHeaderField("foo").stripWhiteSpace().length());
+}
+
+TEST(WebPluginImplTest, PostParserManyHeaders) {
+ // Test a simple case with long headers
+ char *ex1 = "h1:h1\nh2:h2\nh3:h3\nh4:h4\nh5:h5\nh6:h6\nh7:h7\nh8:h8\nh9:h9\nh10:h10\n\nbody";
+ WebCore::ResourceRequest request;
+ bool rv= WebPluginImpl::SetPostData(&request, ex1,
+ static_cast<uint32>(strlen(ex1)));
+ EXPECT_EQ(true, rv);
+ EXPECT_EQ("h1", request.httpHeaderField("h1").stripWhiteSpace());
+ EXPECT_EQ("h2", request.httpHeaderField("h2").stripWhiteSpace());
+ EXPECT_EQ("h3", request.httpHeaderField("h3").stripWhiteSpace());
+ EXPECT_EQ("h4", request.httpHeaderField("h4").stripWhiteSpace());
+ EXPECT_EQ("h5", request.httpHeaderField("h5").stripWhiteSpace());
+ EXPECT_EQ("h6", request.httpHeaderField("h6").stripWhiteSpace());
+ EXPECT_EQ("h7", request.httpHeaderField("h7").stripWhiteSpace());
+ EXPECT_EQ("h8", request.httpHeaderField("h8").stripWhiteSpace());
+ EXPECT_EQ("h9", request.httpHeaderField("h9").stripWhiteSpace());
+ EXPECT_EQ("h10", request.httpHeaderField("h10").stripWhiteSpace());
+ WebCore::FormData *form_data = request.httpBody();
+ WebCore::String string_data = form_data->flattenToString();
+ EXPECT_EQ(string_data, "body");
+}
+
+TEST(WebPluginImplTest, PostParserDuplicateHeaders) {
+ // Test a simple case with long headers
+ // What value gets returned doesn't really matter. It shouldn't error
+ // out.
+ char *ex1 = "h1:h1\nh1:h2\n\nbody";
+ WebCore::ResourceRequest request;
+ bool rv= WebPluginImpl::SetPostData(&request, ex1,
+ static_cast<uint32>(strlen(ex1)));
+ EXPECT_EQ(true, rv);
+}
+
+TEST(WebPluginImplTest, PostParserNoHeaders) {
+ // Test a simple case with no headers but with data
+ char *ex1 = "\nabcdefghij";
+ WebCore::ResourceRequest request;
+ bool rv= WebPluginImpl::SetPostData(&request, ex1,
+ static_cast<uint32>(strlen(ex1)));
+ EXPECT_EQ(true, rv);
+ EXPECT_EQ(0, request.httpHeaderField("foo").length());
+ EXPECT_EQ(0, request.httpHeaderField("bar").length());
+ EXPECT_EQ(0, request.httpHeaderField("Content-length").length());
+ EXPECT_EQ("abcdefghij", request.httpBody()->flattenToString());
+}
+
+TEST(WebPluginImplTest, PostParserNoBody) {
+ // Test a simple case with headers and no body
+ char *ex1 = "Foo:bar\n\n";
+ WebCore::ResourceRequest request;
+ bool rv= WebPluginImpl::SetPostData(&request, ex1,
+ static_cast<uint32>(strlen(ex1)));
+ EXPECT_EQ(true, rv);
+ EXPECT_EQ("bar", request.httpHeaderField("foo").stripWhiteSpace());
+ EXPECT_EQ(0, request.httpHeaderField("bar").length());
+ EXPECT_EQ(0, request.httpHeaderField("Content-length").length());
+ EXPECT_EQ(0, request.httpBody()->flattenToString().length());
+}
+
+TEST(WebPluginImplTest, PostParserBodyWithNewLines) {
+ // Test a simple case with headers and no body
+ char *ex1 = "Foo:bar\n\n\n\nabcdefg\n\nabcdefg";
+ WebCore::ResourceRequest request;
+ bool rv= WebPluginImpl::SetPostData(&request, ex1,
+ static_cast<uint32>(strlen(ex1)));
+ EXPECT_EQ(true, rv);
+ EXPECT_EQ(request.httpBody()->flattenToString(), "\n\nabcdefg\n\nabcdefg");
+}
+
+TEST(WebPluginImplTest, PostParserErrorNoBody) {
+ // Test an error case with headers and no body
+ char *ex1 = "Foo:bar\n";
+ WebCore::ResourceRequest request;
+ bool rv= WebPluginImpl::SetPostData(&request, ex1,
+ static_cast<uint32>(strlen(ex1)));
+ EXPECT_EQ(false, rv);
+}
+
+TEST(WebPluginImplTest, PostParserErrorEmpty) {
+ // Test an error case with an empty string
+ char *ex1 = "";
+ WebCore::ResourceRequest request;
+ bool rv= WebPluginImpl::SetPostData(&request, ex1,
+ static_cast<uint32>(strlen(ex1)));
+ EXPECT_EQ(false, rv);
+}
+
+TEST(WebPluginImplTest, PostParserEmptyName) {
+ // Test an error case with an empty header name field
+ char *ex1 = "foo:bar\n:blat\n\nbody";
+ WebCore::ResourceRequest request;
+ bool rv= WebPluginImpl::SetPostData(&request, ex1,
+ static_cast<uint32>(strlen(ex1)));
+ EXPECT_EQ(true, rv);
+ EXPECT_EQ("bar", request.httpHeaderField("foo").stripWhiteSpace());
+ EXPECT_EQ("body", request.httpBody()->flattenToString());
+}
+
+TEST(WebPluginImplTest, PostParserEmptyValue) {
+ // Test an error case with an empty value field
+ char *ex1 = "foo:bar\nbar:\n\nbody";
+ WebCore::ResourceRequest request;
+ bool rv= WebPluginImpl::SetPostData(&request, ex1,
+ static_cast<uint32>(strlen(ex1)));
+ EXPECT_EQ(true, rv);
+ EXPECT_EQ("bar", request.httpHeaderField("foo").stripWhiteSpace());
+ EXPECT_EQ(0, request.httpHeaderField("bar").length());
+ EXPECT_EQ("body", request.httpBody()->flattenToString());
+}
+
+TEST(WebPluginImplTest, PostParserCRLF) {
+ // Test an error case with an empty value field
+ char *ex1 = "foo: bar\r\nbar:\r\n\r\nbody\r\n\r\nbody2";
+ WebCore::ResourceRequest request;
+ bool rv= WebPluginImpl::SetPostData(&request, ex1,
+ static_cast<uint32>(strlen(ex1)));
+ EXPECT_EQ(true, rv);
+ EXPECT_EQ("bar", request.httpHeaderField("foo").stripWhiteSpace());
+ EXPECT_EQ(0, request.httpHeaderField("bar").length());
+ EXPECT_EQ("body\r\n\r\nbody2", request.httpBody()->flattenToString());
+}
+
+TEST(WebPluginImplTest, PostParserBodyWithBinaryData) {
+ // Test a simple case with headers and binary data.
+ char ex1[33] = "foo: bar\nContent-length: 10\n\n";
+ unsigned int binary_data = 0xFFFFFFF0;
+ memcpy(ex1 + strlen("foo: bar\nContent-length: 10\n\n"), &binary_data,
+ sizeof(binary_data));
+
+ WebCore::ResourceRequest request;
+ bool rv = WebPluginImpl::SetPostData(&request, ex1,
+ sizeof(ex1)/sizeof(ex1[0]));
+ EXPECT_EQ(true, rv);
+ EXPECT_EQ("bar", request.httpHeaderField("foo").stripWhiteSpace());
+ EXPECT_EQ(0, request.httpHeaderField("bar").length());
+ EXPECT_EQ(0, request.httpHeaderField("Content-length").length());
+
+ Vector<char> expected_data;
+ request.httpBody()->flatten(expected_data);
+
+ EXPECT_EQ(0xF0, (unsigned char)expected_data[0]);
+ EXPECT_EQ(0xFF, (unsigned char)expected_data[1]);
+ EXPECT_EQ(0xFF, (unsigned char)expected_data[2]);
+ EXPECT_EQ(0xFF, (unsigned char)expected_data[3]);
+} \ No newline at end of file
diff --git a/webkit/glue/webpreferences.h b/webkit/glue/webpreferences.h
new file mode 100644
index 0000000..21b5181
--- /dev/null
+++ b/webkit/glue/webpreferences.h
@@ -0,0 +1,103 @@
+// 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 struct for managing webkit's settings.
+//
+// Adding new values to this class probably involves updating
+// WebViewImpl::SetPreferences, common/render_messages.h, and
+// browser/profile.cc.
+
+#ifndef WEBKIT_GLUE_WEBPREFERENCES_H__
+#define WEBKIT_GLUE_WEBPREFERENCES_H__
+
+#include <string>
+#include "googleurl/src/gurl.h"
+
+struct WebPreferences {
+ std::wstring standard_font_family;
+ std::wstring fixed_font_family;
+ std::wstring serif_font_family;
+ std::wstring sans_serif_font_family;
+ std::wstring cursive_font_family;
+ std::wstring fantasy_font_family;
+ int default_font_size;
+ int default_fixed_font_size;
+ int minimum_font_size;
+ int minimum_logical_font_size;
+ std::wstring default_encoding;
+ bool javascript_enabled;
+ bool javascript_can_open_windows_automatically;
+ bool loads_images_automatically;
+ bool plugins_enabled;
+ bool dom_paste_enabled;
+ bool developer_extras_enabled;
+ bool shrinks_standalone_images_to_fit;
+ bool uses_universal_detector;
+ bool text_areas_are_resizable;
+ bool dashboard_compatibility_mode;
+ bool java_enabled;
+
+ // TODO(tc): User style sheets will not work in chrome because it tries to
+ // load the style sheet using a request without a frame.
+ bool user_style_sheet_enabled;
+ GURL user_style_sheet_location;
+
+ std::string user_agent;
+
+ // We try to keep the default values the same as the default values in
+ // chrome, except for the cases where it would require lots of extra work for
+ // the embedder to use the same default value.
+ WebPreferences()
+ : standard_font_family(L"Times New Roman"),
+ fixed_font_family(L"Courier New"),
+ serif_font_family(L"Times New Roman"),
+ sans_serif_font_family(L"Arial"),
+ cursive_font_family(L"Script"),
+ fantasy_font_family(), // Not sure what to use on Windows.
+ default_font_size(16),
+ default_fixed_font_size(13),
+ minimum_font_size(1),
+ minimum_logical_font_size(6),
+ default_encoding(L"ISO-8859-1"),
+ javascript_enabled(true),
+ javascript_can_open_windows_automatically(true),
+ loads_images_automatically(true),
+ plugins_enabled(true),
+ dom_paste_enabled(false), // enables execCommand("paste")
+ developer_extras_enabled(false), // Requires extra work by embedder
+ shrinks_standalone_images_to_fit(true),
+ uses_universal_detector(false), // Disabled: page cycler regression
+ user_style_sheet_enabled(false),
+ text_areas_are_resizable(true),
+ dashboard_compatibility_mode(false),
+ java_enabled(true) {
+ }
+};
+
+#endif // WEBKIT_GLUE_WEBPREFERENCES_H__
diff --git a/webkit/glue/webresponse.h b/webkit/glue/webresponse.h
new file mode 100644
index 0000000..e83c08b
--- /dev/null
+++ b/webkit/glue/webresponse.h
@@ -0,0 +1,57 @@
+// 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 WEBKIT_GLUE_WEBURLRESPONSE_H__
+#define WEBKIT_GLUE_WEBURLRESPONSE_H__
+
+#include <string>
+
+class GURL;
+
+class WebResponse {
+ public:
+ // Get the URL.
+ virtual GURL GetURL() const = 0;
+
+ // Get the http status code.
+ virtual int GetHttpStatusCode() const = 0;
+
+ // Returns an opaque value containing the state of the SSL connection that
+ // the resource was loaded on, or an empty string if no SSL connection was
+ // used.
+ virtual std::string GetSecurityInfo() const = 0;
+
+ WebResponse() { }
+ virtual ~WebResponse() { }
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(WebResponse);
+};
+
+#endif // #ifndef WEBKIT_GLUE_WEBURLRESPONSE_H__
diff --git a/webkit/glue/webresponse_impl.h b/webkit/glue/webresponse_impl.h
new file mode 100644
index 0000000..3e2c356
--- /dev/null
+++ b/webkit/glue/webresponse_impl.h
@@ -0,0 +1,72 @@
+// 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 WEBKIT_GLUE_WEBRESPONSEIMPL_H__
+#define WEBKIT_GLUE_WEBRESPONSEIMPL_H__
+
+#include <string>
+
+#include "googleurl/src/gurl.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/webresponse.h"
+
+#include "ResourceResponse.h"
+
+class WebResponseImpl : public WebResponse {
+ public:
+ WebResponseImpl() { }
+ explicit WebResponseImpl(const WebCore::ResourceResponse& response)
+ : response_(response) { }
+
+ virtual ~WebResponseImpl() { }
+
+ // Get the URL.
+ virtual GURL GetURL() const {
+ return webkit_glue::KURLToGURL(response_.url());
+ }
+
+ // Get the http status code.
+ virtual int GetHttpStatusCode() const { return response_.httpStatusCode(); }
+
+ // Get the security info (state of the SSL connection).
+ virtual std::string GetSecurityInfo() const {
+ return webkit_glue::CStringToStdString(response_.getSecurityInfo());
+ }
+
+ void set_resource_response(const WebCore::ResourceResponse& response) {
+ response_ = response;
+ }
+
+ private:
+ WebCore::ResourceResponse response_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(WebResponseImpl);
+};
+
+#endif // #ifndef WEBKIT_GLUE_WEBRESPONSEIMPL_H__
diff --git a/webkit/glue/webtextinput.h b/webkit/glue/webtextinput.h
new file mode 100644
index 0000000..87582ff
--- /dev/null
+++ b/webkit/glue/webtextinput.h
@@ -0,0 +1,87 @@
+// 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.
+//
+// Class WebTextInput provides text input APIs used by TextInputController
+// in test_shell. It only facilitates layout tests and should not be used
+// by renderers.
+
+#ifndef WEBKIT_GLUE_WEBTEXTINPUT_H__
+#define WEBKIT_GLUE_WEBTEXTINPUT_H__
+
+#include <string>
+#include "base/basictypes.h"
+
+class WebTextInput {
+ public:
+ WebTextInput() {}
+ virtual ~WebTextInput() {}
+
+ // Inserts text to the associated frame.
+ virtual void InsertText(std::string& text) = 0;
+
+ // Executes the given editing command on the frame.
+ virtual void DoCommand(std::string& command) = 0;
+
+ // Sets marked text region on the frame.
+ virtual void SetMarkedText(std::string& text,
+ int32_t location, int32_t length) = 0;
+
+ // Clears the marked text region on the frame.
+ virtual void UnMarkText() = 0;
+
+ // Returns true if there are marked texts on the frame, returns false
+ // otherwise.
+ virtual bool HasMarkedText() = 0;
+
+ // Writes the textual representation of the marked range on the frame to
+ // range_str.
+ virtual void MarkedRange(std::string* range_str) = 0;
+
+ // Writes the textual representation of the selected range on the frame to
+ // range_str.
+ virtual void SelectedRange(std::string* range_str) = 0;
+
+ // Writes the textual representation of the attributes of marked text range
+ // on the frame to attributes.
+ virtual void ValidAttributesForMarkedText(std::string* attributes) = 0;
+
+ virtual void ConversationIdentifier() = 0;
+ virtual void SubstringFromRange(int32_t location, int32_t length) = 0;
+ virtual void AttributedSubstringFromRange(int32_t location,
+ int32_t length) = 0;
+ virtual void FirstRectForCharacterRange(int32_t location,
+ int32_t length) = 0;
+ virtual void CharacterIndexForPoint(double x, double y) = 0;
+ virtual void MakeAttributedString(std::string& str) = 0;
+
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(WebTextInput);
+};
+
+#endif // #ifndef WEBKIT_GLUE_WEBTEXTINPUT_H__
diff --git a/webkit/glue/webtextinput_impl.cc b/webkit/glue/webtextinput_impl.cc
new file mode 100644
index 0000000..03cb895
--- /dev/null
+++ b/webkit/glue/webtextinput_impl.cc
@@ -0,0 +1,178 @@
+// 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 <ctype.h>
+#include "config.h"
+
+#pragma warning(push, 0)
+#include "Frame.h"
+#include "Editor.h"
+#pragma warning(pop)
+
+#undef LOG
+
+#include "base/string_util.h"
+#include "webkit/glue/webframe_impl.h"
+#include "webkit/glue/webtextinput_impl.h"
+
+WebTextInputImpl::WebTextInputImpl(WebFrameImpl* web_frame_impl)
+ : WebTextInput(),
+ web_frame_impl_(web_frame_impl) {
+}
+
+WebTextInputImpl::~WebTextInputImpl() {
+}
+
+WebCore::Frame* WebTextInputImpl::GetFrame() {
+ return web_frame_impl_->frame();
+}
+
+WebCore::Editor* WebTextInputImpl::GetEditor() {
+ return web_frame_impl_->frame()->editor();
+}
+
+void WebTextInputImpl::InsertText(std::string& text) {
+ WebCore::String str(text.c_str());
+ GetEditor()->insertText(str, NULL);
+}
+
+void WebTextInputImpl::DoCommand(std::string& command) {
+ // Since we don't have NSControl, we will convert the format of command
+ // string and call the function on Editor directly.
+
+ if (command.length() <= 2)
+ return;
+
+ // Make sure the first letter is upper case.
+ command.replace(0, 1, 1, toupper(command.at(0)));
+
+ // Remove the trailing ':' if existing.
+ if (command.at(command.length() - 1) == ':')
+ command.erase(command.length() - 1, 1);
+
+ // Specially handling commands that Editor::execCommand does not directly
+ // support.
+ if (!command.compare("DeleteToEndOfParagraph")) {
+ DeleteToEndOfParagraph();
+ } else if(!command.compare("Indent")) {
+ GetEditor()->indent();
+ } else if(!command.compare("Outdent")) {
+ GetEditor()->outdent();
+ } else if(!command.compare("DeleteBackward")) {
+ WebCore::AtomicString editor_command("BackwardDelete");
+ GetEditor()->command(editor_command).execute();
+ } else if(!command.compare("DeleteForward")) {
+ WebCore::AtomicString editor_command("ForwardDelete");
+ GetEditor()->command(editor_command).execute();
+ } else {
+ WebCore::AtomicString editor_command(command.c_str());
+ GetEditor()->command(editor_command).execute();
+ }
+
+ return;
+}
+
+void WebTextInputImpl::SetMarkedText(std::string& text,
+ int32_t location,
+ int32_t length) {
+ WebCore::Editor* editor = GetEditor();
+ WebCore::String str(text.c_str());
+
+ editor->confirmComposition(str);
+
+ WebCore::Frame* frame = GetFrame();
+ WTF::Vector<WebCore::CompositionUnderline> decorations;
+
+ editor->setComposition(str, decorations, location, length);
+}
+
+void WebTextInputImpl::UnMarkText() {
+ GetEditor()->confirmCompositionWithoutDisturbingSelection();;
+}
+
+bool WebTextInputImpl::HasMarkedText() {
+ return GetEditor()->hasComposition();
+}
+
+void WebTextInputImpl::ConversationIdentifier() {
+}
+
+void WebTextInputImpl::SubstringFromRange(int32_t location, int32_t length) {
+}
+
+void WebTextInputImpl::AttributedSubstringFromRange(int32_t location,
+ int32_t length) {
+}
+
+void WebTextInputImpl::MarkedRange(std::string* range_str) {
+ RefPtr<WebCore::Range> range = GetEditor()->compositionRange();
+
+ // Range::toString() returns a string different from what test expects.
+ // So we need to construct the string ourselves.
+ SStringPrintf(range_str, "%d,%d", range->startPosition().offset(),
+ range->endPosition().offset());
+}
+
+void WebTextInputImpl::SelectedRange(std::string* range_str) {
+ WTF::RefPtr<WebCore::Range> range
+ = GetFrame()->selectionController()->toRange();
+
+ // Range::toString() returns a string different from what test expects.
+ // So we need to construct the string ourselves.
+ SStringPrintf(range_str, "%d,%d", range.get()->startPosition().offset(),
+ range.get()->endPosition().offset());
+}
+
+void WebTextInputImpl::FirstRectForCharacterRange(int32_t location,
+ int32_t length) {
+}
+
+void WebTextInputImpl::CharacterIndexForPoint(double x, double y) {
+}
+
+void WebTextInputImpl::ValidAttributesForMarkedText(std::string* attributes) {
+ // We simply return a string with relevant keywords.
+ attributes->assign("NSUnderline,NSUnderlineColor,NSMarkedClauseSegment,NSTextInputReplacementRangeAttributeName");
+}
+
+void WebTextInputImpl::MakeAttributedString(std::string& str) {
+}
+
+void WebTextInputImpl::DeleteToEndOfParagraph() {
+ WebCore::Editor* editor = GetEditor();
+ if (!editor->deleteWithDirection(WebCore::SelectionController::FORWARD,
+ WebCore::ParagraphBoundary,
+ true,
+ false)) {
+ editor->deleteWithDirection(WebCore::SelectionController::FORWARD,
+ WebCore::CharacterGranularity,
+ true,
+ false);
+ }
+}
diff --git a/webkit/glue/webtextinput_impl.h b/webkit/glue/webtextinput_impl.h
new file mode 100644
index 0000000..ee6a147
--- /dev/null
+++ b/webkit/glue/webtextinput_impl.h
@@ -0,0 +1,81 @@
+// 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.
+//
+// Class WebTextInputImpl provides implementation of WebTextInput which is
+// used by TextInputController in test_shell. It only facilitates layout tests
+// and should not be used by renderers.
+
+#ifndef WEBKIT_GLUE_WEBTEXTINPUT_IMPL_H__
+#define WEBKIT_GLUE_WEBTEXTINPUT_IMPL_H__
+
+#include "webkit/glue/webtextinput.h"
+
+class WebFrameImpl;
+class WebCore::Editor;
+
+class WebTextInputImpl : public WebTextInput {
+ public:
+ WebTextInputImpl(WebFrameImpl* web_frame_impl);
+ virtual ~WebTextInputImpl();
+
+ // WebTextInput methods
+ virtual void InsertText(std::string& text);
+ virtual void DoCommand(std::string& command);
+ virtual void SetMarkedText(std::string& text,
+ int32_t location, int32_t length);
+ virtual void UnMarkText();
+ virtual bool HasMarkedText();
+ virtual void MarkedRange(std::string* range_str);
+ virtual void SelectedRange(std::string* range_str);
+ virtual void ValidAttributesForMarkedText(std::string* attributes);
+
+ // TODO(huanr): examine all layout tests involving TextInputController
+ // and implement these functions if necessary.
+ virtual void ConversationIdentifier();
+ virtual void SubstringFromRange(int32_t location, int32_t length);
+ virtual void AttributedSubstringFromRange(int32_t location,
+ int32_t length);
+ virtual void FirstRectForCharacterRange(int32_t location,
+ int32_t length);
+ virtual void CharacterIndexForPoint(double x, double y);
+ virtual void MakeAttributedString(std::string& str);
+
+ private:
+ WebCore::Frame* GetFrame();
+ WebCore::Editor* GetEditor();
+
+ void DeleteToEndOfParagraph();
+
+ // Holding a non-owning pointer to the web frame we are associated with.
+ WebFrameImpl* web_frame_impl_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(WebTextInputImpl);
+};
+
+#endif // #ifndef WEBKIT_GLUE_WEBTEXTINPUT_IMPL_H__
diff --git a/webkit/glue/weburlrequest.h b/webkit/glue/weburlrequest.h
new file mode 100644
index 0000000..5e7476f
--- /dev/null
+++ b/webkit/glue/weburlrequest.h
@@ -0,0 +1,128 @@
+// 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 WEBKIT_GLUE_WEBURLREQUEST_H__
+#define WEBKIT_GLUE_WEBURLREQUEST_H__
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/ref_counted.h"
+
+enum WebRequestCachePolicy {
+ WebRequestUseProtocolCachePolicy,
+ WebRequestReloadIgnoringCacheData,
+ WebRequestReturnCacheDataElseLoad,
+ WebRequestReturnCacheDataDontLoad
+};
+
+class GURL;
+
+class WebRequest {
+ public:
+ // Extra information that is associated with a request. The embedder derives
+ // from this REFERENCE COUNTED class to associated data with a request and
+ // get it back when the page loads.
+ //
+ // Note that for reloads (and possibly things like back/forward), there is no
+ // way to specify the request that it will use, so the extra data pointer
+ // will be invalid. Users should always check for NULL.
+ class ExtraData : public base::RefCounted<ExtraData> {
+ public:
+ virtual ~ExtraData() {}
+ };
+
+ // Creates a WebRequest.
+ static WebRequest* Create(const GURL& url);
+
+ // Creates a copy of this WebRequest.
+ virtual WebRequest* Clone() const = 0;
+
+ // Sets the extra request info that the embedder can retrieve later. This
+ // will AddRef the ExtraData and store it with the request.
+ virtual void SetExtraData(ExtraData* extra) = 0;
+
+ // Returns any previously set request info. It does not AddRef, the caller
+ // is assumed to assign this to a RefPtr. This may return NULL if no extra
+ // data has been set on this request. Even if the embedder sets request info
+ // for every request, WebRequests can get created during reload operations
+ // so callers should not assume the data is always valid.
+ virtual ExtraData* GetExtraData() const = 0;
+
+ // Get/set the URL.
+ virtual GURL GetURL() const = 0;
+ virtual void SetURL(const GURL& url) = 0;
+
+ // Get/set the main document URL, which may be different from the URL for a
+ // subframe load.
+ virtual GURL GetMainDocumentURL() const = 0;
+ virtual void SetMainDocumentURL(const GURL& url) = 0;
+
+ // Get/set the cache policy.
+ virtual WebRequestCachePolicy GetCachePolicy() const = 0;
+ virtual void SetCachePolicy(WebRequestCachePolicy policy) = 0;
+
+ // Get/set the HTTP request method.
+ virtual std::wstring GetHttpMethod() const = 0;
+ virtual void SetHttpMethod(const std::wstring& method) = 0;
+
+ // Returns the string corresponding to a header set in the request. If the
+ // given header was not set in the request, the empty string is returned.
+ virtual std::wstring GetHttpHeaderValue(const std::wstring& field) const = 0;
+
+ // Helper function for GetHeaderValue to retrieve the referrer. This
+ // referrer is generated automatically by WebKit when navigation events
+ // occur. If there was no referrer (for example, the browser instructed
+ // WebKit to navigate), the returned string will be empty.
+ //
+ // It is preferred to call this instead of GetHttpHeaderValue, because the
+ // way referrers are stored may change in the future.
+ //
+ virtual std::wstring GetHttpReferrer() const = 0;
+
+ // Get/set the opaque history state (used for back/forward navigations).
+ virtual std::string GetHistoryState() const = 0;
+ virtual void SetHistoryState(const std::string& state) = 0;
+
+ // Get/set an opaque value containing the security info (including SSL
+ // connection state) that should be reported as used in the response for that
+ // request, or an empty string if no security info should be reported. This
+ // is usually used to simulate security errors on a page (typically an error
+ // page that should contain the errors of the actual page that has the
+ // errors).
+ virtual std::string GetSecurityInfo() const = 0;
+ virtual void SetSecurityInfo(const std::string& info) = 0;
+
+ // Returns true if this request contains history state that has form data.
+ virtual bool HasFormData() const = 0;
+
+ virtual ~WebRequest() { }
+};
+
+#endif // #ifndef WEBKIT_GLUE_WEBURLREQUEST_H__
diff --git a/webkit/glue/weburlrequest_impl.cc b/webkit/glue/weburlrequest_impl.cc
new file mode 100644
index 0000000..1f36cb3
--- /dev/null
+++ b/webkit/glue/weburlrequest_impl.cc
@@ -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.
+
+#include "config.h"
+#include "webkit/glue/weburlrequest_impl.h"
+#include "webkit/glue/glue_serialize.h"
+#include "webkit/glue/glue_util.h"
+
+using WebCore::FrameLoadRequest;
+using WebCore::ResourceRequest;
+using WebCore::ResourceRequestCachePolicy;
+using WebCore::String;
+
+// WebRequest -----------------------------------------------------------------
+
+WebRequestImpl::WebRequestImpl() {
+}
+
+WebRequestImpl::WebRequestImpl(const GURL& url)
+ : request_(FrameLoadRequest(webkit_glue::GURLToKURL(url))) {
+}
+
+WebRequestImpl::WebRequestImpl(const WebCore::ResourceRequest& request)
+ : request_(FrameLoadRequest(request)) {
+}
+
+WebRequestImpl::WebRequestImpl(const WebCore::FrameLoadRequest& request)
+ : request_(request) {
+}
+
+WebRequest* WebRequestImpl::Clone() const {
+ return new WebRequestImpl(*this);
+}
+
+void WebRequestImpl::SetExtraData(ExtraData* extra) {
+ extra_data_ = extra;
+}
+
+WebRequest::ExtraData* WebRequestImpl::GetExtraData() const {
+ return extra_data_.get();
+}
+
+GURL WebRequestImpl::GetURL() const {
+ return webkit_glue::KURLToGURL(request_.resourceRequest().url());
+}
+
+void WebRequestImpl::SetURL(const GURL& url) {
+ request_.resourceRequest().setURL(webkit_glue::GURLToKURL(url));
+}
+
+GURL WebRequestImpl::GetMainDocumentURL() const {
+ return webkit_glue::KURLToGURL(request_.resourceRequest().mainDocumentURL());
+}
+
+void WebRequestImpl::SetMainDocumentURL(const GURL& url) {
+ request_.resourceRequest().setMainDocumentURL(webkit_glue::GURLToKURL(url));
+}
+
+WebRequestCachePolicy WebRequestImpl::GetCachePolicy() const {
+ // WebRequestCachePolicy mirrors ResourceRequestCachePolicy
+ return static_cast<WebRequestCachePolicy>(
+ request_.resourceRequest().cachePolicy());
+}
+
+void WebRequestImpl::SetCachePolicy(WebRequestCachePolicy policy) {
+ // WebRequestCachePolicy mirrors ResourceRequestCachePolicy
+ request_.resourceRequest().setCachePolicy(
+ static_cast<WebCore::ResourceRequestCachePolicy>(policy));
+}
+
+std::wstring WebRequestImpl::GetHttpMethod() const {
+ return webkit_glue::StringToStdWString(
+ request_.resourceRequest().httpMethod());
+}
+
+void WebRequestImpl::SetHttpMethod(const std::wstring& method) {
+ request_.resourceRequest().setHTTPMethod(
+ webkit_glue::StdWStringToString(method));
+}
+
+std::wstring WebRequestImpl::GetHttpHeaderValue(const std::wstring& field) const {
+ return webkit_glue::StringToStdWString(
+ request_.resourceRequest().httpHeaderField(
+ webkit_glue::StdWStringToString(field)));
+}
+
+std::wstring WebRequestImpl::GetHttpReferrer() const {
+ return webkit_glue::StringToStdWString(
+ request_.resourceRequest().httpReferrer());
+}
+
+std::string WebRequestImpl::GetHistoryState() const {
+ std::string value;
+ webkit_glue::HistoryItemToString(history_item_, &value);
+ return value;
+}
+
+void WebRequestImpl::SetHistoryState(const std::string& value) {
+ history_item_ = webkit_glue::HistoryItemFromString(value);
+}
+
+std::string WebRequestImpl::GetSecurityInfo() const {
+ return webkit_glue::CStringToStdString(
+ request_.resourceRequest().securityInfo());
+}
+
+void WebRequestImpl::SetSecurityInfo(const std::string& value) {
+ request_.resourceRequest().setSecurityInfo(
+ webkit_glue::StdStringToCString(value));
+}
+
+bool WebRequestImpl::HasFormData() const {
+ return history_item() && history_item()->formData();
+}
+
+// static
+WebRequest* WebRequest::Create(const GURL& url) {
+ return new WebRequestImpl(url);
+}
diff --git a/webkit/glue/weburlrequest_impl.h b/webkit/glue/weburlrequest_impl.h
new file mode 100644
index 0000000..4cab62c
--- /dev/null
+++ b/webkit/glue/weburlrequest_impl.h
@@ -0,0 +1,87 @@
+// 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 WEBKIT_GLUE_WEBURLREQUEST_IMPL_H__
+#define WEBKIT_GLUE_WEBURLREQUEST_IMPL_H__
+
+#include "webkit/glue/weburlrequest.h"
+#include "base/basictypes.h"
+
+#pragma warning(push, 0)
+#include "FrameLoadRequest.h"
+#include "HistoryItem.h"
+#pragma warning(pop)
+
+class WebRequestImpl : public WebRequest {
+ public:
+ WebRequestImpl();
+
+ explicit WebRequestImpl(const GURL& url);
+ explicit WebRequestImpl(const WebCore::ResourceRequest& request);
+ explicit WebRequestImpl(const WebCore::FrameLoadRequest& request);
+
+ // WebRequest
+ virtual WebRequest* Clone() const;
+ virtual void SetExtraData(ExtraData* extra);
+ virtual ExtraData* GetExtraData() const;
+ virtual void SetURL(const GURL& url);
+ virtual GURL GetURL() const;
+ virtual void SetMainDocumentURL(const GURL& url);
+ virtual GURL GetMainDocumentURL() const;
+ virtual WebRequestCachePolicy GetCachePolicy() const;
+ virtual void SetCachePolicy(WebRequestCachePolicy policy);
+ virtual std::wstring GetHttpMethod() const;
+ virtual void SetHttpMethod(const std::wstring& method);
+ virtual std::wstring GetHttpHeaderValue(const std::wstring& field) const;
+ virtual std::wstring GetHttpReferrer() const;
+ virtual std::string GetHistoryState() const;
+ virtual void SetHistoryState(const std::string& value);
+ virtual std::string GetSecurityInfo() const;
+ virtual void SetSecurityInfo(const std::string& value);
+ virtual bool HasFormData() const;
+
+ // WebRequestImpl
+ const WebCore::FrameLoadRequest& frame_load_request() const {
+ return request_;
+ }
+ void set_frame_load_request(const WebCore::FrameLoadRequest& request) {
+ request_ = request;
+ }
+
+ PassRefPtr<WebCore::HistoryItem> history_item() const {
+ return history_item_;
+ }
+
+ protected:
+ WebCore::FrameLoadRequest request_;
+ RefPtr<WebCore::HistoryItem> history_item_;
+ scoped_refptr<ExtraData> extra_data_;
+};
+
+#endif // #ifndef WEBKIT_GLUE_WEBURLREQUEST_IMPL_H__
diff --git a/webkit/glue/webview.h b/webkit/glue/webview.h
new file mode 100644
index 0000000..9f44769
--- /dev/null
+++ b/webkit/glue/webview.h
@@ -0,0 +1,219 @@
+// 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 WEBKIT_GLUE_WEBVIEW_H__
+#define WEBKIT_GLUE_WEBVIEW_H__
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/ref_counted.h"
+#include "webkit/glue/webwidget.h"
+
+struct WebDropData;
+struct WebPreferences;
+class GURL;
+class WebFrame;
+class WebViewDelegate;
+
+//
+// @class WebView
+// WebView manages the interaction between WebFrameViews and WebDataSources.
+// Modification of the policies and behavior of the WebKit is largely managed
+// by WebViews and their delegates.
+//
+// Typical usage:
+//
+// WebView *webView;
+// WebFrame *mainFrame;
+//
+// webView = [[WebView alloc] initWithFrame: NSMakeRect (0,0,640,480)];
+// mainFrame = [webView mainFrame];
+// [mainFrame loadRequest:request];
+//
+// WebViews have a WebViewDelegate that the embedding application implements
+// that are required for tasks like opening new windows and controlling the
+// user interface elements in those windows, monitoring the progress of loads,
+// monitoring URL changes, and making determinations about how content of
+// certain types should be handled.
+class WebView : public WebWidget {
+ public:
+ WebView() {}
+ virtual ~WebView() {}
+
+ // This method creates a WebView that is initially sized to an empty rect.
+ static WebView* Create(WebViewDelegate* delegate,
+ const WebPreferences& prefs);
+
+ // Returns the delegate for this WebView. This is the pointer that was
+ // passed to WebView::Create. The caller must check this value before using
+ // it, it will be NULL during closing of the view.
+ virtual WebViewDelegate* GetDelegate() = 0;
+
+ // Instructs the EditorClient whether to pass editing notifications on to a
+ // delegate, if one is present. This allows embedders that haven't
+ // overridden any editor delegate methods to avoid the performance impact of
+ // calling them.
+ virtual void SetUseEditorDelegate(bool value) = 0;
+
+ // Method that controls whether pressing Tab key cycles through page elements
+ // or inserts a '\t' char in text area
+ virtual void SetTabKeyCyclesThroughElements(bool value) = 0;
+
+ // Returns whether the current view can be closed, after running any
+ // onbeforeunload event handlers.
+ virtual bool ShouldClose() = 0;
+
+ //
+ // @method mainFrame
+ // @abstract Return the top level frame.
+ // @discussion Note that even document that are not framesets will have a
+ // mainFrame.
+ // @result The main frame.
+ // - (WebFrame *)mainFrame;
+ virtual WebFrame* GetMainFrame() = 0;
+
+ // Returns the currently focused frame.
+ virtual WebFrame* GetFocusedFrame() = 0;
+
+ // Sets focus to the frame passed in.
+ virtual void SetFocusedFrame(WebFrame* frame) = 0;
+
+ // Returns the frame with the given name, or NULL if not found.
+ virtual WebFrame* GetFrameWithName(const std::wstring& name) = 0;
+
+ // Returns the frame previous to the specified frame, by traversing the frame
+ // tree, wrapping around if necessary.
+ virtual WebFrame* GetPreviousFrameBefore(WebFrame* frame, bool wrap) = 0;
+
+ // Returns the frame after to the specified frame, by traversing the frame
+ // tree, wrapping around if necessary.
+ virtual WebFrame* GetNextFrameAfter(WebFrame* frame, bool wrap) = 0;
+
+ // ---- TODO(darin): remove from here ----
+
+ //
+ // - (IBAction)stopLoading:(id)sender;
+ virtual void StopLoading() = 0;
+
+ // Sets the maximum size to allow WebCore's internal B/F list to grow to.
+ // If not called, the list will have the default capacity specified in
+ // BackForwardList.cpp.
+ virtual void SetBackForwardListSize(int size) = 0;
+
+ // ---- TODO(darin): remove to here ----
+
+ // Restores focus to the previously focused element.
+ // This method is invoked when the webview is shown after being
+ // hidden, and focus is to be restored. When WebView loses focus, it remembers
+ // the frame/element that had focus, so that when this method is invoked
+ // focus is then restored.
+ virtual void RestoreFocus() = 0;
+
+ // Focus the first (last if reverse is true) focusable node.
+ virtual void SetInitialFocus(bool reverse) = 0;
+
+ // Stores the focused node and clears it if |frame| is the focused frame.
+ // TODO(jcampan): http://b/issue?id=1157486 this is needed to work-around
+ // issues caused by the fix for bug #792423 and should be removed when that
+ // bug is fixed.
+ virtual void StoreFocusForFrame(WebFrame* frame) = 0;
+
+ // Returns whether or not the focused control needs spell-checking.
+ // Currently, this function just retrieves the focused node and determines
+ // whether or not it is a <textarea> element or an element whose
+ // contenteditable attribute is true.
+ // TODO(hbono): Bug 740540: This code just implements the default behavior
+ // proposed in this issue. We should also retrieve "spellcheck" attributes
+ // for text fields and create a flag to over-write the default behavior.
+ virtual bool FocusedFrameNeedsSpellchecking() = 0;
+
+ // Requests the webview to download an image. When done, the delegate is
+ // notified by way of DidDownloadImage. Returns true if the request was
+ // successfully started, false otherwise. id is used to uniquely identify the
+ // request and passed back to the DidDownloadImage method. If the image has
+ // multiple frames, the frame whose size is image_size is returned. If the
+ // image doesn't have a frame at the specified size, the first is returned.
+ virtual bool DownloadImage(int id, const GURL& image_url, int image_size) = 0;
+
+ // Replace the standard setting for the WebView with |preferences|.
+ virtual void SetPreferences(const WebPreferences& preferences) = 0;
+ virtual const WebPreferences& GetPreferences() = 0;
+
+ // Set the encoding of the current main frame. The value comes from
+ // the encoding menu. WebKit uses the function named
+ // SetCustomTextEncodingName to do override encoding job.
+ virtual void SetPageEncoding(const std::wstring& encoding_name) = 0;
+
+ // Return the canonical encoding name of current main webframe in webview.
+ virtual std::wstring GetMainFrameEncodingName() = 0;
+
+ // Change the text zoom level. Text size is made 20% larger or smaller.
+ virtual void MakeTextLarger() = 0;
+ virtual void MakeTextSmaller() = 0;
+ virtual void MakeTextStandardSize() = 0;
+
+ // Copy to the clipboard the image located at a particular point in the
+ // WebView (if there is such an image)
+ virtual void CopyImageAt(int x, int y) = 0;
+
+ // Inspect a particular point in the WebView. (x = -1 || y = -1) is a special
+ // case which means inspect the current page and not a specific point.
+ virtual void InspectElement(int x, int y) = 0;
+
+ // Show the JavaScript console.
+ virtual void ShowJavaScriptConsole() = 0;
+
+ // Notifies the webview that a drag has terminated.
+ virtual void DragSourceEndedAt(
+ int client_x, int client_y, int screen_x, int screen_y) = 0;
+
+ // Notifies the webview that a drag and drop operation is in progress, with
+ // dropable items over the view.
+ virtual void DragSourceMovedTo(
+ int client_x, int client_y, int screen_x, int screen_y) = 0;
+
+ // Notfies the webview that the system drag and drop operation has ended.
+ virtual void DragSourceSystemDragEnded() = 0;
+
+ // Callback methods when a drag and drop operation is trying to drop
+ // something on the renderer.
+ virtual bool DragTargetDragEnter(const WebDropData& drop_data,
+ int client_x, int client_y, int screen_x, int screen_y) = 0;
+ virtual bool DragTargetDragOver(
+ int client_x, int client_y, int screen_x, int screen_y) = 0;
+ virtual void DragTargetDragLeave() = 0;
+ virtual void DragTargetDrop(
+ int client_x, int client_y, int screen_x, int screen_y) = 0;
+
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(WebView);
+};
+
+#endif // WEBKIT_GLUE_WEBVIEW_H__
diff --git a/webkit/glue/webview_delegate.h b/webkit/glue/webview_delegate.h
new file mode 100644
index 0000000..f7aedd5
--- /dev/null
+++ b/webkit/glue/webview_delegate.h
@@ -0,0 +1,731 @@
+// 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.
+
+// WebCore provides hooks for several kinds of functionality, allowing separate
+// classes termed "delegates" to receive notifications (in the form of direct
+// function calls) when certain events are about to occur or have just occurred.
+// In some cases, the delegate implements the needed functionality; in others,
+// the delegate has some control over the behavior but doesn't actually
+// implement it. For example, the UI delegate is responsible for showing a
+// dialog box or otherwise handling a JavaScript window.alert() call, via the
+// RunJavaScriptAlert() method. On the other hand, the editor delegate doesn't
+// actually handle editing functionality, although it could (for example)
+// override whether a content-editable node accepts editing focus by returning
+// false from ShouldBeginEditing(). (It would also possible for a more
+// special-purpose editing delegate to act on the edited node in some way, e.g.
+// to highlight modified text in the DidChangeContents() method.)
+
+// WebKit divides the delegated tasks into several different classes, but we
+// combine them into a single WebViewDelegate. This single delegate encompasses
+// the needed functionality of the WebKit UIDelegate, ContextMenuDelegate,
+// PolicyDelegate, FrameLoadDelegate, and EditorDelegate; additional portions
+// of ChromeClient and FrameLoaderClient not delegated in the WebKit
+// implementation; and some WebView additions.
+
+#ifndef WEBKIT_GLUE_WEBVIEW_DELEGATE_H__
+#define WEBKIT_GLUE_WEBVIEW_DELEGATE_H__
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "googleurl/src/gurl.h"
+#include "webkit/glue/context_node_types.h"
+#include "webkit/glue/webwidget_delegate.h"
+
+namespace gfx {
+ class Point;
+ class Rect;
+}
+
+enum WindowOpenDisposition;
+struct PasswordForm;
+struct WebDropData;
+struct WebPreferences;
+class SkBitmap;
+class WebError;
+class WebFrame;
+class WebHistoryItem;
+class WebPluginDelegate;
+class WebRequest;
+class WebResponse;
+class WebView;
+class WebWidget;
+
+enum WebNavigationType {
+ WebNavigationTypeLinkClicked,
+ WebNavigationTypeFormSubmitted,
+ WebNavigationTypeBackForward,
+ WebNavigationTypeReload,
+ WebNavigationTypeFormResubmitted,
+ WebNavigationTypeOther
+};
+
+enum NavigationGesture {
+ NavigationGestureUser, // User initiated navigation/load. This is not
+ // currently used due to the untrustworthy nature
+ // of userGestureHint (wasRunByUserGesture). See
+ // bug 1051891.
+ NavigationGestureAuto, // Non-user initiated navigation / load. For example
+ // onload or setTimeout triggered document.location
+ // changes, and form.submits. See bug 1046841 for
+ // some cases that should be treated this way but
+ // aren't yet.
+ NavigationGestureUnknown, // What we assign when userGestureHint returns true
+ // because we can't trust it.
+};
+
+
+// Interface passed in to the WebViewDelegate to receive notification of the
+// result of an open file dialog.
+class WebFileChooserCallback {
+ public:
+ WebFileChooserCallback() {}
+ virtual ~WebFileChooserCallback() {}
+ virtual void OnFileChoose(const std::wstring& file_name) { }
+
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(WebFileChooserCallback);
+};
+
+
+// Inheritance here is somewhat weird, but since a WebView is a WebWidget,
+// it makes sense that a WebViewDelegate is a WebWidgetDelegate.
+class WebViewDelegate : virtual public WebWidgetDelegate {
+ public:
+ // WebView additions -------------------------------------------------------
+
+ // This method is called to create a new WebView. The WebView should not be
+ // made visible until the new WebView's Delegate has its Show method called.
+ // The returned WebView pointer is assumed to be owned by the host window,
+ // and the caller of CreateWebView should not release the given WebView.
+ // user_gesture is true if a user action initiated this call.
+ virtual WebView* CreateWebView(WebView* webview, bool user_gesture) {
+ return NULL;
+ }
+
+ // This method is called to create a new WebWidget to act as a popup
+ // (like a drop-down menu).
+ virtual WebWidget* CreatePopupWidget(WebView* webview) {
+ return NULL;
+ }
+
+ // This method is called to create a WebPluginDelegate implementation when a
+ // new plugin is instanced. See webkit_glue::CreateWebPluginDelegateHelper
+ // for a default WebPluginDelegate implementation.
+ virtual WebPluginDelegate* CreatePluginDelegate(
+ WebView* webview,
+ const GURL& url,
+ const std::string& mime_type,
+ const std::string& clsid,
+ std::string* actual_mime_type) {
+ return NULL;
+ }
+
+ // This method is called when default plugin has been correctly created and
+ // initialized, and found that the missing plugin is available to install or
+ // user has started installation.
+ virtual void OnMissingPluginStatus(WebPluginDelegate* delegate, int status) {
+ }
+
+ // This method is called to open a URL in the specified manner.
+ virtual void OpenURL(WebView* webview, const GURL& url,
+ WindowOpenDisposition disposition) {
+ }
+
+ // Notifies how many matches have been found so far, for a given request_id.
+ // |final_update| specifies whether this is the last update (all frames have
+ // completed scoping).
+ virtual void ReportFindInPageMatchCount(int count, int request_id,
+ bool final_update) {
+ }
+
+ // Notifies the browser what tick-mark rect is currently selected. Parameter
+ // |request_id| lets the recipient know which request this message belongs to,
+ // so that it can choose to ignore the message if it has moved on to other
+ // things. |selection_rect| is expected to have coordinates relative to the
+ // top left corner of the web page area and represent where on the screen the
+ // selection rect is currently located.
+ virtual void ReportFindInPageSelection(int request_id,
+ int active_match_ordinal,
+ const gfx::Rect& selection_rect) {
+ }
+
+ // This function is called to retrieve a resource bitmap from the
+ // renderer that was cached as a result of the renderer receiving a
+ // ViewMsg_Preload_Bitmap message from the browser.
+ virtual const SkBitmap* GetPreloadedResourceBitmap(int resource_id) {
+ return NULL;
+ }
+
+ // Returns whether this WebView was opened by a user gesture.
+ virtual bool WasOpenedByUserGesture(WebView* webview) const {
+ return true;
+ }
+
+ // FrameLoaderClient -------------------------------------------------------
+
+ // Notifies the delegate that a load has begun.
+ virtual void DidStartLoading(WebView* webview) {
+ }
+
+ // Notifies the delegate that all loads are finished.
+ virtual void DidStopLoading(WebView* webview) {
+ }
+
+ // The original version of this is WindowScriptObjectAvailable, below. This
+ // is a Chrome-specific version that serves the same purpose, but has been
+ // renamed since we haven't implemented WebScriptObject. Our embedding
+ // implementation binds native objects to the window via the webframe instead.
+ // TODO(pamg): If we do implement WebScriptObject, we may wish to switch to
+ // using the original version of this function.
+ virtual void WindowObjectCleared(WebFrame* webframe) {
+ }
+
+ // PolicyDelegate ----------------------------------------------------------
+
+ // This method is called to notify the delegate, and let it modify a
+ // proposed navigation. It will be called before loading starts, and
+ // on every redirect.
+ //
+ // disposition specifies what should normally happen for this
+ // navigation (open in current tab, start a new tab, start a new
+ // window, etc). This method can return an altered disposition, and
+ // take any additional separate action it wants to.
+ //
+ // is_redirect is true if this is a redirect rather than user action.
+ virtual WindowOpenDisposition DispositionForNavigationAction(
+ WebView* webview,
+ WebFrame* frame,
+ const WebRequest* request,
+ WebNavigationType type,
+ WindowOpenDisposition disposition,
+ bool is_redirect) {
+ return disposition;
+ }
+
+ // FrameLoadDelegate -------------------------------------------------------
+
+ // Notifies the delegate that the provisional load of a specified frame in a
+ // given WebView has started. By the time the provisional load for a frame has
+ // started, we know whether or not the current load is due to a client
+ // redirect or not, so we pass this information through to allow us to set
+ // the referrer properly in those cases. The consumed_client_redirect_src is
+ // an empty invalid GURL in other cases.
+ virtual void DidStartProvisionalLoadForFrame(
+ WebView* webview,
+ WebFrame* frame,
+ NavigationGesture gesture) {
+ }
+
+ // Called when a provisional load is redirected (see GetProvisionalDataSource
+ // for more info on provisional loads). This happens when the server sends
+ // back any type of redirect HTTP response.
+ //
+ // The redirect information can be retrieved from the provisional data
+ // source's redirect chain, which will be updated prior to this callback.
+ // The last element in that vector will be the new URL (which will be the
+ // same as the provisional data source's current URL), and the next-to-last
+ // element will be the referring URL.
+ virtual void DidReceiveProvisionalLoadServerRedirect(WebView* webview,
+ WebFrame* frame) {
+ }
+
+ // @method webView:didFailProvisionalLoadWithError:forFrame:
+ // @abstract Notifies the delegate that the provisional load has failed
+ // @param webView The WebView sending the message
+ // @param error The error that occurred
+ // @param frame The frame for which the error occurred
+ // @discussion This method is called after the provisional data source has
+ // failed to load. The frame will continue to display the contents of the
+ // committed data source if there is one.
+ virtual void DidFailProvisionalLoadWithError(WebView* webview,
+ const WebError& error,
+ WebFrame* frame) {
+ }
+
+ // If the provisional load fails, we try to load a an error page describing
+ // the user about the load failure. |html| is the UTF8 text to display. If
+ // |html| is empty, we will fall back on a local error page.
+ virtual void LoadNavigationErrorPage(WebFrame* frame,
+ const WebRequest* failed_request,
+ const WebError& error,
+ const std::string& html,
+ bool replace) {
+ }
+
+ // Notifies the delegate that the load has changed from provisional to
+ // committed. This method is called after the provisional data source has
+ // become the committed data source.
+ //
+ // In some cases, a single load may be committed more than once. This
+ // happens in the case of multipart/x-mixed-replace, also known as "server
+ // push". In this case, a single location change leads to multiple documents
+ // that are loaded in sequence. When this happens, a new commit will be sent
+ // for each document.
+ //
+ // The "is_new_navigation" flag will be true when a new session history entry
+ // was created for the load. The frame's GetHistoryState method can be used
+ // to get the corresponding session history state.
+ virtual void DidCommitLoadForFrame(WebView* webview, WebFrame* frame,
+ bool is_new_navigation) {
+ }
+
+ //
+ // @method webView:didReceiveTitle:forFrame:
+ // @abstract Notifies the delegate that the page title for a frame has been received
+ // @param webView The WebView sending the message
+ // @param title The new page title
+ // @param frame The frame for which the title has been received
+ // @discussion The title may update during loading; clients should be prepared for this.
+ // - (void)webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame;
+ virtual void DidReceiveTitle(WebView* webview,
+ const std::wstring& title,
+ WebFrame* frame) {
+ }
+
+ //
+ // @method webView:didFinishLoadForFrame:
+ // @abstract Notifies the delegate that the committed load of a frame has completed
+ // @param webView The WebView sending the message
+ // @param frame The frame that finished loading
+ // @discussion This method is called after the committed data source of a frame has successfully loaded
+ // and will only be called when all subresources such as images and stylesheets are done loading.
+ // Plug-In content and JavaScript-requested loads may occur after this method is called.
+ // - (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame;
+ virtual void DidFinishLoadForFrame(WebView* webview,
+ WebFrame* frame) {
+ }
+
+ //
+ // @method webView:didFailLoadWithError:forFrame:
+ // @abstract Notifies the delegate that the committed load of a frame has failed
+ // @param webView The WebView sending the message
+ // @param error The error that occurred
+ // @param frame The frame that failed to load
+ // @discussion This method is called after a data source has committed but failed to completely load.
+ // - (void)webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame;
+ virtual void DidFailLoadWithError(WebView* webview,
+ const WebError& error,
+ WebFrame* forFrame) {
+ }
+
+ // Notifies the delegate of a DOMContentLoaded event.
+ // This is called when the html resource has been loaded, but
+ // not necessarily all subresources (images, stylesheets). So, this is called
+ // before DidFinishLoadForFrame.
+ virtual void DidFinishDocumentLoadForFrame(WebView* webview, WebFrame* frame) {
+ }
+
+ // This method is called when we load a resource from an in-memory cache.
+ // A return value of |false| indicates the load should proceed, but WebCore
+ // appears to largely ignore the return value.
+ virtual bool DidLoadResourceFromMemoryCache(WebView* webview,
+ const WebRequest& request,
+ const WebResponse& response,
+ WebFrame* frame) {
+ return false;
+ }
+
+ // This is called after javascript onload handlers have been fired.
+ virtual void DidHandleOnloadEventsForFrame(WebView* webview, WebFrame* frame) {
+ }
+
+ // This method is called when anchors within a page have been clicked.
+ // It is very similar to DidCommitLoadForFrame.
+ virtual void DidChangeLocationWithinPageForFrame(WebView* webview,
+ WebFrame* frame,
+ bool is_new_navigation) {
+ }
+
+ // This is called when the favicon for a frame has been received.
+ virtual void DidReceiveIconForFrame(WebView* webview, WebFrame* frame) {
+ }
+
+ // Notifies the delegate that a frame will start a client-side redirect. When
+ // this function is called, the redirect has not yet been started (it may
+ // not even be scheduled to happen until some point in the future). When the
+ // redirect has been cancelled or has succeeded, DidStopClientRedirect will
+ // be called.
+ //
+ // WebKit considers meta refreshes, and setting document.location (regardless
+ // of when called) as client redirects (possibly among others).
+ //
+ // This function is intended to continue progress feedback while a
+ // client-side redirect is pending. Watch out: WebKit seems to call us twice
+ // for client redirects, resulting in two calls of this function.
+ virtual void WillPerformClientRedirect(WebView* webview,
+ WebFrame* frame,
+ const GURL& src_url,
+ const GURL& dest_url,
+ unsigned int delay_seconds,
+ unsigned int fire_date) {
+ }
+
+ // Notifies the delegate that a pending client-side redirect has been
+ // cancelled (for example, if the frame changes before the timeout) or has
+ // completed successfully. A client-side redirect is the result of setting
+ // document.location, for example, as opposed to a server side redirect
+ // which is the result of HTTP headers (see DidReceiveServerRedirect).
+ //
+ // On success, this will be called when the provisional load that the client
+ // side redirect initiated is committed.
+ //
+ // See the implementation of FrameLoader::clientRedirectCancelledOrFinished.
+ virtual void DidCancelClientRedirect(WebView* webview,
+ WebFrame* frame) {
+ }
+
+ // Notifies the delegate that the load about to be committed for the specified
+ // webview and frame was due to a client redirect originating from source URL.
+ virtual void DidCompleteClientRedirect(WebView* webview,
+ WebFrame* frame,
+ const GURL& source) {
+ }
+ //
+ // @method webView:willCloseFrame:
+ // @abstract Notifies the delegate that a frame will be closed
+ // @param webView The WebView sending the message
+ // @param frame The frame that will be closed
+ // @discussion This method is called right before WebKit is done with the frame
+ // and the objects that it contains.
+ // - (void)webView:(WebView *)sender willCloseFrame:(WebFrame *)frame;
+ virtual void WillCloseFrame(WebView* webview, WebFrame* frame) {
+ }
+
+ // ResourceLoadDelegate ----------------------------------------------------
+
+ // Associates the given identifier with the initial resource request.
+ // Resource load callbacks will use the identifier throughout the life of the
+ // request.
+ virtual void AssignIdentifierToRequest(WebView* webview,
+ uint32 identifier,
+ const WebRequest& request) {
+ }
+
+ // Notifies the delegate that a request is about to be sent out, giving the
+ // delegate the opportunity to modify the request. Note that request is
+ // writable here, and changes to the URL, for example, will change the request
+ // to be made.
+ virtual void WillSendRequest(WebView* webview,
+ uint32 identifier,
+ WebRequest* request) {
+ }
+
+ // Notifies the delegate that a subresource load has succeeded.
+ virtual void DidFinishLoading(WebView* webview, uint32 identifier) {
+ }
+
+ // Notifies the delegate that a subresource load has failed, and why.
+ virtual void DidFailLoadingWithError(WebView* webview,
+ uint32 identifier,
+ const WebError& error) {
+ }
+
+ // ChromeClient ------------------------------------------------------------
+
+ // Appends a line to the application's error console. The message contains
+ // an error description or other information, the line_no provides a line
+ // number (e.g. for a JavaScript error report), and the source_id contains
+ // a URL or other description of the source of the message.
+ virtual void AddMessageToConsole(WebView* webview,
+ const std::wstring& message,
+ unsigned int line_no,
+ const std::wstring& source_id) {
+ }
+
+ // Notification of possible password forms to be filled/submitted by
+ // the password manager
+ virtual void OnPasswordFormsSeen(WebView* webview,
+ const std::vector<PasswordForm>& forms) {
+ }
+
+ //
+ virtual void OnUnloadListenerChanged(WebView* webview, WebFrame* webframe) {
+ }
+
+ // UIDelegate --------------------------------------------------------------
+
+ // Displays a JavaScript alert panel associated with the given view. Clients
+ // should visually indicate that this panel comes from JavaScript. The panel
+ // should have a single OK button.
+ virtual void RunJavaScriptAlert(WebView* webview,
+ const std::wstring& message) {
+ }
+
+ // Displays a JavaScript confirm panel associated with the given view.
+ // Clients should visually indicate that this panel comes
+ // from JavaScript. The panel should have two buttons, e.g. "OK" and
+ // "Cancel". Returns true if the user hit OK, or false if the user hit Cancel.
+ virtual bool RunJavaScriptConfirm(WebView* webview,
+ const std::wstring& message) {
+ return false;
+ }
+
+ // Displays a JavaScript text input panel associated with the given view.
+ // Clients should visually indicate that this panel comes from JavaScript.
+ // The panel should have two buttons, e.g. "OK" and "Cancel", and an area to
+ // type text. The default_value should appear as the initial text in the
+ // panel when it is shown. If the user hit OK, returns true and fills result
+ // with the text in the box. The value of result is undefined if the user
+ // hit Cancel.
+ virtual bool RunJavaScriptPrompt(WebView* webview,
+ const std::wstring& message,
+ const std::wstring& default_value,
+ std::wstring* result) {
+ return false;
+ }
+
+ // Displays a "before unload" confirm panel associated with the given view.
+ // The panel should have two buttons, e.g. "OK" and "Cancel", where OK means
+ // that the navigation should continue, and Cancel means that the navigation
+ // should be cancelled, leaving the user on the current page. Returns true
+ // if the user hit OK, or false if the user hit Cancel.
+ virtual bool RunBeforeUnloadConfirm(WebView* webview,
+ const std::wstring& message) {
+ return true; // OK, continue to navigate away
+ }
+
+ // Tells the client that we're hovering over a link with a given URL,
+ // if the node is not a link, the URL will be an empty GURL.
+ virtual void UpdateTargetURL(WebView* webview,
+ const GURL& url) {
+ }
+
+ // Called to display a file chooser prompt. The prompt should be pre-
+ // populated with the given initial_filename string. The WebViewDelegate
+ // will own the WebFileChooserCallback object and is responsible for
+ // freeing it.
+ virtual void RunFileChooser(const std::wstring& initial_filename,
+ WebFileChooserCallback* file_chooser) {
+ delete file_chooser;
+ }
+
+ // @abstract Shows a context menu with commands relevant to a specific
+ // element on the current page.
+ // @param webview The WebView sending the delegate method.
+ // @param type The type of node(s) the context menu is being invoked on
+ // @param x The x position of the mouse pointer (relative to the webview)
+ // @param y The y position of the mouse pointer (relative to the webview)
+ // @param link_url The absolute URL of the link that contains the node the
+ // mouse right clicked on
+ // @param image_url The absolute URL of the image that the mouse right
+ // clicked on
+ // @param page_url The URL of the page the mouse right clicked on
+ // @param frame_url The URL of the subframe the mouse right clicked on
+ // @param selection_text The raw text of the selection that the mouse right
+ // clicked on
+ // @param misspelled_word The editable (possibily) misspelled word
+ // in the Editor on which dictionary lookup for suggestions will be done.
+ // @param edit_flags Which edit operations the renderer believes are available
+ 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) {
+ }
+
+ // Starts a drag session with the supplied contextual information.
+ // webview: The WebView sending the delegate method.
+ // drop_data: a WebDropData struct which should contain all the necessary
+ // information for dragging data out of the webview.
+ virtual void StartDragging(WebView* webview, const WebDropData& drop_data) { }
+
+ // Returns the focus to the client.
+ // reverse: Whether the focus should go to the previous (if true) or the next
+ // focusable element.
+ virtual void TakeFocus(WebView* webview, bool reverse) {
+ }
+
+ // Displays JS out-of-memory warning in the infobar
+ virtual void JSOutOfMemory() {
+ }
+
+ // EditorDelegate ----------------------------------------------------------
+
+ // These methods exist primarily to allow a specialized executable to record
+ // edit events for testing purposes. Most embedders are not expected to
+ // override them. In fact, by default these editor delegate methods aren't
+ // even called by the EditorClient, for performance reasons. To enable them,
+ // call WebView::SetUseEditorDelegate(true) for each WebView.
+
+ virtual bool ShouldBeginEditing(WebView* webview, std::wstring range) {
+ return true;
+ }
+
+ virtual bool ShouldEndEditing(WebView* webview, std::wstring range) {
+ return true;
+ }
+
+ virtual bool ShouldInsertNode(WebView* webview,
+ std::wstring node,
+ std::wstring range,
+ std::wstring action) {
+ return true;
+ }
+
+ virtual bool ShouldInsertText(WebView* webview,
+ std::wstring text,
+ std::wstring range,
+ std::wstring action) {
+ return true;
+ }
+
+ virtual bool ShouldChangeSelectedRange(WebView* webview,
+ std::wstring fromRange,
+ std::wstring toRange,
+ std::wstring affinity,
+ bool stillSelecting) {
+ return true;
+ }
+
+ virtual bool ShouldDeleteRange(WebView* webview, std::wstring range) {
+ return true;
+ }
+
+ virtual bool ShouldApplyStyle(WebView* webview,
+ std::wstring style,
+ std::wstring range) {
+ return true;
+ }
+
+ virtual bool SmartInsertDeleteEnabled() {
+ return false;
+ }
+ virtual void DidBeginEditing() { }
+ virtual void DidChangeSelection() { }
+ virtual void DidChangeContents() { }
+ virtual void DidEndEditing() { }
+
+ // Notification that a user metric has occurred.
+ virtual void UserMetricsRecordAction(const std::wstring& action) { }
+ virtual void UserMetricsRecordComputedAction(const std::wstring& action) {
+ UserMetricsRecordAction(action);
+ }
+
+ // -------------------------------------------------------------------------
+
+ // Notification that a request to download an image has completed. |errored|
+ // indicates if there was a network error. The image is empty if there was
+ // a network error, the contents of the page couldn't by converted to an
+ // image, or the response from the host was not 200.
+ // NOTE: image is empty if the response didn't contain image data.
+ virtual void DidDownloadImage(int id,
+ const GURL& image_url,
+ bool errored,
+ const SkBitmap& image) {
+ }
+
+ enum ErrorPageType {
+ DNS_ERROR,
+ HTTP_404
+ };
+ // If providing an alternate error page (like link doctor), returns the URL
+ // to fetch instead. If an invalid url is returned, just fall back on local
+ // error pages. |error_name| tells the delegate what type of error page we
+ // want (e.g., 404 vs dns errors).
+ virtual GURL GetAlternateErrorPageURL(const GURL& failedURL,
+ ErrorPageType error_type) {
+ return GURL();
+ }
+
+ // History Related ---------------------------------------------------------
+
+ // Returns the session history entry at a distance |offset| relative to the
+ // current entry. Returns NULL on failure.
+ virtual WebHistoryItem* GetHistoryEntryAtOffset(int offset) {
+ return NULL;
+ }
+
+ // Asynchronously navigates to the history entry at the given offset.
+ virtual void GoToEntryAtOffsetAsync(int offset) {
+ }
+
+ // Returns how many entries are in the back and forward lists, respectively.
+ virtual int GetHistoryBackListCount() {
+ return 0;
+ }
+ virtual int GetHistoryForwardListCount() {
+ return 0;
+ }
+
+ // Notification that the form state of an element in the document, scroll
+ // position, or possibly something else has changed that affects session
+ // history (HistoryItem). This function will be called frequently, so the
+ // implementor should not perform intensive operations in this notification.
+ virtual void OnNavStateChanged(WebView* webview) { }
+
+ // -------------------------------------------------------------------------
+
+ // Tell the delegate the tooltip text for the current mouse position.
+ virtual void SetTooltipText(WebView* webview,
+ const std::wstring& tooltip_text) { }
+
+ // Downloading -------------------------------------------------------------
+
+ virtual void DownloadUrl(const GURL& url, const GURL& referrer) { }
+
+ // Editor Client -----------------------------------------------------------
+
+ // Returns true if the word is spelled correctly. The word may begin or end
+ // with whitespace or punctuation, so the implementor should be sure to handle
+ // these cases.
+ //
+ // If the word is misspelled (returns false), the given first and last
+ // indices (inclusive) will be filled with the offsets of the boundary of the
+ // word within the given buffer. The out pointers must be specified. If the
+ // word is correctly spelled (returns true), they will be set to (0,0).
+ virtual void SpellCheck(const std::wstring& word, int& misspell_location,
+ int& misspell_length) {
+ misspell_location = misspell_length = 0;
+ }
+
+ // Changes the state of the input method editor.
+ virtual void SetInputMethodState(bool enabled) { }
+
+ // Asks the user to print the page or a specific frame. Called in response to
+ // a window.print() call.
+ virtual void ScriptedPrint(WebFrame* frame) { }
+
+ virtual void WebInspectorOpened(int num_resources) { }
+
+ WebViewDelegate() { }
+ virtual ~WebViewDelegate() { }
+
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(WebViewDelegate);
+};
+
+#endif // WEBKIT_GLUE_WEBVIEW_DELEGATE_H__
diff --git a/webkit/glue/webview_impl.cc b/webkit/glue/webview_impl.cc
new file mode 100644
index 0000000..69b6cd2
--- /dev/null
+++ b/webkit/glue/webview_impl.cc
@@ -0,0 +1,1468 @@
+/*
+* Copyright 2007 Google Inc. All Rights Reserved.
+*
+* Portions Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+*
+* ***** BEGIN LICENSE BLOCK *****
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* 2. 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.
+*
+* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+*
+* ***** END LICENSE BLOCK *****
+*
+*/
+
+#include "config.h"
+
+#pragma warning(push, 0)
+#include "Cursor.h"
+#include "Document.h"
+#include "DragController.h"
+#include "DragData.h"
+#include "Editor.h"
+#include "EventHandler.h"
+#include "FocusController.h"
+#include "FontDescription.h"
+#include "FrameLoader.h"
+#include "FrameTree.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HitTestResult.h"
+#include "Image.h"
+#include "InspectorController.h"
+#include "IntRect.h"
+#include "KeyboardEvent.h"
+#include "MIMETypeRegistry.h"
+#include "Page.h"
+#include "Pasteboard.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformMouseEvent.h"
+#include "PlatformWheelEvent.h"
+#include "PluginInfoStore.h"
+#include "RenderThemeWin.h"
+#include "ResourceHandle.h"
+#include "SelectionController.h"
+#include "Settings.h"
+#include "TypingCommand.h"
+#include "event_conversion.h"
+#pragma warning(pop)
+#undef LOG
+
+#include "base/gfx/rect.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/string_util.h"
+#include "webkit/glue/chrome_client_impl.h"
+#include "webkit/glue/context_menu_client_impl.h"
+#include "webkit/glue/dragclient_impl.h"
+#include "webkit/glue/editor_client_impl.h"
+#include "webkit/glue/event_conversion.h"
+#include "webkit/glue/glue_serialize.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/image_resource_fetcher.h"
+#include "webkit/glue/inspector_client_impl.h"
+#include "webkit/glue/searchable_form_data.h"
+#include "webkit/glue/webdropdata.h"
+#include "webkit/glue/webhistoryitem_impl.h"
+#include "webkit/glue/webinputevent.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/webpreferences.h"
+#include "webkit/glue/webview_delegate.h"
+#include "webkit/glue/webview_impl.h"
+#include "webkit/glue/webwidget_impl.h"
+#include "webkit/port/platform/graphics/PlatformContextSkia.h"
+
+// Get rid of WTF's pow define so we can use std::pow.
+#undef pow
+
+using namespace WebCore;
+
+// Change the text zoom level by kTextSizeMultiplierRatio each time the user
+// zooms text in or out (ie., change by 20%). The min and max values limit
+// text zoom to half and 3x the original text size. These three values match
+// those in Apple's port in WebKit/WebKit/WebView/WebView.mm
+static const double kTextSizeMultiplierRatio = 1.2;
+static const double kMinTextSizeMultiplier = 0.5;
+static const double kMaxTextSizeMultiplier = 3.0;
+
+// The webcore drag operation type when something is trying to be dropped on
+// the webview. These values are taken from Apple's windows port.
+static const WebCore::DragOperation kDropTargetOperation =
+ static_cast<WebCore::DragOperation>(DragOperationCopy | DragOperationLink);
+
+// WebView ----------------------------------------------------------------
+
+/*static*/
+WebView* WebView::Create(WebViewDelegate* delegate,
+ const WebPreferences& prefs) {
+ WebViewImpl* instance = new WebViewImpl();
+ instance->AddRef();
+ instance->SetPreferences(prefs);
+ instance->main_frame_->InitMainFrame(instance);
+ // Set the delegate after initializing the main frame, to avoid trying to
+ // respond to notifications before we're fully initialized.
+ instance->delegate_ = delegate;
+ // Restrict the access to the local file system
+ // (see WebView.mm WebView::_commonInitializationWithFrameName).
+ FrameLoader::setRestrictAccessToLocal(true);
+ return instance;
+}
+
+WebViewImpl::WebViewImpl()
+ : delegate_(NULL),
+ pending_history_item_(NULL),
+#ifndef NDEBUG
+ new_navigation_loader_(NULL),
+#endif
+ observed_new_navigation_(false),
+ text_zoom_level_(0),
+ context_menu_allowed_(false),
+ doing_drag_and_drop_(false),
+ suppress_next_keypress_event_(false),
+ window_open_disposition_(IGNORE_ACTION),
+ ime_accept_events_(true) {
+ // set to impossible point so we always get the first mouse pos
+ last_mouse_position_.SetPoint(-1, -1);
+
+ // the page will take ownership of the various clients
+ page_.reset(new Page(new ChromeClientImpl(this),
+ new ContextMenuClientImpl(this),
+ new EditorClientImpl(this),
+ new DragClientImpl(this),
+ new WebInspectorClient(this)));
+
+ page_->backForwardList()->setClient(this);
+
+ // The group name identifies a namespace of pages. I'm not sure how it's
+ // intended to be used, but keeping all pages in the same group works for us.
+ page_->setGroupName("default");
+
+ // This is created with a refcount of 1, and we assign it to a RefPtr,
+ // giving a refcount of 2. The ref is done on behalf of
+ // FrameWin/FrameLoaderWin which references the WebFrame via the
+ // FrameWinClient/FrameLoaderClient interfaces. See the comment at the
+ // top of webframe_impl.cc
+ main_frame_ = new WebFrameImpl();
+}
+
+WebViewImpl::~WebViewImpl() {
+ DCHECK(main_frame_ == NULL);
+ DCHECK(page_ == NULL);
+ ReleaseFocusReferences();
+ for (std::set<ImageResourceFetcher*>::iterator i = image_fetchers_.begin();
+ i != image_fetchers_.end(); ++i) {
+ delete *i;
+ }
+}
+
+void WebViewImpl::SetUseEditorDelegate(bool value) {
+ ASSERT(page_ != 0); // The macro doesn't like (!page_) with a scoped_ptr.
+ ASSERT(page_->editorClient());
+ EditorClientImpl* editor_client =
+ static_cast<EditorClientImpl*>(page_->editorClient());
+ editor_client->SetUseEditorDelegate(value);
+}
+
+void WebViewImpl::SetTabKeyCyclesThroughElements(bool value) {
+ if (page_ != NULL) {
+ page_->setTabKeyCyclesThroughElements(value);
+ }
+}
+
+void WebViewImpl::MouseMove(const WebMouseEvent& event) {
+ if (!main_frame_->frameview())
+ return;
+
+ last_mouse_position_.SetPoint(event.x, event.y);
+
+ // We call mouseMoved here instead of handleMouseMovedEvent because we need
+ // our ChromeClientImpl to receive changes to the mouse position and
+ // tooltip text, and mouseMoved handles all of that.
+ main_frame_->frameview()->frame()->eventHandler()->mouseMoved(
+ MakePlatformMouseEvent(main_frame_->frameview(), event));
+}
+
+void WebViewImpl::MouseLeave(const WebMouseEvent& event) {
+ // This event gets sent as the main frame is closing. In that case, just
+ // ignore it.
+ if (!main_frame_ || !main_frame_->frameview())
+ return;
+
+ delegate_->UpdateTargetURL(this, GURL());
+
+ main_frame_->frameview()->frame()->eventHandler()->handleMouseMoveEvent(
+ MakePlatformMouseEvent(main_frame_->frameview(), event));
+}
+
+void WebViewImpl::MouseDown(const WebMouseEvent& event) {
+ if (!main_frame_->frameview())
+ return;
+
+ last_mouse_down_point_ = gfx::Point(event.x, event.y);
+ main_frame_->frame()->eventHandler()->handleMousePressEvent(
+ MakePlatformMouseEvent(main_frame_->frameview(), event));
+}
+
+void WebViewImpl::MouseUp(const WebMouseEvent& event) {
+ if (event.button == WebMouseEvent::BUTTON_RIGHT) {
+ page_->contextMenuController()->clearContextMenu();
+
+ MakePlatformMouseEvent pme(main_frame_->frameview(), event);
+
+ // Find the right target frame. See issue 1186900.
+ IntPoint doc_point(
+ main_frame_->frame()->view()->windowToContents(pme.pos()));
+ HitTestResult result =
+ main_frame_->frame()->eventHandler()->hitTestResultAtPoint(doc_point,
+ false);
+ Frame* target_frame;
+ if (result.innerNonSharedNode())
+ target_frame = result.innerNonSharedNode()->document()->frame();
+ else
+ target_frame = page_->focusController()->focusedOrMainFrame();
+
+ target_frame->view()->setCursor(pointerCursor());
+
+ context_menu_allowed_ = true;
+ target_frame->eventHandler()->sendContextMenuEvent(pme);
+ context_menu_allowed_ = false;
+ // Actually showing the context menu is handled by the ContextMenuClient
+ // implementation...
+ }
+
+ if (!main_frame_->frameview())
+ return;
+
+ MouseCaptureLost();
+ main_frame_->frameview()->frame()->eventHandler()->handleMouseReleaseEvent(
+ MakePlatformMouseEvent(main_frame_->frameview(), event));
+}
+
+void WebViewImpl::MouseWheel(const WebMouseWheelEvent& event) {
+ main_frame_->frame()->eventHandler()->handleWheelEvent(
+ MakePlatformWheelEvent(main_frame_->frameview(), event));
+}
+
+bool WebViewImpl::KeyEvent(const WebKeyboardEvent& event) {
+ DCHECK((event.type == WebInputEvent::KEY_DOWN) ||
+ (event.type == WebInputEvent::KEY_UP));
+
+ // Please refer to the comments explaining the suppress_next_keypress_event_
+ // member.
+ // The suppress_next_keypress_event_ is set if the KeyDown is handled by
+ // Webkit. A keyDown event is typically associated with a keyPress(char)
+ // event and a keyUp event. We reset this flag here as this is a new keyDown
+ // event.
+ suppress_next_keypress_event_ = false;
+
+ Frame* frame = GetFocusedWebCoreFrame();
+ if (!frame)
+ return false;
+
+ EventHandler* handler = frame->eventHandler();
+ if (!handler)
+ return KeyEventDefault(event);
+
+ if (((event.modifiers == 0) && (event.key_code == VK_APPS)) ||
+ ((event.modifiers == WebInputEvent::SHIFT_KEY) &&
+ (event.key_code == VK_F10))) {
+ SendContextMenuEvent(event);
+ return true;
+ }
+
+ MakePlatformKeyboardEvent evt(event);
+
+ if (WebInputEvent::KEY_DOWN == event.type) {
+ MakePlatformKeyboardEvent evt_rawkeydown = evt;
+ evt_rawkeydown.SetKeyType(WebCore::PlatformKeyboardEvent::RawKeyDown);
+ if (handler->keyEvent(evt_rawkeydown) && !evt_rawkeydown.isSystemKey()) {
+ suppress_next_keypress_event_ = true;
+ return true;
+ }
+ } else {
+ if (handler->keyEvent(evt)) {
+ return true;
+ }
+ }
+
+ return KeyEventDefault(event);
+}
+
+bool WebViewImpl::CharEvent(const WebKeyboardEvent& event) {
+ DCHECK(event.type == WebInputEvent::CHAR);
+
+ // Please refer to the comments explaining the suppress_next_keypress_event_
+ // member.
+ // The suppress_next_keypress_event_ is set if the KeyDown is handled by
+ // Webkit. A keyDown event is typically associated with a keyPress(char)
+ // event and a keyUp event. We reset this flag here as it only applies
+ // to the current keyPress event.
+ if (suppress_next_keypress_event_) {
+ suppress_next_keypress_event_ = false;
+ return true;
+ }
+
+ Frame* frame = GetFocusedWebCoreFrame();
+ if (!frame)
+ return false;
+
+ EventHandler* handler = frame->eventHandler();
+ if (!handler)
+ return KeyEventDefault(event);
+
+ MakePlatformKeyboardEvent evt(event);
+ if (!evt.IsCharacterKey())
+ return true;
+
+ // Safari 3.1 does not pass off WM_SYSCHAR messages to the
+ // eventHandler::keyEvent. We mimic this behavior.
+ if (evt.isSystemKey())
+ return handler->handleAccessKey(evt);
+
+ if (!handler->keyEvent(evt))
+ return KeyEventDefault(event);
+
+ return true;
+}
+
+/*
+* The WebViewImpl::SendContextMenuEvent function is based on the Webkit
+* function
+* bool WebView::handleContextMenuEvent(WPARAM wParam, LPARAM lParam) in
+* webkit\webkit\win\WebView.cpp. The only significant change in this
+* function is the code to convert from a Keyboard event to the Right
+* Mouse button up event.
+*/
+bool WebViewImpl::SendContextMenuEvent(const WebKeyboardEvent& event) {
+ static const int kContextMenuMargin = 1;
+ FrameView* view = page()->mainFrame()->view();
+ if (!view)
+ return false;
+
+ POINT coords = {-1, -1};
+ int right_aligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
+ IntPoint location;
+
+ // The context menu event was generated from the keyboard, so show the
+ // context menu by the current selection.
+ Position start =
+ page()->mainFrame()->selectionController()->selection().start();
+ Position end = page()->mainFrame()->selectionController()->selection().end();
+
+ if (!start.node() || !end.node()) {
+ location =
+ IntPoint(right_aligned ? view->contentsWidth() - kContextMenuMargin
+ : kContextMenuMargin, kContextMenuMargin);
+ } else {
+ RenderObject* renderer = start.node()->renderer();
+ if (!renderer)
+ return false;
+ // Calculate the rect of the first line of the selection (cribbed from
+ // -[WebCoreFrameBridge firstRectForDOMRange:]).
+ int extra_width_to_EOL = 0;
+ IntRect start_caret_rect = renderer->caretRect(start.offset(), DOWNSTREAM,
+ &extra_width_to_EOL);
+ IntRect end_caret_rect = renderer->caretRect(end.offset(), UPSTREAM);
+ IntRect first_rect;
+ if (start_caret_rect.y() == end_caret_rect.y()) {
+ first_rect = IntRect(std::min(start_caret_rect.x(), end_caret_rect.x()),
+ start_caret_rect.y(),
+ abs(end_caret_rect.x() - start_caret_rect.x()),
+ max(start_caret_rect.height(),
+ end_caret_rect.height()));
+ } else {
+ first_rect = IntRect(start_caret_rect.x(), start_caret_rect.y(),
+ start_caret_rect.width() + extra_width_to_EOL,
+ start_caret_rect.height());
+ }
+ location = IntPoint(right_aligned ? first_rect.right() :
+ first_rect.x(), first_rect.bottom());
+ }
+
+ location = view->contentsToWindow(location);
+ // FIXME: The IntSize(0, -1) is a hack to get the hit-testing to result in
+ // the selected element. Ideally we'd have the position of a context menu
+ // event be separate from its target node.
+ coords = location + IntSize(0, -1);
+
+ // The contextMenuController() holds onto the last context menu that was
+ // popped up on the page until a new one is created. We need to clear
+ // this menu before propagating the event through the DOM so that we can
+ // detect if we create a new menu for this event, since we won't create
+ // a new menu if the DOM swallows the event and the defaultEventHandler does
+ // not run.
+ page()->contextMenuController()->clearContextMenu();
+
+ Frame* focused_frame = page()->focusController()->focusedOrMainFrame();
+ focused_frame->view()->setCursor(pointerCursor());
+ WebMouseEvent mouse_event;
+ mouse_event.button = WebMouseEvent::BUTTON_RIGHT;
+ mouse_event.x = coords.x;
+ mouse_event.y = coords.y;
+ mouse_event.type = WebInputEvent::MOUSE_UP;
+
+ MakePlatformMouseEvent platform_event(view, mouse_event);
+
+ context_menu_allowed_ = true;
+ bool handled =
+ focused_frame->eventHandler()->sendContextMenuEvent(platform_event);
+ context_menu_allowed_ = false;
+ return handled;
+}
+
+bool WebViewImpl::KeyEventDefault(const WebKeyboardEvent& event) {
+ Frame* frame = GetFocusedWebCoreFrame();
+ if (!frame)
+ return false;
+
+ switch (event.type) {
+ case WebInputEvent::CHAR: {
+ if (event.key_code == VK_SPACE) {
+ int key_code = ((event.modifiers & WebInputEvent::SHIFT_KEY) ?
+ VK_PRIOR : VK_NEXT);
+ return ScrollViewWithKeyboard(key_code);
+ }
+ break;
+ }
+
+ case WebInputEvent::KEY_DOWN: {
+ if (event.modifiers == WebInputEvent::CTRL_KEY) {
+ switch (event.key_code) {
+ case 'A':
+ GetFocusedFrame()->SelectAll();
+ return true;
+ case VK_INSERT:
+ case 'C':
+ GetFocusedFrame()->Copy();
+ return true;
+ // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl
+ // key combinations which affect scrolling. Safari is buggy in the
+ // sense that it scrolls the page for all Ctrl+scrolling key
+ // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc.
+ case VK_HOME:
+ case VK_END:
+ break;
+ default:
+ return false;
+ }
+ }
+ if (!event.system_key) {
+ return ScrollViewWithKeyboard(event.key_code);
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+ return false;
+}
+
+bool WebViewImpl::ScrollViewWithKeyboard(int key_code) {
+ Frame* frame = GetFocusedWebCoreFrame();
+ if (!frame)
+ return false;
+
+ ScrollDirection scroll_direction;
+ ScrollGranularity scroll_granularity;
+
+ switch (key_code) {
+ case VK_LEFT:
+ scroll_direction = ScrollLeft;
+ scroll_granularity = ScrollByLine;
+ break;
+ case VK_RIGHT:
+ scroll_direction = ScrollRight;
+ scroll_granularity = ScrollByLine;
+ break;
+ case VK_UP:
+ scroll_direction = ScrollUp;
+ scroll_granularity = ScrollByLine;
+ break;
+ case VK_DOWN:
+ scroll_direction = ScrollDown;
+ scroll_granularity = ScrollByLine;
+ break;
+ case VK_HOME:
+ scroll_direction = ScrollUp;
+ scroll_granularity = ScrollByDocument;
+ break;
+ case VK_END:
+ scroll_direction = ScrollDown;
+ scroll_granularity = ScrollByDocument;
+ break;
+ case VK_PRIOR: // page up
+ scroll_direction = ScrollUp;
+ scroll_granularity = ScrollByPage;
+ break;
+ case VK_NEXT: // page down
+ scroll_direction = ScrollDown;
+ scroll_granularity = ScrollByPage;
+ break;
+ default:
+ return false;
+ }
+
+ bool scroll_handled =
+ frame->eventHandler()->scrollOverflow(scroll_direction,
+ scroll_granularity);
+ Frame* current_frame = frame;
+ while (!scroll_handled && current_frame) {
+ scroll_handled = current_frame->view()->scroll(scroll_direction,
+ scroll_granularity);
+ current_frame = current_frame->tree()->parent();
+ }
+ return scroll_handled;
+}
+
+Frame* WebViewImpl::GetFocusedWebCoreFrame() {
+ if (!main_frame_ || !main_frame_->frame())
+ return NULL;
+
+ return
+ main_frame_->frame()->page()->focusController()->focusedOrMainFrame();
+}
+
+// static
+WebViewImpl* WebViewImpl::FromPage(WebCore::Page* page) {
+ return WebFrameImpl::FromFrame(page->mainFrame())->webview_impl();
+}
+
+// WebView --------------------------------------------------------------------
+
+bool WebViewImpl::ShouldClose() {
+ // TODO(creis): This should really cause a recursive depth-first walk of all
+ // frames in the tree, calling each frame's onbeforeunload. At the moment,
+ // we're consistent with Safari 3.1, not IE/FF.
+ Frame* frame = page_->focusController()->focusedOrMainFrame();
+ if (!frame)
+ return true;
+
+ return frame->shouldClose();
+}
+
+void WebViewImpl::Close() {
+ // Do this first to prevent reentrant notifications from being sent to the
+ // initiator of the close.
+ delegate_ = NULL;
+
+ // Initiate shutdown for the entire frameset.
+ if (main_frame_) {
+ // This will cause a lot of notifications to be sent.
+ main_frame_->frame()->loader()->frameDetached();
+ main_frame_ = NULL;
+ }
+
+ page_.reset();
+}
+
+WebViewDelegate* WebViewImpl::GetDelegate() {
+ return delegate_;
+}
+
+WebFrame* WebViewImpl::GetMainFrame() {
+ return main_frame_.get();
+}
+
+WebFrame* WebViewImpl::GetFocusedFrame() {
+ Frame* frame = GetFocusedWebCoreFrame();
+ return frame ? WebFrameImpl::FromFrame(frame) : NULL;
+}
+
+void WebViewImpl::SetFocusedFrame(WebFrame* frame) {
+ if (!frame) {
+ // Clears the focused frame if any.
+ Frame* frame = GetFocusedWebCoreFrame();
+ if (frame)
+ frame->selectionController()->setFocused(false);
+ return;
+ }
+ WebFrameImpl* frame_impl = static_cast<WebFrameImpl*>(frame);
+ WebCore::Frame* webcore_frame = frame_impl->frame();
+ webcore_frame->page()->focusController()->setFocusedFrame(webcore_frame);
+}
+
+WebFrame* WebViewImpl::GetFrameWithName(const std::wstring& name) {
+ String name_str = webkit_glue::StdWStringToString(name);
+ Frame* frame = main_frame_->frame()->tree()->find(name_str);
+ return frame ? WebFrameImpl::FromFrame(frame) : NULL;
+}
+
+WebFrame* WebViewImpl::GetPreviousFrameBefore(WebFrame* frame, bool wrap) {
+ WebFrameImpl* frame_impl = static_cast<WebFrameImpl*>(frame);
+ WebCore::Frame* previous =
+ frame_impl->frame()->tree()->traversePreviousWithWrap(wrap);
+ return previous ? WebFrameImpl::FromFrame(previous) : NULL;
+}
+
+WebFrame* WebViewImpl::GetNextFrameAfter(WebFrame* frame, bool wrap) {
+ WebFrameImpl* frame_impl = static_cast<WebFrameImpl*>(frame);
+ WebCore::Frame* next =
+ frame_impl->frame()->tree()->traverseNextWithWrap(wrap);
+ return next ? WebFrameImpl::FromFrame(next) : NULL;
+}
+
+void WebViewImpl::Resize(const gfx::Size& new_size) {
+ if (size_ == new_size)
+ return;
+ size_ = new_size;
+
+ if (main_frame_->frameview()) {
+ main_frame_->frameview()->resize(size_.width(), size_.height());
+ main_frame_->frame()->sendResizeEvent();
+ }
+
+ if (delegate_) {
+ gfx::Rect damaged_rect(0, 0, size_.width(), size_.height());
+ delegate_->DidInvalidateRect(this, damaged_rect);
+ }
+}
+
+void WebViewImpl::Layout() {
+ if (main_frame_) {
+ // In order for our child HWNDs (NativeWindowWidgets) to update properly,
+ // they need to be told that we are updating the screen. The problem is
+ // that the native widgets need to recalculate their clip region and not
+ // overlap any of our non-native widgets. To force the resizing, call
+ // setFrameGeometry(). This will be a quick operation for most frames, but
+ // the NativeWindowWidgets will update a proper clipping region.
+ FrameView* frameview = main_frame_->frameview();
+ if (frameview)
+ frameview->setFrameGeometry(frameview->frameGeometry());
+
+ // setFrameGeometry may have the side-effect of causing existing page
+ // layout to be invalidated, so layout needs to be called last.
+
+ main_frame_->Layout();
+ }
+}
+
+void WebViewImpl::Paint(gfx::PlatformCanvas* canvas, const gfx::Rect& rect) {
+ if (main_frame_)
+ main_frame_->Paint(canvas, rect);
+}
+
+// TODO(eseidel): g_current_input_event should be removed once
+// ChromeClient:show() can get the current-event information from WebCore.
+/* static */
+const WebInputEvent* WebViewImpl::g_current_input_event = NULL;
+
+bool WebViewImpl::HandleInputEvent(const WebInputEvent* input_event) {
+ // If we've started a drag and drop operation, ignore input events until
+ // we're done.
+ if (doing_drag_and_drop_)
+ return true;
+
+ // TODO(eseidel): Remove g_current_input_event.
+ // This only exists to allow ChromeClient::show() to know which mouse button
+ // triggered a window.open event.
+ // Safari must perform a similar hack, ours is in our WebKit glue layer
+ // theirs is in the application. This should go when WebCore can be fixed
+ // to pass more event information to ChromeClient::show()
+ g_current_input_event = input_event;
+
+ bool handled = true;
+
+ // TODO(jcampan): WebKit seems to always return false on mouse events
+ // processing methods. For now we'll assume it has processed them (as we are
+ // only interested in whether keyboard events are processed).
+ switch (input_event->type) {
+ case WebInputEvent::MOUSE_MOVE:
+ MouseMove(*static_cast<const WebMouseEvent*>(input_event));
+ break;
+
+ case WebInputEvent::MOUSE_LEAVE:
+ MouseLeave(*static_cast<const WebMouseEvent*>(input_event));
+ break;
+
+ case WebInputEvent::MOUSE_WHEEL:
+ MouseWheel(*static_cast<const WebMouseWheelEvent*>(input_event));
+ break;
+
+ case WebInputEvent::MOUSE_DOWN:
+ case WebInputEvent::MOUSE_DOUBLE_CLICK:
+ MouseDown(*static_cast<const WebMouseEvent*>(input_event));
+ break;
+
+ case WebInputEvent::MOUSE_UP:
+ MouseUp(*static_cast<const WebMouseEvent*>(input_event));
+ break;
+
+ case WebInputEvent::KEY_DOWN:
+ case WebInputEvent::KEY_UP:
+ handled = KeyEvent(*static_cast<const WebKeyboardEvent*>(input_event));
+ break;
+
+ case WebInputEvent::CHAR:
+ handled = CharEvent(*static_cast<const WebKeyboardEvent*>(input_event));
+ break;
+ default:
+ handled = false;
+ }
+
+ g_current_input_event = NULL;
+
+ return handled;
+}
+
+void WebViewImpl::MouseCaptureLost() {
+}
+
+// TODO(darin): these navigation methods should be killed
+
+void WebViewImpl::StopLoading() {
+ main_frame_->StopLoading();
+}
+
+void WebViewImpl::SetBackForwardListSize(int size) {
+ page_->backForwardList()->setCapacity(size);
+}
+
+void WebViewImpl::SetFocus(bool enable) {
+ if (enable) {
+ // Getting the focused frame will have the side-effect of setting the main
+ // frame as the focused frame if it is not already focused. Otherwise, if
+ // there is already a focused frame, then this does nothing.
+ GetFocusedFrame();
+ if (main_frame_ && main_frame_->frame()) {
+ Frame* frame = main_frame_->frame();
+ if (!frame->selectionController()->isFocusedAndActive()) {
+ // No one has focus yet, try to restore focus.
+ RestoreFocus();
+ frame->page()->focusController()->setActive(true);
+ }
+ Frame* focused_frame =
+ frame->page()->focusController()->focusedOrMainFrame();
+ frame->selectionController()->setFocused(frame == focused_frame);
+ }
+ ime_accept_events_ = true;
+ } else {
+ // Clear out who last had focus. If someone has focus, the refs will be
+ // updated below.
+ ReleaseFocusReferences();
+
+ // Clear focus on the currently focused frame if any.
+
+ if (!main_frame_)
+ return;
+
+ Frame* frame = main_frame_->frame();
+ if (!frame)
+ return;
+
+ RefPtr<Frame> focused = frame->page()->focusController()->focusedFrame();
+ if (focused.get()) {
+ // Update the focus refs, this way we can give focus back appropriately.
+ // It's entirely possible to have a focused document, but not a focused
+ // node.
+ RefPtr<Document> document = focused->document();
+ last_focused_frame_ = focused;
+ if (document.get()) {
+ RefPtr<Node> focused_node = document->focusedNode();
+ if (focused_node.get()) {
+ // To workaround bug #792423, we do not blur the focused node. This
+ // should be reenabled when we merge a WebKit that has the fix for
+ // http://bugs.webkit.org/show_bug.cgi?id=16928.
+ // last_focused_node_ = focused_node;
+ // document->setFocusedNode(NULL);
+ }
+ }
+ frame->page()->focusController()->setFocusedFrame(0);
+ // Finish an ongoing composition to delete the composition node.
+ Editor* editor = focused->editor();
+ if (editor && editor->hasComposition())
+ editor->confirmComposition();
+ ime_accept_events_ = false;
+ }
+ // Make sure the main frame doesn't think it has focus.
+ if (frame != focused.get())
+ frame->selectionController()->setFocused(false);
+ }
+}
+
+// TODO(jcampan): http://b/issue?id=1157486 this is needed to work-around
+// issues caused by the fix for bug #792423 and should be removed when that
+// bug is fixed.
+void WebViewImpl::StoreFocusForFrame(WebFrame* frame) {
+ DCHECK(frame);
+
+ // We only want to store focus info if we are the focused frame and if we have
+ // not stored it already.
+ WebCore::Frame* webcore_frame = static_cast<WebFrameImpl*>(frame)->frame();
+ if (last_focused_frame_.get() != webcore_frame || last_focused_node_.get())
+ return;
+
+ // Clear out who last had focus. If someone has focus, the refs will be
+ // updated below.
+ ReleaseFocusReferences();
+
+ last_focused_frame_ = webcore_frame;
+ RefPtr<Document> document = last_focused_frame_->document();
+ if (document.get()) {
+ RefPtr<Node> focused_node = document->focusedNode();
+ if (focused_node.get()) {
+ last_focused_node_ = focused_node;
+ document->setFocusedNode(NULL);
+ }
+ }
+}
+
+void WebViewImpl::ImeSetComposition(int string_type, int cursor_position,
+ int target_start, int target_end,
+ int string_length,
+ const wchar_t *string_data) {
+ Frame* focused = GetFocusedWebCoreFrame();
+ if (!focused || !ime_accept_events_) {
+ return;
+ }
+ Editor* editor = focused->editor();
+ if (!editor)
+ return;
+ if (!editor->canEdit()) {
+ // The input focus has been moved to another WebWidget object.
+ // We should use this |editor| object only to complete the ongoing
+ // composition.
+ if (!editor->hasComposition())
+ return;
+ }
+
+ if (string_type == 0) {
+ // A browser process sent an IPC message which does not contain a valid
+ // string, which means an ongoing composition has been canceled.
+ // If the ongoing composition has been canceled, replace the ongoing
+ // composition string with an empty string and complete it.
+ // TODO(hbono): Need to add a new function to cancel the ongoing
+ // composition to WebCore::Editor?
+ WebCore::String empty_string;
+ editor->confirmComposition(empty_string);
+ } else {
+ // A browser process sent an IPC message which contains a string to be
+ // displayed in this Editor object.
+ // To display the given string, set the given string to the
+ // m_compositionNode member of this Editor object and display it.
+ // NOTE: An empty string (often sent by Chinese IMEs and Korean IMEs)
+ // causes a panic in Editor::setComposition(), which deactivates the
+ // m_frame.m_sel member of this Editor object, i.e. we can never display
+ // composition strings in the m_compositionNode member.
+ // (I have not been able to find good methods for re-activating it.)
+ // Therefore, I have to prevent from calling Editor::setComposition()
+ // with its first argument an empty string.
+ if (string_length > 0) {
+ if (target_start < 0) target_start = 0;
+ if (target_end < 0) target_end = string_length;
+ WebCore::String composition_string(string_data, string_length);
+ // Create custom underlines.
+ // To emphasize the selection, the selected region uses a solid black
+ // for its underline while other regions uses a pale gray for theirs.
+ WTF::Vector<WebCore::CompositionUnderline> underlines(3);
+ underlines[0].startOffset = 0;
+ underlines[0].endOffset = target_start;
+ underlines[0].thick = true;
+ underlines[0].color.setRGB(0xd3, 0xd3, 0xd3);
+ underlines[1].startOffset = target_start;
+ underlines[1].endOffset = target_end;
+ underlines[1].thick = true;
+ underlines[1].color.setRGB(0x00, 0x00, 0x00);
+ underlines[2].startOffset = target_end;
+ underlines[2].endOffset = string_length;
+ underlines[2].thick = true;
+ underlines[2].color.setRGB(0xd3, 0xd3, 0xd3);
+ // When we use custom underlines, WebKit ("InlineTextBox.cpp" Line 282)
+ // prevents from writing a text in between 'selectionStart' and
+ // 'selectionEnd' somehow.
+ // Therefore, we use the 'cursor_position' for these arguments so that
+ // there are not any characters in the above region.
+ editor->setComposition(composition_string, underlines,
+ cursor_position, cursor_position);
+ }
+ // The given string is a result string, which means the ongoing
+ // composition has been completed. I have to call the
+ // Editor::confirmCompletion() and complete this composition.
+ if (string_type == GCS_RESULTSTR) {
+ editor->confirmComposition();
+ }
+ }
+}
+
+bool WebViewImpl::ImeUpdateStatus(bool* enable_ime, const void **id,
+ int* x, int* y) {
+ // Initialize the return values so that we can disable the IME attached
+ // to a browser process when an error occurs while retrieving information
+ // of the focused edit control.
+ *enable_ime = false;
+ *id = NULL;
+ *x = -1;
+ *y = -1;
+ // Store the position of the bottom-left corner of the caret.
+ // This process consists of the following four steps:
+ // 1. Retrieve the selection controller of the focused frame;
+ // 2. Retrieve the caret rectangle from the controller;
+ // 3. Convert the rectangle, which is relative to the parent view, to the
+ // one relative to the client window, and;
+ // 4. Store the position of its bottom-left corner.
+ const Frame* focused = GetFocusedWebCoreFrame();
+ if (!focused)
+ return false;
+ const Editor* editor = focused->editor();
+ if (!editor || !editor->canEdit())
+ return false;
+ const SelectionController* controller = focused->selectionController();
+ if (!controller)
+ return false;
+ const Node* node = controller->start().node();
+ if (!node)
+ return false;
+ const FrameView* view = node->document()->view();
+ if (!view)
+ return false;
+ IntRect rect = view->contentsToWindow(controller->caretRect());
+ *x = rect.x();
+ *y = rect.bottom();
+ return true;
+}
+
+void WebViewImpl::RestoreFocus() {
+ if (last_focused_frame_.get()) {
+ if (last_focused_frame_->page()) {
+ // last_focused_frame_ can be detached from the frame tree, thus,
+ // its page can be null.
+ last_focused_frame_->page()->focusController()->setFocusedFrame(
+ last_focused_frame_.get());
+ }
+ if (last_focused_node_.get()) {
+ // last_focused_node_ may be null, make sure it's valid before trying to
+ // focus it.
+ static_cast<Element*>(last_focused_node_.get())->focus();
+ }
+ // And clear out the refs.
+ ReleaseFocusReferences();
+ }
+}
+
+void WebViewImpl::SetInitialFocus(bool reverse) {
+ if (page_.get()) {
+ // So RestoreFocus does not focus anything when it is called.
+ ReleaseFocusReferences();
+
+ // Since we don't have a keyboard event, we'll create one.
+ WebKeyboardEvent keyboard_event;
+ keyboard_event.type = WebInputEvent::KEY_DOWN;
+ if (reverse)
+ keyboard_event.modifiers = WebInputEvent::SHIFT_KEY;
+ keyboard_event.key_code = VK_TAB;
+ keyboard_event.key_data = L'\t';
+ MakePlatformKeyboardEvent platform_event(keyboard_event);
+ // We have to set the key type explicitly to avoid an assert in the
+ // KeyboardEvent constructor.
+ platform_event.SetKeyType(PlatformKeyboardEvent::RawKeyDown);
+ KeyboardEvent webkit_event(platform_event, NULL);
+ page()->focusController()->setInitialFocus(
+ reverse ? WebCore::FocusDirectionBackward :
+ WebCore::FocusDirectionForward,
+ &webkit_event);
+ }
+}
+
+bool WebViewImpl::FocusedFrameNeedsSpellchecking() {
+ const WebCore::Frame* frame = GetFocusedWebCoreFrame();
+ if (!frame)
+ return false;
+ const WebCore::Document* document = frame->document();
+ if (!document)
+ return false;
+ const WebCore::Node* node = document->focusedNode();
+ if (!node)
+ return false;
+ const WebCore::RenderObject* renderer = node->renderer();
+ if (!renderer)
+ return false;
+ // We should also retrieve the contenteditable attribute of this element to
+ // determine if this element needs spell-checking.
+ const WebCore::EUserModify user_modify = renderer->style()->userModify();
+ return renderer->isTextArea() ||
+ user_modify == WebCore::READ_WRITE ||
+ user_modify == WebCore::READ_WRITE_PLAINTEXT_ONLY;
+}
+
+// Releases references used to restore focus.
+void WebViewImpl::ReleaseFocusReferences() {
+ if (last_focused_frame_.get()) {
+ last_focused_frame_.release();
+ last_focused_node_.release();
+ }
+}
+
+bool WebViewImpl::DownloadImage(int id, const GURL& image_url, int image_size) {
+ if (!main_frame_ || !main_frame_->frame())
+ return false;
+ image_fetchers_.insert(
+ new ImageResourceFetcher(this, id, image_url, image_size));
+ return true;
+}
+
+void WebViewImpl::SetPreferences(const WebPreferences& preferences) {
+ if (!page_.get())
+ return;
+
+ // Keep a local copy of the preferences struct for GetPreferences.
+ webprefs_ = preferences;
+
+ Settings* settings = page_->settings();
+
+ settings->setStandardFontFamily(webkit_glue::StdWStringToString(
+ preferences.standard_font_family));
+ settings->setFixedFontFamily(webkit_glue::StdWStringToString(
+ preferences.fixed_font_family));
+ settings->setSerifFontFamily(webkit_glue::StdWStringToString(
+ preferences.serif_font_family));
+ settings->setSansSerifFontFamily(webkit_glue::StdWStringToString(
+ preferences.sans_serif_font_family));
+ settings->setCursiveFontFamily(webkit_glue::StdWStringToString(
+ preferences.cursive_font_family));
+ settings->setFantasyFontFamily(webkit_glue::StdWStringToString(
+ preferences.fantasy_font_family));
+ settings->setDefaultFontSize(preferences.default_font_size);
+ settings->setDefaultFixedFontSize(preferences.default_fixed_font_size);
+ settings->setMinimumFontSize(preferences.minimum_font_size);
+ settings->setMinimumLogicalFontSize(preferences.minimum_logical_font_size);
+ settings->setDefaultTextEncodingName(webkit_glue::StdWStringToString(
+ preferences.default_encoding));
+ settings->setJavaScriptEnabled(preferences.javascript_enabled);
+ settings->setJavaScriptCanOpenWindowsAutomatically(
+ preferences.javascript_can_open_windows_automatically);
+ settings->setLoadsImagesAutomatically(
+ preferences.loads_images_automatically);
+ settings->setPluginsEnabled(preferences.plugins_enabled);
+ settings->setDOMPasteAllowed(preferences.dom_paste_enabled);
+ settings->setDeveloperExtrasEnabled(preferences.developer_extras_enabled);
+ settings->setShrinksStandaloneImagesToFit(
+ preferences.shrinks_standalone_images_to_fit);
+ settings->setUsesUniversalDetector(preferences.uses_universal_detector);
+ settings->setTextAreasAreResizable(preferences.text_areas_are_resizable);
+ if (preferences.user_style_sheet_enabled) {
+ settings->setUserStyleSheetLocation(webkit_glue::GURLToKURL(
+ preferences.user_style_sheet_location));
+ } else {
+ settings->setUserStyleSheetLocation(KURL());
+ }
+
+ // This setting affects the behavior of links in an editable region:
+ // clicking the link should select it rather than navigate to it.
+ // Safari uses the same default. It is unlikley an embedder would want to
+ // change this, since it would break existing rich text editors.
+ settings->setEditableLinkBehavior(WebCore::EditableLinkNeverLive);
+
+ settings->setUsesDashboardBackwardCompatibilityMode(
+ preferences.dashboard_compatibility_mode);
+ settings->setFontRenderingMode(NormalRenderingMode);
+ settings->setJavaEnabled(preferences.java_enabled);
+
+ // RenderTheme is a singleton that needs to know the default font size to
+ // draw some form controls. We let it know each time the size changes.
+ WebCore::RenderThemeWin::setDefaultFontSize(preferences.default_font_size);
+
+ // Used to make sure if the frameview needs layout, layout is triggered
+ // during Document::updateLayout(). TODO(tc): See bug 1199269 for more
+ // details.
+ FrameView* frameview = main_frame()->frameview();
+ if (frameview && frameview->needsLayout())
+ frameview->setNeedsLayout();
+}
+
+const WebPreferences& WebViewImpl::GetPreferences() {
+ return webprefs_;
+}
+
+// Set the encoding of the current main frame to the one selected by
+// a user in the encoding menu.
+void WebViewImpl::SetPageEncoding(const std::wstring& encoding_name) {
+ if (!main_frame_)
+ return;
+
+ if (!encoding_name.empty()) {
+ // only change override encoding, don't change default encoding
+ String new_encoding_name(encoding_name.data());
+ main_frame_->frame()->loader()->reloadAllowingStaleData(new_encoding_name);
+ }
+}
+
+// Return the canonical encoding name of current main webframe in webview.
+std::wstring WebViewImpl::GetMainFrameEncodingName() {
+ if (!main_frame_)
+ return std::wstring(L"");
+
+ String encoding_name = main_frame_->frame()->loader()->encoding();
+ return std::wstring(encoding_name.charactersWithNullTermination());
+}
+
+void WebViewImpl::MakeTextLarger() {
+ Frame* frame = main_frame()->frame();
+ double multiplier = std::min(std::pow(kTextSizeMultiplierRatio,
+ text_zoom_level_ + 1),
+ kMaxTextSizeMultiplier);
+ int zoom_factor = static_cast<int>(100.0 * multiplier);
+ if (zoom_factor != frame->zoomFactor()) {
+ ++text_zoom_level_;
+ frame->setZoomFactor(zoom_factor);
+ }
+}
+
+void WebViewImpl::MakeTextSmaller() {
+ Frame* frame = main_frame()->frame();
+ double multiplier = std::max(std::pow(kTextSizeMultiplierRatio,
+ text_zoom_level_ - 1),
+ kMinTextSizeMultiplier);
+ int zoom_factor = static_cast<int>(100.0 * multiplier);
+ if (zoom_factor != frame->zoomFactor()) {
+ --text_zoom_level_;
+ frame->setZoomFactor(zoom_factor);
+ }
+}
+
+void WebViewImpl::MakeTextStandardSize() {
+ text_zoom_level_ = 0;
+ main_frame()->frame()->setZoomFactor(100);
+}
+
+void WebViewImpl::CopyImageAt(int x, int y) {
+ IntPoint point = IntPoint(x, y);
+
+ Frame* frame = main_frame_->frame();
+ if (!frame)
+ return;
+
+ HitTestResult result =
+ frame->eventHandler()->hitTestResultAtPoint(point, false);
+
+ if (result.absoluteImageURL().isEmpty()) {
+ // There isn't actually an image at these coordinates. Might be because
+ // the window scrolled while the context menu was open or because the page
+ // changed itself between when we thought there was an image here and when
+ // we actually tried to retreive the image.
+ //
+ // TODO: implement a cache of the most recent HitTestResult to avoid having
+ // to do two hit tests.
+ return;
+ }
+
+ frame->editor()->copyImage(result);
+}
+
+void WebViewImpl::InspectElement(int x, int y) {
+ if (x == -1 || y == -1) {
+ page_->inspectorController()->inspect(NULL);
+ } else {
+ IntPoint point = IntPoint(x, y);
+ HitTestResult result(point);
+
+ if (Frame* frame = main_frame_->frame())
+ result = frame->eventHandler()->hitTestResultAtPoint(point, false);
+
+ if (!result.innerNonSharedNode())
+ return;
+
+ page_->inspectorController()->inspect(result.innerNonSharedNode());
+ }
+}
+
+void WebViewImpl::ShowJavaScriptConsole() {
+ page_->inspectorController()->showConsole();
+}
+
+void WebViewImpl::DragSourceEndedAt(
+ int client_x, int client_y, int screen_x, int screen_y) {
+ PlatformMouseEvent pme(IntPoint(client_x, client_y),
+ IntPoint(screen_x, screen_y),
+ NoButton, MouseEventMoved, 0, false, false, false,
+ false, 0);
+ main_frame_->frame()->eventHandler()->dragSourceEndedAt(pme,
+ DragOperationCopy);
+}
+
+void WebViewImpl::DragSourceMovedTo(
+ int client_x, int client_y, int screen_x, int screen_y) {
+ PlatformMouseEvent pme(IntPoint(client_x, client_y),
+ IntPoint(screen_x, screen_y),
+ LeftButton, MouseEventMoved, 0, false, false, false,
+ false, 0);
+ main_frame_->frame()->eventHandler()->dragSourceMovedTo(pme);
+}
+
+void WebViewImpl::DragSourceSystemDragEnded() {
+ page_->dragController()->dragEnded();
+ DCHECK(doing_drag_and_drop_);
+ doing_drag_and_drop_ = false;
+}
+
+bool WebViewImpl::DragTargetDragEnter(const WebDropData& drop_data,
+ int client_x, int client_y, int screen_x, int screen_y) {
+ DCHECK(!current_drop_data_.get());
+
+ // Copy drop_data into current_drop_data_.
+ WebDropData* drop_data_copy = new WebDropData;
+ *drop_data_copy = drop_data;
+ current_drop_data_.reset(drop_data_copy);
+
+ DragData drag_data(reinterpret_cast<DragDataRef>(current_drop_data_.get()),
+ IntPoint(client_x, client_y), IntPoint(screen_x, screen_y),
+ kDropTargetOperation);
+ DragOperation effect = page_->dragController()->dragEntered(&drag_data);
+ return effect != DragOperationNone;
+}
+
+bool WebViewImpl::DragTargetDragOver(
+ int client_x, int client_y, int screen_x, int screen_y) {
+ DCHECK(current_drop_data_.get());
+ DragData drag_data(reinterpret_cast<DragDataRef>(current_drop_data_.get()),
+ IntPoint(client_x, client_y), IntPoint(screen_x, screen_y),
+ kDropTargetOperation);
+ DragOperation effect = page_->dragController()->dragUpdated(&drag_data);
+ return effect != DragOperationNone;
+}
+
+void WebViewImpl::DragTargetDragLeave() {
+ DCHECK(current_drop_data_.get());
+ DragData drag_data(reinterpret_cast<DragDataRef>(current_drop_data_.get()),
+ IntPoint(), IntPoint(), DragOperationNone);
+ page_->dragController()->dragExited(&drag_data);
+ current_drop_data_.reset(NULL);
+}
+
+void WebViewImpl::DragTargetDrop(
+ int client_x, int client_y, int screen_x, int screen_y) {
+ DCHECK(current_drop_data_.get());
+ DragData drag_data(reinterpret_cast<DragDataRef>(current_drop_data_.get()),
+ IntPoint(client_x, client_y), IntPoint(screen_x, screen_y),
+ kDropTargetOperation);
+ page_->dragController()->performDrag(&drag_data);
+ current_drop_data_.reset(NULL);
+}
+
+SearchableFormData* WebViewImpl::CreateSearchableFormDataForFocusedNode() {
+ if (!main_frame_)
+ return NULL;
+
+ Frame* frame = main_frame_->frame();
+ if (!frame)
+ return NULL;
+
+ if (RefPtr<Frame> focused =
+ frame->page()->focusController()->focusedFrame()) {
+ RefPtr<Document> document = focused->document();
+ if (document.get()) {
+ RefPtr<Node> focused_node = document->focusedNode();
+ if (focused_node.get() &&
+ focused_node->nodeType() == Node::ELEMENT_NODE) {
+ return SearchableFormData::Create(
+ static_cast<Element*>(focused_node.get()));
+ }
+ }
+ }
+ return NULL;
+}
+
+void WebViewImpl::DidCommitLoad(bool* is_new_navigation) {
+ if (is_new_navigation)
+ *is_new_navigation = observed_new_navigation_;
+
+#ifndef NDEBUG
+ DCHECK(!observed_new_navigation_ ||
+ main_frame_->frame()->loader()->documentLoader() == new_navigation_loader_);
+ new_navigation_loader_ = NULL;
+#endif
+ observed_new_navigation_ = false;
+}
+
+void WebViewImpl::StartDragging(const WebDropData& drop_data) {
+ if (delegate_) {
+ DCHECK(!doing_drag_and_drop_);
+ doing_drag_and_drop_ = true;
+ delegate_->StartDragging(this, drop_data);
+ }
+}
+
+const WebCore::Node* WebViewImpl::getInspectedNode(WebCore::Frame* frame) {
+ DCHECK(frame);
+ WebFrameImpl* webframe_impl = WebFrameImpl::FromFrame(frame);
+ if (!webframe_impl)
+ return NULL;
+
+ return webframe_impl->inspected_node();
+}
+
+void WebViewImpl::ImageResourceDownloadDone(ImageResourceFetcher* fetcher,
+ bool errored,
+ const SkBitmap& image) {
+ if (delegate_) {
+ delegate_->DidDownloadImage(fetcher->id(), fetcher->image_url(), errored,
+ image);
+ }
+ DeleteImageResourceFetcher(fetcher);
+}
+
+//-----------------------------------------------------------------------------
+// WebCore::WidgetClientWin
+
+HWND WebViewImpl::containingWindow() {
+ return delegate_ ? delegate_->GetContainingWindow(this) : NULL;
+}
+
+void WebViewImpl::invalidateRect(const IntRect& damaged_rect) {
+ if (delegate_)
+ delegate_->DidInvalidateRect(this, gfx::Rect(damaged_rect.x(),
+ damaged_rect.y(),
+ damaged_rect.width(),
+ damaged_rect.height()));
+}
+
+void WebViewImpl::scrollRect(int dx, int dy, const IntRect& clip_rect) {
+ if (delegate_)
+ delegate_->DidScrollRect(this, dx, dy, gfx::Rect(clip_rect.x(),
+ clip_rect.y(),
+ clip_rect.width(),
+ clip_rect.height()));
+}
+
+void WebViewImpl::popupOpened(WebCore::Widget* widget,
+ const WebCore::IntRect& bounds) {
+ if (!delegate_)
+ return;
+
+ WebWidgetImpl* webwidget =
+ static_cast<WebWidgetImpl*>(delegate_->CreatePopupWidget(this));
+ webwidget->Init(widget, gfx::Rect(bounds.x(), bounds.y(),
+ bounds.width(), bounds.height()));
+}
+
+void WebViewImpl::popupClosed(WebCore::Widget* widget) {
+ NOTREACHED() << "popupClosed called on a non-popup";
+}
+
+void WebViewImpl::setCursor(const WebCore::Cursor& cursor) {
+ if (delegate_)
+ delegate_->SetCursor(this, cursor.impl());
+}
+
+void WebViewImpl::setFocus() {
+ if (delegate_)
+ delegate_->Focus(this);
+}
+
+const SkBitmap* WebViewImpl::getPreloadedResourceBitmap(int resource_id) {
+ if (!delegate_)
+ return NULL;
+
+ return delegate_->GetPreloadedResourceBitmap(resource_id);
+}
+
+void WebViewImpl::onScrollPositionChanged(WebCore::Widget* widget) {
+ // Scroll position changes should be reflected in the session history.
+ if (delegate_)
+ delegate_->OnNavStateChanged(this);
+}
+
+const WTF::Vector<RefPtr<WebCore::Range> >* WebViewImpl::getTickmarks(
+ WebCore::Frame* frame) {
+ DCHECK(frame);
+ WebFrameImpl* webframe_impl = WebFrameImpl::FromFrame(frame);
+ if (!webframe_impl)
+ return NULL;
+
+ return &webframe_impl->tickmarks();
+}
+
+size_t WebViewImpl::getActiveTickmarkIndex(WebCore::Frame* frame) {
+ DCHECK(frame);
+ WebFrameImpl* webframe_impl = WebFrameImpl::FromFrame(frame);
+ if (!webframe_impl)
+ return kNoTickmark;
+
+ // The mainframe can tell us if we are the frame with the active tick-mark.
+ if (webframe_impl != main_frame_->active_tickmark_frame())
+ return kNoTickmark;
+
+ return webframe_impl->active_tickmark_index();
+}
+
+//-----------------------------------------------------------------------------
+// WebCore::BackForwardListClient
+
+void WebViewImpl::didAddHistoryItem(WebCore::HistoryItem* item) {
+ // If WebCore adds a new HistoryItem, it means this is a new navigation
+ // (ie, not a reload or back/forward).
+ observed_new_navigation_ = true;
+#ifndef NDEBUG
+ new_navigation_loader_ = main_frame_->frame()->loader()->documentLoader();
+#endif
+}
+
+void WebViewImpl::willGoToHistoryItem(WebCore::HistoryItem* item) {
+ if (pending_history_item_) {
+ if (item == pending_history_item_->GetHistoryItem()) {
+ // Let the main frame know this HistoryItem is loading, so it can cache
+ // any ExtraData when the DataSource is created.
+ main_frame_->set_currently_loading_history_item(pending_history_item_);
+ pending_history_item_ = 0;
+ }
+ }
+}
+
+WebCore::HistoryItem* WebViewImpl::itemAtIndex(int index) {
+ if (!delegate_)
+ return NULL;
+
+ WebHistoryItem* item = delegate_->GetHistoryEntryAtOffset(index);
+ if (!item)
+ return NULL;
+
+ // If someone has asked for a history item, we probably want to navigate to
+ // it soon. Keep track of it until willGoToHistoryItem is called.
+ pending_history_item_ = static_cast<WebHistoryItemImpl*>(item);
+ return pending_history_item_->GetHistoryItem();
+}
+
+void WebViewImpl::goToItemAtIndexAsync(int index) {
+ if (delegate_)
+ delegate_->GoToEntryAtOffsetAsync(index);
+}
+
+int WebViewImpl::backListCount() {
+ if (!delegate_)
+ return 0;
+
+ return delegate_->GetHistoryBackListCount();
+}
+
+int WebViewImpl::forwardListCount() {
+ if (!delegate_)
+ return 0;
+
+ return delegate_->GetHistoryForwardListCount();
+}
+
+void WebViewImpl::DeleteImageResourceFetcher(ImageResourceFetcher* fetcher) {
+ DCHECK(image_fetchers_.find(fetcher) != image_fetchers_.end());
+ image_fetchers_.erase(fetcher);
+
+ // We're in the callback from the ImageResourceFetcher, best to delay
+ // deletion.
+ MessageLoop::current()->DeleteSoon(FROM_HERE, fetcher);
+}
diff --git a/webkit/glue/webview_impl.h b/webkit/glue/webview_impl.h
new file mode 100644
index 0000000..e22c49f
--- /dev/null
+++ b/webkit/glue/webview_impl.h
@@ -0,0 +1,331 @@
+// 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 WEBKIT_GLUE_WEBVIEW_IMPL_H__
+#define WEBKIT_GLUE_WEBVIEW_IMPL_H__
+
+#include <set>
+
+#include "base/basictypes.h"
+#include "base/gfx/point.h"
+#include "base/gfx/size.h"
+#include "webkit/glue/webdropdata.h"
+#include "webkit/glue/webframe_impl.h"
+#include "webkit/glue/webpreferences.h"
+#include "webkit/glue/webview.h"
+
+#pragma warning(push, 0)
+#include "webkit/port/history/BackForwardList.h"
+#include "webkit/port/platform/WidgetClientWin.h"
+#pragma warning(pop)
+
+namespace WebCore {
+ class Frame;
+ class HistoryItem;
+ class KeyboardEvent;
+ class Page;
+ class PlatformKeyboardEvent;
+ class Range;
+ class Widget;
+}
+
+class ImageResourceFetcher;
+class SearchableFormData;
+struct WebDropData;
+class WebHistoryItemImpl;
+class WebKeyboardEvent;
+class WebMouseEvent;
+class WebMouseWheelEvent;
+class WebViewDelegate;
+
+class WebViewImpl : public WebView,
+ public WebCore::WidgetClientWin,
+ public WebCore::BackForwardListClient {
+ public:
+ // WebView
+ virtual bool ShouldClose();
+ virtual void Close();
+ virtual WebViewDelegate* GetDelegate();
+ virtual void SetUseEditorDelegate(bool value);
+ virtual void SetTabKeyCyclesThroughElements(bool value);
+ virtual WebFrame* GetMainFrame();
+ virtual WebFrame* GetFocusedFrame();
+ virtual void SetFocusedFrame(WebFrame* frame);
+ virtual WebFrame* GetFrameWithName(const std::wstring& name);
+ virtual WebFrame* GetPreviousFrameBefore(WebFrame* frame, bool wrap);
+ virtual WebFrame* GetNextFrameAfter(WebFrame* frame, bool wrap);
+ virtual void Resize(const gfx::Size& new_size);
+ virtual gfx::Size GetSize() { return size(); }
+ virtual void Layout();
+ virtual void Paint(gfx::PlatformCanvas* canvas, const gfx::Rect& rect);
+ virtual bool HandleInputEvent(const WebInputEvent* input_event);
+ virtual void MouseCaptureLost();
+ virtual void SetFocus(bool enable);
+ virtual void StoreFocusForFrame(WebFrame* frame);
+ virtual void ImeSetComposition(int string_type, int cursor_position,
+ int target_start, int target_end,
+ int string_length,
+ const wchar_t *string_data);
+ virtual bool ImeUpdateStatus(bool* enable_ime, const void** id,
+ int* x, int* y);
+ virtual void StopLoading();
+ virtual void SetBackForwardListSize(int size);
+ virtual void RestoreFocus();
+ virtual void SetInitialFocus(bool reverse);
+ virtual bool FocusedFrameNeedsSpellchecking();
+ virtual bool DownloadImage(int id, const GURL& image_url, int image_size);
+ virtual void SetPreferences(const WebPreferences& preferences);
+ virtual const WebPreferences& GetPreferences();
+ virtual void SetPageEncoding(const std::wstring& encoding_name);
+ virtual std::wstring GetMainFrameEncodingName();
+ virtual void MakeTextLarger();
+ virtual void MakeTextSmaller();
+ virtual void MakeTextStandardSize();
+ virtual void CopyImageAt(int x, int y);
+ virtual void InspectElement(int x, int y);
+ virtual void ShowJavaScriptConsole();
+ virtual void DragSourceEndedAt(
+ int client_x, int client_y, int screen_x, int screen_y);
+ virtual void DragSourceMovedTo(
+ int client_x, int client_y, int screen_x, int screen_y);
+ virtual void DragSourceSystemDragEnded();
+ virtual bool DragTargetDragEnter(const WebDropData& drop_data,
+ int client_x, int client_y, int screen_x, int screen_y);
+ virtual bool DragTargetDragOver(
+ int client_x, int client_y, int screen_x, int screen_y);
+ virtual void DragTargetDragLeave();
+ virtual void DragTargetDrop(
+ int client_x, int client_y, int screen_x, int screen_y);
+
+ // WebViewImpl
+
+ const gfx::Size& size() const { return size_; }
+
+ const gfx::Point& last_mouse_down_point() const {
+ return last_mouse_down_point_;
+ }
+
+ WebCore::Frame* GetFocusedWebCoreFrame();
+
+ static WebViewImpl* FromPage(WebCore::Page* page);
+
+ WebFrameImpl* main_frame() {
+ return main_frame_;
+ }
+
+ WebViewDelegate* delegate() {
+ return delegate_.get();
+ }
+
+ // Returns the page object associated with this view. This may be NULL when
+ // the page is shutting down, but will be valid all other times.
+ WebCore::Page* page() const {
+ return page_.get();
+ }
+
+ WebHistoryItemImpl* pending_history_item() const {
+ return pending_history_item_;
+ }
+
+ void MouseMove(const WebMouseEvent& mouse_event);
+ void MouseLeave(const WebMouseEvent& mouse_event);
+ void MouseDown(const WebMouseEvent& mouse_event);
+ void MouseUp(const WebMouseEvent& mouse_event);
+ void MouseDoubleClick(const WebMouseEvent& mouse_event);
+ void MouseWheel(const WebMouseWheelEvent& wheel_event);
+ bool KeyEvent(const WebKeyboardEvent& key_event);
+ bool CharEvent(const WebKeyboardEvent& key_event);
+
+ // Handles context menu events orignated via the the keyboard. These
+ // include the VK_APPS virtual key and the Shift+F10 combine.
+ // Code is based on the Webkit function
+ // bool WebView::handleContextMenuEvent(WPARAM wParam, LPARAM lParam) in
+ // webkit\webkit\win\WebView.cpp. The only significant change in this
+ // function is the code to convert from a Keyboard event to the Right
+ // Mouse button down event.
+ bool SendContextMenuEvent(const WebKeyboardEvent& event);
+
+ // Releases references used to restore focus.
+ void ReleaseFocusReferences();
+
+ // Notifies the WebView that a load has been committed.
+ // is_new_navigation will be true if a new session history item should be
+ // created for that load.
+ void DidCommitLoad(bool* is_new_navigation);
+
+ bool context_menu_allowed() const {
+ return context_menu_allowed_;
+ }
+
+ // Set the disposition for how this webview is to be initially shown.
+ void set_window_open_disposition(WindowOpenDisposition disp) {
+ window_open_disposition_ = disp;
+ }
+ WindowOpenDisposition window_open_disposition() const {
+ return window_open_disposition_;
+ }
+
+ // Start a system drag and drop operation.
+ void StartDragging(const WebDropData& drop_data);
+
+ virtual const WebCore::Node* getInspectedNode(WebCore::Frame* frame);
+
+ // ImageResourceFetcher callback.
+ void ImageResourceDownloadDone(ImageResourceFetcher* fetcher,
+ bool errored,
+ const SkBitmap& image);
+
+ protected:
+ friend class WebView; // So WebView::Create can call our constructor
+
+ WebViewImpl();
+ ~WebViewImpl();
+
+ void ModifySelection(UINT message,
+ WebCore::Frame* frame,
+ const WebCore::PlatformKeyboardEvent& e);
+
+ // WebCore::WidgetClientWin
+ virtual HWND containingWindow();
+ virtual void invalidateRect(const WebCore::IntRect& damaged_rect);
+ virtual void scrollRect(int dx, int dy, const WebCore::IntRect& clip_rect);
+ virtual void popupOpened(WebCore::Widget* widget,
+ const WebCore::IntRect& bounds);
+ virtual void popupClosed(WebCore::Widget* widget);
+ virtual void setCursor(const WebCore::Cursor& cursor);
+ virtual void setFocus();
+ virtual const SkBitmap* getPreloadedResourceBitmap(int resource_id);
+ virtual void onScrollPositionChanged(WebCore::Widget* widget);
+ virtual const WTF::Vector<RefPtr<WebCore::Range> >* getTickmarks(
+ WebCore::Frame* frame);
+ virtual size_t getActiveTickmarkIndex(WebCore::Frame* frame);
+
+ // WebCore::BackForwardListClient
+ virtual void didAddHistoryItem(WebCore::HistoryItem* item);
+ virtual void willGoToHistoryItem(WebCore::HistoryItem* item);
+ virtual WebCore::HistoryItem* itemAtIndex(int index);
+ virtual void goToItemAtIndexAsync(int index);
+ virtual int backListCount();
+ virtual int forwardListCount();
+
+ // Creates and returns a new SearchableFormData for the focused node.
+ // It's up to the caller to free the returned SearchableFormData.
+ // This returns NULL if the focused node is NULL, or not in a valid form.
+ SearchableFormData* CreateSearchableFormDataForFocusedNode();
+
+ scoped_refptr<WebViewDelegate> delegate_;
+ gfx::Size size_;
+
+ scoped_refptr<WebFrameImpl> main_frame_;
+ gfx::Point last_mouse_position_;
+ // Reference to the Frame that last had focus. This is set once when
+ // we lose focus, and used when focus is gained to reinstall focus to
+ // the correct element.
+ RefPtr<WebCore::Frame> last_focused_frame_;
+ // Reference to the node that last had focus.
+ RefPtr<WebCore::Node> last_focused_node_;
+ scoped_ptr<WebCore::Page> page_;
+
+ // The last history item that was accessed via itemAtIndex(). We keep track
+ // of this until willGoToHistoryItem() is called, so we can track the
+ // navigation.
+ scoped_refptr<WebHistoryItemImpl> pending_history_item_;
+
+ // This flag is set when a new navigation is detected. It is used to satisfy
+ // the corresponding argument to WebViewDelegate::DidCommitLoadForFrame.
+ bool observed_new_navigation_;
+#ifndef NDEBUG
+ // Used to assert that the new navigation we observed is the same navigation
+ // when we make use of observed_new_navigation_.
+ const WebCore::DocumentLoader* new_navigation_loader_;
+#endif
+
+ // A copy of the WebPreferences object we receive from the browser.
+ WebPreferences webprefs_;
+
+ // A copy of the web drop data object we received from the browser.
+ scoped_ptr<WebDropData> current_drop_data_;
+
+ private:
+ // Returns true if the event was actually processed.
+ bool KeyEventDefault(const WebKeyboardEvent& event);
+
+ // Returns true if the view was scrolled.
+ bool ScrollViewWithKeyboard(int key_code);
+
+ // Removes fetcher from the set of pending image fetchers and deletes it.
+ // This is invoked after the download is completed (or fails).
+ void DeleteImageResourceFetcher(ImageResourceFetcher* fetcher);
+
+ // ImageResourceFetchers schedule via DownloadImage.
+ std::set<ImageResourceFetcher*> image_fetchers_;
+
+ // The point relative to the client area where the mouse was last pressed
+ // down. This is used by the drag client to determine what was under the
+ // mouse when the drag was initiated. We need to track this here in
+ // WebViewImpl since DragClient::startDrag does not pass the position the
+ // mouse was at when the drag was initiated, only the current point, which
+ // can be misleading as it is usually not over the element the user actually
+ // dragged by the time a drag is initiated.
+ gfx::Point last_mouse_down_point_;
+
+ // Keeps track of the current text zoom level. 0 means no zoom, positive
+ // values mean larger text, negative numbers mean smaller text.
+ int text_zoom_level_;
+
+ bool context_menu_allowed_;
+
+ bool doing_drag_and_drop_;
+
+ // Webkit expects keyPress events to be suppressed if the associated keyDown
+ // event was handled. Safari implements this behavior by peeking out the
+ // associated WM_CHAR event if the keydown was handled. We emulate
+ // this behavior by setting this flag if the keyDown was handled.
+ bool suppress_next_keypress_event_;
+
+ // The disposition for how this webview is to be initially shown.
+ WindowOpenDisposition window_open_disposition_;
+
+ // Represents whether or not this object should process incoming IME events.
+ bool ime_accept_events_;
+
+ // HACK: current_input_event is for ChromeClientImpl::show(), until we can fix
+ // WebKit to pass enough information up into ChromeClient::show() so we can
+ // decide if the window.open event was caused by a middle-mouse click
+public:
+ static const WebInputEvent* current_input_event() {
+ return g_current_input_event;
+ }
+private:
+ static const WebInputEvent* g_current_input_event;
+
+ DISALLOW_EVIL_CONSTRUCTORS(WebViewImpl);
+};
+
+#endif // WEBKIT_GLUE_WEBVIEW_IMPL_H__
diff --git a/webkit/glue/webwidget.h b/webkit/glue/webwidget.h
new file mode 100644
index 0000000..1f5f74c
--- /dev/null
+++ b/webkit/glue/webwidget.h
@@ -0,0 +1,100 @@
+// 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 WEBKIT_GLUE_WEBWIDGET_H__
+#define WEBKIT_GLUE_WEBWIDGET_H__
+
+#include "base/ref_counted.h"
+
+namespace gfx {
+class PlatformCanvas;
+class Rect;
+class Size;
+}
+
+class WebInputEvent;
+class WebWidgetDelegate;
+
+class WebWidget : public base::RefCounted<WebWidget> {
+ public:
+ WebWidget() {}
+ virtual ~WebWidget() {}
+
+ // This method creates a WebWidget that is initially invisible and positioned
+ // according to the given bounds relative to the specified parent window.
+ // The caller is responsible for showing the WebWidget's view window (see
+ // GetViewWindow) once it is ready to have the WebWidget appear on the screen.
+ static WebWidget* Create(WebWidgetDelegate* delegate);
+
+ // This method closes the WebWidget.
+ virtual void Close() = 0;
+
+ // Called to resize the WebWidget.
+ virtual void Resize(const gfx::Size& new_size) = 0;
+
+ // Returns the current size of the WebWidget.
+ virtual gfx::Size GetSize() = 0;
+
+ // Called to layout the WebWidget. This MUST be called before Paint, and it
+ // may result in calls to WebWidgetDelegate::DidInvalidateRect.
+ virtual void Layout() = 0;
+
+ // Called to paint the specified region of the WebWidget onto the given canvas.
+ // You MUST call Layout before calling this method. It is okay to call Paint
+ // multiple times once Layout has been called, assuming no other changes are
+ // made to the WebWidget (e.g., once events are processed, it should be assumed
+ // that another call to Layout is warranted before painting again).
+ virtual void Paint(gfx::PlatformCanvas* canvas, const gfx::Rect& rect) = 0;
+
+ // Called to inform the WebWidget of an input event.
+ // Returns true if the event has been processed, false otherwise.
+ virtual bool HandleInputEvent(const WebInputEvent* input_event) = 0;
+
+ // Called to inform the WebWidget that mouse capture was lost.
+ virtual void MouseCaptureLost() = 0;
+
+ // Called to inform the WebWidget that it has gained or lost keyboard focus.
+ virtual void SetFocus(bool enable) = 0;
+
+ // Called to inform the webwidget of a composition event from IMM
+ // (Input Method Manager).
+ virtual void ImeSetComposition(int string_type, int cursor_position,
+ int target_start, int target_end,
+ int string_length,
+ const wchar_t *string_data) = 0;
+
+ // Retrieve the status of this widget required by IME APIs.
+ virtual bool ImeUpdateStatus(bool* enable_ime, const void** node,
+ int* x, int* y) = 0;
+
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(WebWidget);
+};
+
+#endif // #ifndef WEBKIT_GLUE_WEBWIDGET_H__
diff --git a/webkit/glue/webwidget_delegate.h b/webkit/glue/webwidget_delegate.h
new file mode 100644
index 0000000..d68c38f
--- /dev/null
+++ b/webkit/glue/webwidget_delegate.h
@@ -0,0 +1,111 @@
+// 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 WEBKIT_GLUE_WEBWIDGET_DELEGATE_H__
+#define WEBKIT_GLUE_WEBWIDGET_DELEGATE_H__
+
+typedef struct HWND__* HWND;
+
+namespace gfx {
+ class Point;
+ class Rect;
+}
+
+enum WindowOpenDisposition;
+class WebWidget;
+class WebCursor;
+struct WebPluginGeometry;
+
+class WebWidgetDelegate {
+ public:
+ // Returns the HWND in which the WebWidget is embedded.
+ virtual HWND GetContainingWindow(WebWidget* webwidget) = 0;
+
+ // Called when a region of the WebWidget needs to be re-painted.
+ virtual void DidInvalidateRect(WebWidget* webwidget, const gfx::Rect& rect) = 0;
+
+ // Called when a region of the WebWidget, given by clip_rect, should be
+ // scrolled by the specified dx and dy amounts.
+ virtual void DidScrollRect(WebWidget* webwidget, int dx, int dy,
+ const gfx::Rect& clip_rect) = 0;
+
+ // This method is called to instruct the window containing the WebWidget to
+ // show itself as the topmost window. This method is only used after a
+ // successful call to CreateWebWidget. |disposition| indicates how this new
+ // window should be displayed, but generally only means something for WebViews.
+ virtual void Show(WebWidget* webwidget, WindowOpenDisposition disposition) = 0;
+
+ // This method is called to instruct the window containing the WebWidget to
+ // close. Note: This method should just be the trigger that causes the
+ // WebWidget to eventually close. It should not actually be destroyed until
+ // after this call returns.
+ virtual void CloseWidgetSoon(WebWidget* webwidget) = 0;
+
+ // This method is called to focus the window containing the WebWidget so
+ // that it receives keyboard events.
+ virtual void Focus(WebWidget* webwidget) = 0;
+
+ // This method is called to unfocus the window containing the WebWidget so that
+ // it no longer receives keyboard events.
+ virtual void Blur(WebWidget* webwidget) = 0;
+
+ virtual void SetCursor(WebWidget* webwidget,
+ const WebCursor& cursor) = 0;
+ // Returns the location (x,y) of the WebWidget in screen coordinates.
+ virtual void GetWindowLocation(WebWidget* webwidget, gfx::Point* origin) = 0;
+
+ // This method is called to re-position the WebWidget on the screen. The given
+ // rect is in screen coordinates. The implementation may choose to ignore
+ // this call or modify the given rect. This method may be called before Show
+ // has been called.
+ // TODO(darin): this is more of a request; does this need to take effect
+ // synchronously?
+ virtual void SetWindowRect(WebWidget* webwidget, const gfx::Rect& rect) = 0;
+
+ // Keeps track of the necessary window move for a plugin window that resulted
+ // from a scroll operation. That way, all plugin windows can be moved at the
+ // same time as each other and the page.
+ virtual void DidMove(WebWidget* webwidget, const WebPluginGeometry& move) = 0;
+
+ // Suppress input events to other windows, and do not return until the widget
+ // is closed. This is used to support |window.showModalDialog|.
+ virtual void RunModal(WebWidget* webwidget) = 0;
+
+ // Owners depend on the delegates living as long as they do, so we ref them.
+ virtual void AddRef() = 0;
+ virtual void Release() = 0;
+
+ WebWidgetDelegate() { }
+ virtual ~WebWidgetDelegate() { }
+
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(WebWidgetDelegate);
+};
+
+#endif // #ifndef WEBKIT_GLUE_WEBWIDGET_DELEGATE_H__
diff --git a/webkit/glue/webwidget_impl.cc b/webkit/glue/webwidget_impl.cc
new file mode 100644
index 0000000..010d9f0
--- /dev/null
+++ b/webkit/glue/webwidget_impl.cc
@@ -0,0 +1,275 @@
+// 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 "config.h"
+
+#pragma warning(push, 0)
+#include "Cursor.h"
+#include "FramelessScrollView.h"
+#include "FrameView.h"
+#include "IntRect.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformMouseEvent.h"
+#include "PlatformWheelEvent.h"
+#pragma warning(pop)
+
+#undef LOG
+#include "base/gfx/platform_canvas.h"
+#include "base/gfx/rect.h"
+#include "base/logging.h"
+#include "webkit/glue/event_conversion.h"
+#include "webkit/glue/webinputevent.h"
+#include "webkit/glue/webwidget_delegate.h"
+#include "webkit/glue/webwidget_impl.h"
+#include "graphics/SkiaUtils.h"
+
+using namespace WebCore;
+
+// WebWidget ----------------------------------------------------------------
+
+/*static*/
+WebWidget* WebWidget::Create(WebWidgetDelegate* delegate) {
+ WebWidgetImpl* instance = new WebWidgetImpl(delegate);
+ instance->AddRef();
+ return instance;
+}
+
+WebWidgetImpl::WebWidgetImpl(WebWidgetDelegate* delegate)
+ : delegate_(delegate),
+ widget_(NULL) {
+ // set to impossible point so we always get the first mouse pos
+ last_mouse_position_.SetPoint(-1, -1);
+}
+
+WebWidgetImpl::~WebWidgetImpl() {
+ if (widget_) {
+ widget_->setClient(NULL);
+ }
+}
+
+void WebWidgetImpl::Init(WebCore::Widget* widget, const gfx::Rect& bounds) {
+ DCHECK(widget->isFrameView());
+ widget_ = static_cast<FramelessScrollView*>(widget);
+
+ widget_->setClient(this);
+
+ if (delegate_) {
+ delegate_->SetWindowRect(this, bounds);
+ delegate_->Show(this, WindowOpenDisposition());
+ }
+}
+
+void WebWidgetImpl::MouseMove(const WebMouseEvent& event) {
+ // don't send mouse move messages if the mouse hasn't moved.
+ if (event.x != last_mouse_position_.x() ||
+ event.y != last_mouse_position_.y()) {
+ last_mouse_position_.SetPoint(event.x, event.y);
+
+ widget_->handleMouseMoveEvent(MakePlatformMouseEvent(widget_, event));
+ }
+}
+
+void WebWidgetImpl::MouseLeave(const WebMouseEvent& event) {
+ widget_->handleMouseMoveEvent(MakePlatformMouseEvent(widget_, event));
+}
+
+void WebWidgetImpl::MouseDown(const WebMouseEvent& event) {
+ widget_->handleMouseDownEvent(MakePlatformMouseEvent(widget_, event));
+}
+
+void WebWidgetImpl::MouseUp(const WebMouseEvent& event) {
+ MouseCaptureLost();
+ widget_->handleMouseReleaseEvent(MakePlatformMouseEvent(widget_, event));
+}
+
+void WebWidgetImpl::MouseWheel(const WebMouseWheelEvent& event) {
+ widget_->handleWheelEvent(MakePlatformWheelEvent(widget_, event));
+}
+
+bool WebWidgetImpl::KeyEvent(const WebKeyboardEvent& event) {
+ return widget_->handleKeyEvent(MakePlatformKeyboardEvent(event));
+}
+
+// WebWidget -------------------------------------------------------------------
+
+void WebWidgetImpl::Close() {
+ if (widget_)
+ widget_->hide();
+
+ delegate_ = NULL;
+}
+
+void WebWidgetImpl::Resize(const gfx::Size& new_size) {
+ if (size_ == new_size)
+ return;
+ size_ = new_size;
+
+ if (widget_) {
+ IntRect new_geometry(0, 0, size_.width(), size_.height());
+ widget_->setFrameGeometry(new_geometry);
+ }
+
+ if (delegate_) {
+ gfx::Rect damaged_rect(0, 0, size_.width(), size_.height());
+ delegate_->DidInvalidateRect(this, damaged_rect);
+ }
+}
+
+void WebWidgetImpl::Layout() {
+}
+
+void WebWidgetImpl::Paint(gfx::PlatformCanvas* canvas, const gfx::Rect& rect) {
+ if (!widget_)
+ return;
+
+ if (!rect.IsEmpty()) {
+ PlatformContextSkia context(canvas);
+
+ // PlatformGraphicsContext is actually a pointer to PlatformContextSkia.
+ GraphicsContext gc(reinterpret_cast<PlatformGraphicsContext*>(&context));
+ IntRect dirty_rect(rect.x(), rect.y(), rect.width(), rect.height());
+
+ widget_->paint(&gc, dirty_rect);
+ }
+}
+
+bool WebWidgetImpl::HandleInputEvent(const WebInputEvent* input_event) {
+ if (!widget_)
+ return false;
+
+ // TODO (jcampan): WebKit seems to always return false on mouse events
+ // methods. For now we'll assume it has processed them (as we are only
+ // interested in whether keyboard events are processed).
+ switch (input_event->type) {
+ case WebInputEvent::MOUSE_MOVE:
+ MouseMove(*static_cast<const WebMouseEvent*>(input_event));
+ return true;
+
+ case WebInputEvent::MOUSE_LEAVE:
+ MouseLeave(*static_cast<const WebMouseEvent*>(input_event));
+ return true;
+
+ case WebInputEvent::MOUSE_WHEEL:
+ MouseWheel(*static_cast<const WebMouseWheelEvent*>(input_event));
+ return true;
+
+ case WebInputEvent::MOUSE_DOWN:
+ case WebInputEvent::MOUSE_DOUBLE_CLICK:
+ MouseDown(*static_cast<const WebMouseEvent*>(input_event));
+ return true;
+
+ case WebInputEvent::MOUSE_UP:
+ MouseUp(*static_cast<const WebMouseEvent*>(input_event));
+ return true;
+
+ case WebInputEvent::KEY_DOWN:
+ case WebInputEvent::KEY_UP:
+ return KeyEvent(*static_cast<const WebKeyboardEvent*>(input_event));
+ }
+ return false;
+}
+
+void WebWidgetImpl::MouseCaptureLost() {
+}
+
+void WebWidgetImpl::SetFocus(bool enable) {
+}
+
+void WebWidgetImpl::ImeSetComposition(int string_type, int cursor_position,
+ int target_start, int target_end,
+ int string_length,
+ const wchar_t *string_data) {
+}
+
+bool WebWidgetImpl::ImeUpdateStatus(bool* enable_ime, const void** id,
+ int* x, int* y) {
+ return false;
+}
+
+const SkBitmap* WebWidgetImpl::getPreloadedResourceBitmap(int resource_id) {
+ return NULL;
+}
+
+const WTF::Vector<RefPtr<WebCore::Range> >* WebWidgetImpl::getTickmarks(
+ WebCore::Frame* frame) {
+ return NULL;
+}
+
+size_t WebWidgetImpl::getActiveTickmarkIndex(WebCore::Frame* frame) {
+ return kNoTickmark;
+}
+
+void WebWidgetImpl::onScrollPositionChanged(Widget* widget) {
+}
+
+//-----------------------------------------------------------------------------
+// WebCore::WidgetClientWin
+
+HWND WebWidgetImpl::containingWindow() {
+ return delegate_ ? delegate_->GetContainingWindow(this) : NULL;
+}
+
+void WebWidgetImpl::invalidateRect(const IntRect& damaged_rect) {
+ if (delegate_)
+ delegate_->DidInvalidateRect(this, gfx::Rect(damaged_rect.x(),
+ damaged_rect.y(),
+ damaged_rect.width(),
+ damaged_rect.height()));
+}
+
+void WebWidgetImpl::scrollRect(int dx, int dy, const IntRect& clip_rect) {
+ if (delegate_)
+ delegate_->DidScrollRect(this, dx, dy, gfx::Rect(clip_rect.x(),
+ clip_rect.y(),
+ clip_rect.width(),
+ clip_rect.height()));
+}
+
+void WebWidgetImpl::popupOpened(WebCore::Widget* widget,
+ const WebCore::IntRect& bounds) {
+ NOTREACHED() << "popupOpened called on a popup";
+}
+
+void WebWidgetImpl::popupClosed(WebCore::Widget* widget) {
+ DCHECK(widget == widget_);
+ if (widget_) {
+ widget_->setClient(NULL);
+ widget_ = NULL;
+ }
+ delegate_->CloseWidgetSoon(this);
+}
+
+void WebWidgetImpl::setCursor(const WebCore::Cursor& cursor) {
+ if (delegate_)
+ delegate_->SetCursor(this, cursor.impl());
+}
+
+void WebWidgetImpl::setFocus() {
+ delegate_->Focus(this);
+}
diff --git a/webkit/glue/webwidget_impl.h b/webkit/glue/webwidget_impl.h
new file mode 100644
index 0000000..e885c1d
--- /dev/null
+++ b/webkit/glue/webwidget_impl.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 WEBKIT_GLUE_WEBWIDGET_IMPL_H__
+#define WEBKIT_GLUE_WEBWIDGET_IMPL_H__
+
+#include "base/basictypes.h"
+#include "base/gfx/point.h"
+#include "base/gfx/size.h"
+#include "webkit/glue/webwidget.h"
+
+#pragma warning(push, 0)
+#include "WidgetClientWin.h"
+#pragma warning(pop)
+
+namespace WebCore {
+ class Frame;
+ class FramelessScrollView;
+ class KeyboardEvent;
+ class Page;
+ class PlatformKeyboardEvent;
+ class Range;
+ class Widget;
+}
+
+class WebKeyboardEvent;
+class WebMouseEvent;
+class WebMouseWheelEvent;
+class WebWidgetDelegate;
+
+class WebWidgetImpl : public WebWidget, public WebCore::WidgetClientWin {
+ public:
+ // WebWidget
+ virtual void Close();
+ virtual void Resize(const gfx::Size& new_size);
+ virtual gfx::Size GetSize() { return size(); }
+ virtual void Layout();
+ virtual void Paint(gfx::PlatformCanvas* canvas, const gfx::Rect& rect);
+ virtual bool HandleInputEvent(const WebInputEvent* input_event);
+ virtual void MouseCaptureLost();
+ virtual void SetFocus(bool enable);
+ virtual void ImeSetComposition(int string_type, int cursor_position,
+ int target_start, int target_end,
+ int string_length,
+ const wchar_t *string_data);
+ virtual bool ImeUpdateStatus(bool* enable_ime, const void** id,
+ int* x, int* y);
+
+ // WebWidgetImpl
+ void Init(WebCore::Widget* widget, const gfx::Rect& bounds);
+
+ const gfx::Size& size() const { return size_; }
+
+ WebWidgetDelegate* delegate() {
+ return delegate_;
+ }
+
+ void MouseMove(const WebMouseEvent& mouse_event);
+ void MouseLeave(const WebMouseEvent& mouse_event);
+ void MouseDown(const WebMouseEvent& mouse_event);
+ void MouseUp(const WebMouseEvent& mouse_event);
+ void MouseDoubleClick(const WebMouseEvent& mouse_event);
+ void MouseWheel(const WebMouseWheelEvent& wheel_event);
+ bool KeyEvent(const WebKeyboardEvent& key_event);
+
+ protected:
+ friend class WebWidget; // So WebWidget::Create can call our constructor
+
+ WebWidgetImpl(WebWidgetDelegate* delegate);
+ ~WebWidgetImpl();
+
+ // WebCore::WidgetClientWin
+ virtual HWND containingWindow();
+ virtual void invalidateRect(const WebCore::IntRect& damaged_rect);
+ virtual void scrollRect(int dx, int dy, const WebCore::IntRect& clip_rect);
+ virtual void popupOpened(WebCore::Widget* widget,
+ const WebCore::IntRect& bounds);
+ virtual void popupClosed(WebCore::Widget* widget);
+ virtual void setCursor(const WebCore::Cursor& cursor);
+ virtual void setFocus();
+ virtual const SkBitmap* getPreloadedResourceBitmap(int resource_id);
+ virtual void onScrollPositionChanged(WebCore::Widget* widget);
+ virtual const WTF::Vector<RefPtr<WebCore::Range> >* getTickmarks(
+ WebCore::Frame* frame);
+ virtual size_t getActiveTickmarkIndex(WebCore::Frame* frame);
+
+ WebWidgetDelegate* delegate_;
+ gfx::Size size_;
+
+ gfx::Point last_mouse_position_;
+
+ // This is a non-owning ref. The popup will notify us via popupClosed()
+ // before it is destroyed.
+ WebCore::FramelessScrollView* widget_;
+
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(WebWidgetImpl);
+};
+
+#endif // WEBKIT_GLUE_WEBWIDGET_IMPL_H__
diff --git a/webkit/glue/window_open_disposition.h b/webkit/glue/window_open_disposition.h
new file mode 100644
index 0000000..1bf6801
--- /dev/null
+++ b/webkit/glue/window_open_disposition.h
@@ -0,0 +1,45 @@
+// 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 WEBKIT_GLUE_WINDOW_OPEN_DISPOSITION_H__
+#define WEBKIT_GLUE_WINDOW_OPEN_DISPOSITION_H__
+
+enum WindowOpenDisposition {
+ SUPPRESS_OPEN,
+ CURRENT_TAB,
+ NEW_FOREGROUND_TAB,
+ NEW_BACKGROUND_TAB,
+ NEW_POPUP,
+ NEW_WINDOW,
+ SAVE_TO_DISK,
+ OFF_THE_RECORD,
+ IGNORE_ACTION
+};
+
+#endif // WEBKIT_GLUE_WINDOW_OPEN_DISPOSITION_H__