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