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