1/*
2 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
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 "TiledDrawingAreaTile.h"
28
29#if ENABLE(TILED_BACKING_STORE)
30
31#include "GraphicsContext.h"
32#include "TiledDrawingAreaProxy.h"
33#include "WebPageProxy.h"
34#include "WebProcessProxy.h"
35#include "UpdateChunk.h"
36#include <QApplication>
37#include <QObject>
38#include <QPainter>
39
40using namespace WebCore;
41
42namespace WebKit {
43
44TiledDrawingAreaTile::TiledDrawingAreaTile(TiledDrawingAreaProxy* proxy, const Coordinate& tileCoordinate)
45    : m_proxy(proxy)
46    , m_coordinate(tileCoordinate)
47    , m_rect(proxy->tileRectForCoordinate(tileCoordinate))
48    , m_hasUpdatePending(false)
49    , m_dirtyRegion(m_rect)
50{
51    static int id = 0;
52    m_ID = ++id;
53#ifdef TILE_DEBUG_LOG
54    qDebug() << "deleting tile id=" << m_ID;
55#endif
56}
57
58TiledDrawingAreaTile::~TiledDrawingAreaTile()
59{
60#ifdef TILE_DEBUG_LOG
61    qDebug() << "deleting tile id=" << m_ID;
62#endif
63}
64
65bool TiledDrawingAreaTile::isDirty() const
66{
67    return !m_dirtyRegion.isEmpty();
68}
69
70bool TiledDrawingAreaTile::isReadyToPaint() const
71{
72    return !m_buffer.isNull();
73}
74
75bool TiledDrawingAreaTile::hasReadyBackBuffer() const
76{
77    return !m_backBuffer.isNull() && !m_hasUpdatePending;
78}
79
80void TiledDrawingAreaTile::invalidate(const IntRect& dirtyRect)
81{
82    IntRect tileDirtyRect = intersection(dirtyRect, m_rect);
83    if (tileDirtyRect.isEmpty())
84        return;
85
86    m_dirtyRegion += tileDirtyRect;
87}
88
89void TiledDrawingAreaTile::resize(const IntSize& newSize)
90{
91    IntRect oldRect = m_rect;
92    m_rect = IntRect(m_rect.location(), newSize);
93    if (m_rect.maxX() > oldRect.maxX())
94        invalidate(IntRect(oldRect.maxX(), oldRect.y(), m_rect.maxX() - oldRect.maxX(), m_rect.height()));
95    if (m_rect.maxY() > oldRect.maxY())
96        invalidate(IntRect(oldRect.x(), oldRect.maxY(), m_rect.width(), m_rect.maxY() - oldRect.maxY()));
97}
98
99void TiledDrawingAreaTile::swapBackBufferToFront()
100{
101    ASSERT(!m_backBuffer.isNull());
102
103    m_buffer = m_backBuffer;
104    m_backBuffer = QPixmap();
105}
106
107void TiledDrawingAreaTile::paint(GraphicsContext* context, const IntRect& rect)
108{
109    ASSERT(!m_buffer.isNull());
110
111    IntRect target = intersection(rect, m_rect);
112    IntRect source((target.x() - m_rect.x()),
113                   (target.y() - m_rect.y()),
114                   target.width(),
115                   target.height());
116
117    context->platformContext()->drawPixmap(target, m_buffer, source);
118}
119
120void TiledDrawingAreaTile::updateFromChunk(UpdateChunk* updateChunk, float)
121{
122    QImage image(updateChunk->createImage());
123    const IntRect& updateChunkRect = updateChunk->rect();
124
125#ifdef TILE_DEBUG_LOG
126    qDebug() << "tile updated id=" << ID() << " rect=" << QRect(updateChunkRect);
127#endif
128    if (updateChunkRect.size() == m_proxy->tileSize()) {
129        // Make a deep copy of the image since it's in shared memory.
130        m_backBuffer = QPixmap::fromImage(image.copy());
131    } else {
132        if (m_backBuffer.isNull())
133            m_backBuffer = m_buffer.isNull() ? QPixmap(m_proxy->tileSize()) : m_buffer;
134        QPainter painter(&m_backBuffer);
135        IntSize drawPoint = updateChunkRect.location() - m_rect.location();
136        painter.drawImage(QPoint(drawPoint.width(), drawPoint.height()), image);
137    }
138    m_hasUpdatePending = false;
139}
140
141void TiledDrawingAreaTile::updateBackBuffer()
142{
143    if (isReadyToPaint() && !isDirty())
144        return;
145
146    // FIXME: individual rects
147    IntRect dirtyRect = m_dirtyRegion.boundingRect();
148    m_dirtyRegion = QRegion();
149
150#ifdef TILE_DEBUG_LOG
151    qDebug() << "requesting tile update id=" << m_ID << " rect=" << QRect(dirtyRect) << " scale=" << m_proxy->contentsScale();
152#endif
153    if (!m_proxy->page()->process()->isValid())
154        return;
155    m_proxy->requestTileUpdate(m_ID, dirtyRect);
156
157    m_hasUpdatePending = true;
158}
159
160}
161#endif
162