Use after free in WebCore::DisplayRefreshMonitorClient::fireDisplayRefreshIfNeeded
[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     return m_clients.remove(client);
86 }
87
88 void DisplayRefreshMonitor::displayDidRefresh()
89 {
90     double monotonicAnimationStartTime;
91     {
92         MutexLocker lock(m_mutex);
93          if (!m_scheduled)
94             ++m_unscheduledFireCount;
95         else
96             m_unscheduledFireCount = 0;
97
98         m_scheduled = false;
99         monotonicAnimationStartTime = m_monotonicAnimationStartTime;
100     }
101
102     // The call back can cause all our clients to be unregistered, so we need to protect
103     // against deletion until the end of the method.
104     Ref<DisplayRefreshMonitor> protect(*this);
105     
106     Vector<DisplayRefreshMonitorClient*> clients;
107     copyToVector(m_clients, clients);
108     for (size_t i = 0; i < clients.size(); ++i) {
109         DisplayRefreshMonitorClient* client = clients[i];
110         ASSERT(m_clients.contains(client));
111         client->fireDisplayRefreshIfNeeded(monotonicAnimationStartTime);
112     }
113
114     {
115         MutexLocker lock(m_mutex);
116         m_previousFrameDone = true;
117     }
118     
119     DisplayRefreshMonitorManager::sharedManager()->displayDidRefresh(this);
120 }
121
122 DisplayRefreshMonitorManager* DisplayRefreshMonitorManager::sharedManager()
123 {
124     DEFINE_STATIC_LOCAL(DisplayRefreshMonitorManager, manager, ());
125     return &manager;
126 }
127
128 DisplayRefreshMonitor* DisplayRefreshMonitorManager::ensureMonitorForClient(DisplayRefreshMonitorClient* client)
129 {
130     DisplayRefreshMonitorMap::iterator it = m_monitors.find(client->m_displayID);
131     if (it == m_monitors.end()) {
132         RefPtr<DisplayRefreshMonitor> monitor = DisplayRefreshMonitor::create(client->m_displayID);
133         monitor->addClient(client);
134         DisplayRefreshMonitor* result = monitor.get();
135         m_monitors.add(client->m_displayID, monitor.release());
136         return result;
137     }
138     it->value->addClient(client);
139     return it->value.get();
140 }
141
142 void DisplayRefreshMonitorManager::registerClient(DisplayRefreshMonitorClient* client)
143 {
144     if (!client->m_displayIDIsSet)
145         return;
146         
147     ensureMonitorForClient(client);
148 }
149
150 void DisplayRefreshMonitorManager::unregisterClient(DisplayRefreshMonitorClient* client)
151 {
152     if (!client->m_displayIDIsSet)
153         return;
154
155     DisplayRefreshMonitorMap::iterator it = m_monitors.find(client->m_displayID);
156     if (it == m_monitors.end())
157         return;
158     
159     DisplayRefreshMonitor* monitor = it->value.get();
160     if (monitor->removeClient(client)) {
161         if (!monitor->hasClients())
162             m_monitors.remove(it);
163     }
164 }
165
166 bool DisplayRefreshMonitorManager::scheduleAnimation(DisplayRefreshMonitorClient* client)
167 {
168     if (!client->m_displayIDIsSet)
169         return false;
170         
171     DisplayRefreshMonitor* monitor = ensureMonitorForClient(client);
172
173     client->m_scheduled = true;
174     return monitor->requestRefreshCallback();
175 }
176
177 void DisplayRefreshMonitorManager::displayDidRefresh(DisplayRefreshMonitor* monitor)
178 {
179     if (monitor->shouldBeTerminated()) {
180         ASSERT(m_monitors.contains(monitor->displayID()));
181         m_monitors.remove(monitor->displayID());
182     }
183 }
184
185 void DisplayRefreshMonitorManager::windowScreenDidChange(PlatformDisplayID displayID, DisplayRefreshMonitorClient* client)
186 {
187     if (client->m_displayIDIsSet && client->m_displayID == displayID)
188         return;
189     
190     unregisterClient(client);
191     client->setDisplayID(displayID);
192     registerClient(client);
193     if (client->m_scheduled)
194         scheduleAnimation(client);
195 }
196
197 }
198
199 #endif // USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)