ab2f5becc524259d7c0b9921a12a4a5b276bd3ea
[WebKit-https.git] / Source / WebCore / platform / graphics / chromium / TiledLayerChromium.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27
28 #if USE(ACCELERATED_COMPOSITING)
29
30 #include "TiledLayerChromium.h"
31
32 #include "GraphicsContext3D.h"
33 #include "ManagedTexture.h"
34 #include "Region.h"
35 #include "TextStream.h"
36
37 #include "cc/CCLayerImpl.h"
38 #include "cc/CCLayerTreeHost.h"
39 #include "cc/CCOverdrawMetrics.h"
40 #include "cc/CCTextureUpdater.h"
41 #include "cc/CCTiledLayerImpl.h"
42
43 #include <wtf/CurrentTime.h>
44 #include <wtf/MathExtras.h>
45
46 using namespace std;
47 using WebKit::WebTransformationMatrix;
48
49 namespace WebCore {
50
51 class UpdatableTile : public CCLayerTilingData::Tile {
52     WTF_MAKE_NONCOPYABLE(UpdatableTile);
53 public:
54     static PassOwnPtr<UpdatableTile> create(PassOwnPtr<LayerTextureUpdater::Texture> texture)
55     {
56         return adoptPtr(new UpdatableTile(texture));
57     }
58
59     LayerTextureUpdater::Texture* texture() { return m_texture.get(); }
60     CCPrioritizedTexture* managedTexture() { return m_texture->texture(); }
61
62     bool isDirty() const { return !dirtyRect.isEmpty(); }
63     void copyAndClearDirty()
64     {
65         updateRect = dirtyRect;
66         dirtyRect = IntRect();
67     }
68     // Returns whether the layer was dirty and not updated in the current frame. For tiles that were not culled, the
69     // updateRect holds the area of the tile that was updated. Otherwise, the area that would have been updated.
70     bool isDirtyForCurrentFrame() { return !dirtyRect.isEmpty() && (updateRect.isEmpty() || !updated); }
71
72     IntRect dirtyRect;
73     IntRect updateRect;
74     bool partialUpdate;
75     bool updated;
76     bool isInUseOnImpl;
77 private:
78     explicit UpdatableTile(PassOwnPtr<LayerTextureUpdater::Texture> texture)
79         : partialUpdate(false)
80         , updated(false)
81         , isInUseOnImpl(false)
82         , m_texture(texture)
83     {
84     }
85
86     OwnPtr<LayerTextureUpdater::Texture> m_texture;
87 };
88
89 TiledLayerChromium::TiledLayerChromium()
90     : LayerChromium()
91     , m_textureFormat(GraphicsContext3D::INVALID_ENUM)
92     , m_skipsDraw(false)
93     , m_skipsIdlePaint(false)
94     , m_sampledTexelFormat(LayerTextureUpdater::SampledTexelFormatInvalid)
95     , m_didPaint(false)
96     , m_tilingOption(AutoTile)
97 {
98     m_tiler = CCLayerTilingData::create(IntSize(), CCLayerTilingData::HasBorderTexels);
99 }
100
101 TiledLayerChromium::~TiledLayerChromium()
102 {
103 }
104
105 PassOwnPtr<CCLayerImpl> TiledLayerChromium::createCCLayerImpl()
106 {
107     return CCTiledLayerImpl::create(id());
108 }
109
110 void TiledLayerChromium::updateTileSizeAndTilingOption()
111 {
112     ASSERT(layerTreeHost());
113
114     const IntSize& defaultTileSize = layerTreeHost()->settings().defaultTileSize;
115     const IntSize& maxUntiledLayerSize = layerTreeHost()->settings().maxUntiledLayerSize;
116     int layerWidth = contentBounds().width();
117     int layerHeight = contentBounds().height();
118
119     const IntSize tileSize(min(defaultTileSize.width(), layerWidth), min(defaultTileSize.height(), layerHeight));
120
121     // Tile if both dimensions large, or any one dimension large and the other
122     // extends into a second tile but the total layer area isn't larger than that
123     // of the largest possible untiled layer. This heuristic allows for long skinny layers
124     // (e.g. scrollbars) that are Nx1 tiles to minimize wasted texture space but still avoids
125     // creating very large tiles.
126     const bool anyDimensionLarge = layerWidth > maxUntiledLayerSize.width() || layerHeight > maxUntiledLayerSize.height();
127     const bool anyDimensionOneTile = (layerWidth <= defaultTileSize.width() || layerHeight <= defaultTileSize.height())
128                                       && (layerWidth * layerHeight) <= (maxUntiledLayerSize.width() * maxUntiledLayerSize.height());
129     const bool autoTiled = anyDimensionLarge && !anyDimensionOneTile;
130
131     bool isTiled;
132     if (m_tilingOption == AlwaysTile)
133         isTiled = true;
134     else if (m_tilingOption == NeverTile)
135         isTiled = false;
136     else
137         isTiled = autoTiled;
138
139     IntSize requestedSize = isTiled ? tileSize : contentBounds();
140     const int maxSize = layerTreeHost()->layerRendererCapabilities().maxTextureSize;
141     IntSize clampedSize = requestedSize.shrunkTo(IntSize(maxSize, maxSize));
142     setTileSize(clampedSize);
143 }
144
145 void TiledLayerChromium::updateBounds()
146 {
147     IntSize oldBounds = m_tiler->bounds();
148     IntSize newBounds = contentBounds();
149     if (oldBounds == newBounds)
150         return;
151     m_tiler->setBounds(newBounds);
152
153     // Invalidate any areas that the new bounds exposes.
154     Region oldRegion(IntRect(IntPoint(), oldBounds));
155     Region newRegion(IntRect(IntPoint(), newBounds));
156     newRegion.subtract(oldRegion);
157     Vector<IntRect> rects = newRegion.rects();
158     for (size_t i = 0; i < rects.size(); ++i)
159         invalidateRect(rects[i]);
160 }
161
162 void TiledLayerChromium::setTileSize(const IntSize& size)
163 {
164     m_tiler->setTileSize(size);
165 }
166
167 void TiledLayerChromium::setBorderTexelOption(CCLayerTilingData::BorderTexelOption borderTexelOption)
168 {
169     m_tiler->setBorderTexelOption(borderTexelOption);
170 }
171
172 bool TiledLayerChromium::drawsContent() const
173 {
174     if (!LayerChromium::drawsContent())
175         return false;
176
177     bool hasMoreThanOneTile = m_tiler->numTilesX() > 1 || m_tiler->numTilesY() > 1;
178     if (m_tilingOption == NeverTile && hasMoreThanOneTile)
179         return false;
180
181     return true;
182 }
183
184 bool TiledLayerChromium::needsContentsScale() const
185 {
186     return true;
187 }
188
189 IntSize TiledLayerChromium::contentBounds() const
190 {
191     return IntSize(lroundf(bounds().width() * contentsScale()), lroundf(bounds().height() * contentsScale()));
192 }
193
194 void TiledLayerChromium::setTilingOption(TilingOption tilingOption)
195 {
196     m_tilingOption = tilingOption;
197 }
198
199 void TiledLayerChromium::setIsMask(bool isMask)
200 {
201     setTilingOption(isMask ? NeverTile : AutoTile);
202 }
203
204 void TiledLayerChromium::pushPropertiesTo(CCLayerImpl* layer)
205 {
206     LayerChromium::pushPropertiesTo(layer);
207
208     CCTiledLayerImpl* tiledLayer = static_cast<CCTiledLayerImpl*>(layer);
209
210     tiledLayer->setSkipsDraw(m_skipsDraw);
211     tiledLayer->setContentsSwizzled(m_sampledTexelFormat != LayerTextureUpdater::SampledTexelFormatRGBA);
212     tiledLayer->setTilingData(*m_tiler);
213     Vector<UpdatableTile*> invalidTiles;
214
215     for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) {
216         int i = iter->first.first;
217         int j = iter->first.second;
218         UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
219         // FIXME: This should not ever be null.
220         if (!tile)
221             continue;
222         tile->isInUseOnImpl = false;
223         if (!tile->managedTexture()->haveBackingTexture()) {
224             invalidTiles.append(tile);
225             continue;
226         }
227         if (tile->isDirtyForCurrentFrame())
228             continue;
229
230         tiledLayer->pushTileProperties(i, j, tile->managedTexture()->textureId(), tile->opaqueRect());
231         tile->isInUseOnImpl = true;
232     }
233     for (Vector<UpdatableTile*>::const_iterator iter = invalidTiles.begin(); iter != invalidTiles.end(); ++iter)
234         m_tiler->takeTile((*iter)->i(), (*iter)->j());
235 }
236
237 CCPrioritizedTextureManager* TiledLayerChromium::textureManager() const
238 {
239     if (!layerTreeHost())
240         return 0;
241     return layerTreeHost()->contentsTextureManager();
242 }
243
244 void TiledLayerChromium::setLayerTreeHost(CCLayerTreeHost* host)
245 {
246     if (host && host != layerTreeHost()) {
247         for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) {
248             UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
249             // FIXME: This should not ever be null.
250             if (!tile)
251                 continue;
252             tile->managedTexture()->setTextureManager(host->contentsTextureManager());
253         }
254     }
255     LayerChromium::setLayerTreeHost(host);
256 }
257
258 UpdatableTile* TiledLayerChromium::tileAt(int i, int j) const
259 {
260     return static_cast<UpdatableTile*>(m_tiler->tileAt(i, j));
261 }
262
263 UpdatableTile* TiledLayerChromium::createTile(int i, int j)
264 {
265     createTextureUpdaterIfNeeded();
266
267     OwnPtr<UpdatableTile> tile(UpdatableTile::create(textureUpdater()->createTexture(textureManager())));
268     tile->managedTexture()->setDimensions(m_tiler->tileSize(), m_textureFormat);
269
270     UpdatableTile* addedTile = tile.get();
271     m_tiler->addTile(tile.release(), i, j);
272
273     addedTile->dirtyRect = m_tiler->tileRect(addedTile);
274
275     // Temporary diagnostic crash.
276     if (!addedTile)
277         CRASH();
278     if (!tileAt(i, j))
279         CRASH();
280
281     return addedTile;
282 }
283
284 void TiledLayerChromium::setNeedsDisplayRect(const FloatRect& dirtyRect)
285 {
286     float contentsWidthScale = static_cast<float>(contentBounds().width()) / bounds().width();
287     float contentsHeightScale = static_cast<float>(contentBounds().height()) / bounds().height();
288     FloatRect scaledDirtyRect(dirtyRect);
289     scaledDirtyRect.scale(contentsWidthScale, contentsHeightScale);
290     IntRect dirty = enclosingIntRect(scaledDirtyRect);
291     invalidateRect(dirty);
292     LayerChromium::setNeedsDisplayRect(dirtyRect);
293 }
294
295 void TiledLayerChromium::setIsNonCompositedContent(bool isNonCompositedContent)
296 {
297     LayerChromium::setIsNonCompositedContent(isNonCompositedContent);
298
299     CCLayerTilingData::BorderTexelOption borderTexelOption;
300 #if OS(ANDROID)
301     // Always want border texels and GL_LINEAR due to pinch zoom.
302     borderTexelOption = CCLayerTilingData::HasBorderTexels;
303 #else
304     borderTexelOption = isNonCompositedContent ? CCLayerTilingData::NoBorderTexels : CCLayerTilingData::HasBorderTexels;
305 #endif
306     setBorderTexelOption(borderTexelOption);
307 }
308
309 void TiledLayerChromium::invalidateRect(const IntRect& layerRect)
310 {
311     updateBounds();
312     if (m_tiler->isEmpty() || layerRect.isEmpty() || m_skipsDraw)
313         return;
314
315     for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) {
316         UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
317         ASSERT(tile);
318         // FIXME: This should not ever be null.
319         if (!tile)
320             continue;
321         IntRect bound = m_tiler->tileRect(tile);
322         bound.intersect(layerRect);
323         tile->dirtyRect.unite(bound);
324     }
325 }
326
327 // Returns true if tile is dirty and only part of it needs to be updated.
328 bool TiledLayerChromium::tileOnlyNeedsPartialUpdate(UpdatableTile* tile)
329 {
330     return !tile->dirtyRect.contains(m_tiler->tileRect(tile));
331 }
332
333 // Dirty tiles with valid textures needs buffered update to guarantee that
334 // we don't modify textures currently used for drawing by the impl thread.
335 bool TiledLayerChromium::tileNeedsBufferedUpdate(UpdatableTile* tile)
336 {
337     if (!tile->managedTexture()->haveBackingTexture())
338         return false;
339
340     if (!tile->isDirty())
341         return false;
342
343     if (!tile->isInUseOnImpl)
344         return false;
345
346     return true;
347 }
348
349 void TiledLayerChromium::updateTiles(bool idle, int left, int top, int right, int bottom, CCTextureUpdater& updater, const CCOcclusionTracker* occlusion)
350 {
351     createTextureUpdaterIfNeeded();
352
353     // Create tiles as needed, expanding a dirty rect to contain all
354     // the dirty regions currently being drawn. All dirty tiles that are to be painted
355     // get their updateRect set to dirtyRect and dirtyRect cleared. This way if
356     // invalidateRect is invoked during updateLayerRect we don't lose the request.
357     IntRect paintRect;
358     for (int j = top; j <= bottom; ++j) {
359         for (int i = left; i <= right; ++i) {
360             UpdatableTile* tile = tileAt(i, j);
361             ASSERT(tile); // Did setTexturePriorites get skipped?
362             if (!tile)
363                 tile = createTile(i, j);
364
365             // Temporary diagnostic crash
366             if (!m_tiler)
367                 CRASH();
368
369             if (!tile->managedTexture()->haveBackingTexture()) {
370                 // Sets the dirty rect to a full-sized tile with border texels.
371                 tile->dirtyRect = m_tiler->tileRect(tile);
372             }
373
374             // When not idle painting, if the visible region of the tile is occluded, don't reserve a texture or update the tile.
375             // If any part of the tile is visible, then we need to update it so the tile is pushed to the impl thread.
376             if (!idle && occlusion) {
377                 IntRect visibleTileRect = intersection(m_tiler->tileBounds(i, j), visibleLayerRect());
378                 if (occlusion->occluded(this, visibleTileRect)) {
379                     ASSERT(!tile->updated);
380                     continue;
381                 }
382             }
383
384             // We come through this function multiple times during a commit, and updated should be true if the tile is not culled
385             // any single time through the function.
386             tile->updated = true;
387
388             // Always try to get memory for visible textures.
389             if (!idle && !tile->managedTexture()->canAcquireBackingTexture())
390                 tile->managedTexture()->requestLate();
391
392             if (!tile->managedTexture()->canAcquireBackingTexture()) {
393                 m_skipsIdlePaint = true;
394                 if (!idle) {
395                     m_skipsDraw = true;
396                     m_tiler->reset();
397                 }
398                 return;
399             }
400
401             paintRect.unite(tile->dirtyRect);
402         }
403     }
404
405     // For tiles that were not culled, we are going to update the area currently marked as dirty. So
406     // clear that dirty area and mark it for update instead.
407     for (int j = top; j <= bottom; ++j) {
408         for (int i = left; i <= right; ++i) {
409             UpdatableTile* tile = tileAt(i, j);
410             // FIXME: This should not ever be null.
411             if (!tile)
412                 continue;
413             if (tile->updated)
414                 tile->copyAndClearDirty();
415             else if (!idle && occlusion && tile->isDirty())
416                 occlusion->overdrawMetrics().didCullTileForUpload();
417         }
418     }
419
420     if (paintRect.isEmpty())
421         return;
422
423     if (occlusion)
424         occlusion->overdrawMetrics().didPaint(paintRect);
425
426     // The updateRect should be in layer space. So we have to convert the paintRect from content space to layer space.
427     m_updateRect = FloatRect(paintRect);
428     float widthScale = bounds().width() / static_cast<float>(contentBounds().width());
429     float heightScale = bounds().height() / static_cast<float>(contentBounds().height());
430     m_updateRect.scale(widthScale, heightScale);
431
432     // Calling prepareToUpdate() calls into WebKit to paint, which may have the side
433     // effect of disabling compositing, which causes our reference to the texture updater to be deleted.
434     // However, we can't free the memory backing the SkCanvas until the paint finishes,
435     // so we grab a local reference here to hold the updater alive until the paint completes.
436     RefPtr<LayerTextureUpdater> protector(textureUpdater());
437     IntRect paintedOpaqueRect;
438     textureUpdater()->prepareToUpdate(paintRect, m_tiler->tileSize(), 1 / widthScale, 1 / heightScale, paintedOpaqueRect);
439     m_didPaint = true;
440
441     for (int j = top; j <= bottom; ++j) {
442         for (int i = left; i <= right; ++i) {
443             UpdatableTile* tile = tileAt(i, j);
444             // FIXME: This should not ever be null.
445             if (!tile)
446                 continue;
447
448             IntRect tileRect = m_tiler->tileBounds(i, j);
449
450             if (!tile->updated)
451                 continue;
452
453             // Use updateRect as the above loop copied the dirty rect for this frame to updateRect.
454             const IntRect& dirtyRect = tile->updateRect;
455             if (dirtyRect.isEmpty())
456                 continue;
457
458             // Save what was painted opaque in the tile. Keep the old area if the paint didn't touch it, and didn't paint some
459             // other part of the tile opaque.
460             IntRect tilePaintedRect = intersection(tileRect, paintRect);
461             IntRect tilePaintedOpaqueRect = intersection(tileRect, paintedOpaqueRect);
462             if (!tilePaintedRect.isEmpty()) {
463                 IntRect paintInsideTileOpaqueRect = intersection(tile->opaqueRect(), tilePaintedRect);
464                 bool paintInsideTileOpaqueRectIsNonOpaque = !tilePaintedOpaqueRect.contains(paintInsideTileOpaqueRect);
465                 bool opaquePaintNotInsideTileOpaqueRect = !tilePaintedOpaqueRect.isEmpty() && !tile->opaqueRect().contains(tilePaintedOpaqueRect);
466
467                 if (paintInsideTileOpaqueRectIsNonOpaque || opaquePaintNotInsideTileOpaqueRect)
468                     tile->setOpaqueRect(tilePaintedOpaqueRect);
469             }
470
471             // sourceRect starts as a full-sized tile with border texels included.
472             IntRect sourceRect = m_tiler->tileRect(tile);
473             sourceRect.intersect(dirtyRect);
474             // Paint rect not guaranteed to line up on tile boundaries, so
475             // make sure that sourceRect doesn't extend outside of it.
476             sourceRect.intersect(paintRect);
477
478             tile->updateRect = sourceRect;
479
480             if (sourceRect.isEmpty())
481                 continue;
482
483             tile->texture()->prepareRect(sourceRect);
484             if (occlusion)
485                 occlusion->overdrawMetrics().didUpload(WebTransformationMatrix(), sourceRect, tile->opaqueRect());
486
487             const IntPoint anchor = m_tiler->tileRect(tile).location();
488
489             // Calculate tile-space rectangle to upload into.
490             IntRect destRect(IntPoint(sourceRect.x() - anchor.x(), sourceRect.y() - anchor.y()), sourceRect.size());
491             if (destRect.x() < 0)
492                 CRASH();
493             if (destRect.y() < 0)
494                 CRASH();
495
496             // Offset from paint rectangle to this tile's dirty rectangle.
497             IntPoint paintOffset(sourceRect.x() - paintRect.x(), sourceRect.y() - paintRect.y());
498             if (paintOffset.x() < 0)
499                 CRASH();
500             if (paintOffset.y() < 0)
501                 CRASH();
502             if (paintOffset.x() + destRect.width() > paintRect.width())
503                 CRASH();
504             if (paintOffset.y() + destRect.height() > paintRect.height())
505                 CRASH();
506
507             if (tile->partialUpdate)
508                 updater.appendPartialUpdate(tile->texture(), sourceRect, destRect);
509             else
510                 updater.appendUpdate(tile->texture(), sourceRect, destRect);
511         }
512     }
513 }
514
515 void TiledLayerChromium::setTexturePriorities(const CCPriorityCalculator& priorityCalc)
516 {
517     setTexturePrioritiesInRect(priorityCalc, visibleLayerRect());
518 }
519
520 void TiledLayerChromium::setTexturePrioritiesInRect(const CCPriorityCalculator& priorityCalc, const IntRect& visibleRect)
521 {
522     updateBounds();
523     resetUpdateState();
524
525     IntRect prepaintRect = idlePaintRect(visibleRect);
526
527     // Minimally create the tiles in the desired pre-paint rect.
528     if (!prepaintRect.isEmpty()) {
529         int left, top, right, bottom;
530         m_tiler->layerRectToTileIndices(prepaintRect, left, top, right, bottom);
531         for (int j = top; j <= bottom; ++j)
532             for (int i = left; i <= right; ++i)
533                 if (!tileAt(i, j))
534                     createTile(i, j);
535     }
536
537     // Create additional textures for double-buffered updates when needed.
538     // These textures must stay alive while the updated textures are incrementally
539     // uploaded, swapped atomically via pushProperties, and finally deleted
540     // after the commit is complete, after which they can be recycled.
541     if (!visibleRect.isEmpty()) {
542         int left, top, right, bottom;
543         m_tiler->layerRectToTileIndices(visibleRect, left, top, right, bottom);
544         for (int j = top; j <= bottom; ++j) {
545             for (int i = left; i <= right; ++i) {
546                 UpdatableTile* tile = tileAt(i, j);
547                 if (!tile)
548                     tile = createTile(i, j);
549                 // We need an additional texture if the tile needs a buffered-update and it's not a partial update.
550                 // FIXME: Decide if partial update should be allowed based on cost
551                 // of update. https://bugs.webkit.org/show_bug.cgi?id=77376
552                 if (!layerTreeHost() || !layerTreeHost()->bufferedUpdates() || !tileNeedsBufferedUpdate(tile))
553                     continue;
554                 if (tileOnlyNeedsPartialUpdate(tile) && layerTreeHost()->requestPartialTextureUpdate()) {
555                     tile->partialUpdate = true;
556                     continue;
557                 }
558
559                 tile->dirtyRect = m_tiler->tileRect(tile);
560                 LayerTextureUpdater::Texture* backBuffer = tile->texture();
561                 backBuffer->texture()->setRequestPriority(priorityCalc.priorityFromVisibility(true));
562                 OwnPtr<CCPrioritizedTexture> frontBuffer = CCPrioritizedTexture::create(backBuffer->texture()->textureManager(),
563                                                                                         backBuffer->texture()->size(),
564                                                                                         backBuffer->texture()->format());
565                 // Swap backBuffer into frontBuffer and add it to delete after commit queue.
566                 backBuffer->swapTextureWith(frontBuffer);
567                 layerTreeHost()->deleteTextureAfterCommit(frontBuffer.release());
568             }
569         }
570     }
571
572     // Now set priorities on all tiles.
573     for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) {
574         UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
575         IntRect tileRect = m_tiler->tileRect(tile);
576         // FIXME: This indicates the "small animated layer" case. This special case
577         // can be removed soon with better priorities, but for now paint these layers after
578         // 512 pixels of pre-painting. Later we can just pass an animating flag etc. to the
579         // calculator and it can take care of this special case if we still need it.
580         if (visibleRect.isEmpty() && !prepaintRect.isEmpty())
581             tile->managedTexture()->setRequestPriority(priorityCalc.priorityFromDistance(512));
582         else if (!visibleRect.isEmpty())
583             tile->managedTexture()->setRequestPriority(priorityCalc.priorityFromDistance(visibleRect, tileRect));
584     }
585 }
586
587 Region TiledLayerChromium::visibleContentOpaqueRegion() const
588 {
589     if (m_skipsDraw)
590         return Region();
591     if (opaque())
592         return visibleLayerRect();
593     return m_tiler->opaqueRegionInLayerRect(visibleLayerRect());
594 }
595
596 void TiledLayerChromium::resetUpdateState()
597 {
598     CCLayerTilingData::TileMap::const_iterator end = m_tiler->tiles().end();
599     for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != end; ++iter) {
600         UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
601         // FIXME: This should not ever be null.
602         if (!tile)
603             continue;
604         tile->updateRect = IntRect();
605         tile->updated = false;
606         tile->partialUpdate = false;
607     }
608 }
609
610 void TiledLayerChromium::updateLayerRect(CCTextureUpdater& updater, const IntRect& layerRect, const CCOcclusionTracker* occlusion)
611 {
612     m_skipsDraw = false;
613     m_skipsIdlePaint = false;
614     m_didPaint = false;
615
616     updateBounds();
617
618     if (layerRect.isEmpty() || m_tiler->hasEmptyBounds())
619         return;
620
621     int left, top, right, bottom;
622     m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom);
623
624     updateTiles(false, left, top, right, bottom, updater, occlusion);
625 }
626
627 void TiledLayerChromium::idleUpdateLayerRect(CCTextureUpdater& updater, const IntRect& layerRect, const CCOcclusionTracker* occlusion)
628 {
629     // Abort if we have already painted or run out of memory.
630     if (m_skipsIdlePaint || m_didPaint)
631         return;
632
633     ASSERT(m_tiler);
634
635     updateBounds();
636
637     if (m_tiler->hasEmptyBounds())
638         return;
639
640     IntRect idlePaintLayerRect = idlePaintRect(layerRect);
641     if (idlePaintLayerRect.isEmpty())
642         return;
643
644     int prepaintLeft, prepaintTop, prepaintRight, prepaintBottom;
645     m_tiler->layerRectToTileIndices(idlePaintLayerRect, prepaintLeft, prepaintTop, prepaintRight, prepaintBottom);
646
647     // If the layer is not visible, we have nothing to expand from, so instead we prepaint the outer-most set of tiles.
648     if (layerRect.isEmpty()) {
649         updateTiles(true, prepaintLeft, prepaintTop, prepaintRight, prepaintTop, updater, 0);
650         if (m_didPaint || m_skipsIdlePaint)
651             return;
652         updateTiles(true, prepaintLeft, prepaintBottom, prepaintRight, prepaintBottom, updater, 0);
653         if (m_didPaint || m_skipsIdlePaint)
654             return;
655         updateTiles(true, prepaintLeft, prepaintTop, prepaintLeft, prepaintBottom, updater, 0);
656         if (m_didPaint || m_skipsIdlePaint)
657             return;
658         updateTiles(true, prepaintRight, prepaintTop, prepaintRight, prepaintBottom, updater, 0);
659         return;
660     }
661
662     int left, top, right, bottom;
663     m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom);
664
665     // Otherwise, prepaint anything that was occluded but inside the layer's visible region.
666     updateTiles(true, left, top, right, bottom, updater, 0);
667     if (m_didPaint || m_skipsIdlePaint)
668         return;
669
670     // Then expand outwards from the visible area until we find a dirty row or column to update.
671     while (!m_skipsIdlePaint && (left > prepaintLeft || top > prepaintTop || right < prepaintRight || bottom < prepaintBottom)) {
672         if (bottom < prepaintBottom) {
673             ++bottom;
674             updateTiles(true, left, bottom, right, bottom, updater, 0);
675             if (m_didPaint || m_skipsIdlePaint)
676                 break;
677         }
678         if (top > prepaintTop) {
679             --top;
680             updateTiles(true, left, top, right, top, updater, 0);
681             if (m_didPaint || m_skipsIdlePaint)
682                 break;
683         }
684         if (left > prepaintLeft) {
685             --left;
686             updateTiles(true, left, top, left, bottom, updater, 0);
687             if (m_didPaint || m_skipsIdlePaint)
688                 break;
689         }
690         if (right < prepaintRight) {
691             ++right;
692             updateTiles(true, right, top, right, bottom, updater, 0);
693             if (m_didPaint || m_skipsIdlePaint)
694                 break;
695         }
696     }
697 }
698
699 bool TiledLayerChromium::needsIdlePaint(const IntRect& layerRect)
700 {
701     if (m_skipsIdlePaint)
702         return false;
703
704     if (m_tiler->hasEmptyBounds())
705         return false;
706
707     IntRect idlePaintLayerRect = idlePaintRect(layerRect);
708     if (idlePaintLayerRect.isEmpty())
709         return false;
710
711     int left, top, right, bottom;
712     m_tiler->layerRectToTileIndices(idlePaintLayerRect, left, top, right, bottom);
713
714     for (int j = top; j <= bottom; ++j) {
715         for (int i = left; i <= right; ++i) {
716             // If the layerRect is empty, then we are painting the outer-most set of tiles only.
717             if (layerRect.isEmpty() && i != left && i != right && j != top && j != bottom)
718                 continue;
719             UpdatableTile* tile = tileAt(i, j);
720             ASSERT(tile); // Did setTexturePriorities get skipped?
721             if (!tile)
722                 continue;
723
724             bool updated = tile->updated;
725             bool canAcquire = tile->managedTexture()->canAcquireBackingTexture();
726             bool dirty = tile->isDirty() || !tile->managedTexture()->haveBackingTexture();
727             if (!updated && canAcquire && dirty)
728                 return true;
729         }
730     }
731     return false;
732 }
733
734 IntRect TiledLayerChromium::idlePaintRect(const IntRect& visibleLayerRect)
735 {
736     IntRect contentRect(IntPoint::zero(), contentBounds());
737
738     // For layers that are animating transforms but not visible at all, we don't know what part
739     // of them is going to become visible. For small layers we return the entire layer, for larger
740     // ones we avoid prepainting the layer at all.
741     if (visibleLayerRect.isEmpty()) {
742         bool isSmallLayer = m_tiler->numTilesX() <= 9 && m_tiler->numTilesY() <= 9 && m_tiler->numTilesX() * m_tiler->numTilesY() <= 9;
743         if ((drawTransformIsAnimating() || screenSpaceTransformIsAnimating()) && isSmallLayer)
744             return contentRect;
745         return IntRect();
746     }
747
748     // FIXME: This can be made a lot larger now! We should increase
749     //        this slowly while insuring it doesn't cause any perf issues.
750     IntRect prepaintRect = visibleLayerRect;
751     prepaintRect.inflateX(m_tiler->tileSize().width());
752     prepaintRect.inflateY(m_tiler->tileSize().height() * 2);
753     prepaintRect.intersect(contentRect);
754
755     return prepaintRect;
756 }
757
758 }
759 #endif // USE(ACCELERATED_COMPOSITING)