Diff
Modified: trunk/Source/WebCore/ChangeLog (159644 => 159645)
--- trunk/Source/WebCore/ChangeLog 2013-11-21 21:55:20 UTC (rev 159644)
+++ trunk/Source/WebCore/ChangeLog 2013-11-21 21:57:53 UTC (rev 159645)
@@ -1,3 +1,72 @@
+2013-11-21 Beth Dakin <[email protected]>
+
+ Add a new mode to extend the tile cache beyond the page
+ https://bugs.webkit.org/show_bug.cgi?id=124216
+
+ Reviewed by Simon Fraser.
+
+ This patch makes it possible to give the tile cache a margin of tiles. If there is
+ a margin of tiles, this patch paints those tiles with the background color. Note
+ that this patch does not actually give the tile cache a margin at this time.
+
+ You opt into a margined tiled cache by called setTileMargins() with number of
+ pixels that the margin on that side should be.
+ * platform/graphics/TiledBacking.h:
+ * platform/graphics/ca/mac/TileController.h:
+ * platform/graphics/ca/mac/TileController.mm:
+ (WebCore::TileController::TileController):
+ (WebCore::TileController::tilesWouldChangeForVisibleRect):
+
+ TileController::bounds() now computes the bounds INCLUDING the margin.
+ (WebCore::TileController::bounds):
+
+ adjustRectAtTileIndexForMargin() is a new function that is required to get the
+ rect size for tiles in the margin right. rectForTileIndex() assumes all tiles
+ strive to be the size of m_tileSize, but now margin tiles will be whatever the
+ margin sizes were set to.
+ (WebCore::TileController::adjustRectAtTileIndexForMargin):
+ (WebCore::TileController::rectForTileIndex):
+
+ This is another instance where m_tileSize is not always the right size to use.
+ (WebCore::TileController::getTileIndexRangeForRect):
+
+ The tile coverage rect now might include the margin tiles. Only include them in
+ slow-scrolling mode if the current position is within one tile of the edge.
+ (WebCore::TileController::computeTileCoverageRect):
+
+ tileSizeForCoverageRect() does not make sense in a world where the coverage rect
+ will include margin. Instead, this patch implements the current strategy more
+ explicitly by returning the visibleRect in the slow scrolling case, and in the
+ process this patch also re-names tileSizeForCoverageRect() to computeTileSize()
+ since it no longer takes a coverageRect.
+ (WebCore::TileController::computeTileSize):
+ (WebCore::TileController::revalidateTiles):
+
+ New setters and getters for the tile margins on each side.
+ (WebCore::TileController::setTileMargins):
+ (WebCore::TileController::hasMargins):
+ (WebCore::TileController::topMarginHeight):
+ (WebCore::TileController::bottomMarginHeight):
+ (WebCore::TileController::leftMarginWidth):
+ (WebCore::TileController::rightMarginWidth):
+
+ New function to add margin onto the composited bounds if there is one.
+ * rendering/RenderLayerBacking.cpp:
+ (WebCore::RenderLayerBacking::tiledBackingHasMargin):
+ (WebCore::RenderLayerBacking::paintContents):
+ (WebCore::RenderLayerBacking::compositedBoundsIncludingMargin):
+ * rendering/RenderLayerBacking.h:
+
+ Do not set masks to bounds if there is a margin on the root layer.
+ * rendering/RenderLayerCompositor.cpp:
+ (WebCore::RenderLayerCompositor::updateBacking):
+ (WebCore::RenderLayerCompositor::mainFrameBackingIsTiledWithMargin):
+ * rendering/RenderLayerCompositor.h:
+
+ Allow background color to paint into the margin tiles.
+ * rendering/RenderView.cpp:
+ (WebCore::RenderView::paintBoxDecorations):
+
2013-11-21 Alexey Proskuryakov <[email protected]>
Implement WebCrypto wrapKey
Modified: trunk/Source/WebCore/platform/graphics/TiledBacking.h (159644 => 159645)
--- trunk/Source/WebCore/platform/graphics/TiledBacking.h 2013-11-21 21:55:20 UTC (rev 159644)
+++ trunk/Source/WebCore/platform/graphics/TiledBacking.h 2013-11-21 21:57:53 UTC (rev 159645)
@@ -83,6 +83,14 @@
virtual double retainedTileBackingStoreMemory() const = 0;
+ virtual void setTileMargins(int marginTop, int marginBottom, int marginLeft, int marginRight) = 0;
+ virtual bool hasMargins() const = 0;
+
+ virtual int topMarginHeight() const = 0;
+ virtual int bottomMarginHeight() const = 0;
+ virtual int leftMarginWidth() const = 0;
+ virtual int rightMarginWidth() const = 0;
+
// Exposed for testing
virtual IntRect tileCoverageRect() const = 0;
virtual IntRect tileGridExtent() const = 0;
Modified: trunk/Source/WebCore/platform/graphics/ca/mac/TileController.h (159644 => 159645)
--- trunk/Source/WebCore/platform/graphics/ca/mac/TileController.h 2013-11-21 21:55:20 UTC (rev 159644)
+++ trunk/Source/WebCore/platform/graphics/ca/mac/TileController.h 2013-11-21 21:57:53 UTC (rev 159645)
@@ -123,6 +123,12 @@
virtual IntRect tileCoverageRect() const OVERRIDE;
virtual PlatformCALayer* tiledScrollingIndicatorLayer() OVERRIDE;
virtual void setScrollingModeIndication(ScrollingModeIndication) OVERRIDE;
+ virtual void setTileMargins(int marginTop, int marginBottom, int marginLeft, int marginRight) OVERRIDE;
+ virtual bool hasMargins() const OVERRIDE;
+ virtual int topMarginHeight() const OVERRIDE;
+ virtual int bottomMarginHeight() const OVERRIDE;
+ virtual int leftMarginWidth() const OVERRIDE;
+ virtual int rightMarginWidth() const OVERRIDE;
// PlatformCALayerClient
virtual void platformCALayerLayoutSublayersOfLayer(PlatformCALayer*) OVERRIDE { }
@@ -144,10 +150,11 @@
IntRect bounds() const;
IntRect rectForTileIndex(const TileIndex&) const;
+ void adjustRectAtTileIndexForMargin(const TileIndex&, IntRect&) const;
void getTileIndexRangeForRect(const IntRect&, TileIndex& topLeft, TileIndex& bottomRight) const;
FloatRect computeTileCoverageRect(const FloatRect& previousVisibleRect, const FloatRect& currentVisibleRect) const;
- IntSize tileSizeForCoverageRect(const FloatRect&) const;
+ IntSize computeTileSize() const;
void scheduleTileRevalidation(double interval);
void tileRevalidationTimerFired(Timer<TileController>*);
@@ -220,6 +227,16 @@
float m_deviceScaleFactor;
TileCoverage m_tileCoverage;
+
+ // m_marginTop and m_marginBottom are the height in pixels of the top and bottom margin tiles. The width
+ // of those tiles will be equivalent to the width of the other tiles in the grid. m_marginRight and
+ // m_marginLeft are the width in pixels of the right and left margin tiles, respectively. The height of
+ // those tiles will be equivalent to the height of the other tiles in the grid.
+ int m_marginTop;
+ int m_marginBottom;
+ int m_marginLeft;
+ int m_marginRight;
+
bool m_isInWindow;
bool m_scrollingPerformanceLoggingEnabled;
bool m_aggressivelyRetainsTiles;
Modified: trunk/Source/WebCore/platform/graphics/ca/mac/TileController.mm (159644 => 159645)
--- trunk/Source/WebCore/platform/graphics/ca/mac/TileController.mm 2013-11-21 21:55:20 UTC (rev 159644)
+++ trunk/Source/WebCore/platform/graphics/ca/mac/TileController.mm 2013-11-21 21:57:53 UTC (rev 159645)
@@ -57,6 +57,10 @@
, m_scale(1)
, m_deviceScaleFactor(1)
, m_tileCoverage(CoverageForVisibleArea)
+ , m_marginTop(0)
+ , m_marginBottom(0)
+ , m_marginLeft(0)
+ , m_marginRight(0)
, m_isInWindow(false)
, m_scrollingPerformanceLoggingEnabled(false)
, m_aggressivelyRetainsTiles(false)
@@ -281,7 +285,7 @@
scaledRect.scale(m_scale);
IntRect currentCoverageRectInTileCoords(enclosingIntRect(scaledRect));
- IntSize newTileSize = tileSizeForCoverageRect(currentTileCoverageRect);
+ IntSize newTileSize = computeTileSize();
bool tileSizeChanged = newTileSize != m_tileSize;
if (tileSizeChanged)
return true;
@@ -388,9 +392,44 @@
IntRect TileController::bounds() const
{
- return IntRect(IntPoint(), expandedIntSize(m_tileCacheLayer->bounds().size()));
+ IntPoint boundsOriginIncludingMargin(-leftMarginWidth(), -topMarginHeight());
+ IntSize boundsSizeIncludingMargin = expandedIntSize(m_tileCacheLayer->bounds().size());
+ boundsSizeIncludingMargin.expand(leftMarginWidth() + rightMarginWidth(), topMarginHeight() + bottomMarginHeight());
+
+ return IntRect(boundsOriginIncludingMargin, boundsSizeIncludingMargin);
}
+void TileController::adjustRectAtTileIndexForMargin(const TileIndex& tileIndex, IntRect& rect) const
+{
+ if (!hasMargins())
+ return;
+
+ // This is a tile in the top margin.
+ if (m_marginTop && tileIndex.y() < 0) {
+ rect.setY(tileIndex.y() * topMarginHeight());
+ rect.setHeight(topMarginHeight());
+ }
+
+ // This is a tile in the left margin.
+ if (m_marginLeft && tileIndex.x() < 0) {
+ rect.setX(tileIndex.x() * leftMarginWidth());
+ rect.setWidth(leftMarginWidth());
+ }
+
+ IntRect boundsWithoutMargin = IntRect(IntPoint(), expandedIntSize(m_tileCacheLayer->bounds().size()));
+ TileIndex contentTopLeft;
+ TileIndex contentBottomRight;
+ getTileIndexRangeForRect(boundsWithoutMargin, contentTopLeft, contentBottomRight);
+
+ // This is a tile in the bottom margin.
+ if (m_marginBottom && tileIndex.y() > contentBottomRight.y())
+ rect.setHeight(bottomMarginHeight());
+
+ // This is a tile in the right margin.
+ if (m_marginRight && tileIndex.x() > contentBottomRight.x())
+ rect.setWidth(rightMarginWidth());
+}
+
IntRect TileController::rectForTileIndex(const TileIndex& tileIndex) const
{
IntRect rect(tileIndex.x() * m_tileSize.width(), tileIndex.y() * m_tileSize.height(), m_tileSize.width(), m_tileSize.height());
@@ -399,6 +438,11 @@
rect.intersect(scaledBounds);
+ // These rect computations assume m_tileSize is the correct size to use. However, a tile in the margin area
+ // might be a different size depending on the size of the margins. So adjustRectAtTileIndexForMargin() will
+ // fix the rect we've computed to match the margin sizes if this tile is in the margins.
+ adjustRectAtTileIndexForMargin(tileIndex, rect);
+
return rect;
}
@@ -408,9 +452,16 @@
clampedRect.scale(m_scale);
clampedRect.intersect(rect);
- topLeft.setX(std::max(clampedRect.x() / m_tileSize.width(), 0));
- topLeft.setY(std::max(clampedRect.y() / m_tileSize.height(), 0));
+ if (clampedRect.x() >= 0)
+ topLeft.setX(clampedRect.x() / m_tileSize.width());
+ else
+ topLeft.setX(clampedRect.x() / leftMarginWidth());
+ if (clampedRect.y() >= 0)
+ topLeft.setY(clampedRect.y() / m_tileSize.height());
+ else
+ topLeft.setY(clampedRect.y() / topMarginHeight());
+
int bottomXRatio = ceil((float)clampedRect.maxX() / m_tileSize.width());
bottomRight.setX(std::max(bottomXRatio - 1, 0));
@@ -426,11 +477,41 @@
visibleRect.intersect(m_exposedRect);
// 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.
- // Furthermore, if the page can't have scrollbars (for example if its body element has overflow:hidden) it's very unlikely that the
- // page will ever be scrolled so we limit the tile coverage rect as well.
- if (!m_isInWindow || m_tileCoverage & CoverageForSlowScrolling)
+ if (!m_isInWindow)
return visibleRect;
+ // If our tile coverage is just for slow-scrolling, then we want to limit the tile coverage to the visible rect, but
+ // we should include the margin tiles if we're close to an edge.
+ if (m_tileCoverage & CoverageForSlowScrolling) {
+ FloatSize coverageSize = visibleRect.size();
+ FloatPoint coverageOrigin = visibleRect.location();
+ float tileWidth = visibleRect.width();
+ float tileHeight = visibleRect.height();
+
+ // We're within one tile from the top, so we should make sure we have a top-margin tile.
+ if (visibleRect.y() < tileHeight) {
+ coverageSize.setHeight(coverageSize.height() + topMarginHeight());
+ coverageOrigin.setY(coverageOrigin.y() - topMarginHeight());
+ }
+
+ // We're within one tile from the left edge, so we should make sure we have a left-margin tile.
+ if (visibleRect.x() < tileWidth) {
+ coverageSize.setWidth(coverageSize.width() + leftMarginWidth());
+ coverageOrigin.setX(coverageOrigin.x() - leftMarginWidth());
+ }
+
+ IntSize layerSize = expandedIntSize(m_tileCacheLayer->bounds().size());
+ // We're within one tile from the bottom edge, so we should make sure we have a bottom-margin tile.
+ if (visibleRect.y() + tileHeight > layerSize.height() - tileHeight)
+ coverageSize.setHeight(coverageSize.height() + bottomMarginHeight());
+
+ // We're within one tile from the right edge, so we should make sure we have a right-margin tile.
+ if (visibleRect.x() + tileWidth > layerSize.width() - tileWidth)
+ coverageSize.setWidth(coverageSize.width() + rightMarginWidth());
+
+ return FloatRect(coverageOrigin, coverageSize);
+ }
+
bool largeVisibleRectChange = !previousVisibleRect.isEmpty() && !visibleRect.intersects(previousVisibleRect);
// FIXME: look at how far the document can scroll in each dimension.
@@ -445,8 +526,10 @@
if (m_tileCoverage & CoverageForVerticalScrolling && !largeVisibleRectChange)
coverageVerticalSize *= 3;
+
+ coverageVerticalSize += topMarginHeight() + bottomMarginHeight();
+ coverageHorizontalSize += leftMarginWidth() + rightMarginWidth();
- // Don't extend coverage before 0 or after the end.
FloatRect coverageBounds = bounds();
float coverageLeft = visibleRect.x() - (coverageHorizontalSize - visibleRect.width()) / 2;
coverageLeft = std::min(coverageLeft, coverageBounds.maxX() - coverageHorizontalSize);
@@ -459,10 +542,10 @@
return FloatRect(coverageLeft, coverageTop, coverageHorizontalSize, coverageVerticalSize);
}
-IntSize TileController::tileSizeForCoverageRect(const FloatRect& coverageRect) const
+IntSize TileController::computeTileSize() const
{
if (m_tileCoverage & CoverageForSlowScrolling) {
- FloatSize tileSize = coverageRect.size();
+ FloatSize tileSize = m_visibleRect.size();
tileSize.scale(m_scale);
return expandedIntSize(tileSize);
}
@@ -604,7 +687,7 @@
IntRect coverageRectInTileCoords(enclosingIntRect(scaledRect));
IntSize oldTileSize = m_tileSize;
- m_tileSize = tileSizeForCoverageRect(tileCoverageRect);
+ m_tileSize = computeTileSize();
bool tileSizeChanged = m_tileSize != oldTileSize;
if (tileSizeChanged) {
@@ -925,6 +1008,39 @@
updateTileCoverageMap();
}
+void TileController::setTileMargins(int marginTop, int marginBottom, int marginLeft, int marginRight)
+{
+ m_marginTop = marginTop;
+ m_marginBottom = marginBottom;
+ m_marginLeft = marginLeft;
+ m_marginRight = marginRight;
+}
+
+bool TileController::hasMargins() const
+{
+ return m_marginTop || m_marginBottom || m_marginLeft || m_marginRight;
+}
+
+int TileController::topMarginHeight() const
+{
+ return m_marginTop;
+}
+
+int TileController::bottomMarginHeight() const
+{
+ return m_marginBottom;
+}
+
+int TileController::leftMarginWidth() const
+{
+ return m_marginLeft;
+}
+
+int TileController::rightMarginWidth() const
+{
+ return m_marginRight;
+}
+
RefPtr<PlatformCALayer> TileController::createTileLayer(const IntRect& tileRect)
{
RefPtr<PlatformCALayer> layer = LayerPool::sharedPool()->takeLayerWithSize(tileRect.size());
Modified: trunk/Source/WebCore/rendering/RenderLayerBacking.cpp (159644 => 159645)
--- trunk/Source/WebCore/rendering/RenderLayerBacking.cpp 2013-11-21 21:55:20 UTC (rev 159644)
+++ trunk/Source/WebCore/rendering/RenderLayerBacking.cpp 2013-11-21 21:57:53 UTC (rev 159645)
@@ -190,6 +190,11 @@
return m_usingTiledCacheLayer && m_creatingPrimaryGraphicsLayer;
}
+bool RenderLayerBacking::tiledBackingHasMargin() const
+{
+ return m_usingTiledCacheLayer && tiledBacking()->hasMargins();
+}
+
void RenderLayerBacking::tiledBackingUsageChanged(const GraphicsLayer* layer, bool usingTiledBacking)
{
compositor().layerTiledBackingUsageChanged(layer, usingTiledBacking);
@@ -2084,7 +2089,7 @@
// The dirtyRect is in the coords of the painting root.
IntRect dirtyRect = clip;
if (!(paintingPhase & GraphicsLayerPaintOverflowContents))
- dirtyRect.intersect(enclosingIntRect(compositedBounds()));
+ dirtyRect.intersect(enclosingIntRect(compositedBoundsIncludingMargin()));
// We have to use the same root as for hit testing, because both methods can compute and cache clipRects.
paintIntoLayer(graphicsLayer, &context, dirtyRect, PaintBehaviorNormal, paintingPhase);
@@ -2361,6 +2366,22 @@
m_compositedBounds = bounds;
}
+LayoutRect RenderLayerBacking::compositedBoundsIncludingMargin() const
+{
+ TiledBacking* tiledBacking = this->tiledBacking();
+ if (!tiledBacking || !tiledBacking->hasMargins())
+ return compositedBounds();
+
+ LayoutRect boundsIncludingMargin = compositedBounds();
+ LayoutUnit leftMarginWidth = tiledBacking->leftMarginWidth();
+ LayoutUnit topMarginHeight = tiledBacking->topMarginHeight();
+
+ boundsIncludingMargin.moveBy(IntPoint(-leftMarginWidth, -topMarginHeight));
+ boundsIncludingMargin.expand(leftMarginWidth + (LayoutUnit)tiledBacking->rightMarginWidth(), topMarginHeight + (LayoutUnit)tiledBacking->bottomMarginHeight());
+
+ return boundsIncludingMargin;
+}
+
CSSPropertyID RenderLayerBacking::graphicsLayerToCSSProperty(AnimatedPropertyID property)
{
CSSPropertyID cssProperty = CSSPropertyInvalid;
Modified: trunk/Source/WebCore/rendering/RenderLayerBacking.h (159644 => 159645)
--- trunk/Source/WebCore/rendering/RenderLayerBacking.h 2013-11-21 21:55:20 UTC (rev 159644)
+++ trunk/Source/WebCore/rendering/RenderLayerBacking.h 2013-11-21 21:57:53 UTC (rev 159645)
@@ -150,6 +150,7 @@
bool hasUnpositionedOverflowControlsLayers() const;
bool usingTiledBacking() const { return m_usingTiledCacheLayer; }
+ bool tiledBackingHasMargin() const;
TiledBacking* tiledBacking() const;
void adjustTiledBackingCoverage();
@@ -208,6 +209,8 @@
void destroyGraphicsLayers();
void willDestroyLayer(const GraphicsLayer*);
+
+ LayoutRect compositedBoundsIncludingMargin() const;
std::unique_ptr<GraphicsLayer> createGraphicsLayer(const String&);
Modified: trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp (159644 => 159645)
--- trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp 2013-11-21 21:55:20 UTC (rev 159644)
+++ trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp 2013-11-21 21:57:53 UTC (rev 159645)
@@ -696,6 +696,8 @@
updateLayerForFooter(page->footerHeight());
}
#endif
+ if (mainFrameBackingIsTiledWithMargin())
+ m_rootContentLayer->setMasksToBounds(false);
}
// This layer and all of its descendants have cached repaints rects that are relative to
@@ -2520,6 +2522,19 @@
return backing->usingTiledBacking();
}
+bool RenderLayerCompositor::mainFrameBackingIsTiledWithMargin() const
+{
+ RenderLayer* layer = m_renderView.layer();
+ if (!layer)
+ return false;
+
+ RenderLayerBacking* backing = layer->backing();
+ if (!backing)
+ return false;
+
+ return backing->tiledBackingHasMargin();
+}
+
bool RenderLayerCompositor::shouldCompositeOverflowControls() const
{
FrameView& frameView = m_renderView.frameView();
Modified: trunk/Source/WebCore/rendering/RenderLayerCompositor.h (159644 => 159645)
--- trunk/Source/WebCore/rendering/RenderLayerCompositor.h 2013-11-21 21:55:20 UTC (rev 159644)
+++ trunk/Source/WebCore/rendering/RenderLayerCompositor.h 2013-11-21 21:57:53 UTC (rev 159645)
@@ -289,6 +289,8 @@
void didPaintBacking(RenderLayerBacking*);
+ bool mainFrameBackingIsTiledWithMargin() const;
+
private:
class OverlapMap;
Modified: trunk/Source/WebCore/rendering/RenderView.cpp (159644 => 159645)
--- trunk/Source/WebCore/rendering/RenderView.cpp 2013-11-21 21:55:20 UTC (rev 159644)
+++ trunk/Source/WebCore/rendering/RenderView.cpp 2013-11-21 21:57:53 UTC (rev 159645)
@@ -513,12 +513,14 @@
rootFillsViewport = rootBox && !rootBox->x() && !rootBox->y() && rootBox->width() >= width() && rootBox->height() >= height();
rootObscuresBackground = rendererObscuresBackground(rootRenderer);
}
-
+
+ bool hasTiledMargin = compositor().mainFrameBackingIsTiledWithMargin();
+
Page* page = document().page();
float pageScaleFactor = page ? page->pageScaleFactor() : 1;
// If painting will entirely fill the view, no need to fill the background.
- if (rootFillsViewport && rootObscuresBackground && pageScaleFactor >= 1)
+ if (!hasTiledMargin && rootFillsViewport && rootObscuresBackground && pageScaleFactor >= 1)
return;
// This code typically only executes if the root element's visibility has been set to hidden,
@@ -528,11 +530,11 @@
if (frameView().isTransparent()) // FIXME: This needs to be dynamic. We should be able to go back to blitting if we ever stop being transparent.
frameView().setCannotBlitToWindow(); // The parent must show behind the child.
else {
- Color baseColor = frameView().baseBackgroundColor();
- if (baseColor.alpha()) {
+ Color backgroundColor = hasTiledMargin ? frameView().documentBackgroundColor() : frameView().baseBackgroundColor();
+ if (backgroundColor.alpha()) {
CompositeOperator previousOperator = paintInfo.context->compositeOperation();
paintInfo.context->setCompositeOperation(CompositeCopy);
- paintInfo.context->fillRect(paintInfo.rect, baseColor, style().colorSpace());
+ paintInfo.context->fillRect(paintInfo.rect, backgroundColor, style().colorSpace());
paintInfo.context->setCompositeOperation(previousOperator);
} else
paintInfo.context->clearRect(paintInfo.rect);