99b5b620f19c5cafaca07b63828c76574f05b91d
[WebKit.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 "Logging.h"
31 #include "PlatformCALayer.h"
32 #include "Region.h"
33 #include "TextStream.h"
34 #include "TileCoverageMap.h"
35 #include "TileGrid.h"
36 #include <utility>
37 #include <wtf/MainThread.h>
38
39 #if PLATFORM(IOS)
40 #include "MemoryPressureHandler.h"
41 #include "TileControllerMemoryHandlerIOS.h"
42 #endif
43
44 namespace WebCore {
45
46 static const auto tileSizeUpdateDelay = std::chrono::milliseconds { 500 };
47
48 String TileController::tileGridContainerLayerName()
49 {
50     return ASCIILiteral("TileGrid Container Layer");
51 }
52
53 String TileController::zoomedOutTileGridContainerLayerName()
54 {
55     return ASCIILiteral("Zoomed Out TileGrid Container Layer");
56 }
57
58 TileController::TileController(PlatformCALayer* rootPlatformLayer)
59     : m_tileCacheLayer(rootPlatformLayer)
60     , m_tileGrid(std::make_unique<TileGrid>(*this))
61     , m_tileRevalidationTimer(*this, &TileController::tileRevalidationTimerFired)
62     , m_tileSizeChangeTimer(*this, &TileController::tileSizeChangeTimerFired, tileSizeUpdateDelay)
63     , m_deviceScaleFactor(owningGraphicsLayer()->platformCALayerDeviceScaleFactor())
64     , m_marginEdges(false, false, false, false)
65 {
66 }
67
68 TileController::~TileController()
69 {
70     ASSERT(isMainThread());
71
72 #if PLATFORM(IOS)
73     tileControllerMemoryHandler().removeTileController(this);
74 #endif
75 }
76
77 void TileController::tileCacheLayerBoundsChanged()
78 {
79     ASSERT(owningGraphicsLayer()->isCommittingChanges());
80     setNeedsRevalidateTiles();
81     notePendingTileSizeChange();
82 }
83
84 void TileController::setNeedsDisplay()
85 {
86     tileGrid().setNeedsDisplay();
87     clearZoomedOutTileGrid();
88 }
89
90 void TileController::setNeedsDisplayInRect(const IntRect& rect)
91 {
92     tileGrid().setNeedsDisplayInRect(rect);
93     if (m_zoomedOutTileGrid)
94         m_zoomedOutTileGrid->dropTilesInRect(rect);
95     updateTileCoverageMap();
96 }
97
98 void TileController::setContentsScale(float scale)
99 {
100     ASSERT(owningGraphicsLayer()->isCommittingChanges());
101
102     float deviceScaleFactor = owningGraphicsLayer()->platformCALayerDeviceScaleFactor();
103     // The scale we get is the product of the page scale factor and device scale factor.
104     // Divide by the device scale factor so we'll get the page scale factor.
105     scale /= deviceScaleFactor;
106
107     if (tileGrid().scale() == scale && m_deviceScaleFactor == deviceScaleFactor && !m_hasTilesWithTemporaryScaleFactor)
108         return;
109
110     m_hasTilesWithTemporaryScaleFactor = false;
111     m_deviceScaleFactor = deviceScaleFactor;
112
113     if (m_coverageMap)
114         m_coverageMap->setDeviceScaleFactor(deviceScaleFactor);
115
116     if (m_zoomedOutTileGrid && m_zoomedOutTileGrid->scale() == scale) {
117         m_tileGrid = WTFMove(m_zoomedOutTileGrid);
118         m_tileGrid->setIsZoomedOutTileGrid(false);
119         m_tileGrid->revalidateTiles();
120         tileGridsChanged();
121         return;
122     }
123
124     if (m_zoomedOutContentsScale && m_zoomedOutContentsScale == tileGrid().scale() && tileGrid().scale() != scale && !m_hasTilesWithTemporaryScaleFactor) {
125         m_zoomedOutTileGrid = WTFMove(m_tileGrid);
126         m_zoomedOutTileGrid->setIsZoomedOutTileGrid(true);
127         m_tileGrid = std::make_unique<TileGrid>(*this);
128         tileGridsChanged();
129     }
130
131     tileGrid().setScale(scale);
132     tileGrid().setNeedsDisplay();
133 }
134
135 float TileController::contentsScale() const
136 {
137     return tileGrid().scale() * m_deviceScaleFactor;
138 }
139
140 float TileController::zoomedOutContentsScale() const
141 {
142     return m_zoomedOutContentsScale * m_deviceScaleFactor;
143 }
144
145 void TileController::setZoomedOutContentsScale(float scale)
146 {
147     ASSERT(owningGraphicsLayer()->isCommittingChanges());
148
149     float deviceScaleFactor = owningGraphicsLayer()->platformCALayerDeviceScaleFactor();
150     scale /= deviceScaleFactor;
151
152     if (m_zoomedOutContentsScale == scale)
153         return;
154     m_zoomedOutContentsScale = scale;
155
156     if (m_zoomedOutTileGrid && m_zoomedOutTileGrid->scale() != m_zoomedOutContentsScale)
157         clearZoomedOutTileGrid();
158 }
159
160 void TileController::setAcceleratesDrawing(bool acceleratesDrawing)
161 {
162     if (m_acceleratesDrawing == acceleratesDrawing)
163         return;
164     m_acceleratesDrawing = acceleratesDrawing;
165
166     tileGrid().updateTileLayerProperties();
167 }
168
169 void TileController::setTilesOpaque(bool opaque)
170 {
171     if (opaque == m_tilesAreOpaque)
172         return;
173     m_tilesAreOpaque = opaque;
174
175     tileGrid().updateTileLayerProperties();
176 }
177
178 void TileController::setVisibleRect(const FloatRect& rect)
179 {
180     if (rect == m_visibleRect)
181         return;
182
183     m_visibleRect = rect;
184     updateTileCoverageMap();
185 }
186
187 void TileController::setCoverageRect(const FloatRect& rect)
188 {
189     ASSERT(owningGraphicsLayer()->isCommittingChanges());
190     if (m_coverageRect == rect)
191         return;
192
193     m_coverageRect = rect;
194     setNeedsRevalidateTiles();
195 }
196
197 bool TileController::tilesWouldChangeForCoverageRect(const FloatRect& rect) const
198 {
199     if (bounds().isEmpty())
200         return false;
201
202     return tileGrid().tilesWouldChangeForCoverageRect(rect);
203 }
204
205 void TileController::setVelocity(const VelocityData& velocity)
206 {
207     bool changeAffectsTileCoverage = m_velocity.velocityOrScaleIsChanging() || velocity.velocityOrScaleIsChanging();
208     m_velocity = velocity;
209     
210     if (changeAffectsTileCoverage)
211         setNeedsRevalidateTiles();
212 }
213
214 void TileController::setScrollability(Scrollability scrollability)
215 {
216     if (scrollability == m_scrollability)
217         return;
218     
219     m_scrollability = scrollability;
220     notePendingTileSizeChange();
221 }
222
223 void TileController::setTopContentInset(float topContentInset)
224 {
225     m_topContentInset = topContentInset;
226     setTiledScrollingIndicatorPosition(FloatPoint(0, m_topContentInset));
227 }
228
229 void TileController::setTiledScrollingIndicatorPosition(const FloatPoint& position)
230 {
231     if (!m_coverageMap)
232         return;
233
234     m_coverageMap->setPosition(position);
235     updateTileCoverageMap();
236 }
237
238 void TileController::prepopulateRect(const FloatRect& rect)
239 {
240     if (tileGrid().prepopulateRect(rect))
241         setNeedsRevalidateTiles();
242 }
243
244 void TileController::setIsInWindow(bool isInWindow)
245 {
246     if (m_isInWindow == isInWindow)
247         return;
248
249     m_isInWindow = isInWindow;
250
251     if (m_isInWindow)
252         setNeedsRevalidateTiles();
253     else {
254         const double tileRevalidationTimeout = 4;
255         scheduleTileRevalidation(tileRevalidationTimeout);
256     }
257 }
258
259 void TileController::setTileCoverage(TileCoverage coverage)
260 {
261     if (coverage == m_tileCoverage)
262         return;
263
264     m_tileCoverage = coverage;
265     setNeedsRevalidateTiles();
266 }
267
268 void TileController::revalidateTiles()
269 {
270     ASSERT(owningGraphicsLayer()->isCommittingChanges());
271     tileGrid().revalidateTiles();
272 }
273
274 void TileController::forceRepaint()
275 {
276     setNeedsDisplay();
277 }
278
279 void TileController::setTileDebugBorderWidth(float borderWidth)
280 {
281     if (m_tileDebugBorderWidth == borderWidth)
282         return;
283     m_tileDebugBorderWidth = borderWidth;
284
285     tileGrid().updateTileLayerProperties();
286 }
287
288 void TileController::setTileDebugBorderColor(Color borderColor)
289 {
290     if (m_tileDebugBorderColor == borderColor)
291         return;
292     m_tileDebugBorderColor = borderColor;
293
294     tileGrid().updateTileLayerProperties();
295 }
296
297 IntRect TileController::boundsForSize(const FloatSize& size) const
298 {
299     IntPoint boundsOriginIncludingMargin(-leftMarginWidth(), -topMarginHeight());
300     IntSize boundsSizeIncludingMargin = expandedIntSize(size);
301     boundsSizeIncludingMargin.expand(leftMarginWidth() + rightMarginWidth(), topMarginHeight() + bottomMarginHeight());
302
303     return IntRect(boundsOriginIncludingMargin, boundsSizeIncludingMargin);
304 }
305
306 IntRect TileController::bounds() const
307 {
308     return boundsForSize(m_tileCacheLayer->bounds().size());
309 }
310
311 IntRect TileController::boundsWithoutMargin() const
312 {
313     return IntRect(IntPoint(), expandedIntSize(m_tileCacheLayer->bounds().size()));
314 }
315
316 IntRect TileController::boundsAtLastRevalidateWithoutMargin() const
317 {
318     IntRect boundsWithoutMargin = IntRect(IntPoint(), m_boundsAtLastRevalidate.size());
319     boundsWithoutMargin.contract(IntSize(leftMarginWidth() + rightMarginWidth(), topMarginHeight() + bottomMarginHeight()));
320     return boundsWithoutMargin;
321 }
322
323 #if !PLATFORM(IOS)
324 // Return 'rect' padded evenly on all sides to achieve 'newSize', but make the padding uneven to contain within constrainingRect.
325 static FloatRect expandRectWithinRect(const FloatRect& rect, const FloatSize& newSize, const FloatRect& constrainingRect)
326 {
327     ASSERT(newSize.width() >= rect.width() && newSize.height() >= rect.height());
328
329     FloatSize extraSize = newSize - rect.size();
330     
331     FloatRect expandedRect = rect;
332     expandedRect.inflateX(extraSize.width() / 2);
333     expandedRect.inflateY(extraSize.height() / 2);
334
335     if (expandedRect.x() < constrainingRect.x())
336         expandedRect.setX(constrainingRect.x());
337     else if (expandedRect.maxX() > constrainingRect.maxX())
338         expandedRect.setX(constrainingRect.maxX() - expandedRect.width());
339     
340     if (expandedRect.y() < constrainingRect.y())
341         expandedRect.setY(constrainingRect.y());
342     else if (expandedRect.maxY() > constrainingRect.maxY())
343         expandedRect.setY(constrainingRect.maxY() - expandedRect.height());
344     
345     return intersection(expandedRect, constrainingRect);
346 }
347 #endif
348
349 void TileController::adjustTileCoverageRect(FloatRect& coverageRect, const FloatSize& newSize, const FloatRect& previousVisibleRect, const FloatRect& visibleRect, float contentsScale) const
350 {
351     // 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.
352     if (!m_isInWindow) {
353         coverageRect = visibleRect;
354         return;
355     }
356
357 #if PLATFORM(IOS)
358     // FIXME: unify the iOS and Mac code.
359     UNUSED_PARAM(previousVisibleRect);
360     
361     if (m_tileCoverage == CoverageForVisibleArea || MemoryPressureHandler::singleton().isUnderMemoryPressure()) {
362         coverageRect = visibleRect;
363         return;
364     }
365
366     double horizontalMargin = kDefaultTileSize / contentsScale;
367     double verticalMargin = kDefaultTileSize / contentsScale;
368
369     double currentTime = monotonicallyIncreasingTime();
370     double timeDelta = currentTime - m_velocity.lastUpdateTime;
371
372     FloatRect futureRect = visibleRect;
373     futureRect.setLocation(FloatPoint(
374         futureRect.location().x() + timeDelta * m_velocity.horizontalVelocity,
375         futureRect.location().y() + timeDelta * m_velocity.verticalVelocity));
376
377     if (m_velocity.horizontalVelocity) {
378         futureRect.setWidth(futureRect.width() + horizontalMargin);
379         if (m_velocity.horizontalVelocity < 0)
380             futureRect.setX(futureRect.x() - horizontalMargin);
381     }
382
383     if (m_velocity.verticalVelocity) {
384         futureRect.setHeight(futureRect.height() + verticalMargin);
385         if (m_velocity.verticalVelocity < 0)
386             futureRect.setY(futureRect.y() - verticalMargin);
387     }
388
389     if (!m_velocity.horizontalVelocity && !m_velocity.verticalVelocity) {
390         if (m_velocity.scaleChangeRate > 0) {
391             coverageRect = visibleRect;
392             return;
393         }
394         futureRect.setWidth(futureRect.width() + horizontalMargin);
395         futureRect.setHeight(futureRect.height() + verticalMargin);
396         futureRect.setX(futureRect.x() - horizontalMargin / 2);
397         futureRect.setY(futureRect.y() - verticalMargin / 2);
398     }
399
400     // Can't use m_tileCacheLayer->bounds() here, because the size of the underlying platform layer
401     // hasn't been updated for the current commit.
402     IntSize contentSize = expandedIntSize(newSize);
403     if (futureRect.maxX() > contentSize.width())
404         futureRect.setX(contentSize.width() - futureRect.width());
405     if (futureRect.maxY() > contentSize.height())
406         futureRect.setY(contentSize.height() - futureRect.height());
407     if (futureRect.x() < 0)
408         futureRect.setX(0);
409     if (futureRect.y() < 0)
410         futureRect.setY(0);
411
412     coverageRect.unite(futureRect);
413     return;
414 #else
415     UNUSED_PARAM(contentsScale);
416
417     // FIXME: look at how far the document can scroll in each dimension.
418     FloatSize coverageSize = visibleRect.size();
419
420     bool largeVisibleRectChange = !previousVisibleRect.isEmpty() && !visibleRect.intersects(previousVisibleRect);
421
422     // Inflate the coverage rect so that it covers 2x of the visible width and 3x of the visible height.
423     // These values were chosen because it's more common to have tall pages and to scroll vertically,
424     // so we keep more tiles above and below the current area.
425     float widthScale = 1;
426     float heightScale = 1;
427
428     if (m_tileCoverage & CoverageForHorizontalScrolling && !largeVisibleRectChange)
429         widthScale = 2;
430
431     if (m_tileCoverage & CoverageForVerticalScrolling && !largeVisibleRectChange)
432         heightScale = 3;
433     
434     coverageSize.scale(widthScale, heightScale);
435
436     FloatRect coverageBounds = boundsForSize(newSize);
437     
438     FloatRect coverage = expandRectWithinRect(visibleRect, coverageSize, coverageBounds);
439     LOG_WITH_STREAM(Scrolling, stream << "TileController::computeTileCoverageRect newSize=" << newSize << " mode " << m_tileCoverage << " expanded to " << coverageSize << " bounds with margin " << coverageBounds << " coverage " << coverage);
440     coverageRect.unite(coverage);
441 #endif
442 }
443
444 void TileController::scheduleTileRevalidation(double interval)
445 {
446     if (m_tileRevalidationTimer.isActive() && m_tileRevalidationTimer.nextFireInterval() < interval)
447         return;
448
449     m_tileRevalidationTimer.startOneShot(interval);
450 }
451
452 bool TileController::shouldAggressivelyRetainTiles() const
453 {
454     return owningGraphicsLayer()->platformCALayerShouldAggressivelyRetainTiles(m_tileCacheLayer);
455 }
456
457 bool TileController::shouldTemporarilyRetainTileCohorts() const
458 {
459     return owningGraphicsLayer()->platformCALayerShouldTemporarilyRetainTileCohorts(m_tileCacheLayer);
460 }
461
462 void TileController::willStartLiveResize()
463 {
464     m_inLiveResize = true;
465 }
466
467 void TileController::didEndLiveResize()
468 {
469     m_inLiveResize = false;
470     m_tileSizeLocked = false; // Let the end of a live resize update the tiles.
471 }
472
473 void TileController::notePendingTileSizeChange()
474 {
475     m_tileSizeChangeTimer.restart();
476 }
477
478 void TileController::tileSizeChangeTimerFired()
479 {
480     if (!owningGraphicsLayer())
481         return;
482
483     m_tileSizeLocked = false;
484     setNeedsRevalidateTiles();
485 }
486
487 IntSize TileController::tileSize() const
488 {
489     if (m_inLiveResize || m_tileSizeLocked)
490         return tileGrid().tileSize();
491
492     if (owningGraphicsLayer()->platformCALayerUseGiantTiles())
493         return IntSize(kGiantTileSize, kGiantTileSize);
494
495     IntSize tileSize(kDefaultTileSize, kDefaultTileSize);
496
497     if (m_scrollability == NotScrollable) {
498         IntSize scaledSize = expandedIntSize(boundsWithoutMargin().size() * tileGrid().scale());
499         tileSize = scaledSize.constrainedBetween(IntSize(kDefaultTileSize, kDefaultTileSize), IntSize(kGiantTileSize, kGiantTileSize));
500     } else if (m_scrollability == VerticallyScrollable)
501         tileSize.setWidth(std::min(std::max<int>(ceilf(boundsWithoutMargin().width() * tileGrid().scale()), kDefaultTileSize), kGiantTileSize));
502
503     LOG_WITH_STREAM(Scrolling, stream << "TileController::tileSize newSize=" << tileSize);
504
505     m_tileSizeLocked = true;
506     return tileSize;
507 }
508
509 void TileController::clearZoomedOutTileGrid()
510 {
511     m_zoomedOutTileGrid = nullptr;
512     tileGridsChanged();
513 }
514
515 void TileController::tileGridsChanged()
516 {
517     return owningGraphicsLayer()->platformCALayerCustomSublayersChanged(m_tileCacheLayer);
518 }
519
520 void TileController::tileRevalidationTimerFired()
521 {
522     if (!owningGraphicsLayer())
523         return;
524
525     if (m_isInWindow) {
526         setNeedsRevalidateTiles();
527         return;
528     }
529     // If we are not visible get rid of the zoomed-out tiles.
530     clearZoomedOutTileGrid();
531
532     TileGrid::TileValidationPolicy validationPolicy = (shouldAggressivelyRetainTiles() ? 0 : TileGrid::PruneSecondaryTiles) | TileGrid::UnparentAllTiles;
533
534     tileGrid().revalidateTiles(validationPolicy);
535 }
536
537 void TileController::didRevalidateTiles()
538 {
539     m_boundsAtLastRevalidate = bounds();
540
541     updateTileCoverageMap();
542 }
543
544 unsigned TileController::blankPixelCount() const
545 {
546     return tileGrid().blankPixelCount();
547 }
548
549 unsigned TileController::blankPixelCountForTiles(const PlatformLayerList& tiles, const FloatRect& visibleRect, const IntPoint& tileTranslation)
550 {
551     Region paintedVisibleTiles;
552
553     for (PlatformLayerList::const_iterator it = tiles.begin(), end = tiles.end(); it != end; ++it) {
554         const PlatformLayer* tileLayer = it->get();
555
556         FloatRect visiblePart(CGRectOffset(PlatformCALayer::frameForLayer(tileLayer), tileTranslation.x(), tileTranslation.y()));
557         visiblePart.intersect(visibleRect);
558
559         if (!visiblePart.isEmpty())
560             paintedVisibleTiles.unite(enclosingIntRect(visiblePart));
561     }
562
563     Region uncoveredRegion(enclosingIntRect(visibleRect));
564     uncoveredRegion.subtract(paintedVisibleTiles);
565
566     return uncoveredRegion.totalArea();
567 }
568
569 void TileController::setNeedsRevalidateTiles()
570 {
571     owningGraphicsLayer()->platformCALayerSetNeedsToRevalidateTiles();
572 }
573
574 void TileController::updateTileCoverageMap()
575 {
576     if (m_coverageMap)
577         m_coverageMap->setNeedsUpdate();
578 }
579
580 IntRect TileController::tileGridExtent() const
581 {
582     return tileGrid().extent();
583 }
584
585 double TileController::retainedTileBackingStoreMemory() const
586 {
587     double bytes = tileGrid().retainedTileBackingStoreMemory();
588     if (m_zoomedOutTileGrid)
589         bytes += m_zoomedOutTileGrid->retainedTileBackingStoreMemory();
590     return bytes;
591 }
592
593 // Return the rect in layer coords, not tile coords.
594 IntRect TileController::tileCoverageRect() const
595 {
596     return tileGrid().tileCoverageRect();
597 }
598
599 PlatformCALayer* TileController::tiledScrollingIndicatorLayer()
600 {
601     if (!m_coverageMap)
602         m_coverageMap = std::make_unique<TileCoverageMap>(*this);
603
604     return &m_coverageMap->layer();
605 }
606
607 void TileController::setScrollingModeIndication(ScrollingModeIndication scrollingMode)
608 {
609     if (scrollingMode == m_indicatorMode)
610         return;
611
612     m_indicatorMode = scrollingMode;
613
614     updateTileCoverageMap();
615 }
616
617 void TileController::setHasMargins(bool marginTop, bool marginBottom, bool marginLeft, bool marginRight)
618 {
619     BoxExtent<bool> marginEdges(marginTop, marginRight, marginBottom, marginLeft);
620     if (marginEdges == m_marginEdges)
621         return;
622     
623     m_marginEdges = marginEdges;
624     setNeedsRevalidateTiles();
625 }
626
627 void TileController::setMarginSize(int marginSize)
628 {
629     if (marginSize == m_marginSize)
630         return;
631     
632     m_marginSize = marginSize;
633     setNeedsRevalidateTiles();
634 }
635
636 bool TileController::hasMargins() const
637 {
638     return m_marginSize && (m_marginEdges.top() || m_marginEdges.bottom() || m_marginEdges.left() || m_marginEdges.right());
639 }
640
641 bool TileController::hasHorizontalMargins() const
642 {
643     return m_marginSize && (m_marginEdges.left() || m_marginEdges.right());
644 }
645
646 bool TileController::hasVerticalMargins() const
647 {
648     return m_marginSize && (m_marginEdges.top() || m_marginEdges.bottom());
649 }
650
651 int TileController::topMarginHeight() const
652 {
653     return (m_marginSize * m_marginEdges.top()) / tileGrid().scale();
654 }
655
656 int TileController::bottomMarginHeight() const
657 {
658     return (m_marginSize * m_marginEdges.bottom()) / tileGrid().scale();
659 }
660
661 int TileController::leftMarginWidth() const
662 {
663     return (m_marginSize * m_marginEdges.left()) / tileGrid().scale();
664 }
665
666 int TileController::rightMarginWidth() const
667 {
668     return (m_marginSize * m_marginEdges.right()) / tileGrid().scale();
669 }
670
671 RefPtr<PlatformCALayer> TileController::createTileLayer(const IntRect& tileRect, TileGrid& grid)
672 {
673     RefPtr<PlatformCALayer> layer = m_tileCacheLayer->createCompatibleLayerOrTakeFromPool(PlatformCALayer::LayerTypeTiledBackingTileLayer, &grid, tileRect.size());
674
675     layer->setAnchorPoint(FloatPoint3D());
676     layer->setPosition(tileRect.location());
677     layer->setBorderColor(m_tileDebugBorderColor);
678     layer->setBorderWidth(m_tileDebugBorderWidth);
679     layer->setEdgeAntialiasingMask(0);
680     layer->setOpaque(m_tilesAreOpaque);
681 #ifndef NDEBUG
682     layer->setName("Tile");
683 #endif
684
685     float temporaryScaleFactor = owningGraphicsLayer()->platformCALayerContentsScaleMultiplierForNewTiles(m_tileCacheLayer);
686     m_hasTilesWithTemporaryScaleFactor |= temporaryScaleFactor != 1;
687
688     layer->setContentsScale(m_deviceScaleFactor * temporaryScaleFactor);
689     layer->setAcceleratesDrawing(m_acceleratesDrawing);
690
691     layer->setNeedsDisplay();
692
693     return layer;
694 }
695
696 Vector<RefPtr<PlatformCALayer>> TileController::containerLayers()
697 {
698     Vector<RefPtr<PlatformCALayer>> layerList;
699     if (m_zoomedOutTileGrid)
700         layerList.append(&m_zoomedOutTileGrid->containerLayer());
701     layerList.append(&tileGrid().containerLayer());
702     return layerList;
703 }
704
705 #if PLATFORM(IOS)
706 unsigned TileController::numberOfUnparentedTiles() const
707 {
708     unsigned count = tileGrid().numberOfUnparentedTiles();
709     if (m_zoomedOutTileGrid)
710         count += m_zoomedOutTileGrid->numberOfUnparentedTiles();
711     return count;
712 }
713
714 void TileController::removeUnparentedTilesNow()
715 {
716     tileGrid().removeUnparentedTilesNow();
717     if (m_zoomedOutTileGrid)
718         m_zoomedOutTileGrid->removeUnparentedTilesNow();
719
720     updateTileCoverageMap();
721 }
722 #endif
723
724 } // namespace WebCore