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 |