1/*
2 * Copyright (C) 2010, 2014 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 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#include "DisplayRefreshMonitorManager.h"
28
29#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
30
31#include "DisplayRefreshMonitor.h"
32#include "DisplayRefreshMonitorClient.h"
33#include "Logging.h"
34
35namespace WebCore {
36
37DisplayRefreshMonitorManager::~DisplayRefreshMonitorManager() = default;
38
39DisplayRefreshMonitorManager& DisplayRefreshMonitorManager::sharedManager()
40{
41 static NeverDestroyed<DisplayRefreshMonitorManager> manager;
42 return manager.get();
43}
44
45DisplayRefreshMonitor* DisplayRefreshMonitorManager::createMonitorForClient(DisplayRefreshMonitorClient& client)
46{
47 PlatformDisplayID clientDisplayID = client.displayID();
48 for (const RefPtr<DisplayRefreshMonitor>& monitor : m_monitors) {
49 if (monitor->displayID() != clientDisplayID)
50 continue;
51 monitor->addClient(client);
52 return monitor.get();
53 }
54
55 auto monitor = DisplayRefreshMonitor::create(client);
56 if (!monitor)
57 return nullptr;
58
59 LOG(RequestAnimationFrame, "DisplayRefreshMonitorManager::createMonitorForClient() - created monitor %p", monitor.get());
60 monitor->addClient(client);
61 DisplayRefreshMonitor* result = monitor.get();
62 m_monitors.append(WTFMove(monitor));
63 return result;
64}
65
66void DisplayRefreshMonitorManager::registerClient(DisplayRefreshMonitorClient& client)
67{
68 if (!client.hasDisplayID())
69 return;
70
71 createMonitorForClient(client);
72}
73
74void DisplayRefreshMonitorManager::unregisterClient(DisplayRefreshMonitorClient& client)
75{
76 if (!client.hasDisplayID())
77 return;
78
79 PlatformDisplayID clientDisplayID = client.displayID();
80 for (size_t i = 0; i < m_monitors.size(); ++i) {
81 RefPtr<DisplayRefreshMonitor> monitor = m_monitors[i];
82 if (monitor->displayID() != clientDisplayID)
83 continue;
84 if (monitor->removeClient(client)) {
85 if (!monitor->hasClients())
86 m_monitors.remove(i);
87 }
88 return;
89 }
90}
91
92bool DisplayRefreshMonitorManager::scheduleAnimation(DisplayRefreshMonitorClient& client)
93{
94 if (!client.hasDisplayID())
95 return false;
96
97 DisplayRefreshMonitor* monitor = createMonitorForClient(client);
98 if (!monitor)
99 return false;
100
101 client.setIsScheduled(true);
102 return monitor->requestRefreshCallback();
103}
104
105void DisplayRefreshMonitorManager::displayDidRefresh(DisplayRefreshMonitor& monitor)
106{
107 if (!monitor.shouldBeTerminated())
108 return;
109 LOG(RequestAnimationFrame, "DisplayRefreshMonitorManager::displayDidRefresh() - destroying monitor %p", &monitor);
110
111 size_t monitorIndex = m_monitors.find(&monitor);
112 if (monitorIndex != notFound)
113 m_monitors.remove(monitorIndex);
114}
115
116void DisplayRefreshMonitorManager::windowScreenDidChange(PlatformDisplayID displayID, DisplayRefreshMonitorClient& client)
117{
118 if (client.hasDisplayID() && client.displayID() == displayID)
119 return;
120
121 unregisterClient(client);
122 client.setDisplayID(displayID);
123 registerClient(client);
124 if (client.isScheduled())
125 scheduleAnimation(client);
126}
127
128void DisplayRefreshMonitorManager::displayWasUpdated(PlatformDisplayID displayID)
129{
130 for (const auto& monitor : m_monitors) {
131 if (displayID == monitor->displayID() && monitor->hasRequestedRefreshCallback())
132 monitor->displayLinkFired();
133 }
134}
135
136}
137
138#endif // USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
139