[chromium] Fold LayerChromium::updateCompositorResources into main update
[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 "LayerRendererChromium.h"
34 #include "ManagedTexture.h"
35 #include "Region.h"
36 #include "TextStream.h"
37 #include "TraceEvent.h"
38
39 #include "cc/CCLayerImpl.h"
40 #include "cc/CCTextureUpdater.h"
41 #include "cc/CCTiledLayerImpl.h"
42
43 #include <wtf/CurrentTime.h>
44 #include <wtf/MathExtras.h>
45
46 // Start tiling when the width and height of a layer are larger than this size.
47 static int maxUntiledSize = 512;
48
49 // When tiling is enabled, use tiles of this dimension squared.
50 static int defaultTileSize = 256;
51
52 using namespace std;
53
54 namespace WebCore {
55
56 class UpdatableTile : public CCLayerTilingData::Tile {
57     WTF_MAKE_NONCOPYABLE(UpdatableTile);
58 public:
59     static PassOwnPtr<UpdatableTile> create(PassOwnPtr<LayerTextureUpdater::Texture> texture)
60     {
61         return adoptPtr(new UpdatableTile(texture));
62     }
63
64     LayerTextureUpdater::Texture* texture() { return m_texture.get(); }
65     ManagedTexture* managedTexture() { return m_texture->texture(); }
66
67     bool isDirty() const { return !dirtyRect.isEmpty(); }
68     void copyAndClearDirty()
69     {
70         updateRect = dirtyRect;
71         dirtyRect = IntRect();
72     }
73     // Returns whether the layer was dirty and not updated in the current frame. For tiles that were not culled, the
74     // updateRect holds the area of the tile that was updated. Otherwise, the area that would have been updated.
75     bool isDirtyForCurrentFrame() { return !dirtyRect.isEmpty() && (updateRect.isEmpty() || !updated); }
76
77     IntRect dirtyRect;
78     IntRect updateRect;
79     bool partialUpdate;
80     bool updated;
81 private:
82     explicit UpdatableTile(PassOwnPtr<LayerTextureUpdater::Texture> texture)
83         : partialUpdate(false)
84         , updated(false)
85         , m_texture(texture)
86     {
87     }
88
89     OwnPtr<LayerTextureUpdater::Texture> m_texture;
90 };
91
92 TiledLayerChromium::TiledLayerChromium()
93     : LayerChromium()
94     , m_textureFormat(GraphicsContext3D::INVALID_ENUM)
95     , m_skipsDraw(false)
96     , m_skipsIdlePaint(false)
97     , m_sampledTexelFormat(LayerTextureUpdater::SampledTexelFormatInvalid)
98     , m_didPaint(false)
99     , m_tilingOption(AutoTile)
100 {
101     m_tiler = CCLayerTilingData::create(IntSize(defaultTileSize, defaultTileSize), CCLayerTilingData::HasBorderTexels);
102 }
103
104 TiledLayerChromium::~TiledLayerChromium()
105 {
106 }
107
108 PassOwnPtr<CCLayerImpl> TiledLayerChromium::createCCLayerImpl()
109 {
110     return CCTiledLayerImpl::create(id());
111 }
112
113 void TiledLayerChromium::updateTileSizeAndTilingOption()
114 {
115     const IntSize tileSize(min(defaultTileSize, contentBounds().width()), min(defaultTileSize, contentBounds().height()));
116
117     // Tile if both dimensions large, or any one dimension large and the other
118     // extends into a second tile. This heuristic allows for long skinny layers
119     // (e.g. scrollbars) that are Nx1 tiles to minimize wasted texture space.
120     const bool anyDimensionLarge = contentBounds().width() > maxUntiledSize || contentBounds().height() > maxUntiledSize;
121     const bool anyDimensionOneTile = contentBounds().width() <= defaultTileSize || contentBounds().height() <= defaultTileSize;
122     const bool autoTiled = anyDimensionLarge && !anyDimensionOneTile;
123
124     bool isTiled;
125     if (m_tilingOption == AlwaysTile)
126         isTiled = true;
127     else if (m_tilingOption == NeverTile)
128         isTiled = false;
129     else
130         isTiled = autoTiled;
131
132     IntSize requestedSize = isTiled ? tileSize : contentBounds();
133     const int maxSize = layerTreeHost()->layerRendererCapabilities().maxTextureSize;
134     IntSize clampedSize = requestedSize.shrunkTo(IntSize(maxSize, maxSize));
135     setTileSize(clampedSize);
136 }
137
138 void TiledLayerChromium::updateBounds()
139 {
140     IntSize oldBounds = m_tiler->bounds();
141     IntSize newBounds = contentBounds();
142     if (oldBounds == newBounds)
143         return;
144     m_tiler->setBounds(newBounds);
145
146     // Invalidate any areas that the new bounds exposes.
147     Region oldRegion(IntRect(IntPoint(), oldBounds));
148     Region newRegion(IntRect(IntPoint(), newBounds));
149     newRegion.subtract(oldRegion);
150     Vector<IntRect> rects = newRegion.rects();
151     for (size_t i = 0; i < rects.size(); ++i)
152         invalidateRect(rects[i]);
153 }
154
155 void TiledLayerChromium::setTileSize(const IntSize& size)
156 {
157     m_tiler->setTileSize(size);
158 }
159
160 void TiledLayerChromium::setBorderTexelOption(CCLayerTilingData::BorderTexelOption borderTexelOption)
161 {
162     m_tiler->setBorderTexelOption(borderTexelOption);
163 }
164
165 bool TiledLayerChromium::drawsContent() const
166 {
167     if (!LayerChromium::drawsContent())
168         return false;
169
170     bool hasMoreThanOneTile = m_tiler->numTilesX() > 1 || m_tiler->numTilesY() > 1;
171     if (m_tilingOption == NeverTile && hasMoreThanOneTile)
172         return false;
173
174     return true;
175 }
176
177 bool TiledLayerChromium::needsContentsScale() const
178 {
179     return true;
180 }
181
182 IntSize TiledLayerChromium::contentBounds() const
183 {
184     return IntSize(lroundf(bounds().width() * contentsScale()), lroundf(bounds().height() * contentsScale()));
185 }
186
187 void TiledLayerChromium::setTilingOption(TilingOption tilingOption)
188 {
189     m_tilingOption = tilingOption;
190 }
191
192 void TiledLayerChromium::setIsMask(bool isMask)
193 {
194     setTilingOption(isMask ? NeverTile : AutoTile);
195 }
196
197 void TiledLayerChromium::pushPropertiesTo(CCLayerImpl* layer)
198 {
199     LayerChromium::pushPropertiesTo(layer);
200
201     CCTiledLayerImpl* tiledLayer = static_cast<CCTiledLayerImpl*>(layer);
202
203     tiledLayer->setSkipsDraw(m_skipsDraw);
204     tiledLayer->setContentsSwizzled(m_sampledTexelFormat != LayerTextureUpdater::SampledTexelFormatRGBA);
205     tiledLayer->setTilingData(*m_tiler);
206     Vector<UpdatableTile*> invalidTiles;
207
208     for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) {
209         int i = iter->first.first;
210         int j = iter->first.second;
211         UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
212         if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat)) {
213             invalidTiles.append(tile);
214             continue;
215         }
216         if (tile->isDirtyForCurrentFrame())
217             continue;
218
219         tiledLayer->pushTileProperties(i, j, tile->managedTexture()->textureId(), tile->opaqueRect());
220     }
221     for (Vector<UpdatableTile*>::const_iterator iter = invalidTiles.begin(); iter != invalidTiles.end(); ++iter)
222         m_tiler->takeTile((*iter)->i(), (*iter)->j());
223 }
224
225 TextureManager* TiledLayerChromium::textureManager() const
226 {
227     if (!layerTreeHost())
228         return 0;
229     return layerTreeHost()->contentsTextureManager();
230 }
231
232 void TiledLayerChromium::setLayerTreeHost(CCLayerTreeHost* host)
233 {
234     if (host && host != layerTreeHost()) {
235         for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) {
236             UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
237             tile->managedTexture()->setTextureManager(host->contentsTextureManager());
238         }
239     }
240     LayerChromium::setLayerTreeHost(host);
241 }
242
243 UpdatableTile* TiledLayerChromium::tileAt(int i, int j) const
244 {
245     return static_cast<UpdatableTile*>(m_tiler->tileAt(i, j));
246 }
247
248 UpdatableTile* TiledLayerChromium::createTile(int i, int j)
249 {
250     OwnPtr<UpdatableTile> tile(UpdatableTile::create(textureUpdater()->createTexture(textureManager())));
251     UpdatableTile* addedTile = tile.get();
252     m_tiler->addTile(tile.release(), i, j);
253
254     addedTile->dirtyRect = m_tiler->tileRect(addedTile);
255     return addedTile;
256 }
257
258 void TiledLayerChromium::setNeedsDisplayRect(const FloatRect& dirtyRect)
259 {
260     FloatRect scaledDirtyRect(dirtyRect);
261     scaledDirtyRect.scale(contentsScale());
262     IntRect dirty = enclosingIntRect(scaledDirtyRect);
263     invalidateRect(dirty);
264     LayerChromium::setNeedsDisplayRect(dirtyRect);
265 }
266
267 void TiledLayerChromium::setIsNonCompositedContent(bool isNonCompositedContent)
268 {
269     LayerChromium::setIsNonCompositedContent(isNonCompositedContent);
270
271     CCLayerTilingData::BorderTexelOption borderTexelOption;
272 #if OS(ANDROID)
273     // Always want border texels and GL_LINEAR due to pinch zoom.
274     borderTexelOption = CCLayerTilingData::HasBorderTexels;
275 #else
276     borderTexelOption = isNonCompositedContent ? CCLayerTilingData::NoBorderTexels : CCLayerTilingData::HasBorderTexels;
277 #endif
278     setBorderTexelOption(borderTexelOption);
279 }
280
281 void TiledLayerChromium::invalidateRect(const IntRect& layerRect)
282 {
283     updateBounds();
284     if (m_tiler->isEmpty() || layerRect.isEmpty() || m_skipsDraw)
285         return;
286
287     for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) {
288         UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
289         ASSERT(tile);
290         IntRect bound = m_tiler->tileRect(tile);
291         bound.intersect(layerRect);
292         tile->dirtyRect.unite(bound);
293     }
294 }
295
296 void TiledLayerChromium::protectVisibleTileTextures()
297 {
298     protectTileTextures(visibleLayerRect());
299 }
300
301 void TiledLayerChromium::protectTileTextures(const IntRect& layerRect)
302 {
303     if (m_tiler->isEmpty() || layerRect.isEmpty())
304         return;
305
306     int left, top, right, bottom;
307     m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom);
308
309     for (int j = top; j <= bottom; ++j) {
310         for (int i = left; i <= right; ++i) {
311             UpdatableTile* tile = tileAt(i, j);
312             if (!tile || !tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat))
313                 continue;
314
315             tile->managedTexture()->reserve(m_tiler->tileSize(), m_textureFormat);
316         }
317     }
318 }
319
320 // Returns true if tile is dirty and only part of it needs to be updated.
321 bool TiledLayerChromium::tileOnlyNeedsPartialUpdate(UpdatableTile* tile)
322 {
323     if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat))
324         return false;
325
326     if (!tile->isDirty())
327         return false;
328
329     return !tile->dirtyRect.contains(m_tiler->tileRect(tile));
330 }
331
332 // Dirty tiles with valid textures needs buffered update to guarantee that
333 // we don't modify textures currently used for drawing by the impl thread.
334 bool TiledLayerChromium::tileNeedsBufferedUpdate(UpdatableTile* tile)
335 {
336     // No impl thread?.
337     if (!CCProxy::hasImplThread())
338         return false;
339
340     if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat))
341         return false;
342
343     if (!tile->isDirty())
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             if (!tile)
362                 tile = createTile(i, j);
363
364             if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat)) {
365                 // Sets the dirty rect to a full-sized tile with border texels.
366                 tile->dirtyRect = m_tiler->tileRect(tile);
367             }
368
369             // When not idle painting, if the visible region of the tile is occluded, don't reserve a texture or update the tile.
370             // If any part of the tile is visible, then we need to update it so the tile is pushed to the impl thread.
371             if (!idle && occlusion) {
372                 IntRect visibleTileRect = intersection(m_tiler->tileBounds(i, j), visibleLayerRect());
373                 if (occlusion->occluded(this, visibleTileRect)) {
374                     ASSERT(!tile->updated);
375                     continue;
376                 }
377             }
378
379             // We come through this function multiple times during a commit, and updated should be true if the tile is not culled
380             // any single time through the function.
381             tile->updated = true;
382
383             // FIXME: Decide if partial update should be allowed based on cost
384             // of update. https://bugs.webkit.org/show_bug.cgi?id=77376
385             if (tileOnlyNeedsPartialUpdate(tile) && layerTreeHost() && layerTreeHost()->requestPartialTextureUpdate())
386                 tile->partialUpdate = true;
387             else if (tileNeedsBufferedUpdate(tile) && layerTreeHost()) {
388                 layerTreeHost()->deleteTextureAfterCommit(tile->managedTexture()->steal());
389                 // Sets the dirty rect to a full-sized tile with border texels.
390                 tile->dirtyRect = m_tiler->tileRect(tile);
391             }
392
393             if (!tile->managedTexture()->reserve(m_tiler->tileSize(), m_textureFormat)) {
394                 m_skipsIdlePaint = true;
395                 if (!idle) {
396                     m_skipsDraw = true;
397                     m_tiler->reset();
398                 }
399                 return;
400             }
401
402             paintRect.unite(tile->dirtyRect);
403         }
404     }
405
406     // For tiles that were not culled, we are going to update the area currently marked as dirty. So
407     // clear that dirty area and mark it for update instead.
408     for (int j = top; j <= bottom; ++j) {
409         for (int i = left; i <= right; ++i) {
410             UpdatableTile* tile = tileAt(i, j);
411             if (tile->updated)
412                 tile->copyAndClearDirty();
413             else if (!idle && occlusion && tile->isDirty())
414                 occlusion->overdrawMetrics().didCullTileForUpload();
415         }
416     }
417
418     if (paintRect.isEmpty())
419         return;
420
421     if (occlusion)
422         occlusion->overdrawMetrics().didPaint(paintRect);
423
424     // The updateRect should be in layer space. So we have to convert the paintRect from content space to layer space.
425     m_updateRect = FloatRect(paintRect);
426     float widthScale = bounds().width() / static_cast<float>(contentBounds().width());
427     float heightScale = bounds().height() / static_cast<float>(contentBounds().height());
428     m_updateRect.scale(widthScale, heightScale);
429
430     // Calling prepareToUpdate() calls into WebKit to paint, which may have the side
431     // effect of disabling compositing, which causes our reference to the texture updater to be deleted.
432     // However, we can't free the memory backing the GraphicsContext until the paint finishes,
433     // so we grab a local reference here to hold the updater alive until the paint completes.
434     RefPtr<LayerTextureUpdater> protector(textureUpdater());
435     IntRect paintedOpaqueRect;
436     textureUpdater()->prepareToUpdate(paintRect, m_tiler->tileSize(), m_tiler->hasBorderTexels(), contentsScale(), &paintedOpaqueRect);
437     m_didPaint = true;
438
439     for (int j = top; j <= bottom; ++j) {
440         for (int i = left; i <= right; ++i) {
441             UpdatableTile* tile = tileAt(i, j);
442
443             IntRect tileRect = m_tiler->tileBounds(i, j);
444
445             if (!tile->updated)
446                 continue;
447
448             // Use updateRect as the above loop copied the dirty rect for this frame to updateRect.
449             const IntRect& dirtyRect = tile->updateRect;
450             if (dirtyRect.isEmpty())
451                 continue;
452
453             // Save what was painted opaque in the tile. Keep the old area if the paint didn't touch it, and didn't paint some
454             // other part of the tile opaque.
455             IntRect tilePaintedRect = intersection(tileRect, paintRect);
456             IntRect tilePaintedOpaqueRect = intersection(tileRect, paintedOpaqueRect);
457             if (!tilePaintedRect.isEmpty()) {
458                 IntRect paintInsideTileOpaqueRect = intersection(tile->opaqueRect(), tilePaintedRect);
459                 bool paintInsideTileOpaqueRectIsNonOpaque = !tilePaintedOpaqueRect.contains(paintInsideTileOpaqueRect);
460                 bool opaquePaintNotInsideTileOpaqueRect = !tilePaintedOpaqueRect.isEmpty() && !tile->opaqueRect().contains(tilePaintedOpaqueRect);
461
462                 if (paintInsideTileOpaqueRectIsNonOpaque || opaquePaintNotInsideTileOpaqueRect)
463                     tile->setOpaqueRect(tilePaintedOpaqueRect);
464             }
465
466             // sourceRect starts as a full-sized tile with border texels included.
467             IntRect sourceRect = m_tiler->tileRect(tile);
468             sourceRect.intersect(dirtyRect);
469             // Paint rect not guaranteed to line up on tile boundaries, so
470             // make sure that sourceRect doesn't extend outside of it.
471             sourceRect.intersect(paintRect);
472
473             tile->updateRect = sourceRect;
474
475             if (sourceRect.isEmpty())
476                 continue;
477
478             tile->texture()->prepareRect(sourceRect);
479             if (occlusion)
480                 occlusion->overdrawMetrics().didUpload(TransformationMatrix(), sourceRect, tile->opaqueRect());
481
482             const IntPoint anchor = m_tiler->tileRect(tile).location();
483
484             // Calculate tile-space rectangle to upload into.
485             IntRect destRect(IntPoint(sourceRect.x() - anchor.x(), sourceRect.y() - anchor.y()), sourceRect.size());
486             if (destRect.x() < 0)
487                 CRASH();
488             if (destRect.y() < 0)
489                 CRASH();
490
491             // Offset from paint rectangle to this tile's dirty rectangle.
492             IntPoint paintOffset(sourceRect.x() - paintRect.x(), sourceRect.y() - paintRect.y());
493             if (paintOffset.x() < 0)
494                 CRASH();
495             if (paintOffset.y() < 0)
496                 CRASH();
497             if (paintOffset.x() + destRect.width() > paintRect.width())
498                 CRASH();
499             if (paintOffset.y() + destRect.height() > paintRect.height())
500                 CRASH();
501
502             if (tile->partialUpdate)
503                 updater.appendPartialUpdate(tile->texture(), sourceRect, destRect);
504             else
505                 updater.appendUpdate(tile->texture(), sourceRect, destRect);
506         }
507     }
508 }
509
510 void TiledLayerChromium::reserveTextures()
511 {
512     updateBounds();
513
514     const IntRect& layerRect = visibleLayerRect();
515     if (layerRect.isEmpty() || m_tiler->hasEmptyBounds())
516         return;
517
518     int left, top, right, bottom;
519     m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom);
520
521     createTextureUpdaterIfNeeded();
522     for (int j = top; j <= bottom; ++j) {
523         for (int i = left; i <= right; ++i) {
524             UpdatableTile* tile = tileAt(i, j);
525             if (!tile)
526                 tile = createTile(i, j);
527
528             if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat))
529                 tile->dirtyRect = m_tiler->tileRect(tile);
530
531             if (!tile->managedTexture()->reserve(m_tiler->tileSize(), m_textureFormat))
532                 return;
533         }
534     }
535 }
536
537 Region TiledLayerChromium::visibleContentOpaqueRegion() const
538 {
539     if (m_skipsDraw)
540         return Region();
541     if (opaque())
542         return visibleLayerRect();
543     return m_tiler->opaqueRegionInLayerRect(visibleLayerRect());
544 }
545
546 void TiledLayerChromium::resetUpdateState()
547 {
548     CCLayerTilingData::TileMap::const_iterator end = m_tiler->tiles().end();
549     for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != end; ++iter) {
550         UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
551         tile->updateRect = IntRect();
552         tile->partialUpdate = false;
553         tile->updated = false;
554     }
555 }
556
557 void TiledLayerChromium::updateLayerRect(CCTextureUpdater& updater, const IntRect& layerRect, const CCOcclusionTracker* occlusion)
558 {
559     m_skipsDraw = false;
560     m_skipsIdlePaint = false;
561     m_didPaint = false;
562
563     updateBounds();
564
565     resetUpdateState();
566
567     if (layerRect.isEmpty() || m_tiler->hasEmptyBounds())
568         return;
569
570     int left, top, right, bottom;
571     m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom);
572
573     updateTiles(false, left, top, right, bottom, updater, occlusion);
574 }
575
576 void TiledLayerChromium::idleUpdateLayerRect(CCTextureUpdater& updater, const IntRect& layerRect, const CCOcclusionTracker* occlusion)
577 {
578     // Abort if we have already painted or run out of memory.
579     if (m_skipsIdlePaint || m_didPaint)
580         return;
581
582     ASSERT(m_tiler);
583
584     updateBounds();
585
586     if (m_tiler->hasEmptyBounds())
587         return;
588
589     IntRect idlePaintLayerRect = idlePaintRect(layerRect);
590     if (idlePaintLayerRect.isEmpty())
591         return;
592
593     // Protect any textures in the pre-paint area, as we would steal them from other layers
594     // over time anyhow. This ensures we don't lose tiles in the first rounds of idle painting
595     // that we have already painted.
596     protectTileTextures(idlePaintLayerRect);
597
598     int prepaintLeft, prepaintTop, prepaintRight, prepaintBottom;
599     m_tiler->layerRectToTileIndices(idlePaintLayerRect, prepaintLeft, prepaintTop, prepaintRight, prepaintBottom);
600
601     // If the layer is not visible, we have nothing to expand from, so instead we prepaint the outer-most set of tiles.
602     if (layerRect.isEmpty()) {
603         updateTiles(true, prepaintLeft, prepaintTop, prepaintRight, prepaintTop, updater, 0);
604         if (m_didPaint || m_skipsIdlePaint)
605             return;
606         updateTiles(true, prepaintLeft, prepaintBottom, prepaintRight, prepaintBottom, updater, 0);
607         if (m_didPaint || m_skipsIdlePaint)
608             return;
609         updateTiles(true, prepaintLeft, prepaintTop, prepaintLeft, prepaintBottom, updater, 0);
610         if (m_didPaint || m_skipsIdlePaint)
611             return;
612         updateTiles(true, prepaintRight, prepaintTop, prepaintRight, prepaintBottom, updater, 0);
613         return;
614     }
615
616     int left, top, right, bottom;
617     m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom);
618
619     // Otherwise, prepaint anything that was occluded but inside the layer's visible region.
620     updateTiles(true, left, top, right, bottom, updater, 0);
621     if (m_didPaint || m_skipsIdlePaint)
622         return;
623
624     // Then expand outwards from the visible area until we find a dirty row or column to update.
625     while (!m_skipsIdlePaint && (left > prepaintLeft || top > prepaintTop || right < prepaintRight || bottom < prepaintBottom)) {
626         if (bottom < prepaintBottom) {
627             ++bottom;
628             updateTiles(true, left, bottom, right, bottom, updater, 0);
629             if (m_didPaint || m_skipsIdlePaint)
630                 break;
631         }
632         if (top > prepaintTop) {
633             --top;
634             updateTiles(true, left, top, right, top, updater, 0);
635             if (m_didPaint || m_skipsIdlePaint)
636                 break;
637         }
638         if (left > prepaintLeft) {
639             --left;
640             updateTiles(true, left, top, left, bottom, updater, 0);
641             if (m_didPaint || m_skipsIdlePaint)
642                 break;
643         }
644         if (right < prepaintRight) {
645             ++right;
646             updateTiles(true, right, top, right, bottom, updater, 0);
647             if (m_didPaint || m_skipsIdlePaint)
648                 break;
649         }
650     }
651 }
652
653 bool TiledLayerChromium::needsIdlePaint(const IntRect& layerRect)
654 {
655     if (m_skipsIdlePaint)
656         return false;
657
658     if (m_tiler->hasEmptyBounds())
659         return false;
660
661     IntRect idlePaintLayerRect = idlePaintRect(layerRect);
662     if (idlePaintLayerRect.isEmpty())
663         return false;
664
665     int left, top, right, bottom;
666     m_tiler->layerRectToTileIndices(idlePaintLayerRect, left, top, right, bottom);
667     for (int j = top; j <= bottom; ++j) {
668         for (int i = left; i <= right; ++i) {
669             // If the layerRect is empty, then we are painting the outer-most set of tiles only.
670             if (layerRect.isEmpty() && i != left && i != right && j != top && j != bottom)
671                 continue;
672             UpdatableTile* tile = tileAt(i, j);
673             if (!tile || !tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat) || tile->isDirty())
674                 return true;
675         }
676     }
677     return false;
678 }
679
680 IntRect TiledLayerChromium::idlePaintRect(const IntRect& visibleLayerRect)
681 {
682     // For layers that are animating transforms but not visible at all, we don't know what part
683     // of them is going to become visible. For small layers we return the entire layer, for larger
684     // ones we avoid prepainting the layer at all.
685     if (visibleLayerRect.isEmpty()) {
686         bool isSmallLayer = m_tiler->numTilesX() <= 9 && m_tiler->numTilesY() <= 9 && m_tiler->numTilesX() * m_tiler->numTilesY() <= 9;
687         if ((drawTransformIsAnimating() || screenSpaceTransformIsAnimating()) && isSmallLayer)
688             return IntRect(IntPoint(), contentBounds());
689         return IntRect();
690     }
691
692     IntRect prepaintRect = visibleLayerRect;
693     // FIXME: This can be made a lot larger if we can:
694     // - reserve memory at a lower priority than for visible content
695     // - only reserve idle paint tiles up to a memory reclaim threshold and
696     // - insure we play nicely with other layers
697     prepaintRect.inflateX(m_tiler->tileSize().width());
698     prepaintRect.inflateY(m_tiler->tileSize().height());
699     prepaintRect.intersect(IntRect(IntPoint::zero(), contentBounds()));
700     return prepaintRect;
701 }
702
703 }
704 #endif // USE(ACCELERATED_COMPOSITING)