summaryrefslogtreecommitdiffstats
path: root/Source/WebKit/android/WebCoreSupport
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebKit/android/WebCoreSupport')
-rw-r--r--Source/WebKit/android/WebCoreSupport/CacheResult.cpp251
-rw-r--r--Source/WebKit/android/WebCoreSupport/CacheResult.h86
-rw-r--r--Source/WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.cpp66
-rw-r--r--Source/WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.h63
-rw-r--r--Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp605
-rw-r--r--Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.h216
-rw-r--r--Source/WebKit/android/WebCoreSupport/ChromiumIncludes.h104
-rw-r--r--Source/WebKit/android/WebCoreSupport/ChromiumInit.cpp74
-rw-r--r--Source/WebKit/android/WebCoreSupport/ChromiumInit.h38
-rw-r--r--Source/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.cpp51
-rw-r--r--Source/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.h51
-rw-r--r--Source/WebKit/android/WebCoreSupport/CookieClient.h46
-rw-r--r--Source/WebKit/android/WebCoreSupport/DeviceMotionClientAndroid.cpp84
-rw-r--r--Source/WebKit/android/WebCoreSupport/DeviceMotionClientAndroid.h65
-rw-r--r--Source/WebKit/android/WebCoreSupport/DeviceOrientationClientAndroid.cpp84
-rw-r--r--Source/WebKit/android/WebCoreSupport/DeviceOrientationClientAndroid.h65
-rw-r--r--Source/WebKit/android/WebCoreSupport/DragClientAndroid.cpp46
-rw-r--r--Source/WebKit/android/WebCoreSupport/DragClientAndroid.h51
-rw-r--r--Source/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp280
-rw-r--r--Source/WebKit/android/WebCoreSupport/EditorClientAndroid.h135
-rw-r--r--Source/WebKit/android/WebCoreSupport/FileSystemClient.h41
-rw-r--r--Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp1351
-rw-r--r--Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h271
-rw-r--r--Source/WebKit/android/WebCoreSupport/FrameNetworkingContextAndroid.cpp52
-rw-r--r--Source/WebKit/android/WebCoreSupport/FrameNetworkingContextAndroid.h54
-rwxr-xr-xSource/WebKit/android/WebCoreSupport/GeolocationPermissions.cpp419
-rw-r--r--Source/WebKit/android/WebCoreSupport/GeolocationPermissions.h178
-rw-r--r--Source/WebKit/android/WebCoreSupport/InspectorClientAndroid.h54
-rw-r--r--Source/WebKit/android/WebCoreSupport/KeyGeneratorClient.h46
-rw-r--r--Source/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp654
-rw-r--r--Source/WebKit/android/WebCoreSupport/MemoryUsage.cpp81
-rw-r--r--Source/WebKit/android/WebCoreSupport/MemoryUsage.h45
-rw-r--r--Source/WebKit/android/WebCoreSupport/PlatformBridge.cpp261
-rw-r--r--Source/WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp71
-rw-r--r--Source/WebKit/android/WebCoreSupport/UrlInterceptResponse.cpp130
-rw-r--r--Source/WebKit/android/WebCoreSupport/UrlInterceptResponse.h70
-rw-r--r--Source/WebKit/android/WebCoreSupport/V8Counters.cpp116
-rw-r--r--Source/WebKit/android/WebCoreSupport/V8Counters.h77
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebCache.cpp237
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebCache.h88
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebCookieJar.cpp263
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebCookieJar.h78
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebRequest.cpp531
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebRequest.h125
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebRequestContext.cpp130
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebRequestContext.h64
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebResourceRequest.cpp96
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebResourceRequest.h86
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebResponse.cpp167
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebResponse.h91
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebUrlLoader.cpp87
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebUrlLoader.h57
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp482
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h130
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebViewClientError.cpp132
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebViewClientError.h74
-rw-r--r--Source/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.cpp51
-rw-r--r--Source/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.h54
-rw-r--r--Source/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.cpp139
-rw-r--r--Source/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.h96
-rw-r--r--Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp871
-rw-r--r--Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h187
-rw-r--r--Source/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.cpp35
-rw-r--r--Source/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.h37
-rw-r--r--Source/WebKit/android/WebCoreSupport/autofill/StringUtils.h73
-rw-r--r--Source/WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp296
-rw-r--r--Source/WebKit/android/WebCoreSupport/autofill/WebAutoFill.h127
67 files changed, 11316 insertions, 0 deletions
diff --git a/Source/WebKit/android/WebCoreSupport/CacheResult.cpp b/Source/WebKit/android/WebCoreSupport/CacheResult.cpp
new file mode 100644
index 0000000..5309c66
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/CacheResult.cpp
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2011, 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 "CacheResult.h"
+
+#include "WebResponse.h"
+#include "WebUrlLoaderClient.h"
+#include <platform/FileSystem.h>
+#include <wtf/text/CString.h>
+
+using namespace base;
+using namespace disk_cache;
+using namespace net;
+using namespace std;
+
+namespace android {
+
+// All public methods are called on a UI thread but we do work on the
+// Chromium thread. However, because we block the WebCore thread while this
+// work completes, we can never receive new public method calls while the
+// Chromium thread work is in progress.
+
+// Copied from HttpCache
+enum {
+ kResponseInfoIndex = 0,
+ kResponseContentIndex
+};
+
+CacheResult::CacheResult(disk_cache::Entry* entry, String url)
+ : m_entry(entry)
+ , m_onResponseHeadersDoneCallback(this, &CacheResult::onResponseHeadersDone)
+ , m_onReadNextChunkDoneCallback(this, &CacheResult::onReadNextChunkDone)
+ , m_url(url)
+{
+ ASSERT(m_entry);
+}
+
+CacheResult::~CacheResult()
+{
+ m_entry->Close();
+ // TODO: Should we also call DoneReadingFromEntry() on the cache for our
+ // entry?
+}
+
+int64 CacheResult::contentSize() const
+{
+ // The android stack does not take the content length from the HTTP response
+ // headers but calculates it when writing the content to disk. It can never
+ // overflow a long because we limit the cache size.
+ return m_entry->GetDataSize(kResponseContentIndex);
+}
+
+bool CacheResult::firstResponseHeader(const char* name, String* result, bool allowEmptyString) const
+{
+ string value;
+ if (responseHeaders() && responseHeaders()->EnumerateHeader(NULL, name, &value) && (!value.empty() || allowEmptyString)) {
+ *result = String(value.c_str());
+ return true;
+ }
+ return false;
+}
+
+String CacheResult::mimeType() const
+{
+ string mimeType;
+ if (responseHeaders())
+ responseHeaders()->GetMimeType(&mimeType);
+ if (!mimeType.length() && m_url.length())
+ mimeType = WebResponse::resolveMimeType(std::string(m_url.utf8().data(), m_url.length()), "");
+ return String(mimeType.c_str());
+}
+
+int64 CacheResult::expires() const
+{
+ // We have to do this manually, rather than using HttpResponseHeaders::GetExpiresValue(),
+ // to handle the "-1" and "0" special cases.
+ string expiresString;
+ if (responseHeaders() && responseHeaders()->EnumerateHeader(NULL, "expires", &expiresString)) {
+ wstring expiresStringWide(expiresString.begin(), expiresString.end()); // inflate ascii
+ // We require the time expressed as ms since the epoch.
+ Time time;
+ if (Time::FromString(expiresStringWide.c_str(), &time)) {
+ // Will not overflow for a very long time!
+ return static_cast<int64>(1000.0 * time.ToDoubleT());
+ }
+
+ if (expiresString == "-1" || expiresString == "0")
+ return 0;
+ }
+
+ // TODO
+ // The Android stack applies a heuristic to set an expiry date if the
+ // expires header is not set or can't be parsed. I'm not sure whether the Chromium cache
+ // does this, and if so, it may not be possible for us to get hold of it
+ // anyway to set it on the result.
+ return -1;
+}
+
+int CacheResult::responseCode() const
+{
+ return responseHeaders() ? responseHeaders()->response_code() : 0;
+}
+
+bool CacheResult::writeToFile(const String& filePath) const
+{
+ // Getting the headers is potentially async, so post to the Chromium thread
+ // and block here.
+ MutexLocker lock(m_mutex);
+
+ base::Thread* thread = WebUrlLoaderClient::ioThread();
+ if (!thread)
+ return false;
+
+ CacheResult* me = const_cast<CacheResult*>(this);
+ thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(me, &CacheResult::writeToFileImpl));
+
+ m_filePath = filePath.threadsafeCopy();
+ m_isAsyncOperationInProgress = true;
+ while (m_isAsyncOperationInProgress)
+ m_condition.wait(m_mutex);
+
+ return m_wasWriteToFileSuccessful;
+}
+
+void CacheResult::writeToFileImpl()
+{
+ m_bufferSize = m_entry->GetDataSize(kResponseContentIndex);
+ m_readOffset = 0;
+ m_wasWriteToFileSuccessful = false;
+ readNextChunk();
+}
+
+void CacheResult::readNextChunk()
+{
+ m_buffer = new IOBuffer(m_bufferSize);
+ int rv = m_entry->ReadData(kResponseInfoIndex, m_readOffset, m_buffer, m_bufferSize, &m_onReadNextChunkDoneCallback);
+ if (rv == ERR_IO_PENDING)
+ return;
+
+ onReadNextChunkDone(rv);
+};
+
+void CacheResult::onReadNextChunkDone(int size)
+{
+ if (size > 0) {
+ // Still more reading to be done.
+ if (writeChunkToFile()) {
+ // TODO: I assume that we need to clear and resize the buffer for the next read?
+ m_readOffset += size;
+ m_bufferSize -= size;
+ readNextChunk();
+ } else
+ onWriteToFileDone();
+ return;
+ }
+
+ if (!size) {
+ // Reached end of file.
+ if (writeChunkToFile())
+ m_wasWriteToFileSuccessful = true;
+ }
+ onWriteToFileDone();
+}
+
+bool CacheResult::writeChunkToFile()
+{
+ PlatformFileHandle file;
+ file = openFile(m_filePath, OpenForWrite);
+ if (!isHandleValid(file))
+ return false;
+ return WebCore::writeToFile(file, m_buffer->data(), m_bufferSize) == m_bufferSize;
+}
+
+void CacheResult::onWriteToFileDone()
+{
+ MutexLocker lock(m_mutex);
+ m_isAsyncOperationInProgress = false;
+ m_condition.signal();
+}
+
+HttpResponseHeaders* CacheResult::responseHeaders() const
+{
+ MutexLocker lock(m_mutex);
+ if (m_responseHeaders)
+ return m_responseHeaders;
+
+ // Getting the headers is potentially async, so post to the Chromium thread
+ // and block here.
+ base::Thread* thread = WebUrlLoaderClient::ioThread();
+ if (!thread)
+ return 0;
+
+ CacheResult* me = const_cast<CacheResult*>(this);
+ thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(me, &CacheResult::responseHeadersImpl));
+
+ m_isAsyncOperationInProgress = true;
+ while (m_isAsyncOperationInProgress)
+ m_condition.wait(m_mutex);
+
+ return m_responseHeaders;
+}
+
+void CacheResult::responseHeadersImpl()
+{
+ m_bufferSize = m_entry->GetDataSize(kResponseInfoIndex);
+ m_buffer = new IOBuffer(m_bufferSize);
+
+ int rv = m_entry->ReadData(kResponseInfoIndex, 0, m_buffer, m_bufferSize, &m_onResponseHeadersDoneCallback);
+ if (rv == ERR_IO_PENDING)
+ return;
+
+ onResponseHeadersDone(rv);
+};
+
+void CacheResult::onResponseHeadersDone(int size)
+{
+ MutexLocker lock(m_mutex);
+ // It's OK to throw away the HttpResponseInfo object as we hold our own ref
+ // to the headers.
+ HttpResponseInfo response;
+ bool truncated = false; // TODO: Waht is this param for?
+ if (size == m_bufferSize && HttpCache::ParseResponseInfo(m_buffer->data(), m_bufferSize, &response, &truncated))
+ m_responseHeaders = response.headers;
+ m_isAsyncOperationInProgress = false;
+ m_condition.signal();
+}
+
+} // namespace android
diff --git a/Source/WebKit/android/WebCoreSupport/CacheResult.h b/Source/WebKit/android/WebCoreSupport/CacheResult.h
new file mode 100644
index 0000000..c39570c
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/CacheResult.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2011, 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 CacheResult_h
+#define CacheResult_h
+
+#include "ChromiumIncludes.h"
+
+#include <wtf/RefCounted.h>
+#include <wtf/ThreadingPrimitives.h>
+#include <wtf/text/WTFString.h>
+
+namespace android {
+
+// A wrapper around a disk_cache::Entry. Provides fields appropriate for constructing a Java CacheResult object.
+class CacheResult : public base::RefCountedThreadSafe<CacheResult> {
+public:
+ // Takes ownership of the Entry passed to the constructor.
+ CacheResult(disk_cache::Entry*, String url);
+ ~CacheResult();
+
+ int64 contentSize() const;
+ bool firstResponseHeader(const char* name, WTF::String* result, bool allowEmptyString) const;
+ // The Android stack uses the empty string if no Content-Type headers are
+ // found, so we use the same default here.
+ WTF::String mimeType() const;
+ // Returns the value of the expires header as milliseconds since the epoch.
+ int64 expires() const;
+ int responseCode() const;
+ bool writeToFile(const WTF::String& filePath) const;
+private:
+ net::HttpResponseHeaders* responseHeaders() const;
+ void responseHeadersImpl();
+ void onResponseHeadersDone(int size);
+
+ void writeToFileImpl();
+ void readNextChunk();
+ void onReadNextChunkDone(int size);
+ bool writeChunkToFile();
+ void onWriteToFileDone();
+
+ disk_cache::Entry* m_entry;
+
+ scoped_refptr<net::HttpResponseHeaders> m_responseHeaders;
+
+ int m_readOffset;
+ bool m_wasWriteToFileSuccessful;
+ mutable String m_filePath;
+
+ int m_bufferSize;
+ scoped_refptr<net::IOBuffer> m_buffer;
+ mutable bool m_isAsyncOperationInProgress;
+ mutable WTF::Mutex m_mutex;
+ mutable WTF::ThreadCondition m_condition;
+
+ net::CompletionCallbackImpl<CacheResult> m_onResponseHeadersDoneCallback;
+ net::CompletionCallbackImpl<CacheResult> m_onReadNextChunkDoneCallback;
+
+ String m_url;
+};
+
+} // namespace android
+
+#endif
diff --git a/Source/WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.cpp b/Source/WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.cpp
new file mode 100644
index 0000000..30f374f
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2009, 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 "CachedFramePlatformDataAndroid.h"
+#include "Settings.h"
+
+namespace android {
+
+CachedFramePlatformDataAndroid::CachedFramePlatformDataAndroid(WebCore::Settings* settings)
+{
+#ifdef ANDROID_META_SUPPORT
+ m_viewport_width = settings->viewportWidth();
+ m_viewport_height = settings->viewportHeight();
+ m_viewport_initial_scale = settings->viewportInitialScale();
+ m_viewport_minimum_scale = settings->viewportMinimumScale();
+ m_viewport_maximum_scale = settings->viewportMaximumScale();
+ m_viewport_target_densitydpi = settings->viewportTargetDensityDpi();
+ m_viewport_user_scalable = settings->viewportUserScalable();
+ m_format_detection_address = settings->formatDetectionAddress();
+ m_format_detection_email = settings->formatDetectionEmail();
+ m_format_detection_telephone = settings->formatDetectionTelephone();
+#endif
+
+}
+
+#ifdef ANDROID_META_SUPPORT
+void CachedFramePlatformDataAndroid::restoreMetadata(WebCore::Settings* settings)
+{
+ settings->setViewportWidth(m_viewport_width);
+ settings->setViewportHeight(m_viewport_height);
+ settings->setViewportInitialScale(m_viewport_initial_scale);
+ settings->setViewportMinimumScale(m_viewport_minimum_scale);
+ settings->setViewportMaximumScale(m_viewport_maximum_scale);
+ settings->setViewportTargetDensityDpi(m_viewport_target_densitydpi);
+ settings->setViewportUserScalable(m_viewport_user_scalable);
+ settings->setFormatDetectionAddress(m_format_detection_address);
+ settings->setFormatDetectionEmail(m_format_detection_email);
+ settings->setFormatDetectionTelephone(m_format_detection_telephone);
+}
+#endif
+
+}
diff --git a/Source/WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.h b/Source/WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.h
new file mode 100644
index 0000000..20c7be4
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2009, 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 CachedFramePlatformDatatAndroid_h
+#define CachedFramePlatformDatatAndroid_h
+
+#include "CachedFramePlatformData.h"
+
+namespace WebCore {
+ class Settings;
+}
+
+namespace android {
+
+class CachedFramePlatformDataAndroid : public WebCore::CachedFramePlatformData {
+public:
+ CachedFramePlatformDataAndroid(WebCore::Settings* settings);
+
+#ifdef ANDROID_META_SUPPORT
+ void restoreMetadata(WebCore::Settings* settings);
+#endif
+
+private:
+#ifdef ANDROID_META_SUPPORT
+ // meta data of the frame
+ int m_viewport_width;
+ int m_viewport_height;
+ int m_viewport_initial_scale;
+ int m_viewport_minimum_scale;
+ int m_viewport_maximum_scale;
+ int m_viewport_target_densitydpi;
+ bool m_viewport_user_scalable : 1;
+ bool m_format_detection_address : 1;
+ bool m_format_detection_email : 1;
+ bool m_format_detection_telephone : 1;
+#endif
+};
+
+}
+
+#endif
diff --git a/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp b/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp
new file mode 100644
index 0000000..6f872b8
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp
@@ -0,0 +1,605 @@
+/*
+ * Copyright 2007, 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.
+ */
+
+#define LOG_TAG "WebCore"
+
+#include "config.h"
+
+#include "ApplicationCacheStorage.h"
+#include "ChromeClientAndroid.h"
+#include "DatabaseTracker.h"
+#include "Document.h"
+#include "PlatformString.h"
+#include "FloatRect.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameView.h"
+#include "Geolocation.h"
+#include "HTMLMediaElement.h"
+#include "HTMLNames.h"
+#include "Icon.h"
+#include "LayerAndroid.h"
+#include "Page.h"
+#include "PopupMenuAndroid.h"
+#include "ScriptController.h"
+#include "SearchPopupMenuAndroid.h"
+#include "WebCoreFrameBridge.h"
+#include "WebCoreViewBridge.h"
+#include "WebViewCore.h"
+#include "WindowFeatures.h"
+#include "Settings.h"
+#include "UserGestureIndicator.h"
+#include <wtf/text/CString.h>
+
+namespace android {
+
+#if ENABLE(DATABASE)
+static unsigned long long tryToReclaimDatabaseQuota(SecurityOrigin* originNeedingQuota);
+#endif
+
+#if USE(ACCELERATED_COMPOSITING)
+
+WebCore::GraphicsLayer* ChromeClientAndroid::layersSync()
+{
+ if (m_rootGraphicsLayer && m_needsLayerSync && m_webFrame) {
+ if (FrameView* frameView = m_webFrame->page()->mainFrame()->view())
+ frameView->syncCompositingStateRecursive();
+ }
+ m_needsLayerSync = false;
+ return m_rootGraphicsLayer;
+}
+
+void ChromeClientAndroid::scheduleCompositingLayerSync()
+{
+ if (m_needsLayerSync)
+ return;
+ m_needsLayerSync = true;
+ WebViewCore* webViewCore = WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view());
+ if (webViewCore)
+ webViewCore->layersDraw();
+}
+
+void ChromeClientAndroid::setNeedsOneShotDrawingSynchronization()
+{
+ // This should not be needed
+}
+
+void ChromeClientAndroid::attachRootGraphicsLayer(WebCore::Frame*, WebCore::GraphicsLayer* layer)
+{
+ // frame is not used in Android as we should only get root graphics layer for the main frame
+ m_rootGraphicsLayer = layer;
+ if (!layer)
+ return;
+ scheduleCompositingLayerSync();
+}
+
+#endif
+
+void ChromeClientAndroid::setWebFrame(android::WebFrame* webframe)
+{
+ Release(m_webFrame);
+ m_webFrame = webframe;
+ Retain(m_webFrame);
+}
+
+void ChromeClientAndroid::chromeDestroyed()
+{
+ Release(m_webFrame);
+ delete this;
+}
+
+void ChromeClientAndroid::setWindowRect(const FloatRect&) { notImplemented(); }
+
+FloatRect ChromeClientAndroid::windowRect() {
+ ASSERT(m_webFrame);
+ if (!m_webFrame)
+ return FloatRect();
+ FrameView* frameView = m_webFrame->page()->mainFrame()->view();
+ if (!frameView)
+ return FloatRect();
+ const WebCoreViewBridge* bridge = frameView->platformWidget();
+ const IntRect& rect = bridge->getWindowBounds();
+ FloatRect fRect(rect.x(), rect.y(), rect.width(), rect.height());
+ return fRect;
+}
+
+FloatRect ChromeClientAndroid::pageRect() { notImplemented(); return FloatRect(); }
+
+float ChromeClientAndroid::scaleFactor()
+{
+ ASSERT(m_webFrame);
+ return m_webFrame->density();
+}
+
+void ChromeClientAndroid::focus()
+{
+ ASSERT(m_webFrame);
+ bool isUserGesture = UserGestureIndicator::processingUserGesture();
+
+ // Ask the application to focus this WebView if the action is intiated by the user
+ if (isUserGesture)
+ m_webFrame->requestFocus();
+}
+void ChromeClientAndroid::unfocus() { notImplemented(); }
+
+bool ChromeClientAndroid::canTakeFocus(FocusDirection) { notImplemented(); return false; }
+void ChromeClientAndroid::takeFocus(FocusDirection) { notImplemented(); }
+
+void ChromeClientAndroid::focusedNodeChanged(Node* node)
+{
+ android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->focusNodeChanged(node);
+}
+
+void ChromeClientAndroid::focusedFrameChanged(Frame*) { notImplemented(); }
+
+Page* ChromeClientAndroid::createWindow(Frame* frame, const FrameLoadRequest&,
+ const WindowFeatures& features, const NavigationAction&)
+{
+ ASSERT(frame);
+#ifdef ANDROID_MULTIPLE_WINDOWS
+ if (frame->settings() && !(frame->settings()->supportMultipleWindows()))
+ // If the client doesn't support multiple windows, just return the current page
+ return frame->page();
+#endif
+
+ const WebCoreViewBridge* bridge = frame->view()->platformWidget();
+ bool dialog = features.dialog || !features.resizable
+ || (features.heightSet && features.height < bridge->height()
+ && features.widthSet && features.width < bridge->width())
+ || (!features.menuBarVisible && !features.statusBarVisible
+ && !features.toolBarVisible && !features.locationBarVisible
+ && !features.scrollbarsVisible);
+ // fullscreen definitely means no dialog
+ if (features.fullscreen)
+ dialog = false;
+ WebCore::Frame* newFrame = m_webFrame->createWindow(dialog,
+ ScriptController::processingUserGesture());
+ if (newFrame) {
+ WebCore::Page* page = newFrame->page();
+ page->setGroupName(frame->page()->groupName());
+ return page;
+ }
+ return NULL;
+}
+
+void ChromeClientAndroid::show() { notImplemented(); }
+
+bool ChromeClientAndroid::canRunModal() { notImplemented(); return false; }
+void ChromeClientAndroid::runModal() { notImplemented(); }
+
+void ChromeClientAndroid::setToolbarsVisible(bool) { notImplemented(); }
+bool ChromeClientAndroid::toolbarsVisible() { notImplemented(); return false; }
+
+void ChromeClientAndroid::setStatusbarVisible(bool) { notImplemented(); }
+bool ChromeClientAndroid::statusbarVisible() { notImplemented(); return false; }
+
+void ChromeClientAndroid::setScrollbarsVisible(bool) { notImplemented(); }
+bool ChromeClientAndroid::scrollbarsVisible() { notImplemented(); return false; }
+
+void ChromeClientAndroid::setMenubarVisible(bool) { notImplemented(); }
+bool ChromeClientAndroid::menubarVisible() { notImplemented(); return false; }
+
+void ChromeClientAndroid::setResizable(bool) { notImplemented(); }
+
+#if ENABLE(CONTEXT_MENUS)
+void ChromeClientAndroid::showContextMenu() { notImplemented(); }
+#endif
+
+// This function is called by the JavaScript bindings to print usually an error to
+// a message console. Pass the message to the java side so that the client can
+// handle it as it sees fit.
+void ChromeClientAndroid::addMessageToConsole(MessageSource, MessageType, MessageLevel msgLevel, const String& message, unsigned int lineNumber, const String& sourceID) {
+ android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->addMessageToConsole(message, lineNumber, sourceID, msgLevel);
+}
+
+void ChromeClientAndroid::formDidBlur(const WebCore::Node* node)
+{
+ android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->formDidBlur(node);
+}
+
+bool ChromeClientAndroid::canRunBeforeUnloadConfirmPanel() { return true; }
+bool ChromeClientAndroid::runBeforeUnloadConfirmPanel(const String& message, Frame* frame) {
+ String url = frame->document()->documentURI();
+ return android::WebViewCore::getWebViewCore(frame->view())->jsUnload(url, message);
+}
+
+void ChromeClientAndroid::closeWindowSoon()
+{
+ ASSERT(m_webFrame);
+ Page* page = m_webFrame->page();
+ Frame* mainFrame = page->mainFrame();
+ // This will prevent javascript cross-scripting during unload
+ page->setGroupName(String());
+ // Stop loading but do not send the unload event
+ mainFrame->loader()->stopLoading(UnloadEventPolicyNone);
+ // Cancel all pending loaders
+ mainFrame->loader()->stopAllLoaders();
+ // Remove all event listeners so that no javascript can execute as a result
+ // of mouse/keyboard events.
+ mainFrame->document()->removeAllEventListeners();
+ // Close the window.
+ m_webFrame->closeWindow(android::WebViewCore::getWebViewCore(mainFrame->view()));
+}
+
+void ChromeClientAndroid::runJavaScriptAlert(Frame* frame, const String& message)
+{
+ String url = frame->document()->documentURI();
+
+ android::WebViewCore::getWebViewCore(frame->view())->jsAlert(url, message);
+}
+
+bool ChromeClientAndroid::runJavaScriptConfirm(Frame* frame, const String& message)
+{
+ String url = frame->document()->documentURI();
+
+ return android::WebViewCore::getWebViewCore(frame->view())->jsConfirm(url, message);
+}
+
+/* This function is called for the javascript method Window.prompt(). A dialog should be shown on
+ * the screen with an input put box. First param is the text, the second is the default value for
+ * the input box, third is return param. If the function returns true, the value set in the third parameter
+ * is provided to javascript, else null is returned to the script.
+ */
+bool ChromeClientAndroid::runJavaScriptPrompt(Frame* frame, const String& message, const String& defaultValue, String& result)
+{
+ String url = frame->document()->documentURI();
+ return android::WebViewCore::getWebViewCore(frame->view())->jsPrompt(url, message, defaultValue, result);
+}
+void ChromeClientAndroid::setStatusbarText(const String&) { notImplemented(); }
+
+// This is called by the JavaScript interpreter when a script has been running for a long
+// time. A dialog should be shown to the user asking them if they would like to cancel the
+// Javascript. If true is returned, the script is cancelled.
+// To make a device more responsive, we default to return true to disallow long running script.
+// This implies that some of scripts will not be completed.
+bool ChromeClientAndroid::shouldInterruptJavaScript() {
+ FrameView* frameView = m_webFrame->page()->mainFrame()->view();
+ return android::WebViewCore::getWebViewCore(frameView)->jsInterrupt();
+}
+
+bool ChromeClientAndroid::tabsToLinks() const { return false; }
+
+IntRect ChromeClientAndroid::windowResizerRect() const { return IntRect(0, 0, 0, 0); }
+
+void ChromeClientAndroid::invalidateWindow(const IntRect&, bool)
+{
+ notImplemented();
+}
+
+void ChromeClientAndroid::invalidateContentsAndWindow(const IntRect& updateRect, bool /*immediate*/)
+{
+ notImplemented();
+}
+
+void ChromeClientAndroid::invalidateContentsForSlowScroll(const IntRect& updateRect, bool immediate)
+{
+ notImplemented();
+}
+
+// new to change 38068 (Nov 6, 2008)
+void ChromeClientAndroid::scroll(const IntSize& scrollDelta,
+ const IntRect& rectToScroll, const IntRect& clipRect) {
+ notImplemented();
+}
+
+// new to change 38068 (Nov 6, 2008)
+IntPoint ChromeClientAndroid::screenToWindow(const IntPoint&) const {
+ notImplemented();
+ return IntPoint();
+}
+
+// new to change 38068 (Nov 6, 2008)
+IntRect ChromeClientAndroid::windowToScreen(const IntRect&) const {
+ notImplemented();
+ return IntRect();
+}
+
+PlatformPageClient ChromeClientAndroid::platformPageClient() const {
+ Page* page = m_webFrame->page();
+ Frame* mainFrame = page->mainFrame();
+ FrameView* view = mainFrame->view();
+ PlatformWidget viewBridge = view->platformWidget();
+ return viewBridge;
+}
+
+void ChromeClientAndroid::contentsSizeChanged(Frame*, const IntSize&) const
+{
+ notImplemented();
+}
+
+void ChromeClientAndroid::scrollRectIntoView(const IntRect&, const ScrollView*) const
+{
+ notImplemented();
+}
+
+void ChromeClientAndroid::formStateDidChange(const Node*)
+{
+ notImplemented();
+}
+
+void ChromeClientAndroid::scrollbarsModeDidChange() const
+{
+ notImplemented();
+}
+
+void ChromeClientAndroid::mouseDidMoveOverElement(const HitTestResult&, unsigned int) {}
+void ChromeClientAndroid::setToolTip(const String&, TextDirection) {}
+void ChromeClientAndroid::print(Frame*) {}
+
+/*
+ * This function is called on the main (webcore) thread by SQLTransaction::deliverQuotaIncreaseCallback.
+ * The way that the callback mechanism is designed inside SQLTransaction means that there must be a new quota
+ * (which may be equal to the old quota if the user did not allow more quota) when this function returns. As
+ * we call into the browser thread to ask what to do with the quota, we block here and get woken up when the
+ * browser calls the native WebViewCore::SetDatabaseQuota method with the new quota value.
+ */
+#if ENABLE(DATABASE)
+void ChromeClientAndroid::exceededDatabaseQuota(Frame* frame, const String& name)
+{
+ SecurityOrigin* origin = frame->document()->securityOrigin();
+ DatabaseTracker& tracker = WebCore::DatabaseTracker::tracker();
+
+ // We want to wait on a new quota from the UI thread. Reset the m_newQuota variable to represent we haven't received a new quota.
+ m_newQuota = -1;
+
+ // This origin is being tracked and has exceeded it's quota. Call into
+ // the Java side of things to inform the user.
+ unsigned long long currentQuota = 0;
+ if (tracker.hasEntryForOrigin(origin))
+ currentQuota = tracker.quotaForOrigin(origin);
+
+ unsigned long long estimatedSize = 0;
+
+ // Only update estimatedSize if we are trying to create a a new database, i.e. the usage for the database is 0.
+ if (tracker.usageForDatabase(name, origin) == 0)
+ estimatedSize = tracker.detailsForNameAndOrigin(name, origin).expectedUsage();
+
+ android::WebViewCore::getWebViewCore(frame->view())->exceededDatabaseQuota(frame->document()->documentURI(), name, currentQuota, estimatedSize);
+
+ // We've sent notification to the browser so now wait for it to come back.
+ m_quotaThreadLock.lock();
+ while (m_newQuota == -1) {
+ m_quotaThreadCondition.wait(m_quotaThreadLock);
+ }
+ m_quotaThreadLock.unlock();
+
+ // If new quota is unavailable, we may be able to resolve the situation by shrinking the quota of an origin that asked for a lot but is only using a little.
+ // If we find such a site, shrink it's quota and ask Java to try again.
+
+ if ((unsigned long long) m_newQuota == currentQuota && !m_triedToReclaimDBQuota) {
+ m_triedToReclaimDBQuota = true; // we should only try this once per quota overflow.
+ unsigned long long reclaimedQuotaBytes = tryToReclaimDatabaseQuota(origin);
+
+ // If we were able to free up enough space, try asking Java again.
+ // Otherwise, give up and deny the new database. :(
+ if (reclaimedQuotaBytes >= estimatedSize) {
+ exceededDatabaseQuota(frame, name);
+ return;
+ }
+ }
+
+ // Update the DatabaseTracker with the new quota value (if the user declined
+ // new quota, this may equal the old quota)
+ tracker.setQuota(origin, m_newQuota);
+ m_triedToReclaimDBQuota = false;
+}
+
+static unsigned long long tryToReclaimDatabaseQuota(SecurityOrigin* originNeedingQuota) {
+ DatabaseTracker& tracker = WebCore::DatabaseTracker::tracker();
+ Vector<RefPtr<SecurityOrigin> > origins;
+ tracker.origins(origins);
+ unsigned long long reclaimedQuotaBytes = 0;
+ for (unsigned i = 0; i < origins.size(); i++) {
+ SecurityOrigin* originToReclaimFrom = origins[i].get();
+
+ // Don't try to reclaim from the origin that has exceeded its quota.
+ if (originToReclaimFrom->equal(originNeedingQuota))
+ continue;
+
+ unsigned long long originUsage = tracker.usageForOrigin(originToReclaimFrom);
+ unsigned long long originQuota = tracker.quotaForOrigin(originToReclaimFrom);
+ // If the origin has a quota that is more than it's current usage +1MB, shrink it.
+ static const int ONE_MB = 1 * 1024 * 1024;
+ if (originUsage + ONE_MB < originQuota) {
+ unsigned long long newQuota = originUsage + ONE_MB;
+ tracker.setQuota(originToReclaimFrom, newQuota);
+ reclaimedQuotaBytes += originQuota - newQuota;
+ }
+ }
+ return reclaimedQuotaBytes;
+}
+#endif
+
+#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+void ChromeClientAndroid::reachedMaxAppCacheSize(int64_t spaceNeeded)
+{
+ // Set m_newQuota before calling into the Java side. If we do this after,
+ // we could overwrite the result passed from the Java side and deadlock in the
+ // wait call below.
+ m_newQuota = -1;
+ Page* page = m_webFrame->page();
+ Frame* mainFrame = page->mainFrame();
+ FrameView* view = mainFrame->view();
+ android::WebViewCore::getWebViewCore(view)->reachedMaxAppCacheSize(spaceNeeded);
+
+ // We've sent notification to the browser so now wait for it to come back.
+ m_quotaThreadLock.lock();
+ while (m_newQuota == -1) {
+ m_quotaThreadCondition.wait(m_quotaThreadLock);
+ }
+ m_quotaThreadLock.unlock();
+ if (m_newQuota > 0) {
+ WebCore::cacheStorage().setMaximumSize(m_newQuota);
+ // Now the app cache will retry the saving the previously failed cache.
+ }
+}
+#endif
+
+void ChromeClientAndroid::populateVisitedLinks()
+{
+ Page* page = m_webFrame->page();
+ Frame* mainFrame = page->mainFrame();
+ FrameView* view = mainFrame->view();
+ android::WebViewCore::getWebViewCore(view)->populateVisitedLinks(&page->group());
+}
+
+void ChromeClientAndroid::requestGeolocationPermissionForFrame(Frame* frame, Geolocation* geolocation)
+{
+ ASSERT(geolocation);
+ if (!m_geolocationPermissions) {
+ m_geolocationPermissions = new GeolocationPermissions(android::WebViewCore::getWebViewCore(frame->view()),
+ m_webFrame->page()->mainFrame());
+ }
+ m_geolocationPermissions->queryPermissionState(frame);
+}
+
+void ChromeClientAndroid::cancelGeolocationPermissionRequestForFrame(Frame* frame, WebCore::Geolocation*)
+{
+ if (m_geolocationPermissions)
+ m_geolocationPermissions->cancelPermissionStateQuery(frame);
+}
+
+void ChromeClientAndroid::provideGeolocationPermissions(const String &origin, bool allow, bool remember)
+{
+ ASSERT(m_geolocationPermissions);
+ m_geolocationPermissions->providePermissionState(origin, allow, remember);
+}
+
+void ChromeClientAndroid::storeGeolocationPermissions()
+{
+ GeolocationPermissions::maybeStorePermanentPermissions();
+}
+
+void ChromeClientAndroid::onMainFrameLoadStarted()
+{
+ if (m_geolocationPermissions.get())
+ m_geolocationPermissions->resetTemporaryPermissionStates();
+}
+
+void ChromeClientAndroid::runOpenPanel(Frame* frame,
+ PassRefPtr<FileChooser> chooser)
+{
+ android::WebViewCore* core = android::WebViewCore::getWebViewCore(
+ frame->view());
+ core->openFileChooser(chooser);
+}
+
+void ChromeClientAndroid::chooseIconForFiles(const Vector<WTF::String>&, FileChooser*)
+{
+ notImplemented();
+}
+
+void ChromeClientAndroid::setCursor(const Cursor&)
+{
+ notImplemented();
+}
+
+void ChromeClientAndroid::wakeUpMainThreadWithNewQuota(long newQuota) {
+ MutexLocker locker(m_quotaThreadLock);
+ m_newQuota = newQuota;
+ m_quotaThreadCondition.signal();
+}
+
+#if ENABLE(TOUCH_EVENTS)
+void ChromeClientAndroid::needTouchEvents(bool needTouchEvents)
+{
+ FrameView* frameView = m_webFrame->page()->mainFrame()->view();
+ android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView);
+ if (core)
+ core->needTouchEvents(needTouchEvents);
+}
+#endif
+
+bool ChromeClientAndroid::selectItemWritingDirectionIsNatural()
+{
+ return false;
+}
+
+PassRefPtr<PopupMenu> ChromeClientAndroid::createPopupMenu(PopupMenuClient* client) const
+{
+ return adoptRef(new PopupMenuAndroid(static_cast<ListPopupMenuClient*>(client)));
+}
+
+PassRefPtr<SearchPopupMenu> ChromeClientAndroid::createSearchPopupMenu(PopupMenuClient*) const
+{
+ return adoptRef(new SearchPopupMenuAndroid);
+}
+
+void ChromeClientAndroid::reachedApplicationCacheOriginQuota(SecurityOrigin*)
+{
+ notImplemented();
+}
+
+#if ENABLE(ANDROID_INSTALLABLE_WEB_APPS)
+void ChromeClientAndroid::webAppCanBeInstalled()
+{
+ FrameView* frameView = m_webFrame->page()->mainFrame()->view();
+ android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView);
+ if (core)
+ core->notifyWebAppCanBeInstalled();
+}
+#endif
+
+#if ENABLE(VIDEO)
+bool ChromeClientAndroid::supportsFullscreenForNode(const Node* node)
+{
+ return node->hasTagName(HTMLNames::videoTag);
+}
+
+void ChromeClientAndroid::enterFullscreenForNode(Node* node)
+{
+ if (!node->hasTagName(HTMLNames::videoTag))
+ return;
+
+ HTMLMediaElement* videoElement = static_cast<HTMLMediaElement*>(node);
+ String url = videoElement->currentSrc();
+ LayerAndroid* layer = videoElement->platformLayer();
+ if (!layer)
+ return;
+
+ FrameView* frameView = m_webFrame->page()->mainFrame()->view();
+ android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView);
+ m_webFrame->page()->mainFrame()->document()->webkitWillEnterFullScreenForElement(videoElement);
+ if (core)
+ core->enterFullscreenForVideoLayer(layer->uniqueId(), url);
+}
+
+void ChromeClientAndroid::exitFullscreenForNode(Node* node)
+{
+}
+#endif
+
+#if ENABLE(FULLSCREEN_API)
+void ChromeClientAndroid::exitFullScreenForElement(Element* element)
+{
+ if (!element)
+ return;
+
+ HTMLMediaElement* videoElement = static_cast<HTMLMediaElement*>(element);
+ videoElement->exitFullscreen();
+}
+#endif
+
+}
diff --git a/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.h b/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.h
new file mode 100644
index 0000000..d49cec8
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2007, 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 ChromeClientAndroid_h
+#define ChromeClientAndroid_h
+
+#include "ChromeClient.h"
+
+#include "GeolocationPermissions.h"
+#include "PopupMenu.h"
+#include "SearchPopupMenu.h"
+#include "Timer.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/Threading.h>
+
+namespace WebCore {
+class PopupMenuClient;
+class Geolocation;
+}
+
+using namespace WebCore;
+
+namespace android {
+ class WebFrame;
+
+ class ChromeClientAndroid : public ChromeClient {
+ public:
+ ChromeClientAndroid() : m_webFrame(0), m_geolocationPermissions(0)
+#if USE(ACCELERATED_COMPOSITING)
+ , m_rootGraphicsLayer(0)
+ , m_needsLayerSync(false)
+#endif
+ , m_triedToReclaimDBQuota(false)
+ { }
+ virtual void chromeDestroyed();
+
+ virtual void setWindowRect(const FloatRect&);
+ virtual FloatRect windowRect();
+
+ virtual FloatRect pageRect();
+
+ virtual float scaleFactor();
+
+ virtual void focus();
+ virtual void unfocus();
+ virtual void formDidBlur(const WebCore::Node*);
+ virtual bool canTakeFocus(FocusDirection);
+ virtual void takeFocus(FocusDirection);
+
+ virtual void focusedNodeChanged(Node*);
+ virtual void focusedFrameChanged(Frame*);
+
+ // The Frame pointer provides the ChromeClient with context about which
+ // Frame wants to create the new Page. Also, the newly created window
+ // should not be shown to the user until the ChromeClient of the newly
+ // created Page has its show method called.
+ virtual Page* createWindow(Frame*, const FrameLoadRequest&, const WindowFeatures&, const NavigationAction&);
+ 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(MessageSource, MessageType, MessageLevel, const String& message, unsigned int lineNumber, const String& sourceID);
+
+ virtual bool canRunBeforeUnloadConfirmPanel();
+ virtual bool runBeforeUnloadConfirmPanel(const String& message, Frame* frame);
+
+ virtual void closeWindowSoon();
+
+ virtual void runJavaScriptAlert(Frame*, const String&);
+ virtual bool runJavaScriptConfirm(Frame*, const String&);
+ virtual bool runJavaScriptPrompt(Frame*, const String& message, const String& defaultValue, String& result);
+ virtual void setStatusbarText(const String&);
+ virtual bool shouldInterruptJavaScript();
+ virtual bool tabsToLinks() const;
+
+ virtual IntRect windowResizerRect() const;
+
+ // Methods used by HostWindow.
+ virtual void invalidateWindow(const WebCore::IntRect&, bool);
+ virtual void invalidateContentsAndWindow(const WebCore::IntRect&, bool);
+ virtual void invalidateContentsForSlowScroll(const WebCore::IntRect&, bool);
+ virtual void scroll(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect);
+ virtual IntPoint screenToWindow(const IntPoint&) const;
+ virtual IntRect windowToScreen(const IntRect&) const;
+ virtual PlatformPageClient platformPageClient() const;
+ virtual void contentsSizeChanged(Frame*, const IntSize&) const;
+ virtual void scrollRectIntoView(const IntRect&, const ScrollView*) const;
+ // End methods used by HostWindow.
+
+ virtual void scrollbarsModeDidChange() const;
+ virtual void mouseDidMoveOverElement(const HitTestResult&, unsigned int);
+
+ virtual void setToolTip(const String&, TextDirection);
+
+ virtual void print(Frame*);
+#if ENABLE(DATABASE)
+ virtual void exceededDatabaseQuota(Frame*, const String&);
+#endif
+#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+ virtual void reachedMaxAppCacheSize(int64_t spaceNeeded);
+ virtual void reachedApplicationCacheOriginQuota(SecurityOrigin*);
+#endif
+
+ virtual void populateVisitedLinks();
+
+#if ENABLE(TOUCH_EVENTS)
+ virtual void needTouchEvents(bool);
+#endif
+
+ // Methods used to request and provide Geolocation permissions.
+ virtual void requestGeolocationPermissionForFrame(Frame*, Geolocation*);
+ virtual void cancelGeolocationPermissionRequestForFrame(WebCore::Frame*, WebCore::Geolocation*);
+ // Android-specific
+ void provideGeolocationPermissions(const String &origin, bool allow, bool remember);
+ void storeGeolocationPermissions();
+ void onMainFrameLoadStarted();
+
+ virtual void runOpenPanel(Frame*, PassRefPtr<FileChooser>);
+ virtual void setCursor(const Cursor&);
+ virtual void chooseIconForFiles(const WTF::Vector<WTF::String>&, FileChooser*);
+
+ // Notification that the given form element has changed. This function
+ // will be called frequently, so handling should be very fast.
+ virtual void formStateDidChange(const Node*);
+
+ virtual PassOwnPtr<HTMLParserQuirks> createHTMLParserQuirks() { return 0; }
+
+ // Android-specific
+ void setWebFrame(android::WebFrame* webframe);
+ android::WebFrame* webFrame() { return m_webFrame; }
+ void wakeUpMainThreadWithNewQuota(long newQuota);
+
+#if USE(ACCELERATED_COMPOSITING)
+ virtual void attachRootGraphicsLayer(WebCore::Frame*, WebCore::GraphicsLayer* g);
+ virtual void setNeedsOneShotDrawingSynchronization();
+ virtual void scheduleCompositingLayerSync();
+ virtual bool allowsAcceleratedCompositing() const { return true; }
+ WebCore::GraphicsLayer* layersSync();
+#endif
+
+ virtual bool selectItemWritingDirectionIsNatural();
+ virtual PassRefPtr<WebCore::PopupMenu> createPopupMenu(WebCore::PopupMenuClient*) const;
+ virtual PassRefPtr<WebCore::SearchPopupMenu> createSearchPopupMenu(WebCore::PopupMenuClient*) const;
+
+#if ENABLE(CONTEXT_MENUS)
+ virtual void showContextMenu();
+#endif
+
+#if ENABLE(ANDROID_INSTALLABLE_WEB_APPS)
+ virtual void webAppCanBeInstalled();
+#endif
+
+#if ENABLE(FULLSCREEN_API)
+ virtual void exitFullScreenForElement(Element*);
+#endif
+
+#if ENABLE(VIDEO)
+ virtual bool supportsFullscreenForNode(const WebCore::Node*);
+ virtual void enterFullscreenForNode(WebCore::Node*);
+ virtual void exitFullscreenForNode(WebCore::Node*);
+#endif
+
+ private:
+ android::WebFrame* m_webFrame;
+ // The Geolocation permissions manager.
+ OwnPtr<GeolocationPermissions> m_geolocationPermissions;
+#if USE(ACCELERATED_COMPOSITING)
+ WebCore::GraphicsLayer* m_rootGraphicsLayer;
+ bool m_needsLayerSync;
+#endif
+ WTF::ThreadCondition m_quotaThreadCondition;
+ WTF::Mutex m_quotaThreadLock;
+ long m_newQuota;
+ bool m_triedToReclaimDBQuota;
+ };
+
+}
+
+#endif
diff --git a/Source/WebKit/android/WebCoreSupport/ChromiumIncludes.h b/Source/WebKit/android/WebCoreSupport/ChromiumIncludes.h
new file mode 100644
index 0000000..8166eb7
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/ChromiumIncludes.h
@@ -0,0 +1,104 @@
+/*
+ * 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 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.
+
+// Undefine LOG and LOG_ASSERT before including chrome code, and if they were
+// defined attempt to set the macros to the Android logging macros (which are
+// the only ones that actually log).
+
+#ifdef LOG
+#define LOG_WAS_DEFINED LOG
+#undef LOG
+#endif
+
+#ifdef LOG_ASSERT
+#define LOG_ASSERT_WAS_DEFINED LOG_ASSERT
+#undef LOG_ASSERT
+#endif
+
+#include <android/net/android_network_library_impl.h>
+#include <base/callback.h>
+#include <base/condition_variable.h>
+#include <base/lock.h>
+#include <base/message_loop_proxy.h>
+#include <base/ref_counted.h>
+#include <base/string_util.h>
+#include <base/sys_string_conversions.h>
+#include <base/thread.h>
+#include <base/time.h>
+#include <base/tuple.h>
+#include <chrome/browser/net/sqlite_persistent_cookie_store.h>
+#include <net/base/auth.h>
+#include <net/base/cookie_monster.h>
+#include <net/base/cookie_policy.h>
+#include <net/base/data_url.h>
+#include <net/base/host_resolver.h>
+#include <net/base/io_buffer.h>
+#include <net/base/load_flags.h>
+#include <net/base/net_errors.h>
+#include <net/base/mime_util.h>
+#include <net/base/ssl_config_service.h>
+#include <net/disk_cache/disk_cache.h>
+#include <net/http/http_auth_handler_factory.h>
+#include <net/http/http_cache.h>
+#include <net/http/http_network_layer.h>
+#include <net/http/http_response_headers.h>
+#include <net/proxy/proxy_config_service_android.h>
+#include <net/proxy/proxy_service.h>
+#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__)
+#endif
+
+#undef LOG_ASSERT
+#if defined(LOG_ASSERT_WAS_DEFINED) && defined(LOG_FATAL_IF)
+#define LOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__)
+#endif
+
+#endif
diff --git a/Source/WebKit/android/WebCoreSupport/ChromiumInit.cpp b/Source/WebKit/android/WebCoreSupport/ChromiumInit.cpp
new file mode 100644
index 0000000..1872fb9
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/ChromiumInit.cpp
@@ -0,0 +1,74 @@
+/*
+ * 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 "ChromiumInit.h"
+
+#include "ChromiumIncludes.h"
+
+#include <cutils/log.h>
+#include <string>
+
+namespace android {
+
+bool logMessageHandler(int severity, const char* file, int line, size_t message_start, const std::string& str) {
+ int androidSeverity = ANDROID_LOG_VERBOSE;
+ switch(severity) {
+ case logging::LOG_FATAL:
+ androidSeverity = ANDROID_LOG_FATAL;
+ break;
+ case logging::LOG_ERROR_REPORT:
+ case logging::LOG_ERROR:
+ androidSeverity = ANDROID_LOG_ERROR;
+ break;
+ case logging::LOG_WARNING:
+ androidSeverity = ANDROID_LOG_WARN;
+ break;
+ default:
+ androidSeverity = ANDROID_LOG_VERBOSE;
+ break;
+ }
+ android_printLog(androidSeverity, "chromium", "%s:%d: %s", file, line, str.c_str());
+ return false;
+}
+
+namespace {
+ scoped_ptr<net::NetworkChangeNotifier> networkChangeNotifier;
+}
+
+void initChromium()
+{
+ static Lock lock;
+ AutoLock aLock(lock);
+ static bool initCalled = false;
+ if (!initCalled) {
+ logging::SetLogMessageHandler(logMessageHandler);
+ networkChangeNotifier.reset(net::NetworkChangeNotifier::Create());
+ net::HttpNetworkLayer::EnableSpdy("npn");
+ initCalled = true;
+ }
+}
+
+} // namespace android
diff --git a/Source/WebKit/android/WebCoreSupport/ChromiumInit.h b/Source/WebKit/android/WebCoreSupport/ChromiumInit.h
new file mode 100644
index 0000000..235c3dc
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/ChromiumInit.h
@@ -0,0 +1,38 @@
+/*
+ * 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 ChromiumLogging_h
+#define ChromiumLogging_h
+
+namespace android {
+
+// Sends chromium logs to logcat
+//
+// This only calls into chromium once, but can be called multiple times.
+// It should be called before any other calls into external/chromium.
+void initChromium();
+}
+
+#endif
diff --git a/Source/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.cpp b/Source/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.cpp
new file mode 100644
index 0000000..3dc4b00
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2007, 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 "ContextMenuClientAndroid.h"
+
+#include "NotImplemented.h"
+#include <wtf/Assertions.h>
+
+namespace WebCore {
+
+void ContextMenuClientAndroid::contextMenuDestroyed() { delete this; }
+
+PlatformMenuDescription ContextMenuClientAndroid::getCustomMenuFromDefaultItems(ContextMenu*) { notImplemented(); return 0; }
+void ContextMenuClientAndroid::contextMenuItemSelected(ContextMenuItem*, const ContextMenu*) { notImplemented(); }
+
+void ContextMenuClientAndroid::downloadURL(const KURL& url) { notImplemented(); }
+void ContextMenuClientAndroid::copyImageToClipboard(const HitTestResult&) { notImplemented(); }
+void ContextMenuClientAndroid::searchWithGoogle(const Frame*) { notImplemented(); }
+void ContextMenuClientAndroid::lookUpInDictionary(Frame*) { notImplemented(); }
+void ContextMenuClientAndroid::speak(const String&) { notImplemented(); }
+void ContextMenuClientAndroid::stopSpeaking() { notImplemented(); }
+bool ContextMenuClientAndroid::isSpeaking()
+{
+ notImplemented();
+ return false;
+}
+
+}
diff --git a/Source/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.h b/Source/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.h
new file mode 100644
index 0000000..4563829
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2007, 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 ContextMenuClientAndroid_h
+#define ContextMenuClientAndroid_h
+
+#include "ContextMenuClient.h"
+
+namespace WebCore {
+
+class ContextMenuClientAndroid : public ContextMenuClient {
+public:
+ virtual void contextMenuDestroyed();
+
+ virtual PlatformMenuDescription getCustomMenuFromDefaultItems(ContextMenu*);
+ virtual void contextMenuItemSelected(ContextMenuItem*, const ContextMenu*);
+
+ virtual void downloadURL(const KURL& url);
+ virtual void copyImageToClipboard(const HitTestResult&);
+ virtual void searchWithGoogle(const Frame*);
+ virtual void lookUpInDictionary(Frame*);
+ virtual void speak(const String&);
+ virtual void stopSpeaking();
+ virtual bool isSpeaking();
+};
+
+} // namespace WebCore
+
+#endif // ContextMenuClientAndroid_h
diff --git a/Source/WebKit/android/WebCoreSupport/CookieClient.h b/Source/WebKit/android/WebCoreSupport/CookieClient.h
new file mode 100644
index 0000000..56d9382
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/CookieClient.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2007, 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 COOKIE_CLIENT_H
+#define COOKIE_CLIENT_H
+
+#include <KURL.h>
+#include <PlatformString.h>
+
+using namespace WebCore;
+
+namespace android {
+
+class CookieClient {
+
+public:
+ virtual ~CookieClient() {}
+ virtual void setCookies(const KURL& url, const String& value) = 0;
+ virtual String cookies(const KURL& url) = 0;
+ virtual bool cookiesEnabled() = 0;
+};
+
+}
+#endif
diff --git a/Source/WebKit/android/WebCoreSupport/DeviceMotionClientAndroid.cpp b/Source/WebKit/android/WebCoreSupport/DeviceMotionClientAndroid.cpp
new file mode 100644
index 0000000..f8de733
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/DeviceMotionClientAndroid.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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 "DeviceMotionClientAndroid.h"
+
+#include "WebViewCore.h"
+
+using namespace WebCore;
+
+namespace android {
+
+DeviceMotionClientAndroid::DeviceMotionClientAndroid()
+ : m_client(0)
+{
+}
+
+void DeviceMotionClientAndroid::setWebViewCore(WebViewCore* webViewCore)
+{
+ m_webViewCore = webViewCore;
+ ASSERT(m_webViewCore);
+}
+
+void DeviceMotionClientAndroid::setController(DeviceMotionController* controller)
+{
+ // This will be called by the Page constructor before the WebViewCore
+ // has been configured regarding the mock. We cache the controller for
+ // later use.
+ m_controller = controller;
+ ASSERT(m_controller);
+}
+
+void DeviceMotionClientAndroid::startUpdating()
+{
+ client()->startUpdating();
+}
+
+void DeviceMotionClientAndroid::stopUpdating()
+{
+ client()->stopUpdating();
+}
+
+DeviceMotionData* DeviceMotionClientAndroid::currentDeviceMotion() const
+{
+ return client()->currentDeviceMotion();
+}
+
+void DeviceMotionClientAndroid::deviceMotionControllerDestroyed()
+{
+ delete this;
+}
+
+DeviceMotionClient* DeviceMotionClientAndroid::client() const
+{
+ if (!m_client) {
+ m_client = m_webViewCore->deviceMotionAndOrientationManager()->motionClient();
+ m_client->setController(m_controller);
+ }
+ return m_client;
+}
+
+} // namespace android
diff --git a/Source/WebKit/android/WebCoreSupport/DeviceMotionClientAndroid.h b/Source/WebKit/android/WebCoreSupport/DeviceMotionClientAndroid.h
new file mode 100644
index 0000000..98d4709
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/DeviceMotionClientAndroid.h
@@ -0,0 +1,65 @@
+/*
+ * 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 DeviceMotionClientAndroid_h
+#define DeviceMotionClientAndroid_h
+
+#include <DeviceMotionClient.h>
+
+namespace WebCore {
+class DeviceMotionController;
+}
+
+namespace android {
+
+class WebViewCore;
+
+// The Android implementation of DeviceMotionClient. Acts as a proxy to
+// the real or mock impl, which is owned by the WebViewCore.
+class DeviceMotionClientAndroid : public WebCore::DeviceMotionClient {
+public:
+ DeviceMotionClientAndroid();
+
+ void setWebViewCore(WebViewCore*);
+
+ // DeviceMotionClient methods
+ virtual void setController(WebCore::DeviceMotionController*);
+ virtual void startUpdating();
+ virtual void stopUpdating();
+ virtual WebCore::DeviceMotionData* currentDeviceMotion() const;
+ virtual void deviceMotionControllerDestroyed();
+
+private:
+ WebCore::DeviceMotionClient* client() const;
+
+ WebViewCore* m_webViewCore;
+ WebCore::DeviceMotionController* m_controller;
+ // Lazily obtained cache of the client owned by the WebViewCore.
+ mutable WebCore::DeviceMotionClient* m_client;
+};
+
+} // namespace android
+
+#endif // DeviceMotionClientAndroid_h
diff --git a/Source/WebKit/android/WebCoreSupport/DeviceOrientationClientAndroid.cpp b/Source/WebKit/android/WebCoreSupport/DeviceOrientationClientAndroid.cpp
new file mode 100644
index 0000000..9d7145c
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/DeviceOrientationClientAndroid.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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 "DeviceOrientationClientAndroid.h"
+
+#include "WebViewCore.h"
+
+using namespace WebCore;
+
+namespace android {
+
+DeviceOrientationClientAndroid::DeviceOrientationClientAndroid()
+ : m_client(0)
+{
+}
+
+void DeviceOrientationClientAndroid::setWebViewCore(WebViewCore* webViewCore)
+{
+ m_webViewCore = webViewCore;
+ ASSERT(m_webViewCore);
+}
+
+void DeviceOrientationClientAndroid::setController(DeviceOrientationController* controller)
+{
+ // This will be called by the Page constructor before the WebViewCore
+ // has been configured regarding the mock. We cache the controller for
+ // later use.
+ m_controller = controller;
+ ASSERT(m_controller);
+}
+
+void DeviceOrientationClientAndroid::startUpdating()
+{
+ client()->startUpdating();
+}
+
+void DeviceOrientationClientAndroid::stopUpdating()
+{
+ client()->stopUpdating();
+}
+
+DeviceOrientation* DeviceOrientationClientAndroid::lastOrientation() const
+{
+ return client()->lastOrientation();
+}
+
+void DeviceOrientationClientAndroid::deviceOrientationControllerDestroyed()
+{
+ delete this;
+}
+
+DeviceOrientationClient* DeviceOrientationClientAndroid::client() const
+{
+ if (!m_client) {
+ m_client = m_webViewCore->deviceMotionAndOrientationManager()->orientationClient();
+ m_client->setController(m_controller);
+ }
+ return m_client;
+}
+
+} // namespace android
diff --git a/Source/WebKit/android/WebCoreSupport/DeviceOrientationClientAndroid.h b/Source/WebKit/android/WebCoreSupport/DeviceOrientationClientAndroid.h
new file mode 100644
index 0000000..7842b95
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/DeviceOrientationClientAndroid.h
@@ -0,0 +1,65 @@
+/*
+ * 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 DeviceOrientationClientAndroid_h
+#define DeviceOrientationClientAndroid_h
+
+#include <DeviceOrientationClient.h>
+
+namespace WebCore {
+class DeviceOrientationController;
+}
+
+namespace android {
+
+class WebViewCore;
+
+// The Android implementation of DeviceOrientationClient. Acts as a proxy to
+// the real or mock impl, which is owned by the WebViewCore.
+class DeviceOrientationClientAndroid : public WebCore::DeviceOrientationClient {
+public:
+ DeviceOrientationClientAndroid();
+
+ void setWebViewCore(WebViewCore*);
+
+ // DeviceOrientationClient methods
+ virtual void setController(WebCore::DeviceOrientationController*);
+ virtual void startUpdating();
+ virtual void stopUpdating();
+ virtual WebCore::DeviceOrientation* lastOrientation() const;
+ virtual void deviceOrientationControllerDestroyed();
+
+private:
+ WebCore::DeviceOrientationClient* client() const;
+
+ WebViewCore* m_webViewCore;
+ WebCore::DeviceOrientationController* m_controller;
+ // Lazily obtained cache of the client owned by the WebViewCore.
+ mutable WebCore::DeviceOrientationClient* m_client;
+};
+
+} // namespace android
+
+#endif // DeviceOrientationClientAndroid_h
diff --git a/Source/WebKit/android/WebCoreSupport/DragClientAndroid.cpp b/Source/WebKit/android/WebCoreSupport/DragClientAndroid.cpp
new file mode 100644
index 0000000..f64b80c
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/DragClientAndroid.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2007, 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.
+ */
+
+#define LOG_TAG "WebCore"
+
+#include "config.h"
+#include "DragClientAndroid.h"
+#include "NotImplemented.h"
+
+namespace android {
+
+void DragClientAndroid::dragControllerDestroyed() { notImplemented(); delete this; }
+
+void DragClientAndroid::willPerformDragDestinationAction(DragDestinationAction, DragData*) { notImplemented(); }
+
+DragDestinationAction DragClientAndroid::actionMaskForDrag(DragData*) { notImplemented(); return DragDestinationActionNone; }
+
+DragSourceAction DragClientAndroid::dragSourceActionMaskForPoint(const IntPoint&) { notImplemented(); return DragSourceActionNone; }
+
+void* DragClientAndroid::createDragImageForLink(KURL&, String const&, Frame*) { return NULL; }
+void DragClientAndroid::willPerformDragSourceAction(DragSourceAction, IntPoint const&, Clipboard*) {}
+void DragClientAndroid::startDrag(void*, IntPoint const&, IntPoint const&, Clipboard*, Frame*, bool) {}
+
+}
diff --git a/Source/WebKit/android/WebCoreSupport/DragClientAndroid.h b/Source/WebKit/android/WebCoreSupport/DragClientAndroid.h
new file mode 100644
index 0000000..020e1f1
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/DragClientAndroid.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2007, 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 DragClientAndroid_h
+#define DragClientAndroid_h
+
+#include "DragClient.h"
+
+using namespace WebCore;
+
+namespace android {
+
+ class DragClientAndroid : public DragClient {
+ public:
+ virtual void willPerformDragDestinationAction(DragDestinationAction, DragData*);
+ virtual void willPerformDragSourceAction(DragSourceAction, const IntPoint&, Clipboard*);
+ virtual DragDestinationAction actionMaskForDrag(DragData*);
+ //We work in window rather than view coordinates here
+ virtual DragSourceAction dragSourceActionMaskForPoint(const IntPoint&);
+
+ virtual void startDrag(DragImageRef dragImage, const IntPoint& dragImageOrigin, const IntPoint& eventPos, Clipboard*, Frame*, bool linkDrag = false);
+ virtual DragImageRef createDragImageForLink(KURL&, const String& label, Frame*);
+
+ virtual void dragControllerDestroyed();
+ };
+
+}
+
+#endif
diff --git a/Source/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp b/Source/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp
new file mode 100644
index 0000000..250fdbf
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2007, 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.
+ */
+
+#define LOG_TAG "WebCore"
+
+#include "config.h"
+#include "Editor.h"
+#include "EditorClientAndroid.h"
+#include "Event.h"
+#include "EventNames.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "HTMLNames.h"
+#include "KeyboardEvent.h"
+#include "NotImplemented.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformString.h"
+#include "WebViewCore.h"
+#include "WindowsKeyboardCodes.h"
+
+using namespace WebCore::HTMLNames;
+
+namespace android {
+
+void EditorClientAndroid::pageDestroyed() {
+ delete this;
+}
+
+bool EditorClientAndroid::shouldDeleteRange(Range*) { return true; }
+bool EditorClientAndroid::shouldShowDeleteInterface(HTMLElement*) { notImplemented(); return false; }
+bool EditorClientAndroid::smartInsertDeleteEnabled() { notImplemented(); return false; }
+bool EditorClientAndroid::isSelectTrailingWhitespaceEnabled(){ notImplemented(); return false; }
+bool EditorClientAndroid::isContinuousSpellCheckingEnabled() { notImplemented(); return false; }
+void EditorClientAndroid::toggleContinuousSpellChecking() { notImplemented(); }
+bool EditorClientAndroid::isGrammarCheckingEnabled() { notImplemented(); return false; }
+void EditorClientAndroid::toggleGrammarChecking() { notImplemented(); }
+int EditorClientAndroid::spellCheckerDocumentTag() { notImplemented(); return -1; }
+
+bool EditorClientAndroid::isEditable() { /* notImplemented(); */ return false; }
+
+// Following Qt's implementation. For shouldBeginEditing and shouldEndEditing.
+// Returning true for these fixes issue http://b/issue?id=735185
+bool EditorClientAndroid::shouldBeginEditing(Range*)
+{
+ return true;
+}
+
+bool EditorClientAndroid::shouldEndEditing(Range*)
+{
+ return true;
+}
+
+bool EditorClientAndroid::shouldInsertNode(Node*, Range*, EditorInsertAction) { notImplemented(); return true; }
+bool EditorClientAndroid::shouldInsertText(const String&, Range*, EditorInsertAction) { return true; }
+bool EditorClientAndroid::shouldApplyStyle(CSSStyleDeclaration*, Range*) { notImplemented(); return true; }
+
+void EditorClientAndroid::didBeginEditing() { notImplemented(); }
+
+// This function is called so that the platform can handle changes to content. It is called
+// after the contents have been edited or unedited (ie undo)
+void EditorClientAndroid::respondToChangedContents() { notImplemented(); }
+
+void EditorClientAndroid::didEndEditing() { notImplemented(); }
+void EditorClientAndroid::didWriteSelectionToPasteboard() { notImplemented(); }
+void EditorClientAndroid::didSetSelectionTypesForPasteboard() { notImplemented(); }
+
+// Copied from the Window's port of WebKit.
+static const unsigned AltKey = 1 << 0;
+static const unsigned ShiftKey = 1 << 1;
+
+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, AltKey, "MoveWordLeft" },
+ { VK_LEFT, AltKey | ShiftKey, "MoveWordLeftAndModifySelection" },
+ { VK_RIGHT, 0, "MoveRight" },
+ { VK_RIGHT, ShiftKey, "MoveRightAndModifySelection" },
+ { VK_RIGHT, AltKey, "MoveWordRight" },
+ { VK_RIGHT, AltKey | ShiftKey, "MoveWordRightAndModifySelection" },
+ { VK_UP, 0, "MoveUp" },
+ { VK_UP, ShiftKey, "MoveUpAndModifySelection" },
+ { VK_DOWN, 0, "MoveDown" },
+ { VK_DOWN, ShiftKey, "MoveDownAndModifySelection" },
+
+ { VK_BACK, 0, "BackwardDelete" },
+ { VK_BACK, ShiftKey, "ForwardDelete" },
+ { VK_BACK, AltKey, "DeleteWordBackward" },
+ { VK_BACK, AltKey | ShiftKey, "DeleteWordForward" },
+
+ { VK_ESCAPE, 0, "Cancel" },
+ { VK_TAB, 0, "InsertTab" },
+ { VK_TAB, ShiftKey, "InsertBacktab" },
+ { VK_RETURN, 0, "InsertNewline" },
+ { VK_RETURN, AltKey, "InsertNewline" },
+ { VK_RETURN, AltKey | ShiftKey, "InsertNewline" }
+};
+
+static const KeyPressEntry keyPressEntries[] = {
+ { '\t', 0, "InsertTab" },
+ { '\t', ShiftKey, "InsertBackTab" },
+ { '\r', 0, "InsertNewline" },
+ { '\r', AltKey, "InsertNewline" },
+ { '\r', AltKey | ShiftKey, "InsertNewline" }
+};
+
+static const char* interpretKeyEvent(const KeyboardEvent* evt)
+{
+ const PlatformKeyboardEvent* keyEvent = evt->keyEvent();
+
+ 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 < sizeof(keyDownEntries)/sizeof(KeyDownEntry); i++)
+ keyDownCommandsMap->set(keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey, keyDownEntries[i].name);
+
+ for (unsigned i = 0; i < sizeof(keyPressEntries)/sizeof(KeyPressEntry); 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 (evt->type() == 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;
+}
+
+void EditorClientAndroid::handleKeyboardEvent(KeyboardEvent* event) {
+ ASSERT(m_page);
+ Frame* frame = m_page->focusController()->focusedOrMainFrame();
+ if (!frame)
+ return;
+
+ const PlatformKeyboardEvent* keyEvent = event->keyEvent();
+ // TODO: If the event is not coming from Android Java, e.g. from JavaScript,
+ // PlatformKeyboardEvent is null. We should support this later.
+ if (!keyEvent)
+ return;
+
+ Editor::Command command = frame->editor()->command(interpretKeyEvent(event));
+ if (keyEvent->type() == PlatformKeyboardEvent::RawKeyDown) {
+ if (!command.isTextInsertion() && command.execute(event)) {
+ // This function mimics the Windows version. However, calling event->setDefaultHandled()
+ // prevents the javascript key events for the delete key from happening.
+ // Update: Safari doesn't send delete key events to javascript so
+ // we will mimic that behavior.
+ event->setDefaultHandled();
+ }
+ return;
+ }
+
+ if (command.execute(event)) {
+ event->setDefaultHandled();
+ return;
+ }
+
+ // Don't insert null or control characters as they can result in unexpected behaviour
+ if (event->charCode() < ' ')
+ return;
+
+ if (frame->editor()->insertText(keyEvent->text(), event))
+ event->setDefaultHandled();
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+// we just don't support Undo/Redo at the moment
+
+void EditorClientAndroid::registerCommandForUndo(PassRefPtr<EditCommand>) {}
+void EditorClientAndroid::registerCommandForRedo(PassRefPtr<EditCommand>) {}
+void EditorClientAndroid::clearUndoRedoOperations() {}
+bool EditorClientAndroid::canUndo() const { return false; }
+bool EditorClientAndroid::canRedo() const { return false; }
+void EditorClientAndroid::undo() {}
+void EditorClientAndroid::redo() {}
+
+// functions new to Jun-07 tip of tree merge:
+void EditorClientAndroid::showSpellingUI(bool) {}
+void EditorClientAndroid::getGuessesForWord(String const&, const String&, WTF::Vector<String>&) {}
+bool EditorClientAndroid::spellingUIIsShowing() { return false; }
+void EditorClientAndroid::checkGrammarOfString(unsigned short const*, int, WTF::Vector<GrammarDetail>&, int*, int*) {}
+void EditorClientAndroid::checkSpellingOfString(unsigned short const*, int, int*, int*) {}
+String EditorClientAndroid::getAutoCorrectSuggestionForMisspelledWord(const String&) { return String(); }
+void EditorClientAndroid::textFieldDidEndEditing(Element*) {}
+void EditorClientAndroid::textDidChangeInTextArea(Element*) {}
+void EditorClientAndroid::textDidChangeInTextField(Element*) {}
+void EditorClientAndroid::textFieldDidBeginEditing(Element*) {}
+void EditorClientAndroid::ignoreWordInSpellDocument(String const&) {}
+
+// We need to pass the selection up to the WebTextView
+void EditorClientAndroid::respondToChangedSelection() {
+ if (m_uiGeneratedSelectionChange)
+ return;
+ Frame* frame = m_page->focusController()->focusedOrMainFrame();
+ if (!frame || !frame->view())
+ return;
+ WebViewCore* webViewCore = WebViewCore::getWebViewCore(frame->view());
+ webViewCore->updateTextSelection();
+}
+
+bool EditorClientAndroid::shouldChangeSelectedRange(Range*, Range*, EAffinity,
+ bool) {
+ return m_shouldChangeSelectedRange;
+}
+
+bool EditorClientAndroid::doTextFieldCommandFromEvent(Element*, KeyboardEvent*) { return false; }
+void EditorClientAndroid::textWillBeDeletedInTextField(Element*) {}
+void EditorClientAndroid::updateSpellingUIWithGrammarString(String const&, GrammarDetail const&) {}
+void EditorClientAndroid::updateSpellingUIWithMisspelledWord(String const&) {}
+void EditorClientAndroid::learnWord(String const&) {}
+
+// functions new to the Nov-16-08 tip of tree merge:
+bool EditorClientAndroid::shouldMoveRangeAfterDelete(Range*, Range*) { return true; }
+void EditorClientAndroid::setInputMethodState(bool) {}
+
+// functions new to Feb-19 tip of tree merge:
+void EditorClientAndroid::handleInputMethodKeydown(KeyboardEvent*) {}
+
+void EditorClientAndroid::willSetInputMethodState()
+{
+ notImplemented();
+}
+
+void EditorClientAndroid::requestCheckingOfString(SpellChecker*, int, const String&) {}
+
+#if ENABLE(WEB_AUTOFILL)
+WebAutoFill* EditorClientAndroid::getAutoFill()
+{
+ if (!m_autoFill)
+ m_autoFill.set(new WebAutoFill());
+
+ return m_autoFill.get();
+}
+#endif
+
+}
diff --git a/Source/WebKit/android/WebCoreSupport/EditorClientAndroid.h b/Source/WebKit/android/WebCoreSupport/EditorClientAndroid.h
new file mode 100644
index 0000000..94a6518
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/EditorClientAndroid.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2007, 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 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;
+
+namespace android {
+
+class EditorClientAndroid : public EditorClient {
+public:
+ EditorClientAndroid() {
+ m_shouldChangeSelectedRange = true;
+ m_uiGeneratedSelectionChange = false;
+ }
+ virtual void pageDestroyed();
+
+ virtual bool shouldDeleteRange(Range*);
+ virtual bool shouldShowDeleteInterface(HTMLElement*);
+ virtual bool smartInsertDeleteEnabled();
+ virtual bool isSelectTrailingWhitespaceEnabled();
+ virtual bool isContinuousSpellCheckingEnabled();
+ virtual void toggleContinuousSpellChecking();
+ virtual bool isGrammarCheckingEnabled();
+ virtual void toggleGrammarChecking();
+ virtual int spellCheckerDocumentTag();
+
+ virtual bool isEditable();
+
+ virtual bool shouldBeginEditing(Range*);
+ virtual bool shouldEndEditing(Range*);
+ virtual bool shouldInsertNode(Node*, Range*, EditorInsertAction);
+ virtual bool shouldInsertText(const String&, Range*, EditorInsertAction);
+ virtual bool shouldChangeSelectedRange(Range* fromRange, Range* toRange, EAffinity, bool stillSelecting);
+
+ virtual bool shouldApplyStyle(CSSStyleDeclaration*, Range*);
+// virtual bool shouldChangeTypingStyle(CSSStyleDeclaration* fromStyle, CSSStyleDeclaration* toStyle);
+// virtual bool doCommandBySelector(SEL selector);
+ virtual bool shouldMoveRangeAfterDelete(Range*, Range*);
+
+ virtual void didBeginEditing();
+ virtual void respondToChangedContents();
+ virtual void respondToChangedSelection();
+ virtual void didEndEditing();
+ virtual void didWriteSelectionToPasteboard();
+ virtual void didSetSelectionTypesForPasteboard();
+// virtual void didChangeTypingStyle:(NSNotification *)notification;
+// virtual void didChangeSelection:(NSNotification *)notification;
+// virtual NSUndoManager* undoManager:(WebView *)webView;
+
+ virtual void registerCommandForUndo(PassRefPtr<EditCommand>);
+ virtual void registerCommandForRedo(PassRefPtr<EditCommand>);
+ virtual void clearUndoRedoOperations();
+
+ virtual bool canUndo() const;
+ virtual bool canRedo() const;
+
+ virtual void undo();
+ virtual void redo();
+
+ virtual void handleKeyboardEvent(KeyboardEvent*);
+ virtual void handleInputMethodKeydown(KeyboardEvent*);
+
+ virtual void textFieldDidBeginEditing(Element*);
+ virtual void textFieldDidEndEditing(Element*);
+ virtual void textDidChangeInTextField(Element*);
+ virtual bool doTextFieldCommandFromEvent(Element*, KeyboardEvent*);
+ virtual void textWillBeDeletedInTextField(Element*);
+ virtual void textDidChangeInTextArea(Element*);
+
+ virtual void ignoreWordInSpellDocument(const String&);
+ virtual void learnWord(const String&);
+ virtual void checkSpellingOfString(const UChar*, int length, int* misspellingLocation, int* misspellingLength);
+ virtual String getAutoCorrectSuggestionForMisspelledWord(const String& misspelledWorld);
+ virtual void checkGrammarOfString(const UChar*, int length, WTF::Vector<GrammarDetail>&, int* badGrammarLocation, int* badGrammarLength);
+ virtual void updateSpellingUIWithGrammarString(const String&, const GrammarDetail& detail);
+ virtual void updateSpellingUIWithMisspelledWord(const String&);
+ virtual void showSpellingUI(bool show);
+ virtual bool spellingUIIsShowing();
+ virtual void getGuessesForWord(const String&, const String& context, WTF::Vector<String>& guesses);
+ virtual void willSetInputMethodState();
+ virtual void setInputMethodState(bool);
+ virtual void requestCheckingOfString(SpellChecker*, int, const String&);
+
+ // Android specific:
+ 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
+};
+
+}
+
+#endif
diff --git a/Source/WebKit/android/WebCoreSupport/FileSystemClient.h b/Source/WebKit/android/WebCoreSupport/FileSystemClient.h
new file mode 100644
index 0000000..5bde18a
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/FileSystemClient.h
@@ -0,0 +1,41 @@
+/*
+ * 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 FILESYSTEM_CLIENT_H
+#define FILESYSTEM_CLIENT_H
+
+#include "PlatformString.h"
+
+using namespace WebCore;
+
+namespace android {
+
+class FileSystemClient {
+public:
+ virtual ~FileSystemClient() { }
+ virtual String resolveFilePathForContentUri(const String&) = 0;
+};
+}
+#endif
diff --git a/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp b/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp
new file mode 100644
index 0000000..946a4a7
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp
@@ -0,0 +1,1351 @@
+/*
+ * Copyright 2007, 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.
+ */
+
+#define LOG_TAG "WebCore"
+
+#include "config.h"
+#include "FrameLoaderClientAndroid.h"
+
+#include "BackForwardList.h"
+#include "CachedFrame.h"
+#include "CachedFramePlatformDataAndroid.h"
+#include "Chrome.h"
+#include "ChromeClientAndroid.h"
+#include "DOMImplementation.h"
+#include "Document.h"
+#include "DocumentLoader.h"
+#include "EditorClientAndroid.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameNetworkingContextAndroid.h"
+#include "FrameTree.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HTMLFrameOwnerElement.h"
+#include "HTMLPlugInElement.h"
+#include "HistoryItem.h"
+#include "IconDatabase.h"
+#include "MIMETypeRegistry.h"
+#include "NotImplemented.h"
+#include "PackageNotifier.h"
+#include "Page.h"
+#include "PlatformBridge.h"
+#include "PlatformGraphicsContext.h"
+#include "PlatformString.h"
+#include "PluginDatabase.h"
+#include "PluginView.h"
+#include "PluginViewBase.h"
+#include "ProgressTracker.h"
+#include "RenderPart.h"
+#include "RenderView.h"
+#include "RenderWidget.h"
+#include "ResourceError.h"
+#include "ResourceHandle.h"
+#include "ResourceHandleInternal.h"
+#include "SelectionController.h"
+#include "Settings.h"
+#include "SkCanvas.h"
+#include "SkRect.h"
+#include "TextEncoding.h"
+#include "WebCoreFrameBridge.h"
+#include "WebCoreResourceLoader.h"
+#include "WebHistory.h"
+#include "WebIconDatabase.h"
+#include "WebFrameView.h"
+#include "WebViewClientError.h"
+#include "WebViewCore.h"
+#include "autofill/WebAutoFill.h"
+#include "android_graphics.h"
+
+#include <utils/AssetManager.h>
+#include <wtf/text/CString.h>
+
+extern android::AssetManager* globalAssetManager();
+
+namespace android {
+
+static const int EXTRA_LAYOUT_DELAY = 1000;
+
+FrameLoaderClientAndroid::FrameLoaderClientAndroid(WebFrame* webframe)
+ : m_frame(NULL)
+ , m_webFrame(webframe)
+ , m_manualLoader(NULL)
+ , m_hasSentResponseToPlugin(false)
+ , m_onDemandPluginsEnabled(false) {
+ Retain(m_webFrame);
+}
+
+FrameLoaderClientAndroid* FrameLoaderClientAndroid::get(const WebCore::Frame* frame)
+{
+ return static_cast<FrameLoaderClientAndroid*> (frame->loader()->client());
+}
+
+void FrameLoaderClientAndroid::frameLoaderDestroyed() {
+ registerForIconNotification(false);
+ m_frame = 0;
+ Release(m_webFrame);
+ delete this;
+}
+
+bool FrameLoaderClientAndroid::hasWebView() const {
+ // FIXME,
+ // there is one web view per page, or top frame.
+ // as android's view is created from Java side, it is always there.
+ return true;
+}
+
+void FrameLoaderClientAndroid::makeRepresentation(DocumentLoader*) {
+ m_onDemandPluginsEnabled = false;
+ // don't use representation
+ verifiedOk();
+}
+
+void FrameLoaderClientAndroid::forceLayout() {
+ ASSERT(m_frame);
+ m_frame->view()->forceLayout();
+ // FIXME, should we adjust view size here?
+ m_frame->view()->adjustViewSize();
+}
+
+void FrameLoaderClientAndroid::forceLayoutForNonHTML() {
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::setCopiesOnScroll() {
+ // this is a hint about whether we need to force redraws, or can
+ // just copy the scrolled content. Since we always force a redraw
+ // anyways, we can ignore this call.
+ verifiedOk();
+}
+
+void FrameLoaderClientAndroid::detachedFromParent2() {
+ // FIXME, ready to detach frame from view
+}
+
+void FrameLoaderClientAndroid::detachedFromParent3() {
+ // FIXME, ready to release view
+ notImplemented();
+}
+
+// This function is responsible for associating the "id" with a given
+// subresource load. The following functions that accept an "id" are
+// called for each subresource, so they should not be dispatched to the m_frame.
+void FrameLoaderClientAndroid::assignIdentifierToInitialRequest(unsigned long id,
+ DocumentLoader*, const ResourceRequest&) {
+ lowPriority_notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchWillSendRequest(DocumentLoader*, unsigned long id,
+ ResourceRequest&, const ResourceResponse&) {
+ lowPriority_notImplemented();
+}
+
+bool FrameLoaderClientAndroid::shouldUseCredentialStorage(DocumentLoader*, unsigned long identifier)
+{
+ notImplemented();
+ return false;
+}
+
+void FrameLoaderClientAndroid::dispatchDidReceiveAuthenticationChallenge(DocumentLoader*,
+ unsigned long id, const AuthenticationChallenge&) {
+ lowPriority_notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchDidCancelAuthenticationChallenge(DocumentLoader*,
+ unsigned long id, const AuthenticationChallenge&) {
+ lowPriority_notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchDidReceiveResponse(DocumentLoader*,
+ unsigned long id, const ResourceResponse&) {
+ lowPriority_notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchDidReceiveContentLength(DocumentLoader*,
+ unsigned long id, int lengthReceived) {
+ lowPriority_notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchDidFinishLoading(DocumentLoader*,
+ unsigned long id) {
+ lowPriority_notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchDidFailLoading(DocumentLoader* docLoader,
+ unsigned long id, const ResourceError&) {
+ lowPriority_notImplemented();
+}
+
+bool FrameLoaderClientAndroid::dispatchDidLoadResourceFromMemoryCache(DocumentLoader*,
+ const ResourceRequest&, const ResourceResponse&, int length) {
+ notImplemented();
+ return false;
+}
+
+void FrameLoaderClientAndroid::dispatchDidHandleOnloadEvents() {
+}
+
+void FrameLoaderClientAndroid::dispatchDidReceiveServerRedirectForProvisionalLoad() {
+ ASSERT(m_frame);
+ // Tell the load it was a redirect.
+ m_webFrame->loadStarted(m_frame);
+}
+
+void FrameLoaderClientAndroid::dispatchDidCancelClientRedirect() {
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchWillPerformClientRedirect(const KURL&,
+ double interval, double fireDate) {
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchDidChangeLocationWithinPage() {
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchDidPushStateWithinPage()
+{
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchDidReplaceStateWithinPage()
+{
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchDidPopStateWithinPage()
+{
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchWillClose() {
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchDidReceiveIcon() {
+ ASSERT(m_frame);
+ if (m_frame->tree() && m_frame->tree()->parent())
+ return;
+ WTF::String url(m_frame->loader()->url().string());
+ // Try to obtain the icon image.
+ WebCore::Image* icon = WebCore::iconDatabase()->iconForPageURL(
+ url, WebCore::IntSize(16, 16));
+ // If the request fails, try the original request url.
+ if (!icon) {
+ DocumentLoader* docLoader = m_frame->loader()->activeDocumentLoader();
+ KURL originalURL = docLoader->originalRequest().url();
+ icon = WebCore::iconDatabase()->iconForPageURL(
+ originalURL, WebCore::IntSize(16, 16));
+ }
+ // There is a bug in webkit where cancelling an icon load is treated as a
+ // failure. When this is fixed, we can ASSERT again that we have an icon.
+ if (icon) {
+ LOGV("Received icon (%p) for %s", icon,
+ url.utf8().data());
+ m_webFrame->didReceiveIcon(icon);
+ } else {
+ LOGV("Icon data for %s unavailable, registering for notification...",
+ url.utf8().data());
+ registerForIconNotification();
+ }
+}
+
+void FrameLoaderClientAndroid::dispatchDidReceiveTouchIconURL(const String& url, bool precomposed) {
+ ASSERT(m_frame);
+ // Do not report sub frame touch icons
+ if (m_frame->tree() && m_frame->tree()->parent())
+ return;
+ m_webFrame->didReceiveTouchIconURL(url, precomposed);
+}
+
+void FrameLoaderClientAndroid::dispatchDidStartProvisionalLoad() {
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchDidReceiveTitle(const String& title) {
+ ASSERT(m_frame);
+ // Used to check for FrameLoadTypeStandard but we only want to send the title for
+ // the top frame and not sub-frames.
+ if (!m_frame->tree() || !m_frame->tree()->parent()) {
+ m_webFrame->setTitle(title);
+ }
+}
+
+void FrameLoaderClientAndroid::dispatchDidCommitLoad() {
+#if ENABLE(WEB_AUTOFILL)
+ if (m_frame == m_frame->page()->mainFrame()) {
+ EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(m_frame->page()->editorClient());
+ WebAutoFill* autoFill = editorC->getAutoFill();
+ autoFill->reset();
+ }
+#endif
+ verifiedOk();
+}
+
+static void loadDataIntoFrame(Frame* frame, KURL baseUrl, const String& url,
+ const String& data) {
+ if (baseUrl.isEmpty()) {
+ baseUrl = blankURL();
+ }
+ ResourceRequest request(baseUrl);
+ CString cstr = data.utf8();
+ RefPtr<WebCore::SharedBuffer> buf = WebCore::SharedBuffer::create(cstr.data(), cstr.length());
+ SubstituteData subData(buf, String("text/html"), String("utf-8"),
+ KURL(KURL(), url));
+ frame->loader()->load(request, subData, false);
+}
+
+void FrameLoaderClientAndroid::dispatchDidFailProvisionalLoad(const ResourceError& error) {
+ ASSERT(m_frame);
+ // Ignore ErrorInterrupted since it is due to a policy interruption. This
+ // is caused by a decision to download the main resource rather than
+ // display it.
+ if (error.errorCode() == InternalErrorInterrupted
+ || error.errorCode() == InternalErrorCancelled) {
+ // If we decided to download the main resource or if the user cancelled
+ // it, make sure we report that the load is done.
+ didFinishLoad();
+ return;
+ }
+
+ AssetManager* am = globalAssetManager();
+
+ // Check to see if the error code was not generated internally
+ WebCore::PlatformBridge::rawResId id = WebCore::PlatformBridge::NoDomain;
+ if ((error.errorCode() == ErrorFile ||
+ error.errorCode() == ErrorFileNotFound) &&
+ (!error.localizedDescription().isEmpty())) {
+ id = WebCore::PlatformBridge::LoadError;
+ }
+ String filename = m_webFrame->getRawResourceFilename(id);
+ if (filename.isEmpty())
+ return;
+
+ // Grab the error page from the asset manager
+ Asset* a = am->openNonAsset(
+ filename.utf8().data(), Asset::ACCESS_BUFFER);
+ if (!a)
+ return;
+
+ // Take the failing url and encode html entities so javascript urls are not
+ // executed.
+ CString failingUrl = error.failingURL().utf8();
+ WTF::Vector<char> url;
+ int len = failingUrl.length();
+ const char* data = failingUrl.data();
+ for (int i = 0; i < len; i++) {
+ char c = data[i];
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
+ || (c >= '0' && c <= '9'))
+ url.append(c);
+ else {
+ char buf[16];
+ int res = sprintf(buf, "&#%d;", c);
+ buf[res] = 0;
+ url.append(buf, res);
+ }
+ }
+
+ // Replace all occurances of %s with the failing url.
+ String s = UTF8Encoding().decode((const char*)a->getBuffer(false), a->getLength());
+ s = s.replace("%s", String(url.data(), url.size()));
+
+ // Replace all occurances of %e with the error text
+ s = s.replace("%e", error.localizedDescription());
+
+ // Create the request and the substitute data and tell the FrameLoader to
+ // load with the replacement data.
+ // use KURL(const char*) as KURL(const String& url) can trigger ASSERT for
+ // invalidate URL string.
+ loadDataIntoFrame(m_frame, KURL(ParsedURLString, data), error.failingURL(), s);
+
+ // Delete the asset.
+ delete a;
+
+ // Report that the load is finished, since it failed.
+ didFinishLoad();
+}
+
+void FrameLoaderClientAndroid::dispatchDidFailLoad(const ResourceError&) {
+ // called when page is completed with error
+ didFinishLoad();
+}
+
+void FrameLoaderClientAndroid::dispatchDidFinishDocumentLoad() {
+ // called when finishedParsing
+ lowPriority_notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchDidFinishLoad() {
+ didFinishLoad();
+}
+
+void FrameLoaderClientAndroid::dispatchDidFirstLayout() {
+ ASSERT(m_frame);
+ // set EXTRA_LAYOUT_DELAY if the loader is not completed yet
+ if (!m_frame->loader()->isComplete())
+ m_frame->document()->setExtraLayoutDelay(EXTRA_LAYOUT_DELAY);
+ // we need to do this here instead of dispatchDidFirstVisuallyNonEmptyLayout
+ // so that about:blank will update the screen.
+ if (!m_frame->tree()->parent()) {
+ // Only need to notify Java side for the top frame
+ WebViewCore::getWebViewCore(m_frame->view())->didFirstLayout();
+ }
+}
+
+void FrameLoaderClientAndroid::dispatchDidFirstVisuallyNonEmptyLayout()
+{
+ notImplemented();
+}
+
+Frame* FrameLoaderClientAndroid::dispatchCreatePage(const NavigationAction&) {
+ ASSERT(m_frame);
+#ifdef ANDROID_MULTIPLE_WINDOWS
+ if (m_frame->settings() && m_frame->settings()->supportMultipleWindows())
+ // Always a user gesture since window.open maps to
+ // ChromeClientAndroid::createWindow
+ return m_webFrame->createWindow(false, true);
+ else
+#endif
+ // If the client doesn't support multiple windows, just replace the
+ // current frame's contents.
+ return m_frame;
+}
+
+void FrameLoaderClientAndroid::dispatchShow() {
+ ASSERT(m_frame);
+ m_frame->view()->invalidate();
+}
+
+
+static bool TreatAsAttachment(const String& content_disposition) {
+ // 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 FrameLoaderClientAndroid::dispatchDecidePolicyForMIMEType(FramePolicyFunction func,
+ const String& MIMEType, const ResourceRequest& request) {
+ ASSERT(m_frame);
+ ASSERT(func);
+ if (!func)
+ return;
+
+ PolicyChecker* policy = m_frame->loader()->policyChecker();
+
+ if (request.isNull()) {
+ (policy->*func)(PolicyIgnore);
+ return;
+ }
+ // Default to Use (display internally).
+ PolicyAction action = PolicyUse;
+ // Check if we should Download instead.
+ const ResourceResponse& response = m_frame->loader()->activeDocumentLoader()->response();
+ const String& content_disposition = response.httpHeaderField("Content-Disposition");
+ if (!content_disposition.isEmpty() &&
+ TreatAsAttachment(content_disposition)) {
+ // Server wants to override our normal policy.
+ // Check to see if we are a sub frame (main frame has no owner element)
+ if (m_frame->ownerElement() != 0)
+ action = PolicyIgnore;
+ else
+ action = PolicyDownload;
+ (policy->*func)(action);
+ return;
+ }
+
+ // Ask if it can be handled internally.
+ if (!canShowMIMEType(MIMEType)) {
+ // Check to see if we are a sub frame (main frame has no owner element)
+ if (m_frame->ownerElement() != 0)
+ action = PolicyIgnore;
+ else
+ action = PolicyDownload;
+ (policy->*func)(action);
+ return;
+ }
+ // A status code of 204 indicates no content change. Ignore the result.
+ WebCore::DocumentLoader* docLoader = m_frame->loader()->activeDocumentLoader();
+ if (docLoader->response().httpStatusCode() == 204)
+ action = PolicyIgnore;
+ (policy->*func)(action);
+}
+
+void FrameLoaderClientAndroid::dispatchDecidePolicyForNewWindowAction(FramePolicyFunction func,
+ const NavigationAction& action, const ResourceRequest& request,
+ PassRefPtr<FormState> formState, const String& frameName) {
+ ASSERT(m_frame);
+ ASSERT(func);
+ if (!func)
+ return;
+
+ if (request.isNull()) {
+ (m_frame->loader()->policyChecker()->*func)(PolicyIgnore);
+ return;
+ }
+
+ if (action.type() == NavigationTypeFormSubmitted || action.type() == NavigationTypeFormResubmitted)
+ m_frame->loader()->resetMultipleFormSubmissionProtection();
+
+ // If we get to this point it means that a link has a target that was not
+ // found by the frame tree. Instead of creating a new frame, return the
+ // current frame in dispatchCreatePage.
+ if (canHandleRequest(request))
+ (m_frame->loader()->policyChecker()->*func)(PolicyUse);
+ else
+ (m_frame->loader()->policyChecker()->*func)(PolicyIgnore);
+}
+
+void FrameLoaderClientAndroid::cancelPolicyCheck() {
+ lowPriority_notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchUnableToImplementPolicy(const ResourceError&) {
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchDecidePolicyForNavigationAction(FramePolicyFunction func,
+ const NavigationAction& action, const ResourceRequest& request,
+ PassRefPtr<FormState> formState) {
+ ASSERT(m_frame);
+ ASSERT(func);
+ if (!func)
+ return;
+ if (request.isNull()) {
+ (m_frame->loader()->policyChecker()->*func)(PolicyIgnore);
+ return;
+ }
+
+ // Reset multiple form submission protection. If this is a resubmission, we check with the
+ // user and reset the protection if they choose to resubmit the form (see WebCoreFrameBridge.cpp)
+ if (action.type() == NavigationTypeFormSubmitted)
+ m_frame->loader()->resetMultipleFormSubmissionProtection();
+
+ if (action.type() == NavigationTypeFormResubmitted) {
+ m_webFrame->decidePolicyForFormResubmission(func);
+ return;
+ } else
+ (m_frame->loader()->policyChecker()->*func)(PolicyUse);
+}
+
+void FrameLoaderClientAndroid::dispatchWillSubmitForm(FramePolicyFunction func, PassRefPtr<FormState>) {
+ ASSERT(m_frame);
+ ASSERT(func);
+ (m_frame->loader()->policyChecker()->*func)(PolicyUse);
+}
+
+void FrameLoaderClientAndroid::dispatchWillSendSubmitEvent(HTMLFormElement* form)
+{
+ if (m_webFrame->shouldSaveFormData())
+ m_webFrame->saveFormData(form);
+}
+
+void FrameLoaderClientAndroid::dispatchDidLoadMainResource(DocumentLoader*) {
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::revertToProvisionalState(DocumentLoader*) {
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::setMainDocumentError(DocumentLoader* docLoader, const ResourceError& error) {
+ ASSERT(m_frame);
+ if (m_manualLoader) {
+ m_manualLoader->didFail(error);
+ m_manualLoader = NULL;
+ m_hasSentResponseToPlugin = false;
+ } else {
+ if (!error.isNull() && error.errorCode() >= InternalErrorLast && error.errorCode() != ERROR_OK)
+ m_webFrame->reportError(error.errorCode(),
+ error.localizedDescription(), error.failingURL());
+ }
+}
+
+// This function is called right before the progress is updated.
+void FrameLoaderClientAndroid::willChangeEstimatedProgress() {
+ verifiedOk();
+}
+
+// This function is called after the progress has been updated. The bad part
+// about this is that when a page is completed, this function is called after
+// the progress has been reset to 0.
+void FrameLoaderClientAndroid::didChangeEstimatedProgress() {
+ verifiedOk();
+}
+
+// This will give us the initial estimate when the page first starts to load.
+void FrameLoaderClientAndroid::postProgressStartedNotification() {
+ ASSERT(m_frame);
+ if (m_frame->page())
+ m_webFrame->setProgress(m_frame->page()->progress()->estimatedProgress());
+}
+
+// This will give us any updated progress including the final progress.
+void FrameLoaderClientAndroid::postProgressEstimateChangedNotification() {
+ ASSERT(m_frame);
+ if (m_frame->page())
+ m_webFrame->setProgress(m_frame->page()->progress()->estimatedProgress());
+}
+
+// This is just a notification that the progress has finished. Don't call
+// setProgress(1) because postProgressEstimateChangedNotification will do so.
+void FrameLoaderClientAndroid::postProgressFinishedNotification() {
+ WebViewCore* core = WebViewCore::getWebViewCore(m_frame->view());
+ if (!m_frame->tree()->parent()) {
+ // only need to notify Java for the top frame
+ core->notifyProgressFinished();
+ }
+ // notify plugins that the frame has loaded
+ core->notifyPluginsOnFrameLoad(m_frame);
+}
+
+void FrameLoaderClientAndroid::setMainFrameDocumentReady(bool) {
+ // this is only interesting once we provide an external API for the DOM
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::startDownload(const ResourceRequest&) {
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::willChangeTitle(DocumentLoader*) {
+ verifiedOk();
+}
+
+void FrameLoaderClientAndroid::didChangeTitle(DocumentLoader* loader) {
+ verifiedOk();
+}
+
+void FrameLoaderClientAndroid::finishedLoading(DocumentLoader* docLoader) {
+ // Telling the frame we received some data and passing 0 as the data is our
+ // way to get work done that is normally done when the first bit of data is
+ // received, even for the case of a document with no data (like about:blank)
+ if (!m_manualLoader) {
+ committedLoad(docLoader, 0, 0);
+ return;
+ }
+
+ m_manualLoader->didFinishLoading();
+ m_manualLoader = NULL;
+ m_hasSentResponseToPlugin = false;
+}
+
+void FrameLoaderClientAndroid::updateGlobalHistory() {
+ ASSERT(m_frame);
+
+ DocumentLoader* docLoader = m_frame->loader()->documentLoader();
+ ASSERT(docLoader);
+
+ // Code copied from FrameLoader.cpp:createHistoryItem
+ // Only add this URL to the database if it is a valid page
+ if (docLoader->unreachableURL().isEmpty()
+ && docLoader->response().httpStatusCode() < 400) {
+ m_webFrame->updateVisitedHistory(docLoader->urlForHistory(), false);
+ if (!docLoader->serverRedirectSourceForHistory().isNull())
+ m_webFrame->updateVisitedHistory(KURL(ParsedURLString, docLoader->serverRedirectDestinationForHistory()), false);
+ }
+}
+
+void FrameLoaderClientAndroid::updateGlobalHistoryRedirectLinks() {
+ // Note, do we need to do anything where there is no HistoryItem? If we call
+ // updateGlobalHistory(), we will add bunch of "data:xxx" urls for gmail.com
+ // which is not what we want. Opt to do nothing now.
+}
+
+bool FrameLoaderClientAndroid::shouldGoToHistoryItem(HistoryItem* item) const {
+ // hmmm, seems like we might do a more thoughtful check
+ ASSERT(m_frame);
+ return item != NULL;
+}
+
+void FrameLoaderClientAndroid::didDisplayInsecureContent()
+{
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::didRunInsecureContent(SecurityOrigin*)
+{
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::committedLoad(DocumentLoader* loader, const char* data, int length) {
+ if (!m_manualLoader)
+ loader->commitData(data, length);
+
+ // commit data may have created a manual plugin loader
+ if (m_manualLoader) {
+ if (!m_hasSentResponseToPlugin) {
+ m_manualLoader->didReceiveResponse(loader->response());
+ // Failure could cause the main document to have an error causing
+ // the manual loader to be reset.
+ if (!m_manualLoader)
+ return;
+ m_hasSentResponseToPlugin = true;
+ }
+ m_manualLoader->didReceiveData(data, length);
+ }
+}
+
+ResourceError FrameLoaderClientAndroid::cancelledError(const ResourceRequest& request) {
+ return ResourceError(String(), InternalErrorCancelled, request.url(), String());
+}
+
+ResourceError FrameLoaderClientAndroid::cannotShowURLError(const ResourceRequest& request) {
+ return ResourceError(String(), InternalErrorCannotShowUrl, request.url(), String());
+}
+
+ResourceError FrameLoaderClientAndroid::interruptForPolicyChangeError(const ResourceRequest& request) {
+ return ResourceError(String(), InternalErrorInterrupted, request.url(), String());
+}
+
+ResourceError FrameLoaderClientAndroid::cannotShowMIMETypeError(const ResourceResponse& request) {
+ return ResourceError(String(), InternalErrorCannotShowMimeType, request.url(), String());
+}
+
+ResourceError FrameLoaderClientAndroid::fileDoesNotExistError(const ResourceResponse& request) {
+ return ResourceError(String(), InternalErrorFileDoesNotExist, request.url(), String());
+}
+
+ResourceError FrameLoaderClientAndroid::pluginWillHandleLoadError(const ResourceResponse& request) {
+ return ResourceError(String(), InternalErrorPluginWillHandleLoadError, request.url(), String());
+}
+
+bool FrameLoaderClientAndroid::shouldFallBack(const ResourceError&) {
+ notImplemented();
+ return false;
+}
+
+bool FrameLoaderClientAndroid::canHandleRequest(const ResourceRequest& request) const {
+ ASSERT(m_frame);
+ // Don't allow hijacking of intrapage navigation
+ if (WebCore::equalIgnoringFragmentIdentifier(request.url(), m_frame->loader()->url()))
+ return true;
+
+ // Don't allow hijacking of iframe urls that are http or https
+ if (request.url().protocol().startsWith("http", false) &&
+ m_frame->tree() && m_frame->tree()->parent())
+ return true;
+
+ return m_webFrame->canHandleRequest(request);
+}
+
+bool FrameLoaderClientAndroid::canShowMIMEType(const String& mimeType) const {
+ // FIXME: This looks like it has to do with whether or not a type can be
+ // shown "internally" (i.e. inside the browser) regardless of whether
+ // or not the browser is doing the rendering, e.g. a full page plugin.
+ if (MIMETypeRegistry::isSupportedImageResourceMIMEType(mimeType) ||
+ MIMETypeRegistry::isSupportedNonImageMIMEType(mimeType) ||
+ MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType) ||
+ (m_frame && m_frame->settings()
+ && m_frame->settings()->arePluginsEnabled()
+ && PluginDatabase::installedPlugins()->isMIMETypeRegistered(
+ mimeType)) ||
+ (DOMImplementation::isTextMIMEType(mimeType) &&
+ !mimeType.startsWith("text/vnd")) ||
+ DOMImplementation::isXMLMIMEType(mimeType))
+ return true;
+ return false;
+}
+
+bool FrameLoaderClientAndroid::canShowMIMETypeAsHTML(const String& mimeType) const {
+ return false;
+}
+
+bool FrameLoaderClientAndroid::representationExistsForURLScheme(const String&) const {
+ // don't use representation
+ verifiedOk();
+ return false;
+}
+
+String FrameLoaderClientAndroid::generatedMIMETypeForURLScheme(const String& URLScheme) const {
+ // FIXME, copy from Apple's port
+ String mimetype("x-apple-web-kit/");
+ mimetype.append(URLScheme.lower());
+ return mimetype;
+}
+
+void FrameLoaderClientAndroid::frameLoadCompleted() {
+ // copied from Apple port, without this back with sub-frame will trigger ASSERT
+ ASSERT(m_frame);
+}
+
+void FrameLoaderClientAndroid::saveViewStateToItem(HistoryItem* item) {
+ ASSERT(m_frame);
+ ASSERT(item);
+ // store the current scale (only) for the top frame
+ if (!m_frame->tree()->parent()) {
+ // We should have added a bridge when the child item was added to its
+ // parent.
+ AndroidWebHistoryBridge* bridge = item->bridge();
+ ASSERT(bridge);
+ WebViewCore* webViewCore = WebViewCore::getWebViewCore(m_frame->view());
+ bridge->setScale(webViewCore->scale());
+ bridge->setTextWrapScale(webViewCore->textWrapScale());
+ }
+
+ WebCore::notifyHistoryItemChanged(item);
+}
+
+void FrameLoaderClientAndroid::restoreViewState() {
+ WebViewCore* webViewCore = WebViewCore::getWebViewCore(m_frame->view());
+ HistoryItem* item = m_frame->loader()->history()->currentItem();
+ AndroidWebHistoryBridge* bridge = item->bridge();
+ // restore the scale (only) for the top frame
+ if (!m_frame->tree()->parent()) {
+ webViewCore->restoreScale(bridge->scale(), bridge->textWrapScale());
+ }
+}
+
+void FrameLoaderClientAndroid::dispatchDidAddBackForwardItem(HistoryItem* item) const {
+ ASSERT(m_frame);
+ m_webFrame->addHistoryItem(item);
+}
+
+void FrameLoaderClientAndroid::dispatchDidRemoveBackForwardItem(HistoryItem* item) const {
+ ASSERT(m_frame);
+ m_webFrame->removeHistoryItem(0);
+}
+
+void FrameLoaderClientAndroid::dispatchDidChangeBackForwardIndex() const {
+ ASSERT(m_frame);
+ BackForwardList* list = m_frame->page()->backForwardList();
+ ASSERT(list);
+ m_webFrame->updateHistoryIndex(list->backListCount());
+}
+
+void FrameLoaderClientAndroid::provisionalLoadStarted() {
+ ASSERT(m_frame);
+ m_webFrame->loadStarted(m_frame);
+}
+
+void FrameLoaderClientAndroid::didFinishLoad() {
+ ASSERT(m_frame);
+ m_frame->document()->setExtraLayoutDelay(0);
+ m_webFrame->didFinishLoad(m_frame);
+}
+
+void FrameLoaderClientAndroid::prepareForDataSourceReplacement() {
+ verifiedOk();
+}
+
+PassRefPtr<DocumentLoader> FrameLoaderClientAndroid::createDocumentLoader(
+ const ResourceRequest& request, const SubstituteData& data) {
+ RefPtr<DocumentLoader> loader = DocumentLoader::create(request, data);
+ return loader.release();
+}
+
+void FrameLoaderClientAndroid::setTitle(const String& title, const KURL& url) {
+ // Not needed. dispatchDidReceiveTitle is called immediately after this.
+ // url is used to update the Apple port history items.
+ verifiedOk();
+}
+
+String FrameLoaderClientAndroid::userAgent(const KURL& u) {
+ return m_webFrame->userAgentForURL(&u);
+}
+
+void FrameLoaderClientAndroid::savePlatformDataToCachedFrame(WebCore::CachedFrame* cachedFrame) {
+ CachedFramePlatformDataAndroid* platformData = new CachedFramePlatformDataAndroid(m_frame->settings());
+ cachedFrame->setCachedFramePlatformData(platformData);
+}
+
+void FrameLoaderClientAndroid::transitionToCommittedFromCachedFrame(WebCore::CachedFrame* cachedFrame) {
+ CachedFramePlatformDataAndroid* platformData = reinterpret_cast<CachedFramePlatformDataAndroid*>(cachedFrame->cachedFramePlatformData());
+#ifdef ANDROID_META_SUPPORT
+ platformData->restoreMetadata(m_frame->settings());
+#endif
+ m_webFrame->transitionToCommitted(m_frame);
+}
+
+void FrameLoaderClientAndroid::transitionToCommittedForNewPage() {
+ ASSERT(m_frame);
+
+#ifdef ANDROID_META_SUPPORT
+ // reset metadata settings for the main frame as they are not preserved cross page
+ if (m_frame == m_frame->page()->mainFrame() && m_frame->settings())
+ m_frame->settings()->resetMetadataSettings();
+#endif
+
+ // Save the old WebViewCore before creating a new FrameView. There is one
+ // WebViewCore per page. Each frame, including the main frame and sub frame,
+ // has a 1:1 FrameView and WebFrameView.
+ WebViewCore* webViewCore = WebViewCore::getWebViewCore(m_frame->view());
+ Retain(webViewCore);
+
+ // Save the old WebFrameView's bounds and apply them to the new WebFrameView
+ WebFrameView* oldWebFrameView = static_cast<WebFrameView*> (m_frame->view()->platformWidget());
+ IntRect bounds = oldWebFrameView->getBounds();
+ IntRect visBounds = oldWebFrameView->getVisibleBounds();
+ IntRect windowBounds = oldWebFrameView->getWindowBounds();
+ WebCore::FrameView* oldFrameView = oldWebFrameView->view();
+ const float oldZoomFactor = oldFrameView->frame()->textZoomFactor();
+ m_frame->createView(bounds.size(), oldFrameView->baseBackgroundColor(), oldFrameView->isTransparent(),
+ oldFrameView->fixedLayoutSize(), oldFrameView->useFixedLayout());
+ if (oldZoomFactor != 1.0f && oldZoomFactor != m_frame->textZoomFactor()) {
+ m_frame->setTextZoomFactor(oldZoomFactor);
+ }
+
+ // Create a new WebFrameView for the new FrameView
+ WebFrameView* newFrameView = new WebFrameView(m_frame->view(), webViewCore);
+ newFrameView->setLocation(bounds.x(), bounds.y());
+ newFrameView->setSize(bounds.width(), bounds.height());
+ newFrameView->setVisibleSize(visBounds.width(), visBounds.height());
+ newFrameView->setWindowBounds(windowBounds.x(), windowBounds.y(), windowBounds.width(), windowBounds.height());
+ // newFrameView attaches itself to FrameView which Retains the reference, so
+ // call Release for newFrameView
+ Release(newFrameView);
+ // WebFrameView Retains webViewCore, so call Release for webViewCore
+ Release(webViewCore);
+
+ m_webFrame->transitionToCommitted(m_frame);
+}
+
+void FrameLoaderClientAndroid::dispatchDidBecomeFrameset(bool)
+{
+}
+
+bool FrameLoaderClientAndroid::canCachePage() const {
+ return true;
+}
+
+void FrameLoaderClientAndroid::download(ResourceHandle* handle, const ResourceRequest&,
+ const ResourceRequest&, const ResourceResponse&) {
+ // Get the C++ side of the load listener and tell it to handle the download
+ handle->getInternal()->m_loader->downloadFile();
+}
+
+WTF::PassRefPtr<WebCore::Frame> FrameLoaderClientAndroid::createFrame(const KURL& url, const String& name,
+ HTMLFrameOwnerElement* ownerElement, const String& referrer,
+ bool allowsScrolling, int marginWidth, int marginHeight)
+{
+ Frame* parent = ownerElement->document()->frame();
+ FrameLoaderClientAndroid* loaderC = new FrameLoaderClientAndroid(m_webFrame);
+ RefPtr<Frame> pFrame = Frame::create(parent->page(), ownerElement, loaderC);
+ Frame* newFrame = pFrame.get();
+ loaderC->setFrame(newFrame);
+ // Append the subframe to the parent and set the name of the subframe. The name must be set after
+ // appending the child so that the name becomes unique.
+ parent->tree()->appendChild(newFrame);
+ newFrame->tree()->setName(name);
+ // Create a new FrameView and WebFrameView for the child frame to draw into.
+ RefPtr<FrameView> frameView = FrameView::create(newFrame);
+ WebFrameView* webFrameView = new WebFrameView(frameView.get(),
+ WebViewCore::getWebViewCore(parent->view()));
+ // frameView Retains webFrameView, so call Release for webFrameView
+ Release(webFrameView);
+ // Attach the frameView to the newFrame.
+ newFrame->setView(frameView);
+ newFrame->init();
+ newFrame->selection()->setFocused(true);
+ LOGV("::WebCore:: createSubFrame returning %p", newFrame);
+
+ // The creation of the frame may have run arbitrary JavaScript that removed it from the page already.
+ if (!pFrame->page())
+ return 0;
+
+ parent->loader()->loadURLIntoChildFrame(url, referrer, pFrame.get());
+
+ // onLoad may cuase the frame to be removed from the document. Allow the RefPtr to delete the child frame.
+ if (!pFrame->tree()->parent())
+ return NULL;
+
+ return pFrame.release();
+}
+
+// YouTube flash url path starts with /v/
+static const char slash_v_slash[] = { '/', 'v', '/' };
+static const char slash_e_slash[] = { '/', 'e', '/' };
+
+static bool isValidYouTubeVideo(const String& path)
+{
+ if (!charactersAreAllASCII(path.characters(), path.length()))
+ return false;
+ unsigned int len = path.length();
+ if (len <= sizeof(slash_v_slash)) // check for more than just /v/
+ return false;
+ CString str = path.lower().utf8();
+ const char* data = str.data();
+ // Youtube flash url can start with /v/ or /e/
+ if (memcmp(data, slash_v_slash, sizeof(slash_v_slash)) != 0)
+ if (memcmp(data, slash_e_slash, sizeof(slash_e_slash)) != 0)
+ return false;
+ // Start after /v/
+ for (unsigned int i = sizeof(slash_v_slash); i < len; i++) {
+ char c = data[i];
+ // Check for alpha-numeric characters only.
+ if (WTF::isASCIIAlphanumeric(c) || c == '_' || c == '-')
+ continue;
+ // The url can have more parameters such as &hl=en after the video id.
+ // Once we start seeing extra parameters we can return true.
+ return c == '&' && i > sizeof(slash_v_slash);
+ }
+ return true;
+}
+
+static bool isYouTubeUrl(const KURL& url, const String& mimeType)
+{
+ String host = url.host();
+ bool youtube = host.endsWith("youtube.com")
+ || host.endsWith("youtube-nocookie.com");
+ return youtube && isValidYouTubeVideo(url.path())
+ && equalIgnoringCase(mimeType, "application/x-shockwave-flash");
+}
+
+static bool isYouTubeInstalled() {
+ return WebCore::packageNotifier().isPackageInstalled("com.google.android.youtube");
+}
+
+// Use PluginViewBase rather than an Android specific sub class as we do not require any
+// Android specific functionality; this just renders a placeholder which will later
+// activate the real plugin.
+class PluginToggleWidget : public PluginViewBase {
+public:
+ PluginToggleWidget(Frame* parent, const IntSize& size,
+ HTMLPlugInElement* elem, const KURL& url,
+ const WTF::Vector<String>& paramNames,
+ const WTF::Vector<String>& paramValues, const String& mimeType,
+ bool loadManually)
+ : PluginViewBase(0)
+ , m_parent(parent)
+ , m_size(size)
+ , m_element(elem)
+ , m_url(url)
+ , m_paramNames(paramNames)
+ , m_paramValues(paramValues)
+ , m_mimeType(mimeType)
+ , m_loadManually(loadManually)
+ {
+ resize(size);
+ }
+
+ virtual void paint(GraphicsContext* ctx, const IntRect& rect)
+ {
+ // Most of this code is copied from PluginView::paintMissingPluginIcon
+ // with slight modification.
+
+ static RefPtr<Image> image;
+ if (!image) {
+ image = Image::loadPlatformResource("togglePlugin");
+ }
+
+ IntRect imageRect(x(), y(), image->width(), image->height());
+
+ int xOffset = (width() - imageRect.width()) >> 1;
+ int yOffset = (height() - imageRect.height()) >> 1;
+
+ imageRect.move(xOffset, yOffset);
+
+ if (!rect.intersects(imageRect))
+ return;
+
+ // FIXME: We need to clip similarly to paintMissingPluginIcon but it is
+ // way screwed up right now. It has something to do with how we tell
+ // webkit the scroll position and it causes the placeholder to get
+ // clipped very badly. http://b/issue?id=2533303
+
+ ctx->save();
+ ctx->clip(frameRect());
+
+ ctx->setFillColor(Color::white, ColorSpaceDeviceRGB);
+ ctx->fillRect(frameRect());
+ if (frameRect().contains(imageRect)) {
+ // Leave a 2 pixel padding.
+ const int pixelWidth = 2;
+ IntRect innerRect = frameRect();
+ innerRect.inflate(-pixelWidth);
+ // Draw a 2 pixel light gray border.
+ ctx->setStrokeColor(Color::lightGray, ColorSpaceDeviceRGB);
+ ctx->strokeRect(innerRect, pixelWidth);
+ }
+
+ // Draw the image in the center
+ ctx->drawImage(image.get(), ColorSpaceDeviceRGB, imageRect.location());
+ ctx->restore();
+ }
+
+ virtual void handleEvent(Event* event)
+ {
+ if (event->type() != eventNames().clickEvent)
+ return;
+
+ Frame* frame = m_parent->page()->mainFrame();
+ while (frame) {
+ RenderView* view = frame->contentRenderer();
+ const HashSet<RenderWidget*> widgets = view->widgets();
+ HashSet<RenderWidget*>::const_iterator it = widgets.begin();
+ HashSet<RenderWidget*>::const_iterator end = widgets.end();
+ for (; it != end; ++it) {
+ Widget* widget = (*it)->widget();
+ // PluginWidget is used only with PluginToggleWidget
+ if (widget && widget->isPluginViewBase()) {
+ PluginToggleWidget* ptw =
+ static_cast<PluginToggleWidget*>(widget);
+ ptw->swapPlugin(*it);
+ }
+ }
+ frame = frame->tree()->traverseNext();
+ }
+ }
+
+ void swapPlugin(RenderWidget* renderer) {
+ typedef FrameLoaderClientAndroid FLCA;
+ FLCA* client = static_cast<FLCA*>(m_parent->loader()->client());
+ client->enableOnDemandPlugins();
+ WTF::PassRefPtr<PluginView> prpWidget =
+ PluginView::create(m_parent.get(),
+ m_size,
+ m_element,
+ m_url,
+ m_paramNames,
+ m_paramValues,
+ m_mimeType,
+ m_loadManually);
+ RefPtr<Widget> myProtector(this);
+ prpWidget->focusPluginElement();
+ renderer->setWidget(prpWidget);
+ }
+
+private:
+ void invalidateRect(const IntRect& rect) { }
+
+ RefPtr<Frame> m_parent;
+ IntSize m_size;
+ HTMLPlugInElement* m_element;
+ KURL m_url;
+ WTF::Vector<String> m_paramNames;
+ WTF::Vector<String> m_paramValues;
+ String m_mimeType;
+ bool m_loadManually;
+};
+
+WTF::PassRefPtr<Widget> FrameLoaderClientAndroid::createPlugin(
+ const IntSize& size,
+ HTMLPlugInElement* element,
+ const KURL& url,
+ const WTF::Vector<String>& names,
+ const WTF::Vector<String>& values,
+ const String& mimeType,
+ bool loadManually) {
+ WTF::PassRefPtr<PluginView> prpWidget = 0;
+#ifdef ANDROID_PLUGINS
+ // This is copied from PluginView.cpp. We need to determine if a plugin
+ // will be found before doing some of the work in PluginView.
+ String mimeTypeCopy = mimeType;
+ PluginPackage* plugin =
+ PluginDatabase::installedPlugins()->findPlugin(url, mimeTypeCopy);
+ if (!plugin && PluginDatabase::installedPlugins()->refresh()) {
+ mimeTypeCopy = mimeType;
+ plugin = PluginDatabase::installedPlugins()->findPlugin(url,
+ mimeTypeCopy);
+ }
+ Settings* settings = m_frame->settings();
+ // Do the placeholder if plugins are on-demand and there is a plugin for the
+ // given mime type.
+ if (settings && settings->arePluginsOnDemand() && plugin &&
+ !m_onDemandPluginsEnabled) {
+ return adoptRef(new PluginToggleWidget(m_frame, size, element, url,
+ names, values, mimeType, loadManually));
+ }
+ prpWidget = PluginView::create(m_frame,
+ size,
+ element,
+ url,
+ names,
+ values,
+ mimeType,
+ loadManually);
+ // Return the plugin if it was loaded successfully. Otherwise, fallback to
+ // the youtube placeholder if possible. No need to check prpWidget as
+ // PluginView::create will create a PluginView for missing plugins.
+ // Note: this check really only checks if the plugin was found and not if
+ // the plugin was loaded.
+ if (prpWidget->status() == PluginStatusLoadedSuccessfully)
+ return prpWidget;
+#endif
+ // Create an iframe for youtube urls.
+ if (isYouTubeUrl(url, mimeType) && isYouTubeInstalled()) {
+ WTF::RefPtr<Frame> frame = createFrame(blankURL(), String(), element,
+ String(), false, 0, 0);
+ if (frame) {
+ // grab everything after /v/
+ String videoId = url.path().substring(sizeof(slash_v_slash));
+ // Extract just the video id
+ unsigned videoIdEnd = 0;
+ for (; videoIdEnd < videoId.length(); videoIdEnd++) {
+ if (videoId[videoIdEnd] == '&') {
+ videoId = videoId.left(videoIdEnd);
+ break;
+ }
+ }
+ AssetManager* am = globalAssetManager();
+ Asset* a = am->open("webkit/youtube.html",
+ Asset::ACCESS_BUFFER);
+ if (!a)
+ return NULL;
+ String s = String((const char*)a->getBuffer(false), a->getLength());
+ s = s.replace("VIDEO_ID", videoId);
+ delete a;
+ loadDataIntoFrame(frame.get(),
+ KURL(ParsedURLString, "file:///android_asset/webkit/"), String(), s);
+ // Transfer ownership to a local refptr.
+ WTF::RefPtr<Widget> widget(frame->view());
+ return widget.release();
+ }
+ }
+ return prpWidget;
+}
+
+void FrameLoaderClientAndroid::redirectDataToPlugin(Widget* pluginWidget) {
+ // Do not redirect data if the Widget is our plugin placeholder.
+ if (pluginWidget->isPluginView()) {
+ m_manualLoader = static_cast<PluginView*>(pluginWidget);
+ }
+}
+
+WTF::PassRefPtr<Widget> FrameLoaderClientAndroid::createJavaAppletWidget(const IntSize&, HTMLAppletElement*,
+ const KURL& baseURL, const WTF::Vector<String>& paramNames,
+ const WTF::Vector<String>& paramValues) {
+ // don't support widget yet
+ notImplemented();
+ return 0;
+}
+
+void FrameLoaderClientAndroid::didTransferChildFrameToNewDocument(WebCore::Page*)
+{
+ ASSERT(m_frame);
+ // m_webFrame points to the WebFrame for the page that our frame previously
+ // belonged to. If the frame now belongs to a new page, we need to update
+ // m_webFrame to point to the WebFrame for the new page.
+ Page* newPage = m_frame->page();
+ if (newPage != m_webFrame->page()) {
+ ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(newPage->chrome()->client());
+ Release(m_webFrame);
+ m_webFrame = chromeClient->webFrame();
+ Retain(m_webFrame);
+ }
+}
+
+void FrameLoaderClientAndroid::transferLoadingResourceFromPage(unsigned long, DocumentLoader*, const ResourceRequest&, Page*)
+{
+ notImplemented();
+}
+
+// This function is used by the <OBJECT> element to determine the type of
+// the contents and work out if it can render it.
+ObjectContentType FrameLoaderClientAndroid::objectContentType(const KURL& url,
+ const String& mimeType) {
+ return FrameLoader::defaultObjectContentType(url, mimeType);
+}
+
+// This function allows the application to set the correct CSS media
+// style. Android could use it to set the media style 'handheld'. Safari
+// may use it to set the media style to 'print' when the user wants to print
+// a particular web page.
+String FrameLoaderClientAndroid::overrideMediaType() const {
+ lowPriority_notImplemented();
+ return String();
+}
+
+// This function is used to re-attach Javascript<->native code classes.
+void FrameLoaderClientAndroid::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld* world)
+{
+ if (world != mainThreadNormalWorld())
+ return;
+
+ ASSERT(m_frame);
+ LOGV("::WebCore:: windowObjectCleared called on frame %p for %s\n",
+ m_frame, m_frame->loader()->url().string().ascii().data());
+ m_webFrame->windowObjectCleared(m_frame);
+}
+
+void FrameLoaderClientAndroid::documentElementAvailable() {
+}
+
+// functions new to Jun-07 tip of tree merge:
+ResourceError FrameLoaderClientAndroid::blockedError(ResourceRequest const& request) {
+ return ResourceError(String(), InternalErrorFileDoesNotExist, String(), String());
+}
+
+// functions new to Nov-07 tip of tree merge:
+void FrameLoaderClientAndroid::didPerformFirstNavigation() const {
+ // This seems to be just a notification that the UI can listen to, to
+ // know if the user has performed first navigation action.
+ // It is called from
+ // void FrameLoader::addBackForwardItemClippedAtTarget(bool doClip)
+ // "Navigation" here means a transition from one page to another that
+ // ends up in the back/forward list.
+}
+
+void FrameLoaderClientAndroid::registerForIconNotification(bool listen) {
+ if (listen)
+ WebIconDatabase::RegisterForIconNotification(this);
+ else
+ WebIconDatabase::UnregisterForIconNotification(this);
+}
+
+// This is the WebIconDatabaseClient method for receiving a notification when we
+// get the icon for the page.
+void FrameLoaderClientAndroid::didAddIconForPageUrl(const String& pageUrl) {
+ // This call must happen before dispatchDidReceiveIcon since that method
+ // may register for icon notifications again since the icon data may have
+ // to be read from disk.
+ registerForIconNotification(false);
+ KURL u(ParsedURLString, pageUrl);
+ if (equalIgnoringFragmentIdentifier(u, m_frame->loader()->url())) {
+ dispatchDidReceiveIcon();
+ }
+}
+
+void FrameLoaderClientAndroid::dispatchDidChangeIcons() {
+ notImplemented();
+}
+
+PassRefPtr<FrameNetworkingContext> FrameLoaderClientAndroid::createNetworkingContext()
+{
+ return FrameNetworkingContextAndroid::create(getFrame());
+}
+
+}
diff --git a/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h b/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h
new file mode 100644
index 0000000..25561a8
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2007, 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 FrameLoaderClientAndroid_h
+#define FrameLoaderClientAndroid_h
+
+#include "CacheBuilder.h"
+#include "FrameLoaderClient.h"
+#include "ResourceResponse.h"
+#include "WebIconDatabase.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+class PluginManualLoader;
+}
+
+using namespace WebCore;
+
+namespace android {
+ class WebFrame;
+
+ class FrameLoaderClientAndroid : public FrameLoaderClient,
+ WebIconDatabaseClient {
+ public:
+ FrameLoaderClientAndroid(WebFrame* webframe);
+
+ Frame* getFrame() { return m_frame; }
+ static FrameLoaderClientAndroid* get(const Frame* frame);
+
+ void setFrame(Frame* frame) { m_frame = frame; }
+ WebFrame* webFrame() const { return m_webFrame; }
+
+ virtual void frameLoaderDestroyed();
+
+ virtual bool hasWebView() const; // mainly for assertions
+
+ virtual void makeRepresentation(DocumentLoader*);
+ virtual void forceLayout();
+ virtual void forceLayoutForNonHTML();
+
+ virtual void setCopiesOnScroll();
+
+ virtual void detachedFromParent2();
+ virtual void detachedFromParent3();
+
+ virtual void assignIdentifierToInitialRequest(unsigned long identifier, DocumentLoader*, const ResourceRequest&);
+
+ virtual void dispatchWillSendRequest(DocumentLoader*, unsigned long identifier, ResourceRequest&, const ResourceResponse& redirectResponse);
+ virtual bool shouldUseCredentialStorage(DocumentLoader*, unsigned long identifier);
+ virtual void dispatchDidReceiveAuthenticationChallenge(DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&);
+ virtual void dispatchDidCancelAuthenticationChallenge(DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&);
+ virtual void dispatchDidReceiveResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse&);
+ virtual void dispatchDidReceiveContentLength(DocumentLoader*, unsigned long identifier, int lengthReceived);
+ virtual void dispatchDidFinishLoading(DocumentLoader*, unsigned long identifier);
+ virtual void dispatchDidFailLoading(DocumentLoader*, unsigned long identifier, const ResourceError&);
+ virtual bool dispatchDidLoadResourceFromMemoryCache(DocumentLoader*, const ResourceRequest&, const ResourceResponse&, int length);
+
+ virtual void dispatchDidHandleOnloadEvents();
+ virtual void dispatchDidReceiveServerRedirectForProvisionalLoad();
+ virtual void dispatchDidCancelClientRedirect();
+ virtual void dispatchWillPerformClientRedirect(const KURL&, double interval, double fireDate);
+ virtual void dispatchDidChangeLocationWithinPage();
+ virtual void dispatchDidPushStateWithinPage();
+ virtual void dispatchDidReplaceStateWithinPage();
+ virtual void dispatchDidPopStateWithinPage();
+ virtual void dispatchWillClose();
+ virtual void dispatchDidReceiveIcon();
+ virtual void dispatchDidStartProvisionalLoad();
+ virtual void dispatchDidReceiveTitle(const String& title);
+ virtual void dispatchDidCommitLoad();
+ virtual void dispatchDidFailProvisionalLoad(const ResourceError&);
+ virtual void dispatchDidFailLoad(const ResourceError&);
+ virtual void dispatchDidFinishDocumentLoad();
+ virtual void dispatchDidFinishLoad();
+ virtual void dispatchDidFirstLayout();
+ virtual void dispatchDidFirstVisuallyNonEmptyLayout();
+
+ virtual Frame* dispatchCreatePage(const NavigationAction&);
+ virtual void dispatchShow();
+
+ virtual void dispatchDecidePolicyForMIMEType(FramePolicyFunction, const String& MIMEType, const ResourceRequest&);
+ virtual void dispatchDecidePolicyForNewWindowAction(FramePolicyFunction, const NavigationAction&, const ResourceRequest&, PassRefPtr<FormState>, const String& frameName);
+ virtual void dispatchDecidePolicyForNavigationAction(FramePolicyFunction, const NavigationAction&, const ResourceRequest&, PassRefPtr<FormState>);
+ virtual void cancelPolicyCheck();
+
+ virtual void dispatchUnableToImplementPolicy(const ResourceError&);
+
+ virtual void dispatchWillSubmitForm(FramePolicyFunction, PassRefPtr<FormState>);
+
+ virtual void dispatchDidLoadMainResource(DocumentLoader*);
+ virtual void revertToProvisionalState(DocumentLoader*);
+ virtual void setMainDocumentError(DocumentLoader*, const ResourceError&);
+
+ virtual void willChangeEstimatedProgress();
+ virtual void didChangeEstimatedProgress();
+ virtual void postProgressStartedNotification();
+ virtual void postProgressEstimateChangedNotification();
+ virtual void postProgressFinishedNotification();
+
+ virtual void setMainFrameDocumentReady(bool);
+
+ virtual void startDownload(const ResourceRequest&);
+
+ virtual void willChangeTitle(DocumentLoader*);
+ virtual void didChangeTitle(DocumentLoader*);
+
+ virtual void committedLoad(DocumentLoader*, const char*, int);
+ virtual void finishedLoading(DocumentLoader*);
+
+ virtual void updateGlobalHistory();
+ virtual void updateGlobalHistoryRedirectLinks();
+
+ virtual bool shouldGoToHistoryItem(HistoryItem*) const;
+
+ virtual void didDisplayInsecureContent();
+ virtual void didRunInsecureContent(SecurityOrigin*);
+
+ virtual void dispatchDidAddBackForwardItem(HistoryItem*) const;
+ virtual void dispatchDidRemoveBackForwardItem(HistoryItem*) const;
+ virtual void dispatchDidChangeBackForwardIndex() const;
+
+ virtual ResourceError cancelledError(const ResourceRequest&);
+ virtual ResourceError blockedError(const ResourceRequest&);
+ virtual ResourceError cannotShowURLError(const ResourceRequest&);
+ virtual ResourceError interruptForPolicyChangeError(const ResourceRequest&);
+
+ virtual ResourceError cannotShowMIMETypeError(const ResourceResponse&);
+ virtual ResourceError fileDoesNotExistError(const ResourceResponse&);
+ virtual ResourceError pluginWillHandleLoadError(const ResourceResponse&);
+
+ virtual bool shouldFallBack(const ResourceError&);
+
+ virtual bool canHandleRequest(const ResourceRequest&) const;
+ virtual bool canShowMIMEType(const String& MIMEType) const;
+ virtual bool canShowMIMETypeAsHTML(const String& MIMEType) const;
+ virtual bool representationExistsForURLScheme(const String& URLScheme) const;
+ virtual String generatedMIMETypeForURLScheme(const String& URLScheme) const;
+
+ virtual void frameLoadCompleted();
+ virtual void saveViewStateToItem(HistoryItem*);
+ virtual void restoreViewState();
+ virtual void provisionalLoadStarted();
+ virtual void didFinishLoad();
+ virtual void prepareForDataSourceReplacement();
+
+ virtual PassRefPtr<DocumentLoader> createDocumentLoader(const ResourceRequest&, const SubstituteData&);
+ virtual void setTitle(const String& title, const KURL&);
+
+ // This provides the userAgent to WebCore. It is used by WebCore to
+ // populate navigator.userAgent and to set the HTTP header in
+ // ResourceRequest objects. We also set a userAgent on WebRequestContext
+ // for the Chromium HTTP stack, which overrides the value on the
+ // ResourceRequest.
+ virtual String userAgent(const KURL&);
+
+ virtual void savePlatformDataToCachedFrame(WebCore::CachedFrame*);
+ virtual void transitionToCommittedFromCachedFrame(WebCore::CachedFrame*);
+ virtual void transitionToCommittedForNewPage();
+
+ virtual void dispatchDidBecomeFrameset(bool isFrameSet);
+
+ virtual bool canCachePage() const;
+ virtual void download(ResourceHandle*, const ResourceRequest&, const ResourceRequest&, const ResourceResponse&);
+
+ virtual WTF::PassRefPtr<Frame> createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement, const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight);
+ virtual void didTransferChildFrameToNewDocument(WebCore::Page*);
+ virtual void transferLoadingResourceFromPage(unsigned long identifier, DocumentLoader*, const ResourceRequest&, Page* oldPage);
+ virtual WTF::PassRefPtr<Widget> createPlugin(const IntSize&, HTMLPlugInElement*, const KURL&, const WTF::Vector<String>&, const WTF::Vector<String>&, const String&, bool loadManually);
+ virtual void redirectDataToPlugin(Widget* pluginWidget);
+
+ virtual WTF::PassRefPtr<Widget> createJavaAppletWidget(const IntSize&, HTMLAppletElement*, const KURL& baseURL, const WTF::Vector<String>& paramNames, const WTF::Vector<String>& paramValues);
+
+ virtual ObjectContentType objectContentType(const KURL& url, const String& mimeType);
+ virtual String overrideMediaType() const;
+
+ virtual void dispatchDidClearWindowObjectInWorld(DOMWrapperWorld*);
+ virtual void documentElementAvailable();
+ virtual void didPerformFirstNavigation() const;
+
+#if USE(V8)
+ // TODO(benm): Implement
+ virtual void didCreateScriptContextForFrame() { }
+ virtual void didDestroyScriptContextForFrame() { }
+ virtual void didCreateIsolatedScriptContext() { }
+
+ virtual bool allowScriptExtension(const String& extensionName, int extensionGroup) { return false; }
+#endif
+
+ virtual void registerForIconNotification(bool listen = true);
+
+ virtual void dispatchDidReceiveTouchIconURL(const String& url, bool precomposed);
+
+ virtual PassRefPtr<FrameNetworkingContext> createNetworkingContext();
+
+ // WebIconDatabaseClient api
+ virtual void didAddIconForPageUrl(const String& pageUrl);
+
+ // FIXME: this doesn't really go here, but it's better than Frame
+ CacheBuilder& getCacheBuilder() { return m_cacheBuilder; }
+
+ void enableOnDemandPlugins() { m_onDemandPluginsEnabled = true; }
+
+ void dispatchDidChangeIcons();
+ void dispatchWillSendSubmitEvent(HTMLFormElement*);
+
+ virtual void didSaveToPageCache() { }
+ virtual void didRestoreFromPageCache() { }
+ private:
+ CacheBuilder m_cacheBuilder;
+ Frame* m_frame;
+ WebFrame* m_webFrame;
+ PluginManualLoader* m_manualLoader;
+ bool m_hasSentResponseToPlugin;
+ bool m_onDemandPluginsEnabled;
+
+ enum ResourceErrors {
+ InternalErrorCancelled = -99,
+ InternalErrorCannotShowUrl,
+ InternalErrorInterrupted,
+ InternalErrorCannotShowMimeType,
+ InternalErrorFileDoesNotExist,
+ InternalErrorPluginWillHandleLoadError,
+ InternalErrorLast
+ };
+
+ /* XXX: These must match android.net.http.EventHandler */
+ enum EventHandlerErrors {
+ Error = -1,
+ ErrorLookup = -2,
+ ErrorUnsupportedAuthScheme = -3,
+ ErrorAuth = -4,
+ ErrorProxyAuth = -5,
+ ErrorConnect = -6,
+ ErrorIO = -7,
+ ErrorTimeout = -8,
+ ErrorRedirectLoop = -9,
+ ErrorUnsupportedScheme = -10,
+ ErrorFailedSslHandshake = -11,
+ ErrorBadUrl = -12,
+ ErrorFile = -13,
+ ErrorFileNotFound = -14,
+ ErrorTooManyRequests = -15
+ };
+ friend class CacheBuilder;
+ };
+
+}
+
+#endif
diff --git a/Source/WebKit/android/WebCoreSupport/FrameNetworkingContextAndroid.cpp b/Source/WebKit/android/WebCoreSupport/FrameNetworkingContextAndroid.cpp
new file mode 100644
index 0000000..a5fe494
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/FrameNetworkingContextAndroid.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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 "FrameNetworkingContextAndroid.h"
+
+#include "DocumentLoader.h"
+#include "MainResourceLoader.h"
+#include "Settings.h"
+
+using namespace WebCore;
+
+namespace android {
+
+FrameNetworkingContextAndroid::FrameNetworkingContextAndroid(WebCore::Frame* frame)
+ : WebCore::FrameNetworkingContext(frame)
+{
+}
+
+MainResourceLoader* FrameNetworkingContextAndroid::mainResourceLoader() const
+{
+ return frame()->loader()->activeDocumentLoader()->mainResourceLoader();
+}
+
+FrameLoaderClient* FrameNetworkingContextAndroid::frameLoaderClient() const
+{
+ return frame()->loader()->client();
+}
+
+} // namespace android
diff --git a/Source/WebKit/android/WebCoreSupport/FrameNetworkingContextAndroid.h b/Source/WebKit/android/WebCoreSupport/FrameNetworkingContextAndroid.h
new file mode 100644
index 0000000..d0ff979
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/FrameNetworkingContextAndroid.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 FrameNetworkingContextAndroid_h
+#define FrameNetworkingContextAndroid_h
+
+#include "FrameNetworkingContext.h"
+
+namespace WebCore {
+class MainResourceLoader;
+class FrameLoaderClient;
+}
+
+namespace android {
+
+class FrameNetworkingContextAndroid : public WebCore::FrameNetworkingContext {
+public:
+ static PassRefPtr<FrameNetworkingContextAndroid> create(WebCore::Frame* frame)
+ {
+ return adoptRef(new FrameNetworkingContextAndroid(frame));
+ }
+
+private:
+ FrameNetworkingContextAndroid(WebCore::Frame*);
+
+ virtual WebCore::MainResourceLoader* mainResourceLoader() const;
+ virtual WebCore::FrameLoaderClient* frameLoaderClient() const;
+};
+
+} // namespace android
+
+#endif // FrameNetworkingContextAndroid_h
diff --git a/Source/WebKit/android/WebCoreSupport/GeolocationPermissions.cpp b/Source/WebKit/android/WebCoreSupport/GeolocationPermissions.cpp
new file mode 100755
index 0000000..36a9b61
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/GeolocationPermissions.cpp
@@ -0,0 +1,419 @@
+/*
+ * Copyright 2009, 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 "GeolocationPermissions.h"
+
+#include "DOMWindow.h"
+#include "Frame.h"
+#include "Geolocation.h"
+#include "Navigator.h"
+#include "SQLiteDatabase.h"
+#include "SQLiteFileSystem.h"
+#include "SQLiteStatement.h"
+#include "SQLiteTransaction.h"
+#include "WebViewCore.h"
+
+#include <text/CString.h>
+
+using namespace WebCore;
+
+namespace android {
+
+GeolocationPermissions::PermissionsMap GeolocationPermissions::s_permanentPermissions;
+GeolocationPermissions::GeolocationPermissionsVector GeolocationPermissions::s_instances;
+bool GeolocationPermissions::s_alwaysDeny = false;
+bool GeolocationPermissions::s_permanentPermissionsLoaded = false;
+bool GeolocationPermissions::s_permanentPermissionsModified = false;
+String GeolocationPermissions::s_databasePath;
+
+static const char* databaseName = "GeolocationPermissions.db";
+
+GeolocationPermissions::GeolocationPermissions(WebViewCore* webViewCore, Frame* mainFrame)
+ : m_webViewCore(webViewCore)
+ , m_mainFrame(mainFrame)
+ , m_timer(this, &GeolocationPermissions::timerFired)
+
+{
+ ASSERT(m_webViewCore);
+ maybeLoadPermanentPermissions();
+ s_instances.append(this);
+}
+
+GeolocationPermissions::~GeolocationPermissions()
+{
+ size_t index = s_instances.find(this);
+ s_instances.remove(index);
+}
+
+void GeolocationPermissions::queryPermissionState(Frame* frame)
+{
+ ASSERT(s_permanentPermissionsLoaded);
+
+ // We use SecurityOrigin::toString to key the map. Note that testing
+ // the SecurityOrigin pointer for equality is insufficient.
+ String originString = frame->document()->securityOrigin()->toString();
+
+ // If we've been told to always deny requests, do so.
+ if (s_alwaysDeny) {
+ makeAsynchronousCallbackToGeolocation(originString, false);
+ return;
+ }
+
+ // See if we have a record for this origin in the permanent permissions.
+ // These take precedence over temporary permissions so that changes made
+ // from the browser settings work as intended.
+ PermissionsMap::const_iterator iter = s_permanentPermissions.find(originString);
+ PermissionsMap::const_iterator end = s_permanentPermissions.end();
+ if (iter != end) {
+ bool allow = iter->second;
+ makeAsynchronousCallbackToGeolocation(originString, allow);
+ return;
+ }
+
+ // Check the temporary permisions.
+ iter = m_temporaryPermissions.find(originString);
+ end = m_temporaryPermissions.end();
+ if (iter != end) {
+ bool allow = iter->second;
+ makeAsynchronousCallbackToGeolocation(originString, allow);
+ return;
+ }
+
+ // If there's no pending request, prompt the user.
+ if (nextOriginInQueue().isEmpty()) {
+ // Although multiple tabs may request permissions for the same origin
+ // simultaneously, the routing in WebViewCore/CallbackProxy ensures that
+ // the result of the request will make it back to this object, so
+ // there's no need for a globally unique ID for the request.
+ m_webViewCore->geolocationPermissionsShowPrompt(originString);
+ }
+
+ // Add this request to the queue so we can track which frames requested it.
+ if (m_queuedOrigins.find(originString) == WTF::notFound) {
+ m_queuedOrigins.append(originString);
+ FrameSet frameSet;
+ frameSet.add(frame);
+ m_queuedOriginsToFramesMap.add(originString, frameSet);
+ } else {
+ ASSERT(m_queuedOriginsToFramesMap.contains(originString));
+ m_queuedOriginsToFramesMap.find(originString)->second.add(frame);
+ }
+}
+
+void GeolocationPermissions::cancelPermissionStateQuery(WebCore::Frame* frame)
+{
+ // We cancel any queued request for the given frame. There can be at most
+ // one of these, since each frame maps to a single origin. We only cancel
+ // the request if this frame is the only one reqesting permission for this
+ // origin.
+ //
+ // We can use the origin string to avoid searching the map.
+ String originString = frame->document()->securityOrigin()->toString();
+ size_t index = m_queuedOrigins.find(originString);
+ if (index == WTF::notFound)
+ return;
+
+ ASSERT(m_queuedOriginsToFramesMap.contains(originString));
+ OriginToFramesMap::iterator iter = m_queuedOriginsToFramesMap.find(originString);
+ ASSERT(iter->second.contains(frame));
+ iter->second.remove(frame);
+ if (!iter->second.isEmpty())
+ return;
+
+ m_queuedOrigins.remove(index);
+ m_queuedOriginsToFramesMap.remove(iter);
+
+ // If this is the origin currently being shown, cancel the prompt
+ // and show the next in the queue, if present.
+ if (index == 0) {
+ m_webViewCore->geolocationPermissionsHidePrompt();
+ if (!nextOriginInQueue().isEmpty())
+ m_webViewCore->geolocationPermissionsShowPrompt(nextOriginInQueue());
+ }
+}
+
+void GeolocationPermissions::makeAsynchronousCallbackToGeolocation(String origin, bool allow)
+{
+ m_callbackData.origin = origin;
+ m_callbackData.allow = allow;
+ m_timer.startOneShot(0);
+}
+
+void GeolocationPermissions::providePermissionState(String origin, bool allow, bool remember)
+{
+ ASSERT(s_permanentPermissionsLoaded);
+
+ // It's possible that this method is called with an origin that doesn't
+ // match m_originInProgress. This can occur if this object is reset
+ // while a permission result is in the process of being marshalled back to
+ // the WebCore thread from the browser. In this case, we simply ignore the
+ // call.
+ if (origin != nextOriginInQueue())
+ return;
+
+ maybeCallbackFrames(origin, allow);
+ recordPermissionState(origin, allow, remember);
+
+ // If the permissions are set to be remembered, cancel any queued requests
+ // for this domain in other tabs.
+ if (remember)
+ cancelPendingRequestsInOtherTabs(origin);
+
+ // Clear the origin from the queue.
+ ASSERT(!m_queuedOrigins.isEmpty());
+ m_queuedOrigins.remove(0);
+ ASSERT(m_queuedOriginsToFramesMap.contains(origin));
+ m_queuedOriginsToFramesMap.remove(origin);
+
+ // If there are other requests queued, start the next one.
+ if (!nextOriginInQueue().isEmpty())
+ m_webViewCore->geolocationPermissionsShowPrompt(nextOriginInQueue());
+}
+
+void GeolocationPermissions::recordPermissionState(String origin, bool allow, bool remember)
+{
+ if (remember) {
+ s_permanentPermissions.set(origin, allow);
+ s_permanentPermissionsModified = true;
+ } else {
+ // It's possible that another tab recorded a permanent permission for
+ // this origin while our request was in progress, but we record it
+ // anyway.
+ m_temporaryPermissions.set(origin, allow);
+ }
+}
+
+void GeolocationPermissions::cancelPendingRequestsInOtherTabs(String origin)
+{
+ for (GeolocationPermissionsVector::const_iterator iter = s_instances.begin();
+ iter != s_instances.end();
+ ++iter)
+ (*iter)->cancelPendingRequests(origin);
+}
+
+void GeolocationPermissions::cancelPendingRequests(String origin)
+{
+ size_t index = m_queuedOrigins.find(origin);
+
+ // Don't cancel the request if it's currently being shown, in which case
+ // it's at index 0.
+ if (index == WTF::notFound || !index)
+ return;
+
+ // Get the permission from the permanent list.
+ ASSERT(s_permanentPermissions.contains(origin));
+ PermissionsMap::const_iterator iter = s_permanentPermissions.find(origin);
+ bool allow = iter->second;
+
+ maybeCallbackFrames(origin, allow);
+
+ m_queuedOrigins.remove(index);
+ ASSERT(m_queuedOriginsToFramesMap.contains(origin));
+ m_queuedOriginsToFramesMap.remove(origin);
+}
+
+void GeolocationPermissions::timerFired(Timer<GeolocationPermissions>* timer)
+{
+ ASSERT_UNUSED(timer, timer == &m_timer);
+ maybeCallbackFrames(m_callbackData.origin, m_callbackData.allow);
+}
+
+void GeolocationPermissions::resetTemporaryPermissionStates()
+{
+ ASSERT(s_permanentPermissionsLoaded);
+ m_queuedOrigins.clear();
+ m_queuedOriginsToFramesMap.clear();
+ m_temporaryPermissions.clear();
+ // If any permission results are being marshalled back to this thread, this
+ // will render them inefective.
+ m_timer.stop();
+
+ m_webViewCore->geolocationPermissionsHidePrompt();
+}
+
+const WTF::String& GeolocationPermissions::nextOriginInQueue()
+{
+ static const String emptyString = "";
+ return m_queuedOrigins.isEmpty() ? emptyString : m_queuedOrigins[0];
+}
+
+void GeolocationPermissions::maybeCallbackFrames(String origin, bool allow)
+{
+ // We can't track which frame issued the request, as frames can be deleted
+ // or have their contents replaced. Even uniqueChildName is not unique when
+ // frames are dynamically deleted and created. Instead, we simply call back
+ // to the Geolocation object in all frames from the correct origin.
+ for (Frame* frame = m_mainFrame; frame; frame = frame->tree()->traverseNext()) {
+ if (origin == frame->document()->securityOrigin()->toString()) {
+ // If the page has changed, it may no longer have a Geolocation
+ // object.
+ Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
+ if (geolocation)
+ geolocation->setIsAllowed(allow);
+ }
+ }
+}
+
+GeolocationPermissions::OriginSet GeolocationPermissions::getOrigins()
+{
+ maybeLoadPermanentPermissions();
+ OriginSet origins;
+ PermissionsMap::const_iterator end = s_permanentPermissions.end();
+ for (PermissionsMap::const_iterator iter = s_permanentPermissions.begin(); iter != end; ++iter)
+ origins.add(iter->first);
+ return origins;
+}
+
+bool GeolocationPermissions::getAllowed(String origin)
+{
+ maybeLoadPermanentPermissions();
+ bool allowed = false;
+ PermissionsMap::const_iterator iter = s_permanentPermissions.find(origin);
+ PermissionsMap::const_iterator end = s_permanentPermissions.end();
+ if (iter != end)
+ allowed = iter->second;
+ return allowed;
+}
+
+void GeolocationPermissions::clear(String origin)
+{
+ maybeLoadPermanentPermissions();
+ PermissionsMap::iterator iter = s_permanentPermissions.find(origin);
+ if (iter != s_permanentPermissions.end()) {
+ s_permanentPermissions.remove(iter);
+ s_permanentPermissionsModified = true;
+ }
+}
+
+void GeolocationPermissions::allow(String origin)
+{
+ maybeLoadPermanentPermissions();
+ // We replace any existing permanent permission.
+ s_permanentPermissions.set(origin, true);
+ s_permanentPermissionsModified = true;
+}
+
+void GeolocationPermissions::clearAll()
+{
+ maybeLoadPermanentPermissions();
+ s_permanentPermissions.clear();
+ s_permanentPermissionsModified = true;
+}
+
+void GeolocationPermissions::maybeLoadPermanentPermissions()
+{
+ if (s_permanentPermissionsLoaded)
+ return;
+ s_permanentPermissionsLoaded = true;
+
+ SQLiteDatabase database;
+ if (!openDatabase(&database))
+ return;
+
+ // Create the table here, such that even if we've just created the DB, the
+ // commands below should succeed.
+ if (!database.executeCommand("CREATE TABLE IF NOT EXISTS Permissions (origin TEXT UNIQUE NOT NULL, allow INTEGER NOT NULL)")) {
+ database.close();
+ return;
+ }
+
+ SQLiteStatement statement(database, "SELECT * FROM Permissions");
+ if (statement.prepare() != SQLResultOk) {
+ database.close();
+ return;
+ }
+
+ ASSERT(s_permanentPermissions.size() == 0);
+ while (statement.step() == SQLResultRow)
+ s_permanentPermissions.set(statement.getColumnText(0), statement.getColumnInt64(1));
+
+ database.close();
+}
+
+void GeolocationPermissions::maybeStorePermanentPermissions()
+{
+ // If the permanent permissions haven't been modified, there's no need to
+ // save them to the DB. (If we haven't even loaded them, writing them now
+ // would overwrite the stored permissions with the empty set.)
+ if (!s_permanentPermissionsModified)
+ return;
+
+ SQLiteDatabase database;
+ if (!openDatabase(&database))
+ return;
+
+ SQLiteTransaction transaction(database);
+
+ // The number of entries should be small enough that it's not worth trying
+ // to perform a diff. Simply clear the table and repopulate it.
+ if (!database.executeCommand("DELETE FROM Permissions")) {
+ database.close();
+ return;
+ }
+
+ PermissionsMap::const_iterator end = s_permanentPermissions.end();
+ for (PermissionsMap::const_iterator iter = s_permanentPermissions.begin(); iter != end; ++iter) {
+ SQLiteStatement statement(database, "INSERT INTO Permissions (origin, allow) VALUES (?, ?)");
+ if (statement.prepare() != SQLResultOk)
+ continue;
+ statement.bindText(1, iter->first);
+ statement.bindInt64(2, iter->second);
+ statement.executeCommand();
+ }
+
+ transaction.commit();
+ database.close();
+
+ s_permanentPermissionsModified = false;
+}
+
+void GeolocationPermissions::setDatabasePath(String path)
+{
+ // Take the first non-empty value.
+ if (s_databasePath.length() > 0)
+ return;
+ s_databasePath = path;
+}
+
+bool GeolocationPermissions::openDatabase(SQLiteDatabase* database)
+{
+ ASSERT(database);
+ String filename = SQLiteFileSystem::appendDatabaseFileNameToPath(s_databasePath, databaseName);
+ if (!database->open(filename))
+ return false;
+ if (chmod(filename.utf8().data(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) {
+ database->close();
+ return false;
+ }
+ return true;
+}
+
+void GeolocationPermissions::setAlwaysDeny(bool deny)
+{
+ s_alwaysDeny = deny;
+}
+
+} // namespace android
diff --git a/Source/WebKit/android/WebCoreSupport/GeolocationPermissions.h b/Source/WebKit/android/WebCoreSupport/GeolocationPermissions.h
new file mode 100644
index 0000000..fb31dfe
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/GeolocationPermissions.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2009, 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 GeolocationPermissions_h
+#define GeolocationPermissions_h
+
+#include "PlatformString.h"
+#include "Timer.h"
+
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+ class Frame;
+ class Geolocation;
+ class SQLiteDatabase;
+}
+
+namespace android {
+
+ class WebViewCore;
+
+ // The GeolocationPermissions class manages Geolocation permissions for the
+ // browser. Permissions are managed on a per-origin basis, as required by
+ // the Geolocation spec - http://dev.w3.org/geo/api/spec-source.html. An
+ // origin specifies the scheme, host and port of particular frame. An
+ // origin is represented here as a string, using the output of
+ // WebCore::SecurityOrigin::toString.
+ //
+ // Each instance handles permissions for a given main frame. The class
+ // enforces the following policy.
+ // - Non-remembered permissions last for the dureation of the main frame.
+ // - Remembered permissions last indefinitely.
+ // - All permissions are shared between child frames of a main frame.
+ // - Only remembered permissions are shared between main frames.
+ // - Remembered permissions are made available for use in the browser
+ // settings menu.
+ class GeolocationPermissions : public RefCounted<GeolocationPermissions> {
+ public:
+ // Creates the GeolocationPermissions object to manage permissions for
+ // the specified main frame (i.e. tab). The WebViewCore is used to
+ // communicate with the browser to display UI.
+ GeolocationPermissions(WebViewCore* webViewCore, WebCore::Frame* mainFrame);
+ virtual ~GeolocationPermissions();
+
+ // Queries the permission state for the specified frame. If the
+ // permission state has not yet been set, prompts the user. Once the
+ // permission state has been determined, asynchronously calls back to
+ // the Geolocation objects in all frames in this WebView that are from
+ // the same origin as the requesting frame.
+ void queryPermissionState(WebCore::Frame* frame);
+ void cancelPermissionStateQuery(WebCore::Frame*);
+
+ // Provides this object with a permission state set by the user. The
+ // permission is specified by 'allow' and applied to 'origin'. If
+ // 'remember' is set, the permission state is remembered permanently.
+ // The new permission state is recorded and will trigger callbacks to
+ // geolocation objects as described above. If any other permission
+ // requests are queued, the next is started.
+ void providePermissionState(WTF::String origin, bool allow, bool remember);
+
+ // Clears the temporary permission state and any pending requests. Used
+ // when the main frame is refreshed or navigated to a new URL.
+ void resetTemporaryPermissionStates();
+
+ // Static methods for use from Java. These are used to interact with the
+ // browser settings menu and to update the permanent permissions when
+ // system settings are changed.
+ // Gets the list of all origins for which permanent permissions are
+ // recorded.
+ typedef HashSet<WTF::String> OriginSet;
+ static OriginSet getOrigins();
+ // Gets whether the specified origin is allowed.
+ static bool getAllowed(WTF::String origin);
+ // Clears the permission state for the specified origin.
+ static void clear(WTF::String origin);
+ // Sets the permission state for the specified origin to allowed.
+ static void allow(WTF::String origin);
+ // Clears the permission state for all origins.
+ static void clearAll();
+ // Sets whether the GeolocationPermissions object should always deny
+ // permission requests, irrespective of previously recorded permission
+ // states.
+ static void setAlwaysDeny(bool deny);
+
+ static void setDatabasePath(WTF::String path);
+ static bool openDatabase(WebCore::SQLiteDatabase*);
+
+ // Saves the permanent permissions to the DB if required.
+ static void maybeStorePermanentPermissions();
+
+ private:
+ // Records the permission state for the specified origin and whether
+ // this should be remembered.
+ void recordPermissionState(WTF::String origin, bool allow, bool remember);
+
+ // Used to make an asynchronous callback to the Geolocation objects.
+ void makeAsynchronousCallbackToGeolocation(WTF::String origin, bool allow);
+ void timerFired(WebCore::Timer<GeolocationPermissions>* timer);
+
+ // Calls back to the Geolocation objects in all frames from the
+ // specified origin. There may be no such objects, as the frames using
+ // Geolocation from the specified origin may no longer use Geolocation,
+ // or may have been navigated to a different origin..
+ void maybeCallbackFrames(WTF::String origin, bool allow);
+
+ // Cancels pending permission requests for the specified origin in
+ // other main frames (ie browser tabs). This is used when the user
+ // specifies permission to be remembered.
+ static void cancelPendingRequestsInOtherTabs(WTF::String origin);
+ void cancelPendingRequests(WTF::String origin);
+
+ static void maybeLoadPermanentPermissions();
+
+ const WTF::String& nextOriginInQueue();
+
+ WebViewCore* m_webViewCore;
+ WebCore::Frame* m_mainFrame;
+ // A vector of the origins queued to make a permission request.
+ // The first in the vector is the origin currently making the request.
+ typedef Vector<WTF::String> OriginVector;
+ OriginVector m_queuedOrigins;
+ // A map from a queued origin to the set of frames that have requested
+ // permission for that origin.
+ typedef HashSet<WebCore::Frame*> FrameSet;
+ typedef HashMap<WTF::String, FrameSet> OriginToFramesMap;
+ OriginToFramesMap m_queuedOriginsToFramesMap;
+
+ typedef WTF::HashMap<WTF::String, bool> PermissionsMap;
+ PermissionsMap m_temporaryPermissions;
+ static PermissionsMap s_permanentPermissions;
+
+ typedef WTF::Vector<GeolocationPermissions*> GeolocationPermissionsVector;
+ static GeolocationPermissionsVector s_instances;
+
+ WebCore::Timer<GeolocationPermissions> m_timer;
+
+ struct CallbackData {
+ WTF::String origin;
+ bool allow;
+ };
+ CallbackData m_callbackData;
+
+ static bool s_alwaysDeny;
+
+ static bool s_permanentPermissionsLoaded;
+ static bool s_permanentPermissionsModified;
+ static WTF::String s_databasePath;
+ };
+
+} // namespace android
+
+#endif
diff --git a/Source/WebKit/android/WebCoreSupport/InspectorClientAndroid.h b/Source/WebKit/android/WebCoreSupport/InspectorClientAndroid.h
new file mode 100644
index 0000000..9d734e8
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/InspectorClientAndroid.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2007, 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 InspectorClientAndroid_h
+#define InspectorClientAndroid_h
+
+#include "InspectorClient.h"
+
+#include <wtf/Forward.h>
+
+namespace android {
+
+class InspectorClientAndroid : public InspectorClient {
+public:
+ virtual ~InspectorClientAndroid() { }
+
+ virtual void inspectorDestroyed() { delete this; }
+
+ virtual void openInspectorFrontend(WebCore::InspectorController*) {}
+
+ virtual void highlight(Node*) {}
+ virtual void hideHighlight() {}
+
+ virtual void populateSetting(const String& key, String* value) {}
+ virtual void storeSetting(const String& key, const String& value) {}
+
+ virtual bool sendMessageToFrontend(const WTF::String&) { return false; }
+};
+
+}
+
+#endif
diff --git a/Source/WebKit/android/WebCoreSupport/KeyGeneratorClient.h b/Source/WebKit/android/WebCoreSupport/KeyGeneratorClient.h
new file mode 100644
index 0000000..1bcd8e8
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/KeyGeneratorClient.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2009, 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 KEY_GENERATOR_CLIENT_H
+#define KEY_GENERATOR_CLIENT_H
+
+#include "KURL.h"
+#include "PlatformString.h"
+
+#include <wtf/Vector.h>
+
+using namespace WebCore;
+
+namespace android {
+
+class KeyGeneratorClient {
+public:
+ virtual ~KeyGeneratorClient() { }
+ virtual WTF::Vector<String> getSupportedKeyStrengthList() = 0;
+ virtual String getSignedPublicKeyAndChallengeString(unsigned index,
+ const String& challenge, const KURL& url) = 0;
+ };
+}
+#endif
diff --git a/Source/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp b/Source/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp
new file mode 100644
index 0000000..e6a2710
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp
@@ -0,0 +1,654 @@
+/*
+ * Copyright 2009, 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 "MediaPlayerPrivateAndroid.h"
+
+#if ENABLE(VIDEO)
+
+#include "BaseLayerAndroid.h"
+#include "DocumentLoader.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "SkiaUtils.h"
+#include "VideoLayerAndroid.h"
+#include "WebCoreJni.h"
+#include "WebViewCore.h"
+#include <GraphicsJNI.h>
+#include <JNIHelp.h>
+#include <JNIUtility.h>
+#include <SkBitmap.h>
+#include <gui/SurfaceTexture.h>
+
+using namespace android;
+// Forward decl
+namespace android {
+sp<SurfaceTexture> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz);
+};
+
+namespace WebCore {
+
+static const char* g_ProxyJavaClass = "android/webkit/HTML5VideoViewProxy";
+static const char* g_ProxyJavaClassAudio = "android/webkit/HTML5Audio";
+
+struct MediaPlayerPrivate::JavaGlue {
+ jobject m_javaProxy;
+ jmethodID m_play;
+ jmethodID m_teardown;
+ jmethodID m_seek;
+ jmethodID m_pause;
+ // Audio
+ jmethodID m_newInstance;
+ jmethodID m_setDataSource;
+ jmethodID m_getMaxTimeSeekable;
+ // Video
+ jmethodID m_getInstance;
+ jmethodID m_loadPoster;
+};
+
+MediaPlayerPrivate::~MediaPlayerPrivate()
+{
+ // m_videoLayer is reference counted, unref is enough here.
+ m_videoLayer->unref();
+ if (m_glue->m_javaProxy) {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (env) {
+ env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_teardown);
+ env->DeleteGlobalRef(m_glue->m_javaProxy);
+ }
+ }
+ delete m_glue;
+}
+
+void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
+{
+ registrar(create, getSupportedTypes, supportsType);
+}
+
+MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs)
+{
+ if (WebViewCore::isSupportedMediaMimeType(type))
+ return MediaPlayer::MayBeSupported;
+ return MediaPlayer::IsNotSupported;
+}
+
+void MediaPlayerPrivate::pause()
+{
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env || !m_glue->m_javaProxy || !m_url.length())
+ return;
+
+ m_paused = true;
+ m_player->playbackStateChanged();
+ env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_pause);
+ checkException(env);
+}
+
+void MediaPlayerPrivate::setVisible(bool visible)
+{
+ m_isVisible = visible;
+ if (m_isVisible)
+ createJavaPlayerIfNeeded();
+}
+
+void MediaPlayerPrivate::seek(float time)
+{
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env || !m_url.length())
+ return;
+
+ if (m_glue->m_javaProxy) {
+ env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_seek, static_cast<jint>(time * 1000.0f));
+ m_currentTime = time;
+ }
+ checkException(env);
+}
+
+void MediaPlayerPrivate::prepareToPlay()
+{
+ // We are about to start playing. Since our Java VideoView cannot
+ // buffer any data, we just simply transition to the HaveEnoughData
+ // state in here. This will allow the MediaPlayer to transition to
+ // the "play" state, at which point our VideoView will start downloading
+ // the content and start the playback.
+ m_networkState = MediaPlayer::Loaded;
+ m_player->networkStateChanged();
+ m_readyState = MediaPlayer::HaveEnoughData;
+ m_player->readyStateChanged();
+}
+
+MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
+ : m_player(player),
+ m_glue(0),
+ m_duration(1), // keep this minimal to avoid initial seek problem
+ m_currentTime(0),
+ m_paused(true),
+ m_readyState(MediaPlayer::HaveNothing),
+ m_networkState(MediaPlayer::Empty),
+ m_poster(0),
+ m_naturalSize(100, 100),
+ m_naturalSizeUnknown(true),
+ m_isVisible(false),
+ m_videoLayer(new VideoLayerAndroid())
+{
+}
+
+void MediaPlayerPrivate::onEnded()
+{
+ m_currentTime = duration();
+ m_player->timeChanged();
+ m_paused = true;
+ m_player->playbackStateChanged();
+ m_networkState = MediaPlayer::Idle;
+}
+
+void MediaPlayerPrivate::onPaused()
+{
+ m_paused = true;
+ m_player->playbackStateChanged();
+ m_networkState = MediaPlayer::Idle;
+ m_player->playbackStateChanged();
+}
+
+void MediaPlayerPrivate::onTimeupdate(int position)
+{
+ m_currentTime = position / 1000.0f;
+ m_player->timeChanged();
+}
+
+void MediaPlayerPrivate::onStopFullscreen()
+{
+ if (m_player && m_player->mediaPlayerClient()
+ && m_player->mediaPlayerClient()->mediaPlayerOwningDocument()) {
+ m_player->mediaPlayerClient()->mediaPlayerOwningDocument()->webkitCancelFullScreen();
+ }
+}
+
+class MediaPlayerVideoPrivate : public MediaPlayerPrivate {
+public:
+ void load(const String& url)
+ {
+ m_url = url;
+ // Cheat a bit here to make sure Window.onLoad event can be triggered
+ // at the right time instead of real video play time, since only full
+ // screen video play is supported in Java's VideoView.
+ // See also comments in prepareToPlay function.
+ m_networkState = MediaPlayer::Loading;
+ m_player->networkStateChanged();
+ m_readyState = MediaPlayer::HaveCurrentData;
+ m_player->readyStateChanged();
+ }
+
+ void play()
+ {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env || !m_url.length() || !m_glue->m_javaProxy)
+ return;
+
+ // We only play video fullscreen on Android, so stop sites playing fullscreen video in the onload handler.
+ Frame* frame = m_player->frameView()->frame();
+ if (frame && !frame->loader()->documentLoader()->wasOnloadHandled())
+ return;
+
+ m_paused = false;
+ m_player->playbackStateChanged();
+
+ if (m_currentTime == duration())
+ m_currentTime = 0;
+
+ jstring jUrl = wtfStringToJstring(env, m_url);
+ env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_play, jUrl,
+ static_cast<jint>(m_currentTime * 1000.0f),
+ m_videoLayer->uniqueId());
+ env->DeleteLocalRef(jUrl);
+
+ checkException(env);
+ }
+ bool canLoadPoster() const { return true; }
+ void setPoster(const String& url)
+ {
+ if (m_posterUrl == url)
+ return;
+
+ m_posterUrl = url;
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env || !m_glue->m_javaProxy || !m_posterUrl.length())
+ return;
+ // Send the poster
+ jstring jUrl = wtfStringToJstring(env, m_posterUrl);
+ env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_loadPoster, jUrl);
+ env->DeleteLocalRef(jUrl);
+ }
+ void paint(GraphicsContext* ctxt, const IntRect& r)
+ {
+ if (ctxt->paintingDisabled())
+ return;
+
+ if (!m_isVisible)
+ return;
+
+ if (!m_poster || (!m_poster->getPixels() && !m_poster->pixelRef()))
+ return;
+
+ SkCanvas* canvas = ctxt->platformContext()->mCanvas;
+ // We paint with the following rules in mind:
+ // - only downscale the poster, never upscale
+ // - maintain the natural aspect ratio of the poster
+ // - the poster should be centered in the target rect
+ float originalRatio = static_cast<float>(m_poster->width()) / static_cast<float>(m_poster->height());
+ int posterWidth = r.width() > m_poster->width() ? m_poster->width() : r.width();
+ int posterHeight = posterWidth / originalRatio;
+ int posterX = ((r.width() - posterWidth) / 2) + r.x();
+ int posterY = ((r.height() - posterHeight) / 2) + r.y();
+ IntRect targetRect(posterX, posterY, posterWidth, posterHeight);
+ canvas->drawBitmapRect(*m_poster, 0, targetRect, 0);
+ }
+
+ void onPosterFetched(SkBitmap* poster)
+ {
+ m_poster = poster;
+ if (m_naturalSizeUnknown) {
+ // We had to fake the size at startup, or else our paint
+ // method would not be called. If we haven't yet received
+ // the onPrepared event, update the intrinsic size to the size
+ // of the poster. That will be overriden when onPrepare comes.
+ // In case of an error, we should report the poster size, rather
+ // than our initial fake value.
+ m_naturalSize = IntSize(poster->width(), poster->height());
+ m_player->sizeChanged();
+ }
+ }
+
+ void onPrepared(int duration, int width, int height)
+ {
+ m_duration = duration / 1000.0f;
+ m_naturalSize = IntSize(width, height);
+ m_naturalSizeUnknown = false;
+ m_player->durationChanged();
+ m_player->sizeChanged();
+ }
+
+ virtual bool hasAudio() const { return false; } // do not display the audio UI
+ virtual bool hasVideo() const { return true; }
+ virtual bool supportsFullscreen() const { return true; }
+
+ MediaPlayerVideoPrivate(MediaPlayer* player) : MediaPlayerPrivate(player)
+ {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env)
+ return;
+
+ jclass clazz = env->FindClass(g_ProxyJavaClass);
+
+ if (!clazz)
+ return;
+
+ m_glue = new JavaGlue;
+ m_glue->m_getInstance = env->GetStaticMethodID(clazz, "getInstance", "(Landroid/webkit/WebViewCore;I)Landroid/webkit/HTML5VideoViewProxy;");
+ m_glue->m_loadPoster = env->GetMethodID(clazz, "loadPoster", "(Ljava/lang/String;)V");
+ m_glue->m_play = env->GetMethodID(clazz, "play", "(Ljava/lang/String;II)V");
+
+ m_glue->m_teardown = env->GetMethodID(clazz, "teardown", "()V");
+ m_glue->m_seek = env->GetMethodID(clazz, "seek", "(I)V");
+ m_glue->m_pause = env->GetMethodID(clazz, "pause", "()V");
+ m_glue->m_javaProxy = 0;
+ env->DeleteLocalRef(clazz);
+ // An exception is raised if any of the above fails.
+ checkException(env);
+ }
+
+ void createJavaPlayerIfNeeded()
+ {
+ // Check if we have been already created.
+ if (m_glue->m_javaProxy)
+ return;
+
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env)
+ return;
+
+ jclass clazz = env->FindClass(g_ProxyJavaClass);
+
+ if (!clazz)
+ return;
+
+ jobject obj = 0;
+
+ FrameView* frameView = m_player->frameView();
+ if (!frameView)
+ return;
+ WebViewCore* webViewCore = WebViewCore::getWebViewCore(frameView);
+ ASSERT(webViewCore);
+
+ // Get the HTML5VideoViewProxy instance
+ obj = env->CallStaticObjectMethod(clazz, m_glue->m_getInstance, webViewCore->getJavaObject().get(), this);
+ m_glue->m_javaProxy = env->NewGlobalRef(obj);
+ // Send the poster
+ jstring jUrl = 0;
+ if (m_posterUrl.length())
+ jUrl = wtfStringToJstring(env, m_posterUrl);
+ // Sending a NULL jUrl allows the Java side to try to load the default poster.
+ env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_loadPoster, jUrl);
+ if (jUrl)
+ env->DeleteLocalRef(jUrl);
+
+ // Clean up.
+ if (obj)
+ env->DeleteLocalRef(obj);
+ env->DeleteLocalRef(clazz);
+ checkException(env);
+ }
+
+ float maxTimeSeekable() const
+ {
+ return m_duration;
+ }
+};
+
+class MediaPlayerAudioPrivate : public MediaPlayerPrivate {
+public:
+ void load(const String& url)
+ {
+ m_url = url;
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env || !m_url.length())
+ return;
+
+ createJavaPlayerIfNeeded();
+
+ if (!m_glue->m_javaProxy)
+ return;
+
+ jstring jUrl = wtfStringToJstring(env, m_url);
+ // start loading the data asynchronously
+ env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_setDataSource, jUrl);
+ env->DeleteLocalRef(jUrl);
+ checkException(env);
+ }
+
+ void play()
+ {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env || !m_url.length())
+ return;
+
+ createJavaPlayerIfNeeded();
+
+ if (!m_glue->m_javaProxy)
+ return;
+
+ m_paused = false;
+ m_player->playbackStateChanged();
+ env->CallVoidMethod(m_glue->m_javaProxy, m_glue->m_play);
+ checkException(env);
+ }
+
+ virtual bool hasAudio() const { return true; }
+ virtual bool hasVideo() const { return false; }
+ virtual bool supportsFullscreen() const { return false; }
+
+ float maxTimeSeekable() const
+ {
+ if (m_glue->m_javaProxy) {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (env) {
+ float maxTime = env->CallFloatMethod(m_glue->m_javaProxy,
+ m_glue->m_getMaxTimeSeekable);
+ checkException(env);
+ return maxTime;
+ }
+ }
+ return 0;
+ }
+
+ MediaPlayerAudioPrivate(MediaPlayer* player) : MediaPlayerPrivate(player)
+ {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env)
+ return;
+
+ jclass clazz = env->FindClass(g_ProxyJavaClassAudio);
+
+ if (!clazz)
+ return;
+
+ m_glue = new JavaGlue;
+ m_glue->m_newInstance = env->GetMethodID(clazz, "<init>", "(I)V");
+ m_glue->m_setDataSource = env->GetMethodID(clazz, "setDataSource", "(Ljava/lang/String;)V");
+ m_glue->m_play = env->GetMethodID(clazz, "play", "()V");
+ m_glue->m_getMaxTimeSeekable = env->GetMethodID(clazz, "getMaxTimeSeekable", "()F");
+ m_glue->m_teardown = env->GetMethodID(clazz, "teardown", "()V");
+ m_glue->m_seek = env->GetMethodID(clazz, "seek", "(I)V");
+ m_glue->m_pause = env->GetMethodID(clazz, "pause", "()V");
+ m_glue->m_javaProxy = 0;
+ env->DeleteLocalRef(clazz);
+ // An exception is raised if any of the above fails.
+ checkException(env);
+ }
+
+ void createJavaPlayerIfNeeded()
+ {
+ // Check if we have been already created.
+ if (m_glue->m_javaProxy)
+ return;
+
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ if (!env)
+ return;
+
+ jclass clazz = env->FindClass(g_ProxyJavaClassAudio);
+
+ if (!clazz)
+ return;
+
+ jobject obj = 0;
+
+ // Get the HTML5Audio instance
+ obj = env->NewObject(clazz, m_glue->m_newInstance, this);
+ m_glue->m_javaProxy = env->NewGlobalRef(obj);
+
+ // Clean up.
+ if (obj)
+ env->DeleteLocalRef(obj);
+ env->DeleteLocalRef(clazz);
+ checkException(env);
+ }
+
+ void onPrepared(int duration, int width, int height)
+ {
+ // Android media player gives us a duration of 0 for a live
+ // stream, so in that case set the real duration to infinity.
+ // We'll still be able to handle the case that we genuinely
+ // get an audio clip with a duration of 0s as we'll get the
+ // ended event when it stops playing.
+ if (duration > 0) {
+ m_duration = duration / 1000.0f;
+ } else {
+ m_duration = std::numeric_limits<float>::infinity();
+ }
+ m_player->durationChanged();
+ m_player->sizeChanged();
+ m_player->prepareToPlay();
+ }
+};
+
+MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
+{
+ if (player->mediaElementType() == MediaPlayer::Video)
+ return new MediaPlayerVideoPrivate(player);
+ return new MediaPlayerAudioPrivate(player);
+}
+
+}
+
+namespace android {
+
+static void OnPrepared(JNIEnv* env, jobject obj, int duration, int width, int height, int pointer)
+{
+ if (pointer) {
+ WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
+ player->onPrepared(duration, width, height);
+ }
+}
+
+static void OnEnded(JNIEnv* env, jobject obj, int pointer)
+{
+ if (pointer) {
+ WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
+ player->onEnded();
+ }
+}
+
+static void OnPaused(JNIEnv* env, jobject obj, int pointer)
+{
+ if (pointer) {
+ WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
+ player->onPaused();
+ }
+}
+
+static void OnPosterFetched(JNIEnv* env, jobject obj, jobject poster, int pointer)
+{
+ if (!pointer || !poster)
+ return;
+
+ WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
+ SkBitmap* posterNative = GraphicsJNI::getNativeBitmap(env, poster);
+ if (!posterNative)
+ return;
+ player->onPosterFetched(posterNative);
+}
+
+static void OnBuffering(JNIEnv* env, jobject obj, int percent, int pointer)
+{
+ if (pointer) {
+ WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
+ // TODO: player->onBuffering(percent);
+ }
+}
+
+static void OnTimeupdate(JNIEnv* env, jobject obj, int position, int pointer)
+{
+ if (pointer) {
+ WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
+ player->onTimeupdate(position);
+ }
+}
+
+// This is called on the UI thread only.
+// The video layers are composited on the webkit thread and then copied over
+// to the UI thread with the same ID. For rendering, we are only using the
+// video layers on the UI thread. Therefore, on the UI thread, we have to use
+// the videoLayerId from Java side to find the exact video layer in the tree
+// to set the surface texture.
+// Every time a play call into Java side, the videoLayerId will be sent and
+// saved in Java side. Then every time setBaseLayer call, the saved
+// videoLayerId will be passed to this function to find the Video Layer.
+// Return value: true when the video layer is found.
+static bool SendSurfaceTexture(JNIEnv* env, jobject obj, jobject surfTex,
+ int baseLayer, int videoLayerId,
+ int textureName, int playerState) {
+ if (!surfTex)
+ return false;
+
+ sp<SurfaceTexture> texture = android::SurfaceTexture_getSurfaceTexture(env, surfTex);
+ if (!texture.get())
+ return false;
+
+ BaseLayerAndroid* layerImpl = reinterpret_cast<BaseLayerAndroid*>(baseLayer);
+ if (!layerImpl)
+ return false;
+ if (!layerImpl->countChildren())
+ return false;
+ LayerAndroid* compositedRoot = static_cast<LayerAndroid*>(layerImpl->getChild(0));
+ if (!compositedRoot)
+ return false;
+
+ VideoLayerAndroid* videoLayer =
+ static_cast<VideoLayerAndroid*>(compositedRoot->findById(videoLayerId));
+ if (!videoLayer)
+ return false;
+
+ // Set the SurfaceTexture to the layer we found
+ videoLayer->setSurfaceTexture(texture, textureName, static_cast<PlayerState>(playerState));
+ return true;
+}
+
+static void OnStopFullscreen(JNIEnv* env, jobject obj, int pointer)
+{
+ if (pointer) {
+ WebCore::MediaPlayerPrivate* player =
+ reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer);
+ player->onStopFullscreen();
+ }
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod g_MediaPlayerMethods[] = {
+ { "nativeOnPrepared", "(IIII)V",
+ (void*) OnPrepared },
+ { "nativeOnEnded", "(I)V",
+ (void*) OnEnded },
+ { "nativeOnStopFullscreen", "(I)V",
+ (void*) OnStopFullscreen },
+ { "nativeOnPaused", "(I)V",
+ (void*) OnPaused },
+ { "nativeOnPosterFetched", "(Landroid/graphics/Bitmap;I)V",
+ (void*) OnPosterFetched },
+ { "nativeSendSurfaceTexture", "(Landroid/graphics/SurfaceTexture;IIII)Z",
+ (void*) SendSurfaceTexture },
+ { "nativeOnTimeupdate", "(II)V",
+ (void*) OnTimeupdate },
+};
+
+static JNINativeMethod g_MediaAudioPlayerMethods[] = {
+ { "nativeOnBuffering", "(II)V",
+ (void*) OnBuffering },
+ { "nativeOnEnded", "(I)V",
+ (void*) OnEnded },
+ { "nativeOnPrepared", "(IIII)V",
+ (void*) OnPrepared },
+ { "nativeOnTimeupdate", "(II)V",
+ (void*) OnTimeupdate },
+};
+
+int registerMediaPlayerVideo(JNIEnv* env)
+{
+ return jniRegisterNativeMethods(env, g_ProxyJavaClass,
+ g_MediaPlayerMethods, NELEM(g_MediaPlayerMethods));
+}
+
+int registerMediaPlayerAudio(JNIEnv* env)
+{
+ return jniRegisterNativeMethods(env, g_ProxyJavaClassAudio,
+ g_MediaAudioPlayerMethods, NELEM(g_MediaAudioPlayerMethods));
+}
+
+}
+#endif // VIDEO
diff --git a/Source/WebKit/android/WebCoreSupport/MemoryUsage.cpp b/Source/WebKit/android/WebCoreSupport/MemoryUsage.cpp
new file mode 100644
index 0000000..32cdebf
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/MemoryUsage.cpp
@@ -0,0 +1,81 @@
+/*
+ * 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 "MemoryUsage.h"
+
+#include <malloc.h>
+#include <wtf/CurrentTime.h>
+
+#if USE(V8)
+#include <v8.h>
+#endif // USE(V8)
+
+using namespace WTF;
+
+class MemoryUsageCache {
+public:
+ MemoryUsageCache()
+ : m_cachedMemoryUsage(0)
+ , m_cacheTime(0)
+ {
+ }
+
+ int getCachedMemoryUsage(bool forceFresh);
+
+private:
+ unsigned m_cachedMemoryUsage;
+ double m_cacheTime;
+ static const int CACHE_VALIDITY_MS = 2000;
+};
+
+int MemoryUsageCache::getCachedMemoryUsage(bool forceFresh)
+{
+ if (!forceFresh && currentTimeMS() <= m_cacheTime + CACHE_VALIDITY_MS)
+ return m_cachedMemoryUsage;
+
+ struct mallinfo minfo = mallinfo();
+ m_cachedMemoryUsage = (minfo.hblkhd + minfo.arena) >> 20;
+
+#if USE(V8)
+ v8::HeapStatistics stat;
+ v8::V8::GetHeapStatistics(&stat);
+ unsigned v8Usage = stat.total_heap_size() >> 20;
+ m_cachedMemoryUsage += v8Usage;
+#endif // USE(V8)
+
+ m_cacheTime = currentTimeMS();
+ return m_cachedMemoryUsage;
+}
+
+int MemoryUsage::memoryUsageMb(bool forceFresh)
+{
+ static MemoryUsageCache cache;
+ return cache.getCachedMemoryUsage(forceFresh);
+}
+
+int MemoryUsage::m_lowMemoryUsageMb = 0;
+int MemoryUsage::m_highMemoryUsageMb = 0;
+int MemoryUsage::m_highUsageDeltaMb = 0;
diff --git a/Source/WebKit/android/WebCoreSupport/MemoryUsage.h b/Source/WebKit/android/WebCoreSupport/MemoryUsage.h
new file mode 100644
index 0000000..2a3d7ed
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/MemoryUsage.h
@@ -0,0 +1,45 @@
+/*
+ * 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 MemoryUsage_h
+#define MemoryUsage_h
+
+class MemoryUsage {
+public:
+ static int memoryUsageMb(bool forceFresh);
+ static int lowMemoryUsageMb() { return m_lowMemoryUsageMb; }
+ static int highMemoryUsageMb() { return m_highMemoryUsageMb; }
+ static int highUsageDeltaMb() { return m_highUsageDeltaMb; }
+ static void setHighMemoryUsageMb(int highMemoryUsageMb) { m_highMemoryUsageMb = highMemoryUsageMb; }
+ static void setLowMemoryUsageMb(int lowMemoryUsageMb) { m_lowMemoryUsageMb = lowMemoryUsageMb; }
+ static void setHighUsageDeltaMb(int highUsageDeltaMb) { m_highUsageDeltaMb = highUsageDeltaMb; }
+
+private:
+ static int m_lowMemoryUsageMb;
+ static int m_highMemoryUsageMb;
+ static int m_highUsageDeltaMb;
+};
+
+#endif
diff --git a/Source/WebKit/android/WebCoreSupport/PlatformBridge.cpp b/Source/WebKit/android/WebCoreSupport/PlatformBridge.cpp
new file mode 100644
index 0000000..8d8d809
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/PlatformBridge.cpp
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2009, 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 <PlatformBridge.h>
+
+#include "CookieClient.h"
+#include "Document.h"
+#include "FileSystemClient.h"
+#include "FrameView.h"
+#include "JavaSharedClient.h"
+#include "KeyGeneratorClient.h"
+#include "MemoryUsage.h"
+#include "PluginView.h"
+#include "Settings.h"
+#include "WebCookieJar.h"
+#include "WebRequestContext.h"
+#include "WebViewCore.h"
+#include "npruntime.h"
+
+#include <surfaceflinger/SurfaceComposerClient.h>
+#include <ui/DisplayInfo.h>
+#include <ui/PixelFormat.h>
+#include <wtf/android/AndroidThreading.h>
+#include <wtf/MainThread.h>
+
+using namespace android;
+
+namespace WebCore {
+
+WTF::Vector<String> PlatformBridge::getSupportedKeyStrengthList()
+{
+ KeyGeneratorClient* client = JavaSharedClient::GetKeyGeneratorClient();
+ if (!client)
+ return WTF::Vector<String>();
+
+ return client->getSupportedKeyStrengthList();
+}
+
+String PlatformBridge::getSignedPublicKeyAndChallengeString(unsigned index, const String& challenge, const KURL& url)
+{
+ KeyGeneratorClient* client = JavaSharedClient::GetKeyGeneratorClient();
+ if (!client)
+ return String();
+
+ return client->getSignedPublicKeyAndChallengeString(index, challenge, url);
+}
+
+void PlatformBridge::setCookies(const Document* document, const KURL& url, const String& value)
+{
+#if USE(CHROME_NETWORK_STACK)
+ std::string cookieValue(value.utf8().data());
+ GURL cookieGurl(url.string().utf8().data());
+ bool isPrivateBrowsing = document->settings() && document->settings()->privateBrowsingEnabled();
+ WebCookieJar::get(isPrivateBrowsing)->cookieStore()->SetCookie(cookieGurl, cookieValue);
+#else
+ CookieClient* client = JavaSharedClient::GetCookieClient();
+ if (!client)
+ return;
+
+ client->setCookies(url, value);
+#endif
+}
+
+String PlatformBridge::cookies(const Document* document, const KURL& url)
+{
+#if USE(CHROME_NETWORK_STACK)
+ GURL cookieGurl(url.string().utf8().data());
+ bool isPrivateBrowsing = document->settings() && document->settings()->privateBrowsingEnabled();
+ std::string cookies = WebCookieJar::get(isPrivateBrowsing)->cookieStore()->GetCookies(cookieGurl);
+ String cookieString(cookies.c_str());
+ return cookieString;
+#else
+ CookieClient* client = JavaSharedClient::GetCookieClient();
+ if (!client)
+ return String();
+
+ return client->cookies(url);
+#endif
+}
+
+bool PlatformBridge::cookiesEnabled(const Document* document)
+{
+#if USE(CHROME_NETWORK_STACK)
+ bool isPrivateBrowsing = document->settings() && document->settings()->privateBrowsingEnabled();
+ return WebCookieJar::get(isPrivateBrowsing)->allowCookies();
+#else
+ CookieClient* client = JavaSharedClient::GetCookieClient();
+ if (!client)
+ return false;
+
+ return client->cookiesEnabled();
+#endif
+}
+
+NPObject* PlatformBridge::pluginScriptableObject(Widget* widget)
+{
+#if USE(V8)
+ if (!widget->isPluginView())
+ return 0;
+
+ PluginView* pluginView = static_cast<PluginView*>(widget);
+ return pluginView->getNPObject();
+#else
+ return 0;
+#endif
+}
+
+bool PlatformBridge::isWebViewPaused(const WebCore::FrameView* frameView)
+{
+ android::WebViewCore* webViewCore = android::WebViewCore::getWebViewCore(frameView);
+ return webViewCore->isPaused();
+}
+
+bool PlatformBridge::popupsAllowed(NPP)
+{
+ return false;
+}
+
+String PlatformBridge::resolveFilePathForContentUri(const String& contentUri)
+{
+ FileSystemClient* client = JavaSharedClient::GetFileSystemClient();
+ return client->resolveFilePathForContentUri(contentUri);
+}
+
+int PlatformBridge::PlatformBridge::screenDepth()
+{
+ android::DisplayInfo info;
+ android::SurfaceComposerClient::getDisplayInfo(android::DisplayID(0), &info);
+ return info.pixelFormatInfo.bitsPerPixel;
+}
+
+FloatRect PlatformBridge::screenRect()
+{
+ android::DisplayInfo info;
+ android::SurfaceComposerClient::getDisplayInfo(android::DisplayID(0), &info);
+ return FloatRect(0.0, 0.0, info.w, info.h);
+}
+
+// The visible size on screen in document coordinate
+int PlatformBridge::screenWidthInDocCoord(const WebCore::FrameView* frameView)
+{
+ android::WebViewCore* webViewCore = android::WebViewCore::getWebViewCore(frameView);
+ return webViewCore->screenWidth();
+}
+
+int PlatformBridge::screenHeightInDocCoord(const WebCore::FrameView* frameView)
+{
+ android::WebViewCore* webViewCore = android::WebViewCore::getWebViewCore(frameView);
+ return webViewCore->screenHeight();
+}
+
+String PlatformBridge::computeDefaultLanguage()
+{
+#if USE(CHROME_NETWORK_STACK)
+ String acceptLanguages = WebRequestContext::acceptLanguage();
+ size_t length = acceptLanguages.find(',');
+ if (length == std::string::npos)
+ length = acceptLanguages.length();
+ return acceptLanguages.substring(0, length);
+#else
+ return "en";
+#endif
+}
+
+void PlatformBridge::updateViewport(FrameView* frameView)
+{
+ android::WebViewCore* webViewCore = android::WebViewCore::getWebViewCore(frameView);
+ webViewCore->updateViewport();
+}
+
+void PlatformBridge::updateTextfield(FrameView* frameView, Node* nodePtr, bool changeToPassword, const WTF::String& text)
+{
+ android::WebViewCore* webViewCore = android::WebViewCore::getWebViewCore(frameView);
+ webViewCore->updateTextfield(nodePtr, changeToPassword, text);
+}
+
+void PlatformBridge::setScrollPosition(ScrollView* scrollView, int x, int y) {
+ // Check to make sure the view is the main FrameView.
+ android::WebViewCore *webViewCore = android::WebViewCore::getWebViewCore(scrollView);
+ if (webViewCore->mainFrame()->view() == scrollView)
+ webViewCore->scrollTo(x, y);
+}
+
+int PlatformBridge::lowMemoryUsageMB()
+{
+ return MemoryUsage::lowMemoryUsageMb();
+}
+
+int PlatformBridge::highMemoryUsageMB()
+{
+ return MemoryUsage::highMemoryUsageMb();
+}
+
+int PlatformBridge::highUsageDeltaMB()
+{
+ return MemoryUsage::highUsageDeltaMb();
+}
+
+int PlatformBridge::memoryUsageMB()
+{
+ return MemoryUsage::memoryUsageMb(false);
+}
+
+int PlatformBridge::actualMemoryUsageMB()
+{
+ return MemoryUsage::memoryUsageMb(true);
+}
+
+} // namespace WebCore
+
+
+// This is the implementation of AndroidThreading, which is declared in
+// JavaScriptCore/wtf/android/AndroidThreading.h. It is provided here, rather
+// than in its own source file, to avoid linker problems.
+//
+// By default, when building a shared library, the linker strips from static
+// libraries any compilation units which do not contain any code referenced from
+// that static library. Since
+// AndroidThreading::scheduleDispatchFunctionsOnMainThread is not referenced
+// from libwebcore.a, implementing it in its own compilation unit results in it
+// being stripped. This stripping can be avoided by using the linker option
+// --whole-archive for libwebcore.a, but this adds considerably to the size of
+// libwebcore.so.
+
+namespace WTF {
+
+// Callback in the main thread.
+static void timeoutFired(void*)
+{
+ dispatchFunctionsFromMainThread();
+}
+
+void AndroidThreading::scheduleDispatchFunctionsOnMainThread()
+{
+ JavaSharedClient::EnqueueFunctionPtr(timeoutFired, 0);
+}
+
+} // namespace WTF
diff --git a/Source/WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp b/Source/WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp
new file mode 100644
index 0000000..7f54810
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/ResourceLoaderAndroid.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2009, 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 <ResourceLoaderAndroid.h>
+
+#include "Frame.h"
+#include "FrameLoaderClientAndroid.h"
+#include "WebCoreFrameBridge.h"
+#include "WebCoreResourceLoader.h"
+#include "WebUrlLoader.h"
+#include "WebViewCore.h"
+
+using namespace android;
+
+namespace WebCore {
+
+PassRefPtr<ResourceLoaderAndroid> ResourceLoaderAndroid::start(
+ ResourceHandle* handle, const ResourceRequest& request, FrameLoaderClient* client, bool isMainResource, bool isSync)
+{
+ // Called on main thread
+ FrameLoaderClientAndroid* clientAndroid = static_cast<FrameLoaderClientAndroid*>(client);
+#if USE(CHROME_NETWORK_STACK)
+ WebViewCore* webViewCore = WebViewCore::getWebViewCore(clientAndroid->getFrame()->view());
+ bool isMainFrame = !(clientAndroid->getFrame()->tree() && clientAndroid->getFrame()->tree()->parent());
+ return WebUrlLoader::start(client, handle, request, isMainResource, isMainFrame, isSync, webViewCore->webRequestContext());
+#else
+ return clientAndroid->webFrame()->startLoadingResource(handle, request, isMainResource, isSync);
+#endif
+}
+
+bool ResourceLoaderAndroid::willLoadFromCache(const WebCore::KURL& url, int64_t identifier)
+{
+#if USE(CHROME_NETWORK_STACK)
+ // 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, to prevent the FrameLoader from initiating a
+ // reload. Then in FrameLoaderClientImpl::dispatchWillSendRequest, we
+ // fix-up the cache policy of the request to force a load from the cache.
+ return true;
+#else
+ return WebCoreResourceLoader::willLoadFromCache(url, identifier);
+#endif
+}
+
+}
diff --git a/Source/WebKit/android/WebCoreSupport/UrlInterceptResponse.cpp b/Source/WebKit/android/WebCoreSupport/UrlInterceptResponse.cpp
new file mode 100644
index 0000000..3779ba8
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/UrlInterceptResponse.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "UrlInterceptResponse"
+#include "config.h"
+
+#include "JNIUtility.h"
+#include "UrlInterceptResponse.h"
+#include "WebCoreJni.h"
+
+#include <utils/Log.h>
+
+namespace android {
+
+class JavaInputStreamWrapper {
+public:
+ JavaInputStreamWrapper(JNIEnv* env, jobject inputStream)
+ : m_inputStream(env->NewGlobalRef(inputStream))
+ , m_buffer(0) {
+ LOG_ALWAYS_FATAL_IF(!inputStream);
+ jclass inputStreamClass = env->FindClass("java/io/InputStream");
+ LOG_ALWAYS_FATAL_IF(!inputStreamClass);
+ m_read = env->GetMethodID(inputStreamClass, "read", "([B)I");
+ LOG_ALWAYS_FATAL_IF(!m_read);
+ m_close = env->GetMethodID(inputStreamClass, "close", "()V");
+ LOG_ALWAYS_FATAL_IF(!m_close);
+ }
+
+ ~JavaInputStreamWrapper() {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ env->CallVoidMethod(m_inputStream, m_close);
+ checkException(env);
+ env->DeleteGlobalRef(m_inputStream);
+ // In case we never call read().
+ if (m_buffer)
+ env->DeleteGlobalRef(m_buffer);
+ }
+
+ void read(std::vector<char>* out) {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ // Initialize our read buffer to the capacity of out.
+ if (!m_buffer) {
+ m_buffer = env->NewByteArray(out->capacity());
+ m_buffer = (jbyteArray) env->NewGlobalRef(m_buffer);
+ }
+ int size = (int) env->CallIntMethod(m_inputStream, m_read, m_buffer);
+ if (checkException(env) || size < 0)
+ return;
+ // Copy from m_buffer to out.
+ out->resize(size);
+ env->GetByteArrayRegion(m_buffer, 0, size, (jbyte*)&out->front());
+ }
+
+private:
+ jobject m_inputStream;
+ jbyteArray m_buffer;
+ jmethodID m_read;
+ jmethodID m_close;
+};
+
+UrlInterceptResponse::UrlInterceptResponse(JNIEnv* env, jobject response) {
+ jclass javaResponse = env->FindClass("android/webkit/WebResourceResponse");
+ LOG_ALWAYS_FATAL_IF(!javaResponse);
+ jfieldID mimeType = env->GetFieldID(javaResponse, "mMimeType",
+ "Ljava/lang/String;");
+ LOG_ALWAYS_FATAL_IF(!mimeType);
+ jfieldID encoding = env->GetFieldID(javaResponse, "mEncoding",
+ "Ljava/lang/String;");
+ LOG_ALWAYS_FATAL_IF(!encoding);
+ jfieldID inputStream = env->GetFieldID(javaResponse, "mInputStream",
+ "Ljava/io/InputStream;");
+ LOG_ALWAYS_FATAL_IF(!inputStream);
+
+ jobject stream = env->GetObjectField(response, inputStream);
+ if (stream)
+ m_inputStream.set(new JavaInputStreamWrapper(env, stream));
+
+ jstring mimeStr = (jstring) env->GetObjectField(response, mimeType);
+ jstring encodingStr = (jstring) env->GetObjectField(response, encoding);
+
+ if (mimeStr) {
+ const char* s = env->GetStringUTFChars(mimeStr, NULL);
+ m_mimeType.assign(s, env->GetStringUTFLength(mimeStr));
+ env->ReleaseStringUTFChars(mimeStr, s);
+ }
+ if (encodingStr) {
+ const char* s = env->GetStringUTFChars(encodingStr, NULL);
+ m_encoding.assign(s, env->GetStringUTFLength(encodingStr));
+ env->ReleaseStringUTFChars(encodingStr, s);
+ }
+
+ env->DeleteLocalRef(javaResponse);
+ env->DeleteLocalRef(mimeStr);
+ env->DeleteLocalRef(encodingStr);
+}
+
+UrlInterceptResponse::~UrlInterceptResponse() {
+ // Cannot be inlined because of JavaInputStreamWrapper visibility.
+}
+
+bool UrlInterceptResponse::readStream(std::vector<char>* out) const {
+ if (!m_inputStream)
+ return false;
+ m_inputStream->read(out);
+ return true;
+}
+
+} // namespace android
diff --git a/Source/WebKit/android/WebCoreSupport/UrlInterceptResponse.h b/Source/WebKit/android/WebCoreSupport/UrlInterceptResponse.h
new file mode 100644
index 0000000..64dad69
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/UrlInterceptResponse.h
@@ -0,0 +1,70 @@
+/*
+ * 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 UrlInterceptResponse_h
+#define UrlInterceptResponse_h
+
+#include "PlatformString.h"
+#include "wtf/Noncopyable.h"
+#include "wtf/OwnPtr.h"
+
+#include <jni.h>
+#include <string>
+#include <vector>
+
+namespace android {
+
+class JavaInputStreamWrapper;
+
+class UrlInterceptResponse : public Noncopyable {
+public:
+ UrlInterceptResponse(JNIEnv* env, jobject response);
+ ~UrlInterceptResponse();
+
+ const std::string& mimeType() const {
+ return m_mimeType;
+ }
+
+ const std::string& encoding() const {
+ return m_encoding;
+ }
+
+ int status() const {
+ return m_inputStream ? 200 : 404;
+ }
+
+ // Read from the input stream. Returns false if reading failed.
+ // A size of 0 indicates eof.
+ bool readStream(std::vector<char>* out) const;
+
+private:
+ std::string m_mimeType;
+ std::string m_encoding;
+ OwnPtr<JavaInputStreamWrapper> m_inputStream;
+};
+
+} // namespace android
+
+#endif
diff --git a/Source/WebKit/android/WebCoreSupport/V8Counters.cpp b/Source/WebKit/android/WebCoreSupport/V8Counters.cpp
new file mode 100644
index 0000000..d164f9a
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/V8Counters.cpp
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ */
+
+
+#ifdef ANDROID_INSTRUMENT
+
+#define LOG_TAG "WebCore"
+
+#include "config.h"
+#include "V8Counters.h"
+
+#include "NotImplemented.h"
+#include <utils/Log.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/StringHash.h>
+
+#if USE(V8)
+
+namespace WebCore {
+
+V8Counters::Counter::Counter(bool isHistogram)
+ : m_count(0), m_sampleTotal(0), m_isHistogram(isHistogram) { }
+
+void V8Counters::Counter::addSample(int sample)
+{
+ m_count++;
+ m_sampleTotal += sample;
+}
+
+HashMap<String, V8Counters::Counter*> V8Counters::m_counters;
+
+// static
+int* V8Counters::counterForName(const char* name)
+{
+ Counter* counter = m_counters.get(name);
+ if (!counter) {
+ counter = new Counter(false);
+ m_counters.add(name, counter);
+ }
+ return *counter;
+}
+
+// static
+void* V8Counters::createHistogram(const char* name, int min, int max,
+ size_t buckets)
+{
+ Counter* counter = new Counter(true);
+ m_counters.add(name, counter);
+ return counter;
+}
+
+// static
+void V8Counters::addHistogramSample(void* histogram, int sample)
+{
+ Counter* counter = reinterpret_cast<Counter*>(histogram);
+ counter->addSample(sample);
+}
+
+// static
+void V8Counters::initCounters()
+{
+ static bool isInitialized = false;
+ if (!isInitialized) {
+ v8::V8::SetCounterFunction(counterForName);
+ v8::V8::SetCreateHistogramFunction(createHistogram);
+ v8::V8::SetAddHistogramSampleFunction(addHistogramSample);
+ isInitialized = true;
+ }
+}
+
+// static
+void V8Counters::dumpCounters()
+{
+ LOGD("+----------------------------------------+-------------+\n");
+ LOGD("| Name | Value |\n");
+ LOGD("+----------------------------------------+-------------+\n");
+ typedef HashMap<String, V8Counters::Counter*>::iterator CounterIterator;
+ for (CounterIterator iter = m_counters.begin(); iter != m_counters.end(); ++iter) {
+ Counter* counter = iter->second;
+ if (counter->isHistogram()) {
+ LOGD("| c:%-36s | %11i |\n", iter->first.latin1().data(), counter->count());
+ LOGD("| t:%-36s | %11i |\n", iter->first.latin1().data(), counter->sampleTotal());
+ } else {
+ LOGD("| %-38s | %11i |\n", iter->first.latin1().data(), counter->count());
+ }
+ }
+ LOGD("+----------------------------------------+-------------+\n");
+}
+
+}
+
+#endif // ANDROID_INSTRUMENT
+
+#endif // USE(V8)
diff --git a/Source/WebKit/android/WebCoreSupport/V8Counters.h b/Source/WebKit/android/WebCoreSupport/V8Counters.h
new file mode 100644
index 0000000..499b856
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/V8Counters.h
@@ -0,0 +1,77 @@
+/*
+ * 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 V8Counters_h
+#define V8Counters_h
+
+#if USE(V8)
+
+#ifdef ANDROID_INSTRUMENT
+
+#include <PlatformString.h>
+#include <v8.h>
+#include <wtf/HashMap.h>
+
+namespace WebCore {
+
+class V8Counters {
+public:
+ // Counter callbacks, see v8.h
+ static int* counterForName(const char* name);
+
+ static void* createHistogram(const char* name,
+ int min,
+ int max,
+ size_t buckets);
+
+ static void addHistogramSample(void* histogram, int sample);
+
+ static void initCounters();
+ static void dumpCounters();
+private:
+ class Counter {
+ public:
+ Counter(bool isHistogram);
+
+ int count() { return m_count; }
+ int sampleTotal() { return m_sampleTotal; }
+ bool isHistogram() { return m_isHistogram; }
+ void addSample(int32_t sample);
+
+ operator int*() { return &m_count; }
+ private:
+ int m_count;
+ int m_sampleTotal;
+ bool m_isHistogram;
+ };
+
+ static HashMap<String, Counter*> m_counters;
+};
+
+}
+
+#endif // ANDROID_INSTRUMENT
+#endif // USE(V8)
+#endif // V8Counters_h
diff --git a/Source/WebKit/android/WebCoreSupport/WebCache.cpp b/Source/WebKit/android/WebCoreSupport/WebCache.cpp
new file mode 100644
index 0000000..be9a700
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/WebCache.cpp
@@ -0,0 +1,237 @@
+/*
+ * 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 "WebCache.h"
+
+#include "JNIUtility.h"
+#include "WebCoreJni.h"
+#include "WebRequestContext.h"
+#include "WebUrlLoaderClient.h"
+
+#include <wtf/text/CString.h>
+
+using namespace WTF;
+using namespace disk_cache;
+using namespace net;
+using namespace std;
+
+namespace android {
+
+static WTF::Mutex instanceMutex;
+
+static const string& rootDirectory()
+{
+ // This method may be called on any thread, as the Java method is
+ // synchronized.
+ static WTF::Mutex mutex;
+ MutexLocker lock(mutex);
+ static string cacheDirectory;
+ if (cacheDirectory.empty()) {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ jclass bridgeClass = env->FindClass("android/webkit/JniUtil");
+ jmethodID method = env->GetStaticMethodID(bridgeClass, "getCacheDirectory", "()Ljava/lang/String;");
+ cacheDirectory = jstringToStdString(env, static_cast<jstring>(env->CallStaticObjectMethod(bridgeClass, method)));
+ env->DeleteLocalRef(bridgeClass);
+ }
+ return cacheDirectory;
+}
+
+static string storageDirectory()
+{
+ // Private cache is currently in memory only
+ static const char* const kDirectory = "/webviewCacheChromium";
+ string storageDirectory = rootDirectory();
+ storageDirectory.append(kDirectory);
+ return storageDirectory;
+}
+
+static scoped_refptr<WebCache>* instance(bool isPrivateBrowsing)
+{
+ static scoped_refptr<WebCache> regularInstance;
+ static scoped_refptr<WebCache> privateInstance;
+ return isPrivateBrowsing ? &privateInstance : &regularInstance;
+}
+
+WebCache* WebCache::get(bool isPrivateBrowsing)
+{
+ MutexLocker lock(instanceMutex);
+ scoped_refptr<WebCache>* instancePtr = instance(isPrivateBrowsing);
+ if (!instancePtr->get())
+ *instancePtr = new WebCache(isPrivateBrowsing);
+ return instancePtr->get();
+}
+
+void WebCache::cleanup(bool isPrivateBrowsing)
+{
+ MutexLocker lock(instanceMutex);
+ scoped_refptr<WebCache>* instancePtr = instance(isPrivateBrowsing);
+ *instancePtr = 0;
+}
+
+WebCache::WebCache(bool isPrivateBrowsing)
+ : m_doomAllEntriesCallback(this, &WebCache::doomAllEntries)
+ , m_onClearDoneCallback(this, &WebCache::onClearDone)
+ , m_isClearInProgress(false)
+ , m_openEntryCallback(this, &WebCache::openEntry)
+ , m_onGetEntryDoneCallback(this, &WebCache::onGetEntryDone)
+ , m_isGetEntryInProgress(false)
+ , m_cacheBackend(0)
+{
+ base::Thread* ioThread = WebUrlLoaderClient::ioThread();
+ scoped_refptr<base::MessageLoopProxy> cacheMessageLoopProxy = ioThread->message_loop_proxy();
+
+ static const int kMaximumCacheSizeBytes = 20 * 1024 * 1024;
+ m_hostResolver = net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism, 0, 0);
+
+ m_proxyConfigService = new ProxyConfigServiceAndroid();
+ net::HttpCache::BackendFactory* backendFactory;
+ if (isPrivateBrowsing)
+ backendFactory = net::HttpCache::DefaultBackend::InMemory(kMaximumCacheSizeBytes / 2);
+ else {
+ FilePath directoryPath(storageDirectory().c_str());
+ backendFactory = new net::HttpCache::DefaultBackend(net::DISK_CACHE, directoryPath, kMaximumCacheSizeBytes, cacheMessageLoopProxy);
+ }
+
+ m_cache = new net::HttpCache(m_hostResolver.get(),
+ 0, // dnsrr_resolver
+ 0, // dns_cert_checker
+ net::ProxyService::CreateWithoutProxyResolver(m_proxyConfigService, 0 /* net_log */),
+ net::SSLConfigService::CreateSystemSSLConfigService(),
+ net::HttpAuthHandlerFactory::CreateDefault(m_hostResolver.get()),
+ 0, // network_delegate
+ 0, // net_log
+ backendFactory);
+}
+
+void WebCache::clear()
+{
+ base::Thread* thread = WebUrlLoaderClient::ioThread();
+ if (thread)
+ thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, &WebCache::clearImpl));
+}
+
+void WebCache::clearImpl()
+{
+ if (m_isClearInProgress)
+ return;
+ m_isClearInProgress = true;
+
+ if (!m_cacheBackend) {
+ int code = m_cache->GetBackend(&m_cacheBackend, &m_doomAllEntriesCallback);
+ // Code ERR_IO_PENDING indicates that the operation is still in progress and
+ // the supplied callback will be invoked when it completes.
+ if (code == ERR_IO_PENDING)
+ return;
+ else if (code != OK) {
+ onClearDone(0 /*unused*/);
+ return;
+ }
+ }
+ doomAllEntries(0 /*unused*/);
+}
+
+void WebCache::doomAllEntries(int)
+{
+ if (!m_cacheBackend) {
+ onClearDone(0 /*unused*/);
+ return;
+ }
+
+ // Code ERR_IO_PENDING indicates that the operation is still in progress and
+ // the supplied callback will be invoked when it completes.
+ if (m_cacheBackend->DoomAllEntries(&m_onClearDoneCallback) == ERR_IO_PENDING)
+ return;
+ onClearDone(0 /*unused*/);
+}
+
+void WebCache::onClearDone(int)
+{
+ m_isClearInProgress = false;
+}
+
+scoped_refptr<CacheResult> WebCache::getCacheResult(String url)
+{
+ // This is called on the UI thread.
+ MutexLocker lock(m_getEntryMutex);
+ if (m_isGetEntryInProgress)
+ return 0; // TODO: OK? Or can we queue 'em up?
+
+ // The Chromium methods are asynchronous, but we need this method to be
+ // synchronous. Do the work on the Chromium thread but block this thread
+ // here waiting for the work to complete.
+ base::Thread* thread = WebUrlLoaderClient::ioThread();
+ if (!thread)
+ return 0;
+
+ m_entry = 0;
+ m_isGetEntryInProgress = true;
+ m_entryUrl = url.threadsafeCopy();
+ thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, &WebCache::getEntryImpl));
+
+ while (m_isGetEntryInProgress)
+ m_getEntryCondition.wait(m_getEntryMutex);
+
+ if (!m_entry)
+ return 0;
+
+ return new CacheResult(m_entry, url);
+}
+
+void WebCache::getEntryImpl()
+{
+ if (!m_cacheBackend) {
+ int code = m_cache->GetBackend(&m_cacheBackend, &m_openEntryCallback);
+ if (code == ERR_IO_PENDING)
+ return;
+ else if (code != OK) {
+ onGetEntryDone(0 /*unused*/);
+ return;
+ }
+ }
+ openEntry(0 /*unused*/);
+}
+
+void WebCache::openEntry(int)
+{
+ if (!m_cacheBackend) {
+ onGetEntryDone(0 /*unused*/);
+ return;
+ }
+
+ if (m_cacheBackend->OpenEntry(string(m_entryUrl.utf8().data()), &m_entry, &m_onGetEntryDoneCallback) == ERR_IO_PENDING)
+ return;
+ onGetEntryDone(0 /*unused*/);
+}
+
+void WebCache::onGetEntryDone(int)
+{
+ // Unblock the UI thread in getEntry();
+ MutexLocker lock(m_getEntryMutex);
+ m_isGetEntryInProgress = false;
+ m_getEntryCondition.signal();
+}
+
+} // namespace android
diff --git a/Source/WebKit/android/WebCoreSupport/WebCache.h b/Source/WebKit/android/WebCoreSupport/WebCache.h
new file mode 100644
index 0000000..7149fcc
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/WebCache.h
@@ -0,0 +1,88 @@
+/*
+ * 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 WebCache_h
+#define WebCache_h
+
+#include "CacheResult.h"
+#include "ChromiumIncludes.h"
+
+#include <OwnPtr.h>
+#include <platform/text/PlatformString.h>
+#include <wtf/ThreadingPrimitives.h>
+
+namespace android {
+
+// This class is not generally threadsafe. However, get() and cleanup() are
+// threadsafe.
+class WebCache : public base::RefCountedThreadSafe<WebCache> {
+public:
+ static WebCache* get(bool isPrivateBrowsing);
+ static void cleanup(bool isPrivateBrowsing);
+
+ void clear();
+ scoped_refptr<CacheResult> getCacheResult(WTF::String url);
+ net::HostResolver* hostResolver() { return m_hostResolver.get(); }
+ net::HttpCache* cache() { return m_cache.get(); }
+ net::ProxyConfigServiceAndroid* proxy() { return m_proxyConfigService; }
+
+private:
+ WebCache(bool isPrivateBrowsing);
+
+ // For clear()
+ void clearImpl();
+ void doomAllEntries(int);
+ void onClearDone(int);
+
+ // For getEntry()
+ void getEntryImpl();
+ void openEntry(int);
+ void onGetEntryDone(int);
+
+ OwnPtr<net::HostResolver> m_hostResolver;
+ OwnPtr<net::HttpCache> m_cache;
+ // This is owned by the ProxyService, which is owned by the HttpNetworkLayer,
+ // which is owned by the HttpCache, which is owned by this class.
+ net::ProxyConfigServiceAndroid* m_proxyConfigService;
+
+ // For clear()
+ net::CompletionCallbackImpl<WebCache> m_doomAllEntriesCallback;
+ net::CompletionCallbackImpl<WebCache> m_onClearDoneCallback;
+ bool m_isClearInProgress;
+ // For getEntry()
+ net::CompletionCallbackImpl<WebCache> m_openEntryCallback;
+ net::CompletionCallbackImpl<WebCache> m_onGetEntryDoneCallback;
+ bool m_isGetEntryInProgress;
+ String m_entryUrl;
+ disk_cache::Entry* m_entry;
+ WTF::Mutex m_getEntryMutex;
+ WTF::ThreadCondition m_getEntryCondition;
+
+ disk_cache::Backend* m_cacheBackend;
+};
+
+} // namespace android
+
+#endif
diff --git a/Source/WebKit/android/WebCoreSupport/WebCookieJar.cpp b/Source/WebKit/android/WebCoreSupport/WebCookieJar.cpp
new file mode 100644
index 0000000..99de67e
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/WebCookieJar.cpp
@@ -0,0 +1,263 @@
+/*
+ * 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 "WebCookieJar.h"
+
+#include "JNIUtility.h"
+#include "WebCoreJni.h"
+#include "WebRequestContext.h"
+#include "WebUrlLoaderClient.h"
+
+#include <cutils/log.h>
+#include <dirent.h>
+
+#undef ASSERT
+#define ASSERT(assertion, ...) do \
+ if (!(assertion)) { \
+ android_printLog(ANDROID_LOG_ERROR, __FILE__, __VA_ARGS__); \
+ } \
+while (0)
+
+namespace android {
+
+static WTF::Mutex instanceMutex;
+static bool isFirstInstanceCreated = false;
+static bool fileSchemeCookiesEnabled = false;
+
+static const std::string& databaseDirectory()
+{
+ // This method may be called on any thread, as the Java method is
+ // synchronized.
+ static WTF::Mutex databaseDirectoryMutex;
+ MutexLocker lock(databaseDirectoryMutex);
+ static std::string databaseDirectory;
+ if (databaseDirectory.empty()) {
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ jclass bridgeClass = env->FindClass("android/webkit/JniUtil");
+ jmethodID method = env->GetStaticMethodID(bridgeClass, "getDatabaseDirectory", "()Ljava/lang/String;");
+ databaseDirectory = jstringToStdString(env, static_cast<jstring>(env->CallStaticObjectMethod(bridgeClass, method)));
+ env->DeleteLocalRef(bridgeClass);
+ }
+ return databaseDirectory;
+}
+
+static void removeFileOrDirectory(const char* filename)
+{
+ struct stat filetype;
+ if (stat(filename, &filetype) != 0)
+ return;
+ if (S_ISDIR(filetype.st_mode)) {
+ DIR* directory = opendir(filename);
+ if (directory) {
+ while (struct dirent* entry = readdir(directory)) {
+ if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
+ continue;
+ std::string entryName(filename);
+ entryName.append("/");
+ entryName.append(entry->d_name);
+ removeFileOrDirectory(entryName.c_str());
+ }
+ closedir(directory);
+ rmdir(filename);
+ }
+ return;
+ }
+ unlink(filename);
+}
+
+static std::string databaseDirectory(bool isPrivateBrowsing)
+{
+ static const char* const kDatabaseFilename = "/webviewCookiesChromium.db";
+ static const char* const kDatabaseFilenamePrivateBrowsing = "/webviewCookiesChromiumPrivate.db";
+
+ std::string databaseFilePath = databaseDirectory();
+ databaseFilePath.append(isPrivateBrowsing ? kDatabaseFilenamePrivateBrowsing : kDatabaseFilename);
+ return databaseFilePath;
+}
+
+scoped_refptr<WebCookieJar>* instance(bool isPrivateBrowsing)
+{
+ static scoped_refptr<WebCookieJar> regularInstance;
+ static scoped_refptr<WebCookieJar> privateInstance;
+ return isPrivateBrowsing ? &privateInstance : &regularInstance;
+}
+
+WebCookieJar* WebCookieJar::get(bool isPrivateBrowsing)
+{
+ MutexLocker lock(instanceMutex);
+ if (!isFirstInstanceCreated && fileSchemeCookiesEnabled)
+ net::CookieMonster::EnableFileScheme();
+ isFirstInstanceCreated = true;
+ scoped_refptr<WebCookieJar>* instancePtr = instance(isPrivateBrowsing);
+ if (!instancePtr->get())
+ *instancePtr = new WebCookieJar(databaseDirectory(isPrivateBrowsing));
+ return instancePtr->get();
+}
+
+void WebCookieJar::cleanup(bool isPrivateBrowsing)
+{
+ // This is called on the UI thread.
+ MutexLocker lock(instanceMutex);
+ scoped_refptr<WebCookieJar>* instancePtr = instance(isPrivateBrowsing);
+ *instancePtr = 0;
+ removeFileOrDirectory(databaseDirectory(isPrivateBrowsing).c_str());
+}
+
+WebCookieJar::WebCookieJar(const std::string& databaseFilePath)
+ : m_allowCookies(true)
+{
+ // Setup the permissions for the file
+ const char* cDatabasePath = databaseFilePath.c_str();
+ mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
+ if (access(cDatabasePath, F_OK) == 0)
+ chmod(cDatabasePath, mode);
+ else {
+ int fd = open(cDatabasePath, O_CREAT, mode);
+ if (fd >= 0)
+ close(fd);
+ }
+
+ FilePath cookiePath(databaseFilePath.c_str());
+ m_cookieDb = new SQLitePersistentCookieStore(cookiePath);
+ m_cookieStore = new net::CookieMonster(m_cookieDb.get(), 0);
+}
+
+bool WebCookieJar::allowCookies()
+{
+ MutexLocker lock(m_allowCookiesMutex);
+ return m_allowCookies;
+}
+
+void WebCookieJar::setAllowCookies(bool allow)
+{
+ MutexLocker lock(m_allowCookiesMutex);
+ m_allowCookies = allow;
+}
+
+int WebCookieJar::getNumCookiesInDatabase()
+{
+ if (!m_cookieStore)
+ return 0;
+ return m_cookieStore->GetCookieMonster()->GetAllCookies().size();
+}
+
+// From CookiePolicy in chromium
+int WebCookieJar::CanGetCookies(const GURL&, const GURL&, net::CompletionCallback*)
+{
+ MutexLocker lock(m_allowCookiesMutex);
+ return m_allowCookies ? net::OK : net::ERR_ACCESS_DENIED;
+}
+
+// From CookiePolicy in chromium
+int WebCookieJar::CanSetCookie(const GURL&, const GURL&, const std::string&, net::CompletionCallback*)
+{
+ MutexLocker lock(m_allowCookiesMutex);
+ return m_allowCookies ? net::OK : net::ERR_ACCESS_DENIED;
+}
+
+class FlushSemaphore : public base::RefCounted<FlushSemaphore>
+{
+public:
+ FlushSemaphore()
+ : m_condition(&m_lock)
+ , m_count(0)
+ {}
+
+ void SendFlushRequest(net::CookieMonster* monster) {
+ // FlushStore() needs to run on a Chrome thread (because it will need
+ // to post the callback, and it may want to do so on its own thread.)
+ // We use the IO thread for this purpose.
+ //
+ // TODO(husky): Our threads are hidden away in various files. Clean this
+ // up and consider integrating with Chrome's browser_thread.h. Might be
+ // a better idea to use the DB thread here rather than the IO thread.
+
+ base::Thread* ioThread = WebUrlLoaderClient::ioThread();
+ if (ioThread) {
+ Task* callback = NewRunnableMethod(this, &FlushSemaphore::Callback);
+ ioThread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
+ monster, &net::CookieMonster::FlushStore, callback));
+ } else {
+ Callback();
+ }
+ }
+
+ // Block until the given number of callbacks has been made.
+ void Wait(int numCallbacks) {
+ AutoLock al(m_lock);
+ int lastCount = m_count;
+ while (m_count < numCallbacks) {
+ // TODO(husky): Maybe use TimedWait() here? But it's not obvious what
+ // to do if the flush fails. Might be okay just to let the OS kill us.
+ m_condition.Wait();
+ ASSERT(lastCount != m_count, "Wait finished without incrementing m_count %d %d", m_count, lastCount);
+ lastCount = m_count;
+ }
+ m_count -= numCallbacks;
+ }
+
+private:
+ friend class base::RefCounted<FlushSemaphore>;
+
+ void Callback() {
+ AutoLock al(m_lock);
+ m_count++;
+ m_condition.Broadcast();
+ }
+
+ Lock m_lock;
+ ConditionVariable m_condition;
+ volatile int m_count;
+};
+
+void WebCookieJar::flush()
+{
+ // Flush both cookie stores (private and non-private), wait for 2 callbacks.
+ static scoped_refptr<FlushSemaphore> semaphore(new FlushSemaphore());
+ semaphore->SendFlushRequest(get(false)->cookieStore()->GetCookieMonster());
+ semaphore->SendFlushRequest(get(true)->cookieStore()->GetCookieMonster());
+ semaphore->Wait(2);
+}
+
+bool WebCookieJar::acceptFileSchemeCookies()
+{
+ MutexLocker lock(instanceMutex);
+ return fileSchemeCookiesEnabled;
+}
+
+void WebCookieJar::setAcceptFileSchemeCookies(bool accept)
+{
+ // The Chromium HTTP stack only reflects changes to this flag when creating
+ // a new CookieMonster instance. While we could track whether any
+ // CookieMonster instances currently exist, this would be complicated and is
+ // not required, so we only allow this flag to be changed before the first
+ // instance is created.
+ MutexLocker lock(instanceMutex);
+ if (!isFirstInstanceCreated)
+ fileSchemeCookiesEnabled = accept;
+}
+
+}
diff --git a/Source/WebKit/android/WebCoreSupport/WebCookieJar.h b/Source/WebKit/android/WebCoreSupport/WebCookieJar.h
new file mode 100644
index 0000000..1f4266c
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/WebCookieJar.h
@@ -0,0 +1,78 @@
+/*
+ * 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 WebCookieJar_h
+#define WebCookieJar_h
+
+#include "ChromiumIncludes.h"
+
+#include <wtf/ThreadingPrimitives.h>
+
+namespace android {
+
+// This class is threadsafe. It is used from the IO, WebCore and Chromium IO
+// threads.
+class WebCookieJar : public net::CookiePolicy, public base::RefCountedThreadSafe<WebCookieJar> {
+public:
+ static WebCookieJar* get(bool isPrivateBrowsing);
+ static void cleanup(bool isPrivateBrowsing);
+
+ // Flush all cookies to disk. Synchronous.
+ static void flush();
+
+ // CookiePolicy implementation from external/chromium
+ virtual int CanGetCookies(const GURL& url, const GURL& first_party_for_cookies, net::CompletionCallback*);
+ virtual int CanSetCookie(const GURL& url, const GURL& first_party_for_cookies, const std::string& cookie_line, net::CompletionCallback*);
+
+ bool allowCookies();
+ void setAllowCookies(bool allow);
+
+ // Getter and setter for whether we accept cookies for file scheme URLS.
+ // Defaults to false. Note that calls to the setter are ignored once the
+ // first instance of this class has been created.
+ static bool acceptFileSchemeCookies();
+ static void setAcceptFileSchemeCookies(bool);
+
+ // Instead of this it would probably be better to add the cookie methods
+ // here so the rest of WebKit doesn't have to know about Chromium classes
+ net::CookieStore* cookieStore() { return m_cookieStore.get(); }
+ net::CookiePolicy* cookiePolicy() { return this; }
+
+ // Get the number of cookies that have actually been saved to flash.
+ // (This is used to implement CookieManager.hasCookies() in the Java framework.)
+ int getNumCookiesInDatabase();
+
+private:
+ WebCookieJar(const std::string& databaseFilePath);
+
+ scoped_refptr<SQLitePersistentCookieStore> m_cookieDb;
+ scoped_refptr<net::CookieStore> m_cookieStore;
+ bool m_allowCookies;
+ WTF::Mutex m_allowCookiesMutex;
+};
+
+}
+
+#endif
diff --git a/Source/WebKit/android/WebCoreSupport/WebRequest.cpp b/Source/WebKit/android/WebCoreSupport/WebRequest.cpp
new file mode 100644
index 0000000..a7321da
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/WebRequest.cpp
@@ -0,0 +1,531 @@
+/*
+ * 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 "WebRequest.h"
+
+#include "JNIUtility.h"
+#include "MainThread.h"
+#include "UrlInterceptResponse.h"
+#include "WebCoreFrameBridge.h"
+#include "WebRequestContext.h"
+#include "WebResourceRequest.h"
+#include "WebUrlLoaderClient.h"
+#include "jni.h"
+
+#include <cutils/log.h>
+#include <string>
+#include <utils/AssetManager.h>
+
+extern android::AssetManager* globalAssetManager();
+
+// TODO:
+// - Finish the file upload. Testcase is mobile buzz
+// - Add network throttle needed by Android plugins
+
+// TODO: Turn off asserts crashing before release
+// http://b/issue?id=2951985
+#undef ASSERT
+#define ASSERT(assertion, ...) do \
+ if (!(assertion)) { \
+ android_printLog(ANDROID_LOG_ERROR, __FILE__, __VA_ARGS__); \
+ } \
+while (0)
+
+namespace android {
+
+namespace {
+ const int kInitialReadBufSize = 32768;
+}
+
+WebRequest::WebRequest(WebUrlLoaderClient* loader, const WebResourceRequest& webResourceRequest)
+ : m_urlLoader(loader)
+ , m_androidUrl(false)
+ , m_url(webResourceRequest.url())
+ , m_userAgent(webResourceRequest.userAgent())
+ , m_loadState(Created)
+ , m_authRequestCount(0)
+ , m_cacheMode(0)
+ , m_runnableFactory(this)
+ , m_wantToPause(false)
+ , m_isPaused(false)
+ , m_isSync(false)
+{
+ GURL gurl(m_url);
+
+ m_request = new URLRequest(gurl, this);
+
+ m_request->SetExtraRequestHeaders(webResourceRequest.requestHeaders());
+ m_request->set_referrer(webResourceRequest.referrer());
+ m_request->set_method(webResourceRequest.method());
+ m_request->set_load_flags(webResourceRequest.loadFlags());
+}
+
+// This is a special URL for Android. Query the Java InputStream
+// for data and send to WebCore
+WebRequest::WebRequest(WebUrlLoaderClient* loader, const WebResourceRequest& webResourceRequest, UrlInterceptResponse* intercept)
+ : m_urlLoader(loader)
+ , m_interceptResponse(intercept)
+ , m_androidUrl(true)
+ , m_url(webResourceRequest.url())
+ , m_userAgent(webResourceRequest.userAgent())
+ , m_loadState(Created)
+ , m_authRequestCount(0)
+ , m_cacheMode(0)
+ , m_runnableFactory(this)
+ , m_wantToPause(false)
+ , m_isPaused(false)
+ , m_isSync(false)
+{
+}
+
+WebRequest::~WebRequest()
+{
+ ASSERT(m_loadState == Finished, "dtor called on a WebRequest in a different state than finished (%d)", m_loadState);
+
+ m_loadState = Deleted;
+}
+
+const std::string& WebRequest::getUrl() const
+{
+ return m_url;
+}
+
+const std::string& WebRequest::getUserAgent() const
+{
+ return m_userAgent;
+}
+
+#ifdef LOG_REQUESTS
+namespace {
+int remaining = 0;
+}
+#endif
+
+void WebRequest::finish(bool success)
+{
+ m_runnableFactory.RevokeAll();
+ ASSERT(m_loadState < Finished, "(%p) called finish on an already finished WebRequest (%d) (%s)", this, m_loadState, m_url.c_str());
+ if (m_loadState >= Finished)
+ return;
+#ifdef LOG_REQUESTS
+ time_t finish;
+ time(&finish);
+ finish = finish - m_startTime;
+ struct tm * timeinfo;
+ char buffer[80];
+ timeinfo = localtime(&finish);
+ strftime(buffer, 80, "Time: %M:%S",timeinfo);
+ android_printLog(ANDROID_LOG_DEBUG, "KM", "(%p) finish (%d) (%s) (%d) (%s)", this, --remaining, buffer, success, m_url.c_str());
+#endif
+
+ // Make sure WebUrlLoaderClient doesn't delete us in the middle of this method.
+ scoped_refptr<WebRequest> guard(this);
+
+ m_loadState = Finished;
+ if (success) {
+ m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(
+ m_urlLoader.get(), &WebUrlLoaderClient::didFinishLoading));
+ } else {
+ if (m_interceptResponse == NULL) {
+ OwnPtr<WebResponse> webResponse(new WebResponse(m_request.get()));
+ m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(
+ m_urlLoader.get(), &WebUrlLoaderClient::didFail, webResponse.release()));
+ } else {
+ OwnPtr<WebResponse> webResponse(new WebResponse(m_url, m_interceptResponse->mimeType(), 0,
+ m_interceptResponse->encoding(), m_interceptResponse->status()));
+ m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(
+ m_urlLoader.get(), &WebUrlLoaderClient::didFail, webResponse.release()));
+ }
+ }
+ m_networkBuffer = 0;
+ m_request = 0;
+ m_urlLoader = 0;
+}
+
+void WebRequest::appendFileToUpload(const std::string& filename)
+{
+ // AppendFileToUpload is only valid before calling start
+ ASSERT(m_loadState == Created, "appendFileToUpload called on a WebRequest not in CREATED state: (%s)", m_url.c_str());
+ FilePath filePath(filename);
+ m_request->AppendFileToUpload(filePath);
+}
+
+void WebRequest::appendBytesToUpload(WTF::Vector<char>* data)
+{
+ // AppendBytesToUpload is only valid before calling start
+ ASSERT(m_loadState == Created, "appendBytesToUpload called on a WebRequest not in CREATED state: (%s)", m_url.c_str());
+ m_request->AppendBytesToUpload(data->data(), data->size());
+ delete data;
+}
+
+void WebRequest::setRequestContext(WebRequestContext* context)
+{
+ m_cacheMode = context->getCacheMode();
+ if (m_request)
+ m_request->set_context(context);
+}
+
+void WebRequest::updateLoadFlags(int& loadFlags)
+{
+ if (m_cacheMode == 1) { // LOAD_CACHE_ELSE_NETWORK
+ loadFlags |= net::LOAD_PREFERRING_CACHE;
+ loadFlags &= ~net::LOAD_VALIDATE_CACHE;
+ }
+ if (m_cacheMode == 2) // LOAD_NO_CACHE
+ loadFlags |= net::LOAD_BYPASS_CACHE;
+ if (m_cacheMode == 3) // LOAD_CACHE_ONLY
+ loadFlags |= net::LOAD_ONLY_FROM_CACHE;
+
+ if (m_isSync)
+ loadFlags |= net::LOAD_IGNORE_LIMITS;
+}
+
+void WebRequest::start()
+{
+ ASSERT(m_loadState == Created, "Start called on a WebRequest not in CREATED state: (%s)", m_url.c_str());
+#ifdef LOG_REQUESTS
+ android_printLog(ANDROID_LOG_DEBUG, "KM", "(%p) start (%d) (%s)", this, ++remaining, m_url.c_str());
+ time(&m_startTime);
+#endif
+
+ m_loadState = Started;
+
+ if (m_interceptResponse != NULL)
+ return handleInterceptedURL();
+
+ // Handle data urls before we send it off to the http stack
+ if (m_request->url().SchemeIs("data"))
+ return handleDataURL(m_request->url());
+
+ if (m_request->url().SchemeIs("browser"))
+ return handleBrowserURL(m_request->url());
+
+ // Update load flags with settings from WebSettings
+ int loadFlags = m_request->load_flags();
+ updateLoadFlags(loadFlags);
+ m_request->set_load_flags(loadFlags);
+
+ m_request->Start();
+}
+
+void WebRequest::cancel()
+{
+ ASSERT(m_loadState >= Started, "Cancel called on a not started WebRequest: (%s)", m_url.c_str());
+ ASSERT(m_loadState != Cancelled, "Cancel called on an already cancelled WebRequest: (%s)", m_url.c_str());
+
+ // There is a possible race condition between the IO thread finishing the request and
+ // the WebCore thread cancelling it. If the request has already finished, do
+ // nothing to avoid sending duplicate finish messages to WebCore.
+ if (m_loadState > Cancelled) {
+ return;
+ }
+ ASSERT(m_request, "Request set to 0 before it is finished");
+
+ m_loadState = Cancelled;
+
+ m_request->Cancel();
+ finish(true);
+}
+
+void WebRequest::pauseLoad(bool pause)
+{
+ ASSERT(m_loadState >= GotData, "PauseLoad in state other than RESPONSE and GOTDATA");
+ if (pause) {
+ if (!m_isPaused)
+ m_wantToPause = true;
+ } else {
+ m_wantToPause = false;
+ if (m_isPaused) {
+ m_isPaused = false;
+ MessageLoop::current()->PostTask(FROM_HERE, m_runnableFactory.NewRunnableMethod(&WebRequest::startReading));
+ }
+ }
+}
+
+void WebRequest::handleInterceptedURL()
+{
+ m_loadState = Response;
+
+ const std::string& mime = m_interceptResponse->mimeType();
+ // Get the MIME type from the URL. "text/html" is a last resort, hopefully overridden.
+ std::string mimeType("text/html");
+ if (mime == "") {
+ // Gmail appends the MIME to the end of the URL, with a ? separator.
+ size_t mimeTypeIndex = m_url.find_last_of('?');
+ if (mimeTypeIndex != std::string::npos) {
+ mimeType.assign(m_url.begin() + mimeTypeIndex + 1, m_url.end());
+ } else {
+ // Get the MIME type from the file extension, if any.
+ FilePath path(m_url);
+ net::GetMimeTypeFromFile(path, &mimeType);
+ }
+ } else {
+ // Set from the intercept response.
+ mimeType = mime;
+ }
+
+
+ OwnPtr<WebResponse> webResponse(new WebResponse(m_url, mimeType, 0, m_interceptResponse->encoding(), m_interceptResponse->status()));
+ m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(
+ m_urlLoader.get(), &WebUrlLoaderClient::didReceiveResponse, webResponse.release()));
+
+ do {
+ // data is deleted in WebUrlLoaderClient::didReceiveAndroidFileData
+ // data is sent to the webcore thread
+ OwnPtr<std::vector<char> > data(new std::vector<char>);
+ data->reserve(kInitialReadBufSize);
+
+ // Read returns false on error and size of 0 on eof.
+ if (!m_interceptResponse->readStream(data.get()) || data->size() == 0)
+ break;
+
+ m_loadState = GotData;
+ m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(
+ m_urlLoader.get(), &WebUrlLoaderClient::didReceiveAndroidFileData, data.release()));
+ } while (true);
+
+ finish(m_interceptResponse->status() == 200);
+}
+
+void WebRequest::handleDataURL(GURL url)
+{
+ OwnPtr<std::string> data(new std::string);
+ std::string mimeType;
+ std::string charset;
+
+ if (net::DataURL::Parse(url, &mimeType, &charset, data.get())) {
+ // PopulateURLResponse from chrome implementation
+ // weburlloader_impl.cc
+ m_loadState = Response;
+ OwnPtr<WebResponse> webResponse(new WebResponse(url.spec(), mimeType, data->size(), charset, 200));
+ m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(
+ m_urlLoader.get(), &WebUrlLoaderClient::didReceiveResponse, webResponse.release()));
+
+ if (!data->empty()) {
+ m_loadState = GotData;
+ m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(
+ m_urlLoader.get(), &WebUrlLoaderClient::didReceiveDataUrl, data.release()));
+ }
+ } else {
+ // handle the failed case
+ }
+
+ finish(true);
+}
+
+void WebRequest::handleBrowserURL(GURL url)
+{
+ std::string data("data:text/html;charset=utf-8,");
+ if (url.spec() == "browser:incognito") {
+ AssetManager* assetManager = globalAssetManager();
+ Asset* asset = assetManager->open("webkit/incognito_mode_start_page.html", Asset::ACCESS_BUFFER);
+ if (asset) {
+ data.append((const char*)asset->getBuffer(false), asset->getLength());
+ delete asset;
+ }
+ }
+ GURL dataURL(data.c_str());
+ handleDataURL(dataURL);
+}
+
+// Called upon a server-initiated redirect. The delegate may call the
+// request's Cancel method to prevent the redirect from being followed.
+// Since there may be multiple chained redirects, there may also be more
+// than one redirect call.
+//
+// When this function is called, the request will still contain the
+// original URL, the destination of the redirect is provided in 'new_url'.
+// If the delegate does not cancel the request and |*defer_redirect| is
+// false, then the redirect will be followed, and the request's URL will be
+// changed to the new URL. Otherwise if the delegate does not cancel the
+// request and |*defer_redirect| is true, then the redirect will be
+// followed once FollowDeferredRedirect is called on the URLRequest.
+//
+// The caller must set |*defer_redirect| to false, so that delegates do not
+// need to set it if they are happy with the default behavior of not
+// deferring redirect.
+void WebRequest::OnReceivedRedirect(URLRequest* newRequest, const GURL& newUrl, bool* deferRedirect)
+{
+ ASSERT(m_loadState < Response, "Redirect after receiving response");
+ ASSERT(newRequest && newRequest->status().is_success(), "Invalid redirect");
+
+ OwnPtr<WebResponse> webResponse(new WebResponse(newRequest));
+ webResponse->setUrl(newUrl.spec());
+ m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(
+ m_urlLoader.get(), &WebUrlLoaderClient::willSendRequest, webResponse.release()));
+
+ // Defer the redirect until followDeferredRedirect() is called.
+ *deferRedirect = true;
+}
+
+// Called when we receive an authentication failure. The delegate should
+// call request->SetAuth() with the user's credentials once it obtains them,
+// or request->CancelAuth() to cancel the login and display the error page.
+// When it does so, the request will be reissued, restarting the sequence
+// of On* callbacks.
+void WebRequest::OnAuthRequired(URLRequest* request, net::AuthChallengeInfo* authInfo)
+{
+ ASSERT(m_loadState == Started, "OnAuthRequired called on a WebRequest not in STARTED state (state=%d)", m_loadState);
+
+ scoped_refptr<net::AuthChallengeInfo> authInfoPtr(authInfo);
+ bool firstTime = (m_authRequestCount == 0);
+ ++m_authRequestCount;
+
+ m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(
+ m_urlLoader.get(), &WebUrlLoaderClient::authRequired, authInfoPtr, firstTime));
+}
+
+// Called when we received an SSL certificate error. The delegate will provide
+// the user the options to proceed, cancel, or view certificates.
+void WebRequest::OnSSLCertificateError(URLRequest* request, int cert_error, net::X509Certificate* cert)
+{
+ m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(
+ m_urlLoader.get(), &WebUrlLoaderClient::reportSslCertError, cert_error, cert));
+}
+
+// After calling Start(), the delegate will receive an OnResponseStarted
+// callback when the request has completed. If an error occurred, the
+// request->status() will be set. On success, all redirects have been
+// followed and the final response is beginning to arrive. At this point,
+// meta data about the response is available, including for example HTTP
+// response headers if this is a request for a HTTP resource.
+void WebRequest::OnResponseStarted(URLRequest* request)
+{
+ ASSERT(m_loadState == Started, "Got response after receiving response");
+
+ m_loadState = Response;
+ if (request && request->status().is_success()) {
+ OwnPtr<WebResponse> webResponse(new WebResponse(request));
+ m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(
+ m_urlLoader.get(), &WebUrlLoaderClient::didReceiveResponse, webResponse.release()));
+
+ // Start reading the response
+ startReading();
+ } else {
+ finish(false);
+ }
+}
+
+void WebRequest::setAuth(const string16& username, const string16& password)
+{
+ ASSERT(m_loadState == Started, "setAuth called on a WebRequest not in STARTED state (state=%d)", m_loadState);
+
+ m_request->SetAuth(username, password);
+}
+
+void WebRequest::cancelAuth()
+{
+ ASSERT(m_loadState == Started, "cancelAuth called on a WebRequest not in STARTED state (state=%d)", m_loadState);
+
+ m_request->CancelAuth();
+}
+
+void WebRequest::followDeferredRedirect()
+{
+ ASSERT(m_loadState < Response, "Redirect after receiving response");
+
+ m_request->FollowDeferredRedirect();
+}
+
+void WebRequest::proceedSslCertError()
+{
+ m_request->ContinueDespiteLastError();
+}
+
+void WebRequest::cancelSslCertError(int cert_error)
+{
+ m_request->SimulateError(cert_error);
+}
+
+void WebRequest::startReading()
+{
+ ASSERT(m_networkBuffer == 0, "startReading called with a nonzero buffer");
+ ASSERT(m_isPaused == 0, "startReading called in paused state");
+ ASSERT(m_loadState == Response || m_loadState == GotData, "StartReading in state other than RESPONSE and GOTDATA");
+ if (m_loadState > GotData) // We have been cancelled between reads
+ return;
+
+ if (m_wantToPause) {
+ m_isPaused = true;
+ return;
+ }
+
+ int bytesRead = 0;
+
+ if (!read(&bytesRead)) {
+ if (m_request && m_request->status().is_io_pending())
+ return; // Wait for OnReadCompleted()
+ return finish(false);
+ }
+
+ // bytesRead == 0 indicates finished
+ if (!bytesRead)
+ return finish(true);
+
+ m_loadState = GotData;
+ // Read ok, forward buffer to webcore
+ m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(m_urlLoader.get(), &WebUrlLoaderClient::didReceiveData, m_networkBuffer, bytesRead));
+ m_networkBuffer = 0;
+ MessageLoop::current()->PostTask(FROM_HERE, m_runnableFactory.NewRunnableMethod(&WebRequest::startReading));
+}
+
+bool WebRequest::read(int* bytesRead)
+{
+ ASSERT(m_loadState == Response || m_loadState == GotData, "read in state other than RESPONSE and GOTDATA");
+ ASSERT(m_networkBuffer == 0, "Read called with a nonzero buffer");
+
+ // TODO: when asserts work, check that the buffer is 0 here
+ m_networkBuffer = new net::IOBuffer(kInitialReadBufSize);
+ return m_request->Read(m_networkBuffer, kInitialReadBufSize, bytesRead);
+}
+
+// This is called when there is data available
+
+// Called when the a Read of the response body is completed after an
+// IO_PENDING status from a Read() call.
+// The data read is filled into the buffer which the caller passed
+// to Read() previously.
+//
+// If an error occurred, request->status() will contain the error,
+// and bytes read will be -1.
+void WebRequest::OnReadCompleted(URLRequest* request, int bytesRead)
+{
+ ASSERT(m_loadState == Response || m_loadState == GotData, "OnReadCompleted in state other than RESPONSE and GOTDATA");
+
+ if (request->status().is_success()) {
+ m_loadState = GotData;
+ m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(
+ m_urlLoader.get(), &WebUrlLoaderClient::didReceiveData, m_networkBuffer, bytesRead));
+ m_networkBuffer = 0;
+
+ // Get the rest of the data
+ startReading();
+ } else {
+ finish(false);
+ }
+}
+
+} // namespace android
diff --git a/Source/WebKit/android/WebCoreSupport/WebRequest.h b/Source/WebKit/android/WebCoreSupport/WebRequest.h
new file mode 100644
index 0000000..252267b
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/WebRequest.h
@@ -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.
+ */
+
+#ifndef WebRequest_h
+#define WebRequest_h
+
+#include "ChromiumIncludes.h"
+#include <wtf/Vector.h>
+
+class MessageLoop;
+
+namespace android {
+
+enum LoadState {
+ Created,
+ Started,
+ Response,
+ GotData,
+ Cancelled,
+ Finished,
+ Deleted
+};
+
+class UrlInterceptResponse;
+class WebFrame;
+class WebRequestContext;
+class WebResourceRequest;
+class WebUrlLoaderClient;
+
+// All methods in this class must be called on the io thread
+class WebRequest : public URLRequest::Delegate, public base::RefCountedThreadSafe<WebRequest> {
+public:
+ WebRequest(WebUrlLoaderClient*, const WebResourceRequest&);
+
+ // If this is an android specific url or the application wants to load
+ // custom data, we load the data through an input stream.
+ // Used for:
+ // - file:///android_asset
+ // - file:///android_res
+ // - content://
+ WebRequest(WebUrlLoaderClient*, const WebResourceRequest&, UrlInterceptResponse* intercept);
+
+ // Optional, but if used has to be called before start
+ void appendBytesToUpload(Vector<char>* data);
+ void appendFileToUpload(const std::string& filename);
+
+ void setRequestContext(WebRequestContext* context);
+ void start();
+ void cancel();
+ void pauseLoad(bool pause);
+
+ // From URLRequest::Delegate
+ virtual void OnReceivedRedirect(URLRequest*, const GURL&, bool* deferRedirect);
+ virtual void OnResponseStarted(URLRequest*);
+ virtual void OnReadCompleted(URLRequest*, int bytesRead);
+ virtual void OnAuthRequired(URLRequest*, net::AuthChallengeInfo*);
+ virtual void OnSSLCertificateError(URLRequest* request, int cert_error, net::X509Certificate* cert);
+
+ // Methods called during a request by the UI code (via WebUrlLoaderClient).
+ void setAuth(const string16& username, const string16& password);
+ void cancelAuth();
+ void followDeferredRedirect();
+ void proceedSslCertError();
+ void cancelSslCertError(int cert_error);
+
+ const std::string& getUrl() const;
+ const std::string& getUserAgent() const;
+
+ void setSync(bool sync) { m_isSync = sync; }
+private:
+ void startReading();
+ bool read(int* bytesRead);
+
+ friend class base::RefCountedThreadSafe<WebRequest>;
+ virtual ~WebRequest();
+ void handleDataURL(GURL);
+ void handleBrowserURL(GURL);
+ void handleInterceptedURL();
+ void finish(bool success);
+ void updateLoadFlags(int& loadFlags);
+
+ scoped_refptr<WebUrlLoaderClient> m_urlLoader;
+ OwnPtr<URLRequest> m_request;
+ scoped_refptr<net::IOBuffer> m_networkBuffer;
+ scoped_ptr<UrlInterceptResponse> m_interceptResponse;
+ bool m_androidUrl;
+ std::string m_url;
+ std::string m_userAgent;
+ LoadState m_loadState;
+ int m_authRequestCount;
+ int m_cacheMode;
+ ScopedRunnableMethodFactory<WebRequest> m_runnableFactory;
+ bool m_wantToPause;
+ bool m_isPaused;
+ bool m_isSync;
+#ifdef LOG_REQUESTS
+ time_t m_startTime;
+#endif
+};
+
+} // namespace android
+
+#endif
diff --git a/Source/WebKit/android/WebCoreSupport/WebRequestContext.cpp b/Source/WebKit/android/WebCoreSupport/WebRequestContext.cpp
new file mode 100644
index 0000000..78c3501
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/WebRequestContext.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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 "WebRequestContext.h"
+
+#include "ChromiumIncludes.h"
+#include "ChromiumInit.h"
+#include "WebCache.h"
+#include "WebCookieJar.h"
+
+#include <wtf/text/CString.h>
+
+static std::string acceptLanguageStdString("");
+static WTF::String acceptLanguageWtfString("");
+static WTF::Mutex acceptLanguageMutex;
+
+static int numPrivateBrowsingInstances;
+
+extern void ANPSystemInterface_CleanupIncognito();
+
+using namespace WTF;
+
+namespace android {
+
+WebRequestContext::WebRequestContext(bool isPrivateBrowsing)
+ : m_isPrivateBrowsing(isPrivateBrowsing)
+{
+ // Initialize chromium logging, needs to be done before any chromium code is called.
+ initChromium();
+
+ if (m_isPrivateBrowsing) {
+ // Delete the old files if this is the first private browsing instance
+ // They are probably leftovers from a power cycle
+ // We do not need to clear the cache as it is in memory only for private browsing
+ if (!numPrivateBrowsingInstances)
+ WebCookieJar::cleanup(true);
+ numPrivateBrowsingInstances++;
+ }
+
+ WebCache* cache = WebCache::get(m_isPrivateBrowsing);
+ host_resolver_ = cache->hostResolver();
+ http_transaction_factory_ = cache->cache();
+
+ WebCookieJar* cookieJar = WebCookieJar::get(m_isPrivateBrowsing);
+ cookie_store_ = cookieJar->cookieStore();
+ cookie_policy_ = cookieJar;
+
+ // Also hardcoded in FrameLoader.java
+ accept_charset_ = "utf-8, iso-8859-1, utf-16, *;q=0.7";
+}
+
+WebRequestContext::~WebRequestContext()
+{
+ if (m_isPrivateBrowsing) {
+ numPrivateBrowsingInstances--;
+
+ // This is the last private browsing context, delete the cookies and cache
+ if (!numPrivateBrowsingInstances) {
+ WebCookieJar::cleanup(true);
+ WebCache::cleanup(true);
+ ANPSystemInterface_CleanupIncognito();
+ }
+ }
+}
+
+void WebRequestContext::setUserAgent(const String& string)
+{
+ MutexLocker lock(m_userAgentMutex);
+ m_userAgent = string.utf8().data();
+}
+
+void WebRequestContext::setCacheMode(int mode)
+{
+ m_cacheMode = mode;
+}
+
+int WebRequestContext::getCacheMode()
+{
+ return m_cacheMode;
+}
+
+const std::string& WebRequestContext::GetUserAgent(const GURL& url) const
+{
+ MutexLocker lock(m_userAgentMutex);
+ return m_userAgent;
+}
+
+void WebRequestContext::setAcceptLanguage(const String& string)
+{
+ MutexLocker lock(acceptLanguageMutex);
+ acceptLanguageStdString = string.utf8().data();
+ acceptLanguageWtfString = string;
+}
+
+const std::string& WebRequestContext::GetAcceptLanguage() const
+{
+ MutexLocker lock(acceptLanguageMutex);
+ return acceptLanguageStdString;
+}
+
+const String& WebRequestContext::acceptLanguage()
+{
+ MutexLocker lock(acceptLanguageMutex);
+ return acceptLanguageWtfString;
+}
+
+} // namespace android
diff --git a/Source/WebKit/android/WebCoreSupport/WebRequestContext.h b/Source/WebKit/android/WebCoreSupport/WebRequestContext.h
new file mode 100644
index 0000000..51f0514
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/WebRequestContext.h
@@ -0,0 +1,64 @@
+/*
+ * 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 WebRequestContext_h
+#define WebRequestContext_h
+
+#include "ChromiumIncludes.h"
+#include "PlatformString.h"
+
+#include <wtf/ThreadingPrimitives.h>
+
+namespace android {
+
+// This class is generally not threadsafe.
+class WebRequestContext : public URLRequestContext {
+public:
+ // URLRequestContext overrides.
+ virtual const std::string& GetUserAgent(const GURL&) const;
+ virtual const std::string& GetAcceptLanguage() const;
+
+ WebRequestContext(bool isPrivateBrowsing);
+
+ // These methods are threadsafe.
+ void setUserAgent(const WTF::String&);
+ void setCacheMode(int);
+ int getCacheMode();
+ static void setAcceptLanguage(const WTF::String&);
+ static const WTF::String& acceptLanguage();
+
+private:
+ WebRequestContext();
+ ~WebRequestContext();
+
+ std::string m_userAgent;
+ int m_cacheMode;
+ mutable WTF::Mutex m_userAgentMutex;
+ bool m_isPrivateBrowsing;
+};
+
+} // namespace android
+
+#endif
diff --git a/Source/WebKit/android/WebCoreSupport/WebResourceRequest.cpp b/Source/WebKit/android/WebCoreSupport/WebResourceRequest.cpp
new file mode 100644
index 0000000..9b70fce
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/WebResourceRequest.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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 "WebResourceRequest.h"
+
+#include "ResourceRequest.h"
+
+#include <wtf/text/CString.h>
+
+using namespace WebCore;
+
+namespace android {
+
+WebResourceRequest::WebResourceRequest(const WebCore::ResourceRequest& resourceRequest)
+{
+ // Set the load flags based on the WebCore request.
+ m_loadFlags = net::LOAD_NORMAL;
+ switch (resourceRequest.cachePolicy()) {
+ case ReloadIgnoringCacheData:
+ m_loadFlags |= net::LOAD_VALIDATE_CACHE;
+ break;
+ case ReturnCacheDataElseLoad:
+ m_loadFlags |= net::LOAD_PREFERRING_CACHE;
+ break;
+ case ReturnCacheDataDontLoad:
+ m_loadFlags |= net::LOAD_ONLY_FROM_CACHE;
+ break;
+ case UseProtocolCachePolicy:
+ break;
+ }
+
+ // TODO: We should consider setting these flags and net::LOAD_DO_NOT_SEND_AUTH_DATA
+ // when FrameLoaderClient::shouldUseCredentialStorage() is false. However,
+ // the required WebKit logic is not yet in place. See Chromium's
+ // FrameLoaderClientImpl::shouldUseCredentialStorage().
+ if (!resourceRequest.allowCookies()) {
+ m_loadFlags |= net::LOAD_DO_NOT_SAVE_COOKIES;
+ m_loadFlags |= net::LOAD_DO_NOT_SEND_COOKIES;
+ }
+
+
+ // Set the request headers
+ const HTTPHeaderMap& map = resourceRequest.httpHeaderFields();
+ for (HTTPHeaderMap::const_iterator it = map.begin(); it != map.end(); ++it) {
+ const std::string& nameUtf8 = it->first.string().utf8().data();
+ const std::string& valueUtf8 = it->second.utf8().data();
+
+ // 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 (LowerCaseEqualsASCII(nameUtf8, "referer") || LowerCaseEqualsASCII(nameUtf8, "user-agent"))
+ continue;
+
+ // Skip over "Cache-Control: max-age=0" header if the corresponding
+ // load flag is already specified. FrameLoader sets both the flag and
+ // the extra header -- the extra header is redundant since our network
+ // implementation will add the necessary headers based on load flags.
+ // See http://code.google.com/p/chromium/issues/detail?id=3434.
+ if ((m_loadFlags & net::LOAD_VALIDATE_CACHE) &&
+ LowerCaseEqualsASCII(nameUtf8, "cache-control") && LowerCaseEqualsASCII(valueUtf8, "max-age=0"))
+ continue;
+
+ m_requestHeaders.SetHeader(nameUtf8, valueUtf8);
+ }
+
+ m_method = resourceRequest.httpMethod().utf8().data();
+ m_referrer = resourceRequest.httpReferrer().utf8().data();
+ m_userAgent = resourceRequest.httpUserAgent().utf8().data();
+
+ m_url = resourceRequest.url().string().utf8().data();
+}
+
+} // namespace android
diff --git a/Source/WebKit/android/WebCoreSupport/WebResourceRequest.h b/Source/WebKit/android/WebCoreSupport/WebResourceRequest.h
new file mode 100644
index 0000000..38f37b5
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/WebResourceRequest.h
@@ -0,0 +1,86 @@
+/*
+ * 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 WebResourceRequest_h
+#define WebResourceRequest_h
+
+#include "ChromiumIncludes.h"
+
+#include <string>
+
+namespace WebCore {
+class ResourceRequest;
+}
+
+namespace android {
+
+class WebResourceRequest {
+
+public:
+ WebResourceRequest(const WebCore::ResourceRequest&);
+
+ const std::string& method() const
+ {
+ return m_method;
+ }
+
+ const std::string& referrer() const
+ {
+ return m_referrer;
+ }
+
+ const std::string& userAgent() const
+ {
+ return m_userAgent;
+ }
+
+ const net::HttpRequestHeaders& requestHeaders() const
+ {
+ return m_requestHeaders;
+ }
+
+ const std::string& url() const
+ {
+ return m_url;
+ }
+
+ int loadFlags() const
+ {
+ return m_loadFlags;
+ }
+
+private:
+ std::string m_method;
+ std::string m_referrer;
+ std::string m_userAgent;
+ net::HttpRequestHeaders m_requestHeaders;
+ std::string m_url;
+ int m_loadFlags;
+};
+
+} // namespace android
+
+
+#endif
diff --git a/Source/WebKit/android/WebCoreSupport/WebResponse.cpp b/Source/WebKit/android/WebCoreSupport/WebResponse.cpp
new file mode 100644
index 0000000..4d297d7
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/WebResponse.cpp
@@ -0,0 +1,167 @@
+/*
+ * 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 "WebResponse.h"
+
+#include "MIMETypeRegistry.h"
+#include "PlatformString.h"
+#include "ResourceResponse.h"
+#include "ResourceError.h"
+
+#include <wtf/text/CString.h>
+
+using namespace std;
+
+namespace android {
+
+WebResponse::WebResponse(URLRequest* request)
+ : m_httpStatusCode(0)
+{
+ // The misleadingly-named os_error() is actually a net::Error enum constant.
+ m_error = net::Error(request->status().os_error());
+
+ m_url = request->url().spec();
+ m_host = request->url().HostNoBrackets();
+ request->GetMimeType(&m_mime);
+
+ request->GetCharset(&m_encoding);
+ m_expectedSize = request->GetExpectedContentSize();
+
+ m_sslInfo = request->ssl_info();
+
+ net::HttpResponseHeaders* responseHeaders = request->response_headers();
+ if (!responseHeaders)
+ return;
+
+ m_httpStatusCode = responseHeaders->response_code();
+ m_httpStatusText = responseHeaders->GetStatusText();
+
+ string value;
+ string name;
+ void* iter = 0;
+ while (responseHeaders->EnumerateHeaderLines(&iter, &name, &value))
+ m_headerFields[name] = value;
+}
+
+WebResponse::WebResponse(const string &url, const string &mimeType, long long expectedSize, const string &encoding, int httpStatusCode)
+ : m_error(net::OK)
+ , m_encoding(encoding)
+ , m_httpStatusCode(httpStatusCode)
+ , m_expectedSize(expectedSize)
+ , m_mime(mimeType)
+ , m_url(url)
+{
+}
+
+WebCore::ResourceResponse WebResponse::createResourceResponse()
+{
+ WebCore::ResourceResponse resourceResponse(createKurl(), getMimeType().c_str(), m_expectedSize, m_encoding.c_str(), "");
+ resourceResponse.setHTTPStatusCode(m_httpStatusCode);
+ resourceResponse.setHTTPStatusText(m_httpStatusText.c_str());
+
+ map<string, string>::const_iterator it;
+ for (it = m_headerFields.begin(); it != m_headerFields.end(); ++it)
+ resourceResponse.setHTTPHeaderField(it->first.c_str(), it->second.c_str());
+
+ return resourceResponse;
+}
+
+WebCore::ResourceError WebResponse::createResourceError()
+{
+ WebCore::ResourceError error(m_host.c_str(), ToWebViewClientError(m_error), m_url.c_str(), WTF::String());
+ return error;
+}
+
+
+WebCore::KURL WebResponse::createKurl()
+{
+ WebCore::KURL kurl(WebCore::ParsedURLString, m_url.c_str());
+ return kurl;
+}
+
+const string& WebResponse::getUrl() const
+{
+ return m_url;
+}
+
+void WebResponse::setUrl(const string& url)
+{
+ m_url = url;
+}
+
+// Calls WebCore APIs so should only be called from the WebCore thread.
+// TODO: can we return a WTF::String directly? Need to check all callsites.
+const string& WebResponse::getMimeType()
+{
+ if (!m_url.length())
+ return m_mime;
+
+ if (!m_mime.length() || !m_mime.compare("text/plain") || !m_mime.compare("application/octet-stream"))
+ m_mime = resolveMimeType(m_url, m_mime);
+
+ return m_mime;
+}
+
+const string WebResponse::resolveMimeType(const string& url, const string& old_mime)
+{
+ // Use "text/html" as a default (matching the behaviour of the Apache
+ // HTTP stack -- see guessMimeType() in LoadListener.java).
+ string mimeType = old_mime.length() ? old_mime : "text/html";
+ // Try to guess a better MIME type from the URL. We call
+ // getMIMETypeForExtension rather than getMIMETypeForPath because the
+ // latter defaults to "application/octet-stream" on failure.
+ WebCore::KURL kurl(WebCore::ParsedURLString, url.c_str());
+ WTF::String path = kurl.path();
+ size_t extensionPos = path.reverseFind('.');
+ if (extensionPos != WTF::notFound) {
+ // We found a file extension.
+ path.remove(0, extensionPos + 1);
+ // TODO: Should use content-disposition instead of url if it is there
+ WTF::String mime = WebCore::MIMETypeRegistry::getMIMETypeForExtension(path);
+ if (!mime.isEmpty()) {
+ // Great, we found a MIME type.
+ mimeType = std::string(mime.utf8().data(), mime.length());
+ }
+ }
+ return mimeType;
+}
+
+bool WebResponse::getHeader(const string& header, string* result) const
+{
+ map<string, string>::const_iterator iter = m_headerFields.find(header);
+ if (iter == m_headerFields.end())
+ return false;
+ if (result)
+ *result = iter->second;
+ return true;
+}
+
+long long WebResponse::getExpectedSize() const
+{
+ return m_expectedSize;
+}
+
+} // namespace android
diff --git a/Source/WebKit/android/WebCoreSupport/WebResponse.h b/Source/WebKit/android/WebCoreSupport/WebResponse.h
new file mode 100644
index 0000000..88c8917
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/WebResponse.h
@@ -0,0 +1,91 @@
+/*
+ * 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 WebResponse_h
+#define WebResponse_h
+
+#include "ChromiumIncludes.h"
+#include "KURL.h"
+#include "WebViewClientError.h"
+
+#include <map>
+#include <string>
+
+namespace WebCore {
+class ResourceResponse;
+class ResourceError;
+}
+
+namespace android {
+
+class WebResponse {
+
+public:
+ WebResponse() {}
+ WebResponse(URLRequest*);
+ WebResponse(const std::string &url, const std::string &mimeType, long long expectedSize, const std::string &encoding, int httpStatusCode);
+
+ const std::string& getUrl() const;
+ void setUrl(const std::string&);
+
+ const std::string& getMimeType(); // Use only on WebCore thread.
+ bool getHeader(const std::string& header, std::string* result) const;
+ long long getExpectedSize() const;
+
+ const net::SSLInfo& getSslInfo() const { return m_sslInfo; }
+
+ // The create() methods create WebCore objects. They must only be called on the WebKit thread.
+ WebCore::KURL createKurl();
+ WebCore::ResourceResponse createResourceResponse();
+ WebCore::ResourceError createResourceError();
+
+ static const std::string resolveMimeType(const std::string& url, const std::string& old_mime);
+
+private:
+ net::Error m_error;
+ std::string m_encoding;
+ int m_httpStatusCode;
+ std::string m_host;
+ std::string m_httpStatusText;
+ long long m_expectedSize;
+ std::string m_mime;
+ std::string m_url;
+ net::SSLInfo m_sslInfo;
+
+ struct CaseInsensitiveLessThan {
+ bool operator()(const std::string& lhs, const std::string& rhs) const {
+ return strcasecmp(lhs.c_str(), rhs.c_str()) < 0;
+ }
+ };
+
+ // Header fields are case insensitive, so we use a case-insensitive map.
+ // See RFC 822, 3.4.7, "CASE INDEPENDENCE".
+ std::map<std::string, std::string, CaseInsensitiveLessThan> m_headerFields;
+
+};
+
+} // namespace android
+
+#endif
diff --git a/Source/WebKit/android/WebCoreSupport/WebUrlLoader.cpp b/Source/WebKit/android/WebCoreSupport/WebUrlLoader.cpp
new file mode 100644
index 0000000..0c90bc5
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/WebUrlLoader.cpp
@@ -0,0 +1,87 @@
+/*
+ * 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 "WebUrlLoader.h"
+
+#include "FrameLoaderClientAndroid.h"
+#include "WebCoreFrameBridge.h"
+#include "WebUrlLoaderClient.h"
+
+namespace android {
+
+// on main thread
+WebUrlLoader::WebUrlLoader(WebFrame* webFrame, WebCore::ResourceHandle* resourceHandle, const WebCore::ResourceRequest& resourceRequest)
+{
+ m_loaderClient = new WebUrlLoaderClient(webFrame, resourceHandle, resourceRequest);
+}
+
+// on main thread
+WebUrlLoader::~WebUrlLoader()
+{
+}
+
+PassRefPtr<WebUrlLoader> WebUrlLoader::start(FrameLoaderClient* client, WebCore::ResourceHandle* resourceHandle,
+ const WebCore::ResourceRequest& resourceRequest, bool isMainResource, bool isMainFrame, bool isSync, WebRequestContext* context)
+{
+ FrameLoaderClientAndroid* androidClient = static_cast<FrameLoaderClientAndroid*>(client);
+ WebFrame* webFrame = androidClient->webFrame();
+
+ if (webFrame->blockNetworkLoads() &&
+ (resourceRequest.url().protocolIs("http") ||
+ resourceRequest.url().protocolIs("https")))
+ return NULL;
+
+ webFrame->maybeSavePassword(androidClient->getFrame(), resourceRequest);
+
+ RefPtr<WebUrlLoader> loader = WebUrlLoader::create(webFrame, resourceHandle, resourceRequest);
+ loader->m_loaderClient->start(isMainResource, isMainFrame, isSync, context);
+
+ return loader.release();
+}
+
+PassRefPtr<WebUrlLoader> WebUrlLoader::create(WebFrame* webFrame, WebCore::ResourceHandle* resourceHandle, const WebCore::ResourceRequest& resourceRequest)
+{
+ return adoptRef(new WebUrlLoader(webFrame, resourceHandle, resourceRequest));
+}
+
+// on main thread
+void WebUrlLoader::cancel()
+{
+ m_loaderClient->cancel();
+}
+
+void WebUrlLoader::downloadFile()
+{
+ m_loaderClient->downloadFile();
+}
+
+void WebUrlLoader::pauseLoad(bool pause)
+{
+ m_loaderClient->pauseLoad(pause);
+}
+
+} // namespace android
diff --git a/Source/WebKit/android/WebCoreSupport/WebUrlLoader.h b/Source/WebKit/android/WebCoreSupport/WebUrlLoader.h
new file mode 100644
index 0000000..dd88e73
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/WebUrlLoader.h
@@ -0,0 +1,57 @@
+/*
+ * 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 WebUrlLoader_h
+#define WebUrlLoader_h
+
+#include "ChromiumIncludes.h"
+#include "ResourceLoaderAndroid.h"
+
+using namespace WebCore;
+
+namespace android {
+class WebUrlLoaderClient;
+class WebFrame;
+class WebRequestContext;
+
+class WebUrlLoader : public ResourceLoaderAndroid {
+public:
+ virtual ~WebUrlLoader();
+ static PassRefPtr<WebUrlLoader> start(FrameLoaderClient* client, WebCore::ResourceHandle*, const WebCore::ResourceRequest&, bool isMainResource, bool isMainFrame, bool sync, WebRequestContext*);
+
+ virtual void cancel();
+ virtual void downloadFile();
+ virtual void pauseLoad(bool pause);
+
+private:
+ WebUrlLoader(WebFrame*, WebCore::ResourceHandle*, const WebCore::ResourceRequest&);
+ static PassRefPtr<WebUrlLoader> create(WebFrame*, WebCore::ResourceHandle*, const WebCore::ResourceRequest&);
+
+ scoped_refptr<WebUrlLoaderClient> m_loaderClient;
+};
+
+} // namespace android
+
+#endif
diff --git a/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp b/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp
new file mode 100644
index 0000000..cf218e7
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp
@@ -0,0 +1,482 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "WebUrlLoaderClient"
+
+#include "config.h"
+#include "WebUrlLoaderClient.h"
+
+#include "ChromiumIncludes.h"
+#include "OwnPtr.h"
+#include "ResourceHandle.h"
+#include "ResourceHandleClient.h"
+#include "ResourceResponse.h"
+#include "WebCoreFrameBridge.h"
+#include "WebRequest.h"
+#include "WebResourceRequest.h"
+
+#include <wtf/text/CString.h>
+
+namespace android {
+
+base::Thread* WebUrlLoaderClient::ioThread()
+{
+ static base::Thread* networkThread = 0;
+ static Lock networkThreadLock;
+
+ // Multiple threads appear to access the ioThread so we must ensure the
+ // critical section ordering.
+ AutoLock lock(networkThreadLock);
+
+ if (!networkThread)
+ networkThread = new base::Thread("network");
+
+ if (!networkThread)
+ return 0;
+
+ if (networkThread->IsRunning())
+ return networkThread;
+
+ base::Thread::Options options;
+ options.message_loop_type = MessageLoop::TYPE_IO;
+ if (!networkThread->StartWithOptions(options)) {
+ delete networkThread;
+ networkThread = 0;
+ }
+
+ return networkThread;
+}
+
+Lock* WebUrlLoaderClient::syncLock() {
+ static Lock s_syncLock;
+ return &s_syncLock;
+}
+
+ConditionVariable* WebUrlLoaderClient::syncCondition() {
+ static ConditionVariable s_syncCondition(syncLock());
+ return &s_syncCondition;
+}
+
+WebUrlLoaderClient::~WebUrlLoaderClient()
+{
+}
+
+bool WebUrlLoaderClient::isActive() const
+{
+ if (m_cancelling)
+ return false;
+ if (!m_resourceHandle)
+ return false;
+ if (!m_resourceHandle->client())
+ return false;
+ if (m_finished)
+ return false;
+
+ return true;
+}
+
+WebUrlLoaderClient::WebUrlLoaderClient(WebFrame* webFrame, WebCore::ResourceHandle* resourceHandle, const WebCore::ResourceRequest& resourceRequest)
+ : m_webFrame(webFrame)
+ , m_resourceHandle(resourceHandle)
+ , m_isMainResource(false)
+ , m_isMainFrame(false)
+ , m_isCertMimeType(false)
+ , m_cancelling(false)
+ , m_sync(false)
+ , m_finished(false)
+{
+ WebResourceRequest webResourceRequest(resourceRequest);
+ UrlInterceptResponse* intercept = webFrame->shouldInterceptRequest(resourceRequest.url().string());
+ if (intercept) {
+ m_request = new WebRequest(this, webResourceRequest, intercept);
+ return;
+ }
+
+ m_request = new WebRequest(this, webResourceRequest);
+
+ // Set uploads before start is called on the request
+ if (resourceRequest.httpBody() && !(webResourceRequest.method() == "GET" || webResourceRequest.method() == "HEAD")) {
+ Vector<FormDataElement>::iterator iter;
+ Vector<FormDataElement> elements = resourceRequest.httpBody()->elements();
+ for (iter = elements.begin(); iter != elements.end(); iter++) {
+ FormDataElement element = *iter;
+
+ switch (element.m_type) {
+ case FormDataElement::data:
+ if (!element.m_data.isEmpty()) {
+ // WebKit sometimes gives up empty data to append. These aren't
+ // necessary so we just optimize those out here.
+ base::Thread* thread = ioThread();
+ if (thread) {
+ Vector<char>* data = new Vector<char>(element.m_data);
+ thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::appendBytesToUpload, data));
+ }
+ }
+ break;
+ case FormDataElement::encodedFile:
+ {
+ // Chromium check if it is a directory by checking
+ // element.m_fileLength, that doesn't work in Android
+ std::string filename = element.m_filename.utf8().data();
+ if (filename.size()) {
+ // Change from a url string to a filename
+ if (filename.find("file://") == 0) // Found at pos 0
+ filename.erase(0, 7);
+ base::Thread* thread = ioThread();
+ if (thread)
+ thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::appendFileToUpload, filename));
+ }
+ }
+ break;
+#if ENABLE(BLOB)
+ case FormDataElement::encodedBlob:
+ LOG_ASSERT(false, "Unexpected use of FormDataElement::encodedBlob");
+ break;
+#endif // ENABLE(BLOB)
+ default:
+ LOG_ASSERT(false, "Unexpected default case in WebUrlLoaderClient.cpp");
+ break;
+ }
+ }
+ }
+}
+
+bool WebUrlLoaderClient::start(bool isMainResource, bool isMainFrame, bool sync, WebRequestContext* context)
+{
+ base::Thread* thread = ioThread();
+ if (!thread) {
+ return false;
+ }
+
+ m_isMainResource = isMainResource;
+ m_isMainFrame = isMainFrame;
+ m_sync = sync;
+ if (m_sync) {
+ AutoLock autoLock(*syncLock());
+ m_request->setSync(sync);
+ m_request->setRequestContext(context);
+ thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::start));
+
+ // Run callbacks until the queue is exhausted and m_finished is true.
+ // Sometimes, a sync load can wait forever and lock up the WebCore thread,
+ // here we use TimedWait() with multiple tries to avoid locking.
+ const int kMaxNumTimeout = 3;
+ const int kCallbackWaitingTime = 10;
+ int num_timeout = 0;
+ while(!m_finished) {
+ while (!m_queue.empty()) {
+ OwnPtr<Task> task(m_queue.front());
+ m_queue.pop_front();
+ task->Run();
+ }
+ if (m_finished) break;
+
+ syncCondition()->TimedWait(base::TimeDelta::FromSeconds(kCallbackWaitingTime));
+ if (m_queue.empty()) {
+ LOGE("Synchronous request timed out after %d seconds for the %dth try, URL: %s",
+ kCallbackWaitingTime, num_timeout, m_request->getUrl().c_str());
+ num_timeout++;
+ if (num_timeout >= kMaxNumTimeout) {
+ cancel();
+ m_resourceHandle = 0;
+ return false;
+ }
+ }
+ }
+
+ // This may be the last reference to us, so we may be deleted now.
+ // Don't access any more member variables after releasing this reference.
+ m_resourceHandle = 0;
+ } else {
+ // Asynchronous start.
+ // Important to set this before the thread starts so it has a reference and can't be deleted
+ // before the task starts running on the IO thread.
+ m_request->setRequestContext(context);
+ thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::start));
+ }
+ return true;
+}
+
+namespace {
+// Check if the mime type is for certificate installation.
+// The items must be consistent with the sCertificateTypeMap
+// in frameworks/base/core/java/android/webkit/CertTool.java.
+bool isMimeTypeForCert(const std::string& mimeType)
+{
+ static std::hash_set<std::string> sCertificateTypeSet;
+ if (sCertificateTypeSet.empty()) {
+ sCertificateTypeSet.insert("application/x-x509-ca-cert");
+ sCertificateTypeSet.insert("application/x-x509-user-cert");
+ sCertificateTypeSet.insert("application/x-pkcs12");
+ }
+ return sCertificateTypeSet.find(mimeType) != sCertificateTypeSet.end();
+}
+}
+
+void WebUrlLoaderClient::downloadFile()
+{
+ if (m_response) {
+ std::string contentDisposition;
+ m_response->getHeader("content-disposition", &contentDisposition);
+ m_webFrame->downloadStart(m_response->getUrl(), m_request->getUserAgent(), contentDisposition, m_response->getMimeType(), m_response->getExpectedSize());
+
+ m_isCertMimeType = isMimeTypeForCert(m_response->getMimeType());
+ // Currently, only certificate mime type needs to receive the data.
+ // Other mime type, e.g. wav, will send the url to other application
+ // which will load the data by url.
+ if (!m_isCertMimeType)
+ cancel();
+ } else {
+ LOGE("Unexpected call to downloadFile() before didReceiveResponse(). URL: %s", m_request->getUrl().c_str());
+ // TODO: Turn off asserts crashing before release
+ // http://b/issue?id=2951985
+ CRASH();
+ }
+}
+
+void WebUrlLoaderClient::cancel()
+{
+ if (!isActive())
+ return;
+
+ m_cancelling = true;
+
+ base::Thread* thread = ioThread();
+ if (thread)
+ thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::cancel));
+}
+
+void WebUrlLoaderClient::pauseLoad(bool pause)
+{
+ if (!isActive())
+ return;
+
+ base::Thread* thread = ioThread();
+ if (thread)
+ thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::pauseLoad, pause));
+}
+
+void WebUrlLoaderClient::setAuth(const std::string& username, const std::string& password)
+{
+ if (!isActive())
+ return;
+
+ base::Thread* thread = ioThread();
+ if (!thread) {
+ return;
+ }
+ string16 username16 = ASCIIToUTF16(username);
+ string16 password16 = ASCIIToUTF16(password);
+ thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::setAuth, username16, password16));
+}
+
+void WebUrlLoaderClient::cancelAuth()
+{
+ if (!isActive())
+ return;
+
+ base::Thread* thread = ioThread();
+ if (!thread) {
+ return;
+ }
+ thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::cancelAuth));
+}
+
+void WebUrlLoaderClient::proceedSslCertError()
+{
+ base::Thread* thread = ioThread();
+ if (isActive() && thread)
+ thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::proceedSslCertError));
+ this->Release();
+}
+
+void WebUrlLoaderClient::cancelSslCertError(int cert_error)
+{
+ base::Thread* thread = ioThread();
+ if (isActive() && thread)
+ thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::cancelSslCertError, cert_error));
+ this->Release();
+}
+
+
+void WebUrlLoaderClient::finish()
+{
+ m_finished = true;
+ if (!m_sync) {
+ // This is the last reference to us, so we will be deleted now.
+ // We only release the reference here if start() was called asynchronously!
+ m_resourceHandle = 0;
+ }
+ m_request = 0;
+}
+
+namespace {
+// Trampoline to wrap a Chromium Task* in a WebKit-style static function + void*.
+static void RunTask(void* v) {
+ OwnPtr<Task> task(static_cast<Task*>(v));
+ task->Run();
+}
+}
+
+// This is called from the IO thread, and dispatches the callback to the main thread.
+void WebUrlLoaderClient::maybeCallOnMainThread(Task* task)
+{
+ if (m_sync) {
+ AutoLock autoLock(*syncLock());
+ if (m_queue.empty()) {
+ syncCondition()->Broadcast();
+ }
+ m_queue.push_back(task);
+ } else {
+ // Let WebKit handle it.
+ callOnMainThread(RunTask, task);
+ }
+}
+
+// Response methods
+void WebUrlLoaderClient::didReceiveResponse(PassOwnPtr<WebResponse> webResponse)
+{
+ if (!isActive())
+ return;
+
+ m_response = webResponse;
+ m_resourceHandle->client()->didReceiveResponse(m_resourceHandle.get(), m_response->createResourceResponse());
+
+ // Set the main page's certificate to WebView.
+ if (m_isMainResource && m_isMainFrame) {
+ const net::SSLInfo& ssl_info = m_response->getSslInfo();
+ if (ssl_info.is_valid()) {
+ std::vector<std::string> chain_bytes;
+ ssl_info.cert->GetChainDEREncodedBytes(&chain_bytes);
+ m_webFrame->setCertificate(chain_bytes[0]);
+ }
+
+ // Look for X-Auto-Login on the main resource to log in the user.
+ std::string login;
+ if (m_response->getHeader("x-auto-login", &login))
+ m_webFrame->autoLogin(login);
+ }
+}
+
+void WebUrlLoaderClient::didReceiveData(scoped_refptr<net::IOBuffer> buf, int size)
+{
+ if (m_isMainResource && m_isCertMimeType) {
+ m_webFrame->didReceiveData(buf->data(), size);
+ }
+
+ if (!isActive() || !size)
+ return;
+
+ // didReceiveData will take a copy of the data
+ if (m_resourceHandle && m_resourceHandle->client())
+ m_resourceHandle->client()->didReceiveData(m_resourceHandle.get(), buf->data(), size, size);
+}
+
+// For data url's
+void WebUrlLoaderClient::didReceiveDataUrl(PassOwnPtr<std::string> str)
+{
+ if (!isActive() || !str->size())
+ return;
+
+ // didReceiveData will take a copy of the data
+ m_resourceHandle->client()->didReceiveData(m_resourceHandle.get(), str->data(), str->size(), str->size());
+}
+
+// For special android files
+void WebUrlLoaderClient::didReceiveAndroidFileData(PassOwnPtr<std::vector<char> > vector)
+{
+ if (!isActive() || !vector->size())
+ return;
+
+ // didReceiveData will take a copy of the data
+ m_resourceHandle->client()->didReceiveData(m_resourceHandle.get(), vector->begin(), vector->size(), vector->size());
+}
+
+void WebUrlLoaderClient::didFail(PassOwnPtr<WebResponse> webResponse)
+{
+ if (isActive())
+ m_resourceHandle->client()->didFail(m_resourceHandle.get(), webResponse->createResourceError());
+
+ // Always finish a request, if not it will leak
+ finish();
+}
+
+void WebUrlLoaderClient::willSendRequest(PassOwnPtr<WebResponse> webResponse)
+{
+ if (!isActive())
+ return;
+
+ KURL url = webResponse->createKurl();
+ OwnPtr<WebCore::ResourceRequest> resourceRequest(new WebCore::ResourceRequest(url));
+ m_resourceHandle->client()->willSendRequest(m_resourceHandle.get(), *resourceRequest, webResponse->createResourceResponse());
+
+ // WebKit may have killed the request.
+ if (!isActive())
+ return;
+
+ // Like Chrome, we only follow the redirect if WebKit left the URL unmodified.
+ if (url == resourceRequest->url()) {
+ ioThread()->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::followDeferredRedirect));
+ } else {
+ cancel();
+ }
+}
+
+void WebUrlLoaderClient::didFinishLoading()
+{
+ if (isActive())
+ m_resourceHandle->client()->didFinishLoading(m_resourceHandle.get(), 0);
+
+ if (m_isMainResource && m_isCertMimeType) {
+ m_webFrame->didFinishLoading();
+ }
+
+ // Always finish a request, if not it will leak
+ finish();
+}
+
+void WebUrlLoaderClient::authRequired(scoped_refptr<net::AuthChallengeInfo> authChallengeInfo, bool firstTime)
+{
+ if (!isActive())
+ return;
+
+ std::string host = base::SysWideToUTF8(authChallengeInfo->host_and_port);
+ std::string realm = base::SysWideToUTF8(authChallengeInfo->realm);
+
+ m_webFrame->didReceiveAuthenticationChallenge(this, host, realm, firstTime);
+}
+
+void WebUrlLoaderClient::reportSslCertError(int cert_error, net::X509Certificate* cert)
+{
+ if (!isActive())
+ return;
+
+ std::vector<std::string> chain_bytes;
+ cert->GetChainDEREncodedBytes(&chain_bytes);
+ this->AddRef();
+ m_webFrame->reportSslCertError(this, cert_error, chain_bytes[0]);
+}
+
+} // namespace android
diff --git a/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h b/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h
new file mode 100644
index 0000000..dc101db
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h
@@ -0,0 +1,130 @@
+/*
+ * 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 WebUrlLoaderClient_h
+#define WebUrlLoaderClient_h
+
+#include "ChromiumIncludes.h"
+#include "RefCounted.h"
+#include "WebResponse.h"
+#include "WebUrlLoader.h"
+
+#include <string>
+#include <deque>
+#include <string>
+#include <vector>
+
+class Lock;
+class ConditionVariable;
+
+namespace base {
+class Thread;
+}
+
+namespace net {
+class IOBuffer;
+class AuthChallengeInfo;
+}
+
+namespace android {
+
+class WebFrame;
+class WebRequest;
+class WebRequestContext;
+
+// This class handles communication between the IO thread where loading happens
+// and the webkit main thread.
+// TODO:
+// - Implement didFail
+// - Implement sync requests
+// - Implement downloadFile
+// - Implement pauseLoad
+class WebUrlLoaderClient : public base::RefCountedThreadSafe<WebUrlLoaderClient> {
+public:
+ WebUrlLoaderClient(WebFrame*, WebCore::ResourceHandle*, const WebCore::ResourceRequest&);
+
+ // Called from WebCore, will be forwarded to the IO thread
+ bool start(bool isMainResource, bool isMainFrame, bool sync, WebRequestContext*);
+ void cancel();
+ void downloadFile();
+ void pauseLoad(bool pause);
+ void setAuth(const std::string& username, const std::string& password);
+ void cancelAuth();
+ void proceedSslCertError();
+ void cancelSslCertError(int cert_error);
+
+ typedef void CallbackFunction(void*);
+
+ // This is called from the IO thread, and dispatches the callback to the main thread.
+ // (For asynchronous calls, we just delegate to WebKit's callOnMainThread.)
+ void maybeCallOnMainThread(Task* task);
+
+ // Called by WebRequest (using maybeCallOnMainThread), should be forwarded to WebCore.
+ void didReceiveResponse(PassOwnPtr<WebResponse>);
+ void didReceiveData(scoped_refptr<net::IOBuffer>, int size);
+ void didReceiveDataUrl(PassOwnPtr<std::string>);
+ void didReceiveAndroidFileData(PassOwnPtr<std::vector<char> >);
+ void didFinishLoading();
+ void didFail(PassOwnPtr<WebResponse>);
+ void willSendRequest(PassOwnPtr<WebResponse>);
+ void authRequired(scoped_refptr<net::AuthChallengeInfo>, bool firstTime);
+ void reportSslCertError(int cert_error, net::X509Certificate* cert);
+
+ // Handle to the chrome IO thread
+ static base::Thread* ioThread();
+
+private:
+ friend class base::RefCountedThreadSafe<WebUrlLoaderClient>;
+ virtual ~WebUrlLoaderClient();
+
+ void finish();
+
+ WebFrame* m_webFrame;
+ RefPtr<WebCore::ResourceHandle> m_resourceHandle;
+ bool m_isMainResource;
+ bool m_isMainFrame;
+ bool m_isCertMimeType;
+ bool m_cancelling;
+ bool m_sync;
+ volatile bool m_finished;
+
+ scoped_refptr<WebRequest> m_request;
+ OwnPtr<WebResponse> m_response; // NULL until didReceiveResponse is called.
+
+ // Check if a request is active
+ bool isActive() const;
+
+ // Mutex and condition variable used for synchronous requests.
+ // Note that these are static. This works because there's only one main thread.
+ static Lock* syncLock();
+ static ConditionVariable* syncCondition();
+
+ // Queue of callbacks to be executed by the main thread. Must only be accessed inside mutex.
+ std::deque<Task*> m_queue;
+};
+
+} // namespace android
+
+#endif
diff --git a/Source/WebKit/android/WebCoreSupport/WebViewClientError.cpp b/Source/WebKit/android/WebCoreSupport/WebViewClientError.cpp
new file mode 100644
index 0000000..59542da
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/WebViewClientError.cpp
@@ -0,0 +1,132 @@
+/*
+ * 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 "WebViewClientError.h"
+
+using namespace net;
+
+namespace android {
+
+WebViewClientError ToWebViewClientError(net::Error error) {
+ // Note: many net::Error constants don't have an obvious mapping.
+ // These will be handled by the default case, ERROR_UNKNOWN.
+ switch(error) {
+ case ERR_UNSUPPORTED_AUTH_SCHEME:
+ return ERROR_UNSUPPORTED_AUTH_SCHEME;
+
+ case ERR_INVALID_AUTH_CREDENTIALS:
+ case ERR_MISSING_AUTH_CREDENTIALS:
+ case ERR_MISCONFIGURED_AUTH_ENVIRONMENT:
+ return ERROR_AUTHENTICATION;
+
+ case ERR_TOO_MANY_REDIRECTS:
+ return ERROR_REDIRECT_LOOP;
+
+ case ERR_UPLOAD_FILE_CHANGED:
+ return ERROR_FILE_NOT_FOUND;
+
+ case ERR_INVALID_URL:
+ return ERROR_BAD_URL;
+
+ case ERR_DISALLOWED_URL_SCHEME:
+ case ERR_UNKNOWN_URL_SCHEME:
+ return ERROR_UNSUPPORTED_SCHEME;
+
+ case ERR_IO_PENDING:
+ case ERR_NETWORK_IO_SUSPENDED:
+ return ERROR_IO;
+
+ case ERR_CONNECTION_TIMED_OUT:
+ case ERR_TIMED_OUT:
+ return ERROR_TIMEOUT;
+
+ case ERR_FILE_TOO_BIG:
+ return ERROR_FILE;
+
+ case ERR_HOST_RESOLVER_QUEUE_TOO_LARGE:
+ case ERR_INSUFFICIENT_RESOURCES:
+ case ERR_OUT_OF_MEMORY:
+ return ERROR_TOO_MANY_REQUESTS;
+
+ case ERR_CONNECTION_CLOSED:
+ case ERR_CONNECTION_RESET:
+ case ERR_CONNECTION_REFUSED:
+ case ERR_CONNECTION_ABORTED:
+ case ERR_CONNECTION_FAILED:
+ case ERR_SOCKET_NOT_CONNECTED:
+ return ERROR_CONNECT;
+
+ case ERR_ADDRESS_INVALID:
+ case ERR_ADDRESS_UNREACHABLE:
+ case ERR_NAME_NOT_RESOLVED:
+ case ERR_NAME_RESOLUTION_FAILED:
+ return ERROR_HOST_LOOKUP;
+
+ case ERR_SSL_PROTOCOL_ERROR:
+ case ERR_SSL_CLIENT_AUTH_CERT_NEEDED:
+ case ERR_TUNNEL_CONNECTION_FAILED:
+ case ERR_NO_SSL_VERSIONS_ENABLED:
+ case ERR_SSL_VERSION_OR_CIPHER_MISMATCH:
+ case ERR_SSL_RENEGOTIATION_REQUESTED:
+ case ERR_CERT_ERROR_IN_SSL_RENEGOTIATION:
+ case ERR_BAD_SSL_CLIENT_AUTH_CERT:
+ case ERR_SSL_NO_RENEGOTIATION:
+ case ERR_SSL_DECOMPRESSION_FAILURE_ALERT:
+ case ERR_SSL_BAD_RECORD_MAC_ALERT:
+ case ERR_SSL_UNSAFE_NEGOTIATION:
+ case ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY:
+ case ERR_SSL_SNAP_START_NPN_MISPREDICTION:
+ case ERR_SSL_CLIENT_AUTH_PRIVATE_KEY_ACCESS_DENIED:
+ case ERR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY:
+ return ERROR_FAILED_SSL_HANDSHAKE;
+
+ case ERR_PROXY_AUTH_UNSUPPORTED:
+ case ERR_PROXY_AUTH_REQUESTED:
+ case ERR_PROXY_CONNECTION_FAILED:
+ case ERR_UNEXPECTED_PROXY_AUTH:
+ return ERROR_PROXY_AUTHENTICATION;
+
+ /* The certificate errors are handled by their own dialog
+ * and don't need to be reported to the framework again.
+ */
+ case ERR_CERT_COMMON_NAME_INVALID:
+ case ERR_CERT_DATE_INVALID:
+ case ERR_CERT_AUTHORITY_INVALID:
+ case ERR_CERT_CONTAINS_ERRORS:
+ case ERR_CERT_NO_REVOCATION_MECHANISM:
+ case ERR_CERT_UNABLE_TO_CHECK_REVOCATION:
+ case ERR_CERT_REVOKED:
+ case ERR_CERT_INVALID:
+ case ERR_CERT_WEAK_SIGNATURE_ALGORITHM:
+ case ERR_CERT_NOT_IN_DNS:
+ return ERROR_OK;
+
+ default:
+ return ERROR_UNKNOWN;
+ }
+}
+
+}
diff --git a/Source/WebKit/android/WebCoreSupport/WebViewClientError.h b/Source/WebKit/android/WebCoreSupport/WebViewClientError.h
new file mode 100644
index 0000000..d274dc7
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/WebViewClientError.h
@@ -0,0 +1,74 @@
+/*
+ * 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 WebViewClientError_h
+#define WebViewClientError_h
+
+#include "ChromiumIncludes.h"
+
+namespace android {
+
+// This enum must be kept in sync with WebViewClient.java
+enum WebViewClientError {
+ /** Success */
+ ERROR_OK = 0,
+ /** Generic error */
+ ERROR_UNKNOWN = -1,
+ /** Server or proxy hostname lookup failed */
+ ERROR_HOST_LOOKUP = -2,
+ /** Unsupported authentication scheme (not basic or digest) */
+ ERROR_UNSUPPORTED_AUTH_SCHEME = -3,
+ /** User authentication failed on server */
+ ERROR_AUTHENTICATION = -4,
+ /** User authentication failed on proxy */
+ ERROR_PROXY_AUTHENTICATION = -5,
+ /** Failed to connect to the server */
+ ERROR_CONNECT = -6,
+ /** Failed to read or write to the server */
+ ERROR_IO = -7,
+ /** Connection timed out */
+ ERROR_TIMEOUT = -8,
+ /** Too many redirects */
+ ERROR_REDIRECT_LOOP = -9,
+ /** Unsupported URI scheme */
+ ERROR_UNSUPPORTED_SCHEME = -10,
+ /** Failed to perform SSL handshake */
+ ERROR_FAILED_SSL_HANDSHAKE = -11,
+ /** Malformed URL */
+ ERROR_BAD_URL = -12,
+ /** Generic file error */
+ ERROR_FILE = -13,
+ /** File not found */
+ ERROR_FILE_NOT_FOUND = -14,
+ /** Too many requests during this load */
+ ERROR_TOO_MANY_REQUESTS = -15,
+};
+
+// Get the closest WebViewClient match to the given Chrome error code.
+WebViewClientError ToWebViewClientError(net::Error);
+
+} // namespace android
+
+#endif // WebViewClientError_h
diff --git a/Source/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.cpp b/Source/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.cpp
new file mode 100644
index 0000000..5bc4c92
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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(const std::vector<string16>& names, const std::vector<string16>& labels, const std::vector<string16>& icons, const std::vector<int>& uniqueIds)
+{
+ // TODO: what do we do with icons?
+ if (mAutoFill)
+ mAutoFill->querySuccessful(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/Source/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.h b/Source/WebKit/android/WebCoreSupport/autofill/AutoFillHostAndroid.h
new file mode 100644
index 0000000..9677b46
--- /dev/null
+++ b/Source/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(const std::vector<string16>& names, const std::vector<string16>& labels, const std::vector<string16>& icons, const std::vector<int>& uniqueIds);
+ virtual void AutoFillFormDataFilled(int queryId, const webkit_glue::FormData&);
+
+private:
+ WebAutoFill* mAutoFill;
+};
+}
+
+#endif
diff --git a/Source/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.cpp b/Source/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.cpp
new file mode 100644
index 0000000..6af0875
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.cpp
@@ -0,0 +1,139 @@
+/*
+ * 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 "Element.h"
+#include "HTMLFormControlElement.h"
+#include "HTMLInputElement.h"
+#include "HTMLNames.h"
+#include "HTMLOptionElement.h"
+#include "HTMLSelectElement.h"
+#include "StringUtils.h"
+#include <wtf/Vector.h>
+
+using WebCore::Element;
+using WebCore::HTMLFormControlElement;
+using WebCore::HTMLInputElement;
+using WebCore::HTMLOptionElement;
+using WebCore::HTMLSelectElement;
+
+using namespace WebCore::HTMLNames;
+
+// 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 webkit_glue {
+
+FormField::FormField()
+ : max_length_(0),
+ is_autofilled_(false) {
+}
+
+// TODO: This constructor should probably be deprecated and the
+// functionality moved to FormManager.
+FormField::FormField(const HTMLFormControlElement& element)
+ : max_length_(0),
+ is_autofilled_(false) {
+ name_ = nameForAutoFill(element);
+
+ // TODO: Extract the field label. For now we just use the field
+ // name.
+ label_ = name_;
+
+ form_control_type_ = formControlType(element);
+ if (form_control_type_ == kText) {
+ const HTMLInputElement& input_element = static_cast<const HTMLInputElement&>(element);
+ value_ = WTFStringToString16(input_element.value());
+ max_length_ = input_element.size();
+ is_autofilled_ = input_element.isAutofilled();
+ } else if (form_control_type_ == kSelectOne) {
+ const HTMLSelectElement& const_select_element = static_cast<const HTMLSelectElement&>(element);
+ HTMLSelectElement& select_element = const_cast<HTMLSelectElement&>(const_select_element);
+ value_ = WTFStringToString16(select_element.value());
+
+ // For select-one elements copy option strings.
+ WTF::Vector<Element*> list_items = select_element.listItems();
+ option_strings_.reserve(list_items.size());
+ for (size_t i = 0; i < list_items.size(); ++i) {
+ if (list_items[i]->hasTagName(optionTag))
+ option_strings_.push_back(WTFStringToString16(static_cast<HTMLOptionElement*>(list_items[i])->value()));
+ }
+ }
+
+ TrimWhitespace(value_, TRIM_LEADING, &value_);
+}
+
+FormField::FormField(const string16& label, const string16& name, const string16& value, const string16& form_control_type, int max_length, bool is_autofilled)
+ : label_(label),
+ name_(name),
+ value_(value),
+ form_control_type_(form_control_type),
+ max_length_(max_length),
+ is_autofilled_(is_autofilled) {
+}
+
+FormField::~FormField() {
+}
+
+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_ &&
+ max_length_ == field.max_length_);
+}
+
+bool FormField::operator!=(const FormField& field) const {
+ return !operator==(field);
+}
+
+bool FormField::StrictlyEqualsHack(const FormField& field) const {
+ return (label_ == field.label_ &&
+ name_ == field.name_ &&
+ value_ == field.value_ &&
+ form_control_type_ == field.form_control_type_ &&
+ max_length_ == field.max_length_);
+}
+
+std::ostream& operator<<(std::ostream& os, const FormField& field) {
+ return os
+ << UTF16ToUTF8(field.label())
+ << " "
+ << UTF16ToUTF8(field.name())
+ << " "
+ << UTF16ToUTF8(field.value())
+ << " "
+ << UTF16ToUTF8(field.form_control_type())
+ << " "
+ << field.max_length();
+}
+
+} // namespace webkit_glue
diff --git a/Source/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.h b/Source/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.h
new file mode 100644
index 0000000..c5e3ecc
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/autofill/FormFieldAndroid.h
@@ -0,0 +1,96 @@
+/*
+ * 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.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 WebCore {
+class HTMLFormControlElement;
+}
+
+namespace webkit_glue {
+
+// Stores information about a field in a form.
+class FormField {
+public:
+ FormField();
+ explicit FormField(const WebCore::HTMLFormControlElement& element);
+ FormField(const string16& label, const string16& name, const string16& value, const string16& form_control_type, int max_length, bool is_autofilled);
+ virtual ~FormField();
+
+ 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 max_length() const { return max_length_; }
+ bool is_autofilled() const { return is_autofilled_; }
+
+ // 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_max_length(int max_length) { max_length_ = max_length; }
+ void set_autofilled(bool is_autofilled) { is_autofilled_ = is_autofilled; }
+ void set_option_strings(const std::vector<string16>& strings) { option_strings_ = strings; }
+
+ // Equality tests for identity which does not include |value_| or |size_|.
+ // Use |StrictlyEqualsHack| method to test all members.
+ // TODO: These operators need to be revised when we implement field
+ // ids.
+ bool operator==(const FormField& field) const;
+ bool operator!=(const FormField& field) const;
+
+ // Test equality of all data members.
+ // TODO: This will be removed when we implement field ids.
+ bool StrictlyEqualsHack(const FormField& field) const;
+
+private:
+ string16 label_;
+ string16 name_;
+ string16 value_;
+ string16 form_control_type_;
+ int max_length_;
+ bool is_autofilled_;
+ std::vector<string16> option_strings_;
+};
+
+// So we can compare FormFields with EXPECT_EQ().
+std::ostream& operator<<(std::ostream& os, const FormField& field);
+
+} // namespace webkit_glue
+
+#endif // WEBKIT_GLUE_FORM_FIELD_H_
diff --git a/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp b/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp
new file mode 100644
index 0000000..9652794
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.cpp
@@ -0,0 +1,871 @@
+/*
+ * 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 "DocumentLoader.h"
+#include "Element.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "HTMLCollection.h"
+#include "HTMLFormControlElement.h"
+#include "HTMLFormElement.h"
+#include "HTMLInputElement.h"
+#include "HTMLLabelElement.h"
+#include "HTMLNames.h"
+#include "HTMLOptionElement.h"
+#include "HTMLSelectElement.h"
+#include "Node.h"
+#include "NodeList.h"
+#include "HTMLCollection.h"
+#include "FormAssociatedElement.h"
+#include "FormFieldAndroid.h"
+#include "QualifiedName.h"
+#include "StringUtils.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::Element;
+using WebCore::FormAssociatedElement;
+using WebCore::HTMLCollection;
+using WebCore::HTMLElement;
+using WebCore::HTMLFormControlElement;
+using WebCore::HTMLFormElement;
+using WebCore::HTMLInputElement;
+using WebCore::HTMLLabelElement;
+using WebCore::HTMLOptionElement;
+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;
+
+// The maximum length allowed for form data.
+const size_t kMaxDataLength = 1024;
+
+// This is a helper function for the FindChildText() function.
+// Returns the aggregated values of the descendants or siblings of |node| that
+// are non-empty text nodes. 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. The text is
+// accumulated after the whitespace has been stropped. Search depth is limited
+// with the |depth| parameter.
+string16 FindChildTextInner(Node* node, int depth) {
+ string16 element_text;
+ if (!node || depth <= 0)
+ return element_text;
+
+ string16 node_text = WTFStringToString16(node->nodeValue());
+ TrimWhitespace(node_text, TRIM_ALL, &node_text);
+ if (!node_text.empty())
+ element_text = node_text;
+
+ string16 child_text = FindChildTextInner(node->firstChild(), depth-1);
+ if (!child_text.empty())
+ element_text = element_text + child_text;
+
+ string16 sibling_text = FindChildTextInner(node->nextSibling(), depth-1);
+ if (!sibling_text.empty())
+ element_text = element_text + sibling_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. Search is limited to withing 10 siblings and/or
+// descendants.
+string16 FindChildText(Element* element) {
+ Node* child = element->firstChild();
+
+ const int kChildSearchDepth = 10;
+ return FindChildTextInner(child, kChildSearchDepth);
+}
+
+string16 InferLabelFromPrevious(const HTMLFormControlElement& element) {
+ string16 inferred_label;
+ Node* previous = element.previousSibling();
+ if (!previous)
+ return string16();
+
+ if (previous->isTextNode()) {
+ inferred_label = WTFStringToString16(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() && previous->isElementNode()) {
+ Element* element = static_cast<Element*>(previous);
+ if (element->hasTagName(pTag))
+ inferred_label = FindChildText(element);
+ }
+
+ // 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()) {
+ Node* sibling = previous->previousSibling();
+ if (sibling && sibling->isElementNode()) {
+ Element* element = static_cast<Element*>(sibling);
+ if (element->hasTagName(pTag))
+ inferred_label = FindChildText(element);
+ }
+ }
+
+ // Look for text node prior to <img> tag.
+ // Eg. Some Text<img/><input ...>
+ if (inferred_label.empty()) {
+ while (inferred_label.empty() && previous) {
+ if (previous->isTextNode()) {
+ inferred_label = WTFStringToString16(previous->nodeValue());
+ TrimWhitespace(inferred_label, TRIM_ALL, &inferred_label);
+ } else if (previous->isElementNode()) {
+ Element* element = static_cast<Element*>(previous);
+ if (!element->hasTagName(imgTag))
+ break;
+ } else
+ break;
+ previous = previous->previousSibling();
+ }
+ }
+
+ // Look for label node prior to <input> tag.
+ // Eg. <label>Some Text</label><input ...>
+ if (inferred_label.empty()) {
+ while (inferred_label.empty() && previous) {
+ if (previous->isTextNode()) {
+ inferred_label = WTFStringToString16(previous->nodeValue());
+ TrimWhitespace(inferred_label, TRIM_ALL, &inferred_label);
+ } else if (previous->isElementNode()) {
+ Element* element = static_cast<Element*>(previous);
+ if (element->hasTagName(labelTag)) {
+ inferred_label = FindChildText(element);
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+
+ previous = previous->previousSibling();
+ }
+ }
+
+ return inferred_label;
+}
+
+// Helper for |InferLabelForElement()| that infers a label, if possible, from
+// surrounding table structure.
+// Eg. <tr><td>Some Text</td><td><input ...></td></tr>
+// Eg. <tr><td><b>Some Text</b></td><td><b><input ...></b></td></tr>
+string16 InferLabelFromTable(const HTMLFormControlElement& element) {
+ string16 inferred_label;
+ Node* parent = element.parentNode();
+ while (parent && parent->isElementNode() && !static_cast<Element*>(parent)->hasTagName(tdTag))
+ parent = parent->parentNode();
+
+ // Check all previous siblings, skipping non-element nodes, until we find a
+ // non-empty text block.
+ Node* previous = parent;
+ while(previous) {
+ if (previous->isElementNode()) {
+ Element* e = static_cast<Element*>(previous);
+ if (e->hasTagName(tdTag)) {
+ inferred_label = FindChildText(e);
+ if (!inferred_label.empty())
+ break;
+ }
+ }
+ previous = previous->previousSibling();
+ }
+ return inferred_label;
+}
+
+// Helper for |InferLabelForElement()| that infers a label, if possible, from
+// a surrounding div table.
+// Eg. <div>Some Text<span><input ...></span></div>
+string16 InferLabelFromDivTable(const HTMLFormControlElement& element) {
+ Node* parent = element.parentNode();
+ while (parent && parent->isElementNode() && !static_cast<Element*>(parent)->hasTagName(divTag))
+ parent = parent->parentNode();
+
+ if (!parent || !parent->isElementNode())
+ return string16();
+
+ Element* e = static_cast<Element*>(parent);
+ if (!e || !e->hasTagName(divTag))
+ return string16();
+
+ return FindChildText(e);
+}
+
+// Helper for |InferLabelForElement()| that infers a label, if possible, from
+// a surrounding definition list.
+// Eg. <dl><dt>Some Text</dt><dd><input ...></dd></dl>
+// Eg. <dl><dt><b>Some Text</b></dt><dd><b><input ...></b></dd></dl>
+string16 InferLabelFromDefinitionList(const HTMLFormControlElement& element) {
+ string16 inferred_label;
+ Node* parent = element.parentNode();
+ while (parent && parent->isElementNode() && !static_cast<Element*>(parent)->hasTagName(ddTag))
+ parent = parent->parentNode();
+
+ if (parent && parent->isElementNode()) {
+ Element* element = static_cast<Element*>(parent);
+ if (element->hasTagName(ddTag)) {
+ Node* previous = parent->previousSibling();
+
+ // Skip by any intervening text nodes.
+ while (previous && previous->isTextNode())
+ previous = previous->previousSibling();
+
+ if (previous && previous->isElementNode()) {
+ element = static_cast<Element*>(previous);
+ if (element->hasTagName(dtTag))
+ inferred_label = FindChildText(element);
+ }
+ }
+ }
+ return inferred_label;
+}
+
+void GetOptionStringsFromElement(HTMLFormControlElement* element, std::vector<string16>* option_strings) {
+ DCHECK(element);
+ DCHECK(option_strings);
+ option_strings->clear();
+ if (formControlType(*element) == kSelectOne) {
+ HTMLSelectElement* select_element = static_cast<HTMLSelectElement*>(element);
+
+ // For select-one elements copy option strings.
+ WTF::Vector<Element*> list_items = select_element->listItems();
+ option_strings->reserve(list_items.size());
+ for (size_t i = 0; i < list_items.size(); ++i) {
+ if (list_items[i]->hasTagName(optionTag))
+ option_strings->push_back(WTFStringToString16(static_cast<HTMLOptionElement*>(list_items[i])->value()));
+ }
+ }
+}
+
+} // namespace
+
+namespace android {
+
+struct FormManager::FormElement {
+ RefPtr<HTMLFormElement> form_element;
+ std::vector<RefPtr<HTMLFormControlElement> > control_elements;
+ std::vector<string16> control_values;
+};
+
+FormManager::FormManager() {
+}
+
+FormManager::~FormManager() {
+ Reset();
+}
+
+// static
+void FormManager::HTMLFormControlElementToFormField(HTMLFormControlElement* element, ExtractMask extract_mask, FormField* field) {
+ DCHECK(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(nameForAutoFill(*element));
+ field->set_form_control_type(formControlType(*element));
+
+ if (extract_mask & EXTRACT_OPTIONS) {
+ std::vector<string16> option_strings;
+ GetOptionStringsFromElement(element, &option_strings);
+ field->set_option_strings(option_strings);
+ }
+
+ if (formControlType(*element) == kText) {
+ HTMLInputElement* input_element = static_cast<HTMLInputElement*>(element);
+ field->set_max_length(input_element->maxLength());
+ field->set_autofilled(input_element->isAutofilled());
+ }
+
+ if (!(extract_mask & EXTRACT_VALUE))
+ return;
+
+ // TODO: In WebKit, move value() and setValue() to
+ // WebFormControlElement.
+ string16 value;
+ if (formControlType(*element) == kText ||
+ formControlType(*element) == kHidden) {
+ HTMLInputElement* input_element = static_cast<HTMLInputElement*>(element);
+ value = WTFStringToString16(input_element->value());
+ } else if (formControlType(*element) == kSelectOne) {
+ HTMLSelectElement* select_element = static_cast<HTMLSelectElement*>(element);
+ value = WTFStringToString16(select_element->value());
+
+ // Convert the |select_element| value to text if requested.
+ if (extract_mask & EXTRACT_OPTION_TEXT) {
+ Vector<Element*> list_items = select_element->listItems();
+ for (size_t i = 0; i < list_items.size(); ++i) {
+ if (list_items[i]->hasTagName(optionTag) &&
+ WTFStringToString16(static_cast<HTMLOptionElement*>(list_items[i])->value()) == value) {
+ value = WTFStringToString16(static_cast<HTMLOptionElement*>(list_items[i])->text());
+ break;
+ }
+ }
+ }
+ }
+
+ // TODO: This is a temporary stop-gap measure designed to prevent
+ // a malicious site from DOS'ing the browser with extremely large profile
+ // data. The correct solution is to parse this data asynchronously.
+ // See http://crbug.com/49332.
+ if (value.size() > kMaxDataLength)
+ value = value.substr(0, kMaxDataLength);
+
+ field->set_value(value);
+}
+
+// static
+string16 FormManager::LabelForElement(const HTMLFormControlElement& element) {
+ // Don't scrape labels for hidden elements.
+ if (formControlType(element) == kHidden)
+ return string16();
+
+ 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, ExtractMask extract_mask, FormData* form) {
+ DCHECK(form);
+
+ Frame* frame = element->document()->frame();
+ if (!frame)
+ return false;
+
+ if (requirements & REQUIRE_AUTOCOMPLETE && !element->autoComplete())
+ return false;
+
+ form->name = WTFStringToString16(element->name());
+ form->method = WTFStringToString16(element->method());
+ form->origin = GURL(WTFStringToString16(frame->loader()->documentLoader()->url().string()));
+ form->action = GURL(WTFStringToString16(frame->document()->completeURL(element->action())));
+ form->user_submitted = element->wasUserSubmitted();
+
+ // If the completed URL is not valid, just use the action we get from
+ // WebKit.
+ if (!form->action.is_valid())
+ form->action = GURL(WTFStringToString16(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::FormAssociatedElement*> 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) {
+ if (!control_elements[i]->isFormControlElement())
+ continue;
+
+ HTMLFormControlElement* control_element = static_cast<HTMLFormControlElement*>(control_elements[i]);
+ if (!(control_element->hasTagName(inputTag) || control_element->hasTagName(selectTag)))
+ continue;
+
+ if (requirements & REQUIRE_AUTOCOMPLETE &&
+ formControlType(*control_element) == kText) {
+ const WebCore::HTMLInputElement* input_element = static_cast<const WebCore::HTMLInputElement*>(control_element);
+ if (!input_element->autoComplete())
+ continue;
+ }
+
+ if (requirements & REQUIRE_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, extract_mask, 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) {
+ 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(nameForAutoFill(*field_element));
+ 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;
+
+ if (!control_elements[i]->isFormControlElement())
+ continue;
+
+ const HTMLFormControlElement* control_element = static_cast<HTMLFormControlElement*>(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(Frame* frame) {
+
+ ResetFrame(frame);
+
+ WTF::PassRefPtr<HTMLCollection> web_forms = frame->document()->forms();
+
+ for (size_t i = 0; i < web_forms->length(); ++i) {
+ FormElement* form_element = new FormElement;
+ HTMLFormElement* html_form_element = static_cast<HTMLFormElement*>(web_forms->item(i));
+ form_element->form_element = html_form_element;
+
+ WTF::Vector<FormAssociatedElement*> control_elements = html_form_element->associatedElements();
+ for (size_t j = 0; j < control_elements.size(); ++j) {
+ if (!control_elements[j]->isFormControlElement())
+ continue;
+
+ HTMLFormControlElement* element = static_cast<HTMLFormControlElement*>(control_elements[j]);
+ form_element->control_elements.push_back(element);
+
+ // Save original values of "select-one" inputs so we can restore them
+ // when |ClearFormWithNode()| is invoked.
+ if (formControlType(*element) == kSelectOne) {
+ HTMLSelectElement* select_element = static_cast<HTMLSelectElement*>(element);
+ string16 value = WTFStringToString16(select_element->value());
+ form_element->control_values.push_back(value);
+ } else
+ form_element->control_values.push_back(string16());
+ }
+
+ form_elements_.push_back(form_element);
+ }
+}
+
+void FormManager::GetFormsInFrame(const Frame* frame, RequirementsMask requirements, std::vector<FormData>* forms) {
+ DCHECK(frame);
+ DCHECK(forms);
+
+ for (FormElementList::const_iterator form_iter = form_elements_.begin(); form_iter != form_elements_.end(); ++form_iter) {
+ FormElement* form_element = *form_iter;
+
+ if (form_element->form_element->document()->frame() != frame)
+ continue;
+
+ // 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;
+ HTMLFormElementToFormData(form_element->form_element.get(), requirements, EXTRACT_VALUE, &form);
+ if (form.fields.size() >= kRequiredAutoFillFields)
+ forms->push_back(form);
+ }
+}
+
+bool FormManager::FindFormWithFormControlElement(HTMLFormControlElement* element, RequirementsMask requirements, FormData* form) {
+ DCHECK(form);
+
+ const Frame* frame = element->document()->frame();
+ if (!frame)
+ return false;
+
+ for (FormElementList::const_iterator iter = form_elements_.begin(); iter != form_elements_.end(); ++iter) {
+ const FormElement* form_element = *iter;
+
+ if (form_element->form_element->document()->frame() != frame)
+ continue;
+
+ for (std::vector<RefPtr<HTMLFormControlElement> >::const_iterator iter = form_element->control_elements.begin(); iter != form_element->control_elements.end(); ++iter) {
+ HTMLFormControlElement* candidate = iter->get();
+ if (nameForAutoFill(*candidate) == nameForAutoFill(*element)) {
+ ExtractMask extract_mask = static_cast<ExtractMask>(EXTRACT_VALUE | EXTRACT_OPTIONS);
+ return HTMLFormElementToFormData(form_element->form_element.get(), requirements, extract_mask, form);
+ }
+ }
+ }
+ return false;
+}
+
+bool FormManager::FillForm(const FormData& form, Node* node) {
+ FormElement* form_element = NULL;
+ if (!FindCachedFormElement(form, &form_element))
+ return false;
+
+ RequirementsMask requirements = static_cast<RequirementsMask>(REQUIRE_AUTOCOMPLETE | REQUIRE_ENABLED | REQUIRE_EMPTY);
+ ForEachMatchingFormField(form_element, node, requirements, form, NewCallback(this, &FormManager::FillFormField));
+
+ return true;
+}
+
+bool FormManager::PreviewForm(const FormData& form, Node* node) {
+ FormElement* form_element = NULL;
+ if (!FindCachedFormElement(form, &form_element))
+ return false;
+
+ RequirementsMask requirements = static_cast<RequirementsMask>(REQUIRE_AUTOCOMPLETE | REQUIRE_ENABLED | REQUIRE_EMPTY);
+ ForEachMatchingFormField(form_element, node, requirements, form, NewCallback(this, &FormManager::PreviewFormField));
+
+ return true;
+}
+
+bool FormManager::ClearFormWithNode(Node* node) {
+ FormElement* form_element = NULL;
+ if (!FindCachedFormElementWithNode(node, &form_element))
+ return false;
+
+ for (size_t i = 0; i < form_element->control_elements.size(); ++i) {
+ HTMLFormControlElement* element = form_element->control_elements[i].get();
+ if (formControlType(*element) == kText) {
+ HTMLInputElement* input_element = static_cast<HTMLInputElement*>(element);
+
+ // We don't modify the value of disabled fields.
+ if (!input_element->isEnabledFormControl())
+ continue;
+
+ input_element->setValue("");
+ input_element->setAutofilled(false);
+ // Clearing the value in the focused node (above) can cause selection
+ // to be lost. We force selection range to restore the text cursor.
+ if (node == input_element) {
+ int length = input_element->value().length();
+ input_element->setSelectionRange(length, length);
+ }
+ } else if (formControlType(*element) == kSelectOne) {
+ HTMLSelectElement* select_element = static_cast<HTMLSelectElement*>(element);
+ select_element->setValue(form_element->control_values[i].c_str());
+ }
+ }
+
+ return true;
+}
+
+bool FormManager::ClearPreviewedFormWithNode(Node* node, bool was_autofilled) {
+ FormElement* form_element = NULL;
+ if (!FindCachedFormElementWithNode(node, &form_element))
+ return false;
+
+ for (size_t i = 0; i < form_element->control_elements.size(); ++i) {
+ HTMLFormControlElement* element = form_element->control_elements[i].get();
+
+ // Only input elements can be previewed.
+ if (formControlType(*element) != kText)
+ continue;
+
+ // If the input element has not been auto-filled, FormManager has not
+ // previewed this field, so we have nothing to reset.
+ HTMLInputElement* input_element = static_cast<HTMLInputElement*>(element);
+ if (!input_element->isAutofilled())
+ continue;
+
+ // There might be unrelated elements in this form which have already been
+ // auto-filled. For example, the user might have already filled the address
+ // part of a form and now be dealing with the credit card section. We only
+ // want to reset the auto-filled status for fields that were previewed.
+ if (input_element->suggestedValue().isEmpty())
+ continue;
+
+ // Clear the suggested value. For the initiating node, also restore the
+ // original value.
+ input_element->setSuggestedValue("");
+ bool is_initiating_node = (node == input_element);
+ if (is_initiating_node) {
+ // Call |setValue()| to force the renderer to update the field's displayed
+ // value.
+ input_element->setValue(input_element->value());
+ input_element->setAutofilled(was_autofilled);
+ } else {
+ input_element->setAutofilled(false);
+ }
+
+ // Clearing the suggested value in the focused node (above) can cause
+ // selection to be lost. We force selection range to restore the text
+ // cursor.
+ if (is_initiating_node) {
+ int length = input_element->value().length();
+ input_element->setSelectionRange(length, length);
+ }
+ }
+
+ return true;
+}
+
+void FormManager::Reset() {
+ STLDeleteElements(&form_elements_);
+}
+
+void FormManager::ResetFrame(const Frame* frame) {
+ FormElementList::iterator iter = form_elements_.begin();
+ while (iter != form_elements_.end()) {
+ if ((*iter)->form_element->document()->frame() == frame) {
+ delete *iter;
+ iter = form_elements_.erase(iter);
+ } else
+ ++iter;
+ }
+}
+
+bool FormManager::FormWithNodeIsAutoFilled(Node* node) {
+ FormElement* form_element = NULL;
+ if (!FindCachedFormElementWithNode(node, &form_element))
+ return false;
+
+ for (size_t i = 0; i < form_element->control_elements.size(); ++i) {
+ HTMLFormControlElement* element = form_element->control_elements[i].get();
+ if (formControlType(*element) != kText)
+ continue;
+
+ HTMLInputElement* input_element = static_cast<HTMLInputElement*>(element);
+ if (input_element->isAutofilled())
+ return true;
+ }
+
+ return false;
+}
+
+// static
+string16 FormManager::InferLabelForElement(const HTMLFormControlElement& element) {
+ // Don't scrape labels for hidden elements.
+ if (formControlType(element) == kHidden)
+ return string16();
+
+ string16 inferred_label = InferLabelFromPrevious(element);
+
+ // If we didn't find a label, check for table cell case.
+ if (inferred_label.empty())
+ inferred_label = InferLabelFromTable(element);
+
+ // If we didn't find a label, check for div table case.
+ if (inferred_label.empty())
+ inferred_label = InferLabelFromDivTable(element);
+
+ // If we didn't find a label, check for definition list case.
+ if (inferred_label.empty())
+ inferred_label = InferLabelFromDefinitionList(element);
+
+ return inferred_label;
+}
+
+bool FormManager::FindCachedFormElementWithNode(Node* node,
+ FormElement** form_element) {
+ for (FormElementList::const_iterator form_iter = form_elements_.begin(); form_iter != form_elements_.end(); ++form_iter) {
+ for (std::vector<RefPtr<HTMLFormControlElement> >::const_iterator iter = (*form_iter)->control_elements.begin(); iter != (*form_iter)->control_elements.end(); ++iter) {
+ if (iter->get() == node) {
+ *form_element = *form_iter;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool FormManager::FindCachedFormElement(const FormData& form, FormElement** form_element) {
+ for (FormElementList::iterator form_iter = form_elements_.begin(); form_iter != form_elements_.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(WTFStringToString16((*form_iter)->form_element->name()));
+ GURL action(WTFStringToString16((*form_iter)->form_element->document()->completeURL((*form_iter)->form_element->action()).string()));
+ if (element_name == form.name && action == form.action) {
+ *form_element = *form_iter;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+void FormManager::ForEachMatchingFormField(FormElement* form, Node* node, RequirementsMask requirements, const FormData& data, Callback* callback) {
+ // 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->control_elements.size() && j < data.fields.size(); ++i) {
+ HTMLFormControlElement* element = form->control_elements[i].get();
+ string16 element_name = nameForAutoFill(*element);
+
+ if (element_name.empty())
+ continue;
+
+ // Search forward in the |form| for a corresponding field.
+ size_t k = j;
+ while (k < data.fields.size() && element_name != data.fields[k].name())
+ k++;
+
+ if (k >= data.fields.size())
+ continue;
+
+ DCHECK_EQ(data.fields[k].name(), element_name);
+
+ bool is_initiating_node = false;
+
+ // More than likely |requirements| will contain REQUIRE_AUTOCOMPLETE and/or
+ // REQUIRE_EMPTY, which both require text form control elements, so special-
+ // case this type of element.
+ if (formControlType(*element) == kText) {
+ HTMLInputElement* input_element = static_cast<HTMLInputElement*>(element);
+
+ // TODO: WebKit currently doesn't handle the autocomplete
+ // attribute for select control elements, but it probably should.
+ if (requirements & REQUIRE_AUTOCOMPLETE && !input_element->autoComplete())
+ continue;
+
+ is_initiating_node = (input_element == node);
+ // Don't require the node that initiated the auto-fill process to be
+ // empty. The user is typing in this field and we should complete the
+ // value when the user selects a value to fill out.
+ if (requirements & REQUIRE_EMPTY && !is_initiating_node && !input_element->value().isEmpty())
+ continue;
+ }
+
+ if (requirements & REQUIRE_ENABLED && !element->isEnabledFormControl())
+ continue;
+
+ callback->Run(element, &data.fields[k], is_initiating_node);
+
+ // We found a matching form field so move on to the next.
+ ++j;
+ }
+
+ delete callback;
+}
+
+void FormManager::FillFormField(HTMLFormControlElement* field, const FormField* data, bool is_initiating_node) {
+ // Nothing to fill.
+ if (data->value().empty())
+ return;
+
+ if (formControlType(*field) == kText) {
+ HTMLInputElement* input_element = static_cast<HTMLInputElement*>(field);
+
+ // If the maxlength attribute contains a negative value, maxLength()
+ // returns the default maxlength value.
+ input_element->setValue(data->value().substr(0, input_element->maxLength()).c_str());
+ input_element->setAutofilled(true);
+ if (is_initiating_node) {
+ int length = input_element->value().length();
+ input_element->setSelectionRange(length, length);
+ }
+ } else if (formControlType(*field) == kSelectOne) {
+ HTMLSelectElement* select_element = static_cast<HTMLSelectElement*>(field);
+ select_element->setValue(data->value().c_str());
+ }
+}
+
+void FormManager::PreviewFormField(HTMLFormControlElement* field, const FormField* data, bool is_initiating_node) {
+ // Nothing to preview.
+ if (data->value().empty())
+ return;
+
+ // Only preview input fields.
+ if (formControlType(*field) != kText)
+ return;
+
+ HTMLInputElement* input_element = static_cast<HTMLInputElement*>(field);
+
+ // If the maxlength attribute contains a negative value, maxLength()
+ // returns the default maxlength value.
+ input_element->setSuggestedValue(data->value().substr(0, input_element->maxLength()).c_str());
+ input_element->setAutofilled(true);
+ if (is_initiating_node)
+ input_element->setSelectionRange(0, input_element->suggestedValue().length());
+}
+
+}
diff --git a/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h b/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h
new file mode 100644
index 0000000..e844981
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/autofill/FormManagerAndroid.h
@@ -0,0 +1,187 @@
+/*
+ * 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 Frame;
+class HTMLFormControlElement;
+class HTMLFormElement;
+class Node;
+}
+
+using WebCore::Frame;
+using WebCore::HTMLFormControlElement;
+using WebCore::HTMLFormElement;
+using WebCore::Node;
+
+namespace android {
+
+// Manages the forms in a Document.
+class FormManager {
+public:
+ // A bit field mask for form requirements.
+ enum RequirementsMask {
+ REQUIRE_NONE = 0, // No requirements.
+ REQUIRE_AUTOCOMPLETE = 1 << 0, // Require that autocomplete != off.
+ REQUIRE_ENABLED = 1 << 1, // Require that disabled attribute is off.
+ REQUIRE_EMPTY = 1 << 2, // Require that the fields are empty.
+ };
+
+ // A bit field mask to extract data from HTMLFormControlElement.
+ enum ExtractMask {
+ EXTRACT_NONE = 0,
+ EXTRACT_VALUE = 1 << 0, // Extract value from HTMLFormControlElement.
+ EXTRACT_OPTION_TEXT = 1 << 1, // Extract option text from HTMLFormSelectElement. Only valid when |EXTRACT_VALUE| is set. This is used for form submission where humand readable value is captured.
+ EXTRACT_OPTIONS = 1 << 2, // Extract options from HTMLFormControlElement.
+ };
+
+ FormManager();
+ virtual ~FormManager();
+
+ // Fills out a FormField object from a given HTMLFormControlElement.
+ // |extract_mask|: See the enum ExtractMask above for details.
+ static void HTMLFormControlElementToFormField(HTMLFormControlElement* element, ExtractMask extract_mask, 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 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(HTMLFormElement* element, RequirementsMask requirements, ExtractMask extract_mask, webkit_glue::FormData* form);
+
+ // Scans the DOM in |frame| extracting and storing forms.
+ void ExtractForms(Frame* frame);
+
+ // Returns a vector of forms in |frame| that match |requirements|.
+ void GetFormsInFrame(const Frame* frame, RequirementsMask requirements, std::vector<webkit_glue::FormData>* forms);
+
+ // Finds the form that contains |element| and returns it in |form|. Returns
+ // false if the form is not found.
+ bool FindFormWithFormControlElement(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. |node| is the form
+ // control element that initiated the auto-fill process.
+ // 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, Node* node);
+
+ // Previews the form represented by |form|. |node| is the form control element
+ // that initiated the preview process. Same conditions as FillForm.
+ bool PreviewForm(const webkit_glue::FormData& form, Node* node);
+
+ // Clears the values of all input elements in the form that contains |node|.
+ // Returns false if the form is not found.
+ bool ClearFormWithNode(Node* node);
+
+ // Clears the placeholder values and the auto-filled background for any fields
+ // in the form containing |node| that have been previewed. Resets the
+ // autofilled state of |node| to |was_autofilled|. Returns false if the form
+ // is not found.
+ bool ClearPreviewedFormWithNode(Node* node, bool was_autofilled);
+
+ // Resets the stored set of forms.
+ void Reset();
+
+ // Resets the forms for the specified |frame|.
+ void ResetFrame(const Frame* frame);
+
+ // Returns true if |form| has any auto-filled fields.
+ bool FormWithNodeIsAutoFilled(Node* node);
+
+private:
+ // Stores the HTMLFormElement and the form control elements for a form.
+ // Original form values are stored so when we clear a form we can reset
+ // "select-one" values to their original state.
+ struct FormElement;
+
+ // Type for cache of FormElement objects.
+ typedef std::vector<FormElement*> FormElementList;
+
+ // The callback type used by ForEachMatchingFormField().
+ typedef Callback3<HTMLFormControlElement*, const webkit_glue::FormField*, bool>::Type Callback;
+
+ // 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 HTMLFormControlElement& element);
+
+ // Finds the cached FormElement that contains |node|.
+ bool FindCachedFormElementWithNode(Node* node, FormElement** form_element);
+
+ // Uses the data in |form| to find the cached FormElement.
+ bool FindCachedFormElement(const webkit_glue::FormData& form, FormElement** form_element);
+
+ // For each field in |data| that matches the corresponding field in |form|
+ // and meets the |requirements|, |callback| is called with the actual
+ // WebFormControlElement and the FormField data from |form|. The field that
+ // matches |node| is not required to be empty if |requirements| includes
+ // REQUIRE_EMPTY. This method owns |callback|.
+ void ForEachMatchingFormField(FormElement* form, Node* node, RequirementsMask requirements, const webkit_glue::FormData& data, Callback* callback);
+
+ // A ForEachMatchingFormField() callback that sets |field|'s value using the
+ // value in |data|. This method also sets the autofill attribute, causing the
+ // background to be yellow.
+ void FillFormField(HTMLFormControlElement* field, const webkit_glue::FormField* data, bool is_initiating_node);
+
+ // A ForEachMatchingFormField() callback that sets |field|'s placeholder value
+ // using the value in |data|, causing the test to be greyed-out. This method
+ // also sets the autofill attribute, causing the background to be yellow.
+ void PreviewFormField(HTMLFormControlElement* field, const webkit_glue::FormField* data, bool is_initiaiting_node);
+
+ // The cached FormElement objects.
+ FormElementList form_elements_;
+
+ DISALLOW_COPY_AND_ASSIGN(FormManager);
+};
+
+} // namespace android
+
+#endif // FormManagerAndroid_h
diff --git a/Source/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.cpp b/Source/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.cpp
new file mode 100644
index 0000000..598b9c4
--- /dev/null
+++ b/Source/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/Source/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.h b/Source/WebKit/android/WebCoreSupport/autofill/MainThreadProxy.h
new file mode 100644
index 0000000..d9310bb
--- /dev/null
+++ b/Source/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/Source/WebKit/android/WebCoreSupport/autofill/StringUtils.h b/Source/WebKit/android/WebCoreSupport/autofill/StringUtils.h
new file mode 100644
index 0000000..aa408a5
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/autofill/StringUtils.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2010 The Android Open Source Project. 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.
+ *
+ * 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 AutoFillStringUtils_h_
+#define AutoFillStringUtils_h_
+
+#include "ChromiumIncludes.h"
+#include "HTMLFormControlElement.h"
+#include <wtf/text/WTFString.h>
+
+using WebCore::HTMLFormControlElement;
+
+const string16 kText = ASCIIToUTF16("text");
+const string16 kHidden = ASCIIToUTF16("hidden");
+const string16 kSelectOne = ASCIIToUTF16("select-one");
+
+inline string16 WTFStringToString16(const WTF::String& wtfString)
+{
+ WTF::String str = wtfString;
+
+ if (str.charactersWithNullTermination())
+ return string16(str.charactersWithNullTermination());
+ else
+ return string16();
+}
+
+inline string16 nameForAutoFill(const HTMLFormControlElement& element)
+{
+ // Taken from WebKit/chromium/src/WebFormControlElement.cpp, ported
+ // to use WebCore types for accessing element properties.
+ String name = element.name();
+ String trimmedName = name.stripWhiteSpace();
+ if (!trimmedName.isEmpty())
+ return WTFStringToString16(trimmedName);
+ name = element.getIdAttribute();
+ trimmedName = name.stripWhiteSpace();
+ if (!trimmedName.isEmpty())
+ return WTFStringToString16(trimmedName);
+ return string16();
+}
+
+inline string16 formControlType(const HTMLFormControlElement& element)
+{
+ // Taken from WebKit/chromium/src/WebFormControlElement.cpp, ported
+ // to use WebCore types for accessing element properties.
+ return WTFStringToString16(element.type());
+}
+
+#endif
+
diff --git a/Source/WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp b/Source/WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp
new file mode 100644
index 0000000..a80636c
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/autofill/WebAutoFill.cpp
@@ -0,0 +1,296 @@
+/*
+ * 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 "Frame.h"
+#include "FormData.h"
+#include "FormManagerAndroid.h"
+#include "FrameLoader.h"
+#include "HTMLFormControlElement.h"
+#include "MainThreadProxy.h"
+#include "Node.h"
+#include "Page.h"
+#include "Settings.h"
+#include "WebFrame.h"
+#include "WebRequestContext.h"
+#include "WebUrlLoaderClient.h"
+#include "WebViewCore.h"
+
+#define NO_PROFILE_SET 0
+#define FORM_NOT_AUTOFILLABLE -1
+
+namespace android
+{
+WebAutoFill::WebAutoFill()
+ : mQueryId(1)
+ , mWebViewCore(0)
+ , mLastSearchDomVersion(0)
+ , mParsingForms(false)
+{
+ mTabContents = new TabContents();
+ setEmptyProfile();
+}
+
+void WebAutoFill::init()
+{
+ if (mAutoFillManager)
+ return;
+
+ mFormManager = new FormManager();
+ // We use the WebView's WebRequestContext, which may be a private browsing context.
+ ASSERT(mWebViewCore);
+ mAutoFillManager = new AutoFillManager(mTabContents.get());
+ mAutoFillHost = new AutoFillHostAndroid(this);
+ mTabContents->SetProfileRequestContext(new AndroidURLRequestContextGetter(mWebViewCore->webRequestContext(), WebUrlLoaderClient::ioThread()));
+ mTabContents->SetAutoFillHost(mAutoFillHost.get());
+}
+
+WebAutoFill::~WebAutoFill()
+{
+ cleanUpQueryMap();
+ mUniqueIdMap.clear();
+}
+
+void WebAutoFill::cleanUpQueryMap()
+{
+ for (AutoFillQueryFormDataMap::iterator it = mQueryMap.begin(); it != mQueryMap.end(); it++)
+ delete it->second;
+ mQueryMap.clear();
+}
+
+void WebAutoFill::searchDocument(WebCore::Frame* frame)
+{
+ if (!enabled())
+ return;
+
+ MutexLocker lock(mFormsSeenMutex);
+
+ init();
+
+ cleanUpQueryMap();
+ mUniqueIdMap.clear();
+ mForms.clear();
+ mQueryId = 1;
+
+ ASSERT(mFormManager);
+ ASSERT(mAutoFillManager);
+
+ mAutoFillManager->Reset();
+ mFormManager->Reset();
+
+ mFormManager->ExtractForms(frame);
+ mFormManager->GetFormsInFrame(frame, FormManager::REQUIRE_AUTOCOMPLETE, &mForms);
+
+ // Needs to be done on a Chrome thread as it will make a URL request to the AutoFill server.
+ // TODO: Use our own Autofill thread instead of the IO thread.
+ // TODO: For now, block here. Would like to make this properly async.
+ base::Thread* thread = WebUrlLoaderClient::ioThread();
+ mParsingForms = true;
+ thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, &WebAutoFill::formsSeenImpl));
+ while (mParsingForms)
+ mFormsSeenCondition.wait(mFormsSeenMutex);
+}
+
+// Called on the Chromium IO thread.
+void WebAutoFill::formsSeenImpl()
+{
+ MutexLocker lock(mFormsSeenMutex);
+ mAutoFillManager->FormsSeen(mForms);
+ mParsingForms = false;
+ mFormsSeenCondition.signal();
+}
+
+void WebAutoFill::formFieldFocused(WebCore::HTMLFormControlElement* formFieldElement)
+{
+ ASSERT(formFieldElement);
+
+ Document* doc = formFieldElement->document();
+ Frame* frame = doc->frame();
+
+ // FIXME: AutoFill only works in main frame for now. Should consider
+ // child frames.
+ if (frame != frame->page()->mainFrame())
+ return;
+
+ unsigned domVersion = doc->domTreeVersion();
+ ASSERT(domVersion > 0);
+
+ if (mLastSearchDomVersion != domVersion) {
+ // Need to extract forms as DOM version has changed since the last time
+ // we searched.
+ searchDocument(formFieldElement->document()->frame());
+ mLastSearchDomVersion = domVersion;
+ }
+
+ if (!enabled()) {
+ // In case that we've just been disabled and the last time we got autofill
+ // suggestions and told Java about them, clear that bit Java side now
+ // we're disabled.
+ mWebViewCore->setWebTextViewAutoFillable(FORM_NOT_AUTOFILLABLE, string16());
+ return;
+ }
+
+ // Get the FormField from the Node.
+ webkit_glue::FormField* formField = new webkit_glue::FormField;
+ FormManager::HTMLFormControlElementToFormField(formFieldElement, FormManager::EXTRACT_NONE, formField);
+ formField->set_label(FormManager::LabelForElement(*formFieldElement));
+
+ webkit_glue::FormData* form = new webkit_glue::FormData;
+ mFormManager->FindFormWithFormControlElement(formFieldElement, FormManager::REQUIRE_AUTOCOMPLETE, form);
+ mQueryMap[mQueryId] = new FormDataAndField(form, formField);
+
+ bool suggestions = mAutoFillManager->GetAutoFillSuggestions(*form, *formField);
+
+ mQueryId++;
+ if (!suggestions) {
+ ASSERT(mWebViewCore);
+ // Tell Java no autofill suggestions for this form.
+ mWebViewCore->setWebTextViewAutoFillable(FORM_NOT_AUTOFILLABLE, string16());
+ return;
+ }
+}
+
+void WebAutoFill::querySuccessful(const string16& value, const string16& label, int uniqueId)
+{
+ if (!enabled())
+ return;
+
+ // Store the unique ID for the query and inform java that autofill suggestions for this form are available.
+ // Pass java the queryId so that it can pass it back if the user decides to use autofill.
+ mUniqueIdMap[mQueryId] = uniqueId;
+
+ ASSERT(mWebViewCore);
+ mWebViewCore->setWebTextViewAutoFillable(mQueryId, mAutoFillProfile->Label());
+}
+
+void WebAutoFill::fillFormFields(int queryId)
+{
+ if (!enabled())
+ return;
+
+ webkit_glue::FormData* form = mQueryMap[queryId]->form();
+ webkit_glue::FormField* field = mQueryMap[queryId]->field();
+ ASSERT(form);
+ ASSERT(field);
+
+ AutoFillQueryToUniqueIdMap::iterator iter = mUniqueIdMap.find(queryId);
+ if (iter == mUniqueIdMap.end()) {
+ // The user has most likely tried to AutoFill the form again without
+ // refocussing the form field. The UI should protect against this
+ // but stop here to be certain.
+ return;
+ }
+ mAutoFillManager->FillAutoFillFormData(queryId, *form, *field, iter->second);
+ mUniqueIdMap.erase(iter);
+}
+
+void WebAutoFill::fillFormInPage(int queryId, const webkit_glue::FormData& form)
+{
+ if (!enabled())
+ return;
+
+ // FIXME: Pass a pointer to the Node that triggered the AutoFill flow here instead of 0.
+ // The consquence of passing 0 is that we should always fail the test in FormManader::ForEachMathcingFormField():169
+ // that says "only overwrite an elements current value if the user triggered autofill through that element"
+ // for elements that have a value already. But by a quirk of Android text views we are OK. We should still
+ // fix this though.
+ mFormManager->FillForm(form, 0);
+}
+
+bool WebAutoFill::enabled() const
+{
+ Page* page = mWebViewCore->mainFrame()->page();
+ return page ? page->settings()->autoFillEnabled() : false;
+}
+
+void WebAutoFill::setProfile(const string16& fullName, const string16& emailAddress, const string16& companyName,
+ const string16& addressLine1, const string16& addressLine2, const string16& city,
+ const string16& state, const string16& zipCode, const string16& country, const string16& phoneNumber)
+{
+ if (!mAutoFillProfile)
+ mAutoFillProfile.set(new AutoFillProfile());
+
+ // Update the profile.
+ // Constants for AutoFill field types are found in external/chromium/chrome/browser/autofill/field_types.h.
+ mAutoFillProfile->SetInfo(AutoFillType(NAME_FULL), fullName);
+ mAutoFillProfile->SetInfo(AutoFillType(EMAIL_ADDRESS), emailAddress);
+ mAutoFillProfile->SetInfo(AutoFillType(COMPANY_NAME), companyName);
+ mAutoFillProfile->SetInfo(AutoFillType(ADDRESS_HOME_LINE1), addressLine1);
+ mAutoFillProfile->SetInfo(AutoFillType(ADDRESS_HOME_LINE2), addressLine2);
+ mAutoFillProfile->SetInfo(AutoFillType(ADDRESS_HOME_CITY), city);
+ mAutoFillProfile->SetInfo(AutoFillType(ADDRESS_HOME_STATE), state);
+ mAutoFillProfile->SetInfo(AutoFillType(ADDRESS_HOME_ZIP), zipCode);
+ mAutoFillProfile->SetInfo(AutoFillType(ADDRESS_HOME_COUNTRY), country);
+ mAutoFillProfile->SetInfo(AutoFillType(PHONE_HOME_WHOLE_NUMBER), phoneNumber);
+
+ std::vector<AutoFillProfile> profiles;
+ profiles.push_back(*mAutoFillProfile);
+ updateProfileLabel();
+ mTabContents->profile()->GetPersonalDataManager()->SetProfiles(&profiles);
+}
+
+bool WebAutoFill::updateProfileLabel()
+{
+ std::vector<AutoFillProfile*> profiles;
+ profiles.push_back(mAutoFillProfile.get());
+ return AutoFillProfile::AdjustInferredLabels(&profiles);
+}
+
+void WebAutoFill::clearProfiles()
+{
+ if (!mAutoFillProfile)
+ return;
+ // For now Chromium only ever knows about one profile, so we can just
+ // remove it. If we support multiple profiles in the future
+ // we need to remove them all here.
+ std::string profileGuid = mAutoFillProfile->guid();
+ mTabContents->profile()->GetPersonalDataManager()->RemoveProfile(profileGuid);
+ setEmptyProfile();
+}
+
+void WebAutoFill::setEmptyProfile()
+{
+ // Set an empty profile. This will ensure that when autofill is enabled,
+ // we will still search the document for autofillable forms and inform
+ // java of their presence so we can invite the user to set up
+ // their own profile.
+
+ // Chromium code will strip the values sent into the profile so we need them to be
+ // at least one non-whitespace character long. We need to set all fields of the
+ // profile to a non-empty string so that any field type can trigger the autofill
+ // suggestion. AutoFill will not detect form fields if the profile value for that
+ // field is an empty string.
+ static const string16 empty = string16(ASCIIToUTF16("a"));
+ setProfile(empty, empty, empty, empty, empty, empty, empty, empty, empty, empty);
+}
+
+}
+
+#endif
diff --git a/Source/WebKit/android/WebCoreSupport/autofill/WebAutoFill.h b/Source/WebKit/android/WebCoreSupport/autofill/WebAutoFill.h
new file mode 100644
index 0000000..97e478e
--- /dev/null
+++ b/Source/WebKit/android/WebCoreSupport/autofill/WebAutoFill.h
@@ -0,0 +1,127 @@
+/*
+ * 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>
+#include <wtf/ThreadingPrimitives.h>
+
+class AutoFillManager;
+class AutoFillProfile;
+class AutoFillHost;
+
+namespace WebCore {
+class Frame;
+class HTMLFormControlElement;
+}
+
+namespace android
+{
+class FormManager;
+class WebViewCore;
+
+class FormDataAndField {
+public:
+ FormDataAndField(webkit_glue::FormData* form, webkit_glue::FormField* field)
+ : mForm(form)
+ , mField(field)
+ {
+ }
+
+ webkit_glue::FormData* form() { return mForm.get(); }
+ webkit_glue::FormField* field() { return mField.get(); }
+
+private:
+ OwnPtr<webkit_glue::FormData> mForm;
+ OwnPtr<webkit_glue::FormField> mField;
+};
+
+class WebAutoFill : public Noncopyable
+{
+public:
+ WebAutoFill();
+ virtual ~WebAutoFill();
+ void formFieldFocused(WebCore::HTMLFormControlElement*);
+ void fillFormFields(int queryId);
+ void querySuccessful(const string16& value, const string16& label, int uniqueId);
+ void fillFormInPage(int queryId, const webkit_glue::FormData& form);
+ void setWebViewCore(WebViewCore* webViewCore) { mWebViewCore = webViewCore; }
+ bool enabled() const;
+
+ void setProfile(const string16& fullName, const string16& emailAddress, const string16& companyName,
+ const string16& addressLine1, const string16& addressLine2, const string16& city,
+ const string16& state, const string16& zipCode, const string16& country, const string16& phoneNumber);
+ void clearProfiles();
+
+ bool updateProfileLabel();
+
+ void reset() { mLastSearchDomVersion = 0; }
+
+private:
+ void init();
+ void searchDocument(WebCore::Frame*);
+ void setEmptyProfile();
+ void formsSeenImpl();
+ void cleanUpQueryMap();
+
+ OwnPtr<FormManager> mFormManager;
+ OwnPtr<AutoFillManager> mAutoFillManager;
+ OwnPtr<AutoFillHost> mAutoFillHost;
+ OwnPtr<TabContents> mTabContents;
+ OwnPtr<AutoFillProfile> mAutoFillProfile;
+
+ typedef std::vector<webkit_glue::FormData, std::allocator<webkit_glue::FormData> > FormList;
+ FormList mForms;
+
+ typedef std::map<int, FormDataAndField*> AutoFillQueryFormDataMap;
+ AutoFillQueryFormDataMap mQueryMap;
+
+ typedef std::map<int, int> AutoFillQueryToUniqueIdMap;
+ AutoFillQueryToUniqueIdMap mUniqueIdMap;
+ int mQueryId;
+
+ WebViewCore* mWebViewCore;
+
+ unsigned mLastSearchDomVersion;
+
+ WTF::Mutex mFormsSeenMutex; // Guards mFormsSeenCondition and mParsingForms.
+ WTF::ThreadCondition mFormsSeenCondition;
+ bool volatile mParsingForms;
+};
+
+}
+
+DISABLE_RUNNABLE_METHOD_REFCOUNT(android::WebAutoFill);
+
+#endif // ENABLE(WEB_AUTOFILL)
+#endif // WebAutoFill_h