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#include "GeolocationController.h"
28
29#if ENABLE(GEOLOCATION)
30
31#include "GeolocationClient.h"
32#include "GeolocationError.h"
33#include "GeolocationPosition.h"
34
35namespace WebCore {
36
37GeolocationController::GeolocationController(Page& page, GeolocationClient* client)
38    : m_page(page)
39    , m_client(client)
40{
41    m_page.addViewStateChangeObserver(*this);
42}
43
44GeolocationController::~GeolocationController()
45{
46    ASSERT(m_observers.isEmpty());
47
48    // NOTE: We don't have to remove ourselves from page's ViewStateChangeObserver set, since
49    // we are supplement of the Page, and our destructor getting called means the page is being
50    // torn down.
51
52    if (m_client)
53        m_client->geolocationDestroyed();
54}
55
56void GeolocationController::addObserver(Geolocation* observer, bool enableHighAccuracy)
57{
58    // This may be called multiple times with the same observer, though removeObserver()
59    // is called only once with each.
60    bool wasEmpty = m_observers.isEmpty();
61    m_observers.add(observer);
62    if (enableHighAccuracy)
63        m_highAccuracyObservers.add(observer);
64
65    if (m_client) {
66        if (enableHighAccuracy)
67            m_client->setEnableHighAccuracy(true);
68        if (wasEmpty)
69            m_client->startUpdating();
70    }
71}
72
73void GeolocationController::removeObserver(Geolocation* observer)
74{
75    if (!m_observers.contains(observer))
76        return;
77
78    m_observers.remove(observer);
79    m_highAccuracyObservers.remove(observer);
80
81    if (m_client) {
82        if (m_observers.isEmpty())
83            m_client->stopUpdating();
84        else if (m_highAccuracyObservers.isEmpty())
85            m_client->setEnableHighAccuracy(false);
86    }
87}
88
89void GeolocationController::requestPermission(Geolocation* geolocation)
90{
91    if (!m_page.isVisible()) {
92        m_pendedPermissionRequest.add(geolocation);
93        return;
94    }
95
96    if (m_client)
97        m_client->requestPermission(geolocation);
98}
99
100void GeolocationController::cancelPermissionRequest(Geolocation* geolocation)
101{
102    if (m_pendedPermissionRequest.remove(geolocation))
103        return;
104
105    if (m_client)
106        m_client->cancelPermissionRequest(geolocation);
107}
108
109void GeolocationController::positionChanged(GeolocationPosition* position)
110{
111    m_lastPosition = position;
112    Vector<RefPtr<Geolocation>> observersVector;
113    copyToVector(m_observers, observersVector);
114    for (size_t i = 0; i < observersVector.size(); ++i)
115        observersVector[i]->positionChanged();
116}
117
118void GeolocationController::errorOccurred(GeolocationError* error)
119{
120    Vector<RefPtr<Geolocation>> observersVector;
121    copyToVector(m_observers, observersVector);
122    for (size_t i = 0; i < observersVector.size(); ++i)
123        observersVector[i]->setError(error);
124}
125
126GeolocationPosition* GeolocationController::lastPosition()
127{
128    if (m_lastPosition.get())
129        return m_lastPosition.get();
130
131    if (!m_client)
132        return 0;
133
134    return m_client->lastPosition();
135}
136
137void GeolocationController::viewStateDidChange(ViewState::Flags, ViewState::Flags)
138{
139    if (!m_page.isVisible())
140        return;
141
142    HashSet<RefPtr<Geolocation>> pendedPermissionRequests = WTF::move(m_pendedPermissionRequest);
143    for (auto& permissionRequest : pendedPermissionRequests)
144        m_client->requestPermission(permissionRequest.get());
145}
146
147const char* GeolocationController::supplementName()
148{
149    return "GeolocationController";
150}
151
152void provideGeolocationTo(Page* page, GeolocationClient* client)
153{
154    Supplement<Page>::provideTo(page, GeolocationController::supplementName(), std::make_unique<GeolocationController>(*page, client));
155}
156
157} // namespace WebCore
158
159#endif // ENABLE(GEOLOCATION)
160