Add WTF::move()
[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 "TileControllerMemoryHandlerIOS.h"
39 #endif
40
41 namespace WebCore {
42
43 PassOwnPtr<TileController> TileController::create(PlatformCALayer* rootPlatformLayer)
44 {
45     return adoptPtr(new TileController(rootPlatformLayer));
46 }
47
48 TileController::TileController(PlatformCALayer* rootPlatformLayer)
49     : m_tileCacheLayer(rootPlatformLayer)
50     , m_tileGrid(std::make_unique<TileGrid>(*this))
51     , m_tileSize(defaultTileWidth, defaultTileHeight)
52     , m_tileRevalidationTimer(this, &TileController::tileRevalidationTimerFired)
53     , m_zoomedOutContentsScale(0)
54     , m_deviceScaleFactor(owningGraphicsLayer()->platformCALayerDeviceScaleFactor())
55     , m_tileCoverage(CoverageForVisibleArea)
56     , m_marginTop(0)
57     , m_marginBottom(0)
58     , m_marginLeft(0)
59     , m_marginRight(0)
60     , m_isInWindow(false)
61     , m_scrollingPerformanceLoggingEnabled(false)
62     , m_unparentsOffscreenTiles(false)
63     , m_acceleratesDrawing(false)
64     , m_tilesAreOpaque(false)
65     , m_hasTilesWithTemporaryScaleFactor(false)
66     , m_tileDebugBorderWidth(0)
67     , m_indicatorMode(AsyncScrollingIndication)
68     , m_topContentInset(0)
69 {
70 }
71
72 TileController::~TileController()
73 {
74     ASSERT(isMainThread());
75
76 #if PLATFORM(IOS)
77     tileControllerMemoryHandler().removeTileController(this);
78 #endif
79 }
80
81 void TileController::tileCacheLayerBoundsChanged()
82 {
83     ASSERT(owningGraphicsLayer()->isCommittingChanges());
84     setNeedsRevalidateTiles();
85 }
86
87 void TileController::setNeedsDisplay()
88 {
89     tileGrid().setNeedsDisplay();
90     m_zoomedOutTileGrid = nullptr;
91 }
92
93 void TileController::setNeedsDisplayInRect(const IntRect& rect)
94 {
95     tileGrid().setNeedsDisplayInRect(rect);
96     if (m_zoomedOutTileGrid)
97         m_zoomedOutTileGrid->dropTilesInRect(rect);
98 }
99
100 void TileController::setContentsScale(float scale)
101 {
102     ASSERT(owningGraphicsLayer()->isCommittingChanges());
103
104     float deviceScaleFactor = owningGraphicsLayer()->platformCALayerDeviceScaleFactor();
105     // The scale we get is the product of the page scale factor and device scale factor.
106     // Divide by the device scale factor so we'll get the page scale factor.
107     scale /= deviceScaleFactor;
108
109     if (tileGrid().scale() == scale && m_deviceScaleFactor == deviceScaleFactor && !m_hasTilesWithTemporaryScaleFactor)
110         return;
111
112     m_hasTilesWithTemporaryScaleFactor = false;
113     m_deviceScaleFactor = deviceScaleFactor;
114
115     if (m_coverageMap)
116         m_coverageMap->setDeviceScaleFactor(deviceScaleFactor);
117
118     if (m_zoomedOutTileGrid && m_zoomedOutTileGrid->scale() == scale) {
119         m_tileGrid = WTF::move(m_zoomedOutTileGrid);
120         m_tileGrid->revalidateTiles(0);
121         return;
122     }
123
124     if (m_zoomedOutContentsScale && m_zoomedOutContentsScale == tileGrid().scale() && tileGrid().scale() != scale && !m_hasTilesWithTemporaryScaleFactor) {
125         m_zoomedOutTileGrid = WTF::move(m_tileGrid);
126         m_tileGrid = std::make_unique<TileGrid>(*this);
127     }
128
129     tileGrid().setScale(scale);
130     tileGrid().setNeedsDisplay();
131 }
132
133 float TileController::contentsScale() const
134 {
135     return tileGrid().scale() * m_deviceScaleFactor;
136 }
137
138 float TileController::zoomedOutContentsScale() const
139 {
140     return m_zoomedOutContentsScale * m_deviceScaleFactor;
141 }
142
143 void TileController::setZoomedOutContentsScale(float scale)
144 {
145     ASSERT(owningGraphicsLayer()->isCommittingChanges());
146
147     float deviceScaleFactor = owningGraphicsLayer()->platformCALayerDeviceScaleFactor();
148     scale /= deviceScaleFactor;
149
150     if (m_zoomedOutContentsScale == scale)
151         return;
152     m_zoomedOutContentsScale = scale;
153
154     if (m_zoomedOutTileGrid && m_zoomedOutTileGrid->scale() != m_zoomedOutContentsScale)
155         m_zoomedOutTileGrid = nullptr;
156 }
157
158 void TileController::setAcceleratesDrawing(bool acceleratesDrawing)
159 {
160     if (m_acceleratesDrawing == acceleratesDrawing)
161         return;
162     m_acceleratesDrawing = acceleratesDrawing;
163
164     tileGrid().updateTileLayerProperties();
165 }
166
167 void TileController::setTilesOpaque(bool opaque)
168 {
169     if (opaque == m_tilesAreOpaque)
170         return;
171     m_tilesAreOpaque = opaque;
172
173     tileGrid().updateTileLayerProperties();
174 }
175
176 void TileController::setVisibleRect(const FloatRect& visibleRect)
177 {
178     ASSERT(owningGraphicsLayer()->isCommittingChanges());
179     if (m_visibleRect == visibleRect)
180         return;
181
182     m_visibleRect = visibleRect;
183     setNeedsRevalidateTiles();
184 }
185
186 bool TileController::tilesWouldChangeForVisibleRect(const FloatRect& newVisibleRect) const
187 {
188     if (bounds().isEmpty())
189         return false;
190     return tileGrid().tilesWouldChangeForVisibleRect(newVisibleRect, m_visibleRect);
191 }
192
193 void TileController::setTopContentInset(float topContentInset)
194 {
195     m_topContentInset = topContentInset;
196     setTiledScrollingIndicatorPosition(FloatPoint(0, m_topContentInset));
197 }
198
199 void TileController::setTiledScrollingIndicatorPosition(const FloatPoint& position)
200 {
201     if (!m_coverageMap)
202         return;
203     m_coverageMap->setPosition(position);
204     m_coverageMap->update();
205 }
206
207 void TileController::prepopulateRect(const FloatRect& rect)
208 {
209     if (tileGrid().prepopulateRect(rect))
210         setNeedsRevalidateTiles();
211 }
212
213 void TileController::setIsInWindow(bool isInWindow)
214 {
215     if (m_isInWindow == isInWindow)
216         return;
217
218     m_isInWindow = isInWindow;
219
220     if (m_isInWindow)
221         setNeedsRevalidateTiles();
222     else {
223         const double tileRevalidationTimeout = 4;
224         scheduleTileRevalidation(tileRevalidationTimeout);
225     }
226 }
227
228 void TileController::setTileCoverage(TileCoverage coverage)
229 {
230     if (coverage == m_tileCoverage)
231         return;
232
233     m_tileCoverage = coverage;
234     setNeedsRevalidateTiles();
235 }
236
237 void TileController::revalidateTiles()
238 {
239     ASSERT(owningGraphicsLayer()->isCommittingChanges());
240     tileGrid().revalidateTiles(0);
241     m_visibleRectAtLastRevalidate = m_visibleRect;
242 }
243
244 void TileController::forceRepaint()
245 {
246     setNeedsDisplay();
247 }
248
249 void TileController::setTileDebugBorderWidth(float borderWidth)
250 {
251     if (m_tileDebugBorderWidth == borderWidth)
252         return;
253     m_tileDebugBorderWidth = borderWidth;
254
255     tileGrid().updateTileLayerProperties();
256 }
257
258 void TileController::setTileDebugBorderColor(Color borderColor)
259 {
260     if (m_tileDebugBorderColor == borderColor)
261         return;
262     m_tileDebugBorderColor = borderColor;
263
264     tileGrid().updateTileLayerProperties();
265 }
266
267 IntRect TileController::bounds() const
268 {
269     IntPoint boundsOriginIncludingMargin(-leftMarginWidth(), -topMarginHeight());
270     IntSize boundsSizeIncludingMargin = expandedIntSize(m_tileCacheLayer->bounds().size());
271     boundsSizeIncludingMargin.expand(leftMarginWidth() + rightMarginWidth(), topMarginHeight() + bottomMarginHeight());
272
273     return IntRect(boundsOriginIncludingMargin, boundsSizeIncludingMargin);
274 }
275
276 IntRect TileController::boundsWithoutMargin() const
277 {
278     return IntRect(IntPoint(), expandedIntSize(m_tileCacheLayer->bounds().size()));
279 }
280
281 IntRect TileController::boundsAtLastRevalidateWithoutMargin() const
282 {
283     IntRect boundsWithoutMargin = IntRect(IntPoint(), m_boundsAtLastRevalidate.size());
284     boundsWithoutMargin.contract(IntSize(leftMarginWidth() + rightMarginWidth(), topMarginHeight() + bottomMarginHeight()));
285     return boundsWithoutMargin;
286 }
287
288 FloatRect TileController::computeTileCoverageRect(const FloatRect& previousVisibleRect, const FloatRect& visibleRect) const
289 {
290     // 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.
291     if (!m_isInWindow)
292         return visibleRect;
293
294     // FIXME: look at how far the document can scroll in each dimension.
295     float coverageHorizontalSize = visibleRect.width();
296     float coverageVerticalSize = visibleRect.height();
297
298 #if PLATFORM(IOS)
299     UNUSED_PARAM(previousVisibleRect);
300     return visibleRect;
301 #else
302     bool largeVisibleRectChange = !previousVisibleRect.isEmpty() && !visibleRect.intersects(previousVisibleRect);
303
304     // Inflate the coverage rect so that it covers 2x of the visible width and 3x of the visible height.
305     // These values were chosen because it's more common to have tall pages and to scroll vertically,
306     // so we keep more tiles above and below the current area.
307
308     if (m_tileCoverage & CoverageForHorizontalScrolling && !largeVisibleRectChange)
309         coverageHorizontalSize *= 2;
310
311     if (m_tileCoverage & CoverageForVerticalScrolling && !largeVisibleRectChange)
312         coverageVerticalSize *= 3;
313 #endif
314     coverageVerticalSize += topMarginHeight() + bottomMarginHeight();
315     coverageHorizontalSize += leftMarginWidth() + rightMarginWidth();
316
317     FloatRect coverageBounds = bounds();
318     float coverageLeft = visibleRect.x() - (coverageHorizontalSize - visibleRect.width()) / 2;
319     coverageLeft = std::min(coverageLeft, coverageBounds.maxX() - coverageHorizontalSize);
320     coverageLeft = std::max(coverageLeft, coverageBounds.x());
321
322     float coverageTop = visibleRect.y() - (coverageVerticalSize - visibleRect.height()) / 2;
323     coverageTop = std::min(coverageTop, coverageBounds.maxY() - coverageVerticalSize);
324     coverageTop = std::max(coverageTop, coverageBounds.y());
325
326     return FloatRect(coverageLeft, coverageTop, coverageHorizontalSize, coverageVerticalSize);
327 }
328
329 void TileController::scheduleTileRevalidation(double interval)
330 {
331     if (m_tileRevalidationTimer.isActive() && m_tileRevalidationTimer.nextFireInterval() < interval)
332         return;
333
334     m_tileRevalidationTimer.startOneShot(interval);
335 }
336
337 bool TileController::shouldAggressivelyRetainTiles() const
338 {
339     return owningGraphicsLayer()->platformCALayerShouldAggressivelyRetainTiles(m_tileCacheLayer);
340 }
341
342 bool TileController::shouldTemporarilyRetainTileCohorts() const
343 {
344     return owningGraphicsLayer()->platformCALayerShouldTemporarilyRetainTileCohorts(m_tileCacheLayer);
345 }
346
347 void TileController::tileRevalidationTimerFired(Timer<TileController>*)
348 {
349     if (!owningGraphicsLayer())
350         return;
351
352     if (m_isInWindow) {
353         setNeedsRevalidateTiles();
354         return;
355     }
356     // If we are not visible get rid of the zoomed-out tiles.
357     m_zoomedOutTileGrid = nullptr;
358
359     unsigned validationPolicy = (shouldAggressivelyRetainTiles() ? 0 : TileGrid::PruneSecondaryTiles) | TileGrid::UnparentAllTiles;
360
361     tileGrid().revalidateTiles(validationPolicy);
362 }
363
364 void TileController::didRevalidateTiles()
365 {
366     m_visibleRectAtLastRevalidate = visibleRect();
367     m_boundsAtLastRevalidate = bounds();
368
369     updateTileCoverageMap();
370 }
371
372 unsigned TileController::blankPixelCount() const
373 {
374     return tileGrid().blankPixelCount();
375 }
376
377 unsigned TileController::blankPixelCountForTiles(const PlatformLayerList& tiles, const FloatRect& visibleRect, const IntPoint& tileTranslation)
378 {
379     Region paintedVisibleTiles;
380
381     for (PlatformLayerList::const_iterator it = tiles.begin(), end = tiles.end(); it != end; ++it) {
382         const PlatformLayer* tileLayer = it->get();
383
384         FloatRect visiblePart(CGRectOffset(PlatformCALayer::frameForLayer(tileLayer), tileTranslation.x(), tileTranslation.y()));
385         visiblePart.intersect(visibleRect);
386
387         if (!visiblePart.isEmpty())
388             paintedVisibleTiles.unite(enclosingIntRect(visiblePart));
389     }
390
391     Region uncoveredRegion(enclosingIntRect(visibleRect));
392     uncoveredRegion.subtract(paintedVisibleTiles);
393
394     return uncoveredRegion.totalArea();
395 }
396
397 void TileController::setNeedsRevalidateTiles()
398 {
399     owningGraphicsLayer()->platformCALayerSetNeedsToRevalidateTiles();
400 }
401
402 void TileController::updateTileCoverageMap()
403 {
404     if (m_coverageMap)
405         m_coverageMap->update();
406 }
407
408 IntRect TileController::tileGridExtent() const
409 {
410     return tileGrid().extent();
411 }
412
413 double TileController::retainedTileBackingStoreMemory() const
414 {
415     double bytes = tileGrid().retainedTileBackingStoreMemory();
416     if (m_zoomedOutTileGrid)
417         bytes += m_zoomedOutTileGrid->retainedTileBackingStoreMemory();
418     return bytes;
419 }
420
421 // Return the rect in layer coords, not tile coords.
422 IntRect TileController::tileCoverageRect() const
423 {
424     return tileGrid().tileCoverageRect();
425 }
426
427 PlatformCALayer* TileController::tiledScrollingIndicatorLayer()
428 {
429     if (!m_coverageMap)
430         m_coverageMap = std::make_unique<TileCoverageMap>(*this);
431
432     return &m_coverageMap->layer();
433 }
434
435 void TileController::setScrollingModeIndication(ScrollingModeIndication scrollingMode)
436 {
437     if (scrollingMode == m_indicatorMode)
438         return;
439
440     m_indicatorMode = scrollingMode;
441
442     updateTileCoverageMap();
443 }
444
445 void TileController::setTileMargins(int marginTop, int marginBottom, int marginLeft, int marginRight)
446 {
447     m_marginTop = marginTop;
448     m_marginBottom = marginBottom;
449     m_marginLeft = marginLeft;
450     m_marginRight = marginRight;
451
452     setNeedsRevalidateTiles();
453 }
454
455 bool TileController::hasMargins() const
456 {
457     return m_marginTop || m_marginBottom || m_marginLeft || m_marginRight;
458 }
459
460 bool TileController::hasHorizontalMargins() const
461 {
462     return m_marginLeft || m_marginRight;
463 }
464
465 bool TileController::hasVerticalMargins() const
466 {
467     return m_marginTop || m_marginBottom;
468 }
469
470 int TileController::topMarginHeight() const
471 {
472     return m_marginTop / tileGrid().scale();
473 }
474
475 int TileController::bottomMarginHeight() const
476 {
477     return m_marginBottom / tileGrid().scale();
478 }
479
480 int TileController::leftMarginWidth() const
481 {
482     return m_marginLeft / tileGrid().scale();
483 }
484
485 int TileController::rightMarginWidth() const
486 {
487     return m_marginRight / tileGrid().scale();
488 }
489
490 RefPtr<PlatformCALayer> TileController::createTileLayer(const IntRect& tileRect, TileGrid& grid)
491 {
492     RefPtr<PlatformCALayer> layer = m_tileCacheLayer->createCompatibleLayerOrTakeFromPool(PlatformCALayer::LayerTypeTiledBackingTileLayer, &grid, tileRect.size());
493
494     layer->setAnchorPoint(FloatPoint3D());
495     layer->setPosition(tileRect.location());
496     layer->setBorderColor(m_tileDebugBorderColor);
497     layer->setBorderWidth(m_tileDebugBorderWidth);
498     layer->setEdgeAntialiasingMask(0);
499     layer->setOpaque(m_tilesAreOpaque);
500 #ifndef NDEBUG
501     layer->setName("Tile");
502 #endif
503
504     float temporaryScaleFactor = owningGraphicsLayer()->platformCALayerContentsScaleMultiplierForNewTiles(m_tileCacheLayer);
505     m_hasTilesWithTemporaryScaleFactor |= temporaryScaleFactor != 1;
506
507     layer->setContentsScale(m_deviceScaleFactor * temporaryScaleFactor);
508     layer->setAcceleratesDrawing(m_acceleratesDrawing);
509
510     layer->setNeedsDisplay();
511
512     return layer;
513 }
514
515 Vector<RefPtr<PlatformCALayer>> TileController::containerLayers()
516 {
517     Vector<RefPtr<PlatformCALayer>> layerList;
518     if (m_zoomedOutTileGrid)
519         layerList.append(&m_zoomedOutTileGrid->containerLayer());
520     layerList.append(&tileGrid().containerLayer());
521     return layerList;
522 }
523
524 #if PLATFORM(IOS)
525 unsigned TileController::numberOfUnparentedTiles() const
526 {
527     unsigned count = tileGrid().numberOfUnparentedTiles();
528     if (m_zoomedOutTileGrid)
529         count += m_zoomedOutTileGrid->numberOfUnparentedTiles();
530     return count;
531 }
532
533 void TileController::removeUnparentedTilesNow()
534 {
535     tileGrid().removeUnparentedTilesNow();
536     if (m_zoomedOutTileGrid)
537         m_zoomedOutTileGrid->removeUnparentedTilesNow();
538
539     updateTileCoverageMap();
540 }
541 #endif
542
543 } // namespace WebCore