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 37 namespace WebCore { 38 39 GeolocationController::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 67 void GeolocationController::startUpdatingIfNeeded() 68 { 69 if (m_isClientUpdating) 70 return; 71 m_isClientUpdating = true; 72 m_client->startUpdating(); 73 } 74 75 void GeolocationController::stopUpdatingIfNeeded() 76 { 77 if (!m_isClientUpdating) 78 return; 79 m_isClientUpdating = false; 80 m_client->stopUpdating(); 81 } 82 83 GeolocationController::~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. 95 void GeolocationController::willBeDestroyed() 96 { 97 if (m_client) 98 m_client->geolocationDestroyed(); 99 } 100 101 void GeolocationController::persistentHostHasBeenDestroyed() 102 { 103 observeContext(0); 104 } 105 106 PassOwnPtrWillBeRawPtr<GeolocationController> GeolocationController::create(LocalFrame& frame, GeolocationClient* client) 107 { 108 return adoptPtrWillBeNoop(new GeolocationController(frame, client)); 109 } 110 111 void 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 128 void 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 144 void GeolocationController::requestPermission(Geolocation* geolocation) 145 { 146 if (m_client) 147 m_client->requestPermission(geolocation); 148 } 149 150 void GeolocationController::cancelPermissionRequest(Geolocation* geolocation) 151 { 152 if (m_client) 153 m_client->cancelPermissionRequest(geolocation); 154 } 155 156 void 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 170 void 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 178 GeolocationPosition* 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 189 void 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 199 void 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 210 const char* GeolocationController::supplementName() 211 { 212 return "GeolocationController"; 213 } 214 215 void 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 223 void provideGeolocationTo(LocalFrame& frame, GeolocationClient* client) 224 { 225 WillBeHeapSupplement<LocalFrame>::provideTo(frame, GeolocationController::supplementName(), GeolocationController::create(frame, client)); 226 } 227 228 } // namespace WebCore 229