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