1/*
2 * Copyright (C) 2012 Igalia, S.L.
3 *
4 *  This library is free software; you can redistribute it and/or
5 *  modify it under the terms of the GNU Lesser General Public
6 *  License as published by the Free Software Foundation; either
7 *  version 2 of the License, or (at your option) any later version.
8 *
9 *  This library is distributed in the hope that it will be useful,
10 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 *  Lesser General Public License for more details.
13 *
14 *  You should have received a copy of the GNU Lesser General Public
15 *  License along with this library; if not, write to the Free Software
16 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18
19#include "config.h"
20#include "AcceleratedCompositingContext.h"
21
22#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER_CAIRO)
23
24#include "CairoUtilities.h"
25#include "Chrome.h"
26#include "ChromeClientGtk.h"
27#include "Frame.h"
28#include "FrameView.h"
29#include "PlatformContextCairo.h"
30#include "TextureMapperImageBuffer.h"
31#include "TextureMapperLayer.h"
32#include "webkitwebviewprivate.h"
33#include <cairo.h>
34#include <gdk/gdk.h>
35#include <gtk/gtk.h>
36
37using namespace WebCore;
38
39namespace WebKit {
40
41AcceleratedCompositingContext::AcceleratedCompositingContext(WebKitWebView* webView)
42    : m_webView(webView)
43    , m_syncTimerCallbackId(0)
44    , m_rootTextureMapperLayer(0)
45{
46}
47
48AcceleratedCompositingContext::~AcceleratedCompositingContext()
49{
50    if (m_syncTimerCallbackId)
51        g_source_remove(m_syncTimerCallbackId);
52}
53
54bool AcceleratedCompositingContext::enabled()
55{
56    return m_rootTextureMapperLayer && m_textureMapper;
57}
58
59bool AcceleratedCompositingContext::renderLayersToWindow(cairo_t* cr, const IntRect& clipRect)
60{
61    if (!cr || !enabled())
62        return false;
63
64    GraphicsContext context(cr);
65    m_textureMapper->setGraphicsContext(&context);
66
67    m_textureMapper->beginPainting();
68    m_rootTextureMapperLayer->paint();
69    m_textureMapper->endPainting();
70
71    return true;
72}
73
74void AcceleratedCompositingContext::attachRootGraphicsLayer(GraphicsLayer* graphicsLayer)
75{
76    if (!graphicsLayer) {
77        m_rootGraphicsLayer.clear();
78        m_rootTextureMapperLayer = 0;
79        return;
80    }
81
82    m_rootGraphicsLayer = GraphicsLayer::create(this);
83    m_rootTextureMapperLayer = toTextureMapperLayer(m_rootGraphicsLayer.get());
84    m_rootGraphicsLayer->addChild(graphicsLayer);
85    m_rootGraphicsLayer->setDrawsContent(true);
86    m_rootGraphicsLayer->setMasksToBounds(false);
87    m_rootGraphicsLayer->setNeedsDisplay();
88    m_rootGraphicsLayer->setSize(core(m_webView)->mainFrame()->view()->frameRect().size());
89
90    m_textureMapper = TextureMapperImageBuffer::create();
91    m_rootTextureMapperLayer->setTextureMapper(m_textureMapper.get());
92    m_rootGraphicsLayer->flushCompositingStateForThisLayerOnly();
93}
94
95void AcceleratedCompositingContext::scheduleRootLayerRepaint(const IntRect& rect)
96{
97    if (!m_rootGraphicsLayer)
98        return;
99    if (rect.isEmpty()) {
100        m_rootGraphicsLayer->setNeedsDisplay();
101        return;
102    }
103    m_rootGraphicsLayer->setNeedsDisplayInRect(rect);
104
105    gtk_widget_queue_draw_area(GTK_WIDGET(m_webView), rect.x(), rect.y(), rect.width(), rect.height());
106}
107
108void AcceleratedCompositingContext::resizeRootLayer(const IntSize& size)
109{
110    if (!m_rootGraphicsLayer)
111        return;
112    m_rootGraphicsLayer->setSize(size);
113    m_rootGraphicsLayer->flushCompositingStateForThisLayerOnly();
114}
115
116static gboolean syncLayersTimeoutCallback(AcceleratedCompositingContext* context)
117{
118    context->syncLayersTimeout();
119    return FALSE;
120}
121
122void AcceleratedCompositingContext::markForSync()
123{
124    if (m_syncTimerCallbackId)
125        return;
126
127    // We use a GLib timer because otherwise GTK+ event handling during
128    // dragging can starve WebCore timers, which have a lower priority.
129    m_syncTimerCallbackId = g_timeout_add_full(GDK_PRIORITY_EVENTS, 0, reinterpret_cast<GSourceFunc>(syncLayersTimeoutCallback), this, 0);
130}
131
132void AcceleratedCompositingContext::syncLayersNow()
133{
134    if (core(m_webView)->mainFrame()->view()->needsLayout())
135        core(m_webView)->mainFrame()->view()->layout();
136
137    if (m_rootGraphicsLayer)
138        m_rootGraphicsLayer->flushCompositingStateForThisLayerOnly();
139
140    core(m_webView)->mainFrame()->view()->flushCompositingStateIncludingSubframes();
141}
142
143void AcceleratedCompositingContext::syncLayersTimeout()
144{
145    m_syncTimerCallbackId = 0;
146    syncLayersNow();
147    if (!m_rootGraphicsLayer)
148        return;
149
150    // FIXME: Invalidate just the animations rectangles.
151    gtk_widget_queue_draw(GTK_WIDGET(m_webView));
152
153    if (toTextureMapperLayer(m_rootGraphicsLayer.get())->descendantsOrSelfHaveRunningAnimations())
154        m_syncTimerCallbackId = g_timeout_add_full(GDK_PRIORITY_EVENTS, 1000.0 / 60.0, reinterpret_cast<GSourceFunc>(syncLayersTimeoutCallback), this, 0);
155}
156
157void AcceleratedCompositingContext::notifyAnimationStarted(const GraphicsLayer*, double time)
158{
159
160}
161void AcceleratedCompositingContext::notifyFlushRequired(const GraphicsLayer*)
162{
163
164}
165
166void AcceleratedCompositingContext::paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase, const IntRect& rectToPaint)
167{
168    cairo_t* cr = context.platformContext()->cr();
169    copyRectFromCairoSurfaceToContext(m_webView->priv->backingStore->cairoSurface(), cr, IntSize(), rectToPaint);
170}
171
172} // namespace WebKit
173
174#endif // USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER_CAIRO)
175