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#import "config.h"
27#import "DisplayRefreshMonitorIOS.h"
28
29#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
30
31#import "WebCoreThread.h"
32#import <QuartzCore/QuartzCore.h>
33#import <wtf/CurrentTime.h>
34#import <wtf/MainThread.h>
35
36using namespace WebCore;
37
38@interface WebDisplayLinkHandler : NSObject
39{
40    DisplayRefreshMonitorIOS* m_monitor;
41    CADisplayLink *m_displayLink;
42}
43
44- (id)initWithMonitor:(DisplayRefreshMonitorIOS*)monitor;
45- (void)handleDisplayLink:(CADisplayLink *)sender;
46- (void)invalidate;
47
48@end
49
50@implementation WebDisplayLinkHandler
51
52- (id)initWithMonitor:(DisplayRefreshMonitorIOS*)monitor
53{
54    if (self = [super init]) {
55        m_monitor = monitor;
56        // Note that CADisplayLink retains its target (self), so a call to -invalidate is needed on teardown.
57        m_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDisplayLink:)];
58        [m_displayLink addToRunLoop:WebThreadNSRunLoop() forMode:NSDefaultRunLoopMode];
59    }
60    return self;
61}
62
63- (void)dealloc
64{
65    ASSERT(!m_displayLink); // -invalidate should have been called already.
66    [super dealloc];
67}
68
69- (void)handleDisplayLink:(CADisplayLink *)sender
70{
71    ASSERT(isMainThread());
72    m_monitor->displayLinkFired(sender.timestamp);
73}
74
75- (void)invalidate
76{
77    [m_displayLink invalidate];
78    m_displayLink = nullptr;
79}
80
81@end
82
83namespace WebCore {
84
85DisplayRefreshMonitorIOS::DisplayRefreshMonitorIOS(PlatformDisplayID displayID)
86    : DisplayRefreshMonitor(displayID)
87{
88}
89
90DisplayRefreshMonitorIOS::~DisplayRefreshMonitorIOS()
91{
92    [m_handler invalidate];
93}
94
95bool DisplayRefreshMonitorIOS::requestRefreshCallback()
96{
97    if (!isActive())
98        return false;
99
100    if (!m_handler) {
101        m_handler = adoptNS([[WebDisplayLinkHandler alloc] initWithMonitor:this]);
102        setIsActive(true);
103    }
104
105    setIsScheduled(true);
106    return true;
107}
108
109static double mediaTimeToCurrentTime(CFTimeInterval t)
110{
111    // FIXME: This may be a no-op if CACurrentMediaTime is *guaranteed* to be mach_absolute_time.
112    return monotonicallyIncreasingTime() + t - CACurrentMediaTime();
113}
114
115void DisplayRefreshMonitorIOS::displayLinkFired(double nowSeconds)
116{
117    if (!isPreviousFrameDone())
118        return;
119
120    setIsPreviousFrameDone(false);
121    setMonotonicAnimationStartTime(mediaTimeToCurrentTime(nowSeconds));
122
123    handleDisplayRefreshedNotificationOnMainThread(this);
124}
125
126}
127
128#endif // USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
129