2 * Copyright 2011, The Android Open Source Project
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * 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.
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "TiledTexture.h"
29 #include "TilesManager.h"
30 #include "TilesTracker.h"
32 #include "PaintedSurface.h"
33 #include "PaintTileOperation.h"
35 #include "SkPicture.h"
37 #include <cutils/log.h>
38 #include <wtf/CurrentTime.h>
39 #include <wtf/text/CString.h>
42 #define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "TiledTexture", __VA_ARGS__)
47 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "TiledTexture", __VA_ARGS__)
58 TiledTexture::~TiledTexture()
60 SkSafeUnref(m_paintingPicture);
62 ClassTracker::instance()->decrement("TiledTexture");
67 bool TiledTexture::ready()
69 bool tilesAllReady = true;
70 bool tilesVisible = false;
71 for (unsigned int i = 0; i < m_tiles.size(); i++) {
72 BaseTile* tile = m_tiles[i];
73 if (tile->isTileVisible(m_area)) {
75 if (!tile->isTileReady()) {
76 tilesAllReady = false;
81 // For now, if no textures are available, consider ourselves as ready
82 // in order to unblock the zooming process.
83 // FIXME: have a better system -- maybe keeping the last scale factor
84 // able to fully render everything
85 XLOG("TT %p, ready %d, visible %d, texturesRemain %d",
86 this, tilesAllReady, tilesVisible,
87 TilesManager::instance()->layerTexturesRemain());
89 return !TilesManager::instance()->layerTexturesRemain()
90 || !tilesVisible || tilesAllReady;
93 void TiledTexture::swapTiles()
96 for (unsigned int i = 0; i < m_tiles.size(); i++)
97 if (m_tiles[i]->swapTexturesIfNeeded())
99 XLOG("TT %p swapping, swaps = %d", this, swaps);
102 IntRect TiledTexture::computeTilesArea(IntRect& visibleArea, float scale)
104 IntRect computedArea;
105 IntRect area(visibleArea.x() * scale,
106 visibleArea.y() * scale,
107 ceilf(visibleArea.width() * scale),
108 ceilf(visibleArea.height() * scale));
110 XLOG("TT %p prepare, scale %f, area %d x %d", this, scale, area.width(), area.height());
112 if (area.width() == 0 && area.height() == 0) {
113 computedArea.setWidth(0);
114 computedArea.setHeight(0);
118 int tileWidth = TilesManager::instance()->layerTileWidth();
119 int tileHeight = TilesManager::instance()->layerTileHeight();
121 computedArea.setX(area.x() / tileWidth);
122 computedArea.setY(area.y() / tileHeight);
123 float right = (area.x() + area.width()) / (float) tileWidth;
124 float bottom = (area.y() + area.height()) / (float) tileHeight;
125 computedArea.setWidth(ceilf(right) - computedArea.x());
126 computedArea.setHeight(ceilf(bottom) - computedArea.y());
130 void TiledTexture::prepare(GLWebViewState* state, float scale, bool repaint,
131 bool startFastSwap, IntRect& visibleArea)
136 // first, how many tiles do we need
137 m_area = computeTilesArea(visibleArea, scale);
138 if (m_area.isEmpty())
141 XLOG("for TiledTexture %p, we prepare with scale %.2f, have a visible area of "
142 " %d, %d - %d x %d, corresponding to %d, %d x - %d x %d tiles",
144 visibleArea.x(), visibleArea.y(),
145 visibleArea.width(), visibleArea.height(),
146 m_area.x(), m_area.y(),
147 m_area.width(), m_area.height());
149 bool goingDown = m_prevTileY < m_area.y();
150 m_prevTileY = m_area.y();
152 if (scale != m_scale)
153 TilesManager::instance()->removeOperationsForFilter(new ScaleFilter(this, scale));
157 // apply dirty region to affected tiles
158 if (!m_dirtyRegion.isEmpty()) {
159 for (unsigned int i = 0; i < m_tiles.size(); i++) {
160 // TODO: don't mark all tiles dirty
161 m_tiles[i]->markAsDirty(1, m_dirtyRegion);
164 m_dirtyRegion.setEmpty();
166 for (int i = 0; i < m_area.width(); i++) {
168 for (int j = 0; j < m_area.height(); j++) {
169 prepareTile(repaint, m_area.x() + i, m_area.y() + j);
172 for (int j = m_area.height() - 1; j >= 0; j--) {
173 prepareTile(repaint, m_area.x() + i, m_area.y() + j);
179 void TiledTexture::update(const SkRegion& invalRegion, SkPicture* picture)
181 XLOG("TT %p update, current region empty %d, new empty %d, painting picture %p",
182 this, m_dirtyRegion.isEmpty(), invalRegion.isEmpty(), picture);
183 m_dirtyRegion.op(invalRegion, SkRegion::kUnion_Op);
185 android::Mutex::Autolock lock(m_paintingPictureSync);
187 SkSafeUnref(m_paintingPicture);
188 m_paintingPicture = picture;
191 void TiledTexture::prepareTile(bool repaint, int x, int y)
193 BaseTile* tile = getTile(x, y);
195 tile = new BaseTile(true);
196 m_tiles.append(tile);
199 XLOG("preparing tile %p at %d, %d, painter is this %p", tile, x, y, this);
200 tile->setContents(this, x, y, m_scale);
202 // TODO: move below (which is largely the same for layers / tiled page) into
203 // prepare() function
205 if (tile->isDirty() || !tile->frontTexture())
206 tile->reserveTexture();
207 bool hasPicture = m_paintingPicture != 0; // safely read on UI thread, since only UI thread writes
208 if (tile->backTexture() && tile->isDirty() && !tile->isRepaintPending() && hasPicture) {
209 PaintTileOperation *operation = new PaintTileOperation(tile, m_surface);
210 TilesManager::instance()->scheduleOperation(operation);
214 BaseTile* TiledTexture::getTile(int x, int y)
216 for (unsigned int i = 0; i <m_tiles.size(); i++) {
217 BaseTile* tile = m_tiles[i];
218 if (tile->x() == x && tile->y() == y)
224 int TiledTexture::nbTextures(IntRect& area, float scale)
226 IntRect computedTilesArea = computeTilesArea(area, scale);
227 return computedTilesArea.width() * computedTilesArea.height();
230 bool TiledTexture::draw()
232 XLOG("TT %p draw", this);
235 TilesManager::instance()->getTilesTracker()->trackLayer();
238 if (m_area.width() == 0 || m_area.height() == 0)
242 TilesManager::instance()->getTilesTracker()->trackVisibleLayer();
245 float m_invScale = 1 / m_scale;
246 const float tileWidth = TilesManager::layerTileWidth() * m_invScale;
247 const float tileHeight = TilesManager::layerTileHeight() * m_invScale;
249 bool askRedraw = false;
250 for (unsigned int i = 0; i < m_tiles.size(); i++) {
251 BaseTile* tile = m_tiles[i];
253 if (tile->isTileVisible(m_area)) {
254 askRedraw |= !tile->isTileReady();
256 rect.fLeft = tile->x() * tileWidth;
257 rect.fTop = tile->y() * tileHeight;
258 rect.fRight = rect.fLeft + tileWidth;
259 rect.fBottom = rect.fTop + tileHeight;
260 XLOG("- [%d], { painter %x vs %x }, tile %x %d,%d at scale %.2f vs %.2f [ready: %d] dirty: %d",
261 i, this, tile->painter(), tile, tile->x(), tile->y(),
262 tile->scale(), m_scale, tile->isTileReady(), tile->isDirty());
263 tile->draw(m_surface->opacity(), rect, m_scale);
265 TilesManager::instance()->getTilesTracker()->track(tile->isTileReady(), tile->backTexture());
270 // need to redraw if some visible tile wasn't ready
274 bool TiledTexture::paint(BaseTile* tile, SkCanvas* canvas, unsigned int* pictureUsed)
276 m_paintingPictureSync.lock();
277 SkPicture* picture = m_paintingPicture;
279 m_paintingPictureSync.unlock();
282 XLOG("TT %p COULDNT PAINT, NO PICTURE", this);
286 XLOG("TT %p painting with picture %p", this, picture);
288 canvas->drawPicture(*picture);
290 SkSafeUnref(picture);
295 const TransformationMatrix* TiledTexture::transform()
297 return m_surface->transform();
300 void TiledTexture::removeTiles()
302 for (unsigned int i = 0; i < m_tiles.size(); i++) {
308 void TiledTexture::discardTextures()
310 for (unsigned int i = 0; i < m_tiles.size(); i++)
311 m_tiles[i]->discardTextures();
314 bool TiledTexture::owns(BaseTileTexture* texture)
316 for (unsigned int i = 0; i < m_tiles.size(); i++) {
317 BaseTile* tile = m_tiles[i];
318 if (tile->frontTexture() == texture)
320 if (tile->backTexture() == texture)
326 DualTiledTexture::DualTiledTexture(PaintedSurface* surface)
328 m_textureA = new TiledTexture(surface);
329 m_textureB = new TiledTexture(surface);
330 m_frontTexture = m_textureA;
331 m_backTexture = m_textureB;
337 DualTiledTexture::~DualTiledTexture()
343 void DualTiledTexture::prepare(GLWebViewState* state, float scale, bool repaint,
344 bool startFastSwap, IntRect& visibleArea)
346 // If we are zooming, we will use the previously used area, to prevent the
347 // frontTexture to try to allocate more tiles than what it has already
349 m_preZoomVisibleArea = visibleArea;
351 if (m_futureScale != scale) {
352 m_futureScale = scale;
353 m_zoomUpdateTime = WTF::currentTime() + DualTiledTexture::s_zoomUpdateDelay;
357 XLOG("Preparing DTT %p with scale %.2f, m_scale %.2f, futureScale: %.2f, zooming: %d",
358 this, scale, m_scale, m_futureScale, m_zooming);
361 m_frontTexture->prepare(state, m_scale, repaint, startFastSwap, m_preZoomVisibleArea);
363 // If we had a scheduled update
364 if (m_zooming && m_zoomUpdateTime < WTF::currentTime()) {
365 m_backTexture->prepare(state, m_futureScale, repaint, startFastSwap, visibleArea);
366 if (m_backTexture->ready()) {
373 void DualTiledTexture::swap()
375 m_frontTexture = m_frontTexture == m_textureA ? m_textureB : m_textureA;
376 m_backTexture = m_backTexture == m_textureA ? m_textureB : m_textureA;
377 m_scale = m_futureScale;
378 m_backTexture->discardTextures();
381 bool DualTiledTexture::draw()
383 bool needsRepaint = m_frontTexture->draw();
384 needsRepaint |= m_zooming;
385 needsRepaint |= (m_scale <= 0);
389 void DualTiledTexture::update(const SkRegion& dirtyArea, SkPicture* picture)
391 m_backTexture->update(dirtyArea, picture);
392 m_frontTexture->update(dirtyArea, picture);
395 void DualTiledTexture::swapTiles()
397 m_backTexture->swapTiles();
398 m_frontTexture->swapTiles();
401 bool DualTiledTexture::owns(BaseTileTexture* texture)
403 bool owns = m_textureA->owns(texture);
404 owns |= m_textureB->owns(texture);
408 } // namespace WebCore