void TiledDrawingAreaProxy::paint(const IntRect& rect, PlatformDrawingContext context) { if (m_isWaitingForDidSetFrameNotification) { WebPageProxy* page = this->page(); if (!page->isValid()) return; if (page->process()->isLaunching()) return; } adjustVisibleRect(); GraphicsContext gc(context); gc.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. gc.scale(FloatSize(1 / m_contentsScale, 1 / m_contentsScale)); IntRect dirtyRect = mapFromContents(rect); TiledDrawingAreaTile::Coordinate topLeft = tileCoordinateForPoint(dirtyRect.topLeft()); TiledDrawingAreaTile::Coordinate bottomRight = tileCoordinateForPoint(dirtyRect.bottomRight()); for (unsigned yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoordinate) { for (unsigned xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xCoordinate) { TiledDrawingAreaTile::Coordinate currentCoordinate(xCoordinate, yCoordinate); RefPtr<TiledDrawingAreaTile> currentTile = tileAt(currentCoordinate); if (currentTile && currentTile->isReadyToPaint()) currentTile->paint(&gc, dirtyRect); else { IntRect tileRect = tileRectForCoordinate(currentCoordinate); IntRect target = intersection(tileRect, dirtyRect); if (target.isEmpty()) continue; TiledDrawingAreaTile::paintCheckerPattern(&gc, FloatRect(target)); } } } gc.restore(); }
double TiledDrawingAreaProxy::tileDistance(const IntRect& viewport, const TiledDrawingAreaTile::Coordinate& tileCoordinate) { if (viewport.intersects(tileRectForCoordinate(tileCoordinate))) return 0; IntPoint viewCenter = viewport.location() + IntSize(viewport.width() / 2, viewport.height() / 2); TiledDrawingAreaTile::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 TiledDrawingAreaProxy::createTiles() { IntRect visibleRect = mapFromContents(webViewVisibleRect()); m_previousVisibleRect = visibleRect; if (visibleRect.isEmpty()) return; // Resize tiles on edges in case the contents size has changed. bool didResizeTiles = resizeEdgeTiles(); // Remove tiles outside out current maximum keep rect. dropTilesOutsideRect(calculateKeepRect(visibleRect)); // Cover the cover rect with tiles. IntRect coverRect = calculateCoverRect(visibleRect); // 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<TiledDrawingAreaTile::Coordinate> tilesToCreate; unsigned requiredTileCount = 0; bool hasVisibleCheckers = false; TiledDrawingAreaTile::Coordinate topLeft = tileCoordinateForPoint(coverRect.topLeft()); TiledDrawingAreaTile::Coordinate bottomRight = tileCoordinateForPoint(coverRect.bottomRight()); for (unsigned yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoordinate) { for (unsigned xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xCoordinate) { TiledDrawingAreaTile::Coordinate currentCoordinate(xCoordinate, yCoordinate); // Distance is 0 for all currently visible tiles. double distance = tileDistance(visibleRect, currentCoordinate); RefPtr<TiledDrawingAreaTile> tile = tileAt(currentCoordinate); if (!distance && (!tile || !tile->isReadyToPaint())) hasVisibleCheckers = true; if (tile) continue; ++requiredTileCount; if (distance > shortestDistance) continue; if (distance < shortestDistance) { tilesToCreate.clear(); shortestDistance = distance; } tilesToCreate.append(currentCoordinate); } } if (hasVisibleCheckers && shortestDistance > 0) return; // Now construct the tile(s). unsigned tilesToCreateCount = tilesToCreate.size(); for (unsigned n = 0; n < tilesToCreateCount; ++n) createTile(tilesToCreate[n]); requiredTileCount -= tilesToCreateCount; // Paint the content of the newly created tiles. if (tilesToCreateCount || didResizeTiles) updateTileBuffers(); // Keep creating tiles until the whole coverRect is covered. if (requiredTileCount) m_tileCreationTimer.startOneShot(m_tileCreationDelay); }