1/*
2 Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library 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 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB.  If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18 */
19
20#include "config.h"
21
22#if USE(TEXTURE_MAPPER)
23#include "TextureMapperTiledBackingStore.h"
24
25#include "ImageBuffer.h"
26#include "TextureMapper.h"
27
28namespace WebCore {
29
30class GraphicsLayer;
31
32TextureMapperTiledBackingStore::TextureMapperTiledBackingStore()
33{
34}
35
36void TextureMapperTiledBackingStore::updateContentsFromImageIfNeeded(TextureMapper* textureMapper)
37{
38    if (!m_image)
39        return;
40
41    updateContents(textureMapper, m_image.get(), m_image->size(), enclosingIntRect(m_image->rect()), BitmapTexture::UpdateCannotModifyOriginalImageData);
42    m_image.clear();
43}
44
45TransformationMatrix TextureMapperTiledBackingStore::adjustedTransformForRect(const FloatRect& targetRect)
46{
47    return TransformationMatrix::rectToRect(rect(), targetRect);
48}
49
50void TextureMapperTiledBackingStore::paintToTextureMapper(TextureMapper* textureMapper, const FloatRect& targetRect, const TransformationMatrix& transform, float opacity)
51{
52    updateContentsFromImageIfNeeded(textureMapper);
53    TransformationMatrix adjustedTransform = transform * adjustedTransformForRect(targetRect);
54    for (size_t i = 0; i < m_tiles.size(); ++i)
55        m_tiles[i].paint(textureMapper, adjustedTransform, opacity, calculateExposedTileEdges(rect(), m_tiles[i].rect()));
56}
57
58void TextureMapperTiledBackingStore::drawBorder(TextureMapper* textureMapper, const Color& borderColor, float borderWidth, const FloatRect& targetRect, const TransformationMatrix& transform)
59{
60    TransformationMatrix adjustedTransform = transform * adjustedTransformForRect(targetRect);
61    for (size_t i = 0; i < m_tiles.size(); ++i)
62        textureMapper->drawBorder(borderColor, borderWidth, m_tiles[i].rect(), adjustedTransform);
63}
64
65void TextureMapperTiledBackingStore::drawRepaintCounter(TextureMapper* textureMapper, int repaintCount, const Color& borderColor, const FloatRect& targetRect, const TransformationMatrix& transform)
66{
67    TransformationMatrix adjustedTransform = transform * adjustedTransformForRect(targetRect);
68    for (size_t i = 0; i < m_tiles.size(); ++i)
69        textureMapper->drawNumber(repaintCount, borderColor, m_tiles[i].rect().location(), adjustedTransform);
70}
71
72void TextureMapperTiledBackingStore::createOrDestroyTilesIfNeeded(const FloatSize& size, const IntSize& tileSize, bool hasAlpha)
73{
74    if (size == m_size)
75        return;
76
77    m_size = size;
78
79    Vector<FloatRect> tileRectsToAdd;
80    Vector<int> tileIndicesToRemove;
81    static const size_t TileEraseThreshold = 6;
82
83    // This method recycles tiles. We check which tiles we need to add, which to remove, and use as many
84    // removable tiles as replacement for new tiles when possible.
85    for (float y = 0; y < m_size.height(); y += tileSize.height()) {
86        for (float x = 0; x < m_size.width(); x += tileSize.width()) {
87            FloatRect tileRect(x, y, tileSize.width(), tileSize.height());
88            tileRect.intersect(rect());
89            tileRectsToAdd.append(tileRect);
90        }
91    }
92
93    // Check which tiles need to be removed, and which already exist.
94    for (int i = m_tiles.size() - 1; i >= 0; --i) {
95        FloatRect oldTile = m_tiles[i].rect();
96        bool existsAlready = false;
97
98        for (int j = tileRectsToAdd.size() - 1; j >= 0; --j) {
99            FloatRect newTile = tileRectsToAdd[j];
100            if (oldTile != newTile)
101                continue;
102
103            // A tile that we want to add already exists, no need to add or remove it.
104            existsAlready = true;
105            tileRectsToAdd.remove(j);
106            break;
107        }
108
109        // This tile is not needed.
110        if (!existsAlready)
111            tileIndicesToRemove.append(i);
112    }
113
114    // Recycle removable tiles to be used for newly requested tiles.
115    for (size_t i = 0; i < tileRectsToAdd.size(); ++i) {
116        if (!tileIndicesToRemove.isEmpty()) {
117            // We recycle an existing tile for usage with a new tile rect.
118            TextureMapperTile& tile = m_tiles[tileIndicesToRemove.last()];
119            tileIndicesToRemove.removeLast();
120            tile.setRect(tileRectsToAdd[i]);
121
122            if (tile.texture())
123                tile.texture()->reset(enclosingIntRect(tile.rect()).size(), hasAlpha ? BitmapTexture::SupportsAlpha : 0);
124            continue;
125        }
126
127        m_tiles.append(TextureMapperTile(tileRectsToAdd[i]));
128    }
129
130    // Remove unnecessary tiles, if they weren't recycled.
131    // We use a threshold to make sure we don't create/destroy tiles too eagerly.
132    for (size_t i = 0; i < tileIndicesToRemove.size() && m_tiles.size() > TileEraseThreshold; ++i)
133        m_tiles.remove(tileIndicesToRemove[i]);
134}
135
136void TextureMapperTiledBackingStore::updateContents(TextureMapper* textureMapper, Image* image, const FloatSize& totalSize, const IntRect& dirtyRect, BitmapTexture::UpdateContentsFlag updateContentsFlag)
137{
138    createOrDestroyTilesIfNeeded(totalSize, textureMapper->maxTextureSize(), !image->currentFrameKnownToBeOpaque());
139    for (size_t i = 0; i < m_tiles.size(); ++i)
140        m_tiles[i].updateContents(textureMapper, image, dirtyRect, updateContentsFlag);
141}
142
143void TextureMapperTiledBackingStore::updateContents(TextureMapper* textureMapper, GraphicsLayer* sourceLayer, const FloatSize& totalSize, const IntRect& dirtyRect, BitmapTexture::UpdateContentsFlag updateContentsFlag)
144{
145    createOrDestroyTilesIfNeeded(totalSize, textureMapper->maxTextureSize(), true);
146    for (size_t i = 0; i < m_tiles.size(); ++i)
147        m_tiles[i].updateContents(textureMapper, sourceLayer, dirtyRect, updateContentsFlag);
148}
149
150PassRefPtr<BitmapTexture> TextureMapperTiledBackingStore::texture() const
151{
152    for (size_t i = 0; i < m_tiles.size(); ++i) {
153        RefPtr<BitmapTexture> texture = m_tiles[i].texture();
154        if (texture)
155            return texture;
156    }
157
158    return PassRefPtr<BitmapTexture>();
159}
160
161} // namespace WebCore
162#endif
163