Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / platform / graphics / ca / TileController.cpp
1 /*
2  * Copyright (C) 2011-2014 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "TileController.h"
28
29 #include "IntRect.h"
30 #include "PlatformCALayer.h"
31 #include "Region.h"
32 #include "TileCoverageMap.h"
33 #include "TileGrid.h"
34 #include <utility>
35 #include <wtf/MainThread.h>
36
37 #if PLATFORM(IOS)
38 #include "MemoryPressureHandler.h"
39 #include "TileControllerMemoryHandlerIOS.h"
40 #endif
41
42 namespace WebCore {
43
44 String TileController::tileGridContainerLayerName()
45 {
46     return ASCIILiteral("TileGrid Container Layer");
47 }
48
49 String TileController::zoomedOutTileGridContainerLayerName()
50 {
51     return ASCIILiteral("Zoomed Out TileGrid Container Layer");
52 }
53
54 TileController::TileController(PlatformCALayer* rootPlatformLayer)
55     : m_tileCacheLayer(rootPlatformLayer)
56     , m_tileGrid(std::make_unique<TileGrid>(*this))
57     , m_tileRevalidationTimer(*this, &TileController::tileRevalidationTimerFired)
58     , m_zoomedOutContentsScale(0)
59     , m_deviceScaleFactor(owningGraphicsLayer()->platformCALayerDeviceScaleFactor())
60     , m_tileCoverage(CoverageForVisibleArea)
61     , m_marginTop(0)
62     , m_marginBottom(0)
63     , m_marginLeft(0)
64     , m_marginRight(0)
65     , m_isInWindow(false)
66     , m_scrollingPerformanceLoggingEnabled(false)
67     , m_unparentsOffscreenTiles(false)
68     , m_acceleratesDrawing(false)
69     , m_tilesAreOpaque(false)
70     , m_hasTilesWithTemporaryScaleFactor(false)
71     , m_tileDebugBorderWidth(0)
72     , m_indicatorMode(SynchronousScrollingBecauseOfLackOfScrollingCoordinatorIndication)
73     , m_topContentInset(0)
74 {
75 }
76
77 TileController::~TileController()
78 {
79     ASSERT(isMainThread());
80
81 #if PLATFORM(IOS)
82     tileControllerMemoryHandler().removeTileController(this);
83 #endif
84 }
85
86 void TileController::tileCacheLayerBoundsChanged()
87 {
88     ASSERT(owningGraphicsLayer()->isCommittingChanges());
89     setNeedsRevalidateTiles();
90 }
91
92 void TileController::setNeedsDisplay()
93 {
94     tileGrid().setNeedsDisplay();
95     clearZoomedOutTileGrid();
96 }
97
98 void TileController::setNeedsDisplayInRect(const IntRect& rect)
99 {
100     tileGrid().setNeedsDisplayInRect(rect);
101     if (m_zoomedOutTileGrid)
102         m_zoomedOutTileGrid->dropTilesInRect(rect);
103     updateTileCoverageMap();
104 }
105
106 void TileController::setContentsScale(float scale)
107 {
108     ASSERT(owningGraphicsLayer()->isCommittingChanges());
109
110     float deviceScaleFactor = owningGraphicsLayer()->platformCALayerDeviceScaleFactor();
111     // The scale we get is the product of the page scale factor and device scale factor.
112     // Divide by the device scale factor so we'll get the page scale factor.
113     scale /= deviceScaleFactor;
114
115     if (tileGrid().scale() == scale && m_deviceScaleFactor == deviceScaleFactor && !m_hasTilesWithTemporaryScaleFactor)
116         return;
117
118     m_hasTilesWithTemporaryScaleFactor = false;
119     m_deviceScaleFactor = deviceScaleFactor;
120
121     if (m_coverageMap)
122         m_coverageMap->setDeviceScaleFactor(deviceScaleFactor);
123
124     if (m_zoomedOutTileGrid && m_zoomedOutTileGrid->scale() == scale) {
125         m_tileGrid = WTFMove(m_zoomedOutTileGrid);
126         m_tileGrid->setIsZoomedOutTileGrid(false);
127         m_tileGrid->revalidateTiles();
128         tileGridsChanged();
129         return;
130     }
131
132     if (m_zoomedOutContentsScale && m_zoomedOutContentsScale == tileGrid().scale() && tileGrid().scale() != scale && !m_hasTilesWithTemporaryScaleFactor) {
133         m_zoomedOutTileGrid = WTFMove(m_tileGrid);
134         m_zoomedOutTileGrid->setIsZoomedOutTileGrid(true);
135         m_tileGrid = std::make_unique<TileGrid>(*this);
136         tileGridsChanged();
137     }
138
139     tileGrid().setScale(scale);
140     tileGrid().setNeedsDisplay();
141 }
142
143 float TileController::contentsScale() const
144 {
145     return tileGrid().scale() * m_deviceScaleFactor;
146 }
147
148 float TileController::zoomedOutContentsScale() const
149 {
150     return m_zoomedOutContentsScale * m_deviceScaleFactor;
151 }
152
153 void TileController::setZoomedOutContentsScale(float scale)
154 {
155     ASSERT(owningGraphicsLayer()->isCommittingChanges());
156
157     float deviceScaleFactor = owningGraphicsLayer()->platformCALayerDeviceScaleFactor();
158     scale /= deviceScaleFactor;
159
160     if (m_zoomedOutContentsScale == scale)
161         return;
162     m_zoomedOutContentsScale = scale;
163
164     if (m_zoomedOutTileGrid && m_zoomedOutTileGrid->scale() != m_zoomedOutContentsScale)
165         clearZoomedOutTileGrid();
166 }
167
168 void TileController::setAcceleratesDrawing(bool acceleratesDrawing)
169 {
170     if (m_acceleratesDrawing == acceleratesDrawing)
171         return;
172     m_acceleratesDrawing = acceleratesDrawing;
173
174     tileGrid().updateTileLayerProperties();
175 }
176
177 void TileController::setTilesOpaque(bool opaque)
178 {
179     if (opaque == m_tilesAreOpaque)
180         return;
181     m_tilesAreOpaque = opaque;
182
183     tileGrid().updateTileLayerProperties();
184 }
185
186 void TileController::setVisibleRect(const FloatRect& rect)
187 {
188     m_visibleRect = rect;
189 }
190
191 void TileController::setCoverageRect(const FloatRect& rect)
192 {
193     ASSERT(owningGraphicsLayer()->isCommittingChanges());
194     if (m_coverageRect == rect)
195         return;
196
197     m_coverageRect = rect;
198     setNeedsRevalidateTiles();
199 }
200
201 bool TileController::tilesWouldChangeForCoverageRect(const FloatRect& rect) const
202 {
203     if (bounds().isEmpty())
204         return false;
205
206     return tileGrid().tilesWouldChangeForCoverageRect(rect);
207 }
208
209 void TileController::setVelocity(const VelocityData& velocity)
210 {
211     bool changeAffectsTileCoverage = m_velocity.velocityOrScaleIsChanging() || velocity.velocityOrScaleIsChanging();
212     m_velocity = velocity;
213     
214     if (changeAffectsTileCoverage)
215         setNeedsRevalidateTiles();
216 }
217
218 void TileController::setTopContentInset(float topContentInset)
219 {
220     m_topContentInset = topContentInset;
221     setTiledScrollingIndicatorPosition(FloatPoint(0, m_topContentInset));
222 }
223
224 void TileController::setTiledScrollingIndicatorPosition(const FloatPoint& position)
225 {
226     if (!m_coverageMap)
227         return;
228     m_coverageMap->setPosition(position);
229     m_coverageMap->update();
230 }
231
232 void TileController::prepopulateRect(const FloatRect& rect)
233 {
234     if (tileGrid().prepopulateRect(rect))
235         setNeedsRevalidateTiles();
236 }
237
238 void TileController::setIsInWindow(bool isInWindow)
239 {
240     if (m_isInWindow == isInWindow)
241         return;
242
243     m_isInWindow = isInWindow;
244
245     if (m_isInWindow)
246         setNeedsRevalidateTiles();
247     else {
248         const double tileRevalidationTimeout = 4;
249         scheduleTileRevalidation(tileRevalidationTimeout);
250     }
251 }
252
253 void TileController::setTileCoverage(TileCoverage coverage)
254 {
255     if (coverage == m_tileCoverage)
256         return;
257
258     m_tileCoverage = coverage;
259     setNeedsRevalidateTiles();
260 }
261
262 void TileController::revalidateTiles()
263 {
264     ASSERT(owningGraphicsLayer()->isCommittingChanges());
265     tileGrid().revalidateTiles();
266 }
267
268 void TileController::forceRepaint()
269 {
270     setNeedsDisplay();
271 }
272
273 void TileController::setTileDebugBorderWidth(float borderWidth)
274 {
275     if (m_tileDebugBorderWidth == borderWidth)
276         return;
277     m_tileDebugBorderWidth = borderWidth;
278
279     tileGrid().updateTileLayerProperties();
280 }
281
282 void TileController::setTileDebugBorderColor(Color borderColor)
283 {
284     if (m_tileDebugBorderColor == borderColor)
285         return;
286     m_tileDebugBorderColor = borderColor;
287
288     tileGrid().updateTileLayerProperties();
289 }
290
291 IntRect TileController::boundsForSize(const FloatSize& size) const
292 {
293     IntPoint boundsOriginIncludingMargin(-leftMarginWidth(), -topMarginHeight());
294     IntSize boundsSizeIncludingMargin = expandedIntSize(size);
295     boundsSizeIncludingMargin.expand(leftMarginWidth() + rightMarginWidth(), topMarginHeight() + bottomMarginHeight());
296
297     return IntRect(boundsOriginIncludingMargin, boundsSizeIncludingMargin);
298 }
299
300 IntRect TileController::bounds() const
301 {
302     return boundsForSize(m_tileCacheLayer->bounds().size());
303 }
304
305 IntRect TileController::boundsWithoutMargin() const
306 {
307     return IntRect(IntPoint(), expandedIntSize(m_tileCacheLayer->bounds().size()));
308 }
309
310 IntRect TileController::boundsAtLastRevalidateWithoutMargin() const
311 {
312     IntRect boundsWithoutMargin = IntRect(IntPoint(), m_boundsAtLastRevalidate.size());
313     boundsWithoutMargin.contract(IntSize(leftMarginWidth() + rightMarginWidth(), topMarginHeight() + bottomMarginHeight()));
314     return boundsWithoutMargin;
315 }
316
317 FloatRect TileController::computeTileCoverageRect(const FloatSize& newSize, const FloatRect& previousVisibleRect, const FloatRect& visibleRect, float contentsScale) const
318 {
319     // If the page is not in a window (for example if it's in a background tab), we limit the tile coverage rect to the visible rect.
320     if (!m_isInWindow)
321         return visibleRect;
322
323 #if PLATFORM(IOS)
324     // FIXME: unify the iOS and Mac code.
325     UNUSED_PARAM(previousVisibleRect);
326     
327     if (m_tileCoverage == CoverageForVisibleArea || MemoryPressureHandler::singleton().isUnderMemoryPressure())
328         return visibleRect;
329
330     double horizontalMargin = tileSize().width() / contentsScale;
331     double verticalMargin = tileSize().height() / contentsScale;
332
333     double currentTime = monotonicallyIncreasingTime();
334     double timeDelta = currentTime - m_velocity.lastUpdateTime;
335
336     FloatRect futureRect = visibleRect;
337     futureRect.setLocation(FloatPoint(
338         futureRect.location().x() + timeDelta * m_velocity.horizontalVelocity,
339         futureRect.location().y() + timeDelta * m_velocity.verticalVelocity));
340
341     if (m_velocity.horizontalVelocity) {
342         futureRect.setWidth(futureRect.width() + horizontalMargin);
343         if (m_velocity.horizontalVelocity < 0)
344             futureRect.setX(futureRect.x() - horizontalMargin);
345     }
346
347     if (m_velocity.verticalVelocity) {
348         futureRect.setHeight(futureRect.height() + verticalMargin);
349         if (m_velocity.verticalVelocity < 0)
350             futureRect.setY(futureRect.y() - verticalMargin);
351     }
352
353     if (!m_velocity.horizontalVelocity && !m_velocity.verticalVelocity) {
354         if (m_velocity.scaleChangeRate > 0)
355             return visibleRect;
356         futureRect.setWidth(futureRect.width() + horizontalMargin);
357         futureRect.setHeight(futureRect.height() + verticalMargin);
358         futureRect.setX(futureRect.x() - horizontalMargin / 2);
359         futureRect.setY(futureRect.y() - verticalMargin / 2);
360     }
361
362     // Can't use m_tileCacheLayer->bounds() here, because the size of the underlying platform layer
363     // hasn't been updated for the current commit.
364     IntSize contentSize = expandedIntSize(newSize);
365     if (futureRect.maxX() > contentSize.width())
366         futureRect.setX(contentSize.width() - futureRect.width());
367     if (futureRect.maxY() > contentSize.height())
368         futureRect.setY(contentSize.height() - futureRect.height());
369     if (futureRect.x() < 0)
370         futureRect.setX(0);
371     if (futureRect.y() < 0)
372         futureRect.setY(0);
373
374     return futureRect;
375 #else
376     UNUSED_PARAM(contentsScale);
377
378     // FIXME: look at how far the document can scroll in each dimension.
379     float coverageHorizontalSize = visibleRect.width();
380     float coverageVerticalSize = visibleRect.height();
381
382     bool largeVisibleRectChange = !previousVisibleRect.isEmpty() && !visibleRect.intersects(previousVisibleRect);
383
384     // Inflate the coverage rect so that it covers 2x of the visible width and 3x of the visible height.
385     // These values were chosen because it's more common to have tall pages and to scroll vertically,
386     // so we keep more tiles above and below the current area.
387
388     if (m_tileCoverage & CoverageForHorizontalScrolling && !largeVisibleRectChange)
389         coverageHorizontalSize *= 2;
390
391     if (m_tileCoverage & CoverageForVerticalScrolling && !largeVisibleRectChange)
392         coverageVerticalSize *= 3;
393
394     coverageVerticalSize += topMarginHeight() + bottomMarginHeight();
395     coverageHorizontalSize += leftMarginWidth() + rightMarginWidth();
396
397     // Can't use m_tileCacheLayer->bounds() here, because the size of the underlying platform layer
398     // hasn't been updated for the current commit.
399     FloatRect coverageBounds = boundsForSize(newSize);
400     float coverageLeft = visibleRect.x() - (coverageHorizontalSize - visibleRect.width()) / 2;
401     coverageLeft = std::min(coverageLeft, coverageBounds.maxX() - coverageHorizontalSize);
402     coverageLeft = std::max(coverageLeft, coverageBounds.x());
403
404     float coverageTop = visibleRect.y() - (coverageVerticalSize - visibleRect.height()) / 2;
405     coverageTop = std::min(coverageTop, coverageBounds.maxY() - coverageVerticalSize);
406     coverageTop = std::max(coverageTop, coverageBounds.y());
407
408     return FloatRect(coverageLeft, coverageTop, coverageHorizontalSize, coverageVerticalSize);
409 #endif
410 }
411
412 void TileController::scheduleTileRevalidation(double interval)
413 {
414     if (m_tileRevalidationTimer.isActive() && m_tileRevalidationTimer.nextFireInterval() < interval)
415         return;
416
417     m_tileRevalidationTimer.startOneShot(interval);
418 }
419
420 bool TileController::shouldAggressivelyRetainTiles() const
421 {
422     return owningGraphicsLayer()->platformCALayerShouldAggressivelyRetainTiles(m_tileCacheLayer);
423 }
424
425 bool TileController::shouldTemporarilyRetainTileCohorts() const
426 {
427     return owningGraphicsLayer()->platformCALayerShouldTemporarilyRetainTileCohorts(m_tileCacheLayer);
428 }
429
430 IntSize TileController::tileSize() const
431 {
432     return owningGraphicsLayer()->platformCALayerTileSize();
433 }
434
435 void TileController::clearZoomedOutTileGrid()
436 {
437     m_zoomedOutTileGrid = nullptr;
438     tileGridsChanged();
439 }
440
441 void TileController::tileGridsChanged()
442 {
443     return owningGraphicsLayer()->platformCALayerCustomSublayersChanged(m_tileCacheLayer);
444 }
445
446 void TileController::tileRevalidationTimerFired()
447 {
448     if (!owningGraphicsLayer())
449         return;
450
451     if (m_isInWindow) {
452         setNeedsRevalidateTiles();
453         return;
454     }
455     // If we are not visible get rid of the zoomed-out tiles.
456     clearZoomedOutTileGrid();
457
458     TileGrid::TileValidationPolicy validationPolicy = (shouldAggressivelyRetainTiles() ? 0 : TileGrid::PruneSecondaryTiles) | TileGrid::UnparentAllTiles;
459
460     tileGrid().revalidateTiles(validationPolicy);
461 }
462
463 void TileController::didRevalidateTiles()
464 {
465     m_boundsAtLastRevalidate = bounds();
466
467     updateTileCoverageMap();
468 }
469
470 unsigned TileController::blankPixelCount() const
471 {
472     return tileGrid().blankPixelCount();
473 }
474
475 unsigned TileController::blankPixelCountForTiles(const PlatformLayerList& tiles, const FloatRect& visibleRect, const IntPoint& tileTranslation)
476 {
477     Region paintedVisibleTiles;
478
479     for (PlatformLayerList::const_iterator it = tiles.begin(), end = tiles.end(); it != end; ++it) {
480         const PlatformLayer* tileLayer = it->get();
481
482         FloatRect visiblePart(CGRectOffset(PlatformCALayer::frameForLayer(tileLayer), tileTranslation.x(), tileTranslation.y()));
483         visiblePart.intersect(visibleRect);
484
485         if (!visiblePart.isEmpty())
486             paintedVisibleTiles.unite(enclosingIntRect(visiblePart));
487     }
488
489     Region uncoveredRegion(enclosingIntRect(visibleRect));
490     uncoveredRegion.subtract(paintedVisibleTiles);
491
492     return uncoveredRegion.totalArea();
493 }
494
495 void TileController::setNeedsRevalidateTiles()
496 {
497     owningGraphicsLayer()->platformCALayerSetNeedsToRevalidateTiles();
498 }
499
500 void TileController::updateTileCoverageMap()
501 {
502     if (m_coverageMap)
503         m_coverageMap->update();
504 }
505
506 IntRect TileController::tileGridExtent() const
507 {
508     return tileGrid().extent();
509 }
510
511 double TileController::retainedTileBackingStoreMemory() const
512 {
513     double bytes = tileGrid().retainedTileBackingStoreMemory();
514     if (m_zoomedOutTileGrid)
515         bytes += m_zoomedOutTileGrid->retainedTileBackingStoreMemory();
516     return bytes;
517 }
518
519 // Return the rect in layer coords, not tile coords.
520 IntRect TileController::tileCoverageRect() const
521 {
522     return tileGrid().tileCoverageRect();
523 }
524
525 PlatformCALayer* TileController::tiledScrollingIndicatorLayer()
526 {
527     if (!m_coverageMap)
528         m_coverageMap = std::make_unique<TileCoverageMap>(*this);
529
530     return &m_coverageMap->layer();
531 }
532
533 void TileController::setScrollingModeIndication(ScrollingModeIndication scrollingMode)
534 {
535     if (scrollingMode == m_indicatorMode)
536         return;
537
538     m_indicatorMode = scrollingMode;
539
540     updateTileCoverageMap();
541 }
542
543 void TileController::setTileMargins(int marginTop, int marginBottom, int marginLeft, int marginRight)
544 {
545     m_marginTop = marginTop;
546     m_marginBottom = marginBottom;
547     m_marginLeft = marginLeft;
548     m_marginRight = marginRight;
549
550     setNeedsRevalidateTiles();
551 }
552
553 bool TileController::hasMargins() const
554 {
555     return m_marginTop || m_marginBottom || m_marginLeft || m_marginRight;
556 }
557
558 bool TileController::hasHorizontalMargins() const
559 {
560     return m_marginLeft || m_marginRight;
561 }
562
563 bool TileController::hasVerticalMargins() const
564 {
565     return m_marginTop || m_marginBottom;
566 }
567
568 int TileController::topMarginHeight() const
569 {
570     return m_marginTop / tileGrid().scale();
571 }
572
573 int TileController::bottomMarginHeight() const
574 {
575     return m_marginBottom / tileGrid().scale();
576 }
577
578 int TileController::leftMarginWidth() const
579 {
580     return m_marginLeft / tileGrid().scale();
581 }
582
583 int TileController::rightMarginWidth() const
584 {
585     return m_marginRight / tileGrid().scale();
586 }
587
588 RefPtr<PlatformCALayer> TileController::createTileLayer(const IntRect& tileRect, TileGrid& grid)
589 {
590     RefPtr<PlatformCALayer> layer = m_tileCacheLayer->createCompatibleLayerOrTakeFromPool(PlatformCALayer::LayerTypeTiledBackingTileLayer, &grid, tileRect.size());
591
592     layer->setAnchorPoint(FloatPoint3D());
593     layer->setPosition(tileRect.location());
594     layer->setBorderColor(m_tileDebugBorderColor);
595     layer->setBorderWidth(m_tileDebugBorderWidth);
596     layer->setEdgeAntialiasingMask(0);
597     layer->setOpaque(m_tilesAreOpaque);
598 #ifndef NDEBUG
599     layer->setName("Tile");
600 #endif
601
602     float temporaryScaleFactor = owningGraphicsLayer()->platformCALayerContentsScaleMultiplierForNewTiles(m_tileCacheLayer);
603     m_hasTilesWithTemporaryScaleFactor |= temporaryScaleFactor != 1;
604
605     layer->setContentsScale(m_deviceScaleFactor * temporaryScaleFactor);
606     layer->setAcceleratesDrawing(m_acceleratesDrawing);
607
608     layer->setNeedsDisplay();
609
610     return layer;
611 }
612
613 Vector<RefPtr<PlatformCALayer>> TileController::containerLayers()
614 {
615     Vector<RefPtr<PlatformCALayer>> layerList;
616     if (m_zoomedOutTileGrid)
617         layerList.append(&m_zoomedOutTileGrid->containerLayer());
618     layerList.append(&tileGrid().containerLayer());
619     return layerList;
620 }
621
622 #if PLATFORM(IOS)
623 unsigned TileController::numberOfUnparentedTiles() const
624 {
625     unsigned count = tileGrid().numberOfUnparentedTiles();
626     if (m_zoomedOutTileGrid)
627         count += m_zoomedOutTileGrid->numberOfUnparentedTiles();
628     return count;
629 }
630
631 void TileController::removeUnparentedTilesNow()
632 {
633     tileGrid().removeUnparentedTilesNow();
634     if (m_zoomedOutTileGrid)
635         m_zoomedOutTileGrid->removeUnparentedTilesNow();
636
637     updateTileCoverageMap();
638 }
639 #endif
640
641 } // namespace WebCore