1/* 2 * Copyright (C) 2011 Collabora Ltd. 3 * Copyright (C) 2012 Igalia, S.L. 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20#include "config.h" 21#include "AcceleratedCompositingContext.h" 22 23#if USE(ACCELERATED_COMPOSITING) && USE(CLUTTER) 24 25#include "Frame.h" 26#include "FrameView.h" 27#include "GraphicsLayer.h" 28#include "GraphicsLayerActor.h" 29#include "NotImplemented.h" 30#include "Settings.h" 31#include "webkitwebviewprivate.h" 32#include <clutter-gtk/clutter-gtk.h> 33#include <clutter/clutter.h> 34 35using namespace WebCore; 36 37namespace WebKit { 38 39AcceleratedCompositingContext::AcceleratedCompositingContext(WebKitWebView* webView) 40 : m_webView(webView) 41 , m_layerFlushTimerCallbackId(0) 42 , m_rootLayerEmbedder(0) 43{ 44} 45 46void AcceleratedCompositingContext::initialize() 47{ 48 if (m_rootLayer) 49 return; 50 51 GtkAllocation allocation; 52 gtk_widget_get_allocation(GTK_WIDGET(m_webView), &allocation); 53 IntSize pageSize(allocation.width, allocation.height); 54 55 m_rootLayer = GraphicsLayer::create(0, this); 56 m_rootLayer->setDrawsContent(false); 57 m_rootLayer->setSize(pageSize); 58 59 // The non-composited contents are a child of the root layer. 60 m_nonCompositedContentLayer = GraphicsLayer::create(0, this); 61 m_nonCompositedContentLayer->setDrawsContent(true); 62 m_nonCompositedContentLayer->setContentsOpaque(!m_webView->priv->transparent); 63 m_nonCompositedContentLayer->setSize(pageSize); 64 if (core(m_webView)->settings()->acceleratedDrawingEnabled()) 65 m_nonCompositedContentLayer->setAcceleratesDrawing(true); 66 67#ifndef NDEBUG 68 m_rootLayer->setName("Root layer"); 69 m_nonCompositedContentLayer->setName("Non-composited content"); 70#endif 71 72 m_rootLayer->addChild(m_nonCompositedContentLayer.get()); 73 m_nonCompositedContentLayer->setNeedsDisplay(); 74 75 scheduleLayerFlush(); 76} 77 78AcceleratedCompositingContext::~AcceleratedCompositingContext() 79{ 80 if (m_layerFlushTimerCallbackId) 81 g_source_remove(m_layerFlushTimerCallbackId); 82} 83 84bool AcceleratedCompositingContext::enabled() 85{ 86 return m_rootLayer; 87} 88 89bool AcceleratedCompositingContext::renderLayersToWindow(cairo_t*, const IntRect& clipRect) 90{ 91 notImplemented(); 92 return true; 93} 94 95void AcceleratedCompositingContext::setRootCompositingLayer(GraphicsLayer* graphicsLayer) 96{ 97 if (!graphicsLayer) { 98 gtk_container_remove(GTK_CONTAINER(m_webView), m_rootLayerEmbedder); 99 m_rootLayerEmbedder = 0; 100 m_rootLayer = nullptr; 101 m_nonCompositedContentLayer = nullptr; 102 return; 103 } 104 105 // Create an instance of GtkClutterEmbed to embed actors as GraphicsLayers. 106 if (!m_rootLayerEmbedder) { 107 m_rootLayerEmbedder = gtk_clutter_embed_new(); 108 gtk_container_add(GTK_CONTAINER(m_webView), m_rootLayerEmbedder); 109 110 GtkAllocation allocation; 111 gtk_widget_get_allocation(GTK_WIDGET(m_webView), &allocation); 112 gtk_widget_size_allocate(GTK_WIDGET(m_rootLayerEmbedder), &allocation); 113 gtk_widget_show(m_rootLayerEmbedder); 114 } 115 116 // Add the accelerated layer tree hierarchy. 117 initialize(); 118 119 m_nonCompositedContentLayer->removeAllChildren(); 120 m_nonCompositedContentLayer->addChild(graphicsLayer); 121 122 // Add a root GraphicsLayer to the stage. 123 if (graphicsLayer) { 124 ClutterColor stageColor = { 0xFF, 0xFF, 0xFF, 0xFF }; 125 ClutterActor* stage = gtk_clutter_embed_get_stage(GTK_CLUTTER_EMBED(m_rootLayerEmbedder)); 126 clutter_actor_set_background_color(stage, &stageColor); 127 clutter_actor_add_child(stage, m_rootLayer->platformLayer()); 128 } 129 130 scheduleLayerFlush(); 131} 132 133void AcceleratedCompositingContext::setNonCompositedContentsNeedDisplay(const IntRect& rect) 134{ 135 if (!m_rootLayer) 136 return; 137 138 if (rect.isEmpty()) { 139 m_rootLayer->setNeedsDisplay(); 140 return; 141 } 142 143 m_nonCompositedContentLayer->setNeedsDisplayInRect(rect); 144 scheduleLayerFlush(); 145} 146 147void AcceleratedCompositingContext::resizeRootLayer(const IntSize& newSize) 148{ 149 if (!m_rootLayerEmbedder) 150 return; 151 152 if (m_rootLayer->size() == newSize) 153 return; 154 155 GtkAllocation allocation; 156 allocation.x = 0; 157 allocation.y = 0; 158 allocation.width = newSize.width(); 159 allocation.height = newSize.height(); 160 gtk_widget_size_allocate(GTK_WIDGET(m_rootLayerEmbedder), &allocation); 161 162 m_rootLayer->setSize(newSize); 163 164 // If the newSize exposes new areas of the non-composited content a setNeedsDisplay is needed 165 // for those newly exposed areas. 166 FloatSize oldSize = m_nonCompositedContentLayer->size(); 167 m_nonCompositedContentLayer->setSize(newSize); 168 169 if (newSize.width() > oldSize.width()) { 170 float height = std::min(static_cast<float>(newSize.height()), oldSize.height()); 171 m_nonCompositedContentLayer->setNeedsDisplayInRect(FloatRect(oldSize.width(), 0, newSize.width() - oldSize.width(), height)); 172 } 173 174 if (newSize.height() > oldSize.height()) 175 m_nonCompositedContentLayer->setNeedsDisplayInRect(FloatRect(0, oldSize.height(), newSize.width(), newSize.height() - oldSize.height())); 176 177 m_nonCompositedContentLayer->setNeedsDisplayInRect(IntRect(IntPoint(), newSize)); 178 scheduleLayerFlush(); 179} 180 181void AcceleratedCompositingContext::scrollNonCompositedContents(const IntRect& scrollRect, const IntSize& scrollOffset) 182{ 183 m_nonCompositedContentLayer->setNeedsDisplayInRect(scrollRect); 184 scheduleLayerFlush(); 185} 186 187gboolean AcceleratedCompositingContext::layerFlushTimerFiredCallback(AcceleratedCompositingContext* context) 188{ 189 context->flushAndRenderLayers(); 190 return FALSE; 191} 192 193void AcceleratedCompositingContext::scheduleLayerFlush() 194{ 195 if (m_layerFlushTimerCallbackId) 196 return; 197 198 // We use a GLib timer because otherwise GTK+ event handling during 199 // dragging can starve WebCore timers, which have a lower priority. 200 m_layerFlushTimerCallbackId = g_timeout_add_full(GDK_PRIORITY_EVENTS, 0, reinterpret_cast<GSourceFunc>(layerFlushTimerFiredCallback), this, 0); 201} 202 203bool AcceleratedCompositingContext::flushPendingLayerChanges() 204{ 205 if (m_rootLayer) { 206 m_rootLayer->flushCompositingStateForThisLayerOnly(); 207 m_nonCompositedContentLayer->flushCompositingStateForThisLayerOnly(); 208 } 209 210 return core(m_webView)->mainFrame()->view()->flushCompositingStateIncludingSubframes(); 211} 212 213void AcceleratedCompositingContext::flushAndRenderLayers() 214{ 215 m_layerFlushTimerCallbackId = 0; 216 217 if (!enabled()) 218 return; 219 220 Frame* frame = core(m_webView)->mainFrame(); 221 if (!frame || !frame->contentRenderer() || !frame->view()) 222 return; 223 frame->view()->updateLayoutAndStyleIfNeededRecursive(); 224 225 if (!flushPendingLayerChanges()) 226 return; 227} 228 229void AcceleratedCompositingContext::notifyAnimationStarted(const WebCore::GraphicsLayer*, double time) 230{ 231 notImplemented(); 232} 233void AcceleratedCompositingContext::notifyFlushRequired(const WebCore::GraphicsLayer*) 234{ 235 notImplemented(); 236} 237 238void AcceleratedCompositingContext::paintContents(const WebCore::GraphicsLayer*, WebCore::GraphicsContext& context, WebCore::GraphicsLayerPaintingPhase, const WebCore::IntRect& rectToPaint) 239{ 240 context.save(); 241 context.clip(rectToPaint); 242 core(m_webView)->mainFrame()->view()->paint(&context, rectToPaint); 243 context.restore(); 244} 245 246} // namespace WebKit 247 248#endif // USE(ACCELERATED_COMPOSITING) && USE(CLUTTER) 249