private void computeCoverAndKeepRect(final Rect visibleRect, Rect coverRect, Rect keepRect) { visibleRect.copyTo(coverRect); visibleRect.copyTo(keepRect); // If we cover more that the actual viewport we can be smart about which tiles we choose to // render. if (mCoverAreaMultiplier > 1) { // The initial cover area covers equally in each direction, according to the // coverAreaMultiplier. coverRect.inflate( (int) (visibleRect.getWidth() * (mCoverAreaMultiplier - 1) / 2), (int) (visibleRect.getHeight() * (mCoverAreaMultiplier - 1) / 2)); coverRect.copyTo(keepRect); if (mPendingTrajectoryVector.getX() != 0 || mPendingTrajectoryVector.getY() != 0) { // A null trajectory vector (no motion) means that tiles for the coverArea will be created. // A non-null trajectory vector will shrink the covered rect to visibleRect plus its // expansion from its // center toward the cover area edges in the direction of the given vector. // E.g. if visibleRect == (10,10)5x5 and coverAreaMultiplier == 3.0: // a (0,0) trajectory vector will create tiles intersecting (5,5)15x15, // a (1,0) trajectory vector will create tiles intersecting (10,10)10x5, // and a (1,1) trajectory vector will create tiles intersecting (10,10)10x10. // Multiply the vector by the distance to the edge of the cover area. float trajectoryVectorMultiplier = (mCoverAreaMultiplier - 1) / 2; // Unite the visible rect with a "ghost" of the visible rect moved in the direction of the // trajectory vector. visibleRect.copyTo(coverRect); coverRect.offset( (int) (coverRect.getWidth() * mTrajectoryVector.getX() * trajectoryVectorMultiplier), (int) (coverRect.getHeight() * mTrajectoryVector.getY() * trajectoryVectorMultiplier)); coverRect.composite(visibleRect); } assert (keepRect.contains(coverRect)); } adjustForContentsRect(coverRect); // The keep rect is an inflated version of the cover rect, inflated in tile dimensions. keepRect.composite(coverRect); keepRect.inflate(mTileSize.getWidth() / 2, mTileSize.getHeight() / 2); keepRect.intersect(mRect); assert (coverRect.isEmpty() || keepRect.contains(coverRect)); }
public void coverWithTilesIfNeeded(BSTimerTask task) { Rect visibleRect = visibleRect(); Rect rect = mapFromContents(mClient.tbsGetContentsRect()); boolean didChange = !mTrajectoryVector.equals(mPendingTrajectoryVector) || !mVisibleRect.equals(visibleRect) || !mRect.equals(rect); if (didChange || mPendingTileCreation) createTiles(task); }
public void setTrajectoryVector(final PointF trajectoryVector) { if (trajectoryVector == null) return; trajectoryVector.copyTo(mPendingTrajectoryVector); mPendingTrajectoryVector.normalize(); }
private void createTiles(BSTimerTask task) { // Guard here as as these can change before the timer fires. if (isBackingStoreUpdatesSuspended()) return; // Update our backing store geometry. final Rect previousRect = mRect.clone(); mapFromContents(mClient.tbsGetContentsRect()).copyTo(mRect); mPendingTrajectoryVector.copyTo(mTrajectoryVector); visibleRect().copyTo(mVisibleRect); if (mRect.isEmpty()) { setCoverRect(new Rect()); setKeepRect(new Rect()); 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. */ Rect coverRect = new Rect(); Rect keepRect = new Rect(); computeCoverAndKeepRect(mVisibleRect, 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. boolean didResizeTiles = false; if (!previousRect.equals(mRect)) 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 = Double.POSITIVE_INFINITY; List<Coordinate> tilesToCreate = new ArrayList<Coordinate>(); int 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. Coordinate topLeft = tileCoordinateForPoint(coverRect.getLeft(), coverRect.getTop()); Coordinate bottomRight = tileCoordinateForPoint(coverRect.getRight(), coverRect.getBottom()); for (int yCoordinate = topLeft.getY(); yCoordinate <= bottomRight.getY(); ++yCoordinate) { for (int xCoordinate = topLeft.getX(); xCoordinate <= bottomRight.getX(); ++xCoordinate) { if (getTileAt(xCoordinate, yCoordinate) != null) continue; ++requiredTileCount; double distance = tileDistance(mVisibleRect, xCoordinate, yCoordinate); if (distance > shortestDistance) continue; if (distance < shortestDistance) { tilesToCreate.clear(); shortestDistance = distance; } tilesToCreate.add(new Coordinate(xCoordinate, yCoordinate)); } } // Now construct the tile(s) within the shortest distance. int tilesToCreateCount = tilesToCreate.size(); for (int n = 0; n < tilesToCreateCount; ++n) { Coordinate coordinate = tilesToCreate.get(n); setTile(coordinate, mBackend.createTile(coordinate)); } requiredTileCount -= tilesToCreateCount; // Paint the content of the newly created tiles or resized tiles. if (tilesToCreateCount != 0 || didResizeTiles) updateTileBuffers(task); // Re-call createTiles on a timer to cover the visible area with the newest shortest distance. mPendingTileCreation = requiredTileCount != 0; if (mPendingTileCreation) { if (!mCommitTileUpdatesOnIdleEventLoop) { mClient.tbsHasPendingTileCreation(); return; } Log.d( "tt", "start BSUpdate scheduleTask in createTiles func scale " + mContentsScale + " pending scale " + mPendingScale); if (task == null || !task.cancelled()) startBSUpdateTask(TILE_CREATION_DELAY_MS); } }