6ba852b21ed4d8ed5a808348bbf0868e17bc375f
[platform/framework/web/webkit-efl.git] / Source / WebCore / platform / graphics / texmap / TextureMapperBackingStore.cpp
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(ACCELERATED_COMPOSITING)
23 #include "TextureMapperBackingStore.h"
24
25 #include "GraphicsLayer.h"
26 #include "ImageBuffer.h"
27 #include "TextureMapper.h"
28
29 #if USE(GRAPHICS_SURFACE) || ENABLE(TIZEN_CANVAS_GRAPHICS_SURFACE)
30 #include "GraphicsSurface.h"
31 #include "TextureMapperGL.h"
32 #endif
33
34 namespace WebCore {
35
36 #if USE(GRAPHICS_SURFACE) || ENABLE(TIZEN_CANVAS_GRAPHICS_SURFACE)
37 #if ENABLE(TIZEN_WEBKIT2_TILED_AC)
38 void TextureMapperSurfaceBackingStore::setGraphicsSurface(PlatformBufferHandle graphicsSurfaceToken, const IntSize& surfaceSize, PlatformBufferHandle frontBuffer, int flags)
39 #else
40 void TextureMapperSurfaceBackingStore::setGraphicsSurface(uint64_t graphicsSurfaceToken, const IntSize& surfaceSize, uint32_t frontBuffer)
41 #endif
42 {
43 #if ENABLE(TIZEN_WEBKIT2_TILED_AC)
44     if (graphicsSurfaceToken != m_graphicsSurfaceToken || m_graphicsSurfaceSize != surfaceSize) {
45 #else
46     if (graphicsSurfaceToken != m_graphicsSurfaceToken) {
47 #endif
48         GraphicsSurface::Flags surfaceFlags = GraphicsSurface::SupportsTextureTarget
49                                             | GraphicsSurface::SupportsSharing;
50 #if ENABLE(TIZEN_WEBKIT2_TILED_AC)
51         setSurface(GraphicsSurface::create(surfaceSize, surfaceFlags, graphicsSurfaceToken, flags));
52 #else
53         setSurface(GraphicsSurface::create(surfaceSize, surfaceFlags, graphicsSurfaceToken));
54 #endif
55         m_graphicsSurfaceSize = surfaceSize;
56     }
57
58     RefPtr<WebCore::GraphicsSurface> surface = graphicsSurface();
59     if (surface && surface->frontBuffer() != frontBuffer)
60 #if ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
61         surface->swapBuffers(frontBuffer);
62 #else
63         surface->swapBuffers();
64 #endif
65 }
66
67 PassRefPtr<BitmapTexture> TextureMapperSurfaceBackingStore::texture() const
68 {
69     // FIXME: Instead of just returning an empty texture, we should wrap the texture contents into a BitmapTexture.
70     RefPtr<BitmapTexture> emptyTexture;
71     return emptyTexture;
72 }
73
74 void TextureMapperSurfaceBackingStore::paintToTextureMapper(TextureMapper* textureMapper, const FloatRect& targetRect, const TransformationMatrix& transform, float opacity)
75 {
76     if (m_graphicsSurface)
77         m_graphicsSurface->paintToTextureMapper(textureMapper, targetRect, transform, opacity);
78 }
79
80 void TextureMapperSurfaceBackingStore::setSurface(PassRefPtr<GraphicsSurface> surface)
81 {
82     if (surface) {
83         m_graphicsSurface = surface;
84         m_graphicsSurfaceToken = m_graphicsSurface->exportToken();
85     } else {
86         m_graphicsSurface = RefPtr<GraphicsSurface>();
87         m_graphicsSurfaceToken = 0;
88     }
89 }
90 #endif
91
92 void TextureMapperTile::updateContents(TextureMapper* textureMapper, Image* image, const IntRect& dirtyRect)
93 {
94     IntRect targetRect = enclosingIntRect(m_rect);
95     targetRect.intersect(dirtyRect);
96     if (targetRect.isEmpty())
97         return;
98     IntPoint sourceOffset = targetRect.location();
99
100     // Normalize sourceRect to the buffer's coordinates.
101     sourceOffset.move(-dirtyRect.x(), -dirtyRect.y());
102
103     // Normalize targetRect to the texture's coordinates.
104     targetRect.move(-m_rect.x(), -m_rect.y());
105     if (!m_texture) {
106         m_texture = textureMapper->createTexture();
107         m_texture->reset(targetRect.size(), image->currentFrameHasAlpha() ? BitmapTexture::SupportsAlpha : 0);
108     }
109
110     m_texture->updateContents(image, targetRect, sourceOffset);
111 }
112
113 void TextureMapperTile::paint(TextureMapper* textureMapper, const TransformationMatrix& transform, float opacity, const unsigned exposedEdges)
114 {
115     if (texture().get())
116         textureMapper->drawTexture(*texture().get(), rect(), transform, opacity, exposedEdges);
117 }
118
119 TextureMapperTiledBackingStore::TextureMapperTiledBackingStore()
120     : m_drawsDebugBorders(false)
121 {
122 }
123
124 void TextureMapperTiledBackingStore::updateContentsFromImageIfNeeded(TextureMapper* textureMapper)
125 {
126     if (!m_image)
127         return;
128
129     updateContents(textureMapper, m_image.get());
130     m_image.clear();
131 }
132
133 unsigned TextureMapperBackingStore::calculateExposedTileEdges(const FloatRect& totalRect, const FloatRect& tileRect)
134 {
135     unsigned exposedEdges = TextureMapper::NoEdges;
136     if (!tileRect.x())
137         exposedEdges |= TextureMapper::LeftEdge;
138     if (!tileRect.y())
139         exposedEdges |= TextureMapper::TopEdge;
140     if (tileRect.width() + tileRect.x() >= totalRect.width())
141         exposedEdges |= TextureMapper::RightEdge;
142     if (tileRect.height() + tileRect.y() >= totalRect.height())
143         exposedEdges |= TextureMapper::BottomEdge;
144     return exposedEdges;
145 }
146
147 void TextureMapperTiledBackingStore::paintToTextureMapper(TextureMapper* textureMapper, const FloatRect& targetRect, const TransformationMatrix& transform, float opacity)
148 {
149     updateContentsFromImageIfNeeded(textureMapper);
150     TransformationMatrix adjustedTransform = transform;
151     adjustedTransform.multiply(TransformationMatrix::rectToRect(rect(), targetRect));
152     for (size_t i = 0; i < m_tiles.size(); ++i) {
153         m_tiles[i].paint(textureMapper, adjustedTransform, opacity, calculateExposedTileEdges(rect(), m_tiles[i].rect()));
154         if (m_drawsDebugBorders)
155             textureMapper->drawBorder(m_debugBorderColor, m_debugBorderWidth, m_tiles[i].rect(), adjustedTransform);
156     }
157 }
158
159 void TextureMapperTiledBackingStore::createOrDestroyTilesIfNeeded(const FloatSize& size, const IntSize& tileSize, bool hasAlpha)
160 {
161     if (size == m_size)
162         return;
163
164     m_size = size;
165
166     Vector<FloatRect> tileRectsToAdd;
167     Vector<int> tileIndicesToRemove;
168     static const size_t TileEraseThreshold = 6;
169
170     // This method recycles tiles. We check which tiles we need to add, which to remove, and use as many
171     // removable tiles as replacement for new tiles when possible.
172     for (float y = 0; y < m_size.height(); y += tileSize.height()) {
173         for (float x = 0; x < m_size.width(); x += tileSize.width()) {
174             FloatRect tileRect(x, y, tileSize.width(), tileSize.height());
175             tileRect.intersect(rect());
176             tileRectsToAdd.append(tileRect);
177         }
178     }
179
180     // Check which tiles need to be removed, and which already exist.
181     for (int i = m_tiles.size() - 1; i >= 0; --i) {
182         FloatRect oldTile = m_tiles[i].rect();
183         bool existsAlready = false;
184
185         for (int j = tileRectsToAdd.size() - 1; j >= 0; --j) {
186             FloatRect newTile = tileRectsToAdd[j];
187             if (oldTile != newTile)
188                 continue;
189
190             // A tile that we want to add already exists, no need to add or remove it.
191             existsAlready = true;
192             tileRectsToAdd.remove(j);
193             break;
194         }
195
196         // This tile is not needed.
197         if (!existsAlready)
198             tileIndicesToRemove.append(i);
199     }
200
201     // Recycle removable tiles to be used for newly requested tiles.
202     for (size_t i = 0; i < tileRectsToAdd.size(); ++i) {
203         if (!tileIndicesToRemove.isEmpty()) {
204             // We recycle an existing tile for usage with a new tile rect.
205             TextureMapperTile& tile = m_tiles[tileIndicesToRemove.last()];
206             tileIndicesToRemove.removeLast();
207             tile.setRect(tileRectsToAdd[i]);
208
209             if (tile.texture())
210                 tile.texture()->reset(enclosingIntRect(tile.rect()).size(), hasAlpha ? BitmapTexture::SupportsAlpha : 0);
211             continue;
212         }
213
214         m_tiles.append(TextureMapperTile(tileRectsToAdd[i]));
215     }
216
217     // Remove unnecessary tiles, if they weren't recycled.
218     // We use a threshold to make sure we don't create/destroy tiles too eagerly.
219     for (size_t i = 0; i < tileIndicesToRemove.size() && m_tiles.size() > TileEraseThreshold; ++i)
220         m_tiles.remove(tileIndicesToRemove[i]);
221 }
222
223 void TextureMapperTiledBackingStore::updateContents(TextureMapper* textureMapper, Image* image, const FloatSize& totalSize, const IntRect& dirtyRect)
224 {
225     createOrDestroyTilesIfNeeded(totalSize, textureMapper->maxTextureSize(), image->currentFrameHasAlpha());
226     for (size_t i = 0; i < m_tiles.size(); ++i)
227         m_tiles[i].updateContents(textureMapper, image, dirtyRect);
228 }
229
230 PassRefPtr<BitmapTexture> TextureMapperTiledBackingStore::texture() const
231 {
232     for (size_t i = 0; i < m_tiles.size(); ++i) {
233         RefPtr<BitmapTexture> texture = m_tiles[i].texture();
234         if (texture)
235             return texture;
236     }
237
238     return PassRefPtr<BitmapTexture>();
239 }
240
241 void TextureMapperTiledBackingStore::setDebugBorder(const Color& color, float width)
242 {
243     m_debugBorderColor = color;
244     m_debugBorderWidth = width;
245 }
246
247 }
248 #endif