• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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