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

Unified Diff: Source/core/rendering/RenderBoxModelObject.cpp

Issue 559733005: Move painting code from RenderBoxModelObject into BoxPainter. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 years, 3 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
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())

Powered by Google App Engine
This is Rietveld 408576698