2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
5 * (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com)
6 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
7 * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public License
20 * along with this library; see the file COPYING.LIB. If not, write to
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
27 #include "core/rendering/RenderBox.h"
31 #include "HTMLNames.h"
32 #include "core/dom/Document.h"
33 #include "core/editing/htmlediting.h"
34 #include "core/frame/FrameView.h"
35 #include "core/frame/LocalFrame.h"
36 #include "core/html/HTMLElement.h"
37 #include "core/html/HTMLFrameElementBase.h"
38 #include "core/html/HTMLFrameOwnerElement.h"
39 #include "core/page/AutoscrollController.h"
40 #include "core/page/EventHandler.h"
41 #include "core/page/Page.h"
42 #include "core/rendering/HitTestResult.h"
43 #include "core/rendering/LayoutRectRecorder.h"
44 #include "core/rendering/PaintInfo.h"
45 #include "core/rendering/RenderDeprecatedFlexibleBox.h"
46 #include "core/rendering/RenderFlexibleBox.h"
47 #include "core/rendering/RenderGeometryMap.h"
48 #include "core/rendering/RenderGrid.h"
49 #include "core/rendering/RenderInline.h"
50 #include "core/rendering/RenderLayer.h"
51 #include "core/rendering/RenderListMarker.h"
52 #include "core/rendering/RenderTableCell.h"
53 #include "core/rendering/RenderTheme.h"
54 #include "core/rendering/RenderView.h"
55 #include "core/rendering/compositing/RenderLayerCompositor.h"
56 #include "platform/LengthFunctions.h"
57 #include "platform/geometry/FloatQuad.h"
58 #include "platform/geometry/TransformState.h"
59 #include "platform/graphics/GraphicsContextStateSaver.h"
65 using namespace HTMLNames;
67 // Used by flexible boxes when flexing this element and by table cells.
68 typedef WTF::HashMap<const RenderBox*, LayoutUnit> OverrideSizeMap;
70 // Used by grid elements to properly size their grid items.
71 // FIXME: Move these into RenderBoxRareData.
72 static OverrideSizeMap* gOverrideContainingBlockLogicalHeightMap = 0;
73 static OverrideSizeMap* gOverrideContainingBlockLogicalWidthMap = 0;
76 // Size of border belt for autoscroll. When mouse pointer in border belt,
77 // autoscroll is started.
78 static const int autoscrollBeltSize = 20;
79 static const unsigned backgroundObscurationTestMaxDepth = 4;
81 static bool skipBodyBackground(const RenderBox* bodyElementRenderer)
83 ASSERT(bodyElementRenderer->isBody());
84 // The <body> only paints its background if the root element has defined a background independent of the body,
85 // or if the <body>'s parent is not the document element's renderer (e.g. inside SVG foreignObject).
86 RenderObject* documentElementRenderer = bodyElementRenderer->document().documentElement()->renderer();
87 return documentElementRenderer
88 && !documentElementRenderer->hasBackground()
89 && (documentElementRenderer == bodyElementRenderer->parent());
92 RenderBox::RenderBox(ContainerNode* node)
93 : RenderBoxModelObject(node)
94 , m_intrinsicContentLogicalHeight(-1)
95 , m_minPreferredLogicalWidth(-1)
96 , m_maxPreferredLogicalWidth(-1)
101 void RenderBox::willBeDestroyed()
104 clearContainingBlockOverrideSize();
106 RenderBlock::removePercentHeightDescendantIfNeeded(this);
108 ShapeOutsideInfo::removeInfo(*this);
110 RenderBoxModelObject::willBeDestroyed();
113 void RenderBox::removeFloatingOrPositionedChildFromBlockLists()
115 ASSERT(isFloatingOrOutOfFlowPositioned());
117 if (documentBeingDestroyed())
121 RenderBlockFlow* parentBlockFlow = 0;
122 for (RenderObject* curr = parent(); curr && !curr->isRenderView(); curr = curr->parent()) {
123 if (curr->isRenderBlockFlow()) {
124 RenderBlockFlow* currBlockFlow = toRenderBlockFlow(curr);
125 if (!parentBlockFlow || currBlockFlow->containsFloat(this))
126 parentBlockFlow = currBlockFlow;
130 if (parentBlockFlow) {
131 parentBlockFlow->markSiblingsWithFloatsForLayout(this);
132 parentBlockFlow->markAllDescendantsWithFloatsForLayout(this, false);
136 if (isOutOfFlowPositioned())
137 RenderBlock::removePositionedObject(this);
140 void RenderBox::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
142 RenderStyle* oldStyle = style();
144 // The background of the root element or the body element could propagate up to
145 // the canvas. Just dirty the entire canvas when our style changes substantially.
146 if (diff >= StyleDifferenceRepaint && node() &&
147 (isHTMLHtmlElement(*node()) || isHTMLBodyElement(*node()))) {
149 if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled() || diff != StyleDifferenceLayout)
152 if (oldStyle->hasEntirelyFixedBackground() != newStyle->hasEntirelyFixedBackground())
153 view()->compositor()->rootFixedBackgroundsChanged();
156 // When a layout hint happens and an object's position style changes, we have to do a layout
157 // to dirty the render tree using the old position value now.
158 if (diff == StyleDifferenceLayout && parent() && oldStyle->position() != newStyle->position()) {
159 markContainingBlocksForLayout();
160 if (oldStyle->position() == StaticPosition)
162 else if (newStyle->hasOutOfFlowPosition())
163 parent()->setChildNeedsLayout();
164 if (isFloating() && !isOutOfFlowPositioned() && newStyle->hasOutOfFlowPosition())
165 removeFloatingOrPositionedChildFromBlockLists();
167 } else if (newStyle && isBody())
170 RenderBoxModelObject::styleWillChange(diff, newStyle);
173 void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
175 // Horizontal writing mode definition is updated in RenderBoxModelObject::updateFromStyle,
176 // (as part of the RenderBoxModelObject::styleDidChange call below). So, we can safely cache the horizontal
177 // writing mode value before style change here.
178 bool oldHorizontalWritingMode = isHorizontalWritingMode();
180 RenderBoxModelObject::styleDidChange(diff, oldStyle);
182 RenderStyle* newStyle = style();
183 if (needsLayout() && oldStyle) {
184 RenderBlock::removePercentHeightDescendantIfNeeded(this);
186 // Normally we can do optimized positioning layout for absolute/fixed positioned objects. There is one special case, however, which is
187 // when the positioned object's margin-before is changed. In this case the parent has to get a layout in order to run margin collapsing
188 // to determine the new static position.
189 if (isOutOfFlowPositioned() && newStyle->hasStaticBlockPosition(isHorizontalWritingMode()) && oldStyle->marginBefore() != newStyle->marginBefore()
190 && parent() && !parent()->normalChildNeedsLayout())
191 parent()->setChildNeedsLayout();
194 if (RenderBlock::hasPercentHeightContainerMap() && firstChild()
195 && oldHorizontalWritingMode != isHorizontalWritingMode())
196 RenderBlock::clearPercentHeightDescendantsFrom(this);
198 // If our zoom factor changes and we have a defined scrollLeft/Top, we need to adjust that value into the
199 // new zoomed coordinate space.
200 if (hasOverflowClip() && oldStyle && newStyle && oldStyle->effectiveZoom() != newStyle->effectiveZoom() && layer()) {
201 if (int left = layer()->scrollableArea()->scrollXOffset()) {
202 left = (left / oldStyle->effectiveZoom()) * newStyle->effectiveZoom();
203 layer()->scrollableArea()->scrollToXOffset(left);
205 if (int top = layer()->scrollableArea()->scrollYOffset()) {
206 top = (top / oldStyle->effectiveZoom()) * newStyle->effectiveZoom();
207 layer()->scrollableArea()->scrollToYOffset(top);
211 // Our opaqueness might have changed without triggering layout.
212 if (diff == StyleDifferenceRepaint || diff == StyleDifferenceRepaintIfTextOrColorChange || diff == StyleDifferenceRepaintLayer) {
213 RenderObject* parentToInvalidate = parent();
214 for (unsigned i = 0; i < backgroundObscurationTestMaxDepth && parentToInvalidate; ++i) {
215 parentToInvalidate->invalidateBackgroundObscurationStatus();
216 parentToInvalidate = parentToInvalidate->parent();
220 if (isRoot() || isBody())
221 document().view()->recalculateScrollbarOverlayStyle();
223 updateShapeOutsideInfoAfterStyleChange(*style(), oldStyle);
224 updateGridPositionAfterStyleChange(oldStyle);
227 void RenderBox::updateShapeOutsideInfoAfterStyleChange(const RenderStyle& style, const RenderStyle* oldStyle)
229 const ShapeValue* shapeOutside = style.shapeOutside();
230 const ShapeValue* oldShapeOutside = oldStyle ? oldStyle->shapeOutside() : RenderStyle::initialShapeOutside();
232 Length shapeMargin = style.shapeMargin();
233 Length oldShapeMargin = oldStyle ? oldStyle->shapeMargin() : RenderStyle::initialShapeMargin();
235 float shapeImageThreshold = style.shapeImageThreshold();
236 float oldShapeImageThreshold = oldStyle ? oldStyle->shapeImageThreshold() : RenderStyle::initialShapeImageThreshold();
238 // FIXME: A future optimization would do a deep comparison for equality. (bug 100811)
239 if (shapeOutside == oldShapeOutside && shapeMargin == oldShapeMargin && shapeImageThreshold == oldShapeImageThreshold)
243 ShapeOutsideInfo::removeInfo(*this);
245 ShapeOutsideInfo::ensureInfo(*this).markShapeAsDirty();
247 if (shapeOutside || shapeOutside != oldShapeOutside)
248 markShapeOutsideDependentsForLayout();
251 void RenderBox::updateGridPositionAfterStyleChange(const RenderStyle* oldStyle)
253 if (!oldStyle || !parent() || !parent()->isRenderGrid())
256 if (oldStyle->gridColumnStart() == style()->gridColumnStart()
257 && oldStyle->gridColumnEnd() == style()->gridColumnEnd()
258 && oldStyle->gridRowStart() == style()->gridRowStart()
259 && oldStyle->gridRowEnd() == style()->gridRowEnd()
260 && oldStyle->order() == style()->order()
261 && oldStyle->hasOutOfFlowPosition() == style()->hasOutOfFlowPosition())
264 // It should be possible to not dirty the grid in some cases (like moving an explicitly placed grid item).
265 // For now, it's more simple to just always recompute the grid.
266 toRenderGrid(parent())->dirtyGrid();
269 void RenderBox::updateFromStyle()
271 RenderBoxModelObject::updateFromStyle();
273 RenderStyle* styleToUse = style();
274 bool isRootObject = isRoot();
275 bool isViewObject = isRenderView();
277 // The root and the RenderView always paint their backgrounds/borders.
278 if (isRootObject || isViewObject)
279 setHasBoxDecorations(true);
281 setFloating(!isOutOfFlowPositioned() && styleToUse->isFloating());
283 bool boxHasOverflowClip = false;
284 if (!styleToUse->isOverflowVisible() && isRenderBlock() && !isViewObject) {
285 // If overflow has been propagated to the viewport, it has no effect here.
286 if (node() != document().viewportDefiningElement()) {
287 boxHasOverflowClip = true;
288 if (!hasOverflowClip()) {
289 // If we are getting an overflow clip, preemptively erase any overflowing content.
290 // FIXME: This should probably consult RenderOverflow.
291 if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled())
297 if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && (boxHasOverflowClip != hasOverflowClip())) {
298 // FIXME: This shouldn't be required if we tracked the visual overflow
299 // generated by positioned children or self painting layers. crbug.com/345403
300 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
301 LayoutRectRecorder childRecorder(*child);
302 child->setShouldDoFullRepaintIfSelfPaintingLayer(true);
306 setHasOverflowClip(boxHasOverflowClip);
308 setHasTransform(styleToUse->hasTransformRelatedProperty());
309 setHasReflection(styleToUse->boxReflect());
312 void RenderBox::layout()
314 ASSERT(needsLayout());
316 LayoutRectRecorder recorder(*this);
318 RenderObject* child = firstChild();
324 LayoutStateMaintainer statePusher(*this, locationOffset());
326 child->layoutIfNeeded();
327 ASSERT(!child->needsLayout());
328 child = child->nextSibling();
330 invalidateBackgroundObscurationStatus();
334 // More IE extensions. clientWidth and clientHeight represent the interior of an object
335 // excluding border and scrollbar.
336 LayoutUnit RenderBox::clientWidth() const
338 return width() - borderLeft() - borderRight() - verticalScrollbarWidth();
341 LayoutUnit RenderBox::clientHeight() const
343 return height() - borderTop() - borderBottom() - horizontalScrollbarHeight();
346 int RenderBox::pixelSnappedClientWidth() const
348 return snapSizeToPixel(clientWidth(), x() + clientLeft());
351 int RenderBox::pixelSnappedClientHeight() const
353 return snapSizeToPixel(clientHeight(), y() + clientTop());
356 int RenderBox::pixelSnappedOffsetWidth() const
358 return snapSizeToPixel(offsetWidth(), x() + clientLeft());
361 int RenderBox::pixelSnappedOffsetHeight() const
363 return snapSizeToPixel(offsetHeight(), y() + clientTop());
366 bool RenderBox::canDetermineWidthWithoutLayout() const
368 // FIXME: Remove function and callers.
372 LayoutUnit RenderBox::fixedOffsetWidth() const
374 ASSERT(canDetermineWidthWithoutLayout());
376 RenderStyle* style = this->style();
378 LayoutUnit width = std::max(LayoutUnit(style->minWidth().value()), LayoutUnit(style->width().value()));
379 if (style->maxWidth().isFixed())
380 width = std::min(LayoutUnit(style->maxWidth().value()), width);
382 LayoutUnit borderLeft = style->borderLeft().nonZero() ? style->borderLeft().width() : 0;
383 LayoutUnit borderRight = style->borderRight().nonZero() ? style->borderRight().width() : 0;
385 return width + borderLeft + borderRight + style->paddingLeft().value() + style->paddingRight().value();
388 int RenderBox::scrollWidth() const
390 if (hasOverflowClip())
391 return layer()->scrollableArea()->scrollWidth();
392 // For objects with visible overflow, this matches IE.
393 // FIXME: Need to work right with writing modes.
394 if (style()->isLeftToRightDirection())
395 return snapSizeToPixel(max(clientWidth(), layoutOverflowRect().maxX() - borderLeft()), x() + clientLeft());
396 return clientWidth() - min<LayoutUnit>(0, layoutOverflowRect().x() - borderLeft());
399 int RenderBox::scrollHeight() const
401 if (hasOverflowClip())
402 return layer()->scrollableArea()->scrollHeight();
403 // For objects with visible overflow, this matches IE.
404 // FIXME: Need to work right with writing modes.
405 return snapSizeToPixel(max(clientHeight(), layoutOverflowRect().maxY() - borderTop()), y() + clientTop());
408 int RenderBox::scrollLeft() const
410 return hasOverflowClip() ? layer()->scrollableArea()->scrollXOffset() : 0;
413 int RenderBox::scrollTop() const
415 return hasOverflowClip() ? layer()->scrollableArea()->scrollYOffset() : 0;
418 void RenderBox::setScrollLeft(int newLeft)
420 // This doesn't hit in any tests, but since the equivalent code in setScrollTop
421 // does, presumably this code does as well.
422 DisableCompositingQueryAsserts disabler;
424 if (hasOverflowClip())
425 layer()->scrollableArea()->scrollToXOffset(newLeft, ScrollOffsetClamped);
428 void RenderBox::setScrollTop(int newTop)
430 // Hits in compositing/overflow/do-not-assert-on-invisible-composited-layers.html
431 DisableCompositingQueryAsserts disabler;
433 if (hasOverflowClip())
434 layer()->scrollableArea()->scrollToYOffset(newTop, ScrollOffsetClamped);
437 void RenderBox::scrollToOffset(const IntSize& offset)
439 ASSERT(hasOverflowClip());
441 // This doesn't hit in any tests, but since the equivalent code in setScrollTop
442 // does, presumably this code does as well.
443 DisableCompositingQueryAsserts disabler;
444 layer()->scrollableArea()->scrollToOffset(offset, ScrollOffsetClamped);
447 static inline bool frameElementAndViewPermitScroll(HTMLFrameElementBase* frameElementBase, FrameView* frameView)
449 // If scrollbars aren't explicitly forbidden, permit scrolling.
450 if (frameElementBase && frameElementBase->scrollingMode() != ScrollbarAlwaysOff)
453 // If scrollbars are forbidden, user initiated scrolls should obviously be ignored.
454 if (frameView->wasScrolledByUser())
457 // Forbid autoscrolls when scrollbars are off, but permits other programmatic scrolls,
458 // like navigation to an anchor.
459 Page* page = frameView->frame().page();
462 return !page->autoscrollController().autoscrollInProgress();
465 void RenderBox::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
467 // Presumably the same issue as in setScrollTop. See crbug.com/343132.
468 DisableCompositingQueryAsserts disabler;
470 RenderBox* parentBox = 0;
471 LayoutRect newRect = rect;
473 bool restrictedByLineClamp = false;
475 parentBox = parent()->enclosingBox();
476 restrictedByLineClamp = !parent()->style()->lineClamp().isNone();
479 if (hasOverflowClip() && !restrictedByLineClamp) {
480 // Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property.
481 // This will prevent us from revealing text hidden by the slider in Safari RSS.
482 newRect = layer()->scrollableArea()->exposeRect(rect, alignX, alignY);
483 } else if (!parentBox && canBeProgramaticallyScrolled()) {
484 if (FrameView* frameView = this->frameView()) {
485 Element* ownerElement = document().ownerElement();
487 if (ownerElement && ownerElement->renderer()) {
488 HTMLFrameElementBase* frameElementBase = 0;
490 if (isHTMLFrameElement(*ownerElement) || isHTMLIFrameElement(*ownerElement))
491 frameElementBase = toHTMLFrameElementBase(ownerElement);
493 if (frameElementAndViewPermitScroll(frameElementBase, frameView)) {
494 LayoutRect viewRect = frameView->visibleContentRect();
495 LayoutRect exposeRect = ScrollAlignment::getRectToExpose(viewRect, rect, alignX, alignY);
497 int xOffset = roundToInt(exposeRect.x());
498 int yOffset = roundToInt(exposeRect.y());
499 // Adjust offsets if they're outside of the allowable range.
500 xOffset = max(0, min(frameView->contentsWidth(), xOffset));
501 yOffset = max(0, min(frameView->contentsHeight(), yOffset));
503 frameView->setScrollPosition(IntPoint(xOffset, yOffset));
504 if (frameView->safeToPropagateScrollToParent()) {
505 parentBox = ownerElement->renderer()->enclosingBox();
506 // FIXME: This doesn't correctly convert the rect to
507 // absolute coordinates in the parent.
508 newRect.setX(rect.x() - frameView->scrollX() + frameView->x());
509 newRect.setY(rect.y() - frameView->scrollY() + frameView->y());
515 LayoutRect viewRect = frameView->visibleContentRect();
516 LayoutRect r = ScrollAlignment::getRectToExpose(viewRect, rect, alignX, alignY);
517 frameView->setScrollPosition(roundedIntPoint(r.location()));
522 if (frame()->page()->autoscrollController().autoscrollInProgress())
523 parentBox = enclosingScrollableBox();
526 parentBox->scrollRectToVisible(newRect, alignX, alignY);
529 void RenderBox::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
531 rects.append(pixelSnappedIntRect(accumulatedOffset, size()));
534 void RenderBox::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
536 quads.append(localToAbsoluteQuad(FloatRect(0, 0, width().toFloat(), height().toFloat()), 0 /* mode */, wasFixed));
539 void RenderBox::updateLayerTransform()
541 // Transform-origin depends on box size, so we need to update the layer transform after layout.
543 layer()->updateTransform();
546 LayoutUnit RenderBox::constrainLogicalWidthByMinMax(LayoutUnit logicalWidth, LayoutUnit availableWidth, RenderBlock* cb) const
548 RenderStyle* styleToUse = style();
549 if (!styleToUse->logicalMaxWidth().isUndefined())
550 logicalWidth = min(logicalWidth, computeLogicalWidthUsing(MaxSize, styleToUse->logicalMaxWidth(), availableWidth, cb));
551 return max(logicalWidth, computeLogicalWidthUsing(MinSize, styleToUse->logicalMinWidth(), availableWidth, cb));
554 LayoutUnit RenderBox::constrainLogicalHeightByMinMax(LayoutUnit logicalHeight, LayoutUnit intrinsicContentHeight) const
556 RenderStyle* styleToUse = style();
557 if (!styleToUse->logicalMaxHeight().isUndefined()) {
558 LayoutUnit maxH = computeLogicalHeightUsing(styleToUse->logicalMaxHeight(), intrinsicContentHeight);
560 logicalHeight = min(logicalHeight, maxH);
562 return max(logicalHeight, computeLogicalHeightUsing(styleToUse->logicalMinHeight(), intrinsicContentHeight));
565 LayoutUnit RenderBox::constrainContentBoxLogicalHeightByMinMax(LayoutUnit logicalHeight, LayoutUnit intrinsicContentHeight) const
567 RenderStyle* styleToUse = style();
568 if (!styleToUse->logicalMaxHeight().isUndefined()) {
569 LayoutUnit maxH = computeContentLogicalHeight(styleToUse->logicalMaxHeight(), intrinsicContentHeight);
571 logicalHeight = min(logicalHeight, maxH);
573 return max(logicalHeight, computeContentLogicalHeight(styleToUse->logicalMinHeight(), intrinsicContentHeight));
576 IntRect RenderBox::absoluteContentBox() const
578 // This is wrong with transforms and flipped writing modes.
579 IntRect rect = pixelSnappedIntRect(contentBoxRect());
580 FloatPoint absPos = localToAbsolute();
581 rect.move(absPos.x(), absPos.y());
585 FloatQuad RenderBox::absoluteContentQuad() const
587 LayoutRect rect = contentBoxRect();
588 return localToAbsoluteQuad(FloatRect(rect));
591 LayoutRect RenderBox::outlineBoundsForRepaint(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap) const
593 LayoutRect box = borderBoundingBox();
594 adjustRectForOutline(box);
596 if (repaintContainer != this) {
597 FloatQuad containerRelativeQuad;
599 containerRelativeQuad = geometryMap->mapToContainer(box, repaintContainer);
601 containerRelativeQuad = localToContainerQuad(FloatRect(box), repaintContainer);
603 box = containerRelativeQuad.enclosingBoundingBox();
606 if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) {
607 // FIXME: layoutDelta needs to be applied in parts before/after transforms and
608 // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
609 box.move(view()->layoutDelta());
615 void RenderBox::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*)
617 if (!size().isEmpty())
618 rects.append(pixelSnappedIntRect(additionalOffset, size()));
621 bool RenderBox::canResize() const
623 // We need a special case for <iframe> because they never have
624 // hasOverflowClip(). However, they do "implicitly" clip their contents, so
625 // we want to allow resizing them also.
626 return (hasOverflowClip() || isRenderIFrame()) && style()->resize() != RESIZE_NONE;
629 void RenderBox::addLayerHitTestRects(LayerHitTestRects& layerRects, const RenderLayer* currentLayer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const
631 LayoutPoint adjustedLayerOffset = layerOffset + locationOffset();
632 RenderBoxModelObject::addLayerHitTestRects(layerRects, currentLayer, adjustedLayerOffset, containerRect);
635 void RenderBox::computeSelfHitTestRects(Vector<LayoutRect>& rects, const LayoutPoint& layerOffset) const
637 if (!size().isEmpty())
638 rects.append(LayoutRect(layerOffset, size()));
641 LayoutRect RenderBox::reflectionBox() const
644 if (!style()->boxReflect())
646 LayoutRect box = borderBoxRect();
648 switch (style()->boxReflect()->direction()) {
649 case ReflectionBelow:
650 result.move(0, box.height() + reflectionOffset());
652 case ReflectionAbove:
653 result.move(0, -box.height() - reflectionOffset());
656 result.move(-box.width() - reflectionOffset(), 0);
658 case ReflectionRight:
659 result.move(box.width() + reflectionOffset(), 0);
665 int RenderBox::reflectionOffset() const
667 if (!style()->boxReflect())
669 if (style()->boxReflect()->direction() == ReflectionLeft || style()->boxReflect()->direction() == ReflectionRight)
670 return valueForLength(style()->boxReflect()->offset(), borderBoxRect().width());
671 return valueForLength(style()->boxReflect()->offset(), borderBoxRect().height());
674 LayoutRect RenderBox::reflectedRect(const LayoutRect& r) const
676 if (!style()->boxReflect())
679 LayoutRect box = borderBoxRect();
680 LayoutRect result = r;
681 switch (style()->boxReflect()->direction()) {
682 case ReflectionBelow:
683 result.setY(box.maxY() + reflectionOffset() + (box.maxY() - r.maxY()));
685 case ReflectionAbove:
686 result.setY(box.y() - reflectionOffset() - box.height() + (box.maxY() - r.maxY()));
689 result.setX(box.x() - reflectionOffset() - box.width() + (box.maxX() - r.maxX()));
691 case ReflectionRight:
692 result.setX(box.maxX() + reflectionOffset() + (box.maxX() - r.maxX()));
698 int RenderBox::verticalScrollbarWidth() const
700 if (!hasOverflowClip() || style()->overflowY() == OOVERLAY)
703 return layer()->scrollableArea()->verticalScrollbarWidth();
706 int RenderBox::horizontalScrollbarHeight() const
708 if (!hasOverflowClip() || style()->overflowX() == OOVERLAY)
711 return layer()->scrollableArea()->horizontalScrollbarHeight();
714 int RenderBox::instrinsicScrollbarLogicalWidth() const
716 if (!hasOverflowClip())
719 if (isHorizontalWritingMode() && style()->overflowY() == OSCROLL) {
720 ASSERT(layer()->scrollableArea() && layer()->scrollableArea()->hasVerticalScrollbar());
721 return verticalScrollbarWidth();
724 if (!isHorizontalWritingMode() && style()->overflowX() == OSCROLL) {
725 ASSERT(layer()->scrollableArea() && layer()->scrollableArea()->hasHorizontalScrollbar());
726 return horizontalScrollbarHeight();
732 bool RenderBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float delta)
734 // Presumably the same issue as in setScrollTop. See crbug.com/343132.
735 DisableCompositingQueryAsserts disabler;
737 // Logical scroll is a higher level concept, all directions by here must be physical
738 ASSERT(!isLogical(direction));
740 if (!layer() || !layer()->scrollableArea())
743 return layer()->scrollableArea()->scroll(direction, granularity, delta);
746 bool RenderBox::canBeScrolledAndHasScrollableArea() const
748 return canBeProgramaticallyScrolled() && (scrollHeight() != clientHeight() || scrollWidth() != clientWidth());
751 bool RenderBox::canBeProgramaticallyScrolled() const
753 Node* node = this->node();
754 if (node && node->isDocumentNode())
757 if (!hasOverflowClip())
760 bool hasScrollableOverflow = hasScrollableOverflowX() || hasScrollableOverflowY();
761 if (scrollsOverflow() && hasScrollableOverflow)
764 return node && node->rendererIsEditable();
767 bool RenderBox::usesCompositedScrolling() const
769 return hasOverflowClip() && hasLayer() && layer()->scrollableArea()->usesCompositedScrolling();
772 void RenderBox::autoscroll(const IntPoint& position)
774 LocalFrame* frame = this->frame();
778 FrameView* frameView = frame->view();
782 IntPoint currentDocumentPosition = frameView->windowToContents(position);
783 scrollRectToVisible(LayoutRect(currentDocumentPosition, LayoutSize(1, 1)), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
786 bool RenderBox::autoscrollInProgress() const
788 return frame() && frame()->page() && frame()->page()->autoscrollController().autoscrollInProgress(this);
791 // There are two kinds of renderer that can autoscroll.
792 bool RenderBox::canAutoscroll() const
794 if (node() && node()->isDocumentNode())
795 return view()->frameView()->isScrollable();
797 // Check for a box that can be scrolled in its own right.
798 return canBeScrolledAndHasScrollableArea();
801 // If specified point is in border belt, returned offset denotes direction of
803 IntSize RenderBox::calculateAutoscrollDirection(const IntPoint& windowPoint) const
808 FrameView* frameView = frame()->view();
812 IntRect box(absoluteBoundingBoxRect());
813 box.move(view()->frameView()->scrollOffset());
814 IntRect windowBox = view()->frameView()->contentsToWindow(box);
816 IntPoint windowAutoscrollPoint = windowPoint;
818 if (windowAutoscrollPoint.x() < windowBox.x() + autoscrollBeltSize)
819 windowAutoscrollPoint.move(-autoscrollBeltSize, 0);
820 else if (windowAutoscrollPoint.x() > windowBox.maxX() - autoscrollBeltSize)
821 windowAutoscrollPoint.move(autoscrollBeltSize, 0);
823 if (windowAutoscrollPoint.y() < windowBox.y() + autoscrollBeltSize)
824 windowAutoscrollPoint.move(0, -autoscrollBeltSize);
825 else if (windowAutoscrollPoint.y() > windowBox.maxY() - autoscrollBeltSize)
826 windowAutoscrollPoint.move(0, autoscrollBeltSize);
828 return windowAutoscrollPoint - windowPoint;
831 RenderBox* RenderBox::findAutoscrollable(RenderObject* renderer)
833 while (renderer && !(renderer->isBox() && toRenderBox(renderer)->canAutoscroll())) {
834 if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document().ownerElement())
835 renderer = renderer->document().ownerElement()->renderer();
837 renderer = renderer->parent();
840 return renderer && renderer->isBox() ? toRenderBox(renderer) : 0;
843 static inline int adjustedScrollDelta(int beginningDelta)
845 // This implemention matches Firefox's.
846 // http://mxr.mozilla.org/firefox/source/toolkit/content/widgets/browser.xml#856.
847 const int speedReducer = 12;
849 int adjustedDelta = beginningDelta / speedReducer;
850 if (adjustedDelta > 1)
851 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(adjustedDelta))) - 1;
852 else if (adjustedDelta < -1)
853 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(-adjustedDelta))) + 1;
855 return adjustedDelta;
858 static inline IntSize adjustedScrollDelta(const IntSize& delta)
860 return IntSize(adjustedScrollDelta(delta.width()), adjustedScrollDelta(delta.height()));
863 void RenderBox::panScroll(const IntPoint& sourcePoint)
865 LocalFrame* frame = this->frame();
869 IntPoint lastKnownMousePosition = frame->eventHandler().lastKnownMousePosition();
871 // We need to check if the last known mouse position is out of the window. When the mouse is out of the window, the position is incoherent
872 static IntPoint previousMousePosition;
873 if (lastKnownMousePosition.x() < 0 || lastKnownMousePosition.y() < 0)
874 lastKnownMousePosition = previousMousePosition;
876 previousMousePosition = lastKnownMousePosition;
878 IntSize delta = lastKnownMousePosition - sourcePoint;
880 if (abs(delta.width()) <= ScrollView::noPanScrollRadius) // at the center we let the space for the icon
882 if (abs(delta.height()) <= ScrollView::noPanScrollRadius)
885 scrollByRecursively(adjustedScrollDelta(delta), ScrollOffsetClamped);
888 void RenderBox::scrollByRecursively(const IntSize& delta, ScrollOffsetClamping clamp)
893 bool restrictedByLineClamp = false;
895 restrictedByLineClamp = !parent()->style()->lineClamp().isNone();
897 if (hasOverflowClip() && !restrictedByLineClamp) {
898 IntSize newScrollOffset = layer()->scrollableArea()->adjustedScrollOffset() + delta;
899 layer()->scrollableArea()->scrollToOffset(newScrollOffset, clamp);
901 // If this layer can't do the scroll we ask the next layer up that can scroll to try
902 IntSize remainingScrollOffset = newScrollOffset - layer()->scrollableArea()->adjustedScrollOffset();
903 if (!remainingScrollOffset.isZero() && parent()) {
904 if (RenderBox* scrollableBox = enclosingScrollableBox())
905 scrollableBox->scrollByRecursively(remainingScrollOffset, clamp);
907 LocalFrame* frame = this->frame();
908 if (frame && frame->page())
909 frame->page()->autoscrollController().updateAutoscrollRenderer();
911 } else if (view()->frameView()) {
912 // If we are here, we were called on a renderer that can be programmatically scrolled, but doesn't
913 // have an overflow clip. Which means that it is a document node that can be scrolled.
914 view()->frameView()->scrollBy(delta);
916 // FIXME: If we didn't scroll the whole way, do we want to try looking at the frames ownerElement?
917 // https://bugs.webkit.org/show_bug.cgi?id=28237
921 bool RenderBox::needsPreferredWidthsRecalculation() const
923 return style()->paddingStart().isPercent() || style()->paddingEnd().isPercent();
926 IntSize RenderBox::scrolledContentOffset() const
928 ASSERT(hasOverflowClip());
930 return layer()->scrollableArea()->scrollOffset();
933 LayoutSize RenderBox::cachedSizeForOverflowClip() const
935 ASSERT(hasOverflowClip());
937 return layer()->size();
940 void RenderBox::applyCachedClipAndScrollOffsetForRepaint(LayoutRect& paintRect) const
942 flipForWritingMode(paintRect);
943 paintRect.move(-scrolledContentOffset()); // For overflow:auto/scroll/hidden.
945 // Do not clip scroll layer contents to reduce the number of repaints while scrolling.
946 if (usesCompositedScrolling()) {
947 flipForWritingMode(paintRect);
951 // height() is inaccurate if we're in the middle of a layout of this RenderBox, so use the
952 // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint
953 // anyway if its size does change.
954 LayoutRect clipRect(LayoutPoint(), cachedSizeForOverflowClip());
955 paintRect = intersection(paintRect, clipRect);
956 flipForWritingMode(paintRect);
959 void RenderBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
961 minLogicalWidth = minPreferredLogicalWidth() - borderAndPaddingLogicalWidth();
962 maxLogicalWidth = maxPreferredLogicalWidth() - borderAndPaddingLogicalWidth();
965 LayoutUnit RenderBox::minPreferredLogicalWidth() const
967 if (preferredLogicalWidthsDirty()) {
969 SetLayoutNeededForbiddenScope layoutForbiddenScope(const_cast<RenderBox*>(this));
971 const_cast<RenderBox*>(this)->computePreferredLogicalWidths();
974 return m_minPreferredLogicalWidth;
977 LayoutUnit RenderBox::maxPreferredLogicalWidth() const
979 if (preferredLogicalWidthsDirty()) {
981 SetLayoutNeededForbiddenScope layoutForbiddenScope(const_cast<RenderBox*>(this));
983 const_cast<RenderBox*>(this)->computePreferredLogicalWidths();
986 return m_maxPreferredLogicalWidth;
989 bool RenderBox::hasOverrideHeight() const
991 return m_rareData && m_rareData->m_overrideLogicalContentHeight != -1;
994 bool RenderBox::hasOverrideWidth() const
996 return m_rareData && m_rareData->m_overrideLogicalContentWidth != -1;
999 void RenderBox::setOverrideLogicalContentHeight(LayoutUnit height)
1001 ASSERT(height >= 0);
1002 ensureRareData().m_overrideLogicalContentHeight = height;
1005 void RenderBox::setOverrideLogicalContentWidth(LayoutUnit width)
1008 ensureRareData().m_overrideLogicalContentWidth = width;
1011 void RenderBox::clearOverrideLogicalContentHeight()
1014 m_rareData->m_overrideLogicalContentHeight = -1;
1017 void RenderBox::clearOverrideLogicalContentWidth()
1020 m_rareData->m_overrideLogicalContentWidth = -1;
1023 void RenderBox::clearOverrideSize()
1025 clearOverrideLogicalContentHeight();
1026 clearOverrideLogicalContentWidth();
1029 LayoutUnit RenderBox::overrideLogicalContentWidth() const
1031 ASSERT(hasOverrideWidth());
1032 return m_rareData->m_overrideLogicalContentWidth;
1035 LayoutUnit RenderBox::overrideLogicalContentHeight() const
1037 ASSERT(hasOverrideHeight());
1038 return m_rareData->m_overrideLogicalContentHeight;
1041 LayoutUnit RenderBox::overrideContainingBlockContentLogicalWidth() const
1043 ASSERT(hasOverrideContainingBlockLogicalWidth());
1044 return gOverrideContainingBlockLogicalWidthMap->get(this);
1047 LayoutUnit RenderBox::overrideContainingBlockContentLogicalHeight() const
1049 ASSERT(hasOverrideContainingBlockLogicalHeight());
1050 return gOverrideContainingBlockLogicalHeightMap->get(this);
1053 bool RenderBox::hasOverrideContainingBlockLogicalWidth() const
1055 return gOverrideContainingBlockLogicalWidthMap && gOverrideContainingBlockLogicalWidthMap->contains(this);
1058 bool RenderBox::hasOverrideContainingBlockLogicalHeight() const
1060 return gOverrideContainingBlockLogicalHeightMap && gOverrideContainingBlockLogicalHeightMap->contains(this);
1063 void RenderBox::setOverrideContainingBlockContentLogicalWidth(LayoutUnit logicalWidth)
1065 if (!gOverrideContainingBlockLogicalWidthMap)
1066 gOverrideContainingBlockLogicalWidthMap = new OverrideSizeMap;
1067 gOverrideContainingBlockLogicalWidthMap->set(this, logicalWidth);
1070 void RenderBox::setOverrideContainingBlockContentLogicalHeight(LayoutUnit logicalHeight)
1072 if (!gOverrideContainingBlockLogicalHeightMap)
1073 gOverrideContainingBlockLogicalHeightMap = new OverrideSizeMap;
1074 gOverrideContainingBlockLogicalHeightMap->set(this, logicalHeight);
1077 void RenderBox::clearContainingBlockOverrideSize()
1079 if (gOverrideContainingBlockLogicalWidthMap)
1080 gOverrideContainingBlockLogicalWidthMap->remove(this);
1081 clearOverrideContainingBlockContentLogicalHeight();
1084 void RenderBox::clearOverrideContainingBlockContentLogicalHeight()
1086 if (gOverrideContainingBlockLogicalHeightMap)
1087 gOverrideContainingBlockLogicalHeightMap->remove(this);
1090 LayoutUnit RenderBox::adjustBorderBoxLogicalWidthForBoxSizing(LayoutUnit width) const
1092 LayoutUnit bordersPlusPadding = borderAndPaddingLogicalWidth();
1093 if (style()->boxSizing() == CONTENT_BOX)
1094 return width + bordersPlusPadding;
1095 return max(width, bordersPlusPadding);
1098 LayoutUnit RenderBox::adjustBorderBoxLogicalHeightForBoxSizing(LayoutUnit height) const
1100 LayoutUnit bordersPlusPadding = borderAndPaddingLogicalHeight();
1101 if (style()->boxSizing() == CONTENT_BOX)
1102 return height + bordersPlusPadding;
1103 return max(height, bordersPlusPadding);
1106 LayoutUnit RenderBox::adjustContentBoxLogicalWidthForBoxSizing(LayoutUnit width) const
1108 if (style()->boxSizing() == BORDER_BOX)
1109 width -= borderAndPaddingLogicalWidth();
1110 return max<LayoutUnit>(0, width);
1113 LayoutUnit RenderBox::adjustContentBoxLogicalHeightForBoxSizing(LayoutUnit height) const
1115 if (style()->boxSizing() == BORDER_BOX)
1116 height -= borderAndPaddingLogicalHeight();
1117 return max<LayoutUnit>(0, height);
1121 bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
1123 LayoutPoint adjustedLocation = accumulatedOffset + location();
1125 // Check kids first.
1126 for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
1127 if (!child->hasLayer() && child->nodeAtPoint(request, result, locationInContainer, adjustedLocation, action)) {
1128 updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation));
1133 // Check our bounds next. For this purpose always assume that we can only be hit in the
1134 // foreground phase (which is true for replaced elements like images).
1135 LayoutRect boundsRect = borderBoxRect();
1136 boundsRect.moveBy(adjustedLocation);
1137 if (visibleToHitTestRequest(request) && action == HitTestForeground && locationInContainer.intersects(boundsRect)) {
1138 updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation));
1139 if (!result.addNodeToRectBasedTestResult(node(), request, locationInContainer, boundsRect))
1146 // --------------------- painting stuff -------------------------------
1148 void RenderBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1150 LayoutPoint adjustedPaintOffset = paintOffset + location();
1151 // default implementation. Just pass paint through to the children
1152 PaintInfo childInfo(paintInfo);
1153 childInfo.updatePaintingRootForChildren(this);
1154 for (RenderObject* child = firstChild(); child; child = child->nextSibling())
1155 child->paint(childInfo, adjustedPaintOffset);
1158 void RenderBox::paintRootBoxFillLayers(const PaintInfo& paintInfo)
1160 if (paintInfo.skipRootBackground())
1163 RenderObject* rootBackgroundRenderer = rendererForRootBackground();
1165 const FillLayer* bgLayer = rootBackgroundRenderer->style()->backgroundLayers();
1166 Color bgColor = rootBackgroundRenderer->resolveColor(CSSPropertyBackgroundColor);
1168 paintFillLayers(paintInfo, bgColor, bgLayer, view()->backgroundRect(this), BackgroundBleedNone, CompositeSourceOver, rootBackgroundRenderer);
1171 BackgroundBleedAvoidance RenderBox::determineBackgroundBleedAvoidance(GraphicsContext* context) const
1173 if (context->paintingDisabled())
1174 return BackgroundBleedNone;
1176 const RenderStyle* style = this->style();
1178 if (!style->hasBackground() || !style->hasBorder() || !style->hasBorderRadius() || borderImageIsLoadedAndCanBeRendered())
1179 return BackgroundBleedNone;
1181 AffineTransform ctm = context->getCTM();
1182 FloatSize contextScaling(static_cast<float>(ctm.xScale()), static_cast<float>(ctm.yScale()));
1184 // Because RoundedRect uses IntRect internally the inset applied by the
1185 // BackgroundBleedShrinkBackground strategy cannot be less than one integer
1186 // layout coordinate, even with subpixel layout enabled. To take that into
1187 // account, we clamp the contextScaling to 1.0 for the following test so
1188 // that borderObscuresBackgroundEdge can only return true if the border
1189 // widths are greater than 2 in both layout coordinates and screen
1191 // This precaution will become obsolete if RoundedRect is ever promoted to
1192 // a sub-pixel representation.
1193 if (contextScaling.width() > 1)
1194 contextScaling.setWidth(1);
1195 if (contextScaling.height() > 1)
1196 contextScaling.setHeight(1);
1198 if (borderObscuresBackgroundEdge(contextScaling))
1199 return BackgroundBleedShrinkBackground;
1200 if (!style->hasAppearance() && borderObscuresBackground() && backgroundHasOpaqueTopLayer())
1201 return BackgroundBleedBackgroundOverBorder;
1203 return BackgroundBleedClipBackground;
1206 void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1208 if (!paintInfo.shouldPaintWithinRoot(this))
1211 LayoutRect paintRect = borderBoxRect();
1212 paintRect.moveBy(paintOffset);
1213 paintBoxDecorationsWithRect(paintInfo, paintOffset, paintRect);
1216 void RenderBox::paintBoxDecorationsWithRect(PaintInfo& paintInfo, const LayoutPoint& paintOffset, const LayoutRect& paintRect)
1218 BackgroundBleedAvoidance bleedAvoidance = determineBackgroundBleedAvoidance(paintInfo.context);
1220 // FIXME: Should eventually give the theme control over whether the box shadow should paint, since controls could have
1221 // custom shadows of their own.
1222 if (!boxShadowShouldBeAppliedToBackground(bleedAvoidance))
1223 paintBoxShadow(paintInfo, paintRect, style(), Normal);
1225 GraphicsContextStateSaver stateSaver(*paintInfo.context, false);
1226 if (bleedAvoidance == BackgroundBleedClipBackground) {
1228 RoundedRect border = style()->getRoundedBorderFor(paintRect);
1229 paintInfo.context->clipRoundedRect(border);
1232 paintBackgroundWithBorderAndBoxShadow(paintInfo, paintRect, bleedAvoidance);
1235 void RenderBox::paintBackgroundWithBorderAndBoxShadow(PaintInfo& paintInfo, const LayoutRect& paintRect, BackgroundBleedAvoidance bleedAvoidance)
1237 // If we have a native theme appearance, paint that before painting our background.
1238 // The theme will tell us whether or not we should also paint the CSS background.
1239 IntRect snappedPaintRect(pixelSnappedIntRect(paintRect));
1240 bool themePainted = style()->hasAppearance() && !RenderTheme::theme().paint(this, paintInfo, snappedPaintRect);
1241 if (!themePainted) {
1242 if (bleedAvoidance == BackgroundBleedBackgroundOverBorder)
1243 paintBorder(paintInfo, paintRect, style(), bleedAvoidance);
1245 paintBackground(paintInfo, paintRect, bleedAvoidance);
1247 if (style()->hasAppearance())
1248 RenderTheme::theme().paintDecorations(this, paintInfo, snappedPaintRect);
1250 paintBoxShadow(paintInfo, paintRect, style(), Inset);
1252 // The theme will tell us whether or not we should also paint the CSS border.
1253 if (bleedAvoidance != BackgroundBleedBackgroundOverBorder && (!style()->hasAppearance() || (!themePainted && RenderTheme::theme().paintBorderOnly(this, paintInfo, snappedPaintRect))) && style()->hasBorder() && !(isTable() && toRenderTable(this)->collapseBorders()))
1254 paintBorder(paintInfo, paintRect, style(), bleedAvoidance);
1257 void RenderBox::paintBackground(const PaintInfo& paintInfo, const LayoutRect& paintRect, BackgroundBleedAvoidance bleedAvoidance)
1260 paintRootBoxFillLayers(paintInfo);
1263 if (isBody() && skipBodyBackground(this))
1265 if (backgroundIsKnownToBeObscured())
1267 paintFillLayers(paintInfo, resolveColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), paintRect, bleedAvoidance);
1270 LayoutRect RenderBox::backgroundPaintedExtent() const
1272 ASSERT(hasBackground());
1273 LayoutRect backgroundRect = pixelSnappedIntRect(borderBoxRect());
1275 Color backgroundColor = resolveColor(CSSPropertyBackgroundColor);
1276 if (backgroundColor.alpha())
1277 return backgroundRect;
1278 if (!style()->backgroundLayers()->image() || style()->backgroundLayers()->next())
1279 return backgroundRect;
1280 BackgroundImageGeometry geometry;
1281 const_cast<RenderBox*>(this)->calculateBackgroundImageGeometry(style()->backgroundLayers(), backgroundRect, geometry);
1282 return geometry.destRect();
1285 bool RenderBox::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const
1287 if (isBody() && skipBodyBackground(this))
1290 Color backgroundColor = resolveColor(CSSPropertyBackgroundColor);
1291 if (backgroundColor.hasAlpha())
1294 // If the element has appearance, it might be painted by theme.
1295 // We cannot be sure if theme paints the background opaque.
1296 // In this case it is safe to not assume opaqueness.
1297 // FIXME: May be ask theme if it paints opaque.
1298 if (style()->hasAppearance())
1300 // FIXME: Check the opaqueness of background images.
1302 // FIXME: Use rounded rect if border radius is present.
1303 if (style()->hasBorderRadius())
1305 // FIXME: The background color clip is defined by the last layer.
1306 if (style()->backgroundLayers()->next())
1308 LayoutRect backgroundRect;
1309 switch (style()->backgroundClip()) {
1311 backgroundRect = borderBoxRect();
1313 case PaddingFillBox:
1314 backgroundRect = paddingBoxRect();
1316 case ContentFillBox:
1317 backgroundRect = contentBoxRect();
1322 return backgroundRect.contains(localRect);
1325 static bool isCandidateForOpaquenessTest(RenderBox* childBox)
1327 RenderStyle* childStyle = childBox->style();
1328 if (childStyle->position() != StaticPosition && childBox->containingBlock() != childBox->parent())
1330 if (childStyle->visibility() != VISIBLE || childStyle->shapeOutside())
1332 if (!childBox->width() || !childBox->height())
1334 if (RenderLayer* childLayer = childBox->layer()) {
1335 // FIXME: perhaps this could be less conservative?
1336 if (childLayer->compositingState() != NotComposited)
1338 // FIXME: Deal with z-index.
1339 if (!childStyle->hasAutoZIndex())
1341 if (childLayer->hasTransform() || childLayer->isTransparent() || childLayer->hasFilter())
1343 if (childBox->hasOverflowClip() && childStyle->hasBorderRadius())
1349 bool RenderBox::foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, unsigned maxDepthToTest) const
1351 if (!maxDepthToTest)
1353 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
1354 if (!child->isBox())
1356 RenderBox* childBox = toRenderBox(child);
1357 if (!isCandidateForOpaquenessTest(childBox))
1359 LayoutPoint childLocation = childBox->location();
1360 if (childBox->isRelPositioned())
1361 childLocation.move(childBox->relativePositionOffset());
1362 LayoutRect childLocalRect = localRect;
1363 childLocalRect.moveBy(-childLocation);
1364 if (childLocalRect.y() < 0 || childLocalRect.x() < 0) {
1365 // If there is unobscured area above/left of a static positioned box then the rect is probably not covered.
1366 if (childBox->style()->position() == StaticPosition)
1370 if (childLocalRect.maxY() > childBox->height() || childLocalRect.maxX() > childBox->width())
1372 if (childBox->backgroundIsKnownToBeOpaqueInRect(childLocalRect))
1374 if (childBox->foregroundIsKnownToBeOpaqueInRect(childLocalRect, maxDepthToTest - 1))
1380 bool RenderBox::computeBackgroundIsKnownToBeObscured()
1382 // Test to see if the children trivially obscure the background.
1383 // FIXME: This test can be much more comprehensive.
1384 if (!hasBackground())
1386 // Table and root background painting is special.
1387 if (isTable() || isRoot())
1389 // FIXME: box-shadow is painted while background painting.
1390 if (style()->boxShadow())
1392 LayoutRect backgroundRect = backgroundPaintedExtent();
1393 return foregroundIsKnownToBeOpaqueInRect(backgroundRect, backgroundObscurationTestMaxDepth);
1396 bool RenderBox::backgroundHasOpaqueTopLayer() const
1398 const FillLayer* fillLayer = style()->backgroundLayers();
1399 if (!fillLayer || fillLayer->clip() != BorderFillBox)
1402 // Clipped with local scrolling
1403 if (hasOverflowClip() && fillLayer->attachment() == LocalBackgroundAttachment)
1406 if (fillLayer->hasOpaqueImage(this) && fillLayer->hasRepeatXY() && fillLayer->image()->canRender(this, style()->effectiveZoom()))
1409 // If there is only one layer and no image, check whether the background color is opaque
1410 if (!fillLayer->next() && !fillLayer->hasImage()) {
1411 Color bgColor = resolveColor(CSSPropertyBackgroundColor);
1412 if (bgColor.alpha() == 255)
1419 void RenderBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1421 if (!paintInfo.shouldPaintWithinRoot(this) || style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask || paintInfo.context->paintingDisabled())
1424 LayoutRect paintRect = LayoutRect(paintOffset, size());
1425 paintMaskImages(paintInfo, paintRect);
1428 void RenderBox::paintClippingMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1430 if (!paintInfo.shouldPaintWithinRoot(this) || style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseClippingMask || paintInfo.context->paintingDisabled())
1433 if (!layer() || layer()->compositingState() != PaintsIntoOwnBacking)
1436 // We should never have this state in this function. A layer with a mask
1437 // should have always created its own backing if it became composited.
1438 ASSERT(layer()->compositingState() != HasOwnBackingButPaintsIntoAncestor);
1440 LayoutRect paintRect = LayoutRect(paintOffset, size());
1441 paintInfo.context->fillRect(pixelSnappedIntRect(paintRect), Color::black);
1444 void RenderBox::paintMaskImages(const PaintInfo& paintInfo, const LayoutRect& paintRect)
1446 // Figure out if we need to push a transparency layer to render our mask.
1447 bool pushTransparencyLayer = false;
1448 bool compositedMask = hasLayer() && layer()->hasCompositedMask();
1449 bool flattenCompositingLayers = view()->frameView() && view()->frameView()->paintBehavior() & PaintBehaviorFlattenCompositingLayers;
1450 CompositeOperator compositeOp = CompositeSourceOver;
1452 bool allMaskImagesLoaded = true;
1454 if (!compositedMask || flattenCompositingLayers) {
1455 pushTransparencyLayer = true;
1456 StyleImage* maskBoxImage = style()->maskBoxImage().image();
1457 const FillLayer* maskLayers = style()->maskLayers();
1459 // Don't render a masked element until all the mask images have loaded, to prevent a flash of unmasked content.
1461 allMaskImagesLoaded &= maskBoxImage->isLoaded();
1464 allMaskImagesLoaded &= maskLayers->imagesAreLoaded();
1466 paintInfo.context->setCompositeOperation(CompositeDestinationIn);
1467 paintInfo.context->beginTransparencyLayer(1);
1468 compositeOp = CompositeSourceOver;
1471 if (allMaskImagesLoaded) {
1472 paintFillLayers(paintInfo, Color::transparent, style()->maskLayers(), paintRect, BackgroundBleedNone, compositeOp);
1473 paintNinePieceImage(paintInfo.context, paintRect, style(), style()->maskBoxImage(), compositeOp);
1476 if (pushTransparencyLayer)
1477 paintInfo.context->endLayer();
1480 LayoutRect RenderBox::maskClipRect()
1482 const NinePieceImage& maskBoxImage = style()->maskBoxImage();
1483 if (maskBoxImage.image()) {
1484 LayoutRect borderImageRect = borderBoxRect();
1486 // Apply outsets to the border box.
1487 borderImageRect.expand(style()->maskBoxImageOutsets());
1488 return borderImageRect;
1492 LayoutRect borderBox = borderBoxRect();
1493 for (const FillLayer* maskLayer = style()->maskLayers(); maskLayer; maskLayer = maskLayer->next()) {
1494 if (maskLayer->image()) {
1495 BackgroundImageGeometry geometry;
1496 calculateBackgroundImageGeometry(maskLayer, borderBox, geometry);
1497 result.unite(geometry.destRect());
1503 void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, const LayoutRect& rect,
1504 BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderObject* backgroundObject)
1506 Vector<const FillLayer*, 8> layers;
1507 const FillLayer* curLayer = fillLayer;
1508 bool shouldDrawBackgroundInSeparateBuffer = false;
1510 layers.append(curLayer);
1511 // Stop traversal when an opaque layer is encountered.
1512 // FIXME : It would be possible for the following occlusion culling test to be more aggressive
1513 // on layers with no repeat by testing whether the image covers the layout rect.
1514 // Testing that here would imply duplicating a lot of calculations that are currently done in
1515 // RenderBoxModelObject::paintFillLayerExtended. A more efficient solution might be to move
1516 // the layer recursion into paintFillLayerExtended, or to compute the layer geometry here
1517 // and pass it down.
1519 if (!shouldDrawBackgroundInSeparateBuffer && curLayer->blendMode() != blink::WebBlendModeNormal)
1520 shouldDrawBackgroundInSeparateBuffer = true;
1522 // The clipOccludesNextLayers condition must be evaluated first to avoid short-circuiting.
1523 if (curLayer->clipOccludesNextLayers(curLayer == fillLayer) && curLayer->hasOpaqueImage(this) && curLayer->image()->canRender(this, style()->effectiveZoom()) && curLayer->hasRepeatXY() && curLayer->blendMode() == blink::WebBlendModeNormal && !boxShadowShouldBeAppliedToBackground(bleedAvoidance))
1525 curLayer = curLayer->next();
1528 GraphicsContext* context = paintInfo.context;
1530 shouldDrawBackgroundInSeparateBuffer = false;
1531 if (shouldDrawBackgroundInSeparateBuffer)
1532 context->beginTransparencyLayer(1);
1534 Vector<const FillLayer*>::const_reverse_iterator topLayer = layers.rend();
1535 for (Vector<const FillLayer*>::const_reverse_iterator it = layers.rbegin(); it != topLayer; ++it)
1536 paintFillLayer(paintInfo, c, *it, rect, bleedAvoidance, op, backgroundObject);
1538 if (shouldDrawBackgroundInSeparateBuffer)
1539 context->endLayer();
1542 void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, const LayoutRect& rect,
1543 BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderObject* backgroundObject)
1545 paintFillLayerExtended(paintInfo, c, fillLayer, rect, bleedAvoidance, 0, LayoutSize(), op, backgroundObject);
1548 static bool layersUseImage(WrappedImagePtr image, const FillLayer* layers)
1550 for (const FillLayer* curLayer = layers; curLayer; curLayer = curLayer->next()) {
1551 if (curLayer->image() && image == curLayer->image()->data())
1558 void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*)
1563 AllowRepaintScope scoper(frameView());
1565 if ((style()->borderImage().image() && style()->borderImage().image()->data() == image) ||
1566 (style()->maskBoxImage().image() && style()->maskBoxImage().image()->data() == image)) {
1571 ShapeValue* shapeOutsideValue = style()->shapeOutside();
1572 if (!frameView()->isInPerformLayout() && isFloating() && shapeOutsideValue && shapeOutsideValue->image() && shapeOutsideValue->image()->data() == image) {
1573 ShapeOutsideInfo::ensureInfo(*this).markShapeAsDirty();
1574 markShapeOutsideDependentsForLayout();
1577 bool didFullRepaint = repaintLayerRectsForImage(image, style()->backgroundLayers(), true);
1578 if (!didFullRepaint)
1579 repaintLayerRectsForImage(image, style()->maskLayers(), false);
1581 if (hasLayer() && layer()->hasCompositedMask() && layersUseImage(image, style()->maskLayers()))
1582 layer()->contentChanged(MaskImageChanged);
1585 bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer* layers, bool drawingBackground)
1587 LayoutRect rendererRect;
1588 RenderBox* layerRenderer = 0;
1590 for (const FillLayer* curLayer = layers; curLayer; curLayer = curLayer->next()) {
1591 if (curLayer->image() && image == curLayer->image()->data() && curLayer->image()->canRender(this, style()->effectiveZoom())) {
1592 // Now that we know this image is being used, compute the renderer and the rect
1593 // if we haven't already
1594 if (!layerRenderer) {
1595 bool drawingRootBackground = drawingBackground && (isRoot() || (isBody() && !document().documentElement()->renderer()->hasBackground()));
1596 if (drawingRootBackground) {
1597 layerRenderer = view();
1602 if (FrameView* frameView = toRenderView(layerRenderer)->frameView()) {
1603 rw = frameView->contentsWidth();
1604 rh = frameView->contentsHeight();
1606 rw = layerRenderer->width();
1607 rh = layerRenderer->height();
1609 rendererRect = LayoutRect(-layerRenderer->marginLeft(),
1610 -layerRenderer->marginTop(),
1611 max(layerRenderer->width() + layerRenderer->marginWidth() + layerRenderer->borderLeft() + layerRenderer->borderRight(), rw),
1612 max(layerRenderer->height() + layerRenderer->marginHeight() + layerRenderer->borderTop() + layerRenderer->borderBottom(), rh));
1614 layerRenderer = this;
1615 rendererRect = borderBoxRect();
1619 BackgroundImageGeometry geometry;
1620 layerRenderer->calculateBackgroundImageGeometry(curLayer, rendererRect, geometry);
1621 layerRenderer->repaintRectangle(geometry.destRect());
1622 if (geometry.destRect() == rendererRect)
1629 bool RenderBox::pushContentsClip(PaintInfo& paintInfo, const LayoutPoint& accumulatedOffset, ContentsClipBehavior contentsClipBehavior)
1631 if (paintInfo.phase == PaintPhaseBlockBackground || paintInfo.phase == PaintPhaseSelfOutline || paintInfo.phase == PaintPhaseMask)
1634 bool isControlClip = hasControlClip();
1635 bool isOverflowClip = hasOverflowClip() && !layer()->isSelfPaintingLayer();
1637 if (!isControlClip && !isOverflowClip)
1640 LayoutRect clipRect = isControlClip ? controlClipRect(accumulatedOffset) : overflowClipRect(accumulatedOffset);
1641 RoundedRect clipRoundedRect(0, 0, 0, 0);
1642 bool hasBorderRadius = style()->hasBorderRadius();
1643 if (hasBorderRadius)
1644 clipRoundedRect = style()->getRoundedInnerBorderFor(LayoutRect(accumulatedOffset, size()));
1646 if (contentsClipBehavior == SkipContentsClipIfPossible) {
1647 LayoutRect contentsVisualOverflow = contentsVisualOverflowRect();
1648 if (contentsVisualOverflow.isEmpty())
1651 LayoutRect conservativeClipRect = clipRect;
1652 if (hasBorderRadius)
1653 conservativeClipRect.intersect(clipRoundedRect.radiusCenterRect());
1654 conservativeClipRect.moveBy(-accumulatedOffset);
1656 conservativeClipRect.move(scrolledContentOffset());
1657 if (conservativeClipRect.contains(contentsVisualOverflow))
1661 if (paintInfo.phase == PaintPhaseOutline)
1662 paintInfo.phase = PaintPhaseChildOutlines;
1663 else if (paintInfo.phase == PaintPhaseChildBlockBackground) {
1664 paintInfo.phase = PaintPhaseBlockBackground;
1665 paintObject(paintInfo, accumulatedOffset);
1666 paintInfo.phase = PaintPhaseChildBlockBackgrounds;
1668 paintInfo.context->save();
1669 if (hasBorderRadius)
1670 paintInfo.context->clipRoundedRect(clipRoundedRect);
1671 paintInfo.context->clip(pixelSnappedIntRect(clipRect));
1675 void RenderBox::popContentsClip(PaintInfo& paintInfo, PaintPhase originalPhase, const LayoutPoint& accumulatedOffset)
1677 ASSERT(hasControlClip() || (hasOverflowClip() && !layer()->isSelfPaintingLayer()));
1679 paintInfo.context->restore();
1680 if (originalPhase == PaintPhaseOutline) {
1681 paintInfo.phase = PaintPhaseSelfOutline;
1682 paintObject(paintInfo, accumulatedOffset);
1683 paintInfo.phase = originalPhase;
1684 } else if (originalPhase == PaintPhaseChildBlockBackground)
1685 paintInfo.phase = originalPhase;
1688 LayoutRect RenderBox::overflowClipRect(const LayoutPoint& location, OverlayScrollbarSizeRelevancy relevancy)
1690 // FIXME: When overflow-clip (CSS3) is implemented, we'll obtain the property
1692 LayoutRect clipRect = borderBoxRect();
1693 clipRect.setLocation(location + clipRect.location() + LayoutSize(borderLeft(), borderTop()));
1694 clipRect.setSize(clipRect.size() - LayoutSize(borderLeft() + borderRight(), borderTop() + borderBottom()));
1696 if (!hasOverflowClip())
1699 // Subtract out scrollbars if we have them.
1700 if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
1701 clipRect.move(layer()->scrollableArea()->verticalScrollbarWidth(relevancy), 0);
1702 clipRect.contract(layer()->scrollableArea()->verticalScrollbarWidth(relevancy), layer()->scrollableArea()->horizontalScrollbarHeight(relevancy));
1707 LayoutRect RenderBox::clipRect(const LayoutPoint& location)
1709 LayoutRect borderBoxRect = this->borderBoxRect();
1710 LayoutRect clipRect = LayoutRect(borderBoxRect.location() + location, borderBoxRect.size());
1712 if (!style()->clipLeft().isAuto()) {
1713 LayoutUnit c = valueForLength(style()->clipLeft(), borderBoxRect.width());
1714 clipRect.move(c, 0);
1715 clipRect.contract(c, 0);
1718 if (!style()->clipRight().isAuto())
1719 clipRect.contract(width() - valueForLength(style()->clipRight(), width()), 0);
1721 if (!style()->clipTop().isAuto()) {
1722 LayoutUnit c = valueForLength(style()->clipTop(), borderBoxRect.height());
1723 clipRect.move(0, c);
1724 clipRect.contract(0, c);
1727 if (!style()->clipBottom().isAuto())
1728 clipRect.contract(0, height() - valueForLength(style()->clipBottom(), height()));
1733 LayoutUnit RenderBox::shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStart, LayoutUnit childMarginEnd, const RenderBlockFlow* cb) const
1735 LayoutUnit logicalTopPosition = logicalTop();
1736 LayoutUnit result = cb->availableLogicalWidthForLine(logicalTopPosition, false) - childMarginStart - childMarginEnd;
1738 // We need to see if margins on either the start side or the end side can contain the floats in question. If they can,
1739 // then just using the line width is inaccurate. In the case where a float completely fits, we don't need to use the line
1740 // offset at all, but can instead push all the way to the content edge of the containing block. In the case where the float
1741 // 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
1742 // "consumed" by the float. Negative margins aren't consumed by the float, and so we ignore them.
1743 if (childMarginStart > 0) {
1744 LayoutUnit startContentSide = cb->startOffsetForContent();
1745 LayoutUnit startContentSideWithMargin = startContentSide + childMarginStart;
1746 LayoutUnit startOffset = cb->startOffsetForLine(logicalTopPosition, false);
1747 if (startOffset > startContentSideWithMargin)
1748 result += childMarginStart;
1750 result += startOffset - startContentSide;
1753 if (childMarginEnd > 0) {
1754 LayoutUnit endContentSide = cb->endOffsetForContent();
1755 LayoutUnit endContentSideWithMargin = endContentSide + childMarginEnd;
1756 LayoutUnit endOffset = cb->endOffsetForLine(logicalTopPosition, false);
1757 if (endOffset > endContentSideWithMargin)
1758 result += childMarginEnd;
1760 result += endOffset - endContentSide;
1766 LayoutUnit RenderBox::containingBlockLogicalWidthForContent() const
1768 if (hasOverrideContainingBlockLogicalWidth())
1769 return overrideContainingBlockContentLogicalWidth();
1771 RenderBlock* cb = containingBlock();
1772 return cb->availableLogicalWidth();
1775 LayoutUnit RenderBox::containingBlockLogicalHeightForContent(AvailableLogicalHeightType heightType) const
1777 if (hasOverrideContainingBlockLogicalHeight())
1778 return overrideContainingBlockContentLogicalHeight();
1780 RenderBlock* cb = containingBlock();
1781 return cb->availableLogicalHeight(heightType);
1784 LayoutUnit RenderBox::containingBlockAvailableLineWidth() const
1786 RenderBlock* cb = containingBlock();
1787 if (cb->isRenderBlockFlow())
1788 return toRenderBlockFlow(cb)->availableLogicalWidthForLine(logicalTop(), false, availableLogicalHeight(IncludeMarginBorderPadding));
1792 LayoutUnit RenderBox::perpendicularContainingBlockLogicalHeight() const
1794 if (hasOverrideContainingBlockLogicalHeight())
1795 return overrideContainingBlockContentLogicalHeight();
1797 RenderBlock* cb = containingBlock();
1798 if (cb->hasOverrideHeight())
1799 return cb->overrideLogicalContentHeight();
1801 RenderStyle* containingBlockStyle = cb->style();
1802 Length logicalHeightLength = containingBlockStyle->logicalHeight();
1804 // FIXME: For now just support fixed heights. Eventually should support percentage heights as well.
1805 if (!logicalHeightLength.isFixed()) {
1806 LayoutUnit fillFallbackExtent = containingBlockStyle->isHorizontalWritingMode() ? view()->frameView()->visibleHeight() : view()->frameView()->visibleWidth();
1807 LayoutUnit fillAvailableExtent = containingBlock()->availableLogicalHeight(ExcludeMarginBorderPadding);
1808 return min(fillAvailableExtent, fillFallbackExtent);
1811 // Use the content box logical height as specified by the style.
1812 return cb->adjustContentBoxLogicalHeightForBoxSizing(logicalHeightLength.value());
1815 void RenderBox::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const
1817 if (repaintContainer == this)
1820 if (RenderView* v = view()) {
1821 if (v->layoutStateEnabled() && !repaintContainer) {
1822 LayoutState* layoutState = v->layoutState();
1823 LayoutSize offset = layoutState->paintOffset() + locationOffset();
1824 if (style()->hasInFlowPosition() && layer())
1825 offset += layer()->offsetForInFlowPosition();
1826 transformState.move(offset);
1831 bool containerSkipped;
1832 RenderObject* o = container(repaintContainer, &containerSkipped);
1836 bool isFixedPos = style()->position() == FixedPosition;
1837 bool hasTransform = hasLayer() && layer()->transform();
1838 // If this box has a transform, it acts as a fixed position container for fixed descendants,
1839 // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
1840 if (hasTransform && !isFixedPos)
1842 else if (isFixedPos)
1846 *wasFixed = mode & IsFixed;
1848 LayoutSize containerOffset = offsetFromContainer(o, roundedLayoutPoint(transformState.mappedPoint()));
1850 bool preserve3D = mode & UseTransforms && (o->style()->preserves3D() || style()->preserves3D());
1851 if (mode & UseTransforms && shouldUseTransformFromContainer(o)) {
1852 TransformationMatrix t;
1853 getTransformFromContainer(o, containerOffset, t);
1854 transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1856 transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1858 if (containerSkipped) {
1859 // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
1860 // to just subtract the delta between the repaintContainer and o.
1861 LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
1862 transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1866 mode &= ~ApplyContainerFlip;
1868 o->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed);
1871 void RenderBox::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState& transformState) const
1873 // We don't expect to be called during layout.
1874 ASSERT(!view() || !view()->layoutStateEnabled());
1876 bool isFixedPos = style()->position() == FixedPosition;
1877 bool hasTransform = hasLayer() && layer()->transform();
1878 if (hasTransform && !isFixedPos) {
1879 // If this box has a transform, it acts as a fixed position container for fixed descendants,
1880 // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
1882 } else if (isFixedPos)
1885 RenderBoxModelObject::mapAbsoluteToLocalPoint(mode, transformState);
1888 LayoutSize RenderBox::offsetFromContainer(RenderObject* o, const LayoutPoint& point, bool* offsetDependsOnPoint) const
1890 ASSERT(o == container());
1893 if (isInFlowPositioned())
1894 offset += offsetForInFlowPosition();
1896 if (!isInline() || isReplaced()) {
1897 if (!style()->hasOutOfFlowPosition() && o->hasColumns()) {
1898 RenderBlock* block = toRenderBlock(o);
1899 LayoutRect columnRect(frameRect());
1900 block->adjustStartEdgeForWritingModeIncludingColumns(columnRect);
1901 offset += toSize(columnRect.location());
1902 LayoutPoint columnPoint = block->flipForWritingModeIncludingColumns(point + offset);
1903 offset = toLayoutSize(block->flipForWritingModeIncludingColumns(toLayoutPoint(offset)));
1904 o->adjustForColumns(offset, columnPoint);
1905 offset = block->flipForWritingMode(offset);
1907 if (offsetDependsOnPoint)
1908 *offsetDependsOnPoint = true;
1910 offset += topLeftLocationOffset();
1913 if (o->hasOverflowClip())
1914 offset -= toRenderBox(o)->scrolledContentOffset();
1916 if (style()->position() == AbsolutePosition && o->isInFlowPositioned() && o->isRenderInline())
1917 offset += toRenderInline(o)->offsetForInFlowPositionedInline(*this);
1919 if (offsetDependsOnPoint)
1920 *offsetDependsOnPoint |= o->isRenderFlowThread();
1925 InlineBox* RenderBox::createInlineBox()
1927 return new InlineBox(*this);
1930 void RenderBox::dirtyLineBoxes(bool fullLayout)
1932 if (inlineBoxWrapper()) {
1934 inlineBoxWrapper()->destroy();
1936 m_rareData->m_inlineBoxWrapper = 0;
1938 inlineBoxWrapper()->dirtyLineBoxes();
1943 void RenderBox::positionLineBox(InlineBox* box)
1945 if (isOutOfFlowPositioned()) {
1946 // Cache the x position only if we were an INLINE type originally.
1947 bool wasInline = style()->isOriginalDisplayInlineType();
1949 // The value is cached in the xPos of the box. We only need this value if
1950 // our object was inline originally, since otherwise it would have ended up underneath
1952 RootInlineBox& root = box->root();
1953 root.block().setStaticInlinePositionForChild(this, root.lineTopWithLeading(), LayoutUnit::fromFloatRound(box->logicalLeft()));
1954 if (style()->hasStaticInlinePosition(box->isHorizontal()))
1955 setChildNeedsLayout(MarkOnlyThis); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
1957 // Our object was a block originally, so we make our normal flow position be
1958 // just below the line box (as though all the inlines that came before us got
1959 // wrapped in an anonymous block, which is what would have happened had we been
1960 // in flow). This value was cached in the y() of the box.
1961 layer()->setStaticBlockPosition(box->logicalTop());
1962 if (style()->hasStaticBlockPosition(box->isHorizontal()))
1963 setChildNeedsLayout(MarkOnlyThis); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
1969 } else if (isReplaced()) {
1970 setLocation(roundedLayoutPoint(box->topLeft()));
1971 setInlineBoxWrapper(box);
1975 void RenderBox::deleteLineBoxWrapper()
1977 if (inlineBoxWrapper()) {
1978 if (!documentBeingDestroyed())
1979 inlineBoxWrapper()->remove();
1980 inlineBoxWrapper()->destroy();
1982 m_rareData->m_inlineBoxWrapper = 0;
1986 LayoutRect RenderBox::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const
1988 if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent())
1989 return LayoutRect();
1991 LayoutRect r = visualOverflowRect();
1993 RenderView* v = view();
1994 if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && v) {
1995 // FIXME: layoutDelta needs to be applied in parts before/after transforms and
1996 // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
1997 r.move(v->layoutDelta());
2000 computeRectForRepaint(repaintContainer, r);
2004 void RenderBox::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& rect, bool fixed) const
2006 // The rect we compute at each step is shifted by our x/y offset in the parent container's coordinate space.
2007 // Only when we cross a writing mode boundary will we have to possibly flipForWritingMode (to convert into a more appropriate
2008 // offset corner for the enclosing container). This allows for a fully RL or BT document to repaint
2009 // properly even during layout, since the rect remains flipped all the way until the end.
2011 // RenderView::computeRectForRepaint then converts the rect to physical coordinates. We also convert to
2012 // physical when we hit a repaintContainer boundary. Therefore the final rect returned is always in the
2013 // physical coordinate space of the repaintContainer.
2014 RenderStyle* styleToUse = style();
2015 if (RenderView* v = view()) {
2016 // LayoutState is only valid for root-relative, non-fixed position repainting
2017 if (v->layoutStateEnabled() && !repaintContainer && styleToUse->position() != FixedPosition) {
2018 LayoutState* layoutState = v->layoutState();
2020 if (layer() && layer()->transform())
2021 rect = layer()->transform()->mapRect(pixelSnappedIntRect(rect));
2023 // We can't trust the bits on RenderObject, because this might be called while re-resolving style.
2024 if (styleToUse->hasInFlowPosition() && layer())
2025 rect.move(layer()->offsetForInFlowPosition());
2027 rect.moveBy(location());
2028 rect.move(layoutState->paintOffset());
2029 if (layoutState->isClipped())
2030 rect.intersect(layoutState->clipRect());
2035 if (hasReflection())
2036 rect.unite(reflectedRect(rect));
2038 if (repaintContainer == this) {
2039 if (repaintContainer->style()->isFlippedBlocksWritingMode())
2040 flipForWritingMode(rect);
2044 bool containerSkipped;
2045 RenderObject* o = container(repaintContainer, &containerSkipped);
2049 if (isWritingModeRoot() && !isOutOfFlowPositioned())
2050 flipForWritingMode(rect);
2052 LayoutPoint topLeft = rect.location();
2053 topLeft.move(locationOffset());
2055 EPosition position = styleToUse->position();
2057 // We are now in our parent container's coordinate space. Apply our transform to obtain a bounding box
2058 // in the parent's coordinate space that encloses us.
2059 if (hasLayer() && layer()->transform()) {
2060 fixed = position == FixedPosition;
2061 rect = layer()->transform()->mapRect(pixelSnappedIntRect(rect));
2062 topLeft = rect.location();
2063 topLeft.move(locationOffset());
2064 } else if (position == FixedPosition)
2067 if (position == AbsolutePosition && o->isInFlowPositioned() && o->isRenderInline()) {
2068 topLeft += toRenderInline(o)->offsetForInFlowPositionedInline(*this);
2069 } else if (styleToUse->hasInFlowPosition() && layer()) {
2070 // Apply the relative position offset when invalidating a rectangle. The layer
2071 // is translated, but the render box isn't, so we need to do this to get the
2072 // right dirty rect. Since this is called from RenderObject::setStyle, the relative position
2073 // flag on the RenderObject has been cleared, so use the one on the style().
2074 topLeft += layer()->offsetForInFlowPosition();
2077 if (position != AbsolutePosition && position != FixedPosition && o->hasColumns() && o->isRenderBlockFlow()) {
2078 LayoutRect repaintRect(topLeft, rect.size());
2079 toRenderBlock(o)->adjustRectForColumns(repaintRect);
2080 topLeft = repaintRect.location();
2084 // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
2085 // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
2086 rect.setLocation(topLeft);
2087 if (o->hasOverflowClip()) {
2088 RenderBox* containerBox = toRenderBox(o);
2089 containerBox->applyCachedClipAndScrollOffsetForRepaint(rect);
2094 if (containerSkipped) {
2095 // If the repaintContainer is below o, then we need to map the rect into repaintContainer's coordinates.
2096 LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
2097 rect.move(-containerOffset);
2101 o->computeRectForRepaint(repaintContainer, rect, fixed);
2104 void RenderBox::repaintDuringLayoutIfMoved(const LayoutRect& oldRect)
2106 if (oldRect.location() != m_frameRect.location()) {
2107 LayoutRect newRect = m_frameRect;
2108 // The child moved. Invalidate the object's old and new positions. We have to do this
2109 // since the object may not have gotten a layout.
2110 m_frameRect = oldRect;
2112 repaintOverhangingFloats(true);
2113 m_frameRect = newRect;
2115 repaintOverhangingFloats(true);
2119 void RenderBox::repaintOverhangingFloats(bool)
2123 void RenderBox::updateLogicalWidth()
2125 LogicalExtentComputedValues computedValues;
2126 computeLogicalWidth(computedValues);
2128 setLogicalWidth(computedValues.m_extent);
2129 setLogicalLeft(computedValues.m_position);
2130 setMarginStart(computedValues.m_margins.m_start);
2131 setMarginEnd(computedValues.m_margins.m_end);
2134 static float getMaxWidthListMarker(const RenderBox* renderer)
2138 Node* parentNode = renderer->generatingNode();
2140 ASSERT(isHTMLOListElement(parentNode) || isHTMLUListElement(parentNode));
2141 ASSERT(renderer->style()->textAutosizingMultiplier() != 1);
2144 for (RenderObject* child = renderer->firstChild(); child; child = child->nextSibling()) {
2145 if (!child->isListItem())
2148 RenderBox* listItem = toRenderBox(child);
2149 for (RenderObject* itemChild = listItem->firstChild(); itemChild; itemChild = itemChild->nextSibling()) {
2150 if (!itemChild->isListMarker())
2152 RenderBox* itemMarker = toRenderBox(itemChild);
2153 // FIXME: canDetermineWidthWithoutLayout expects us to use fixedOffsetWidth, which this code
2154 // does not do! This check is likely wrong.
2155 if (!itemMarker->canDetermineWidthWithoutLayout() && itemMarker->needsLayout()) {
2156 // Make sure to compute the autosized width.
2157 itemMarker->layout();
2159 maxWidth = max<float>(maxWidth, toRenderListMarker(itemMarker)->logicalWidth().toFloat());
2166 void RenderBox::computeLogicalWidth(LogicalExtentComputedValues& computedValues) const
2168 computedValues.m_extent = logicalWidth();
2169 computedValues.m_position = logicalLeft();
2170 computedValues.m_margins.m_start = marginStart();
2171 computedValues.m_margins.m_end = marginEnd();
2173 if (isOutOfFlowPositioned()) {
2174 // FIXME: This calculation is not patched for block-flow yet.
2175 // https://bugs.webkit.org/show_bug.cgi?id=46500
2176 computePositionedLogicalWidth(computedValues);
2180 // If layout is limited to a subtree, the subtree root's logical width does not change.
2181 if (node() && view()->frameView() && view()->frameView()->layoutRoot(true) == this)
2184 // The parent box is flexing us, so it has increased or decreased our
2185 // width. Use the width from the style context.
2186 // FIXME: Account for block-flow in flexible boxes.
2187 // https://bugs.webkit.org/show_bug.cgi?id=46418
2188 if (hasOverrideWidth() && (style()->borderFit() == BorderFitLines || parent()->isFlexibleBoxIncludingDeprecated())) {
2189 computedValues.m_extent = overrideLogicalContentWidth() + borderAndPaddingLogicalWidth();
2193 // FIXME: Account for block-flow in flexible boxes.
2194 // https://bugs.webkit.org/show_bug.cgi?id=46418
2195 bool inVerticalBox = parent()->isDeprecatedFlexibleBox() && (parent()->style()->boxOrient() == VERTICAL);
2196 bool stretching = (parent()->style()->boxAlign() == BSTRETCH);
2197 bool treatAsReplaced = shouldComputeSizeAsReplaced() && (!inVerticalBox || !stretching);
2199 RenderStyle* styleToUse = style();
2200 Length logicalWidthLength = treatAsReplaced ? Length(computeReplacedLogicalWidth(), Fixed) : styleToUse->logicalWidth();
2202 RenderBlock* cb = containingBlock();
2203 LayoutUnit containerLogicalWidth = max<LayoutUnit>(0, containingBlockLogicalWidthForContent());
2204 bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHorizontalWritingMode();
2206 if (isInline() && !isInlineBlockOrInlineTable()) {
2207 // just calculate margins
2208 computedValues.m_margins.m_start = minimumValueForLength(styleToUse->marginStart(), containerLogicalWidth);
2209 computedValues.m_margins.m_end = minimumValueForLength(styleToUse->marginEnd(), containerLogicalWidth);
2210 if (treatAsReplaced)
2211 computedValues.m_extent = max<LayoutUnit>(floatValueForLength(logicalWidthLength, 0) + borderAndPaddingLogicalWidth(), minPreferredLogicalWidth());
2215 // Width calculations
2216 if (treatAsReplaced)
2217 computedValues.m_extent = logicalWidthLength.value() + borderAndPaddingLogicalWidth();
2219 LayoutUnit containerWidthInInlineDirection = containerLogicalWidth;
2220 if (hasPerpendicularContainingBlock)
2221 containerWidthInInlineDirection = perpendicularContainingBlockLogicalHeight();
2222 LayoutUnit preferredWidth = computeLogicalWidthUsing(MainOrPreferredSize, styleToUse->logicalWidth(), containerWidthInInlineDirection, cb);
2223 computedValues.m_extent = constrainLogicalWidthByMinMax(preferredWidth, containerWidthInInlineDirection, cb);
2226 // Margin calculations.
2227 if (hasPerpendicularContainingBlock || isFloating() || isInline()) {
2228 computedValues.m_margins.m_start = minimumValueForLength(styleToUse->marginStart(), containerLogicalWidth);
2229 computedValues.m_margins.m_end = minimumValueForLength(styleToUse->marginEnd(), containerLogicalWidth);
2231 bool hasInvertedDirection = cb->style()->isLeftToRightDirection() != style()->isLeftToRightDirection();
2232 computeInlineDirectionMargins(cb, containerLogicalWidth, computedValues.m_extent,
2233 hasInvertedDirection ? computedValues.m_margins.m_end : computedValues.m_margins.m_start,
2234 hasInvertedDirection ? computedValues.m_margins.m_start : computedValues.m_margins.m_end);
2237 if (!hasPerpendicularContainingBlock && containerLogicalWidth && containerLogicalWidth != (computedValues.m_extent + computedValues.m_margins.m_start + computedValues.m_margins.m_end)
2238 && !isFloating() && !isInline() && !cb->isFlexibleBoxIncludingDeprecated() && !cb->isRenderGrid()) {
2239 LayoutUnit newMargin = containerLogicalWidth - computedValues.m_extent - cb->marginStartForChild(this);
2240 bool hasInvertedDirection = cb->style()->isLeftToRightDirection() != style()->isLeftToRightDirection();
2241 if (hasInvertedDirection)
2242 computedValues.m_margins.m_start = newMargin;
2244 computedValues.m_margins.m_end = newMargin;
2247 if (styleToUse->textAutosizingMultiplier() != 1 && styleToUse->marginStart().type() == Fixed) {
2248 Node* parentNode = generatingNode();
2249 if (parentNode && (isHTMLOListElement(*parentNode) || isHTMLUListElement(*parentNode))) {
2250 // Make sure the markers in a list are properly positioned (i.e. not chopped off) when autosized.
2251 const float adjustedMargin = (1 - 1.0 / styleToUse->textAutosizingMultiplier()) * getMaxWidthListMarker(this);
2252 bool hasInvertedDirection = cb->style()->isLeftToRightDirection() != style()->isLeftToRightDirection();
2253 if (hasInvertedDirection)
2254 computedValues.m_margins.m_end += adjustedMargin;
2256 computedValues.m_margins.m_start += adjustedMargin;
2261 LayoutUnit RenderBox::fillAvailableMeasure(LayoutUnit availableLogicalWidth) const
2263 LayoutUnit marginStart = 0;
2264 LayoutUnit marginEnd = 0;
2265 return fillAvailableMeasure(availableLogicalWidth, marginStart, marginEnd);
2268 LayoutUnit RenderBox::fillAvailableMeasure(LayoutUnit availableLogicalWidth, LayoutUnit& marginStart, LayoutUnit& marginEnd) const
2270 marginStart = minimumValueForLength(style()->marginStart(), availableLogicalWidth);
2271 marginEnd = minimumValueForLength(style()->marginEnd(), availableLogicalWidth);
2272 return availableLogicalWidth - marginStart - marginEnd;
2275 LayoutUnit RenderBox::computeIntrinsicLogicalWidthUsing(Length logicalWidthLength, LayoutUnit availableLogicalWidth, LayoutUnit borderAndPadding) const
2277 if (logicalWidthLength.type() == FillAvailable)
2278 return fillAvailableMeasure(availableLogicalWidth);
2280 LayoutUnit minLogicalWidth = 0;
2281 LayoutUnit maxLogicalWidth = 0;
2282 computeIntrinsicLogicalWidths(minLogicalWidth, maxLogicalWidth);
2284 if (logicalWidthLength.type() == MinContent)
2285 return minLogicalWidth + borderAndPadding;
2287 if (logicalWidthLength.type() == MaxContent)
2288 return maxLogicalWidth + borderAndPadding;
2290 if (logicalWidthLength.type() == FitContent) {
2291 minLogicalWidth += borderAndPadding;
2292 maxLogicalWidth += borderAndPadding;
2293 return max(minLogicalWidth, min(maxLogicalWidth, fillAvailableMeasure(availableLogicalWidth)));
2296 ASSERT_NOT_REACHED();
2300 LayoutUnit RenderBox::computeLogicalWidthUsing(SizeType widthType, Length logicalWidth, LayoutUnit availableLogicalWidth, const RenderBlock* cb) const
2302 if (!logicalWidth.isIntrinsicOrAuto()) {
2303 // FIXME: If the containing block flow is perpendicular to our direction we need to use the available logical height instead.
2304 return adjustBorderBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, availableLogicalWidth));
2307 if (logicalWidth.isIntrinsic())
2308 return computeIntrinsicLogicalWidthUsing(logicalWidth, availableLogicalWidth, borderAndPaddingLogicalWidth());
2310 LayoutUnit marginStart = 0;
2311 LayoutUnit marginEnd = 0;
2312 LayoutUnit logicalWidthResult = fillAvailableMeasure(availableLogicalWidth, marginStart, marginEnd);
2314 if (shrinkToAvoidFloats() && cb->containsFloats())
2315 logicalWidthResult = min(logicalWidthResult, shrinkLogicalWidthToAvoidFloats(marginStart, marginEnd, toRenderBlockFlow(cb)));
2317 if (widthType == MainOrPreferredSize && sizesLogicalWidthToFitContent(widthType))
2318 return max(minPreferredLogicalWidth(), min(maxPreferredLogicalWidth(), logicalWidthResult));
2319 return logicalWidthResult;
2322 static bool columnFlexItemHasStretchAlignment(const RenderObject* flexitem)
2324 RenderObject* parent = flexitem->parent();
2325 // auto margins mean we don't stretch. Note that this function will only be used for
2326 // widths, so we don't have to check marginBefore/marginAfter.
2327 ASSERT(parent->style()->isColumnFlexDirection());
2328 if (flexitem->style()->marginStart().isAuto() || flexitem->style()->marginEnd().isAuto())
2330 return flexitem->style()->alignSelf() == ItemPositionStretch || (flexitem->style()->alignSelf() == ItemPositionAuto && parent->style()->alignItems() == ItemPositionStretch);
2333 static bool isStretchingColumnFlexItem(const RenderObject* flexitem)
2335 RenderObject* parent = flexitem->parent();
2336 if (parent->isDeprecatedFlexibleBox() && parent->style()->boxOrient() == VERTICAL && parent->style()->boxAlign() == BSTRETCH)
2339 // We don't stretch multiline flexboxes because they need to apply line spacing (align-content) first.
2340 if (parent->isFlexibleBox() && parent->style()->flexWrap() == FlexNoWrap && parent->style()->isColumnFlexDirection() && columnFlexItemHasStretchAlignment(flexitem))
2345 bool RenderBox::sizesLogicalWidthToFitContent(SizeType widthType) const
2347 // Marquees in WinIE are like a mixture of blocks and inline-blocks. They size as though they're blocks,
2348 // but they allow text to sit on the same line as the marquee.
2349 if (isFloating() || (isInlineBlockOrInlineTable() && !isMarquee()))
2352 // This code may look a bit strange. Basically width:intrinsic should clamp the size when testing both
2353 // min-width and width. max-width is only clamped if it is also intrinsic.
2354 Length logicalWidth = (widthType == MaxSize) ? style()->logicalMaxWidth() : style()->logicalWidth();
2355 if (logicalWidth.type() == Intrinsic)
2358 // Children of a horizontal marquee do not fill the container by default.
2359 // FIXME: Need to deal with MAUTO value properly. It could be vertical.
2360 // FIXME: Think about block-flow here. Need to find out how marquee direction relates to
2361 // block-flow (as well as how marquee overflow should relate to block flow).
2362 // https://bugs.webkit.org/show_bug.cgi?id=46472
2363 if (parent()->isMarquee()) {
2364 EMarqueeDirection dir = parent()->style()->marqueeDirection();
2365 if (dir == MAUTO || dir == MFORWARD || dir == MBACKWARD || dir == MLEFT || dir == MRIGHT)
2369 // Flexible box items should shrink wrap, so we lay them out at their intrinsic widths.
2370 // In the case of columns that have a stretch alignment, we go ahead and layout at the
2371 // stretched size to avoid an extra layout when applying alignment.
2372 if (parent()->isFlexibleBox()) {
2373 // For multiline columns, we need to apply align-content first, so we can't stretch now.
2374 if (!parent()->style()->isColumnFlexDirection() || parent()->style()->flexWrap() != FlexNoWrap)
2376 if (!columnFlexItemHasStretchAlignment(this))
2380 // Flexible horizontal boxes lay out children at their intrinsic widths. Also vertical boxes
2381 // that don't stretch their kids lay out their children at their intrinsic widths.
2382 // FIXME: Think about block-flow here.
2383 // https://bugs.webkit.org/show_bug.cgi?id=46473
2384 if (parent()->isDeprecatedFlexibleBox() && (parent()->style()->boxOrient() == HORIZONTAL || parent()->style()->boxAlign() != BSTRETCH))
2387 // Button, input, select, textarea, and legend treat width value of 'auto' as 'intrinsic' unless it's in a
2388 // stretching column flexbox.
2389 // FIXME: Think about block-flow here.
2390 // https://bugs.webkit.org/show_bug.cgi?id=46473
2391 if (logicalWidth.type() == Auto && !isStretchingColumnFlexItem(this) && autoWidthShouldFitContent())
2394 if (isHorizontalWritingMode() != containingBlock()->isHorizontalWritingMode())
2400 bool RenderBox::autoWidthShouldFitContent() const
2402 return node() && (isHTMLInputElement(*node()) || isHTMLSelectElement(*node()) || isHTMLButtonElement(*node())
2403 || isHTMLTextAreaElement(*node()) || (isHTMLLegendElement(*node()) && !style()->hasOutOfFlowPosition()));
2406 void RenderBox::computeInlineDirectionMargins(RenderBlock* containingBlock, LayoutUnit containerWidth, LayoutUnit childWidth, LayoutUnit& marginStart, LayoutUnit& marginEnd) const
2408 const RenderStyle* containingBlockStyle = containingBlock->style();
2409 Length marginStartLength = style()->marginStartUsing(containingBlockStyle);
2410 Length marginEndLength = style()->marginEndUsing(containingBlockStyle);
2412 if (isFloating() || isInline()) {
2413 // Inline blocks/tables and floats don't have their margins increased.
2414 marginStart = minimumValueForLength(marginStartLength, containerWidth);
2415 marginEnd = minimumValueForLength(marginEndLength, containerWidth);
2419 if (containingBlock->isFlexibleBox()) {
2420 // We need to let flexbox handle the margin adjustment - otherwise, flexbox
2421 // will think we're wider than we actually are and calculate line sizes wrong.
2422 // See also http://dev.w3.org/csswg/css-flexbox/#auto-margins
2423 if (marginStartLength.isAuto())
2424 marginStartLength.setValue(0);
2425 if (marginEndLength.isAuto())
2426 marginEndLength.setValue(0);
2429 LayoutUnit availableWidth = containerWidth;
2430 if (avoidsFloats() && containingBlock->containsFloats())
2431 availableWidth = containingBlockAvailableLineWidth();
2433 // Case One: The object is being centered in the containing block's available logical width.
2434 if ((marginStartLength.isAuto() && marginEndLength.isAuto() && childWidth < availableWidth)
2435 || (!marginStartLength.isAuto() && !marginEndLength.isAuto() && containingBlock->style()->textAlign() == WEBKIT_CENTER)) {
2436 // Other browsers center the margin box for align=center elements so we match them here.
2437 LayoutUnit marginStartWidth = minimumValueForLength(marginStartLength, containerWidth);
2438 LayoutUnit marginEndWidth = minimumValueForLength(marginEndLength, containerWidth);
2439 LayoutUnit centeredMarginBoxStart = max<LayoutUnit>(0, (availableWidth - childWidth - marginStartWidth - marginEndWidth) / 2);
2440 marginStart = centeredMarginBoxStart + marginStartWidth;
2441 marginEnd = availableWidth - childWidth - marginStart + marginEndWidth;
2445 // Case Two: The object is being pushed to the start of the containing block's available logical width.
2446 if (marginEndLength.isAuto() && childWidth < availableWidth) {
2447 marginStart = valueForLength(marginStartLength, containerWidth);
2448 marginEnd = availableWidth - childWidth - marginStart;
2452 // Case Three: The object is being pushed to the end of the containing block's available logical width.
2453 bool pushToEndFromTextAlign = !marginEndLength.isAuto() && ((!containingBlockStyle->isLeftToRightDirection() && containingBlockStyle->textAlign() == WEBKIT_LEFT)
2454 || (containingBlockStyle->isLeftToRightDirection() && containingBlockStyle->textAlign() == WEBKIT_RIGHT));
2455 if ((marginStartLength.isAuto() && childWidth < availableWidth) || pushToEndFromTextAlign) {
2456 marginEnd = valueForLength(marginEndLength, containerWidth);
2457 marginStart = availableWidth - childWidth - marginEnd;
2461 // Case Four: Either no auto margins, or our width is >= the container width (css2.1, 10.3.3). In that case
2462 // auto margins will just turn into 0.
2463 marginStart = minimumValueForLength(marginStartLength, containerWidth);
2464 marginEnd = minimumValueForLength(marginEndLength, containerWidth);
2467 static bool shouldFlipBeforeAfterMargins(const RenderStyle* containingBlockStyle, const RenderStyle* childStyle)
2469 ASSERT(containingBlockStyle->isHorizontalWritingMode() != childStyle->isHorizontalWritingMode());
2470 WritingMode childWritingMode = childStyle->writingMode();
2471 bool shouldFlip = false;
2472 switch (containingBlockStyle->writingMode()) {
2473 case TopToBottomWritingMode:
2474 shouldFlip = (childWritingMode == RightToLeftWritingMode);
2476 case BottomToTopWritingMode:
2477 shouldFlip = (childWritingMode == RightToLeftWritingMode);
2479 case RightToLeftWritingMode:
2480 shouldFlip = (childWritingMode == BottomToTopWritingMode);
2482 case LeftToRightWritingMode:
2483 shouldFlip = (childWritingMode == BottomToTopWritingMode);
2487 if (!containingBlockStyle->isLeftToRightDirection())
2488 shouldFlip = !shouldFlip;
2493 void RenderBox::updateLogicalHeight()
2495 m_intrinsicContentLogicalHeight = contentLogicalHeight();
2497 LogicalExtentComputedValues computedValues;
2498 computeLogicalHeight(logicalHeight(), logicalTop(), computedValues);
2500 setLogicalHeight(computedValues.m_extent);
2501 setLogicalTop(computedValues.m_position);
2502 setMarginBefore(computedValues.m_margins.m_before);
2503 setMarginAfter(computedValues.m_margins.m_after);
2506 void RenderBox::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const
2508 computedValues.m_extent = logicalHeight;
2509 computedValues.m_position = logicalTop;
2511 // Cell height is managed by the table and inline non-replaced elements do not support a height property.
2512 if (isTableCell() || (isInline() && !isReplaced()))
2516 if (isOutOfFlowPositioned())
2517 computePositionedLogicalHeight(computedValues);
2519 RenderBlock* cb = containingBlock();
2520 bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHorizontalWritingMode();
2522 if (!hasPerpendicularContainingBlock) {
2523 bool shouldFlipBeforeAfter = cb->style()->writingMode() != style()->writingMode();
2524 computeBlockDirectionMargins(cb,
2525 shouldFlipBeforeAfter ? computedValues.m_margins.m_after : computedValues.m_margins.m_before,
2526 shouldFlipBeforeAfter ? computedValues.m_margins.m_before : computedValues.m_margins.m_after);
2529 // For tables, calculate margins only.
2531 if (hasPerpendicularContainingBlock) {
2532 bool shouldFlipBeforeAfter = shouldFlipBeforeAfterMargins(cb->style(), style());
2533 computeInlineDirectionMargins(cb, containingBlockLogicalWidthForContent(), computedValues.m_extent,
2534 shouldFlipBeforeAfter ? computedValues.m_margins.m_after : computedValues.m_margins.m_before,
2535 shouldFlipBeforeAfter ? computedValues.m_margins.m_before : computedValues.m_margins.m_after);
2540 // FIXME: Account for block-flow in flexible boxes.
2541 // https://bugs.webkit.org/show_bug.cgi?id=46418
2542 bool inHorizontalBox = parent()->isDeprecatedFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL;
2543 bool stretching = parent()->style()->boxAlign() == BSTRETCH;
2544 bool treatAsReplaced = shouldComputeSizeAsReplaced() && (!inHorizontalBox || !stretching);
2545 bool checkMinMaxHeight = false;
2547 // The parent box is flexing us, so it has increased or decreased our height. We have to
2548 // grab our cached flexible height.
2549 // FIXME: Account for block-flow in flexible boxes.
2550 // https://bugs.webkit.org/show_bug.cgi?id=46418
2551 if (hasOverrideHeight() && parent()->isFlexibleBoxIncludingDeprecated())
2552 h = Length(overrideLogicalContentHeight(), Fixed);
2553 else if (treatAsReplaced)
2554 h = Length(computeReplacedLogicalHeight(), Fixed);
2556 h = style()->logicalHeight();
2557 checkMinMaxHeight = true;
2560 // Block children of horizontal flexible boxes fill the height of the box.
2561 // FIXME: Account for block-flow in flexible boxes.
2562 // https://bugs.webkit.org/show_bug.cgi?id=46418
2563 if (h.isAuto() && inHorizontalBox && toRenderDeprecatedFlexibleBox(parent())->isStretchingChildren()) {
2564 h = Length(parentBox()->contentLogicalHeight() - marginBefore() - marginAfter() - borderAndPaddingLogicalHeight(), Fixed);
2565 checkMinMaxHeight = false;
2568 LayoutUnit heightResult;
2569 if (checkMinMaxHeight) {
2570 heightResult = computeLogicalHeightUsing(style()->logicalHeight(), computedValues.m_extent - borderAndPaddingLogicalHeight());
2571 if (heightResult == -1)
2572 heightResult = computedValues.m_extent;
2573 heightResult = constrainLogicalHeightByMinMax(heightResult, computedValues.m_extent - borderAndPaddingLogicalHeight());
2575 // The only times we don't check min/max height are when a fixed length has
2576 // been given as an override. Just use that. The value has already been adjusted
2578 ASSERT(h.isFixed());
2579 heightResult = h.value() + borderAndPaddingLogicalHeight();
2582 computedValues.m_extent = heightResult;
2584 if (hasPerpendicularContainingBlock) {
2585 bool shouldFlipBeforeAfter = shouldFlipBeforeAfterMargins(cb->style(), style());
2586 computeInlineDirectionMargins(cb, containingBlockLogicalWidthForContent(), heightResult,
2587 shouldFlipBeforeAfter ? computedValues.m_margins.m_after : computedValues.m_margins.m_before,
2588 shouldFlipBeforeAfter ? computedValues.m_margins.m_before : computedValues.m_margins.m_after);
2592 // WinIE quirk: The <html> block always fills the entire canvas in quirks mode. The <body> always fills the
2593 // <html> block in quirks mode. Only apply this quirk if the block is normal flow and no height
2594 // is specified. When we're printing, we also need this quirk if the body or root has a percentage
2595 // height since we don't set a height in RenderView when we're printing. So without this quirk, the
2596 // height has nothing to be a percentage of, and it ends up being 0. That is bad.
2597 bool paginatedContentNeedsBaseHeight = document().printing() && h.isPercent()
2598 && (isRoot() || (isBody() && document().documentElement()->renderer()->style()->logicalHeight().isPercent())) && !isInline();
2599 if (stretchesToViewport() || paginatedContentNeedsBaseHeight) {
2600 LayoutUnit margins = collapsedMarginBefore() + collapsedMarginAfter();
2601 LayoutUnit visibleHeight = viewLogicalHeightForPercentages();
2603 computedValues.m_extent = max(computedValues.m_extent, visibleHeight - margins);
2605 LayoutUnit marginsBordersPadding = margins + parentBox()->marginBefore() + parentBox()->marginAfter() + parentBox()->borderAndPaddingLogicalHeight();
2606 computedValues.m_extent = max(computedValues.m_extent, visibleHeight - marginsBordersPadding);
2611 LayoutUnit RenderBox::viewLogicalHeightForPercentages() const
2613 if (document().printing())
2614 return static_cast<LayoutUnit>(view()->pageLogicalHeight());
2615 return view()->viewLogicalHeight();
2618 LayoutUnit RenderBox::computeLogicalHeightUsing(const Length& height, LayoutUnit intrinsicContentHeight) const
2620 LayoutUnit logicalHeight = computeContentAndScrollbarLogicalHeightUsing(height, intrinsicContentHeight);
2621 if (logicalHeight != -1)
2622 logicalHeight = adjustBorderBoxLogicalHeightForBoxSizing(logicalHeight);
2623 return logicalHeight;
2626 LayoutUnit RenderBox::computeContentLogicalHeight(const Length& height, LayoutUnit intrinsicContentHeight) const
2628 LayoutUnit heightIncludingScrollbar = computeContentAndScrollbarLogicalHeightUsing(height, intrinsicContentHeight);
2629 if (heightIncludingScrollbar == -1)
2631 return std::max<LayoutUnit>(0, adjustContentBoxLogicalHeightForBoxSizing(heightIncludingScrollbar) - scrollbarLogicalHeight());
2634 LayoutUnit RenderBox::computeIntrinsicLogicalContentHeightUsing(Length logicalHeightLength, LayoutUnit intrinsicContentHeight, LayoutUnit borderAndPadding) const
2636 // FIXME(cbiesinger): The css-sizing spec is considering changing what min-content/max-content should resolve to.
2637 // If that happens, this code will have to change.
2638 if (logicalHeightLength.isMinContent() || logicalHeightLength.isMaxContent() || logicalHeightLength.isFitContent()) {
2640 return intrinsicSize().height();
2641 if (m_intrinsicContentLogicalHeight != -1)
2642 return m_intrinsicContentLogicalHeight;
2643 return intrinsicContentHeight;
2645 if (logicalHeightLength.isFillAvailable())
2646 return containingBlock()->availableLogicalHeight(ExcludeMarginBorderPadding) - borderAndPadding;
2647 ASSERT_NOT_REACHED();
2651 LayoutUnit RenderBox::computeContentAndScrollbarLogicalHeightUsing(const Length& height, LayoutUnit intrinsicContentHeight) const
2653 // FIXME(cbiesinger): The css-sizing spec is considering changing what min-content/max-content should resolve to.
2654 // If that happens, this code will have to change.
2655 if (height.isIntrinsic()) {
2656 if (intrinsicContentHeight == -1)
2657 return -1; // Intrinsic height isn't available.
2658 return computeIntrinsicLogicalContentHeightUsing(height, intrinsicContentHeight, borderAndPaddingLogicalHeight());
2660 if (height.isFixed())
2661 return height.value();
2662 if (height.isPercent())
2663 return computePercentageLogicalHeight(height);
2667 bool RenderBox::skipContainingBlockForPercentHeightCalculation(const RenderBox* containingBlock) const
2669 // Flow threads for multicol or paged overflow should be skipped. They are invisible to the DOM,
2670 // and percent heights of children should be resolved against the multicol or paged container.
2671 if (containingBlock->isRenderFlowThread())
2674 // For quirks mode and anonymous blocks, we skip auto-height containingBlocks when computing percentages.
2675 // For standards mode, we treat the percentage as auto if it has an auto-height containing block.
2676 if (!document().inQuirksMode() && !containingBlock->isAnonymousBlock())
2678 return !containingBlock->isTableCell() && !containingBlock->isOutOfFlowPositioned() && containingBlock->style()->logicalHeight().isAuto() && isHorizontalWritingMode() == containingBlock->isHorizontalWritingMode();
2681 LayoutUnit RenderBox::computePercentageLogicalHeight(const Length& height) const
2683 LayoutUnit availableHeight = -1;
2685 bool skippedAutoHeightContainingBlock = false;
2686 RenderBlock* cb = containingBlock();
2687 const RenderBox* containingBlockChild = this;
2688 LayoutUnit rootMarginBorderPaddingHeight = 0;
2689 while (!cb->isRenderView() && skipContainingBlockForPercentHeightCalculation(cb)) {
2690 if (cb->isBody() || cb->isRoot())
2691 rootMarginBorderPaddingHeight += cb->marginBefore() + cb->marginAfter() + cb->borderAndPaddingLogicalHeight();
2692 skippedAutoHeightContainingBlock = true;
2693 containingBlockChild = cb;
2694 cb = cb->containingBlock();
2696 cb->addPercentHeightDescendant(const_cast<RenderBox*>(this));
2698 RenderStyle* cbstyle = cb->style();
2700 // A positioned element that specified both top/bottom or that specifies height should be treated as though it has a height
2701 // explicitly specified that can be used for any percentage computations.
2702 bool isOutOfFlowPositionedWithSpecifiedHeight = cb->isOutOfFlowPositioned() && (!cbstyle->logicalHeight().isAuto() || (!cbstyle->logicalTop().isAuto() && !cbstyle->logicalBottom().isAuto()));
2704 bool includeBorderPadding = isTable();
2706 if (isHorizontalWritingMode() != cb->isHorizontalWritingMode())
2707 availableHeight = containingBlockChild->containingBlockLogicalWidthForContent();
2708 else if (hasOverrideContainingBlockLogicalHeight())
2709 availableHeight = overrideContainingBlockContentLogicalHeight();
2710 else if (cb->isTableCell()) {
2711 if (!skippedAutoHeightContainingBlock) {
2712 // Table cells violate what the CSS spec says to do with heights. Basically we
2713 // don't care if the cell specified a height or not. We just always make ourselves
2714 // be a percentage of the cell's current content height.
2715 if (!cb->hasOverrideHeight()) {
2716 // Normally we would let the cell size intrinsically, but scrolling overflow has to be
2717 // treated differently, since WinIE lets scrolled overflow regions shrink as needed.
2718 // While we can't get all cases right, we can at least detect when the cell has a specified
2719 // height or when the table has a specified height. In these cases we want to initially have
2720 // no size and allow the flexing of the table or the cell to its specified height to cause us
2721 // to grow to fill the space. This could end up being wrong in some cases, but it is
2722 // preferable to the alternative (sizing intrinsically and making the row end up too big).
2723 RenderTableCell* cell = toRenderTableCell(cb);
2724 if (scrollsOverflowY() && (!cell->style()->logicalHeight().isAuto() || !cell->table()->style()->logicalHeight().isAuto()))
2728 availableHeight = cb->overrideLogicalContentHeight();
2729 includeBorderPadding = true;
2731 } else if (cbstyle->logicalHeight().isFixed()) {
2732 LayoutUnit contentBoxHeight = cb->adjustContentBoxLogicalHeightForBoxSizing(cbstyle->logicalHeight().value());
2733 availableHeight = max<LayoutUnit>(0, cb->constrainContentBoxLogicalHeightByMinMax(contentBoxHeight - cb->scrollbarLogicalHeight(), -1));
2734 } else if (cbstyle->logicalHeight().isPercent() && !isOutOfFlowPositionedWithSpecifiedHeight) {
2735 // We need to recur and compute the percentage height for our containing block.
2736 LayoutUnit heightWithScrollbar = cb->computePercentageLogicalHeight(cbstyle->logicalHeight());
2737 if (heightWithScrollbar != -1) {
2738 LayoutUnit contentBoxHeightWithScrollbar = cb->adjustContentBoxLogicalHeightForBoxSizing(heightWithScrollbar);
2739 // We need to adjust for min/max height because this method does not
2740 // handle the min/max of the current block, its caller does. So the
2741 // return value from the recursive call will not have been adjusted
2743 LayoutUnit contentBoxHeight = cb->constrainContentBoxLogicalHeightByMinMax(contentBoxHeightWithScrollbar - cb->scrollbarLogicalHeight(), -1);
2744 availableHeight = max<LayoutUnit>(0, contentBoxHeight);
2746 } else if (isOutOfFlowPositionedWithSpecifiedHeight) {
2747 // Don't allow this to affect the block' height() member variable, since this
2748 // can get called while the block is still laying out its kids.
2749 LogicalExtentComputedValues computedValues;
2750 cb->computeLogicalHeight(cb->logicalHeight(), 0, computedValues);
2751 availableHeight = computedValues.m_extent - cb->borderAndPaddingLogicalHeight() - cb->scrollbarLogicalHeight();
2752 } else if (cb->isRenderView())
2753 availableHeight = viewLogicalHeightForPercentages();
2755 if (availableHeight == -1)
2756 return availableHeight;
2758 availableHeight -= rootMarginBorderPaddingHeight;
2760 LayoutUnit result = valueForLength(height, availableHeight);
2761 if (includeBorderPadding) {
2762 // FIXME: Table cells should default to box-sizing: border-box so we can avoid this hack.
2763 // It is necessary to use the border-box to match WinIE's broken
2764 // box model. This is essential for sizing inside
2765 // table cells using percentage heights.
2766 result -= borderAndPaddingLogicalHeight();
2767 return max<LayoutUnit>(0, result);
2772 LayoutUnit RenderBox::computeReplacedLogicalWidth(ShouldComputePreferred shouldComputePreferred) const
2774 return computeReplacedLogicalWidthRespectingMinMaxWidth(computeReplacedLogicalWidthUsing(style()->logicalWidth()), shouldComputePreferred);
2777 LayoutUnit RenderBox::computeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUnit logicalWidth, ShouldComputePreferred shouldComputePreferred) const
2779 LayoutUnit minLogicalWidth = (shouldComputePreferred == ComputePreferred && style()->logicalMinWidth().isPercent()) || style()->logicalMinWidth().isUndefined() ? logicalWidth : computeReplacedLogicalWidthUsing(style()->logicalMinWidth());
2780 LayoutUnit maxLogicalWidth = (shouldComputePreferred == ComputePreferred && style()->logicalMaxWidth().isPercent()) || style()->logicalMaxWidth().isUndefined() ? logicalWidth : computeReplacedLogicalWidthUsing(style()->logicalMaxWidth());
2781 return max(minLogicalWidth, min(logicalWidth, maxLogicalWidth));
2784 LayoutUnit RenderBox::computeReplacedLogicalWidthUsing(Length logicalWidth) const
2786 switch (logicalWidth.type()) {
2788 return adjustContentBoxLogicalWidthForBoxSizing(logicalWidth.value());
2791 // MinContent/MaxContent don't need the availableLogicalWidth argument.
2792 LayoutUnit availableLogicalWidth = 0;
2793 return computeIntrinsicLogicalWidthUsing(logicalWidth, availableLogicalWidth, borderAndPaddingLogicalWidth()) - borderAndPaddingLogicalWidth();
2799 // FIXME: containingBlockLogicalWidthForContent() is wrong if the replaced element's block-flow is perpendicular to the
2800 // containing block's block-flow.
2801 // https://bugs.webkit.org/show_bug.cgi?id=46496
2802 const LayoutUnit cw = isOutOfFlowPositioned() ? containingBlockLogicalWidthForPositioned(toRenderBoxModelObject(container())) : containingBlockLogicalWidthForContent();
2803 Length containerLogicalWidth = containingBlock()->style()->logicalWidth();
2804 // FIXME: Handle cases when containing block width is calculated or viewport percent.
2805 // https://bugs.webkit.org/show_bug.cgi?id=91071
2806 if (logicalWidth.isIntrinsic())
2807 return computeIntrinsicLogicalWidthUsing(logicalWidth, cw, borderAndPaddingLogicalWidth()) - borderAndPaddingLogicalWidth();
2808 if (cw > 0 || (!cw && (containerLogicalWidth.isFixed() || containerLogicalWidth.isPercent())))
2809 return adjustContentBoxLogicalWidthForBoxSizing(minimumValueForLength(logicalWidth, cw));
2816 return intrinsicLogicalWidth();
2823 ASSERT_NOT_REACHED();
2827 LayoutUnit RenderBox::computeReplacedLogicalHeight() const
2829 return computeReplacedLogicalHeightRespectingMinMaxHeight(computeReplacedLogicalHeightUsing(style()->logicalHeight()));
2832 LayoutUnit RenderBox::computeReplacedLogicalHeightRespectingMinMaxHeight(LayoutUnit logicalHeight) const
2834 LayoutUnit minLogicalHeight = computeReplacedLogicalHeightUsing(style()->logicalMinHeight());
2835 LayoutUnit maxLogicalHeight = style()->logicalMaxHeight().isUndefined() ? logicalHeight : computeReplacedLogicalHeightUsing(style()->logicalMaxHeight());
2836 return max(minLogicalHeight, min(logicalHeight, maxLogicalHeight));
2839 LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(Length logicalHeight) const
2841 switch (logicalHeight.type()) {
2843 return adjustContentBoxLogicalHeightForBoxSizing(logicalHeight.value());
2847 RenderObject* cb = isOutOfFlowPositioned() ? container() : containingBlock();
2848 while (cb->isAnonymous())
2849 cb = cb->containingBlock();
2850 if (cb->isRenderBlock())
2851 toRenderBlock(cb)->addPercentHeightDescendant(const_cast<RenderBox*>(this));
2853 // FIXME: This calculation is not patched for block-flow yet.
2854 // https://bugs.webkit.org/show_bug.cgi?id=46500
2855 if (cb->isOutOfFlowPositioned() && cb->style()->height().isAuto() && !(cb->style()->top().isAuto() || cb->style()->bottom().isAuto())) {
2856 ASSERT_WITH_SECURITY_IMPLICATION(cb->isRenderBlock());
2857 RenderBlock* block = toRenderBlock(cb);
2858 LogicalExtentComputedValues computedValues;
2859 block->computeLogicalHeight(block->logicalHeight(), 0, computedValues);
2860 LayoutUnit newContentHeight = computedValues.m_extent - block->borderAndPaddingLogicalHeight() - block->scrollbarLogicalHeight();
2861 LayoutUnit newHeight = block->adjustContentBoxLogicalHeightForBoxSizing(newContentHeight);
2862 return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeight, newHeight));
2865 // FIXME: availableLogicalHeight() is wrong if the replaced element's block-flow is perpendicular to the
2866 // containing block's block-flow.
2867 // https://bugs.webkit.org/show_bug.cgi?id=46496
2868 LayoutUnit availableHeight;
2869 if (isOutOfFlowPositioned())
2870 availableHeight = containingBlockLogicalHeightForPositioned(toRenderBoxModelObject(cb));
2872 availableHeight = containingBlockLogicalHeightForContent(IncludeMarginBorderPadding);
2873 // It is necessary to use the border-box to match WinIE's broken
2874 // box model. This is essential for sizing inside
2875 // table cells using percentage heights.
2876 // FIXME: This needs to be made block-flow-aware. If the cell and image are perpendicular block-flows, this isn't right.
2877 // https://bugs.webkit.org/show_bug.cgi?id=46997
2878 while (cb && !cb->isRenderView() && (cb->style()->logicalHeight().isAuto() || cb->style()->logicalHeight().isPercent())) {
2879 if (cb->isTableCell()) {
2880 // Don't let table cells squeeze percent-height replaced elements
2881 // <http://bugs.webkit.org/show_bug.cgi?id=15359>
2882 availableHeight = max(availableHeight, intrinsicLogicalHeight());
2883 return valueForLength(logicalHeight, availableHeight - borderAndPaddingLogicalHeight());
2885 toRenderBlock(cb)->addPercentHeightDescendant(const_cast<RenderBox*>(this));
2886 cb = cb->containingBlock();
2889 return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeight, availableHeight));
2895 return adjustContentBoxLogicalHeightForBoxSizing(computeIntrinsicLogicalContentHeightUsing(logicalHeight, intrinsicLogicalHeight(), borderAndPaddingHeight()));
2897 return intrinsicLogicalHeight();
2901 LayoutUnit RenderBox::availableLogicalHeight(AvailableLogicalHeightType heightType) const
2903 return constrainLogicalHeightByMinMax(availableLogicalHeightUsing(style()->logicalHeight(), heightType), -1);
2906 LayoutUnit RenderBox::availableLogicalHeightUsing(const Length& h, AvailableLogicalHeightType heightType) const
2909 return isHorizontalWritingMode() ? toRenderView(this)->frameView()->visibleHeight() : toRenderView(this)->frameView()->visibleWidth();
2911 // We need to stop here, since we don't want to increase the height of the table
2912 // artificially. We're going to rely on this cell getting expanded to some new
2913 // height, and then when we lay out again we'll use the calculation below.
2914 if (isTableCell() && (h.isAuto() || h.isPercent())) {
2915 if (hasOverrideHeight())
2916 return overrideLogicalContentHeight();
2917 return logicalHeight() - borderAndPaddingLogicalHeight();
2920 if (h.isPercent() && isOutOfFlowPositioned() && !isRenderFlowThread()) {
2921 // FIXME: This is wrong if the containingBlock has a perpendicular writing mode.
2922 LayoutUnit availableHeight = containingBlockLogicalHeightForPositioned(containingBlock());
2923 return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(h, availableHeight));
2926 LayoutUnit heightIncludingScrollbar = computeContentAndScrollbarLogicalHeightUsing(h, -1);
2927 if (heightIncludingScrollbar != -1)
2928 return std::max<LayoutUnit>(0, adjustContentBoxLogicalHeightForBoxSizing(heightIncludingScrollbar) - scrollbarLogicalHeight());
2930 // FIXME: Check logicalTop/logicalBottom here to correctly handle vertical writing-mode.
2931 // https://bugs.webkit.org/show_bug.cgi?id=46500
2932 if (isRenderBlock() && isOutOfFlowPositioned() && style()->height().isAuto() && !(style()->top().isAuto() || style()->bottom().isAuto())) {
2933 RenderBlock* block = const_cast<RenderBlock*>(toRenderBlock(this));
2934 LogicalExtentComputedValues computedValues;
2935 block->computeLogicalHeight(block->logicalHeight(), 0, computedValues);
2936 LayoutUnit newContentHeight = computedValues.m_extent - block->borderAndPaddingLogicalHeight() - block->scrollbarLogicalHeight();
2937 return adjustContentBoxLogicalHeightForBoxSizing(newContentHeight);
2940 // FIXME: This is wrong if the containingBlock has a perpendicular writing mode.
2941 LayoutUnit availableHeight = containingBlockLogicalHeightForContent(heightType);
2942 if (heightType == ExcludeMarginBorderPadding) {
2943 // FIXME: Margin collapsing hasn't happened yet, so this incorrectly removes collapsed margins.
2944 availableHeight -= marginBefore() + marginAfter() + borderAndPaddingLogicalHeight();
2946 return availableHeight;
2949 void RenderBox::computeBlockDirectionMargins(const RenderBlock* containingBlock, LayoutUnit& marginBefore, LayoutUnit& marginAfter) const
2951 if (isTableCell()) {
2952 // FIXME: Not right if we allow cells to have different directionality than the table. If we do allow this, though,
2953 // we may just do it with an extra anonymous block inside the cell.
2959 // Margins are calculated with respect to the logical width of
2960 // the containing block (8.3)
2961 LayoutUnit cw = containingBlockLogicalWidthForContent();
2962 RenderStyle* containingBlockStyle = containingBlock->style();
2963 marginBefore = minimumValueForLength(style()->marginBeforeUsing(containingBlockStyle), cw);
2964 marginAfter = minimumValueForLength(style()->marginAfterUsing(containingBlockStyle), cw);
2967 void RenderBox::computeAndSetBlockDirectionMargins(const RenderBlock* containingBlock)
2969 LayoutUnit marginBefore;
2970 LayoutUnit marginAfter;
2971 computeBlockDirectionMargins(containingBlock, marginBefore, marginAfter);
2972 containingBlock->setMarginBeforeForChild(this, marginBefore);
2973 containingBlock->setMarginAfterForChild(this, marginAfter);
2976 LayoutUnit RenderBox::containingBlockLogicalWidthForPositioned(const RenderBoxModelObject* containingBlock, bool checkForPerpendicularWritingMode) const
2978 if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWritingMode() != isHorizontalWritingMode())
2979 return containingBlockLogicalHeightForPositioned(containingBlock, false);
2981 // Use viewport as container for top-level fixed-position elements.
2982 if (style()->position() == FixedPosition && containingBlock->isRenderView()) {
2983 const RenderView* view = toRenderView(containingBlock);
2984 if (FrameView* frameView = view->frameView()) {
2985 LayoutRect viewportRect = frameView->viewportConstrainedVisibleContentRect();
2986 return containingBlock->isHorizontalWritingMode() ? viewportRect.width() : viewportRect.height();
2990 if (containingBlock->isBox())
2991 return toRenderBox(containingBlock)->clientLogicalWidth();
2993 ASSERT(containingBlock->isRenderInline() && containingBlock->isInFlowPositioned());
2995 const RenderInline* flow = toRenderInline(containingBlock);
2996 InlineFlowBox* first = flow->firstLineBox();
2997 InlineFlowBox* last = flow->lastLineBox();
2999 // If the containing block is empty, return a width of 0.
3000 if (!first || !last)
3003 LayoutUnit fromLeft;
3004 LayoutUnit fromRight;
3005 if (containingBlock->style()->isLeftToRightDirection()) {
3006 fromLeft = first->logicalLeft() + first->borderLogicalLeft();
3007 fromRight = last->logicalLeft() + last->logicalWidth() - last->borderLogicalRight();
3009 fromRight = first->logicalLeft() + first->logicalWidth() - first->borderLogicalRight();
3010 fromLeft = last->logicalLeft() + last->borderLogicalLeft();
3013 return max<LayoutUnit>(0, fromRight - fromLeft);
3016 LayoutUnit RenderBox::containingBlockLogicalHeightForPositioned(const RenderBoxModelObject* containingBlock, bool checkForPerpendicularWritingMode) const
3018 if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWritingMode() != isHorizontalWritingMode())
3019 return containingBlockLogicalWidthForPositioned(containingBlock, false);
3021 // Use viewport as container for top-level fixed-position elements.
3022 if (style()->position() == FixedPosition && containingBlock->isRenderView()) {
3023 const RenderView* view = toRenderView(containingBlock);
3024 if (FrameView* frameView = view->frameView()) {
3025 LayoutRect viewportRect = frameView->viewportConstrainedVisibleContentRect();
3026 return containingBlock->isHorizontalWritingMode() ? viewportRect.height() : viewportRect.width();
3030 if (containingBlock->isBox()) {
3031 const RenderBlock* cb = containingBlock->isRenderBlock() ?
3032 toRenderBlock(containingBlock) : containingBlock->containingBlock();
3033 return cb->clientLogicalHeight();
3036 ASSERT(containingBlock->isRenderInline() && containingBlock->isInFlowPositioned());
3038 const RenderInline* flow = toRenderInline(containingBlock);
3039 InlineFlowBox* first = flow->firstLineBox();
3040 InlineFlowBox* last = flow->lastLineBox();
3042 // If the containing block is empty, return a height of 0.
3043 if (!first || !last)
3046 LayoutUnit heightResult;
3047 LayoutRect boundingBox = flow->linesBoundingBox();
3048 if (containingBlock->isHorizontalWritingMode())
3049 heightResult = boundingBox.height();
3051 heightResult = boundingBox.width();
3052 heightResult -= (containingBlock->borderBefore() + containingBlock->borderAfter());
3053 return heightResult;
3056 static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRight, const RenderBox* child, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalWidth)
3058 if (!logicalLeft.isAuto() || !logicalRight.isAuto())
3061 // FIXME: The static distance computation has not been patched for mixed writing modes yet.
3062 if (child->parent()->style()->direction() == LTR) {
3063 LayoutUnit staticPosition = child->layer()->staticInlinePosition() - containerBlock->borderLogicalLeft();
3064 for (RenderObject* curr = child->parent(); curr && curr != containerBlock; curr = curr->container()) {
3065 if (curr->isBox()) {
3066 staticPosition += toRenderBox(curr)->logicalLeft();
3067 if (toRenderBox(curr)->isRelPositioned())
3068 staticPosition += toRenderBox(curr)->relativePositionOffset().width();
3069 } else if (curr->isInline()) {
3070 if (curr->isRelPositioned()) {
3071 if (!curr->style()->logicalLeft().isAuto())
3072 staticPosition += curr->style()->logicalLeft().value();
3074 staticPosition -= curr->style()->logicalRight().value();
3078 logicalLeft.setValue(Fixed, staticPosition);
3080 RenderBox* enclosingBox = child->parent()->enclosingBox();
3081 LayoutUnit staticPosition = child->layer()->staticInlinePosition() + containerLogicalWidth + containerBlock->borderLogicalLeft();
3082 for (RenderObject* curr = child->parent(); curr; curr = curr->container()) {
3083 if (curr->isBox()) {
3084 if (curr != containerBlock) {
3085 staticPosition -= toRenderBox(curr)->logicalLeft();
3086 if (toRenderBox(curr)->isRelPositioned())
3087 staticPosition -= toRenderBox(curr)->relativePositionOffset().width();
3089 if (curr == enclosingBox)
3090 staticPosition -= enclosingBox->logicalWidth();
3091 } else if (curr->isInline()) {
3092 if (curr->isRelPositioned()) {
3093 if (!curr->style()->logicalLeft().isAuto())
3094 staticPosition -= curr->style()->logicalLeft().value();
3096 staticPosition += curr->style()->logicalRight().value();
3099 if (curr == containerBlock)
3102 logicalRight.setValue(Fixed, staticPosition);
3106 void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& computedValues) const
3109 computePositionedLogicalWidthReplaced(computedValues);
3114 // FIXME 1: Should we still deal with these the cases of 'left' or 'right' having
3115 // the type 'static' in determining whether to calculate the static distance?
3116 // NOTE: 'static' is not a legal value for 'left' or 'right' as of CSS 2.1.
3118 // FIXME 2: Can perhaps optimize out cases when max-width/min-width are greater
3119 // than or less than the computed width(). Be careful of box-sizing and
3120 // percentage issues.
3122 // The following is based off of the W3C Working Draft from April 11, 2006 of
3123 // CSS 2.1: Section 10.3.7 "Absolutely positioned, non-replaced elements"
3124 // <http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width>
3125 // (block-style-comments in this function and in computePositionedLogicalWidthUsing()
3126 // correspond to text from the spec)
3129 // We don't use containingBlock(), since we may be positioned by an enclosing
3130 // relative positioned inline.
3131 const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
3133 const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock);
3135 // Use the container block's direction except when calculating the static distance
3136 // This conforms with the reference results for abspos-replaced-width-margin-000.htm
3137 // of the CSS 2.1 test suite
3138 TextDirection containerDirection = containerBlock->style()->direction();
3140 bool isHorizontal = isHorizontalWritingMode();
3141 const LayoutUnit bordersPlusPadding = borderAndPaddingLogicalWidth();
3142 const Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->marginTop();
3143 const Length marginLogicalRight = isHorizontal ? style()->marginRight() : style()->marginBottom();
3145 Length logicalLeftLength = style()->logicalLeft();
3146 Length logicalRightLength = style()->logicalRight();
3148 /*---------------------------------------------------------------------------*\
3149 * For the purposes of this section and the next, the term "static position"
3150 * (of an element) refers, roughly, to the position an element would have had
3151 * in the normal flow. More precisely:
3153 * * The static position for 'left' is the distance from the left edge of the
3154 * containing block to the left margin edge of a hypothetical box that would
3155 * have been the first box of the element if its 'position' property had
3156 * been 'static' and 'float' had been 'none'. The value is negative if the
3157 * hypothetical box is to the left of the containing block.
3158 * * The static position for 'right' is the distance from the right edge of the
3159 * containing block to the right margin edge of the same hypothetical box as
3160 * above. The value is positive if the hypothetical box is to the left of the
3161 * containing block's edge.
3163 * But rather than actually calculating the dimensions of that hypothetical box,
3164 * user agents are free to make a guess at its probable position.
3166 * For the purposes of calculating the static position, the containing block of
3167 * fixed positioned elements is the initial containing block instead of the
3168 * viewport, and all scrollable boxes should be assumed to be scrolled to their
3170 \*---------------------------------------------------------------------------*/
3173 // Calculate the static distance if needed.
3174 computeInlineStaticDistance(logicalLeftLength, logicalRightLength, this, containerBlock, containerLogicalWidth);
3176 // Calculate constraint equation values for 'width' case.
3177 computePositionedLogicalWidthUsing(style()->logicalWidth(), containerBlock, containerDirection,
3178 containerLogicalWidth, bordersPlusPadding,
3179 logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight,
3182 // Calculate constraint equation values for 'max-width' case.
3183 if (!style()->logicalMaxWidth().isUndefined()) {
3184 LogicalExtentComputedValues maxValues;
3186 computePositionedLogicalWidthUsing(style()->logicalMaxWidth(), containerBlock, containerDirection,
3187 containerLogicalWidth, bordersPlusPadding,
3188 logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight,
3191 if (computedValues.m_extent > maxValues.m_extent) {
3192 computedValues.m_extent = maxValues.m_extent;
3193 computedValues.m_position = maxValues.m_position;
3194 computedValues.m_margins.m_start = maxValues.m_margins.m_start;
3195 computedValues.m_margins.m_end = maxValues.m_margins.m_end;
3199 // Calculate constraint equation values for 'min-width' case.
3200 if (!style()->logicalMinWidth().isZero() || style()->logicalMinWidth().isIntrinsic()) {
3201 LogicalExtentComputedValues minValues;
3203 computePositionedLogicalWidthUsing(style()->logicalMinWidth(), containerBlock, containerDirection,
3204 containerLogicalWidth, bordersPlusPadding,
3205 logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight,
3208 if (computedValues.m_extent < minValues.m_extent) {
3209 computedValues.m_extent = minValues.m_extent;
3210 computedValues.m_position = minValues.m_position;
3211 computedValues.m_margins.m_start = minValues.m_margins.m_start;
3212 computedValues.m_margins.m_end = minValues.m_margins.m_end;
3216 computedValues.m_extent += bordersPlusPadding;
3219 static void computeLogicalLeftPositionedOffset(LayoutUnit& logicalLeftPos, const RenderBox* child, LayoutUnit logicalWidthValue, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalWidth)
3221 // Deal with differing writing modes here. Our offset needs to be in the containing block's coordinate space. If the containing block is flipped
3222 // along this axis, then we need to flip the coordinate. This can only happen if the containing block is both a flipped mode and perpendicular to us.
3223 if (containerBlock->isHorizontalWritingMode() != child->isHorizontalWritingMode() && containerBlock->style()->isFlippedBlocksWritingMode()) {
3224 logicalLeftPos = containerLogicalWidth - logicalWidthValue - logicalLeftPos;
3225 logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->borderRight() : containerBlock->borderBottom());
3227 logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->borderLeft() : containerBlock->borderTop());
3231 void RenderBox::shrinkToFitWidth(const LayoutUnit availableSpace, const LayoutUnit logicalLeftValue, const LayoutUnit bordersPlusPadding, LogicalExtentComputedValues& computedValues) const
3233 // FIXME: would it be better to have shrink-to-fit in one step?
3234 LayoutUnit preferredWidth = maxPreferredLogicalWidth() - bordersPlusPadding;
3235 LayoutUnit preferredMinWidth = minPreferredLogicalWidth() - bordersPlusPadding;
3236 LayoutUnit availableWidth = availableSpace - logicalLeftValue;
3237 computedValues.m_extent = min(max(preferredMinWidth, availableWidth), preferredWidth);
3240 void RenderBox::computePositionedLogicalWidthUsing(Length logicalWidth, const RenderBoxModelObject* containerBlock, TextDirection containerDirection,
3241 LayoutUnit containerLogicalWidth, LayoutUnit bordersPlusPadding,
3242 Length logicalLeft, Length logicalRight, Length marginLogicalLeft, Length marginLogicalRight,
3243 LogicalExtentComputedValues& computedValues) const
3245 if (logicalWidth.isIntrinsic())
3246 logicalWidth = Length(computeIntrinsicLogicalWidthUsing(logicalWidth, containerLogicalWidth, bordersPlusPadding) - bordersPlusPadding, Fixed);
3248 // 'left' and 'right' cannot both be 'auto' because one would of been
3249 // converted to the static position already
3250 ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto()));
3252 LayoutUnit logicalLeftValue = 0;
3254 const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, false);
3256 bool logicalWidthIsAuto = logicalWidth.isIntrinsicOrAuto();
3257 bool logicalLeftIsAuto = logicalLeft.isAuto();
3258 bool logicalRightIsAuto = logicalRight.isAuto();
3259 LayoutUnit& marginLogicalLeftValue = style()->isLeftToRightDirection() ? computedValues.m_margins.m_start : computedValues.m_margins.m_end;
3260 LayoutUnit& marginLogicalRightValue = style()->isLeftToRightDirection() ? computedValues.m_margins.m_end : computedValues.m_margins.m_start;
3261 if (!logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) {
3262 /*-----------------------------------------------------------------------*\
3263 * If none of the three is 'auto': If both 'margin-left' and 'margin-
3264 * right' are 'auto', solve the equation under the extra constraint that
3265 * the two margins get equal values, unless this would make them negative,
3266 * in which case when direction of the containing block is 'ltr' ('rtl'),
3267 * set 'margin-left' ('margin-right') to zero and solve for 'margin-right'
3268 * ('margin-left'). If one of 'margin-left' or 'margin-right' is 'auto',
3269 * solve the equation for that value. If the values are over-constrained,
3270 * ignore the value for 'left' (in case the 'direction' property of the
3271 * containing block is 'rtl') or 'right' (in case 'direction' is 'ltr')
3272 * and solve for that value.
3273 \*-----------------------------------------------------------------------*/
3274 // NOTE: It is not necessary to solve for 'right' in the over constrained
3275 // case because the value is not used for any further calculations.
3277 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3278 computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, containerLogicalWidth));
3280 const LayoutUnit availableSpace = containerLogicalWidth - (logicalLeftValue + computedValues.m_extent + valueForLength(logicalRight, containerLogicalWidth) + bordersPlusPadding);
3282 // Margins are now the only unknown
3283 if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) {
3284 // Both margins auto, solve for equality
3285 if (availableSpace >= 0) {
3286 marginLogicalLeftValue = availableSpace / 2; // split the difference
3287 marginLogicalRightValue = availableSpace - marginLogicalLeftValue; // account for odd valued differences
3289 // Use the containing block's direction rather than the parent block's
3290 // per CSS 2.1 reference test abspos-non-replaced-width-margin-000.
3291 if (containerDirection == LTR) {
3292 marginLogicalLeftValue = 0;
3293 marginLogicalRightValue = availableSpace; // will be negative
3295 marginLogicalLeftValue = availableSpace; // will be negative
3296 marginLogicalRightValue = 0;
3299 } else if (marginLogicalLeft.isAuto()) {
3300 // Solve for left margin
3301 marginLogicalRightValue = valueForLength(marginLogicalRight, containerRelativeLogicalWidth);
3302 marginLogicalLeftValue = availableSpace - marginLogicalRightValue;
3303 } else if (marginLogicalRight.isAuto()) {
3304 // Solve for right margin
3305 marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth);
3306 marginLogicalRightValue = availableSpace - marginLogicalLeftValue;
3308 // Over-constrained, solve for left if direction is RTL
3309 marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth);
3310 marginLogicalRightValue = valueForLength(marginLogicalRight, containerRelativeLogicalWidth);
3312 // Use the containing block's direction rather than the parent block's
3313 // per CSS 2.1 reference test abspos-non-replaced-width-margin-000.
3314 if (containerDirection == RTL)
3315 logicalLeftValue = (availableSpace + logicalLeftValue) - marginLogicalLeftValue - marginLogicalRightValue;
3318 /*--------------------------------------------------------------------*\
3319 * Otherwise, set 'auto' values for 'margin-left' and 'margin-right'
3320 * to 0, and pick the one of the following six rules that applies.
3322 * 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the
3323 * width is shrink-to-fit. Then solve for 'left'
3325 * OMIT RULE 2 AS IT SHOULD NEVER BE HIT
3326 * ------------------------------------------------------------------
3327 * 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if
3328 * the 'direction' property of the containing block is 'ltr' set
3329 * 'left' to the static position, otherwise set 'right' to the
3330 * static position. Then solve for 'left' (if 'direction is 'rtl')
3331 * or 'right' (if 'direction' is 'ltr').
3332 * ------------------------------------------------------------------
3334 * 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the
3335 * width is shrink-to-fit . Then solve for 'right'
3336 * 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve
3338 * 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve
3340 * 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve
3343 * Calculation of the shrink-to-fit width is similar to calculating the
3344 * width of a table cell using the automatic table layout algorithm.
3345 * Roughly: calculate the preferred width by formatting the content
3346 * without breaking lines other than where explicit line breaks occur,
3347 * and also calculate the preferred minimum width, e.g., by trying all
3348 * possible line breaks. CSS 2.1 does not define the exact algorithm.
3349 * Thirdly, calculate the available width: this is found by solving
3350 * for 'width' after setting 'left' (in case 1) or 'right' (in case 3)
3353 * Then the shrink-to-fit width is:
3354 * min(max(preferred minimum width, available width), preferred width).
3355 \*--------------------------------------------------------------------*/
3356 // NOTE: For rules 3 and 6 it is not necessary to solve for 'right'
3357 // because the value is not used for any further calculations.
3359 // Calculate margins, 'auto' margins are ignored.
3360 marginLogicalLeftValue = minimumValueForLength(marginLogicalLeft, containerRelativeLogicalWidth);
3361 marginLogicalRightValue = minimumValueForLength(marginLogicalRight, containerRelativeLogicalWidth);
3363 const LayoutUnit availableSpace = containerLogicalWidth - (marginLogicalLeftValue + marginLogicalRightValue + bordersPlusPadding);
3365 // FIXME: Is there a faster way to find the correct case?
3366 // Use rule/case that applies.
3367 if (logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAuto) {
3368 // RULE 1: (use shrink-to-fit for width, and solve of left)
3369 LayoutUnit logicalRightValue = valueForLength(logicalRight, containerLogicalWidth);
3371 // FIXME: would it be better to have shrink-to-fit in one step?
3372 LayoutUnit preferredWidth = maxPreferredLogicalWidth() - bordersPlusPadding;
3373 LayoutUnit preferredMinWidth = minPreferredLogicalWidth() - bordersPlusPadding;
3374 LayoutUnit availableWidth = availableSpace - logicalRightValue;
3375 computedValues.m_extent = min(max(preferredMinWidth, availableWidth), preferredWidth);
3376 logicalLeftValue = availableSpace - (computedValues.m_extent + logicalRightValue);
3377 } else if (!logicalLeftIsAuto && logicalWidthIsAuto && logicalRightIsAuto) {
3378 // RULE 3: (use shrink-to-fit for width, and no need solve of right)
3379 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3381 shrinkToFitWidth(availableSpace, logicalLeftValue, bordersPlusPadding, computedValues);
3382 } else if (logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) {
3383 // RULE 4: (solve for left)
3384 computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, containerLogicalWidth));
3385 logicalLeftValue = availableSpace - (computedValues.m_extent + valueForLength(logicalRight, containerLogicalWidth));
3386 } else if (!logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAuto) {
3387 // RULE 5: (solve for width)
3388 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3389 if (autoWidthShouldFitContent())
3390 shrinkToFitWidth(availableSpace, logicalLeftValue, bordersPlusPadding, computedValues);
3392 computedValues.m_extent = availableSpace - (logicalLeftValue + valueForLength(logicalRight, containerLogicalWidth));
3393 } else if (!logicalLeftIsAuto && !logicalWidthIsAuto && logicalRightIsAuto) {
3394 // RULE 6: (no need solve for right)
3395 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3396 computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, containerLogicalWidth));
3400 // Use computed values to calculate the horizontal position.
3402 // FIXME: This hack is needed to calculate the logical left position for a 'rtl' relatively
3403 // positioned, inline because right now, it is using the logical left position
3404 // of the first line box when really it should use the last line box. When
3405 // this is fixed elsewhere, this block should be removed.
3406 if (containerBlock->isRenderInline() && !containerBlock->style()->isLeftToRightDirection()) {
3407 const RenderInline* flow = toRenderInline(containerBlock);
3408 InlineFlowBox* firstLine = flow->firstLineBox();
3409 InlineFlowBox* lastLine = flow->lastLineBox();
3410 if (firstLine && lastLine && firstLine != lastLine) {
3411 computedValues.m_position = logicalLeftValue + marginLogicalLeftValue + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logicalLeft());
3416 if (containerBlock->isBox() && toRenderBox(containerBlock)->scrollsOverflowY() && containerBlock->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
3417 logicalLeftValue = logicalLeftValue + toRenderBox(containerBlock)->verticalScrollbarWidth();
3420 computedValues.m_position = logicalLeftValue + marginLogicalLeftValue;
3421 computeLogicalLeftPositionedOffset(computedValues.m_position, this, computedValues.m_extent, containerBlock, containerLogicalWidth);
3424 static void computeBlockStaticDistance(Length& logicalTop, Length& logicalBottom, const RenderBox* child, const RenderBoxModelObject* containerBlock)
3426 if (!logicalTop.isAuto() || !logicalBottom.isAuto())
3429 // FIXME: The static distance computation has not been patched for mixed writing modes.
3430 LayoutUnit staticLogicalTop = child->layer()->staticBlockPosition() - containerBlock->borderBefore();
3431 for (RenderObject* curr = child->parent(); curr && curr != containerBlock; curr = curr->container()) {
3432 if (curr->isBox() && !curr->isTableRow())
3433 staticLogicalTop += toRenderBox(curr)->logicalTop();
3435 logicalTop.setValue(Fixed, staticLogicalTop);
3438 void RenderBox::computePositionedLogicalHeight(LogicalExtentComputedValues& computedValues) const
3441 computePositionedLogicalHeightReplaced(computedValues);
3445 // The following is based off of the W3C Working Draft from April 11, 2006 of
3446 // CSS 2.1: Section 10.6.4 "Absolutely positioned, non-replaced elements"
3447 // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-non-replaced-height>
3448 // (block-style-comments in this function and in computePositionedLogicalHeightUsing()
3449 // correspond to text from the spec)
3452 // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
3453 const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
3455 const LayoutUnit containerLogicalHeight = containingBlockLogicalHeightForPositioned(containerBlock);
3457 RenderStyle* styleToUse = style();
3458 const LayoutUnit bordersPlusPadding = borderAndPaddingLogicalHeight();
3459 const Length marginBefore = styleToUse->marginBefore();
3460 const Length marginAfter = styleToUse->marginAfter();
3461 Length logicalTopLength = styleToUse->logicalTop();
3462 Length logicalBottomLength = styleToUse->logicalBottom();
3464 /*---------------------------------------------------------------------------*\
3465 * For the purposes of this section and the next, the term "static position"
3466 * (of an element) refers, roughly, to the position an element would have had
3467 * in the normal flow. More precisely, the static position for 'top' is the
3468 * distance from the top edge of the containing block to the top margin edge
3469 * of a hypothetical box that would have been the first box of the element if
3470 * its 'position' property had been 'static' and 'float' had been 'none'. The
3471 * value is negative if the hypothetical box is above the containing block.
3473 * But rather than actually calculating the dimensions of that hypothetical
3474 * box, user agents are free to make a guess at its probable position.
3476 * For the purposes of calculating the static position, the containing block
3477 * of fixed positioned elements is the initial containing block instead of
3479 \*---------------------------------------------------------------------------*/
3482 // Calculate the static distance if needed.
3483 computeBlockStaticDistance(logicalTopLength, logicalBottomLength, this, containerBlock);
3485 // Calculate constraint equation values for 'height' case.
3486 LayoutUnit logicalHeight = computedValues.m_extent;
3487 computePositionedLogicalHeightUsing(styleToUse->logicalHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight,
3488 logicalTopLength, logicalBottomLength, marginBefore, marginAfter,
3491 // Avoid doing any work in the common case (where the values of min-height and max-height are their defaults).
3494 // Calculate constraint equation values for 'max-height' case.
3495 if (!styleToUse->logicalMaxHeight().isUndefined()) {
3496 LogicalExtentComputedValues maxValues;
3498 computePositionedLogicalHeightUsing(styleToUse->logicalMaxHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight,
3499 logicalTopLength, logicalBottomLength, marginBefore, marginAfter,
3502 if (computedValues.m_extent > maxValues.m_extent) {
3503 computedValues.m_extent = maxValues.m_extent;
3504 computedValues.m_position = maxValues.m_position;
3505 computedValues.m_margins.m_before = maxValues.m_margins.m_before;
3506 computedValues.m_margins.m_after = maxValues.m_margins.m_after;
3510 // Calculate constraint equation values for 'min-height' case.
3511 if (!styleToUse->logicalMinHeight().isZero() || styleToUse->logicalMinHeight().isIntrinsic()) {
3512 LogicalExtentComputedValues minValues;
3514 computePositionedLogicalHeightUsing(styleToUse->logicalMinHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight,
3515 logicalTopLength, logicalBottomLength, marginBefore, marginAfter,
3518 if (computedValues.m_extent < minValues.m_extent) {
3519 computedValues.m_extent = minValues.m_extent;
3520 computedValues.m_position = minValues.m_position;
3521 computedValues.m_margins.m_before = minValues.m_margins.m_before;
3522 computedValues.m_margins.m_after = minValues.m_margins.m_after;
3526 // Set final height value.
3527 computedValues.m_extent += bordersPlusPadding;
3530 static void computeLogicalTopPositionedOffset(LayoutUnit& logicalTopPos, const RenderBox* child, LayoutUnit logicalHeightValue, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalHeight)
3532 // Deal with differing writing modes here. Our offset needs to be in the containing block's coordinate space. If the containing block is flipped
3533 // along this axis, then we need to flip the coordinate. This can only happen if the containing block is both a flipped mode and perpendicular to us.
3534 if ((child->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() != containerBlock->isHorizontalWritingMode())
3535 || (child->style()->isFlippedBlocksWritingMode() != containerBlock->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode()))
3536 logicalTopPos = containerLogicalHeight - logicalHeightValue - logicalTopPos;
3538 // Our offset is from the logical bottom edge in a flipped environment, e.g., right for vertical-rl and bottom for horizontal-bt.
3539 if (containerBlock->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode()) {
3540 if (child->isHorizontalWritingMode())
3541 logicalTopPos += containerBlock->borderBottom();
3543 logicalTopPos += containerBlock->borderRight();
3545 if (child->isHorizontalWritingMode())
3546 logicalTopPos += containerBlock->borderTop();
3548 logicalTopPos += containerBlock->borderLeft();
3552 void RenderBox::computePositionedLogicalHeightUsing(Length logicalHeightLength, const RenderBoxModelObject* containerBlock,
3553 LayoutUnit containerLogicalHeight, LayoutUnit bordersPlusPadding, LayoutUnit logicalHeight,
3554 Length logicalTop, Length logicalBottom, Length marginBefore, Length marginAfter,
3555 LogicalExtentComputedValues& computedValues) const
3557 // 'top' and 'bottom' cannot both be 'auto' because 'top would of been
3558 // converted to the static position in computePositionedLogicalHeight()
3559 ASSERT(!(logicalTop.isAuto() && logicalBottom.isAuto()));
3561 LayoutUnit logicalHeightValue;
3562 LayoutUnit contentLogicalHeight = logicalHeight - bordersPlusPadding;
3564 const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, false);
3566 LayoutUnit logicalTopValue = 0;
3568 bool logicalHeightIsAuto = logicalHeightLength.isAuto();
3569 bool logicalTopIsAuto = logicalTop.isAuto();
3570 bool logicalBottomIsAuto = logicalBottom.isAuto();
3572 LayoutUnit resolvedLogicalHeight;
3573 // Height is never unsolved for tables.
3575 resolvedLogicalHeight = contentLogicalHeight;
3576 logicalHeightIsAuto = false;
3578 if (logicalHeightLength.isIntrinsic())
3579 resolvedLogicalHeight = computeIntrinsicLogicalContentHeightUsing(logicalHeightLength, contentLogicalHeight, bordersPlusPadding);
3581 resolvedLogicalHeight = adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeightLength, containerLogicalHeight));
3584 if (!logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsAuto) {
3585 /*-----------------------------------------------------------------------*\
3586 * If none of the three are 'auto': If both 'margin-top' and 'margin-
3587 * bottom' are 'auto', solve the equation under the extra constraint that
3588 * the two margins get equal values. If one of 'margin-top' or 'margin-
3589 * bottom' is 'auto', solve the equation for that value. If the values
3590 * are over-constrained, ignore the value for 'bottom' and solve for that
3592 \*-----------------------------------------------------------------------*/
3593 // NOTE: It is not necessary to solve for 'bottom' in the over constrained
3594 // case because the value is not used for any further calculations.
3596 logicalHeightValue = resolvedLogicalHeight;
3597 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3599 const LayoutUnit availableSpace = containerLogicalHeight - (logicalTopValue + logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight) + bordersPlusPadding);
3601 // Margins are now the only unknown
3602 if (marginBefore.isAuto() && marginAfter.isAuto()) {
3603 // Both margins auto, solve for equality
3604 // NOTE: This may result in negative values.
3605 computedValues.m_margins.m_before = availableSpace / 2; // split the difference
3606 computedValues.m_margins.m_after = availableSpace - computedValues.m_margins.m_before; // account for odd valued differences
3607 } else if (marginBefore.isAuto()) {
3608 // Solve for top margin
3609 computedValues.m_margins.m_after = valueForLength(marginAfter, containerRelativeLogicalWidth);
3610 computedValues.m_margins.m_before = availableSpace - computedValues.m_margins.m_after;
3611 } else if (marginAfter.isAuto()) {
3612 // Solve for bottom margin
3613 computedValues.m_margins.m_before = valueForLength(marginBefore, containerRelativeLogicalWidth);
3614 computedValues.m_margins.m_after = availableSpace - computedValues.m_margins.m_before;
3616 // Over-constrained, (no need solve for bottom)
3617 computedValues.m_margins.m_before = valueForLength(marginBefore, containerRelativeLogicalWidth);
3618 computedValues.m_margins.m_after = valueForLength(marginAfter, containerRelativeLogicalWidth);
3621 /*--------------------------------------------------------------------*\
3622 * Otherwise, set 'auto' values for 'margin-top' and 'margin-bottom'
3623 * to 0, and pick the one of the following six rules that applies.
3625 * 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then
3626 * the height is based on the content, and solve for 'top'.
3628 * OMIT RULE 2 AS IT SHOULD NEVER BE HIT
3629 * ------------------------------------------------------------------
3630 * 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then
3631 * set 'top' to the static position, and solve for 'bottom'.
3632 * ------------------------------------------------------------------
3634 * 3. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then
3635 * the height is based on the content, and solve for 'bottom'.
3636 * 4. 'top' is 'auto', 'height' and 'bottom' are not 'auto', and
3638 * 5. 'height' is 'auto', 'top' and 'bottom' are not 'auto', and
3639 * solve for 'height'.
3640 * 6. 'bottom' is 'auto', 'top' and 'height' are not 'auto', and
3641 * solve for 'bottom'.
3642 \*--------------------------------------------------------------------*/
3643 // NOTE: For rules 3 and 6 it is not necessary to solve for 'bottom'
3644 // because the value is not used for any further calculations.
3646 // Calculate margins, 'auto' margins are ignored.
3647 computedValues.m_margins.m_before = minimumValueForLength(marginBefore, containerRelativeLogicalWidth);
3648 computedValues.m_margins.m_after = minimumValueForLength(marginAfter, containerRelativeLogicalWidth);
3650 const LayoutUnit availableSpace = containerLogicalHeight - (computedValues.m_margins.m_before + computedValues.m_margins.m_after + bordersPlusPadding);
3652 // Use rule/case that applies.
3653 if (logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) {
3654 // RULE 1: (height is content based, solve of top)
3655 logicalHeightValue = contentLogicalHeight;
3656 logicalTopValue = availableSpace - (logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight));
3657 } else if (!logicalTopIsAuto && logicalHeightIsAuto && logicalBottomIsAuto) {
3658 // RULE 3: (height is content based, no need solve of bottom)
3659 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3660 logicalHeightValue = contentLogicalHeight;
3661 } else if (logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsAuto) {
3662 // RULE 4: (solve of top)
3663 logicalHeightValue = resolvedLogicalHeight;
3664 logicalTopValue = availableSpace - (logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight));
3665 } else if (!logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) {
3666 // RULE 5: (solve of height)
3667 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3668 logicalHeightValue = max<LayoutUnit>(0, availableSpace - (logicalTopValue + valueForLength(logicalBottom, containerLogicalHeight)));
3669 } else if (!logicalTopIsAuto && !logicalHeightIsAuto && logicalBottomIsAuto) {
3670 // RULE 6: (no need solve of bottom)
3671 logicalHeightValue = resolvedLogicalHeight;
3672 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3675 computedValues.m_extent = logicalHeightValue;
3677 // Use computed values to calculate the vertical position.
3678 computedValues.m_position = logicalTopValue + computedValues.m_margins.m_before;
3679 computeLogicalTopPositionedOffset(computedValues.m_position, this, logicalHeightValue, containerBlock, containerLogicalHeight);
3682 void RenderBox::computePositionedLogicalWidthReplaced(LogicalExtentComputedValues& computedValues) const
3684 // The following is based off of the W3C Working Draft from April 11, 2006 of
3685 // CSS 2.1: Section 10.3.8 "Absolutely positioned, replaced elements"
3686 // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-width>
3687 // (block-style-comments in this function correspond to text from the spec and
3688 // the numbers correspond to numbers in spec)
3690 // We don't use containingBlock(), since we may be positioned by an enclosing
3691 // relative positioned inline.
3692 const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
3694 const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock);
3695 const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, false);
3697 // To match WinIE, in quirks mode use the parent's 'direction' property
3698 // instead of the the container block's.
3699 TextDirection containerDirection = containerBlock->style()->direction();
3701 // Variables to solve.
3702 bool isHorizontal = isHorizontalWritingMode();
3703 Length logicalLeft = style()->logicalLeft();
3704 Length logicalRight = style()->logicalRight();
3705 Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->marginTop();
3706 Length marginLogicalRight = isHorizontal ? style()->marginRight() : style()->marginBottom();
3707 LayoutUnit& marginLogicalLeftAlias = style()->isLeftToRightDirection() ? computedValues.m_margins.m_start : computedValues.m_margins.m_end;
3708 LayoutUnit& marginLogicalRightAlias = style()->isLeftToRightDirection() ? computedValues.m_margins.m_end : computedValues.m_margins.m_start;
3710 /*-----------------------------------------------------------------------*\
3711 * 1. The used value of 'width' is determined as for inline replaced
3713 \*-----------------------------------------------------------------------*/
3714 // NOTE: This value of width is FINAL in that the min/max width calculations
3715 // are dealt with in computeReplacedWidth(). This means that the steps to produce
3716 // correct max/min in the non-replaced version, are not necessary.
3717 computedValues.m_extent = computeReplacedLogicalWidth() + borderAndPaddingLogicalWidth();
3719 const LayoutUnit availableSpace = containerLogicalWidth - computedValues.m_extent;
3721 /*-----------------------------------------------------------------------*\
3722 * 2. If both 'left' and 'right' have the value 'auto', then if 'direction'
3723 * of the containing block is 'ltr', set 'left' to the static position;
3724 * else if 'direction' is 'rtl', set 'right' to the static position.
3725 \*-----------------------------------------------------------------------*/
3727 computeInlineStaticDistance(logicalLeft, logicalRight, this, containerBlock, containerLogicalWidth);
3729 /*-----------------------------------------------------------------------*\
3730 * 3. If 'left' or 'right' are 'auto', replace any 'auto' on 'margin-left'
3731 * or 'margin-right' with '0'.
3732 \*-----------------------------------------------------------------------*/
3733 if (logicalLeft.isAuto() || logicalRight.isAuto()) {
3734 if (marginLogicalLeft.isAuto())
3735 marginLogicalLeft.setValue(Fixed, 0);
3736 if (marginLogicalRight.isAuto())
3737 marginLogicalRight.setValue(Fixed, 0);
3740 /*-----------------------------------------------------------------------*\
3741 * 4. If at this point both 'margin-left' and 'margin-right' are still
3742 * 'auto', solve the equation under the extra constraint that the two
3743 * margins must get equal values, unless this would make them negative,
3744 * in which case when the direction of the containing block is 'ltr'
3745 * ('rtl'), set 'margin-left' ('margin-right') to zero and solve for
3746 * 'margin-right' ('margin-left').
3747 \*-----------------------------------------------------------------------*/
3748 LayoutUnit logicalLeftValue = 0;
3749 LayoutUnit logicalRightValue = 0;
3751 if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) {
3752 // 'left' and 'right' cannot be 'auto' due to step 3
3753 ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto()));
3755 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3756 logicalRightValue = valueForLength(logicalRight, containerLogicalWidth);
3758 LayoutUnit difference = availableSpace - (logicalLeftValue + logicalRightValue);
3759 if (difference > 0) {
3760 marginLogicalLeftAlias = difference / 2; // split the difference
3761 marginLogicalRightAlias = difference - marginLogicalLeftAlias; // account for odd valued differences
3763 // Use the containing block's direction rather than the parent block's
3764 // per CSS 2.1 reference test abspos-replaced-width-margin-000.
3765 if (containerDirection == LTR) {
3766 marginLogicalLeftAlias = 0;
3767 marginLogicalRightAlias = difference; // will be negative
3769 marginLogicalLeftAlias = difference; // will be negative
3770 marginLogicalRightAlias = 0;
3774 /*-----------------------------------------------------------------------*\
3775 * 5. If at this point there is an 'auto' left, solve the equation for
3777 \*-----------------------------------------------------------------------*/
3778 } else if (logicalLeft.isAuto()) {
3779 marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth);
3780 marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth);
3781 logicalRightValue = valueForLength(logicalRight, containerLogicalWidth);
3784 logicalLeftValue = availableSpace - (logicalRightValue + marginLogicalLeftAlias + marginLogicalRightAlias);
3785 } else if (logicalRight.isAuto()) {
3786 marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth);
3787 marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth);
3788 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3790 // Solve for 'right'
3791 logicalRightValue = availableSpace - (logicalLeftValue + marginLogicalLeftAlias + marginLogicalRightAlias);
3792 } else if (marginLogicalLeft.isAuto()) {
3793 marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth);
3794 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3795 logicalRightValue = valueForLength(logicalRight, containerLogicalWidth);
3797 // Solve for 'margin-left'
3798 marginLogicalLeftAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalRightAlias);
3799 } else if (marginLogicalRight.isAuto()) {
3800 marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth);
3801 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3802 logicalRightValue = valueForLength(logicalRight, containerLogicalWidth);
3804 // Solve for 'margin-right'
3805 marginLogicalRightAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalLeftAlias);
3807 // Nothing is 'auto', just calculate the values.
3808 marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth);
3809 marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth);
3810 logicalRightValue = valueForLength(logicalRight, containerLogicalWidth);
3811 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3812 // If the containing block is right-to-left, then push the left position as far to the right as possible
3813 if (containerDirection == RTL) {
3814 int totalLogicalWidth = computedValues.m_extent + logicalLeftValue + logicalRightValue + marginLogicalLeftAlias + marginLogicalRightAlias;
3815 logicalLeftValue = containerLogicalWidth - (totalLogicalWidth - logicalLeftValue);
3819 /*-----------------------------------------------------------------------*\
3820 * 6. If at this point the values are over-constrained, ignore the value
3821 * for either 'left' (in case the 'direction' property of the
3822 * containing block is 'rtl') or 'right' (in case 'direction' is
3823 * 'ltr') and solve for that value.
3824 \*-----------------------------------------------------------------------*/
3825 // NOTE: Constraints imposed by the width of the containing block and its content have already been accounted for above.
3827 // FIXME: Deal with differing writing modes here. Our offset needs to be in the containing block's coordinate space, so that
3828 // can make the result here rather complicated to compute.
3830 // Use computed values to calculate the horizontal position.
3832 // FIXME: This hack is needed to calculate the logical left position for a 'rtl' relatively
3833 // positioned, inline containing block because right now, it is using the logical left position
3834 // of the first line box when really it should use the last line box. When
3835 // this is fixed elsewhere, this block should be removed.
3836 if (containerBlock->isRenderInline() && !containerBlock->style()->isLeftToRightDirection()) {
3837 const RenderInline* flow = toRenderInline(containerBlock);
3838 InlineFlowBox* firstLine = flow->firstLineBox();
3839 InlineFlowBox* lastLine = flow->lastLineBox();
3840 if (firstLine && lastLine && firstLine != lastLine) {
3841 computedValues.m_position = logicalLeftValue + marginLogicalLeftAlias + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logicalLeft());
3846 LayoutUnit logicalLeftPos = logicalLeftValue + marginLogicalLeftAlias;
3847 computeLogicalLeftPositionedOffset(logicalLeftPos, this, computedValues.m_extent, containerBlock, containerLogicalWidth);
3848 computedValues.m_position = logicalLeftPos;
3851 void RenderBox::computePositionedLogicalHeightReplaced(LogicalExtentComputedValues& computedValues) const
3853 // The following is based off of the W3C Working Draft from April 11, 2006 of
3854 // CSS 2.1: Section 10.6.5 "Absolutely positioned, replaced elements"
3855 // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-height>
3856 // (block-style-comments in this function correspond to text from the spec and
3857 // the numbers correspond to numbers in spec)
3859 // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
3860 const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
3862 const LayoutUnit containerLogicalHeight = containingBlockLogicalHeightForPositioned(containerBlock);
3863 const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, false);
3865 // Variables to solve.
3866 Length marginBefore = style()->marginBefore();
3867 Length marginAfter = style()->marginAfter();
3868 LayoutUnit& marginBeforeAlias = computedValues.m_margins.m_before;
3869 LayoutUnit& marginAfterAlias = computedValues.m_margins.m_after;
3871 Length logicalTop = style()->logicalTop();
3872 Length logicalBottom = style()->logicalBottom();
3874 /*-----------------------------------------------------------------------*\
3875 * 1. The used value of 'height' is determined as for inline replaced
3877 \*-----------------------------------------------------------------------*/
3878 // NOTE: This value of height is FINAL in that the min/max height calculations
3879 // are dealt with in computeReplacedHeight(). This means that the steps to produce
3880 // correct max/min in the non-replaced version, are not necessary.
3881 computedValues.m_extent = computeReplacedLogicalHeight() + borderAndPaddingLogicalHeight();
3882 const LayoutUnit availableSpace = containerLogicalHeight - computedValues.m_extent;
3884 /*-----------------------------------------------------------------------*\
3885 * 2. If both 'top' and 'bottom' have the value 'auto', replace 'top'
3886 * with the element's static position.
3887 \*-----------------------------------------------------------------------*/
3889 computeBlockStaticDistance(logicalTop, logicalBottom, this, containerBlock);
3891 /*-----------------------------------------------------------------------*\
3892 * 3. If 'bottom' is 'auto', replace any 'auto' on 'margin-top' or
3893 * 'margin-bottom' with '0'.
3894 \*-----------------------------------------------------------------------*/
3895 // FIXME: The spec. says that this step should only be taken when bottom is
3896 // auto, but if only top is auto, this makes step 4 impossible.
3897 if (logicalTop.isAuto() || logicalBottom.isAuto()) {
3898 if (marginBefore.isAuto())
3899 marginBefore.setValue(Fixed, 0);
3900 if (marginAfter.isAuto())
3901 marginAfter.setValue(Fixed, 0);
3904 /*-----------------------------------------------------------------------*\
3905 * 4. If at this point both 'margin-top' and 'margin-bottom' are still
3906 * 'auto', solve the equation under the extra constraint that the two
3907 * margins must get equal values.
3908 \*-----------------------------------------------------------------------*/
3909 LayoutUnit logicalTopValue = 0;
3910 LayoutUnit logicalBottomValue = 0;
3912 if (marginBefore.isAuto() && marginAfter.isAuto()) {
3913 // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combined.
3914 ASSERT(!(logicalTop.isAuto() || logicalBottom.isAuto()));
3916 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3917 logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight);
3919 LayoutUnit difference = availableSpace - (logicalTopValue + logicalBottomValue);
3920 // NOTE: This may result in negative values.
3921 marginBeforeAlias = difference / 2; // split the difference
3922 marginAfterAlias = difference - marginBeforeAlias; // account for odd valued differences
3924 /*-----------------------------------------------------------------------*\
3925 * 5. If at this point there is only one 'auto' left, solve the equation
3927 \*-----------------------------------------------------------------------*/
3928 } else if (logicalTop.isAuto()) {
3929 marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth);
3930 marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth);
3931 logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight);
3934 logicalTopValue = availableSpace - (logicalBottomValue + marginBeforeAlias + marginAfterAlias);
3935 } else if (logicalBottom.isAuto()) {
3936 marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth);
3937 marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth);
3938 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3940 // Solve for 'bottom'
3941 // NOTE: It is not necessary to solve for 'bottom' because we don't ever
3943 } else if (marginBefore.isAuto()) {
3944 marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth);
3945 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3946 logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight);
3948 // Solve for 'margin-top'
3949 marginBeforeAlias = availableSpace - (logicalTopValue + logicalBottomValue + marginAfterAlias);
3950 } else if (marginAfter.isAuto()) {
3951 marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth);
3952 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3953 logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight);
3955 // Solve for 'margin-bottom'
3956 marginAfterAlias = availableSpace - (logicalTopValue + logicalBottomValue + marginBeforeAlias);
3958 // Nothing is 'auto', just calculate the values.
3959 marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth);
3960 marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth);
3961 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3962 // NOTE: It is not necessary to solve for 'bottom' because we don't ever
3966 /*-----------------------------------------------------------------------*\
3967 * 6. If at this point the values are over-constrained, ignore the value
3968 * for 'bottom' and solve for that value.
3969 \*-----------------------------------------------------------------------*/
3970 // NOTE: It is not necessary to do this step because we don't end up using
3971 // the value of 'bottom' regardless of whether the values are over-constrained
3974 // Use computed values to calculate the vertical position.
3975 LayoutUnit logicalTopPos = logicalTopValue + marginBeforeAlias;
3976 computeLogicalTopPositionedOffset(logicalTopPos, this, computedValues.m_extent, containerBlock, containerLogicalHeight);
3977 computedValues.m_position = logicalTopPos;
3980 LayoutRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, LayoutUnit* extraWidthToEndOfLine)
3982 // VisiblePositions at offsets inside containers either a) refer to the positions before/after
3983 // those containers (tables and select elements) or b) refer to the position inside an empty block.
3984 // They never refer to children.
3985 // FIXME: Paint the carets inside empty blocks differently than the carets before/after elements.
3987 LayoutRect rect(location(), LayoutSize(caretWidth, height()));
3988 bool ltr = box ? box->isLeftToRightDirection() : style()->isLeftToRightDirection();
3990 if ((!caretOffset) ^ ltr)
3991 rect.move(LayoutSize(width() - caretWidth, 0));
3994 RootInlineBox& rootBox = box->root();
3995 LayoutUnit top = rootBox.lineTop();
3997 rect.setHeight(rootBox.lineBottom() - top);
4000 // If height of box is smaller than font height, use the latter one,
4001 // otherwise the caret might become invisible.
4003 // Also, if the box is not a replaced element, always use the font height.
4004 // This prevents the "big caret" bug described in:
4005 // <rdar://problem/3777804> Deleting all content in a document can result in giant tall-as-window insertion point
4007 // FIXME: ignoring :first-line, missing good reason to take care of
4008 LayoutUnit fontHeight = style()->fontMetrics().height();
4009 if (fontHeight > rect.height() || (!isReplaced() && !isTable()))
4010 rect.setHeight(fontHeight);
4012 if (extraWidthToEndOfLine)
4013 *extraWidthToEndOfLine = x() + width() - rect.maxX();
4015 // Move to local coords
4016 rect.moveBy(-location());
4018 // FIXME: Border/padding should be added for all elements but this workaround
4019 // is needed because we use offsets inside an "atomic" element to represent
4020 // positions before and after the element in deprecated editing offsets.
4021 if (node() && !(editingIgnoresContent(node()) || isRenderedTable(node()))) {
4022 rect.setX(rect.x() + borderLeft() + paddingLeft());
4023 rect.setY(rect.y() + paddingTop() + borderTop());
4026 if (!isHorizontalWritingMode())
4027 return rect.transposedRect();
4032 PositionWithAffinity RenderBox::positionForPoint(const LayoutPoint& point)
4034 // no children...return this render object's element, if there is one, and offset 0
4036 return createPositionWithAffinity(nonPseudoNode() ? firstPositionInOrBeforeNode(nonPseudoNode()) : Position());
4038 if (isTable() && nonPseudoNode()) {
4039 LayoutUnit right = contentWidth() + borderAndPaddingWidth();
4040 LayoutUnit bottom = contentHeight() + borderAndPaddingHeight();
4042 if (point.x() < 0 || point.x() > right || point.y() < 0 || point.y() > bottom) {
4043 if (point.x() <= right / 2)
4044 return createPositionWithAffinity(firstPositionInOrBeforeNode(nonPseudoNode()));
4045 return createPositionWithAffinity(lastPositionInOrAfterNode(nonPseudoNode()));
4049 // Pass off to the closest child.
4050 LayoutUnit minDist = LayoutUnit::max();
4051 RenderBox* closestRenderer = 0;
4052 LayoutPoint adjustedPoint = point;
4054 adjustedPoint.moveBy(location());
4056 for (RenderObject* renderObject = firstChild(); renderObject; renderObject = renderObject->nextSibling()) {
4057 if ((!renderObject->firstChild() && !renderObject->isInline() && !renderObject->isRenderBlockFlow() )
4058 || renderObject->style()->visibility() != VISIBLE)
4061 if (!renderObject->isBox())
4064 RenderBox* renderer = toRenderBox(renderObject);
4066 LayoutUnit top = renderer->borderTop() + renderer->paddingTop() + (isTableRow() ? LayoutUnit() : renderer->y());
4067 LayoutUnit bottom = top + renderer->contentHeight();
4068 LayoutUnit left = renderer->borderLeft() + renderer->paddingLeft() + (isTableRow() ? LayoutUnit() : renderer->x());
4069 LayoutUnit right = left + renderer->contentWidth();
4071 if (point.x() <= right && point.x() >= left && point.y() <= top && point.y() >= bottom) {
4072 if (renderer->isTableRow())
4073 return renderer->positionForPoint(point + adjustedPoint - renderer->locationOffset());
4074 return renderer->positionForPoint(point - renderer->locationOffset());
4077 // Find the distance from (x, y) to the box. Split the space around the box into 8 pieces
4078 // and use a different compare depending on which piece (x, y) is in.
4080 if (point.x() > right) {
4081 if (point.y() < top)
4082 cmp = LayoutPoint(right, top);
4083 else if (point.y() > bottom)
4084 cmp = LayoutPoint(right, bottom);
4086 cmp = LayoutPoint(right, point.y());
4087 } else if (point.x() < left) {
4088 if (point.y() < top)
4089 cmp = LayoutPoint(left, top);
4090 else if (point.y() > bottom)
4091 cmp = LayoutPoint(left, bottom);
4093 cmp = LayoutPoint(left, point.y());
4095 if (point.y() < top)
4096 cmp = LayoutPoint(point.x(), top);
4098 cmp = LayoutPoint(point.x(), bottom);
4101 LayoutSize difference = cmp - point;
4103 LayoutUnit dist = difference.width() * difference.width() + difference.height() * difference.height();
4104 if (dist < minDist) {
4105 closestRenderer = renderer;
4110 if (closestRenderer)
4111 return closestRenderer->positionForPoint(adjustedPoint - closestRenderer->locationOffset());
4112 return createPositionWithAffinity(firstPositionInOrBeforeNode(nonPseudoNode()));
4115 bool RenderBox::shrinkToAvoidFloats() const
4117 // Floating objects don't shrink. Objects that don't avoid floats don't shrink. Marquees don't shrink.
4118 if ((isInline() && !isMarquee()) || !avoidsFloats() || isFloating())
4121 // Only auto width objects can possibly shrink to avoid floats.
4122 return style()->width().isAuto();
4125 bool RenderBox::avoidsFloats() const
4127 return isReplaced() || hasOverflowClip() || isHR() || isLegend() || isWritingModeRoot() || isFlexItemIncludingDeprecated();
4130 void RenderBox::markForPaginationRelayoutIfNeeded(SubtreeLayoutScope& layoutScope)
4132 ASSERT(!needsLayout());
4133 // If fragmentation height has changed, we need to lay out. No need to enter the renderer if it
4134 // is childless, though.
4135 if (view()->layoutState()->pageLogicalHeightChanged() && firstChild())
4136 layoutScope.setChildNeedsLayout(this);
4139 void RenderBox::addVisualEffectOverflow()
4141 if (!style()->boxShadow() && !style()->hasBorderImageOutsets() && !style()->hasOutline())
4144 bool isFlipped = style()->isFlippedBlocksWritingMode();
4145 bool isHorizontal = isHorizontalWritingMode();
4147 LayoutRect borderBox = borderBoxRect();
4148 LayoutUnit overflowMinX = borderBox.x();
4149 LayoutUnit overflowMaxX = borderBox.maxX();
4150 LayoutUnit overflowMinY = borderBox.y();
4151 LayoutUnit overflowMaxY = borderBox.maxY();
4153 // Compute box-shadow overflow first.
4154 if (style()->boxShadow()) {
4155 LayoutUnit shadowLeft;
4156 LayoutUnit shadowRight;
4157 LayoutUnit shadowTop;
4158 LayoutUnit shadowBottom;
4159 style()->getBoxShadowExtent(shadowTop, shadowRight, shadowBottom, shadowLeft);
4161 // In flipped blocks writing modes such as vertical-rl, the physical right shadow value is actually at the lower x-coordinate.
4162 overflowMinX = borderBox.x() + ((!isFlipped || isHorizontal) ? shadowLeft : -shadowRight);
4163 overflowMaxX = borderBox.maxX() + ((!isFlipped || isHorizontal) ? shadowRight : -shadowLeft);
4164 overflowMinY = borderBox.y() + ((!isFlipped || !isHorizontal) ? shadowTop : -shadowBottom);
4165 overflowMaxY = borderBox.maxY() + ((!isFlipped || !isHorizontal) ? shadowBottom : -shadowTop);
4168 // Now compute border-image-outset overflow.
4169 if (style()->hasBorderImageOutsets()) {
4170 LayoutBoxExtent borderOutsets = style()->borderImageOutsets();
4172 // In flipped blocks writing modes, the physical sides are inverted. For example in vertical-rl, the right
4173 // border is at the lower x coordinate value.
4174 overflowMinX = min(overflowMinX, borderBox.x() - ((!isFlipped || isHorizontal) ? borderOutsets.left() : borderOutsets.right()));
4175 overflowMaxX = max(overflowMaxX, borderBox.maxX() + ((!isFlipped || isHorizontal) ? borderOutsets.right() : borderOutsets.left()));
4176 overflowMinY = min(overflowMinY, borderBox.y() - ((!isFlipped || !isHorizontal) ? borderOutsets.top() : borderOutsets.bottom()));
4177 overflowMaxY = max(overflowMaxY, borderBox.maxY() + ((!isFlipped || !isHorizontal) ? borderOutsets.bottom() : borderOutsets.top()));
4180 if (style()->hasOutline()) {
4181 LayoutUnit outlineSize = style()->outlineSize();
4183 overflowMinX = min(overflowMinX, borderBox.x() - outlineSize);
4184 overflowMaxX = max(overflowMaxX, borderBox.maxX() + outlineSize);
4185 overflowMinY = min(overflowMinY, borderBox.y() - outlineSize);
4186 overflowMaxY = max(overflowMaxY, borderBox.maxY() + outlineSize);
4189 // Add in the final overflow with shadows, outsets and outline combined.
4190 LayoutRect visualEffectOverflow(overflowMinX, overflowMinY, overflowMaxX - overflowMinX, overflowMaxY - overflowMinY);
4191 addVisualOverflow(visualEffectOverflow);
4194 void RenderBox::addOverflowFromChild(RenderBox* child, const LayoutSize& delta)
4196 // Never allow flow threads to propagate overflow up to a parent.
4197 if (child->isRenderFlowThread())
4200 // Only propagate layout overflow from the child if the child isn't clipping its overflow. If it is, then
4201 // its overflow is internal to it, and we don't care about it. layoutOverflowRectForPropagation takes care of this
4202 // and just propagates the border box rect instead.
4203 LayoutRect childLayoutOverflowRect = child->layoutOverflowRectForPropagation(style());
4204 childLayoutOverflowRect.move(delta);
4205 addLayoutOverflow(childLayoutOverflowRect);
4207 // Add in visual overflow from the child. Even if the child clips its overflow, it may still
4208 // have visual overflow of its own set from box shadows or reflections. It is unnecessary to propagate this
4209 // overflow if we are clipping our own overflow.
4210 if (child->hasSelfPaintingLayer())
4212 LayoutRect childVisualOverflowRect = child->visualOverflowRectForPropagation(style());
4213 childVisualOverflowRect.move(delta);
4214 addContentsVisualOverflow(childVisualOverflowRect);
4217 void RenderBox::addLayoutOverflow(const LayoutRect& rect)
4219 LayoutRect clientBox = noOverflowRect();
4220 if (clientBox.contains(rect) || rect.isEmpty())
4223 // For overflow clip objects, we don't want to propagate overflow into unreachable areas.
4224 LayoutRect overflowRect(rect);
4225 if (hasOverflowClip() || isRenderView()) {
4226 // Overflow is in the block's coordinate space and thus is flipped for horizontal-bt and vertical-rl
4227 // writing modes. At this stage that is actually a simplification, since we can treat horizontal-tb/bt as the same
4228 // and vertical-lr/rl as the same.
4229 bool hasTopOverflow = !style()->isLeftToRightDirection() && !isHorizontalWritingMode();
4230 bool hasLeftOverflow = !style()->isLeftToRightDirection() && isHorizontalWritingMode();
4231 if (isFlexibleBox() && style()->isReverseFlexDirection()) {
4232 RenderFlexibleBox* flexibleBox = toRenderFlexibleBox(this);
4233 if (flexibleBox->isHorizontalFlow())
4234 hasLeftOverflow = true;
4236 hasTopOverflow = true;
4239 if (!hasTopOverflow)
4240 overflowRect.shiftYEdgeTo(max(overflowRect.y(), clientBox.y()));
4242 overflowRect.shiftMaxYEdgeTo(min(overflowRect.maxY(), clientBox.maxY()));
4243 if (!hasLeftOverflow)
4244 overflowRect.shiftXEdgeTo(max(overflowRect.x(), clientBox.x()));
4246 overflowRect.shiftMaxXEdgeTo(min(overflowRect.maxX(), clientBox.maxX()));
4248 // Now re-test with the adjusted rectangle and see if it has become unreachable or fully
4250 if (clientBox.contains(overflowRect) || overflowRect.isEmpty())
4255 m_overflow = adoptPtr(new RenderOverflow(clientBox, borderBoxRect()));
4257 m_overflow->addLayoutOverflow(overflowRect);
4260 void RenderBox::addVisualOverflow(const LayoutRect& rect)
4262 LayoutRect borderBox = borderBoxRect();
4263 if (borderBox.contains(rect) || rect.isEmpty())
4267 m_overflow = adoptPtr(new RenderOverflow(noOverflowRect(), borderBox));
4269 m_overflow->addVisualOverflow(rect);
4272 void RenderBox::addContentsVisualOverflow(const LayoutRect& rect)
4274 if (!hasOverflowClip()) {
4275 addVisualOverflow(rect);
4280 LayoutRect clientBox = clientBoxRect();
4281 if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
4282 clientBox.move(-verticalScrollbarWidth(), 0);
4283 m_overflow = adoptPtr(new RenderOverflow(clientBox, borderBoxRect()));
4285 m_overflow->addContentsVisualOverflow(rect);
4288 void RenderBox::clearLayoutOverflow()
4293 if (!hasVisualOverflow() && contentsVisualOverflowRect().isEmpty()) {
4298 m_overflow->setLayoutOverflow(noOverflowRect());
4301 inline static bool percentageLogicalHeightIsResolvable(const RenderBox* box)
4303 return RenderBox::percentageLogicalHeightIsResolvableFromBlock(box->containingBlock(), box->isOutOfFlowPositioned());
4306 bool RenderBox::percentageLogicalHeightIsResolvableFromBlock(const RenderBlock* containingBlock, bool isOutOfFlowPositioned)
4308 // In quirks mode, blocks with auto height are skipped, and we keep looking for an enclosing
4309 // block that may have a specified height and then use it. In strict mode, this violates the
4310 // specification, which states that percentage heights just revert to auto if the containing
4311 // block has an auto height. We still skip anonymous containing blocks in both modes, though, and look
4312 // only at explicit containers.
4313 const RenderBlock* cb = containingBlock;
4314 bool inQuirksMode = cb->document().inQuirksMode();
4315 while (!cb->isRenderView() && !cb->isBody() && !cb->isTableCell() && !cb->isOutOfFlowPositioned() && cb->style()->logicalHeight().isAuto()) {
4316 if (!inQuirksMode && !cb->isAnonymousBlock())
4318 cb = cb->containingBlock();
4321 // A positioned element that specified both top/bottom or that specifies height should be treated as though it has a height
4322 // explicitly specified that can be used for any percentage computations.
4323 // FIXME: We can't just check top/bottom here.
4324 // https://bugs.webkit.org/show_bug.cgi?id=46500
4325 bool isOutOfFlowPositionedWithSpecifiedHeight = cb->isOutOfFlowPositioned() && (!cb->style()->logicalHeight().isAuto() || (!cb->style()->top().isAuto() && !cb->style()->bottom().isAuto()));
4327 // Table cells violate what the CSS spec says to do with heights. Basically we
4328 // don't care if the cell specified a height or not. We just always make ourselves
4329 // be a percentage of the cell's current content height.
4330 if (cb->isTableCell())
4333 // Otherwise we only use our percentage height if our containing block had a specified
4335 if (cb->style()->logicalHeight().isFixed())
4337 if (cb->style()->logicalHeight().isPercent() && !isOutOfFlowPositionedWithSpecifiedHeight)
4338 return percentageLogicalHeightIsResolvableFromBlock(cb->containingBlock(), cb->isOutOfFlowPositioned());
4339 if (cb->isRenderView() || inQuirksMode || isOutOfFlowPositionedWithSpecifiedHeight)
4341 if (cb->isRoot() && isOutOfFlowPositioned) {
4342 // Match the positioned objects behavior, which is that positioned objects will fill their viewport
4343 // always. Note we could only hit this case by recurring into computePercentageLogicalHeight on a positioned containing block.
4350 bool RenderBox::hasUnsplittableScrollingOverflow() const
4352 // We will paginate as long as we don't scroll overflow in the pagination direction.
4353 bool isHorizontal = isHorizontalWritingMode();
4354 if ((isHorizontal && !scrollsOverflowY()) || (!isHorizontal && !scrollsOverflowX()))
4357 // We do have overflow. We'll still be willing to paginate as long as the block
4358 // has auto logical height, auto or undefined max-logical-height and a zero or auto min-logical-height.
4359 // Note this is just a heuristic, and it's still possible to have overflow under these
4360 // conditions, but it should work out to be good enough for common cases. Paginating overflow
4361 // with scrollbars present is not the end of the world and is what we used to do in the old model anyway.
4362 return !style()->logicalHeight().isIntrinsicOrAuto()
4363 || (!style()->logicalMaxHeight().isIntrinsicOrAuto() && !style()->logicalMaxHeight().isUndefined() && (!style()->logicalMaxHeight().isPercent() || percentageLogicalHeightIsResolvable(this)))
4364 || (!style()->logicalMinHeight().isIntrinsicOrAuto() && style()->logicalMinHeight().isPositive() && (!style()->logicalMinHeight().isPercent() || percentageLogicalHeightIsResolvable(this)));
4367 bool RenderBox::isUnsplittableForPagination() const
4369 return isReplaced() || hasUnsplittableScrollingOverflow() || (parent() && isWritingModeRoot());
4372 LayoutUnit RenderBox::lineHeight(bool /*firstLine*/, LineDirectionMode direction, LinePositionMode /*linePositionMode*/) const
4375 return direction == HorizontalLine ? m_marginBox.top() + height() + m_marginBox.bottom() : m_marginBox.right() + width() + m_marginBox.left();
4379 int RenderBox::baselinePosition(FontBaseline baselineType, bool /*firstLine*/, LineDirectionMode direction, LinePositionMode linePositionMode) const
4381 ASSERT(linePositionMode == PositionOnContainingLine);
4383 int result = direction == HorizontalLine ? m_marginBox.top() + height() + m_marginBox.bottom() : m_marginBox.right() + width() + m_marginBox.left();
4384 if (baselineType == AlphabeticBaseline)
4386 return result - result / 2;
4392 RenderLayer* RenderBox::enclosingFloatPaintingLayer() const
4394 const RenderObject* curr = this;
4396 RenderLayer* layer = curr->hasLayer() && curr->isBox() ? toRenderBox(curr)->layer() : 0;
4397 if (layer && layer->isSelfPaintingLayer())
4399 curr = curr->parent();
4404 LayoutRect RenderBox::logicalVisualOverflowRectForPropagation(RenderStyle* parentStyle) const
4406 LayoutRect rect = visualOverflowRectForPropagation(parentStyle);
4407 if (!parentStyle->isHorizontalWritingMode())
4408 return rect.transposedRect();
4412 LayoutRect RenderBox::visualOverflowRectForPropagation(RenderStyle* parentStyle) const
4414 // If the writing modes of the child and parent match, then we don't have to
4415 // do anything fancy. Just return the result.
4416 LayoutRect rect = visualOverflowRect();
4417 if (parentStyle->writingMode() == style()->writingMode())
4420 // We are putting ourselves into our parent's coordinate space. If there is a flipped block mismatch
4421 // in a particular axis, then we have to flip the rect along that axis.
4422 if (style()->writingMode() == RightToLeftWritingMode || parentStyle->writingMode() == RightToLeftWritingMode)
4423 rect.setX(width() - rect.maxX());
4424 else if (style()->writingMode() == BottomToTopWritingMode || parentStyle->writingMode() == BottomToTopWritingMode)
4425 rect.setY(height() - rect.maxY());
4430 LayoutRect RenderBox::logicalLayoutOverflowRectForPropagation(RenderStyle* parentStyle) const
4432 LayoutRect rect = layoutOverflowRectForPropagation(parentStyle);
4433 if (!parentStyle->isHorizontalWritingMode())
4434 return rect.transposedRect();
4438 LayoutRect RenderBox::layoutOverflowRectForPropagation(RenderStyle* parentStyle) const
4440 // Only propagate interior layout overflow if we don't clip it.
4441 LayoutRect rect = borderBoxRect();
4442 // We want to include the margin, but only when it adds height. Quirky margins don't contribute height
4443 // nor do the margins of self-collapsing blocks.
4444 if (!style()->hasMarginAfterQuirk() && !isSelfCollapsingBlock())
4445 rect.expand(isHorizontalWritingMode() ? LayoutSize(LayoutUnit(), marginAfter()) : LayoutSize(marginAfter(), LayoutUnit()));
4447 if (!hasOverflowClip())
4448 rect.unite(layoutOverflowRect());
4450 bool hasTransform = hasLayer() && layer()->transform();
4451 if (isInFlowPositioned() || hasTransform) {
4452 // If we are relatively positioned or if we have a transform, then we have to convert
4453 // this rectangle into physical coordinates, apply relative positioning and transforms
4454 // to it, and then convert it back.
4455 flipForWritingMode(rect);
4458 rect = layer()->currentTransform().mapRect(rect);
4460 if (isInFlowPositioned())
4461 rect.move(offsetForInFlowPosition());
4463 // Now we need to flip back.
4464 flipForWritingMode(rect);
4467 // If the writing modes of the child and parent match, then we don't have to
4468 // do anything fancy. Just return the result.
4469 if (parentStyle->writingMode() == style()->writingMode())
4472 // We are putting ourselves into our parent's coordinate space. If there is a flipped block mismatch
4473 // in a particular axis, then we have to flip the rect along that axis.
4474 if (style()->writingMode() == RightToLeftWritingMode || parentStyle->writingMode() == RightToLeftWritingMode)
4475 rect.setX(width() - rect.maxX());
4476 else if (style()->writingMode() == BottomToTopWritingMode || parentStyle->writingMode() == BottomToTopWritingMode)
4477 rect.setY(height() - rect.maxY());
4482 LayoutRect RenderBox::noOverflowRect() const
4484 // Because of the special coordinate system used for overflow rectangles and many other
4485 // rectangles (not quite logical, not quite physical), we need to flip the block progression
4486 // coordinate in vertical-rl and horizontal-bt writing modes. In other words, the rectangle
4487 // returned is physical, except for the block direction progression coordinate (y in horizontal
4488 // writing modes, x in vertical writing modes), which is always "logical top". Apart from the
4489 // flipping, this method does the same as clientBoxRect().
4491 const int scrollBarWidth = verticalScrollbarWidth();
4492 const int scrollBarHeight = horizontalScrollbarHeight();
4493 LayoutUnit left = borderLeft() + (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft() ? scrollBarWidth : 0);
4494 LayoutUnit top = borderTop();
4495 LayoutUnit right = borderRight();
4496 LayoutUnit bottom = borderBottom();
4497 LayoutRect rect(left, top, width() - left - right, height() - top - bottom);
4498 flipForWritingMode(rect);
4499 // Subtract space occupied by scrollbars. Order is important here: first flip, then subtract
4500 // scrollbars. This may seem backwards and weird, since one would think that a horizontal
4501 // scrollbar at the physical bottom in horizontal-bt ought to be at the logical top (physical
4502 // bottom), between the logical top (physical bottom) border and the logical top (physical
4503 // bottom) padding. But this is how the rest of the code expects us to behave. This is highly
4504 // related to https://bugs.webkit.org/show_bug.cgi?id=76129
4505 // FIXME: when the above mentioned bug is fixed, it should hopefully be possible to call
4506 // clientBoxRect() or paddingBoxRect() in this method, rather than fiddling with the edges on
4508 if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
4509 rect.contract(0, scrollBarHeight);
4511 rect.contract(scrollBarWidth, scrollBarHeight);
4515 LayoutRect RenderBox::overflowRectForPaintRejection() const
4517 LayoutRect overflowRect = visualOverflowRect();
4518 if (!m_overflow || !usesCompositedScrolling())
4519 return overflowRect;
4521 overflowRect.unite(layoutOverflowRect());
4522 overflowRect.move(-scrolledContentOffset());
4523 return overflowRect;
4526 LayoutUnit RenderBox::offsetLeft() const
4528 return adjustedPositionRelativeToOffsetParent(topLeftLocation()).x();
4531 LayoutUnit RenderBox::offsetTop() const
4533 return adjustedPositionRelativeToOffsetParent(topLeftLocation()).y();
4536 LayoutPoint RenderBox::flipForWritingModeForChild(const RenderBox* child, const LayoutPoint& point) const
4538 if (!style()->isFlippedBlocksWritingMode())
4541 // The child is going to add in its x() and y(), so we have to make sure it ends up in
4543 if (isHorizontalWritingMode())
4544 return LayoutPoint(point.x(), point.y() + height() - child->height() - (2 * child->y()));
4545 return LayoutPoint(point.x() + width() - child->width() - (2 * child->x()), point.y());
4548 void RenderBox::flipForWritingMode(LayoutRect& rect) const
4550 if (!style()->isFlippedBlocksWritingMode())
4553 if (isHorizontalWritingMode())
4554 rect.setY(height() - rect.maxY());
4556 rect.setX(width() - rect.maxX());
4559 LayoutUnit RenderBox::flipForWritingMode(LayoutUnit position) const
4561 if (!style()->isFlippedBlocksWritingMode())
4563 return logicalHeight() - position;
4566 LayoutPoint RenderBox::flipForWritingMode(const LayoutPoint& position) const
4568 if (!style()->isFlippedBlocksWritingMode())
4570 return isHorizontalWritingMode() ? LayoutPoint(position.x(), height() - position.y()) : LayoutPoint(width() - position.x(), position.y());
4573 LayoutPoint RenderBox::flipForWritingModeIncludingColumns(const LayoutPoint& point) const
4575 if (!hasColumns() || !style()->isFlippedBlocksWritingMode())
4576 return flipForWritingMode(point);
4577 return toRenderBlock(this)->flipForWritingModeIncludingColumns(point);
4580 LayoutSize RenderBox::flipForWritingMode(const LayoutSize& offset) const
4582 if (!style()->isFlippedBlocksWritingMode())
4584 return isHorizontalWritingMode() ? LayoutSize(offset.width(), height() - offset.height()) : LayoutSize(width() - offset.width(), offset.height());
4587 FloatPoint RenderBox::flipForWritingMode(const FloatPoint& position) const
4589 if (!style()->isFlippedBlocksWritingMode())
4591 return isHorizontalWritingMode() ? FloatPoint(position.x(), height() - position.y()) : FloatPoint(width() - position.x(), position.y());
4594 void RenderBox::flipForWritingMode(FloatRect& rect) const
4596 if (!style()->isFlippedBlocksWritingMode())
4599 if (isHorizontalWritingMode())
4600 rect.setY(height() - rect.maxY());
4602 rect.setX(width() - rect.maxX());
4605 LayoutPoint RenderBox::topLeftLocation() const
4607 RenderBlock* containerBlock = containingBlock();
4608 if (!containerBlock || containerBlock == this)
4610 return containerBlock->flipForWritingModeForChild(this, location());
4613 LayoutSize RenderBox::topLeftLocationOffset() const
4615 RenderBlock* containerBlock = containingBlock();
4616 if (!containerBlock || containerBlock == this)
4617 return locationOffset();
4619 LayoutRect rect(frameRect());
4620 containerBlock->flipForWritingMode(rect); // FIXME: This is wrong if we are an absolutely positioned object enclosed by a relative-positioned inline.
4621 return LayoutSize(rect.x(), rect.y());
4624 bool RenderBox::hasRelativeLogicalHeight() const
4626 return style()->logicalHeight().isPercent()
4627 || style()->logicalMinHeight().isPercent()
4628 || style()->logicalMaxHeight().isPercent();
4631 static void markBoxForRelayoutAfterSplit(RenderBox* box)
4633 // FIXME: The table code should handle that automatically. If not,
4634 // we should fix it and remove the table part checks.
4635 if (box->isTable()) {
4636 // Because we may have added some sections with already computed column structures, we need to
4637 // sync the table structure with them now. This avoids crashes when adding new cells to the table.
4638 toRenderTable(box)->forceSectionsRecalc();
4639 } else if (box->isTableSection())
4640 toRenderTableSection(box)->setNeedsCellRecalc();
4642 box->setNeedsLayoutAndPrefWidthsRecalc();
4645 RenderObject* RenderBox::splitAnonymousBoxesAroundChild(RenderObject* beforeChild)
4647 bool didSplitParentAnonymousBoxes = false;
4649 while (beforeChild->parent() != this) {
4650 RenderBox* boxToSplit = toRenderBox(beforeChild->parent());
4651 if (boxToSplit->firstChild() != beforeChild && boxToSplit->isAnonymous()) {
4652 didSplitParentAnonymousBoxes = true;
4654 // We have to split the parent box into two boxes and move children
4655 // from |beforeChild| to end into the new post box.
4656 RenderBox* postBox = boxToSplit->createAnonymousBoxWithSameTypeAs(this);
4657 postBox->setChildrenInline(boxToSplit->childrenInline());
4658 RenderBox* parentBox = toRenderBox(boxToSplit->parent());
4659 // We need to invalidate the |parentBox| before inserting the new node
4660 // so that the table repainting logic knows the structure is dirty.
4661 // See for example RenderTableCell:clippedOverflowRectForRepaint.
4662 markBoxForRelayoutAfterSplit(parentBox);
4663 parentBox->virtualChildren()->insertChildNode(parentBox, postBox, boxToSplit->nextSibling());
4664 boxToSplit->moveChildrenTo(postBox, beforeChild, 0, true);
4666 markBoxForRelayoutAfterSplit(boxToSplit);
4667 markBoxForRelayoutAfterSplit(postBox);
4669 beforeChild = postBox;
4671 beforeChild = boxToSplit;
4674 if (didSplitParentAnonymousBoxes)
4675 markBoxForRelayoutAfterSplit(this);
4677 ASSERT(beforeChild->parent() == this);
4681 LayoutUnit RenderBox::offsetFromLogicalTopOfFirstPage() const
4683 LayoutState* layoutState = view()->layoutState();
4684 if (layoutState && !layoutState->isPaginated())
4687 if (!layoutState && !flowThreadContainingBlock())
4690 RenderBlock* containerBlock = containingBlock();
4691 return containerBlock->offsetFromLogicalTopOfFirstPage() + logicalTop();
4694 } // namespace WebCore