| Index: third_party/WebKit/Source/modules/geolocation/Geolocation.cpp | 
| diff --git a/third_party/WebKit/Source/modules/geolocation/Geolocation.cpp b/third_party/WebKit/Source/modules/geolocation/Geolocation.cpp | 
| index efdb860a03b604b053a2dcc6507b1a5393f3035a..6b510b3256682204294aa9209c4fc5d486cd91da 100644 | 
| --- a/third_party/WebKit/Source/modules/geolocation/Geolocation.cpp | 
| +++ b/third_party/WebKit/Source/modules/geolocation/Geolocation.cpp | 
| @@ -32,64 +32,67 @@ | 
| #include "core/frame/OriginsUsingFeatures.h" | 
| #include "core/frame/Settings.h" | 
| #include "modules/geolocation/Coordinates.h" | 
| -#include "modules/geolocation/GeolocationController.h" | 
| #include "modules/geolocation/GeolocationError.h" | 
| -#include "modules/geolocation/GeolocationPosition.h" | 
| -#include "platform/weborigin/SecurityOrigin.h" | 
| +#include "platform/mojo/MojoHelper.h" | 
| +#include "public/platform/ServiceRegistry.h" | 
| #include "wtf/CurrentTime.h" | 
|  | 
| namespace blink { | 
| +namespace { | 
|  | 
| static const char permissionDeniedErrorMessage[] = "User denied Geolocation"; | 
| static const char failedToStartServiceErrorMessage[] = "Failed to start Geolocation service"; | 
| static const char framelessDocumentErrorMessage[] = "Geolocation cannot be used in frameless documents"; | 
|  | 
| -static Geoposition* createGeoposition(GeolocationPosition* position) | 
| +static Geoposition* createGeoposition(const mojom::blink::Geoposition& position) | 
| { | 
| -    if (!position) | 
| -        return nullptr; | 
| - | 
| Coordinates* coordinates = Coordinates::create( | 
| -        position->latitude(), | 
| -        position->longitude(), | 
| -        position->canProvideAltitude(), | 
| -        position->altitude(), | 
| -        position->accuracy(), | 
| -        position->canProvideAltitudeAccuracy(), | 
| -        position->altitudeAccuracy(), | 
| -        position->canProvideHeading(), | 
| -        position->heading(), | 
| -        position->canProvideSpeed(), | 
| -        position->speed()); | 
| -    return Geoposition::create(coordinates, convertSecondsToDOMTimeStamp(position->timestamp())); | 
| -} | 
| - | 
| -static PositionError* createPositionError(GeolocationError* error) | 
| -{ | 
| -    PositionError::ErrorCode code = PositionError::POSITION_UNAVAILABLE; | 
| -    switch (error->code()) { | 
| -    case GeolocationError::PermissionDenied: | 
| -        code = PositionError::PERMISSION_DENIED; | 
| +        position.latitude, | 
| +        position.longitude, | 
| +        position.altitude > -10000., | 
| +        position.altitude, | 
| +        position.accuracy, | 
| +        position.altitude_accuracy >= 0., | 
| +        position.altitude_accuracy, | 
| +        position.heading >= 0. && position.heading <= 360., | 
| +        position.heading, | 
| +        position.speed >= 0., | 
| +        position.speed); | 
| +    return Geoposition::create(coordinates, convertSecondsToDOMTimeStamp(position.timestamp)); | 
| +} | 
| + | 
| +static PositionError* createPositionError(mojom::blink::Geoposition::ErrorCode mojomErrorCode, const String& error) | 
| +{ | 
| +    PositionError::ErrorCode errorCode = PositionError::POSITION_UNAVAILABLE; | 
| +    switch (mojomErrorCode) { | 
| +    case mojom::blink::Geoposition::ErrorCode::PERMISSION_DENIED: | 
| +        errorCode = PositionError::PERMISSION_DENIED; | 
| +        break; | 
| +    case mojom::blink::Geoposition::ErrorCode::POSITION_UNAVAILABLE: | 
| +        errorCode = PositionError::POSITION_UNAVAILABLE; | 
| break; | 
| -    case GeolocationError::PositionUnavailable: | 
| -        code = PositionError::POSITION_UNAVAILABLE; | 
| +    case mojom::blink::Geoposition::ErrorCode::NONE: | 
| +    case mojom::blink::Geoposition::ErrorCode::TIMEOUT: | 
| +        NOTREACHED(); | 
| break; | 
| } | 
| - | 
| -    return PositionError::create(code, error->message()); | 
| +    return PositionError::create(errorCode, error); | 
| } | 
|  | 
| +} // namespace | 
| + | 
| Geolocation* Geolocation::create(ExecutionContext* context) | 
| { | 
| Geolocation* geolocation = new Geolocation(context); | 
| -    geolocation->suspendIfNeeded(); | 
| return geolocation; | 
| } | 
|  | 
| Geolocation::Geolocation(ExecutionContext* context) | 
| -    : ActiveDOMObject(context) | 
| +    : ContextLifecycleObserver(context) | 
| +    , PageLifecycleObserver(document()->page()) | 
| , m_geolocationPermission(PermissionUnknown) | 
| { | 
| +    ThreadState::current()->registerPreFinalizer(this); | 
| } | 
|  | 
| Geolocation::~Geolocation() | 
| @@ -103,8 +106,8 @@ DEFINE_TRACE(Geolocation) | 
| visitor->trace(m_watchers); | 
| visitor->trace(m_pendingForPermissionNotifiers); | 
| visitor->trace(m_lastPosition); | 
| -    visitor->trace(m_requestsAwaitingCachedPosition); | 
| -    ActiveDOMObject::trace(visitor); | 
| +    ContextLifecycleObserver::trace(visitor); | 
| +    PageLifecycleObserver::trace(visitor); | 
| } | 
|  | 
| Document* Geolocation::document() const | 
| @@ -117,28 +120,18 @@ LocalFrame* Geolocation::frame() const | 
| return document() ? document()->frame() : 0; | 
| } | 
|  | 
| -void Geolocation::stop() | 
| +void Geolocation::contextDestroyed() | 
| { | 
| -    LocalFrame* frame = this->frame(); | 
| -    if (frame && m_geolocationPermission == PermissionRequested) | 
| -        GeolocationController::from(frame)->cancelPermissionRequest(this); | 
| +    if (m_permissionService) | 
| +        m_permissionService.reset(); | 
|  | 
| -    // The frame may be moving to a new page and we want to get the permissions from the new page's client. | 
| -    m_geolocationPermission = PermissionUnknown; | 
| cancelAllRequests(); | 
| stopUpdating(); | 
| +    m_geolocationPermission = PermissionDenied; | 
| m_pendingForPermissionNotifiers.clear(); | 
| -} | 
| - | 
| -Geoposition* Geolocation::lastPosition() | 
| -{ | 
| -    LocalFrame* frame = this->frame(); | 
| -    if (!frame) | 
| -        return 0; | 
| - | 
| -    m_lastPosition = createGeoposition(GeolocationController::from(frame)->lastPosition()); | 
| - | 
| -    return m_lastPosition; | 
| +    m_lastPosition = nullptr; | 
| +    ContextLifecycleObserver::clearContext(); | 
| +    PageLifecycleObserver::clearContext(); | 
| } | 
|  | 
| void Geolocation::recordOriginTypeAccess() const | 
| @@ -218,10 +211,10 @@ void Geolocation::startRequest(GeoNotifier *notifier) | 
| // if we don't yet have permission, request for permission before calling startUpdating() | 
| m_pendingForPermissionNotifiers.add(notifier); | 
| requestPermission(); | 
| -    } else if (startUpdating(notifier)) | 
| +    } else { | 
| +        startUpdating(notifier); | 
| notifier->startTimer(); | 
| -    else | 
| -        notifier->setFatalError(PositionError::create(PositionError::POSITION_UNAVAILABLE, failedToStartServiceErrorMessage)); | 
| +    } | 
| } | 
|  | 
| void Geolocation::fatalErrorOccurred(GeoNotifier* notifier) | 
| @@ -236,47 +229,20 @@ void Geolocation::fatalErrorOccurred(GeoNotifier* notifier) | 
|  | 
| void Geolocation::requestUsesCachedPosition(GeoNotifier* notifier) | 
| { | 
| -    // This is called asynchronously, so the permissions could have been denied | 
| -    // since we last checked in startRequest. | 
| -    if (isDenied()) { | 
| -        notifier->setFatalError(PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage)); | 
| -        return; | 
| -    } | 
| +    DCHECK(isAllowed()); | 
|  | 
| -    m_requestsAwaitingCachedPosition.add(notifier); | 
| +    notifier->runSuccessCallback(m_lastPosition); | 
|  | 
| -    // If permissions are allowed, make the callback | 
| -    if (isAllowed()) { | 
| -        makeCachedPositionCallbacks(); | 
| -        return; | 
| -    } | 
| - | 
| -    // Request permissions, which may be synchronous or asynchronous. | 
| -    requestPermission(); | 
| -} | 
| - | 
| -void Geolocation::makeCachedPositionCallbacks() | 
| -{ | 
| -    // All modifications to m_requestsAwaitingCachedPosition are done | 
| -    // asynchronously, so we don't need to worry about it being modified from | 
| -    // the callbacks. | 
| -    for (GeoNotifier* notifier : m_requestsAwaitingCachedPosition) { | 
| -        notifier->runSuccessCallback(lastPosition()); | 
| - | 
| -        // If this is a one-shot request, stop it. Otherwise, if the watch still | 
| -        // exists, start the service to get updates. | 
| -        if (m_oneShots.contains(notifier)) | 
| -            m_oneShots.remove(notifier); | 
| -        else if (m_watchers.contains(notifier)) { | 
| -            if (!notifier->options().timeout() || startUpdating(notifier)) | 
| -                notifier->startTimer(); | 
| -            else | 
| -                notifier->setFatalError(PositionError::create(PositionError::POSITION_UNAVAILABLE, failedToStartServiceErrorMessage)); | 
| -        } | 
| +    // If this is a one-shot request, stop it. Otherwise, if the watch still | 
| +    // exists, start the service to get updates. | 
| +    if (m_oneShots.contains(notifier)) { | 
| +        m_oneShots.remove(notifier); | 
| +    } else if (m_watchers.contains(notifier)) { | 
| +        if (notifier->options().timeout()) | 
| +            startUpdating(notifier); | 
| +        notifier->startTimer(); | 
| } | 
|  | 
| -    m_requestsAwaitingCachedPosition.clear(); | 
| - | 
| if (!hasListeners()) | 
| stopUpdating(); | 
| } | 
| @@ -292,13 +258,13 @@ void Geolocation::requestTimedOut(GeoNotifier* notifier) | 
|  | 
| bool Geolocation::haveSuitableCachedPosition(const PositionOptions& options) | 
| { | 
| -    Geoposition* cachedPosition = lastPosition(); | 
| -    if (!cachedPosition) | 
| +    if (!m_lastPosition) | 
| return false; | 
| +    DCHECK(isAllowed()); | 
| if (!options.maximumAge()) | 
| return false; | 
| DOMTimeStamp currentTimeMillis = convertSecondsToDOMTimeStamp(currentTime()); | 
| -    return cachedPosition->timestamp() > currentTimeMillis - options.maximumAge(); | 
| +    return m_lastPosition->timestamp() > currentTimeMillis - options.maximumAge(); | 
| } | 
|  | 
| void Geolocation::clearWatch(int watchID) | 
| @@ -314,33 +280,25 @@ void Geolocation::clearWatch(int watchID) | 
| stopUpdating(); | 
| } | 
|  | 
| -void Geolocation::setIsAllowed(bool allowed) | 
| +void Geolocation::onGeolocationPermissionUpdated(mojom::blink::PermissionStatus status) | 
| { | 
| // This may be due to either a new position from the service, or a cached position. | 
| -    m_geolocationPermission = allowed ? PermissionAllowed : PermissionDenied; | 
| +    m_geolocationPermission = status == mojom::blink::PermissionStatus::GRANTED ? PermissionAllowed : PermissionDenied; | 
| +    m_permissionService.reset(); | 
|  | 
| -    // Permission request was made during the startRequest process | 
| -    if (!m_pendingForPermissionNotifiers.isEmpty()) { | 
| -        handlePendingPermissionNotifiers(); | 
| -        m_pendingForPermissionNotifiers.clear(); | 
| -        return; | 
| -    } | 
| - | 
| -    if (!isAllowed()) { | 
| -        PositionError* error = PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage); | 
| -        error->setIsFatal(true); | 
| -        handleError(error); | 
| -        m_requestsAwaitingCachedPosition.clear(); | 
| -        return; | 
| +    // While we iterate through the list, we need not worry about the list being modified as the permission | 
| +    // is already set to Yes/No and no new listeners will be added to the pending list. | 
| +    for (GeoNotifier* notifier : m_pendingForPermissionNotifiers) { | 
| +        if (isAllowed()) { | 
| +            // Start all pending notification requests as permission granted. | 
| +            // The notifier is always ref'ed by m_oneShots or m_watchers. | 
| +            startUpdating(notifier); | 
| +            notifier->startTimer(); | 
| +        } else { | 
| +            notifier->setFatalError(PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage)); | 
| +        } | 
| } | 
| - | 
| -    // If the service has a last position, use it to call back for all requests. | 
| -    // If any of the requests are waiting for permission for a cached position, | 
| -    // the position from the service will be at least as fresh. | 
| -    if (lastPosition()) | 
| -        makeSuccessCallbacks(); | 
| -    else | 
| -        makeCachedPositionCallbacks(); | 
| +    m_pendingForPermissionNotifiers.clear(); | 
| } | 
|  | 
| void Geolocation::sendError(GeoNotifierVector& notifiers, PositionError* error) | 
| @@ -463,14 +421,20 @@ void Geolocation::requestPermission() | 
| return; | 
|  | 
| m_geolocationPermission = PermissionRequested; | 
| +    frame->serviceRegistry()->connectToRemoteService( | 
| +        mojo::GetProxy(&m_permissionService)); | 
| +    m_permissionService.set_connection_error_handler(sameThreadBindForMojo(&Geolocation::onPermissionConnectionError, this)); | 
|  | 
| // Ask the embedder: it maintains the geolocation challenge policy itself. | 
| -    GeolocationController::from(frame)->requestPermission(this); | 
| +    m_permissionService->RequestPermission( | 
| +        mojom::blink::PermissionName::GEOLOCATION, | 
| +        getExecutionContext()->getSecurityOrigin()->toString(), | 
| +        sameThreadBindForMojo(&Geolocation::onGeolocationPermissionUpdated, this)); | 
| } | 
|  | 
| void Geolocation::makeSuccessCallbacks() | 
| { | 
| -    ASSERT(lastPosition()); | 
| +    ASSERT(m_lastPosition); | 
| ASSERT(isAllowed()); | 
|  | 
| GeoNotifierVector oneShotsCopy; | 
| @@ -484,13 +448,8 @@ void Geolocation::makeSuccessCallbacks() | 
| // further callbacks to these notifiers. | 
| m_oneShots.clear(); | 
|  | 
| -    // Also clear the set of notifiers waiting for a cached position. All the | 
| -    // oneshots and watchers will receive a position now, and if they happen to | 
| -    // be lingering in that set, avoid this bug: http://crbug.com/311876 . | 
| -    m_requestsAwaitingCachedPosition.clear(); | 
| - | 
| -    sendPosition(oneShotsCopy, lastPosition()); | 
| -    sendPosition(watchersCopy, lastPosition()); | 
| +    sendPosition(oneShotsCopy, m_lastPosition); | 
| +    sendPosition(watchersCopy, m_lastPosition); | 
|  | 
| if (!hasListeners()) | 
| stopUpdating(); | 
| @@ -506,46 +465,75 @@ void Geolocation::positionChanged() | 
| makeSuccessCallbacks(); | 
| } | 
|  | 
| -void Geolocation::setError(GeolocationError* error) | 
| +void Geolocation::startUpdating(GeoNotifier* notifier) | 
| { | 
| -    handleError(createPositionError(error)); | 
| +    m_updating = true; | 
| +    if (notifier->options().enableHighAccuracy() && !m_enableHighAccuracy) { | 
| +        m_enableHighAccuracy = true; | 
| +        if (m_geolocationService) | 
| +            m_geolocationService->SetHighAccuracy(true); | 
| +    } | 
| +    updateGeolocationServiceConnection(); | 
| } | 
|  | 
| -bool Geolocation::startUpdating(GeoNotifier* notifier) | 
| +void Geolocation::stopUpdating() | 
| { | 
| -    LocalFrame* frame = this->frame(); | 
| -    if (!frame) | 
| -        return false; | 
| - | 
| -    GeolocationController::from(frame)->addObserver(this, notifier->options().enableHighAccuracy()); | 
| -    return true; | 
| +    m_updating = false; | 
| +    updateGeolocationServiceConnection(); | 
| +    m_enableHighAccuracy = false; | 
| } | 
|  | 
| -void Geolocation::stopUpdating() | 
| +void Geolocation::updateGeolocationServiceConnection() | 
| { | 
| -    LocalFrame* frame = this->frame(); | 
| -    if (!frame) | 
| +    if (!getExecutionContext() || !page() || !page()->isPageVisible() || !m_updating) { | 
| +        m_geolocationService.reset(); | 
| +        m_disconnectedGeolocationService = true; | 
| +        return; | 
| +    } | 
| +    if (m_geolocationService) | 
| return; | 
|  | 
| -    GeolocationController::from(frame)->removeObserver(this); | 
| +    frame()->serviceRegistry()->connectToRemoteService(mojo::GetProxy(&m_geolocationService)); | 
| +    m_geolocationService.set_connection_error_handler(sameThreadBindForMojo(&Geolocation::onGeolocationConnectionError, this)); | 
| +    if (m_enableHighAccuracy) | 
| +        m_geolocationService->SetHighAccuracy(true); | 
| +    queryNextPosition(); | 
| } | 
|  | 
| -void Geolocation::handlePendingPermissionNotifiers() | 
| +void Geolocation::queryNextPosition() | 
| { | 
| -    // While we iterate through the list, we need not worry about list being modified as the permission | 
| -    // is already set to Yes/No and no new listeners will be added to the pending list. | 
| -    for (GeoNotifier* notifier : m_pendingForPermissionNotifiers) { | 
| -        if (isAllowed()) { | 
| -            // start all pending notification requests as permission granted. | 
| -            // The notifier is always ref'ed by m_oneShots or m_watchers. | 
| -            if (startUpdating(notifier)) | 
| -                notifier->startTimer(); | 
| -            else | 
| -                notifier->setFatalError(PositionError::create(PositionError::POSITION_UNAVAILABLE, failedToStartServiceErrorMessage)); | 
| -        } else { | 
| -            notifier->setFatalError(PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage)); | 
| -        } | 
| +    m_geolocationService->QueryNextPosition( | 
| +        sameThreadBindForMojo(&Geolocation::onPositionUpdated, this)); | 
| +} | 
| + | 
| +void Geolocation::onPositionUpdated(mojom::blink::GeopositionPtr position) | 
| +{ | 
| +    m_disconnectedGeolocationService = false; | 
| +    if (position->valid) { | 
| +        m_lastPosition = createGeoposition(*position); | 
| +        positionChanged(); | 
| +    } else { | 
| +        handleError(createPositionError(position->error_code, position->error_message)); | 
| } | 
| +    if (!m_disconnectedGeolocationService) | 
| +        queryNextPosition(); | 
| +} | 
| + | 
| +void Geolocation::pageVisibilityChanged() | 
| +{ | 
| +    updateGeolocationServiceConnection(); | 
| +} | 
| + | 
| +void Geolocation::onGeolocationConnectionError() | 
| +{ | 
| +    PositionError* error = PositionError::create(PositionError::POSITION_UNAVAILABLE, failedToStartServiceErrorMessage); | 
| +    error->setIsFatal(true); | 
| +    handleError(error); | 
| +} | 
| + | 
| +void Geolocation::onPermissionConnectionError() | 
| +{ | 
| +    onGeolocationPermissionUpdated(mojom::blink::PermissionStatus::DENIED); | 
| } | 
|  | 
| } // namespace blink | 
|  |