Rename first/second to key/value in HashMap iterators
[WebKit-https.git] / Source / WebCore / platform / graphics / DisplayRefreshMonitor.cpp
1 /*
2  * Copyright (C) 2010 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. ``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 APPLE COMPUTER, INC. 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
28 #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
29
30 #include "DisplayRefreshMonitor.h"
31
32 #include <wtf/CurrentTime.h>
33
34 namespace WebCore {
35
36 DisplayRefreshMonitorClient::DisplayRefreshMonitorClient()
37     : m_scheduled(false)
38     , m_displayIDIsSet(false)
39 {
40 }
41
42 DisplayRefreshMonitorClient::~DisplayRefreshMonitorClient()
43 {
44     DisplayRefreshMonitorManager::sharedManager()->unregisterClient(this);
45 }
46
47 void DisplayRefreshMonitorClient::fireDisplayRefreshIfNeeded(double timestamp)
48 {
49     if (m_scheduled) {
50         m_scheduled = false;
51         displayRefreshFired(timestamp);
52     }
53 }
54
55 DisplayRefreshMonitor::DisplayRefreshMonitor(PlatformDisplayID displayID)
56     : m_timestamp(0)
57     , m_active(true)
58     , m_scheduled(false)
59     , m_previousFrameDone(true)
60     , m_unscheduledFireCount(0)
61     , m_displayID(displayID)
62 #if PLATFORM(MAC)
63     , m_displayLink(0)
64 #endif
65 #if PLATFORM(BLACKBERRY)
66     , m_animationClient(0)
67 #endif
68 {
69 }
70
71 void DisplayRefreshMonitor::handleDisplayRefreshedNotificationOnMainThread(void* data)
72 {
73     DisplayRefreshMonitor* monitor = static_cast<DisplayRefreshMonitor*>(data);
74     monitor->displayDidRefresh();
75 }
76
77 void DisplayRefreshMonitor::addClient(DisplayRefreshMonitorClient* client)
78 {
79     m_clients.add(client);
80 }
81
82 bool DisplayRefreshMonitor::removeClient(DisplayRefreshMonitorClient* client)
83 {
84     DisplayRefreshMonitorClientSet::iterator it = m_clients.find(client);
85     if (it != m_clients.end()) {
86         m_clients.remove(it);
87         return true;
88     }
89     return false;
90 }
91
92 void DisplayRefreshMonitor::displayDidRefresh()
93 {
94     double timestamp;
95     {
96         MutexLocker lock(m_mutex);
97          if (!m_scheduled)
98             ++m_unscheduledFireCount;
99         else
100             m_unscheduledFireCount = 0;
101
102         m_scheduled = false;
103         timestamp = m_timestamp;
104     }
105
106     // The call back can cause all our clients to be unregistered, so we need to protect
107     // against deletion until the end of the method.
108     RefPtr<DisplayRefreshMonitor> protector(this);
109     
110     Vector<DisplayRefreshMonitorClient*> clients;
111     copyToVector(m_clients, clients);
112     for (size_t i = 0; i < clients.size(); ++i)
113         clients[i]->fireDisplayRefreshIfNeeded(timestamp);
114
115     {
116         MutexLocker lock(m_mutex);
117         m_previousFrameDone = true;
118     }
119     
120     DisplayRefreshMonitorManager::sharedManager()->displayDidRefresh(this);
121 }
122
123 DisplayRefreshMonitorManager* DisplayRefreshMonitorManager::sharedManager()
124 {
125     DEFINE_STATIC_LOCAL(DisplayRefreshMonitorManager, manager, ());
126     return &manager;
127 }
128
129 DisplayRefreshMonitor* DisplayRefreshMonitorManager::ensureMonitorForClient(DisplayRefreshMonitorClient* client)
130 {
131     DisplayRefreshMonitorMap::iterator it = m_monitors.find(client->m_displayID);
132     if (it == m_monitors.end()) {
133         RefPtr<DisplayRefreshMonitor> monitor = DisplayRefreshMonitor::create(client->m_displayID);
134         monitor->addClient(client);
135         DisplayRefreshMonitor* result = monitor.get();
136         m_monitors.add(client->m_displayID, monitor.release());
137         return result;
138     }
139
140     return it->value.get();
141 }
142
143 void DisplayRefreshMonitorManager::registerClient(DisplayRefreshMonitorClient* client)
144 {
145     if (!client->m_displayIDIsSet)
146         return;
147         
148     ensureMonitorForClient(client);
149 }
150
151 void DisplayRefreshMonitorManager::unregisterClient(DisplayRefreshMonitorClient* client)
152 {
153     if (!client->m_displayIDIsSet)
154         return;
155
156     DisplayRefreshMonitorMap::iterator it = m_monitors.find(client->m_displayID);
157     if (it == m_monitors.end())
158         return;
159     
160     DisplayRefreshMonitor* monitor = it->value.get();
161     if (monitor->removeClient(client)) {
162         if (!monitor->hasClients())
163             m_monitors.remove(it);
164     }
165 }
166
167 bool DisplayRefreshMonitorManager::scheduleAnimation(DisplayRefreshMonitorClient* client)
168 {
169     if (!client->m_displayIDIsSet)
170         return false;
171         
172     DisplayRefreshMonitor* monitor = ensureMonitorForClient(client);
173
174     client->m_scheduled = true;
175     return monitor->requestRefreshCallback();
176 }
177
178 void DisplayRefreshMonitorManager::displayDidRefresh(DisplayRefreshMonitor* monitor)
179 {
180     if (monitor->shouldBeTerminated()) {
181         DisplayRefreshMonitorMap::iterator it = m_monitors.find(monitor->displayID());
182         ASSERT(it != m_monitors.end());
183         m_monitors.remove(it);
184     }
185 }
186
187 void DisplayRefreshMonitorManager::windowScreenDidChange(PlatformDisplayID displayID, DisplayRefreshMonitorClient* client)
188 {
189     if (client->m_displayIDIsSet && client->m_displayID == displayID)
190         return;
191     
192     unregisterClient(client);
193     client->setDisplayID(displayID);
194     registerClient(client);
195     if (client->m_scheduled)
196         scheduleAnimation(client);
197 }
198
199 }
200
201 #endif // USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)