diff options
author | Ben Murdoch <benm@google.com> | 2009-08-18 11:35:14 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2009-08-18 11:35:14 +0100 |
commit | e0330ac957b8434cd2c9c7b5447aaa0faabe77ec (patch) | |
tree | 395ba85351595e79b5e357e46af5c28a0dcb5211 /WebCore | |
parent | b32f88b61a9162a5194ab02c12fc3aff6140e30e (diff) | |
parent | 8ca4160fde81af362cf2ea375997797b1df8243d (diff) | |
download | external_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.cpp | 151 | ||||
-rw-r--r-- | WebCore/bindings/v8/ScriptController.cpp | 7 | ||||
-rw-r--r-- | WebCore/html/HTMLBodyElement.cpp | 13 | ||||
-rw-r--r-- | WebCore/html/HTMLMetaElement.cpp | 8 | ||||
-rw-r--r-- | WebCore/page/Geolocation.cpp | 136 | ||||
-rw-r--r-- | WebCore/page/Geolocation.h | 22 | ||||
-rw-r--r-- | WebCore/page/PositionError.h | 6 | ||||
-rw-r--r-- | WebCore/page/PositionOptions.h | 37 | ||||
-rw-r--r-- | WebCore/page/SecurityOrigin.cpp | 7 | ||||
-rw-r--r-- | WebCore/platform/android/GeolocationServiceAndroid.cpp | 361 | ||||
-rw-r--r-- | WebCore/platform/android/GeolocationServiceAndroid.h | 73 | ||||
-rw-r--r-- | WebCore/plugins/PluginPackage.cpp | 5 | ||||
-rw-r--r-- | WebCore/plugins/PluginPackage.h | 3 | ||||
-rw-r--r-- | WebCore/plugins/android/PluginPackageAndroid.cpp | 106 | ||||
-rw-r--r-- | WebCore/rendering/RenderPartObject.cpp | 109 |
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(); |