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 blink { 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(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 70void GeolocationController::startUpdatingIfNeeded() 71{ 72 if (m_isClientUpdating) 73 return; 74 m_isClientUpdating = true; 75 m_client->startUpdating(); 76} 77 78void GeolocationController::stopUpdatingIfNeeded() 79{ 80 if (!m_isClientUpdating) 81 return; 82 m_isClientUpdating = false; 83 m_client->stopUpdating(); 84} 85 86GeolocationController::~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 102PassOwnPtrWillBeRawPtr<GeolocationController> GeolocationController::create(LocalFrame& frame, GeolocationClient* client) 103{ 104 return adoptPtrWillBeNoop(new GeolocationController(frame, client)); 105} 106 107void 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 124void 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 140void GeolocationController::requestPermission(Geolocation* geolocation) 141{ 142 if (m_client) 143 m_client->requestPermission(geolocation); 144} 145 146void GeolocationController::cancelPermissionRequest(Geolocation* geolocation) 147{ 148 if (m_client) 149 m_client->cancelPermissionRequest(geolocation); 150} 151 152void 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 166void 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 174GeolocationPosition* 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 185void 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 195void 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 206const char* GeolocationController::supplementName() 207{ 208 return "GeolocationController"; 209} 210 211void 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 221void provideGeolocationTo(LocalFrame& frame, GeolocationClient* client) 222{ 223 WillBeHeapSupplement<LocalFrame>::provideTo(frame, GeolocationController::supplementName(), GeolocationController::create(frame, client)); 224} 225 226} // namespace blink 227