OSDN Git Service

Merge "Fix the poster issue and full screen behavior html5 video"
[android-x86/external-webkit.git] / Source / WebCore / platform / graphics / android / TiledPage.cpp
1 /*
2  * Copyright 2010, 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 "TiledPage.h"
28
29 #if USE(ACCELERATED_COMPOSITING)
30
31 #include "GLUtils.h"
32 #include "IntRect.h"
33 #include "PaintTileOperation.h"
34 #include "TilesManager.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, "TiledPage", __VA_ARGS__)
42
43 #ifdef DEBUG
44
45 #undef XLOG
46 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "TiledPage", __VA_ARGS__)
47
48 #else
49
50 #undef XLOG
51 #define XLOG(...)
52
53 #endif // DEBUG
54
55 namespace WebCore {
56
57 using namespace android;
58
59 TiledPage::TiledPage(int id, GLWebViewState* state)
60     : m_baseTiles(0)
61     , m_baseTileSize(0)
62     , m_id(id)
63     , m_scale(1)
64     , m_invScale(1)
65     , m_glWebViewState(state)
66     , m_latestPictureInval(0)
67     , m_prepare(false)
68 {
69     m_baseTiles = new BaseTile[TilesManager::getMaxTextureAllocation() + 1];
70 #ifdef DEBUG_COUNT
71     ClassTracker::instance()->increment("TiledPage");
72 #endif
73 }
74
75 void TiledPage::updateBaseTileSize()
76 {
77     // This value must be at least 1 greater than the max number of allowed
78     // textures. This is because prepare() asks for a tile before it reserves
79     // a texture for that tile. If all textures are currently in use by the
80     // page then there will be no available tile and having the extra tile
81     // ensures that this does not happen. After claiming the extra tile the call
82     // to reserveTexture() will cause some other tile in the page to lose it's
83     // texture and become available, thus ensuring that we always have at least
84     // one tile that is available.
85     int baseTileSize = TilesManager::instance()->maxTextureCount() + 1;
86     if (baseTileSize > m_baseTileSize)
87         m_baseTileSize = baseTileSize;
88 }
89
90 TiledPage::~TiledPage()
91 {
92     // In order to delete the page we must ensure that none of its BaseTiles are
93     // currently painting or scheduled to be painted by the TextureGenerator
94     TilesManager::instance()->removeOperationsForPage(this);
95     delete[] m_baseTiles;
96 #ifdef DEBUG_COUNT
97     ClassTracker::instance()->decrement("TiledPage");
98 #endif
99 }
100
101 BaseTile* TiledPage::getBaseTile(int x, int y) const
102 {
103     // TODO: replace loop over array with HashMap indexing
104     for (int j = 0; j < m_baseTileSize; j++) {
105         BaseTile& tile = m_baseTiles[j];
106         if (tile.x() == x && tile.y() == y)
107             return &tile;
108     }
109     return 0;
110 }
111
112 void TiledPage::discardTextures()
113 {
114     for (int j = 0; j < m_baseTileSize; j++) {
115         BaseTile& tile = m_baseTiles[j];
116         tile.discardTextures();
117     }
118     return;
119 }
120
121 void TiledPage::invalidateRect(const IntRect& inval, const unsigned int pictureCount)
122 {
123     // Given the current scale level we need to mark the appropriate tiles as dirty
124     const float invTileContentWidth = m_scale / TilesManager::tileWidth();
125     const float invTileContentHeight = m_scale / TilesManager::tileHeight();
126
127     const int firstDirtyTileX = static_cast<int>(floorf(inval.x() * invTileContentWidth));
128     const int firstDirtyTileY = static_cast<int>(floorf(inval.y() * invTileContentHeight));
129     const int lastDirtyTileX = static_cast<int>(ceilf(inval.maxX() * invTileContentWidth));
130     const int lastDirtyTileY = static_cast<int>(ceilf(inval.maxY() * invTileContentHeight));
131
132     XLOG("Marking X %d-%d and Y %d-%d dirty", firstDirtyTileX, lastDirtyTileX, firstDirtyTileY, lastDirtyTileY);
133     // We defer marking the tile as dirty until the next time we need to prepare
134     // to draw.
135     m_invalRegion.op(firstDirtyTileX, firstDirtyTileY, lastDirtyTileX, lastDirtyTileY, SkRegion::kUnion_Op);
136     m_invalTilesRegion.op(inval.x(), inval.y(), inval.maxX(), inval.maxY(), SkRegion::kUnion_Op);
137     m_latestPictureInval = pictureCount;
138 }
139
140 void TiledPage::prepareRow(bool goingLeft, int tilesInRow, int firstTileX, int y, const SkIRect& tileBounds)
141 {
142     if (y < 0)
143         return;
144
145     for (int i = 0; i < tilesInRow; i++) {
146         int x = firstTileX;
147
148         // If we are goingLeft, we want to schedule the tiles starting from the
149         // right (and to the left if not). This is because tiles are appended to
150         // the list and the texture uploader goes through the set front to back.
151         if (goingLeft)
152             x += (tilesInRow - 1) - i;
153         else
154             x += i;
155
156         if (x < 0)
157             continue;
158
159         BaseTile* currentTile = 0;
160         BaseTile* availableTile = 0;
161         for (int j = 0; j < m_baseTileSize; j++) {
162             BaseTile& tile = m_baseTiles[j];
163             if (tile.x() == x && tile.y() == y) {
164                 currentTile = &tile;
165                 break;
166             }
167
168             if (!availableTile || (tile.drawCount() < availableTile->drawCount()))
169                 availableTile = &tile;
170         }
171
172         if (!currentTile && availableTile) {
173             XLOG("STEALING tile %d, %d (draw count %llu) for tile %d, %d",
174                   availableTile->x(), availableTile->y(), availableTile->drawCount(), x, y);
175             currentTile = availableTile;
176         }
177
178         if (!currentTile) {
179             XLOG("ERROR: No tile available for tile %d %d", x, y);
180         }
181
182         if (currentTile) {
183             currentTile->setGLWebViewState(m_glWebViewState);
184             currentTile->setPage(this);
185
186             currentTile->setContents(this, x, y, m_scale);
187
188             // TODO: move below (which is largely the same for layers / tiled
189             // page) into prepare() function
190
191             // ensure there is a texture associated with the tile and then check to
192             // see if the texture is dirty and in need of repainting
193             if (currentTile->isDirty() || !currentTile->frontTexture())
194                 currentTile->reserveTexture();
195             if (currentTile->backTexture()
196                     && currentTile->isDirty()
197                     && !currentTile->isRepaintPending()) {
198                 PaintTileOperation *operation = new PaintTileOperation(currentTile);
199                 TilesManager::instance()->scheduleOperation(operation);
200             }
201         }
202     }
203 }
204
205 bool TiledPage::updateTileDirtiness(const SkIRect& tileBounds)
206 {
207     if (!m_glWebViewState || tileBounds.isEmpty()) {
208         m_invalRegion.setEmpty();
209         m_invalTilesRegion.setEmpty();
210         return false;
211     }
212
213     bool visibleTileIsDirty = false;
214     for (int x = 0; x < m_baseTileSize; x++) {
215
216         BaseTile& tile = m_baseTiles[x];
217
218         // if the tile is in the dirty region then we must invalidate it
219         if (m_invalRegion.contains(tile.x(), tile.y())) {
220             tile.markAsDirty(m_latestPictureInval, m_invalTilesRegion);
221             if (tileBounds.contains(tile.x(), tile.y()))
222                 visibleTileIsDirty = true;
223         }
224     }
225
226     // clear the invalidated region as all tiles within that region have now
227     // been marked as dirty.
228     m_invalRegion.setEmpty();
229     m_invalTilesRegion.setEmpty();
230     return visibleTileIsDirty;
231 }
232
233 void TiledPage::prepare(bool goingDown, bool goingLeft, const SkIRect& tileBounds, PrepareBounds bounds)
234 {
235     if (!m_glWebViewState)
236         return;
237
238     TilesManager::instance()->gatherTextures();
239     m_scrollingDown = goingDown;
240
241     int firstTileX = tileBounds.fLeft;
242     int firstTileY = tileBounds.fTop;
243     int nbTilesWidth = tileBounds.width();
244     int nbTilesHeight = tileBounds.height();
245
246     int lastTileX = tileBounds.fRight - 1;
247     int lastTileY = tileBounds.fBottom - 1;
248
249     // Expand number of tiles to allow tiles outside of viewport to be prepared for
250     // smoother scrolling.
251     int nTilesToPrepare = nbTilesWidth * nbTilesHeight;
252     int nMaxTilesPerPage = m_baseTileSize / 2;
253
254     if (bounds == ExpandedBounds) {
255         // prepare tiles outside of the visible bounds
256         int expandX = m_glWebViewState->expandedTileBoundsX();
257         int expandY = m_glWebViewState->expandedTileBoundsY();
258
259         firstTileX -= expandX;
260         lastTileX += expandX;
261         nbTilesWidth += expandX * 2;
262
263         firstTileY -= expandY;
264         lastTileY += expandY;
265         nbTilesHeight += expandY * 2;
266     }
267
268     m_expandedTileBounds.fLeft = firstTileX;
269     m_expandedTileBounds.fTop = firstTileY;
270     m_expandedTileBounds.fRight = lastTileX;
271     m_expandedTileBounds.fBottom = lastTileY;
272
273     if (nbTilesHeight * nbTilesWidth > TilesManager::getMaxTextureAllocation() + 1) {
274         XLOGC("ERROR: We don't have enough tiles for this page!"
275               " nbTilesHeight %d nbTilesWidth %d", nbTilesHeight, nbTilesWidth);
276         return;
277     }
278     for (int i = 0; i < nbTilesHeight; i++)
279         prepareRow(goingLeft, nbTilesWidth, firstTileX, firstTileY + i, tileBounds);
280
281     m_prepare = true;
282 }
283
284 bool TiledPage::swapBuffersIfReady(const SkIRect& tileBounds, float scale, SwapMethod swap)
285 {
286     if (!m_glWebViewState)
287         return false;
288
289     if (!m_invalRegion.isEmpty() && !m_prepare)
290         return false;
291
292     if (m_scale != scale)
293         return false;
294
295     int swaps = 0;
296     if (swap == SwapWholePage) {
297         for (int x = tileBounds.fLeft; x < tileBounds.fRight; x++) {
298             for (int y = tileBounds.fTop; y < tileBounds.fBottom; y++) {
299                 BaseTile* t = getBaseTile(x, y);
300                 if (!t || !t->isTileReady())
301                     return false;
302             }
303         }
304         for (int x = tileBounds.fLeft; x < tileBounds.fRight; x++) {
305             for (int y = tileBounds.fTop; y < tileBounds.fBottom; y++) {
306                 BaseTile* t = getBaseTile(x, y);
307                 if (t->swapTexturesIfNeeded())
308                     swaps++;
309             }
310         }
311         XLOG("%p whole page swapped %d textures, returning true", this, swaps);
312         return true;
313     } else { // SwapWhateveryIsReady
314         bool fullSwap = true;
315         for (int x = tileBounds.fLeft; x < tileBounds.fRight; x++) {
316             for (int y = tileBounds.fTop; y < tileBounds.fBottom; y++) {
317                 BaseTile* t = getBaseTile(x, y);
318                 if (!t || !t->isTileReady())
319                     fullSwap = false;
320                 else {
321                     if (t->swapTexturesIfNeeded())
322                         swaps++;
323                 }
324             }
325         }
326         XLOG("%p greedy swap swapped %d tiles, returning %d", this, swaps, fullSwap);
327         return fullSwap;
328     }
329 }
330
331
332 void TiledPage::draw(float transparency, const SkIRect& tileBounds)
333 {
334     if (!m_glWebViewState)
335         return;
336
337     const float tileWidth = TilesManager::tileWidth() * m_invScale;
338     const float tileHeight = TilesManager::tileHeight() * m_invScale;
339
340     SkIRect actualTileBounds = tileBounds;
341     actualTileBounds.fTop -= m_glWebViewState->expandedTileBoundsY();
342     actualTileBounds.fBottom += m_glWebViewState->expandedTileBoundsY();
343     actualTileBounds.fLeft -= m_glWebViewState->expandedTileBoundsX();
344     actualTileBounds.fRight += m_glWebViewState->expandedTileBoundsX();
345
346     actualTileBounds.fTop = std::max(0, actualTileBounds.fTop);
347     actualTileBounds.fLeft = std::max(0, actualTileBounds.fLeft);
348
349     for (int j = 0; j < m_baseTileSize; j++) {
350         BaseTile& tile = m_baseTiles[j];
351         bool tileInView = actualTileBounds.contains(tile.x(), tile.y());
352         if (tileInView) {
353             SkRect rect;
354             rect.fLeft = tile.x() * tileWidth;
355             rect.fTop = tile.y() * tileHeight;
356             rect.fRight = rect.fLeft + tileWidth;
357             rect.fBottom = rect.fTop + tileHeight;
358
359             tile.draw(transparency, rect, m_scale);
360         }
361
362         TilesManager::instance()->getProfiler()->nextTile(tile, m_invScale, tileInView);
363     }
364 }
365
366 bool TiledPage::paint(BaseTile* tile, SkCanvas* canvas, unsigned int* pictureUsed)
367 {
368     if (!m_glWebViewState)
369         return false;
370
371     *pictureUsed = m_glWebViewState->paintBaseLayerContent(canvas);
372     return true;
373 }
374
375 void TiledPage::paintExtra(SkCanvas* canvas)
376 {
377 }
378
379 TiledPage* TiledPage::sibling()
380 {
381     if (!m_glWebViewState)
382         return 0;
383     return m_glWebViewState->sibling(this);
384 }
385
386 } // namespace WebCore
387
388 #endif // USE(ACCELERATED_COMPOSITING)