1 /*
2 * Copyright (C) 2011 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. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "config.h"
27 #include "LayerTreeHostCAWin.h"
28
29 #if HAVE(WKQCA)
30
31 #include "DrawingAreaImpl.h"
32 #include "ShareableBitmap.h"
33 #include "UpdateInfo.h"
34 #include "WebPage.h"
35 #include <WebCore/GraphicsLayerCA.h>
36 #include <WebCore/LayerChangesFlusher.h>
37 #include <WebCore/PlatformCALayer.h>
38 #include <WebCore/WebCoreInstanceHandle.h>
39 #include <WebKitQuartzCoreAdditions/WKCACFImage.h>
40 #include <WebKitQuartzCoreAdditions/WKCACFView.h>
41 #include <wtf/CurrentTime.h>
42 #include <wtf/Threading.h>
43
44 #ifdef DEBUG_ALL
45 #pragma comment(lib, "WebKitQuartzCoreAdditions_debug")
46 #else
47 #pragma comment(lib, "WebKitQuartzCoreAdditions")
48 #endif
49
50 using namespace WebCore;
51
52 namespace WebKit {
53
54 static HWND dummyWindow;
55 static LPCWSTR dummyWindowClass = L"LayerTreeHostCAWindowClass";
56 static size_t validLayerTreeHostCount;
57
registerDummyWindowClass()58 static void registerDummyWindowClass()
59 {
60 static bool didRegister;
61 if (didRegister)
62 return;
63 didRegister = true;
64
65 WNDCLASSW wndClass = {0};
66 wndClass.lpszClassName = dummyWindowClass;
67 wndClass.lpfnWndProc = ::DefWindowProcW;
68 wndClass.hInstance = instanceHandle();
69
70 ::RegisterClassW(&wndClass);
71 }
72
73 // This window is never shown. It is only needed so that D3D can determine the display mode, etc.
createDummyWindow()74 static HWND createDummyWindow()
75 {
76 registerDummyWindowClass();
77 return ::CreateWindowW(dummyWindowClass, 0, WS_POPUP, 0, 0, 10, 10, 0, 0, instanceHandle(), 0);
78 }
79
supportsAcceleratedCompositing()80 bool LayerTreeHostCAWin::supportsAcceleratedCompositing()
81 {
82 static bool initialized;
83 static bool supportsAcceleratedCompositing;
84 if (initialized)
85 return supportsAcceleratedCompositing;
86 initialized = true;
87
88 ASSERT(!dummyWindow);
89 dummyWindow = createDummyWindow();
90 RetainPtr<WKCACFViewRef> view(AdoptCF, WKCACFViewCreate(kWKCACFViewDrawingDestinationImage));
91 CGRect fakeBounds = CGRectMake(0, 0, 10, 10);
92 WKCACFViewUpdate(view.get(), dummyWindow, &fakeBounds);
93
94 supportsAcceleratedCompositing = WKCACFViewCanDraw(view.get());
95
96 WKCACFViewUpdate(view.get(), 0, 0);
97 ::DestroyWindow(dummyWindow);
98 dummyWindow = 0;
99
100 return supportsAcceleratedCompositing;
101 }
102
create(WebPage * webPage)103 PassRefPtr<LayerTreeHostCAWin> LayerTreeHostCAWin::create(WebPage* webPage)
104 {
105 RefPtr<LayerTreeHostCAWin> host = adoptRef(new LayerTreeHostCAWin(webPage));
106 host->initialize();
107 return host.release();
108 }
109
LayerTreeHostCAWin(WebPage * webPage)110 LayerTreeHostCAWin::LayerTreeHostCAWin(WebPage* webPage)
111 : LayerTreeHostCA(webPage)
112 , m_isFlushingLayerChanges(false)
113 , m_nextDisplayTime(0)
114 {
115 }
116
~LayerTreeHostCAWin()117 LayerTreeHostCAWin::~LayerTreeHostCAWin()
118 {
119 }
120
platformInitialize(LayerTreeContext &)121 void LayerTreeHostCAWin::platformInitialize(LayerTreeContext&)
122 {
123 ++validLayerTreeHostCount;
124 if (!dummyWindow)
125 dummyWindow = createDummyWindow();
126
127 m_view.adoptCF(WKCACFViewCreate(kWKCACFViewDrawingDestinationImage));
128 WKCACFViewSetContextUserData(m_view.get(), static_cast<AbstractCACFLayerTreeHost*>(this));
129 WKCACFViewSetLayer(m_view.get(), rootLayer()->platformLayer());
130 WKCACFViewSetContextDidChangeCallback(m_view.get(), contextDidChangeCallback, this);
131
132 CGRect bounds = m_webPage->bounds();
133 WKCACFViewUpdate(m_view.get(), dummyWindow, &bounds);
134 }
135
invalidate()136 void LayerTreeHostCAWin::invalidate()
137 {
138 LayerChangesFlusher::shared().cancelPendingFlush(this);
139
140 WKCACFViewUpdate(m_view.get(), 0, 0);
141 WKCACFViewSetContextUserData(m_view.get(), 0);
142 WKCACFViewSetLayer(m_view.get(), 0);
143 WKCACFViewSetContextDidChangeCallback(m_view.get(), 0, 0);
144
145 LayerTreeHostCA::invalidate();
146
147 if (--validLayerTreeHostCount)
148 return;
149 ::DestroyWindow(dummyWindow);
150 dummyWindow = 0;
151 }
152
scheduleLayerFlush()153 void LayerTreeHostCAWin::scheduleLayerFlush()
154 {
155 LayerChangesFlusher::shared().flushPendingLayerChangesSoon(this);
156 }
157
participatesInDisplay()158 bool LayerTreeHostCAWin::participatesInDisplay()
159 {
160 return true;
161 }
162
needsDisplay()163 bool LayerTreeHostCAWin::needsDisplay()
164 {
165 return timeUntilNextDisplay() <= 0;
166 }
167
timeUntilNextDisplay()168 double LayerTreeHostCAWin::timeUntilNextDisplay()
169 {
170 return m_nextDisplayTime - currentTime();
171 }
172
size(WKCACFImageRef image)173 static IntSize size(WKCACFImageRef image)
174 {
175 return IntSize(WKCACFImageGetWidth(image), WKCACFImageGetHeight(image));
176 }
177
toShareableBitmap(WKCACFImageRef image)178 static PassRefPtr<ShareableBitmap> toShareableBitmap(WKCACFImageRef image)
179 {
180 size_t fileMappingSize;
181 HANDLE mapping = WKCACFImageCopyFileMapping(image, &fileMappingSize);
182 if (!mapping)
183 return 0;
184
185 RefPtr<SharedMemory> sharedMemory = SharedMemory::adopt(mapping, fileMappingSize, SharedMemory::ReadWrite);
186 if (!sharedMemory) {
187 ::CloseHandle(mapping);
188 return 0;
189 }
190
191 // WKCACFImage never has an alpha channel.
192 return ShareableBitmap::create(size(image), 0, sharedMemory.release());
193 }
194
display(UpdateInfo & updateInfo)195 void LayerTreeHostCAWin::display(UpdateInfo& updateInfo)
196 {
197 CGPoint imageOrigin;
198 CFTimeInterval nextDrawTime;
199 RetainPtr<WKCACFImageRef> image(AdoptCF, WKCACFViewCopyDrawnImage(m_view.get(), &imageOrigin, &nextDrawTime));
200 m_nextDisplayTime = nextDrawTime - CACurrentMediaTime() + currentTime();
201 if (!image)
202 return;
203 RefPtr<ShareableBitmap> bitmap = toShareableBitmap(image.get());
204 if (!bitmap)
205 return;
206 if (!bitmap->createHandle(updateInfo.bitmapHandle))
207 return;
208 updateInfo.updateRectBounds = IntRect(IntPoint(imageOrigin.x, m_webPage->size().height() - imageOrigin.y - bitmap->size().height()), bitmap->size());
209 updateInfo.updateRects.append(updateInfo.updateRectBounds);
210 }
211
sizeDidChange(const IntSize & newSize)212 void LayerTreeHostCAWin::sizeDidChange(const IntSize& newSize)
213 {
214 LayerTreeHostCA::sizeDidChange(newSize);
215 CGRect bounds = CGRectMake(0, 0, newSize.width(), newSize.height());
216 WKCACFViewUpdate(m_view.get(), dummyWindow, &bounds);
217 WKCACFViewFlushContext(m_view.get());
218 }
219
forceRepaint()220 void LayerTreeHostCAWin::forceRepaint()
221 {
222 LayerTreeHostCA::forceRepaint();
223 WKCACFViewFlushContext(m_view.get());
224 }
225
contextDidChangeCallback(WKCACFViewRef view,void * info)226 void LayerTreeHostCAWin::contextDidChangeCallback(WKCACFViewRef view, void* info)
227 {
228 // This should only be called on a background thread when no changes have actually
229 // been committed to the context, eg. when a video frame has been added to an image
230 // queue, so return without triggering animations etc.
231 if (!isMainThread())
232 return;
233
234 LayerTreeHostCAWin* host = static_cast<LayerTreeHostCAWin*>(info);
235 ASSERT_ARG(view, view == host->m_view);
236 host->contextDidChange();
237 }
238
contextDidChange()239 void LayerTreeHostCAWin::contextDidChange()
240 {
241 // Send currentTime to the pending animations. This function is called by CACF in a callback
242 // which occurs after the drawInContext calls. So currentTime is very close to the time
243 // the animations actually start
244 double currentTime = WTF::currentTime();
245
246 HashSet<RefPtr<PlatformCALayer> >::iterator end = m_pendingAnimatedLayers.end();
247 for (HashSet<RefPtr<PlatformCALayer> >::iterator it = m_pendingAnimatedLayers.begin(); it != end; ++it)
248 (*it)->animationStarted(currentTime);
249
250 m_pendingAnimatedLayers.clear();
251
252 m_nextDisplayTime = 0;
253 static_cast<DrawingAreaImpl*>(m_webPage->drawingArea())->setLayerHostNeedsDisplay();
254 }
255
rootLayer() const256 PlatformCALayer* LayerTreeHostCAWin::rootLayer() const
257 {
258 return static_cast<GraphicsLayerCA*>(LayerTreeHostCA::rootLayer())->platformCALayer();
259 }
260
addPendingAnimatedLayer(PassRefPtr<PlatformCALayer> layer)261 void LayerTreeHostCAWin::addPendingAnimatedLayer(PassRefPtr<PlatformCALayer> layer)
262 {
263 m_pendingAnimatedLayers.add(layer);
264 }
265
layerTreeDidChange()266 void LayerTreeHostCAWin::layerTreeDidChange()
267 {
268 if (m_isFlushingLayerChanges) {
269 // The layer tree is changing as a result of flushing GraphicsLayer changes to their
270 // underlying PlatformCALayers. We'll flush those changes to the context as part of that
271 // process, so there's no need to schedule another flush here.
272 return;
273 }
274
275 // The layer tree is changing as a result of someone modifying a PlatformCALayer that doesn't
276 // have a corresponding GraphicsLayer. Schedule a flush since we won't schedule one through the
277 // normal GraphicsLayer mechanisms.
278 LayerChangesFlusher::shared().flushPendingLayerChangesSoon(this);
279 }
280
flushPendingLayerChangesNow()281 void LayerTreeHostCAWin::flushPendingLayerChangesNow()
282 {
283 RefPtr<LayerTreeHostCA> protector(this);
284
285 m_isFlushingLayerChanges = true;
286
287 // Flush changes stored up in GraphicsLayers to their underlying PlatformCALayers, if
288 // requested.
289 performScheduledLayerFlush();
290
291 // Flush changes stored up in PlatformCALayers to the context so they will be rendered.
292 WKCACFViewFlushContext(m_view.get());
293
294 m_isFlushingLayerChanges = false;
295 }
296
297 } // namespace WebKit
298
299 #endif // HAVE(WKQCA)
300