1/*
2 * Copyright 2010, The Android Open Source Project
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 *  * Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 *  * 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 THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "DeviceOrientationController.h"
28
29#include "DeviceOrientation.h"
30#include "DeviceOrientationClient.h"
31#include "DeviceOrientationEvent.h"
32
33namespace WebCore {
34
35DeviceOrientationController::DeviceOrientationController(Page* page, DeviceOrientationClient* client)
36    : m_page(page)
37    , m_client(client)
38    , m_timer(this, &DeviceOrientationController::timerFired)
39{
40    ASSERT(m_client);
41    m_client->setController(this);
42}
43
44DeviceOrientationController::~DeviceOrientationController()
45{
46    m_client->deviceOrientationControllerDestroyed();
47}
48
49void DeviceOrientationController::timerFired(Timer<DeviceOrientationController>* timer)
50{
51    ASSERT_UNUSED(timer, timer == &m_timer);
52    ASSERT(m_client->lastOrientation());
53
54    RefPtr<DeviceOrientation> orientation = m_client->lastOrientation();
55    RefPtr<DeviceOrientationEvent> event = DeviceOrientationEvent::create(eventNames().deviceorientationEvent, orientation.get());
56
57    Vector<RefPtr<DOMWindow> > listenersVector;
58    copyToVector(m_newListeners, listenersVector);
59    m_newListeners.clear();
60    for (size_t i = 0; i < listenersVector.size(); ++i)
61        listenersVector[i]->dispatchEvent(event);
62}
63
64void DeviceOrientationController::addListener(DOMWindow* window)
65{
66    // If the client already has an orientation, we should fire an event with that
67    // orientation. The event is fired asynchronously, but without
68    // waiting for the client to get a new orientation.
69    if (m_client->lastOrientation()) {
70        m_newListeners.add(window);
71        if (!m_timer.isActive())
72            m_timer.startOneShot(0);
73    }
74
75    // The client must not call back synchronously.
76    bool wasEmpty = m_listeners.isEmpty();
77    m_listeners.add(window);
78    if (wasEmpty)
79        m_client->startUpdating();
80}
81
82void DeviceOrientationController::removeListener(DOMWindow* window)
83{
84    m_listeners.remove(window);
85    m_newListeners.remove(window);
86    if (m_listeners.isEmpty())
87        m_client->stopUpdating();
88}
89
90void DeviceOrientationController::removeAllListeners(DOMWindow* window)
91{
92    // May be called with a DOMWindow that's not a listener.
93    if (!m_listeners.contains(window))
94        return;
95
96    m_listeners.removeAll(window);
97    m_newListeners.remove(window);
98    if (m_listeners.isEmpty())
99        m_client->stopUpdating();
100}
101
102void DeviceOrientationController::didChangeDeviceOrientation(DeviceOrientation* orientation)
103{
104    RefPtr<DeviceOrientationEvent> event = DeviceOrientationEvent::create(eventNames().deviceorientationEvent, orientation);
105    Vector<RefPtr<DOMWindow> > listenersVector;
106    copyToVector(m_listeners, listenersVector);
107    for (size_t i = 0; i < listenersVector.size(); ++i)
108        listenersVector[i]->dispatchEvent(event);
109}
110
111} // namespace WebCore
112