summaryrefslogtreecommitdiffstats
path: root/WebCore
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 /WebCore
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
Diffstat (limited to 'WebCore')
-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
15 files changed, 758 insertions, 286 deletions
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();