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