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#ifndef DisplayRefreshMonitor_h
27#define DisplayRefreshMonitor_h
28
29#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
30
31#include "PlatformScreen.h"
32#include <wtf/HashMap.h>
33#include <wtf/HashSet.h>
34#include <wtf/RefCounted.h>
35#include <wtf/RefPtr.h>
36#include <wtf/Threading.h>
37#if PLATFORM(BLACKBERRY)
38#include <BlackBerryPlatformAnimationFrameRateController.h>
39#endif
40
41#if PLATFORM(MAC)
42typedef struct __CVDisplayLink *CVDisplayLinkRef;
43#endif
44
45namespace WebCore {
46
47class DisplayAnimationClient;
48class DisplayRefreshMonitor;
49class DisplayRefreshMonitorManager;
50
51//
52// Abstract virtual client which receives refresh fired messages on the main thread
53//
54class DisplayRefreshMonitorClient {
55    friend class DisplayRefreshMonitor;
56    friend class DisplayRefreshMonitorManager;
57
58public:
59    DisplayRefreshMonitorClient();
60    virtual ~DisplayRefreshMonitorClient();
61
62    virtual void displayRefreshFired(double timestamp) = 0;
63
64private:
65    void fireDisplayRefreshIfNeeded(double timestamp);
66
67    void setDisplayID(PlatformDisplayID displayID)
68    {
69        m_displayID = displayID;
70        m_displayIDIsSet = true;
71    }
72
73    bool m_scheduled;
74    bool m_displayIDIsSet;
75    PlatformDisplayID m_displayID;
76};
77
78//
79// Monitor for display refresh messages for a given screen
80//
81
82class DisplayRefreshMonitor : public RefCounted<DisplayRefreshMonitor> {
83public:
84    static PassRefPtr<DisplayRefreshMonitor> create(PlatformDisplayID displayID)
85    {
86        return adoptRef(new DisplayRefreshMonitor(displayID));
87    }
88
89    ~DisplayRefreshMonitor();
90
91    // Return true if callback request was scheduled, false if it couldn't be
92    // (e.g., hardware refresh is not available)
93    bool requestRefreshCallback();
94    void windowScreenDidChange(PlatformDisplayID);
95
96    bool hasClients() const { return m_clients.size(); }
97    void addClient(DisplayRefreshMonitorClient*);
98    bool removeClient(DisplayRefreshMonitorClient*);
99
100    PlatformDisplayID displayID() const { return m_displayID; }
101
102    bool shouldBeTerminated() const
103    {
104        const int maxInactiveFireCount = 10;
105        return !m_scheduled && m_unscheduledFireCount > maxInactiveFireCount;
106    }
107
108private:
109    explicit DisplayRefreshMonitor(PlatformDisplayID);
110
111    void displayDidRefresh();
112    static void handleDisplayRefreshedNotificationOnMainThread(void* data);
113
114    double m_monotonicAnimationStartTime;
115    bool m_active;
116    bool m_scheduled;
117    bool m_previousFrameDone;
118    int m_unscheduledFireCount; // Number of times the display link has fired with no clients.
119    PlatformDisplayID m_displayID;
120    Mutex m_mutex;
121
122    HashSet<DisplayRefreshMonitorClient*> m_clients;
123    HashSet<DisplayRefreshMonitorClient*>* m_clientsToBeNotified;
124
125#if PLATFORM(BLACKBERRY)
126public:
127    void displayLinkFired();
128private:
129    DisplayAnimationClient *m_animationClient;
130    void startAnimationClient();
131    void stopAnimationClient();
132#endif
133
134#if PLATFORM(MAC)
135public:
136    void displayLinkFired(double nowSeconds, double outputTimeSeconds);
137private:
138    CVDisplayLinkRef m_displayLink;
139#endif
140};
141
142//
143// Singleton manager for all the DisplayRefreshMonitors. This is the interface to the
144// outside world. It distributes requests to the appropriate monitor. When the display
145// refresh event fires, the passed DisplayRefreshMonitorClient is called directly on
146// the main thread.
147//
148class DisplayRefreshMonitorManager {
149public:
150    static DisplayRefreshMonitorManager* sharedManager();
151
152    void registerClient(DisplayRefreshMonitorClient*);
153    void unregisterClient(DisplayRefreshMonitorClient*);
154
155    bool scheduleAnimation(DisplayRefreshMonitorClient*);
156    void windowScreenDidChange(PlatformDisplayID, DisplayRefreshMonitorClient*);
157
158private:
159    friend class DisplayRefreshMonitor;
160    void displayDidRefresh(DisplayRefreshMonitor*);
161
162    DisplayRefreshMonitorManager() { }
163    DisplayRefreshMonitor* ensureMonitorForClient(DisplayRefreshMonitorClient*);
164
165    // We know nothing about the values of PlatformDisplayIDs, so use UnsignedWithZeroKeyHashTraits.
166    // FIXME: Since we know nothing about these values, this is not sufficient.
167    // Even with UnsignedWithZeroKeyHashTraits, there are still two special values used for empty and deleted hash table slots.
168    typedef HashMap<uint64_t, RefPtr<DisplayRefreshMonitor>, WTF::IntHash<uint64_t>, WTF::UnsignedWithZeroKeyHashTraits<uint64_t>> DisplayRefreshMonitorMap;
169    DisplayRefreshMonitorMap m_monitors;
170};
171
172}
173
174#endif // USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
175
176#endif
177