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

Unified Diff: Source/core/paint/BoxPainter.cpp

Issue 1300103003: Refactor code for calculating background image geometry (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 5 years, 4 months 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
« no previous file with comments | « Source/core/paint/BoxPainter.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/paint/BoxPainter.cpp
diff --git a/Source/core/paint/BoxPainter.cpp b/Source/core/paint/BoxPainter.cpp
index 23c02de8e83c4958db7ba929610ca4ea1a52e75d..4e8cd240aa6f97510879643cac08ba7859262758 100644
--- a/Source/core/paint/BoxPainter.cpp
+++ b/Source/core/paint/BoxPainter.cpp
@@ -440,7 +440,7 @@ void BoxPainter::paintFillLayerExtended(LayoutBoxModelObject& obj, const PaintIn
BackgroundImageGeometry geometry;
if (bgImage)
- calculateBackgroundImageGeometry(obj, paintInfo.paintContainer(), paintInfo.globalPaintFlags(), bgLayer, scrolledPaintRect, geometry, backgroundObject);
+ geometry.calculate(obj, paintInfo.paintContainer(), paintInfo.globalPaintFlags(), bgLayer, scrolledPaintRect, backgroundObject);
bool shouldPaintBackgroundImage = bgImage && bgImage->canRender(obj, obj.style()->effectiveZoom());
// Paint the color first underneath all images, culled if background image occludes it.
@@ -570,297 +570,11 @@ void BoxPainter::paintClippingMask(const PaintInfo& paintInfo, const LayoutPoint
paintInfo.context->fillRect(paintRect, Color::black);
}
-// Return the amount of space to leave between image tiles for the background-repeat: space property.
-static inline int getSpaceBetweenImageTiles(int areaSize, int tileSize)
-{
- int numberOfTiles = areaSize / tileSize;
- int 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));
- }
-
- return space;
-}
-
-void BoxPainter::calculateBackgroundImageGeometry(const LayoutBoxModelObject& obj, const LayoutBoxModelObject* paintContainer, const GlobalPaintFlags globalPaintFlags, const FillLayer& fillLayer, const LayoutRect& paintRect,
- BackgroundImageGeometry& geometry, LayoutObject* backgroundObject)
-{
- LayoutUnit left = 0;
- LayoutUnit top = 0;
- IntSize positioningAreaSize;
- IntRect snappedPaintRect = pixelSnappedIntRect(paintRect);
- bool isLayoutView = obj.isLayoutView();
- const LayoutBox* rootBox = nullptr;
- if (isLayoutView) {
- // It is only possible reach here when root element has a box.
- Element* documentElement = obj.document().documentElement();
- ASSERT(documentElement);
- ASSERT(documentElement->layoutObject());
- ASSERT(documentElement->layoutObject()->isBox());
- rootBox = toLayoutBox(documentElement->layoutObject());
- }
- const LayoutBoxModelObject& positioningBox = isLayoutView ? static_cast<const LayoutBoxModelObject&>(*rootBox) : obj;
-
- // Determine the background positioning area and set destRect to the background painting area.
- // destRect will be adjusted later if the background is non-repeating.
- // FIXME: transforms spec says that fixed backgrounds behave like scroll inside transforms.
- bool fixedAttachment = fillLayer.attachment() == FixedBackgroundAttachment;
-
- if (RuntimeEnabledFeatures::fastMobileScrollingEnabled()) {
- // As a side effect of an optimization to blit on scroll, we do not honor the CSS
- // property "background-attachment: fixed" because it may result in rendering
- // artifacts. Note, these artifacts only appear if we are blitting on scroll of
- // a page that has fixed background images.
- fixedAttachment = false;
- }
-
- if (!fixedAttachment) {
- geometry.setDestRect(snappedPaintRect);
-
- LayoutUnit right = 0;
- LayoutUnit bottom = 0;
- // Scroll and Local.
- if (fillLayer.origin() != BorderFillBox) {
- left = positioningBox.borderLeft();
- right = positioningBox.borderRight();
- top = positioningBox.borderTop();
- bottom = positioningBox.borderBottom();
- if (fillLayer.origin() == ContentFillBox) {
- left += positioningBox.paddingLeft();
- right += positioningBox.paddingRight();
- top += positioningBox.paddingTop();
- bottom += positioningBox.paddingBottom();
- }
- }
-
- if (isLayoutView) {
- // 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());
- // 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());
- }
- } else {
- geometry.setHasNonLocalGeometry();
-
- IntRect viewportRect = pixelSnappedIntRect(obj.viewRect());
- if (fixedBackgroundPaintsInLocalCoordinates(obj, globalPaintFlags))
- viewportRect.setLocation(IntPoint());
- else if (FrameView* frameView = obj.view()->frameView())
- viewportRect.setLocation(frameView->scrollPosition());
-
- if (paintContainer) {
- IntPoint absoluteContainerOffset = roundedIntPoint(paintContainer->localToAbsolute(FloatPoint()));
- viewportRect.moveBy(-absoluteContainerOffset);
- }
-
- geometry.setDestRect(viewportRect);
- positioningAreaSize = geometry.destRect().size();
- }
-
- const LayoutObject* clientForBackgroundImage = backgroundObject ? backgroundObject : &obj;
- IntSize fillTileSize = calculateFillTileSize(positioningBox, fillLayer, positioningAreaSize);
- fillLayer.image()->setContainerSizeForLayoutObject(clientForBackgroundImage, fillTileSize, obj.style()->effectiveZoom());
- geometry.setTileSize(fillTileSize);
-
- EFillRepeat backgroundRepeatX = fillLayer.repeatX();
- EFillRepeat backgroundRepeatY = fillLayer.repeatY();
- int availableWidth = positioningAreaSize.width() - geometry.tileSize().width();
- int availableHeight = positioningAreaSize.height() - geometry.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()));
-
- // Round tile size per css3-background spec.
- fillTileSize.setWidth(lroundf(positioningAreaSize.width() / (float)nrTiles));
-
- // Maintain aspect ratio if background-size: auto is set
- if (fillLayer.size().size.height().isAuto() && backgroundRepeatY != RoundFill) {
- fillTileSize.setHeight(fillTileSize.height() * positioningAreaSize.width() / (nrTiles * fillTileSize.width()));
- }
-
- geometry.setTileSize(fillTileSize);
- geometry.setPhaseX(geometry.tileSize().width() ? geometry.tileSize().width() - roundToInt(computedXPosition + left) % geometry.tileSize().width() : 0);
- geometry.setSpaceSize(IntSize());
- }
-
- 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()));
-
- // Round tile size per css3-background spec.
- fillTileSize.setHeight(lroundf(positioningAreaSize.height() / (float)nrTiles));
-
- // Maintain aspect ratio if background-size: auto is set
- if (fillLayer.size().size.width().isAuto() && backgroundRepeatX != RoundFill) {
- fillTileSize.setWidth(fillTileSize.width() * positioningAreaSize.height() / (nrTiles * fillTileSize.height()));
- }
-
- geometry.setTileSize(fillTileSize);
- geometry.setPhaseY(geometry.tileSize().height() ? geometry.tileSize().height() - roundToInt(computedYPosition + top) % geometry.tileSize().height() : 0);
- geometry.setSpaceSize(IntSize());
- }
-
- if (backgroundRepeatX == RepeatFill) {
- int xOffset = fillLayer.backgroundXOrigin() == RightEdge ? availableWidth - computedXPosition : computedXPosition;
- geometry.setPhaseX(geometry.tileSize().width() ? geometry.tileSize().width() - roundToInt(xOffset + left) % geometry.tileSize().width() : 0);
- geometry.setSpaceSize(IntSize());
- } else if (backgroundRepeatX == SpaceFill && fillTileSize.width() > 0) {
- int space = getSpaceBetweenImageTiles(positioningAreaSize.width(), geometry.tileSize().width());
- int actualWidth = geometry.tileSize().width() + space;
-
- if (space >= 0) {
- computedXPosition = roundedMinimumValueForLength(Length(), availableWidth);
- geometry.setSpaceSize(IntSize(space, 0));
- geometry.setPhaseX(actualWidth ? actualWidth - roundToInt(computedXPosition + left) % actualWidth : 0);
- } else {
- backgroundRepeatX = NoRepeatFill;
- }
- }
- if (backgroundRepeatX == NoRepeatFill) {
- int xOffset = fillLayer.backgroundXOrigin() == RightEdge ? availableWidth - computedXPosition : computedXPosition;
- geometry.setNoRepeatX(left + xOffset);
- geometry.setSpaceSize(IntSize(0, geometry.spaceSize().height()));
- }
-
- if (backgroundRepeatY == RepeatFill) {
- int yOffset = fillLayer.backgroundYOrigin() == BottomEdge ? availableHeight - computedYPosition : computedYPosition;
- geometry.setPhaseY(geometry.tileSize().height() ? geometry.tileSize().height() - roundToInt(yOffset + top) % geometry.tileSize().height() : 0);
- geometry.setSpaceSize(IntSize(geometry.spaceSize().width(), 0));
- } else if (backgroundRepeatY == SpaceFill && fillTileSize.height() > 0) {
- int space = getSpaceBetweenImageTiles(positioningAreaSize.height(), geometry.tileSize().height());
- int actualHeight = geometry.tileSize().height() + space;
-
- if (space >= 0) {
- computedYPosition = roundedMinimumValueForLength(Length(), availableHeight);
- geometry.setSpaceSize(IntSize(geometry.spaceSize().width(), space));
- geometry.setPhaseY(actualHeight ? actualHeight - roundToInt(computedYPosition + top) % actualHeight : 0);
- } else {
- backgroundRepeatY = NoRepeatFill;
- }
- }
- if (backgroundRepeatY == NoRepeatFill) {
- int yOffset = fillLayer.backgroundYOrigin() == BottomEdge ? availableHeight - computedYPosition : computedYPosition;
- geometry.setNoRepeatY(top + yOffset);
- geometry.setSpaceSize(IntSize(geometry.spaceSize().width(), 0));
- }
-
- if (fixedAttachment)
- geometry.useFixedAttachment(snappedPaintRect.location());
-
- geometry.clip(snappedPaintRect);
-}
-
InterpolationQuality BoxPainter::chooseInterpolationQuality(LayoutObject& obj, GraphicsContext* context, Image* image, const void* layer, const LayoutSize& size)
{
return ImageQualityController::imageQualityController()->chooseInterpolationQuality(context, &obj, image, layer, size);
}
-bool BoxPainter::fixedBackgroundPaintsInLocalCoordinates(const LayoutObject& obj, const GlobalPaintFlags globalPaintFlags)
-{
- if (!obj.isLayoutView())
- return false;
-
- const LayoutView& view = toLayoutView(obj);
-
- if (globalPaintFlags & GlobalPaintFlattenCompositingLayers)
- return false;
-
- DeprecatedPaintLayer* rootLayer = view.layer();
- if (!rootLayer || rootLayer->compositingState() == NotComposited)
- return false;
-
- return rootLayer->compositedDeprecatedPaintLayerMapping()->backgroundLayerPaintsFixedRootBackground();
-}
-
-static 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());
-}
-
-IntSize BoxPainter::calculateFillTileSize(const LayoutBoxModelObject& obj, const FillLayer& fillLayer, const IntSize& positioningAreaSize)
-{
- StyleImage* image = fillLayer.image();
- EFillSizeType type = fillLayer.size().type;
-
- IntSize imageIntrinsicSize = obj.calculateImageIntrinsicDimensions(image, positioningAreaSize, LayoutBoxModelObject::ScaleByEffectiveZoom);
- imageIntrinsicSize.scale(1 / image->imageScaleFactor(), 1 / image->imageScaleFactor());
- switch (type) {
- case SizeLength: {
- LayoutSize tileSize(positioningAreaSize);
-
- Length layerWidth = fillLayer.size().size.width();
- Length layerHeight = fillLayer.size().size.height();
-
- if (layerWidth.isFixed())
- tileSize.setWidth(layerWidth.value());
- else if (layerWidth.hasPercent())
- tileSize.setWidth(valueForLength(layerWidth, positioningAreaSize.width()));
-
- if (layerHeight.isFixed())
- tileSize.setHeight(layerHeight.value());
- 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()) {
- if (imageIntrinsicSize.height()) {
- LayoutUnit adjustedWidth = imageIntrinsicSize.width() * tileSize.height() / imageIntrinsicSize.height();
- if (imageIntrinsicSize.width() >= 1 && adjustedWidth < 1)
- adjustedWidth = 1;
- tileSize.setWidth(adjustedWidth);
- }
- } else if (!layerWidth.isAuto() && layerHeight.isAuto()) {
- if (imageIntrinsicSize.width()) {
- LayoutUnit adjustedHeight = imageIntrinsicSize.height() * tileSize.width() / imageIntrinsicSize.width();
- if (imageIntrinsicSize.height() >= 1 && adjustedHeight < 1)
- adjustedHeight = 1;
- tileSize.setHeight(adjustedHeight);
- }
- } else if (layerWidth.isAuto() && layerHeight.isAuto()) {
- // If both width and height are auto, use the image's intrinsic size.
- tileSize = LayoutSize(imageIntrinsicSize);
- }
-
- tileSize.clampNegativeToZero();
- return flooredIntSize(tileSize);
- }
- case SizeNone: {
- // If both values are 'auto' then the intrinsic width and/or height of the image should be used, if any.
- if (!imageIntrinsicSize.isEmpty())
- return imageIntrinsicSize;
-
- // If the image has neither an intrinsic width nor an intrinsic height, its size is determined as for 'contain'.
- type = Contain;
- }
- case Contain:
- case Cover: {
- float horizontalScaleFactor = imageIntrinsicSize.width()
- ? static_cast<float>(positioningAreaSize.width()) / imageIntrinsicSize.width() : 1;
- float verticalScaleFactor = imageIntrinsicSize.height()
- ? static_cast<float>(positioningAreaSize.height()) / 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)));
- }
- }
-
- ASSERT_NOT_REACHED();
- return IntSize();
-}
-
bool BoxPainter::paintNinePieceImage(LayoutBoxModelObject& obj, GraphicsContext* graphicsContext, const LayoutRect& rect, const ComputedStyle& style, const NinePieceImage& ninePieceImage, SkXfermode::Mode op)
{
NinePieceImagePainter ninePieceImagePainter(obj);
« no previous file with comments | « Source/core/paint/BoxPainter.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698