void TiledBackingStore::paint(GraphicsContext* context, const IntRect& rect) { context->save(); // Assumes the backing store is painted with the scale transform applied. // Since tile content is already scaled, first revert the scaling from the painter. context->scale(FloatSize(1.f / m_contentsScale, 1.f / m_contentsScale)); IntRect dirtyRect = mapFromContents(rect); Tile::Coordinate topLeft = tileCoordinateForPoint(dirtyRect.location()); Tile::Coordinate bottomRight = tileCoordinateForPoint(innerBottomRight(dirtyRect)); for (unsigned yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoordinate) { for (unsigned xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xCoordinate) { Tile::Coordinate currentCoordinate(xCoordinate, yCoordinate); RefPtr<Tile> currentTile = tileAt(currentCoordinate); if (currentTile && currentTile->isReadyToPaint()) currentTile->paint(context, dirtyRect); else { IntRect tileRect = tileRectForCoordinate(currentCoordinate); IntRect target = intersection(tileRect, dirtyRect); if (target.isEmpty()) continue; m_backend->paintCheckerPattern(context, FloatRect(target)); } } } context->restore(); }
void TiledBackingStore::invalidate(const IntRect& contentsDirtyRect) { IntRect dirtyRect(mapFromContents(contentsDirtyRect)); IntRect keepRectFitToTileSize = tileRectForCoordinate(tileCoordinateForPoint(m_keepRect.location())); keepRectFitToTileSize.unite(tileRectForCoordinate(tileCoordinateForPoint(innerBottomRight(m_keepRect)))); // Only iterate on the part of the rect that we know we might have tiles. IntRect coveredDirtyRect = intersection(dirtyRect, keepRectFitToTileSize); Tile::Coordinate topLeft = tileCoordinateForPoint(coveredDirtyRect.location()); Tile::Coordinate bottomRight = tileCoordinateForPoint(innerBottomRight(coveredDirtyRect)); for (int yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoordinate) { for (int xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xCoordinate) { RefPtr<Tile> currentTile = tileAt(Tile::Coordinate(xCoordinate, yCoordinate)); if (!currentTile) continue; // Pass the full rect to each tile as coveredDirtyRect might not // contain them completely and we don't want partial tile redraws. #if PLATFORM(JS) fprintf(stderr, "WebKit: TiledBackingStore: invalidate: invalidating currentTile (x,y,w,h): %i %i %i %i\n",dirtyRect.x(),dirtyRect.y(),dirtyRect.width(),dirtyRect.height()); #endif currentTile->invalidate(dirtyRect); } } startTileBufferUpdateTimer(); }
void TiledBackingStore::invalidate(const IntRect& contentsDirtyRect) { IntRect dirtyRect(mapFromContents(contentsDirtyRect)); Tile::Coordinate topLeft = tileCoordinateForPoint(dirtyRect.location()); Tile::Coordinate bottomRight = tileCoordinateForPoint(innerBottomRight(dirtyRect)); for (unsigned yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoordinate) { for (unsigned xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xCoordinate) { RefPtr<Tile> currentTile = tileAt(Tile::Coordinate(xCoordinate, yCoordinate)); if (!currentTile) continue; currentTile->invalidate(dirtyRect); } } startTileBufferUpdateTimer(); }
IntRect TiledBackingStore::tileRectForCoordinate(const Tile::Coordinate& coordinate) const { IntRect rect(coordinate.x() * m_tileSize.width(), coordinate.y() * m_tileSize.height(), m_tileSize.width(), m_tileSize.height()); rect.intersect(contentsRect()); return rect; }
double TiledBackingStore::tileDistance(const IntRect& viewport, const Tile::Coordinate& tileCoordinate) const { if (viewport.intersects(tileRectForCoordinate(tileCoordinate))) return 0; IntPoint viewCenter = viewport.location() + IntSize(viewport.width() / 2, viewport.height() / 2); Tile::Coordinate centerCoordinate = tileCoordinateForPoint(viewCenter); return std::max(abs(centerCoordinate.y() - tileCoordinate.y()), abs(centerCoordinate.x() - tileCoordinate.x())); }
// Returns a ratio between 0.0f and 1.0f of the surface of contentsRect covered by rendered tiles. float TiledBackingStore::coverageRatio(const WebCore::IntRect& contentsRect) const { IntRect dirtyRect = mapFromContents(contentsRect); float rectArea = dirtyRect.width() * dirtyRect.height(); float coverArea = 0.0f; Tile::Coordinate topLeft = tileCoordinateForPoint(dirtyRect.location()); Tile::Coordinate bottomRight = tileCoordinateForPoint(innerBottomRight(dirtyRect)); for (unsigned yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoordinate) { for (unsigned xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xCoordinate) { Tile::Coordinate currentCoordinate(xCoordinate, yCoordinate); RefPtr<Tile> currentTile = tileAt(Tile::Coordinate(xCoordinate, yCoordinate)); if (currentTile && currentTile->isReadyToPaint()) { IntRect coverRect = intersection(dirtyRect, currentTile->rect()); coverArea += coverRect.width() * coverRect.height(); } } } return coverArea / rectArea; }
double TiledBackingStore::tileDistance(const IntRect& viewport, const Tile::Coordinate& tileCoordinate) const { if (viewport.intersects(tileRectForCoordinate(tileCoordinate))) return 0; IntPoint viewCenter = viewport.location() + IntSize(viewport.width() / 2, viewport.height() / 2); Tile::Coordinate centerCoordinate = tileCoordinateForPoint(viewCenter); // Manhattan distance, biased so that vertical distances are shorter. const double horizontalBias = 1.3; return abs(centerCoordinate.y() - tileCoordinate.y()) + horizontalBias * abs(centerCoordinate.x() - tileCoordinate.x()); }
void TiledBackingStore::createTiles() { if (m_contentsFrozen) return; IntRect visibleRect = visibleContentsRect(); m_previousVisibleRect = visibleRect; if (visibleRect.isEmpty()) return; // Resize tiles on edges in case the contents size has changed. bool didResizeTiles = resizeEdgeTiles(); IntRect keepRect; IntRect coverRect; computeCoverAndKeepRect(visibleRect, coverRect, keepRect); dropTilesOutsideRect(keepRect); // Search for the tile position closest to the viewport center that does not yet contain a tile. // Which position is considered the closest depends on the tileDistance function. double shortestDistance = std::numeric_limits<double>::infinity(); Vector<Tile::Coordinate> tilesToCreate; unsigned requiredTileCount = 0; Tile::Coordinate topLeft = tileCoordinateForPoint(coverRect.location()); Tile::Coordinate bottomRight = tileCoordinateForPoint(innerBottomRight(coverRect)); for (unsigned yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoordinate) { for (unsigned xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xCoordinate) { Tile::Coordinate currentCoordinate(xCoordinate, yCoordinate); if (tileAt(currentCoordinate)) continue; ++requiredTileCount; // Distance is 0 for all tiles inside the visibleRect. double distance = tileDistance(visibleRect, currentCoordinate); if (distance > shortestDistance) continue; if (distance < shortestDistance) { tilesToCreate.clear(); shortestDistance = distance; } tilesToCreate.append(currentCoordinate); } } // Now construct the tile(s) within the shortest distance. unsigned tilesToCreateCount = tilesToCreate.size(); for (unsigned n = 0; n < tilesToCreateCount; ++n) { Tile::Coordinate coordinate = tilesToCreate[n]; setTile(coordinate, m_backend->createTile(this, coordinate)); } requiredTileCount -= tilesToCreateCount; // Paint the content of the newly created tiles. if (tilesToCreateCount || didResizeTiles) updateTileBuffers(); // Re-call createTiles on a timer to cover the visible area with the newest shortest distance. if (requiredTileCount) m_tileCreationTimer->startOneShot(m_tileCreationDelay); }
void TiledBackingStore::createTiles() { // Guard here as as these can change before the timer fires. if (isBackingStoreUpdatesSuspended()) return; // Update our backing store geometry. const IntRect previousRect = m_rect; m_rect = mapFromContents(m_client->tiledBackingStoreContentsRect()); const IntRect visibleRect = this->visibleRect(); m_visibleRect = visibleRect; if (visibleRect.isEmpty()) return; IntRect keepRect; IntRect coverRect; computeCoverAndKeepRect(visibleRect, coverRect, keepRect); setKeepRect(keepRect); // Resize tiles at the edge in case the contents size has changed, but only do so // after having dropped tiles outside the keep rect. bool didResizeTiles = false; if (previousRect != m_rect) didResizeTiles = resizeEdgeTiles(); // Search for the tile position closest to the viewport center that does not yet contain a tile. // Which position is considered the closest depends on the tileDistance function. double shortestDistance = std::numeric_limits<double>::infinity(); Vector<Tile::Coordinate> tilesToCreate; unsigned requiredTileCount = 0; // Cover areas (in tiles) with minimum distance from the visible rect. If the visible rect is // not covered already it will be covered first in one go, due to the distance being 0 for tiles // inside the visible rect. Tile::Coordinate topLeft = tileCoordinateForPoint(coverRect.location()); Tile::Coordinate bottomRight = tileCoordinateForPoint(innerBottomRight(coverRect)); for (unsigned yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoordinate) { for (unsigned xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xCoordinate) { Tile::Coordinate currentCoordinate(xCoordinate, yCoordinate); if (tileAt(currentCoordinate)) continue; ++requiredTileCount; double distance = tileDistance(visibleRect, currentCoordinate); if (distance > shortestDistance) continue; if (distance < shortestDistance) { tilesToCreate.clear(); shortestDistance = distance; } tilesToCreate.append(currentCoordinate); } } // Now construct the tile(s) within the shortest distance. unsigned tilesToCreateCount = tilesToCreate.size(); for (unsigned n = 0; n < tilesToCreateCount; ++n) { Tile::Coordinate coordinate = tilesToCreate[n]; setTile(coordinate, m_backend->createTile(this, coordinate)); } requiredTileCount -= tilesToCreateCount; // Paint the content of the newly created tiles or resized tiles. if (tilesToCreateCount || didResizeTiles) updateTileBuffers(); // Re-call createTiles on a timer to cover the visible area with the newest shortest distance. if (requiredTileCount) m_backingStoreUpdateTimer.startOneShot(m_tileCreationDelay); }
void TiledBackingStore::createTiles() { if (m_contentsFrozen) return; IntRect visibleRect = mapFromContents(m_client->tiledBackingStoreVisibleRect()); m_previousVisibleRect = visibleRect; if (visibleRect.isEmpty()) return; // Remove tiles that extend outside the current contents rect. dropOverhangingTiles(); IntRect keepRect = visibleRect; // Inflates to both sides, so divide inflate delta by 2 keepRect.inflateX(visibleRect.width() * (m_keepAreaMultiplier.width() - 1.f) / 2); keepRect.inflateY(visibleRect.height() * (m_keepAreaMultiplier.height() - 1.f) / 2); keepRect.intersect(contentsRect()); dropTilesOutsideRect(keepRect); IntRect coverRect = visibleRect; // Inflates to both sides, so divide inflate delta by 2 coverRect.inflateX(visibleRect.width() * (m_coverAreaMultiplier.width() - 1.f) / 2); coverRect.inflateY(visibleRect.height() * (m_coverAreaMultiplier.height() - 1.f) / 2); coverRect.intersect(contentsRect()); // Search for the tile position closest to the viewport center that does not yet contain a tile. // Which position is considered the closest depends on the tileDistance function. double shortestDistance = std::numeric_limits<double>::infinity(); Vector<Tile::Coordinate> tilesToCreate; unsigned requiredTileCount = 0; Tile::Coordinate topLeft = tileCoordinateForPoint(coverRect.location()); Tile::Coordinate bottomRight = tileCoordinateForPoint(IntPoint(coverRect.maxX(), coverRect.maxY())); for (unsigned yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoordinate) { for (unsigned xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xCoordinate) { Tile::Coordinate currentCoordinate(xCoordinate, yCoordinate); if (tileAt(currentCoordinate)) continue; ++requiredTileCount; // Distance is 0 for all currently visible tiles. double distance = tileDistance(visibleRect, currentCoordinate); if (distance > shortestDistance) continue; if (distance < shortestDistance) { tilesToCreate.clear(); shortestDistance = distance; } tilesToCreate.append(currentCoordinate); } } // Now construct the tile(s) unsigned tilesToCreateCount = tilesToCreate.size(); for (unsigned n = 0; n < tilesToCreateCount; ++n) { Tile::Coordinate coordinate = tilesToCreate[n]; setTile(coordinate, Tile::create(this, coordinate)); } requiredTileCount -= tilesToCreateCount; // Paint the content of the newly created tiles if (tilesToCreateCount) updateTileBuffers(); // Keep creating tiles until the whole coverRect is covered. if (requiredTileCount) m_tileCreationTimer->startOneShot(m_tileCreationDelay); }
void TiledBackingStore::createTiles() { // Guard here as as these can change before the timer fires. if (isBackingStoreUpdatesSuspended()) return; // Update our backing store geometry. const IntRect previousRect = m_rect; m_rect = mapFromContents(m_client->tiledBackingStoreContentsRect()); m_trajectoryVector = m_pendingTrajectoryVector; m_visibleRect = visibleRect(); if (m_rect.isEmpty()) { setCoverRect(IntRect()); setKeepRect(IntRect()); return; } /* We must compute cover and keep rects using the visibleRect, instead of the rect intersecting the visibleRect with m_rect, * because TBS can be used as a backing store of GraphicsLayer and the visible rect usually does not intersect with m_rect. * In the below case, the intersecting rect is an empty. * * +---------------+ * | | * | m_rect | * | +-------|-----------------------+ * | | HERE | cover or keep | * +---------------+ rect | * | +---------+ | * | | visible | | * | | rect | | * | +---------+ | * | | * | | * +-------------------------------+ * * We must create or keep the tiles in the HERE region. */ IntRect coverRect; IntRect keepRect; computeCoverAndKeepRect(m_visibleRect, coverRect, keepRect); setCoverRect(coverRect); setKeepRect(keepRect); if (coverRect.isEmpty()) return; // Resize tiles at the edge in case the contents size has changed, but only do so // after having dropped tiles outside the keep rect. bool didResizeTiles = false; if (previousRect != m_rect) didResizeTiles = resizeEdgeTiles(); // Search for the tile position closest to the viewport center that does not yet contain a tile. // Which position is considered the closest depends on the tileDistance function. double shortestDistance = std::numeric_limits<double>::infinity(); Vector<Tile::Coordinate> tilesToCreate; unsigned requiredTileCount = 0; // Cover areas (in tiles) with minimum distance from the visible rect. If the visible rect is // not covered already it will be covered first in one go, due to the distance being 0 for tiles // inside the visible rect. Tile::Coordinate topLeft = tileCoordinateForPoint(coverRect.location()); Tile::Coordinate bottomRight = tileCoordinateForPoint(innerBottomRight(coverRect)); for (int yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoordinate) { for (int xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xCoordinate) { Tile::Coordinate currentCoordinate(xCoordinate, yCoordinate); if (tileAt(currentCoordinate)) continue; ++requiredTileCount; double distance = tileDistance(m_visibleRect, currentCoordinate); if (distance > shortestDistance) continue; if (distance < shortestDistance) { tilesToCreate.clear(); shortestDistance = distance; } tilesToCreate.append(currentCoordinate); } } // Now construct the tile(s) within the shortest distance. unsigned tilesToCreateCount = tilesToCreate.size(); for (unsigned n = 0; n < tilesToCreateCount; ++n) { Tile::Coordinate coordinate = tilesToCreate[n]; setTile(coordinate, m_backend->createTile(this, coordinate)); } requiredTileCount -= tilesToCreateCount; // Paint the content of the newly created tiles or resized tiles. if (tilesToCreateCount || didResizeTiles) updateTileBuffers(); // Re-call createTiles on a timer to cover the visible area with the newest shortest distance. m_pendingTileCreation = requiredTileCount; if (m_pendingTileCreation) { if (!m_commitTileUpdatesOnIdleEventLoop) { m_client->tiledBackingStoreHasPendingTileCreation(); return; } static const double tileCreationDelay = 0.01; startBackingStoreUpdateTimer(tileCreationDelay); } }