summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2009-08-18 11:35:14 +0100
committerBen Murdoch <benm@google.com>2009-08-18 11:35:14 +0100
commite0330ac957b8434cd2c9c7b5447aaa0faabe77ec (patch)
tree395ba85351595e79b5e357e46af5c28a0dcb5211
parentb32f88b61a9162a5194ab02c12fc3aff6140e30e (diff)
parent8ca4160fde81af362cf2ea375997797b1df8243d (diff)
downloadexternal_webkit-e0330ac957b8434cd2c9c7b5447aaa0faabe77ec.zip
external_webkit-e0330ac957b8434cd2c9c7b5447aaa0faabe77ec.tar.gz
external_webkit-e0330ac957b8434cd2c9c7b5447aaa0faabe77ec.tar.bz2
Merge commit 'goog/master' into merge
Conflicts: WebCore/bindings/v8/ScriptController.cpp WebCore/page/Geolocation.cpp WebCore/platform/android/GeolocationServiceAndroid.cpp
-rw-r--r--Android.jsc.mk4
-rw-r--r--Android.v8.mk4
-rw-r--r--V8Binding/Android.v8shell.mk2
-rw-r--r--V8Binding/v8/include/v8.h8
-rw-r--r--V8Binding/v8/src/api.cc9
-rw-r--r--WebCore/bindings/js/JSGeolocationCustom.cpp151
-rw-r--r--WebCore/bindings/v8/ScriptController.cpp7
-rw-r--r--WebCore/html/HTMLBodyElement.cpp13
-rw-r--r--WebCore/html/HTMLMetaElement.cpp8
-rw-r--r--WebCore/page/Geolocation.cpp136
-rw-r--r--WebCore/page/Geolocation.h22
-rw-r--r--WebCore/page/PositionError.h6
-rw-r--r--WebCore/page/PositionOptions.h37
-rw-r--r--WebCore/page/SecurityOrigin.cpp7
-rw-r--r--WebCore/platform/android/GeolocationServiceAndroid.cpp361
-rw-r--r--WebCore/platform/android/GeolocationServiceAndroid.h73
-rw-r--r--WebCore/plugins/PluginPackage.cpp5
-rw-r--r--WebCore/plugins/PluginPackage.h3
-rw-r--r--WebCore/plugins/android/PluginPackageAndroid.cpp106
-rw-r--r--WebCore/rendering/RenderPartObject.cpp109
-rw-r--r--WebKit/Android.mk1
-rw-r--r--WebKit/android/TimeCounter.cpp2
-rw-r--r--WebKit/android/TimeCounter.h18
-rw-r--r--WebKit/android/WebCoreSupport/EditorClientAndroid.cpp20
-rw-r--r--WebKit/android/WebCoreSupport/EditorClientAndroid.h11
-rw-r--r--WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp25
-rwxr-xr-xWebKit/android/jni/MockGeolocation.cpp96
-rw-r--r--WebKit/android/jni/WebCoreFrameBridge.cpp3
-rw-r--r--WebKit/android/jni/WebCoreJniOnLoad.cpp4
-rw-r--r--WebKit/android/jni/WebViewCore.cpp79
-rw-r--r--WebKit/android/jni/WebViewCore.h13
-rw-r--r--WebKit/android/nav/WebView.cpp39
-rw-r--r--WebKit/android/plugins/android_npapi.h140
33 files changed, 1165 insertions, 357 deletions
diff --git a/Android.jsc.mk b/Android.jsc.mk
index 2643afd..be45278 100644
--- a/Android.jsc.mk
+++ b/Android.jsc.mk
@@ -207,6 +207,10 @@ LOCAL_SHARED_LIBRARIES := \
libicui18n \
libmedia
+ifeq ($(WEBCORE_INSTRUMENTATION),true)
+LOCAL_SHARED_LIBRARIES += libhardware_legacy
+endif
+
# We have to use the android version of libdl when we are not on the simulator
ifneq ($(TARGET_SIMULATOR),true)
LOCAL_SHARED_LIBRARIES += libdl
diff --git a/Android.v8.mk b/Android.v8.mk
index e9cad06..1ba09c6 100644
--- a/Android.v8.mk
+++ b/Android.v8.mk
@@ -191,6 +191,10 @@ LOCAL_SHARED_LIBRARIES := \
libicui18n \
libmedia
+ifeq ($(WEBCORE_INSTRUMENTATION),true)
+LOCAL_SHARED_LIBRARIES += libhardware_legacy
+endif
+
# We have to use the android version of libdl when we are not on the simulator
ifneq ($(TARGET_SIMULATOR),true)
LOCAL_SHARED_LIBRARIES += libdl
diff --git a/V8Binding/Android.v8shell.mk b/V8Binding/Android.v8shell.mk
index 09a77ef..e8790f1 100644
--- a/V8Binding/Android.v8shell.mk
+++ b/V8Binding/Android.v8shell.mk
@@ -9,6 +9,8 @@ LOCAL_CPP_EXTENSION := .cc
LOCAL_STATIC_LIBRARIES := libv8
LOCAL_SHARED_LIBRARIES := libcutils
+LOCAL_MODULE_TAGS := optional
+
LOCAL_C_INCLUDES += $(LOCAL_PATH)/v8/include
include $(BUILD_EXECUTABLE)
diff --git a/V8Binding/v8/include/v8.h b/V8Binding/v8/include/v8.h
index 83d5bed..6815ec9 100644
--- a/V8Binding/v8/include/v8.h
+++ b/V8Binding/v8/include/v8.h
@@ -2184,6 +2184,14 @@ class V8EXPORT V8 {
*/
static int GetLogLines(int from_pos, char* dest_buf, int max_size);
+#if defined(ANDROID)
+ /**
+ * Android system sends the browser low memory signal, and it is good to
+ * collect JS heap, which can free some DOM nodes.
+ * This function should ONLY be used by the browser in low memory condition.
+ */
+ static void CollectAllGarbage();
+#endif
/**
* Releases any resources used by v8 and stops any utility threads
diff --git a/V8Binding/v8/src/api.cc b/V8Binding/v8/src/api.cc
index 0f0d002..3eb6d60 100644
--- a/V8Binding/v8/src/api.cc
+++ b/V8Binding/v8/src/api.cc
@@ -2590,7 +2590,8 @@ Persistent<Context> v8::Context::New(
{
ENTER_V8;
#if defined(ANDROID)
- // On mobile devices, full GC is expensive.
+ // On mobile device, full GC is expensive, leave it to the system to
+ // decide when should make a full GC.
#else
// Give the heap a chance to cleanup if we've disposed contexts.
i::Heap::CollectAllGarbageIfContextDisposed();
@@ -3297,6 +3298,12 @@ int V8::GetLogLines(int from_pos, char* dest_buf, int max_size) {
return 0;
}
+
+void V8::CollectAllGarbage() {
+ i::Heap::CollectAllGarbage();
+}
+
+
String::Utf8Value::Utf8Value(v8::Handle<v8::Value> obj) {
EnsureInitialized("v8::String::Utf8Value::Utf8Value()");
if (obj.IsEmpty()) {
diff --git a/WebCore/bindings/js/JSGeolocationCustom.cpp b/WebCore/bindings/js/JSGeolocationCustom.cpp
index 493166c..6379a1c 100644
--- a/WebCore/bindings/js/JSGeolocationCustom.cpp
+++ b/WebCore/bindings/js/JSGeolocationCustom.cpp
@@ -20,7 +20,7 @@
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
@@ -36,112 +36,129 @@
#include "PositionOptions.h"
using namespace JSC;
+using namespace std;
namespace WebCore {
-static PassRefPtr<PositionOptions> createPositionOptions(ExecState* exec, JSValue value)
+static PassRefPtr<PositionCallback> createPositionCallback(ExecState* exec, JSValue value)
{
- if (!value.isObject())
+ // The spec specifies 'FunctionOnly' for this object.
+ if (!value.isObject(&InternalFunction::info)) {
+ setDOMException(exec, TYPE_MISMATCH_ERR);
return 0;
+ }
JSObject* object = asObject(value);
+ Frame* frame = toJSDOMWindow(exec->lexicalGlobalObject())->impl()->frame();
+ return JSCustomPositionCallback::create(object, frame);
+}
- JSValue enableHighAccuracyValue = object->get(exec, Identifier(exec, "enableHighAccuracy"));
- if (exec->hadException())
+static PassRefPtr<PositionErrorCallback> createPositionErrorCallback(ExecState* exec, JSValue value)
+{
+ // Argument is optional (hence undefined is allowed), and null is allowed.
+ if (value.isUndefinedOrNull())
return 0;
- bool enableHighAccuracy = enableHighAccuracyValue.toBoolean(exec);
- if (exec->hadException())
+
+ // The spec specifies 'FunctionOnly' for this object.
+ if (!value.isObject(&InternalFunction::info)) {
+ setDOMException(exec, TYPE_MISMATCH_ERR);
return 0;
+ }
- JSValue timeoutValue = object->get(exec, Identifier(exec, "timeout"));
+ JSObject* object = asObject(value);
+ Frame* frame = toJSDOMWindow(exec->lexicalGlobalObject())->impl()->frame();
+ return JSCustomPositionErrorCallback::create(object, frame);
+}
+
+static PassRefPtr<PositionOptions> createPositionOptions(ExecState* exec, JSValue value)
+{
+ // Create default options.
+ RefPtr<PositionOptions> options = PositionOptions::create();
+
+ // Argument is optional (hence undefined is allowed), and null is allowed.
+ if (value.isUndefinedOrNull()) {
+ // Use default options.
+ return options.release();
+ }
+
+ // Given the above test, this will always yield an object.
+ JSObject* object = value.toObject(exec);
+
+ // For all three properties, we apply the following ...
+ // - If the getter or the property's valueOf method throws an exception, we
+ // quit so as not to risk overwriting the exception.
+ // - If the value is absent or undefined, we don't override the default.
+ JSValue enableHighAccuracyValue = object->get(exec, Identifier(exec, "enableHighAccuracy"));
if (exec->hadException())
return 0;
- unsigned timeout = timeoutValue.toUInt32(exec);
+ if(!enableHighAccuracyValue.isUndefined()) {
+ options->setEnableHighAccuracy(enableHighAccuracyValue.toBoolean(exec));
+ if (exec->hadException())
+ return 0;
+ }
+
+ JSValue timeoutValue = object->get(exec, Identifier(exec, "timeout"));
if (exec->hadException())
return 0;
+ if (!timeoutValue.isUndefined()) {
+ // Wrap to int32 and force non-negative to match behavior of window.setTimeout.
+ options->setTimeout(max(0, timeoutValue.toInt32(exec)));
+ if (exec->hadException())
+ return 0;
+ }
JSValue maximumAgeValue = object->get(exec, Identifier(exec, "maximumAge"));
if (exec->hadException())
return 0;
- unsigned maximumAge = maximumAgeValue.toUInt32(exec);
- if (exec->hadException())
- return 0;
+ if (!maximumAgeValue.isUndefined()) {
+ // Wrap to int32 and force non-negative to match behavior of window.setTimeout.
+ options->setMaximumAge(max(0, maximumAgeValue.toInt32(exec)));
+ if (exec->hadException())
+ return 0;
+ }
- return PositionOptions::create(enableHighAccuracy, timeout, maximumAge);
+ return options.release();
}
JSValue JSGeolocation::getCurrentPosition(ExecState* exec, const ArgList& args)
{
// Arguments: PositionCallback, (optional)PositionErrorCallback, (optional)PositionOptions
- RefPtr<PositionCallback> positionCallback;
- JSObject* object = args.at(0).getObject();
+
+ RefPtr<PositionCallback> positionCallback = createPositionCallback(exec, args.at(0));
if (exec->hadException())
return jsUndefined();
- if (!object) {
- setDOMException(exec, TYPE_MISMATCH_ERR);
+ ASSERT(positionCallback);
+
+ RefPtr<PositionErrorCallback> positionErrorCallback = createPositionErrorCallback(exec, args.at(1));
+ if (exec->hadException())
return jsUndefined();
- }
- if (Frame* frame = toJSDOMWindow(exec->lexicalGlobalObject())->impl()->frame())
- positionCallback = JSCustomPositionCallback::create(object, frame);
-
- RefPtr<PositionErrorCallback> positionErrorCallback;
- if (!args.at(1).isUndefinedOrNull()) {
- JSObject* object = args.at(1).getObject();
- if (!object) {
- setDOMException(exec, TYPE_MISMATCH_ERR);
- return jsUndefined();
- }
-
- if (Frame* frame = toJSDOMWindow(exec->lexicalGlobalObject())->impl()->frame())
- positionErrorCallback = JSCustomPositionErrorCallback::create(object, frame);
- }
-
- RefPtr<PositionOptions> positionOptions;
- if (!args.at(2).isUndefinedOrNull()) {
- positionOptions = createPositionOptions(exec, args.at(2));
- if (exec->hadException())
- return jsUndefined();
- }
+ RefPtr<PositionOptions> positionOptions = createPositionOptions(exec, args.at(2));
+ if (exec->hadException())
+ return jsUndefined();
+ ASSERT(positionOptions);
m_impl->getCurrentPosition(positionCallback.release(), positionErrorCallback.release(), positionOptions.release());
-
return jsUndefined();
}
JSValue JSGeolocation::watchPosition(ExecState* exec, const ArgList& args)
{
// Arguments: PositionCallback, (optional)PositionErrorCallback, (optional)PositionOptions
- RefPtr<PositionCallback> positionCallback;
- JSObject* object = args.at(0).getObject();
+
+ RefPtr<PositionCallback> positionCallback = createPositionCallback(exec, args.at(0));
if (exec->hadException())
return jsUndefined();
- if (!object) {
- setDOMException(exec, TYPE_MISMATCH_ERR);
+ ASSERT(positionCallback);
+
+ RefPtr<PositionErrorCallback> positionErrorCallback = createPositionErrorCallback(exec, args.at(1));
+ if (exec->hadException())
return jsUndefined();
- }
-
- if (Frame* frame = toJSDOMWindow(exec->lexicalGlobalObject())->impl()->frame())
- positionCallback = JSCustomPositionCallback::create(object, frame);
-
- RefPtr<PositionErrorCallback> positionErrorCallback;
- if (!args.at(1).isUndefinedOrNull()) {
- JSObject* object = args.at(1).getObject();
- if (!object) {
- setDOMException(exec, TYPE_MISMATCH_ERR);
- return jsUndefined();
- }
-
- if (Frame* frame = toJSDOMWindow(exec->lexicalGlobalObject())->impl()->frame())
- positionErrorCallback = JSCustomPositionErrorCallback::create(object, frame);
- }
-
- RefPtr<PositionOptions> positionOptions;
- if (!args.at(2).isUndefinedOrNull()) {
- positionOptions = createPositionOptions(exec, args.at(2));
- if (exec->hadException())
- return jsUndefined();
- }
+
+ RefPtr<PositionOptions> positionOptions = createPositionOptions(exec, args.at(2));
+ if (exec->hadException())
+ return jsUndefined();
+ ASSERT(positionOptions);
int watchID = m_impl->watchPosition(positionCallback.release(), positionErrorCallback.release(), positionOptions.release());
return jsNumber(exec, watchID);
diff --git a/WebCore/bindings/v8/ScriptController.cpp b/WebCore/bindings/v8/ScriptController.cpp
index 9e5f5b5..3c99c61 100644
--- a/WebCore/bindings/v8/ScriptController.cpp
+++ b/WebCore/bindings/v8/ScriptController.cpp
@@ -270,9 +270,12 @@ void ScriptController::collectGarbage()
if (v8Context.IsEmpty())
return;
- v8::Context::Scope scope(v8Context);
-
+ v8::Context::Scope scope(context);
+#if PLATFORM(ANDROID)
+ v8::V8::CollectAllGarbage();
+#else
m_proxy->evaluate(ScriptSourceCode("if (window.gc) void(gc());"), 0);
+#endif
}
bool ScriptController::haveInterpreter() const
diff --git a/WebCore/html/HTMLBodyElement.cpp b/WebCore/html/HTMLBodyElement.cpp
index f81377d..be6663f 100644
--- a/WebCore/html/HTMLBodyElement.cpp
+++ b/WebCore/html/HTMLBodyElement.cpp
@@ -35,6 +35,10 @@
#include "MappedAttribute.h"
#include "ScriptEventListener.h"
+#ifdef ANDROID_META_SUPPORT
+#include "Settings.h"
+#endif
+
namespace WebCore {
using namespace HTMLNames;
@@ -171,6 +175,15 @@ void HTMLBodyElement::insertedIntoDocument()
setAttribute(marginheightAttr, String::number(marginHeight));
}
+#ifdef ANDROID_META_SUPPORT
+ Settings * settings = document()->settings();
+ String host = document()->baseURI().host().lower();
+ if (settings->viewportWidth() == -1 && (host.startsWith("m.") || host.startsWith("mobile.")
+ || host.contains(".m.") || host.contains(".mobile.")))
+ // fit mobile sites directly in the screen
+ settings->setMetadataSettings("width", "device-width");
+#endif
+
// FIXME: This call to scheduleRelayout should not be needed here.
// But without it we hang during WebKit tests; need to fix that and remove this.
if (FrameView* view = document()->view())
diff --git a/WebCore/html/HTMLMetaElement.cpp b/WebCore/html/HTMLMetaElement.cpp
index 48284e3..5d3e925 100644
--- a/WebCore/html/HTMLMetaElement.cpp
+++ b/WebCore/html/HTMLMetaElement.cpp
@@ -27,6 +27,10 @@
#include "HTMLNames.h"
#include "MappedAttribute.h"
+#ifdef ANDROID_META_SUPPORT
+#include "Settings.h"
+#endif
+
namespace WebCore {
using namespace HTMLNames;
@@ -68,6 +72,10 @@ void HTMLMetaElement::process()
return;
if (equalIgnoringCase(name(), "viewport") || equalIgnoringCase(name(), "format-detection"))
document()->processMetadataSettings(m_content);
+ else if (equalIgnoringCase(name(), "HandheldFriendly") && equalIgnoringCase(m_content, "true")
+ && document()->settings()->viewportWidth() == -1)
+ // fit mobile sites directly in the screen
+ document()->settings()->setMetadataSettings("width", "device-width");
#endif
// Get the document to process the tag, but only if we're actually part of DOM tree (changing a meta tag while
// it's not in the tree shouldn't have any effect on the document)
diff --git a/WebCore/page/Geolocation.cpp b/WebCore/page/Geolocation.cpp
index 5337bcc..e57a8b5 100644
--- a/WebCore/page/Geolocation.cpp
+++ b/WebCore/page/Geolocation.cpp
@@ -31,32 +31,56 @@
#include "Document.h"
#include "Frame.h"
#include "Page.h"
-#include "PositionError.h"
namespace WebCore {
-Geolocation::GeoNotifier::GeoNotifier(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options)
- : m_successCallback(successCallback)
+static const char* permissionDeniedErrorMessage = "User denied Geolocation";
+
+Geolocation::GeoNotifier::GeoNotifier(Geolocation* geolocation, PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options)
+ : m_geolocation(geolocation)
+ , m_successCallback(successCallback)
, m_errorCallback(errorCallback)
, m_options(options)
, m_timer(this, &Geolocation::GeoNotifier::timerFired)
+ , m_fatalError(0)
+{
+ ASSERT(m_geolocation);
+ ASSERT(m_successCallback);
+ // If no options were supplied from JS, we should have created a default set
+ // of options in JSGeolocationCustom.cpp.
+ ASSERT(m_options);
+}
+
+void Geolocation::GeoNotifier::setFatalError(PassRefPtr<PositionError> error)
{
+ m_fatalError = error;
+ m_timer.startOneShot(0);
}
-void Geolocation::GeoNotifier::startTimer()
+void Geolocation::GeoNotifier::startTimerIfNeeded()
{
- if (m_errorCallback && m_options)
+ if (m_options->hasTimeout())
m_timer.startOneShot(m_options->timeout() / 1000.0);
}
void Geolocation::GeoNotifier::timerFired(Timer<GeoNotifier>*)
{
- ASSERT(m_errorCallback);
-
m_timer.stop();
- RefPtr<PositionError> error = PositionError::create(PositionError::TIMEOUT, "Timed out");
- m_errorCallback->handleEvent(error.get());
+ if (m_fatalError) {
+ if (m_errorCallback) {
+ m_errorCallback->handleEvent(m_fatalError.get());
+ }
+ // This will cause this notifier to be deleted.
+ m_geolocation->fatalErrorOccurred(this);
+ return;
+ }
+
+ if (m_errorCallback) {
+ RefPtr<PositionError> error = PositionError::create(PositionError::TIMEOUT, "Timed out");
+ m_errorCallback->handleEvent(error.get());
+ }
+ m_geolocation->requestTimedOut(this);
}
Geolocation::Geolocation(Frame* frame)
@@ -81,29 +105,63 @@ void Geolocation::disconnectFrame()
void Geolocation::getCurrentPosition(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options)
{
- RefPtr<GeoNotifier> notifier = GeoNotifier::create(successCallback, errorCallback, options);
+ RefPtr<GeoNotifier> notifier = GeoNotifier::create(this, successCallback, errorCallback, options);
- if (!m_service->startUpdating(notifier->m_options.get())) {
- if (notifier->m_errorCallback) {
- RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, "Unable to Start");
- notifier->m_errorCallback->handleEvent(error.get());
+ // Check whether permissions have already been denied. Note that if this is the case,
+ // the permission state can not change again in the lifetime of this page.
+ if (isDenied()) {
+ RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage);
+ notifier->setFatalError(error.release());
+ } else {
+ if (m_service->startUpdating(notifier->m_options.get()))
+ notifier->startTimerIfNeeded();
+ else {
+ if (notifier->m_errorCallback) {
+ RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, "Unable to Start");
+ notifier->m_errorCallback->handleEvent(error.get());
+ }
+ return;
}
- return;
}
m_oneShots.add(notifier);
+
+}
+
+void Geolocation::fatalErrorOccurred(Geolocation::GeoNotifier* notifier)
+{
+ // This request has failed fatally. Remove it from our lists.
+ m_oneShots.remove(notifier);
+ for (GeoNotifierMap::iterator iter = m_watchers.begin(); iter != m_watchers.end(); ++iter) {
+ if (iter->second == notifier) {
+ m_watchers.remove(iter);
+ break;
+ }
+ }
+
+ if (!hasListeners())
+ m_service->stopUpdating();
}
int Geolocation::watchPosition(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options)
{
- RefPtr<GeoNotifier> notifier = GeoNotifier::create(successCallback, errorCallback, options);
+ RefPtr<GeoNotifier> notifier = GeoNotifier::create(this, successCallback, errorCallback, options);
- if (!m_service->startUpdating(notifier->m_options.get())) {
- if (notifier->m_errorCallback) {
- RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, "Unable to Start");
- notifier->m_errorCallback->handleEvent(error.get());
+ // Check whether permissions have already been denied. Note that if this is the case,
+ // the permission state can not change again in the lifetime of this page.
+ if (isDenied()) {
+ RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage);
+ notifier->setFatalError(error.release());
+ } else {
+ if (m_service->startUpdating(notifier->m_options.get()))
+ notifier->startTimerIfNeeded();
+ else {
+ if (notifier->m_errorCallback) {
+ RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, "Unable to Start");
+ notifier->m_errorCallback->handleEvent(error.get());
+ }
+ return 0;
}
- return 0;
}
static int sIdentifier = 0;
@@ -113,6 +171,15 @@ int Geolocation::watchPosition(PassRefPtr<PositionCallback> successCallback, Pas
return sIdentifier;
}
+void Geolocation::requestTimedOut(GeoNotifier* notifier)
+{
+ // If this is a one-shot request, stop it.
+ m_oneShots.remove(notifier);
+
+ if (!hasListeners())
+ m_service->stopUpdating();
+}
+
void Geolocation::clearWatch(int watchId)
{
m_watchers.remove(watchId);
@@ -138,10 +205,10 @@ void Geolocation::setIsAllowed(bool allowed)
m_allowGeolocation = allowed ? Yes : No;
if (isAllowed()) {
- startTimers();
makeSuccessCallbacks();
} else {
- WTF::RefPtr<WebCore::PositionError> error = WebCore::PositionError::create(PositionError::PERMISSION_DENIED, "User disallowed GeoLocation");
+ WTF::RefPtr<WebCore::PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage);
+ error->setIsFatal(true);
handleError(error.get());
}
}
@@ -201,35 +268,35 @@ void Geolocation::sendPositionToWatchers(Geoposition* position)
sendPosition(copy, position);
}
-void Geolocation::startTimer(Vector<RefPtr<GeoNotifier> >& notifiers)
+void Geolocation::stopTimer(Vector<RefPtr<GeoNotifier> >& notifiers)
{
Vector<RefPtr<GeoNotifier> >::const_iterator end = notifiers.end();
for (Vector<RefPtr<GeoNotifier> >::const_iterator it = notifiers.begin(); it != end; ++it) {
RefPtr<GeoNotifier> notifier = *it;
- notifier->startTimer();
+ notifier->m_timer.stop();
}
}
-void Geolocation::startTimersForOneShots()
+void Geolocation::stopTimersForOneShots()
{
Vector<RefPtr<GeoNotifier> > copy;
copyToVector(m_oneShots, copy);
- startTimer(copy);
+ stopTimer(copy);
}
-void Geolocation::startTimersForWatchers()
+void Geolocation::stopTimersForWatchers()
{
Vector<RefPtr<GeoNotifier> > copy;
copyValuesToVector(m_watchers, copy);
- startTimer(copy);
+ stopTimer(copy);
}
-void Geolocation::startTimers()
+void Geolocation::stopTimers()
{
- startTimersForOneShots();
- startTimersForWatchers();
+ stopTimersForOneShots();
+ stopTimersForWatchers();
}
void Geolocation::handleError(PositionError* error)
@@ -240,6 +307,8 @@ void Geolocation::handleError(PositionError* error)
sendErrorToWatchers(error);
m_oneShots.clear();
+ if (error->isFatal())
+ m_watchers.clear();
if (!hasListeners())
m_service->stopUpdating();
@@ -267,6 +336,9 @@ void Geolocation::geolocationServicePositionChanged(GeolocationService*)
{
ASSERT(m_service->lastPosition());
+ // Stop all currently running timers.
+ stopTimers();
+
if (!isAllowed()) {
// requestPermission() will ask the chrome for permission. This may be
// implemented synchronously or asynchronously. In both cases,
diff --git a/WebCore/page/Geolocation.h b/WebCore/page/Geolocation.h
index a3fd5e8..6681592 100644
--- a/WebCore/page/Geolocation.h
+++ b/WebCore/page/Geolocation.h
@@ -28,6 +28,7 @@
#include "GeolocationService.h"
#include "PositionCallback.h"
+#include "PositionError.h"
#include "PositionErrorCallback.h"
#include "PositionOptions.h"
#include "Timer.h"
@@ -64,6 +65,7 @@ public:
void setIsAllowed(bool);
bool isAllowed() const { return m_allowGeolocation == Yes; }
+ bool isDenied() const { return m_allowGeolocation == No; }
void setShouldClearCache(bool shouldClearCache) { m_shouldClearCache = shouldClearCache; }
bool shouldClearCache() const { return m_shouldClearCache; }
@@ -73,18 +75,21 @@ private:
class GeoNotifier : public RefCounted<GeoNotifier> {
public:
- static PassRefPtr<GeoNotifier> create(PassRefPtr<PositionCallback> positionCallback, PassRefPtr<PositionErrorCallback> positionErrorCallback, PassRefPtr<PositionOptions> options) { return adoptRef(new GeoNotifier(positionCallback, positionErrorCallback, options)); }
+ static PassRefPtr<GeoNotifier> create(Geolocation* geolocation, PassRefPtr<PositionCallback> positionCallback, PassRefPtr<PositionErrorCallback> positionErrorCallback, PassRefPtr<PositionOptions> options) { return adoptRef(new GeoNotifier(geolocation, positionCallback, positionErrorCallback, options)); }
- void startTimer();
+ void setFatalError(PassRefPtr<PositionError> error);
+ void startTimerIfNeeded();
void timerFired(Timer<GeoNotifier>*);
+ Geolocation* m_geolocation;
RefPtr<PositionCallback> m_successCallback;
RefPtr<PositionErrorCallback> m_errorCallback;
RefPtr<PositionOptions> m_options;
Timer<GeoNotifier> m_timer;
+ RefPtr<PositionError> m_fatalError;
private:
- GeoNotifier(PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PassRefPtr<PositionOptions>);
+ GeoNotifier(Geolocation* geolocation, PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PassRefPtr<PositionOptions>);
};
bool hasListeners() const { return !m_oneShots.isEmpty() || !m_watchers.isEmpty(); }
@@ -97,10 +102,10 @@ private:
void sendPositionToOneShots(Geoposition*);
void sendPositionToWatchers(Geoposition*);
- static void startTimer(Vector<RefPtr<GeoNotifier> >&);
- void startTimersForOneShots();
- void startTimersForWatchers();
- void startTimers();
+ static void stopTimer(Vector<RefPtr<GeoNotifier> >&);
+ void stopTimersForOneShots();
+ void stopTimersForWatchers();
+ void stopTimers();
void makeSuccessCallbacks();
void handleError(PositionError*);
@@ -111,6 +116,9 @@ private:
virtual void geolocationServicePositionChanged(GeolocationService*);
virtual void geolocationServiceErrorOccurred(GeolocationService*);
+ void fatalErrorOccurred(GeoNotifier* notifier);
+ void requestTimedOut(GeoNotifier* notifier);
+
typedef HashSet<RefPtr<GeoNotifier> > GeoNotifierSet;
typedef HashMap<int, RefPtr<GeoNotifier> > GeoNotifierMap;
diff --git a/WebCore/page/PositionError.h b/WebCore/page/PositionError.h
index 1d31f3b..c309061 100644
--- a/WebCore/page/PositionError.h
+++ b/WebCore/page/PositionError.h
@@ -45,16 +45,22 @@ public:
ErrorCode code() const { return m_code; }
const String& message() const { return m_message; }
+ void setIsFatal(bool isFatal) { m_isFatal = isFatal; }
+ bool isFatal() { return m_isFatal; }
private:
PositionError(ErrorCode code, const String& message)
: m_code(code)
, m_message(message)
+ , m_isFatal(false)
{
}
ErrorCode m_code;
String m_message;
+ // Whether the error is fatal, such that no request can ever obtain a good
+ // position fix in the future.
+ bool m_isFatal;
};
} // namespace WebCore
diff --git a/WebCore/page/PositionOptions.h b/WebCore/page/PositionOptions.h
index 10845d3..0a7f625 100644
--- a/WebCore/page/PositionOptions.h
+++ b/WebCore/page/PositionOptions.h
@@ -33,26 +33,41 @@ namespace WebCore {
class PositionOptions : public RefCounted<PositionOptions> {
public:
- static PassRefPtr<PositionOptions> create(bool highAccuracy, unsigned timeout, unsigned maximumAge) { return adoptRef(new PositionOptions(highAccuracy, timeout, maximumAge)); }
+ static PassRefPtr<PositionOptions> create() { return adoptRef(new PositionOptions); }
bool enableHighAccuracy() const { return m_highAccuracy; }
void setEnableHighAccuracy(bool enable) { m_highAccuracy = enable; }
- unsigned timeout() const { return m_timeout; }
- void setTimeout(unsigned t) { m_timeout = t; }
- unsigned maximumAge() const { return m_maximumAge; }
- void setMaximumAge(unsigned a) { m_maximumAge = a; }
+ bool hasTimeout() { return m_hasTimeout; }
+ int timeout() const
+ {
+ ASSERT(hasTimeout());
+ return m_timeout;
+ }
+ void setTimeout(int timeout)
+ {
+ ASSERT(timeout >= 0);
+ m_hasTimeout = true;
+ m_timeout = timeout;
+ }
+ int maximumAge() const { return m_maximumAge; }
+ void setMaximumAge(int age)
+ {
+ ASSERT(age >= 0);
+ m_maximumAge = age;
+ }
private:
- PositionOptions(bool highAccuracy, unsigned timeout, unsigned maximumAge)
- : m_highAccuracy(highAccuracy)
- , m_timeout(timeout)
- , m_maximumAge(maximumAge)
+ PositionOptions()
+ : m_highAccuracy(false)
+ , m_hasTimeout(false)
+ , m_maximumAge(0)
{
}
bool m_highAccuracy;
- unsigned m_timeout;
- unsigned m_maximumAge;
+ bool m_hasTimeout;
+ int m_timeout;
+ int m_maximumAge;
};
} // namespace WebCore
diff --git a/WebCore/page/SecurityOrigin.cpp b/WebCore/page/SecurityOrigin.cpp
index baafd4e..14a1b59 100644
--- a/WebCore/page/SecurityOrigin.cpp
+++ b/WebCore/page/SecurityOrigin.cpp
@@ -281,15 +281,16 @@ PassRefPtr<SecurityOrigin> SecurityOrigin::createFromDatabaseIdentifier(const St
if (separator2 == -1)
return create(KURL());
- // Ensure there were at least 2 seperator characters. Some hostnames on intranets have
+ // Ensure there were at least 2 separator characters. Some hostnames on intranets have
// underscores in them, so we'll assume that any additional underscores are part of the host.
- if (separator1 != separator2)
+ if (separator1 == separator2)
return create(KURL());
// Make sure the port section is a valid port number or doesn't exist
bool portOkay;
int port = databaseIdentifier.right(databaseIdentifier.length() - separator2 - 1).toInt(&portOkay);
- if (!portOkay && separator2 + 1 == static_cast<int>(databaseIdentifier.length()))
+ bool portAbsent = (separator2 == static_cast<int>(databaseIdentifier.length()) - 1);
+ if (!(portOkay || portAbsent))
return create(KURL());
if (port < 0 || port > 65535)
diff --git a/WebCore/platform/android/GeolocationServiceAndroid.cpp b/WebCore/platform/android/GeolocationServiceAndroid.cpp
index cd33bc6..e1d34b0 100644
--- a/WebCore/platform/android/GeolocationServiceAndroid.cpp
+++ b/WebCore/platform/android/GeolocationServiceAndroid.cpp
@@ -24,12 +24,365 @@
*/
#include "config.h"
+#include "GeolocationServiceAndroid.h"
-#include "GeolocationService.h"
+#include <JNIHelp.h> // For jniRegisterNativeMethods
+#include <jni_utility.h> // For getJNIEnv
+
+#include "Frame.h"
+#include "Geoposition.h"
+#include "PositionError.h"
+#include "PositionOptions.h"
+#include "WebViewCore.h"
+#include <wtf/CurrentTime.h>
+
+using JSC::Bindings::getJNIEnv;
+using std::max;
namespace WebCore {
-// TODO(steveblock): Implement Geolocation on Android.
-GeolocationService::FactoryFunction* GeolocationService::s_factoryFunction = 0;
+// GeolocationServiceBridge is the bridge to the Java implementation. It manages
+// the lifetime of the Java object. It is an implementation detail of
+// GeolocationServiceAndroid.
+class GeolocationServiceBridge {
+public:
+ typedef GeolocationServiceAndroid ListenerInterface;
+ GeolocationServiceBridge(ListenerInterface* listener);
+ ~GeolocationServiceBridge();
+
+ void start();
+ void setEnableGps(bool enable);
+
+ // Static wrapper functions to hide JNI nastiness.
+ static void newLocationAvailable(JNIEnv *env, jclass, jlong nativeObject, jobject location);
+ static void newErrorAvailable(JNIEnv *env, jclass, jlong nativeObject, jstring message);
+ static PassRefPtr<Geoposition> convertLocationToGeoposition(JNIEnv *env, const jobject &location);
+
+private:
+ void startJavaImplementation();
+ void stopJavaImplementation();
+
+ ListenerInterface* m_listener;
+ jobject m_javaGeolocationServiceObject;
+};
+
+static const char* kJavaGeolocationServiceClass = "android/webkit/GeolocationService";
+enum kJavaGeolocationServiceClassMethods {
+ GEOLOCATION_SERVICE_METHOD_INIT = 0,
+ GEOLOCATION_SERVICE_METHOD_START,
+ GEOLOCATION_SERVICE_METHOD_STOP,
+ GEOLOCATION_SERVICE_METHOD_SET_ENABLE_GPS,
+ GEOLOCATION_SERVICE_METHOD_COUNT,
+};
+static jmethodID javaGeolocationServiceClassMethodIDs[GEOLOCATION_SERVICE_METHOD_COUNT];
+
+static const JNINativeMethod kJavaGeolocationServiceClassNativeMethods[] = {
+ { "nativeNewLocationAvailable", "(JLandroid/location/Location;)V",
+ (void*) GeolocationServiceBridge::newLocationAvailable },
+ { "nativeNewErrorAvailable", "(JLjava/lang/String;)V",
+ (void*) GeolocationServiceBridge::newErrorAvailable }
+};
+
+static const char *kJavaLocationClass = "android/location/Location";
+enum kJavaLocationClassMethods {
+ LOCATION_METHOD_GET_LATITUDE = 0,
+ LOCATION_METHOD_GET_LONGITUDE,
+ LOCATION_METHOD_HAS_ALTITUDE,
+ LOCATION_METHOD_GET_ALTITUDE,
+ LOCATION_METHOD_HAS_ACCURACY,
+ LOCATION_METHOD_GET_ACCURACY,
+ LOCATION_METHOD_HAS_BEARING,
+ LOCATION_METHOD_GET_BEARING,
+ LOCATION_METHOD_HAS_SPEED,
+ LOCATION_METHOD_GET_SPEED,
+ LOCATION_METHOD_GET_TIME,
+ LOCATION_METHOD_COUNT,
+};
+static jmethodID javaLocationClassMethodIDs[LOCATION_METHOD_COUNT];
+
+GeolocationServiceBridge::GeolocationServiceBridge(ListenerInterface* listener)
+ : m_listener(listener)
+ , m_javaGeolocationServiceObject(0)
+{
+ ASSERT(m_listener);
+ startJavaImplementation();
+}
+
+GeolocationServiceBridge::~GeolocationServiceBridge()
+{
+ stopJavaImplementation();
+}
+
+void GeolocationServiceBridge::start()
+{
+ ASSERT(m_javaGeolocationServiceObject);
+ getJNIEnv()->CallVoidMethod(m_javaGeolocationServiceObject,
+ javaGeolocationServiceClassMethodIDs[GEOLOCATION_SERVICE_METHOD_START]);
+}
+
+void GeolocationServiceBridge::setEnableGps(bool enable)
+{
+ ASSERT(m_javaGeolocationServiceObject);
+ getJNIEnv()->CallVoidMethod(m_javaGeolocationServiceObject,
+ javaGeolocationServiceClassMethodIDs[GEOLOCATION_SERVICE_METHOD_SET_ENABLE_GPS],
+ enable);
+}
+
+void GeolocationServiceBridge::newLocationAvailable(JNIEnv* env, jclass, jlong nativeObject, jobject location)
+{
+ ASSERT(nativeObject);
+ ASSERT(location);
+ GeolocationServiceBridge* object = reinterpret_cast<GeolocationServiceBridge*>(nativeObject);
+ object->m_listener->newPositionAvailable(convertLocationToGeoposition(env, location));
+}
+
+void GeolocationServiceBridge::newErrorAvailable(JNIEnv* env, jclass, jlong nativeObject, jstring message)
+{
+ GeolocationServiceBridge* object = reinterpret_cast<GeolocationServiceBridge*>(nativeObject);
+ RefPtr<PositionError> error =
+ PositionError::create(PositionError::POSITION_UNAVAILABLE, android::to_string(env, message));
+ object->m_listener->newErrorAvailable(error.release());
+}
+
+PassRefPtr<Geoposition> GeolocationServiceBridge::convertLocationToGeoposition(JNIEnv *env,
+ const jobject &location)
+{
+ // altitude is optional and may not be supplied.
+ bool hasAltitude =
+ env->CallBooleanMethod(location, javaLocationClassMethodIDs[LOCATION_METHOD_HAS_ALTITUDE]);
+ double altitude =
+ hasAltitude ?
+ env->CallFloatMethod(location, javaLocationClassMethodIDs[LOCATION_METHOD_GET_ALTITUDE]) :
+ 0.0;
+ // accuracy is required, but is not supplied by the emulator.
+ double accuracy =
+ env->CallBooleanMethod(location, javaLocationClassMethodIDs[LOCATION_METHOD_HAS_ACCURACY]) ?
+ env->CallFloatMethod(location, javaLocationClassMethodIDs[LOCATION_METHOD_GET_ACCURACY]) :
+ 0.0;
+ // heading is optional and may not be supplied.
+ bool hasHeading =
+ env->CallBooleanMethod(location, javaLocationClassMethodIDs[LOCATION_METHOD_HAS_BEARING]);
+ double heading =
+ hasHeading ?
+ env->CallFloatMethod(location, javaLocationClassMethodIDs[LOCATION_METHOD_GET_BEARING]) :
+ 0.0;
+ // speed is optional and may not be supplied.
+ bool hasSpeed =
+ env->CallBooleanMethod(location, javaLocationClassMethodIDs[LOCATION_METHOD_HAS_SPEED]);
+ double speed =
+ hasSpeed ?
+ env->CallFloatMethod(location, javaLocationClassMethodIDs[LOCATION_METHOD_GET_SPEED]) :
+ 0.0;
+
+ RefPtr<Coordinates> newCoordinates = WebCore::Coordinates::create(
+ env->CallDoubleMethod(location, javaLocationClassMethodIDs[LOCATION_METHOD_GET_LATITUDE]),
+ env->CallDoubleMethod(location, javaLocationClassMethodIDs[LOCATION_METHOD_GET_LONGITUDE]),
+ hasAltitude, altitude,
+ accuracy,
+ false, 0.0, // altitudeAccuracy not provided.
+ hasHeading, heading,
+ hasSpeed, speed);
+
+ return WebCore::Geoposition::create(
+ newCoordinates.release(),
+ env->CallLongMethod(location, javaLocationClassMethodIDs[LOCATION_METHOD_GET_TIME]));
+}
+
+void GeolocationServiceBridge::startJavaImplementation()
+{
+ JNIEnv* env = getJNIEnv();
+
+ // Get the Java GeolocationService class.
+ jclass javaGeolocationServiceClass = env->FindClass(kJavaGeolocationServiceClass);
+ ASSERT(javaGeolocationServiceClass);
+
+ // Set up the methods we wish to call on the Java GeolocationService class.
+ javaGeolocationServiceClassMethodIDs[GEOLOCATION_SERVICE_METHOD_INIT] =
+ env->GetMethodID(javaGeolocationServiceClass, "<init>", "(J)V");
+ javaGeolocationServiceClassMethodIDs[GEOLOCATION_SERVICE_METHOD_START] =
+ env->GetMethodID(javaGeolocationServiceClass, "start", "()V");
+ javaGeolocationServiceClassMethodIDs[GEOLOCATION_SERVICE_METHOD_STOP] =
+ env->GetMethodID(javaGeolocationServiceClass, "stop", "()V");
+ javaGeolocationServiceClassMethodIDs[GEOLOCATION_SERVICE_METHOD_SET_ENABLE_GPS] =
+ env->GetMethodID(javaGeolocationServiceClass, "setEnableGps", "(Z)V");
+
+ // Create the Java GeolocationService object.
+ jlong nativeObject = reinterpret_cast<jlong>(this);
+ jobject object = env->NewObject(javaGeolocationServiceClass,
+ javaGeolocationServiceClassMethodIDs[GEOLOCATION_SERVICE_METHOD_INIT],
+ nativeObject);
+
+ m_javaGeolocationServiceObject = getJNIEnv()->NewGlobalRef(object);
+ ASSERT(m_javaGeolocationServiceObject);
+
+ // Register to handle calls to native methods of the Java GeolocationService
+ // object. We register once only.
+ static int registered = jniRegisterNativeMethods(env,
+ kJavaGeolocationServiceClass,
+ kJavaGeolocationServiceClassNativeMethods,
+ NELEM(kJavaGeolocationServiceClassNativeMethods));
+ ASSERT(registered == NELEM(kJavaGeolocationServiceClassNativeMethods));
+
+ // Set up the methods we wish to call on the Java Location class.
+ jclass javaLocationClass = env->FindClass(kJavaLocationClass);
+ ASSERT(javaLocationClass);
+ javaLocationClassMethodIDs[LOCATION_METHOD_GET_LATITUDE] =
+ env->GetMethodID(javaLocationClass, "getLatitude", "()D");
+ javaLocationClassMethodIDs[LOCATION_METHOD_GET_LONGITUDE] =
+ env->GetMethodID(javaLocationClass, "getLongitude", "()D");
+ javaLocationClassMethodIDs[LOCATION_METHOD_HAS_ALTITUDE] =
+ env->GetMethodID(javaLocationClass, "hasAltitude", "()Z");
+ javaLocationClassMethodIDs[LOCATION_METHOD_GET_ALTITUDE] =
+ env->GetMethodID(javaLocationClass, "getAltitude", "()D");
+ javaLocationClassMethodIDs[LOCATION_METHOD_HAS_ACCURACY] =
+ env->GetMethodID(javaLocationClass, "hasAccuracy", "()Z");
+ javaLocationClassMethodIDs[LOCATION_METHOD_GET_ACCURACY] =
+ env->GetMethodID(javaLocationClass, "getAccuracy", "()F");
+ javaLocationClassMethodIDs[LOCATION_METHOD_HAS_BEARING] =
+ env->GetMethodID(javaLocationClass, "hasBearing", "()Z");
+ javaLocationClassMethodIDs[LOCATION_METHOD_GET_BEARING] =
+ env->GetMethodID(javaLocationClass, "getBearing", "()F");
+ javaLocationClassMethodIDs[LOCATION_METHOD_HAS_SPEED] =
+ env->GetMethodID(javaLocationClass, "hasSpeed", "()Z");
+ javaLocationClassMethodIDs[LOCATION_METHOD_GET_SPEED] =
+ env->GetMethodID(javaLocationClass, "getSpeed", "()F");
+ javaLocationClassMethodIDs[LOCATION_METHOD_GET_TIME] =
+ env->GetMethodID(javaLocationClass, "getTime", "()J");
+}
+
+void GeolocationServiceBridge::stopJavaImplementation()
+{
+ // Called by GeolocationServiceAndroid on WebKit thread.
+ ASSERT(m_javaGeolocationServiceObject);
+ getJNIEnv()->CallVoidMethod(m_javaGeolocationServiceObject,
+ javaGeolocationServiceClassMethodIDs[GEOLOCATION_SERVICE_METHOD_STOP]);
+ getJNIEnv()->DeleteGlobalRef(m_javaGeolocationServiceObject);
+}
+
+// GeolocationServiceAndroid is the Android implmentation of Geolocation
+// service. Each object of this class owns an object of type
+// GeolocationServiceBridge, which in turn owns a Java GeolocationService
+// object. Therefore, there is a 1:1 mapping between Geolocation,
+// GeolocationServiceAndroid, GeolocationServiceBridge and Java
+// GeolocationService objects. In the case where multiple Geolocation objects
+// exist simultaneously, the corresponsing Java GeolocationService objects all
+// register with the platform location service. It is the platform service that
+// handles making sure that updates are passed to all Geolocation objects.
+GeolocationService* GeolocationServiceAndroid::create(GeolocationServiceClient* client)
+{
+ return new GeolocationServiceAndroid(client);
+}
+
+GeolocationService::FactoryFunction* GeolocationService::s_factoryFunction = &GeolocationServiceAndroid::create;
+
+GeolocationServiceAndroid::GeolocationServiceAndroid(GeolocationServiceClient* client)
+ : GeolocationService(client)
+ , m_timer(this, &GeolocationServiceAndroid::timerFired)
+ , m_javaBridge(0)
+{
+}
+
+bool GeolocationServiceAndroid::startUpdating(PositionOptions* options)
+{
+ // This method is called every time a new watch or one-shot position request
+ // is started. If we already have a position or an error, call back
+ // immediately.
+ if (m_lastPosition || m_lastError) {
+ ASSERT(m_javaBridge);
+ m_timer.startOneShot(0);
+ }
+
+ // Lazilly create the Java object.
+ bool haveJavaBridge = m_javaBridge;
+ if (!haveJavaBridge)
+ m_javaBridge.set(new GeolocationServiceBridge(this));
+ ASSERT(m_javaBridge);
+
+ // On Android, high power == GPS. Set whether to use GPS before we start the
+ // implementation.
+ // FIXME: Checking for the presence of options will probably not be required
+ // once WebKit bug 27254 is fixed.
+ if (options && options->enableHighAccuracy())
+ m_javaBridge->setEnableGps(true);
+
+ if (!haveJavaBridge)
+ m_javaBridge->start();
+
+ return true;
+}
+
+void GeolocationServiceAndroid::stopUpdating()
+{
+ // Called when the Geolocation object has no watches or one shots in
+ // progress.
+ m_javaBridge.clear();
+ // Reset last position and error to make sure that we always try to get a
+ // new position from the system service when a request is first made.
+ m_lastPosition = 0;
+ m_lastError = 0;
+}
+
+// Note that there is no guarantee that subsequent calls to this method offer a
+// more accurate or updated position.
+void GeolocationServiceAndroid::newPositionAvailable(PassRefPtr<Geoposition> position)
+{
+ ASSERT(position);
+ if (!m_lastPosition
+ || isPositionMovement(m_lastPosition.get(), position.get())
+ || isPositionMoreAccurate(m_lastPosition.get(), position.get())
+ || isPositionMoreTimely(m_lastPosition.get(), position.get())) {
+ m_lastPosition = position;
+ // Remove the last error.
+ m_lastError = 0;
+ positionChanged();
+ }
+}
+
+void GeolocationServiceAndroid::newErrorAvailable(PassRefPtr<PositionError> error)
+{
+ ASSERT(error);
+ // We leave the last position
+ m_lastError = error;
+ errorOccurred();
+}
+
+void GeolocationServiceAndroid::timerFired(Timer<GeolocationServiceAndroid>* timer) {
+ ASSERT(m_timer == timer);
+ ASSERT(m_lastPosition || m_lastError);
+ if (m_lastPosition)
+ positionChanged();
+ else
+ errorOccurred();
+}
+
+bool GeolocationServiceAndroid::isPositionMovement(Geoposition* position1, Geoposition* position2)
+{
+ ASSERT(position1 && position2);
+ // For the small distances in which we are likely concerned, it's reasonable
+ // to approximate the distance between the two positions as the sum of the
+ // differences in latitude and longitude.
+ double delta = fabs(position1->coords()->latitude() - position2->coords()->latitude())
+ + fabs(position1->coords()->longitude() - position2->coords()->longitude());
+ // Approximate conversion from degrees of arc to metres.
+ delta *= 60 * 1852;
+ // The threshold is when the distance between the two positions exceeds the
+ // worse (larger) of the two accuracies.
+ int maxAccuracy = max(position1->coords()->accuracy(), position2->coords()->accuracy());
+ return delta > maxAccuracy;
+}
+
+bool GeolocationServiceAndroid::isPositionMoreAccurate(Geoposition* position1, Geoposition* position2)
+{
+ ASSERT(position1 && position2);
+ return position2->coords()->accuracy() < position1->coords()->accuracy();
+}
+
+bool GeolocationServiceAndroid::isPositionMoreTimely(Geoposition* position1, Geoposition* position2)
+{
+ ASSERT(position1 && position2);
+ DOMTimeStamp currentTimeMillis = WTF::currentTime() * 1000.0;
+ DOMTimeStamp maximumAgeMillis = 10 * 60 * 1000; // 10 minutes
+ return currentTimeMillis - position1->timestamp() > maximumAgeMillis;
+}
-} // namespace WebCore
+} // namespace WebCore
diff --git a/WebCore/platform/android/GeolocationServiceAndroid.h b/WebCore/platform/android/GeolocationServiceAndroid.h
new file mode 100644
index 0000000..90a8864
--- /dev/null
+++ b/WebCore/platform/android/GeolocationServiceAndroid.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GeolocationServiceAndroid_h
+#define GeolocationServiceAndroid_h
+
+#include "GeolocationService.h"
+#include "Timer.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+ // The GeolocationServiceBridge is the bridge to the Java implementation of
+ // the Geolocation service. It is an implementation detail of
+ // GeolocationServiceAndroid.
+ class GeolocationServiceBridge;
+
+ class GeolocationServiceAndroid : public GeolocationService {
+ public:
+ static GeolocationService* create(GeolocationServiceClient*);
+
+ GeolocationServiceAndroid(GeolocationServiceClient*);
+ virtual ~GeolocationServiceAndroid() {};
+
+ virtual bool startUpdating(PositionOptions*);
+ virtual void stopUpdating();
+
+ virtual Geoposition* lastPosition() const { return m_lastPosition.get(); }
+ virtual PositionError* lastError() const { return m_lastError.get(); }
+
+ // Android-specific
+ void newPositionAvailable(PassRefPtr<Geoposition>);
+ void newErrorAvailable(PassRefPtr<PositionError>);
+ void timerFired(Timer<GeolocationServiceAndroid>* timer);
+
+ private:
+ static bool isPositionMovement(Geoposition* position1, Geoposition* position2);
+ static bool isPositionMoreAccurate(Geoposition* position1, Geoposition* position2);
+ static bool isPositionMoreTimely(Geoposition* position1, Geoposition* position2);
+
+ Timer<GeolocationServiceAndroid> m_timer;
+ RefPtr<Geoposition> m_lastPosition;
+ RefPtr<PositionError> m_lastError;
+ OwnPtr<GeolocationServiceBridge> m_javaBridge;
+ };
+
+} // namespace WebCore
+
+#endif // GeolocationServiceAndroid_h
diff --git a/WebCore/plugins/PluginPackage.cpp b/WebCore/plugins/PluginPackage.cpp
index 2cd54d4..7e8885d 100644
--- a/WebCore/plugins/PluginPackage.cpp
+++ b/WebCore/plugins/PluginPackage.cpp
@@ -140,11 +140,6 @@ void PluginPackage::unloadWithoutShutdown()
ASSERT(!m_loadCount);
ASSERT(m_module);
-#if defined(ANDROID_PLUGINS)
- // Remove the Java object from PluginList.
- unregisterPluginObject();
-#endif
-
// <rdar://5530519>: Crash when closing tab with pdf file (Reader 7 only)
// If the plugin has subclassed its parent window, as with Reader 7, we may have
// gotten here by way of the plugin's internal window proc forwarding a message to our
diff --git a/WebCore/plugins/PluginPackage.h b/WebCore/plugins/PluginPackage.h
index 67c6fbe..2055391 100644
--- a/WebCore/plugins/PluginPackage.h
+++ b/WebCore/plugins/PluginPackage.h
@@ -114,9 +114,6 @@ namespace WebCore {
#if defined(ANDROID_PLUGINS)
// Java Plugin object.
jobject m_pluginObject;
- // Called from unloadWithoutShutdown() to remove the object
- // from the PluginList.
- void unregisterPluginObject();
#endif
};
diff --git a/WebCore/plugins/android/PluginPackageAndroid.cpp b/WebCore/plugins/android/PluginPackageAndroid.cpp
index 0dd8342..e3c0e56 100644
--- a/WebCore/plugins/android/PluginPackageAndroid.cpp
+++ b/WebCore/plugins/android/PluginPackageAndroid.cpp
@@ -238,74 +238,6 @@ static jobject createPluginObject(const char *name,
return pluginObject;
}
-static jobject getPluginListObject()
-{
- JNIEnv *env = JSC::Bindings::getJNIEnv();
- // Get WebView.getPluginList()
- jclass webViewClass = env->FindClass("android/webkit/WebView");
- if(!webViewClass) {
- PLUGIN_LOG("Couldn't find class android.webkit.WebView\n");
- return 0;
- }
- jmethodID getPluginList = env->GetStaticMethodID(
- webViewClass,
- "getPluginList",
- "()Landroid/webkit/PluginList;");
- if(!getPluginList) {
- PLUGIN_LOG("Couldn't find android.webkit.WebView.getPluginList()\n");
- return 0;
- }
- // Get the PluginList instance
- jobject pluginListObject = env->CallStaticObjectMethod(webViewClass,
- getPluginList);
- if(!pluginListObject) {
- PLUGIN_LOG("Couldn't get PluginList object\n");
- return 0;
- }
- return pluginListObject;
-}
-
-static bool addPluginObjectToList(jobject pluginList, jobject plugin)
-{
- // Add the Plugin object
- JNIEnv *env = JSC::Bindings::getJNIEnv();
- jclass pluginListClass = env->FindClass("android/webkit/PluginList");
- if(!pluginListClass) {
- PLUGIN_LOG("Couldn't find class android.webkit.PluginList\n");
- return false;
- }
- jmethodID addPlugin = env->GetMethodID(
- pluginListClass,
- "addPlugin",
- "(Landroid/webkit/Plugin;)V");
- if(!addPlugin) {
- PLUGIN_LOG("Couldn't find android.webkit.PluginList.addPlugin()\n");
- return false;
- }
- env->CallVoidMethod(pluginList, addPlugin, plugin);
- return true;
-}
-
-static void removePluginObjectFromList(jobject pluginList, jobject plugin)
-{
- // Remove the Plugin object
- JNIEnv *env = JSC::Bindings::getJNIEnv();
- jclass pluginListClass = env->FindClass("android/webkit/PluginList");
- if(!pluginListClass) {
- PLUGIN_LOG("Couldn't find class android.webkit.PluginList\n");
- return;
- }
- jmethodID removePlugin = env->GetMethodID(
- pluginListClass,
- "removePlugin",
- "(Landroid/webkit/Plugin;)V");
- if(!removePlugin) {
- PLUGIN_LOG("Couldn't find android.webkit.PluginList.removePlugin()\n");
- return;
- }
- env->CallVoidMethod(pluginList, removePlugin, plugin);
-}
-
bool PluginPackage::load()
{
PLUGIN_LOG("tid:%d isActive:%d isLoaded:%d loadCount:%d\n",
@@ -379,23 +311,6 @@ bool PluginPackage::load()
return true;
}
-void PluginPackage::unregisterPluginObject()
-{
- PLUGIN_LOG("unregisterPluginObject\n");
- // Called by unloadWithoutShutdown(). Remove the plugin from the
- // PluginList
- if(m_pluginObject) {
- jobject pluginListObject = getPluginListObject();
- if(pluginListObject) {
- removePluginObjectFromList(pluginListObject, m_pluginObject);
- }
- // Remove a reference to the Plugin object so it can
- // garbage collect.
- JSC::Bindings::getJNIEnv()->DeleteGlobalRef(m_pluginObject);
- m_pluginObject = 0;
- }
-}
-
bool PluginPackage::fetchInfo()
{
PLUGIN_LOG("Fetch Info Loading \"%s\"\n", m_path.utf8().data());
@@ -501,27 +416,6 @@ bool PluginPackage::fetchInfo()
PLUGIN_LOG("Couldn't create Java Plugin\n");
return false;
}
-
- // Add the Plugin to the PluginList. This list is used to show the
- // user the list of plugins installed in the webkit.
-
- // The list of plugins are also available from the global static
- // function PluginDatabase::installedPlugins(). However, the method
- // on WebView to get the plugin list is a static method, and runs in the
- // UI thread. We can not easily drop all the GlobalRefs this implementation
- // has and switch to just calling through JNI to aforementioned API as
- // WebKit runs in another thread and the WebView call would need to change
- // to being async.
- jobject pluginListObject = getPluginListObject();
- if(!pluginListObject) {
- PLUGIN_LOG("Couldn't get PluginList object\n");
- return false;
- }
- if(!addPluginObjectToList(pluginListObject, pluginObject)) {
- PLUGIN_LOG("Couldn't add Plugin to PluginList\n");
- m_NPP_Shutdown();
- return false;
- }
// Retain the Java Plugin object
m_pluginObject = JSC::Bindings::getJNIEnv()->NewGlobalRef(pluginObject);
diff --git a/WebCore/rendering/RenderPartObject.cpp b/WebCore/rendering/RenderPartObject.cpp
index b020ef6..5f6d903 100644
--- a/WebCore/rendering/RenderPartObject.cpp
+++ b/WebCore/rendering/RenderPartObject.cpp
@@ -352,46 +352,58 @@ void RenderPartObject::layout()
RenderPart::calcWidth();
RenderPart::calcHeight();
// Some IFrames have a width and/or height of 1 when they are meant to be
- // hidden. If that is the case, don't try to expand.
- int w = width();
- int h = height();
- if (widget() && widget()->isFrameView() &&
- w > 1 && h > 1) {
- FrameView* view = static_cast<FrameView*>(widget());
- RenderView* root = NULL;
- if (view->frame() && view->frame()->document() &&
- view->frame()->document()->renderer() && view->frame()->document()->renderer()->isRenderView())
- root = static_cast<RenderView*>(view->frame()->document()->renderer());
- if (root) {
- // Update the dimensions to get the correct minimum preferred width
- updateWidgetPosition();
-
- int extraWidth = paddingLeft() + paddingRight() + borderLeft() + borderRight();
- int extraHeight = paddingTop() + paddingBottom() + borderTop() + borderBottom();
- // Use the preferred width if it is larger.
- setWidth(max(w, root->minPrefWidth()) + extraWidth);
-
- // Resize the view to recalc the height.
- int height = h - extraHeight;
- int width = w - extraWidth;
- if (width > view->width())
- height = 0;
- if (width != view->width() || height != view->height()) {
- view->resize(width, height);
- root->setNeedsLayout(true, false);
+ // hidden. If that is the case, do not try to expand.
+ if (node()->hasTagName(iframeTag) && widget() && widget()->isFrameView()
+ && width() > 1 && height() > 1) {
+ HTMLIFrameElement* element = static_cast<HTMLIFrameElement*>(node());
+ bool scrolling = element->scrollingMode() != ScrollbarAlwaysOff;
+ bool widthIsFixed = style()->width().isFixed();
+ bool heightIsFixed = style()->height().isFixed();
+ // If an iframe has a fixed dimension and suppresses scrollbars, it
+ // will disrupt layout if we force it to expand. Plus on a desktop,
+ // the extra content is not accessible.
+ if (scrolling || !widthIsFixed || !heightIsFixed) {
+ FrameView* view = static_cast<FrameView*>(widget());
+ RenderView* root = view ? view->frame()->contentRenderer() : NULL;
+ RenderPart* owner = view->frame()->ownerRenderer();
+ if (root && style()->visibility() != HIDDEN
+ && (!owner || owner->style()->visibility() != HIDDEN)) {
+ // Update the dimensions to get the correct minimum preferred
+ // width
+ updateWidgetPosition();
+
+ int extraWidth = paddingLeft() + paddingRight() + borderLeft() + borderRight();
+ int extraHeight = paddingTop() + paddingBottom() + borderTop() + borderBottom();
+ // Use the preferred width if it is larger and only if
+ // scrollbars are visible or the width style is not fixed.
+ if (scrolling || !widthIsFixed)
+ setWidth(max(width(), root->minPrefWidth()) + extraWidth);
+
+ // Resize the view to recalc the height.
+ int h = height() - extraHeight;
+ int w = width() - extraWidth;
+ if (w > view->width())
+ h = 0;
+ if (w != view->width() || h != view->height()) {
+ view->resize(w, h);
+ root->setNeedsLayout(true, false);
+ }
+ // Layout the view.
+ if (view->needsLayout())
+ view->layout();
+ int contentHeight = view->contentsHeight();
+ int contentWidth = view->contentsWidth();
+ // Only change the width or height if scrollbars are visible or
+ // if the style is not a fixed value. Use the maximum value so
+ // that iframes never shrink.
+ if (scrolling || !heightIsFixed)
+ setHeight(max(height(), contentHeight + extraHeight));
+ if (scrolling || !widthIsFixed)
+ setWidth(max(width(), contentWidth + extraWidth));
+
+ // Update one last time
+ updateWidgetPosition();
}
- // Layout the view.
- if (view->needsLayout())
- view->layout();
- int contentHeight = view->contentsHeight();
- int contentWidth = view->contentsWidth();
- // Do not shrink iframes with a specified height.
- if (contentHeight > (h - extraHeight) || style()->height().isAuto())
- setHeight(contentHeight + extraHeight);
- setWidth(contentWidth + extraWidth);
-
- // Update one last time
- updateWidgetPosition();
}
}
#else
@@ -412,12 +424,16 @@ void RenderPartObject::layout()
#ifdef FLATTEN_IFRAME
void RenderPartObject::calcWidth() {
RenderPart::calcWidth();
- if (!widget() || !widget()->isFrameView())
+ if (!node()->hasTagName(iframeTag) || !widget() || !widget()->isFrameView())
return;
FrameView* view = static_cast<FrameView*>(widget());
RenderView* root = static_cast<RenderView*>(view->frame()->contentRenderer());
if (!root)
return;
+ // Do not expand if the scrollbars are suppressed and the width is fixed.
+ bool scrolling = static_cast<HTMLIFrameElement*>(node())->scrollingMode() != ScrollbarAlwaysOff;
+ if (!scrolling && style()->width().isFixed())
+ return;
// Update the dimensions to get the correct minimum preferred
// width
updateWidgetPosition();
@@ -433,7 +449,7 @@ void RenderPartObject::calcWidth() {
while (view->needsLayout())
view->layout();
- setWidth(view->contentsWidth() + extraWidth);
+ setWidth(max(width(), view->contentsWidth() + extraWidth));
// Update one last time to ensure the dimensions.
updateWidgetPosition();
@@ -441,12 +457,16 @@ void RenderPartObject::calcWidth() {
void RenderPartObject::calcHeight() {
RenderPart::calcHeight();
- if (!widget() || !widget()->isFrameView())
+ if (!node()->hasTagName(iframeTag) || !widget() || !widget()->isFrameView())
return;
FrameView* view = static_cast<FrameView*>(widget());
RenderView* root = static_cast<RenderView*>(view->frame()->contentRenderer());
if (!root)
return;
+ // Do not expand if the scrollbars are suppressed and the height is fixed.
+ bool scrolling = static_cast<HTMLIFrameElement*>(node())->scrollingMode() != ScrollbarAlwaysOff;
+ if (!scrolling && style()->height().isFixed())
+ return;
// Update the widget
updateWidgetPosition();
@@ -454,11 +474,8 @@ void RenderPartObject::calcHeight() {
while (view->needsLayout())
view->layout();
- // Do not shrink the height if the size is specified
- int h = view->contentsHeight();
int extraHeight = paddingTop() + paddingBottom() + borderTop() + borderBottom();
- if (h > height() - extraHeight || style()->height().isAuto())
- setHeight(h + extraHeight);
+ setHeight(max(width(), view->contentsHeight() + extraHeight));
// Update one last time to ensure the dimensions.
updateWidgetPosition();
diff --git a/WebKit/Android.mk b/WebKit/Android.mk
index 784326c..c309910 100644
--- a/WebKit/Android.mk
+++ b/WebKit/Android.mk
@@ -36,6 +36,7 @@ LOCAL_SRC_FILES := \
android/jni/GeolocationPermissionsBridge.cpp \
android/jni/JavaBridge.cpp \
android/jni/JavaSharedClient.cpp \
+ android/jni/MockGeolocation.cpp \
android/jni/PictureSet.cpp \
android/jni/WebCoreFrameBridge.cpp \
android/jni/WebCoreJni.cpp \
diff --git a/WebKit/android/TimeCounter.cpp b/WebKit/android/TimeCounter.cpp
index 5f69cf6..7abc113 100644
--- a/WebKit/android/TimeCounter.cpp
+++ b/WebKit/android/TimeCounter.cpp
@@ -65,6 +65,8 @@ uint32_t TimeCounter::sCounter[TimeCounter::TotalTimeCounterCount];
uint32_t TimeCounter::sLastCounter[TimeCounter::TotalTimeCounterCount];
uint32_t TimeCounter::sStartTime[TimeCounter::TotalTimeCounterCount];
+int QemuTracerAuto::reentry_count = 0;
+
static const char* timeCounterNames[] = {
"css parsing",
"javascript",
diff --git a/WebKit/android/TimeCounter.h b/WebKit/android/TimeCounter.h
index c78d10f..29c3eb9 100644
--- a/WebKit/android/TimeCounter.h
+++ b/WebKit/android/TimeCounter.h
@@ -28,6 +28,7 @@
#ifdef ANDROID_INSTRUMENT
+#include "hardware_legacy/qemu_tracing.h"
#include <wtf/CurrentTime.h>
namespace WebCore {
@@ -95,6 +96,23 @@ private:
uint32_t m_startTime;
};
+class QemuTracerAuto {
+public:
+ QemuTracerAuto() {
+ if (!reentry_count)
+ qemu_start_tracing();
+ reentry_count++;
+ }
+
+ ~QemuTracerAuto() {
+ reentry_count--;
+ if (!reentry_count)
+ qemu_stop_tracing();
+ }
+private:
+ static int reentry_count;
+};
+
}
#endif
diff --git a/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp b/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp
index 4918ee9..d2e45ff 100644
--- a/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp
+++ b/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp
@@ -36,6 +36,7 @@
#include "NotImplemented.h"
#include "PlatformKeyboardEvent.h"
#include "PlatformString.h"
+#include "WebViewCore.h"
namespace android {
@@ -225,8 +226,23 @@ void EditorClientAndroid::textDidChangeInTextArea(Element*) {}
void EditorClientAndroid::textDidChangeInTextField(Element*) {}
void EditorClientAndroid::textFieldDidBeginEditing(Element*) {}
void EditorClientAndroid::ignoreWordInSpellDocument(String const&) {}
-void EditorClientAndroid::respondToChangedSelection() {}
-bool EditorClientAndroid::shouldChangeSelectedRange(Range*, Range*, EAffinity, bool) { return m_notFromClick; }
+
+// 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&) {}
diff --git a/WebKit/android/WebCoreSupport/EditorClientAndroid.h b/WebKit/android/WebCoreSupport/EditorClientAndroid.h
index 9697d66..3569f10 100644
--- a/WebKit/android/WebCoreSupport/EditorClientAndroid.h
+++ b/WebKit/android/WebCoreSupport/EditorClientAndroid.h
@@ -35,7 +35,10 @@ namespace android {
class EditorClientAndroid : public EditorClient {
public:
- EditorClientAndroid() { m_notFromClick = true; }
+ EditorClientAndroid() {
+ m_shouldChangeSelectedRange = true;
+ m_uiGeneratedSelectionChange = false;
+ }
virtual void pageDestroyed();
virtual bool shouldDeleteRange(Range*);
@@ -105,10 +108,12 @@ public:
// Android specific:
void setPage(Page* page) { m_page = page; }
- void setFromClick(bool fromClick) { m_notFromClick = !fromClick; }
+ void setShouldChangeSelectedRange(bool shouldChangeSelectedRange) { m_shouldChangeSelectedRange = shouldChangeSelectedRange; }
+ void setUiGeneratedSelectionChange(bool uiGenerated) { m_uiGeneratedSelectionChange = uiGenerated; }
private:
Page* m_page;
- bool m_notFromClick;
+ bool m_shouldChangeSelectedRange;
+ bool m_uiGeneratedSelectionChange;
};
}
diff --git a/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp b/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp
index 14e34fd..103dc4b 100644
--- a/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp
+++ b/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp
@@ -426,9 +426,15 @@ static bool TreatAsAttachment(const String& content_disposition) {
}
void FrameLoaderClientAndroid::dispatchDecidePolicyForMIMEType(FramePolicyFunction func,
- const String& MIMEType, const ResourceRequest&) {
+ const String& MIMEType, const ResourceRequest& request) {
ASSERT(m_frame);
ASSERT(func);
+ if (!func)
+ return;
+ if (request.isNull()) {
+ (m_frame->loader()->*func)(PolicyIgnore);
+ return;
+ }
// Default to Use (display internally).
PolicyAction action = PolicyUse;
// Check if we should Download instead.
@@ -461,13 +467,20 @@ void FrameLoaderClientAndroid::dispatchDecidePolicyForMIMEType(FramePolicyFuncti
}
void FrameLoaderClientAndroid::dispatchDecidePolicyForNewWindowAction(FramePolicyFunction func,
- const NavigationAction&, const ResourceRequest& req,
+ const NavigationAction&, const ResourceRequest& request,
PassRefPtr<FormState> formState, const String& frameName) {
ASSERT(m_frame);
+ ASSERT(func);
+ if (!func)
+ return;
+ if (request.isNull()) {
+ (m_frame->loader()->*func)(PolicyIgnore);
+ return;
+ }
// 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(req))
+ if (canHandleRequest(request))
(m_frame->loader()->*func)(PolicyUse);
else
(m_frame->loader()->*func)(PolicyIgnore);
@@ -486,6 +499,12 @@ void FrameLoaderClientAndroid::dispatchDecidePolicyForNavigationAction(FramePoli
PassRefPtr<FormState> formState) {
ASSERT(m_frame);
ASSERT(func);
+ if (!func)
+ return;
+ if (request.isNull()) {
+ (m_frame->loader()->*func)(PolicyIgnore);
+ return;
+ }
if (action.type() == NavigationTypeFormResubmitted) {
m_webFrame->decidePolicyForFormResubmission(func);
return;
diff --git a/WebKit/android/jni/MockGeolocation.cpp b/WebKit/android/jni/MockGeolocation.cpp
new file mode 100755
index 0000000..2f6ca60
--- /dev/null
+++ b/WebKit/android/jni/MockGeolocation.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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 APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// The functions in this file are used to configure the mock GeolocationService
+// for the LayoutTests.
+
+#include "config.h"
+
+#include <JNIHelp.h>
+#include "Coordinates.h"
+#include "GeolocationService.h"
+#include "Geoposition.h"
+#include "JavaSharedClient.h"
+#include "jni_utility.h"
+#include "PositionError.h"
+#include "WebCoreJni.h"
+#include <wtf/CurrentTime.h>
+
+using namespace WebCore;
+
+namespace android {
+
+static const char* javaMockGeolocationClass = "android/webkit/MockGeolocation";
+
+static void setPosition(JNIEnv* env, jobject, double latitude, double longitude, double accuracy)
+{
+ RefPtr<Coordinates> coordinates = Coordinates::create(latitude,
+ longitude,
+ false, 0.0, // altitude,
+ accuracy,
+ false, 0.0, // altitudeAccuracy,
+ false, 0.0, // heading
+ false, 0.0); // speed
+ RefPtr<Geoposition> position = Geoposition::create(coordinates.release(), WTF::currentTime());
+ GeolocationService::setMockPosition(position.release());
+}
+
+static void setError(JNIEnv* env, jobject, int code, jstring message)
+{
+ PositionError::ErrorCode codeEnum;
+ switch (code) {
+ case PositionError::UNKNOWN_ERROR:
+ codeEnum = PositionError::UNKNOWN_ERROR;
+ break;
+ case PositionError::PERMISSION_DENIED:
+ codeEnum = PositionError::PERMISSION_DENIED;
+ break;
+ case PositionError::POSITION_UNAVAILABLE:
+ codeEnum = PositionError::POSITION_UNAVAILABLE;
+ break;
+ case PositionError::TIMEOUT:
+ codeEnum = PositionError::TIMEOUT;
+ break;
+ default:
+ ASSERT(false);
+ }
+ String messageString = to_string(env, message);
+ RefPtr<PositionError> error = PositionError::create(codeEnum, messageString);
+ GeolocationService::setMockError(error.release());
+}
+
+static JNINativeMethod gMockGeolocationMethods[] = {
+ { "nativeSetPosition", "(DDD)V", (void*) setPosition },
+ { "nativeSetError", "(ILjava/lang/String;)V", (void*) setError }
+};
+
+int register_mock_geolocation(JNIEnv* env)
+{
+ jclass mockGeolocation = env->FindClass(javaMockGeolocationClass);
+ LOG_ASSERT(mockGeolocation, "Unable to find class");
+ return jniRegisterNativeMethods(env, javaMockGeolocationClass, gMockGeolocationMethods, NELEM(gMockGeolocationMethods));
+}
+
+}
diff --git a/WebKit/android/jni/WebCoreFrameBridge.cpp b/WebKit/android/jni/WebCoreFrameBridge.cpp
index d042c92..17b908d 100644
--- a/WebKit/android/jni/WebCoreFrameBridge.cpp
+++ b/WebKit/android/jni/WebCoreFrameBridge.cpp
@@ -1137,6 +1137,9 @@ static void ClearCache(JNIEnv *env, jobject obj)
#if USE(JSC)
// force JavaScript to GC when clear cache
WebCore::gcController().garbageCollectSoon();
+#elif USE(V8)
+ WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
+ pFrame->script()->collectGarbage();
#endif // USE(JSC)
}
diff --git a/WebKit/android/jni/WebCoreJniOnLoad.cpp b/WebKit/android/jni/WebCoreJniOnLoad.cpp
index 3a29f43..25afc61 100644
--- a/WebKit/android/jni/WebCoreJniOnLoad.cpp
+++ b/WebKit/android/jni/WebCoreJniOnLoad.cpp
@@ -45,6 +45,7 @@ extern int register_webcorejni(JNIEnv*);
extern int register_webstorage(JNIEnv*);
#endif
extern int register_geolocation_permissions(JNIEnv*);
+extern int register_mock_geolocation(JNIEnv*);
}
@@ -66,7 +67,8 @@ static RegistrationMethod gWebCoreRegMethods[] = {
{ "WebStorage", android::register_webstorage },
#endif
{ "WebView", android::register_webview },
- { "GeolocationPermissions", android::register_geolocation_permissions }
+ { "GeolocationPermissions", android::register_geolocation_permissions },
+ { "MockGeolocation", android::register_mock_geolocation }
};
EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
diff --git a/WebKit/android/jni/WebViewCore.cpp b/WebKit/android/jni/WebViewCore.cpp
index 8e56fcc..3ede30a 100644
--- a/WebKit/android/jni/WebViewCore.cpp
+++ b/WebKit/android/jni/WebViewCore.cpp
@@ -171,6 +171,7 @@ struct WebViewCore::JavaGlue {
jmethodID m_sendNotifyProgressFinished;
jmethodID m_sendViewInvalidate;
jmethodID m_updateTextfield;
+ jmethodID m_updateTextSelection;
jmethodID m_clearTextEntry;
jmethodID m_restoreScale;
jmethodID m_restoreScreenWidthScale;
@@ -244,6 +245,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m
m_javaGlue->m_sendNotifyProgressFinished = GetJMethod(env, clazz, "sendNotifyProgressFinished", "()V");
m_javaGlue->m_sendViewInvalidate = GetJMethod(env, clazz, "sendViewInvalidate", "(IIII)V");
m_javaGlue->m_updateTextfield = GetJMethod(env, clazz, "updateTextfield", "(IZLjava/lang/String;I)V");
+ m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIII)V");
m_javaGlue->m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V");
m_javaGlue->m_restoreScale = GetJMethod(env, clazz, "restoreScale", "(I)V");
m_javaGlue->m_restoreScreenWidthScale = GetJMethod(env, clazz, "restoreScreenWidthScale", "(I)V");
@@ -438,7 +440,7 @@ void WebViewCore::recordPictureSet(PictureSet* content)
// If the frame doesn't have an owner then it is the top frame and the
// view size is the frame size.
WebCore::RenderPart* owner = frame->ownerRenderer();
- if (owner) {
+ if (owner && owner->style()->visibility() == VISIBLE) {
int x = owner->x();
int y = owner->y();
@@ -1086,7 +1088,7 @@ void WebViewCore::updateCacheOnNodeChange()
return;
if (CacheBuilder::validNode(m_mainFrame, frame, node)) {
RenderObject* renderer = node->renderer();
- if (renderer) {
+ if (renderer && renderer->style()->visibility() != HIDDEN) {
IntRect absBox = renderer->absoluteBoundingBoxRect();
int globalX, globalY;
CacheBuilder::GetGlobalOffset(frame, &globalX, &globalY);
@@ -1499,7 +1501,13 @@ void WebViewCore::setSelection(int start, int end)
start = end;
end = temp;
}
+ // Tell our EditorClient that this change was generated from the UI, so it
+ // does not need to echo it to the UI.
+ EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
+ m_mainFrame->editor()->client());
+ client->setUiGeneratedSelectionChange(true);
rtc->setSelectionRange(start, end);
+ client->setUiGeneratedSelectionChange(false);
focus->document()->frame()->revealSelection();
setFocusControllerActive(true);
}
@@ -1524,8 +1532,14 @@ void WebViewCore::replaceTextfieldText(int oldStart,
if (!focus)
return;
setSelection(oldStart, oldEnd);
+ // Prevent our editor client from passing a message to change the
+ // selection.
+ EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
+ m_mainFrame->editor()->client());
+ client->setUiGeneratedSelectionChange(true);
WebCore::TypingCommand::insertText(focus->document(), replace,
false);
+ client->setUiGeneratedSelectionChange(false);
setSelection(start, end);
m_textGeneration = textGeneration;
}
@@ -1547,7 +1561,13 @@ void WebViewCore::passToJs(int generation, const WebCore::String& current,
}
// Block text field updates during a key press.
m_blockTextfieldUpdates = true;
+ // Also prevent our editor client from passing a message to change the
+ // selection.
+ EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
+ m_mainFrame->editor()->client());
+ client->setUiGeneratedSelectionChange(true);
key(event);
+ client->setUiGeneratedSelectionChange(false);
m_blockTextfieldUpdates = false;
m_textGeneration = generation;
setFocusControllerActive(true);
@@ -1783,8 +1803,14 @@ void WebViewCore::click(WebCore::Frame* frame, WebCore::Node* node) {
" node=%p", m_mousePos.x(), m_mousePos.y(),
m_scrollOffsetX, m_scrollOffsetY, pt.x(), pt.y(), node);
}
- if (node)
+ if (node) {
+ EditorClientAndroid* client
+ = static_cast<EditorClientAndroid*>(
+ m_mainFrame->editor()->client());
+ client->setShouldChangeSelectedRange(false);
handleMouseClick(frame, node);
+ client->setShouldChangeSelectedRange(true);
+ }
}
bool WebViewCore::handleTouchEvent(int action, int x, int y)
@@ -1816,7 +1842,7 @@ bool WebViewCore::handleTouchEvent(int action, int x, int y)
}
void WebViewCore::touchUp(int touchGeneration,
- WebCore::Frame* frame, WebCore::Node* node, int x, int y, int size)
+ WebCore::Frame* frame, WebCore::Node* node, int x, int y)
{
if (m_touchGeneration > touchGeneration) {
DBG_NAV_LOGD("m_touchGeneration=%d > touchGeneration=%d"
@@ -1828,12 +1854,30 @@ void WebViewCore::touchUp(int touchGeneration,
if (frame && CacheBuilder::validNode(m_mainFrame, frame, 0)) {
frame->loader()->resetMultipleFormSubmissionProtection();
}
- EditorClientAndroid* client = static_cast<EditorClientAndroid*>(m_mainFrame->editor()->client());
- client->setFromClick(true);
+ // If the click is on an unselected textfield/area we do not want to allow
+ // the click to change the selection, because we will set it ourselves
+ // elsewhere - beginning for textareas, end for textfields
+ bool needToIgnoreChangesToSelectedRange = true;
+ WebCore::Node* focusNode = currentFocus();
+ if (focusNode) {
+ WebCore::RenderObject* renderer = focusNode->renderer();
+ if (renderer && (renderer->isTextField() || renderer->isTextArea())) {
+ // Now check to see if the click is inside the focused textfield
+ if (focusNode->getRect().contains(x, y))
+ needToIgnoreChangesToSelectedRange = false;
+ }
+ }
+ EditorClientAndroid* client = 0;
+ if (needToIgnoreChangesToSelectedRange) {
+ client = static_cast<EditorClientAndroid*>(
+ m_mainFrame->editor()->client());
+ client->setShouldChangeSelectedRange(false);
+ }
DBG_NAV_LOGD("touchGeneration=%d handleMouseClick frame=%p node=%p"
" x=%d y=%d", touchGeneration, frame, node, x, y);
handleMouseClick(frame, node);
- client->setFromClick(false);
+ if (needToIgnoreChangesToSelectedRange)
+ client->setShouldChangeSelectedRange(true);
}
// Common code for both clicking with the trackball and touchUp
@@ -2056,6 +2100,21 @@ WebViewCore::getWebViewJavaObject()
return env->GetObjectField(m_javaGlue->object(env).get(), gWebViewCoreFields.m_webView);
}
+void WebViewCore::updateTextSelection() {
+ WebCore::Node* focusNode = currentFocus();
+ if (!focusNode)
+ return;
+ RenderObject* renderer = focusNode->renderer();
+ if (!renderer || (!renderer->isTextArea() && !renderer->isTextField()))
+ return;
+ RenderTextControl* rtc = static_cast<RenderTextControl*>(renderer);
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ env->CallVoidMethod(m_javaGlue->object(env).get(),
+ m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(focusNode),
+ rtc->selectionStart(), rtc->selectionEnd(), m_textGeneration);
+ checkException(env);
+}
+
void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword,
const WebCore::String& text)
{
@@ -2369,7 +2428,7 @@ static jboolean HandleTouchEvent(JNIEnv *env, jobject obj, jint action, jint x,
}
static void TouchUp(JNIEnv *env, jobject obj, jint touchGeneration,
- jint frame, jint node, jint x, jint y, jint size)
+ jint frame, jint node, jint x, jint y)
{
#ifdef ANDROID_INSTRUMENT
TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
@@ -2377,7 +2436,7 @@ static void TouchUp(JNIEnv *env, jobject obj, jint touchGeneration,
WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
viewImpl->touchUp(touchGeneration,
- (WebCore::Frame*) frame, (WebCore::Node*) node, x, y, size);
+ (WebCore::Frame*) frame, (WebCore::Node*) node, x, y);
}
static jstring RetrieveHref(JNIEnv *env, jobject obj, jint frame,
@@ -2702,7 +2761,7 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = {
(void*) FindAddress },
{ "nativeHandleTouchEvent", "(III)Z",
(void*) HandleTouchEvent },
- { "nativeTouchUp", "(IIIIII)V",
+ { "nativeTouchUp", "(IIIII)V",
(void*) TouchUp },
{ "nativeRetrieveHref", "(II)Ljava/lang/String;",
(void*) RetrieveHref },
diff --git a/WebKit/android/jni/WebViewCore.h b/WebKit/android/jni/WebViewCore.h
index 22e00e2..1408cb7 100644
--- a/WebKit/android/jni/WebViewCore.h
+++ b/WebKit/android/jni/WebViewCore.h
@@ -173,6 +173,15 @@ namespace android {
*/
void updateTextfield(WebCore::Node* pointer,
bool changeToPassword, const WebCore::String& text);
+
+ /**
+ * Tell the java side to update the current selection in the focused
+ * textfield to the WebTextView. This function finds the currently
+ * focused textinput, and passes its selection to java.
+ * If there is no focus, or it is not a text input, this does nothing.
+ */
+ void updateTextSelection();
+
void clearTextEntry();
// JavaScript support
void jsAlert(const WebCore::String& url, const WebCore::String& text);
@@ -260,8 +269,8 @@ namespace android {
* Handle motionUp event from the UI thread (called touchUp in the
* WebCore thread).
*/
- void touchUp(int touchGeneration,
- WebCore::Frame* frame, WebCore::Node* node, int x, int y, int size);
+ void touchUp(int touchGeneration, WebCore::Frame* frame,
+ WebCore::Node* node, int x, int y);
/**
* Sets the index of the label from a popup
diff --git a/WebKit/android/nav/WebView.cpp b/WebKit/android/nav/WebView.cpp
index a920777..59d0c6f 100644
--- a/WebKit/android/nav/WebView.cpp
+++ b/WebKit/android/nav/WebView.cpp
@@ -131,7 +131,7 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl)
m_javaGlue.m_sendPluginState = GetJMethod(env, clazz, "sendPluginState", "(I)V");
m_javaGlue.m_sendMoveMouse = GetJMethod(env, clazz, "sendMoveMouse", "(IIII)V");
m_javaGlue.m_sendMoveMouseIfLatest = GetJMethod(env, clazz, "sendMoveMouseIfLatest", "(Z)V");
- m_javaGlue.m_sendMotionUp = GetJMethod(env, clazz, "sendMotionUp", "(IIIIII)V");
+ m_javaGlue.m_sendMotionUp = GetJMethod(env, clazz, "sendMotionUp", "(IIIII)V");
m_javaGlue.m_getScaledMaxXScroll = GetJMethod(env, clazz, "getScaledMaxXScroll", "()I");
m_javaGlue.m_getScaledMaxYScroll = GetJMethod(env, clazz, "getScaledMaxYScroll", "()I");
m_javaGlue.m_getVisibleRect = GetJMethod(env, clazz, "sendOurVisibleRect", "()Landroid/graphics/Rect;");
@@ -909,6 +909,26 @@ void setNavBounds(const WebCore::IntRect& rect)
root->rootHistory()->setNavBounds(rect);
}
+/**
+ * This function is only to be called by WebTextView, when there is a motion up
+ * on an already focused text input. Unlike motionUp which may change our
+ * cursor, it simply passes the click, so it can change the selection.
+ * Variables are in content space, relative to the page.
+ */
+void textInputMotionUp(int x, int y)
+{
+ const CachedRoot* root = getFrameCache(DontAllowNewer);
+ if (!root) {
+ return;
+ }
+ const CachedFrame* frame;
+ const CachedNode* node = root->currentCursor(&frame);
+ if (node) {
+ sendMotionUp(static_cast<WebCore::Frame*>(frame->framePointer()),
+ static_cast<WebCore::Node*>(node->nodePointer()), x, y);
+ }
+}
+
bool motionUp(int x, int y, int slop)
{
bool pageScrolled = false;
@@ -931,7 +951,7 @@ bool motionUp(int x, int y, int slop)
pageScrolled = true;
}
sendMotionUp(frame ? (WebCore::Frame*) frame->framePointer() : 0,
- 0, x, y, slop);
+ 0, x, y);
viewInvalidate();
clearTextEntry();
setPluginReceivesEvents(false);
@@ -948,8 +968,7 @@ bool motionUp(int x, int y, int slop)
if (type == NORMAL_CACHEDNODETYPE) {
sendMotionUp(
frame ? (WebCore::Frame*) frame->framePointer() : 0,
- result ? (WebCore::Node*) result->nodePointer() : 0, rx, ry,
- slop);
+ result ? (WebCore::Node*) result->nodePointer() : 0, rx, ry);
}
viewInvalidate();
if (result->isTextField() || result->isTextArea()) {
@@ -1177,7 +1196,7 @@ void sendMoveMouseIfLatest(bool disableFocusController)
}
void sendMotionUp(
- WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y, int slop)
+ WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y)
{
m_viewImpl->m_touchGeneration = m_viewImpl->m_generation = ++m_generation;
DBG_NAV_LOGD("m_generation=%d framePtr=%p nodePtr=%p x=%d y=%d slop=%d",
@@ -1185,7 +1204,7 @@ void sendMotionUp(
LOG_ASSERT(m_javaGlue.m_obj, "A WebView was not associated with this WebViewNative!");
JNIEnv* env = JSC::Bindings::getJNIEnv();
env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_sendMotionUp,
- m_generation, (jint) framePtr, (jint) nodePtr, x, y, slop);
+ m_generation, (jint) framePtr, (jint) nodePtr, x, y);
checkException(env);
}
@@ -1699,6 +1718,12 @@ static jint nativeTextGeneration(JNIEnv *env, jobject obj)
return root ? root->textGeneration() : 0;
}
+static void nativeTextInputMotionUp(JNIEnv *env, jobject obj, int x, int y)
+{
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ view->textInputMotionUp(x, y);
+}
+
static bool nativeMotionUp(JNIEnv *env, jobject obj,
int x, int y, int slop)
{
@@ -2057,6 +2082,8 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeImageURI },
{ "nativeInstrumentReport", "()V",
(void*) nativeInstrumentReport },
+ { "nativeTextInputMotionUp", "(II)V",
+ (void*) nativeTextInputMotionUp },
{ "nativeMotionUp", "(III)Z",
(void*) nativeMotionUp },
{ "nativeMoveCursor", "(IIZ)Z",
diff --git a/WebKit/android/plugins/android_npapi.h b/WebKit/android/plugins/android_npapi.h
index 0ab3879..1c7655b 100644
--- a/WebKit/android/plugins/android_npapi.h
+++ b/WebKit/android/plugins/android_npapi.h
@@ -87,6 +87,10 @@ struct ANPMatrix;
struct ANPPaint;
struct ANPPath;
struct ANPRegion;
+/** The ANPSurface acts as a handle between the plugin and the native libraries
+ that render the surface to the screen.
+ */
+struct ANPSurface;
struct ANPTypeface;
enum ANPMatrixFlags {
@@ -101,7 +105,7 @@ typedef uint32_t ANPMatrixFlag;
///////////////////////////////////////////////////////////////////////////////
// NPN_GetValue
-/* queries for a specific ANPInterface.
+/** queries for a specific ANPInterface.
Maybe called with NULL for the NPP instance
@@ -119,7 +123,7 @@ typedef uint32_t ANPMatrixFlag;
#define kSurfaceInterfaceV0_ANPGetValue ((NPNVariable)1009)
#define kSystemInterfaceV0_ANPGetValue ((NPNVariable)1010)
-/* queries for which drawing model is desired (for the draw event)
+/** queries for which drawing model is desired (for the draw event)
Should be called inside NPP_New(...)
@@ -132,11 +136,11 @@ typedef uint32_t ANPMatrixFlag;
/** Request to set the drawing model.
- NPN_SetValue(inst, ANPRequestDrawingModel_EnumValue, (void*)foo_DrawingModel)
+ NPN_SetValue(inst, ANPRequestDrawingModel_EnumValue, (void*)foo_ANPDrawingModel)
*/
#define kRequestDrawingModel_ANPSetValue ((NPPVariable)1000)
-/* These are used as bitfields in ANPSupportedDrawingModels_EnumValue,
+/** These are used as bitfields in ANPSupportedDrawingModels_EnumValue,
and as-is in ANPRequestDrawingModel_EnumValue. The drawing model determines
how to interpret the ANPDrawingContext provided in the Draw event and how
to interpret the NPWindow->window field.
@@ -146,6 +150,14 @@ enum ANPDrawingModels {
NPWindow->window is reserved (ignore)
*/
kBitmap_ANPDrawingModel = 0,
+ /** Draw into a surface (e.g. raster, opengl, etc.)using the surface interface.
+ Unlike the bitmap model a surface model is opaque so no html content behind
+ the plugin will be visible. Unless the surface needs to be transparent the
+ surface model should be chosen over the bitmap model as it will have faster
+ performance. An example surface is the raster surface where the service
+ interface is used to lock/unlock and draw into bitmap without waiting for
+ draw events.
+ */
kSurface_ANPDrawingModel = 1,
};
typedef int32_t ANPDrawingModel;
@@ -158,7 +170,7 @@ typedef int32_t ANPDrawingModel;
*/
#define kAcceptEvents_ANPSetValue ((NPPVariable)1001)
-/* The EventFlags are a set of bits used to determine which types of events the
+/** The EventFlags are a set of bits used to determine which types of events the
plugin wishes to receive. For example, if the value is 0x03 then both key
and touch events will be provided to the plugin.
*/
@@ -168,8 +180,8 @@ enum ANPEventFlag {
};
typedef uint32_t ANPEventFlags;
-/* Interfaces provide additional functionality to the plugin via function ptrs.
- Once an interface is retrived, it is valid for the lifetime of the plugin
+/** Interfaces provide additional functionality to the plugin via function ptrs.
+ Once an interface is retrieved, it is valid for the lifetime of the plugin
(just like browserfuncs).
All ANPInterfaces begin with an inSize field, which must be set by the
@@ -188,8 +200,9 @@ enum ANPLogTypes {
typedef int32_t ANPLogType;
struct ANPLogInterfaceV0 : ANPInterface {
- // dumps printf messages to the log file
- // e.g. interface->log(instance, kWarning_ANPLogType, "value is %d", value);
+ /** dumps printf messages to the log file
+ e.g. interface->log(instance, kWarning_ANPLogType, "value is %d", value);
+ */
void (*log)(NPP instance, ANPLogType, const char format[], ...);
};
@@ -200,14 +213,13 @@ struct ANPBitmapInterfaceV0 : ANPInterface {
bool (*getPixelPacking)(ANPBitmapFormat, ANPPixelPacking* packing);
};
-/** The ANPSurface acts as a handle between the plugin and the native libraries
- that render the surface to the screen.
- */
-struct ANPSurface;
-
struct ANPSurfaceInterfaceV0 : ANPInterface {
/** Creates a new raster surface handle based on the given bitmap format. If
- raster surfaces or the bitmap format is not supported then NULL is returned.
+ raster surfaces or the bitmap format is not supported then NULL is
+ returned. Setting the fixedSize parameter to true notifies the browser
+ that it is responsible for scaling the bitmap when zoomed. Setting the
+ fixedSize to false will cause a kChanged_ANPSurfaceAction to be fired
+ each time the user changes the zoom level.
*/
ANPSurface* (*newRasterSurface)(NPP instance, ANPBitmapFormat, bool fixedSize);
/** Given a valid surface handle (i.e. one created by calling newSurface)
@@ -230,10 +242,10 @@ struct ANPSurfaceInterfaceV0 : ANPInterface {
};
struct ANPMatrixInterfaceV0 : ANPInterface {
- /* Return a new identity matrix
+ /** Return a new identity matrix
*/
ANPMatrix* (*newMatrix)();
- /* Delete a matrix previously allocated by newMatrix()
+ /** Delete a matrix previously allocated by newMatrix()
*/
void (*deleteMatrix)(ANPMatrix*);
@@ -241,14 +253,14 @@ struct ANPMatrixInterfaceV0 : ANPInterface {
void (*copy)(ANPMatrix* dst, const ANPMatrix* src);
- /* Return the matrix values in a float array (allcoated by the caller),
+ /** Return the matrix values in a float array (allcoated by the caller),
where the values are treated as follows:
w = x * [6] + y * [7] + [8];
x' = (x * [0] + y * [1] + [2]) / w;
y' = (x * [3] + y * [4] + [5]) / w;
*/
void (*get3x3)(const ANPMatrix*, float[9]);
- /* Initialize the matrix from values in a float array,
+ /** Initialize the matrix from values in a float array,
where the values are treated as follows:
w = x * [6] + y * [7] + [8];
x' = (x * [0] + y * [1] + [2]) / w;
@@ -268,12 +280,12 @@ struct ANPMatrixInterfaceV0 : ANPInterface {
void (*preConcat)(ANPMatrix*, const ANPMatrix*);
void (*postConcat)(ANPMatrix*, const ANPMatrix*);
- /* Return true if src is invertible, and if so, return its inverse in dst.
+ /** Return true if src is invertible, and if so, return its inverse in dst.
If src is not invertible, return false and ignore dst.
*/
bool (*invert)(ANPMatrix* dst, const ANPMatrix* src);
- /* Transform the x,y pairs in src[] by this matrix, and store the results
+ /** Transform the x,y pairs in src[] by this matrix, and store the results
in dst[]. The count parameter is treated as the number of pairs in the
array. It is legal for src and dst to point to the same memory, but
illegal for the two arrays to partially overlap.
@@ -283,28 +295,28 @@ struct ANPMatrixInterfaceV0 : ANPInterface {
};
struct ANPPathInterfaceV0 : ANPInterface {
- /* Return a new path */
+ /** Return a new path */
ANPPath* (*newPath)();
- /* Delete a path previously allocated by ANPPath() */
+ /** Delete a path previously allocated by ANPPath() */
void (*deletePath)(ANPPath*);
- /* Make a deep copy of the src path, into the dst path (already allocated
- by the caller).
+ /** Make a deep copy of the src path, into the dst path (already allocated
+ by the caller).
*/
void (*copy)(ANPPath* dst, const ANPPath* src);
- /* Returns true if the two paths are the same (i.e. have the same points)
+ /** Returns true if the two paths are the same (i.e. have the same points)
*/
bool (*equal)(const ANPPath* path0, const ANPPath* path1);
- /* Remove any previous points, initializing the path back to empty. */
+ /** Remove any previous points, initializing the path back to empty. */
void (*reset)(ANPPath*);
- /* Return true if the path is empty (has no lines, quads or cubics). */
+ /** Return true if the path is empty (has no lines, quads or cubics). */
bool (*isEmpty)(const ANPPath*);
- /* Return the path's bounds in bounds. */
+ /** Return the path's bounds in bounds. */
void (*getBounds)(const ANPPath*, ANPRectF* bounds);
void (*moveTo)(ANPPath*, float x, float y);
@@ -314,14 +326,14 @@ struct ANPPathInterfaceV0 : ANPInterface {
float x2, float y2);
void (*close)(ANPPath*);
- /* Offset the src path by [dx, dy]. If dst is null, apply the
+ /** Offset the src path by [dx, dy]. If dst is null, apply the
change directly to the src path. If dst is not null, write the
changed path into dst, and leave the src path unchanged. In that case
dst must have been previously allocated by the caller.
*/
void (*offset)(ANPPath* src, float dx, float dy, ANPPath* dst);
- /* Transform the path by the matrix. If dst is null, apply the
+ /** Transform the path by the matrix. If dst is null, apply the
change directly to the src path. If dst is not null, write the
changed path into dst, and leave the src path unchanged. In that case
dst must have been previously allocated by the caller.
@@ -400,15 +412,15 @@ typedef uint32_t ANPTypefaceStyle;
typedef uint32_t ANPFontTableTag;
struct ANPFontMetrics {
- //! The greatest distance above the baseline for any glyph (will be <= 0)
+ /** The greatest distance above the baseline for any glyph (will be <= 0) */
float fTop;
- //! The recommended distance above the baseline (will be <= 0)
+ /** The recommended distance above the baseline (will be <= 0) */
float fAscent;
- //! The recommended distance below the baseline (will be >= 0)
+ /** The recommended distance below the baseline (will be >= 0) */
float fDescent;
- //! The greatest distance below the baseline for any glyph (will be >= 0)
+ /** The greatest distance below the baseline for any glyph (will be >= 0) */
float fBottom;
- //! The recommended distance to add between lines of text (will be >= 0)
+ /** The recommended distance to add between lines of text (will be >= 0) */
float fLeading;
};
@@ -491,7 +503,7 @@ struct ANPTypefaceInterfaceV0 : ANPInterface {
};
struct ANPPaintInterfaceV0 : ANPInterface {
- /* Return a new paint object, which holds all of the color and style
+ /** Return a new paint object, which holds all of the color and style
attributes that affect how things (geometry, text, bitmaps) are drawn
in a ANPCanvas.
@@ -563,7 +575,7 @@ struct ANPPaintInterfaceV0 : ANPInterface {
};
struct ANPCanvasInterfaceV0 : ANPInterface {
- /* Return a canvas that will draw into the specified bitmap. Note: the
+ /** Return a canvas that will draw into the specified bitmap. Note: the
canvas copies the fields of the bitmap, so it need not persist after
this call, but the canvas DOES point to the same pixel memory that the
bitmap did, so the canvas should not be used after that pixel memory
@@ -587,15 +599,15 @@ struct ANPCanvasInterfaceV0 : ANPInterface {
void (*clipRect)(ANPCanvas*, const ANPRectF*);
void (*clipPath)(ANPCanvas*, const ANPPath*);
- /* Return the current matrix on the canvas
+ /** Return the current matrix on the canvas
*/
void (*getTotalMatrix)(ANPCanvas*, ANPMatrix*);
- /* Return the current clip bounds in local coordinates, expanding it to
+ /** Return the current clip bounds in local coordinates, expanding it to
account for antialiasing edge effects if aa is true. If the
current clip is empty, return false and ignore the bounds argument.
*/
bool (*getLocalClipBounds)(ANPCanvas*, ANPRectF* bounds, bool aa);
- /* Return the current clip bounds in device coordinates in bounds. If the
+ /** Return the current clip bounds in device coordinates in bounds. If the
current clip is empty, return false and ignore the bounds argument.
*/
bool (*getDeviceClipBounds)(ANPCanvas*, ANPRectI* bounds);
@@ -718,13 +730,19 @@ typedef void (*ANPAudioCallbackProc)(ANPAudioEvent event, void* user,
struct ANPAudioTrack; // abstract type for audio tracks
struct ANPAudioTrackInterfaceV0 : ANPInterface {
- /* Create a new audio track, or NULL on failure.
+ /** Create a new audio track, or NULL on failure. The track is initially in
+ the stopped state and therefore ANPAudioCallbackProc will not be called
+ until the track is started.
*/
ANPAudioTrack* (*newTrack)(uint32_t sampleRate, // sampling rate in Hz
ANPSampleFormat,
int channelCount, // MONO=1, STEREO=2
ANPAudioCallbackProc,
void* user);
+ /** Deletes a track that was created using newTrack. The track can be
+ deleted in any state and it waits for the ANPAudioCallbackProc thread
+ to exit before returning.
+ */
void (*deleteTrack)(ANPAudioTrack*);
void (*start)(ANPAudioTrack*);
@@ -742,8 +760,20 @@ struct ANPAudioTrackInterfaceV0 : ANPInterface {
enum ANPEventTypes {
kNull_ANPEventType = 0,
kKey_ANPEventType = 1,
+ /** Mouse events are triggered by either clicking with the navigational pad
+ or by tapping the touchscreen (if the kDown_ANPTouchAction is handled by
+ the plugin then no mouse event is generated). The kKey_ANPEventFlag has
+ to be set to true in order to receive these events.
+ */
kMouse_ANPEventType = 2,
+ /** Touch events are generated when the user touches on the screen. The
+ kTouch_ANPEventFlag has to be set to true in order to receive these
+ events.
+ */
kTouch_ANPEventType = 3,
+ /** Only triggered by a plugin using the kBitmap_ANPDrawingModel. This event
+ signals that the plugin needs to redraw itself into the provided bitmap.
+ */
kDraw_ANPEventType = 4,
kLifecycle_ANPEventType = 5,
kSurface_ANPEventType = 6,
@@ -773,6 +803,11 @@ enum ANPMouseActions {
typedef int32_t ANPMouseAction;
enum ANPTouchActions {
+ /** This occurs when the user first touches on the screen. As such, this
+ action will always occur prior to any of the other touch actions. If
+ the plugin chooses to not handle this action then no other events
+ related to that particular touch gesture will be generated.
+ */
kDown_ANPTouchAction = 0,
kUp_ANPTouchAction = 1,
kMove_ANPTouchAction = 2,
@@ -781,10 +816,26 @@ enum ANPTouchActions {
typedef int32_t ANPTouchAction;
enum ANPLifecycleActions {
+ /** The web view containing this plugin has been paused. See documentation
+ on the android activity lifecycle for more information.
+ */
kPause_ANPLifecycleAction = 0,
+ /** The web view containing this plugin has been resumed. See documentation
+ on the android activity lifecycle for more information.
+ */
kResume_ANPLifecycleAction = 1,
+ /** The plugin has focus and is now the recipient of input events (e.g. key,
+ touch, etc.)
+ */
kGainFocus_ANPLifecycleAction = 2,
+ /** The plugin has lost focus and will not receive any input events until it
+ regains focus. This event is always preceded by a GainFocus action.
+ */
kLoseFocus_ANPLifecycleAction = 3,
+ /** The browser is running low on available memory and is requesting that
+ the plugin free any unused/inactive resources to prevent a performance
+ degradation.
+ */
kFreeMemory_ANPLifecycleAction = 4,
/** The page has finished loading. This happens when the page's top level
frame reports that it has completed loading.
@@ -798,7 +849,10 @@ enum ANPSurfaceActions {
lock/unlock before this action will fail.
*/
kCreated_ANPSurfaceAction = 0,
- /** The surface's dimension has changed.
+ /** The surface's dimension has changed. If the surface is responsible for
+ manually scaling then this action will be generated each time the zoom
+ level of browser is changed. This event is also triggered when the
+ plugin's dimensions in the DOM are changed (e.g. css or javascript).
*/
kChanged_ANPSurfaceAction = 1,
/** The surface has been destroyed. This happens when the view system has