Index: Source/core/rendering/RenderBoxModelObject.cpp |
diff --git a/Source/core/rendering/RenderBoxModelObject.cpp b/Source/core/rendering/RenderBoxModelObject.cpp |
index 82c774028269a2f0d9cf7fb0d6ce8720f324395c..07811e165129f84e23e634bff36cac2d7cd0c26f 100644 |
--- a/Source/core/rendering/RenderBoxModelObject.cpp |
+++ b/Source/core/rendering/RenderBoxModelObject.cpp |
@@ -26,9 +26,6 @@ |
#include "config.h" |
#include "core/rendering/RenderBoxModelObject.h" |
-#include "core/HTMLNames.h" |
-#include "core/frame/Settings.h" |
-#include "core/html/HTMLFrameOwnerElement.h" |
#include "core/page/scrolling/ScrollingConstraints.h" |
#include "core/rendering/ImageQualityController.h" |
#include "core/rendering/RenderBlock.h" |
@@ -53,8 +50,6 @@ |
namespace blink { |
-using namespace HTMLNames; |
- |
// The HashMap for storing continuation pointers. |
// An inline can be split with blocks occuring in between the inline content. |
// When this occurs we need a pointer to the next object. We can basically be |
@@ -102,11 +97,6 @@ bool RenderBoxModelObject::hasAcceleratedCompositing() const |
return view()->compositor()->hasAcceleratedCompositing(); |
} |
-InterpolationQuality RenderBoxModelObject::chooseInterpolationQuality(GraphicsContext* context, Image* image, const void* layer, const LayoutSize& size) |
-{ |
- return ImageQualityController::imageQualityController()->chooseInterpolationQuality(context, this, image, layer, size); |
-} |
- |
RenderBoxModelObject::RenderBoxModelObject(ContainerNode* node) |
: RenderLayerModelObject(node) |
{ |
@@ -202,65 +192,6 @@ bool RenderBoxModelObject::hasAutoHeightOrContainingBlockWithAutoHeight() const |
return cb->hasAutoHeightOrContainingBlockWithAutoHeight(); |
} |
-bool RenderBoxModelObject::isDocumentElementWithOpaqueBackground() const |
-{ |
- if (!isDocumentElement()) |
- return false; |
- |
- // The background is opaque only if we're the root document, since iframes with |
- // no background in the child document should show the parent's background. |
- bool isOpaque = true; |
- Element* ownerElement = document().ownerElement(); |
- if (ownerElement) { |
- if (!isHTMLFrameElement(*ownerElement)) { |
- // Locate the <body> element using the DOM. This is easier than trying |
- // to crawl around a render tree with potential :before/:after content and |
- // anonymous blocks created by inline <body> tags etc. We can locate the <body> |
- // render object very easily via the DOM. |
- HTMLElement* body = document().body(); |
- if (body) { |
- // Can't scroll a frameset document anyway. |
- isOpaque = body->hasTagName(framesetTag); |
- } else { |
- // FIXME: SVG specific behavior should be in the SVG code. |
- // SVG documents and XML documents with SVG root nodes are transparent. |
- isOpaque = !document().hasSVGRootNode(); |
- } |
- } |
- } else if (view()->frameView()) { |
- isOpaque = !view()->frameView()->isTransparent(); |
- } |
- |
- return isOpaque; |
-} |
- |
-void RenderBoxModelObject::paintRootBackgroundColor(const PaintInfo& paintInfo, const LayoutRect& rect, const Color& bgColor) |
-{ |
- GraphicsContext* context = paintInfo.context; |
- if (rect.isEmpty()) |
- return; |
- |
- ASSERT(isDocumentElement()); |
- |
- IntRect backgroundRect(pixelSnappedIntRect(rect)); |
- backgroundRect.intersect(paintInfo.rect); |
- |
- Color baseColor = view()->frameView()->baseBackgroundColor(); |
- bool shouldClearDocumentBackground = document().settings() && document().settings()->shouldClearDocumentBackground(); |
- CompositeOperator operation = shouldClearDocumentBackground ? CompositeCopy : context->compositeOperation(); |
- |
- // If we have an alpha go ahead and blend with the base background color. |
- if (baseColor.alpha()) { |
- if (bgColor.alpha()) |
- baseColor = baseColor.blend(bgColor); |
- context->fillRect(backgroundRect, baseColor, operation); |
- } else if (bgColor.alpha()) { |
- context->fillRect(backgroundRect, bgColor, operation); |
- } else if (shouldClearDocumentBackground) { |
- context->clearRect(backgroundRect); |
- } |
-} |
- |
LayoutSize RenderBoxModelObject::relativePositionOffset() const |
{ |
LayoutSize offset = accumulateInFlowPositionOffsets(this); |
@@ -380,50 +311,6 @@ LayoutUnit RenderBoxModelObject::computedCSSPadding(const Length& padding) const |
return minimumValueForLength(padding, w); |
} |
-RoundedRect RenderBoxModelObject::getBackgroundRoundedRect(const LayoutRect& borderRect, InlineFlowBox* box, LayoutUnit inlineBoxWidth, LayoutUnit inlineBoxHeight, |
- bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const |
-{ |
- RoundedRect border = style()->getRoundedBorderFor(borderRect, includeLogicalLeftEdge, includeLogicalRightEdge); |
- if (box && (box->nextLineBox() || box->prevLineBox())) { |
- RoundedRect segmentBorder = style()->getRoundedBorderFor(LayoutRect(0, 0, inlineBoxWidth, inlineBoxHeight), includeLogicalLeftEdge, includeLogicalRightEdge); |
- border.setRadii(segmentBorder.radii()); |
- } |
- |
- return border; |
-} |
- |
-void RenderBoxModelObject::clipRoundedInnerRect(GraphicsContext * context, const LayoutRect& rect, const RoundedRect& clipRect) |
-{ |
- if (clipRect.isRenderable()) |
- context->clipRoundedRect(clipRect); |
- else { |
- // We create a rounded rect for each of the corners and clip it, while making sure we clip opposing corners together. |
- if (!clipRect.radii().topLeft().isEmpty() || !clipRect.radii().bottomRight().isEmpty()) { |
- IntRect topCorner(clipRect.rect().x(), clipRect.rect().y(), rect.maxX() - clipRect.rect().x(), rect.maxY() - clipRect.rect().y()); |
- RoundedRect::Radii topCornerRadii; |
- topCornerRadii.setTopLeft(clipRect.radii().topLeft()); |
- context->clipRoundedRect(RoundedRect(topCorner, topCornerRadii)); |
- |
- IntRect bottomCorner(rect.x(), rect.y(), clipRect.rect().maxX() - rect.x(), clipRect.rect().maxY() - rect.y()); |
- RoundedRect::Radii bottomCornerRadii; |
- bottomCornerRadii.setBottomRight(clipRect.radii().bottomRight()); |
- context->clipRoundedRect(RoundedRect(bottomCorner, bottomCornerRadii)); |
- } |
- |
- if (!clipRect.radii().topRight().isEmpty() || !clipRect.radii().bottomLeft().isEmpty()) { |
- IntRect topCorner(rect.x(), clipRect.rect().y(), clipRect.rect().maxX() - rect.x(), rect.maxY() - clipRect.rect().y()); |
- RoundedRect::Radii topCornerRadii; |
- topCornerRadii.setTopRight(clipRect.radii().topRight()); |
- context->clipRoundedRect(RoundedRect(topCorner, topCornerRadii)); |
- |
- IntRect bottomCorner(clipRect.rect().x(), rect.y(), rect.maxX() - clipRect.rect().x(), clipRect.rect().maxY() - rect.y()); |
- RoundedRect::Radii bottomCornerRadii; |
- bottomCornerRadii.setBottomLeft(clipRect.radii().bottomLeft()); |
- context->clipRoundedRect(RoundedRect(bottomCorner, bottomCornerRadii)); |
- } |
- } |
-} |
- |
// FIXME: See crbug.com/382491. The use of getCTM in this context is incorrect because the matrix returned does not |
// include scales applied at raster time, such as the device zoom. |
static LayoutRect shrinkRectByOnePixel(GraphicsContext* context, const LayoutRect& rect) |
@@ -441,250 +328,6 @@ LayoutRect RenderBoxModelObject::borderInnerRectAdjustedForBleedAvoidance(Graphi |
return (bleedAvoidance == BackgroundBleedBackgroundOverBorder) ? shrinkRectByOnePixel(context, rect) : rect; |
} |
-RoundedRect RenderBoxModelObject::backgroundRoundedRectAdjustedForBleedAvoidance(GraphicsContext* context, const LayoutRect& borderRect, BackgroundBleedAvoidance bleedAvoidance, InlineFlowBox* box, const LayoutSize& boxSize, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const |
-{ |
- if (bleedAvoidance == BackgroundBleedShrinkBackground) { |
- // We shrink the rectangle by one pixel on each side because the bleed is one pixel maximum. |
- return getBackgroundRoundedRect(shrinkRectByOnePixel(context, borderRect), box, boxSize.width(), boxSize.height(), includeLogicalLeftEdge, includeLogicalRightEdge); |
- } |
- if (bleedAvoidance == BackgroundBleedBackgroundOverBorder) |
- return style()->getRoundedInnerBorderFor(borderRect, includeLogicalLeftEdge, includeLogicalRightEdge); |
- |
- return getBackgroundRoundedRect(borderRect, box, boxSize.width(), boxSize.height(), includeLogicalLeftEdge, includeLogicalRightEdge); |
-} |
- |
-static void applyBoxShadowForBackground(GraphicsContext* context, const RenderObject* renderer) |
-{ |
- const ShadowList* shadowList = renderer->style()->boxShadow(); |
- ASSERT(shadowList); |
- for (size_t i = shadowList->shadows().size(); i--; ) { |
- const ShadowData& boxShadow = shadowList->shadows()[i]; |
- if (boxShadow.style() != Normal) |
- continue; |
- FloatSize shadowOffset(boxShadow.x(), boxShadow.y()); |
- context->setShadow(shadowOffset, boxShadow.blur(), boxShadow.color(), |
- DrawLooperBuilder::ShadowRespectsTransforms, DrawLooperBuilder::ShadowIgnoresAlpha); |
- return; |
- } |
-} |
- |
-void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, const Color& color, const FillLayer& bgLayer, const LayoutRect& rect, |
- BackgroundBleedAvoidance bleedAvoidance, InlineFlowBox* box, const LayoutSize& boxSize, CompositeOperator op, RenderObject* backgroundObject, bool skipBaseColor) |
-{ |
- GraphicsContext* context = paintInfo.context; |
- if (rect.isEmpty()) |
- return; |
- |
- bool includeLeftEdge = box ? box->includeLogicalLeftEdge() : true; |
- bool includeRightEdge = box ? box->includeLogicalRightEdge() : true; |
- |
- bool hasRoundedBorder = style()->hasBorderRadius() && (includeLeftEdge || includeRightEdge); |
- bool clippedWithLocalScrolling = hasOverflowClip() && bgLayer.attachment() == LocalBackgroundAttachment; |
- bool isBorderFill = bgLayer.clip() == BorderFillBox; |
- bool isDocumentElementRenderer = this->isDocumentElement(); |
- bool isBottomLayer = !bgLayer.next(); |
- |
- Color bgColor = color; |
- StyleImage* bgImage = bgLayer.image(); |
- bool shouldPaintBackgroundImage = bgImage && bgImage->canRender(*this, style()->effectiveZoom()); |
- |
- bool forceBackgroundToWhite = false; |
- if (document().printing()) { |
- if (style()->printColorAdjust() == PrintColorAdjustEconomy) |
- forceBackgroundToWhite = true; |
- if (document().settings() && document().settings()->shouldPrintBackgrounds()) |
- forceBackgroundToWhite = false; |
- } |
- |
- // When printing backgrounds is disabled or using economy mode, |
- // change existing background colors and images to a solid white background. |
- // If there's no bg color or image, leave it untouched to avoid affecting transparency. |
- // We don't try to avoid loading the background images, because this style flag is only set |
- // when printing, and at that point we've already loaded the background images anyway. (To avoid |
- // loading the background images we'd have to do this check when applying styles rather than |
- // while rendering.) |
- if (forceBackgroundToWhite) { |
- // Note that we can't reuse this variable below because the bgColor might be changed |
- bool shouldPaintBackgroundColor = isBottomLayer && bgColor.alpha(); |
- if (shouldPaintBackgroundImage || shouldPaintBackgroundColor) { |
- bgColor = Color::white; |
- shouldPaintBackgroundImage = false; |
- } |
- } |
- |
- bool colorVisible = bgColor.alpha(); |
- |
- // Fast path for drawing simple color backgrounds. |
- if (!isDocumentElementRenderer && !clippedWithLocalScrolling && !shouldPaintBackgroundImage && isBorderFill && isBottomLayer) { |
- if (!colorVisible) |
- return; |
- |
- bool boxShadowShouldBeAppliedToBackground = this->boxShadowShouldBeAppliedToBackground(bleedAvoidance, box); |
- GraphicsContextStateSaver shadowStateSaver(*context, boxShadowShouldBeAppliedToBackground); |
- if (boxShadowShouldBeAppliedToBackground) |
- applyBoxShadowForBackground(context, this); |
- |
- if (hasRoundedBorder && bleedAvoidance != BackgroundBleedClipBackground) { |
- RoundedRect border = backgroundRoundedRectAdjustedForBleedAvoidance(context, rect, bleedAvoidance, box, boxSize, includeLeftEdge, includeRightEdge); |
- if (border.isRenderable()) |
- context->fillRoundedRect(border, bgColor); |
- else { |
- context->save(); |
- clipRoundedInnerRect(context, rect, border); |
- context->fillRect(border.rect(), bgColor); |
- context->restore(); |
- } |
- } else { |
- context->fillRect(pixelSnappedIntRect(rect), bgColor); |
- } |
- |
- return; |
- } |
- |
- // BorderFillBox radius clipping is taken care of by BackgroundBleedClipBackground |
- bool clipToBorderRadius = hasRoundedBorder && !(isBorderFill && bleedAvoidance == BackgroundBleedClipBackground); |
- GraphicsContextStateSaver clipToBorderStateSaver(*context, clipToBorderRadius); |
- if (clipToBorderRadius) { |
- RoundedRect border = isBorderFill ? backgroundRoundedRectAdjustedForBleedAvoidance(context, rect, bleedAvoidance, box, boxSize, includeLeftEdge, includeRightEdge) : getBackgroundRoundedRect(rect, box, boxSize.width(), boxSize.height(), includeLeftEdge, includeRightEdge); |
- |
- // Clip to the padding or content boxes as necessary. |
- if (bgLayer.clip() == ContentFillBox) { |
- border = style()->getRoundedInnerBorderFor(border.rect(), |
- paddingTop() + borderTop(), paddingBottom() + borderBottom(), paddingLeft() + borderLeft(), paddingRight() + borderRight(), includeLeftEdge, includeRightEdge); |
- } else if (bgLayer.clip() == PaddingFillBox) |
- border = style()->getRoundedInnerBorderFor(border.rect(), includeLeftEdge, includeRightEdge); |
- |
- clipRoundedInnerRect(context, rect, border); |
- } |
- |
- int bLeft = includeLeftEdge ? borderLeft() : 0; |
- int bRight = includeRightEdge ? borderRight() : 0; |
- LayoutUnit pLeft = includeLeftEdge ? paddingLeft() : LayoutUnit(); |
- LayoutUnit pRight = includeRightEdge ? paddingRight() : LayoutUnit(); |
- |
- GraphicsContextStateSaver clipWithScrollingStateSaver(*context, clippedWithLocalScrolling); |
- LayoutRect scrolledPaintRect = rect; |
- if (clippedWithLocalScrolling) { |
- // Clip to the overflow area. |
- RenderBox* thisBox = toRenderBox(this); |
- context->clip(thisBox->overflowClipRect(rect.location())); |
- |
- // Adjust the paint rect to reflect a scrolled content box with borders at the ends. |
- IntSize offset = thisBox->scrolledContentOffset(); |
- scrolledPaintRect.move(-offset); |
- scrolledPaintRect.setWidth(bLeft + thisBox->scrollWidth() + bRight); |
- scrolledPaintRect.setHeight(borderTop() + thisBox->scrollHeight() + borderBottom()); |
- } |
- |
- GraphicsContextStateSaver backgroundClipStateSaver(*context, false); |
- IntRect maskRect; |
- |
- switch (bgLayer.clip()) { |
- case PaddingFillBox: |
- case ContentFillBox: { |
- if (clipToBorderRadius) |
- break; |
- |
- // Clip to the padding or content boxes as necessary. |
- bool includePadding = bgLayer.clip() == ContentFillBox; |
- LayoutRect clipRect = LayoutRect(scrolledPaintRect.x() + bLeft + (includePadding ? pLeft : LayoutUnit()), |
- scrolledPaintRect.y() + borderTop() + (includePadding ? paddingTop() : LayoutUnit()), |
- scrolledPaintRect.width() - bLeft - bRight - (includePadding ? pLeft + pRight : LayoutUnit()), |
- scrolledPaintRect.height() - borderTop() - borderBottom() - (includePadding ? paddingTop() + paddingBottom() : LayoutUnit())); |
- backgroundClipStateSaver.save(); |
- context->clip(clipRect); |
- |
- break; |
- } |
- case TextFillBox: { |
- // First figure out how big the mask has to be. It should be no bigger than what we need |
- // to actually render, so we should intersect the dirty rect with the border box of the background. |
- maskRect = pixelSnappedIntRect(rect); |
- maskRect.intersect(paintInfo.rect); |
- |
- // We draw the background into a separate layer, to be later masked with yet another layer |
- // holding the text content. |
- backgroundClipStateSaver.save(); |
- context->clip(maskRect); |
- context->beginTransparencyLayer(1); |
- |
- break; |
- } |
- case BorderFillBox: |
- break; |
- default: |
- ASSERT_NOT_REACHED(); |
- break; |
- } |
- |
- // Paint the color first underneath all images, culled if background image occludes it. |
- // FIXME: In the bgLayer->hasFiniteBounds() case, we could improve the culling test |
- // by verifying whether the background image covers the entire layout rect. |
- if (isBottomLayer) { |
- IntRect backgroundRect(pixelSnappedIntRect(scrolledPaintRect)); |
- bool boxShadowShouldBeAppliedToBackground = this->boxShadowShouldBeAppliedToBackground(bleedAvoidance, box); |
- bool isOpaqueRoot = (isDocumentElementRenderer && !bgColor.hasAlpha()) || isDocumentElementWithOpaqueBackground(); |
- if (boxShadowShouldBeAppliedToBackground || !shouldPaintBackgroundImage || !bgLayer.hasOpaqueImage(this) || !bgLayer.hasRepeatXY() || (isOpaqueRoot && !toRenderBox(this)->height())) { |
- if (!boxShadowShouldBeAppliedToBackground) |
- backgroundRect.intersect(paintInfo.rect); |
- |
- GraphicsContextStateSaver shadowStateSaver(*context, boxShadowShouldBeAppliedToBackground); |
- if (boxShadowShouldBeAppliedToBackground) |
- applyBoxShadowForBackground(context, this); |
- |
- if (isOpaqueRoot && !skipBaseColor) { |
- paintRootBackgroundColor(paintInfo, rect, bgColor); |
- } else if (bgColor.alpha()) { |
- context->fillRect(backgroundRect, bgColor, context->compositeOperation()); |
- } |
- } |
- } |
- |
- // no progressive loading of the background image |
- if (shouldPaintBackgroundImage) { |
- BackgroundImageGeometry geometry; |
- calculateBackgroundImageGeometry(paintInfo.paintContainer(), bgLayer, scrolledPaintRect, geometry, backgroundObject); |
- geometry.clip(paintInfo.rect); |
- if (!geometry.destRect().isEmpty()) { |
- CompositeOperator compositeOp = op == CompositeSourceOver ? bgLayer.composite() : op; |
- RenderObject* clientForBackgroundImage = backgroundObject ? backgroundObject : this; |
- RefPtr<Image> image = bgImage->image(clientForBackgroundImage, geometry.tileSize()); |
- InterpolationQuality interpolationQuality = chooseInterpolationQuality(context, image.get(), &bgLayer, geometry.tileSize()); |
- if (bgLayer.maskSourceType() == MaskLuminance) |
- context->setColorFilter(ColorFilterLuminanceToAlpha); |
- InterpolationQuality previousInterpolationQuality = context->imageInterpolationQuality(); |
- context->setImageInterpolationQuality(interpolationQuality); |
- context->drawTiledImage(image.get(), geometry.destRect(), geometry.relativePhase(), geometry.tileSize(), |
- compositeOp, bgLayer.blendMode(), geometry.spaceSize()); |
- context->setImageInterpolationQuality(previousInterpolationQuality); |
- } |
- } |
- |
- if (bgLayer.clip() == TextFillBox) { |
- // Create the text mask layer. |
- context->setCompositeOperation(CompositeDestinationIn); |
- context->beginTransparencyLayer(1); |
- |
- // FIXME: Workaround for https://code.google.com/p/skia/issues/detail?id=1291. |
- context->clearRect(maskRect); |
- |
- // Now draw the text into the mask. We do this by painting using a special paint phase that signals to |
- // InlineTextBoxes that they should just add their contents to the clip. |
- PaintInfo info(context, maskRect, PaintPhaseTextClip, PaintBehaviorForceBlackText, 0); |
- context->setCompositeOperation(CompositeSourceOver); |
- if (box) { |
- RootInlineBox& root = box->root(); |
- box->paint(info, LayoutPoint(scrolledPaintRect.x() - box->x(), scrolledPaintRect.y() - box->y()), root.lineTop(), root.lineBottom()); |
- } else { |
- LayoutSize localOffset = isBox() ? toRenderBox(this)->locationOffset() : LayoutSize(); |
- paint(info, scrolledPaintRect.location() - localOffset); |
- } |
- |
- context->endLayer(); |
- context->endLayer(); |
- } |
-} |
- |
static inline int resolveWidthForRatio(int height, const FloatSize& intrinsicRatio) |
{ |
return ceilf(height * intrinsicRatio.width() / intrinsicRatio.height()); |
@@ -775,288 +418,6 @@ IntSize RenderBoxModelObject::calculateImageIntrinsicDimensions(StyleImage* imag |
return positioningAreaSize; |
} |
-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 RenderBoxModelObject::calculateFillTileSize(const FillLayer& fillLayer, const IntSize& positioningAreaSize) const |
-{ |
- StyleImage* image = fillLayer.image(); |
- EFillSizeType type = fillLayer.size().type; |
- |
- IntSize imageIntrinsicSize = calculateImageIntrinsicDimensions(image, positioningAreaSize, 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.isPercent()) |
- tileSize.setWidth(valueForLength(layerWidth, positioningAreaSize.width())); |
- |
- if (layerHeight.isFixed()) |
- tileSize.setHeight(layerHeight.value()); |
- else if (layerHeight.isPercent()) |
- 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()) |
- tileSize.setWidth(imageIntrinsicSize.width() * tileSize.height() / imageIntrinsicSize.height()); |
- } else if (!layerWidth.isAuto() && layerHeight.isAuto()) { |
- if (imageIntrinsicSize.width()) |
- tileSize.setHeight(imageIntrinsicSize.height() * tileSize.width() / imageIntrinsicSize.width()); |
- } else if (layerWidth.isAuto() && layerHeight.isAuto()) { |
- // If both width and height are auto, use the image's intrinsic size. |
- tileSize = 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(); |
-} |
- |
-void RenderBoxModelObject::BackgroundImageGeometry::setNoRepeatX(int 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)); |
-} |
-void RenderBoxModelObject::BackgroundImageGeometry::setNoRepeatY(int 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)); |
-} |
- |
-void RenderBoxModelObject::BackgroundImageGeometry::useFixedAttachment(const IntPoint& attachmentPoint) |
-{ |
- IntPoint alignedPoint = attachmentPoint; |
- m_phase.move(std::max(alignedPoint.x() - m_destRect.x(), 0), std::max(alignedPoint.y() - m_destRect.y(), 0)); |
-} |
- |
-void RenderBoxModelObject::BackgroundImageGeometry::clip(const IntRect& clipRect) |
-{ |
- m_destRect.intersect(clipRect); |
-} |
- |
-IntPoint RenderBoxModelObject::BackgroundImageGeometry::relativePhase() const |
-{ |
- IntPoint phase = m_phase; |
- phase += m_destRect.location() - m_destOrigin; |
- return phase; |
-} |
- |
-bool RenderBoxModelObject::fixedBackgroundPaintsInLocalCoordinates() const |
-{ |
- if (!isDocumentElement()) |
- return false; |
- |
- if (view()->frameView() && view()->frameView()->paintBehavior() & PaintBehaviorFlattenCompositingLayers) |
- return false; |
- |
- RenderLayer* rootLayer = view()->layer(); |
- if (!rootLayer || rootLayer->compositingState() == NotComposited) |
- return false; |
- |
- return rootLayer->compositedLayerMapping()->backgroundLayerPaintsFixedRootBackground(); |
-} |
- |
-static inline int getSpace(int areaSize, int tileSize) |
-{ |
- int numberOfTiles = areaSize / tileSize; |
- int space = -1; |
- |
- if (numberOfTiles > 1) |
- space = lroundf((float)(areaSize - numberOfTiles * tileSize) / (numberOfTiles - 1)); |
- |
- return space; |
-} |
- |
-void RenderBoxModelObject::calculateBackgroundImageGeometry(const RenderLayerModelObject* paintContainer, const FillLayer& fillLayer, const LayoutRect& paintRect, |
- BackgroundImageGeometry& geometry, RenderObject* backgroundObject) const |
-{ |
- LayoutUnit left = 0; |
- LayoutUnit top = 0; |
- IntSize positioningAreaSize; |
- IntRect snappedPaintRect = pixelSnappedIntRect(paintRect); |
- |
- // 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 = borderLeft(); |
- right = borderRight(); |
- top = borderTop(); |
- bottom = borderBottom(); |
- if (fillLayer.origin() == ContentFillBox) { |
- left += paddingLeft(); |
- right += paddingRight(); |
- top += paddingTop(); |
- bottom += paddingBottom(); |
- } |
- } |
- |
- // The background of the box generated by the root element covers the entire canvas including |
- // its margins. Since those were added in already, we have to factor them out when computing |
- // the background positioning area. |
- if (isDocumentElement()) { |
- positioningAreaSize = pixelSnappedIntSize(toRenderBox(this)->size() - LayoutSize(left + right, top + bottom), toRenderBox(this)->location()); |
- left += marginLeft(); |
- top += marginTop(); |
- } else |
- positioningAreaSize = pixelSnappedIntSize(paintRect.size() - LayoutSize(left + right, top + bottom), paintRect.location()); |
- } else { |
- geometry.setHasNonLocalGeometry(); |
- |
- IntRect viewportRect = pixelSnappedIntRect(viewRect()); |
- if (fixedBackgroundPaintsInLocalCoordinates()) |
- viewportRect.setLocation(IntPoint()); |
- else if (FrameView* frameView = view()->frameView()) |
- viewportRect.setLocation(IntPoint(frameView->scrollOffsetForFixedPosition())); |
- |
- if (paintContainer) { |
- IntPoint absoluteContainerOffset = roundedIntPoint(paintContainer->localToAbsolute(FloatPoint())); |
- viewportRect.moveBy(-absoluteContainerOffset); |
- } |
- |
- geometry.setDestRect(pixelSnappedIntRect(viewportRect)); |
- positioningAreaSize = geometry.destRect().size(); |
- } |
- |
- const RenderObject* clientForBackgroundImage = backgroundObject ? backgroundObject : this; |
- IntSize fillTileSize = calculateFillTileSize(fillLayer, positioningAreaSize); |
- fillLayer.image()->setContainerSizeForRenderer(clientForBackgroundImage, fillTileSize, 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())); |
- |
- if (fillLayer.size().size.height().isAuto() && backgroundRepeatY != RoundFill) { |
- fillTileSize.setHeight(fillTileSize.height() * positioningAreaSize.width() / (nrTiles * fillTileSize.width())); |
- } |
- |
- fillTileSize.setWidth(positioningAreaSize.width() / nrTiles); |
- 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())); |
- |
- if (fillLayer.size().size.width().isAuto() && backgroundRepeatX != RoundFill) { |
- fillTileSize.setWidth(fillTileSize.width() * positioningAreaSize.height() / (nrTiles * fillTileSize.height())); |
- } |
- |
- fillTileSize.setHeight(positioningAreaSize.height() / nrTiles); |
- geometry.setTileSize(fillTileSize); |
- geometry.setPhaseY(geometry.tileSize().height() ? geometry.tileSize().height() - roundToInt(computedYPosition + top) % geometry.tileSize().height() : 0); |
- geometry.setSpaceSize(IntSize()); |
- } |
- |
- if (backgroundRepeatX == RepeatFill) { |
- geometry.setPhaseX(geometry.tileSize().width() ? geometry.tileSize().width() - roundToInt(computedXPosition + left) % geometry.tileSize().width() : 0); |
- geometry.setSpaceSize(IntSize()); |
- } else if (backgroundRepeatX == SpaceFill && fillTileSize.width() > 0) { |
- int space = getSpace(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) { |
- geometry.setPhaseY(geometry.tileSize().height() ? geometry.tileSize().height() - roundToInt(computedYPosition + top) % geometry.tileSize().height() : 0); |
- geometry.setSpaceSize(IntSize(geometry.spaceSize().width(), 0)); |
- } else if (backgroundRepeatY == SpaceFill && fillTileSize.height() > 0) { |
- int space = getSpace(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); |
- geometry.setDestOrigin(geometry.destRect().location()); |
-} |
- |
static LayoutUnit computeBorderImageSide(const BorderImageLength& borderSlice, LayoutUnit borderSide, LayoutUnit imageSide, LayoutUnit boxExtent) |
{ |
if (borderSlice.isNumber()) |