[chromium] Add diagnostic CRASH calls for tiler crashes
[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 using namespace std;
47
48 namespace WebCore {
49
50 class UpdatableTile : public CCLayerTilingData::Tile {
51     WTF_MAKE_NONCOPYABLE(UpdatableTile);
52 public:
53     static PassOwnPtr<UpdatableTile> create(PassOwnPtr<LayerTextureUpdater::Texture> texture)
54     {
55         return adoptPtr(new UpdatableTile(texture));
56     }
57
58     LayerTextureUpdater::Texture* texture() { return m_texture.get(); }
59     ManagedTexture* managedTexture() { return m_texture->texture(); }
60
61     bool isDirty() const { return !dirtyRect.isEmpty(); }
62     void copyAndClearDirty()
63     {
64         updateRect = dirtyRect;
65         dirtyRect = IntRect();
66     }
67     // Returns whether the layer was dirty and not updated in the current frame. For tiles that were not culled, the
68     // updateRect holds the area of the tile that was updated. Otherwise, the area that would have been updated.
69     bool isDirtyForCurrentFrame() { return !dirtyRect.isEmpty() && (updateRect.isEmpty() || !updated); }
70
71     IntRect dirtyRect;
72     IntRect updateRect;
73     bool partialUpdate;
74     bool updated;
75     bool isInUseOnImpl;
76 private:
77     explicit UpdatableTile(PassOwnPtr<LayerTextureUpdater::Texture> texture)
78         : partialUpdate(false)
79         , updated(false)
80         , isInUseOnImpl(false)
81         , m_texture(texture)
82     {
83     }
84
85     OwnPtr<LayerTextureUpdater::Texture> m_texture;
86 };
87
88 TiledLayerChromium::TiledLayerChromium()
89     : LayerChromium()
90     , m_textureFormat(GraphicsContext3D::INVALID_ENUM)
91     , m_skipsDraw(false)
92     , m_skipsIdlePaint(false)
93     , m_sampledTexelFormat(LayerTextureUpdater::SampledTexelFormatInvalid)
94     , m_didPaint(false)
95     , m_tilingOption(AutoTile)
96 {
97     m_tiler = CCLayerTilingData::create(IntSize(), CCLayerTilingData::HasBorderTexels);
98 }
99
100 TiledLayerChromium::~TiledLayerChromium()
101 {
102 }
103
104 PassOwnPtr<CCLayerImpl> TiledLayerChromium::createCCLayerImpl()
105 {
106     return CCTiledLayerImpl::create(id());
107 }
108
109 void TiledLayerChromium::updateTileSizeAndTilingOption()
110 {
111     ASSERT(layerTreeHost());
112
113     const CCSettings& settings = layerTreeHost()->settings();
114     const IntSize& defaultTileSize = settings.defaultTileSize;
115     const IntSize& maxUntiledLayerSize = 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         tile->isInUseOnImpl = false;
220         if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat)) {
221             invalidTiles.append(tile);
222             continue;
223         }
224         if (tile->isDirtyForCurrentFrame())
225             continue;
226
227         tiledLayer->pushTileProperties(i, j, tile->managedTexture()->textureId(), tile->opaqueRect());
228         tile->isInUseOnImpl = true;
229     }
230     for (Vector<UpdatableTile*>::const_iterator iter = invalidTiles.begin(); iter != invalidTiles.end(); ++iter)
231         m_tiler->takeTile((*iter)->i(), (*iter)->j());
232 }
233
234 TextureManager* TiledLayerChromium::textureManager() const
235 {
236     if (!layerTreeHost())
237         return 0;
238     return layerTreeHost()->contentsTextureManager();
239 }
240
241 void TiledLayerChromium::setLayerTreeHost(CCLayerTreeHost* host)
242 {
243     if (host && host != layerTreeHost()) {
244         for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) {
245             UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
246             tile->managedTexture()->setTextureManager(host->contentsTextureManager());
247         }
248     }
249     LayerChromium::setLayerTreeHost(host);
250 }
251
252 UpdatableTile* TiledLayerChromium::tileAt(int i, int j) const
253 {
254     return static_cast<UpdatableTile*>(m_tiler->tileAt(i, j));
255 }
256
257 UpdatableTile* TiledLayerChromium::createTile(int i, int j)
258 {
259     OwnPtr<UpdatableTile> tile(UpdatableTile::create(textureUpdater()->createTexture(textureManager())));
260     UpdatableTile* addedTile = tile.get();
261     m_tiler->addTile(tile.release(), i, j);
262
263     addedTile->dirtyRect = m_tiler->tileRect(addedTile);
264
265     // Temporary diagnostic crash.
266     if (!addedTile)
267         CRASH();
268     if (!tileAt(i, j))
269         CRASH();
270
271     return addedTile;
272 }
273
274 void TiledLayerChromium::setNeedsDisplayRect(const FloatRect& dirtyRect)
275 {
276     FloatRect scaledDirtyRect(dirtyRect);
277     scaledDirtyRect.scale(contentsScale());
278     IntRect dirty = enclosingIntRect(scaledDirtyRect);
279     invalidateRect(dirty);
280     LayerChromium::setNeedsDisplayRect(dirtyRect);
281 }
282
283 void TiledLayerChromium::setIsNonCompositedContent(bool isNonCompositedContent)
284 {
285     LayerChromium::setIsNonCompositedContent(isNonCompositedContent);
286
287     CCLayerTilingData::BorderTexelOption borderTexelOption;
288 #if OS(ANDROID)
289     // Always want border texels and GL_LINEAR due to pinch zoom.
290     borderTexelOption = CCLayerTilingData::HasBorderTexels;
291 #else
292     borderTexelOption = isNonCompositedContent ? CCLayerTilingData::NoBorderTexels : CCLayerTilingData::HasBorderTexels;
293 #endif
294     setBorderTexelOption(borderTexelOption);
295 }
296
297 void TiledLayerChromium::invalidateRect(const IntRect& layerRect)
298 {
299     updateBounds();
300     if (m_tiler->isEmpty() || layerRect.isEmpty() || m_skipsDraw)
301         return;
302
303     for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) {
304         UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
305         ASSERT(tile);
306         IntRect bound = m_tiler->tileRect(tile);
307         bound.intersect(layerRect);
308         tile->dirtyRect.unite(bound);
309     }
310 }
311
312 void TiledLayerChromium::protectVisibleTileTextures()
313 {
314     protectTileTextures(visibleLayerRect());
315 }
316
317 void TiledLayerChromium::protectTileTextures(const IntRect& layerRect)
318 {
319     if (m_tiler->isEmpty() || layerRect.isEmpty())
320         return;
321
322     int left, top, right, bottom;
323     m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom);
324
325     for (int j = top; j <= bottom; ++j) {
326         for (int i = left; i <= right; ++i) {
327             UpdatableTile* tile = tileAt(i, j);
328             if (!tile || !tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat))
329                 continue;
330
331             tile->managedTexture()->reserve(m_tiler->tileSize(), m_textureFormat);
332         }
333     }
334 }
335
336 // Returns true if tile is dirty and only part of it needs to be updated.
337 bool TiledLayerChromium::tileOnlyNeedsPartialUpdate(UpdatableTile* tile)
338 {
339     return !tile->dirtyRect.contains(m_tiler->tileRect(tile));
340 }
341
342 // Dirty tiles with valid textures needs buffered update to guarantee that
343 // we don't modify textures currently used for drawing by the impl thread.
344 bool TiledLayerChromium::tileNeedsBufferedUpdate(UpdatableTile* tile)
345 {
346     if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat))
347         return false;
348
349     if (!tile->isDirty())
350         return false;
351
352     if (!tile->isInUseOnImpl)
353         return false;
354
355     return true;
356 }
357
358 void TiledLayerChromium::updateTiles(bool idle, int left, int top, int right, int bottom, CCTextureUpdater& updater, const CCOcclusionTracker* occlusion)
359 {
360     createTextureUpdaterIfNeeded();
361
362     // Create tiles as needed, expanding a dirty rect to contain all
363     // the dirty regions currently being drawn. All dirty tiles that are to be painted
364     // get their updateRect set to dirtyRect and dirtyRect cleared. This way if
365     // invalidateRect is invoked during updateLayerRect we don't lose the request.
366     IntRect paintRect;
367     for (int j = top; j <= bottom; ++j) {
368         for (int i = left; i <= right; ++i) {
369             UpdatableTile* tile = tileAt(i, j);
370             if (!tile)
371                 tile = createTile(i, j);
372
373             // Temporary diagnostic crash
374             if (!m_tiler)
375                 CRASH();
376
377             if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat)) {
378                 // Sets the dirty rect to a full-sized tile with border texels.
379                 tile->dirtyRect = m_tiler->tileRect(tile);
380             }
381
382             // When not idle painting, if the visible region of the tile is occluded, don't reserve a texture or update the tile.
383             // If any part of the tile is visible, then we need to update it so the tile is pushed to the impl thread.
384             if (!idle && occlusion) {
385                 IntRect visibleTileRect = intersection(m_tiler->tileBounds(i, j), visibleLayerRect());
386                 if (occlusion->occluded(this, visibleTileRect)) {
387                     ASSERT(!tile->updated);
388                     continue;
389                 }
390             }
391
392             // We come through this function multiple times during a commit, and updated should be true if the tile is not culled
393             // any single time through the function.
394             tile->updated = true;
395
396             if (layerTreeHost() && layerTreeHost()->bufferedUpdates() && tileNeedsBufferedUpdate(tile)) {
397                 // FIXME: Decide if partial update should be allowed based on cost
398                 // of update. https://bugs.webkit.org/show_bug.cgi?id=77376
399                 if (tileOnlyNeedsPartialUpdate(tile) && layerTreeHost()->requestPartialTextureUpdate())
400                     tile->partialUpdate = true;
401                 else {
402                     layerTreeHost()->deleteTextureAfterCommit(tile->managedTexture()->steal());
403                     // Sets the dirty rect to a full-sized tile with border texels.
404                     tile->dirtyRect = m_tiler->tileRect(tile);
405                 }
406             }
407
408             if (!tile->managedTexture()->reserve(m_tiler->tileSize(), m_textureFormat)) {
409                 m_skipsIdlePaint = true;
410                 if (!idle) {
411                     m_skipsDraw = true;
412                     m_tiler->reset();
413                 }
414                 return;
415             }
416
417             paintRect.unite(tile->dirtyRect);
418         }
419     }
420
421     // For tiles that were not culled, we are going to update the area currently marked as dirty. So
422     // clear that dirty area and mark it for update instead.
423     for (int j = top; j <= bottom; ++j) {
424         for (int i = left; i <= right; ++i) {
425             UpdatableTile* tile = tileAt(i, j);
426             if (!tile)
427                 CRASH();
428             if (tile->updated)
429                 tile->copyAndClearDirty();
430             else if (!idle && occlusion && tile->isDirty())
431                 occlusion->overdrawMetrics().didCullTileForUpload();
432         }
433     }
434
435     if (paintRect.isEmpty())
436         return;
437
438     if (occlusion)
439         occlusion->overdrawMetrics().didPaint(paintRect);
440
441     // The updateRect should be in layer space. So we have to convert the paintRect from content space to layer space.
442     m_updateRect = FloatRect(paintRect);
443     float widthScale = bounds().width() / static_cast<float>(contentBounds().width());
444     float heightScale = bounds().height() / static_cast<float>(contentBounds().height());
445     m_updateRect.scale(widthScale, heightScale);
446
447     // Calling prepareToUpdate() calls into WebKit to paint, which may have the side
448     // effect of disabling compositing, which causes our reference to the texture updater to be deleted.
449     // However, we can't free the memory backing the GraphicsContext until the paint finishes,
450     // so we grab a local reference here to hold the updater alive until the paint completes.
451     RefPtr<LayerTextureUpdater> protector(textureUpdater());
452     IntRect paintedOpaqueRect;
453     textureUpdater()->prepareToUpdate(paintRect, m_tiler->tileSize(), m_tiler->hasBorderTexels(), contentsScale(), paintedOpaqueRect);
454     m_didPaint = true;
455
456     for (int j = top; j <= bottom; ++j) {
457         for (int i = left; i <= right; ++i) {
458             UpdatableTile* tile = tileAt(i, j);
459
460             IntRect tileRect = m_tiler->tileBounds(i, j);
461
462             if (!tile->updated)
463                 continue;
464
465             // Use updateRect as the above loop copied the dirty rect for this frame to updateRect.
466             const IntRect& dirtyRect = tile->updateRect;
467             if (dirtyRect.isEmpty())
468                 continue;
469
470             // Save what was painted opaque in the tile. Keep the old area if the paint didn't touch it, and didn't paint some
471             // other part of the tile opaque.
472             IntRect tilePaintedRect = intersection(tileRect, paintRect);
473             IntRect tilePaintedOpaqueRect = intersection(tileRect, paintedOpaqueRect);
474             if (!tilePaintedRect.isEmpty()) {
475                 IntRect paintInsideTileOpaqueRect = intersection(tile->opaqueRect(), tilePaintedRect);
476                 bool paintInsideTileOpaqueRectIsNonOpaque = !tilePaintedOpaqueRect.contains(paintInsideTileOpaqueRect);
477                 bool opaquePaintNotInsideTileOpaqueRect = !tilePaintedOpaqueRect.isEmpty() && !tile->opaqueRect().contains(tilePaintedOpaqueRect);
478
479                 if (paintInsideTileOpaqueRectIsNonOpaque || opaquePaintNotInsideTileOpaqueRect)
480                     tile->setOpaqueRect(tilePaintedOpaqueRect);
481             }
482
483             // sourceRect starts as a full-sized tile with border texels included.
484             IntRect sourceRect = m_tiler->tileRect(tile);
485             sourceRect.intersect(dirtyRect);
486             // Paint rect not guaranteed to line up on tile boundaries, so
487             // make sure that sourceRect doesn't extend outside of it.
488             sourceRect.intersect(paintRect);
489
490             tile->updateRect = sourceRect;
491
492             if (sourceRect.isEmpty())
493                 continue;
494
495             tile->texture()->prepareRect(sourceRect);
496             if (occlusion)
497                 occlusion->overdrawMetrics().didUpload(TransformationMatrix(), sourceRect, tile->opaqueRect());
498
499             const IntPoint anchor = m_tiler->tileRect(tile).location();
500
501             // Calculate tile-space rectangle to upload into.
502             IntRect destRect(IntPoint(sourceRect.x() - anchor.x(), sourceRect.y() - anchor.y()), sourceRect.size());
503             if (destRect.x() < 0)
504                 CRASH();
505             if (destRect.y() < 0)
506                 CRASH();
507
508             // Offset from paint rectangle to this tile's dirty rectangle.
509             IntPoint paintOffset(sourceRect.x() - paintRect.x(), sourceRect.y() - paintRect.y());
510             if (paintOffset.x() < 0)
511                 CRASH();
512             if (paintOffset.y() < 0)
513                 CRASH();
514             if (paintOffset.x() + destRect.width() > paintRect.width())
515                 CRASH();
516             if (paintOffset.y() + destRect.height() > paintRect.height())
517                 CRASH();
518
519             if (tile->partialUpdate)
520                 updater.appendPartialUpdate(tile->texture(), sourceRect, destRect);
521             else
522                 updater.appendUpdate(tile->texture(), sourceRect, destRect);
523         }
524     }
525 }
526
527 void TiledLayerChromium::reserveTextures()
528 {
529     updateBounds();
530
531     const IntRect& layerRect = visibleLayerRect();
532     if (layerRect.isEmpty() || m_tiler->hasEmptyBounds())
533         return;
534
535     int left, top, right, bottom;
536     m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom);
537
538     createTextureUpdaterIfNeeded();
539     for (int j = top; j <= bottom; ++j) {
540         for (int i = left; i <= right; ++i) {
541             UpdatableTile* tile = tileAt(i, j);
542             if (!tile)
543                 tile = createTile(i, j);
544
545             if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat))
546                 tile->dirtyRect = m_tiler->tileRect(tile);
547
548             if (!tile->managedTexture()->reserve(m_tiler->tileSize(), m_textureFormat))
549                 return;
550         }
551     }
552 }
553
554 Region TiledLayerChromium::visibleContentOpaqueRegion() const
555 {
556     if (m_skipsDraw)
557         return Region();
558     if (opaque())
559         return visibleLayerRect();
560     return m_tiler->opaqueRegionInLayerRect(visibleLayerRect());
561 }
562
563 void TiledLayerChromium::resetUpdateState()
564 {
565     CCLayerTilingData::TileMap::const_iterator end = m_tiler->tiles().end();
566     for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != end; ++iter) {
567         UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
568         tile->updateRect = IntRect();
569         tile->partialUpdate = false;
570         tile->updated = false;
571     }
572 }
573
574 void TiledLayerChromium::updateLayerRect(CCTextureUpdater& updater, const IntRect& layerRect, const CCOcclusionTracker* occlusion)
575 {
576     m_skipsDraw = false;
577     m_skipsIdlePaint = false;
578     m_didPaint = false;
579
580     updateBounds();
581
582     resetUpdateState();
583
584     if (layerRect.isEmpty() || m_tiler->hasEmptyBounds())
585         return;
586
587     int left, top, right, bottom;
588     m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom);
589
590     updateTiles(false, left, top, right, bottom, updater, occlusion);
591 }
592
593 void TiledLayerChromium::idleUpdateLayerRect(CCTextureUpdater& updater, const IntRect& layerRect, const CCOcclusionTracker* occlusion)
594 {
595     // Abort if we have already painted or run out of memory.
596     if (m_skipsIdlePaint || m_didPaint)
597         return;
598
599     ASSERT(m_tiler);
600
601     updateBounds();
602
603     if (m_tiler->hasEmptyBounds())
604         return;
605
606     IntRect idlePaintLayerRect = idlePaintRect(layerRect);
607     if (idlePaintLayerRect.isEmpty())
608         return;
609
610     // Protect any textures in the pre-paint area, as we would steal them from other layers
611     // over time anyhow. This ensures we don't lose tiles in the first rounds of idle painting
612     // that we have already painted.
613     protectTileTextures(idlePaintLayerRect);
614
615     int prepaintLeft, prepaintTop, prepaintRight, prepaintBottom;
616     m_tiler->layerRectToTileIndices(idlePaintLayerRect, prepaintLeft, prepaintTop, prepaintRight, prepaintBottom);
617
618     // If the layer is not visible, we have nothing to expand from, so instead we prepaint the outer-most set of tiles.
619     if (layerRect.isEmpty()) {
620         updateTiles(true, prepaintLeft, prepaintTop, prepaintRight, prepaintTop, updater, 0);
621         if (m_didPaint || m_skipsIdlePaint)
622             return;
623         updateTiles(true, prepaintLeft, prepaintBottom, prepaintRight, prepaintBottom, updater, 0);
624         if (m_didPaint || m_skipsIdlePaint)
625             return;
626         updateTiles(true, prepaintLeft, prepaintTop, prepaintLeft, prepaintBottom, updater, 0);
627         if (m_didPaint || m_skipsIdlePaint)
628             return;
629         updateTiles(true, prepaintRight, prepaintTop, prepaintRight, prepaintBottom, updater, 0);
630         return;
631     }
632
633     int left, top, right, bottom;
634     m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom);
635
636     // Otherwise, prepaint anything that was occluded but inside the layer's visible region.
637     updateTiles(true, left, top, right, bottom, updater, 0);
638     if (m_didPaint || m_skipsIdlePaint)
639         return;
640
641     // Then expand outwards from the visible area until we find a dirty row or column to update.
642     while (!m_skipsIdlePaint && (left > prepaintLeft || top > prepaintTop || right < prepaintRight || bottom < prepaintBottom)) {
643         if (bottom < prepaintBottom) {
644             ++bottom;
645             updateTiles(true, left, bottom, right, bottom, updater, 0);
646             if (m_didPaint || m_skipsIdlePaint)
647                 break;
648         }
649         if (top > prepaintTop) {
650             --top;
651             updateTiles(true, left, top, right, top, updater, 0);
652             if (m_didPaint || m_skipsIdlePaint)
653                 break;
654         }
655         if (left > prepaintLeft) {
656             --left;
657             updateTiles(true, left, top, left, bottom, updater, 0);
658             if (m_didPaint || m_skipsIdlePaint)
659                 break;
660         }
661         if (right < prepaintRight) {
662             ++right;
663             updateTiles(true, right, top, right, bottom, updater, 0);
664             if (m_didPaint || m_skipsIdlePaint)
665                 break;
666         }
667     }
668 }
669
670 bool TiledLayerChromium::needsIdlePaint(const IntRect& layerRect)
671 {
672     if (m_skipsIdlePaint)
673         return false;
674
675     if (m_tiler->hasEmptyBounds())
676         return false;
677
678     IntRect idlePaintLayerRect = idlePaintRect(layerRect);
679     if (idlePaintLayerRect.isEmpty())
680         return false;
681
682     int left, top, right, bottom;
683     m_tiler->layerRectToTileIndices(idlePaintLayerRect, left, top, right, bottom);
684     for (int j = top; j <= bottom; ++j) {
685         for (int i = left; i <= right; ++i) {
686             // If the layerRect is empty, then we are painting the outer-most set of tiles only.
687             if (layerRect.isEmpty() && i != left && i != right && j != top && j != bottom)
688                 continue;
689             UpdatableTile* tile = tileAt(i, j);
690             if (!tile || !tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat) || tile->isDirty())
691                 return true;
692         }
693     }
694     return false;
695 }
696
697 IntRect TiledLayerChromium::idlePaintRect(const IntRect& visibleLayerRect)
698 {
699     // For layers that are animating transforms but not visible at all, we don't know what part
700     // of them is going to become visible. For small layers we return the entire layer, for larger
701     // ones we avoid prepainting the layer at all.
702     if (visibleLayerRect.isEmpty()) {
703         bool isSmallLayer = m_tiler->numTilesX() <= 9 && m_tiler->numTilesY() <= 9 && m_tiler->numTilesX() * m_tiler->numTilesY() <= 9;
704         if ((drawTransformIsAnimating() || screenSpaceTransformIsAnimating()) && isSmallLayer)
705             return IntRect(IntPoint(), contentBounds());
706         return IntRect();
707     }
708
709     IntRect prepaintRect = visibleLayerRect;
710     // FIXME: This can be made a lot larger if we can:
711     // - reserve memory at a lower priority than for visible content
712     // - only reserve idle paint tiles up to a memory reclaim threshold and
713     // - insure we play nicely with other layers
714     prepaintRect.inflateX(m_tiler->tileSize().width());
715     prepaintRect.inflateY(m_tiler->tileSize().height());
716     prepaintRect.intersect(IntRect(IntPoint::zero(), contentBounds()));
717     return prepaintRect;
718 }
719
720 }
721 #endif // USE(ACCELERATED_COMPOSITING)