blob: 9b9e20f2fb3832cab20156d10cdde7375688c5ef [file] [log] [blame]
/*
* Copyright (C) 2011-2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "TileController.h"
#if USE(CG)
#include "GraphicsLayer.h"
#include "IntRect.h"
#include "Logging.h"
#include "PlatformCALayer.h"
#include "Region.h"
#include "TileCoverageMap.h"
#include "TileGrid.h"
#include "VelocityData.h"
#include <utility>
#include <wtf/MainThread.h>
#include <wtf/MemoryPressureHandler.h>
#include <wtf/text/TextStream.h>
#if HAVE(IOSURFACE)
#include "IOSurface.h"
#endif
#if PLATFORM(IOS_FAMILY)
#include "TileControllerMemoryHandlerIOS.h"
#endif
namespace WebCore {
static const Seconds tileSizeUpdateDelay { 500_ms };
String TileController::tileGridContainerLayerName()
{
return "TileGrid container"_s;
}
String TileController::zoomedOutTileGridContainerLayerName()
{
return "Zoomed-out TileGrid container"_s;
}
TileController::TileController(PlatformCALayer* rootPlatformLayer)
: m_tileCacheLayer(rootPlatformLayer)
, m_deviceScaleFactor(owningGraphicsLayer()->platformCALayerDeviceScaleFactor())
, m_tileGrid(makeUnique<TileGrid>(*this))
, m_tileRevalidationTimer(*this, &TileController::tileRevalidationTimerFired)
, m_tileSizeChangeTimer(*this, &TileController::tileSizeChangeTimerFired, tileSizeUpdateDelay)
, m_marginEdges(false, false, false, false)
{
}
TileController::~TileController()
{
ASSERT(isMainThread());
#if PLATFORM(IOS_FAMILY)
tileControllerMemoryHandler().removeTileController(this);
#endif
}
void TileController::tileCacheLayerBoundsChanged()
{
ASSERT(owningGraphicsLayer()->isCommittingChanges());
setNeedsRevalidateTiles();
notePendingTileSizeChange();
}
void TileController::setNeedsDisplay()
{
tileGrid().setNeedsDisplay();
clearZoomedOutTileGrid();
}
void TileController::setNeedsDisplayInRect(const IntRect& rect)
{
tileGrid().setNeedsDisplayInRect(rect);
if (m_zoomedOutTileGrid)
m_zoomedOutTileGrid->dropTilesInRect(rect);
updateTileCoverageMap();
}
void TileController::setContentsScale(float scale)
{
ASSERT(owningGraphicsLayer()->isCommittingChanges());
float deviceScaleFactor = owningGraphicsLayer()->platformCALayerDeviceScaleFactor();
// The scale we get is the product of the page scale factor and device scale factor.
// Divide by the device scale factor so we'll get the page scale factor.
scale /= deviceScaleFactor;
if (tileGrid().scale() == scale && m_deviceScaleFactor == deviceScaleFactor && !m_hasTilesWithTemporaryScaleFactor)
return;
m_hasTilesWithTemporaryScaleFactor = false;
m_deviceScaleFactor = deviceScaleFactor;
if (m_coverageMap)
m_coverageMap->setDeviceScaleFactor(deviceScaleFactor);
if (m_zoomedOutTileGrid && m_zoomedOutTileGrid->scale() == scale) {
m_tileGrid = WTFMove(m_zoomedOutTileGrid);
m_tileGrid->setIsZoomedOutTileGrid(false);
m_tileGrid->revalidateTiles();
tileGridsChanged();
return;
}
if (m_zoomedOutContentsScale && m_zoomedOutContentsScale == tileGrid().scale() && tileGrid().scale() != scale && !m_hasTilesWithTemporaryScaleFactor) {
m_zoomedOutTileGrid = WTFMove(m_tileGrid);
m_zoomedOutTileGrid->setIsZoomedOutTileGrid(true);
m_tileGrid = makeUnique<TileGrid>(*this);
tileGridsChanged();
}
tileGrid().setScale(scale);
tileGrid().setNeedsDisplay();
}
float TileController::contentsScale() const
{
return tileGrid().scale() * m_deviceScaleFactor;
}
float TileController::zoomedOutContentsScale() const
{
return m_zoomedOutContentsScale * m_deviceScaleFactor;
}
void TileController::setZoomedOutContentsScale(float scale)
{
ASSERT(owningGraphicsLayer()->isCommittingChanges());
float deviceScaleFactor = owningGraphicsLayer()->platformCALayerDeviceScaleFactor();
scale /= deviceScaleFactor;
if (m_zoomedOutContentsScale == scale)
return;
m_zoomedOutContentsScale = scale;
if (m_zoomedOutTileGrid && m_zoomedOutTileGrid->scale() != m_zoomedOutContentsScale)
clearZoomedOutTileGrid();
}
void TileController::setAcceleratesDrawing(bool acceleratesDrawing)
{
if (m_acceleratesDrawing == acceleratesDrawing)
return;
m_acceleratesDrawing = acceleratesDrawing;
tileGrid().updateTileLayerProperties();
}
void TileController::setWantsDeepColorBackingStore(bool wantsDeepColorBackingStore)
{
if (m_wantsDeepColorBackingStore == wantsDeepColorBackingStore)
return;
m_wantsDeepColorBackingStore = wantsDeepColorBackingStore;
tileGrid().updateTileLayerProperties();
}
void TileController::setSupportsSubpixelAntialiasedText(bool supportsSubpixelAntialiasedText)
{
if (m_supportsSubpixelAntialiasedText == supportsSubpixelAntialiasedText)
return;
m_supportsSubpixelAntialiasedText = supportsSubpixelAntialiasedText;
tileGrid().updateTileLayerProperties();
}
void TileController::setTilesOpaque(bool opaque)
{
if (opaque == m_tilesAreOpaque)
return;
m_tilesAreOpaque = opaque;
tileGrid().updateTileLayerProperties();
}
void TileController::setVisibleRect(const FloatRect& rect)
{
if (rect == m_visibleRect)
return;
m_visibleRect = rect;
updateTileCoverageMap();
}
void TileController::setLayoutViewportRect(std::optional<FloatRect> rect)
{
if (rect == m_layoutViewportRect)
return;
m_layoutViewportRect = rect;
updateTileCoverageMap();
}
void TileController::setCoverageRect(const FloatRect& rect)
{
ASSERT(owningGraphicsLayer()->isCommittingChanges());
if (m_coverageRect == rect)
return;
m_coverageRect = rect;
setNeedsRevalidateTiles();
}
bool TileController::tilesWouldChangeForCoverageRect(const FloatRect& rect) const
{
if (bounds().isEmpty())
return false;
return tileGrid().tilesWouldChangeForCoverageRect(rect);
}
void TileController::setVelocity(const VelocityData& velocity)
{
bool changeAffectsTileCoverage = m_velocity.velocityOrScaleIsChanging() || velocity.velocityOrScaleIsChanging();
m_velocity = velocity;
m_haveExternalVelocityData = true;
if (changeAffectsTileCoverage)
setNeedsRevalidateTiles();
}
void TileController::setScrollability(Scrollability scrollability)
{
if (scrollability == m_scrollability)
return;
m_scrollability = scrollability;
notePendingTileSizeChange();
}
void TileController::setTopContentInset(float topContentInset)
{
m_topContentInset = topContentInset;
setTiledScrollingIndicatorPosition(FloatPoint(0, m_topContentInset));
}
void TileController::setTiledScrollingIndicatorPosition(const FloatPoint& position)
{
if (!m_coverageMap)
return;
m_coverageMap->setPosition(position);
updateTileCoverageMap();
}
void TileController::prepopulateRect(const FloatRect& rect)
{
if (tileGrid().prepopulateRect(rect))
setNeedsRevalidateTiles();
}
void TileController::setIsInWindow(bool isInWindow)
{
if (m_isInWindow == isInWindow)
return;
m_isInWindow = isInWindow;
if (m_isInWindow)
setNeedsRevalidateTiles();
else {
const Seconds tileRevalidationTimeout = 4_s;
scheduleTileRevalidation(tileRevalidationTimeout);
}
}
void TileController::setTileCoverage(TileCoverage coverage)
{
if (coverage == m_tileCoverage)
return;
m_tileCoverage = coverage;
setNeedsRevalidateTiles();
}
void TileController::revalidateTiles()
{
ASSERT(owningGraphicsLayer()->isCommittingChanges());
tileGrid().revalidateTiles();
}
void TileController::forceRepaint()
{
setNeedsDisplay();
}
void TileController::setTileDebugBorderWidth(float borderWidth)
{
if (m_tileDebugBorderWidth == borderWidth)
return;
m_tileDebugBorderWidth = borderWidth;
tileGrid().updateTileLayerProperties();
}
void TileController::setTileDebugBorderColor(Color borderColor)
{
if (m_tileDebugBorderColor == borderColor)
return;
m_tileDebugBorderColor = borderColor;
tileGrid().updateTileLayerProperties();
}
void TileController::setTileSizeUpdateDelayDisabledForTesting(bool value)
{
m_isTileSizeUpdateDelayDisabledForTesting = value;
}
IntRect TileController::boundsForSize(const FloatSize& size) const
{
IntPoint boundsOriginIncludingMargin(-leftMarginWidth(), -topMarginHeight());
IntSize boundsSizeIncludingMargin = expandedIntSize(size);
boundsSizeIncludingMargin.expand(leftMarginWidth() + rightMarginWidth(), topMarginHeight() + bottomMarginHeight());
return IntRect(boundsOriginIncludingMargin, boundsSizeIncludingMargin);
}
IntRect TileController::bounds() const
{
return boundsForSize(m_tileCacheLayer->bounds().size());
}
IntRect TileController::boundsWithoutMargin() const
{
return IntRect(IntPoint(), expandedIntSize(m_tileCacheLayer->bounds().size()));
}
IntRect TileController::boundsAtLastRevalidateWithoutMargin() const
{
IntRect boundsWithoutMargin = IntRect(IntPoint(), m_boundsAtLastRevalidate.size());
boundsWithoutMargin.contract(IntSize(leftMarginWidth() + rightMarginWidth(), topMarginHeight() + bottomMarginHeight()));
return boundsWithoutMargin;
}
FloatRect TileController::adjustTileCoverageRect(const FloatRect& coverageRect, const FloatRect& previousVisibleRect, const FloatRect& currentVisibleRect, bool sizeChanged)
{
if (sizeChanged || MemoryPressureHandler::singleton().isUnderMemoryPressure())
return unionRect(coverageRect, currentVisibleRect);
return GraphicsLayer::adjustCoverageRectForMovement(coverageRect, previousVisibleRect, currentVisibleRect);
}
#if !PLATFORM(IOS_FAMILY)
// Coverage expansion for less memory-constrained devices.
// Kept separate to preserve historical behavior; should be merged with adjustTileCoverageWithScrollingVelocity eventually.
FloatRect TileController::adjustTileCoverageForDesktopPageScrolling(const FloatRect& coverageRect, const FloatSize& newSize, const FloatRect& previousVisibleRect, const FloatRect& visibleRect) const
{
// FIXME: look at how far the document can scroll in each dimension.
FloatSize coverageSize = visibleRect.size();
bool largeVisibleRectChange = !previousVisibleRect.isEmpty() && !visibleRect.intersects(previousVisibleRect);
// Inflate the coverage rect so that it covers 2x of the visible width and 3x of the visible height.
// These values were chosen because it's more common to have tall pages and to scroll vertically,
// so we keep more tiles above and below the current area.
float widthScale = 1;
float heightScale = 1;
if (m_tileCoverage & CoverageForHorizontalScrolling && !largeVisibleRectChange)
widthScale = 2;
if (m_tileCoverage & CoverageForVerticalScrolling && !largeVisibleRectChange)
heightScale = 3;
coverageSize.scale(widthScale, heightScale);
FloatRect coverageBounds = boundsForSize(newSize);
// Return 'rect' padded evenly on all sides to achieve 'newSize', but make the padding uneven to contain within constrainingRect.
auto expandRectWithinRect = [](const FloatRect& rect, const FloatSize& newSize, const FloatRect& constrainingRect) {
ASSERT(newSize.width() >= rect.width() && newSize.height() >= rect.height());
FloatSize extraSize = newSize - rect.size();
FloatRect expandedRect = rect;
expandedRect.inflateX(extraSize.width() / 2);
expandedRect.inflateY(extraSize.height() / 2);
if (expandedRect.x() < constrainingRect.x())
expandedRect.setX(constrainingRect.x());
else if (expandedRect.maxX() > constrainingRect.maxX())
expandedRect.setX(constrainingRect.maxX() - expandedRect.width());
if (expandedRect.y() < constrainingRect.y())
expandedRect.setY(constrainingRect.y());
else if (expandedRect.maxY() > constrainingRect.maxY())
expandedRect.setY(constrainingRect.maxY() - expandedRect.height());
return intersection(expandedRect, constrainingRect);
};
FloatRect coverage = expandRectWithinRect(visibleRect, coverageSize, coverageBounds);
LOG_WITH_STREAM(Tiling, stream << "TileController::adjustTileCoverageForDesktopPageScrolling newSize=" << newSize << " mode " << m_tileCoverage << " expanded to " << coverageSize << " bounds with margin " << coverageBounds << " coverage " << coverage);
return unionRect(coverageRect, coverage);
}
#endif
FloatRect TileController::adjustTileCoverageWithScrollingVelocity(const FloatRect& coverageRect, const FloatSize& newSize, const FloatRect& visibleRect, float contentsScale) const
{
if (m_tileCoverage == CoverageForVisibleArea || MemoryPressureHandler::singleton().isUnderMemoryPressure())
return visibleRect;
double horizontalMargin = kDefaultTileSize / contentsScale;
double verticalMargin = kDefaultTileSize / contentsScale;
MonotonicTime currentTime = MonotonicTime::now();
Seconds timeDelta = currentTime - m_velocity.lastUpdateTime;
FloatRect futureRect = visibleRect;
futureRect.setLocation(FloatPoint(
futureRect.location().x() + timeDelta.value() * m_velocity.horizontalVelocity,
futureRect.location().y() + timeDelta.value() * m_velocity.verticalVelocity));
if (m_velocity.horizontalVelocity) {
futureRect.setWidth(futureRect.width() + horizontalMargin);
if (m_velocity.horizontalVelocity < 0)
futureRect.setX(futureRect.x() - horizontalMargin);
}
if (m_velocity.verticalVelocity) {
futureRect.setHeight(futureRect.height() + verticalMargin);
if (m_velocity.verticalVelocity < 0)
futureRect.setY(futureRect.y() - verticalMargin);
}
if (!m_velocity.horizontalVelocity && !m_velocity.verticalVelocity) {
if (m_velocity.scaleChangeRate > 0) {
LOG_WITH_STREAM(Tiling, stream << "TileController " << this << " computeTileCoverageRect - zooming, coverage is visible rect " << coverageRect);
return visibleRect;
}
futureRect.setWidth(futureRect.width() + horizontalMargin);
futureRect.setHeight(futureRect.height() + verticalMargin);
futureRect.setX(futureRect.x() - horizontalMargin / 2);
futureRect.setY(futureRect.y() - verticalMargin / 2);
}
// Can't use m_tileCacheLayer->bounds() here, because the size of the underlying platform layer
// hasn't been updated for the current commit.
IntSize contentSize = expandedIntSize(newSize);
if (futureRect.maxX() > contentSize.width())
futureRect.setX(contentSize.width() - futureRect.width());
if (futureRect.maxY() > contentSize.height())
futureRect.setY(contentSize.height() - futureRect.height());
if (futureRect.x() < 0)
futureRect.setX(0);
if (futureRect.y() < 0)
futureRect.setY(0);
LOG_WITH_STREAM(Tiling, stream << "TileController " << this << " adjustTileCoverageForScrolling - coverage " << coverageRect << " expanded to " << unionRect(coverageRect, futureRect) << " velocity " << m_velocity);
return unionRect(coverageRect, futureRect);
}
FloatRect TileController::adjustTileCoverageRectForScrolling(const FloatRect& coverageRect, const FloatSize& newSize, const FloatRect& previousVisibleRect, const FloatRect& visibleRect, float contentsScale)
{
// 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.
if (!m_isInWindow)
return visibleRect;
#if !PLATFORM(IOS_FAMILY)
if (m_tileCacheLayer->isPageTiledBackingLayer())
return adjustTileCoverageForDesktopPageScrolling(coverageRect, newSize, previousVisibleRect, visibleRect);
#else
UNUSED_PARAM(previousVisibleRect);
#endif
auto computeVelocityIfNecessary = [&](FloatPoint scrollOffset) {
if (m_haveExternalVelocityData)
return;
if (!m_historicalVelocityData)
m_historicalVelocityData = makeUnique<HistoricalVelocityData>();
m_velocity = m_historicalVelocityData->velocityForNewData(scrollOffset, contentsScale, MonotonicTime::now());
};
computeVelocityIfNecessary(visibleRect.location());
return adjustTileCoverageWithScrollingVelocity(coverageRect, newSize, visibleRect, contentsScale);
}
void TileController::scheduleTileRevalidation(Seconds interval)
{
if (m_tileRevalidationTimer.isActive() && m_tileRevalidationTimer.nextFireInterval() < interval)
return;
m_tileRevalidationTimer.startOneShot(interval);
}
bool TileController::shouldAggressivelyRetainTiles() const
{
return owningGraphicsLayer()->platformCALayerShouldAggressivelyRetainTiles(m_tileCacheLayer);
}
bool TileController::shouldTemporarilyRetainTileCohorts() const
{
return owningGraphicsLayer()->platformCALayerShouldTemporarilyRetainTileCohorts(m_tileCacheLayer);
}
void TileController::willStartLiveResize()
{
m_inLiveResize = true;
}
void TileController::didEndLiveResize()
{
m_inLiveResize = false;
m_tileSizeLocked = false; // Let the end of a live resize update the tiles.
}
void TileController::notePendingTileSizeChange()
{
if (m_isTileSizeUpdateDelayDisabledForTesting)
tileSizeChangeTimerFired();
else
m_tileSizeChangeTimer.restart();
}
void TileController::tileSizeChangeTimerFired()
{
if (!owningGraphicsLayer())
return;
m_tileSizeLocked = false;
setNeedsRevalidateTiles();
}
IntSize TileController::tileSize() const
{
return tileGrid().tileSize();
}
IntSize TileController::computeTileSize()
{
if (m_inLiveResize || m_tileSizeLocked)
return tileGrid().tileSize();
const int kLowestCommonDenominatorMaxTileSize = 4 * 1024;
IntSize maxTileSize(kLowestCommonDenominatorMaxTileSize, kLowestCommonDenominatorMaxTileSize);
#if HAVE(IOSURFACE)
IntSize surfaceSizeLimit = IOSurface::maximumSize();
surfaceSizeLimit.scale(1 / m_deviceScaleFactor);
maxTileSize = maxTileSize.shrunkTo(surfaceSizeLimit);
#endif
if (owningGraphicsLayer()->platformCALayerUseGiantTiles())
return maxTileSize;
IntSize tileSize(kDefaultTileSize, kDefaultTileSize);
if (m_scrollability == NotScrollable) {
IntSize scaledSize = expandedIntSize(boundsWithoutMargin().size() * tileGrid().scale());
tileSize = scaledSize.constrainedBetween(IntSize(kDefaultTileSize, kDefaultTileSize), maxTileSize);
} else if (m_scrollability == VerticallyScrollable)
tileSize.setWidth(std::min(std::max<int>(ceilf(boundsWithoutMargin().width() * tileGrid().scale()), kDefaultTileSize), maxTileSize.width()));
LOG_WITH_STREAM(Scrolling, stream << "TileController::tileSize newSize=" << tileSize);
m_tileSizeLocked = true;
return tileSize;
}
void TileController::clearZoomedOutTileGrid()
{
m_zoomedOutTileGrid = nullptr;
tileGridsChanged();
}
void TileController::tileGridsChanged()
{
return owningGraphicsLayer()->platformCALayerCustomSublayersChanged(m_tileCacheLayer);
}
void TileController::tileRevalidationTimerFired()
{
if (!owningGraphicsLayer())
return;
if (m_isInWindow) {
setNeedsRevalidateTiles();
return;
}
// If we are not visible get rid of the zoomed-out tiles.
clearZoomedOutTileGrid();
tileGrid().revalidateTiles(shouldAggressivelyRetainTiles()
? OptionSet { TileGrid::PruneSecondaryTiles, TileGrid::UnparentAllTiles }
: OptionSet { TileGrid::UnparentAllTiles });
}
void TileController::didRevalidateTiles()
{
m_boundsAtLastRevalidate = bounds();
updateTileCoverageMap();
}
unsigned TileController::blankPixelCount() const
{
return tileGrid().blankPixelCount();
}
unsigned TileController::blankPixelCountForTiles(const PlatformLayerList& tiles, const FloatRect& visibleRect, const IntPoint& tileTranslation)
{
Region paintedVisibleTiles;
for (PlatformLayerList::const_iterator it = tiles.begin(), end = tiles.end(); it != end; ++it) {
const PlatformLayer* tileLayer = it->get();
FloatRect visiblePart(CGRectOffset(PlatformCALayer::frameForLayer(tileLayer), tileTranslation.x(), tileTranslation.y()));
visiblePart.intersect(visibleRect);
if (!visiblePart.isEmpty())
paintedVisibleTiles.unite(enclosingIntRect(visiblePart));
}
Region uncoveredRegion(enclosingIntRect(visibleRect));
uncoveredRegion.subtract(paintedVisibleTiles);
return static_cast<unsigned>(uncoveredRegion.totalArea());
}
void TileController::setNeedsRevalidateTiles()
{
owningGraphicsLayer()->platformCALayerSetNeedsToRevalidateTiles();
}
void TileController::updateTileCoverageMap()
{
if (m_coverageMap)
m_coverageMap->setNeedsUpdate();
}
IntRect TileController::tileGridExtent() const
{
return tileGrid().extent();
}
double TileController::retainedTileBackingStoreMemory() const
{
double bytes = tileGrid().retainedTileBackingStoreMemory();
if (m_zoomedOutTileGrid)
bytes += m_zoomedOutTileGrid->retainedTileBackingStoreMemory();
return bytes;
}
// Return the rect in layer coords, not tile coords.
IntRect TileController::tileCoverageRect() const
{
return tileGrid().tileCoverageRect();
}
PlatformCALayer* TileController::tiledScrollingIndicatorLayer()
{
if (!m_coverageMap)
m_coverageMap = makeUnique<TileCoverageMap>(*this);
return &m_coverageMap->layer();
}
void TileController::setScrollingModeIndication(ScrollingModeIndication scrollingMode)
{
if (scrollingMode == m_indicatorMode)
return;
m_indicatorMode = scrollingMode;
updateTileCoverageMap();
}
void TileController::setHasMargins(bool marginTop, bool marginBottom, bool marginLeft, bool marginRight)
{
RectEdges<bool> marginEdges(marginTop, marginRight, marginBottom, marginLeft);
if (marginEdges == m_marginEdges)
return;
m_marginEdges = marginEdges;
setNeedsRevalidateTiles();
}
void TileController::setMarginSize(int marginSize)
{
if (marginSize == m_marginSize)
return;
m_marginSize = marginSize;
setNeedsRevalidateTiles();
}
bool TileController::hasMargins() const
{
return m_marginSize && (m_marginEdges.top() || m_marginEdges.bottom() || m_marginEdges.left() || m_marginEdges.right());
}
bool TileController::hasHorizontalMargins() const
{
return m_marginSize && (m_marginEdges.left() || m_marginEdges.right());
}
bool TileController::hasVerticalMargins() const
{
return m_marginSize && (m_marginEdges.top() || m_marginEdges.bottom());
}
int TileController::topMarginHeight() const
{
return (m_marginSize * m_marginEdges.top()) / tileGrid().scale();
}
int TileController::bottomMarginHeight() const
{
return (m_marginSize * m_marginEdges.bottom()) / tileGrid().scale();
}
int TileController::leftMarginWidth() const
{
return (m_marginSize * m_marginEdges.left()) / tileGrid().scale();
}
int TileController::rightMarginWidth() const
{
return (m_marginSize * m_marginEdges.right()) / tileGrid().scale();
}
Ref<PlatformCALayer> TileController::createTileLayer(const IntRect& tileRect, TileGrid& grid)
{
float temporaryScaleFactor = owningGraphicsLayer()->platformCALayerContentsScaleMultiplierForNewTiles(m_tileCacheLayer);
m_hasTilesWithTemporaryScaleFactor |= temporaryScaleFactor != 1;
auto layer = m_tileCacheLayer->createCompatibleLayerOrTakeFromPool(PlatformCALayer::LayerTypeTiledBackingTileLayer, &grid, tileRect.size());
layer->setAnchorPoint(FloatPoint3D());
layer->setPosition(tileRect.location());
layer->setBorderColor(m_tileDebugBorderColor);
layer->setBorderWidth(m_tileDebugBorderWidth);
layer->setEdgeAntialiasingMask(0);
layer->setOpaque(m_tilesAreOpaque);
layer->setName(makeString("tile at ", tileRect.location().x(), ',', tileRect.location().y()));
layer->setContentsScale(m_deviceScaleFactor * temporaryScaleFactor);
layer->setAcceleratesDrawing(m_acceleratesDrawing);
layer->setWantsDeepColorBackingStore(m_wantsDeepColorBackingStore);
layer->setSupportsSubpixelAntialiasedText(m_supportsSubpixelAntialiasedText);
layer->setNeedsDisplay();
return layer;
}
Vector<RefPtr<PlatformCALayer>> TileController::containerLayers()
{
Vector<RefPtr<PlatformCALayer>> layerList;
if (m_zoomedOutTileGrid)
layerList.append(&m_zoomedOutTileGrid->containerLayer());
layerList.append(&tileGrid().containerLayer());
return layerList;
}
#if PLATFORM(IOS_FAMILY)
unsigned TileController::numberOfUnparentedTiles() const
{
unsigned count = tileGrid().numberOfUnparentedTiles();
if (m_zoomedOutTileGrid)
count += m_zoomedOutTileGrid->numberOfUnparentedTiles();
return count;
}
void TileController::removeUnparentedTilesNow()
{
tileGrid().removeUnparentedTilesNow();
if (m_zoomedOutTileGrid)
m_zoomedOutTileGrid->removeUnparentedTilesNow();
updateTileCoverageMap();
}
#endif
void TileController::logFilledVisibleFreshTile(unsigned blankPixelCount)
{
owningGraphicsLayer()->platformCALayerLogFilledVisibleFreshTile(blankPixelCount);
}
} // namespace WebCore
#endif