1/*
2 * Copyright (C) 2011, 2012 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 "WKCACFViewLayerTreeHost.h"
28
29#include "PlatformCALayer.h"
30#include "SoftLinking.h"
31#include <wtf/CurrentTime.h>
32#include <wtf/MainThread.h>
33
34typedef struct _CACFLayer* CACFLayerRef;
35
36namespace WebCore {
37
38#ifdef DEBUG_ALL
39SOFT_LINK_DEBUG_LIBRARY(WebKitQuartzCoreAdditions)
40#else
41SOFT_LINK_LIBRARY(WebKitQuartzCoreAdditions)
42#endif
43
44enum WKCACFViewDrawingDestination {
45    kWKCACFViewDrawingDestinationWindow = 0,
46    kWKCACFViewDrawingDestinationImage,
47};
48typedef enum WKCACFViewDrawingDestination WKCACFViewDrawingDestination;
49
50SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewCreate, WKCACFViewRef, __cdecl, (WKCACFViewDrawingDestination destination), (destination))
51SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewSetLayer, void, __cdecl, (WKCACFViewRef view, CACFLayerRef layer), (view, layer))
52SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewUpdate, void, __cdecl, (WKCACFViewRef view, HWND window, const CGRect* bounds), (view, window, bounds))
53SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewCanDraw, bool, __cdecl, (WKCACFViewRef view), (view))
54SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewDraw, void, __cdecl, (WKCACFViewRef view), (view))
55SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewFlushContext, void, __cdecl, (WKCACFViewRef view), (view))
56SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewInvalidateRects, void, __cdecl, (WKCACFViewRef view, const CGRect rects[], size_t count), (view, rects, count))
57typedef void (*WKCACFViewContextDidChangeCallback)(WKCACFViewRef view, void* info);
58SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewSetContextDidChangeCallback, void, __cdecl, (WKCACFViewRef view, WKCACFViewContextDidChangeCallback callback, void* info), (view, callback, info))
59SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewGetLastCommitTime, CFTimeInterval, __cdecl, (WKCACFViewRef view), (view))
60SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewSetContextUserData, void, __cdecl, (WKCACFViewRef view, void* userData), (view, userData))
61SOFT_LINK_OPTIONAL(WebKitQuartzCoreAdditions, WKCACFViewSetShouldInvertColors, void, _cdecl, (WKCACFViewRef view, bool shouldInvertColors))
62SOFT_LINK_OPTIONAL(WebKitQuartzCoreAdditions, WKCACFViewGetD3DDevice9, IDirect3DDevice9*, _cdecl, (WKCACFViewRef view))
63
64PassRefPtr<WKCACFViewLayerTreeHost> WKCACFViewLayerTreeHost::create()
65{
66    if (!WebKitQuartzCoreAdditionsLibrary())
67        return 0;
68
69    return adoptRef(new WKCACFViewLayerTreeHost);
70}
71
72WKCACFViewLayerTreeHost::WKCACFViewLayerTreeHost()
73    : m_view(adoptCF(WKCACFViewCreate(kWKCACFViewDrawingDestinationWindow)))
74    , m_viewNeedsUpdate(true)
75{
76}
77
78void WKCACFViewLayerTreeHost::updateViewIfNeeded()
79{
80    if (!m_viewNeedsUpdate)
81        return;
82    m_viewNeedsUpdate = false;
83
84    CGRect layerBounds = rootLayer()->bounds();
85
86    CGRect bounds = this->bounds();
87    WKCACFViewUpdate(m_view.get(), window(), &bounds);
88
89    if (CGRectEqualToRect(layerBounds, rootLayer()->bounds()))
90        return;
91
92    // Flush the context so the layer's rendered bounds will match our bounds.
93    flushContext();
94}
95
96void WKCACFViewLayerTreeHost::contextDidChangeCallback(WKCACFViewRef view, void* info)
97{
98    ASSERT_ARG(view, view);
99    ASSERT_ARG(info, info);
100
101    WKCACFViewLayerTreeHost* host = static_cast<WKCACFViewLayerTreeHost*>(info);
102    ASSERT_ARG(view, view == host->m_view);
103    host->contextDidChange();
104}
105
106void WKCACFViewLayerTreeHost::contextDidChange()
107{
108    // This should only be called on a background thread when no changes have actually
109    // been committed to the context, eg. when a video frame has been added to an image
110    // queue, so return without triggering animations etc.
111    if (!isMainThread())
112        return;
113
114    // Tell the WKCACFView to start rendering now that we have some contents to render.
115    updateViewIfNeeded();
116
117    CACFLayerTreeHost::contextDidChange();
118}
119
120void WKCACFViewLayerTreeHost::initializeContext(void* userData, PlatformCALayer* layer)
121{
122    WKCACFViewSetContextUserData(m_view.get(), userData);
123    WKCACFViewSetLayer(m_view.get(), layer->platformLayer());
124    WKCACFViewSetContextDidChangeCallback(m_view.get(), contextDidChangeCallback, this);
125}
126
127void WKCACFViewLayerTreeHost::resize()
128{
129    m_viewNeedsUpdate = true;
130}
131
132bool WKCACFViewLayerTreeHost::createRenderer()
133{
134    updateViewIfNeeded();
135    return WKCACFViewCanDraw(m_view.get());
136}
137
138void WKCACFViewLayerTreeHost::destroyRenderer()
139{
140    m_viewNeedsUpdate = true;
141    WKCACFViewUpdate(m_view.get(), 0, 0);
142    WKCACFViewSetContextUserData(m_view.get(), 0);
143    WKCACFViewSetLayer(m_view.get(), 0);
144    WKCACFViewSetContextDidChangeCallback(m_view.get(), 0, 0);
145
146    CACFLayerTreeHost::destroyRenderer();
147}
148
149CFTimeInterval WKCACFViewLayerTreeHost::lastCommitTime() const
150{
151    return WKCACFViewGetLastCommitTime(m_view.get());
152}
153
154void WKCACFViewLayerTreeHost::flushContext()
155{
156    WKCACFViewFlushContext(m_view.get());
157}
158
159void WKCACFViewLayerTreeHost::paint()
160{
161    updateViewIfNeeded();
162    CACFLayerTreeHost::paint();
163}
164
165void WKCACFViewLayerTreeHost::render(const Vector<CGRect>& dirtyRects)
166{
167    WKCACFViewInvalidateRects(m_view.get(), dirtyRects.data(), dirtyRects.size());
168    WKCACFViewDraw(m_view.get());
169}
170
171void WKCACFViewLayerTreeHost::setShouldInvertColors(bool shouldInvertColors)
172{
173    if (WKCACFViewSetShouldInvertColorsPtr())
174        WKCACFViewSetShouldInvertColorsPtr()(m_view.get(), shouldInvertColors);
175}
176
177#if USE(AVFOUNDATION)
178GraphicsDeviceAdapter* WKCACFViewLayerTreeHost::graphicsDeviceAdapter() const
179{
180    if (!WKCACFViewGetD3DDevice9Ptr())
181        return 0;
182
183    return reinterpret_cast<GraphicsDeviceAdapter*>(WKCACFViewGetD3DDevice9Ptr()(m_view.get()));
184}
185#endif
186
187} // namespace WebCore
188