diff options
Diffstat (limited to 'Source/WebCore/rendering/RenderBox.cpp')
| -rw-r--r-- | Source/WebCore/rendering/RenderBox.cpp | 1094 |
1 files changed, 741 insertions, 353 deletions
diff --git a/Source/WebCore/rendering/RenderBox.cpp b/Source/WebCore/rendering/RenderBox.cpp index 6c341ddb2..03b81ac9a 100644 --- a/Source/WebCore/rendering/RenderBox.cpp +++ b/Source/WebCore/rendering/RenderBox.cpp @@ -25,19 +25,19 @@ #include "config.h" #include "RenderBox.h" -#include "CachedImage.h" #include "Chrome.h" #include "ChromeClient.h" #include "Document.h" +#include "FloatQuad.h" +#include "Frame.h" #include "FrameView.h" #include "GraphicsContext.h" -#include "HitTestResult.h" -#include "htmlediting.h" #include "HTMLElement.h" +#include "HTMLFrameOwnerElement.h" +#include "HTMLInputElement.h" #include "HTMLNames.h" -#include "ImageBuffer.h" -#include "FloatQuad.h" -#include "Frame.h" +#include "HTMLTextAreaElement.h" +#include "HitTestResult.h" #include "Page.h" #include "PaintInfo.h" #include "RenderArena.h" @@ -47,15 +47,19 @@ #include "RenderGeometryMap.h" #include "RenderInline.h" #include "RenderLayer.h" -#include "RenderPart.h" #include "RenderRegion.h" #include "RenderTableCell.h" #include "RenderTheme.h" #include "RenderView.h" -#include "ScrollbarTheme.h" #include "TransformState.h" +#include "htmlediting.h" #include <algorithm> #include <math.h> +#include <wtf/StackStats.h> + +#if USE(ACCELERATED_COMPOSITING) +#include "RenderLayerCompositor.h" +#endif using namespace std; @@ -72,9 +76,26 @@ static OverrideSizeMap* gOverrideWidthMap = 0; static OverrideSizeMap* gOverrideContainingBlockLogicalHeightMap = 0; static OverrideSizeMap* gOverrideContainingBlockLogicalWidthMap = 0; + +// Size of border belt for autoscroll. When mouse pointer in border belt, +// autoscroll is started. +static const int autoscrollBeltSize = 20; +static const unsigned backgroundObscurationTestMaxDepth = 4; + bool RenderBox::s_hadOverflowClip = false; -RenderBox::RenderBox(Node* node) +static bool skipBodyBackground(const RenderBox* bodyElementRenderer) +{ + ASSERT(bodyElementRenderer->isBody()); + // The <body> only paints its background if the root element has defined a background independent of the body, + // or if the <body>'s parent is not the document element's renderer (e.g. inside SVG foreignObject). + RenderObject* documentElementRenderer = bodyElementRenderer->document()->documentElement()->renderer(); + return documentElementRenderer + && !documentElementRenderer->hasBackground() + && (documentElementRenderer == bodyElementRenderer->parent()); +} + +RenderBox::RenderBox(ContainerNode* node) : RenderBoxModelObject(node) , m_minPreferredLogicalWidth(-1) , m_maxPreferredLogicalWidth(-1) @@ -87,13 +108,13 @@ RenderBox::~RenderBox() { } -LayoutRect RenderBox::borderBoxRectInRegion(RenderRegion* region, LayoutUnit offsetFromTopOfFirstPage, RenderBoxRegionInfoFlags cacheFlag) const +LayoutRect RenderBox::borderBoxRectInRegion(RenderRegion* region, RenderBoxRegionInfoFlags cacheFlag) const { if (!region) return borderBoxRect(); // Compute the logical width and placement in this region. - RenderBoxRegionInfo* boxInfo = renderBoxRegionInfo(region, offsetFromTopOfFirstPage, cacheFlag); + RenderBoxRegionInfo* boxInfo = renderBoxRegionInfo(region, cacheFlag); if (!boxInfo) return borderBoxRect(); @@ -104,17 +125,15 @@ LayoutRect RenderBox::borderBoxRectInRegion(RenderRegion* region, LayoutUnit off // Now apply the parent inset since it is cumulative whenever anything in the containing block chain shifts. // FIXME: Doesn't work right with perpendicular writing modes. const RenderBlock* currentBox = containingBlock(); - offsetFromTopOfFirstPage -= logicalTop(); - RenderBoxRegionInfo* currentBoxInfo = currentBox->renderBoxRegionInfo(region, offsetFromTopOfFirstPage); + RenderBoxRegionInfo* currentBoxInfo = currentBox->renderBoxRegionInfo(region); while (currentBoxInfo && currentBoxInfo->isShifted()) { if (currentBox->style()->direction() == LTR) logicalLeft += currentBoxInfo->logicalLeft(); else logicalLeft -= (currentBox->logicalWidth() - currentBoxInfo->logicalWidth()) - currentBoxInfo->logicalLeft(); - offsetFromTopOfFirstPage -= logicalTop(); currentBox = currentBox->containingBlock(); region = currentBox->clampToStartAndEndRegions(region); - currentBoxInfo = currentBox->renderBoxRegionInfo(region, offsetFromTopOfFirstPage); + currentBoxInfo = currentBox->renderBoxRegionInfo(region); } if (cacheFlag == DoNotCacheRenderBoxRegionInfo) @@ -127,11 +146,12 @@ LayoutRect RenderBox::borderBoxRectInRegion(RenderRegion* region, LayoutUnit off void RenderBox::clearRenderBoxRegionInfo() { - if (!inRenderFlowThread() || isRenderFlowThread()) + if (isRenderFlowThread()) return; - RenderFlowThread* flowThread = enclosingRenderFlowThread(); - flowThread->removeRenderBoxRegionInfo(this); + RenderFlowThread* flowThread = flowThreadContainingBlock(); + if (flowThread) + flowThread->removeRenderBoxRegionInfo(this); } void RenderBox::willBeDestroyed() @@ -141,6 +161,10 @@ void RenderBox::willBeDestroyed() RenderBlock::removePercentHeightDescendantIfNeeded(this); +#if ENABLE(CSS_SHAPES) + ShapeOutsideInfo::removeInfo(this); +#endif + RenderBoxModelObject::willBeDestroyed(); } @@ -184,8 +208,14 @@ void RenderBox::styleWillChange(StyleDifference diff, const RenderStyle* newStyl // The background of the root element or the body element could propagate up to // the canvas. Just dirty the entire canvas when our style changes substantially. if (diff >= StyleDifferenceRepaint && node() && - (node()->hasTagName(htmlTag) || node()->hasTagName(bodyTag))) + (node()->hasTagName(htmlTag) || node()->hasTagName(bodyTag))) { view()->repaint(); + +#if USE(ACCELERATED_COMPOSITING) + if (oldStyle->hasEntirelyFixedBackground() != newStyle->hasEntirelyFixedBackground()) + view()->compositor()->rootFixedBackgroundsChanged(); +#endif + } // When a layout hint happens and an object's position style changes, we have to do a layout // to dirty the render tree using the old position value now. @@ -242,6 +272,15 @@ void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle } } + // Our opaqueness might have changed without triggering layout. + if (diff >= StyleDifferenceRepaint && diff <= StyleDifferenceRepaintLayer) { + RenderObject* parentToInvalidate = parent(); + for (unsigned i = 0; i < backgroundObscurationTestMaxDepth && parentToInvalidate; ++i) { + parentToInvalidate->invalidateBackgroundObscurationStatus(); + parentToInvalidate = parentToInvalidate->parent(); + } + } + bool isBodyRenderer = isBody(); bool isRootRenderer = isRoot(); @@ -253,6 +292,7 @@ void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle // Propagate the new writing mode and direction up to the RenderView. RenderView* viewRenderer = view(); RenderStyle* viewStyle = viewRenderer->style(); + bool viewChangedWritingMode = false; if (viewStyle->direction() != newStyle->direction() && (isRootRenderer || !document()->directionSetOnDocumentElement())) { viewStyle->setDirection(newStyle->direction()); if (isBodyRenderer) @@ -262,6 +302,7 @@ void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle if (viewStyle->writingMode() != newStyle->writingMode() && (isRootRenderer || !document()->writingModeSetOnDocumentElement())) { viewStyle->setWritingMode(newStyle->writingMode()); + viewChangedWritingMode = true; viewRenderer->setHorizontalWritingMode(newStyle->isHorizontalWritingMode()); viewRenderer->markAllDescendantsWithFloatsForLayout(); if (isBodyRenderer) { @@ -272,9 +313,35 @@ void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle } frame()->view()->recalculateScrollbarOverlayStyle(); + + const Pagination& pagination = frame()->view()->pagination(); + if (viewChangedWritingMode && pagination.mode != Pagination::Unpaginated) { + viewStyle->setColumnStylesFromPaginationMode(pagination.mode); + if (viewRenderer->hasColumns()) + viewRenderer->updateColumnInfoFromStyle(viewStyle); + } } + +#if ENABLE(CSS_SHAPES) + updateShapeOutsideInfoAfterStyleChange(style()->shapeOutside(), oldStyle ? oldStyle->shapeOutside() : 0); +#endif } +#if ENABLE(CSS_SHAPES) +void RenderBox::updateShapeOutsideInfoAfterStyleChange(const ShapeValue* shapeOutside, const ShapeValue* oldShapeOutside) +{ + // FIXME: A future optimization would do a deep comparison for equality. (bug 100811) + if (shapeOutside == oldShapeOutside) + return; + + if (shapeOutside) { + ShapeOutsideInfo* shapeOutsideInfo = ShapeOutsideInfo::ensureInfo(this); + shapeOutsideInfo->dirtyShapeSize(); + } else + ShapeOutsideInfo::removeInfo(this); +} +#endif + void RenderBox::updateFromStyle() { RenderBoxModelObject::updateFromStyle(); @@ -287,7 +354,6 @@ void RenderBox::updateFromStyle() if (isRootObject || isViewObject) setHasBoxDecorations(true); - setPositioned(styleToUse->hasOutOfFlowPosition()); setFloating(!isOutOfFlowPositioned() && styleToUse->isFloating()); // We also handle <body> and <html>, whose overflow applies to the viewport. @@ -336,6 +402,7 @@ void RenderBox::layout() child = child->nextSibling(); } statePusher.pop(); + invalidateBackgroundObscurationStatus(); setNeedsLayout(false); } @@ -361,6 +428,16 @@ int RenderBox::pixelSnappedClientHeight() const return snapSizeToPixel(clientHeight(), y() + clientTop()); } +int RenderBox::pixelSnappedOffsetWidth() const +{ + return snapSizeToPixel(offsetWidth(), x() + clientLeft()); +} + +int RenderBox::pixelSnappedOffsetHeight() const +{ + return snapSizeToPixel(offsetHeight(), y() + clientTop()); +} + int RenderBox::scrollWidth() const { if (hasOverflowClip()) @@ -420,23 +497,34 @@ void RenderBox::updateLayerTransform() layer()->updateTransform(); } -LayoutUnit RenderBox::constrainLogicalWidthInRegionByMinMax(LayoutUnit logicalWidth, LayoutUnit availableWidth, RenderBlock* cb, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const +LayoutUnit RenderBox::constrainLogicalWidthInRegionByMinMax(LayoutUnit logicalWidth, LayoutUnit availableWidth, RenderBlock* cb, RenderRegion* region) const { RenderStyle* styleToUse = style(); if (!styleToUse->logicalMaxWidth().isUndefined()) - logicalWidth = min(logicalWidth, computeLogicalWidthInRegionUsing(MaxSize, availableWidth, cb, region, offsetFromLogicalTopOfFirstPage)); - return max(logicalWidth, computeLogicalWidthInRegionUsing(MinSize, availableWidth, cb, region, offsetFromLogicalTopOfFirstPage)); + logicalWidth = min(logicalWidth, computeLogicalWidthInRegionUsing(MaxSize, styleToUse->logicalMaxWidth(), availableWidth, cb, region)); + return max(logicalWidth, computeLogicalWidthInRegionUsing(MinSize, styleToUse->logicalMinWidth(), availableWidth, cb, region)); } LayoutUnit RenderBox::constrainLogicalHeightByMinMax(LayoutUnit logicalHeight) const { RenderStyle* styleToUse = style(); if (!styleToUse->logicalMaxHeight().isUndefined()) { - LayoutUnit maxH = computeLogicalHeightUsing(MaxSize, styleToUse->logicalMaxHeight()); + LayoutUnit maxH = computeLogicalHeightUsing(styleToUse->logicalMaxHeight()); if (maxH != -1) logicalHeight = min(logicalHeight, maxH); } - return max(logicalHeight, computeLogicalHeightUsing(MinSize, styleToUse->logicalMinHeight())); + return max(logicalHeight, computeLogicalHeightUsing(styleToUse->logicalMinHeight())); +} + +LayoutUnit RenderBox::constrainContentBoxLogicalHeightByMinMax(LayoutUnit logicalHeight) const +{ + RenderStyle* styleToUse = style(); + if (!styleToUse->logicalMaxHeight().isUndefined()) { + LayoutUnit maxH = computeContentLogicalHeight(styleToUse->logicalMaxHeight()); + if (maxH != -1) + logicalHeight = min(logicalHeight, maxH); + } + return max(logicalHeight, computeContentLogicalHeight(styleToUse->logicalMinHeight())); } IntRect RenderBox::absoluteContentBox() const @@ -459,14 +547,16 @@ LayoutRect RenderBox::outlineBoundsForRepaint(const RenderLayerModelObject* repa LayoutRect box = borderBoundingBox(); adjustRectForOutlineAndShadow(box); - FloatQuad containerRelativeQuad; - if (geometryMap) - containerRelativeQuad = geometryMap->mapToContainer(box, repaintContainer); - else - containerRelativeQuad = localToContainerQuad(FloatRect(box), repaintContainer); - - box = containerRelativeQuad.enclosingBoundingBox(); + if (repaintContainer != this) { + FloatQuad containerRelativeQuad; + if (geometryMap) + containerRelativeQuad = geometryMap->mapToContainer(box, repaintContainer); + else + containerRelativeQuad = localToContainerQuad(FloatRect(box), repaintContainer); + box = containerRelativeQuad.enclosingBoundingBox(); + } + // FIXME: layoutDelta needs to be applied in parts before/after transforms and // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308 box.move(view()->layoutDelta()); @@ -474,7 +564,7 @@ LayoutRect RenderBox::outlineBoundsForRepaint(const RenderLayerModelObject* repa return box; } -void RenderBox::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset) +void RenderBox::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*) { if (!size().isEmpty()) rects.append(pixelSnappedIntRect(additionalOffset, size())); @@ -565,6 +655,24 @@ int RenderBox::horizontalScrollbarHeight() const return includeHorizontalScrollbarSize() ? layer()->horizontalScrollbarHeight() : 0; } +int RenderBox::instrinsicScrollbarLogicalWidth() const +{ + if (!hasOverflowClip()) + return 0; + + if (isHorizontalWritingMode() && style()->overflowY() == OSCROLL) { + ASSERT(layer()->hasVerticalScrollbar()); + return verticalScrollbarWidth(); + } + + if (!isHorizontalWritingMode() && style()->overflowX() == OSCROLL) { + ASSERT(layer()->hasHorizontalScrollbar()); + return horizontalScrollbarHeight(); + } + + return 0; +} + bool RenderBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode) { RenderLayer* l = layer(); @@ -628,10 +736,70 @@ bool RenderBox::usesCompositedScrolling() const return hasOverflowClip() && hasLayer() && layer()->usesCompositedScrolling(); } -void RenderBox::autoscroll() +void RenderBox::autoscroll(const IntPoint& position) { if (layer()) - layer()->autoscroll(); + layer()->autoscroll(position); +} + +// There are two kinds of renderer that can autoscroll. +bool RenderBox::canAutoscroll() const +{ + // Check for a box that can be scrolled in its own right. + if (canBeScrolledAndHasScrollableArea()) + return true; + + // Check for a box that represents the top level of a web page. + // This can be scrolled by calling Chrome::scrollRectIntoView. + // This only has an effect on the Mac platform in applications + // that put web views into scrolling containers, such as Mac OS X Mail. + // The code for this is in RenderLayer::scrollRectToVisible. + if (node() != document()) + return false; + Frame* frame = this->frame(); + if (!frame) + return false; + Page* page = frame->page(); + return page && page->mainFrame() == frame && frame->view()->isScrollable(); +} + +// If specified point is in border belt, returned offset denotes direction of +// scrolling. +IntSize RenderBox::calculateAutoscrollDirection(const IntPoint& windowPoint) const +{ + if (!frame()) + return IntSize(); + + FrameView* frameView = frame()->view(); + if (!frameView) + return IntSize(); + + IntSize offset; + IntPoint point = frameView->windowToContents(windowPoint); + IntRect box(absoluteBoundingBoxRect()); + + if (point.x() < box.x() + autoscrollBeltSize) + point.move(-autoscrollBeltSize, 0); + else if (point.x() > box.maxX() - autoscrollBeltSize) + point.move(autoscrollBeltSize, 0); + + if (point.y() < box.y() + autoscrollBeltSize) + point.move(0, -autoscrollBeltSize); + else if (point.y() > box.maxY() - autoscrollBeltSize) + point.move(0, autoscrollBeltSize); + return frameView->contentsToWindow(point) - windowPoint; +} + +RenderBox* RenderBox::findAutoscrollable(RenderObject* renderer) +{ + while (renderer && !(renderer->isBox() && toRenderBox(renderer)->canAutoscroll())) { + if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document()->ownerElement()) + renderer = renderer->document()->ownerElement()->renderer(); + else + renderer = renderer->parent(); + } + + return renderer && renderer->isBox() ? toRenderBox(renderer) : 0; } void RenderBox::panScroll(const IntPoint& source) @@ -661,31 +829,49 @@ LayoutSize RenderBox::cachedSizeForOverflowClip() const void RenderBox::applyCachedClipAndScrollOffsetForRepaint(LayoutRect& paintRect) const { + flipForWritingMode(paintRect); paintRect.move(-scrolledContentOffset()); // For overflow:auto/scroll/hidden. // Do not clip scroll layer contents to reduce the number of repaints while scrolling. - if (usesCompositedScrolling()) + if (usesCompositedScrolling()) { + flipForWritingMode(paintRect); return; + } // height() is inaccurate if we're in the middle of a layout of this RenderBox, so use the // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint // anyway if its size does change. LayoutRect clipRect(LayoutPoint(), cachedSizeForOverflowClip()); paintRect = intersection(paintRect, clipRect); + flipForWritingMode(paintRect); +} + +void RenderBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const +{ + minLogicalWidth = minPreferredLogicalWidth() - borderAndPaddingLogicalWidth(); + maxLogicalWidth = maxPreferredLogicalWidth() - borderAndPaddingLogicalWidth(); } LayoutUnit RenderBox::minPreferredLogicalWidth() const { - if (preferredLogicalWidthsDirty()) + if (preferredLogicalWidthsDirty()) { +#ifndef NDEBUG + SetLayoutNeededForbiddenScope layoutForbiddenScope(const_cast<RenderBox*>(this)); +#endif const_cast<RenderBox*>(this)->computePreferredLogicalWidths(); + } return m_minPreferredLogicalWidth; } LayoutUnit RenderBox::maxPreferredLogicalWidth() const { - if (preferredLogicalWidthsDirty()) + if (preferredLogicalWidthsDirty()) { +#ifndef NDEBUG + SetLayoutNeededForbiddenScope layoutForbiddenScope(const_cast<RenderBox*>(this)); +#endif const_cast<RenderBox*>(this)->computePreferredLogicalWidths(); + } return m_maxPreferredLogicalWidth; } @@ -784,6 +970,11 @@ void RenderBox::clearContainingBlockOverrideSize() { if (gOverrideContainingBlockLogicalWidthMap) gOverrideContainingBlockLogicalWidthMap->remove(this); + clearOverrideContainingBlockContentLogicalHeight(); +} + +void RenderBox::clearOverrideContainingBlockContentLogicalHeight() +{ if (gOverrideContainingBlockLogicalHeightMap) gOverrideContainingBlockLogicalHeightMap->remove(this); } @@ -851,13 +1042,16 @@ void RenderBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) LayoutPoint adjustedPaintOffset = paintOffset + location(); // default implementation. Just pass paint through to the children PaintInfo childInfo(paintInfo); - childInfo.updatePaintingRootForChildren(this); + childInfo.updateSubtreePaintRootForChildren(this); for (RenderObject* child = firstChild(); child; child = child->nextSibling()) child->paint(childInfo, adjustedPaintOffset); } void RenderBox::paintRootBoxFillLayers(const PaintInfo& paintInfo) { + if (paintInfo.skipRootBackground()) + return; + RenderObject* rootBackgroundRenderer = rendererForRootBackground(); const FillLayer* bgLayer = rootBackgroundRenderer->style()->backgroundLayers(); @@ -878,9 +1072,24 @@ BackgroundBleedAvoidance RenderBox::determineBackgroundBleedAvoidance(GraphicsCo AffineTransform ctm = context->getCTM(); FloatSize contextScaling(static_cast<float>(ctm.xScale()), static_cast<float>(ctm.yScale())); + + // Because RoundedRect uses IntRect internally the inset applied by the + // BackgroundBleedShrinkBackground strategy cannot be less than one integer + // layout coordinate, even with subpixel layout enabled. To take that into + // account, we clamp the contextScaling to 1.0 for the following test so + // that borderObscuresBackgroundEdge can only return true if the border + // widths are greater than 2 in both layout coordinates and screen + // coordinates. + // This precaution will become obsolete if RoundedRect is ever promoted to + // a sub-pixel representation. + if (contextScaling.width() > 1) + contextScaling.setWidth(1); + if (contextScaling.height() > 1) + contextScaling.setHeight(1); + if (borderObscuresBackgroundEdge(contextScaling)) return BackgroundBleedShrinkBackground; - if (!style->hasAppearance() && borderObscuresBackground() && backgroundIsSingleOpaqueLayer()) + if (!style->hasAppearance() && borderObscuresBackground() && backgroundHasOpaqueTopLayer()) return BackgroundBleedBackgroundOverBorder; return BackgroundBleedUseTransparencyLayer; @@ -894,10 +1103,6 @@ void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& pai LayoutRect paintRect = borderBoxRectInRegion(paintInfo.renderRegion); paintRect.moveBy(paintOffset); - // border-fit can adjust where we paint our border and background. If set, we snugly fit our line box descendants. (The iChat - // balloon layout is an example of this). - borderFitAdjust(paintRect); - BackgroundBleedAvoidance bleedAvoidance = determineBackgroundBleedAvoidance(paintInfo.context); // FIXME: Should eventually give the theme control over whether the box shadow should paint, since controls could have @@ -912,7 +1117,7 @@ void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& pai // beginning the layer). RoundedRect border = style()->getRoundedBorderFor(paintRect, view()); stateSaver.save(); - paintInfo.context->addRoundedRectClip(border); + paintInfo.context->clipRoundedRect(border); paintInfo.context->beginTransparencyLayer(1); } @@ -941,33 +1146,168 @@ void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& pai void RenderBox::paintBackground(const PaintInfo& paintInfo, const LayoutRect& paintRect, BackgroundBleedAvoidance bleedAvoidance) { - if (isRoot()) + if (isRoot()) { paintRootBoxFillLayers(paintInfo); - else if (!isBody() - || (document()->documentElement()->renderer() && document()->documentElement()->renderer()->hasBackground()) - || (document()->documentElement()->renderer() != parent())) { - // The <body> only paints its background if the root element has defined a background independent of the body, - // or if the <body>'s parent is not the document element's renderer (e.g. inside SVG foreignObject). - if (!backgroundIsObscured()) - paintFillLayers(paintInfo, style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), paintRect, bleedAvoidance); + return; + } + if (isBody() && skipBodyBackground(this)) + return; + if (backgroundIsKnownToBeObscured() && !boxShadowShouldBeAppliedToBackground(bleedAvoidance)) + return; + paintFillLayers(paintInfo, style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), paintRect, bleedAvoidance); +} + +bool RenderBox::getBackgroundPaintedExtent(LayoutRect& paintedExtent) const +{ + ASSERT(hasBackground()); + LayoutRect backgroundRect = pixelSnappedIntRect(borderBoxRect()); + + Color backgroundColor = style()->visitedDependentColor(CSSPropertyBackgroundColor); + if (backgroundColor.isValid() && backgroundColor.alpha()) { + paintedExtent = backgroundRect; + return true; + } + + if (!style()->backgroundLayers()->image() || style()->backgroundLayers()->next()) { + paintedExtent = backgroundRect; + return true; + } + + BackgroundImageGeometry geometry; + calculateBackgroundImageGeometry(0, style()->backgroundLayers(), backgroundRect, geometry); + paintedExtent = geometry.destRect(); + return !geometry.hasNonLocalGeometry(); +} + +bool RenderBox::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const +{ + if (isBody() && skipBodyBackground(this)) + return false; + + Color backgroundColor = style()->visitedDependentColor(CSSPropertyBackgroundColor); + if (!backgroundColor.isValid() || backgroundColor.hasAlpha()) + return false; + + // If the element has appearance, it might be painted by theme. + // We cannot be sure if theme paints the background opaque. + // In this case it is safe to not assume opaqueness. + // FIXME: May be ask theme if it paints opaque. + if (style()->hasAppearance()) + return false; + // FIXME: Check the opaqueness of background images. + + // FIXME: Use rounded rect if border radius is present. + if (style()->hasBorderRadius()) + return false; + // FIXME: The background color clip is defined by the last layer. + if (style()->backgroundLayers()->next()) + return false; + LayoutRect backgroundRect; + switch (style()->backgroundClip()) { + case BorderFillBox: + backgroundRect = borderBoxRect(); + break; + case PaddingFillBox: + backgroundRect = paddingBoxRect(); + break; + case ContentFillBox: + backgroundRect = contentBoxRect(); + break; + default: + break; + } + return backgroundRect.contains(localRect); +} + +static bool isCandidateForOpaquenessTest(RenderBox* childBox) +{ + RenderStyle* childStyle = childBox->style(); + if (childStyle->position() != StaticPosition && childBox->containingBlock() != childBox->parent()) + return false; + if (childStyle->visibility() != VISIBLE || childStyle->shapeOutside()) + return false; + if (!childBox->width() || !childBox->height()) + return false; + if (RenderLayer* childLayer = childBox->layer()) { +#if USE(ACCELERATED_COMPOSITING) + if (childLayer->isComposited()) + return false; +#endif + // FIXME: Deal with z-index. + if (!childStyle->hasAutoZIndex()) + return false; + if (childLayer->hasTransform() || childLayer->isTransparent() || childLayer->hasFilter()) + return false; + } + return true; +} + +bool RenderBox::foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, unsigned maxDepthToTest) const +{ + if (!maxDepthToTest) + return false; + for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { + if (!child->isBox()) + continue; + RenderBox* childBox = toRenderBox(child); + if (!isCandidateForOpaquenessTest(childBox)) + continue; + LayoutPoint childLocation = childBox->location(); + if (childBox->isRelPositioned()) + childLocation.move(childBox->relativePositionOffset()); + LayoutRect childLocalRect = localRect; + childLocalRect.moveBy(-childLocation); + if (childLocalRect.y() < 0 || childLocalRect.x() < 0) { + // If there is unobscured area above/left of a static positioned box then the rect is probably not covered. + if (childBox->style()->position() == StaticPosition) + return false; + continue; + } + if (childLocalRect.maxY() > childBox->height() || childLocalRect.maxX() > childBox->width()) + continue; + if (childBox->backgroundIsKnownToBeOpaqueInRect(childLocalRect)) + return true; + if (childBox->foregroundIsKnownToBeOpaqueInRect(childLocalRect, maxDepthToTest - 1)) + return true; } + return false; } -bool RenderBox::backgroundIsSingleOpaqueLayer() const +bool RenderBox::computeBackgroundIsKnownToBeObscured() +{ + // Test to see if the children trivially obscure the background. + // FIXME: This test can be much more comprehensive. + if (!hasBackground()) + return false; + // Table and root background painting is special. + if (isTable() || isRoot()) + return false; + + LayoutRect backgroundRect; + if (!getBackgroundPaintedExtent(backgroundRect)) + return false; + return foregroundIsKnownToBeOpaqueInRect(backgroundRect, backgroundObscurationTestMaxDepth); +} + +bool RenderBox::backgroundHasOpaqueTopLayer() const { const FillLayer* fillLayer = style()->backgroundLayers(); - if (!fillLayer || fillLayer->next() || fillLayer->clip() != BorderFillBox || fillLayer->composite() != CompositeSourceOver) + if (!fillLayer || fillLayer->clip() != BorderFillBox) return false; // Clipped with local scrolling if (hasOverflowClip() && fillLayer->attachment() == LocalBackgroundAttachment) return false; - Color bgColor = style()->visitedDependentColor(CSSPropertyBackgroundColor); - if (bgColor.isValid() && bgColor.alpha() == 255) + if (fillLayer->hasOpaqueImage(this) && fillLayer->hasRepeatXY() && fillLayer->image()->canRender(this, style()->effectiveZoom())) return true; - - // FIXME: return true if a background image is present and is opaque + + // If there is only one layer and no image, check whether the background color is opaque + if (!fillLayer->next() && !fillLayer->hasImage()) { + Color bgColor = style()->visitedDependentColor(CSSPropertyBackgroundColor); + if (bgColor.isValid() && bgColor.alpha() == 255) + return true; + } return false; } @@ -978,11 +1318,6 @@ void RenderBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset) return; LayoutRect paintRect = LayoutRect(paintOffset, size()); - - // border-fit can adjust where we paint our border and background. If set, we snugly fit our line box descendants. (The iChat - // balloon layout is an example of this). - borderFitAdjust(paintRect); - paintMaskImages(paintInfo, paintRect); } @@ -1038,7 +1373,8 @@ LayoutRect RenderBox::maskClipRect() for (const FillLayer* maskLayer = style()->maskLayers(); maskLayer; maskLayer = maskLayer->next()) { if (maskLayer->image()) { BackgroundImageGeometry geometry; - calculateBackgroundImageGeometry(maskLayer, borderBox, geometry); + // Masks should never have fixed attachment, so it's OK for paintContainer to be null. + calculateBackgroundImageGeometry(0, maskLayer, borderBox, geometry); result.unite(geometry.destRect()); } } @@ -1048,18 +1384,40 @@ LayoutRect RenderBox::maskClipRect() void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, const LayoutRect& rect, BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderObject* backgroundObject) { - if (!fillLayer) - return; + Vector<const FillLayer*, 8> layers; + const FillLayer* curLayer = fillLayer; + bool shouldDrawBackgroundInSeparateBuffer = false; + while (curLayer) { + layers.append(curLayer); + // Stop traversal when an opaque layer is encountered. + // FIXME : It would be possible for the following occlusion culling test to be more aggressive + // on layers with no repeat by testing whether the image covers the layout rect. + // Testing that here would imply duplicating a lot of calculations that are currently done in + // RenderBoxModelObject::paintFillLayerExtended. A more efficient solution might be to move + // the layer recursion into paintFillLayerExtended, or to compute the layer geometry here + // and pass it down. + + if (!shouldDrawBackgroundInSeparateBuffer && curLayer->blendMode() != BlendModeNormal) + shouldDrawBackgroundInSeparateBuffer = true; + + // The clipOccludesNextLayers condition must be evaluated first to avoid short-circuiting. + if (curLayer->clipOccludesNextLayers(curLayer == fillLayer) && curLayer->hasOpaqueImage(this) && curLayer->image()->canRender(this, style()->effectiveZoom()) && curLayer->hasRepeatXY() && curLayer->blendMode() == BlendModeNormal) + break; + curLayer = curLayer->next(); + } + + GraphicsContext* context = paintInfo.context; + if (!context) + shouldDrawBackgroundInSeparateBuffer = false; + if (shouldDrawBackgroundInSeparateBuffer) + context->beginTransparencyLayer(1); - // FIXME : It would be possible for the following occlusion culling test to be more aggressive - // on layers with no repeat by testing whether the image covers the layout rect. - // Testing that here would imply duplicating a lot of calculations that are currently done in - // RenderBoxModelOBject::paintFillLayerExtended. A more efficient solution might be to move - // the layer recursion into paintFillLayerExtended, or to compute the layer geometry here - // and pass it down. - if (fillLayer->next() && (!fillLayer->hasOpaqueImage(this) || !fillLayer->image()->canRender(this, style()->effectiveZoom()) || !fillLayer->hasRepeatXY())) - paintFillLayers(paintInfo, c, fillLayer->next(), rect, bleedAvoidance, op, backgroundObject); - paintFillLayer(paintInfo, c, fillLayer, rect, bleedAvoidance, op, backgroundObject); + Vector<const FillLayer*>::const_reverse_iterator topLayer = layers.rend(); + for (Vector<const FillLayer*>::const_reverse_iterator it = layers.rbegin(); it != topLayer; ++it) + paintFillLayer(paintInfo, c, *it, rect, bleedAvoidance, op, backgroundObject); + + if (shouldDrawBackgroundInSeparateBuffer) + context->endTransparencyLayer(); } void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, const LayoutRect& rect, @@ -1097,8 +1455,13 @@ void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*) #if USE(ACCELERATED_COMPOSITING) - if (hasLayer() && layer()->hasCompositedMask() && layersUseImage(image, style()->maskLayers())) + if (!isComposited()) + return; + + if (layer()->hasCompositedMask() && layersUseImage(image, style()->maskLayers())) layer()->contentChanged(MaskImageChanged); + if (layersUseImage(image, style()->backgroundLayers())) + layer()->contentChanged(BackgroundImageChanged); #endif } @@ -1109,8 +1472,7 @@ bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer for (const FillLayer* curLayer = layers; curLayer; curLayer = curLayer->next()) { if (curLayer->image() && image == curLayer->image()->data() && curLayer->image()->canRender(this, style()->effectiveZoom())) { - // Now that we know this image is being used, compute the renderer and the rect - // if we haven't already + // Now that we know this image is being used, compute the renderer and the rect if we haven't already. if (!layerRenderer) { bool drawingRootBackground = drawingBackground && (isRoot() || (isBody() && !document()->documentElement()->renderer()->hasBackground())); if (drawingRootBackground) { @@ -1137,7 +1499,14 @@ bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer } BackgroundImageGeometry geometry; - layerRenderer->calculateBackgroundImageGeometry(curLayer, rendererRect, geometry); + layerRenderer->calculateBackgroundImageGeometry(0, curLayer, rendererRect, geometry); + if (geometry.hasNonLocalGeometry()) { + // Rather than incur the costs of computing the paintContainer for renderers with fixed backgrounds + // in order to get the right destRect, just repaint the entire renderer. + layerRenderer->repaint(); + return true; + } + layerRenderer->repaintRectangle(geometry.destRect()); if (geometry.destRect() == rendererRect) return true; @@ -1162,10 +1531,10 @@ void RenderBox::paintCustomHighlight(const LayoutPoint& paintOffset, const Atomi if (r) { FloatRect rootRect(paintOffset.x() + r->x(), paintOffset.y() + r->selectionTop(), r->logicalWidth(), r->selectionHeight()); FloatRect imageRect(paintOffset.x() + x(), rootRect.y(), width(), rootRect.height()); - page->chrome()->client()->paintCustomHighlight(node(), type, imageRect, rootRect, behindText, false); + page->chrome().client()->paintCustomHighlight(node(), type, imageRect, rootRect, behindText, false); } else { FloatRect imageRect(paintOffset.x() + x(), paintOffset.y() + y(), width(), height()); - page->chrome()->client()->paintCustomHighlight(node(), type, imageRect, imageRect, behindText, false); + page->chrome().client()->paintCustomHighlight(node(), type, imageRect, imageRect, behindText, false); } } @@ -1189,10 +1558,10 @@ bool RenderBox::pushContentsClip(PaintInfo& paintInfo, const LayoutPoint& accumu paintObject(paintInfo, accumulatedOffset); paintInfo.phase = PaintPhaseChildBlockBackgrounds; } - IntRect clipRect = pixelSnappedIntRect(isControlClip ? controlClipRect(accumulatedOffset) : overflowClipRect(accumulatedOffset, paintInfo.renderRegion)); + IntRect clipRect = pixelSnappedIntRect(isControlClip ? controlClipRect(accumulatedOffset) : overflowClipRect(accumulatedOffset, paintInfo.renderRegion, IgnoreOverlayScrollbarSize, paintInfo.phase)); paintInfo.context->save(); if (style()->hasBorderRadius()) - paintInfo.context->addRoundedRectClip(style()->getRoundedInnerBorderFor(LayoutRect(accumulatedOffset, size()))); + paintInfo.context->clipRoundedRect(style()->getRoundedInnerBorderFor(LayoutRect(accumulatedOffset, size()))); paintInfo.context->clip(clipRect); return true; } @@ -1210,7 +1579,7 @@ void RenderBox::popContentsClip(PaintInfo& paintInfo, PaintPhase originalPhase, paintInfo.phase = originalPhase; } -LayoutRect RenderBox::overflowClipRect(const LayoutPoint& location, RenderRegion* region, OverlayScrollbarSizeRelevancy relevancy) +LayoutRect RenderBox::overflowClipRect(const LayoutPoint& location, RenderRegion* region, OverlayScrollbarSizeRelevancy relevancy, PaintPhase) { // FIXME: When overflow-clip (CSS3) is implemented, we'll obtain the property // here. @@ -1258,18 +1627,17 @@ LayoutRect RenderBox::clipRect(const LayoutPoint& location, RenderRegion* region return clipRect; } -LayoutUnit RenderBox::shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStart, LayoutUnit childMarginEnd, const RenderBlock* cb, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const +LayoutUnit RenderBox::shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStart, LayoutUnit childMarginEnd, const RenderBlock* cb, RenderRegion* region) const { RenderRegion* containingBlockRegion = 0; LayoutUnit logicalTopPosition = logicalTop(); - LayoutUnit adjustedPageOffsetForContainingBlock = offsetFromLogicalTopOfFirstPage - logicalTop(); if (region) { - LayoutUnit offsetFromLogicalTopOfRegion = region ? region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage : LayoutUnit(); + LayoutUnit offsetFromLogicalTopOfRegion = region ? region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage() : LayoutUnit(); logicalTopPosition = max(logicalTopPosition, logicalTopPosition + offsetFromLogicalTopOfRegion); containingBlockRegion = cb->clampToStartAndEndRegions(region); } - LayoutUnit result = cb->availableLogicalWidthForLine(logicalTopPosition, false, containingBlockRegion, adjustedPageOffsetForContainingBlock) - childMarginStart - childMarginEnd; + LayoutUnit result = cb->availableLogicalWidthForLine(logicalTopPosition, false, containingBlockRegion) - childMarginStart - childMarginEnd; // We need to see if margins on either the start side or the end side can contain the floats in question. If they can, // then just using the line width is inaccurate. In the case where a float completely fits, we don't need to use the line @@ -1277,9 +1645,9 @@ LayoutUnit RenderBox::shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStar // doesn't fit, we can use the line offset, but we need to grow it by the margin to reflect the fact that the margin was // "consumed" by the float. Negative margins aren't consumed by the float, and so we ignore them. if (childMarginStart > 0) { - LayoutUnit startContentSide = cb->startOffsetForContent(containingBlockRegion, adjustedPageOffsetForContainingBlock); + LayoutUnit startContentSide = cb->startOffsetForContent(containingBlockRegion); LayoutUnit startContentSideWithMargin = startContentSide + childMarginStart; - LayoutUnit startOffset = cb->startOffsetForLine(logicalTopPosition, false, containingBlockRegion, adjustedPageOffsetForContainingBlock); + LayoutUnit startOffset = cb->startOffsetForLine(logicalTopPosition, false, containingBlockRegion); if (startOffset > startContentSideWithMargin) result += childMarginStart; else @@ -1287,9 +1655,9 @@ LayoutUnit RenderBox::shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStar } if (childMarginEnd > 0) { - LayoutUnit endContentSide = cb->endOffsetForContent(containingBlockRegion, adjustedPageOffsetForContainingBlock); + LayoutUnit endContentSide = cb->endOffsetForContent(containingBlockRegion); LayoutUnit endContentSideWithMargin = endContentSide + childMarginEnd; - LayoutUnit endOffset = cb->endOffsetForLine(logicalTopPosition, false, containingBlockRegion, adjustedPageOffsetForContainingBlock); + LayoutUnit endOffset = cb->endOffsetForLine(logicalTopPosition, false, containingBlockRegion); if (endOffset > endContentSideWithMargin) result += childMarginEnd; else @@ -1308,16 +1676,16 @@ LayoutUnit RenderBox::containingBlockLogicalWidthForContent() const return cb->availableLogicalWidth(); } -LayoutUnit RenderBox::containingBlockLogicalHeightForContent() const +LayoutUnit RenderBox::containingBlockLogicalHeightForContent(AvailableLogicalHeightType heightType) const { if (hasOverrideContainingBlockLogicalHeight()) return overrideContainingBlockContentLogicalHeight(); RenderBlock* cb = containingBlock(); - return cb->availableLogicalHeight(); + return cb->availableLogicalHeight(heightType); } -LayoutUnit RenderBox::containingBlockLogicalWidthForContentInRegion(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const +LayoutUnit RenderBox::containingBlockLogicalWidthForContentInRegion(RenderRegion* region) const { if (!region) return containingBlockLogicalWidthForContent(); @@ -1327,24 +1695,23 @@ LayoutUnit RenderBox::containingBlockLogicalWidthForContentInRegion(RenderRegion // FIXME: It's unclear if a region's content should use the containing block's override logical width. // If it should, the following line should call containingBlockLogicalWidthForContent. LayoutUnit result = cb->availableLogicalWidth(); - RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(containingBlockRegion, offsetFromLogicalTopOfFirstPage - logicalTop()); + RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(containingBlockRegion); if (!boxInfo) return result; return max<LayoutUnit>(0, result - (cb->logicalWidth() - boxInfo->logicalWidth())); } -LayoutUnit RenderBox::containingBlockAvailableLineWidthInRegion(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const +LayoutUnit RenderBox::containingBlockAvailableLineWidthInRegion(RenderRegion* region) const { RenderBlock* cb = containingBlock(); RenderRegion* containingBlockRegion = 0; LayoutUnit logicalTopPosition = logicalTop(); - LayoutUnit adjustedPageOffsetForContainingBlock = offsetFromLogicalTopOfFirstPage - logicalTop(); if (region) { - LayoutUnit offsetFromLogicalTopOfRegion = region ? region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage : LayoutUnit(); + LayoutUnit offsetFromLogicalTopOfRegion = region ? region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage() : LayoutUnit(); logicalTopPosition = max(logicalTopPosition, logicalTopPosition + offsetFromLogicalTopOfRegion); containingBlockRegion = cb->clampToStartAndEndRegions(region); } - return cb->availableLogicalWidthForLine(logicalTopPosition, false, containingBlockRegion, adjustedPageOffsetForContainingBlock, availableLogicalHeight()); + return cb->availableLogicalWidthForLine(logicalTopPosition, false, containingBlockRegion, availableLogicalHeight(IncludeMarginBorderPadding)); } LayoutUnit RenderBox::perpendicularContainingBlockLogicalHeight() const @@ -1358,15 +1725,14 @@ LayoutUnit RenderBox::perpendicularContainingBlockLogicalHeight() const RenderStyle* containingBlockStyle = cb->style(); Length logicalHeightLength = containingBlockStyle->logicalHeight(); - + // FIXME: For now just support fixed heights. Eventually should support percentage heights as well. if (!logicalHeightLength.isFixed()) { - // Rather than making the child be completely unconstrained, WinIE uses the viewport width and height - // as a constraint. We do that for now as well even though it's likely being unconstrained is what the spec - // will decide. - return containingBlockStyle->isHorizontalWritingMode() ? view()->frameView()->visibleHeight() : view()->frameView()->visibleWidth(); + LayoutUnit fillFallbackExtent = containingBlockStyle->isHorizontalWritingMode() ? view()->frameView()->visibleHeight() : view()->frameView()->visibleWidth(); + LayoutUnit fillAvailableExtent = containingBlock()->availableLogicalHeight(ExcludeMarginBorderPadding); + return min(fillAvailableExtent, fillFallbackExtent); } - + // Use the content box logical height as specified by the style. return cb->adjustContentBoxLogicalHeightForBoxSizing(logicalHeightLength.value()); } @@ -1405,8 +1771,6 @@ void RenderBox::mapLocalToContainer(const RenderLayerModelObject* repaintContain *wasFixed = mode & IsFixed; LayoutSize containerOffset = offsetFromContainer(o, roundedLayoutPoint(transformState.mappedPoint())); - if (mode & SnapOffsetForTransforms) - containerOffset = roundedIntSize(containerOffset); bool preserve3D = mode & UseTransforms && (o->style()->preserves3D() || style()->preserves3D()); if (mode & UseTransforms && shouldUseTransformFromContainer(o)) { @@ -1425,13 +1789,6 @@ void RenderBox::mapLocalToContainer(const RenderLayerModelObject* repaintContain } mode &= ~ApplyContainerFlip; - if (o->isRenderFlowThread()) { - // Transform from render flow coordinates into region coordinates. - RenderRegion* region = toRenderFlowThread(o)->mapFromFlowToRegion(transformState); - if (region) - region->mapLocalToContainer(region->containerForRepaint(), transformState, mode, wasFixed); - return; - } o->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed); } @@ -1457,12 +1814,7 @@ const RenderObject* RenderBox::pushMappingToContainer(const RenderLayerModelObje bool offsetDependsOnPoint = false; LayoutSize containerOffset = offsetFromContainer(container, LayoutPoint(), &offsetDependsOnPoint); - if (geometryMap.mapCoordinatesFlags() & SnapOffsetForTransforms) - containerOffset = roundedIntSize(containerOffset); - if (container->isRenderFlowThread()) - offsetDependsOnPoint = true; - bool preserve3D = container->style()->preserves3D() || style()->preserves3D(); if (shouldUseTransformFromContainer(container)) { TransformationMatrix t; @@ -1494,7 +1846,8 @@ void RenderBox::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState LayoutSize RenderBox::offsetFromContainer(RenderObject* o, const LayoutPoint& point, bool* offsetDependsOnPoint) const { - ASSERT(o == container()); + // A region "has" boxes inside it without being their container. + ASSERT(o == container() || o->isRenderRegion()); LayoutSize offset; if (isInFlowPositioned()) @@ -1523,6 +1876,9 @@ LayoutSize RenderBox::offsetFromContainer(RenderObject* o, const LayoutPoint& po if (style()->position() == AbsolutePosition && o->isInFlowPositioned() && o->isRenderInline()) offset += toRenderInline(o)->offsetForInFlowPositionedInline(this); + if (offsetDependsOnPoint) + *offsetDependsOnPoint |= o->isRenderFlowThread(); + return offset; } @@ -1680,7 +2036,7 @@ void RenderBox::computeRectForRepaint(const RenderLayerModelObject* repaintConta if (position == AbsolutePosition && o->isInFlowPositioned() && o->isRenderInline()) topLeft += toRenderInline(o)->offsetForInFlowPositionedInline(this); - else if ((position == RelativePosition || position == StickyPosition) && layer()) { + else if (styleToUse->hasInFlowPosition() && layer()) { // Apply the relative position offset when invalidating a rectangle. The layer // is translated, but the render box isn't, so we need to do this to get the // right dirty rect. Since this is called from RenderObject::setStyle, the relative position @@ -1730,6 +2086,10 @@ void RenderBox::repaintDuringLayoutIfMoved(const LayoutRect& oldRect) } } +void RenderBox::repaintOverhangingFloats(bool) +{ +} + void RenderBox::updateLogicalWidth() { LogicalExtentComputedValues computedValues; @@ -1741,7 +2101,7 @@ void RenderBox::updateLogicalWidth() setMarginEnd(computedValues.m_margins.m_end); } -void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& computedValues, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const +void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& computedValues, RenderRegion* region) const { computedValues.m_extent = logicalWidth(); computedValues.m_position = logicalLeft(); @@ -1751,7 +2111,7 @@ void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& compute if (isOutOfFlowPositioned()) { // FIXME: This calculation is not patched for block-flow yet. // https://bugs.webkit.org/show_bug.cgi?id=46500 - computePositionedLogicalWidth(computedValues, region, offsetFromLogicalTopOfFirstPage); + computePositionedLogicalWidth(computedValues, region); return; } @@ -1763,7 +2123,7 @@ void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& compute // width. Use the width from the style context. // FIXME: Account for block-flow in flexible boxes. // https://bugs.webkit.org/show_bug.cgi?id=46418 - if (hasOverrideWidth() && parent()->isFlexibleBoxIncludingDeprecated()) { + if (hasOverrideWidth() && (style()->borderFit() == BorderFitLines || parent()->isFlexibleBoxIncludingDeprecated())) { computedValues.m_extent = overrideLogicalContentWidth() + borderAndPaddingLogicalWidth(); return; } @@ -1778,11 +2138,8 @@ void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& compute Length logicalWidthLength = treatAsReplaced ? Length(computeReplacedLogicalWidth(), Fixed) : styleToUse->logicalWidth(); RenderBlock* cb = containingBlock(); - LayoutUnit containerLogicalWidth = max<LayoutUnit>(0, containingBlockLogicalWidthForContentInRegion(region, offsetFromLogicalTopOfFirstPage)); + LayoutUnit containerLogicalWidth = max<LayoutUnit>(0, containingBlockLogicalWidthForContentInRegion(region)); bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHorizontalWritingMode(); - LayoutUnit containerWidthInInlineDirection = containerLogicalWidth; - if (hasPerpendicularContainingBlock) - containerWidthInInlineDirection = perpendicularContainingBlockLogicalHeight(); if (isInline() && !isInlineBlockOrInlineTable()) { // just calculate margins @@ -1798,14 +2155,13 @@ void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& compute if (treatAsReplaced) computedValues.m_extent = logicalWidthLength.value() + borderAndPaddingLogicalWidth(); else { - LayoutUnit preferredWidth = computeLogicalWidthInRegionUsing(MainOrPreferredSize, containerWidthInInlineDirection, cb, region, offsetFromLogicalTopOfFirstPage); - computedValues.m_extent = constrainLogicalWidthInRegionByMinMax(preferredWidth, containerWidthInInlineDirection, cb, region, offsetFromLogicalTopOfFirstPage); + LayoutUnit containerWidthInInlineDirection = containerLogicalWidth; + if (hasPerpendicularContainingBlock) + containerWidthInInlineDirection = perpendicularContainingBlockLogicalHeight(); + LayoutUnit preferredWidth = computeLogicalWidthInRegionUsing(MainOrPreferredSize, styleToUse->logicalWidth(), containerWidthInInlineDirection, cb, region); + computedValues.m_extent = constrainLogicalWidthInRegionByMinMax(preferredWidth, containerWidthInInlineDirection, cb, region); } - // Fieldsets are currently the only objects that stretch to their minimum width. - if (stretchesToMinIntrinsicLogicalWidth()) - computedValues.m_extent = max(computedValues.m_extent, minPreferredLogicalWidth()); - // Margin calculations. if (hasPerpendicularContainingBlock || isFloating() || isInline()) { RenderView* renderView = view(); @@ -1814,7 +2170,7 @@ void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& compute } else { LayoutUnit containerLogicalWidthForAutoMargins = containerLogicalWidth; if (avoidsFloats() && cb->containsFloats()) - containerLogicalWidthForAutoMargins = containingBlockAvailableLineWidthInRegion(region, offsetFromLogicalTopOfFirstPage); + containerLogicalWidthForAutoMargins = containingBlockAvailableLineWidthInRegion(region); bool hasInvertedDirection = cb->style()->isLeftToRightDirection() != style()->isLeftToRightDirection(); computeInlineDirectionMargins(cb, containerLogicalWidthForAutoMargins, computedValues.m_extent, hasInvertedDirection ? computedValues.m_margins.m_end : computedValues.m_margins.m_start, @@ -1822,7 +2178,7 @@ void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& compute } if (!hasPerpendicularContainingBlock && containerLogicalWidth && containerLogicalWidth != (computedValues.m_extent + computedValues.m_margins.m_start + computedValues.m_margins.m_end) - && !isFloating() && !isInline() && !cb->isFlexibleBoxIncludingDeprecated()) { + && !isFloating() && !isInline() && !cb->isFlexibleBoxIncludingDeprecated() && !cb->isRenderGrid()) { LayoutUnit newMargin = containerLogicalWidth - computedValues.m_extent - cb->marginStartForChild(this); bool hasInvertedDirection = cb->style()->isLeftToRightDirection() != style()->isLeftToRightDirection(); if (hasInvertedDirection) @@ -1832,44 +2188,65 @@ void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& compute } } -LayoutUnit RenderBox::computeLogicalWidthInRegionUsing(SizeType widthType, LayoutUnit availableLogicalWidth, - const RenderBlock* cb, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const +LayoutUnit RenderBox::fillAvailableMeasure(LayoutUnit availableLogicalWidth) const { - RenderStyle* styleToUse = style(); - Length logicalWidth; - if (widthType == MainOrPreferredSize) - logicalWidth = styleToUse->logicalWidth(); - else if (widthType == MinSize) - logicalWidth = styleToUse->logicalMinWidth(); - else - logicalWidth = styleToUse->logicalMaxWidth(); + LayoutUnit marginStart = 0; + LayoutUnit marginEnd = 0; + return fillAvailableMeasure(availableLogicalWidth, marginStart, marginEnd); +} - ASSERT(!logicalWidth.isUndefined()); +LayoutUnit RenderBox::fillAvailableMeasure(LayoutUnit availableLogicalWidth, LayoutUnit& marginStart, LayoutUnit& marginEnd) const +{ + RenderView* renderView = view(); + marginStart = minimumValueForLength(style()->marginStart(), availableLogicalWidth, renderView); + marginEnd = minimumValueForLength(style()->marginEnd(), availableLogicalWidth, renderView); + return availableLogicalWidth - marginStart - marginEnd; +} - if (widthType == MinSize && logicalWidth.isAuto()) - return adjustBorderBoxLogicalWidthForBoxSizing(0); - +LayoutUnit RenderBox::computeIntrinsicLogicalWidthUsing(Length logicalWidthLength, LayoutUnit availableLogicalWidth, LayoutUnit borderAndPadding) const +{ + if (logicalWidthLength.type() == FillAvailable) + return fillAvailableMeasure(availableLogicalWidth); + + LayoutUnit minLogicalWidth = 0; + LayoutUnit maxLogicalWidth = 0; + computeIntrinsicLogicalWidths(minLogicalWidth, maxLogicalWidth); + + if (logicalWidthLength.type() == MinContent) + return minLogicalWidth + borderAndPadding; + + if (logicalWidthLength.type() == MaxContent) + return maxLogicalWidth + borderAndPadding; + + if (logicalWidthLength.type() == FitContent) { + minLogicalWidth += borderAndPadding; + maxLogicalWidth += borderAndPadding; + return max(minLogicalWidth, min(maxLogicalWidth, fillAvailableMeasure(availableLogicalWidth))); + } + + ASSERT_NOT_REACHED(); + return 0; +} + +LayoutUnit RenderBox::computeLogicalWidthInRegionUsing(SizeType widthType, Length logicalWidth, LayoutUnit availableLogicalWidth, + const RenderBlock* cb, RenderRegion* region) const +{ if (!logicalWidth.isIntrinsicOrAuto()) { // FIXME: If the containing block flow is perpendicular to our direction we need to use the available logical height instead. return adjustBorderBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, availableLogicalWidth, view())); } - if (logicalWidth.type() == MinContent) - return minPreferredLogicalWidth(); - if (logicalWidth.type() == MaxContent) - return maxPreferredLogicalWidth(); + if (logicalWidth.isIntrinsic()) + return computeIntrinsicLogicalWidthUsing(logicalWidth, availableLogicalWidth, borderAndPaddingLogicalWidth()); - RenderView* renderView = view(); - LayoutUnit marginStart = minimumValueForLength(styleToUse->marginStart(), availableLogicalWidth, renderView); - LayoutUnit marginEnd = minimumValueForLength(styleToUse->marginEnd(), availableLogicalWidth, renderView); - LayoutUnit logicalWidthResult = availableLogicalWidth - marginStart - marginEnd; + LayoutUnit marginStart = 0; + LayoutUnit marginEnd = 0; + LayoutUnit logicalWidthResult = fillAvailableMeasure(availableLogicalWidth, marginStart, marginEnd); - // shrinkToAvoidFloats() is only true for width: auto so the below code works correctly for - // width: fill-available since no case matches and it returns the logicalWidthResult from above. if (shrinkToAvoidFloats() && cb->containsFloats()) - logicalWidthResult = min(logicalWidthResult, shrinkLogicalWidthToAvoidFloats(marginStart, marginEnd, cb, region, offsetFromLogicalTopOfFirstPage)); + logicalWidthResult = min(logicalWidthResult, shrinkLogicalWidthToAvoidFloats(marginStart, marginEnd, cb, region)); - if (logicalWidth.type() == FitContent || (logicalWidth.type() != FillAvailable && sizesLogicalWidthToFitContent(widthType))) + if (widthType == MainOrPreferredSize && sizesLogicalWidthToFitContent(widthType)) return max(minPreferredLogicalWidth(), min(maxPreferredLogicalWidth(), logicalWidthResult)); return logicalWidthResult; } @@ -1938,7 +2315,7 @@ bool RenderBox::sizesLogicalWidthToFitContent(SizeType widthType) const // stretching column flexbox. // FIXME: Think about block-flow here. // https://bugs.webkit.org/show_bug.cgi?id=46473 - if (logicalWidth.type() == Auto && !isStretchingColumnFlexItem(this) && node() && (node()->hasTagName(inputTag) || node()->hasTagName(selectTag) || node()->hasTagName(buttonTag) || node()->hasTagName(textareaTag) || node()->hasTagName(legendTag))) + if (logicalWidth.type() == Auto && !isStretchingColumnFlexItem(this) && node() && (isHTMLInputElement(node()) || node()->hasTagName(selectTag) || node()->hasTagName(buttonTag) || isHTMLTextAreaElement(node()) || node()->hasTagName(legendTag))) return true; if (isHorizontalWritingMode() != containingBlock()->isHorizontalWritingMode()) @@ -1995,7 +2372,7 @@ void RenderBox::computeInlineDirectionMargins(RenderBlock* containingBlock, Layo marginEnd = minimumValueForLength(marginEndLength, containerWidth, renderView); } -RenderBoxRegionInfo* RenderBox::renderBoxRegionInfo(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage, RenderBoxRegionInfoFlags cacheFlag) const +RenderBoxRegionInfo* RenderBox::renderBoxRegionInfo(RenderRegion* region, RenderBoxRegionInfoFlags cacheFlag) const { // Make sure nobody is trying to call this with a null region. if (!region) @@ -2010,22 +2387,17 @@ RenderBoxRegionInfo* RenderBox::renderBoxRegionInfo(RenderRegion* region, Layout // No cached value was found, so we have to compute our insets in this region. // FIXME: For now we limit this computation to normal RenderBlocks. Future patches will expand // support to cover all boxes. - if (!inRenderFlowThread() || isFloating() || isReplaced() || isInline() || hasColumns() - || isTableCell() || !isBlockFlow() || isRenderFlowThread()) - return 0; - - RenderFlowThread* flowThread = enclosingRenderFlowThread(); - if (flowThread->style()->writingMode() != style()->writingMode()) + RenderFlowThread* flowThread = flowThreadContainingBlock(); + if (isRenderFlowThread() || !flowThread || !canHaveBoxInfoInRegion() || flowThread->style()->writingMode() != style()->writingMode()) return 0; LogicalExtentComputedValues computedValues; - computeLogicalWidthInRegion(computedValues, region, offsetFromLogicalTopOfFirstPage); + computeLogicalWidthInRegion(computedValues, region); // Now determine the insets based off where this object is supposed to be positioned. RenderBlock* cb = containingBlock(); RenderRegion* clampedContainingBlockRegion = cb->clampToStartAndEndRegions(region); - RenderBoxRegionInfo* containingBlockInfo = cb->renderBoxRegionInfo(clampedContainingBlockRegion, - offsetFromLogicalTopOfFirstPage - logicalTop()); + RenderBoxRegionInfo* containingBlockInfo = cb->renderBoxRegionInfo(clampedContainingBlockRegion); LayoutUnit containingBlockLogicalWidth = cb->logicalWidth(); LayoutUnit containingBlockLogicalWidthInRegion = containingBlockInfo ? containingBlockInfo->logicalWidth() : containingBlockLogicalWidth; @@ -2042,7 +2414,7 @@ RenderBoxRegionInfo* RenderBox::renderBoxRegionInfo(RenderRegion* region, Layout LayoutUnit logicalLeftOffset = 0; if (!isOutOfFlowPositioned() && avoidsFloats() && cb->containsFloats()) { - LayoutUnit startPositionDelta = cb->computeStartPositionDeltaForChildAvoidingFloats(this, marginStartInRegion, region, offsetFromLogicalTopOfFirstPage); + LayoutUnit startPositionDelta = cb->computeStartPositionDeltaForChildAvoidingFloats(this, marginStartInRegion, region); if (cb->style()->isLeftToRightDirection()) logicalLeftDelta += startPositionDelta; else @@ -2167,7 +2539,7 @@ void RenderBox::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logica LayoutUnit heightResult; if (checkMinMaxHeight) { - heightResult = computeLogicalHeightUsing(MainOrPreferredSize, style()->logicalHeight()); + heightResult = computeLogicalHeightUsing(style()->logicalHeight()); if (heightResult == -1) heightResult = computedValues.m_extent; heightResult = constrainLogicalHeightByMinMax(heightResult); @@ -2194,49 +2566,37 @@ void RenderBox::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logica // height since we don't set a height in RenderView when we're printing. So without this quirk, the // height has nothing to be a percentage of, and it ends up being 0. That is bad. bool paginatedContentNeedsBaseHeight = document()->printing() && h.isPercent() - && (isRoot() || (isBody() && document()->documentElement()->renderer()->style()->logicalHeight().isPercent())); + && (isRoot() || (isBody() && document()->documentElement()->renderer()->style()->logicalHeight().isPercent())) && !isInline(); if (stretchesToViewport() || paginatedContentNeedsBaseHeight) { - // FIXME: Finish accounting for block flow here. - // https://bugs.webkit.org/show_bug.cgi?id=46603 LayoutUnit margins = collapsedMarginBefore() + collapsedMarginAfter(); - LayoutUnit visHeight; - if (document()->printing()) - visHeight = static_cast<LayoutUnit>(view()->pageLogicalHeight()); - else { - if (isHorizontalWritingMode()) - visHeight = view()->viewHeight(); - else - visHeight = view()->viewWidth(); - } + LayoutUnit visibleHeight = view()->pageOrViewLogicalHeight(); if (isRoot()) - computedValues.m_extent = max(computedValues.m_extent, visHeight - margins); + computedValues.m_extent = max(computedValues.m_extent, visibleHeight - margins); else { LayoutUnit marginsBordersPadding = margins + parentBox()->marginBefore() + parentBox()->marginAfter() + parentBox()->borderAndPaddingLogicalHeight(); - computedValues.m_extent = max(computedValues.m_extent, visHeight - marginsBordersPadding); + computedValues.m_extent = max(computedValues.m_extent, visibleHeight - marginsBordersPadding); } } } -LayoutUnit RenderBox::computeLogicalHeightUsing(SizeType heightType, const Length& height) const +LayoutUnit RenderBox::computeLogicalHeightUsing(const Length& height) const { - LayoutUnit logicalHeight = computeContentAndScrollbarLogicalHeightUsing(heightType, height); + LayoutUnit logicalHeight = computeContentAndScrollbarLogicalHeightUsing(height); if (logicalHeight != -1) logicalHeight = adjustBorderBoxLogicalHeightForBoxSizing(logicalHeight); return logicalHeight; } -LayoutUnit RenderBox::computeContentLogicalHeight(SizeType heightType, const Length& height) +LayoutUnit RenderBox::computeContentLogicalHeight(const Length& height) const { - LayoutUnit heightIncludingScrollbar = computeContentAndScrollbarLogicalHeightUsing(heightType, height); + LayoutUnit heightIncludingScrollbar = computeContentAndScrollbarLogicalHeightUsing(height); if (heightIncludingScrollbar == -1) return -1; return std::max<LayoutUnit>(0, adjustContentBoxLogicalHeightForBoxSizing(heightIncludingScrollbar) - scrollbarLogicalHeight()); } -LayoutUnit RenderBox::computeContentAndScrollbarLogicalHeightUsing(SizeType heightType, const Length& height) const +LayoutUnit RenderBox::computeContentAndScrollbarLogicalHeightUsing(const Length& height) const { - if (height.isAuto()) - return heightType == MinSize ? 0 : -1; if (height.isFixed()) return height.value(); if (height.isPercent()) @@ -2276,9 +2636,7 @@ LayoutUnit RenderBox::computePercentageLogicalHeight(const Length& height) const // A positioned element that specified both top/bottom or that specifies height should be treated as though it has a height // explicitly specified that can be used for any percentage computations. - // FIXME: We can't just check top/bottom here. - // https://bugs.webkit.org/show_bug.cgi?id=46500 - bool isOutOfFlowPositionedWithSpecifiedHeight = cb->isOutOfFlowPositioned() && (!cbstyle->logicalHeight().isAuto() || (!cbstyle->top().isAuto() && !cbstyle->bottom().isAuto())); + bool isOutOfFlowPositionedWithSpecifiedHeight = cb->isOutOfFlowPositioned() && (!cbstyle->logicalHeight().isAuto() || (!cbstyle->logicalTop().isAuto() && !cbstyle->logicalBottom().isAuto())); bool includeBorderPadding = isTable(); @@ -2308,22 +2666,28 @@ LayoutUnit RenderBox::computePercentageLogicalHeight(const Length& height) const includeBorderPadding = true; } } else if (cbstyle->logicalHeight().isFixed()) { - LayoutUnit contentBoxHeightWithScrollbar = cb->adjustContentBoxLogicalHeightForBoxSizing(cbstyle->logicalHeight().value()); - availableHeight = max<LayoutUnit>(0, contentBoxHeightWithScrollbar - cb->scrollbarLogicalHeight()); + LayoutUnit contentBoxHeight = cb->adjustContentBoxLogicalHeightForBoxSizing(cbstyle->logicalHeight().value()); + availableHeight = max<LayoutUnit>(0, cb->constrainContentBoxLogicalHeightByMinMax(contentBoxHeight - cb->scrollbarLogicalHeight())); } else if (cbstyle->logicalHeight().isPercent() && !isOutOfFlowPositionedWithSpecifiedHeight) { // We need to recur and compute the percentage height for our containing block. LayoutUnit heightWithScrollbar = cb->computePercentageLogicalHeight(cbstyle->logicalHeight()); if (heightWithScrollbar != -1) { LayoutUnit contentBoxHeightWithScrollbar = cb->adjustContentBoxLogicalHeightForBoxSizing(heightWithScrollbar); - availableHeight = max<LayoutUnit>(0, contentBoxHeightWithScrollbar - cb->scrollbarLogicalHeight()); + // We need to adjust for min/max height because this method does not + // handle the min/max of the current block, its caller does. So the + // return value from the recursive call will not have been adjusted + // yet. + LayoutUnit contentBoxHeight = cb->constrainContentBoxLogicalHeightByMinMax(contentBoxHeightWithScrollbar - cb->scrollbarLogicalHeight()); + availableHeight = max<LayoutUnit>(0, contentBoxHeight); } - } else if (cb->isRenderView() || isOutOfFlowPositionedWithSpecifiedHeight) { + } else if (isOutOfFlowPositionedWithSpecifiedHeight) { // Don't allow this to affect the block' height() member variable, since this // can get called while the block is still laying out its kids. LogicalExtentComputedValues computedValues; cb->computeLogicalHeight(cb->logicalHeight(), 0, computedValues); availableHeight = computedValues.m_extent - cb->borderAndPaddingLogicalHeight() - cb->scrollbarLogicalHeight(); - } + } else if (cb->isRenderView()) + availableHeight = view()->pageOrViewLogicalHeight(); if (availableHeight == -1) return availableHeight; @@ -2342,30 +2706,36 @@ LayoutUnit RenderBox::computePercentageLogicalHeight(const Length& height) const return result; } -LayoutUnit RenderBox::computeReplacedLogicalWidth(bool includeMaxWidth) const +LayoutUnit RenderBox::computeReplacedLogicalWidth(ShouldComputePreferred shouldComputePreferred) const { - return computeReplacedLogicalWidthRespectingMinMaxWidth(computeReplacedLogicalWidthUsing(MainOrPreferredSize, style()->logicalWidth()), includeMaxWidth); + return computeReplacedLogicalWidthRespectingMinMaxWidth(computeReplacedLogicalWidthUsing(style()->logicalWidth()), shouldComputePreferred); } -LayoutUnit RenderBox::computeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUnit logicalWidth, bool includeMaxWidth) const +LayoutUnit RenderBox::computeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUnit logicalWidth, ShouldComputePreferred shouldComputePreferred) const { - LayoutUnit minLogicalWidth = computeReplacedLogicalWidthUsing(MinSize, style()->logicalMinWidth()); - LayoutUnit maxLogicalWidth = !includeMaxWidth || style()->logicalMaxWidth().isUndefined() ? logicalWidth : computeReplacedLogicalWidthUsing(MaxSize, style()->logicalMaxWidth()); + LayoutUnit minLogicalWidth = (shouldComputePreferred == ComputePreferred && style()->logicalMinWidth().isPercent()) || style()->logicalMinWidth().isUndefined() ? logicalWidth : computeReplacedLogicalWidthUsing(style()->logicalMinWidth()); + LayoutUnit maxLogicalWidth = (shouldComputePreferred == ComputePreferred && style()->logicalMaxWidth().isPercent()) || style()->logicalMaxWidth().isUndefined() ? logicalWidth : computeReplacedLogicalWidthUsing(style()->logicalMaxWidth()); return max(minLogicalWidth, min(logicalWidth, maxLogicalWidth)); } -LayoutUnit RenderBox::computeReplacedLogicalWidthUsing(SizeType sizeType, Length logicalWidth) const +LayoutUnit RenderBox::computeReplacedLogicalWidthUsing(Length logicalWidth) const { - if (sizeType == MinSize && logicalWidth.isAuto()) - return adjustContentBoxLogicalWidthForBoxSizing(0); - switch (logicalWidth.type()) { case Fixed: return adjustContentBoxLogicalWidthForBoxSizing(logicalWidth.value()); + case MinContent: + case MaxContent: { + // MinContent/MaxContent don't need the availableLogicalWidth argument. + LayoutUnit availableLogicalWidth = 0; + return computeIntrinsicLogicalWidthUsing(logicalWidth, availableLogicalWidth, borderAndPaddingLogicalWidth()) - borderAndPaddingLogicalWidth(); + } case ViewportPercentageWidth: case ViewportPercentageHeight: case ViewportPercentageMin: + case ViewportPercentageMax: return adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, 0, view())); + case FitContent: + case FillAvailable: case Percent: case Calculated: { // FIXME: containingBlockLogicalWidthForContent() is wrong if the replaced element's block-flow is perpendicular to the @@ -2375,32 +2745,38 @@ LayoutUnit RenderBox::computeReplacedLogicalWidthUsing(SizeType sizeType, Length Length containerLogicalWidth = containingBlock()->style()->logicalWidth(); // FIXME: Handle cases when containing block width is calculated or viewport percent. // https://bugs.webkit.org/show_bug.cgi?id=91071 + if (logicalWidth.isIntrinsic()) + return computeIntrinsicLogicalWidthUsing(logicalWidth, cw, borderAndPaddingLogicalWidth()) - borderAndPaddingLogicalWidth(); if (cw > 0 || (!cw && (containerLogicalWidth.isFixed() || containerLogicalWidth.isPercent()))) return adjustContentBoxLogicalWidthForBoxSizing(minimumValueForLength(logicalWidth, cw)); } // fall through - default: + case Intrinsic: + case MinIntrinsic: + case Auto: + case Relative: + case Undefined: return intrinsicLogicalWidth(); - } + } + + ASSERT_NOT_REACHED(); + return 0; } LayoutUnit RenderBox::computeReplacedLogicalHeight() const { - return computeReplacedLogicalHeightRespectingMinMaxHeight(computeReplacedLogicalHeightUsing(MainOrPreferredSize, style()->logicalHeight())); + return computeReplacedLogicalHeightRespectingMinMaxHeight(computeReplacedLogicalHeightUsing(style()->logicalHeight())); } LayoutUnit RenderBox::computeReplacedLogicalHeightRespectingMinMaxHeight(LayoutUnit logicalHeight) const { - LayoutUnit minLogicalHeight = computeReplacedLogicalHeightUsing(MinSize, style()->logicalMinHeight()); - LayoutUnit maxLogicalHeight = style()->logicalMaxHeight().isUndefined() ? logicalHeight : computeReplacedLogicalHeightUsing(MaxSize, style()->logicalMaxHeight()); + LayoutUnit minLogicalHeight = computeReplacedLogicalHeightUsing(style()->logicalMinHeight()); + LayoutUnit maxLogicalHeight = style()->logicalMaxHeight().isUndefined() ? logicalHeight : computeReplacedLogicalHeightUsing(style()->logicalMaxHeight()); return max(minLogicalHeight, min(logicalHeight, maxLogicalHeight)); } -LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(SizeType sizeType, Length logicalHeight) const +LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(Length logicalHeight) const { - if (sizeType == MinSize && logicalHeight.isAuto()) - return adjustContentBoxLogicalHeightForBoxSizing(0); - switch (logicalHeight.type()) { case Fixed: return adjustContentBoxLogicalHeightForBoxSizing(logicalHeight.value()); @@ -2416,7 +2792,7 @@ LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(SizeType sizeType, Lengt // FIXME: This calculation is not patched for block-flow yet. // https://bugs.webkit.org/show_bug.cgi?id=46500 if (cb->isOutOfFlowPositioned() && cb->style()->height().isAuto() && !(cb->style()->top().isAuto() || cb->style()->bottom().isAuto())) { - ASSERT(cb->isRenderBlock()); + ASSERT_WITH_SECURITY_IMPLICATION(cb->isRenderBlock()); RenderBlock* block = toRenderBlock(cb); LogicalExtentComputedValues computedValues; block->computeLogicalHeight(block->logicalHeight(), 0, computedValues); @@ -2432,7 +2808,7 @@ LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(SizeType sizeType, Lengt if (isOutOfFlowPositioned()) availableHeight = containingBlockLogicalHeightForPositioned(toRenderBoxModelObject(cb)); else { - availableHeight = containingBlockLogicalHeightForContent(); + availableHeight = containingBlockLogicalHeightForContent(IncludeMarginBorderPadding); // It is necessary to use the border-box to match WinIE's broken // box model. This is essential for sizing inside // table cells using percentage heights. @@ -2454,18 +2830,19 @@ LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(SizeType sizeType, Lengt case ViewportPercentageWidth: case ViewportPercentageHeight: case ViewportPercentageMin: + case ViewportPercentageMax: return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeight, 0, view())); default: return intrinsicLogicalHeight(); } } -LayoutUnit RenderBox::availableLogicalHeight() const +LayoutUnit RenderBox::availableLogicalHeight(AvailableLogicalHeightType heightType) const { - return availableLogicalHeightUsing(style()->logicalHeight()); + return constrainLogicalHeightByMinMax(availableLogicalHeightUsing(style()->logicalHeight(), heightType)); } -LayoutUnit RenderBox::availableLogicalHeightUsing(const Length& h) const +LayoutUnit RenderBox::availableLogicalHeightUsing(const Length& h, AvailableLogicalHeightType heightType) const { if (isRenderView()) return isHorizontalWritingMode() ? toRenderView(this)->frameView()->visibleHeight() : toRenderView(this)->frameView()->visibleWidth(); @@ -2479,13 +2856,13 @@ LayoutUnit RenderBox::availableLogicalHeightUsing(const Length& h) const return logicalHeight() - borderAndPaddingLogicalHeight(); } - if (h.isPercent() && isOutOfFlowPositioned()) { + if (h.isPercent() && isOutOfFlowPositioned() && !isRenderFlowThread()) { // FIXME: This is wrong if the containingBlock has a perpendicular writing mode. LayoutUnit availableHeight = containingBlockLogicalHeightForPositioned(containingBlock()); return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(h, availableHeight)); } - LayoutUnit heightIncludingScrollbar = computeContentAndScrollbarLogicalHeightUsing(MainOrPreferredSize, h); + LayoutUnit heightIncludingScrollbar = computeContentAndScrollbarLogicalHeightUsing(h); if (heightIncludingScrollbar != -1) return std::max<LayoutUnit>(0, adjustContentBoxLogicalHeightForBoxSizing(heightIncludingScrollbar) - scrollbarLogicalHeight()); @@ -2500,7 +2877,12 @@ LayoutUnit RenderBox::availableLogicalHeightUsing(const Length& h) const } // FIXME: This is wrong if the containingBlock has a perpendicular writing mode. - return containingBlockLogicalHeightForContent(); + LayoutUnit availableHeight = containingBlockLogicalHeightForContent(heightType); + if (heightType == ExcludeMarginBorderPadding) { + // FIXME: Margin collapsing hasn't happened yet, so this incorrectly removes collapsed margins. + availableHeight -= marginBefore() + marginAfter() + borderAndPaddingLogicalHeight(); + } + return availableHeight; } void RenderBox::computeBlockDirectionMargins(const RenderBlock* containingBlock, LayoutUnit& marginBefore, LayoutUnit& marginAfter) const @@ -2531,8 +2913,7 @@ void RenderBox::computeAndSetBlockDirectionMargins(const RenderBlock* containing containingBlock->setMarginAfterForChild(this, marginAfter); } -LayoutUnit RenderBox::containingBlockLogicalWidthForPositioned(const RenderBoxModelObject* containingBlock, RenderRegion* region, - LayoutUnit offsetFromLogicalTopOfFirstPage, bool checkForPerpendicularWritingMode) const +LayoutUnit RenderBox::containingBlockLogicalWidthForPositioned(const RenderBoxModelObject* containingBlock, RenderRegion* region, bool checkForPerpendicularWritingMode) const { // Container for position:fixed is the frame. Frame* frame = view() ? view()->frame(): 0; @@ -2544,29 +2925,28 @@ LayoutUnit RenderBox::containingBlockLogicalWidthForPositioned(const RenderBoxMo return containingBlockLogicalHeightForPositioned(containingBlock, false); if (containingBlock->isBox()) { + RenderFlowThread* flowThread = flowThreadContainingBlock(); + if (!flowThread) + return toRenderBox(containingBlock)->clientLogicalWidth(); + const RenderBlock* cb = toRenderBlock(containingBlock); - LayoutUnit result = cb->clientLogicalWidth(); - if (inRenderFlowThread()) { - RenderBoxRegionInfo* boxInfo = 0; - if (!region) { - if (containingBlock->isRenderFlowThread() && !checkForPerpendicularWritingMode) - return toRenderFlowThread(containingBlock)->contentLogicalWidthOfFirstRegion(); - if (isWritingModeRoot()) { - LayoutUnit cbPageOffset = offsetFromLogicalTopOfFirstPage - logicalTop(); - RenderRegion* cbRegion = cb->regionAtBlockOffset(cbPageOffset); - if (cbRegion) { - cbRegion = cb->clampToStartAndEndRegions(cbRegion); - boxInfo = cb->renderBoxRegionInfo(cbRegion, cbPageOffset); - } + RenderBoxRegionInfo* boxInfo = 0; + if (!region) { + if (containingBlock->isRenderFlowThread() && !checkForPerpendicularWritingMode) + return toRenderFlowThread(containingBlock)->contentLogicalWidthOfFirstRegion(); + if (isWritingModeRoot()) { + LayoutUnit cbPageOffset = cb->offsetFromLogicalTopOfFirstPage(); + RenderRegion* cbRegion = cb->regionAtBlockOffset(cbPageOffset); + if (cbRegion) { + cbRegion = cb->clampToStartAndEndRegions(cbRegion); + boxInfo = cb->renderBoxRegionInfo(cbRegion); } - } else if (region && enclosingRenderFlowThread()->isHorizontalWritingMode() == containingBlock->isHorizontalWritingMode()) { - RenderRegion* containingBlockRegion = cb->clampToStartAndEndRegions(region); - boxInfo = cb->renderBoxRegionInfo(containingBlockRegion, offsetFromLogicalTopOfFirstPage - logicalTop()); } - if (boxInfo) - return max<LayoutUnit>(0, result - (cb->logicalWidth() - boxInfo->logicalWidth())); + } else if (region && flowThread->isHorizontalWritingMode() == containingBlock->isHorizontalWritingMode()) { + RenderRegion* containingBlockRegion = cb->clampToStartAndEndRegions(region); + boxInfo = cb->renderBoxRegionInfo(containingBlockRegion); } - return result; + return (boxInfo) ? max<LayoutUnit>(0, cb->clientLogicalWidth() - (cb->logicalWidth() - boxInfo->logicalWidth())) : cb->clientLogicalWidth(); } ASSERT(containingBlock->isRenderInline() && containingBlock->isInFlowPositioned()); @@ -2600,12 +2980,13 @@ LayoutUnit RenderBox::containingBlockLogicalHeightForPositioned(const RenderBoxM return (view()->isHorizontalWritingMode() ? frameView->visibleHeight() : frameView->visibleWidth()) / frame->frameScaleFactor(); if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWritingMode() != isHorizontalWritingMode()) - return containingBlockLogicalWidthForPositioned(containingBlock, 0, 0, false); + return containingBlockLogicalWidthForPositioned(containingBlock, 0, false); if (containingBlock->isBox()) { const RenderBlock* cb = toRenderBlock(containingBlock); LayoutUnit result = cb->clientLogicalHeight(); - if (inRenderFlowThread() && containingBlock->isRenderFlowThread() && enclosingRenderFlowThread()->isHorizontalWritingMode() == containingBlock->isHorizontalWritingMode()) + RenderFlowThread* flowThread = flowThreadContainingBlock(); + if (flowThread && containingBlock->isRenderFlowThread() && flowThread->isHorizontalWritingMode() == containingBlock->isHorizontalWritingMode()) return toRenderFlowThread(containingBlock)->contentLogicalHeightOfFirstRegion(); return result; } @@ -2644,7 +3025,7 @@ static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRigh if (region && curr->isRenderBlock()) { const RenderBlock* cb = toRenderBlock(curr); region = cb->clampToStartAndEndRegions(region); - RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(region, region->logicalTopForFlowThreadContent()); + RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(region); if (boxInfo) staticPosition += boxInfo->logicalLeft(); } @@ -2661,10 +3042,10 @@ static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRigh if (curr == enclosingBox) staticPosition -= enclosingBox->logicalWidth(); if (region && curr->isRenderBlock()) { - const RenderBlock* cb = toRenderBlock(curr); - region = cb->clampToStartAndEndRegions(region); - RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(region, region->logicalTopForFlowThreadContent()); - if (boxInfo) { + const RenderBlock* cb = toRenderBlock(curr); + region = cb->clampToStartAndEndRegions(region); + RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(region); + if (boxInfo) { if (curr != containerBlock) staticPosition -= cb->logicalWidth() - (boxInfo->logicalLeft() + boxInfo->logicalWidth()); if (curr == enclosingBox) @@ -2679,17 +3060,13 @@ static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRigh } } -void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& computedValues, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const +void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& computedValues, RenderRegion* region) const { if (isReplaced()) { - // FIXME: For regions with width auto, we want to compute width using the normal block sizing code. - // For now, regions are replaced elements and this code can be removed once the RenderRegion - // will inherit from RenderBlock instead of RenderReplaced. - // (see https://bugs.webkit.org/show_bug.cgi?id=74132 ) - if (!isRenderRegion() || (isRenderRegion() && shouldComputeSizeAsReplaced())) { - computePositionedLogicalWidthReplaced(computedValues); // FIXME: Patch for regions when we add replaced element support. - return; - } + // FIXME: Positioned replaced elements inside a flow thread are not working properly + // with variable width regions (see https://bugs.webkit.org/show_bug.cgi?id=69896 ). + computePositionedLogicalWidthReplaced(computedValues); + return; } // QUESTIONS @@ -2712,7 +3089,7 @@ void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& compu // relative positioned inline. const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container()); - const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, region, offsetFromLogicalTopOfFirstPage); + const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, region); // Use the container block's direction except when calculating the static distance // This conforms with the reference results for abspos-replaced-width-margin-000.htm @@ -2756,7 +3133,7 @@ void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& compu computeInlineStaticDistance(logicalLeftLength, logicalRightLength, this, containerBlock, containerLogicalWidth, region); // Calculate constraint equation values for 'width' case. - computePositionedLogicalWidthUsing(MainOrPreferredSize, style()->logicalWidth(), containerBlock, containerDirection, + computePositionedLogicalWidthUsing(style()->logicalWidth(), containerBlock, containerDirection, containerLogicalWidth, bordersPlusPadding, logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight, computedValues); @@ -2765,7 +3142,7 @@ void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& compu if (!style()->logicalMaxWidth().isUndefined()) { LogicalExtentComputedValues maxValues; - computePositionedLogicalWidthUsing(MaxSize, style()->logicalMaxWidth(), containerBlock, containerDirection, + computePositionedLogicalWidthUsing(style()->logicalMaxWidth(), containerBlock, containerDirection, containerLogicalWidth, bordersPlusPadding, logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight, maxValues); @@ -2779,10 +3156,10 @@ void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& compu } // Calculate constraint equation values for 'min-width' case. - if (!style()->logicalMinWidth().isZero()) { + if (!style()->logicalMinWidth().isZero() || style()->logicalMinWidth().isIntrinsic()) { LogicalExtentComputedValues minValues; - computePositionedLogicalWidthUsing(MinSize, style()->logicalMinWidth(), containerBlock, containerDirection, + computePositionedLogicalWidthUsing(style()->logicalMinWidth(), containerBlock, containerDirection, containerLogicalWidth, bordersPlusPadding, logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight, minValues); @@ -2795,24 +3172,20 @@ void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& compu } } - if (stretchesToMinIntrinsicLogicalWidth() && computedValues.m_extent < minPreferredLogicalWidth() - bordersPlusPadding) { - computePositionedLogicalWidthUsing(MainOrPreferredSize, Length(minPreferredLogicalWidth() - bordersPlusPadding, Fixed), containerBlock, containerDirection, - containerLogicalWidth, bordersPlusPadding, - logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight, - computedValues); - } - computedValues.m_extent += bordersPlusPadding; // Adjust logicalLeft if we need to for the flipped version of our writing mode in regions. - if (inRenderFlowThread() && !region && isWritingModeRoot() && isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode()) { + // FIXME: Add support for other types of objects as containerBlock, not only RenderBlock. + RenderFlowThread* flowThread = flowThreadContainingBlock(); + if (flowThread && !region && isWritingModeRoot() && isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode() && containerBlock->isRenderBlock()) { + ASSERT(containerBlock->canHaveBoxInfoInRegion()); LayoutUnit logicalLeftPos = computedValues.m_position; const RenderBlock* cb = toRenderBlock(containerBlock); - LayoutUnit cbPageOffset = offsetFromLogicalTopOfFirstPage - logicalTop(); + LayoutUnit cbPageOffset = cb->offsetFromLogicalTopOfFirstPage(); RenderRegion* cbRegion = cb->regionAtBlockOffset(cbPageOffset); if (cbRegion) { cbRegion = cb->clampToStartAndEndRegions(cbRegion); - RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(cbRegion, cbPageOffset); + RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(cbRegion); if (boxInfo) { logicalLeftPos += boxInfo->logicalLeft(); computedValues.m_position = logicalLeftPos; @@ -2832,13 +3205,13 @@ static void computeLogicalLeftPositionedOffset(LayoutUnit& logicalLeftPos, const logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->borderLeft() : containerBlock->borderTop()); } -void RenderBox::computePositionedLogicalWidthUsing(SizeType widthSizeType, Length logicalWidth, const RenderBoxModelObject* containerBlock, TextDirection containerDirection, +void RenderBox::computePositionedLogicalWidthUsing(Length logicalWidth, const RenderBoxModelObject* containerBlock, TextDirection containerDirection, LayoutUnit containerLogicalWidth, LayoutUnit bordersPlusPadding, Length logicalLeft, Length logicalRight, Length marginLogicalLeft, Length marginLogicalRight, LogicalExtentComputedValues& computedValues) const { - if (widthSizeType == MinSize && logicalWidth.isAuto()) - logicalWidth = Length(0, Fixed); + if (logicalWidth.isIntrinsic()) + logicalWidth = Length(computeIntrinsicLogicalWidthUsing(logicalWidth, containerLogicalWidth, bordersPlusPadding) - bordersPlusPadding, Fixed); // 'left' and 'right' cannot both be 'auto' because one would of been // converted to the static position already @@ -2846,6 +3219,8 @@ void RenderBox::computePositionedLogicalWidthUsing(SizeType widthSizeType, Lengt LayoutUnit logicalLeftValue = 0; + const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, 0, false); + bool logicalWidthIsAuto = logicalWidth.isIntrinsicOrAuto(); bool logicalLeftIsAuto = logicalLeft.isAuto(); bool logicalRightIsAuto = logicalRight.isAuto(); @@ -2893,16 +3268,16 @@ void RenderBox::computePositionedLogicalWidthUsing(SizeType widthSizeType, Lengt } } else if (marginLogicalLeft.isAuto()) { // Solve for left margin - marginLogicalRightValue = valueForLength(marginLogicalRight, containerLogicalWidth, renderView); + marginLogicalRightValue = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView); marginLogicalLeftValue = availableSpace - marginLogicalRightValue; } else if (marginLogicalRight.isAuto()) { // Solve for right margin - marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerLogicalWidth, renderView); + marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView); marginLogicalRightValue = availableSpace - marginLogicalLeftValue; } else { // Over-constrained, solve for left if direction is RTL - marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerLogicalWidth, renderView); - marginLogicalRightValue = valueForLength(marginLogicalRight, containerLogicalWidth, renderView); + marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView); + marginLogicalRightValue = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView); // Use the containing block's direction rather than the parent block's // per CSS 2.1 reference test abspos-non-replaced-width-margin-000. @@ -2952,8 +3327,8 @@ void RenderBox::computePositionedLogicalWidthUsing(SizeType widthSizeType, Lengt // because the value is not used for any further calculations. // Calculate margins, 'auto' margins are ignored. - marginLogicalLeftValue = minimumValueForLength(marginLogicalLeft, containerLogicalWidth, renderView); - marginLogicalRightValue = minimumValueForLength(marginLogicalRight, containerLogicalWidth, renderView); + marginLogicalLeftValue = minimumValueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView); + marginLogicalRightValue = minimumValueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView); const LayoutUnit availableSpace = containerLogicalWidth - (marginLogicalLeftValue + marginLogicalRightValue + bordersPlusPadding); @@ -3030,14 +3405,8 @@ static void computeBlockStaticDistance(Length& logicalTop, Length& logicalBottom void RenderBox::computePositionedLogicalHeight(LogicalExtentComputedValues& computedValues) const { if (isReplaced()) { - // FIXME: For regions with height auto, we want to compute width using the normal block sizing code. - // For now, regions are replaced elements and this code can be removed once the RenderRegion - // will inherit from RenderBlock instead of RenderReplaced. - // (see https://bugs.webkit.org/show_bug.cgi?id=74132 ) - if (!isRenderRegion() || (isRenderRegion() && shouldComputeSizeAsReplaced())) { - computePositionedLogicalHeightReplaced(computedValues); - return; - } + computePositionedLogicalHeightReplaced(computedValues); + return; } // The following is based off of the W3C Working Draft from April 11, 2006 of @@ -3082,7 +3451,7 @@ void RenderBox::computePositionedLogicalHeight(LogicalExtentComputedValues& comp // Calculate constraint equation values for 'height' case. LayoutUnit logicalHeight = computedValues.m_extent; - computePositionedLogicalHeightUsing(MainOrPreferredSize, styleToUse->logicalHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight, + computePositionedLogicalHeightUsing(styleToUse->logicalHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight, logicalTopLength, logicalBottomLength, marginBefore, marginAfter, computedValues); @@ -3093,7 +3462,7 @@ void RenderBox::computePositionedLogicalHeight(LogicalExtentComputedValues& comp if (!styleToUse->logicalMaxHeight().isUndefined()) { LogicalExtentComputedValues maxValues; - computePositionedLogicalHeightUsing(MaxSize, styleToUse->logicalMaxHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight, + computePositionedLogicalHeightUsing(styleToUse->logicalMaxHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight, logicalTopLength, logicalBottomLength, marginBefore, marginAfter, maxValues); @@ -3109,7 +3478,7 @@ void RenderBox::computePositionedLogicalHeight(LogicalExtentComputedValues& comp if (!styleToUse->logicalMinHeight().isZero()) { LogicalExtentComputedValues minValues; - computePositionedLogicalHeightUsing(MinSize, styleToUse->logicalMinHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight, + computePositionedLogicalHeightUsing(styleToUse->logicalMinHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight, logicalTopLength, logicalBottomLength, marginBefore, marginAfter, minValues); @@ -3125,14 +3494,17 @@ void RenderBox::computePositionedLogicalHeight(LogicalExtentComputedValues& comp computedValues.m_extent += bordersPlusPadding; // Adjust logicalTop if we need to for perpendicular writing modes in regions. - if (inRenderFlowThread() && isHorizontalWritingMode() != containerBlock->isHorizontalWritingMode()) { + // FIXME: Add support for other types of objects as containerBlock, not only RenderBlock. + RenderFlowThread* flowThread = flowThreadContainingBlock(); + if (flowThread && isHorizontalWritingMode() != containerBlock->isHorizontalWritingMode() && containerBlock->isRenderBlock()) { + ASSERT(containerBlock->canHaveBoxInfoInRegion()); LayoutUnit logicalTopPos = computedValues.m_position; const RenderBlock* cb = toRenderBlock(containerBlock); LayoutUnit cbPageOffset = cb->offsetFromLogicalTopOfFirstPage() - logicalLeft(); RenderRegion* cbRegion = cb->regionAtBlockOffset(cbPageOffset); if (cbRegion) { cbRegion = cb->clampToStartAndEndRegions(cbRegion); - RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(cbRegion, cbPageOffset); + RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(cbRegion); if (boxInfo) { logicalTopPos += boxInfo->logicalLeft(); computedValues.m_position = logicalTopPos; @@ -3163,14 +3535,11 @@ static void computeLogicalTopPositionedOffset(LayoutUnit& logicalTopPos, const R } } -void RenderBox::computePositionedLogicalHeightUsing(SizeType heightSizeType, Length logicalHeightLength, const RenderBoxModelObject* containerBlock, +void RenderBox::computePositionedLogicalHeightUsing(Length logicalHeightLength, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalHeight, LayoutUnit bordersPlusPadding, LayoutUnit logicalHeight, Length logicalTop, Length logicalBottom, Length marginBefore, Length marginAfter, LogicalExtentComputedValues& computedValues) const { - if (heightSizeType == MinSize && logicalHeightLength.isAuto()) - logicalHeightLength = Length(0, Fixed); - // 'top' and 'bottom' cannot both be 'auto' because 'top would of been // converted to the static position in computePositionedLogicalHeight() ASSERT(!(logicalTop.isAuto() && logicalBottom.isAuto())); @@ -3178,6 +3547,8 @@ void RenderBox::computePositionedLogicalHeightUsing(SizeType heightSizeType, Len LayoutUnit logicalHeightValue; LayoutUnit contentLogicalHeight = logicalHeight - bordersPlusPadding; + const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, 0, false); + LayoutUnit logicalTopValue = 0; bool logicalHeightIsAuto = logicalHeightLength.isAuto(); @@ -3216,16 +3587,16 @@ void RenderBox::computePositionedLogicalHeightUsing(SizeType heightSizeType, Len computedValues.m_margins.m_after = availableSpace - computedValues.m_margins.m_before; // account for odd valued differences } else if (marginBefore.isAuto()) { // Solve for top margin - computedValues.m_margins.m_after = valueForLength(marginAfter, containerLogicalHeight, renderView); + computedValues.m_margins.m_after = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView); computedValues.m_margins.m_before = availableSpace - computedValues.m_margins.m_after; } else if (marginAfter.isAuto()) { // Solve for bottom margin - computedValues.m_margins.m_before = valueForLength(marginBefore, containerLogicalHeight, renderView); + computedValues.m_margins.m_before = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView); computedValues.m_margins.m_after = availableSpace - computedValues.m_margins.m_before; } else { // Over-constrained, (no need solve for bottom) - computedValues.m_margins.m_before = valueForLength(marginBefore, containerLogicalHeight, renderView); - computedValues.m_margins.m_after = valueForLength(marginAfter, containerLogicalHeight, renderView); + computedValues.m_margins.m_before = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView); + computedValues.m_margins.m_after = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView); } } else { /*--------------------------------------------------------------------*\ @@ -3254,8 +3625,8 @@ void RenderBox::computePositionedLogicalHeightUsing(SizeType heightSizeType, Len // because the value is not used for any further calculations. // Calculate margins, 'auto' margins are ignored. - computedValues.m_margins.m_before = minimumValueForLength(marginBefore, containerLogicalHeight, renderView); - computedValues.m_margins.m_after = minimumValueForLength(marginAfter, containerLogicalHeight, renderView); + computedValues.m_margins.m_before = minimumValueForLength(marginBefore, containerRelativeLogicalWidth, renderView); + computedValues.m_margins.m_after = minimumValueForLength(marginAfter, containerRelativeLogicalWidth, renderView); const LayoutUnit availableSpace = containerLogicalHeight - (computedValues.m_margins.m_before + computedValues.m_margins.m_after + bordersPlusPadding); @@ -3302,6 +3673,7 @@ void RenderBox::computePositionedLogicalWidthReplaced(LogicalExtentComputedValue const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container()); const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock); + const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, 0, false); // To match WinIE, in quirks mode use the parent's 'direction' property // instead of the the container block's. @@ -3386,28 +3758,28 @@ void RenderBox::computePositionedLogicalWidthReplaced(LogicalExtentComputedValue * that value. \*-----------------------------------------------------------------------*/ } else if (logicalLeft.isAuto()) { - marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerLogicalWidth, renderView); - marginLogicalRightAlias = valueForLength(marginLogicalRight, containerLogicalWidth, renderView); + marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView); + marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView); logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView); // Solve for 'left' logicalLeftValue = availableSpace - (logicalRightValue + marginLogicalLeftAlias + marginLogicalRightAlias); } else if (logicalRight.isAuto()) { - marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerLogicalWidth, renderView); - marginLogicalRightAlias = valueForLength(marginLogicalRight, containerLogicalWidth, renderView); + marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView); + marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView); logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView); // Solve for 'right' logicalRightValue = availableSpace - (logicalLeftValue + marginLogicalLeftAlias + marginLogicalRightAlias); } else if (marginLogicalLeft.isAuto()) { - marginLogicalRightAlias = valueForLength(marginLogicalRight, containerLogicalWidth, renderView); + marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView); logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView); logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView); // Solve for 'margin-left' marginLogicalLeftAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalRightAlias); } else if (marginLogicalRight.isAuto()) { - marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerLogicalWidth, renderView); + marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView); logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView); logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView); @@ -3415,8 +3787,8 @@ void RenderBox::computePositionedLogicalWidthReplaced(LogicalExtentComputedValue marginLogicalRightAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalLeftAlias); } else { // Nothing is 'auto', just calculate the values. - marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerLogicalWidth, renderView); - marginLogicalRightAlias = valueForLength(marginLogicalRight, containerLogicalWidth, renderView); + marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView); + marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView); logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView); logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView); // If the containing block is right-to-left, then push the left position as far to the right as possible @@ -3470,6 +3842,7 @@ void RenderBox::computePositionedLogicalHeightReplaced(LogicalExtentComputedValu const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container()); const LayoutUnit containerLogicalHeight = containingBlockLogicalHeightForPositioned(containerBlock); + const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, 0, false); // Variables to solve. Length marginBefore = style()->marginBefore(); @@ -3536,29 +3909,29 @@ void RenderBox::computePositionedLogicalHeightReplaced(LogicalExtentComputedValu * for that value. \*-----------------------------------------------------------------------*/ } else if (logicalTop.isAuto()) { - marginBeforeAlias = valueForLength(marginBefore, containerLogicalHeight, renderView); - marginAfterAlias = valueForLength(marginAfter, containerLogicalHeight, renderView); + marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView); + marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView); logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight, renderView); // Solve for 'top' logicalTopValue = availableSpace - (logicalBottomValue + marginBeforeAlias + marginAfterAlias); } else if (logicalBottom.isAuto()) { - marginBeforeAlias = valueForLength(marginBefore, containerLogicalHeight, renderView); - marginAfterAlias = valueForLength(marginAfter, containerLogicalHeight, renderView); + marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView); + marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView); logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView); // Solve for 'bottom' // NOTE: It is not necessary to solve for 'bottom' because we don't ever // use the value. } else if (marginBefore.isAuto()) { - marginAfterAlias = valueForLength(marginAfter, containerLogicalHeight, renderView); + marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView); logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView); logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight, renderView); // Solve for 'margin-top' marginBeforeAlias = availableSpace - (logicalTopValue + logicalBottomValue + marginAfterAlias); } else if (marginAfter.isAuto()) { - marginBeforeAlias = valueForLength(marginBefore, containerLogicalHeight, renderView); + marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView); logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView); logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight, renderView); @@ -3566,8 +3939,8 @@ void RenderBox::computePositionedLogicalHeightReplaced(LogicalExtentComputedValu marginAfterAlias = availableSpace - (logicalTopValue + logicalBottomValue + marginBeforeAlias); } else { // Nothing is 'auto', just calculate the values. - marginBeforeAlias = valueForLength(marginBefore, containerLogicalHeight, renderView); - marginAfterAlias = valueForLength(marginAfter, containerLogicalHeight, renderView); + marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView); + marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView); logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView); // NOTE: It is not necessary to solve for 'bottom' because we don't ever // use the value. @@ -3594,7 +3967,6 @@ LayoutRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, LayoutUnit // They never refer to children. // FIXME: Paint the carets inside empty blocks differently than the carets before/after elements. - // FIXME: What about border and padding? LayoutRect rect(location(), LayoutSize(caretWidth, height())); bool ltr = box ? box->isLeftToRightDirection() : style()->isLeftToRightDirection(); @@ -3626,6 +3998,14 @@ LayoutRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, LayoutUnit // Move to local coords rect.moveBy(-location()); + // FIXME: Border/padding should be added for all elements but this workaround + // is needed because we use offsets inside an "atomic" element to represent + // positions before and after the element in deprecated editing offsets. + if (node() && !(editingIgnoresContent(node()) || isTableElement(node()))) { + rect.setX(rect.x() + borderLeft() + paddingLeft()); + rect.setY(rect.y() + paddingTop() + borderTop()); + } + if (!isHorizontalWritingMode()) return rect.transposedRect(); @@ -3636,16 +4016,16 @@ VisiblePosition RenderBox::positionForPoint(const LayoutPoint& point) { // no children...return this render object's element, if there is one, and offset 0 if (!firstChild()) - return createVisiblePosition(node() ? firstPositionInOrBeforeNode(node()) : Position()); + return createVisiblePosition(nonPseudoNode() ? firstPositionInOrBeforeNode(nonPseudoNode()) : Position()); - if (isTable() && node()) { + if (isTable() && nonPseudoNode()) { LayoutUnit right = contentWidth() + borderAndPaddingWidth(); LayoutUnit bottom = contentHeight() + borderAndPaddingHeight(); if (point.x() < 0 || point.x() > right || point.y() < 0 || point.y() > bottom) { if (point.x() <= right / 2) - return createVisiblePosition(firstPositionInOrBeforeNode(node())); - return createVisiblePosition(lastPositionInOrAfterNode(node())); + return createVisiblePosition(firstPositionInOrBeforeNode(nonPseudoNode())); + return createVisiblePosition(lastPositionInOrAfterNode(nonPseudoNode())); } } @@ -3713,7 +4093,7 @@ VisiblePosition RenderBox::positionForPoint(const LayoutPoint& point) if (closestRenderer) return closestRenderer->positionForPoint(adjustedPoint - closestRenderer->locationOffset()); - return createVisiblePosition(firstPositionInOrBeforeNode(node())); + return createVisiblePosition(firstPositionInOrBeforeNode(nonPseudoNode())); } bool RenderBox::shrinkToAvoidFloats() const @@ -3728,7 +4108,7 @@ bool RenderBox::shrinkToAvoidFloats() const bool RenderBox::avoidsFloats() const { - return isReplaced() || hasOverflowClip() || isHR() || isLegend() || isWritingModeRoot() || isDeprecatedFlexItem(); + return isReplaced() || hasOverflowClip() || isHR() || isLegend() || isWritingModeRoot() || isFlexItemIncludingDeprecated(); } void RenderBox::addVisualEffectOverflow() @@ -3778,6 +4158,10 @@ void RenderBox::addVisualEffectOverflow() void RenderBox::addOverflowFromChild(RenderBox* child, const LayoutSize& delta) { + // Never allow flow threads to propagate overflow up to a parent. + if (child->isRenderFlowThread()) + return; + // Only propagate layout overflow from the child if the child isn't clipping its overflow. If it is, then // its overflow is internal to it, and we don't care about it. layoutOverflowRectForPropagation takes care of this // and just propagates the border box rect instead. @@ -3810,7 +4194,7 @@ void RenderBox::addLayoutOverflow(const LayoutRect& rect) bool hasTopOverflow = !style()->isLeftToRightDirection() && !isHorizontalWritingMode(); bool hasLeftOverflow = !style()->isLeftToRightDirection() && isHorizontalWritingMode(); if (isFlexibleBox() && style()->isReverseFlexDirection()) { - RenderFlexibleBox* flexibleBox = static_cast<RenderFlexibleBox*>(this); + RenderFlexibleBox* flexibleBox = toRenderFlexibleBox(this); if (flexibleBox->isHorizontalFlow()) hasLeftOverflow = true; else @@ -3857,19 +4241,6 @@ void RenderBox::addVisualOverflow(const LayoutRect& rect) m_overflow->addVisualOverflow(rect); } -void RenderBox::clearLayoutOverflow() -{ - if (!m_overflow) - return; - - if (visualOverflowRect() == borderBoxRect()) { - m_overflow.clear(); - return; - } - - m_overflow->setLayoutOverflow(borderBoxRect()); -} - inline static bool percentageLogicalHeightIsResolvable(const RenderBox* box) { return RenderBox::percentageLogicalHeightIsResolvableFromBlock(box->containingBlock(), box->isOutOfFlowPositioned()); @@ -4168,6 +4539,13 @@ bool RenderBox::hasRelativeLogicalHeight() const || style()->logicalMaxHeight().isPercent(); } +bool RenderBox::hasViewportPercentageLogicalHeight() const +{ + return style()->logicalHeight().isViewportPercentage() + || style()->logicalMinHeight().isViewportPercentage() + || style()->logicalMaxHeight().isViewportPercentage(); +} + static void markBoxForRelayoutAfterSplit(RenderBox* box) { // FIXME: The table code should handle that automatically. If not, @@ -4218,4 +4596,14 @@ RenderObject* RenderBox::splitAnonymousBoxesAroundChild(RenderObject* beforeChil return beforeChild; } +LayoutUnit RenderBox::offsetFromLogicalTopOfFirstPage() const +{ + LayoutState* layoutState = view()->layoutState(); + if ((layoutState && !layoutState->isPaginated()) || (!layoutState && !flowThreadContainingBlock())) + return 0; + + RenderBlock* containerBlock = containingBlock(); + return containerBlock->offsetFromLogicalTopOfFirstPage() + logicalTop(); +} + } // namespace WebCore |
