+2011-01-17 Adam Roben <aroben@apple.com>
+
+ Paint directly into a GraphicsLayer when using accelerated compositing
+
+ Before this patch, we were painting into our normal backing store
+ HBITMAP, wrapping it in a CGImage, and handing it off to Core
+ Animation. This had at least two disadvantages:
+ 1) The bitmap could be modified while Core Animation was using it.
+ 2) It introduced extra complexity.
+
+ When entering accelerated compositing mode, WebView now creates a
+ GraphicsLayer to draw into. This GraphicsLayer sits between the root
+ layer (owned by WKCACFLayerRenderer) and the RenderView's layer. When
+ WebView invalidates, it just calls setNeedsDisplayInRect on its
+ GraphicsLayer. When WebView paints, it just tells its
+ WKCACFLayerRenderer to paint, which will call back to WebView to draw
+ into the GraphicsLayer if it has a dirty region. This is very similar
+ to the current implementation of LayerBackedDrawingArea in WebKit2.
+
+ Fixes <http://webkit.org/b/52582> WebView should paint directly into a
+ GraphicsLayer when in accelerated compositing mode
+
+ Reviewed by Simon Fraser and Chris Marrin.
+
+ * WebCoreSupport/WebChromeClient.cpp:
+ (WebChromeClient::attachRootGraphicsLayer):
+ (WebChromeClient::scheduleCompositingLayerSync):
+ Updated for WebView changes.
+
+ * WebView.cpp:
+ (WebView::repaint): When using accelerated compositing, just invalidate
+ our backing layer. This matches the behavior of LayerBackedDrawingArea.
+ (WebView::deleteBackingStore): Removed accelerated compositing code.
+ The WKCACFLayerRenderer doesn't need to know about our backing store
+ anymore; we don't use it at all when in accelerated compositing mode.
+ (WebView::addToDirtyRegion): When using accelerated compositing, just
+ invalidate our backing layer.
+ (WebView::scrollBackingStore): Added an assertion that this isn't
+ called in accelerated compositing mode.
+ (WebView::sizeChanged): Update our backing layer's size, too, and
+ invalidate it.
+ (WebView::updateBackingStore): Added an assertion that this isn't
+ called in accelerated compositing mode.
+ (WebView::paint): If we're in accelerated compositing mode, sync our
+ compositing state. If we're *still* in accelerated compositing mode,
+ just tell our WKCACFLayerRenderer to paint and clear our dirty region.
+ (The later changes in this function are just un-indenting code that
+ used to be inside an if.)
+
+ (WebView::paintIntoBackingStore):
+ (WebView::paintIntoWindow):
+ Added assertions that these aren't called in accelerated compositing
+ mode.
+
+ (WebView::WebViewWndProc): Updated WM_XP_THEMECHANGED handling for
+ removal of setRootLayerNeedsDisplay.
+ (WebView::setRootChildLayer): Changed to take a GraphicsLayer. We now
+ set the layer as a child of our own backing layer.
+ (WebView::scheduleCompositingLayerSync): Just call through to
+ WKCACFLayerRenderer.
+ (WebView::setAcceleratedCompositing): Create our backing layer and set
+ it as the child of WKCACFLayerRenderer's root layer.
+ (WebView::notifyAnimationStarted): Added. We never expect this
+ GraphicsLayerClient override to be called, as we don't use animations
+ on our backing layer.
+ (WebView::notifySyncRequired): Added. Just schedule a sync.
+ (WebView::paintContents): Added. Just clip and paint!
+
+ (WebView::showDebugBorders):
+ (WebView::showRepaintCounter):
+ Added. These just call through to Settings.
+
+ (WebView::syncCompositingState): Changed to first update layout, then
+ sync state for our backing layer, then sync WebCore's state. This
+ matches LayerBackedDrawingArea.
+
+ * WebView.h: WebView now implements the GraphicsLayerClient interface.
+ Removed setRootLayerNeedsDisplay; it's been replaced by calling
+ setNeedsDisplay on our backing layer and calling
+ syncCompositingStateSoon on WKCACFLayerRenderer as needed. Removed
+ updateRootLayerContents; that function was used to pass our backing
+ store to Core Animation, which we no longer do. Added m_backingLayer.
+
2011-01-17 Tony Gentilcore <tonyg@chromium.org>
Reviewed by Alexey Proskuryakov.
void WebView::repaint(const WebCore::IntRect& windowRect, bool contentChanged, bool immediate, bool repaintContentOnly)
{
#if USE(ACCELERATED_COMPOSITING)
- if (isAcceleratedCompositing())
- setRootLayerNeedsDisplay();
+ if (isAcceleratedCompositing()) {
+ // The contentChanged, immediate, and repaintContentOnly parameters are all based on a non-
+ // compositing painting/scrolling model.
+ addToDirtyRegion(windowRect);
+ return;
+ }
#endif
if (!repaintContentOnly) {
}
m_backingStoreBitmap.clear();
m_backingStoreDirtyRegion.clear();
-#if USE(ACCELERATED_COMPOSITING)
- if (m_layerRenderer)
- m_layerRenderer->setBackingStoreDirty(false);
-#endif
-
m_backingStoreSize.cx = m_backingStoreSize.cy = 0;
}
// but it was being hit during our layout tests, and is being investigated in
// http://webkit.org/b/29350.
+#if USE(ACCELERATED_COMPOSITING)
+ if (isAcceleratedCompositing()) {
+ m_backingLayer->setNeedsDisplayInRect(dirtyRect);
+ return;
+ }
+#endif
+
HRGN newRegion = ::CreateRectRgn(dirtyRect.x(), dirtyRect.y(),
dirtyRect.right(), dirtyRect.bottom());
addToDirtyRegion(newRegion);
void WebView::addToDirtyRegion(HRGN newRegion)
{
+#if USE(ACCELERATED_COMPOSITING)
+ ASSERT(!isAcceleratedCompositing());
+#endif
+
LOCAL_GDI_COUNTER(0, __FUNCTION__);
if (m_backingStoreDirtyRegion) {
} else
m_backingStoreDirtyRegion = RefCountedHRGN::create(newRegion);
-#if USE(ACCELERATED_COMPOSITING)
- if (m_layerRenderer)
- m_layerRenderer->setBackingStoreDirty(true);
-#endif
-
if (m_uiDelegatePrivate)
m_uiDelegatePrivate->webViewDidInvalidate(this);
}
void WebView::scrollBackingStore(FrameView* frameView, int dx, int dy, const IntRect& scrollViewRect, const IntRect& clipRect)
{
+#if USE(ACCELERATED_COMPOSITING)
+ ASSERT(!isAcceleratedCompositing());
+#endif
+
LOCAL_GDI_COUNTER(0, __FUNCTION__);
// If there's no backing store we don't need to update it
#if USE(ACCELERATED_COMPOSITING)
if (m_layerRenderer)
m_layerRenderer->resize();
+ if (m_backingLayer) {
+ m_backingLayer->setSize(newSize);
+ m_backingLayer->setNeedsDisplay();
+ }
#endif
}
void WebView::updateBackingStore(FrameView* frameView, HDC dc, bool backingStoreCompletelyDirty, WindowsToPaint windowsToPaint)
{
+#if USE(ACCELERATED_COMPOSITING)
+ ASSERT(!isAcceleratedCompositing());
+#endif
+
LOCAL_GDI_COUNTER(0, __FUNCTION__);
HDC windowDC = 0;
m_uiDelegatePrivate->webViewPainted(this);
m_backingStoreDirtyRegion.clear();
-#if USE(ACCELERATED_COMPOSITING)
- if (m_layerRenderer)
- m_layerRenderer->setBackingStoreDirty(false);
-#endif
}
if (!dc) {
{
LOCAL_GDI_COUNTER(0, __FUNCTION__);
+#if USE(ACCELERATED_COMPOSITING)
+ if (isAcceleratedCompositing()) {
+ syncCompositingState();
+ // Syncing might have taken us out of compositing mode.
+ if (isAcceleratedCompositing()) {
+ // FIXME: We need to paint into dc (if provided). <http://webkit.org/b/52578>
+ m_layerRenderer->paint();
+ ::ValidateRect(m_viewWindow, 0);
+ return;
+ }
+ }
+#endif
+
Frame* coreFrame = core(m_mainFrame);
if (!coreFrame)
return;
// Update our backing store if needed.
updateBackingStore(frameView, bitmapDC, backingStoreCompletelyDirty, windowsToPaint);
-#if USE(ACCELERATED_COMPOSITING)
- if (!isAcceleratedCompositing()) {
-#endif
- // Now we blit the updated backing store
- IntRect windowDirtyRect = rcPaint;
-
- // Apply the same heuristic for this update region too.
- Vector<IntRect> blitRects;
- if (region && regionType == COMPLEXREGION)
- getUpdateRects(region.get(), windowDirtyRect, blitRects);
- else
- blitRects.append(windowDirtyRect);
+ // Now we blit the updated backing store
+ IntRect windowDirtyRect = rcPaint;
+
+ // Apply the same heuristic for this update region too.
+ Vector<IntRect> blitRects;
+ if (region && regionType == COMPLEXREGION)
+ getUpdateRects(region.get(), windowDirtyRect, blitRects);
+ else
+ blitRects.append(windowDirtyRect);
- for (unsigned i = 0; i < blitRects.size(); ++i)
- paintIntoWindow(bitmapDC, hdc, blitRects[i]);
-#if USE(ACCELERATED_COMPOSITING)
- } else
- updateRootLayerContents();
-#endif
+ for (unsigned i = 0; i < blitRects.size(); ++i)
+ paintIntoWindow(bitmapDC, hdc, blitRects[i]);
::SelectObject(bitmapDC, oldBitmap);
::DeleteDC(bitmapDC);
void WebView::paintIntoBackingStore(FrameView* frameView, HDC bitmapDC, const IntRect& dirtyRect, WindowsToPaint windowsToPaint)
{
+#if USE(ACCELERATED_COMPOSITING)
+ ASSERT(!isAcceleratedCompositing());
+#endif
+
LOCAL_GDI_COUNTER(0, __FUNCTION__);
// FIXME: We want an assert here saying that the dirtyRect is inside the clienRect,
void WebView::paintIntoWindow(HDC bitmapDC, HDC windowDC, const IntRect& dirtyRect)
{
+#if USE(ACCELERATED_COMPOSITING)
+ ASSERT(!isAcceleratedCompositing());
+#endif
+
LOCAL_GDI_COUNTER(0, __FUNCTION__);
#if FLASH_WINDOW_REDRAW
OwnPtr<HBRUSH> greenBrush = CreateSolidBrush(RGB(0, 255, 0));
::InvalidateRect(hWnd, &windowRect, false);
#if USE(ACCELERATED_COMPOSITING)
if (webView->isAcceleratedCompositing())
- webView->setRootLayerNeedsDisplay();
+ webView->m_backingLayer->setNeedsDisplay();
#endif
}
break;
}
#if USE(ACCELERATED_COMPOSITING)
-void WebView::setRootChildLayer(WebCore::PlatformCALayer* layer)
+void WebView::setRootChildLayer(GraphicsLayer* layer)
{
setAcceleratedCompositing(layer ? true : false);
- if (m_layerRenderer)
- m_layerRenderer->setRootChildLayer(layer);
+ if (!m_backingLayer)
+ return;
+ m_backingLayer->addChild(layer);
+}
+
+void WebView::scheduleCompositingLayerSync()
+{
+ if (!m_layerRenderer)
+ return;
+ m_layerRenderer->syncCompositingStateSoon();
}
void WebView::setAcceleratedCompositing(bool accelerated)
ASSERT(m_viewWindow);
m_layerRenderer->setHostWindow(m_viewWindow);
m_layerRenderer->createRenderer();
+
+ // FIXME: We could perhaps get better performance by never allowing this layer to
+ // become tiled (or choosing a higher-than-normal tiling threshold).
+ // <http://webkit.org/b/52603>
+ m_backingLayer = GraphicsLayer::create(this);
+ m_backingLayer->setDrawsContent(true);
+ m_backingLayer->setContentsOpaque(true);
+ RECT clientRect;
+ ::GetClientRect(m_viewWindow, &clientRect);
+ m_backingLayer->setSize(IntRect(clientRect).size());
+ m_backingLayer->setNeedsDisplay();
+
+ m_layerRenderer->setRootChildLayer(PlatformCALayer::platformCALayer(m_backingLayer->platformLayer()));
+
+ // We aren't going to be using our backing store while we're in accelerated compositing
+ // mode. But don't delete it immediately, in case we switch out of accelerated
+ // compositing mode soon (e.g., if we're only compositing for a :hover animation).
+ deleteBackingStoreSoon();
}
} else {
m_layerRenderer = 0;
+ m_backingLayer = 0;
m_isAcceleratedCompositing = false;
}
}
-void releaseBackingStoreCallback(void* info, const void* data, size_t size)
-{
- // Release the backing store bitmap previously retained by updateRootLayerContents().
- ASSERT(info);
- if (info)
- static_cast<RefCountedHBITMAP*>(info)->deref();
-}
-
-void WebView::updateRootLayerContents()
-{
- if (!m_backingStoreBitmap || !m_layerRenderer)
- return;
-
- // Get the backing store into a CGImage
- BITMAP bitmap;
- GetObject(m_backingStoreBitmap->handle(), sizeof(bitmap), &bitmap);
- size_t bmSize = bitmap.bmWidthBytes * bitmap.bmHeight;
- RetainPtr<CGDataProviderRef> cgData(AdoptCF,
- CGDataProviderCreateWithData(static_cast<void*>(m_backingStoreBitmap.get()),
- bitmap.bmBits, bmSize,
- releaseBackingStoreCallback));
- RetainPtr<CGColorSpaceRef> space(AdoptCF, CGColorSpaceCreateDeviceRGB());
- RetainPtr<CGImageRef> backingStoreImage(AdoptCF, CGImageCreate(bitmap.bmWidth, bitmap.bmHeight,
- 8, bitmap.bmBitsPixel,
- bitmap.bmWidthBytes, space.get(),
- kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst,
- cgData.get(), 0, false,
- kCGRenderingIntentDefault));
-
- // Retain the backing store bitmap so that it is not deleted by deleteBackingStore()
- // while still in use within CA. When CA is done with the bitmap, it will
- // call releaseBackingStoreCallback(), which will release the backing store bitmap.
- m_backingStoreBitmap->ref();
-
- // Hand the CGImage to CACF for compositing
- if (m_nextDisplayIsSynchronous) {
- m_layerRenderer->setRootContentsAndDisplay(backingStoreImage.get());
- m_nextDisplayIsSynchronous = false;
- } else
- m_layerRenderer->setRootContents(backingStoreImage.get());
-}
-
void WebView::layerRendererBecameVisible()
{
m_layerRenderer->createRenderer();
}
#if USE(ACCELERATED_COMPOSITING)
+void WebView::notifyAnimationStarted(const GraphicsLayer*, double)
+{
+ // We never set any animations on our backing layer.
+ ASSERT_NOT_REACHED();
+}
+
+void WebView::notifySyncRequired(const GraphicsLayer*)
+{
+ scheduleCompositingLayerSync();
+}
+
+void WebView::paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase, const IntRect& inClip)
+{
+ Frame* frame = core(m_mainFrame);
+ if (!frame)
+ return;
+
+ context.save();
+ context.clip(inClip);
+ frame->view()->paint(&context, inClip);
+ context.restore();
+}
+
+bool WebView::showDebugBorders() const
+{
+ return m_page->settings()->showDebugBorders();
+}
+
+bool WebView::showRepaintCounter() const
+{
+ return m_page->settings()->showRepaintCounter();
+}
+
bool WebView::shouldRender() const
{
Frame* coreFrame = core(m_mainFrame);
void WebView::syncCompositingState()
{
Frame* coreFrame = core(m_mainFrame);
- if (coreFrame && coreFrame->view())
- coreFrame->view()->syncCompositingStateRecursive();
+ if (!coreFrame)
+ return;
+ FrameView* view = coreFrame->view();
+ if (!view)
+ return;
+ if (!m_backingLayer)
+ return;
+
+ view->updateLayoutAndStyleIfNeededRecursive();
+
+ // Updating layout might have taken us out of compositing mode.
+ if (m_backingLayer)
+ m_backingLayer->syncCompositingStateForThisLayerOnly();
+
+ view->syncCompositingStateRecursive();
}
#endif