| 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())
|
|
|