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 blink { 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(nullptr) 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 OwnPtrWillBeRawPtr<GeolocationInspectorAgent> geolocationAgent(GeolocationInspectorAgent::create()); 51 m_inspectorAgent = geolocationAgent.get(); 52 frame.page()->inspectorController().registerModuleAgent(geolocationAgent.release()); 53 } else if (frame.page()->mainFrame()->isLocalFrame()) { 54 m_inspectorAgent = GeolocationController::from(frame.page()->deprecatedLocalMainFrame())->m_inspectorAgent; 55 } 56 57 // m_inspectorAgent is 0 for out of process iframe instantiations, since inspector is currently unable 58 // to handle that scenario. 59 if (m_inspectorAgent) 60 m_inspectorAgent->addController(this); 61 62 if (!frame.isMainFrame() && frame.page()->mainFrame()->isLocalFrame()) { 63 // internals.setGeolocationClientMock is per page. 64 GeolocationController* mainController = GeolocationController::from(frame.page()->deprecatedLocalMainFrame()); 65 if (mainController->hasClientForTest()) 66 setClientForTest(mainController->client()); 67 } 68 } 69 70 void GeolocationController::startUpdatingIfNeeded() 71 { 72 if (m_isClientUpdating) 73 return; 74 m_isClientUpdating = true; 75 m_client->startUpdating(); 76 } 77 78 void GeolocationController::stopUpdatingIfNeeded() 79 { 80 if (!m_isClientUpdating) 81 return; 82 m_isClientUpdating = false; 83 m_client->stopUpdating(); 84 } 85 86 GeolocationController::~GeolocationController() 87 { 88 ASSERT(m_observers.isEmpty()); 89 #if !ENABLE(OILPAN) 90 if (page() && m_inspectorAgent) { 91 m_inspectorAgent->removeController(this); 92 m_inspectorAgent = nullptr; 93 } 94 95 if (m_hasClientForTest) { 96 m_client->controllerForTestRemoved(this); 97 m_hasClientForTest = false; 98 } 99 #endif 100 } 101 102 PassOwnPtrWillBeRawPtr<GeolocationController> GeolocationController::create(LocalFrame& frame, GeolocationClient* client) 103 { 104 return adoptPtrWillBeNoop(new GeolocationController(frame, client)); 105 } 106 107 void GeolocationController::addObserver(Geolocation* observer, bool enableHighAccuracy) 108 { 109 // This may be called multiple times with the same observer, though removeObserver() 110 // is called only once with each. 111 bool wasEmpty = m_observers.isEmpty(); 112 m_observers.add(observer); 113 if (enableHighAccuracy) 114 m_highAccuracyObservers.add(observer); 115 116 if (m_client) { 117 if (enableHighAccuracy) 118 m_client->setEnableHighAccuracy(true); 119 if (wasEmpty && page() && page()->visibilityState() == PageVisibilityStateVisible) 120 startUpdatingIfNeeded(); 121 } 122 } 123 124 void GeolocationController::removeObserver(Geolocation* observer) 125 { 126 if (!m_observers.contains(observer)) 127 return; 128 129 m_observers.remove(observer); 130 m_highAccuracyObservers.remove(observer); 131 132 if (m_client) { 133 if (m_observers.isEmpty()) 134 stopUpdatingIfNeeded(); 135 else if (m_highAccuracyObservers.isEmpty()) 136 m_client->setEnableHighAccuracy(false); 137 } 138 } 139 140 void GeolocationController::requestPermission(Geolocation* geolocation) 141 { 142 if (m_client) 143 m_client->requestPermission(geolocation); 144 } 145 146 void GeolocationController::cancelPermissionRequest(Geolocation* geolocation) 147 { 148 if (m_client) 149 m_client->cancelPermissionRequest(geolocation); 150 } 151 152 void GeolocationController::positionChanged(GeolocationPosition* position) 153 { 154 position = m_inspectorAgent->overrideGeolocationPosition(position); 155 if (!position) { 156 errorOccurred(GeolocationError::create(GeolocationError::PositionUnavailable, "PositionUnavailable")); 157 return; 158 } 159 m_lastPosition = position; 160 HeapVector<Member<Geolocation> > observersVector; 161 copyToVector(m_observers, observersVector); 162 for (size_t i = 0; i < observersVector.size(); ++i) 163 observersVector[i]->positionChanged(); 164 } 165 166 void GeolocationController::errorOccurred(GeolocationError* error) 167 { 168 HeapVector<Member<Geolocation> > observersVector; 169 copyToVector(m_observers, observersVector); 170 for (size_t i = 0; i < observersVector.size(); ++i) 171 observersVector[i]->setError(error); 172 } 173 174 GeolocationPosition* GeolocationController::lastPosition() 175 { 176 if (m_lastPosition.get()) 177 return m_lastPosition.get(); 178 179 if (!m_client) 180 return 0; 181 182 return m_client->lastPosition(); 183 } 184 185 void GeolocationController::setClientForTest(GeolocationClient* client) 186 { 187 if (m_hasClientForTest) 188 m_client->controllerForTestRemoved(this); 189 m_client = client; 190 m_hasClientForTest = true; 191 192 client->controllerForTestAdded(this); 193 } 194 195 void GeolocationController::pageVisibilityChanged() 196 { 197 if (m_observers.isEmpty() || !m_client) 198 return; 199 200 if (page() && page()->visibilityState() == PageVisibilityStateVisible) 201 startUpdatingIfNeeded(); 202 else 203 stopUpdatingIfNeeded(); 204 } 205 206 const char* GeolocationController::supplementName() 207 { 208 return "GeolocationController"; 209 } 210 211 void GeolocationController::trace(Visitor* visitor) 212 { 213 visitor->trace(m_client); 214 visitor->trace(m_lastPosition); 215 visitor->trace(m_observers); 216 visitor->trace(m_highAccuracyObservers); 217 visitor->trace(m_inspectorAgent); 218 WillBeHeapSupplement<LocalFrame>::trace(visitor); 219 } 220 221 void provideGeolocationTo(LocalFrame& frame, GeolocationClient* client) 222 { 223 WillBeHeapSupplement<LocalFrame>::provideTo(frame, GeolocationController::supplementName(), GeolocationController::create(frame, client)); 224 } 225 226 } // namespace blink 227