OSDN Git Service

Merge "Fix combobox metrics and asset scaling" 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
36 #include <cutils/log.h>
37 #include <wtf/CurrentTime.h>
38 #include <wtf/text/CString.h>
39
40 #undef XLOGC
41 #define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "TiledTexture", __VA_ARGS__)
42
43 #ifdef DEBUG
44
45 #undef XLOG
46 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "TiledTexture", __VA_ARGS__)
47
48 #else
49
50 #undef XLOG
51 #define XLOG(...)
52
53 #endif // DEBUG
54
55 namespace WebCore {
56
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)) {
63             tilesVisible = true;
64             if (!tile->isTileReady()) {
65                 tilesAllReady = false;
66                 break;
67             }
68         }
69     }
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;
76 }
77
78 IntRect TiledTexture::computeTilesArea(IntRect& visibleArea, float scale)
79 {
80     IntRect computedArea;
81     IntRect area(visibleArea.x() * scale,
82                  visibleArea.y() * scale,
83                  ceilf(visibleArea.width() * scale),
84                  ceilf(visibleArea.height() * scale));
85
86     if (area.width() == 0 && area.height() == 0) {
87         computedArea.setWidth(0);
88         computedArea.setHeight(0);
89         return computedArea;
90     }
91
92     int tileWidth = TilesManager::instance()->layerTileWidth();
93     int tileHeight = TilesManager::instance()->layerTileHeight();
94
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());
101     return computedArea;
102 }
103
104 void TiledTexture::prepare(GLWebViewState* state, float scale, bool repaint,
105                            bool startFastSwap, IntRect& area)
106 {
107     if (!m_surface)
108         return;
109
110     if (!m_surface->layer())
111         return;
112
113     m_area = computeTilesArea(area, scale);
114     if (m_area.isEmpty())
115         return;
116
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",
119          this, scale,
120          visibleArea.x(), visibleArea.y(),
121          visibleArea.width(), visibleArea.height(),
122          m_area.x(), m_area.y(),
123          m_area.width(), m_area.height());
124
125     bool goingDown = m_prevTileY < m_area.y();
126     m_prevTileY = m_area.y();
127
128     if (scale != m_scale)
129         TilesManager::instance()->removeOperationsForFilter(new ScaleFilter(this, scale));
130
131     m_scale = scale;
132
133     // unlock if tiles all ready
134     bool tilesAllReady = ready();
135
136     // startFastSwap=true will swap all ready tiles each
137     // frame until all visible tiles are up to date
138     if (tilesAllReady)
139         m_swapWhateverIsReady = false;
140     else if (startFastSwap)
141         m_swapWhateverIsReady = true;
142
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();
148     }
149
150     if (tilesAllReady) {
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();
156     }
157
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);
163         }
164     }
165     m_dirtyRegion.setEmpty();
166
167     for (int i = 0; i < m_area.width(); i++) {
168         if (goingDown) {
169             for (int j = 0; j < m_area.height(); j++) {
170                 prepareTile(repaint, m_area.x() + i, m_area.y() + j);
171             }
172         } else {
173             for (int j = m_area.height() - 1; j >= 0; j--) {
174                 prepareTile(repaint, m_area.x() + i, m_area.y() + j);
175             }
176         }
177     }
178 }
179
180 void TiledTexture::update(const SkRegion& invalRegion, SkPicture* picture)
181 {
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);
188 }
189
190 void TiledTexture::prepareTile(bool repaint, int x, int y)
191 {
192     BaseTile* tile = getTile(x, y);
193     if (!tile) {
194         tile = new BaseTile(true);
195         m_tiles.append(tile);
196     }
197
198     XLOG("preparing tile %p, painter is this %p", tile, this);
199     tile->setContents(this, x, y, m_scale);
200
201     // TODO: move below (which is largely the same for layers / tiled page) into
202     // prepare() function
203
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);
210     }
211 }
212
213 BaseTile* TiledTexture::getTile(int x, int y)
214 {
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)
218             return tile;
219     }
220     return 0;
221 }
222
223 int TiledTexture::nbTextures(IntRect& area, float scale)
224 {
225     IntRect computedTilesArea = computeTilesArea(area, scale);
226     return computedTilesArea.width() * computedTilesArea.height();
227 }
228
229 bool TiledTexture::draw()
230 {
231 #ifdef DEBUG
232     TilesManager::instance()->getTilesTracker()->trackLayer();
233 #endif
234
235     if (m_area.width() == 0 || m_area.height() == 0)
236         return false;
237
238 #ifdef DEBUG
239     TilesManager::instance()->getTilesTracker()->trackVisibleLayer();
240 #endif
241
242     float m_invScale = 1 / m_scale;
243     const float tileWidth = TilesManager::layerTileWidth() * m_invScale;
244     const float tileHeight = TilesManager::layerTileHeight() * m_invScale;
245
246     bool askRedraw = false;
247     for (unsigned int i = 0; i < m_tiles.size(); i++) {
248         BaseTile* tile = m_tiles[i];
249
250         if (tile->isTileVisible(m_area)) {
251             askRedraw |= !tile->isTileReady();
252             SkRect rect;
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);
261 #ifdef DEBUG
262             TilesManager::instance()->getTilesTracker()->track(tile->isTileReady(), tile->backTexture());
263 #endif
264         }
265     }
266
267     // need to redraw if some visible tile wasn't ready
268     return askRedraw;
269 }
270
271 bool TiledTexture::paint(BaseTile* tile, SkCanvas* canvas, unsigned int* pictureUsed)
272 {
273     return m_updateManager.paint(tile, canvas, pictureUsed);
274 }
275
276 const TransformationMatrix* TiledTexture::transform()
277 {
278     return m_surface->transform();
279 }
280
281 void TiledTexture::removeTiles()
282 {
283     for (unsigned int i = 0; i < m_tiles.size(); i++) {
284         delete m_tiles[i];
285     }
286     m_tiles.clear();
287 }
288
289 void TiledTexture::discardTextures()
290 {
291     for (unsigned int i = 0; i < m_tiles.size(); i++)
292         m_tiles[i]->discardTextures();
293 }
294
295 bool TiledTexture::owns(BaseTileTexture* texture)
296 {
297     for (unsigned int i = 0; i < m_tiles.size(); i++) {
298         BaseTile* tile = m_tiles[i];
299         if (tile->frontTexture() == texture)
300             return true;
301         if (tile->backTexture() == texture)
302             return true;
303     }
304     return false;
305 }
306
307 DualTiledTexture::DualTiledTexture(PaintedSurface* surface)
308 {
309     m_textureA = new TiledTexture(surface);
310     m_textureB = new TiledTexture(surface);
311     m_frontTexture = m_textureA;
312     m_backTexture = m_textureB;
313     m_scale = -1;
314     m_futureScale = -1;
315     m_zooming = false;
316 }
317
318 DualTiledTexture::~DualTiledTexture()
319 {
320     delete m_textureA;
321     delete m_textureB;
322 }
323
324 void DualTiledTexture::prepare(GLWebViewState* state, float scale, bool repaint,
325                                bool startFastSwap, IntRect& visibleArea)
326 {
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
329     if (!m_zooming)
330         m_preZoomVisibleArea = visibleArea;
331
332     if (m_futureScale != scale) {
333         m_futureScale = scale;
334         m_zoomUpdateTime = WTF::currentTime() + DualTiledTexture::s_zoomUpdateDelay;
335         m_zooming = true;
336     }
337
338     XLOG("\n*** %x Drawing with scale %.2f, futureScale: %.2f, zooming: %d",
339           this, scale, m_futureScale, m_zooming);
340
341     if (m_scale > 0)
342         m_frontTexture->prepare(state, m_scale, repaint, startFastSwap, m_preZoomVisibleArea);
343
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()) {
348             swap();
349             m_zooming = false;
350         }
351     }
352 }
353
354 void DualTiledTexture::swap()
355 {
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();
360 }
361
362 bool DualTiledTexture::draw()
363 {
364     bool needsRepaint = m_frontTexture->draw();
365     needsRepaint |= m_zooming;
366     needsRepaint |= (m_scale <= 0);
367     return needsRepaint;
368 }
369
370 void DualTiledTexture::update(const SkRegion& dirtyArea, SkPicture* picture)
371 {
372     m_backTexture->update(dirtyArea, picture);
373     m_frontTexture->update(dirtyArea, picture);
374 }
375
376 bool DualTiledTexture::owns(BaseTileTexture* texture)
377 {
378     bool owns = m_textureA->owns(texture);
379     owns |= m_textureB->owns(texture);
380     return owns;
381 }
382
383 } // namespace WebCore