Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(207)

Side by Side Diff: Source/WebCore/platform/graphics/TiledBackingStore.cpp

Issue 13818029: Remove TiledBacking / TileCache code (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: rebased Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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
OLDNEW
« no previous file with comments | « Source/WebCore/platform/graphics/TiledBackingStore.h ('k') | Source/WebCore/platform/graphics/TiledBackingStoreBackend.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698