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