| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 Copyright (C) 2010-2012 Nokia Corporation and/or its subsidiary(-ies) | |
| 3 | |
| 4 This library is free software; you can redistribute it and/or | |
| 5 modify it under the terms of the GNU Library General Public | |
| 6 License as published by the Free Software Foundation; either | |
| 7 version 2 of the License, or (at your option) any later version. | |
| 8 | |
| 9 This library is distributed in the hope that it will be useful, | |
| 10 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 12 Library General Public License for more details. | |
| 13 | |
| 14 You should have received a copy of the GNU Library General Public License | |
| 15 along with this library; see the file COPYING.LIB. If not, write to | |
| 16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
| 17 Boston, MA 02110-1301, USA. | |
| 18 */ | |
| 19 | |
| 20 #include "config.h" | |
| 21 #include "TiledBackingStore.h" | |
| 22 | |
| 23 #if USE(TILED_BACKING_STORE) | |
| 24 | |
| 25 #include "GraphicsContext.h" | |
| 26 #include "TiledBackingStoreClient.h" | |
| 27 | |
| 28 namespace WebCore { | |
| 29 | |
| 30 static const int defaultTileDimension = 512; | |
| 31 | |
| 32 static IntPoint innerBottomRight(const IntRect& rect) | |
| 33 { | |
| 34 // Actually, the rect does not contain rect.maxX(). Refer to IntRect::contai
n. | |
| 35 return IntPoint(rect.maxX() - 1, rect.maxY() - 1); | |
| 36 } | |
| 37 | |
| 38 TiledBackingStore::TiledBackingStore(TiledBackingStoreClient* client, PassOwnPtr
<TiledBackingStoreBackend> backend) | |
| 39 : m_client(client) | |
| 40 , m_backend(backend) | |
| 41 , m_tileBufferUpdateTimer(this, &TiledBackingStore::tileBufferUpdateTimerFir
ed) | |
| 42 , m_backingStoreUpdateTimer(this, &TiledBackingStore::backingStoreUpdateTime
rFired) | |
| 43 , m_tileSize(defaultTileDimension, defaultTileDimension) | |
| 44 , m_coverAreaMultiplier(2.0f) | |
| 45 , m_contentsScale(1.f) | |
| 46 , m_pendingScale(0) | |
| 47 , m_commitTileUpdatesOnIdleEventLoop(false) | |
| 48 , m_contentsFrozen(false) | |
| 49 , m_supportsAlpha(false) | |
| 50 , m_pendingTileCreation(false) | |
| 51 { | |
| 52 } | |
| 53 | |
| 54 TiledBackingStore::~TiledBackingStore() | |
| 55 { | |
| 56 } | |
| 57 | |
| 58 void TiledBackingStore::setTileSize(const IntSize& size) | |
| 59 { | |
| 60 m_tileSize = size; | |
| 61 m_tiles.clear(); | |
| 62 startBackingStoreUpdateTimer(); | |
| 63 } | |
| 64 | |
| 65 void TiledBackingStore::setTrajectoryVector(const FloatPoint& trajectoryVector) | |
| 66 { | |
| 67 m_pendingTrajectoryVector = trajectoryVector; | |
| 68 m_pendingTrajectoryVector.normalize(); | |
| 69 } | |
| 70 | |
| 71 void TiledBackingStore::coverWithTilesIfNeeded() | |
| 72 { | |
| 73 IntRect visibleRect = this->visibleRect(); | |
| 74 IntRect rect = mapFromContents(m_client->tiledBackingStoreContentsRect()); | |
| 75 | |
| 76 bool didChange = m_trajectoryVector != m_pendingTrajectoryVector || m_visibl
eRect != visibleRect || m_rect != rect; | |
| 77 if (didChange || m_pendingTileCreation) | |
| 78 createTiles(); | |
| 79 } | |
| 80 | |
| 81 void TiledBackingStore::invalidate(const IntRect& contentsDirtyRect) | |
| 82 { | |
| 83 IntRect dirtyRect(mapFromContents(contentsDirtyRect)); | |
| 84 | |
| 85 // Only iterate on the part of the rect that we know we might have tiles. | |
| 86 IntRect coveredDirtyRect = intersection(dirtyRect, m_keepRect); | |
| 87 Tile::Coordinate topLeft = tileCoordinateForPoint(coveredDirtyRect.location(
)); | |
| 88 Tile::Coordinate bottomRight = tileCoordinateForPoint(innerBottomRight(cover
edDirtyRect)); | |
| 89 | |
| 90 for (int yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoord
inate) { | |
| 91 for (int xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xC
oordinate) { | |
| 92 RefPtr<Tile> currentTile = tileAt(Tile::Coordinate(xCoordinate, yCoo
rdinate)); | |
| 93 if (!currentTile) | |
| 94 continue; | |
| 95 // Pass the full rect to each tile as coveredDirtyRect might not | |
| 96 // contain them completely and we don't want partial tile redraws. | |
| 97 currentTile->invalidate(dirtyRect); | |
| 98 } | |
| 99 } | |
| 100 | |
| 101 startTileBufferUpdateTimer(); | |
| 102 } | |
| 103 | |
| 104 void TiledBackingStore::updateTileBuffers() | |
| 105 { | |
| 106 if (m_contentsFrozen) | |
| 107 return; | |
| 108 | |
| 109 m_client->tiledBackingStorePaintBegin(); | |
| 110 | |
| 111 Vector<IntRect> paintedArea; | |
| 112 Vector<RefPtr<Tile> > dirtyTiles; | |
| 113 TileMap::iterator end = m_tiles.end(); | |
| 114 for (TileMap::iterator it = m_tiles.begin(); it != end; ++it) { | |
| 115 if (!it->value->isDirty()) | |
| 116 continue; | |
| 117 dirtyTiles.append(it->value); | |
| 118 } | |
| 119 | |
| 120 if (dirtyTiles.isEmpty()) { | |
| 121 m_client->tiledBackingStorePaintEnd(paintedArea); | |
| 122 return; | |
| 123 } | |
| 124 | |
| 125 // FIXME: In single threaded case, tile back buffers could be updated asynch
ronously | |
| 126 // one by one and then swapped to front in one go. This would minimize the t
ime spent | |
| 127 // blocking on tile updates. | |
| 128 unsigned size = dirtyTiles.size(); | |
| 129 for (unsigned n = 0; n < size; ++n) { | |
| 130 Vector<IntRect> paintedRects = dirtyTiles[n]->updateBackBuffer(); | |
| 131 paintedArea.append(paintedRects); | |
| 132 dirtyTiles[n]->swapBackBufferToFront(); | |
| 133 } | |
| 134 | |
| 135 m_client->tiledBackingStorePaintEnd(paintedArea); | |
| 136 } | |
| 137 | |
| 138 void TiledBackingStore::paint(GraphicsContext* context, const IntRect& rect) | |
| 139 { | |
| 140 context->save(); | |
| 141 | |
| 142 // Assumes the backing store is painted with the scale transform applied. | |
| 143 // Since tile content is already scaled, first revert the scaling from the p
ainter. | |
| 144 context->scale(FloatSize(1.f / m_contentsScale, 1.f / m_contentsScale)); | |
| 145 | |
| 146 IntRect dirtyRect = mapFromContents(rect); | |
| 147 | |
| 148 Tile::Coordinate topLeft = tileCoordinateForPoint(dirtyRect.location()); | |
| 149 Tile::Coordinate bottomRight = tileCoordinateForPoint(innerBottomRight(dirty
Rect)); | |
| 150 | |
| 151 for (int yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoord
inate) { | |
| 152 for (int xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xC
oordinate) { | |
| 153 Tile::Coordinate currentCoordinate(xCoordinate, yCoordinate); | |
| 154 RefPtr<Tile> currentTile = tileAt(currentCoordinate); | |
| 155 if (currentTile && currentTile->isReadyToPaint()) | |
| 156 currentTile->paint(context, dirtyRect); | |
| 157 else { | |
| 158 IntRect tileRect = tileRectForCoordinate(currentCoordinate); | |
| 159 IntRect target = intersection(tileRect, dirtyRect); | |
| 160 if (target.isEmpty()) | |
| 161 continue; | |
| 162 m_backend->paintCheckerPattern(context, FloatRect(target)); | |
| 163 } | |
| 164 } | |
| 165 } | |
| 166 context->restore(); | |
| 167 } | |
| 168 | |
| 169 IntRect TiledBackingStore::visibleRect() const | |
| 170 { | |
| 171 return mapFromContents(m_client->tiledBackingStoreVisibleRect()); | |
| 172 } | |
| 173 | |
| 174 void TiledBackingStore::setContentsScale(float scale) | |
| 175 { | |
| 176 if (m_pendingScale == m_contentsScale) { | |
| 177 m_pendingScale = 0; | |
| 178 return; | |
| 179 } | |
| 180 m_pendingScale = scale; | |
| 181 if (m_contentsFrozen) | |
| 182 return; | |
| 183 commitScaleChange(); | |
| 184 } | |
| 185 | |
| 186 void TiledBackingStore::commitScaleChange() | |
| 187 { | |
| 188 m_contentsScale = m_pendingScale; | |
| 189 m_pendingScale = 0; | |
| 190 m_tiles.clear(); | |
| 191 coverWithTilesIfNeeded(); | |
| 192 } | |
| 193 | |
| 194 double TiledBackingStore::tileDistance(const IntRect& viewport, const Tile::Coor
dinate& tileCoordinate) const | |
| 195 { | |
| 196 if (viewport.intersects(tileRectForCoordinate(tileCoordinate))) | |
| 197 return 0; | |
| 198 | |
| 199 IntPoint viewCenter = viewport.location() + IntSize(viewport.width() / 2, vi
ewport.height() / 2); | |
| 200 Tile::Coordinate centerCoordinate = tileCoordinateForPoint(viewCenter); | |
| 201 | |
| 202 return std::max(abs(centerCoordinate.y() - tileCoordinate.y()), abs(centerCo
ordinate.x() - tileCoordinate.x())); | |
| 203 } | |
| 204 | |
| 205 // Returns a ratio between 0.0f and 1.0f of the surface of contentsRect covered
by rendered tiles. | |
| 206 float TiledBackingStore::coverageRatio(const WebCore::IntRect& contentsRect) con
st | |
| 207 { | |
| 208 IntRect dirtyRect = mapFromContents(contentsRect); | |
| 209 float rectArea = dirtyRect.width() * dirtyRect.height(); | |
| 210 float coverArea = 0.0f; | |
| 211 | |
| 212 Tile::Coordinate topLeft = tileCoordinateForPoint(dirtyRect.location()); | |
| 213 Tile::Coordinate bottomRight = tileCoordinateForPoint(innerBottomRight(dirty
Rect)); | |
| 214 | |
| 215 for (int yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoord
inate) { | |
| 216 for (int xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xC
oordinate) { | |
| 217 Tile::Coordinate currentCoordinate(xCoordinate, yCoordinate); | |
| 218 RefPtr<Tile> currentTile = tileAt(currentCoordinate); | |
| 219 if (currentTile && currentTile->isReadyToPaint()) { | |
| 220 IntRect coverRect = intersection(dirtyRect, currentTile->rect())
; | |
| 221 coverArea += coverRect.width() * coverRect.height(); | |
| 222 } | |
| 223 } | |
| 224 } | |
| 225 return coverArea / rectArea; | |
| 226 } | |
| 227 | |
| 228 bool TiledBackingStore::visibleAreaIsCovered() const | |
| 229 { | |
| 230 IntRect boundedVisibleContentsRect = intersection(m_client->tiledBackingStor
eVisibleRect(), m_client->tiledBackingStoreContentsRect()); | |
| 231 return coverageRatio(boundedVisibleContentsRect) == 1.0f; | |
| 232 } | |
| 233 | |
| 234 void TiledBackingStore::createTiles() | |
| 235 { | |
| 236 // Guard here as as these can change before the timer fires. | |
| 237 if (isBackingStoreUpdatesSuspended()) | |
| 238 return; | |
| 239 | |
| 240 // Update our backing store geometry. | |
| 241 const IntRect previousRect = m_rect; | |
| 242 m_rect = mapFromContents(m_client->tiledBackingStoreContentsRect()); | |
| 243 m_trajectoryVector = m_pendingTrajectoryVector; | |
| 244 m_visibleRect = visibleRect(); | |
| 245 | |
| 246 if (m_rect.isEmpty()) { | |
| 247 setCoverRect(IntRect()); | |
| 248 setKeepRect(IntRect()); | |
| 249 return; | |
| 250 } | |
| 251 | |
| 252 /* We must compute cover and keep rects using the visibleRect, instead of th
e rect intersecting the visibleRect with m_rect, | |
| 253 * because TBS can be used as a backing store of GraphicsLayer and the visib
le rect usually does not intersect with m_rect. | |
| 254 * In the below case, the intersecting rect is an empty. | |
| 255 * | |
| 256 * +---------------+ | |
| 257 * | | | |
| 258 * | m_rect | | |
| 259 * | +-------|-----------------------+ | |
| 260 * | | HERE | cover or keep | | |
| 261 * +---------------+ rect | | |
| 262 * | +---------+ | | |
| 263 * | | visible | | | |
| 264 * | | rect | | | |
| 265 * | +---------+ | | |
| 266 * | | | |
| 267 * | | | |
| 268 * +-------------------------------+ | |
| 269 * | |
| 270 * We must create or keep the tiles in the HERE region. | |
| 271 */ | |
| 272 | |
| 273 IntRect coverRect; | |
| 274 IntRect keepRect; | |
| 275 computeCoverAndKeepRect(m_visibleRect, coverRect, keepRect); | |
| 276 | |
| 277 setCoverRect(coverRect); | |
| 278 setKeepRect(keepRect); | |
| 279 | |
| 280 if (coverRect.isEmpty()) | |
| 281 return; | |
| 282 | |
| 283 // Resize tiles at the edge in case the contents size has changed, but only
do so | |
| 284 // after having dropped tiles outside the keep rect. | |
| 285 bool didResizeTiles = false; | |
| 286 if (previousRect != m_rect) | |
| 287 didResizeTiles = resizeEdgeTiles(); | |
| 288 | |
| 289 // Search for the tile position closest to the viewport center that does not
yet contain a tile. | |
| 290 // Which position is considered the closest depends on the tileDistance func
tion. | |
| 291 double shortestDistance = std::numeric_limits<double>::infinity(); | |
| 292 Vector<Tile::Coordinate> tilesToCreate; | |
| 293 unsigned requiredTileCount = 0; | |
| 294 | |
| 295 // Cover areas (in tiles) with minimum distance from the visible rect. If th
e visible rect is | |
| 296 // not covered already it will be covered first in one go, due to the distan
ce being 0 for tiles | |
| 297 // inside the visible rect. | |
| 298 Tile::Coordinate topLeft = tileCoordinateForPoint(coverRect.location()); | |
| 299 Tile::Coordinate bottomRight = tileCoordinateForPoint(innerBottomRight(cover
Rect)); | |
| 300 for (int yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoord
inate) { | |
| 301 for (int xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xC
oordinate) { | |
| 302 Tile::Coordinate currentCoordinate(xCoordinate, yCoordinate); | |
| 303 if (tileAt(currentCoordinate)) | |
| 304 continue; | |
| 305 ++requiredTileCount; | |
| 306 double distance = tileDistance(m_visibleRect, currentCoordinate); | |
| 307 if (distance > shortestDistance) | |
| 308 continue; | |
| 309 if (distance < shortestDistance) { | |
| 310 tilesToCreate.clear(); | |
| 311 shortestDistance = distance; | |
| 312 } | |
| 313 tilesToCreate.append(currentCoordinate); | |
| 314 } | |
| 315 } | |
| 316 | |
| 317 // Now construct the tile(s) within the shortest distance. | |
| 318 unsigned tilesToCreateCount = tilesToCreate.size(); | |
| 319 for (unsigned n = 0; n < tilesToCreateCount; ++n) { | |
| 320 Tile::Coordinate coordinate = tilesToCreate[n]; | |
| 321 setTile(coordinate, m_backend->createTile(this, coordinate)); | |
| 322 } | |
| 323 requiredTileCount -= tilesToCreateCount; | |
| 324 | |
| 325 // Paint the content of the newly created tiles or resized tiles. | |
| 326 if (tilesToCreateCount || didResizeTiles) | |
| 327 updateTileBuffers(); | |
| 328 | |
| 329 // Re-call createTiles on a timer to cover the visible area with the newest
shortest distance. | |
| 330 m_pendingTileCreation = requiredTileCount; | |
| 331 if (m_pendingTileCreation) { | |
| 332 if (!m_commitTileUpdatesOnIdleEventLoop) { | |
| 333 m_client->tiledBackingStoreHasPendingTileCreation(); | |
| 334 return; | |
| 335 } | |
| 336 | |
| 337 static const double tileCreationDelay = 0.01; | |
| 338 startBackingStoreUpdateTimer(tileCreationDelay); | |
| 339 } | |
| 340 } | |
| 341 | |
| 342 void TiledBackingStore::adjustForContentsRect(IntRect& rect) const | |
| 343 { | |
| 344 IntRect bounds = m_rect; | |
| 345 IntSize candidateSize = rect.size(); | |
| 346 | |
| 347 rect.intersect(bounds); | |
| 348 | |
| 349 if (rect.size() == candidateSize) | |
| 350 return; | |
| 351 | |
| 352 /* | |
| 353 * In the following case, there is no intersection of the contents rect and
the cover rect. | |
| 354 * Thus the latter should not be inflated. | |
| 355 * | |
| 356 * +---------------+ | |
| 357 * | m_rect | | |
| 358 * +---------------+ | |
| 359 * | |
| 360 * +-------------------------------+ | |
| 361 * | cover rect | | |
| 362 * | +---------+ | | |
| 363 * | | visible | | | |
| 364 * | | rect | | | |
| 365 * | +---------+ | | |
| 366 * +-------------------------------+ | |
| 367 */ | |
| 368 if (rect.isEmpty()) | |
| 369 return; | |
| 370 | |
| 371 // Try to create a cover rect of the same size as the candidate, but within
content bounds. | |
| 372 int pixelsCovered = candidateSize.width() * candidateSize.height(); | |
| 373 | |
| 374 if (rect.width() < candidateSize.width()) | |
| 375 rect.inflateY(((pixelsCovered / rect.width()) - rect.height()) / 2); | |
| 376 if (rect.height() < candidateSize.height()) | |
| 377 rect.inflateX(((pixelsCovered / rect.height()) - rect.width()) / 2); | |
| 378 | |
| 379 rect.intersect(bounds); | |
| 380 } | |
| 381 | |
| 382 void TiledBackingStore::computeCoverAndKeepRect(const IntRect& visibleRect, IntR
ect& coverRect, IntRect& keepRect) const | |
| 383 { | |
| 384 coverRect = visibleRect; | |
| 385 keepRect = visibleRect; | |
| 386 | |
| 387 // If we cover more that the actual viewport we can be smart about which til
es we choose to render. | |
| 388 if (m_coverAreaMultiplier > 1) { | |
| 389 // The initial cover area covers equally in each direction, according to
the coverAreaMultiplier. | |
| 390 coverRect.inflateX(visibleRect.width() * (m_coverAreaMultiplier - 1) / 2
); | |
| 391 coverRect.inflateY(visibleRect.height() * (m_coverAreaMultiplier - 1) /
2); | |
| 392 keepRect = coverRect; | |
| 393 | |
| 394 if (m_trajectoryVector != FloatPoint::zero()) { | |
| 395 // A null trajectory vector (no motion) means that tiles for the cov
erArea will be created. | |
| 396 // A non-null trajectory vector will shrink the covered rect to visi
bleRect plus its expansion from its | |
| 397 // center toward the cover area edges in the direction of the given
vector. | |
| 398 | |
| 399 // E.g. if visibleRect == (10,10)5x5 and coverAreaMultiplier == 3.0: | |
| 400 // a (0,0) trajectory vector will create tiles intersecting (5,5)15x
15, | |
| 401 // a (1,0) trajectory vector will create tiles intersecting (10,10)1
0x5, | |
| 402 // and a (1,1) trajectory vector will create tiles intersecting (10,
10)10x10. | |
| 403 | |
| 404 // Multiply the vector by the distance to the edge of the cover area
. | |
| 405 float trajectoryVectorMultiplier = (m_coverAreaMultiplier - 1) / 2; | |
| 406 | |
| 407 // Unite the visible rect with a "ghost" of the visible rect moved i
n the direction of the trajectory vector. | |
| 408 coverRect = visibleRect; | |
| 409 coverRect.move(coverRect.width() * m_trajectoryVector.x() * trajecto
ryVectorMultiplier, | |
| 410 coverRect.height() * m_trajectoryVector.y() * traject
oryVectorMultiplier); | |
| 411 | |
| 412 coverRect.unite(visibleRect); | |
| 413 } | |
| 414 ASSERT(keepRect.contains(coverRect)); | |
| 415 } | |
| 416 | |
| 417 adjustForContentsRect(coverRect); | |
| 418 | |
| 419 // The keep rect is an inflated version of the cover rect, inflated in tile
dimensions. | |
| 420 keepRect.unite(coverRect); | |
| 421 keepRect.inflateX(m_tileSize.width() / 2); | |
| 422 keepRect.inflateY(m_tileSize.height() / 2); | |
| 423 keepRect.intersect(m_rect); | |
| 424 | |
| 425 ASSERT(coverRect.isEmpty() || keepRect.contains(coverRect)); | |
| 426 } | |
| 427 | |
| 428 bool TiledBackingStore::isBackingStoreUpdatesSuspended() const | |
| 429 { | |
| 430 return m_contentsFrozen; | |
| 431 } | |
| 432 | |
| 433 bool TiledBackingStore::isTileBufferUpdatesSuspended() const | |
| 434 { | |
| 435 return m_contentsFrozen; | |
| 436 } | |
| 437 | |
| 438 bool TiledBackingStore::resizeEdgeTiles() | |
| 439 { | |
| 440 bool wasResized = false; | |
| 441 Vector<Tile::Coordinate> tilesToRemove; | |
| 442 TileMap::iterator end = m_tiles.end(); | |
| 443 for (TileMap::iterator it = m_tiles.begin(); it != end; ++it) { | |
| 444 Tile::Coordinate tileCoordinate = it->value->coordinate(); | |
| 445 IntRect tileRect = it->value->rect(); | |
| 446 IntRect expectedTileRect = tileRectForCoordinate(tileCoordinate); | |
| 447 if (expectedTileRect.isEmpty()) | |
| 448 tilesToRemove.append(tileCoordinate); | |
| 449 else if (expectedTileRect != tileRect) { | |
| 450 it->value->resize(expectedTileRect.size()); | |
| 451 wasResized = true; | |
| 452 } | |
| 453 } | |
| 454 unsigned removeCount = tilesToRemove.size(); | |
| 455 for (unsigned n = 0; n < removeCount; ++n) | |
| 456 removeTile(tilesToRemove[n]); | |
| 457 return wasResized; | |
| 458 } | |
| 459 | |
| 460 void TiledBackingStore::setKeepRect(const IntRect& keepRect) | |
| 461 { | |
| 462 // Drop tiles outside the new keepRect. | |
| 463 | |
| 464 FloatRect keepRectF = keepRect; | |
| 465 | |
| 466 Vector<Tile::Coordinate> toRemove; | |
| 467 TileMap::iterator end = m_tiles.end(); | |
| 468 for (TileMap::iterator it = m_tiles.begin(); it != end; ++it) { | |
| 469 Tile::Coordinate coordinate = it->value->coordinate(); | |
| 470 FloatRect tileRect = it->value->rect(); | |
| 471 if (!tileRect.intersects(keepRectF)) | |
| 472 toRemove.append(coordinate); | |
| 473 } | |
| 474 unsigned removeCount = toRemove.size(); | |
| 475 for (unsigned n = 0; n < removeCount; ++n) | |
| 476 removeTile(toRemove[n]); | |
| 477 | |
| 478 m_keepRect = keepRect; | |
| 479 } | |
| 480 | |
| 481 void TiledBackingStore::removeAllNonVisibleTiles() | |
| 482 { | |
| 483 IntRect boundedVisibleRect = mapFromContents(intersection(m_client->tiledBac
kingStoreVisibleRect(), m_client->tiledBackingStoreContentsRect())); | |
| 484 setKeepRect(boundedVisibleRect); | |
| 485 } | |
| 486 | |
| 487 PassRefPtr<Tile> TiledBackingStore::tileAt(const Tile::Coordinate& coordinate) c
onst | |
| 488 { | |
| 489 return m_tiles.get(coordinate); | |
| 490 } | |
| 491 | |
| 492 void TiledBackingStore::setTile(const Tile::Coordinate& coordinate, PassRefPtr<T
ile> tile) | |
| 493 { | |
| 494 m_tiles.set(coordinate, tile); | |
| 495 } | |
| 496 | |
| 497 void TiledBackingStore::removeTile(const Tile::Coordinate& coordinate) | |
| 498 { | |
| 499 m_tiles.remove(coordinate); | |
| 500 } | |
| 501 | |
| 502 IntRect TiledBackingStore::mapToContents(const IntRect& rect) const | |
| 503 { | |
| 504 return enclosingIntRect(FloatRect(rect.x() / m_contentsScale, | |
| 505 rect.y() / m_contentsScale, | |
| 506 rect.width() / m_contentsScale, | |
| 507 rect.height() / m_contentsScale)); | |
| 508 } | |
| 509 | |
| 510 IntRect TiledBackingStore::mapFromContents(const IntRect& rect) const | |
| 511 { | |
| 512 return enclosingIntRect(FloatRect(rect.x() * m_contentsScale, | |
| 513 rect.y() * m_contentsScale, | |
| 514 rect.width() * m_contentsScale, | |
| 515 rect.height() * m_contentsScale)); | |
| 516 } | |
| 517 | |
| 518 IntRect TiledBackingStore::tileRectForCoordinate(const Tile::Coordinate& coordin
ate) const | |
| 519 { | |
| 520 IntRect rect(coordinate.x() * m_tileSize.width(), | |
| 521 coordinate.y() * m_tileSize.height(), | |
| 522 m_tileSize.width(), | |
| 523 m_tileSize.height()); | |
| 524 | |
| 525 rect.intersect(m_rect); | |
| 526 return rect; | |
| 527 } | |
| 528 | |
| 529 Tile::Coordinate TiledBackingStore::tileCoordinateForPoint(const IntPoint& point
) const | |
| 530 { | |
| 531 int x = point.x() / m_tileSize.width(); | |
| 532 int y = point.y() / m_tileSize.height(); | |
| 533 return Tile::Coordinate(std::max(x, 0), std::max(y, 0)); | |
| 534 } | |
| 535 | |
| 536 void TiledBackingStore::startTileBufferUpdateTimer() | |
| 537 { | |
| 538 if (!m_commitTileUpdatesOnIdleEventLoop) | |
| 539 return; | |
| 540 | |
| 541 if (m_tileBufferUpdateTimer.isActive() || isTileBufferUpdatesSuspended()) | |
| 542 return; | |
| 543 m_tileBufferUpdateTimer.startOneShot(0); | |
| 544 } | |
| 545 | |
| 546 void TiledBackingStore::tileBufferUpdateTimerFired(Timer<TiledBackingStore>*) | |
| 547 { | |
| 548 ASSERT(m_commitTileUpdatesOnIdleEventLoop); | |
| 549 updateTileBuffers(); | |
| 550 } | |
| 551 | |
| 552 void TiledBackingStore::startBackingStoreUpdateTimer(double interval) | |
| 553 { | |
| 554 if (!m_commitTileUpdatesOnIdleEventLoop) | |
| 555 return; | |
| 556 | |
| 557 if (m_backingStoreUpdateTimer.isActive() || isBackingStoreUpdatesSuspended()
) | |
| 558 return; | |
| 559 m_backingStoreUpdateTimer.startOneShot(interval); | |
| 560 } | |
| 561 | |
| 562 void TiledBackingStore::backingStoreUpdateTimerFired(Timer<TiledBackingStore>*) | |
| 563 { | |
| 564 ASSERT(m_commitTileUpdatesOnIdleEventLoop); | |
| 565 createTiles(); | |
| 566 } | |
| 567 | |
| 568 void TiledBackingStore::setContentsFrozen(bool freeze) | |
| 569 { | |
| 570 if (m_contentsFrozen == freeze) | |
| 571 return; | |
| 572 | |
| 573 m_contentsFrozen = freeze; | |
| 574 | |
| 575 // Restart the timers. There might be pending invalidations that | |
| 576 // were not painted or created because tiles are not created or | |
| 577 // painted when in frozen state. | |
| 578 if (m_contentsFrozen) | |
| 579 return; | |
| 580 if (m_pendingScale) | |
| 581 commitScaleChange(); | |
| 582 else { | |
| 583 startBackingStoreUpdateTimer(); | |
| 584 startTileBufferUpdateTimer(); | |
| 585 } | |
| 586 } | |
| 587 | |
| 588 void TiledBackingStore::setSupportsAlpha(bool a) | |
| 589 { | |
| 590 if (a == m_supportsAlpha) | |
| 591 return; | |
| 592 m_supportsAlpha = a; | |
| 593 invalidate(m_rect); | |
| 594 } | |
| 595 | |
| 596 } | |
| 597 | |
| 598 #endif | |
| OLD | NEW |