OSDN Git Service

Merge "Content and viewport rects set in one step." into ics-mr1
[android-x86/external-webkit.git] / Source / WebCore / platform / graphics / android / TiledTexture.cpp
1 /*
2  * Copyright 2011, The Android Open Source Project
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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.
24  */
25
26 #include "config.h"
27 #include "TiledTexture.h"
28
29 #include "TilesManager.h"
30 #include "TilesTracker.h"
31
32 #include "PaintedSurface.h"
33 #include "PaintTileOperation.h"
34 #include "SkCanvas.h"
35 #include "SkPicture.h"
36
37 #include <cutils/log.h>
38 #include <wtf/CurrentTime.h>
39 #include <wtf/text/CString.h>
40
41 #undef XLOGC
42 #define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "TiledTexture", __VA_ARGS__)
43
44 #ifdef DEBUG
45
46 #undef XLOG
47 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "TiledTexture", __VA_ARGS__)
48
49 #else
50
51 #undef XLOG
52 #define XLOG(...)
53
54 #endif // DEBUG
55
56 namespace WebCore {
57
58 TiledTexture::~TiledTexture()
59 {
60     SkSafeUnref(m_paintingPicture);
61 #ifdef DEBUG_COUNT
62     ClassTracker::instance()->decrement("TiledTexture");
63 #endif
64     removeTiles();
65 }
66
67 bool TiledTexture::ready()
68 {
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)) {
74             tilesVisible = true;
75             if (!tile->isTileReady()) {
76                 tilesAllReady = false;
77                 break;
78             }
79         }
80     }
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());
88
89     return !TilesManager::instance()->layerTexturesRemain()
90             || !tilesVisible || tilesAllReady;
91 }
92
93 void TiledTexture::swapTiles()
94 {
95     int swaps = 0;
96     for (unsigned int i = 0; i < m_tiles.size(); i++)
97         if (m_tiles[i]->swapTexturesIfNeeded())
98             swaps++;
99     XLOG("TT %p swapping, swaps = %d", this, swaps);
100 }
101
102 IntRect TiledTexture::computeTilesArea(IntRect& visibleArea, float scale)
103 {
104     IntRect computedArea;
105     IntRect area(visibleArea.x() * scale,
106                  visibleArea.y() * scale,
107                  ceilf(visibleArea.width() * scale),
108                  ceilf(visibleArea.height() * scale));
109
110     XLOG("TT %p prepare, scale %f, area %d x %d", this, scale, area.width(), area.height());
111
112     if (area.width() == 0 && area.height() == 0) {
113         computedArea.setWidth(0);
114         computedArea.setHeight(0);
115         return computedArea;
116     }
117
118     int tileWidth = TilesManager::instance()->layerTileWidth();
119     int tileHeight = TilesManager::instance()->layerTileHeight();
120
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());
127     return computedArea;
128 }
129
130 void TiledTexture::prepare(GLWebViewState* state, float scale, bool repaint,
131                            bool startFastSwap, IntRect& visibleArea)
132 {
133     if (!m_surface)
134         return;
135
136     // first, how many tiles do we need
137     m_area = computeTilesArea(visibleArea, scale);
138     if (m_area.isEmpty())
139         return;
140
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",
143          this, scale,
144          visibleArea.x(), visibleArea.y(),
145          visibleArea.width(), visibleArea.height(),
146          m_area.x(), m_area.y(),
147          m_area.width(), m_area.height());
148
149     bool goingDown = m_prevTileY < m_area.y();
150     m_prevTileY = m_area.y();
151
152     if (scale != m_scale)
153         TilesManager::instance()->removeOperationsForFilter(new ScaleFilter(this, scale));
154
155     m_scale = scale;
156
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);
162         }
163     }
164     m_dirtyRegion.setEmpty();
165
166     for (int i = 0; i < m_area.width(); i++) {
167         if (goingDown) {
168             for (int j = 0; j < m_area.height(); j++) {
169                 prepareTile(repaint, m_area.x() + i, m_area.y() + j);
170             }
171         } else {
172             for (int j = m_area.height() - 1; j >= 0; j--) {
173                 prepareTile(repaint, m_area.x() + i, m_area.y() + j);
174             }
175         }
176     }
177 }
178
179 void TiledTexture::update(const SkRegion& invalRegion, SkPicture* picture)
180 {
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);
184
185     android::Mutex::Autolock lock(m_paintingPictureSync);
186     SkSafeRef(picture);
187     SkSafeUnref(m_paintingPicture);
188     m_paintingPicture = picture;
189 }
190
191 void TiledTexture::prepareTile(bool repaint, int x, int y)
192 {
193     BaseTile* tile = getTile(x, y);
194     if (!tile) {
195         tile = new BaseTile(true);
196         m_tiles.append(tile);
197     }
198
199     XLOG("preparing tile %p at %d, %d, painter is this %p", tile, x, y, this);
200     tile->setContents(this, x, y, m_scale);
201
202     // TODO: move below (which is largely the same for layers / tiled page) into
203     // prepare() function
204
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);
211     }
212 }
213
214 BaseTile* TiledTexture::getTile(int x, int y)
215 {
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)
219             return tile;
220     }
221     return 0;
222 }
223
224 int TiledTexture::nbTextures(IntRect& area, float scale)
225 {
226     IntRect computedTilesArea = computeTilesArea(area, scale);
227     return computedTilesArea.width() * computedTilesArea.height();
228 }
229
230 bool TiledTexture::draw()
231 {
232     XLOG("TT %p draw", this);
233
234 #ifdef DEBUG
235     TilesManager::instance()->getTilesTracker()->trackLayer();
236 #endif
237
238     if (m_area.width() == 0 || m_area.height() == 0)
239         return false;
240
241 #ifdef DEBUG
242     TilesManager::instance()->getTilesTracker()->trackVisibleLayer();
243 #endif
244
245     float m_invScale = 1 / m_scale;
246     const float tileWidth = TilesManager::layerTileWidth() * m_invScale;
247     const float tileHeight = TilesManager::layerTileHeight() * m_invScale;
248
249     bool askRedraw = false;
250     for (unsigned int i = 0; i < m_tiles.size(); i++) {
251         BaseTile* tile = m_tiles[i];
252
253         if (tile->isTileVisible(m_area)) {
254             askRedraw |= !tile->isTileReady();
255             SkRect rect;
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);
264 #ifdef DEBUG
265             TilesManager::instance()->getTilesTracker()->track(tile->isTileReady(), tile->backTexture());
266 #endif
267         }
268     }
269
270     // need to redraw if some visible tile wasn't ready
271     return askRedraw;
272 }
273
274 bool TiledTexture::paint(BaseTile* tile, SkCanvas* canvas, unsigned int* pictureUsed)
275 {
276     m_paintingPictureSync.lock();
277     SkPicture* picture = m_paintingPicture;
278     SkSafeRef(picture);
279     m_paintingPictureSync.unlock();
280
281     if (!picture) {
282         XLOG("TT %p COULDNT PAINT, NO PICTURE", this);
283         return false;
284     }
285
286     XLOG("TT %p painting with picture %p", this, picture);
287
288     canvas->drawPicture(*picture);
289
290     SkSafeUnref(picture);
291
292     return true;
293 }
294
295 const TransformationMatrix* TiledTexture::transform()
296 {
297     return m_surface->transform();
298 }
299
300 void TiledTexture::removeTiles()
301 {
302     for (unsigned int i = 0; i < m_tiles.size(); i++) {
303         delete m_tiles[i];
304     }
305     m_tiles.clear();
306 }
307
308 void TiledTexture::discardTextures()
309 {
310     for (unsigned int i = 0; i < m_tiles.size(); i++)
311         m_tiles[i]->discardTextures();
312 }
313
314 bool TiledTexture::owns(BaseTileTexture* texture)
315 {
316     for (unsigned int i = 0; i < m_tiles.size(); i++) {
317         BaseTile* tile = m_tiles[i];
318         if (tile->frontTexture() == texture)
319             return true;
320         if (tile->backTexture() == texture)
321             return true;
322     }
323     return false;
324 }
325
326 DualTiledTexture::DualTiledTexture(PaintedSurface* surface)
327 {
328     m_textureA = new TiledTexture(surface);
329     m_textureB = new TiledTexture(surface);
330     m_frontTexture = m_textureA;
331     m_backTexture = m_textureB;
332     m_scale = -1;
333     m_futureScale = -1;
334     m_zooming = false;
335 }
336
337 DualTiledTexture::~DualTiledTexture()
338 {
339     delete m_textureA;
340     delete m_textureB;
341 }
342
343 void DualTiledTexture::prepare(GLWebViewState* state, float scale, bool repaint,
344                                bool startFastSwap, IntRect& visibleArea)
345 {
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
348     if (!m_zooming)
349         m_preZoomVisibleArea = visibleArea;
350
351     if (m_futureScale != scale) {
352         m_futureScale = scale;
353         m_zoomUpdateTime = WTF::currentTime() + DualTiledTexture::s_zoomUpdateDelay;
354         m_zooming = true;
355     }
356
357     XLOG("Preparing DTT %p with scale %.2f, m_scale %.2f, futureScale: %.2f, zooming: %d",
358           this, scale, m_scale, m_futureScale, m_zooming);
359
360     if (m_scale > 0)
361         m_frontTexture->prepare(state, m_scale, repaint, startFastSwap, m_preZoomVisibleArea);
362
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()) {
367             swap();
368             m_zooming = false;
369         }
370     }
371 }
372
373 void DualTiledTexture::swap()
374 {
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();
379 }
380
381 bool DualTiledTexture::draw()
382 {
383     bool needsRepaint = m_frontTexture->draw();
384     needsRepaint |= m_zooming;
385     needsRepaint |= (m_scale <= 0);
386     return needsRepaint;
387 }
388
389 void DualTiledTexture::update(const SkRegion& dirtyArea, SkPicture* picture)
390 {
391     m_backTexture->update(dirtyArea, picture);
392     m_frontTexture->update(dirtyArea, picture);
393 }
394
395 void DualTiledTexture::swapTiles()
396 {
397     m_backTexture->swapTiles();
398     m_frontTexture->swapTiles();
399 }
400
401 bool DualTiledTexture::owns(BaseTileTexture* texture)
402 {
403     bool owns = m_textureA->owns(texture);
404     owns |= m_textureB->owns(texture);
405     return owns;
406 }
407
408 } // namespace WebCore