summaryrefslogtreecommitdiffstats
path: root/WebKit
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2010-09-10 19:21:43 +0100
committerBen Murdoch <benm@google.com>2010-09-13 15:40:15 +0100
commitd0fc68897b5a7379951aaa5d50f0802dbe9e00d4 (patch)
treecaae822138344fe325cee666aadd08a600df70f0 /WebKit
parenta62761cdadec4e097c2dec84fb740e188e2a9f3a (diff)
downloadexternal_webkit-d0fc68897b5a7379951aaa5d50f0802dbe9e00d4.zip
external_webkit-d0fc68897b5a7379951aaa5d50f0802dbe9e00d4.tar.gz
external_webkit-d0fc68897b5a7379951aaa5d50f0802dbe9e00d4.tar.bz2
Initial autofill changes in libwebcore.
Initial checkin of WebKit source for enabling AutoFill on Android. This code calls into the chromium library to perform the autofill magic. There's still lots to do, but this and a corresponding change in external/chromium enable the feature (basically) end to end. The feature is disabled by default until we implement it more fully with some proper UI. To turn it on, set the ENABLE_AUTOFILL environment variable to "true" and rebuild. This is only useful for preliminary testing though as for now we use a precanned profile, which won't be relevant unless your name happens to be John Smith. Change-Id: I4a3e0e840617f7cf8f522af33ae1be560768a6c5
Diffstat (limited to 'WebKit')
-rw-r--r--WebKit/Android.mk11
-rw-r--r--WebKit/android/WebCoreSupport/ChromiumIncludes.h16
-rw-r--r--WebKit/android/WebCoreSupport/EditorClientAndroid.cpp27
-rw-r--r--WebKit/android/WebCoreSupport/EditorClientAndroid.h12
-rw-r--r--WebKit/android/WebCoreSupport/WebRequestContext.cpp4
-rw-r--r--WebKit/android/WebCoreSupport/WebUrlLoaderClient.h6
-rw-r--r--WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.cpp50
-rw-r--r--WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.h54
-rw-r--r--WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.cpp80
-rw-r--r--WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.h100
-rw-r--r--WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp637
-rw-r--r--WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h163
-rw-r--r--WebKit/android/WebCoreSupport/autofill/MainThreadProxy.cpp35
-rw-r--r--WebKit/android/WebCoreSupport/autofill/MainThreadProxy.h37
-rw-r--r--WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp125
-rw-r--r--WebKit/android/WebCoreSupport/autofill/WebAutoFill.h80
-rw-r--r--WebKit/android/jni/WebCoreFrameBridge.cpp11
17 files changed, 1444 insertions, 4 deletions
diff --git a/WebKit/Android.mk b/WebKit/Android.mk
index 01ede0f..a361974 100644
--- a/WebKit/Android.mk
+++ b/WebKit/Android.mk
@@ -106,3 +106,14 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \
android/wds/Command.cpp \
android/wds/Connection.cpp \
android/wds/DebugServer.cpp
+
+# Needed for autofill.
+ifeq ($(ENABLE_AUTOFILL),true)
+LOCAL_CFLAGS += -DENABLE_WEB_AUTOFILL
+
+LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \
+ android/WebCoreSupport/autofill/AutoFillHostAndroid.cpp \
+ android/WebCoreSupport/autofill/FormFieldAndroid.cpp \
+ android/WebCoreSupport/autofill/FormManagerAndroid.cpp \
+ android/WebCoreSupport/autofill/WebAutoFill.cpp
+endif # ENABLE_AUTOFILL == true
diff --git a/WebKit/android/WebCoreSupport/ChromiumIncludes.h b/WebKit/android/WebCoreSupport/ChromiumIncludes.h
index a7abef1..1a69ff1 100644
--- a/WebKit/android/WebCoreSupport/ChromiumIncludes.h
+++ b/WebKit/android/WebCoreSupport/ChromiumIncludes.h
@@ -26,6 +26,8 @@
#ifndef ChromiumIncludes_h
#define ChromiumIncludes_h
+#include "config.h"
+
// Include all external/chromium files in this file so the problems with the LOG
// and LOG_ASSERT defines can be handled in one place.
@@ -64,6 +66,20 @@
#include <net/url_request/url_request.h>
#include <net/url_request/url_request_context.h>
+#if ENABLE(WEB_AUTOFILL)
+#include <autofill/autofill_manager.h>
+#include <autofill/autofill_profile.h>
+#include <autofill/personal_data_manager.h>
+#include <base/logging.h>
+#include <base/scoped_vector.h>
+#include <base/string16.h>
+#include <base/utf_string_conversions.h>
+#include <chrome/browser/autofill/autofill_host.h>
+#include <chrome/browser/profile.h>
+#include <chrome/browser/tab_contents/tab_contents.h>
+#include <webkit/glue/form_data.h>
+#endif
+
#undef LOG
#if defined(LOG_WAS_DEFINED) && defined(LOG_PRI)
#define LOG(priority, tag, ...) LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
diff --git a/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp b/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp
index 45498c0..f5f8211 100644
--- a/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp
+++ b/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp
@@ -32,6 +32,7 @@
#include "EventNames.h"
#include "FocusController.h"
#include "Frame.h"
+#include "HTMLNames.h"
#include "KeyboardEvent.h"
#include "NotImplemented.h"
#include "PlatformKeyboardEvent.h"
@@ -39,6 +40,8 @@
#include "WebViewCore.h"
#include "WindowsKeyboardCodes.h"
+using namespace WebCore::HTMLNames;
+
namespace android {
void EditorClientAndroid::pageDestroyed() {
@@ -235,6 +238,19 @@ void EditorClientAndroid::respondToChangedSelection() {
Frame* frame = m_page->focusController()->focusedOrMainFrame();
if (!frame || !frame->view())
return;
+
+#if ENABLE(WEB_AUTOFILL)
+ WebCore::Node* focusedNode = frame->document()->focusedNode();
+ if (focusedNode && focusedNode->hasTagName(inputTag)) {
+ WebCore::HTMLInputElement* element = static_cast<WebCore::HTMLInputElement*>(focusedNode);
+ // TODO: If it's a text field, inform AutoFill that it should get AutoFill suggestions for
+ // the form it belongs to. AutoFill can also work with select-one elements (i.e. <select>
+ // without the "multiple" attribute set. Is it safe to call this function with select elements?
+ // How should AutoFill communicate select suggestions to Java?
+ if (element->isTextField())
+ m_autoFill->formFieldFocused(static_cast<HTMLFormControlElement*>(focusedNode));
+ }
+#endif
WebViewCore* webViewCore = WebViewCore::getWebViewCore(frame->view());
webViewCore->updateTextSelection();
}
@@ -261,4 +277,15 @@ void EditorClientAndroid::willSetInputMethodState()
{
notImplemented();
}
+
+#if ENABLE(WEB_AUTOFILL)
+WebAutoFill* EditorClientAndroid::getAutoFill()
+{
+ if (!m_autoFill)
+ m_autoFill.set(new WebAutoFill());
+
+ return m_autoFill.get();
+}
+#endif
+
}
diff --git a/WebKit/android/WebCoreSupport/EditorClientAndroid.h b/WebKit/android/WebCoreSupport/EditorClientAndroid.h
index 6d49f48..9aed88c 100644
--- a/WebKit/android/WebCoreSupport/EditorClientAndroid.h
+++ b/WebKit/android/WebCoreSupport/EditorClientAndroid.h
@@ -26,8 +26,14 @@
#ifndef EditorClientAndroid_h
#define EditorClientAndroid_h
+#include "config.h"
+
+
#include "EditorClient.h"
#include "Page.h"
+#include "autofill/WebAutoFill.h"
+
+#include <wtf/OwnPtr.h>
using namespace WebCore;
@@ -111,10 +117,16 @@ public:
void setPage(Page* page) { m_page = page; }
void setShouldChangeSelectedRange(bool shouldChangeSelectedRange) { m_shouldChangeSelectedRange = shouldChangeSelectedRange; }
void setUiGeneratedSelectionChange(bool uiGenerated) { m_uiGeneratedSelectionChange = uiGenerated; }
+#if ENABLE(WEB_AUTOFILL)
+ WebAutoFill* getAutoFill();
+#endif
private:
Page* m_page;
bool m_shouldChangeSelectedRange;
bool m_uiGeneratedSelectionChange;
+#if ENABLE(WEB_AUTOFILL)
+ OwnPtr<WebAutoFill> m_autoFill;
+#endif
};
}
diff --git a/WebKit/android/WebCoreSupport/WebRequestContext.cpp b/WebKit/android/WebCoreSupport/WebRequestContext.cpp
index dc9feae..0dda816 100644
--- a/WebKit/android/WebCoreSupport/WebRequestContext.cpp
+++ b/WebKit/android/WebCoreSupport/WebRequestContext.cpp
@@ -28,6 +28,7 @@
#include "WebRequestContext.h"
#include "JNIUtility.h"
+#include "WebUrlLoaderClient.h"
#include "jni.h"
#include <dirent.h>
#include <sys/types.h>
@@ -121,7 +122,8 @@ scoped_refptr<WebRequestContext> WebRequestContext::GetAndroidContextForPath(con
scoped_refptr<WebRequestContext> androidContext = new WebRequestContext();
androidContext->host_resolver_ = net::CreateSystemHostResolver(0);
- scoped_refptr<base::MessageLoopProxy> cacheMessageLoopProxy = base::MessageLoopProxy::CreateForCurrentThread();
+ base::Thread* ioThread = WebUrlLoaderClient::ioThread();
+ scoped_refptr<base::MessageLoopProxy> cacheMessageLoopProxy = ioThread->message_loop_proxy();
// Todo: check if the context takes ownership of the cache
net::HttpCache::DefaultBackend* defaultBackend = new net::HttpCache::DefaultBackend(net::DISK_CACHE, cachePath, 20 * 1024 * 1024, cacheMessageLoopProxy);
androidContext->http_transaction_factory_ = new net::HttpCache(androidContext->host_resolver(), net::ProxyService::CreateNull(), net::SSLConfigService::CreateSystemSSLConfigService(), net::HttpAuthHandlerFactory::CreateDefault(), 0, 0, defaultBackend);
diff --git a/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h b/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h
index 1a8118c..92c7bb5 100644
--- a/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h
+++ b/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h
@@ -83,6 +83,9 @@ public:
static void didFail(void*);
static void willSendRequest(void*);
+ // Handle to the chrome IO thread
+ static base::Thread* ioThread();
+
private:
void finish();
RefPtr<WebCore::ResourceHandle> m_resourceHandle;
@@ -93,9 +96,6 @@ private:
// Not an OwnPtr since it should be deleted on another thread
WebRequest* m_request;
- // Handle to the chrome IO thread
- static base::Thread* ioThread();
-
// Check if a request is active
bool isActive() const;
diff --git a/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.cpp b/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.cpp
new file mode 100644
index 0000000..51f7a93
--- /dev/null
+++ b/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 "AutoFillHostAndroid.h"
+
+#include "autofill/WebAutoFill.h"
+
+namespace android {
+
+AutoFillHostAndroid::AutoFillHostAndroid(WebAutoFill* autoFill)
+ : mAutoFill(autoFill)
+{
+}
+
+void AutoFillHostAndroid::AutoFillSuggestionsReturned(int queryId, const std::vector<string16>& names, const std::vector<string16>& labels, const std::vector<int>& uniqueIds)
+{
+ if (mAutoFill)
+ mAutoFill->fillFormFields(queryId, names[0], labels[0], uniqueIds[0]);
+}
+
+void AutoFillHostAndroid::AutoFillFormDataFilled(int queryId, const webkit_glue::FormData& form)
+{
+ if (mAutoFill)
+ mAutoFill->fillFormInPage(queryId, form);
+}
+
+}
diff --git a/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.h b/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.h
new file mode 100644
index 0000000..1984098
--- /dev/null
+++ b/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 AutoFillHostAndroid_h
+#define AutoFillHostAndroid_h
+
+#include "ChromiumIncludes.h"
+
+#include <vector>
+
+namespace webkit_glue {
+class FormData;
+}
+
+namespace android {
+class WebAutoFill;
+
+// This class receives the callbacks from the AutoFillManager in the Chromium code.
+class AutoFillHostAndroid : public AutoFillHost {
+public:
+ AutoFillHostAndroid(WebAutoFill* autoFill);
+ virtual ~AutoFillHostAndroid() { }
+
+ virtual void AutoFillSuggestionsReturned(int queryId, const std::vector<string16>& names, const std::vector<string16>& labels, const std::vector<int>& uniqueIds);
+ virtual void AutoFillFormDataFilled(int queryId, const webkit_glue::FormData&);
+
+private:
+ WebAutoFill* mAutoFill;
+};
+}
+
+#endif
diff --git a/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.cpp b/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.cpp
new file mode 100644
index 0000000..00213a1
--- /dev/null
+++ b/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2010 The Chromium Authors. All rights reserved.
+ * Copyright 2010, The Android Open Source Project
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 "FormFieldAndroid.h"
+
+#include "ChromiumIncludes.h"
+#include "HTMLFormControlElement.h"
+#include "HTMLInputElement.h"
+#include "HTMLSelectElement.h"
+
+// TODO: This file is taken from chromium/webkit/glue/form_field.h and
+// customised to use WebCore types rather than WebKit API types. It would
+// be nice and would ease future merge pain if the two could be combined.
+
+namespace webkit_glue {
+FormField::FormField()
+ : size_(0) {
+}
+
+FormField::FormField(WebCore::HTMLFormControlElement& element)
+ : size_(0) {
+ name_ = string16(element.name().characters());
+
+ // TODO: Extract the field label. For now we just use the field
+ // name.
+ label_ = name_;
+
+ form_control_type_ = string16(element.type().characters());
+ if (form_control_type_ == ASCIIToUTF16("text")) {
+ WebCore::HTMLInputElement* input_element = static_cast<WebCore::HTMLInputElement*>(&element);
+ value_ = string16(input_element->value().characters());
+ size_ = input_element->size();
+ } else if (form_control_type_ == ASCIIToUTF16("select-one")) {
+ WebCore::HTMLSelectElement* select_element = static_cast<WebCore::HTMLSelectElement*>(&element);
+ value_ = string16(select_element->value().characters());
+ }
+
+ TrimWhitespace(value_, TRIM_LEADING, &value_);
+}
+
+FormField::FormField(const string16& label,
+ const string16& name,
+ const string16& value,
+ const string16& form_control_type,
+ int size)
+ : label_(label),
+ name_(name),
+ value_(value),
+ form_control_type_(form_control_type),
+ size_(size) {
+}
+
+bool FormField::operator!=(const FormField& field) const {
+ return !operator==(field);
+}
+} // namespace webkit_glue
diff --git a/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.h b/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.h
new file mode 100644
index 0000000..51bb24b
--- /dev/null
+++ b/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2010 The Chromium Authors. All rights reserved.
+ * Copyright 2010, The Android Open Source Project
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 FormFieldAndroid_h
+#define FormFieldAndroid_h
+
+#include <base/string16.h>
+#include <vector>
+
+// TODO: This file is taken from chromium/webkit/glue/form_field.cc and
+// customised to use WebCore types rather than WebKit API types. It would
+// be nice and would ease future merge pain if the two could be combined.
+
+namespace WebCore {
+class HTMLFormControlElement;
+}
+
+namespace webkit_glue {
+
+// Stores information about a field in a form.
+class FormField {
+public:
+ FormField();
+ explicit FormField(WebCore::HTMLFormControlElement& element);
+ FormField(const string16& label,
+ const string16& name,
+ const string16& value,
+ const string16& form_control_type,
+ int size);
+
+ const string16& label() const { return label_; }
+ const string16& name() const { return name_; }
+ const string16& value() const { return value_; }
+ const string16& form_control_type() const { return form_control_type_; }
+ int size() const { return size_; }
+ // Returns option string for elements for which they make sense (select-one,
+ // for example) for the rest of elements return an empty array.
+ const std::vector<string16>& option_strings() const {
+ return option_strings_;
+ }
+
+
+ void set_label(const string16& label) { label_ = label; }
+ void set_name(const string16& name) { name_ = name; }
+ void set_value(const string16& value) { value_ = value; }
+ void set_form_control_type(const string16& form_control_type) {
+ form_control_type_ = form_control_type;
+ }
+ void set_size(int size) { size_ = size; }
+ void set_option_strings(const std::vector<string16>& strings) {
+ option_strings_ = strings;
+ }
+
+ bool operator==(const FormField& field) const;
+ bool operator!=(const FormField& field) const;
+
+private:
+ string16 label_;
+ string16 name_;
+ string16 value_;
+ string16 form_control_type_;
+ int size_;
+ std::vector<string16> option_strings_;
+};
+
+inline bool FormField::operator==(const FormField& field) const {
+ // A FormField stores a value, but the value is not part of the identity of
+ // the field, so we don't want to compare the values.
+ return (label_ == field.label_ &&
+ name_ == field.name_ &&
+ form_control_type_ == field.form_control_type_);
+
+}
+
+} // namespace webkit_glue
+
+#endif // WEBKIT_GLUE_FORM_FIELD_H_
diff --git a/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp b/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp
new file mode 100644
index 0000000..c97a2a8
--- /dev/null
+++ b/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp
@@ -0,0 +1,637 @@
+/*
+ * Copyright (c) 2010 The Chromium Authors. All rights reserved.
+ * Copyright 2010, The Android Open Source Project
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 "FormManagerAndroid.h"
+
+#include "HTMLFormControlElement.h"
+#include "HTMLFormElement.h"
+#include "HTMLTextAreaElement.h"
+#include "HTMLInputElement.h"
+#include "HTMLLabelElement.h"
+#include "HTMLNames.h"
+#include "HTMLSelectElement.h"
+#include "NodeList.h"
+#include "HTMLCollection.h"
+#include "FormFieldAndroid.h"
+#include "QualifiedName.h"
+
+
+// TODO: This file is taken from chromium/chrome/renderer/form_manager.cc and
+// customised to use WebCore types rather than WebKit API types. It would be
+// nice and would ease future merge pain if the two could be combined.
+
+using webkit_glue::FormData;
+using webkit_glue::FormField;
+using WebCore::HTMLElement;
+using WebCore::HTMLFormControlElement;
+using WebCore::HTMLFormElement;
+using WebCore::HTMLLabelElement;
+using WebCore::HTMLSelectElement;
+using WebCore::Node;
+using WebCore::NodeList;
+
+using namespace WebCore::HTMLNames;
+
+namespace {
+
+// The number of fields required by AutoFill. Ideally we could send the forms
+// to AutoFill no matter how many fields are in the forms; however, finding the
+// label for each field is a costly operation and we can't spare the cycles if
+// it's not necessary.
+// Note the on ANDROID we reduce this from Chromium's 3 as it allows us to
+// autofill simple name/email forms for example. This improves the mobile
+// device experience where form filling can be time consuming and frustrating.
+const size_t kRequiredAutoFillFields = 2;
+
+string16 WTFStringToString16(const WTF::String& wtfString)
+{
+ WTF::String str = wtfString;
+
+ if (str.charactersWithNullTermination())
+ return string16(str.charactersWithNullTermination());
+ else
+ return string16();
+}
+
+string16 S(const WTF::AtomicString& str)
+{
+ return WTFStringToString16(str.string());
+}
+
+string16 S(const WTF::String& string)
+{
+ return WTFStringToString16(string);
+}
+
+// This is a helper function for the FindChildText() function.
+// Returns the node value of the descendant or sibling of |node| that is a
+// non-empty text node. This is a faster alternative to |innerText()| for
+// performance critical operations. It does a full depth-first search so
+// can be used when the structure is not directly known. It does not aggregate
+// the text of multiple nodes, it just returns the value of the first found.
+// "Non-empty" in this case means non-empty after the whitespace has been
+// stripped.
+string16 FindChildTextInner(const Node* node) {
+ string16 element_text;
+ if (!node)
+ return element_text;
+
+ element_text = S(node->nodeValue());
+ TrimWhitespace(element_text, TRIM_ALL, &element_text);
+ if (!element_text.empty())
+ return element_text;
+
+ element_text = FindChildTextInner(node->firstChild());
+ if (!element_text.empty())
+ return element_text;
+
+ element_text = FindChildTextInner(node->nextSibling());
+ if (!element_text.empty())
+ return element_text;
+
+ return element_text;
+}
+
+// Returns the node value of the first decendant of |element| that is a
+// non-empty text node. "Non-empty" in this case means non-empty after the
+// whitespace has been stripped.
+string16 FindChildText(const HTMLElement* element) {
+ Node* child = element->firstChild();
+ return FindChildTextInner(child);
+}
+
+} // namespace
+
+namespace android {
+
+FormManager::FormManager() {
+}
+
+FormManager::~FormManager() {
+ Reset();
+}
+
+// static
+void FormManager::HTMLFormControlElementToFormField(
+ const HTMLFormControlElement& element, bool get_value, FormField* field) {
+ ASSERT(field);
+
+ // The label is not officially part of a HTMLFormControlElement; however, the
+ // labels for all form control elements are scraped from the DOM and set in
+ // WebFormElementToFormData.
+ field->set_name(S(element.name()));
+ field->set_form_control_type(S(element.type()));
+
+ if (!get_value)
+ return;
+
+ string16 value;
+ if (element.type() == WTF::AtomicString("text")) {
+ const WebCore::HTMLTextAreaElement* input_element = static_cast<const WebCore::HTMLTextAreaElement*>(&element);
+ if (input_element->renderer())
+ value = S(input_element->value());
+ } else if (element.type() == WTF::AtomicString("select-one")) {
+ // TODO: This is ugly. SelectElement::value() is a non-const
+ // method. Look into fixing this on the WebKit side.
+ HTMLFormControlElement& e = const_cast<HTMLFormControlElement&>(element);
+ HTMLSelectElement& select_element = static_cast<HTMLSelectElement&>(e);
+ value = S(select_element.value());
+ }
+ field->set_value(value);
+}
+
+// static
+string16 FormManager::LabelForElement(const HTMLFormControlElement& element) {
+ RefPtr<NodeList> labels = element.document()->getElementsByTagName("label");
+ for (unsigned i = 0; i < labels->length(); ++i) {
+ Node* e = labels->item(i);
+ if (e->hasTagName(labelTag)) {
+ HTMLLabelElement* label = static_cast<HTMLLabelElement*>(e);
+ if (label->control() == &element)
+ return FindChildText(label);
+ }
+ }
+
+ // Infer the label from context if not found in label element.
+ return FormManager::InferLabelForElement(element);
+}
+
+// static
+bool FormManager::HTMLFormElementToFormData(HTMLFormElement& element,
+ RequirementsMask requirements,
+ bool get_values,
+ FormData* form) {
+ ASSERT(form);
+
+ const WebCore::Document* document = element.document();
+ if (!document)
+ return false;
+
+ if (requirements & REQUIRE_AUTOCOMPLETE && !element.autoComplete())
+ return false;
+
+ form->name = S(element.name());
+ form->method = S(element.method());
+ form->origin = GURL(S(document->documentURI()));
+ form->action = GURL(S(document->completeURL(element.action())));
+ // If the completed URL is not valid, just use the action we get from
+ // WebKit.
+ if (!form->action.is_valid())
+ form->action = GURL(S(element.action()));
+
+ // A map from a FormField's name to the FormField itself.
+ std::map<string16, FormField*> name_map;
+
+ // The extracted FormFields. We use pointers so we can store them in
+ // |name_map|.
+ ScopedVector<FormField> form_fields;
+
+ WTF::Vector<WebCore::HTMLFormControlElement*> control_elements = element.associatedElements();
+
+ // A vector of bools that indicate whether each field in the form meets the
+ // requirements and thus will be in the resulting |form|.
+ std::vector<bool> fields_extracted(control_elements.size(), false);
+ for (size_t i = 0; i < control_elements.size(); ++i) {
+ const HTMLFormControlElement* control_element = control_elements[i];
+
+ if (requirements & REQUIRE_AUTOCOMPLETE &&
+ control_element->type() == WTF::String("text")) {
+ const WebCore::HTMLInputElement* input_element = static_cast<const WebCore::HTMLInputElement*>(control_element);
+ if (!input_element->autoComplete())
+ continue;
+ }
+
+ if (requirements & REQUIRE_ELEMENTS_ENABLED && !control_element->isEnabledFormControl())
+ continue;
+
+ // Create a new FormField, fill it out and map it to the field's name.
+ FormField* field = new FormField;
+ HTMLFormControlElementToFormField(*control_element, get_values, field);
+ form_fields.push_back(field);
+ // TODO: A label element is mapped to a form control element's id.
+ // field->name() will contain the id only if the name does not exist. Add
+ // an id() method to HTMLFormControlElement and use that here.
+ name_map[field->name()] = field;
+ fields_extracted[i] = true;
+ }
+
+ // Don't extract field labels if we have no fields.
+ if (form_fields.empty())
+ return false;
+
+ // Loop through the label elements inside the form element. For each label
+ // element, get the corresponding form control element, use the form control
+ // element's name as a key into the <name, FormField> map to find the
+ // previously created FormField and set the FormField's label to the
+ // label.firstChild().nodeValue() of the label element.
+ RefPtr<WebCore::NodeList> labels = element.getElementsByTagName("label");
+ for (unsigned i = 0; i < labels->length(); ++i) {
+ WebCore::HTMLLabelElement* label = static_cast<WebCore::HTMLLabelElement*>(labels->item(i));
+ HTMLFormControlElement* field_element = label->control();
+ if (!field_element || field_element->type() == "hidden")
+ continue;
+
+ std::map<string16, FormField*>::iterator iter =
+ name_map.find(S(field_element->name()));
+ if (iter != name_map.end())
+ iter->second->set_label(FindChildText(label));
+ }
+
+ // Loop through the form control elements, extracting the label text from the
+ // DOM. We use the |fields_extracted| vector to make sure we assign the
+ // extracted label to the correct field, as it's possible |form_fields| will
+ // not contain all of the elements in |control_elements|.
+ for (size_t i = 0, field_idx = 0;
+ i < control_elements.size() && field_idx < form_fields.size(); ++i) {
+ // This field didn't meet the requirements, so don't try to find a label for
+ // it.
+ if (!fields_extracted[i])
+ continue;
+
+ const HTMLFormControlElement* control_element = control_elements[i];
+ if (form_fields[field_idx]->label().empty())
+ form_fields[field_idx]->set_label(
+ FormManager::InferLabelForElement(*control_element));
+
+ ++field_idx;
+
+ }
+ // Copy the created FormFields into the resulting FormData object.
+ for (ScopedVector<FormField>::const_iterator iter = form_fields.begin();
+ iter != form_fields.end(); ++iter) {
+ form->fields.push_back(**iter);
+ }
+
+ return true;
+}
+
+void FormManager::ExtractForms(WebCore::Document* document) {
+
+ WTF::PassRefPtr<WebCore::HTMLCollection> collection = document->forms();
+
+ WebCore::HTMLFormElement* form;
+ WebCore::HTMLInputElement* input;
+ for (Node* node = collection->firstItem();
+ node && !node->namespaceURI().isNull() && !node->namespaceURI().isEmpty();
+ node = collection->nextItem()) {
+ FormElement* form_elements = new FormElement;
+ form = static_cast<WebCore::HTMLFormElement*>(node);
+ if (form->autoComplete()) {
+ WTF::Vector<WebCore::HTMLFormControlElement*> elements = form->associatedElements();
+ size_t size = elements.size();
+ for (size_t i = 0; i < size; i++) {
+ WebCore::HTMLFormControlElement* e = elements[i];
+ form_elements->control_elements.push_back(e);
+ }
+ form_elements->form_element = form;
+ }
+ form_elements_map_[document].push_back(form_elements);
+ }
+}
+
+void FormManager::GetForms(RequirementsMask requirements,
+ std::vector<FormData>* forms) {
+ ASSERT(forms);
+
+ for (DocumentFormElementMap::iterator iter = form_elements_map_.begin();
+ iter != form_elements_map_.end(); ++iter) {
+ for (std::vector<FormElement*>::iterator form_iter = iter->second.begin();
+ form_iter != iter->second.end(); ++form_iter) {
+ FormData form;
+ if (HTMLFormElementToFormData(*(*form_iter)->form_element,
+ requirements,
+ true,
+ &form))
+ forms->push_back(form);
+ }
+ }
+}
+
+void FormManager::GetFormsInDocument(const WebCore::Document* document,
+ RequirementsMask requirements,
+ std::vector<FormData>* forms) {
+ ASSERT(document);
+ ASSERT(forms);
+
+ DocumentFormElementMap::iterator iter = form_elements_map_.find(document);
+ if (iter == form_elements_map_.end())
+ return;
+
+ // TODO: Factor this out and use it here and in GetForms.
+ const std::vector<FormElement*>& form_elements = iter->second;
+ for (std::vector<FormElement*>::const_iterator form_iter =
+ form_elements.begin();
+ form_iter != form_elements.end(); ++form_iter) {
+ FormElement* form_element = *form_iter;
+
+ // We need at least |kRequiredAutoFillFields| fields before appending this
+ // form to |forms|.
+ if (form_element->control_elements.size() < kRequiredAutoFillFields)
+ continue;
+
+ if (requirements & REQUIRE_AUTOCOMPLETE &&
+ !form_element->form_element->autoComplete())
+ continue;
+
+ FormData form;
+ FormElementToFormData(document, form_element, requirements, &form);
+ if (form.fields.size() >= kRequiredAutoFillFields)
+ forms->push_back(form);
+ }
+}
+
+bool FormManager::FindForm(const HTMLFormElement& element,
+ RequirementsMask requirements,
+ FormData* form) {
+ ASSERT(form);
+
+ const WebCore::Document* document = element.document();
+ DocumentFormElementMap::const_iterator document_iter =
+ form_elements_map_.find(document);
+ if (document_iter == form_elements_map_.end())
+ return false;
+
+ for (std::vector<FormElement*>::const_iterator iter =
+ document_iter->second.begin();
+ iter != document_iter->second.end(); ++iter) {
+ if ((*iter)->form_element->name() != element.name())
+ continue;
+ return FormElementToFormData(document, *iter, requirements, form);
+ }
+ return false;
+}
+
+bool FormManager::FindFormWithFormControlElement(
+ const HTMLFormControlElement& element,
+ RequirementsMask requirements,
+ FormData* form) {
+ ASSERT(form);
+
+ const WebCore::Document* document = element.document();
+ if (form_elements_map_.find(document) == form_elements_map_.end())
+ return false;
+
+ const std::vector<FormElement*> forms = form_elements_map_[document];
+ for (std::vector<FormElement*>::const_iterator iter = forms.begin();
+ iter != forms.end(); ++iter) {
+ const FormElement* form_element = *iter;
+
+ for (std::vector<HTMLFormControlElement*>::const_iterator iter =
+ form_element->control_elements.begin();
+ iter != form_element->control_elements.end(); ++iter) {
+ if ((*iter)->name() == element.name()) {
+ HTMLFormElementToFormData(
+ *form_element->form_element, requirements, true, form);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool FormManager::FillForm(const FormData& form) {
+ FormElement* form_element = NULL;
+
+ for (DocumentFormElementMap::iterator iter = form_elements_map_.begin();
+ iter != form_elements_map_.end(); ++iter) {
+ const WebCore::Document* document = iter->first;
+
+ for (std::vector<FormElement*>::iterator form_iter = iter->second.begin();
+ form_iter != iter->second.end(); ++form_iter) {
+ // TODO: matching on form name here which is not guaranteed to
+ // be unique for the page, nor is it guaranteed to be non-empty. Need to
+ // find a way to uniquely identify the form cross-process. For now we'll
+ // check form name and form action for identity.
+ // http://crbug.com/37990 test file sample8.html.
+ // Also note that WebString() == WebString(string16()) does not seem to
+ // evaluate to |true| for some reason TBD, so forcing to string16.
+ string16 element_name(S((*form_iter)->form_element->name()));
+ GURL action(
+ S(document->completeURL((*form_iter)->form_element->action()).string()));
+ if (element_name == form.name && action == form.action) {
+ form_element = *form_iter;
+ break;
+ }
+ }
+ }
+
+ if (!form_element)
+ return false;
+
+ // It's possible that the site has injected fields into the form after the
+ // page has loaded, so we can't assert that the size of the cached control
+ // elements is equal to the size of the fields in |form|. Fortunately, the
+ // one case in the wild where this happens, paypal.com signup form, the fields
+ // are appended to the end of the form and are not visible.
+
+ for (size_t i = 0, j = 0;
+ i < form_element->control_elements.size() && j < form.fields.size();
+ ++i, ++j) {
+ // Once again, empty WebString != empty string16, so we have to explicitly
+ // check for this case.
+ if (form_element->control_elements[i]->name().length() == 0 &&
+ form.fields[j].name().empty())
+ continue;
+
+ // We assume that the intersection of the fields in
+ // |form_element->control_elements| and |form.fields| is ordered, but it's
+ // possible that one or the other sets may have more fields than the other,
+ // so loop past non-matching fields in the set with more elements.
+ while (S(form_element->control_elements[i]->name()) !=
+ form.fields[j].name()) {
+ if (form_element->control_elements.size() > form.fields.size()) {
+ // We're at the end of the elements already.
+ if (i + 1 == form_element->control_elements.size())
+ break;
+ ++i;
+ } else if (form.fields.size() > form_element->control_elements.size()) {
+ // We're at the end of the elements already.
+ if (j + 1 == form.fields.size())
+ break;
+ ++j;
+ } else {
+ // Shouldn't get here.
+ ASSERT(false);
+ }
+
+ continue;
+ }
+
+ HTMLFormControlElement* element = form_element->control_elements[i];
+ if (!form.fields[j].value().empty() &&
+ element->type() != WTF::String("submit")) {
+ if (element->type() == WTF::String("text")) {
+ WebCore::HTMLInputElement* input_element = static_cast<WebCore::HTMLInputElement*>(element);
+ // If the maxlength attribute contains a negative value, maxLength()
+ // returns the default maxlength value.
+ input_element->setValue(
+ WTF::String(form.fields[j].value().substr(0, input_element->maxLength()).c_str()));
+ input_element->setAutofilled(true);
+ } else if (element->type() ==
+ WTF::String("select-one")) {
+ WebCore::HTMLSelectElement* select_element = static_cast<WebCore::HTMLSelectElement*>(element);
+ select_element->setValue(WTF::String(form.fields[j].value().c_str()));
+ }
+ }
+ }
+
+ return true;
+}
+
+void FormManager::FillForms(const std::vector<webkit_glue::FormData>& forms) {
+ for (std::vector<webkit_glue::FormData>::const_iterator iter = forms.begin();
+ iter != forms.end(); ++iter) {
+ FillForm(*iter);
+ }
+}
+
+void FormManager::Reset() {
+ for (DocumentFormElementMap::iterator iter = form_elements_map_.begin();
+ iter != form_elements_map_.end(); ++iter) {
+ STLDeleteElements(&iter->second);
+ }
+ form_elements_map_.clear();
+}
+
+void FormManager::ResetFrame(const WebCore::Document* document) {
+
+ DocumentFormElementMap::iterator iter = form_elements_map_.find(document);
+ if (iter != form_elements_map_.end()) {
+ STLDeleteElements(&iter->second);
+ form_elements_map_.erase(iter);
+ }
+}
+
+// static
+bool FormManager::FormElementToFormData(const WebCore::Document* document,
+ const FormElement* form_element,
+ RequirementsMask requirements,
+ FormData* form) {
+ if (requirements & REQUIRE_AUTOCOMPLETE &&
+ !form_element->form_element->autoComplete())
+ return false;
+
+ form->name = S(form_element->form_element->name());
+ form->method = S(form_element->form_element->method());
+ form->origin = GURL(S(document->documentURI()));
+ form->action = GURL(S(document->completeURL(form_element->form_element->action())));
+
+ // If the completed URL is not valid, just use the action we get from
+ // WebKit.
+ if (!form->action.is_valid())
+ form->action = GURL(S(form_element->form_element->action()));
+
+ // Form elements loop.
+ for (std::vector<HTMLFormControlElement*>::const_iterator element_iter =
+ form_element->control_elements.begin();
+ element_iter != form_element->control_elements.end(); ++element_iter) {
+ const HTMLFormControlElement* control_element = *element_iter;
+
+ if (requirements & REQUIRE_AUTOCOMPLETE &&
+ control_element->type() == WTF::String("text")) {
+ const WebCore::HTMLInputElement* input_element =
+ static_cast<const WebCore::HTMLInputElement*>(control_element);
+ if (!input_element->autoComplete())
+ continue;
+ }
+
+ if (requirements & REQUIRE_ELEMENTS_ENABLED && !control_element->isEnabledFormControl())
+ continue;
+
+ FormField field;
+ HTMLFormControlElementToFormField(*control_element, false, &field);
+ form->fields.push_back(field);
+ }
+
+ return true;
+}
+
+// static
+string16 FormManager::InferLabelForElement(
+ const HTMLFormControlElement& element) {
+ string16 inferred_label;
+ Node* previous = element.previousSibling();
+ if (previous) {
+ if (previous->isTextNode()) {
+ inferred_label = S(previous->nodeValue());
+ TrimWhitespace(inferred_label, TRIM_ALL, &inferred_label);
+ }
+
+ // If we didn't find text, check for previous paragraph.
+ // Eg. <p>Some Text</p><input ...>
+ // Note the lack of whitespace between <p> and <input> elements.
+ if (inferred_label.empty()) {
+ if (previous->isElementNode()) {
+ if (previous->hasTagName(pTag)) {
+ inferred_label = FindChildText((HTMLElement*)previous);
+ }
+ }
+ }
+
+ // If we didn't find paragraph, check for previous paragraph to this.
+ // Eg. <p>Some Text</p> <input ...>
+ // Note the whitespace between <p> and <input> elements.
+ if (inferred_label.empty()) {
+ previous = previous->previousSibling();
+ if (previous) {
+ if (previous->hasTagName(pTag)) {
+ inferred_label = FindChildText((HTMLElement*)previous);
+ }
+ }
+ }
+ }
+
+ // If we didn't find paragraph, check for table cell case.
+ // Eg. <tr><td>Some Text</td><td><input ...></td></tr>
+ // Eg. <tr><td><b>Some Text</b></td><td><b><input ...></b></td></tr>
+ if (inferred_label.empty()) {
+ Node* parent = element.parentNode();
+ while (parent &&
+ !parent->hasTagName(tdTag))
+ parent = parent->parentNode();
+
+ if (parent) {
+ if (parent->hasTagName(tdTag)) {
+ previous = parent->previousSibling();
+
+ // Skip by any intervening text nodes.
+ while (previous && previous->isTextNode())
+ previous = previous->previousSibling();
+
+ if (previous) {
+ if (previous->hasTagName(tdTag)) {
+ inferred_label = FindChildText((HTMLElement*)previous);
+ }
+ }
+ }
+ }
+ }
+ return inferred_label;
+}
+
+}
diff --git a/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h b/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h
new file mode 100644
index 0000000..395e651
--- /dev/null
+++ b/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2010 The Chromium Authors. All rights reserved.
+ * Copyright 2010, The Android Open Source Project
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 FormManagerAndroid_h
+#define FormManagerAndroid_h
+
+#include "ChromiumIncludes.h"
+
+#include <map>
+#include <vector>
+
+// TODO: This file is taken from chromium/chrome/renderer/form_manager.h and
+// customised to use WebCore types rather than WebKit API types. It would be
+// nice and would ease future merge pain if the two could be combined.
+
+namespace webkit_glue {
+struct FormData;
+class FormField;
+} // namespace webkit_glue
+
+namespace WebCore {
+ class HTMLFormControlElement;
+ class HTMLFormElement;
+ class Document;
+}
+
+namespace android {
+
+// Manages the forms in a Document.
+class FormManager {
+ public:
+ // A bit field mask for form requirements.
+ enum RequirementsMask {
+ REQUIRE_NONE = 0x0, // No requirements.
+ REQUIRE_AUTOCOMPLETE = 0x1, // Require that autocomplete != off.
+ REQUIRE_ELEMENTS_ENABLED = 0x2 // Require that disabled attribute is off.
+ };
+
+ FormManager();
+ virtual ~FormManager();
+
+ // Fills out a FormField object from a given WebFormControlElement.
+ // If |get_value| is true, |field| will have the value set from |element|.
+ static void HTMLFormControlElementToFormField(
+ const WebCore::HTMLFormControlElement& element,
+ bool get_value,
+ webkit_glue::FormField* field);
+
+ // Returns the corresponding label for |element|. WARNING: This method can
+ // potentially be very slow. Do not use during any code paths where the page
+ // is loading.
+ static string16 LabelForElement(const WebCore::HTMLFormControlElement& element);
+
+ // Fills out a FormData object from a given WebFormElement. If |get_values|
+ // is true, the fields in |form| will have the values filled out. Returns
+ // true if |form| is filled out; it's possible that |element| won't meet the
+ // requirements in |requirements|. This also returns false if there are no
+ // fields in |form|.
+ // TODO: Remove the user of this in RenderView and move this to
+ // private.
+ static bool HTMLFormElementToFormData(WebCore::HTMLFormElement& element,
+ RequirementsMask requirements,
+ bool get_values,
+ webkit_glue::FormData* form);
+
+ // Scans the DOM in |document| extracting and storing forms.
+ void ExtractForms(WebCore::Document* document);
+
+ // Returns a vector of forms that match |requirements|.
+ void GetForms(RequirementsMask requirements,
+ std::vector<webkit_glue::FormData>* forms);
+
+ // Returns a vector of forms in |document| that match |requirements|.
+ void GetFormsInDocument(const WebCore::Document* document,
+ RequirementsMask requirements,
+ std::vector<webkit_glue::FormData>* forms);
+
+ // Returns the cached FormData for |element|. Returns true if the form was
+ // found in the cache.
+ bool FindForm(const WebCore::HTMLFormElement& element,
+ RequirementsMask requirements,
+ webkit_glue::FormData* form);
+
+ // Finds the form that contains |element| and returns it in |form|. Returns
+ // false if the form is not found.
+ bool FindFormWithFormControlElement(
+ const WebCore::HTMLFormControlElement& element,
+ RequirementsMask requirements,
+ webkit_glue::FormData* form);
+
+ // Fills the form represented by |form|. |form| should have the name set to
+ // the name of the form to fill out, and the number of elements and values
+ // must match the number of stored elements in the form.
+ // TODO: Is matching on name alone good enough? It's possible to
+ // store multiple forms with the same names from different frames.
+ bool FillForm(const webkit_glue::FormData& form);
+
+ // Fills all of the forms in the cache with form data from |forms|.
+ void FillForms(const std::vector<webkit_glue::FormData>& forms);
+
+ // Resets the stored set of forms.
+ void Reset();
+
+ // Resets the forms for the specified |document|.
+ void ResetFrame(const WebCore::Document* document);
+
+ private:
+ // Stores the HTMLFormElement and the form control elements for a form.
+ struct FormElement {
+ WebCore::HTMLFormElement* form_element;
+ std::vector<WebCore::HTMLFormControlElement*> control_elements;
+ };
+
+ // A map of vectors of FormElements keyed by the Document containing each
+ // form.
+ typedef std::map<const WebCore::Document*, std::vector<FormElement*> >
+ DocumentFormElementMap;
+
+ // Converts a FormElement to FormData storage. Returns false if the form does
+ // not meet all the requirements in the requirements mask.
+ static bool FormElementToFormData(const WebCore::Document* document,
+ const FormElement* form_element,
+ RequirementsMask requirements,
+ webkit_glue::FormData* form);
+
+ // Infers corresponding label for |element| from surrounding context in the
+ // DOM. Contents of preceeding <p> tag or preceeding text element found in
+ // the form.
+ static string16 InferLabelForElement(
+ const WebCore::HTMLFormControlElement& element);
+
+ // The map of form elements.
+ DocumentFormElementMap form_elements_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(FormManager);
+};
+
+} // namespace android
+
+#endif // FormManagerAndroid_h
diff --git a/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.cpp b/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.cpp
new file mode 100644
index 0000000..598b9c4
--- /dev/null
+++ b/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 "MainThreadProxy.h"
+
+#include <wtf/MainThread.h>
+
+void MainThreadProxy::CallOnMainThread(CallOnMainThreadFunction f, void* c)
+{
+ callOnMainThread(f, c);
+}
diff --git a/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.h b/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.h
new file mode 100644
index 0000000..d9310bb
--- /dev/null
+++ b/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 MAIN_THREAD_PROXY_H
+#define MAIN_THREAD_PROXY_H
+
+typedef void CallOnMainThreadFunction(void*);
+
+class MainThreadProxy
+{
+public:
+ static void CallOnMainThread(CallOnMainThreadFunction, void*);
+};
+
+#endif
diff --git a/WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp b/WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp
new file mode 100644
index 0000000..08d5e58
--- /dev/null
+++ b/WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 "WebAutoFill.h"
+
+#if ENABLE(WEB_AUTOFILL)
+
+#include "AutoFillHostAndroid.h"
+#include "Document.h"
+#include "Frame.h"
+#include "FormData.h"
+#include "FormManagerAndroid.h"
+#include "FrameLoader.h"
+#include "HTMLFormControlElement.h"
+#include "MainThreadProxy.h"
+#include "Node.h"
+#include "WebFrame.h"
+#include "WebRequestContext.h"
+#include "WebUrlLoaderClient.h"
+#include "WebViewCore.h"
+
+namespace android
+{
+
+WebAutoFill::WebAutoFill()
+{
+ mFormManager = new FormManager();
+ mQueryId = 1;
+
+ AndroidURLRequestContextGetter::Get()->SetURLRequestContext(WebRequestContext::GetAndroidContext());
+ AndroidURLRequestContextGetter::Get()->SetIOThread(WebUrlLoaderClient::ioThread());
+ TabContents* tabContents = new TabContents();
+ mAutoFillManager = new AutoFillManager(tabContents);
+
+ // FIXME: For testing use a precanned profile. This should come from Java land!
+ mAutoFillProfile = new AutoFillProfile();
+ mAutoFillProfile->SetInfo(AutoFillType(NAME_FULL), string16(ASCIIToUTF16("John Smith")));
+ mAutoFillProfile->SetInfo(AutoFillType(EMAIL_ADDRESS), string16(ASCIIToUTF16("jsmith@gmail.com")));
+ mAutoFillProfile->SetInfo(AutoFillType(ADDRESS_HOME_ZIP), string16(ASCIIToUTF16("AB12 3DE")));
+ mAutoFillProfile->SetInfo(AutoFillType(PHONE_HOME_WHOLE_NUMBER), string16(ASCIIToUTF16("0123456789")));
+
+ std::vector<AutoFillProfile> profiles;
+ profiles.push_back(*mAutoFillProfile);
+ tabContents->profile()->GetPersonalDataManager()->SetProfiles(&profiles);
+ mAutoFillHost = new AutoFillHostAndroid(this);
+ tabContents->SetAutoFillHost(mAutoFillHost.get());
+}
+
+WebAutoFill::~WebAutoFill()
+{
+ mQueryMap.clear();
+}
+
+void WebAutoFill::searchDocument(WebCore::Document* document)
+{
+ // TODO: This method is called when the main frame finishes loading and
+ // scans the document for forms and tries to work out the type of the
+ // fields in those forms. It's currently synchronous and might be slow
+ // if the page has many or complex forms. Might want to make this an
+ // async method.
+ if (!mFormManager)
+ return;
+
+ mQueryMap.clear();
+ mQueryId = 1;
+ mAutoFillManager->Reset();
+ mFormManager->Reset();
+ mFormManager->ExtractForms(document);
+ mForms.clear();
+ mFormManager->GetForms(FormManager::REQUIRE_AUTOCOMPLETE, &mForms);
+ mAutoFillManager->FormsSeen(mForms);
+}
+
+void WebAutoFill::formFieldFocused(WebCore::HTMLFormControlElement* formFieldElement)
+{
+ // Get the FormField from the Node.
+ webkit_glue::FormField formField;
+ FormManager::HTMLFormControlElementToFormField(*formFieldElement, false, &formField);
+ formField.set_label(FormManager::LabelForElement(*formFieldElement));
+
+ webkit_glue::FormData* form = new webkit_glue::FormData;
+ mFormManager->FindFormWithFormControlElement(*formFieldElement, FormManager::REQUIRE_AUTOCOMPLETE, form);
+ mQueryMap[mQueryId] = form;
+
+ mAutoFillManager->GetAutoFillSuggestions(mQueryId, false, formField);
+ mQueryId++;
+}
+
+void WebAutoFill::fillFormFields(int queryId, const string16& value, const string16& label, int uniqueId)
+{
+ webkit_glue::FormData* form = mQueryMap[queryId];
+ mAutoFillManager->FillAutoFillFormData(queryId, *form, value, label, uniqueId);
+}
+
+void WebAutoFill::fillFormInPage(int queryId, const webkit_glue::FormData& form)
+{
+ mFormManager->FillForm(form);
+}
+
+}
+
+#endif
diff --git a/WebKit/android/WebCoreSupport/autofill/WebAutoFill.h b/WebKit/android/WebCoreSupport/autofill/WebAutoFill.h
new file mode 100644
index 0000000..335f9b2
--- /dev/null
+++ b/WebKit/android/WebCoreSupport/autofill/WebAutoFill.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 WebAutoFill_h
+#define WebAutoFill_h
+
+#if ENABLE(WEB_AUTOFILL)
+
+#include "ChromiumIncludes.h"
+
+#include <map>
+#include <vector>
+#include <wtf/Noncopyable.h>
+#include <wtf/OwnPtr.h>
+
+class AutoFillManager;
+class AutoFillProfile;
+class AutoFillHost;
+
+namespace WebCore {
+class Document;
+class HTMLFormControlElement;
+}
+
+namespace android
+{
+class FormManager;
+class WebViewCore;
+
+class WebAutoFill : public Noncopyable
+{
+public:
+ WebAutoFill();
+ virtual ~WebAutoFill();
+
+ void searchDocument(WebCore::Document*);
+ void formFieldFocused(WebCore::HTMLFormControlElement*);
+ void fillFormFields(int queryId, const string16& value, const string16& label, int uniqueId);
+ void fillFormInPage(int queryId, const webkit_glue::FormData& form);
+
+private:
+ OwnPtr<FormManager> mFormManager;
+ OwnPtr<AutoFillManager> mAutoFillManager;
+ OwnPtr<AutoFillProfile> mAutoFillProfile;
+ OwnPtr<AutoFillHost> mAutoFillHost;
+
+ typedef std::vector<webkit_glue::FormData, std::allocator<webkit_glue::FormData> > FormList;
+ FormList mForms;
+
+ typedef std::map<int, webkit_glue::FormData*> AutoFillQueryMap;
+ AutoFillQueryMap mQueryMap;
+ int mQueryId;
+};
+
+}
+
+#endif // ENABLE(WEB_AUTOFILL)
+#endif // WebAutoFill_h
diff --git a/WebKit/android/jni/WebCoreFrameBridge.cpp b/WebKit/android/jni/WebCoreFrameBridge.cpp
index a717301..c1cb907 100644
--- a/WebKit/android/jni/WebCoreFrameBridge.cpp
+++ b/WebKit/android/jni/WebCoreFrameBridge.cpp
@@ -120,6 +120,10 @@
#include "WebArchiveAndroid.h"
#endif
+#if ENABLE(WEB_AUTOFILL)
+#include "autofill/WebAutoFill.h"
+#endif
+
using namespace JSC::Bindings;
static String* gUploadFileLabel;
@@ -639,6 +643,13 @@ WebFrame::didFinishLoad(WebCore::Frame* frame)
(int)loadType, isMainFrame);
checkException(env);
env->DeleteLocalRef(urlStr);
+#if ENABLE(WEB_AUTOFILL)
+ // TODO: Need to consider child frames.
+ if (isMainFrame) {
+ EditorClientAndroid* editorClient = static_cast<EditorClientAndroid*>(mPage->editorClient());
+ editorClient->getAutoFill()->searchDocument(frame->document());
+ }
+#endif
}
void