Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(537)

Unified Diff: third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp

Issue 1456813002: Calculate Background Image Geometries using sub-pixel values (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: MOAR expectations Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
diff --git a/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp b/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
index 4cfbef505d2f0c4db10089db7c794b5847673b2f..ef37cf3ece731dcf97b5bd801b738181c5decaba 100644
--- a/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
+++ b/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
@@ -18,21 +18,15 @@ namespace blink {
namespace {
-inline void applySubPixelHeuristicForTileSize(LayoutSize& tileSize, const IntSize& positioningAreaSize)
-{
- tileSize.setWidth(positioningAreaSize.width() - tileSize.width() <= 1 ? tileSize.width().ceil() : tileSize.width().floor());
- tileSize.setHeight(positioningAreaSize.height() - tileSize.height() <= 1 ? tileSize.height().ceil() : tileSize.height().floor());
-}
-
// Return the amount of space to leave between image tiles for the background-repeat: space property.
-inline int getSpaceBetweenImageTiles(int areaSize, int tileSize)
+inline LayoutUnit getSpaceBetweenImageTiles(LayoutUnit areaSize, LayoutUnit tileSize)
{
int numberOfTiles = areaSize / tileSize;
- int space = -1;
+ LayoutUnit space = -1;
if (numberOfTiles > 1) {
// Spec doesn't specify rounding, so use the same method as for background-repeat: round.
- space = lroundf((areaSize - numberOfTiles * tileSize) / (float)(numberOfTiles - 1));
+ space = (areaSize - numberOfTiles * tileSize) / (numberOfTiles - 1);
}
return space;
@@ -55,12 +49,12 @@ bool fixedBackgroundPaintsInLocalCoordinates(const LayoutObject& obj, const Glob
return rootLayer->compositedLayerMapping()->backgroundLayerPaintsFixedRootBackground();
}
-IntSize calculateFillTileSize(const LayoutBoxModelObject& obj, const FillLayer& fillLayer, const IntSize& positioningAreaSize)
+LayoutSize calculateFillTileSize(const LayoutBoxModelObject& obj, const FillLayer& fillLayer, const LayoutSize& positioningAreaSize)
{
StyleImage* image = fillLayer.image();
EFillSizeType type = fillLayer.size().type;
- IntSize imageIntrinsicSize = obj.calculateImageIntrinsicDimensions(image, positioningAreaSize, LayoutBoxModelObject::ScaleByEffectiveZoom);
+ LayoutSize imageIntrinsicSize = obj.calculateImageIntrinsicDimensions(image, positioningAreaSize, LayoutBoxModelObject::ScaleByEffectiveZoom);
imageIntrinsicSize.scale(1 / image->imageScaleFactor(), 1 / image->imageScaleFactor());
switch (type) {
case SizeLength: {
@@ -79,8 +73,6 @@ IntSize calculateFillTileSize(const LayoutBoxModelObject& obj, const FillLayer&
else if (layerHeight.hasPercent())
tileSize.setHeight(valueForLength(layerHeight, positioningAreaSize.height()));
- applySubPixelHeuristicForTileSize(tileSize, positioningAreaSize);
-
// If one of the values is auto we have to use the appropriate
// scale to maintain our aspect ratio.
if (layerWidth.isAuto() && !layerHeight.isAuto()) {
@@ -99,11 +91,11 @@ IntSize calculateFillTileSize(const LayoutBoxModelObject& obj, const FillLayer&
}
} else if (layerWidth.isAuto() && layerHeight.isAuto()) {
// If both width and height are auto, use the image's intrinsic size.
- tileSize = LayoutSize(imageIntrinsicSize);
+ tileSize = imageIntrinsicSize;
}
tileSize.clampNegativeToZero();
- return flooredIntSize(tileSize);
+ return tileSize;
}
case SizeNone: {
// If both values are 'auto' then the intrinsic width and/or height of the image should be used, if any.
@@ -116,16 +108,16 @@ IntSize calculateFillTileSize(const LayoutBoxModelObject& obj, const FillLayer&
case Contain:
case Cover: {
float horizontalScaleFactor = imageIntrinsicSize.width()
- ? static_cast<float>(positioningAreaSize.width()) / imageIntrinsicSize.width() : 1;
+ ? positioningAreaSize.width().toFloat() / imageIntrinsicSize.width() : 1;
float verticalScaleFactor = imageIntrinsicSize.height()
- ? static_cast<float>(positioningAreaSize.height()) / imageIntrinsicSize.height() : 1;
+ ? positioningAreaSize.height().toFloat() / imageIntrinsicSize.height() : 1;
float scaleFactor = type == Contain ? std::min(horizontalScaleFactor, verticalScaleFactor) : std::max(horizontalScaleFactor, verticalScaleFactor);
- return IntSize(std::max(1l, lround(imageIntrinsicSize.width() * scaleFactor)), std::max(1l, lround(imageIntrinsicSize.height() * scaleFactor)));
+ return LayoutSize(std::max<LayoutUnit>(1, imageIntrinsicSize.width() * scaleFactor), std::max<LayoutUnit>(1, imageIntrinsicSize.height() * scaleFactor));
}
}
ASSERT_NOT_REACHED();
- return IntSize();
+ return LayoutSize();
}
IntPoint accumulatedScrollOffset(const LayoutBoxModelObject& object, const LayoutBoxModelObject* container)
@@ -144,38 +136,57 @@ IntPoint accumulatedScrollOffset(const LayoutBoxModelObject& object, const Layou
} // anonymous namespace
-void BackgroundImageGeometry::setNoRepeatX(int xOffset)
+void BackgroundImageGeometry::setNoRepeatX(LayoutUnit xOffset)
{
- m_destRect.move(std::max(xOffset, 0), 0);
- m_phase.setX(-std::min(xOffset, 0));
- m_destRect.setWidth(m_tileSize.width() + std::min(xOffset, 0));
+ m_destRect.move(std::max(xOffset, LayoutUnit()), LayoutUnit());
+ m_phase.setX(-std::min(xOffset, LayoutUnit()));
+ m_destRect.setWidth(m_tileSize.width() + std::min(xOffset, LayoutUnit()));
}
-void BackgroundImageGeometry::setNoRepeatY(int yOffset)
+void BackgroundImageGeometry::setNoRepeatY(LayoutUnit yOffset)
{
- m_destRect.move(0, std::max(yOffset, 0));
- m_phase.setY(-std::min(yOffset, 0));
- m_destRect.setHeight(m_tileSize.height() + std::min(yOffset, 0));
+ m_destRect.move(LayoutUnit(), std::max(yOffset, LayoutUnit()));
+ m_phase.setY(-std::min(yOffset, LayoutUnit()));
+ m_destRect.setHeight(m_tileSize.height() + std::min(yOffset, LayoutUnit()));
}
-void BackgroundImageGeometry::useFixedAttachment(const IntPoint& attachmentPoint)
+void BackgroundImageGeometry::useFixedAttachment(const LayoutPoint& attachmentPoint)
{
- IntPoint alignedPoint = attachmentPoint;
- m_phase.move(std::max(alignedPoint.x() - m_destRect.x(), 0), std::max(alignedPoint.y() - m_destRect.y(), 0));
+ LayoutPoint alignedPoint = attachmentPoint;
+ m_phase.move(std::max(alignedPoint.x() - m_destRect.x(), LayoutUnit()), std::max(alignedPoint.y() - m_destRect.y(), LayoutUnit()));
}
-void BackgroundImageGeometry::clip(const IntRect& clipRect)
+void BackgroundImageGeometry::clip(const LayoutRect& clipRect)
{
m_destRect.intersect(clipRect);
}
+// When we match the destination rect in a dimension, we snap the same way. Otherwise
+// we floor to avoid growing our tile size. Often these tiles are from a sprite map,
+// and bleeding adjactent sprites is visually worse than clipping the intenteded one.
+static LayoutSize applySubPixelHeuristicToImageSize(const LayoutSize& size, const LayoutRect& destination)
+{
+ LayoutSize snappedSize = LayoutSize(
+ size.width() == destination.width() ? destination.pixelSnappedWidth() : size.width().floor(),
+ size.height() == destination.height() ? destination.pixelSnappedHeight() : size.height().floor());
+ return snappedSize;
+}
+
+void BackgroundImageGeometry::pixelSnapGeometry()
+{
+ setTileSize(applySubPixelHeuristicToImageSize(m_tileSize, m_destRect));
+ setImageContainerSize(applySubPixelHeuristicToImageSize(m_imageContainerSize, m_destRect));
+ setSpaceSize(LayoutSize(roundedIntSize(m_repeatSpacing)));
+ setDestRect(LayoutRect(pixelSnappedIntRect(m_destRect)));
+ setPhase(LayoutPoint(flooredIntPoint(m_phase)));
+}
+
void BackgroundImageGeometry::calculate(const LayoutBoxModelObject& obj, const LayoutBoxModelObject* paintContainer,
const GlobalPaintFlags globalPaintFlags, const FillLayer& fillLayer, const LayoutRect& paintRect)
{
- LayoutUnit left = 0;
- LayoutUnit top = 0;
- IntSize positioningAreaSize;
- IntRect snappedPaintRect = pixelSnappedIntRect(paintRect);
+ LayoutUnit left;
+ LayoutUnit top;
+ LayoutSize positioningAreaSize;
bool isLayoutView = obj.isLayoutView();
const LayoutBox* rootBox = nullptr;
if (isLayoutView) {
@@ -202,10 +213,10 @@ void BackgroundImageGeometry::calculate(const LayoutBoxModelObject& obj, const L
}
if (!fixedAttachment) {
- setDestRect(snappedPaintRect);
+ setDestRect(paintRect);
- LayoutUnit right = 0;
- LayoutUnit bottom = 0;
+ LayoutUnit right;
+ LayoutUnit bottom;
// Scroll and Local.
if (fillLayer.origin() != BorderFillBox) {
left = positioningBox.borderLeft();
@@ -224,21 +235,21 @@ void BackgroundImageGeometry::calculate(const LayoutBoxModelObject& obj, const L
// The background of the box generated by the root element covers the entire canvas and will
// be painted by the view object, but the we should still use the root element box for
// positioning.
- positioningAreaSize = pixelSnappedIntSize(rootBox->size() - LayoutSize(left + right, top + bottom), rootBox->location());
+ positioningAreaSize = rootBox->size() - LayoutSize(left + right, top + bottom), rootBox->location();
// The input paint rect is specified in root element local coordinate (i.e. a transform
// is applied on the context for painting), and is expanded to cover the whole canvas.
// Since left/top is relative to the paint rect, we need to offset them back.
left -= paintRect.x();
top -= paintRect.y();
} else {
- positioningAreaSize = pixelSnappedIntSize(paintRect.size() - LayoutSize(left + right, top + bottom), paintRect.location());
+ positioningAreaSize = paintRect.size() - LayoutSize(left + right, top + bottom);
}
} else {
setHasNonLocalGeometry();
- IntRect viewportRect = pixelSnappedIntRect(obj.viewRect());
+ LayoutRect viewportRect = obj.viewRect();
if (fixedBackgroundPaintsInLocalCoordinates(obj, globalPaintFlags)) {
- viewportRect.setLocation(IntPoint());
+ viewportRect.setLocation(LayoutPoint());
} else {
if (FrameView* frameView = obj.view()->frameView())
viewportRect.setLocation(frameView->scrollPosition());
@@ -247,30 +258,27 @@ void BackgroundImageGeometry::calculate(const LayoutBoxModelObject& obj, const L
viewportRect.moveBy(accumulatedScrollOffset(obj, paintContainer));
}
- if (paintContainer) {
- IntPoint absoluteContainerOffset = roundedIntPoint(paintContainer->localToAbsolute(FloatPoint()));
- viewportRect.moveBy(-absoluteContainerOffset);
- }
+ if (paintContainer)
+ viewportRect.moveBy(LayoutPoint(-paintContainer->localToAbsolute(FloatPoint())));
setDestRect(viewportRect);
positioningAreaSize = destRect().size();
}
- IntSize fillTileSize = calculateFillTileSize(positioningBox, fillLayer, positioningAreaSize);
+ LayoutSize fillTileSize = calculateFillTileSize(positioningBox, fillLayer, positioningAreaSize);
setTileSize(fillTileSize);
setImageContainerSize(fillTileSize);
EFillRepeat backgroundRepeatX = fillLayer.repeatX();
EFillRepeat backgroundRepeatY = fillLayer.repeatY();
- int availableWidth = positioningAreaSize.width() - tileSize().width();
- int availableHeight = positioningAreaSize.height() - tileSize().height();
+ LayoutUnit availableWidth = positioningAreaSize.width() - tileSize().width();
+ LayoutUnit availableHeight = positioningAreaSize.height() - tileSize().height();
LayoutUnit computedXPosition = roundedMinimumValueForLength(fillLayer.xPosition(), availableWidth);
- if (backgroundRepeatX == RoundFill && positioningAreaSize.width() > 0 && fillTileSize.width() > 0) {
- long nrTiles = std::max(1l, lroundf((float)positioningAreaSize.width() / fillTileSize.width()));
+ if (backgroundRepeatX == RoundFill && positioningAreaSize.width() > LayoutUnit() && fillTileSize.width() > LayoutUnit()) {
+ int nrTiles = std::max(1, roundToInt(positioningAreaSize.width() / fillTileSize.width()));
- // Round tile size per css3-background spec.
- fillTileSize.setWidth(lroundf(positioningAreaSize.width() / (float)nrTiles));
+ fillTileSize.setWidth(positioningAreaSize.width() / nrTiles);
// Maintain aspect ratio if background-size: auto is set
if (fillLayer.size().size.height().isAuto() && backgroundRepeatY != RoundFill) {
@@ -278,16 +286,16 @@ void BackgroundImageGeometry::calculate(const LayoutBoxModelObject& obj, const L
}
setTileSize(fillTileSize);
- setPhaseX(tileSize().width() ? tileSize().width() - roundToInt(computedXPosition + left) % tileSize().width() : 0);
- setSpaceSize(IntSize());
+ setImageContainerSize(fillTileSize);
+ setPhaseX(tileSize().width() ? tileSize().width() - fmodf((computedXPosition + left), tileSize().width()) : 0.0f);
+ setSpaceSize(LayoutSize());
}
LayoutUnit computedYPosition = roundedMinimumValueForLength(fillLayer.yPosition(), availableHeight);
- if (backgroundRepeatY == RoundFill && positioningAreaSize.height() > 0 && fillTileSize.height() > 0) {
- long nrTiles = std::max(1l, lroundf((float)positioningAreaSize.height() / fillTileSize.height()));
+ if (backgroundRepeatY == RoundFill && positioningAreaSize.height() > LayoutUnit() && fillTileSize.height() > LayoutUnit()) {
+ int nrTiles = std::max(1, roundToInt(positioningAreaSize.height() / fillTileSize.height()));
- // Round tile size per css3-background spec.
- fillTileSize.setHeight(lroundf(positioningAreaSize.height() / (float)nrTiles));
+ fillTileSize.setHeight(positioningAreaSize.height() / nrTiles);
// Maintain aspect ratio if background-size: auto is set
if (fillLayer.size().size.width().isAuto() && backgroundRepeatX != RoundFill) {
@@ -295,22 +303,23 @@ void BackgroundImageGeometry::calculate(const LayoutBoxModelObject& obj, const L
}
setTileSize(fillTileSize);
- setPhaseY(tileSize().height() ? tileSize().height() - roundToInt(computedYPosition + top) % tileSize().height() : 0);
- setSpaceSize(IntSize());
+ setImageContainerSize(fillTileSize);
+ setPhaseY(tileSize().height() ? tileSize().height() - fmodf((computedYPosition + top), tileSize().height()) : 0.0f);
+ setSpaceSize(LayoutSize());
}
if (backgroundRepeatX == RepeatFill) {
LayoutUnit xOffset = fillLayer.backgroundXOrigin() == RightEdge ? availableWidth - computedXPosition : computedXPosition;
- setPhaseX(tileSize().width() ? tileSize().width() - roundToInt(xOffset + left) % tileSize().width() : 0);
- setSpaceSize(IntSize());
- } else if (backgroundRepeatX == SpaceFill && fillTileSize.width() > 0) {
- int space = getSpaceBetweenImageTiles(positioningAreaSize.width(), tileSize().width());
- int actualWidth = tileSize().width() + space;
+ setPhaseX(tileSize().width() ? tileSize().width() - fmodf((xOffset + left), tileSize().width()) : 0.0f);
+ setSpaceSize(LayoutSize());
+ } else if (backgroundRepeatX == SpaceFill && fillTileSize.width() > LayoutUnit()) {
+ LayoutUnit space = getSpaceBetweenImageTiles(positioningAreaSize.width(), tileSize().width());
+ LayoutUnit actualWidth = tileSize().width() + space;
- if (space >= 0) {
+ if (space >= LayoutUnit()) {
computedXPosition = roundedMinimumValueForLength(Length(), availableWidth);
- setSpaceSize(IntSize(space, 0));
- setPhaseX(actualWidth ? actualWidth - roundToInt(computedXPosition + left) % actualWidth : 0);
+ setSpaceSize(LayoutSize(space, LayoutUnit()));
+ setPhaseX(actualWidth ? actualWidth - fmodf((computedXPosition + left), actualWidth) : 0.0f);
} else {
backgroundRepeatX = NoRepeatFill;
}
@@ -318,21 +327,21 @@ void BackgroundImageGeometry::calculate(const LayoutBoxModelObject& obj, const L
if (backgroundRepeatX == NoRepeatFill) {
LayoutUnit xOffset = fillLayer.backgroundXOrigin() == RightEdge ? availableWidth - computedXPosition : computedXPosition;
setNoRepeatX(left + xOffset);
- setSpaceSize(IntSize(0, spaceSize().height()));
+ setSpaceSize(LayoutSize(LayoutUnit(), spaceSize().height()));
}
if (backgroundRepeatY == RepeatFill) {
LayoutUnit yOffset = fillLayer.backgroundYOrigin() == BottomEdge ? availableHeight - computedYPosition : computedYPosition;
- setPhaseY(tileSize().height() ? tileSize().height() - roundToInt(yOffset + top) % tileSize().height() : 0);
- setSpaceSize(IntSize(spaceSize().width(), 0));
- } else if (backgroundRepeatY == SpaceFill && fillTileSize.height() > 0) {
- int space = getSpaceBetweenImageTiles(positioningAreaSize.height(), tileSize().height());
- int actualHeight = tileSize().height() + space;
+ setPhaseY(tileSize().height() ? tileSize().height() - fmodf((yOffset + top), tileSize().height()) : 0.0f);
+ setSpaceSize(LayoutSize(spaceSize().width(), LayoutUnit()));
+ } else if (backgroundRepeatY == SpaceFill && fillTileSize.height() > LayoutUnit()) {
+ LayoutUnit space = getSpaceBetweenImageTiles(positioningAreaSize.height(), tileSize().height());
+ LayoutUnit actualHeight = tileSize().height() + space;
- if (space >= 0) {
+ if (space >= LayoutUnit()) {
computedYPosition = roundedMinimumValueForLength(Length(), availableHeight);
- setSpaceSize(IntSize(spaceSize().width(), space));
- setPhaseY(actualHeight ? actualHeight - roundToInt(computedYPosition + top) % actualHeight : 0);
+ setSpaceSize(LayoutSize(spaceSize().width(), space));
+ setPhaseY(actualHeight ? actualHeight - fmodf((computedYPosition + top), actualHeight) : 0.0f);
} else {
backgroundRepeatY = NoRepeatFill;
}
@@ -340,13 +349,14 @@ void BackgroundImageGeometry::calculate(const LayoutBoxModelObject& obj, const L
if (backgroundRepeatY == NoRepeatFill) {
LayoutUnit yOffset = fillLayer.backgroundYOrigin() == BottomEdge ? availableHeight - computedYPosition : computedYPosition;
setNoRepeatY(top + yOffset);
- setSpaceSize(IntSize(spaceSize().width(), 0));
+ setSpaceSize(LayoutSize(spaceSize().width(), LayoutUnit()));
}
if (fixedAttachment)
- useFixedAttachment(snappedPaintRect.location());
+ useFixedAttachment(paintRect.location());
- clip(snappedPaintRect);
+ clip(paintRect);
+ pixelSnapGeometry();
}
} // namespace blink
« no previous file with comments | « third_party/WebKit/Source/core/paint/BackgroundImageGeometry.h ('k') | third_party/WebKit/Source/core/paint/BoxPainter.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698