Modified: trunk/Source/WebCore/platform/graphics/ca/mac/TileCache.mm (137386 => 137387)
--- trunk/Source/WebCore/platform/graphics/ca/mac/TileCache.mm 2012-12-12 00:47:19 UTC (rev 137386)
+++ trunk/Source/WebCore/platform/graphics/ca/mac/TileCache.mm 2012-12-12 00:47:24 UTC (rev 137387)
@@ -94,6 +94,7 @@
, m_tileContainerLayer(adoptCF([[CALayer alloc] init]))
, m_tileSize(defaultTileCacheWidth, defaultTileCacheHeight)
, m_tileRevalidationTimer(this, &TileCache::tileRevalidationTimerFired)
+ , m_cohortRemovalTimer(this, &TileCache::cohortRemovalTimerFired)
, m_scale(1)
, m_deviceScaleFactor(1)
, m_tileCoverage(CoverageForVisibleArea)
@@ -118,8 +119,8 @@
ASSERT(isMainThread());
for (TileMap::iterator it = m_tiles.begin(), end = m_tiles.end(); it != end; ++it) {
- WebTileLayer* tileLayer = it->value.get();
- [tileLayer setTileCache:0];
+ const TileInfo& tileInfo = it->value;
+ [tileInfo.layer.get() setTileCache:0];
}
if (m_tiledScrollingIndicatorLayer)
@@ -140,8 +141,10 @@
void TileCache::setNeedsDisplay()
{
- for (TileMap::const_iterator it = m_tiles.begin(), end = m_tiles.end(); it != end; ++it)
- [it->value.get() setNeedsDisplay];
+ for (TileMap::const_iterator it = m_tiles.begin(), end = m_tiles.end(); it != end; ++it) {
+ const TileInfo& tileInfo = it->value;
+ [tileInfo.layer.get() setNeedsDisplay];
+ }
}
void TileCache::setNeedsDisplayInRect(const IntRect& rect)
@@ -151,37 +154,57 @@
FloatRect scaledRect(rect);
scaledRect.scale(m_scale);
+ IntRect repaintRectInTileCoords(enclosingIntRect(scaledRect));
- // Find the tiles that need to be invalidated.
- IntRect coveredRect = intersection(enclosingIntRect(scaledRect), m_tileCoverageRect);
- if (coveredRect.isEmpty())
+ // For small invalidations, lookup the covered tiles.
+ if (repaintRectInTileCoords.height() < 2 * m_tileSize.height() && repaintRectInTileCoords.width() < 2 * m_tileSize.width()) {
+ TileIndex topLeft;
+ TileIndex bottomRight;
+ getTileIndexRangeForRect(repaintRectInTileCoords, topLeft, bottomRight);
+
+ for (int y = topLeft.y(); y <= bottomRight.y(); ++y) {
+ for (int x = topLeft.x(); x <= bottomRight.x(); ++x) {
+ TileIndex tileIndex(x, y);
+
+ TileMap::iterator it = m_tiles.find(tileIndex);
+ if (it != m_tiles.end())
+ setTileNeedsDisplayInRect(tileIndex, it->value, repaintRectInTileCoords, m_primaryTileCoverageRect);
+ }
+ }
return;
+ }
- TileIndex topLeft;
- TileIndex bottomRight;
- getTileIndexRangeForRect(coveredRect, topLeft, bottomRight);
+ for (TileMap::iterator it = m_tiles.begin(), end = m_tiles.end(); it != end; ++it)
+ setTileNeedsDisplayInRect(it->key, it->value, repaintRectInTileCoords, m_primaryTileCoverageRect);
+}
- for (int y = topLeft.y(); y <= bottomRight.y(); ++y) {
- for (int x = topLeft.x(); x <= bottomRight.x(); ++x) {
- WebTileLayer* tileLayer = tileLayerAtIndex(TileIndex(x, y));
- if (!tileLayer)
- continue;
+void TileCache::setTileNeedsDisplayInRect(const TileIndex& tileIndex, TileInfo& tileInfo, const IntRect& repaintRectInTileCoords, const IntRect& coverageRectInTileCoords)
+{
+ WebTileLayer* tileLayer = tileInfo.layer.get();
- CGRect tileRect = [m_tileCacheLayer convertRect:rect toLayer:tileLayer];
- if (CGRectIsEmpty(tileRect))
- continue;
+ IntRect tileRect = rectForTileIndex(tileIndex);
+ IntRect tileRepaintRect = tileRect;
+ tileRepaintRect.intersect(repaintRectInTileCoords);
+ if (tileRepaintRect.isEmpty())
+ return;
- [tileLayer setNeedsDisplayInRect:tileRect];
+ tileRepaintRect.moveBy(-tileRect.location());
+
+ // We could test for intersection with the visible rect. This would reduce painting yet more,
+ // but may make scrolling stale tiles into view more frequent.
+ if (tileRect.intersects(coverageRectInTileCoords)) {
+ [tileLayer setNeedsDisplayInRect:tileRepaintRect];
- if (shouldShowRepaintCounters()) {
- CGRect bounds = [tileLayer bounds];
- CGRect indicatorRect = CGRectMake(bounds.origin.x, bounds.origin.y, 52, 27);
- [tileLayer setNeedsDisplayInRect:indicatorRect];
- }
+ if (shouldShowRepaintCounters()) {
+ CGRect bounds = [tileLayer bounds];
+ CGRect indicatorRect = CGRectMake(bounds.origin.x, bounds.origin.y, 52, 27);
+ [tileLayer setNeedsDisplayInRect:indicatorRect];
}
- }
+ } else
+ tileInfo.hasStaleContent = true;
}
+
void TileCache::drawLayer(WebTileLayer *layer, CGContextRef context)
{
PlatformCALayer* platformLayer = PlatformCALayer::platformCALayer(m_tileCacheLayer);
@@ -219,10 +242,11 @@
m_scale = scale;
[m_tileContainerLayer.get() setTransform:CATransform3DMakeScale(1 / m_scale, 1 / m_scale, 1)];
- revalidateTiles();
+ revalidateTiles(PruneSecondaryTiles);
for (TileMap::const_iterator it = m_tiles.begin(), end = m_tiles.end(); it != end; ++it) {
- [it->value.get() setContentsScale:deviceScaleFactor];
+ const TileInfo& tileInfo = it->value;
+ [tileInfo.layer.get() setContentsScale:deviceScaleFactor];
IntRect tileRect = rectForTileIndex(it->key);
FloatRect scaledTileRect = tileRect;
@@ -243,8 +267,10 @@
m_acceleratesDrawing = acceleratesDrawing;
- for (TileMap::const_iterator it = m_tiles.begin(), end = m_tiles.end(); it != end; ++it)
- [it->value.get() setAcceleratesDrawing:m_acceleratesDrawing];
+ for (TileMap::const_iterator it = m_tiles.begin(), end = m_tiles.end(); it != end; ++it) {
+ const TileInfo& tileInfo = it->value;
+ [tileInfo.layer.get() setAcceleratesDrawing:m_acceleratesDrawing];
+ }
#else
UNUSED_PARAM(acceleratesDrawing);
#endif
@@ -258,8 +284,8 @@
m_tilesAreOpaque = opaque;
for (TileMap::iterator it = m_tiles.begin(), end = m_tiles.end(); it != end; ++it) {
- WebTileLayer* tileLayer = it->value.get();
- [tileLayer setOpaque:opaque];
+ const TileInfo& tileInfo = it->value;
+ [tileInfo.layer.get() setOpaque:opaque];
}
}
@@ -272,6 +298,11 @@
revalidateTiles();
}
+void TileCache::prepopulateRect(const IntRect& rect)
+{
+ ensureTilesForRect(rect);
+}
+
void TileCache::setIsInWindow(bool isInWindow)
{
if (m_isInWindow == isInWindow)
@@ -305,8 +336,10 @@
return;
m_tileDebugBorderWidth = borderWidth;
- for (TileMap::const_iterator it = m_tiles.begin(), end = m_tiles.end(); it != end; ++it)
- [it->value.get() setBorderWidth:m_tileDebugBorderWidth];
+ for (TileMap::const_iterator it = m_tiles.begin(), end = m_tiles.end(); it != end; ++it) {
+ const TileInfo& tileInfo = it->value;
+ [tileInfo.layer.get() setBorderWidth:m_tileDebugBorderWidth];
+ }
}
void TileCache::setTileDebugBorderColor(CGColorRef borderColor)
@@ -315,8 +348,10 @@
return;
m_tileDebugBorderColor = borderColor;
- for (TileMap::const_iterator it = m_tiles.begin(), end = m_tiles.end(); it != end; ++it)
- [it->value.get() setBorderColor:m_tileDebugBorderColor.get()];
+ for (TileMap::const_iterator it = m_tiles.begin(), end = m_tiles.end(); it != end; ++it) {
+ const TileInfo& tileInfo = it->value;
+ [tileInfo.layer.get() setBorderColor:m_tileDebugBorderColor.get()];
+ }
}
IntRect TileCache::bounds() const
@@ -351,31 +386,47 @@
bottomRight.setY(max(bottomYRatio - 1, 0));
}
-IntRect TileCache::computeTileCoverageRect() const
+IntRect TileCache::computeTileCoverageRect(const IntRect& previousVisibleRect) const
{
- IntRect tileCoverageRect = m_visibleRect;
-
// If the page is not in a window (for example if it's in a background tab), we limit the tile coverage rect to the visible rect.
// Furthermore, if the page can't have scrollbars (for example if its body element has overflow:hidden) it's very unlikely that the
// page will ever be scrolled so we limit the tile coverage rect as well.
- if (m_isInWindow && !(m_tileCoverage & CoverageForSlowScrolling)) {
- // Inflate the coverage rect so that it covers 2x of the visible width and 3x of the visible height.
- // These values were chosen because it's more common to have tall pages and to scroll vertically,
- // so we keep more tiles above and below the current area.
- if (m_tileCoverage & CoverageForHorizontalScrolling)
- tileCoverageRect.inflateX(tileCoverageRect.width() / 2);
+ if (!m_isInWindow || m_tileCoverage & CoverageForSlowScrolling)
+ return m_visibleRect;
- if (m_tileCoverage & CoverageForVerticalScrolling)
- tileCoverageRect.inflateY(tileCoverageRect.height());
- }
+ bool largeVisibleRectChange = !previousVisibleRect.isEmpty() && !m_visibleRect.intersects(previousVisibleRect);
+
+ // FIXME: look at how far the document can scroll in each dimension.
+ int coverageHorizontalSize = m_visibleRect.width();
+ int coverageVerticalSize = m_visibleRect.height();
+
+ // Inflate the coverage rect so that it covers 2x of the visible width and 3x of the visible height.
+ // These values were chosen because it's more common to have tall pages and to scroll vertically,
+ // so we keep more tiles above and below the current area.
+ if (m_tileCoverage & CoverageForHorizontalScrolling && !largeVisibleRectChange)
+ coverageHorizontalSize *= 2;
- return tileCoverageRect;
+ if (m_tileCoverage & CoverageForVerticalScrolling && !largeVisibleRectChange)
+ coverageVerticalSize *= 3;
+
+ // Don't extend coverage before 0 or after the end.
+ IntRect coverageBounds = bounds();
+ int coverageLeft = m_visibleRect.x() - (coverageHorizontalSize - m_visibleRect.width()) / 2;
+ coverageLeft = min(coverageLeft, coverageBounds.maxX() - coverageHorizontalSize);
+ coverageLeft = max(coverageLeft, coverageBounds.x());
+
+ int coverageTop = m_visibleRect.y() - (coverageVerticalSize - m_visibleRect.height()) / 2;
+ coverageTop = min(coverageTop, coverageBounds.maxY() - coverageVerticalSize);
+ coverageTop = max(coverageTop, coverageBounds.y());
+
+ return IntRect(coverageLeft, coverageTop, coverageHorizontalSize, coverageVerticalSize);
}
IntSize TileCache::tileSizeForCoverageRect(const IntRect& coverageRect) const
{
if (m_tileCoverage & CoverageForSlowScrolling)
return coverageRect.size();
+
return IntSize(defaultTileCacheWidth, defaultTileCacheHeight);
}
@@ -389,14 +440,16 @@
void TileCache::tileRevalidationTimerFired(Timer<TileCache>*)
{
- revalidateTiles();
+ revalidateTiles(PruneSecondaryTiles);
}
unsigned TileCache::blankPixelCount() const
{
WebTileLayerList tiles(m_tiles.size());
- tiles.appendRange(m_tiles.begin().values(), m_tiles.end().values());
+ for (TileMap::const_iterator it = m_tiles.begin(), end = m_tiles.end(); it != end; ++it)
+ tiles.append(it->value.layer);
+
return blankPixelCountForTiles(tiles, m_visibleRect, IntPoint(0,0));
}
@@ -420,8 +473,66 @@
return uncoveredRegion.totalArea();
}
-void TileCache::revalidateTiles()
+static inline void queueTileForRemoval(const TileCache::TileIndex& tileIndex, const TileCache::TileInfo& tileInfo, Vector<TileCache::TileIndex>& tilesToRemove)
{
+ WebTileLayer* tileLayer = tileInfo.layer.get();
+ [tileLayer removeFromSuperlayer];
+ [tileLayer setTileCache:0];
+ tilesToRemove.append(tileIndex);
+}
+
+void TileCache::removeAllTiles()
+{
+ Vector<TileIndex> tilesToRemove;
+
+ for (TileMap::iterator it = m_tiles.begin(), end = m_tiles.end(); it != end; ++it)
+ queueTileForRemoval(it->key, it->value, tilesToRemove);
+
+ for (size_t i = 0; i < tilesToRemove.size(); ++i) {
+ TileInfo tileInfo = m_tiles.take(tilesToRemove[i]);
+ LayerPool::sharedPool()->addLayer(tileInfo.layer);
+ }
+}
+
+void TileCache::removeAllSecondaryTiles()
+{
+ Vector<TileIndex> tilesToRemove;
+
+ for (TileMap::iterator it = m_tiles.begin(), end = m_tiles.end(); it != end; ++it) {
+ const TileInfo& tileInfo = it->value;
+ if (tileInfo.cohort == VisibleTileCohort)
+ continue;
+
+ queueTileForRemoval(it->key, it->value, tilesToRemove);
+ }
+
+ for (size_t i = 0; i < tilesToRemove.size(); ++i) {
+ TileInfo tileInfo = m_tiles.take(tilesToRemove[i]);
+ LayerPool::sharedPool()->addLayer(tileInfo.layer);
+ }
+}
+
+void TileCache::removeTilesInCohort(TileCohort cohort)
+{
+ ASSERT(cohort != VisibleTileCohort);
+ Vector<TileIndex> tilesToRemove;
+
+ for (TileMap::iterator it = m_tiles.begin(), end = m_tiles.end(); it != end; ++it) {
+ const TileInfo& tileInfo = it->value;
+ if (tileInfo.cohort != cohort)
+ continue;
+
+ queueTileForRemoval(it->key, it->value, tilesToRemove);
+ }
+
+ for (size_t i = 0; i < tilesToRemove.size(); ++i) {
+ TileInfo tileInfo = m_tiles.take(tilesToRemove[i]);
+ LayerPool::sharedPool()->addLayer(tileInfo.layer);
+ }
+}
+
+void TileCache::revalidateTiles(TileValidationPolicy validationPolicy)
+{
// If the underlying PlatformLayer has been destroyed, but the WebTileCacheLayer hasn't
// platformLayer will be null here.
PlatformCALayer* platformLayer = PlatformCALayer::platformCALayer(m_tileCacheLayer);
@@ -431,58 +542,87 @@
if (m_visibleRect.isEmpty() || bounds().isEmpty())
return;
- IntRect tileCoverageRect = computeTileCoverageRect();
- IntRect coverageRectInTileCoords(tileCoverageRect);
- coverageRectInTileCoords.scale(m_scale);
+ // If the visible rect size changed, drop secondary tiles to avoid lots of repainting.
+ // FIXME: when scaled, this changes due to rounding. We should use FloatRects or something.
+ // Also changes on rubber banding.
+ if (m_visibleRectAtLastRevalidate.size() != m_visibleRect.size())
+ validationPolicy = PruneSecondaryTiles;
+
+ IntRect tileCoverageRect = computeTileCoverageRect(m_visibleRectAtLastRevalidate);
+ FloatRect scaledRect(tileCoverageRect);
+ scaledRect.scale(m_scale);
+ IntRect coverageRectInTileCoords(enclosingIntRect(scaledRect));
IntSize oldTileSize = m_tileSize;
m_tileSize = tileSizeForCoverageRect(tileCoverageRect);
bool tileSizeChanged = m_tileSize != oldTileSize;
- Vector<TileIndex> tilesToRemove;
+ if (tileSizeChanged) {
+ removeAllTiles();
+ m_cohortList.clear();
+ } else {
+ TileCohort currCohort = nextTileCohort();
+ unsigned tilesInCohort = 0;
+
+ // Move tiles newly outside the coverage rect into the cohort map.
+ for (TileMap::iterator it = m_tiles.begin(), end = m_tiles.end(); it != end; ++it) {
+ TileInfo& tileInfo = it->value;
+ TileIndex tileIndex = it->key;
- for (TileMap::iterator it = m_tiles.begin(), end = m_tiles.end(); it != end; ++it) {
- const TileIndex& tileIndex = it->key;
+ WebTileLayer* tileLayer = tileInfo.layer.get();
+ IntRect tileRect = rectForTileIndex(tileIndex);
+ if (tileRect.intersects(coverageRectInTileCoords)) {
+ tileInfo.cohort = VisibleTileCohort;
+ if (tileInfo.hasStaleContent) {
+ // FIXME: store a dirty region per layer?
+ [tileLayer setNeedsDisplay];
+ tileInfo.hasStaleContent = false;
+ }
+ } else {
+ // Add to the currentCohort if not already in one.
+ if (tileInfo.cohort == VisibleTileCohort) {
+ tileInfo.cohort = currCohort;
+ ++tilesInCohort;
+ }
+ }
+ }
+
+ if (tilesInCohort)
+ startedNewCohort(currCohort);
- WebTileLayer* tileLayer = it->value.get();
-
- if (!rectForTileIndex(tileIndex).intersects(coverageRectInTileCoords) || tileSizeChanged) {
- // Remove this layer.
- [tileLayer removeFromSuperlayer];
- [tileLayer setTileCache:0];
-
- tilesToRemove.append(tileIndex);
- }
+ scheduleCohortRemoval();
}
- // FIXME: Be more clever about which tiles to remove. We might not want to remove all
- // the tiles that are outside the coverage rect. When we know that we're going to be scrolling up,
- // we might want to remove the ones below the coverage rect but keep the ones above.
- for (size_t i = 0; i < tilesToRemove.size(); ++i)
- LayerPool::sharedPool()->addLayer(m_tiles.take(tilesToRemove[i]));
-
TileIndex topLeft;
TileIndex bottomRight;
getTileIndexRangeForRect(coverageRectInTileCoords, topLeft, bottomRight);
Vector<FloatRect> dirtyRects;
-
+
+ // Ensure primary tile coverage tiles.
+ m_primaryTileCoverageRect = IntRect();
+ int primaryLayerCount = 0;
+
for (int y = topLeft.y(); y <= bottomRight.y(); ++y) {
for (int x = topLeft.x(); x <= bottomRight.x(); ++x) {
TileIndex tileIndex(x, y);
IntRect tileRect = rectForTileIndex(tileIndex);
- RetainPtr<WebTileLayer>& tileLayer = m_tiles.add(tileIndex, 0).iterator->value;
- if (!tileLayer) {
- tileLayer = createTileLayer(tileRect);
- [m_tileContainerLayer.get() addSublayer:tileLayer.get()];
+ m_primaryTileCoverageRect.unite(tileRect);
+
+ TileInfo& tileInfo = m_tiles.add(tileIndex, TileInfo()).iterator->value;
+ if (!tileInfo.layer) {
+ tileInfo.layer = createTileLayer(tileRect);
+ [m_tileContainerLayer.get() addSublayer:tileInfo.layer.get()];
} else {
// We already have a layer for this tile. Ensure that its size is correct.
- CGSize tileLayerSize = [tileLayer.get() frame].size;
+ CGSize tileLayerSize = [tileInfo.layer.get() frame].size;
if (tileLayerSize.width >= tileRect.width() && tileLayerSize.height >= tileRect.height())
continue;
- [tileLayer.get() setFrame:tileRect];
+ [tileInfo.layer.get() setFrame:tileRect];
}
+
+ ++primaryLayerCount;
FloatRect scaledTileRect = tileRect;
scaledTileRect.scale(1 / m_scale);
@@ -490,21 +630,131 @@
}
}
- m_tileCoverageRect = IntRect();
- for (TileMap::iterator it = m_tiles.begin(), end = m_tiles.end(); it != end; ++it) {
- const TileIndex& tileIndex = it->key;
-
- m_tileCoverageRect.unite(rectForTileIndex(tileIndex));
+ if (validationPolicy == PruneSecondaryTiles) {
+ removeAllSecondaryTiles();
+ m_cohortList.clear();
}
-
+
if (m_tiledScrollingIndicatorLayer)
updateTileCoverageMap();
+ m_visibleRectAtLastRevalidate = m_visibleRect;
+
if (dirtyRects.isEmpty())
return;
platformLayer->owner()->platformCALayerDidCreateTiles(dirtyRects);
}
+TileCache::TileCohort TileCache::nextTileCohort() const
+{
+ if (!m_cohortList.isEmpty())
+ return m_cohortList.last().cohort + 1;
+
+ return 1;
+}
+
+void TileCache::startedNewCohort(TileCohort cohort)
+{
+ m_cohortList.append(TileCohortInfo(cohort, monotonicallyIncreasingTime()));
+}
+
+TileCache::TileCohort TileCache::newestTileCohort() const
+{
+ return m_cohortList.isEmpty() ? 0 : m_cohortList.last().cohort;
+}
+
+TileCache::TileCohort TileCache::oldestTileCohort() const
+{
+ return m_cohortList.isEmpty() ? 0 : m_cohortList.first().cohort;
+}
+
+void TileCache::scheduleCohortRemoval()
+{
+ const double cohortRemovalTimerSeconds = 1;
+
+ // Start the timer, or reschedule the timer from now if it's already active.
+ if (!m_cohortRemovalTimer.isActive())
+ m_cohortRemovalTimer.startRepeating(cohortRemovalTimerSeconds);
+}
+
+void TileCache::cohortRemovalTimerFired(Timer<TileCache>*)
+{
+ if (m_cohortList.isEmpty()) {
+ m_cohortRemovalTimer.stop();
+ return;
+ }
+
+ double cohortLifeTimeSeconds = 2;
+ double timeThreshold = monotonicallyIncreasingTime() - cohortLifeTimeSeconds;
+
+ while (!m_cohortList.isEmpty() && m_cohortList.first().creationTime < timeThreshold) {
+ TileCohortInfo firstCohort = m_cohortList.takeFirst();
+ removeTilesInCohort(firstCohort.cohort);
+ }
+
+ if (m_tiledScrollingIndicatorLayer)
+ updateTileCoverageMap();
+}
+
+void TileCache::ensureTilesForRect(const IntRect& rect)
+{
+ PlatformCALayer* platformLayer = PlatformCALayer::platformCALayer(m_tileCacheLayer);
+ if (!platformLayer)
+ return;
+
+ FloatRect scaledRect(rect);
+ scaledRect.scale(m_scale);
+ IntRect rectInTileCoords(enclosingIntRect(scaledRect));
+
+ if (m_primaryTileCoverageRect.contains(rectInTileCoords))
+ return;
+
+ TileIndex topLeft;
+ TileIndex bottomRight;
+ getTileIndexRangeForRect(rectInTileCoords, topLeft, bottomRight);
+
+ Vector<FloatRect> dirtyRects;
+ TileCohort currCohort = nextTileCohort();
+ unsigned tilesInCohort = 0;
+
+ for (int y = topLeft.y(); y <= bottomRight.y(); ++y) {
+ for (int x = topLeft.x(); x <= bottomRight.x(); ++x) {
+ TileIndex tileIndex(x, y);
+
+ IntRect tileRect = rectForTileIndex(tileIndex);
+ TileInfo& tileInfo = m_tiles.add(tileIndex, TileInfo()).iterator->value;
+ if (!tileInfo.layer) {
+ tileInfo.layer = createTileLayer(tileRect);
+ [m_tileContainerLayer.get() addSublayer:tileInfo.layer.get()];
+ } else {
+ // We already have a layer for this tile. Ensure that its size is correct.
+ CGSize tileLayerSize = [tileInfo.layer.get() frame].size;
+ if (tileLayerSize.width >= tileRect.width() && tileLayerSize.height >= tileRect.height())
+ continue;
+ [tileInfo.layer.get() setFrame:tileRect];
+ }
+
+ if (!tileRect.intersects(m_primaryTileCoverageRect)) {
+ tileInfo.cohort = currCohort;
+ ++tilesInCohort;
+ }
+
+ FloatRect scaledTileRect = tileRect;
+ scaledTileRect.scale(1 / m_scale);
+ dirtyRects.append(scaledTileRect);
+ }
+ }
+
+ if (tilesInCohort)
+ startedNewCohort(currCohort);
+
+ if (m_tiledScrollingIndicatorLayer)
+ updateTileCoverageMap();
+
+ if (!dirtyRects.isEmpty())
+ platformLayer->owner()->platformCALayerDidCreateTiles(dirtyRects);
+}
+
void TileCache::updateTileCoverageMap()
{
FloatRect containerBounds = bounds();
@@ -553,7 +803,7 @@
{
TileIndex topLeft;
TileIndex bottomRight;
- getTileIndexRangeForRect(m_tileCoverageRect, topLeft, bottomRight);
+ getTileIndexRangeForRect(m_primaryTileCoverageRect, topLeft, bottomRight);
// Return index of top, left tile and the number of tiles across and down.
return IntRect(topLeft.x(), topLeft.y(), bottomRight.x() - topLeft.x() + 1, bottomRight.y() - topLeft.y() + 1);
@@ -562,7 +812,7 @@
// Return the rect in layer coords, not tile coords.
IntRect TileCache::tileCoverageRect() const
{
- IntRect coverageRectInLayerCoords(m_tileCoverageRect);
+ IntRect coverageRectInLayerCoords(m_primaryTileCoverageRect);
coverageRectInLayerCoords.scale(1 / m_scale);
return coverageRectInLayerCoords;
}
@@ -594,7 +844,7 @@
WebTileLayer* TileCache::tileLayerAtIndex(const TileIndex& index) const
{
- return m_tiles.get(index).get();
+ return m_tiles.get(index).layer.get();
}
RetainPtr<WebTileLayer> TileCache::createTileLayer(const IntRect& tileRect)
@@ -681,12 +931,11 @@
void TileCache::drawTileMapContents(CGContextRef context, CGRect layerBounds)
{
- CGContextSetRGBFillColor(context, 0.5, 0.5, 0.5, 1);
+ CGContextSetRGBFillColor(context, 0.3, 0.3, 0.3, 1);
CGContextFillRect(context, layerBounds);
CGFloat scaleFactor = layerBounds.size.width / bounds().width();
- CGContextSetRGBFillColor(context, 1, 1, 1, 1);
CGContextSetRGBStrokeColor(context, 0, 0, 0, 1);
CGFloat contextScale = scaleFactor / scale();
@@ -695,7 +944,27 @@
CGContextSetLineWidth(context, 0.5 / contextScale);
for (TileMap::const_iterator it = m_tiles.begin(), end = m_tiles.end(); it != end; ++it) {
- WebTileLayer* tileLayer = it->value.get();
+ const TileInfo& tileInfo = it->value;
+ WebTileLayer* tileLayer = tileInfo.layer.get();
+
+ CGFloat red = 1;
+ CGFloat green = 1;
+ CGFloat blue = 1;
+ if (tileInfo.hasStaleContent) {
+ red = 0.25;
+ green = 0.125;
+ blue = 0;
+ }
+
+ TileCohort newestCohort = newestTileCohort();
+ TileCohort oldestCohort = oldestTileCohort();
+
+ if (tileInfo.cohort != VisibleTileCohort && newestCohort > oldestCohort) {
+ float cohortProportion = static_cast<float>((newestCohort - tileInfo.cohort)) / (newestCohort - oldestCohort);
+ CGContextSetRGBFillColor(context, red, green, blue, 1 - cohortProportion);
+ } else
+ CGContextSetRGBFillColor(context, red, green, blue, 1);
+
CGRect frame = [tileLayer frame];
CGContextFillRect(context, frame);
CGContextStrokeRect(context, frame);