1/* 2 * Copyright (C) 2009 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27 28#include "modules/geolocation/GeolocationController.h" 29 30#include "core/inspector/InspectorController.h" 31#include "core/page/Page.h" 32#include "modules/geolocation/GeolocationClient.h" 33#include "modules/geolocation/GeolocationError.h" 34#include "modules/geolocation/GeolocationInspectorAgent.h" 35#include "modules/geolocation/GeolocationPosition.h" 36 37namespace WebCore { 38 39GeolocationController::GeolocationController(LocalFrame& frame, GeolocationClient* client) 40 : PageLifecycleObserver(frame.page()) 41 , m_client(client) 42 , m_hasClientForTest(false) 43 , m_isClientUpdating(false) 44 , m_inspectorAgent() 45{ 46 // FIXME: Once GeolocationInspectorAgent is per frame, there will be a 1:1 relationship between 47 // it and this class. Until then, there's one GeolocationInspectorAgent per page that the main 48 // frame is responsible for creating. 49 if (frame.isMainFrame()) { 50 OwnPtr<GeolocationInspectorAgent> geolocationAgent(GeolocationInspectorAgent::create()); 51 m_inspectorAgent = geolocationAgent.get(); 52 frame.page()->inspectorController().registerModuleAgent(geolocationAgent.release()); 53 } else { 54 m_inspectorAgent = GeolocationController::from(frame.page()->deprecatedLocalMainFrame())->m_inspectorAgent; 55 } 56 57 m_inspectorAgent->AddController(this); 58 59 if (!frame.isMainFrame()) { 60 // internals.setGeolocationClientMock is per page. 61 GeolocationController* mainController = GeolocationController::from(frame.page()->deprecatedLocalMainFrame()); 62 if (mainController->hasClientForTest()) 63 setClientForTest(mainController->client()); 64 } 65} 66 67void GeolocationController::startUpdatingIfNeeded() 68{ 69 if (m_isClientUpdating) 70 return; 71 m_isClientUpdating = true; 72 m_client->startUpdating(); 73} 74 75void GeolocationController::stopUpdatingIfNeeded() 76{ 77 if (!m_isClientUpdating) 78 return; 79 m_isClientUpdating = false; 80 m_client->stopUpdating(); 81} 82 83GeolocationController::~GeolocationController() 84{ 85 ASSERT(m_observers.isEmpty()); 86 if (page()) 87 m_inspectorAgent->RemoveController(this); 88 89 if (m_hasClientForTest) 90 m_client->controllerForTestRemoved(this); 91} 92 93// FIXME: Oilpan: Once GeolocationClient is on-heap m_client should be a strong 94// pointer and |willBeDestroyed| can potentially be removed from Supplement. 95void GeolocationController::willBeDestroyed() 96{ 97 if (m_client) 98 m_client->geolocationDestroyed(); 99} 100 101void GeolocationController::persistentHostHasBeenDestroyed() 102{ 103 observeContext(0); 104} 105 106PassOwnPtrWillBeRawPtr<GeolocationController> GeolocationController::create(LocalFrame& frame, GeolocationClient* client) 107{ 108 return adoptPtrWillBeNoop(new GeolocationController(frame, client)); 109} 110 111void GeolocationController::addObserver(Geolocation* observer, bool enableHighAccuracy) 112{ 113 // This may be called multiple times with the same observer, though removeObserver() 114 // is called only once with each. 115 bool wasEmpty = m_observers.isEmpty(); 116 m_observers.add(observer); 117 if (enableHighAccuracy) 118 m_highAccuracyObservers.add(observer); 119 120 if (m_client) { 121 if (enableHighAccuracy) 122 m_client->setEnableHighAccuracy(true); 123 if (wasEmpty && page() && page()->visibilityState() == PageVisibilityStateVisible) 124 startUpdatingIfNeeded(); 125 } 126} 127 128void GeolocationController::removeObserver(Geolocation* observer) 129{ 130 if (!m_observers.contains(observer)) 131 return; 132 133 m_observers.remove(observer); 134 m_highAccuracyObservers.remove(observer); 135 136 if (m_client) { 137 if (m_observers.isEmpty()) 138 stopUpdatingIfNeeded(); 139 else if (m_highAccuracyObservers.isEmpty()) 140 m_client->setEnableHighAccuracy(false); 141 } 142} 143 144void GeolocationController::requestPermission(Geolocation* geolocation) 145{ 146 if (m_client) 147 m_client->requestPermission(geolocation); 148} 149 150void GeolocationController::cancelPermissionRequest(Geolocation* geolocation) 151{ 152 if (m_client) 153 m_client->cancelPermissionRequest(geolocation); 154} 155 156void GeolocationController::positionChanged(GeolocationPosition* position) 157{ 158 position = m_inspectorAgent->overrideGeolocationPosition(position); 159 if (!position) { 160 errorOccurred(GeolocationError::create(GeolocationError::PositionUnavailable, "PositionUnavailable")); 161 return; 162 } 163 m_lastPosition = position; 164 HeapVector<Member<Geolocation> > observersVector; 165 copyToVector(m_observers, observersVector); 166 for (size_t i = 0; i < observersVector.size(); ++i) 167 observersVector[i]->positionChanged(); 168} 169 170void GeolocationController::errorOccurred(GeolocationError* error) 171{ 172 HeapVector<Member<Geolocation> > observersVector; 173 copyToVector(m_observers, observersVector); 174 for (size_t i = 0; i < observersVector.size(); ++i) 175 observersVector[i]->setError(error); 176} 177 178GeolocationPosition* GeolocationController::lastPosition() 179{ 180 if (m_lastPosition.get()) 181 return m_lastPosition.get(); 182 183 if (!m_client) 184 return 0; 185 186 return m_client->lastPosition(); 187} 188 189void GeolocationController::setClientForTest(GeolocationClient* client) 190{ 191 if (m_hasClientForTest) 192 m_client->controllerForTestRemoved(this); 193 m_client = client; 194 m_hasClientForTest = true; 195 196 client->controllerForTestAdded(this); 197} 198 199void GeolocationController::pageVisibilityChanged() 200{ 201 if (m_observers.isEmpty() || !m_client) 202 return; 203 204 if (page() && page()->visibilityState() == PageVisibilityStateVisible) 205 startUpdatingIfNeeded(); 206 else 207 stopUpdatingIfNeeded(); 208} 209 210const char* GeolocationController::supplementName() 211{ 212 return "GeolocationController"; 213} 214 215void GeolocationController::trace(Visitor* visitor) 216{ 217 visitor->trace(m_lastPosition); 218 visitor->trace(m_observers); 219 visitor->trace(m_highAccuracyObservers); 220 WillBeHeapSupplement<LocalFrame>::trace(visitor); 221} 222 223void provideGeolocationTo(LocalFrame& frame, GeolocationClient* client) 224{ 225 WillBeHeapSupplement<LocalFrame>::provideTo(frame, GeolocationController::supplementName(), GeolocationController::create(frame, client)); 226} 227 228} // namespace WebCore 229