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"
36 #include <cutils/log.h>
37 #include <wtf/CurrentTime.h>
38 #include <wtf/text/CString.h>
41 #define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "TiledTexture", __VA_ARGS__)
46 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "TiledTexture", __VA_ARGS__)
57 bool TiledTexture::ready() {
58 bool tilesAllReady = true;
59 bool tilesVisible = false;
60 for (unsigned int i = 0; i < m_tiles.size(); i++) {
61 BaseTile* tile = m_tiles[i];
62 if (tile->isTileVisible(m_area) && !tile->isTileReady()) {
63 tilesAllReady = false;
66 if (tile->isTileVisible(m_area))
69 // For now, if no textures are available, consider ourselves as ready
70 // in order to unblock the zooming process.
71 // FIXME: have a better system -- maybe keeping the last scale factor
72 // able to fully render everything
73 return !TilesManager::instance()->layerTexturesRemain()
74 || !tilesVisible || tilesAllReady;
77 void TiledTexture::prepare(GLWebViewState* state, float scale, bool repaint,
78 bool startFastSwap, IntRect& visibleArea)
83 if (!m_surface->layer())
86 // first, how many tiles do we need
87 IntRect area(visibleArea.x() * scale,
88 visibleArea.y() * scale,
89 ceilf(visibleArea.width() * scale),
90 ceilf(visibleArea.height() * scale));
92 if (area.width() == 0 && area.height() == 0) {
98 int tileWidth = TilesManager::instance()->layerTileWidth();
99 int tileHeight = TilesManager::instance()->layerTileHeight();
101 m_area.setX(area.x() / tileWidth);
102 m_area.setY(area.y() / tileHeight);
103 float right = (area.x() + area.width()) / (float) tileWidth;
104 float bottom = (area.y() + area.height()) / (float) tileHeight;
105 m_area.setWidth(ceilf(right) - m_area.x());
106 m_area.setHeight(ceilf(bottom) - m_area.y());
108 XLOG("for TiledTexture %p, we prepare with scale %.2f, have a visible area of %d, %d - %d x %d, corresponding to %d, %d x - %d x %d tiles",
110 visibleArea.x(), visibleArea.y(),
111 visibleArea.width(), visibleArea.height(),
112 m_area.x(), m_area.y(),
113 m_area.width(), m_area.height());
115 bool goingDown = m_prevTileY < m_area.y();
116 m_prevTileY = m_area.y();
118 if (scale != m_scale)
119 TilesManager::instance()->removeOperationsForFilter(new ScaleFilter(this, scale));
123 // unlock if tiles all ready
124 bool tilesAllReady = ready();
126 // startFastSwap=true will swap all ready tiles each
127 // frame until all visible tiles are up to date
129 m_swapWhateverIsReady = false;
130 else if (startFastSwap)
131 m_swapWhateverIsReady = true;
133 // swap as appropriate
134 for (unsigned int i = 0; i < m_tiles.size(); i++) {
135 BaseTile* tile = m_tiles[i];
136 if (tilesAllReady || m_swapWhateverIsReady)
137 tile->swapTexturesIfNeeded();
141 m_updateManager.swap();
142 m_dirtyRegion.op(m_updateManager.getPaintingInval(), SkRegion::kUnion_Op);
143 XLOG("TT %p swapping, now painting with picture %p"
144 this, m_updateManager.getPaintingPicture());
145 m_updateManager.clearPaintingInval();
148 // apply dirty region to affected tiles
149 if (!m_dirtyRegion.isEmpty()) {
150 for (unsigned int i = 0; i < m_tiles.size(); i++) {
151 // TODO: don't mark all tiles dirty
152 m_tiles[i]->markAsDirty(1, m_dirtyRegion);
155 m_dirtyRegion.setEmpty();
157 for (int i = 0; i < m_area.width(); i++) {
159 for (int j = 0; j < m_area.height(); j++) {
160 prepareTile(repaint, m_area.x() + i, m_area.y() + j);
163 for (int j = m_area.height() - 1; j >= 0; j--) {
164 prepareTile(repaint, m_area.x() + i, m_area.y() + j);
170 void TiledTexture::update(const SkRegion& invalRegion, SkPicture* picture)
172 XLOG("TT %p, update manager %p updated with picture %p, region empty %d",
173 this, &m_updateManager, picture, invalRegion.isEmpty());
174 // attempt to update inval and picture. these may be deferred below instead
175 // of used immediately.
176 m_updateManager.updateInval(invalRegion);
177 m_updateManager.updatePicture(picture);
180 void TiledTexture::prepareTile(bool repaint, int x, int y)
182 BaseTile* tile = getTile(x, y);
184 tile = new BaseTile(true);
185 m_tiles.append(tile);
188 XLOG("preparing tile %p, painter is this %p", tile, this);
189 tile->setContents(this, x, y, m_scale);
191 // TODO: move below (which is largely the same for layers / tiled page) into
192 // prepare() function
194 if (tile->isDirty() || !tile->frontTexture())
195 tile->reserveTexture();
196 LayerAndroid* layer = m_surface->layer();
197 if (tile->backTexture() && tile->isDirty() && !tile->isRepaintPending() && layer) {
198 PaintTileOperation *operation = new PaintTileOperation(tile, m_surface);
199 TilesManager::instance()->scheduleOperation(operation);
203 BaseTile* TiledTexture::getTile(int x, int y)
205 for (unsigned int i = 0; i <m_tiles.size(); i++) {
206 BaseTile* tile = m_tiles[i];
207 if (tile->x() == x && tile->y() == y)
213 bool TiledTexture::draw()
216 TilesManager::instance()->getTilesTracker()->trackLayer();
219 if (m_area.width() == 0 || m_area.height() == 0)
223 TilesManager::instance()->getTilesTracker()->trackVisibleLayer();
226 float m_invScale = 1 / m_scale;
227 const float tileWidth = TilesManager::layerTileWidth() * m_invScale;
228 const float tileHeight = TilesManager::layerTileHeight() * m_invScale;
230 bool askRedraw = false;
231 for (unsigned int i = 0; i < m_tiles.size(); i++) {
232 BaseTile* tile = m_tiles[i];
234 if (tile->isTileVisible(m_area)) {
235 askRedraw |= !tile->isTileReady();
237 rect.fLeft = tile->x() * tileWidth;
238 rect.fTop = tile->y() * tileHeight;
239 rect.fRight = rect.fLeft + tileWidth;
240 rect.fBottom = rect.fTop + tileHeight;
241 XLOG(" - [%d], { painter %x vs %x }, tile %x %d,%d at scale %.2f vs %.2f [ready: %d] dirty: %d",
242 i, this, tile->painter(), tile, tile->x(), tile->y(),
243 tile->scale(), m_scale, tile->isTileReady(), tile->isDirty());
244 tile->draw(m_surface->opacity(), rect, m_scale);
246 TilesManager::instance()->getTilesTracker()->track(tile->isTileReady(), tile->backTexture());
251 // need to redraw if some visible tile wasn't ready
255 bool TiledTexture::paint(BaseTile* tile, SkCanvas* canvas, unsigned int* pictureUsed)
257 return m_updateManager.paint(tile, canvas, pictureUsed);
260 const TransformationMatrix* TiledTexture::transform()
262 return m_surface->transform();
265 void TiledTexture::removeTiles()
267 for (unsigned int i = 0; i < m_tiles.size(); i++) {
273 void TiledTexture::discardTextures()
275 for (unsigned int i = 0; i < m_tiles.size(); i++)
276 m_tiles[i]->discardTextures();
279 bool TiledTexture::owns(BaseTileTexture* texture)
281 for (unsigned int i = 0; i < m_tiles.size(); i++) {
282 BaseTile* tile = m_tiles[i];
283 if (tile->frontTexture() == texture)
285 if (tile->backTexture() == texture)
291 DualTiledTexture::DualTiledTexture(PaintedSurface* surface)
293 m_textureA = new TiledTexture(surface);
294 m_textureB = new TiledTexture(surface);
295 m_frontTexture = m_textureA;
296 m_backTexture = m_textureB;
302 DualTiledTexture::~DualTiledTexture()
308 void DualTiledTexture::prepare(GLWebViewState* state, float scale, bool repaint,
309 bool startFastSwap, IntRect& visibleArea)
311 // If we are zooming, we will use the previously used area, to prevent the
312 // frontTexture to try to allocate more tiles than what it has already
314 m_preZoomVisibleArea = visibleArea;
316 if (m_futureScale != scale) {
317 m_futureScale = scale;
318 m_zoomUpdateTime = WTF::currentTime() + DualTiledTexture::s_zoomUpdateDelay;
322 XLOG("\n*** %x Drawing with scale %.2f, futureScale: %.2f, zooming: %d",
323 this, scale, m_futureScale, m_zooming);
326 m_frontTexture->prepare(state, m_scale, repaint, startFastSwap, m_preZoomVisibleArea);
328 // If we had a scheduled update
329 if (m_zooming && m_zoomUpdateTime < WTF::currentTime()) {
330 m_backTexture->prepare(state, m_futureScale, repaint, startFastSwap, visibleArea);
331 if (m_backTexture->ready()) {
338 void DualTiledTexture::swap()
340 m_frontTexture = m_frontTexture == m_textureA ? m_textureB : m_textureA;
341 m_backTexture = m_backTexture == m_textureA ? m_textureB : m_textureA;
342 m_scale = m_futureScale;
343 m_backTexture->discardTextures();
346 bool DualTiledTexture::draw()
348 bool needsRepaint = m_frontTexture->draw();
349 needsRepaint |= m_zooming;
350 needsRepaint |= (m_scale <= 0);
354 void DualTiledTexture::update(const SkRegion& dirtyArea, SkPicture* picture)
356 m_backTexture->update(dirtyArea, picture);
357 m_frontTexture->update(dirtyArea, picture);
360 bool DualTiledTexture::owns(BaseTileTexture* texture)
362 bool owns = m_textureA->owns(texture);
363 owns |= m_textureB->owns(texture);
367 } // namespace WebCore