[chromium] Compute occlusion during paint loop
[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 "MathExtras.h"
36 #include "Region.h"
37 #include "TextStream.h"
38 #include "cc/CCLayerImpl.h"
39 #include "cc/CCTextureUpdater.h"
40 #include "cc/CCTiledLayerImpl.h"
41 #include <wtf/CurrentTime.h>
42
43 // Start tiling when the width and height of a layer are larger than this size.
44 static int maxUntiledSize = 512;
45
46 // When tiling is enabled, use tiles of this dimension squared.
47 static int defaultTileSize = 256;
48
49 using namespace std;
50
51 namespace WebCore {
52
53 class UpdatableTile : public CCLayerTilingData::Tile {
54     WTF_MAKE_NONCOPYABLE(UpdatableTile);
55 public:
56     explicit UpdatableTile(PassOwnPtr<LayerTextureUpdater::Texture> texture) : m_texture(texture) { }
57
58     LayerTextureUpdater::Texture* texture() { return m_texture.get(); }
59     ManagedTexture* managedTexture() { return m_texture->texture(); }
60
61     bool isDirty() const { return !m_dirtyRect.isEmpty(); }
62     void copyAndClearDirty()
63     {
64         m_updateRect = m_dirtyRect;
65         m_dirtyRect = IntRect();
66     }
67
68     IntRect m_dirtyRect;
69     IntRect m_updateRect;
70     IntRect m_opaqueRect;
71 private:
72     OwnPtr<LayerTextureUpdater::Texture> m_texture;
73 };
74
75 TiledLayerChromium::TiledLayerChromium()
76     : LayerChromium()
77     , m_textureFormat(GraphicsContext3D::INVALID_ENUM)
78     , m_skipsDraw(false)
79     , m_skipsIdlePaint(false)
80     , m_sampledTexelFormat(LayerTextureUpdater::SampledTexelFormatInvalid)
81     , m_tilingOption(AutoTile)
82 {
83     m_tiler = CCLayerTilingData::create(IntSize(defaultTileSize, defaultTileSize), CCLayerTilingData::HasBorderTexels);
84 }
85
86 TiledLayerChromium::~TiledLayerChromium()
87 {
88 }
89
90 PassRefPtr<CCLayerImpl> TiledLayerChromium::createCCLayerImpl()
91 {
92     return CCTiledLayerImpl::create(id());
93 }
94
95 void TiledLayerChromium::cleanupResources()
96 {
97     LayerChromium::cleanupResources();
98
99     m_tiler->reset();
100     m_paintRect = IntRect();
101     m_requestedUpdateTilesRect = IntRect();
102 }
103
104 void TiledLayerChromium::updateTileSizeAndTilingOption()
105 {
106     const IntSize tileSize(min(defaultTileSize, contentBounds().width()), min(defaultTileSize, contentBounds().height()));
107
108     // Tile if both dimensions large, or any one dimension large and the other
109     // extends into a second tile. This heuristic allows for long skinny layers
110     // (e.g. scrollbars) that are Nx1 tiles to minimize wasted texture space.
111     const bool anyDimensionLarge = contentBounds().width() > maxUntiledSize || contentBounds().height() > maxUntiledSize;
112     const bool anyDimensionOneTile = contentBounds().width() <= defaultTileSize || contentBounds().height() <= defaultTileSize;
113     const bool autoTiled = anyDimensionLarge && !anyDimensionOneTile;
114
115     bool isTiled;
116     if (m_tilingOption == AlwaysTile)
117         isTiled = true;
118     else if (m_tilingOption == NeverTile)
119         isTiled = false;
120     else
121         isTiled = autoTiled;
122
123     IntSize requestedSize = isTiled ? tileSize : contentBounds();
124     const int maxSize = layerTreeHost()->layerRendererCapabilities().maxTextureSize;
125     IntSize clampedSize = requestedSize.shrunkTo(IntSize(maxSize, maxSize));
126     setTileSize(clampedSize);
127 }
128
129 void TiledLayerChromium::updateBounds()
130 {
131     IntSize oldBounds = m_tiler->bounds();
132     IntSize newBounds = contentBounds();
133     if (oldBounds == newBounds)
134         return;
135     m_tiler->setBounds(newBounds);
136
137     // Invalidate any areas that the new bounds exposes.
138     Region oldRegion(IntRect(IntPoint(), oldBounds));
139     Region newRegion(IntRect(IntPoint(), newBounds));
140     newRegion.subtract(oldRegion);
141     Vector<IntRect> rects = newRegion.rects();
142     for (size_t i = 0; i < rects.size(); ++i)
143         invalidateRect(rects[i]);
144 }
145
146 void TiledLayerChromium::setTileSize(const IntSize& size)
147 {
148     m_tiler->setTileSize(size);
149 }
150
151 void TiledLayerChromium::setBorderTexelOption(CCLayerTilingData::BorderTexelOption borderTexelOption)
152 {
153     m_tiler->setBorderTexelOption(borderTexelOption);
154 }
155
156 bool TiledLayerChromium::drawsContent() const
157 {
158     if (!LayerChromium::drawsContent())
159         return false;
160
161     if (m_tilingOption == NeverTile && m_tiler->numTiles() > 1)
162         return false;
163
164     return true;
165 }
166
167 bool TiledLayerChromium::needsContentsScale() const
168 {
169     return true;
170 }
171
172 IntSize TiledLayerChromium::contentBounds() const
173 {
174     return IntSize(lroundf(bounds().width() * contentsScale()), lroundf(bounds().height() * contentsScale()));
175 }
176
177 void TiledLayerChromium::setLayerTreeHost(CCLayerTreeHost* host)
178 {
179     if (host == layerTreeHost())
180         return;
181
182     LayerChromium::setLayerTreeHost(host);
183
184     if (!host)
185         return;
186
187     createTextureUpdater(host);
188     setTextureFormat(host->layerRendererCapabilities().bestTextureFormat);
189     m_sampledTexelFormat = textureUpdater()->sampledTexelFormat(m_textureFormat);
190 }
191
192 void TiledLayerChromium::updateCompositorResources(GraphicsContext3D*, CCTextureUpdater& updater)
193 {
194     // Painting could cause compositing to get turned off, which may cause the tiler to become invalidated mid-update.
195     if (m_skipsDraw || m_requestedUpdateTilesRect.isEmpty() || m_tiler->isEmpty())
196         return;
197
198     int left = m_requestedUpdateTilesRect.x();
199     int top = m_requestedUpdateTilesRect.y();
200     int right = m_requestedUpdateTilesRect.maxX() - 1;
201     int bottom = m_requestedUpdateTilesRect.maxY() - 1;
202     for (int j = top; j <= bottom; ++j) {
203         for (int i = left; i <= right; ++i) {
204             UpdatableTile* tile = tileAt(i, j);
205
206             // Required tiles are created in prepareToUpdate(). A tile should
207             // never be removed between the call to prepareToUpdate() and the
208             // call to updateCompositorResources().
209             if (!tile)
210                 CRASH();
211
212             IntRect sourceRect = tile->m_updateRect;
213             if (tile->m_updateRect.isEmpty())
214                 continue;
215
216             ASSERT(tile->managedTexture()->isReserved());
217             const IntPoint anchor = m_tiler->tileRect(tile).location();
218
219             // Calculate tile-space rectangle to upload into.
220             IntRect destRect(IntPoint(sourceRect.x() - anchor.x(), sourceRect.y() - anchor.y()), sourceRect.size());
221             if (destRect.x() < 0)
222                 CRASH();
223             if (destRect.y() < 0)
224                 CRASH();
225
226             // Offset from paint rectangle to this tile's dirty rectangle.
227             IntPoint paintOffset(sourceRect.x() - m_paintRect.x(), sourceRect.y() - m_paintRect.y());
228             if (paintOffset.x() < 0)
229                 CRASH();
230             if (paintOffset.y() < 0)
231                 CRASH();
232             if (paintOffset.x() + destRect.width() > m_paintRect.width())
233                 CRASH();
234             if (paintOffset.y() + destRect.height() > m_paintRect.height())
235                 CRASH();
236
237             updater.append(tile->texture(), sourceRect, destRect);
238         }
239     }
240
241     // The updateRect should be in layer space. So we have to convert the paintRect from content space to layer space.
242     m_updateRect = FloatRect(m_paintRect);
243     float widthScale = bounds().width() / static_cast<float>(contentBounds().width());
244     float heightScale = bounds().height() / static_cast<float>(contentBounds().height());
245     m_updateRect.scale(widthScale, heightScale);
246 }
247
248 void TiledLayerChromium::setTilingOption(TilingOption tilingOption)
249 {
250     m_tilingOption = tilingOption;
251 }
252
253 void TiledLayerChromium::setIsMask(bool isMask)
254 {
255     setTilingOption(isMask ? NeverTile : AutoTile);
256 }
257
258 void TiledLayerChromium::pushPropertiesTo(CCLayerImpl* layer)
259 {
260     LayerChromium::pushPropertiesTo(layer);
261
262     CCTiledLayerImpl* tiledLayer = static_cast<CCTiledLayerImpl*>(layer);
263
264     tiledLayer->setSkipsDraw(m_skipsDraw);
265     tiledLayer->setContentsSwizzled(m_sampledTexelFormat != LayerTextureUpdater::SampledTexelFormatRGBA);
266     tiledLayer->setTilingData(*m_tiler);
267
268     for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) {
269         int i = iter->first.first;
270         int j = iter->first.second;
271         UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
272         if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat))
273             continue;
274         if (tile->isDirty())
275             continue;
276
277         tiledLayer->pushTileProperties(i, j, tile->managedTexture()->textureId(), tile->m_opaqueRect);
278     }
279 }
280
281 TextureManager* TiledLayerChromium::textureManager() const
282 {
283     if (!layerTreeHost())
284         return 0;
285     return layerTreeHost()->contentsTextureManager();
286 }
287
288 UpdatableTile* TiledLayerChromium::tileAt(int i, int j) const
289 {
290     return static_cast<UpdatableTile*>(m_tiler->tileAt(i, j));
291 }
292
293 UpdatableTile* TiledLayerChromium::createTile(int i, int j)
294 {
295     RefPtr<UpdatableTile> tile = adoptRef(new UpdatableTile(textureUpdater()->createTexture(textureManager())));
296     m_tiler->addTile(tile, i, j);
297     tile->m_dirtyRect = m_tiler->tileRect(tile.get());
298
299     return tile.get();
300 }
301
302 void TiledLayerChromium::setNeedsDisplayRect(const FloatRect& dirtyRect)
303 {
304     IntRect dirty = enclosingIntRect(dirtyRect);
305     invalidateRect(dirty);
306     LayerChromium::setNeedsDisplayRect(dirtyRect);
307 }
308
309 void TiledLayerChromium::setIsNonCompositedContent(bool isNonCompositedContent)
310 {
311     LayerChromium::setIsNonCompositedContent(isNonCompositedContent);
312
313     CCLayerTilingData::BorderTexelOption borderTexelOption;
314 #if OS(ANDROID)
315     // Always want border texels and GL_LINEAR due to pinch zoom.
316     borderTexelOption = CCLayerTilingData::HasBorderTexels;
317 #else
318     borderTexelOption = isNonCompositedContent ? CCLayerTilingData::NoBorderTexels : CCLayerTilingData::HasBorderTexels;
319 #endif
320     setBorderTexelOption(borderTexelOption);
321 }
322
323 void TiledLayerChromium::invalidateRect(const IntRect& layerRect)
324 {
325     if (m_tiler->isEmpty() || layerRect.isEmpty() || m_skipsDraw)
326         return;
327
328     int left, top, right, bottom;
329     m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom);
330     for (int j = top; j <= bottom; ++j) {
331         for (int i = left; i <= right; ++i) {
332             UpdatableTile* tile = tileAt(i, j);
333             if (!tile)
334                 continue;
335             IntRect bound = m_tiler->tileRect(tile);
336             bound.intersect(layerRect);
337             tile->m_dirtyRect.unite(bound);
338         }
339     }
340 }
341
342 void TiledLayerChromium::protectVisibleTileTextures()
343 {
344     protectTileTextures(IntRect(IntPoint::zero(), contentBounds()));
345 }
346
347 void TiledLayerChromium::protectTileTextures(const IntRect& layerRect)
348 {
349     if (m_tiler->isEmpty() || layerRect.isEmpty())
350         return;
351
352     int left, top, right, bottom;
353     m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom);
354
355     for (int j = top; j <= bottom; ++j) {
356         for (int i = left; i <= right; ++i) {
357             UpdatableTile* tile = tileAt(i, j);
358             if (!tile || !tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat))
359                 continue;
360
361             tile->managedTexture()->reserve(m_tiler->tileSize(), m_textureFormat);
362         }
363     }
364 }
365
366 void TiledLayerChromium::prepareToUpdateTiles(bool idle, int left, int top, int right, int bottom)
367 {
368     // Reset m_updateRect for all tiles.
369     for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) {
370         UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get());
371         tile->m_updateRect = IntRect();
372     }
373
374     // Create tiles as needed, expanding a dirty rect to contain all
375     // the dirty regions currently being drawn. All dirty tiles that are to be painted
376     // get their m_updateRect set to m_dirtyRect and m_dirtyRect cleared. This way if
377     // invalidateRect is invoked during prepareToUpdate we don't lose the request.
378     IntRect dirtyLayerRect;
379     for (int j = top; j <= bottom; ++j) {
380         for (int i = left; i <= right; ++i) {
381             UpdatableTile* tile = tileAt(i, j);
382             if (!tile)
383                 tile = createTile(i, j);
384
385             // Do post commit deletion of current texture when partial texture
386             // updates are not used.
387             if (tile->isDirty() && layerTreeHost() && !layerTreeHost()->settings().partialTextureUpdates)
388                 layerTreeHost()->deleteTextureAfterCommit(tile->managedTexture()->steal());
389
390             if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat))
391                 tile->m_dirtyRect = m_tiler->tileRect(tile);
392
393             if (!tile->managedTexture()->reserve(m_tiler->tileSize(), m_textureFormat)) {
394                 m_skipsIdlePaint = true;
395                 if (!idle) {
396                     // If the background covers the viewport, always draw this
397                     // layer so that checkerboarded tiles will still draw.
398                     if (!backgroundCoversViewport())
399                         m_skipsDraw = true;
400                     cleanupResources();
401                 }
402                 return;
403             }
404
405             dirtyLayerRect.unite(tile->m_dirtyRect);
406             tile->copyAndClearDirty();
407         }
408     }
409
410     m_paintRect = dirtyLayerRect;
411     if (dirtyLayerRect.isEmpty())
412         return;
413
414     // Due to borders, when the paint rect is extended to tile boundaries, it
415     // may end up overlapping more tiles than the original content rect. Record
416     // the original tiles so we don't upload more tiles than necessary.
417     if (!m_paintRect.isEmpty())
418         m_requestedUpdateTilesRect = IntRect(left, top, right - left + 1, bottom - top + 1);
419
420     // Calling prepareToUpdate() calls into WebKit to paint, which may have the side
421     // effect of disabling compositing, which causes our reference to the texture updater to be deleted.
422     // However, we can't free the memory backing the GraphicsContext until the paint finishes,
423     // so we grab a local reference here to hold the updater alive until the paint completes.
424     RefPtr<LayerTextureUpdater> protector(textureUpdater());
425     IntRect paintedOpaqueRect;
426     textureUpdater()->prepareToUpdate(m_paintRect, m_tiler->tileSize(), m_tiler->hasBorderTexels(), contentsScale(), &paintedOpaqueRect);
427     for (int j = top; j <= bottom; ++j) {
428         for (int i = left; i <= right; ++i) {
429             UpdatableTile* tile = tileAt(i, j);
430
431             // Tiles are created before prepareToUpdate() is called.
432             if (!tile)
433                 CRASH();
434
435             IntRect tileRect = m_tiler->tileBounds(i, j);
436
437             // Save what was painted opaque in the tile. If everything painted in the tile was opaque, and the area is a subset of an
438             // already opaque area, keep the old area.
439             IntRect tilePaintedRect = intersection(tileRect, m_paintRect);
440             IntRect tilePaintedOpaqueRect = intersection(tileRect, paintedOpaqueRect);
441             if (tilePaintedOpaqueRect != tilePaintedRect || !tile->m_opaqueRect.contains(tilePaintedOpaqueRect))
442                 tile->m_opaqueRect = tilePaintedOpaqueRect;
443
444             // Use m_updateRect as copyAndClearDirty above moved the existing dirty rect to m_updateRect.
445             const IntRect& dirtyRect = tile->m_updateRect;
446             if (dirtyRect.isEmpty())
447                 continue;
448
449             // sourceRect starts as a full-sized tile with border texels included.
450             IntRect sourceRect = m_tiler->tileRect(tile);
451             sourceRect.intersect(dirtyRect);
452             // Paint rect not guaranteed to line up on tile boundaries, so
453             // make sure that sourceRect doesn't extend outside of it.
454             sourceRect.intersect(m_paintRect);
455
456             tile->m_updateRect = sourceRect;
457             if (sourceRect.isEmpty())
458                 continue;
459
460             tile->texture()->prepareRect(sourceRect);
461         }
462     }
463 }
464
465 void TiledLayerChromium::reserveTextures()
466 {
467     updateBounds();
468
469     const IntRect& layerRect = visibleLayerRect();
470     if (layerRect.isEmpty() || !m_tiler->numTiles())
471         return;
472
473     int left, top, right, bottom;
474     m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom);
475
476     for (int j = top; j <= bottom; ++j) {
477         for (int i = left; i <= right; ++i) {
478             UpdatableTile* tile = tileAt(i, j);
479             if (!tile)
480                 tile = createTile(i, j);
481
482             if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat))
483                 tile->m_dirtyRect = m_tiler->tileRect(tile);
484
485             if (!tile->managedTexture()->reserve(m_tiler->tileSize(), m_textureFormat))
486                 return;
487         }
488     }
489 }
490
491 void TiledLayerChromium::addSelfToOccludedScreenSpace(Region& occludedScreenSpace)
492 {
493     if (m_skipsDraw || drawOpacity() != 1 || !isPaintedAxisAlignedInScreen())
494         return;
495
496     if (opaque()) {
497         LayerChromium::addSelfToOccludedScreenSpace(occludedScreenSpace);
498         return;
499     }
500
501     IntRect visibleRect = visibleLayerRect();
502     TransformationMatrix contentTransform = contentToScreenSpaceTransform();
503
504     // FIXME: Create/Use a FloatRegion for the occludedScreenSpace, instead of a Region based on ints, to avoid this step and get better accuracy between layers in target space.
505     Region tileRegion;
506     int left, top, right, bottom;
507     m_tiler->layerRectToTileIndices(visibleLayerRect(), left, top, right, bottom);
508     for (int j = top; j <= bottom; ++j) {
509         for (int i = left; i <= right; ++i) {
510             UpdatableTile* tile = tileAt(i, j);
511             if (tile) {
512                 IntRect visibleTileOpaqueRect = intersection(visibleRect, tile->m_opaqueRect);
513                 FloatRect screenRect = contentTransform.mapRect(FloatRect(visibleTileOpaqueRect));
514                 occludedScreenSpace.unite(enclosedIntRect(screenRect));
515             }
516         }
517     }
518 }
519
520 void TiledLayerChromium::prepareToUpdate(const IntRect& layerRect)
521 {
522     m_skipsDraw = false;
523     m_skipsIdlePaint = false;
524     m_requestedUpdateTilesRect = IntRect();
525     m_paintRect = IntRect();
526
527     updateBounds();
528
529     if (layerRect.isEmpty() || !m_tiler->numTiles())
530         return;
531
532     int left, top, right, bottom;
533     m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom);
534
535     prepareToUpdateTiles(false, left, top, right, bottom);
536 }
537
538 void TiledLayerChromium::prepareToUpdateIdle(const IntRect& layerRect)
539 {
540     // Abort if we have already prepared a paint or run out of memory.
541     if (m_skipsIdlePaint || !m_paintRect.isEmpty())
542         return;
543
544     ASSERT(m_tiler);
545
546     updateBounds();
547
548     if (m_tiler->isEmpty())
549         return;
550
551     // Protect any textures in the pre-paint area so we don't end up just
552     // reclaiming them below.
553     IntRect idlePaintLayerRect = idlePaintRect(layerRect);
554     protectTileTextures(idlePaintLayerRect);
555
556     // Expand outwards until we find a dirty row or column to update.
557     int left, top, right, bottom;
558     m_tiler->layerRectToTileIndices(layerRect, left, top, right, bottom);
559     int prepaintLeft, prepaintTop, prepaintRight, prepaintBottom;
560     m_tiler->layerRectToTileIndices(idlePaintLayerRect, prepaintLeft, prepaintTop, prepaintRight, prepaintBottom);
561     while (!m_skipsIdlePaint && (left > prepaintLeft || top > prepaintTop || right < prepaintRight || bottom < prepaintBottom)) {
562         if (bottom < prepaintBottom) {
563             ++bottom;
564             prepareToUpdateTiles(true, left, bottom, right, bottom);
565             if (!m_paintRect.isEmpty() || m_skipsIdlePaint)
566                 break;
567         }
568         if (top > prepaintTop) {
569             --top;
570             prepareToUpdateTiles(true, left, top, right, top);
571             if (!m_paintRect.isEmpty() || m_skipsIdlePaint)
572                 break;
573         }
574         if (left > prepaintLeft) {
575             --left;
576             prepareToUpdateTiles(true, left, top, left, bottom);
577             if (!m_paintRect.isEmpty() || m_skipsIdlePaint)
578                 break;
579         }
580         if (right < prepaintRight) {
581             ++right;
582             prepareToUpdateTiles(true, right, top, right, bottom);
583             if (!m_paintRect.isEmpty() || m_skipsIdlePaint)
584                 break;
585         }
586     }
587 }
588
589 bool TiledLayerChromium::needsIdlePaint(const IntRect& layerRect)
590 {
591     if (m_skipsIdlePaint)
592         return false;
593
594     IntRect idlePaintLayerRect = idlePaintRect(layerRect);
595
596     int left, top, right, bottom;
597     m_tiler->layerRectToTileIndices(idlePaintLayerRect, left, top, right, bottom);
598     for (int j = top; j <= bottom; ++j) {
599         for (int i = left; i <= right; ++i) {
600             if (m_requestedUpdateTilesRect.contains(IntPoint(i, j)))
601                 continue;
602             UpdatableTile* tile = tileAt(i, j);
603             if (!tile || !tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat) || tile->isDirty())
604                 return true;
605         }
606     }
607     return false;
608 }
609
610 IntRect TiledLayerChromium::idlePaintRect(const IntRect& visibleLayerRect)
611 {
612     IntRect prepaintRect = visibleLayerRect;
613     // FIXME: This can be made a lot larger if we can:
614     // - reserve memory at a lower priority than for visible content
615     // - only reserve idle paint tiles up to a memory reclaim threshold and
616     // - insure we play nicely with other layers
617     prepaintRect.inflateX(m_tiler->tileSize().width());
618     prepaintRect.inflateY(m_tiler->tileSize().height());
619     prepaintRect.intersect(IntRect(IntPoint::zero(), contentBounds()));
620     return prepaintRect;
621 }
622
623 }
624 #endif // USE(ACCELERATED_COMPOSITING)