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)) {
64 if (!tile->isTileReady()) {
65 tilesAllReady = false;
70 // For now, if no textures are available, consider ourselves as ready
71 // in order to unblock the zooming process.
72 // FIXME: have a better system -- maybe keeping the last scale factor
73 // able to fully render everything
74 return !TilesManager::instance()->layerTexturesRemain()
75 || !tilesVisible || tilesAllReady;
78 IntRect TiledTexture::computeTilesArea(IntRect& visibleArea, float scale)
81 IntRect area(visibleArea.x() * scale,
82 visibleArea.y() * scale,
83 ceilf(visibleArea.width() * scale),
84 ceilf(visibleArea.height() * scale));
86 if (area.width() == 0 && area.height() == 0) {
87 computedArea.setWidth(0);
88 computedArea.setHeight(0);
92 int tileWidth = TilesManager::instance()->layerTileWidth();
93 int tileHeight = TilesManager::instance()->layerTileHeight();
95 computedArea.setX(area.x() / tileWidth);
96 computedArea.setY(area.y() / tileHeight);
97 float right = (area.x() + area.width()) / (float) tileWidth;
98 float bottom = (area.y() + area.height()) / (float) tileHeight;
99 computedArea.setWidth(ceilf(right) - computedArea.x());
100 computedArea.setHeight(ceilf(bottom) - computedArea.y());
104 void TiledTexture::prepare(GLWebViewState* state, float scale, bool repaint,
105 bool startFastSwap, IntRect& area)
110 if (!m_surface->layer())
113 m_area = computeTilesArea(area, scale);
114 if (m_area.isEmpty())
117 XLOG("for TiledTexture %p, we prepare with scale %.2f, have a visible area of "
118 " %d, %d - %d x %d, corresponding to %d, %d x - %d x %d tiles",
120 visibleArea.x(), visibleArea.y(),
121 visibleArea.width(), visibleArea.height(),
122 m_area.x(), m_area.y(),
123 m_area.width(), m_area.height());
125 bool goingDown = m_prevTileY < m_area.y();
126 m_prevTileY = m_area.y();
128 if (scale != m_scale)
129 TilesManager::instance()->removeOperationsForFilter(new ScaleFilter(this, scale));
133 // unlock if tiles all ready
134 bool tilesAllReady = ready();
136 // startFastSwap=true will swap all ready tiles each
137 // frame until all visible tiles are up to date
139 m_swapWhateverIsReady = false;
140 else if (startFastSwap)
141 m_swapWhateverIsReady = true;
143 // swap as appropriate
144 for (unsigned int i = 0; i < m_tiles.size(); i++) {
145 BaseTile* tile = m_tiles[i];
146 if (tilesAllReady || m_swapWhateverIsReady)
147 tile->swapTexturesIfNeeded();
151 m_updateManager.swap();
152 m_dirtyRegion.op(m_updateManager.getPaintingInval(), SkRegion::kUnion_Op);
153 XLOG("TT %p swapping, now painting with picture %p"
154 this, m_updateManager.getPaintingPicture());
155 m_updateManager.clearPaintingInval();
158 // apply dirty region to affected tiles
159 if (!m_dirtyRegion.isEmpty()) {
160 for (unsigned int i = 0; i < m_tiles.size(); i++) {
161 // TODO: don't mark all tiles dirty
162 m_tiles[i]->markAsDirty(1, m_dirtyRegion);
165 m_dirtyRegion.setEmpty();
167 for (int i = 0; i < m_area.width(); i++) {
169 for (int j = 0; j < m_area.height(); j++) {
170 prepareTile(repaint, m_area.x() + i, m_area.y() + j);
173 for (int j = m_area.height() - 1; j >= 0; j--) {
174 prepareTile(repaint, m_area.x() + i, m_area.y() + j);
180 void TiledTexture::update(const SkRegion& invalRegion, SkPicture* picture)
182 XLOG("TT %p, update manager %p updated with picture %p, region empty %d",
183 this, &m_updateManager, picture, invalRegion.isEmpty());
184 // attempt to update inval and picture. these may be deferred below instead
185 // of used immediately.
186 m_updateManager.updateInval(invalRegion);
187 m_updateManager.updatePicture(picture);
190 void TiledTexture::prepareTile(bool repaint, int x, int y)
192 BaseTile* tile = getTile(x, y);
194 tile = new BaseTile(true);
195 m_tiles.append(tile);
198 XLOG("preparing tile %p, painter is this %p", tile, this);
199 tile->setContents(this, x, y, m_scale);
201 // TODO: move below (which is largely the same for layers / tiled page) into
202 // prepare() function
204 if (tile->isDirty() || !tile->frontTexture())
205 tile->reserveTexture();
206 LayerAndroid* layer = m_surface->layer();
207 if (tile->backTexture() && tile->isDirty() && !tile->isRepaintPending() && layer) {
208 PaintTileOperation *operation = new PaintTileOperation(tile, m_surface);
209 TilesManager::instance()->scheduleOperation(operation);
213 BaseTile* TiledTexture::getTile(int x, int y)
215 for (unsigned int i = 0; i <m_tiles.size(); i++) {
216 BaseTile* tile = m_tiles[i];
217 if (tile->x() == x && tile->y() == y)
223 int TiledTexture::nbTextures(IntRect& area, float scale)
225 IntRect computedTilesArea = computeTilesArea(area, scale);
226 return computedTilesArea.width() * computedTilesArea.height();
229 bool TiledTexture::draw()
232 TilesManager::instance()->getTilesTracker()->trackLayer();
235 if (m_area.width() == 0 || m_area.height() == 0)
239 TilesManager::instance()->getTilesTracker()->trackVisibleLayer();
242 float m_invScale = 1 / m_scale;
243 const float tileWidth = TilesManager::layerTileWidth() * m_invScale;
244 const float tileHeight = TilesManager::layerTileHeight() * m_invScale;
246 bool askRedraw = false;
247 for (unsigned int i = 0; i < m_tiles.size(); i++) {
248 BaseTile* tile = m_tiles[i];
250 if (tile->isTileVisible(m_area)) {
251 askRedraw |= !tile->isTileReady();
253 rect.fLeft = tile->x() * tileWidth;
254 rect.fTop = tile->y() * tileHeight;
255 rect.fRight = rect.fLeft + tileWidth;
256 rect.fBottom = rect.fTop + tileHeight;
257 XLOG(" - [%d], { painter %x vs %x }, tile %x %d,%d at scale %.2f vs %.2f [ready: %d] dirty: %d",
258 i, this, tile->painter(), tile, tile->x(), tile->y(),
259 tile->scale(), m_scale, tile->isTileReady(), tile->isDirty());
260 tile->draw(m_surface->opacity(), rect, m_scale);
262 TilesManager::instance()->getTilesTracker()->track(tile->isTileReady(), tile->backTexture());
267 // need to redraw if some visible tile wasn't ready
271 bool TiledTexture::paint(BaseTile* tile, SkCanvas* canvas, unsigned int* pictureUsed)
273 return m_updateManager.paint(tile, canvas, pictureUsed);
276 const TransformationMatrix* TiledTexture::transform()
278 return m_surface->transform();
281 void TiledTexture::removeTiles()
283 for (unsigned int i = 0; i < m_tiles.size(); i++) {
289 void TiledTexture::discardTextures()
291 for (unsigned int i = 0; i < m_tiles.size(); i++)
292 m_tiles[i]->discardTextures();
295 bool TiledTexture::owns(BaseTileTexture* texture)
297 for (unsigned int i = 0; i < m_tiles.size(); i++) {
298 BaseTile* tile = m_tiles[i];
299 if (tile->frontTexture() == texture)
301 if (tile->backTexture() == texture)
307 DualTiledTexture::DualTiledTexture(PaintedSurface* surface)
309 m_textureA = new TiledTexture(surface);
310 m_textureB = new TiledTexture(surface);
311 m_frontTexture = m_textureA;
312 m_backTexture = m_textureB;
318 DualTiledTexture::~DualTiledTexture()
324 void DualTiledTexture::prepare(GLWebViewState* state, float scale, bool repaint,
325 bool startFastSwap, IntRect& visibleArea)
327 // If we are zooming, we will use the previously used area, to prevent the
328 // frontTexture to try to allocate more tiles than what it has already
330 m_preZoomVisibleArea = visibleArea;
332 if (m_futureScale != scale) {
333 m_futureScale = scale;
334 m_zoomUpdateTime = WTF::currentTime() + DualTiledTexture::s_zoomUpdateDelay;
338 XLOG("\n*** %x Drawing with scale %.2f, futureScale: %.2f, zooming: %d",
339 this, scale, m_futureScale, m_zooming);
342 m_frontTexture->prepare(state, m_scale, repaint, startFastSwap, m_preZoomVisibleArea);
344 // If we had a scheduled update
345 if (m_zooming && m_zoomUpdateTime < WTF::currentTime()) {
346 m_backTexture->prepare(state, m_futureScale, repaint, startFastSwap, visibleArea);
347 if (m_backTexture->ready()) {
354 void DualTiledTexture::swap()
356 m_frontTexture = m_frontTexture == m_textureA ? m_textureB : m_textureA;
357 m_backTexture = m_backTexture == m_textureA ? m_textureB : m_textureA;
358 m_scale = m_futureScale;
359 m_backTexture->discardTextures();
362 bool DualTiledTexture::draw()
364 bool needsRepaint = m_frontTexture->draw();
365 needsRepaint |= m_zooming;
366 needsRepaint |= (m_scale <= 0);
370 void DualTiledTexture::update(const SkRegion& dirtyArea, SkPicture* picture)
372 m_backTexture->update(dirtyArea, picture);
373 m_frontTexture->update(dirtyArea, picture);
376 bool DualTiledTexture::owns(BaseTileTexture* texture)
378 bool owns = m_textureA->owns(texture);
379 owns |= m_textureB->owns(texture);
383 } // namespace WebCore