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"
29 #include "core/HTMLNames.h"
30 #include "core/dom/Document.h"
31 #include "core/editing/htmlediting.h"
32 #include "core/frame/FrameHost.h"
33 #include "core/frame/FrameView.h"
34 #include "core/frame/LocalFrame.h"
35 #include "core/frame/PinchViewport.h"
36 #include "core/frame/Settings.h"
37 #include "core/html/HTMLElement.h"
38 #include "core/html/HTMLFrameElementBase.h"
39 #include "core/html/HTMLFrameOwnerElement.h"
40 #include "core/page/AutoscrollController.h"
41 #include "core/page/EventHandler.h"
42 #include "core/page/Page.h"
43 #include "core/rendering/HitTestResult.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/RenderListBox.h"
52 #include "core/rendering/RenderListMarker.h"
53 #include "core/rendering/RenderTableCell.h"
54 #include "core/rendering/RenderTheme.h"
55 #include "core/rendering/RenderView.h"
56 #include "core/rendering/compositing/RenderLayerCompositor.h"
57 #include "platform/LengthFunctions.h"
58 #include "platform/geometry/FloatQuad.h"
59 #include "platform/geometry/TransformState.h"
60 #include "platform/graphics/GraphicsContextStateSaver.h"
66 using namespace HTMLNames;
68 // Used by flexible boxes when flexing this element and by table cells.
69 typedef WTF::HashMap<const RenderBox*, LayoutUnit> OverrideSizeMap;
71 // Used by grid elements to properly size their grid items.
72 // FIXME: Move these into RenderBoxRareData.
73 static OverrideSizeMap* gOverrideContainingBlockLogicalHeightMap = 0;
74 static OverrideSizeMap* gOverrideContainingBlockLogicalWidthMap = 0;
77 // Size of border belt for autoscroll. When mouse pointer in border belt,
78 // autoscroll is started.
79 static const int autoscrollBeltSize = 20;
80 static const unsigned backgroundObscurationTestMaxDepth = 4;
82 static bool skipBodyBackground(const RenderBox* bodyElementRenderer)
84 ASSERT(bodyElementRenderer->isBody());
85 // The <body> only paints its background if the root element has defined a background independent of the body,
86 // or if the <body>'s parent is not the document element's renderer (e.g. inside SVG foreignObject).
87 RenderObject* documentElementRenderer = bodyElementRenderer->document().documentElement()->renderer();
88 return documentElementRenderer
89 && !documentElementRenderer->hasBackground()
90 && (documentElementRenderer == bodyElementRenderer->parent());
93 RenderBox::RenderBox(ContainerNode* node)
94 : RenderBoxModelObject(node)
95 , m_intrinsicContentLogicalHeight(-1)
96 , m_minPreferredLogicalWidth(-1)
97 , m_maxPreferredLogicalWidth(-1)
102 void RenderBox::willBeDestroyed()
105 clearContainingBlockOverrideSize();
107 RenderBlock::removePercentHeightDescendantIfNeeded(this);
109 ShapeOutsideInfo::removeInfo(*this);
111 RenderBoxModelObject::willBeDestroyed();
114 void RenderBox::removeFloatingOrPositionedChildFromBlockLists()
116 ASSERT(isFloatingOrOutOfFlowPositioned());
118 if (documentBeingDestroyed())
122 RenderBlockFlow* parentBlockFlow = 0;
123 for (RenderObject* curr = parent(); curr && !curr->isRenderView(); curr = curr->parent()) {
124 if (curr->isRenderBlockFlow()) {
125 RenderBlockFlow* currBlockFlow = toRenderBlockFlow(curr);
126 if (!parentBlockFlow || currBlockFlow->containsFloat(this))
127 parentBlockFlow = currBlockFlow;
131 if (parentBlockFlow) {
132 parentBlockFlow->markSiblingsWithFloatsForLayout(this);
133 parentBlockFlow->markAllDescendantsWithFloatsForLayout(this, false);
137 if (isOutOfFlowPositioned())
138 RenderBlock::removePositionedObject(this);
141 void RenderBox::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
143 RenderStyle* oldStyle = style();
145 // The background of the root element or the body element could propagate up to
146 // the canvas. Just dirty the entire canvas when our style changes substantially.
147 if ((diff.needsPaintInvalidation() || diff.needsLayout()) && node()
148 && (isHTMLHtmlElement(*node()) || isHTMLBodyElement(*node()))) {
149 view()->paintInvalidationForWholeRenderer();
151 if (oldStyle->hasEntirelyFixedBackground() != newStyle.hasEntirelyFixedBackground())
152 view()->compositor()->setNeedsUpdateFixedBackground();
155 // When a layout hint happens and an object's position style changes, we have to do a layout
156 // to dirty the render tree using the old position value now.
157 if (diff.needsFullLayout() && parent() && oldStyle->position() != newStyle.position()) {
158 markContainingBlocksForLayout();
159 if (oldStyle->position() == StaticPosition)
160 paintInvalidationForWholeRenderer();
161 else if (newStyle.hasOutOfFlowPosition())
162 parent()->setChildNeedsLayout();
163 if (isFloating() && !isOutOfFlowPositioned() && newStyle.hasOutOfFlowPosition())
164 removeFloatingOrPositionedChildFromBlockLists();
166 // FIXME: This branch runs when !oldStyle, which means that layout was never called
167 // so what's the point in invalidating the whole view that we never painted?
168 } else if (isBody()) {
169 view()->paintInvalidationForWholeRenderer();
172 RenderBoxModelObject::styleWillChange(diff, newStyle);
175 void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
177 // Horizontal writing mode definition is updated in RenderBoxModelObject::updateFromStyle,
178 // (as part of the RenderBoxModelObject::styleDidChange call below). So, we can safely cache the horizontal
179 // writing mode value before style change here.
180 bool oldHorizontalWritingMode = isHorizontalWritingMode();
182 RenderBoxModelObject::styleDidChange(diff, oldStyle);
184 RenderStyle* newStyle = style();
185 if (needsLayout() && oldStyle) {
186 RenderBlock::removePercentHeightDescendantIfNeeded(this);
188 // Normally we can do optimized positioning layout for absolute/fixed positioned objects. There is one special case, however, which is
189 // 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
190 // to determine the new static position.
191 if (isOutOfFlowPositioned() && newStyle->hasStaticBlockPosition(isHorizontalWritingMode()) && oldStyle->marginBefore() != newStyle->marginBefore()
192 && parent() && !parent()->normalChildNeedsLayout())
193 parent()->setChildNeedsLayout();
196 if (RenderBlock::hasPercentHeightContainerMap() && slowFirstChild()
197 && oldHorizontalWritingMode != isHorizontalWritingMode())
198 RenderBlock::clearPercentHeightDescendantsFrom(this);
200 // If our zoom factor changes and we have a defined scrollLeft/Top, we need to adjust that value into the
201 // new zoomed coordinate space.
202 if (hasOverflowClip() && oldStyle && newStyle && oldStyle->effectiveZoom() != newStyle->effectiveZoom() && layer()) {
203 if (int left = layer()->scrollableArea()->scrollXOffset()) {
204 left = (left / oldStyle->effectiveZoom()) * newStyle->effectiveZoom();
205 layer()->scrollableArea()->scrollToXOffset(left);
207 if (int top = layer()->scrollableArea()->scrollYOffset()) {
208 top = (top / oldStyle->effectiveZoom()) * newStyle->effectiveZoom();
209 layer()->scrollableArea()->scrollToYOffset(top);
213 // Our opaqueness might have changed without triggering layout.
214 if (diff.needsPaintInvalidation()) {
215 RenderObject* parentToInvalidate = parent();
216 for (unsigned i = 0; i < backgroundObscurationTestMaxDepth && parentToInvalidate; ++i) {
217 parentToInvalidate->invalidateBackgroundObscurationStatus();
218 parentToInvalidate = parentToInvalidate->parent();
222 if (isDocumentElement() || isBody())
223 document().view()->recalculateScrollbarOverlayStyle();
225 updateShapeOutsideInfoAfterStyleChange(*style(), oldStyle);
226 updateGridPositionAfterStyleChange(oldStyle);
229 void RenderBox::updateShapeOutsideInfoAfterStyleChange(const RenderStyle& style, const RenderStyle* oldStyle)
231 const ShapeValue* shapeOutside = style.shapeOutside();
232 const ShapeValue* oldShapeOutside = oldStyle ? oldStyle->shapeOutside() : RenderStyle::initialShapeOutside();
234 Length shapeMargin = style.shapeMargin();
235 Length oldShapeMargin = oldStyle ? oldStyle->shapeMargin() : RenderStyle::initialShapeMargin();
237 float shapeImageThreshold = style.shapeImageThreshold();
238 float oldShapeImageThreshold = oldStyle ? oldStyle->shapeImageThreshold() : RenderStyle::initialShapeImageThreshold();
240 // FIXME: A future optimization would do a deep comparison for equality. (bug 100811)
241 if (shapeOutside == oldShapeOutside && shapeMargin == oldShapeMargin && shapeImageThreshold == oldShapeImageThreshold)
245 ShapeOutsideInfo::removeInfo(*this);
247 ShapeOutsideInfo::ensureInfo(*this).markShapeAsDirty();
249 if (shapeOutside || shapeOutside != oldShapeOutside)
250 markShapeOutsideDependentsForLayout();
253 void RenderBox::updateGridPositionAfterStyleChange(const RenderStyle* oldStyle)
255 if (!oldStyle || !parent() || !parent()->isRenderGrid())
258 if (oldStyle->gridColumnStart() == style()->gridColumnStart()
259 && oldStyle->gridColumnEnd() == style()->gridColumnEnd()
260 && oldStyle->gridRowStart() == style()->gridRowStart()
261 && oldStyle->gridRowEnd() == style()->gridRowEnd()
262 && oldStyle->order() == style()->order()
263 && oldStyle->hasOutOfFlowPosition() == style()->hasOutOfFlowPosition())
266 // It should be possible to not dirty the grid in some cases (like moving an explicitly placed grid item).
267 // For now, it's more simple to just always recompute the grid.
268 toRenderGrid(parent())->dirtyGrid();
271 void RenderBox::updateFromStyle()
273 RenderBoxModelObject::updateFromStyle();
275 RenderStyle* styleToUse = style();
276 bool isRootObject = isDocumentElement();
277 bool isViewObject = isRenderView();
279 // The root and the RenderView always paint their backgrounds/borders.
280 if (isRootObject || isViewObject)
281 setHasBoxDecorationBackground(true);
283 setFloating(!isOutOfFlowPositioned() && styleToUse->isFloating());
285 bool boxHasOverflowClip = false;
286 if (!styleToUse->isOverflowVisible() && isRenderBlock() && !isViewObject) {
287 // If overflow has been propagated to the viewport, it has no effect here.
288 if (node() != document().viewportDefiningElement())
289 boxHasOverflowClip = true;
292 if (boxHasOverflowClip != hasOverflowClip()) {
293 // FIXME: This shouldn't be required if we tracked the visual overflow
294 // generated by positioned children or self painting layers. crbug.com/345403
295 for (RenderObject* child = slowFirstChild(); child; child = child->nextSibling())
296 child->setShouldDoFullPaintInvalidationIfSelfPaintingLayer(true);
299 toRenderBlock(this)->invalidatePositionedObjectsAffectedByOverflowClip();
302 setHasOverflowClip(boxHasOverflowClip);
304 setHasTransform(styleToUse->hasTransformRelatedProperty());
305 setHasReflection(styleToUse->boxReflect());
308 void RenderBox::layout()
310 ASSERT(needsLayout());
312 RenderObject* child = slowFirstChild();
318 LayoutState state(*this, locationOffset());
320 child->layoutIfNeeded();
321 ASSERT(!child->needsLayout());
322 child = child->nextSibling();
324 invalidateBackgroundObscurationStatus();
328 // More IE extensions. clientWidth and clientHeight represent the interior of an object
329 // excluding border and scrollbar.
330 LayoutUnit RenderBox::clientWidth() const
332 return width() - borderLeft() - borderRight() - verticalScrollbarWidth();
335 LayoutUnit RenderBox::clientHeight() const
337 return height() - borderTop() - borderBottom() - horizontalScrollbarHeight();
340 int RenderBox::pixelSnappedClientWidth() const
342 return snapSizeToPixel(clientWidth(), x() + clientLeft());
345 int RenderBox::pixelSnappedClientHeight() const
347 return snapSizeToPixel(clientHeight(), y() + clientTop());
350 int RenderBox::pixelSnappedOffsetWidth() const
352 return snapSizeToPixel(offsetWidth(), x() + clientLeft());
355 int RenderBox::pixelSnappedOffsetHeight() const
357 return snapSizeToPixel(offsetHeight(), y() + clientTop());
360 LayoutUnit RenderBox::scrollWidth() const
362 if (hasOverflowClip())
363 return layer()->scrollableArea()->scrollWidth();
364 // For objects with visible overflow, this matches IE.
365 // FIXME: Need to work right with writing modes.
366 if (style()->isLeftToRightDirection())
367 return std::max(clientWidth(), layoutOverflowRect().maxX() - borderLeft());
368 return clientWidth() - std::min<LayoutUnit>(0, layoutOverflowRect().x() - borderLeft());
371 LayoutUnit RenderBox::scrollHeight() const
373 if (hasOverflowClip())
374 return layer()->scrollableArea()->scrollHeight();
375 // For objects with visible overflow, this matches IE.
376 // FIXME: Need to work right with writing modes.
377 return std::max(clientHeight(), layoutOverflowRect().maxY() - borderTop());
380 LayoutUnit RenderBox::scrollLeft() const
382 return hasOverflowClip() ? layer()->scrollableArea()->scrollXOffset() : 0;
385 LayoutUnit RenderBox::scrollTop() const
387 return hasOverflowClip() ? layer()->scrollableArea()->scrollYOffset() : 0;
390 int RenderBox::pixelSnappedScrollWidth() const
392 return snapSizeToPixel(scrollWidth(), x() + clientLeft());
395 int RenderBox::pixelSnappedScrollHeight() const
397 if (hasOverflowClip())
398 return layer()->scrollableArea()->scrollHeight();
399 // For objects with visible overflow, this matches IE.
400 // FIXME: Need to work right with writing modes.
401 return snapSizeToPixel(scrollHeight(), y() + clientTop());
404 void RenderBox::setScrollLeft(LayoutUnit newLeft)
406 // This doesn't hit in any tests, but since the equivalent code in setScrollTop
407 // does, presumably this code does as well.
408 DisableCompositingQueryAsserts disabler;
410 if (hasOverflowClip())
411 layer()->scrollableArea()->scrollToXOffset(newLeft, ScrollOffsetClamped);
414 void RenderBox::setScrollTop(LayoutUnit newTop)
416 // Hits in compositing/overflow/do-not-assert-on-invisible-composited-layers.html
417 DisableCompositingQueryAsserts disabler;
419 if (hasOverflowClip())
420 layer()->scrollableArea()->scrollToYOffset(newTop, ScrollOffsetClamped);
423 void RenderBox::scrollToOffset(const IntSize& offset)
425 ASSERT(hasOverflowClip());
427 // This doesn't hit in any tests, but since the equivalent code in setScrollTop
428 // does, presumably this code does as well.
429 DisableCompositingQueryAsserts disabler;
430 layer()->scrollableArea()->scrollToOffset(offset, ScrollOffsetClamped);
433 static inline bool frameElementAndViewPermitScroll(HTMLFrameElementBase* frameElementBase, FrameView* frameView)
435 // If scrollbars aren't explicitly forbidden, permit scrolling.
436 if (frameElementBase && frameElementBase->scrollingMode() != ScrollbarAlwaysOff)
439 // If scrollbars are forbidden, user initiated scrolls should obviously be ignored.
440 if (frameView->wasScrolledByUser())
443 // Forbid autoscrolls when scrollbars are off, but permits other programmatic scrolls,
444 // like navigation to an anchor.
445 Page* page = frameView->frame().page();
448 return !page->autoscrollController().autoscrollInProgress();
451 void RenderBox::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
453 // Presumably the same issue as in setScrollTop. See crbug.com/343132.
454 DisableCompositingQueryAsserts disabler;
456 RenderBox* parentBox = 0;
457 LayoutRect newRect = rect;
459 bool restrictedByLineClamp = false;
461 parentBox = parent()->enclosingBox();
462 restrictedByLineClamp = !parent()->style()->lineClamp().isNone();
465 if (hasOverflowClip() && !restrictedByLineClamp) {
466 // Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property.
467 // This will prevent us from revealing text hidden by the slider in Safari RSS.
468 newRect = layer()->scrollableArea()->exposeRect(rect, alignX, alignY);
469 } else if (!parentBox && canBeProgramaticallyScrolled()) {
470 if (FrameView* frameView = this->frameView()) {
471 Element* ownerElement = document().ownerElement();
473 if (ownerElement && ownerElement->renderer()) {
474 HTMLFrameElementBase* frameElementBase = 0;
476 if (isHTMLFrameElement(*ownerElement) || isHTMLIFrameElement(*ownerElement))
477 frameElementBase = toHTMLFrameElementBase(ownerElement);
479 if (frameElementAndViewPermitScroll(frameElementBase, frameView)) {
480 LayoutRect viewRect = frameView->visibleContentRect();
481 LayoutRect exposeRect = ScrollAlignment::getRectToExpose(viewRect, rect, alignX, alignY);
483 int xOffset = roundToInt(exposeRect.x());
484 int yOffset = roundToInt(exposeRect.y());
485 // Adjust offsets if they're outside of the allowable range.
486 xOffset = std::max(0, std::min(frameView->contentsWidth(), xOffset));
487 yOffset = std::max(0, std::min(frameView->contentsHeight(), yOffset));
489 frameView->setScrollPosition(IntPoint(xOffset, yOffset));
490 if (frameView->safeToPropagateScrollToParent()) {
491 parentBox = ownerElement->renderer()->enclosingBox();
492 // FIXME: This doesn't correctly convert the rect to
493 // absolute coordinates in the parent.
494 newRect.setX(rect.x() - frameView->scrollX() + frameView->x());
495 newRect.setY(rect.y() - frameView->scrollY() + frameView->y());
501 if (frame()->settings()->pinchVirtualViewportEnabled()) {
502 PinchViewport& pinchViewport = frame()->page()->frameHost().pinchViewport();
503 LayoutRect r = ScrollAlignment::getRectToExpose(LayoutRect(pinchViewport.visibleRectInDocument()), rect, alignX, alignY);
504 pinchViewport.scrollIntoView(r);
506 LayoutRect viewRect = frameView->visibleContentRect();
507 LayoutRect r = ScrollAlignment::getRectToExpose(viewRect, rect, alignX, alignY);
508 frameView->setScrollPosition(roundedIntPoint(r.location()));
514 if (frame()->page()->autoscrollController().autoscrollInProgress())
515 parentBox = enclosingScrollableBox();
518 parentBox->scrollRectToVisible(newRect, alignX, alignY);
521 void RenderBox::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
523 rects.append(pixelSnappedIntRect(accumulatedOffset, size()));
526 void RenderBox::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
528 quads.append(localToAbsoluteQuad(FloatRect(0, 0, width().toFloat(), height().toFloat()), 0 /* mode */, wasFixed));
531 void RenderBox::updateLayerTransformAfterLayout()
533 // Transform-origin depends on box size, so we need to update the layer transform after layout.
535 layer()->updateTransformationMatrix();
538 LayoutUnit RenderBox::constrainLogicalWidthByMinMax(LayoutUnit logicalWidth, LayoutUnit availableWidth, RenderBlock* cb) const
540 RenderStyle* styleToUse = style();
541 if (!styleToUse->logicalMaxWidth().isUndefined())
542 logicalWidth = std::min(logicalWidth, computeLogicalWidthUsing(MaxSize, styleToUse->logicalMaxWidth(), availableWidth, cb));
543 return std::max(logicalWidth, computeLogicalWidthUsing(MinSize, styleToUse->logicalMinWidth(), availableWidth, cb));
546 LayoutUnit RenderBox::constrainLogicalHeightByMinMax(LayoutUnit logicalHeight, LayoutUnit intrinsicContentHeight) const
548 RenderStyle* styleToUse = style();
549 if (!styleToUse->logicalMaxHeight().isUndefined()) {
550 LayoutUnit maxH = computeLogicalHeightUsing(styleToUse->logicalMaxHeight(), intrinsicContentHeight);
552 logicalHeight = std::min(logicalHeight, maxH);
554 return std::max(logicalHeight, computeLogicalHeightUsing(styleToUse->logicalMinHeight(), intrinsicContentHeight));
557 LayoutUnit RenderBox::constrainContentBoxLogicalHeightByMinMax(LayoutUnit logicalHeight, LayoutUnit intrinsicContentHeight) const
559 RenderStyle* styleToUse = style();
560 if (!styleToUse->logicalMaxHeight().isUndefined()) {
561 LayoutUnit maxH = computeContentLogicalHeight(styleToUse->logicalMaxHeight(), intrinsicContentHeight);
563 logicalHeight = std::min(logicalHeight, maxH);
565 return std::max(logicalHeight, computeContentLogicalHeight(styleToUse->logicalMinHeight(), intrinsicContentHeight));
568 IntRect RenderBox::absoluteContentBox() const
570 // This is wrong with transforms and flipped writing modes.
571 IntRect rect = pixelSnappedIntRect(contentBoxRect());
572 FloatPoint absPos = localToAbsolute();
573 rect.move(absPos.x(), absPos.y());
577 FloatQuad RenderBox::absoluteContentQuad() const
579 LayoutRect rect = contentBoxRect();
580 return localToAbsoluteQuad(FloatRect(rect));
583 void RenderBox::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*) const
585 if (!size().isEmpty())
586 rects.append(pixelSnappedIntRect(additionalOffset, size()));
589 bool RenderBox::canResize() const
591 // We need a special case for <iframe> because they never have
592 // hasOverflowClip(). However, they do "implicitly" clip their contents, so
593 // we want to allow resizing them also.
594 return (hasOverflowClip() || isRenderIFrame()) && style()->resize() != RESIZE_NONE;
597 void RenderBox::addLayerHitTestRects(LayerHitTestRects& layerRects, const RenderLayer* currentLayer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const
599 LayoutPoint adjustedLayerOffset = layerOffset + locationOffset();
600 RenderBoxModelObject::addLayerHitTestRects(layerRects, currentLayer, adjustedLayerOffset, containerRect);
603 void RenderBox::computeSelfHitTestRects(Vector<LayoutRect>& rects, const LayoutPoint& layerOffset) const
605 if (!size().isEmpty())
606 rects.append(LayoutRect(layerOffset, size()));
609 int RenderBox::reflectionOffset() const
611 if (!style()->boxReflect())
613 if (style()->boxReflect()->direction() == ReflectionLeft || style()->boxReflect()->direction() == ReflectionRight)
614 return valueForLength(style()->boxReflect()->offset(), borderBoxRect().width());
615 return valueForLength(style()->boxReflect()->offset(), borderBoxRect().height());
618 LayoutRect RenderBox::reflectedRect(const LayoutRect& r) const
620 if (!style()->boxReflect())
623 LayoutRect box = borderBoxRect();
624 LayoutRect result = r;
625 switch (style()->boxReflect()->direction()) {
626 case ReflectionBelow:
627 result.setY(box.maxY() + reflectionOffset() + (box.maxY() - r.maxY()));
629 case ReflectionAbove:
630 result.setY(box.y() - reflectionOffset() - box.height() + (box.maxY() - r.maxY()));
633 result.setX(box.x() - reflectionOffset() - box.width() + (box.maxX() - r.maxX()));
635 case ReflectionRight:
636 result.setX(box.maxX() + reflectionOffset() + (box.maxX() - r.maxX()));
642 int RenderBox::verticalScrollbarWidth() const
644 if (!hasOverflowClip() || style()->overflowY() == OOVERLAY)
647 return layer()->scrollableArea()->verticalScrollbarWidth();
650 int RenderBox::horizontalScrollbarHeight() const
652 if (!hasOverflowClip() || style()->overflowX() == OOVERLAY)
655 return layer()->scrollableArea()->horizontalScrollbarHeight();
658 int RenderBox::instrinsicScrollbarLogicalWidth() const
660 if (!hasOverflowClip())
663 if (isHorizontalWritingMode() && style()->overflowY() == OSCROLL) {
664 ASSERT(layer()->scrollableArea() && layer()->scrollableArea()->hasVerticalScrollbar());
665 return verticalScrollbarWidth();
668 if (!isHorizontalWritingMode() && style()->overflowX() == OSCROLL) {
669 ASSERT(layer()->scrollableArea() && layer()->scrollableArea()->hasHorizontalScrollbar());
670 return horizontalScrollbarHeight();
676 bool RenderBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float delta)
678 // Presumably the same issue as in setScrollTop. See crbug.com/343132.
679 DisableCompositingQueryAsserts disabler;
681 // Logical scroll is a higher level concept, all directions by here must be physical
682 ASSERT(!isLogical(direction));
684 if (!layer() || !layer()->scrollableArea())
687 return layer()->scrollableArea()->scroll(direction, granularity, delta);
690 bool RenderBox::canBeScrolledAndHasScrollableArea() const
692 return canBeProgramaticallyScrolled() && (pixelSnappedScrollHeight() != pixelSnappedClientHeight() || pixelSnappedScrollWidth() != pixelSnappedClientWidth());
695 bool RenderBox::canBeProgramaticallyScrolled() const
697 Node* node = this->node();
698 if (node && node->isDocumentNode())
701 if (!hasOverflowClip())
704 bool hasScrollableOverflow = hasScrollableOverflowX() || hasScrollableOverflowY();
705 if (scrollsOverflow() && hasScrollableOverflow)
708 return node && node->hasEditableStyle();
711 bool RenderBox::usesCompositedScrolling() const
713 return hasOverflowClip() && hasLayer() && layer()->scrollableArea()->usesCompositedScrolling();
716 void RenderBox::autoscroll(const IntPoint& position)
718 LocalFrame* frame = this->frame();
722 FrameView* frameView = frame->view();
726 IntPoint currentDocumentPosition = frameView->windowToContents(position);
727 scrollRectToVisible(LayoutRect(currentDocumentPosition, LayoutSize(1, 1)), ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
730 bool RenderBox::autoscrollInProgress() const
732 return frame() && frame()->page() && frame()->page()->autoscrollController().autoscrollInProgress(this);
735 // There are two kinds of renderer that can autoscroll.
736 bool RenderBox::canAutoscroll() const
738 if (node() && node()->isDocumentNode())
739 return view()->frameView()->isScrollable();
741 // Check for a box that can be scrolled in its own right.
742 return canBeScrolledAndHasScrollableArea();
745 // If specified point is in border belt, returned offset denotes direction of
747 IntSize RenderBox::calculateAutoscrollDirection(const IntPoint& windowPoint) const
752 FrameView* frameView = frame()->view();
756 IntRect box(absoluteBoundingBoxRect());
757 box.move(view()->frameView()->scrollOffset());
758 IntRect windowBox = view()->frameView()->contentsToWindow(box);
760 IntPoint windowAutoscrollPoint = windowPoint;
762 if (windowAutoscrollPoint.x() < windowBox.x() + autoscrollBeltSize)
763 windowAutoscrollPoint.move(-autoscrollBeltSize, 0);
764 else if (windowAutoscrollPoint.x() > windowBox.maxX() - autoscrollBeltSize)
765 windowAutoscrollPoint.move(autoscrollBeltSize, 0);
767 if (windowAutoscrollPoint.y() < windowBox.y() + autoscrollBeltSize)
768 windowAutoscrollPoint.move(0, -autoscrollBeltSize);
769 else if (windowAutoscrollPoint.y() > windowBox.maxY() - autoscrollBeltSize)
770 windowAutoscrollPoint.move(0, autoscrollBeltSize);
772 return windowAutoscrollPoint - windowPoint;
775 RenderBox* RenderBox::findAutoscrollable(RenderObject* renderer)
777 while (renderer && !(renderer->isBox() && toRenderBox(renderer)->canAutoscroll())) {
778 if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document().ownerElement())
779 renderer = renderer->document().ownerElement()->renderer();
781 renderer = renderer->parent();
784 return renderer && renderer->isBox() ? toRenderBox(renderer) : 0;
787 static inline int adjustedScrollDelta(int beginningDelta)
789 // This implemention matches Firefox's.
790 // http://mxr.mozilla.org/firefox/source/toolkit/content/widgets/browser.xml#856.
791 const int speedReducer = 12;
793 int adjustedDelta = beginningDelta / speedReducer;
794 if (adjustedDelta > 1)
795 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(adjustedDelta))) - 1;
796 else if (adjustedDelta < -1)
797 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(-adjustedDelta))) + 1;
799 return adjustedDelta;
802 static inline IntSize adjustedScrollDelta(const IntSize& delta)
804 return IntSize(adjustedScrollDelta(delta.width()), adjustedScrollDelta(delta.height()));
807 void RenderBox::panScroll(const IntPoint& sourcePoint)
809 LocalFrame* frame = this->frame();
813 IntPoint lastKnownMousePosition = frame->eventHandler().lastKnownMousePosition();
815 // 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
816 static IntPoint previousMousePosition;
817 if (lastKnownMousePosition.x() < 0 || lastKnownMousePosition.y() < 0)
818 lastKnownMousePosition = previousMousePosition;
820 previousMousePosition = lastKnownMousePosition;
822 IntSize delta = lastKnownMousePosition - sourcePoint;
824 if (abs(delta.width()) <= ScrollView::noPanScrollRadius) // at the center we let the space for the icon
826 if (abs(delta.height()) <= ScrollView::noPanScrollRadius)
829 scrollByRecursively(adjustedScrollDelta(delta), ScrollOffsetClamped);
832 void RenderBox::scrollByRecursively(const IntSize& delta, ScrollOffsetClamping clamp)
837 bool restrictedByLineClamp = false;
839 restrictedByLineClamp = !parent()->style()->lineClamp().isNone();
841 if (hasOverflowClip() && !restrictedByLineClamp) {
842 IntSize newScrollOffset = layer()->scrollableArea()->adjustedScrollOffset() + delta;
843 layer()->scrollableArea()->scrollToOffset(newScrollOffset, clamp);
845 // If this layer can't do the scroll we ask the next layer up that can scroll to try
846 IntSize remainingScrollOffset = newScrollOffset - layer()->scrollableArea()->adjustedScrollOffset();
847 if (!remainingScrollOffset.isZero() && parent()) {
848 if (RenderBox* scrollableBox = enclosingScrollableBox())
849 scrollableBox->scrollByRecursively(remainingScrollOffset, clamp);
851 LocalFrame* frame = this->frame();
852 if (frame && frame->page())
853 frame->page()->autoscrollController().updateAutoscrollRenderer();
855 } else if (view()->frameView()) {
856 // If we are here, we were called on a renderer that can be programmatically scrolled, but doesn't
857 // have an overflow clip. Which means that it is a document node that can be scrolled.
858 view()->frameView()->scrollBy(delta);
860 // FIXME: If we didn't scroll the whole way, do we want to try looking at the frames ownerElement?
861 // https://bugs.webkit.org/show_bug.cgi?id=28237
865 bool RenderBox::needsPreferredWidthsRecalculation() const
867 return style()->paddingStart().isPercent() || style()->paddingEnd().isPercent();
870 IntSize RenderBox::scrolledContentOffset() const
872 ASSERT(hasOverflowClip());
874 return layer()->scrollableArea()->scrollOffset();
877 void RenderBox::applyCachedClipAndScrollOffsetForRepaint(LayoutRect& paintRect) const
880 ASSERT(hasOverflowClip());
882 flipForWritingMode(paintRect);
883 paintRect.move(-scrolledContentOffset()); // For overflow:auto/scroll/hidden.
885 // Do not clip scroll layer contents to reduce the number of repaints while scrolling.
886 if (usesCompositedScrolling()) {
887 flipForWritingMode(paintRect);
891 // height() is inaccurate if we're in the middle of a layout of this RenderBox, so use the
892 // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint
893 // anyway if its size does change.
894 LayoutRect clipRect(LayoutPoint(), layer()->size());
895 paintRect = intersection(paintRect, clipRect);
896 flipForWritingMode(paintRect);
899 void RenderBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
901 minLogicalWidth = minPreferredLogicalWidth() - borderAndPaddingLogicalWidth();
902 maxLogicalWidth = maxPreferredLogicalWidth() - borderAndPaddingLogicalWidth();
905 LayoutUnit RenderBox::minPreferredLogicalWidth() const
907 if (preferredLogicalWidthsDirty()) {
909 SetLayoutNeededForbiddenScope layoutForbiddenScope(const_cast<RenderBox&>(*this));
911 const_cast<RenderBox*>(this)->computePreferredLogicalWidths();
914 return m_minPreferredLogicalWidth;
917 LayoutUnit RenderBox::maxPreferredLogicalWidth() const
919 if (preferredLogicalWidthsDirty()) {
921 SetLayoutNeededForbiddenScope layoutForbiddenScope(const_cast<RenderBox&>(*this));
923 const_cast<RenderBox*>(this)->computePreferredLogicalWidths();
926 return m_maxPreferredLogicalWidth;
929 bool RenderBox::hasOverrideHeight() const
931 return m_rareData && m_rareData->m_overrideLogicalContentHeight != -1;
934 bool RenderBox::hasOverrideWidth() const
936 return m_rareData && m_rareData->m_overrideLogicalContentWidth != -1;
939 void RenderBox::setOverrideLogicalContentHeight(LayoutUnit height)
942 ensureRareData().m_overrideLogicalContentHeight = height;
945 void RenderBox::setOverrideLogicalContentWidth(LayoutUnit width)
948 ensureRareData().m_overrideLogicalContentWidth = width;
951 void RenderBox::clearOverrideLogicalContentHeight()
954 m_rareData->m_overrideLogicalContentHeight = -1;
957 void RenderBox::clearOverrideLogicalContentWidth()
960 m_rareData->m_overrideLogicalContentWidth = -1;
963 void RenderBox::clearOverrideSize()
965 clearOverrideLogicalContentHeight();
966 clearOverrideLogicalContentWidth();
969 LayoutUnit RenderBox::overrideLogicalContentWidth() const
971 ASSERT(hasOverrideWidth());
972 return m_rareData->m_overrideLogicalContentWidth;
975 LayoutUnit RenderBox::overrideLogicalContentHeight() const
977 ASSERT(hasOverrideHeight());
978 return m_rareData->m_overrideLogicalContentHeight;
981 LayoutUnit RenderBox::overrideContainingBlockContentLogicalWidth() const
983 ASSERT(hasOverrideContainingBlockLogicalWidth());
984 return gOverrideContainingBlockLogicalWidthMap->get(this);
987 LayoutUnit RenderBox::overrideContainingBlockContentLogicalHeight() const
989 ASSERT(hasOverrideContainingBlockLogicalHeight());
990 return gOverrideContainingBlockLogicalHeightMap->get(this);
993 bool RenderBox::hasOverrideContainingBlockLogicalWidth() const
995 return gOverrideContainingBlockLogicalWidthMap && gOverrideContainingBlockLogicalWidthMap->contains(this);
998 bool RenderBox::hasOverrideContainingBlockLogicalHeight() const
1000 return gOverrideContainingBlockLogicalHeightMap && gOverrideContainingBlockLogicalHeightMap->contains(this);
1003 void RenderBox::setOverrideContainingBlockContentLogicalWidth(LayoutUnit logicalWidth)
1005 if (!gOverrideContainingBlockLogicalWidthMap)
1006 gOverrideContainingBlockLogicalWidthMap = new OverrideSizeMap;
1007 gOverrideContainingBlockLogicalWidthMap->set(this, logicalWidth);
1010 void RenderBox::setOverrideContainingBlockContentLogicalHeight(LayoutUnit logicalHeight)
1012 if (!gOverrideContainingBlockLogicalHeightMap)
1013 gOverrideContainingBlockLogicalHeightMap = new OverrideSizeMap;
1014 gOverrideContainingBlockLogicalHeightMap->set(this, logicalHeight);
1017 void RenderBox::clearContainingBlockOverrideSize()
1019 if (gOverrideContainingBlockLogicalWidthMap)
1020 gOverrideContainingBlockLogicalWidthMap->remove(this);
1021 clearOverrideContainingBlockContentLogicalHeight();
1024 void RenderBox::clearOverrideContainingBlockContentLogicalHeight()
1026 if (gOverrideContainingBlockLogicalHeightMap)
1027 gOverrideContainingBlockLogicalHeightMap->remove(this);
1030 LayoutUnit RenderBox::adjustBorderBoxLogicalWidthForBoxSizing(LayoutUnit width) const
1032 LayoutUnit bordersPlusPadding = borderAndPaddingLogicalWidth();
1033 if (style()->boxSizing() == CONTENT_BOX)
1034 return width + bordersPlusPadding;
1035 return std::max(width, bordersPlusPadding);
1038 LayoutUnit RenderBox::adjustBorderBoxLogicalHeightForBoxSizing(LayoutUnit height) const
1040 LayoutUnit bordersPlusPadding = borderAndPaddingLogicalHeight();
1041 if (style()->boxSizing() == CONTENT_BOX)
1042 return height + bordersPlusPadding;
1043 return std::max(height, bordersPlusPadding);
1046 LayoutUnit RenderBox::adjustContentBoxLogicalWidthForBoxSizing(LayoutUnit width) const
1048 if (style()->boxSizing() == BORDER_BOX)
1049 width -= borderAndPaddingLogicalWidth();
1050 return std::max<LayoutUnit>(0, width);
1053 LayoutUnit RenderBox::adjustContentBoxLogicalHeightForBoxSizing(LayoutUnit height) const
1055 if (style()->boxSizing() == BORDER_BOX)
1056 height -= borderAndPaddingLogicalHeight();
1057 return std::max<LayoutUnit>(0, height);
1061 bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
1063 LayoutPoint adjustedLocation = accumulatedOffset + location();
1065 // Check kids first.
1066 for (RenderObject* child = slowLastChild(); child; child = child->previousSibling()) {
1067 if ((!child->hasLayer() || !toRenderLayerModelObject(child)->layer()->isSelfPaintingLayer()) && child->nodeAtPoint(request, result, locationInContainer, adjustedLocation, action)) {
1068 updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation));
1073 // Check our bounds next. For this purpose always assume that we can only be hit in the
1074 // foreground phase (which is true for replaced elements like images).
1075 LayoutRect boundsRect = borderBoxRect();
1076 boundsRect.moveBy(adjustedLocation);
1077 if (visibleToHitTestRequest(request) && action == HitTestForeground && locationInContainer.intersects(boundsRect)) {
1078 updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation));
1079 if (!result.addNodeToRectBasedTestResult(node(), request, locationInContainer, boundsRect))
1086 // --------------------- painting stuff -------------------------------
1088 void RenderBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1090 LayoutPoint adjustedPaintOffset = paintOffset + location();
1091 // default implementation. Just pass paint through to the children
1092 PaintInfo childInfo(paintInfo);
1093 childInfo.updatePaintingRootForChildren(this);
1094 for (RenderObject* child = slowFirstChild(); child; child = child->nextSibling())
1095 child->paint(childInfo, adjustedPaintOffset);
1098 void RenderBox::paintRootBoxFillLayers(const PaintInfo& paintInfo)
1100 if (paintInfo.skipRootBackground())
1103 RenderObject* rootBackgroundRenderer = rendererForRootBackground();
1105 const FillLayer& bgLayer = rootBackgroundRenderer->style()->backgroundLayers();
1106 Color bgColor = rootBackgroundRenderer->resolveColor(CSSPropertyBackgroundColor);
1108 paintFillLayers(paintInfo, bgColor, bgLayer, view()->backgroundRect(this), BackgroundBleedNone, CompositeSourceOver, rootBackgroundRenderer);
1111 BackgroundBleedAvoidance RenderBox::determineBackgroundBleedAvoidance(GraphicsContext* context, const BoxDecorationData& boxDecorationData) const
1113 if (!boxDecorationData.hasBackground || !boxDecorationData.hasBorder || !style()->hasBorderRadius() || canRenderBorderImage())
1114 return BackgroundBleedNone;
1116 // FIXME: See crbug.com/382491. getCTM does not accurately reflect the scale at the time content is
1117 // rasterized, and should not be relied on to make decisions about bleeding.
1118 AffineTransform ctm = context->getCTM();
1119 FloatSize contextScaling(static_cast<float>(ctm.xScale()), static_cast<float>(ctm.yScale()));
1121 // Because RoundedRect uses IntRect internally the inset applied by the
1122 // BackgroundBleedShrinkBackground strategy cannot be less than one integer
1123 // layout coordinate, even with subpixel layout enabled. To take that into
1124 // account, we clamp the contextScaling to 1.0 for the following test so
1125 // that borderObscuresBackgroundEdge can only return true if the border
1126 // widths are greater than 2 in both layout coordinates and screen
1128 // This precaution will become obsolete if RoundedRect is ever promoted to
1129 // a sub-pixel representation.
1130 if (contextScaling.width() > 1)
1131 contextScaling.setWidth(1);
1132 if (contextScaling.height() > 1)
1133 contextScaling.setHeight(1);
1135 if (borderObscuresBackgroundEdge(contextScaling))
1136 return BackgroundBleedShrinkBackground;
1137 if (!boxDecorationData.hasAppearance && borderObscuresBackground() && backgroundHasOpaqueTopLayer())
1138 return BackgroundBleedBackgroundOverBorder;
1140 return BackgroundBleedClipBackground;
1143 void RenderBox::paintBoxDecorationBackground(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1145 if (!paintInfo.shouldPaintWithinRoot(this))
1148 LayoutRect paintRect = borderBoxRect();
1149 paintRect.moveBy(paintOffset);
1150 paintBoxDecorationBackgroundWithRect(paintInfo, paintOffset, paintRect);
1153 void RenderBox::paintBoxDecorationBackgroundWithRect(PaintInfo& paintInfo, const LayoutPoint& paintOffset, const LayoutRect& paintRect)
1155 RenderStyle* style = this->style();
1156 BoxDecorationData boxDecorationData(*style);
1157 BackgroundBleedAvoidance bleedAvoidance = determineBackgroundBleedAvoidance(paintInfo.context, boxDecorationData);
1159 // FIXME: Should eventually give the theme control over whether the box shadow should paint, since controls could have
1160 // custom shadows of their own.
1161 if (!boxShadowShouldBeAppliedToBackground(bleedAvoidance))
1162 paintBoxShadow(paintInfo, paintRect, style, Normal);
1164 GraphicsContextStateSaver stateSaver(*paintInfo.context, false);
1165 if (bleedAvoidance == BackgroundBleedClipBackground) {
1167 RoundedRect border = style->getRoundedBorderFor(paintRect);
1168 paintInfo.context->clipRoundedRect(border);
1171 // If we have a native theme appearance, paint that before painting our background.
1172 // The theme will tell us whether or not we should also paint the CSS background.
1173 IntRect snappedPaintRect(pixelSnappedIntRect(paintRect));
1174 bool themePainted = boxDecorationData.hasAppearance && !RenderTheme::theme().paint(this, paintInfo, snappedPaintRect);
1175 if (!themePainted) {
1176 if (bleedAvoidance == BackgroundBleedBackgroundOverBorder)
1177 paintBorder(paintInfo, paintRect, style, bleedAvoidance);
1179 paintBackground(paintInfo, paintRect, boxDecorationData.backgroundColor, bleedAvoidance);
1181 if (boxDecorationData.hasAppearance)
1182 RenderTheme::theme().paintDecorations(this, paintInfo, snappedPaintRect);
1184 paintBoxShadow(paintInfo, paintRect, style, Inset);
1186 // The theme will tell us whether or not we should also paint the CSS border.
1187 if (boxDecorationData.hasBorder && bleedAvoidance != BackgroundBleedBackgroundOverBorder && (!boxDecorationData.hasAppearance || (!themePainted && RenderTheme::theme().paintBorderOnly(this, paintInfo, snappedPaintRect))) && !(isTable() && toRenderTable(this)->collapseBorders()))
1188 paintBorder(paintInfo, paintRect, style, bleedAvoidance);
1191 void RenderBox::paintBackground(const PaintInfo& paintInfo, const LayoutRect& paintRect, const Color& backgroundColor, BackgroundBleedAvoidance bleedAvoidance)
1193 if (isDocumentElement()) {
1194 paintRootBoxFillLayers(paintInfo);
1197 if (isBody() && skipBodyBackground(this))
1199 if (boxDecorationBackgroundIsKnownToBeObscured())
1201 paintFillLayers(paintInfo, backgroundColor, style()->backgroundLayers(), paintRect, bleedAvoidance);
1204 bool RenderBox::getBackgroundPaintedExtent(LayoutRect& paintedExtent) const
1206 ASSERT(hasBackground());
1207 LayoutRect backgroundRect = pixelSnappedIntRect(borderBoxRect());
1209 Color backgroundColor = resolveColor(CSSPropertyBackgroundColor);
1210 if (backgroundColor.alpha()) {
1211 paintedExtent = backgroundRect;
1215 if (!style()->backgroundLayers().image() || style()->backgroundLayers().next()) {
1216 paintedExtent = backgroundRect;
1220 BackgroundImageGeometry geometry;
1221 calculateBackgroundImageGeometry(0, style()->backgroundLayers(), backgroundRect, geometry);
1222 if (geometry.hasNonLocalGeometry())
1224 paintedExtent = geometry.destRect();
1228 bool RenderBox::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const
1230 if (isBody() && skipBodyBackground(this))
1233 Color backgroundColor = resolveColor(CSSPropertyBackgroundColor);
1234 if (backgroundColor.hasAlpha())
1237 // If the element has appearance, it might be painted by theme.
1238 // We cannot be sure if theme paints the background opaque.
1239 // In this case it is safe to not assume opaqueness.
1240 // FIXME: May be ask theme if it paints opaque.
1241 if (style()->hasAppearance())
1243 // FIXME: Check the opaqueness of background images.
1245 // FIXME: Use rounded rect if border radius is present.
1246 if (style()->hasBorderRadius())
1248 // FIXME: The background color clip is defined by the last layer.
1249 if (style()->backgroundLayers().next())
1251 LayoutRect backgroundRect;
1252 switch (style()->backgroundClip()) {
1254 backgroundRect = borderBoxRect();
1256 case PaddingFillBox:
1257 backgroundRect = paddingBoxRect();
1259 case ContentFillBox:
1260 backgroundRect = contentBoxRect();
1265 return backgroundRect.contains(localRect);
1268 static bool isCandidateForOpaquenessTest(RenderBox* childBox)
1270 RenderStyle* childStyle = childBox->style();
1271 if (childStyle->position() != StaticPosition && childBox->containingBlock() != childBox->parent())
1273 if (childStyle->visibility() != VISIBLE || childStyle->shapeOutside())
1275 if (!childBox->width() || !childBox->height())
1277 if (RenderLayer* childLayer = childBox->layer()) {
1278 // FIXME: perhaps this could be less conservative?
1279 if (childLayer->compositingState() != NotComposited)
1281 // FIXME: Deal with z-index.
1282 if (!childStyle->hasAutoZIndex())
1284 if (childLayer->hasTransform() || childLayer->isTransparent() || childLayer->hasFilter())
1286 if (childBox->hasOverflowClip() && childStyle->hasBorderRadius())
1292 bool RenderBox::foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, unsigned maxDepthToTest) const
1294 if (!maxDepthToTest)
1296 for (RenderObject* child = slowFirstChild(); child; child = child->nextSibling()) {
1297 if (!child->isBox())
1299 RenderBox* childBox = toRenderBox(child);
1300 if (!isCandidateForOpaquenessTest(childBox))
1302 LayoutPoint childLocation = childBox->location();
1303 if (childBox->isRelPositioned())
1304 childLocation.move(childBox->relativePositionOffset());
1305 LayoutRect childLocalRect = localRect;
1306 childLocalRect.moveBy(-childLocation);
1307 if (childLocalRect.y() < 0 || childLocalRect.x() < 0) {
1308 // If there is unobscured area above/left of a static positioned box then the rect is probably not covered.
1309 if (childBox->style()->position() == StaticPosition)
1313 if (childLocalRect.maxY() > childBox->height() || childLocalRect.maxX() > childBox->width())
1315 if (childBox->backgroundIsKnownToBeOpaqueInRect(childLocalRect))
1317 if (childBox->foregroundIsKnownToBeOpaqueInRect(childLocalRect, maxDepthToTest - 1))
1323 bool RenderBox::computeBackgroundIsKnownToBeObscured()
1325 // Test to see if the children trivially obscure the background.
1326 // FIXME: This test can be much more comprehensive.
1327 if (!hasBackground())
1329 // Table and root background painting is special.
1330 if (isTable() || isDocumentElement())
1332 // FIXME: box-shadow is painted while background painting.
1333 if (style()->boxShadow())
1335 LayoutRect backgroundRect;
1336 if (!getBackgroundPaintedExtent(backgroundRect))
1338 return foregroundIsKnownToBeOpaqueInRect(backgroundRect, backgroundObscurationTestMaxDepth);
1341 bool RenderBox::backgroundHasOpaqueTopLayer() const
1343 const FillLayer& fillLayer = style()->backgroundLayers();
1344 if (fillLayer.clip() != BorderFillBox)
1347 // Clipped with local scrolling
1348 if (hasOverflowClip() && fillLayer.attachment() == LocalBackgroundAttachment)
1351 if (fillLayer.hasOpaqueImage(this) && fillLayer.hasRepeatXY() && fillLayer.image()->canRender(*this, style()->effectiveZoom()))
1354 // If there is only one layer and no image, check whether the background color is opaque
1355 if (!fillLayer.next() && !fillLayer.hasImage()) {
1356 Color bgColor = resolveColor(CSSPropertyBackgroundColor);
1357 if (bgColor.alpha() == 255)
1364 void RenderBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1366 if (!paintInfo.shouldPaintWithinRoot(this) || style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
1369 LayoutRect paintRect = LayoutRect(paintOffset, size());
1370 paintMaskImages(paintInfo, paintRect);
1373 void RenderBox::paintClippingMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1375 if (!paintInfo.shouldPaintWithinRoot(this) || style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseClippingMask)
1378 if (!layer() || layer()->compositingState() != PaintsIntoOwnBacking)
1381 // We should never have this state in this function. A layer with a mask
1382 // should have always created its own backing if it became composited.
1383 ASSERT(layer()->compositingState() != HasOwnBackingButPaintsIntoAncestor);
1385 LayoutRect paintRect = LayoutRect(paintOffset, size());
1386 paintInfo.context->fillRect(pixelSnappedIntRect(paintRect), Color::black);
1389 void RenderBox::paintMaskImages(const PaintInfo& paintInfo, const LayoutRect& paintRect)
1391 // Figure out if we need to push a transparency layer to render our mask.
1392 bool pushTransparencyLayer = false;
1393 bool compositedMask = hasLayer() && layer()->hasCompositedMask();
1394 bool flattenCompositingLayers = view()->frameView() && view()->frameView()->paintBehavior() & PaintBehaviorFlattenCompositingLayers;
1395 CompositeOperator compositeOp = CompositeSourceOver;
1397 bool allMaskImagesLoaded = true;
1399 if (!compositedMask || flattenCompositingLayers) {
1400 pushTransparencyLayer = true;
1401 StyleImage* maskBoxImage = style()->maskBoxImage().image();
1402 const FillLayer& maskLayers = style()->maskLayers();
1404 // Don't render a masked element until all the mask images have loaded, to prevent a flash of unmasked content.
1406 allMaskImagesLoaded &= maskBoxImage->isLoaded();
1408 allMaskImagesLoaded &= maskLayers.imagesAreLoaded();
1410 paintInfo.context->setCompositeOperation(CompositeDestinationIn);
1411 paintInfo.context->beginTransparencyLayer(1);
1412 compositeOp = CompositeSourceOver;
1415 if (allMaskImagesLoaded) {
1416 paintFillLayers(paintInfo, Color::transparent, style()->maskLayers(), paintRect, BackgroundBleedNone, compositeOp);
1417 paintNinePieceImage(paintInfo.context, paintRect, style(), style()->maskBoxImage(), compositeOp);
1420 if (pushTransparencyLayer)
1421 paintInfo.context->endLayer();
1424 void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer& fillLayer, const LayoutRect& rect,
1425 BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderObject* backgroundObject)
1427 Vector<const FillLayer*, 8> layers;
1428 const FillLayer* curLayer = &fillLayer;
1429 bool shouldDrawBackgroundInSeparateBuffer = false;
1431 layers.append(curLayer);
1432 // Stop traversal when an opaque layer is encountered.
1433 // FIXME : It would be possible for the following occlusion culling test to be more aggressive
1434 // on layers with no repeat by testing whether the image covers the layout rect.
1435 // Testing that here would imply duplicating a lot of calculations that are currently done in
1436 // RenderBoxModelObject::paintFillLayerExtended. A more efficient solution might be to move
1437 // the layer recursion into paintFillLayerExtended, or to compute the layer geometry here
1438 // and pass it down.
1440 if (!shouldDrawBackgroundInSeparateBuffer && curLayer->blendMode() != WebBlendModeNormal)
1441 shouldDrawBackgroundInSeparateBuffer = true;
1443 // The clipOccludesNextLayers condition must be evaluated first to avoid short-circuiting.
1444 if (curLayer->clipOccludesNextLayers(curLayer == &fillLayer) && curLayer->hasOpaqueImage(this) && curLayer->image()->canRender(*this, style()->effectiveZoom()) && curLayer->hasRepeatXY() && curLayer->blendMode() == WebBlendModeNormal && !boxShadowShouldBeAppliedToBackground(bleedAvoidance))
1446 curLayer = curLayer->next();
1449 GraphicsContext* context = paintInfo.context;
1451 shouldDrawBackgroundInSeparateBuffer = false;
1452 if (shouldDrawBackgroundInSeparateBuffer)
1453 context->beginTransparencyLayer(1);
1455 Vector<const FillLayer*>::const_reverse_iterator topLayer = layers.rend();
1456 for (Vector<const FillLayer*>::const_reverse_iterator it = layers.rbegin(); it != topLayer; ++it)
1457 paintFillLayer(paintInfo, c, **it, rect, bleedAvoidance, op, backgroundObject);
1459 if (shouldDrawBackgroundInSeparateBuffer)
1460 context->endLayer();
1463 void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer& fillLayer, const LayoutRect& rect,
1464 BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderObject* backgroundObject)
1466 paintFillLayerExtended(paintInfo, c, fillLayer, rect, bleedAvoidance, 0, LayoutSize(), op, backgroundObject);
1469 void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*)
1474 AllowPaintInvalidationScope scoper(frameView());
1476 if ((style()->borderImage().image() && style()->borderImage().image()->data() == image) ||
1477 (style()->maskBoxImage().image() && style()->maskBoxImage().image()->data() == image)) {
1478 paintInvalidationForWholeRenderer();
1482 ShapeValue* shapeOutsideValue = style()->shapeOutside();
1483 if (!frameView()->isInPerformLayout() && isFloating() && shapeOutsideValue && shapeOutsideValue->image() && shapeOutsideValue->image()->data() == image) {
1484 ShapeOutsideInfo::ensureInfo(*this).markShapeAsDirty();
1485 markShapeOutsideDependentsForLayout();
1488 bool didFullRepaint = repaintLayerRectsForImage(image, style()->backgroundLayers(), true);
1489 if (!didFullRepaint)
1490 repaintLayerRectsForImage(image, style()->maskLayers(), false);
1493 bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer& layers, bool drawingBackground)
1495 LayoutRect rendererRect;
1496 RenderBox* layerRenderer = 0;
1498 for (const FillLayer* curLayer = &layers; curLayer; curLayer = curLayer->next()) {
1499 if (curLayer->image() && image == curLayer->image()->data() && curLayer->image()->canRender(*this, style()->effectiveZoom())) {
1500 // Now that we know this image is being used, compute the renderer and the rect if we haven't already.
1501 if (!layerRenderer) {
1502 bool drawingRootBackground = drawingBackground && (isDocumentElement() || (isBody() && !document().documentElement()->renderer()->hasBackground()));
1503 if (drawingRootBackground) {
1504 layerRenderer = view();
1509 if (FrameView* frameView = toRenderView(layerRenderer)->frameView()) {
1510 rw = frameView->contentsWidth();
1511 rh = frameView->contentsHeight();
1513 rw = layerRenderer->width();
1514 rh = layerRenderer->height();
1516 rendererRect = LayoutRect(-layerRenderer->marginLeft(),
1517 -layerRenderer->marginTop(),
1518 std::max(layerRenderer->width() + layerRenderer->marginWidth() + layerRenderer->borderLeft() + layerRenderer->borderRight(), rw),
1519 std::max(layerRenderer->height() + layerRenderer->marginHeight() + layerRenderer->borderTop() + layerRenderer->borderBottom(), rh));
1521 layerRenderer = this;
1522 rendererRect = borderBoxRect();
1526 BackgroundImageGeometry geometry;
1527 layerRenderer->calculateBackgroundImageGeometry(0, *curLayer, rendererRect, geometry);
1528 if (geometry.hasNonLocalGeometry()) {
1529 // Rather than incur the costs of computing the paintContainer for renderers with fixed backgrounds
1530 // in order to get the right destRect, just repaint the entire renderer.
1531 layerRenderer->paintInvalidationForWholeRenderer();
1535 layerRenderer->invalidatePaintRectangle(geometry.destRect());
1536 if (geometry.destRect() == rendererRect)
1543 InvalidationReason RenderBox::invalidatePaintIfNeeded(const PaintInvalidationState& paintInvalidationState, const RenderLayerModelObject& newPaintInvalidationContainer)
1545 const LayoutRect oldPaintInvalidationRect = previousPaintInvalidationRect();
1546 const LayoutPoint oldPositionFromPaintInvalidationContainer = previousPositionFromPaintInvalidationContainer();
1547 setPreviousPaintInvalidationRect(boundsRectForPaintInvalidation(&newPaintInvalidationContainer, &paintInvalidationState));
1548 setPreviousPositionFromPaintInvalidationContainer(RenderLayer::positionFromPaintInvalidationContainer(this, &newPaintInvalidationContainer, &paintInvalidationState));
1550 InvalidationReason reason = InvalidationNone;
1552 // If we are set to do a full paint invalidation that means the RenderView will be
1553 // issue paint invalidations. We can then skip issuing of paint invalidations for the child
1554 // renderers as they'll be covered by the RenderView.
1555 if (!view()->doingFullPaintInvalidation()) {
1556 if ((onlyNeededPositionedMovementLayout() && compositingState() != PaintsIntoOwnBacking)
1557 || (shouldDoFullPaintInvalidationIfSelfPaintingLayer()
1559 && layer()->isSelfPaintingLayer())) {
1560 setShouldDoFullPaintInvalidation(true, MarkOnlyThis);
1563 reason = RenderObject::invalidatePaintIfNeeded(newPaintInvalidationContainer, oldPaintInvalidationRect, oldPositionFromPaintInvalidationContainer, paintInvalidationState);
1564 if (reason == InvalidationNone || reason == InvalidationIncremental)
1565 invalidatePaintForOverflowIfNeeded();
1567 // Issue paint invalidations for any scrollbars if there is a scrollable area for this renderer.
1568 if (ScrollableArea* area = scrollableArea()) {
1569 if (area->hasVerticalBarDamage())
1570 invalidatePaintRectangle(area->verticalBarDamage());
1571 if (area->hasHorizontalBarDamage())
1572 invalidatePaintRectangle(area->horizontalBarDamage());
1576 // This is for the next invalidatePaintIfNeeded so must be at the end.
1577 savePreviousBorderBoxSizeIfNeeded();
1581 void RenderBox::clearPaintInvalidationState(const PaintInvalidationState& paintInvalidationState)
1583 RenderBoxModelObject::clearPaintInvalidationState(paintInvalidationState);
1585 if (ScrollableArea* area = scrollableArea())
1586 area->resetScrollbarDamage();
1590 bool RenderBox::paintInvalidationStateIsDirty() const
1592 if (ScrollableArea* area = scrollableArea()) {
1593 if (area->hasVerticalBarDamage() || area->hasHorizontalBarDamage())
1596 return RenderBoxModelObject::paintInvalidationStateIsDirty();
1600 bool RenderBox::pushContentsClip(PaintInfo& paintInfo, const LayoutPoint& accumulatedOffset, ContentsClipBehavior contentsClipBehavior)
1602 if (paintInfo.phase == PaintPhaseBlockBackground || paintInfo.phase == PaintPhaseSelfOutline || paintInfo.phase == PaintPhaseMask)
1605 bool isControlClip = hasControlClip();
1606 bool isOverflowClip = hasOverflowClip() && !layer()->isSelfPaintingLayer();
1608 if (!isControlClip && !isOverflowClip)
1611 LayoutRect clipRect = isControlClip ? controlClipRect(accumulatedOffset) : overflowClipRect(accumulatedOffset);
1612 RoundedRect clipRoundedRect(0, 0, 0, 0);
1613 bool hasBorderRadius = style()->hasBorderRadius();
1614 if (hasBorderRadius)
1615 clipRoundedRect = style()->getRoundedInnerBorderFor(LayoutRect(accumulatedOffset, size()));
1617 if (contentsClipBehavior == SkipContentsClipIfPossible) {
1618 LayoutRect contentsVisualOverflow = contentsVisualOverflowRect();
1619 if (contentsVisualOverflow.isEmpty())
1622 LayoutRect conservativeClipRect = clipRect;
1623 if (hasBorderRadius)
1624 conservativeClipRect.intersect(clipRoundedRect.radiusCenterRect());
1625 conservativeClipRect.moveBy(-accumulatedOffset);
1627 conservativeClipRect.move(scrolledContentOffset());
1628 if (conservativeClipRect.contains(contentsVisualOverflow))
1632 if (paintInfo.phase == PaintPhaseOutline)
1633 paintInfo.phase = PaintPhaseChildOutlines;
1634 else if (paintInfo.phase == PaintPhaseChildBlockBackground) {
1635 paintInfo.phase = PaintPhaseBlockBackground;
1636 paintObject(paintInfo, accumulatedOffset);
1637 paintInfo.phase = PaintPhaseChildBlockBackgrounds;
1639 paintInfo.context->save();
1640 if (hasBorderRadius)
1641 paintInfo.context->clipRoundedRect(clipRoundedRect);
1642 paintInfo.context->clip(pixelSnappedIntRect(clipRect));
1646 void RenderBox::popContentsClip(PaintInfo& paintInfo, PaintPhase originalPhase, const LayoutPoint& accumulatedOffset)
1648 ASSERT(hasControlClip() || (hasOverflowClip() && !layer()->isSelfPaintingLayer()));
1650 paintInfo.context->restore();
1651 if (originalPhase == PaintPhaseOutline) {
1652 paintInfo.phase = PaintPhaseSelfOutline;
1653 paintObject(paintInfo, accumulatedOffset);
1654 paintInfo.phase = originalPhase;
1655 } else if (originalPhase == PaintPhaseChildBlockBackground)
1656 paintInfo.phase = originalPhase;
1659 LayoutRect RenderBox::overflowClipRect(const LayoutPoint& location, OverlayScrollbarSizeRelevancy relevancy)
1661 // FIXME: When overflow-clip (CSS3) is implemented, we'll obtain the property
1663 LayoutRect clipRect = borderBoxRect();
1664 clipRect.setLocation(location + clipRect.location() + LayoutSize(borderLeft(), borderTop()));
1665 clipRect.setSize(clipRect.size() - LayoutSize(borderLeft() + borderRight(), borderTop() + borderBottom()));
1667 if (!hasOverflowClip())
1670 // Subtract out scrollbars if we have them.
1671 if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
1672 clipRect.move(layer()->scrollableArea()->verticalScrollbarWidth(relevancy), 0);
1673 clipRect.contract(layer()->scrollableArea()->verticalScrollbarWidth(relevancy), layer()->scrollableArea()->horizontalScrollbarHeight(relevancy));
1678 LayoutRect RenderBox::clipRect(const LayoutPoint& location)
1680 LayoutRect borderBoxRect = this->borderBoxRect();
1681 LayoutRect clipRect = LayoutRect(borderBoxRect.location() + location, borderBoxRect.size());
1683 if (!style()->clipLeft().isAuto()) {
1684 LayoutUnit c = valueForLength(style()->clipLeft(), borderBoxRect.width());
1685 clipRect.move(c, 0);
1686 clipRect.contract(c, 0);
1689 if (!style()->clipRight().isAuto())
1690 clipRect.contract(width() - valueForLength(style()->clipRight(), width()), 0);
1692 if (!style()->clipTop().isAuto()) {
1693 LayoutUnit c = valueForLength(style()->clipTop(), borderBoxRect.height());
1694 clipRect.move(0, c);
1695 clipRect.contract(0, c);
1698 if (!style()->clipBottom().isAuto())
1699 clipRect.contract(0, height() - valueForLength(style()->clipBottom(), height()));
1704 static LayoutUnit portionOfMarginNotConsumedByFloat(LayoutUnit childMargin, LayoutUnit contentSide, LayoutUnit offset)
1706 if (childMargin <= 0)
1708 LayoutUnit contentSideWithMargin = contentSide + childMargin;
1709 if (offset > contentSideWithMargin)
1711 return offset - contentSide;
1714 LayoutUnit RenderBox::shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStart, LayoutUnit childMarginEnd, const RenderBlockFlow* cb) const
1716 LayoutUnit logicalTopPosition = logicalTop();
1717 LayoutUnit width = cb->availableLogicalWidthForLine(logicalTopPosition, false) - std::max<LayoutUnit>(0, childMarginStart) - std::max<LayoutUnit>(0, childMarginEnd);
1719 // We need to see if margins on either the start side or the end side can contain the floats in question. If they can,
1720 // then just using the line width is inaccurate. In the case where a float completely fits, we don't need to use the line
1721 // offset at all, but can instead push all the way to the content edge of the containing block. In the case where the float
1722 // 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
1723 // "consumed" by the float. Negative margins aren't consumed by the float, and so we ignore them.
1724 width += portionOfMarginNotConsumedByFloat(childMarginStart, cb->startOffsetForContent(), cb->startOffsetForLine(logicalTopPosition, false));
1725 width += portionOfMarginNotConsumedByFloat(childMarginEnd, cb->endOffsetForContent(), cb->endOffsetForLine(logicalTopPosition, false));
1729 LayoutUnit RenderBox::containingBlockLogicalWidthForContent() const
1731 if (hasOverrideContainingBlockLogicalWidth())
1732 return overrideContainingBlockContentLogicalWidth();
1734 RenderBlock* cb = containingBlock();
1735 return cb->availableLogicalWidth();
1738 LayoutUnit RenderBox::containingBlockLogicalHeightForContent(AvailableLogicalHeightType heightType) const
1740 if (hasOverrideContainingBlockLogicalHeight())
1741 return overrideContainingBlockContentLogicalHeight();
1743 RenderBlock* cb = containingBlock();
1744 return cb->availableLogicalHeight(heightType);
1747 LayoutUnit RenderBox::containingBlockAvailableLineWidth() const
1749 RenderBlock* cb = containingBlock();
1750 if (cb->isRenderBlockFlow())
1751 return toRenderBlockFlow(cb)->availableLogicalWidthForLine(logicalTop(), false, availableLogicalHeight(IncludeMarginBorderPadding));
1755 LayoutUnit RenderBox::perpendicularContainingBlockLogicalHeight() const
1757 if (hasOverrideContainingBlockLogicalHeight())
1758 return overrideContainingBlockContentLogicalHeight();
1760 RenderBlock* cb = containingBlock();
1761 if (cb->hasOverrideHeight())
1762 return cb->overrideLogicalContentHeight();
1764 RenderStyle* containingBlockStyle = cb->style();
1765 Length logicalHeightLength = containingBlockStyle->logicalHeight();
1767 // FIXME: For now just support fixed heights. Eventually should support percentage heights as well.
1768 if (!logicalHeightLength.isFixed()) {
1769 LayoutUnit fillFallbackExtent = containingBlockStyle->isHorizontalWritingMode() ? view()->frameView()->visibleHeight() : view()->frameView()->visibleWidth();
1770 LayoutUnit fillAvailableExtent = containingBlock()->availableLogicalHeight(ExcludeMarginBorderPadding);
1771 return std::min(fillAvailableExtent, fillFallbackExtent);
1774 // Use the content box logical height as specified by the style.
1775 return cb->adjustContentBoxLogicalHeightForBoxSizing(logicalHeightLength.value());
1778 void RenderBox::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const
1780 if (repaintContainer == this)
1783 if (paintInvalidationState && paintInvalidationState->canMapToContainer(repaintContainer)) {
1784 LayoutSize offset = paintInvalidationState->paintOffset() + locationOffset();
1785 if (style()->hasInFlowPosition() && layer())
1786 offset += layer()->offsetForInFlowPosition();
1787 transformState.move(offset);
1791 bool containerSkipped;
1792 RenderObject* o = container(repaintContainer, &containerSkipped);
1796 bool isFixedPos = style()->position() == FixedPosition;
1797 bool hasTransform = hasLayer() && layer()->transform();
1798 // If this box has a transform, it acts as a fixed position container for fixed descendants,
1799 // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
1800 if (hasTransform && !isFixedPos)
1802 else if (isFixedPos)
1806 *wasFixed = mode & IsFixed;
1808 LayoutSize containerOffset = offsetFromContainer(o, roundedLayoutPoint(transformState.mappedPoint()));
1810 bool preserve3D = mode & UseTransforms && (o->style()->preserves3D() || style()->preserves3D());
1811 if (mode & UseTransforms && shouldUseTransformFromContainer(o)) {
1812 TransformationMatrix t;
1813 getTransformFromContainer(o, containerOffset, t);
1814 transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1816 transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1818 if (containerSkipped) {
1819 // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
1820 // to just subtract the delta between the repaintContainer and o.
1821 LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
1822 transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1826 mode &= ~ApplyContainerFlip;
1828 o->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed);
1831 void RenderBox::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState& transformState) const
1833 bool isFixedPos = style()->position() == FixedPosition;
1834 bool hasTransform = hasLayer() && layer()->transform();
1835 if (hasTransform && !isFixedPos) {
1836 // If this box has a transform, it acts as a fixed position container for fixed descendants,
1837 // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
1839 } else if (isFixedPos)
1842 RenderBoxModelObject::mapAbsoluteToLocalPoint(mode, transformState);
1845 LayoutSize RenderBox::offsetFromContainer(const RenderObject* o, const LayoutPoint& point, bool* offsetDependsOnPoint) const
1847 ASSERT(o == container());
1850 if (isRelPositioned())
1851 offset += offsetForInFlowPosition();
1853 if (!isInline() || isReplaced()) {
1854 if (!style()->hasOutOfFlowPosition() && o->hasColumns()) {
1855 const RenderBlock* block = toRenderBlock(o);
1856 LayoutRect columnRect(frameRect());
1857 block->adjustStartEdgeForWritingModeIncludingColumns(columnRect);
1858 offset += toSize(columnRect.location());
1859 LayoutPoint columnPoint = block->flipForWritingModeIncludingColumns(point + offset);
1860 offset = toLayoutSize(block->flipForWritingModeIncludingColumns(toLayoutPoint(offset)));
1861 offset += o->columnOffset(columnPoint);
1862 offset = block->flipForWritingMode(offset);
1864 if (offsetDependsOnPoint)
1865 *offsetDependsOnPoint = true;
1867 offset += topLeftLocationOffset();
1868 if (o->isRenderFlowThread()) {
1869 // So far the point has been in flow thread coordinates (i.e. as if everything in
1870 // the fragmentation context lived in one tall single column). Convert it to a
1871 // visual point now.
1872 LayoutPoint pointInContainer = point + offset;
1873 offset += o->columnOffset(pointInContainer);
1874 if (offsetDependsOnPoint)
1875 *offsetDependsOnPoint = true;
1880 if (o->hasOverflowClip())
1881 offset -= toRenderBox(o)->scrolledContentOffset();
1883 if (style()->position() == AbsolutePosition && o->isRelPositioned() && o->isRenderInline())
1884 offset += toRenderInline(o)->offsetForInFlowPositionedInline(*this);
1889 InlineBox* RenderBox::createInlineBox()
1891 return new InlineBox(*this);
1894 void RenderBox::dirtyLineBoxes(bool fullLayout)
1896 if (inlineBoxWrapper()) {
1898 inlineBoxWrapper()->destroy();
1900 m_rareData->m_inlineBoxWrapper = 0;
1902 inlineBoxWrapper()->dirtyLineBoxes();
1907 void RenderBox::positionLineBox(InlineBox* box)
1909 if (isOutOfFlowPositioned()) {
1910 // Cache the x position only if we were an INLINE type originally.
1911 bool wasInline = style()->isOriginalDisplayInlineType();
1913 // The value is cached in the xPos of the box. We only need this value if
1914 // our object was inline originally, since otherwise it would have ended up underneath
1916 RootInlineBox& root = box->root();
1917 root.block().setStaticInlinePositionForChild(this, LayoutUnit::fromFloatRound(box->logicalLeft()));
1918 if (style()->hasStaticInlinePosition(box->isHorizontal()))
1919 setChildNeedsLayout(MarkOnlyThis); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
1921 // Our object was a block originally, so we make our normal flow position be
1922 // just below the line box (as though all the inlines that came before us got
1923 // wrapped in an anonymous block, which is what would have happened had we been
1924 // in flow). This value was cached in the y() of the box.
1925 layer()->setStaticBlockPosition(box->logicalTop());
1926 if (style()->hasStaticBlockPosition(box->isHorizontal()))
1927 setChildNeedsLayout(MarkOnlyThis); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
1930 if (container()->isRenderInline())
1931 moveWithEdgeOfInlineContainerIfNecessary(box->isHorizontal());
1934 box->remove(DontMarkLineBoxes);
1936 } else if (isReplaced()) {
1937 setLocation(roundedLayoutPoint(box->topLeft()));
1938 setInlineBoxWrapper(box);
1942 void RenderBox::moveWithEdgeOfInlineContainerIfNecessary(bool isHorizontal)
1944 ASSERT(isOutOfFlowPositioned() && container()->isRenderInline() && container()->isRelPositioned());
1945 // If this object is inside a relative positioned inline and its inline position is an explicit offset from the edge of its container
1946 // then it will need to move if its inline container has changed width. We do not track if the width has changed
1947 // but if we are here then we are laying out lines inside it, so it probably has - mark our object for layout so that it can
1948 // move to the new offset created by the new width.
1949 if (!normalChildNeedsLayout() && !style()->hasStaticInlinePosition(isHorizontal))
1950 setChildNeedsLayout(MarkOnlyThis);
1953 void RenderBox::deleteLineBoxWrapper()
1955 if (inlineBoxWrapper()) {
1956 if (!documentBeingDestroyed())
1957 inlineBoxWrapper()->remove();
1958 inlineBoxWrapper()->destroy();
1960 m_rareData->m_inlineBoxWrapper = 0;
1964 LayoutRect RenderBox::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, const PaintInvalidationState* paintInvalidationState) const
1966 if (style()->visibility() != VISIBLE) {
1967 RenderLayer* layer = enclosingLayer();
1968 layer->updateDescendantDependentFlags();
1969 if (layer->subtreeIsInvisible())
1970 return LayoutRect();
1973 LayoutRect r = visualOverflowRect();
1974 ViewportConstrainedPosition viewportConstraint = style()->position() == FixedPosition ? IsFixedPosition : IsNotFixedPosition;
1975 mapRectToPaintInvalidationBacking(paintInvalidationContainer, r, viewportConstraint, paintInvalidationState);
1979 void RenderBox::mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect, ViewportConstrainedPosition, const PaintInvalidationState* paintInvalidationState) const
1981 // The rect we compute at each step is shifted by our x/y offset in the parent container's coordinate space.
1982 // Only when we cross a writing mode boundary will we have to possibly flipForWritingMode (to convert into a more appropriate
1983 // offset corner for the enclosing container). This allows for a fully RL or BT document to repaint
1984 // properly even during layout, since the rect remains flipped all the way until the end.
1986 // RenderView::computeRectForRepaint then converts the rect to physical coordinates. We also convert to
1987 // physical when we hit a paintInvalidationContainer boundary. Therefore the final rect returned is always in the
1988 // physical coordinate space of the paintInvalidationContainer.
1989 RenderStyle* styleToUse = style();
1991 EPosition position = styleToUse->position();
1993 if (paintInvalidationState && paintInvalidationState->canMapToContainer(paintInvalidationContainer) && position != FixedPosition) {
1994 if (layer() && layer()->transform())
1995 rect = layer()->transform()->mapRect(pixelSnappedIntRect(rect));
1997 // We can't trust the bits on RenderObject, because this might be called while re-resolving style.
1998 if (styleToUse->hasInFlowPosition() && layer())
1999 rect.move(layer()->offsetForInFlowPosition());
2001 rect.moveBy(location());
2002 rect.move(paintInvalidationState->paintOffset());
2003 if (paintInvalidationState->isClipped())
2004 rect.intersect(paintInvalidationState->clipRect());
2008 if (hasReflection())
2009 rect.unite(reflectedRect(rect));
2011 if (paintInvalidationContainer == this) {
2012 if (paintInvalidationContainer->style()->isFlippedBlocksWritingMode())
2013 flipForWritingMode(rect);
2017 bool containerSkipped;
2018 RenderObject* o = container(paintInvalidationContainer, &containerSkipped);
2022 if (isWritingModeRoot())
2023 flipForWritingMode(rect);
2025 LayoutPoint topLeft = rect.location();
2026 topLeft.move(locationOffset());
2028 // We are now in our parent container's coordinate space. Apply our transform to obtain a bounding box
2029 // in the parent's coordinate space that encloses us.
2030 if (hasLayer() && layer()->transform()) {
2031 rect = layer()->transform()->mapRect(pixelSnappedIntRect(rect));
2032 topLeft = rect.location();
2033 topLeft.move(locationOffset());
2036 if (position == AbsolutePosition && o->isRelPositioned() && o->isRenderInline()) {
2037 topLeft += toRenderInline(o)->offsetForInFlowPositionedInline(*this);
2038 } else if (styleToUse->hasInFlowPosition() && layer()) {
2039 // Apply the relative position offset when invalidating a rectangle. The layer
2040 // is translated, but the render box isn't, so we need to do this to get the
2041 // right dirty rect. Since this is called from RenderObject::setStyle, the relative position
2042 // flag on the RenderObject has been cleared, so use the one on the style().
2043 topLeft += layer()->offsetForInFlowPosition();
2046 if (position != AbsolutePosition && position != FixedPosition && o->hasColumns() && o->isRenderBlockFlow()) {
2047 LayoutRect repaintRect(topLeft, rect.size());
2048 toRenderBlock(o)->adjustRectForColumns(repaintRect);
2049 topLeft = repaintRect.location();
2053 // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
2054 // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
2055 rect.setLocation(topLeft);
2056 if (o->hasOverflowClip() && !shouldDoFullPaintInvalidationIfSelfPaintingLayer()) {
2057 RenderBox* containerBox = toRenderBox(o);
2058 containerBox->applyCachedClipAndScrollOffsetForRepaint(rect);
2063 if (containerSkipped) {
2064 // If the paintInvalidationContainer is below o, then we need to map the rect into paintInvalidationContainer's coordinates.
2065 LayoutSize containerOffset = paintInvalidationContainer->offsetFromAncestorContainer(o);
2066 rect.move(-containerOffset);
2070 ViewportConstrainedPosition viewportConstraint = position == FixedPosition ? IsFixedPosition : IsNotFixedPosition;
2071 o->mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, viewportConstraint, paintInvalidationState);
2074 void RenderBox::invalidatePaintForOverhangingFloats(bool)
2078 void RenderBox::updateLogicalWidth()
2080 LogicalExtentComputedValues computedValues;
2081 computeLogicalWidth(computedValues);
2083 setLogicalWidth(computedValues.m_extent);
2084 setLogicalLeft(computedValues.m_position);
2085 setMarginStart(computedValues.m_margins.m_start);
2086 setMarginEnd(computedValues.m_margins.m_end);
2089 static float getMaxWidthListMarker(const RenderBox* renderer)
2093 Node* parentNode = renderer->generatingNode();
2095 ASSERT(isHTMLOListElement(parentNode) || isHTMLUListElement(parentNode));
2096 ASSERT(renderer->style()->textAutosizingMultiplier() != 1);
2099 for (RenderObject* child = renderer->slowFirstChild(); child; child = child->nextSibling()) {
2100 if (!child->isListItem())
2103 RenderBox* listItem = toRenderBox(child);
2104 for (RenderObject* itemChild = listItem->slowFirstChild(); itemChild; itemChild = itemChild->nextSibling()) {
2105 if (!itemChild->isListMarker())
2107 RenderBox* itemMarker = toRenderBox(itemChild);
2108 // Make sure to compute the autosized width.
2109 if (itemMarker->needsLayout())
2110 itemMarker->layout();
2111 maxWidth = std::max<float>(maxWidth, toRenderListMarker(itemMarker)->logicalWidth().toFloat());
2118 void RenderBox::computeLogicalWidth(LogicalExtentComputedValues& computedValues) const
2120 computedValues.m_extent = logicalWidth();
2121 computedValues.m_position = logicalLeft();
2122 computedValues.m_margins.m_start = marginStart();
2123 computedValues.m_margins.m_end = marginEnd();
2125 if (isOutOfFlowPositioned()) {
2126 // FIXME: This calculation is not patched for block-flow yet.
2127 // https://bugs.webkit.org/show_bug.cgi?id=46500
2128 computePositionedLogicalWidth(computedValues);
2132 // If layout is limited to a subtree, the subtree root's logical width does not change.
2133 if (node() && view()->frameView() && view()->frameView()->layoutRoot(true) == this)
2136 // The parent box is flexing us, so it has increased or decreased our
2137 // width. Use the width from the style context.
2138 // FIXME: Account for block-flow in flexible boxes.
2139 // https://bugs.webkit.org/show_bug.cgi?id=46418
2140 if (hasOverrideWidth() && (style()->borderFit() == BorderFitLines || parent()->isFlexibleBoxIncludingDeprecated())) {
2141 computedValues.m_extent = overrideLogicalContentWidth() + borderAndPaddingLogicalWidth();
2145 // FIXME: Account for block-flow in flexible boxes.
2146 // https://bugs.webkit.org/show_bug.cgi?id=46418
2147 bool inVerticalBox = parent()->isDeprecatedFlexibleBox() && (parent()->style()->boxOrient() == VERTICAL);
2148 bool stretching = (parent()->style()->boxAlign() == BSTRETCH);
2149 bool treatAsReplaced = shouldComputeSizeAsReplaced() && (!inVerticalBox || !stretching);
2151 RenderStyle* styleToUse = style();
2152 Length logicalWidthLength = treatAsReplaced ? Length(computeReplacedLogicalWidth(), Fixed) : styleToUse->logicalWidth();
2154 RenderBlock* cb = containingBlock();
2155 LayoutUnit containerLogicalWidth = std::max<LayoutUnit>(0, containingBlockLogicalWidthForContent());
2156 bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHorizontalWritingMode();
2158 if (isInline() && !isInlineBlockOrInlineTable()) {
2159 // just calculate margins
2160 computedValues.m_margins.m_start = minimumValueForLength(styleToUse->marginStart(), containerLogicalWidth);
2161 computedValues.m_margins.m_end = minimumValueForLength(styleToUse->marginEnd(), containerLogicalWidth);
2162 if (treatAsReplaced)
2163 computedValues.m_extent = std::max<LayoutUnit>(floatValueForLength(logicalWidthLength, 0) + borderAndPaddingLogicalWidth(), minPreferredLogicalWidth());
2167 // Width calculations
2168 if (treatAsReplaced)
2169 computedValues.m_extent = logicalWidthLength.value() + borderAndPaddingLogicalWidth();
2171 LayoutUnit containerWidthInInlineDirection = containerLogicalWidth;
2172 if (hasPerpendicularContainingBlock)
2173 containerWidthInInlineDirection = perpendicularContainingBlockLogicalHeight();
2174 LayoutUnit preferredWidth = computeLogicalWidthUsing(MainOrPreferredSize, styleToUse->logicalWidth(), containerWidthInInlineDirection, cb);
2175 computedValues.m_extent = constrainLogicalWidthByMinMax(preferredWidth, containerWidthInInlineDirection, cb);
2178 // Margin calculations.
2179 computeMarginsForDirection(InlineDirection, cb, containerLogicalWidth, computedValues.m_extent, computedValues.m_margins.m_start,
2180 computedValues.m_margins.m_end, style()->marginStart(), style()->marginEnd());
2182 if (!hasPerpendicularContainingBlock && containerLogicalWidth && containerLogicalWidth != (computedValues.m_extent + computedValues.m_margins.m_start + computedValues.m_margins.m_end)
2183 && !isFloating() && !isInline() && !cb->isFlexibleBoxIncludingDeprecated() && !cb->isRenderGrid()) {
2184 LayoutUnit newMargin = containerLogicalWidth - computedValues.m_extent - cb->marginStartForChild(this);
2185 bool hasInvertedDirection = cb->style()->isLeftToRightDirection() != style()->isLeftToRightDirection();
2186 if (hasInvertedDirection)
2187 computedValues.m_margins.m_start = newMargin;
2189 computedValues.m_margins.m_end = newMargin;
2192 if (styleToUse->textAutosizingMultiplier() != 1 && styleToUse->marginStart().type() == Fixed) {
2193 Node* parentNode = generatingNode();
2194 if (parentNode && (isHTMLOListElement(*parentNode) || isHTMLUListElement(*parentNode))) {
2195 // Make sure the markers in a list are properly positioned (i.e. not chopped off) when autosized.
2196 const float adjustedMargin = (1 - 1.0 / styleToUse->textAutosizingMultiplier()) * getMaxWidthListMarker(this);
2197 bool hasInvertedDirection = cb->style()->isLeftToRightDirection() != style()->isLeftToRightDirection();
2198 if (hasInvertedDirection)
2199 computedValues.m_margins.m_end += adjustedMargin;
2201 computedValues.m_margins.m_start += adjustedMargin;
2206 LayoutUnit RenderBox::fillAvailableMeasure(LayoutUnit availableLogicalWidth) const
2208 LayoutUnit marginStart = 0;
2209 LayoutUnit marginEnd = 0;
2210 return fillAvailableMeasure(availableLogicalWidth, marginStart, marginEnd);
2213 LayoutUnit RenderBox::fillAvailableMeasure(LayoutUnit availableLogicalWidth, LayoutUnit& marginStart, LayoutUnit& marginEnd) const
2215 marginStart = minimumValueForLength(style()->marginStart(), availableLogicalWidth);
2216 marginEnd = minimumValueForLength(style()->marginEnd(), availableLogicalWidth);
2217 return availableLogicalWidth - marginStart - marginEnd;
2220 LayoutUnit RenderBox::computeIntrinsicLogicalWidthUsing(const Length& logicalWidthLength, LayoutUnit availableLogicalWidth, LayoutUnit borderAndPadding) const
2222 if (logicalWidthLength.type() == FillAvailable)
2223 return fillAvailableMeasure(availableLogicalWidth);
2225 LayoutUnit minLogicalWidth = 0;
2226 LayoutUnit maxLogicalWidth = 0;
2227 computeIntrinsicLogicalWidths(minLogicalWidth, maxLogicalWidth);
2229 if (logicalWidthLength.type() == MinContent)
2230 return minLogicalWidth + borderAndPadding;
2232 if (logicalWidthLength.type() == MaxContent)
2233 return maxLogicalWidth + borderAndPadding;
2235 if (logicalWidthLength.type() == FitContent) {
2236 minLogicalWidth += borderAndPadding;
2237 maxLogicalWidth += borderAndPadding;
2238 return std::max(minLogicalWidth, std::min(maxLogicalWidth, fillAvailableMeasure(availableLogicalWidth)));
2241 ASSERT_NOT_REACHED();
2245 LayoutUnit RenderBox::computeLogicalWidthUsing(SizeType widthType, const Length& logicalWidth, LayoutUnit availableLogicalWidth, const RenderBlock* cb) const
2247 if (!logicalWidth.isIntrinsicOrAuto()) {
2248 // FIXME: If the containing block flow is perpendicular to our direction we need to use the available logical height instead.
2249 return adjustBorderBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, availableLogicalWidth));
2252 if (logicalWidth.isIntrinsic())
2253 return computeIntrinsicLogicalWidthUsing(logicalWidth, availableLogicalWidth, borderAndPaddingLogicalWidth());
2255 LayoutUnit marginStart = 0;
2256 LayoutUnit marginEnd = 0;
2257 LayoutUnit logicalWidthResult = fillAvailableMeasure(availableLogicalWidth, marginStart, marginEnd);
2259 if (shrinkToAvoidFloats() && cb->isRenderBlockFlow() && toRenderBlockFlow(cb)->containsFloats())
2260 logicalWidthResult = std::min(logicalWidthResult, shrinkLogicalWidthToAvoidFloats(marginStart, marginEnd, toRenderBlockFlow(cb)));
2262 if (widthType == MainOrPreferredSize && sizesLogicalWidthToFitContent(logicalWidth))
2263 return std::max(minPreferredLogicalWidth(), std::min(maxPreferredLogicalWidth(), logicalWidthResult));
2264 return logicalWidthResult;
2267 static bool columnFlexItemHasStretchAlignment(const RenderObject* flexitem)
2269 RenderObject* parent = flexitem->parent();
2270 // auto margins mean we don't stretch. Note that this function will only be used for
2271 // widths, so we don't have to check marginBefore/marginAfter.
2272 ASSERT(parent->style()->isColumnFlexDirection());
2273 if (flexitem->style()->marginStart().isAuto() || flexitem->style()->marginEnd().isAuto())
2275 return flexitem->style()->alignSelf() == ItemPositionStretch || (flexitem->style()->alignSelf() == ItemPositionAuto && parent->style()->alignItems() == ItemPositionStretch);
2278 static bool isStretchingColumnFlexItem(const RenderObject* flexitem)
2280 RenderObject* parent = flexitem->parent();
2281 if (parent->isDeprecatedFlexibleBox() && parent->style()->boxOrient() == VERTICAL && parent->style()->boxAlign() == BSTRETCH)
2284 // We don't stretch multiline flexboxes because they need to apply line spacing (align-content) first.
2285 if (parent->isFlexibleBox() && parent->style()->flexWrap() == FlexNoWrap && parent->style()->isColumnFlexDirection() && columnFlexItemHasStretchAlignment(flexitem))
2290 bool RenderBox::sizesLogicalWidthToFitContent(const Length& logicalWidth) const
2292 // Marquees in WinIE are like a mixture of blocks and inline-blocks. They size as though they're blocks,
2293 // but they allow text to sit on the same line as the marquee.
2294 if (isFloating() || (isInlineBlockOrInlineTable() && !isMarquee()))
2297 if (logicalWidth.type() == Intrinsic)
2300 // Children of a horizontal marquee do not fill the container by default.
2301 // FIXME: Need to deal with MAUTO value properly. It could be vertical.
2302 // FIXME: Think about block-flow here. Need to find out how marquee direction relates to
2303 // block-flow (as well as how marquee overflow should relate to block flow).
2304 // https://bugs.webkit.org/show_bug.cgi?id=46472
2305 if (parent()->isMarquee()) {
2306 EMarqueeDirection dir = parent()->style()->marqueeDirection();
2307 if (dir == MAUTO || dir == MFORWARD || dir == MBACKWARD || dir == MLEFT || dir == MRIGHT)
2311 // Flexible box items should shrink wrap, so we lay them out at their intrinsic widths.
2312 // In the case of columns that have a stretch alignment, we go ahead and layout at the
2313 // stretched size to avoid an extra layout when applying alignment.
2314 if (parent()->isFlexibleBox()) {
2315 // For multiline columns, we need to apply align-content first, so we can't stretch now.
2316 if (!parent()->style()->isColumnFlexDirection() || parent()->style()->flexWrap() != FlexNoWrap)
2318 if (!columnFlexItemHasStretchAlignment(this))
2322 // Flexible horizontal boxes lay out children at their intrinsic widths. Also vertical boxes
2323 // that don't stretch their kids lay out their children at their intrinsic widths.
2324 // FIXME: Think about block-flow here.
2325 // https://bugs.webkit.org/show_bug.cgi?id=46473
2326 if (parent()->isDeprecatedFlexibleBox() && (parent()->style()->boxOrient() == HORIZONTAL || parent()->style()->boxAlign() != BSTRETCH))
2329 // Button, input, select, textarea, and legend treat width value of 'auto' as 'intrinsic' unless it's in a
2330 // stretching column flexbox.
2331 // FIXME: Think about block-flow here.
2332 // https://bugs.webkit.org/show_bug.cgi?id=46473
2333 if (logicalWidth.isAuto() && !isStretchingColumnFlexItem(this) && autoWidthShouldFitContent())
2336 if (isHorizontalWritingMode() != containingBlock()->isHorizontalWritingMode())
2342 bool RenderBox::autoWidthShouldFitContent() const
2344 return node() && (isHTMLInputElement(*node()) || isHTMLSelectElement(*node()) || isHTMLButtonElement(*node())
2345 || isHTMLTextAreaElement(*node()) || (isHTMLLegendElement(*node()) && !style()->hasOutOfFlowPosition()));
2348 void RenderBox::computeMarginsForDirection(MarginDirection flowDirection, const RenderBlock* containingBlock, LayoutUnit containerWidth, LayoutUnit childWidth, LayoutUnit& marginStart, LayoutUnit& marginEnd, Length marginStartLength, Length marginEndLength) const
2350 if (flowDirection == BlockDirection || isFloating() || isInline()) {
2351 if (isTableCell() && flowDirection == BlockDirection) {
2352 // FIXME: Not right if we allow cells to have different directionality than the table. If we do allow this, though,
2353 // we may just do it with an extra anonymous block inside the cell.
2359 // Margins are calculated with respect to the logical width of
2360 // the containing block (8.3)
2361 // Inline blocks/tables and floats don't have their margins increased.
2362 marginStart = minimumValueForLength(marginStartLength, containerWidth);
2363 marginEnd = minimumValueForLength(marginEndLength, containerWidth);
2367 if (containingBlock->isFlexibleBox()) {
2368 // We need to let flexbox handle the margin adjustment - otherwise, flexbox
2369 // will think we're wider than we actually are and calculate line sizes wrong.
2370 // See also http://dev.w3.org/csswg/css-flexbox/#auto-margins
2371 if (marginStartLength.isAuto())
2372 marginStartLength.setValue(0);
2373 if (marginEndLength.isAuto())
2374 marginEndLength.setValue(0);
2377 LayoutUnit marginStartWidth = minimumValueForLength(marginStartLength, containerWidth);
2378 LayoutUnit marginEndWidth = minimumValueForLength(marginEndLength, containerWidth);
2380 LayoutUnit availableWidth = containerWidth;
2381 if (avoidsFloats() && containingBlock->isRenderBlockFlow() && toRenderBlockFlow(containingBlock)->containsFloats()) {
2382 availableWidth = containingBlockAvailableLineWidth();
2383 if (shrinkToAvoidFloats() && availableWidth < containerWidth) {
2384 marginStart = std::max<LayoutUnit>(0, marginStartWidth);
2385 marginEnd = std::max<LayoutUnit>(0, marginEndWidth);
2389 // CSS 2.1 (10.3.3): "If 'width' is not 'auto' and 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width'
2390 // (plus any of 'margin-left' or 'margin-right' that are not 'auto') is larger than the width of the containing block, then any 'auto'
2391 // values for 'margin-left' or 'margin-right' are, for the following rules, treated as zero.
2392 LayoutUnit marginBoxWidth = childWidth + (!style()->width().isAuto() ? marginStartWidth + marginEndWidth : LayoutUnit());
2394 // CSS 2.1: "If both 'margin-left' and 'margin-right' are 'auto', their used values are equal. This horizontally centers the element
2395 // with respect to the edges of the containing block."
2396 const RenderStyle* containingBlockStyle = containingBlock->style();
2397 if ((marginStartLength.isAuto() && marginEndLength.isAuto() && marginBoxWidth < availableWidth)
2398 || (!marginStartLength.isAuto() && !marginEndLength.isAuto() && containingBlockStyle->textAlign() == WEBKIT_CENTER)) {
2399 // Other browsers center the margin box for align=center elements so we match them here.
2400 LayoutUnit centeredMarginBoxStart = std::max<LayoutUnit>(0, (availableWidth - childWidth - marginStartWidth - marginEndWidth) / 2);
2401 marginStart = centeredMarginBoxStart + marginStartWidth;
2402 marginEnd = availableWidth - childWidth - marginStart + marginEndWidth;
2406 // CSS 2.1: "If there is exactly one value specified as 'auto', its used value follows from the equality."
2407 if (marginEndLength.isAuto() && marginBoxWidth < availableWidth) {
2408 marginStart = marginStartWidth;
2409 marginEnd = availableWidth - childWidth - marginStart;
2413 bool pushToEndFromTextAlign = !marginEndLength.isAuto() && ((!containingBlockStyle->isLeftToRightDirection() && containingBlockStyle->textAlign() == WEBKIT_LEFT)
2414 || (containingBlockStyle->isLeftToRightDirection() && containingBlockStyle->textAlign() == WEBKIT_RIGHT));
2415 if ((marginStartLength.isAuto() && marginBoxWidth < availableWidth) || pushToEndFromTextAlign) {
2416 marginEnd = marginEndWidth;
2417 marginStart = availableWidth - childWidth - marginEnd;
2421 // Either no auto margins, or our margin box width is >= the container width, auto margins will just turn into 0.
2422 marginStart = marginStartWidth;
2423 marginEnd = marginEndWidth;
2426 void RenderBox::updateLogicalHeight()
2428 m_intrinsicContentLogicalHeight = contentLogicalHeight();
2430 LogicalExtentComputedValues computedValues;
2431 computeLogicalHeight(logicalHeight(), logicalTop(), computedValues);
2433 setLogicalHeight(computedValues.m_extent);
2434 setLogicalTop(computedValues.m_position);
2435 setMarginBefore(computedValues.m_margins.m_before);
2436 setMarginAfter(computedValues.m_margins.m_after);
2439 void RenderBox::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const
2441 computedValues.m_extent = logicalHeight;
2442 computedValues.m_position = logicalTop;
2444 // Cell height is managed by the table and inline non-replaced elements do not support a height property.
2445 if (isTableCell() || (isInline() && !isReplaced()))
2449 if (isOutOfFlowPositioned())
2450 computePositionedLogicalHeight(computedValues);
2452 RenderBlock* cb = containingBlock();
2454 // If we are perpendicular to our containing block then we need to resolve our block-start and block-end margins so that if they
2455 // are 'auto' we are centred or aligned within the inline flow containing block: this is done by computing the margins as though they are inline.
2456 // Note that as this is the 'sizing phase' we are using our own writing mode rather than the containing block's. We use the containing block's
2457 // writing mode when figuring out the block-direction margins for positioning in |computeAndSetBlockDirectionMargins| (i.e. margin collapsing etc.).
2458 // See http://www.w3.org/TR/2014/CR-css-writing-modes-3-20140320/#orthogonal-flows
2459 MarginDirection flowDirection = isHorizontalWritingMode() != cb->isHorizontalWritingMode() ? InlineDirection : BlockDirection;
2461 // For tables, calculate margins only.
2463 computeMarginsForDirection(flowDirection, cb, containingBlockLogicalWidthForContent(), computedValues.m_extent, computedValues.m_margins.m_before,
2464 computedValues.m_margins.m_after, style()->marginBefore(), style()->marginAfter());
2468 // FIXME: Account for block-flow in flexible boxes.
2469 // https://bugs.webkit.org/show_bug.cgi?id=46418
2470 bool inHorizontalBox = parent()->isDeprecatedFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL;
2471 bool stretching = parent()->style()->boxAlign() == BSTRETCH;
2472 bool treatAsReplaced = shouldComputeSizeAsReplaced() && (!inHorizontalBox || !stretching);
2473 bool checkMinMaxHeight = false;
2475 // The parent box is flexing us, so it has increased or decreased our height. We have to
2476 // grab our cached flexible height.
2477 // FIXME: Account for block-flow in flexible boxes.
2478 // https://bugs.webkit.org/show_bug.cgi?id=46418
2479 if (hasOverrideHeight() && parent()->isFlexibleBoxIncludingDeprecated())
2480 h = Length(overrideLogicalContentHeight(), Fixed);
2481 else if (treatAsReplaced)
2482 h = Length(computeReplacedLogicalHeight(), Fixed);
2484 h = style()->logicalHeight();
2485 checkMinMaxHeight = true;
2488 // Block children of horizontal flexible boxes fill the height of the box.
2489 // FIXME: Account for block-flow in flexible boxes.
2490 // https://bugs.webkit.org/show_bug.cgi?id=46418
2491 if (h.isAuto() && inHorizontalBox && toRenderDeprecatedFlexibleBox(parent())->isStretchingChildren()) {
2492 h = Length(parentBox()->contentLogicalHeight() - marginBefore() - marginAfter() - borderAndPaddingLogicalHeight(), Fixed);
2493 checkMinMaxHeight = false;
2496 LayoutUnit heightResult;
2497 if (checkMinMaxHeight) {
2498 heightResult = computeLogicalHeightUsing(style()->logicalHeight(), computedValues.m_extent - borderAndPaddingLogicalHeight());
2499 if (heightResult == -1)
2500 heightResult = computedValues.m_extent;
2501 heightResult = constrainLogicalHeightByMinMax(heightResult, computedValues.m_extent - borderAndPaddingLogicalHeight());
2503 // The only times we don't check min/max height are when a fixed length has
2504 // been given as an override. Just use that. The value has already been adjusted
2506 ASSERT(h.isFixed());
2507 heightResult = h.value() + borderAndPaddingLogicalHeight();
2510 computedValues.m_extent = heightResult;
2511 computeMarginsForDirection(flowDirection, cb, containingBlockLogicalWidthForContent(), computedValues.m_extent, computedValues.m_margins.m_before,
2512 computedValues.m_margins.m_after, style()->marginBefore(), style()->marginAfter());
2515 // WinIE quirk: The <html> block always fills the entire canvas in quirks mode. The <body> always fills the
2516 // <html> block in quirks mode. Only apply this quirk if the block is normal flow and no height
2517 // is specified. When we're printing, we also need this quirk if the body or root has a percentage
2518 // height since we don't set a height in RenderView when we're printing. So without this quirk, the
2519 // height has nothing to be a percentage of, and it ends up being 0. That is bad.
2520 bool paginatedContentNeedsBaseHeight = document().printing() && h.isPercent()
2521 && (isDocumentElement() || (isBody() && document().documentElement()->renderer()->style()->logicalHeight().isPercent())) && !isInline();
2522 if (stretchesToViewport() || paginatedContentNeedsBaseHeight) {
2523 LayoutUnit margins = collapsedMarginBefore() + collapsedMarginAfter();
2524 LayoutUnit visibleHeight = view()->viewLogicalHeightForPercentages();
2525 if (isDocumentElement())
2526 computedValues.m_extent = std::max(computedValues.m_extent, visibleHeight - margins);
2528 LayoutUnit marginsBordersPadding = margins + parentBox()->marginBefore() + parentBox()->marginAfter() + parentBox()->borderAndPaddingLogicalHeight();
2529 computedValues.m_extent = std::max(computedValues.m_extent, visibleHeight - marginsBordersPadding);
2534 LayoutUnit RenderBox::computeLogicalHeightUsing(const Length& height, LayoutUnit intrinsicContentHeight) const
2536 LayoutUnit logicalHeight = computeContentAndScrollbarLogicalHeightUsing(height, intrinsicContentHeight);
2537 if (logicalHeight != -1)
2538 logicalHeight = adjustBorderBoxLogicalHeightForBoxSizing(logicalHeight);
2539 return logicalHeight;
2542 LayoutUnit RenderBox::computeContentLogicalHeight(const Length& height, LayoutUnit intrinsicContentHeight) const
2544 LayoutUnit heightIncludingScrollbar = computeContentAndScrollbarLogicalHeightUsing(height, intrinsicContentHeight);
2545 if (heightIncludingScrollbar == -1)
2547 return std::max<LayoutUnit>(0, adjustContentBoxLogicalHeightForBoxSizing(heightIncludingScrollbar) - scrollbarLogicalHeight());
2550 LayoutUnit RenderBox::computeIntrinsicLogicalContentHeightUsing(const Length& logicalHeightLength, LayoutUnit intrinsicContentHeight, LayoutUnit borderAndPadding) const
2552 // FIXME(cbiesinger): The css-sizing spec is considering changing what min-content/max-content should resolve to.
2553 // If that happens, this code will have to change.
2554 if (logicalHeightLength.isMinContent() || logicalHeightLength.isMaxContent() || logicalHeightLength.isFitContent()) {
2556 return intrinsicSize().height();
2557 if (m_intrinsicContentLogicalHeight != -1)
2558 return m_intrinsicContentLogicalHeight;
2559 return intrinsicContentHeight;
2561 if (logicalHeightLength.isFillAvailable())
2562 return containingBlock()->availableLogicalHeight(ExcludeMarginBorderPadding) - borderAndPadding;
2563 ASSERT_NOT_REACHED();
2567 LayoutUnit RenderBox::computeContentAndScrollbarLogicalHeightUsing(const Length& height, LayoutUnit intrinsicContentHeight) const
2569 // FIXME(cbiesinger): The css-sizing spec is considering changing what min-content/max-content should resolve to.
2570 // If that happens, this code will have to change.
2571 if (height.isIntrinsic()) {
2572 if (intrinsicContentHeight == -1)
2573 return -1; // Intrinsic height isn't available.
2574 return computeIntrinsicLogicalContentHeightUsing(height, intrinsicContentHeight, borderAndPaddingLogicalHeight());
2576 if (height.isFixed())
2577 return height.value();
2578 if (height.isPercent())
2579 return computePercentageLogicalHeight(height);
2583 bool RenderBox::skipContainingBlockForPercentHeightCalculation(const RenderBox* containingBlock) const
2585 // Flow threads for multicol or paged overflow should be skipped. They are invisible to the DOM,
2586 // and percent heights of children should be resolved against the multicol or paged container.
2587 if (containingBlock->isRenderFlowThread())
2590 // For quirks mode and anonymous blocks, we skip auto-height containingBlocks when computing percentages.
2591 // For standards mode, we treat the percentage as auto if it has an auto-height containing block.
2592 if (!document().inQuirksMode() && !containingBlock->isAnonymousBlock())
2594 return !containingBlock->isTableCell() && !containingBlock->isOutOfFlowPositioned() && containingBlock->style()->logicalHeight().isAuto() && isHorizontalWritingMode() == containingBlock->isHorizontalWritingMode();
2597 LayoutUnit RenderBox::computePercentageLogicalHeight(const Length& height) const
2599 LayoutUnit availableHeight = -1;
2601 bool skippedAutoHeightContainingBlock = false;
2602 RenderBlock* cb = containingBlock();
2603 const RenderBox* containingBlockChild = this;
2604 LayoutUnit rootMarginBorderPaddingHeight = 0;
2605 while (!cb->isRenderView() && skipContainingBlockForPercentHeightCalculation(cb)) {
2606 if (cb->isBody() || cb->isDocumentElement())
2607 rootMarginBorderPaddingHeight += cb->marginBefore() + cb->marginAfter() + cb->borderAndPaddingLogicalHeight();
2608 skippedAutoHeightContainingBlock = true;
2609 containingBlockChild = cb;
2610 cb = cb->containingBlock();
2612 cb->addPercentHeightDescendant(const_cast<RenderBox*>(this));
2614 RenderStyle* cbstyle = cb->style();
2616 // A positioned element that specified both top/bottom or that specifies height should be treated as though it has a height
2617 // explicitly specified that can be used for any percentage computations.
2618 bool isOutOfFlowPositionedWithSpecifiedHeight = cb->isOutOfFlowPositioned() && (!cbstyle->logicalHeight().isAuto() || (!cbstyle->logicalTop().isAuto() && !cbstyle->logicalBottom().isAuto()));
2620 bool includeBorderPadding = isTable();
2622 if (isHorizontalWritingMode() != cb->isHorizontalWritingMode())
2623 availableHeight = containingBlockChild->containingBlockLogicalWidthForContent();
2624 else if (hasOverrideContainingBlockLogicalHeight())
2625 availableHeight = overrideContainingBlockContentLogicalHeight();
2626 else if (cb->isTableCell()) {
2627 if (!skippedAutoHeightContainingBlock) {
2628 // Table cells violate what the CSS spec says to do with heights. Basically we
2629 // don't care if the cell specified a height or not. We just always make ourselves
2630 // be a percentage of the cell's current content height.
2631 if (!cb->hasOverrideHeight()) {
2632 // Normally we would let the cell size intrinsically, but scrolling overflow has to be
2633 // treated differently, since WinIE lets scrolled overflow regions shrink as needed.
2634 // While we can't get all cases right, we can at least detect when the cell has a specified
2635 // height or when the table has a specified height. In these cases we want to initially have
2636 // no size and allow the flexing of the table or the cell to its specified height to cause us
2637 // to grow to fill the space. This could end up being wrong in some cases, but it is
2638 // preferable to the alternative (sizing intrinsically and making the row end up too big).
2639 RenderTableCell* cell = toRenderTableCell(cb);
2640 if (scrollsOverflowY() && (!cell->style()->logicalHeight().isAuto() || !cell->table()->style()->logicalHeight().isAuto()))
2644 availableHeight = cb->overrideLogicalContentHeight();
2645 includeBorderPadding = true;
2647 } else if (cbstyle->logicalHeight().isFixed()) {
2648 LayoutUnit contentBoxHeight = cb->adjustContentBoxLogicalHeightForBoxSizing(cbstyle->logicalHeight().value());
2649 availableHeight = std::max<LayoutUnit>(0, cb->constrainContentBoxLogicalHeightByMinMax(contentBoxHeight - cb->scrollbarLogicalHeight(), -1));
2650 } else if (cbstyle->logicalHeight().isPercent() && !isOutOfFlowPositionedWithSpecifiedHeight) {
2651 // We need to recur and compute the percentage height for our containing block.
2652 LayoutUnit heightWithScrollbar = cb->computePercentageLogicalHeight(cbstyle->logicalHeight());
2653 if (heightWithScrollbar != -1) {
2654 LayoutUnit contentBoxHeightWithScrollbar = cb->adjustContentBoxLogicalHeightForBoxSizing(heightWithScrollbar);
2655 // We need to adjust for min/max height because this method does not
2656 // handle the min/max of the current block, its caller does. So the
2657 // return value from the recursive call will not have been adjusted
2659 LayoutUnit contentBoxHeight = cb->constrainContentBoxLogicalHeightByMinMax(contentBoxHeightWithScrollbar - cb->scrollbarLogicalHeight(), -1);
2660 availableHeight = std::max<LayoutUnit>(0, contentBoxHeight);
2662 } else if (isOutOfFlowPositionedWithSpecifiedHeight) {
2663 // Don't allow this to affect the block' height() member variable, since this
2664 // can get called while the block is still laying out its kids.
2665 LogicalExtentComputedValues computedValues;
2666 cb->computeLogicalHeight(cb->logicalHeight(), 0, computedValues);
2667 availableHeight = computedValues.m_extent - cb->borderAndPaddingLogicalHeight() - cb->scrollbarLogicalHeight();
2668 } else if (cb->isRenderView())
2669 availableHeight = view()->viewLogicalHeightForPercentages();
2671 if (availableHeight == -1)
2672 return availableHeight;
2674 availableHeight -= rootMarginBorderPaddingHeight;
2676 if (isTable() && isOutOfFlowPositioned())
2677 availableHeight += cb->paddingLogicalHeight();
2679 LayoutUnit result = valueForLength(height, availableHeight);
2680 if (includeBorderPadding) {
2681 // FIXME: Table cells should default to box-sizing: border-box so we can avoid this hack.
2682 // It is necessary to use the border-box to match WinIE's broken
2683 // box model. This is essential for sizing inside
2684 // table cells using percentage heights.
2685 result -= borderAndPaddingLogicalHeight();
2686 return std::max<LayoutUnit>(0, result);
2691 LayoutUnit RenderBox::computeReplacedLogicalWidth(ShouldComputePreferred shouldComputePreferred) const
2693 return computeReplacedLogicalWidthRespectingMinMaxWidth(computeReplacedLogicalWidthUsing(style()->logicalWidth()), shouldComputePreferred);
2696 LayoutUnit RenderBox::computeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUnit logicalWidth, ShouldComputePreferred shouldComputePreferred) const
2698 LayoutUnit minLogicalWidth = (shouldComputePreferred == ComputePreferred && style()->logicalMinWidth().isPercent()) || style()->logicalMinWidth().isUndefined() ? logicalWidth : computeReplacedLogicalWidthUsing(style()->logicalMinWidth());
2699 LayoutUnit maxLogicalWidth = (shouldComputePreferred == ComputePreferred && style()->logicalMaxWidth().isPercent()) || style()->logicalMaxWidth().isUndefined() ? logicalWidth : computeReplacedLogicalWidthUsing(style()->logicalMaxWidth());
2700 return std::max(minLogicalWidth, std::min(logicalWidth, maxLogicalWidth));
2703 LayoutUnit RenderBox::computeReplacedLogicalWidthUsing(const Length& logicalWidth) const
2705 switch (logicalWidth.type()) {
2707 return adjustContentBoxLogicalWidthForBoxSizing(logicalWidth.value());
2710 // MinContent/MaxContent don't need the availableLogicalWidth argument.
2711 LayoutUnit availableLogicalWidth = 0;
2712 return computeIntrinsicLogicalWidthUsing(logicalWidth, availableLogicalWidth, borderAndPaddingLogicalWidth()) - borderAndPaddingLogicalWidth();
2718 // FIXME: containingBlockLogicalWidthForContent() is wrong if the replaced element's block-flow is perpendicular to the
2719 // containing block's block-flow.
2720 // https://bugs.webkit.org/show_bug.cgi?id=46496
2721 const LayoutUnit cw = isOutOfFlowPositioned() ? containingBlockLogicalWidthForPositioned(toRenderBoxModelObject(container())) : containingBlockLogicalWidthForContent();
2722 Length containerLogicalWidth = containingBlock()->style()->logicalWidth();
2723 // FIXME: Handle cases when containing block width is calculated or viewport percent.
2724 // https://bugs.webkit.org/show_bug.cgi?id=91071
2725 if (logicalWidth.isIntrinsic())
2726 return computeIntrinsicLogicalWidthUsing(logicalWidth, cw, borderAndPaddingLogicalWidth()) - borderAndPaddingLogicalWidth();
2727 if (cw > 0 || (!cw && (containerLogicalWidth.isFixed() || containerLogicalWidth.isPercent())))
2728 return adjustContentBoxLogicalWidthForBoxSizing(minimumValueForLength(logicalWidth, cw));
2735 return intrinsicLogicalWidth();
2742 ASSERT_NOT_REACHED();
2746 LayoutUnit RenderBox::computeReplacedLogicalHeight() const
2748 return computeReplacedLogicalHeightRespectingMinMaxHeight(computeReplacedLogicalHeightUsing(style()->logicalHeight()));
2751 bool RenderBox::logicalHeightComputesAsNone(SizeType sizeType) const
2753 ASSERT(sizeType == MinSize || sizeType == MaxSize);
2754 Length logicalHeight = sizeType == MinSize ? style()->logicalMinHeight() : style()->logicalMaxHeight();
2755 Length initialLogicalHeight = sizeType == MinSize ? RenderStyle::initialMinSize() : RenderStyle::initialMaxSize();
2757 if (logicalHeight == initialLogicalHeight)
2760 if (!logicalHeight.isPercent() || isOutOfFlowPositioned())
2763 // Anonymous block boxes are ignored when resolving percentage values that would refer to it:
2764 // the closest non-anonymous ancestor box is used instead.
2765 RenderBlock* containingBlock = this->containingBlock();
2766 while (containingBlock->isAnonymous())
2767 containingBlock = containingBlock->containingBlock();
2769 return containingBlock->hasAutoHeightOrContainingBlockWithAutoHeight();
2772 LayoutUnit RenderBox::computeReplacedLogicalHeightRespectingMinMaxHeight(LayoutUnit logicalHeight) const
2774 // If the height of the containing block is not specified explicitly (i.e., it depends on content height), and this element is not absolutely positioned,
2775 // the percentage value is treated as '0' (for 'min-height') or 'none' (for 'max-height').
2776 LayoutUnit minLogicalHeight;
2777 if (!logicalHeightComputesAsNone(MinSize))
2778 minLogicalHeight = computeReplacedLogicalHeightUsing(style()->logicalMinHeight());
2779 LayoutUnit maxLogicalHeight = logicalHeight;
2780 if (!logicalHeightComputesAsNone(MaxSize))
2781 maxLogicalHeight = computeReplacedLogicalHeightUsing(style()->logicalMaxHeight());
2782 return std::max(minLogicalHeight, std::min(logicalHeight, maxLogicalHeight));
2785 LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(const Length& logicalHeight) const
2787 switch (logicalHeight.type()) {
2789 return adjustContentBoxLogicalHeightForBoxSizing(logicalHeight.value());
2793 RenderObject* cb = isOutOfFlowPositioned() ? container() : containingBlock();
2794 while (cb->isAnonymous())
2795 cb = cb->containingBlock();
2796 if (cb->isRenderBlock())
2797 toRenderBlock(cb)->addPercentHeightDescendant(const_cast<RenderBox*>(this));
2799 // FIXME: This calculation is not patched for block-flow yet.
2800 // https://bugs.webkit.org/show_bug.cgi?id=46500
2801 if (cb->isOutOfFlowPositioned() && cb->style()->height().isAuto() && !(cb->style()->top().isAuto() || cb->style()->bottom().isAuto())) {
2802 ASSERT_WITH_SECURITY_IMPLICATION(cb->isRenderBlock());
2803 RenderBlock* block = toRenderBlock(cb);
2804 LogicalExtentComputedValues computedValues;
2805 block->computeLogicalHeight(block->logicalHeight(), 0, computedValues);
2806 LayoutUnit newContentHeight = computedValues.m_extent - block->borderAndPaddingLogicalHeight() - block->scrollbarLogicalHeight();
2807 LayoutUnit newHeight = block->adjustContentBoxLogicalHeightForBoxSizing(newContentHeight);
2808 return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeight, newHeight));
2811 // FIXME: availableLogicalHeight() is wrong if the replaced element's block-flow is perpendicular to the
2812 // containing block's block-flow.
2813 // https://bugs.webkit.org/show_bug.cgi?id=46496
2814 LayoutUnit availableHeight;
2815 if (isOutOfFlowPositioned())
2816 availableHeight = containingBlockLogicalHeightForPositioned(toRenderBoxModelObject(cb));
2818 availableHeight = containingBlockLogicalHeightForContent(IncludeMarginBorderPadding);
2819 // It is necessary to use the border-box to match WinIE's broken
2820 // box model. This is essential for sizing inside
2821 // table cells using percentage heights.
2822 // FIXME: This needs to be made block-flow-aware. If the cell and image are perpendicular block-flows, this isn't right.
2823 // https://bugs.webkit.org/show_bug.cgi?id=46997
2824 while (cb && !cb->isRenderView() && (cb->style()->logicalHeight().isAuto() || cb->style()->logicalHeight().isPercent())) {
2825 if (cb->isTableCell()) {
2826 // Don't let table cells squeeze percent-height replaced elements
2827 // <http://bugs.webkit.org/show_bug.cgi?id=15359>
2828 availableHeight = std::max(availableHeight, intrinsicLogicalHeight());
2829 return valueForLength(logicalHeight, availableHeight - borderAndPaddingLogicalHeight());
2831 toRenderBlock(cb)->addPercentHeightDescendant(const_cast<RenderBox*>(this));
2832 cb = cb->containingBlock();
2835 return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeight, availableHeight));
2841 return adjustContentBoxLogicalHeightForBoxSizing(computeIntrinsicLogicalContentHeightUsing(logicalHeight, intrinsicLogicalHeight(), borderAndPaddingHeight()));
2843 return intrinsicLogicalHeight();
2847 LayoutUnit RenderBox::availableLogicalHeight(AvailableLogicalHeightType heightType) const
2849 // http://www.w3.org/TR/CSS2/visudet.html#propdef-height - We are interested in the content height.
2850 return constrainContentBoxLogicalHeightByMinMax(availableLogicalHeightUsing(style()->logicalHeight(), heightType), -1);
2853 LayoutUnit RenderBox::availableLogicalHeightUsing(const Length& h, AvailableLogicalHeightType heightType) const
2856 return isHorizontalWritingMode() ? toRenderView(this)->frameView()->visibleHeight() : toRenderView(this)->frameView()->visibleWidth();
2858 // We need to stop here, since we don't want to increase the height of the table
2859 // artificially. We're going to rely on this cell getting expanded to some new
2860 // height, and then when we lay out again we'll use the calculation below.
2861 if (isTableCell() && (h.isAuto() || h.isPercent())) {
2862 if (hasOverrideHeight())
2863 return overrideLogicalContentHeight();
2864 return logicalHeight() - borderAndPaddingLogicalHeight();
2867 if (h.isPercent() && isOutOfFlowPositioned() && !isRenderFlowThread()) {
2868 // FIXME: This is wrong if the containingBlock has a perpendicular writing mode.
2869 LayoutUnit availableHeight = containingBlockLogicalHeightForPositioned(containingBlock());
2870 return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(h, availableHeight));
2873 LayoutUnit heightIncludingScrollbar = computeContentAndScrollbarLogicalHeightUsing(h, -1);
2874 if (heightIncludingScrollbar != -1)
2875 return std::max<LayoutUnit>(0, adjustContentBoxLogicalHeightForBoxSizing(heightIncludingScrollbar) - scrollbarLogicalHeight());
2877 // FIXME: Check logicalTop/logicalBottom here to correctly handle vertical writing-mode.
2878 // https://bugs.webkit.org/show_bug.cgi?id=46500
2879 if (isRenderBlock() && isOutOfFlowPositioned() && style()->height().isAuto() && !(style()->top().isAuto() || style()->bottom().isAuto())) {
2880 RenderBlock* block = const_cast<RenderBlock*>(toRenderBlock(this));
2881 LogicalExtentComputedValues computedValues;
2882 block->computeLogicalHeight(block->logicalHeight(), 0, computedValues);
2883 LayoutUnit newContentHeight = computedValues.m_extent - block->borderAndPaddingLogicalHeight() - block->scrollbarLogicalHeight();
2884 return adjustContentBoxLogicalHeightForBoxSizing(newContentHeight);
2887 // FIXME: This is wrong if the containingBlock has a perpendicular writing mode.
2888 LayoutUnit availableHeight = containingBlockLogicalHeightForContent(heightType);
2889 if (heightType == ExcludeMarginBorderPadding) {
2890 // FIXME: Margin collapsing hasn't happened yet, so this incorrectly removes collapsed margins.
2891 availableHeight -= marginBefore() + marginAfter() + borderAndPaddingLogicalHeight();
2893 return availableHeight;
2896 void RenderBox::computeAndSetBlockDirectionMargins(const RenderBlock* containingBlock)
2898 LayoutUnit marginBefore;
2899 LayoutUnit marginAfter;
2900 computeMarginsForDirection(BlockDirection, containingBlock, containingBlockLogicalWidthForContent(), logicalHeight(), marginBefore, marginAfter,
2901 style()->marginBeforeUsing(containingBlock->style()),
2902 style()->marginAfterUsing(containingBlock->style()));
2903 // Note that in this 'positioning phase' of the layout we are using the containing block's writing mode rather than our own when calculating margins.
2904 // See http://www.w3.org/TR/2014/CR-css-writing-modes-3-20140320/#orthogonal-flows
2905 containingBlock->setMarginBeforeForChild(this, marginBefore);
2906 containingBlock->setMarginAfterForChild(this, marginAfter);
2909 LayoutUnit RenderBox::containingBlockLogicalWidthForPositioned(const RenderBoxModelObject* containingBlock, bool checkForPerpendicularWritingMode) const
2911 if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWritingMode() != isHorizontalWritingMode())
2912 return containingBlockLogicalHeightForPositioned(containingBlock, false);
2914 // Use viewport as container for top-level fixed-position elements.
2915 if (style()->position() == FixedPosition && containingBlock->isRenderView()) {
2916 const RenderView* view = toRenderView(containingBlock);
2917 if (FrameView* frameView = view->frameView()) {
2918 LayoutRect viewportRect = frameView->viewportConstrainedVisibleContentRect();
2919 return containingBlock->isHorizontalWritingMode() ? viewportRect.width() : viewportRect.height();
2923 if (containingBlock->isBox())
2924 return toRenderBox(containingBlock)->clientLogicalWidth();
2926 ASSERT(containingBlock->isRenderInline() && containingBlock->isRelPositioned());
2928 const RenderInline* flow = toRenderInline(containingBlock);
2929 InlineFlowBox* first = flow->firstLineBox();
2930 InlineFlowBox* last = flow->lastLineBox();
2932 // If the containing block is empty, return a width of 0.
2933 if (!first || !last)
2936 LayoutUnit fromLeft;
2937 LayoutUnit fromRight;
2938 if (containingBlock->style()->isLeftToRightDirection()) {
2939 fromLeft = first->logicalLeft() + first->borderLogicalLeft();
2940 fromRight = last->logicalLeft() + last->logicalWidth() - last->borderLogicalRight();
2942 fromRight = first->logicalLeft() + first->logicalWidth() - first->borderLogicalRight();
2943 fromLeft = last->logicalLeft() + last->borderLogicalLeft();
2946 return std::max<LayoutUnit>(0, fromRight - fromLeft);
2949 LayoutUnit RenderBox::containingBlockLogicalHeightForPositioned(const RenderBoxModelObject* containingBlock, bool checkForPerpendicularWritingMode) const
2951 if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWritingMode() != isHorizontalWritingMode())
2952 return containingBlockLogicalWidthForPositioned(containingBlock, false);
2954 // Use viewport as container for top-level fixed-position elements.
2955 if (style()->position() == FixedPosition && containingBlock->isRenderView()) {
2956 const RenderView* view = toRenderView(containingBlock);
2957 if (FrameView* frameView = view->frameView()) {
2958 LayoutRect viewportRect = frameView->viewportConstrainedVisibleContentRect();
2959 return containingBlock->isHorizontalWritingMode() ? viewportRect.height() : viewportRect.width();
2963 if (containingBlock->isBox()) {
2964 const RenderBlock* cb = containingBlock->isRenderBlock() ?
2965 toRenderBlock(containingBlock) : containingBlock->containingBlock();
2966 return cb->clientLogicalHeight();
2969 ASSERT(containingBlock->isRenderInline() && containingBlock->isRelPositioned());
2971 const RenderInline* flow = toRenderInline(containingBlock);
2972 InlineFlowBox* first = flow->firstLineBox();
2973 InlineFlowBox* last = flow->lastLineBox();
2975 // If the containing block is empty, return a height of 0.
2976 if (!first || !last)
2979 LayoutUnit heightResult;
2980 LayoutRect boundingBox = flow->linesBoundingBox();
2981 if (containingBlock->isHorizontalWritingMode())
2982 heightResult = boundingBox.height();
2984 heightResult = boundingBox.width();
2985 heightResult -= (containingBlock->borderBefore() + containingBlock->borderAfter());
2986 return heightResult;
2989 static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRight, const RenderBox* child, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalWidth)
2991 if (!logicalLeft.isAuto() || !logicalRight.isAuto())
2994 // FIXME: The static distance computation has not been patched for mixed writing modes yet.
2995 if (child->parent()->style()->direction() == LTR) {
2996 LayoutUnit staticPosition = child->layer()->staticInlinePosition() - containerBlock->borderLogicalLeft();
2997 for (RenderObject* curr = child->parent(); curr && curr != containerBlock; curr = curr->container()) {
2998 if (curr->isBox()) {
2999 staticPosition += toRenderBox(curr)->logicalLeft();
3000 if (toRenderBox(curr)->isRelPositioned())
3001 staticPosition += toRenderBox(curr)->relativePositionOffset().width();
3002 } else if (curr->isInline()) {
3003 if (curr->isRelPositioned()) {
3004 if (!curr->style()->logicalLeft().isAuto())
3005 staticPosition += curr->style()->logicalLeft().value();
3007 staticPosition -= curr->style()->logicalRight().value();
3011 logicalLeft.setValue(Fixed, staticPosition);
3013 RenderBox* enclosingBox = child->parent()->enclosingBox();
3014 LayoutUnit staticPosition = child->layer()->staticInlinePosition() + containerLogicalWidth + containerBlock->borderLogicalLeft();
3015 for (RenderObject* curr = child->parent(); curr; curr = curr->container()) {
3016 if (curr->isBox()) {
3017 if (curr != containerBlock) {
3018 staticPosition -= toRenderBox(curr)->logicalLeft();
3019 if (toRenderBox(curr)->isRelPositioned())
3020 staticPosition -= toRenderBox(curr)->relativePositionOffset().width();
3022 if (curr == enclosingBox)
3023 staticPosition -= enclosingBox->logicalWidth();
3024 } else if (curr->isInline()) {
3025 if (curr->isRelPositioned()) {
3026 if (!curr->style()->logicalLeft().isAuto())
3027 staticPosition -= curr->style()->logicalLeft().value();
3029 staticPosition += curr->style()->logicalRight().value();
3032 if (curr == containerBlock)
3035 logicalRight.setValue(Fixed, staticPosition);
3039 void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& computedValues) const
3042 computePositionedLogicalWidthReplaced(computedValues);
3047 // FIXME 1: Should we still deal with these the cases of 'left' or 'right' having
3048 // the type 'static' in determining whether to calculate the static distance?
3049 // NOTE: 'static' is not a legal value for 'left' or 'right' as of CSS 2.1.
3051 // FIXME 2: Can perhaps optimize out cases when max-width/min-width are greater
3052 // than or less than the computed width(). Be careful of box-sizing and
3053 // percentage issues.
3055 // The following is based off of the W3C Working Draft from April 11, 2006 of
3056 // CSS 2.1: Section 10.3.7 "Absolutely positioned, non-replaced elements"
3057 // <http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width>
3058 // (block-style-comments in this function and in computePositionedLogicalWidthUsing()
3059 // correspond to text from the spec)
3062 // We don't use containingBlock(), since we may be positioned by an enclosing
3063 // relative positioned inline.
3064 const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
3066 const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock);
3068 // Use the container block's direction except when calculating the static distance
3069 // This conforms with the reference results for abspos-replaced-width-margin-000.htm
3070 // of the CSS 2.1 test suite
3071 TextDirection containerDirection = containerBlock->style()->direction();
3073 bool isHorizontal = isHorizontalWritingMode();
3074 const LayoutUnit bordersPlusPadding = borderAndPaddingLogicalWidth();
3075 const Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->marginTop();
3076 const Length marginLogicalRight = isHorizontal ? style()->marginRight() : style()->marginBottom();
3078 Length logicalLeftLength = style()->logicalLeft();
3079 Length logicalRightLength = style()->logicalRight();
3081 /*---------------------------------------------------------------------------*\
3082 * For the purposes of this section and the next, the term "static position"
3083 * (of an element) refers, roughly, to the position an element would have had
3084 * in the normal flow. More precisely:
3086 * * The static position for 'left' is the distance from the left edge of the
3087 * containing block to the left margin edge of a hypothetical box that would
3088 * have been the first box of the element if its 'position' property had
3089 * been 'static' and 'float' had been 'none'. The value is negative if the
3090 * hypothetical box is to the left of the containing block.
3091 * * The static position for 'right' is the distance from the right edge of the
3092 * containing block to the right margin edge of the same hypothetical box as
3093 * above. The value is positive if the hypothetical box is to the left of the
3094 * containing block's edge.
3096 * But rather than actually calculating the dimensions of that hypothetical box,
3097 * user agents are free to make a guess at its probable position.
3099 * For the purposes of calculating the static position, the containing block of
3100 * fixed positioned elements is the initial containing block instead of the
3101 * viewport, and all scrollable boxes should be assumed to be scrolled to their
3103 \*---------------------------------------------------------------------------*/
3106 // Calculate the static distance if needed.
3107 computeInlineStaticDistance(logicalLeftLength, logicalRightLength, this, containerBlock, containerLogicalWidth);
3109 // Calculate constraint equation values for 'width' case.
3110 computePositionedLogicalWidthUsing(style()->logicalWidth(), containerBlock, containerDirection,
3111 containerLogicalWidth, bordersPlusPadding,
3112 logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight,
3115 // Calculate constraint equation values for 'max-width' case.
3116 if (!style()->logicalMaxWidth().isUndefined()) {
3117 LogicalExtentComputedValues maxValues;
3119 computePositionedLogicalWidthUsing(style()->logicalMaxWidth(), containerBlock, containerDirection,
3120 containerLogicalWidth, bordersPlusPadding,
3121 logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight,
3124 if (computedValues.m_extent > maxValues.m_extent) {
3125 computedValues.m_extent = maxValues.m_extent;
3126 computedValues.m_position = maxValues.m_position;
3127 computedValues.m_margins.m_start = maxValues.m_margins.m_start;
3128 computedValues.m_margins.m_end = maxValues.m_margins.m_end;
3132 // Calculate constraint equation values for 'min-width' case.
3133 if (!style()->logicalMinWidth().isZero() || style()->logicalMinWidth().isIntrinsic()) {
3134 LogicalExtentComputedValues minValues;
3136 computePositionedLogicalWidthUsing(style()->logicalMinWidth(), containerBlock, containerDirection,
3137 containerLogicalWidth, bordersPlusPadding,
3138 logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight,
3141 if (computedValues.m_extent < minValues.m_extent) {
3142 computedValues.m_extent = minValues.m_extent;
3143 computedValues.m_position = minValues.m_position;
3144 computedValues.m_margins.m_start = minValues.m_margins.m_start;
3145 computedValues.m_margins.m_end = minValues.m_margins.m_end;
3149 computedValues.m_extent += bordersPlusPadding;
3152 static void computeLogicalLeftPositionedOffset(LayoutUnit& logicalLeftPos, const RenderBox* child, LayoutUnit logicalWidthValue, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalWidth)
3154 // Deal with differing writing modes here. Our offset needs to be in the containing block's coordinate space. If the containing block is flipped
3155 // 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.
3156 if (containerBlock->isHorizontalWritingMode() != child->isHorizontalWritingMode() && containerBlock->style()->isFlippedBlocksWritingMode()) {
3157 logicalLeftPos = containerLogicalWidth - logicalWidthValue - logicalLeftPos;
3158 logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->borderRight() : containerBlock->borderBottom());
3160 logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->borderLeft() : containerBlock->borderTop());
3164 void RenderBox::shrinkToFitWidth(const LayoutUnit availableSpace, const LayoutUnit logicalLeftValue, const LayoutUnit bordersPlusPadding, LogicalExtentComputedValues& computedValues) const
3166 // FIXME: would it be better to have shrink-to-fit in one step?
3167 LayoutUnit preferredWidth = maxPreferredLogicalWidth() - bordersPlusPadding;
3168 LayoutUnit preferredMinWidth = minPreferredLogicalWidth() - bordersPlusPadding;
3169 LayoutUnit availableWidth = availableSpace - logicalLeftValue;
3170 computedValues.m_extent = std::min(std::max(preferredMinWidth, availableWidth), preferredWidth);
3173 void RenderBox::computePositionedLogicalWidthUsing(Length logicalWidth, const RenderBoxModelObject* containerBlock, TextDirection containerDirection,
3174 LayoutUnit containerLogicalWidth, LayoutUnit bordersPlusPadding,
3175 const Length& logicalLeft, const Length& logicalRight, const Length& marginLogicalLeft,
3176 const Length& marginLogicalRight, LogicalExtentComputedValues& computedValues) const
3178 if (logicalWidth.isIntrinsic())
3179 logicalWidth = Length(computeIntrinsicLogicalWidthUsing(logicalWidth, containerLogicalWidth, bordersPlusPadding) - bordersPlusPadding, Fixed);
3181 // 'left' and 'right' cannot both be 'auto' because one would of been
3182 // converted to the static position already
3183 ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto()));
3185 LayoutUnit logicalLeftValue = 0;
3187 const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, false);
3189 bool logicalWidthIsAuto = logicalWidth.isIntrinsicOrAuto();
3190 bool logicalLeftIsAuto = logicalLeft.isAuto();
3191 bool logicalRightIsAuto = logicalRight.isAuto();
3192 LayoutUnit& marginLogicalLeftValue = style()->isLeftToRightDirection() ? computedValues.m_margins.m_start : computedValues.m_margins.m_end;
3193 LayoutUnit& marginLogicalRightValue = style()->isLeftToRightDirection() ? computedValues.m_margins.m_end : computedValues.m_margins.m_start;
3194 if (!logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) {
3195 /*-----------------------------------------------------------------------*\
3196 * If none of the three is 'auto': If both 'margin-left' and 'margin-
3197 * right' are 'auto', solve the equation under the extra constraint that
3198 * the two margins get equal values, unless this would make them negative,
3199 * in which case when direction of the containing block is 'ltr' ('rtl'),
3200 * set 'margin-left' ('margin-right') to zero and solve for 'margin-right'
3201 * ('margin-left'). If one of 'margin-left' or 'margin-right' is 'auto',
3202 * solve the equation for that value. If the values are over-constrained,
3203 * ignore the value for 'left' (in case the 'direction' property of the
3204 * containing block is 'rtl') or 'right' (in case 'direction' is 'ltr')
3205 * and solve for that value.
3206 \*-----------------------------------------------------------------------*/
3207 // NOTE: It is not necessary to solve for 'right' in the over constrained
3208 // case because the value is not used for any further calculations.
3210 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3211 computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, containerLogicalWidth));
3213 const LayoutUnit availableSpace = containerLogicalWidth - (logicalLeftValue + computedValues.m_extent + valueForLength(logicalRight, containerLogicalWidth) + bordersPlusPadding);
3215 // Margins are now the only unknown
3216 if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) {
3217 // Both margins auto, solve for equality
3218 if (availableSpace >= 0) {
3219 marginLogicalLeftValue = availableSpace / 2; // split the difference
3220 marginLogicalRightValue = availableSpace - marginLogicalLeftValue; // account for odd valued differences
3222 // Use the containing block's direction rather than the parent block's
3223 // per CSS 2.1 reference test abspos-non-replaced-width-margin-000.
3224 if (containerDirection == LTR) {
3225 marginLogicalLeftValue = 0;
3226 marginLogicalRightValue = availableSpace; // will be negative
3228 marginLogicalLeftValue = availableSpace; // will be negative
3229 marginLogicalRightValue = 0;
3232 } else if (marginLogicalLeft.isAuto()) {
3233 // Solve for left margin
3234 marginLogicalRightValue = valueForLength(marginLogicalRight, containerRelativeLogicalWidth);
3235 marginLogicalLeftValue = availableSpace - marginLogicalRightValue;
3236 } else if (marginLogicalRight.isAuto()) {
3237 // Solve for right margin
3238 marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth);
3239 marginLogicalRightValue = availableSpace - marginLogicalLeftValue;
3241 // Over-constrained, solve for left if direction is RTL
3242 marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth);
3243 marginLogicalRightValue = valueForLength(marginLogicalRight, containerRelativeLogicalWidth);
3245 // Use the containing block's direction rather than the parent block's
3246 // per CSS 2.1 reference test abspos-non-replaced-width-margin-000.
3247 if (containerDirection == RTL)
3248 logicalLeftValue = (availableSpace + logicalLeftValue) - marginLogicalLeftValue - marginLogicalRightValue;
3251 /*--------------------------------------------------------------------*\
3252 * Otherwise, set 'auto' values for 'margin-left' and 'margin-right'
3253 * to 0, and pick the one of the following six rules that applies.
3255 * 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the
3256 * width is shrink-to-fit. Then solve for 'left'
3258 * OMIT RULE 2 AS IT SHOULD NEVER BE HIT
3259 * ------------------------------------------------------------------
3260 * 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if
3261 * the 'direction' property of the containing block is 'ltr' set
3262 * 'left' to the static position, otherwise set 'right' to the
3263 * static position. Then solve for 'left' (if 'direction is 'rtl')
3264 * or 'right' (if 'direction' is 'ltr').
3265 * ------------------------------------------------------------------
3267 * 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the
3268 * width is shrink-to-fit . Then solve for 'right'
3269 * 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve
3271 * 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve
3273 * 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve
3276 * Calculation of the shrink-to-fit width is similar to calculating the
3277 * width of a table cell using the automatic table layout algorithm.
3278 * Roughly: calculate the preferred width by formatting the content
3279 * without breaking lines other than where explicit line breaks occur,
3280 * and also calculate the preferred minimum width, e.g., by trying all
3281 * possible line breaks. CSS 2.1 does not define the exact algorithm.
3282 * Thirdly, calculate the available width: this is found by solving
3283 * for 'width' after setting 'left' (in case 1) or 'right' (in case 3)
3286 * Then the shrink-to-fit width is:
3287 * min(max(preferred minimum width, available width), preferred width).
3288 \*--------------------------------------------------------------------*/
3289 // NOTE: For rules 3 and 6 it is not necessary to solve for 'right'
3290 // because the value is not used for any further calculations.
3292 // Calculate margins, 'auto' margins are ignored.
3293 marginLogicalLeftValue = minimumValueForLength(marginLogicalLeft, containerRelativeLogicalWidth);
3294 marginLogicalRightValue = minimumValueForLength(marginLogicalRight, containerRelativeLogicalWidth);
3296 const LayoutUnit availableSpace = containerLogicalWidth - (marginLogicalLeftValue + marginLogicalRightValue + bordersPlusPadding);
3298 // FIXME: Is there a faster way to find the correct case?
3299 // Use rule/case that applies.
3300 if (logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAuto) {
3301 // RULE 1: (use shrink-to-fit for width, and solve of left)
3302 LayoutUnit logicalRightValue = valueForLength(logicalRight, containerLogicalWidth);
3304 // FIXME: would it be better to have shrink-to-fit in one step?
3305 LayoutUnit preferredWidth = maxPreferredLogicalWidth() - bordersPlusPadding;
3306 LayoutUnit preferredMinWidth = minPreferredLogicalWidth() - bordersPlusPadding;
3307 LayoutUnit availableWidth = availableSpace - logicalRightValue;
3308 computedValues.m_extent = std::min(std::max(preferredMinWidth, availableWidth), preferredWidth);
3309 logicalLeftValue = availableSpace - (computedValues.m_extent + logicalRightValue);
3310 } else if (!logicalLeftIsAuto && logicalWidthIsAuto && logicalRightIsAuto) {
3311 // RULE 3: (use shrink-to-fit for width, and no need solve of right)
3312 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3314 shrinkToFitWidth(availableSpace, logicalLeftValue, bordersPlusPadding, computedValues);
3315 } else if (logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) {
3316 // RULE 4: (solve for left)
3317 computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, containerLogicalWidth));
3318 logicalLeftValue = availableSpace - (computedValues.m_extent + valueForLength(logicalRight, containerLogicalWidth));
3319 } else if (!logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAuto) {
3320 // RULE 5: (solve for width)
3321 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3322 if (autoWidthShouldFitContent())
3323 shrinkToFitWidth(availableSpace, logicalLeftValue, bordersPlusPadding, computedValues);
3325 computedValues.m_extent = availableSpace - (logicalLeftValue + valueForLength(logicalRight, containerLogicalWidth));
3326 } else if (!logicalLeftIsAuto && !logicalWidthIsAuto && logicalRightIsAuto) {
3327 // RULE 6: (no need solve for right)
3328 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3329 computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, containerLogicalWidth));
3333 // Use computed values to calculate the horizontal position.
3335 // FIXME: This hack is needed to calculate the logical left position for a 'rtl' relatively
3336 // positioned, inline because right now, it is using the logical left position
3337 // of the first line box when really it should use the last line box. When
3338 // this is fixed elsewhere, this block should be removed.
3339 if (containerBlock->isRenderInline() && !containerBlock->style()->isLeftToRightDirection()) {
3340 const RenderInline* flow = toRenderInline(containerBlock);
3341 InlineFlowBox* firstLine = flow->firstLineBox();
3342 InlineFlowBox* lastLine = flow->lastLineBox();
3343 if (firstLine && lastLine && firstLine != lastLine) {
3344 computedValues.m_position = logicalLeftValue + marginLogicalLeftValue + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logicalLeft());
3349 if (containerBlock->isBox() && toRenderBox(containerBlock)->scrollsOverflowY() && containerBlock->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
3350 logicalLeftValue = logicalLeftValue + toRenderBox(containerBlock)->verticalScrollbarWidth();
3353 computedValues.m_position = logicalLeftValue + marginLogicalLeftValue;
3354 computeLogicalLeftPositionedOffset(computedValues.m_position, this, computedValues.m_extent, containerBlock, containerLogicalWidth);
3357 static void computeBlockStaticDistance(Length& logicalTop, Length& logicalBottom, const RenderBox* child, const RenderBoxModelObject* containerBlock)
3359 if (!logicalTop.isAuto() || !logicalBottom.isAuto())
3362 // FIXME: The static distance computation has not been patched for mixed writing modes.
3363 LayoutUnit staticLogicalTop = child->layer()->staticBlockPosition() - containerBlock->borderBefore();
3364 for (RenderObject* curr = child->parent(); curr && curr != containerBlock; curr = curr->container()) {
3365 if (curr->isBox() && !curr->isTableRow())
3366 staticLogicalTop += toRenderBox(curr)->logicalTop();
3368 logicalTop.setValue(Fixed, staticLogicalTop);
3371 void RenderBox::computePositionedLogicalHeight(LogicalExtentComputedValues& computedValues) const
3374 computePositionedLogicalHeightReplaced(computedValues);
3378 // The following is based off of the W3C Working Draft from April 11, 2006 of
3379 // CSS 2.1: Section 10.6.4 "Absolutely positioned, non-replaced elements"
3380 // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-non-replaced-height>
3381 // (block-style-comments in this function and in computePositionedLogicalHeightUsing()
3382 // correspond to text from the spec)
3385 // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
3386 const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
3388 const LayoutUnit containerLogicalHeight = containingBlockLogicalHeightForPositioned(containerBlock);
3390 RenderStyle* styleToUse = style();
3391 const LayoutUnit bordersPlusPadding = borderAndPaddingLogicalHeight();
3392 const Length marginBefore = styleToUse->marginBefore();
3393 const Length marginAfter = styleToUse->marginAfter();
3394 Length logicalTopLength = styleToUse->logicalTop();
3395 Length logicalBottomLength = styleToUse->logicalBottom();
3397 /*---------------------------------------------------------------------------*\
3398 * For the purposes of this section and the next, the term "static position"
3399 * (of an element) refers, roughly, to the position an element would have had
3400 * in the normal flow. More precisely, the static position for 'top' is the
3401 * distance from the top edge of the containing block to the top margin edge
3402 * of a hypothetical box that would have been the first box of the element if
3403 * its 'position' property had been 'static' and 'float' had been 'none'. The
3404 * value is negative if the hypothetical box is above the containing block.
3406 * But rather than actually calculating the dimensions of that hypothetical
3407 * box, user agents are free to make a guess at its probable position.
3409 * For the purposes of calculating the static position, the containing block
3410 * of fixed positioned elements is the initial containing block instead of
3412 \*---------------------------------------------------------------------------*/
3415 // Calculate the static distance if needed.
3416 computeBlockStaticDistance(logicalTopLength, logicalBottomLength, this, containerBlock);
3418 // Calculate constraint equation values for 'height' case.
3419 LayoutUnit logicalHeight = computedValues.m_extent;
3420 computePositionedLogicalHeightUsing(styleToUse->logicalHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight,
3421 logicalTopLength, logicalBottomLength, marginBefore, marginAfter,
3424 // Avoid doing any work in the common case (where the values of min-height and max-height are their defaults).
3427 // Calculate constraint equation values for 'max-height' case.
3428 if (!styleToUse->logicalMaxHeight().isUndefined()) {
3429 LogicalExtentComputedValues maxValues;
3431 computePositionedLogicalHeightUsing(styleToUse->logicalMaxHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight,
3432 logicalTopLength, logicalBottomLength, marginBefore, marginAfter,
3435 if (computedValues.m_extent > maxValues.m_extent) {
3436 computedValues.m_extent = maxValues.m_extent;
3437 computedValues.m_position = maxValues.m_position;
3438 computedValues.m_margins.m_before = maxValues.m_margins.m_before;
3439 computedValues.m_margins.m_after = maxValues.m_margins.m_after;
3443 // Calculate constraint equation values for 'min-height' case.
3444 if (!styleToUse->logicalMinHeight().isZero() || styleToUse->logicalMinHeight().isIntrinsic()) {
3445 LogicalExtentComputedValues minValues;
3447 computePositionedLogicalHeightUsing(styleToUse->logicalMinHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight,
3448 logicalTopLength, logicalBottomLength, marginBefore, marginAfter,
3451 if (computedValues.m_extent < minValues.m_extent) {
3452 computedValues.m_extent = minValues.m_extent;
3453 computedValues.m_position = minValues.m_position;
3454 computedValues.m_margins.m_before = minValues.m_margins.m_before;
3455 computedValues.m_margins.m_after = minValues.m_margins.m_after;
3459 // Set final height value.
3460 computedValues.m_extent += bordersPlusPadding;
3463 static void computeLogicalTopPositionedOffset(LayoutUnit& logicalTopPos, const RenderBox* child, LayoutUnit logicalHeightValue, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalHeight)
3465 // Deal with differing writing modes here. Our offset needs to be in the containing block's coordinate space. If the containing block is flipped
3466 // 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.
3467 if ((child->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() != containerBlock->isHorizontalWritingMode())
3468 || (child->style()->isFlippedBlocksWritingMode() != containerBlock->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode()))
3469 logicalTopPos = containerLogicalHeight - logicalHeightValue - logicalTopPos;
3471 // Our offset is from the logical bottom edge in a flipped environment, e.g., right for vertical-rl and bottom for horizontal-bt.
3472 if (containerBlock->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode()) {
3473 if (child->isHorizontalWritingMode())
3474 logicalTopPos += containerBlock->borderBottom();
3476 logicalTopPos += containerBlock->borderRight();
3478 if (child->isHorizontalWritingMode())
3479 logicalTopPos += containerBlock->borderTop();
3481 logicalTopPos += containerBlock->borderLeft();
3485 void RenderBox::computePositionedLogicalHeightUsing(Length logicalHeightLength, const RenderBoxModelObject* containerBlock,
3486 LayoutUnit containerLogicalHeight, LayoutUnit bordersPlusPadding, LayoutUnit logicalHeight,
3487 const Length& logicalTop, const Length& logicalBottom, const Length& marginBefore,
3488 const Length& marginAfter, LogicalExtentComputedValues& computedValues) const
3490 // 'top' and 'bottom' cannot both be 'auto' because 'top would of been
3491 // converted to the static position in computePositionedLogicalHeight()
3492 ASSERT(!(logicalTop.isAuto() && logicalBottom.isAuto()));
3494 LayoutUnit logicalHeightValue;
3495 LayoutUnit contentLogicalHeight = logicalHeight - bordersPlusPadding;
3497 const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, false);
3499 LayoutUnit logicalTopValue = 0;
3501 bool logicalHeightIsAuto = logicalHeightLength.isAuto();
3502 bool logicalTopIsAuto = logicalTop.isAuto();
3503 bool logicalBottomIsAuto = logicalBottom.isAuto();
3505 LayoutUnit resolvedLogicalHeight;
3506 // Height is never unsolved for tables.
3508 resolvedLogicalHeight = contentLogicalHeight;
3509 logicalHeightIsAuto = false;
3511 if (logicalHeightLength.isIntrinsic())
3512 resolvedLogicalHeight = computeIntrinsicLogicalContentHeightUsing(logicalHeightLength, contentLogicalHeight, bordersPlusPadding);
3514 resolvedLogicalHeight = adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeightLength, containerLogicalHeight));
3517 if (!logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsAuto) {
3518 /*-----------------------------------------------------------------------*\
3519 * If none of the three are 'auto': If both 'margin-top' and 'margin-
3520 * bottom' are 'auto', solve the equation under the extra constraint that
3521 * the two margins get equal values. If one of 'margin-top' or 'margin-
3522 * bottom' is 'auto', solve the equation for that value. If the values
3523 * are over-constrained, ignore the value for 'bottom' and solve for that
3525 \*-----------------------------------------------------------------------*/
3526 // NOTE: It is not necessary to solve for 'bottom' in the over constrained
3527 // case because the value is not used for any further calculations.
3529 logicalHeightValue = resolvedLogicalHeight;
3530 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3532 const LayoutUnit availableSpace = containerLogicalHeight - (logicalTopValue + logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight) + bordersPlusPadding);
3534 // Margins are now the only unknown
3535 if (marginBefore.isAuto() && marginAfter.isAuto()) {
3536 // Both margins auto, solve for equality
3537 // NOTE: This may result in negative values.
3538 computedValues.m_margins.m_before = availableSpace / 2; // split the difference
3539 computedValues.m_margins.m_after = availableSpace - computedValues.m_margins.m_before; // account for odd valued differences
3540 } else if (marginBefore.isAuto()) {
3541 // Solve for top margin
3542 computedValues.m_margins.m_after = valueForLength(marginAfter, containerRelativeLogicalWidth);
3543 computedValues.m_margins.m_before = availableSpace - computedValues.m_margins.m_after;
3544 } else if (marginAfter.isAuto()) {
3545 // Solve for bottom margin
3546 computedValues.m_margins.m_before = valueForLength(marginBefore, containerRelativeLogicalWidth);
3547 computedValues.m_margins.m_after = availableSpace - computedValues.m_margins.m_before;
3549 // Over-constrained, (no need solve for bottom)
3550 computedValues.m_margins.m_before = valueForLength(marginBefore, containerRelativeLogicalWidth);
3551 computedValues.m_margins.m_after = valueForLength(marginAfter, containerRelativeLogicalWidth);
3554 /*--------------------------------------------------------------------*\
3555 * Otherwise, set 'auto' values for 'margin-top' and 'margin-bottom'
3556 * to 0, and pick the one of the following six rules that applies.
3558 * 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then
3559 * the height is based on the content, and solve for 'top'.
3561 * OMIT RULE 2 AS IT SHOULD NEVER BE HIT
3562 * ------------------------------------------------------------------
3563 * 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then
3564 * set 'top' to the static position, and solve for 'bottom'.
3565 * ------------------------------------------------------------------
3567 * 3. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then
3568 * the height is based on the content, and solve for 'bottom'.
3569 * 4. 'top' is 'auto', 'height' and 'bottom' are not 'auto', and
3571 * 5. 'height' is 'auto', 'top' and 'bottom' are not 'auto', and
3572 * solve for 'height'.
3573 * 6. 'bottom' is 'auto', 'top' and 'height' are not 'auto', and
3574 * solve for 'bottom'.
3575 \*--------------------------------------------------------------------*/
3576 // NOTE: For rules 3 and 6 it is not necessary to solve for 'bottom'
3577 // because the value is not used for any further calculations.
3579 // Calculate margins, 'auto' margins are ignored.
3580 computedValues.m_margins.m_before = minimumValueForLength(marginBefore, containerRelativeLogicalWidth);
3581 computedValues.m_margins.m_after = minimumValueForLength(marginAfter, containerRelativeLogicalWidth);
3583 const LayoutUnit availableSpace = containerLogicalHeight - (computedValues.m_margins.m_before + computedValues.m_margins.m_after + bordersPlusPadding);
3585 // Use rule/case that applies.
3586 if (logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) {
3587 // RULE 1: (height is content based, solve of top)
3588 logicalHeightValue = contentLogicalHeight;
3589 logicalTopValue = availableSpace - (logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight));
3590 } else if (!logicalTopIsAuto && logicalHeightIsAuto && logicalBottomIsAuto) {
3591 // RULE 3: (height is content based, no need solve of bottom)
3592 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3593 logicalHeightValue = contentLogicalHeight;
3594 } else if (logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsAuto) {
3595 // RULE 4: (solve of top)
3596 logicalHeightValue = resolvedLogicalHeight;
3597 logicalTopValue = availableSpace - (logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight));
3598 } else if (!logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) {
3599 // RULE 5: (solve of height)
3600 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3601 logicalHeightValue = std::max<LayoutUnit>(0, availableSpace - (logicalTopValue + valueForLength(logicalBottom, containerLogicalHeight)));
3602 } else if (!logicalTopIsAuto && !logicalHeightIsAuto && logicalBottomIsAuto) {
3603 // RULE 6: (no need solve of bottom)
3604 logicalHeightValue = resolvedLogicalHeight;
3605 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3608 computedValues.m_extent = logicalHeightValue;
3610 // Use computed values to calculate the vertical position.
3611 computedValues.m_position = logicalTopValue + computedValues.m_margins.m_before;
3612 computeLogicalTopPositionedOffset(computedValues.m_position, this, logicalHeightValue, containerBlock, containerLogicalHeight);
3615 void RenderBox::computePositionedLogicalWidthReplaced(LogicalExtentComputedValues& computedValues) const
3617 // The following is based off of the W3C Working Draft from April 11, 2006 of
3618 // CSS 2.1: Section 10.3.8 "Absolutely positioned, replaced elements"
3619 // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-width>
3620 // (block-style-comments in this function correspond to text from the spec and
3621 // the numbers correspond to numbers in spec)
3623 // We don't use containingBlock(), since we may be positioned by an enclosing
3624 // relative positioned inline.
3625 const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
3627 const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock);
3628 const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, false);
3630 // To match WinIE, in quirks mode use the parent's 'direction' property
3631 // instead of the the container block's.
3632 TextDirection containerDirection = containerBlock->style()->direction();
3634 // Variables to solve.
3635 bool isHorizontal = isHorizontalWritingMode();
3636 Length logicalLeft = style()->logicalLeft();
3637 Length logicalRight = style()->logicalRight();
3638 Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->marginTop();
3639 Length marginLogicalRight = isHorizontal ? style()->marginRight() : style()->marginBottom();
3640 LayoutUnit& marginLogicalLeftAlias = style()->isLeftToRightDirection() ? computedValues.m_margins.m_start : computedValues.m_margins.m_end;
3641 LayoutUnit& marginLogicalRightAlias = style()->isLeftToRightDirection() ? computedValues.m_margins.m_end : computedValues.m_margins.m_start;
3643 /*-----------------------------------------------------------------------*\
3644 * 1. The used value of 'width' is determined as for inline replaced
3646 \*-----------------------------------------------------------------------*/
3647 // NOTE: This value of width is FINAL in that the min/max width calculations
3648 // are dealt with in computeReplacedWidth(). This means that the steps to produce
3649 // correct max/min in the non-replaced version, are not necessary.
3650 computedValues.m_extent = computeReplacedLogicalWidth() + borderAndPaddingLogicalWidth();
3652 const LayoutUnit availableSpace = containerLogicalWidth - computedValues.m_extent;
3654 /*-----------------------------------------------------------------------*\
3655 * 2. If both 'left' and 'right' have the value 'auto', then if 'direction'
3656 * of the containing block is 'ltr', set 'left' to the static position;
3657 * else if 'direction' is 'rtl', set 'right' to the static position.
3658 \*-----------------------------------------------------------------------*/
3660 computeInlineStaticDistance(logicalLeft, logicalRight, this, containerBlock, containerLogicalWidth);
3662 /*-----------------------------------------------------------------------*\
3663 * 3. If 'left' or 'right' are 'auto', replace any 'auto' on 'margin-left'
3664 * or 'margin-right' with '0'.
3665 \*-----------------------------------------------------------------------*/
3666 if (logicalLeft.isAuto() || logicalRight.isAuto()) {
3667 if (marginLogicalLeft.isAuto())
3668 marginLogicalLeft.setValue(Fixed, 0);
3669 if (marginLogicalRight.isAuto())
3670 marginLogicalRight.setValue(Fixed, 0);
3673 /*-----------------------------------------------------------------------*\
3674 * 4. If at this point both 'margin-left' and 'margin-right' are still
3675 * 'auto', solve the equation under the extra constraint that the two
3676 * margins must get equal values, unless this would make them negative,
3677 * in which case when the direction of the containing block is 'ltr'
3678 * ('rtl'), set 'margin-left' ('margin-right') to zero and solve for
3679 * 'margin-right' ('margin-left').
3680 \*-----------------------------------------------------------------------*/
3681 LayoutUnit logicalLeftValue = 0;
3682 LayoutUnit logicalRightValue = 0;
3684 if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) {
3685 // 'left' and 'right' cannot be 'auto' due to step 3
3686 ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto()));
3688 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3689 logicalRightValue = valueForLength(logicalRight, containerLogicalWidth);
3691 LayoutUnit difference = availableSpace - (logicalLeftValue + logicalRightValue);
3692 if (difference > 0) {
3693 marginLogicalLeftAlias = difference / 2; // split the difference
3694 marginLogicalRightAlias = difference - marginLogicalLeftAlias; // account for odd valued differences
3696 // Use the containing block's direction rather than the parent block's
3697 // per CSS 2.1 reference test abspos-replaced-width-margin-000.
3698 if (containerDirection == LTR) {
3699 marginLogicalLeftAlias = 0;
3700 marginLogicalRightAlias = difference; // will be negative
3702 marginLogicalLeftAlias = difference; // will be negative
3703 marginLogicalRightAlias = 0;
3707 /*-----------------------------------------------------------------------*\
3708 * 5. If at this point there is an 'auto' left, solve the equation for
3710 \*-----------------------------------------------------------------------*/
3711 } else if (logicalLeft.isAuto()) {
3712 marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth);
3713 marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth);
3714 logicalRightValue = valueForLength(logicalRight, containerLogicalWidth);
3717 logicalLeftValue = availableSpace - (logicalRightValue + marginLogicalLeftAlias + marginLogicalRightAlias);
3718 } else if (logicalRight.isAuto()) {
3719 marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth);
3720 marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth);
3721 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3723 // Solve for 'right'
3724 logicalRightValue = availableSpace - (logicalLeftValue + marginLogicalLeftAlias + marginLogicalRightAlias);
3725 } else if (marginLogicalLeft.isAuto()) {
3726 marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth);
3727 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3728 logicalRightValue = valueForLength(logicalRight, containerLogicalWidth);
3730 // Solve for 'margin-left'
3731 marginLogicalLeftAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalRightAlias);
3732 } else if (marginLogicalRight.isAuto()) {
3733 marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth);
3734 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3735 logicalRightValue = valueForLength(logicalRight, containerLogicalWidth);
3737 // Solve for 'margin-right'
3738 marginLogicalRightAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalLeftAlias);
3740 // Nothing is 'auto', just calculate the values.
3741 marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth);
3742 marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth);
3743 logicalRightValue = valueForLength(logicalRight, containerLogicalWidth);
3744 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3745 // If the containing block is right-to-left, then push the left position as far to the right as possible
3746 if (containerDirection == RTL) {
3747 int totalLogicalWidth = computedValues.m_extent + logicalLeftValue + logicalRightValue + marginLogicalLeftAlias + marginLogicalRightAlias;
3748 logicalLeftValue = containerLogicalWidth - (totalLogicalWidth - logicalLeftValue);
3752 /*-----------------------------------------------------------------------*\
3753 * 6. If at this point the values are over-constrained, ignore the value
3754 * for either 'left' (in case the 'direction' property of the
3755 * containing block is 'rtl') or 'right' (in case 'direction' is
3756 * 'ltr') and solve for that value.
3757 \*-----------------------------------------------------------------------*/
3758 // NOTE: Constraints imposed by the width of the containing block and its content have already been accounted for above.
3760 // FIXME: Deal with differing writing modes here. Our offset needs to be in the containing block's coordinate space, so that
3761 // can make the result here rather complicated to compute.
3763 // Use computed values to calculate the horizontal position.
3765 // FIXME: This hack is needed to calculate the logical left position for a 'rtl' relatively
3766 // positioned, inline containing block because right now, it is using the logical left position
3767 // of the first line box when really it should use the last line box. When
3768 // this is fixed elsewhere, this block should be removed.
3769 if (containerBlock->isRenderInline() && !containerBlock->style()->isLeftToRightDirection()) {
3770 const RenderInline* flow = toRenderInline(containerBlock);
3771 InlineFlowBox* firstLine = flow->firstLineBox();
3772 InlineFlowBox* lastLine = flow->lastLineBox();
3773 if (firstLine && lastLine && firstLine != lastLine) {
3774 computedValues.m_position = logicalLeftValue + marginLogicalLeftAlias + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logicalLeft());
3779 LayoutUnit logicalLeftPos = logicalLeftValue + marginLogicalLeftAlias;
3780 computeLogicalLeftPositionedOffset(logicalLeftPos, this, computedValues.m_extent, containerBlock, containerLogicalWidth);
3781 computedValues.m_position = logicalLeftPos;
3784 void RenderBox::computePositionedLogicalHeightReplaced(LogicalExtentComputedValues& computedValues) const
3786 // The following is based off of the W3C Working Draft from April 11, 2006 of
3787 // CSS 2.1: Section 10.6.5 "Absolutely positioned, replaced elements"
3788 // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-height>
3789 // (block-style-comments in this function correspond to text from the spec and
3790 // the numbers correspond to numbers in spec)
3792 // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
3793 const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
3795 const LayoutUnit containerLogicalHeight = containingBlockLogicalHeightForPositioned(containerBlock);
3796 const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, false);
3798 // Variables to solve.
3799 Length marginBefore = style()->marginBefore();
3800 Length marginAfter = style()->marginAfter();
3801 LayoutUnit& marginBeforeAlias = computedValues.m_margins.m_before;
3802 LayoutUnit& marginAfterAlias = computedValues.m_margins.m_after;
3804 Length logicalTop = style()->logicalTop();
3805 Length logicalBottom = style()->logicalBottom();
3807 /*-----------------------------------------------------------------------*\
3808 * 1. The used value of 'height' is determined as for inline replaced
3810 \*-----------------------------------------------------------------------*/
3811 // NOTE: This value of height is FINAL in that the min/max height calculations
3812 // are dealt with in computeReplacedHeight(). This means that the steps to produce
3813 // correct max/min in the non-replaced version, are not necessary.
3814 computedValues.m_extent = computeReplacedLogicalHeight() + borderAndPaddingLogicalHeight();
3815 const LayoutUnit availableSpace = containerLogicalHeight - computedValues.m_extent;
3817 /*-----------------------------------------------------------------------*\
3818 * 2. If both 'top' and 'bottom' have the value 'auto', replace 'top'
3819 * with the element's static position.
3820 \*-----------------------------------------------------------------------*/
3822 computeBlockStaticDistance(logicalTop, logicalBottom, this, containerBlock);
3824 /*-----------------------------------------------------------------------*\
3825 * 3. If 'bottom' is 'auto', replace any 'auto' on 'margin-top' or
3826 * 'margin-bottom' with '0'.
3827 \*-----------------------------------------------------------------------*/
3828 // FIXME: The spec. says that this step should only be taken when bottom is
3829 // auto, but if only top is auto, this makes step 4 impossible.
3830 if (logicalTop.isAuto() || logicalBottom.isAuto()) {
3831 if (marginBefore.isAuto())
3832 marginBefore.setValue(Fixed, 0);
3833 if (marginAfter.isAuto())
3834 marginAfter.setValue(Fixed, 0);
3837 /*-----------------------------------------------------------------------*\
3838 * 4. If at this point both 'margin-top' and 'margin-bottom' are still
3839 * 'auto', solve the equation under the extra constraint that the two
3840 * margins must get equal values.
3841 \*-----------------------------------------------------------------------*/
3842 LayoutUnit logicalTopValue = 0;
3843 LayoutUnit logicalBottomValue = 0;
3845 if (marginBefore.isAuto() && marginAfter.isAuto()) {
3846 // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combined.
3847 ASSERT(!(logicalTop.isAuto() || logicalBottom.isAuto()));
3849 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3850 logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight);
3852 LayoutUnit difference = availableSpace - (logicalTopValue + logicalBottomValue);
3853 // NOTE: This may result in negative values.
3854 marginBeforeAlias = difference / 2; // split the difference
3855 marginAfterAlias = difference - marginBeforeAlias; // account for odd valued differences
3857 /*-----------------------------------------------------------------------*\
3858 * 5. If at this point there is only one 'auto' left, solve the equation
3860 \*-----------------------------------------------------------------------*/
3861 } else if (logicalTop.isAuto()) {
3862 marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth);
3863 marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth);
3864 logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight);
3867 logicalTopValue = availableSpace - (logicalBottomValue + marginBeforeAlias + marginAfterAlias);
3868 } else if (logicalBottom.isAuto()) {
3869 marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth);
3870 marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth);
3871 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3873 // Solve for 'bottom'
3874 // NOTE: It is not necessary to solve for 'bottom' because we don't ever
3876 } else if (marginBefore.isAuto()) {
3877 marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth);
3878 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3879 logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight);
3881 // Solve for 'margin-top'
3882 marginBeforeAlias = availableSpace - (logicalTopValue + logicalBottomValue + marginAfterAlias);
3883 } else if (marginAfter.isAuto()) {
3884 marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth);
3885 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3886 logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight);
3888 // Solve for 'margin-bottom'
3889 marginAfterAlias = availableSpace - (logicalTopValue + logicalBottomValue + marginBeforeAlias);
3891 // Nothing is 'auto', just calculate the values.
3892 marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth);
3893 marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth);
3894 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3895 // NOTE: It is not necessary to solve for 'bottom' because we don't ever
3899 /*-----------------------------------------------------------------------*\
3900 * 6. If at this point the values are over-constrained, ignore the value
3901 * for 'bottom' and solve for that value.
3902 \*-----------------------------------------------------------------------*/
3903 // NOTE: It is not necessary to do this step because we don't end up using
3904 // the value of 'bottom' regardless of whether the values are over-constrained
3907 // Use computed values to calculate the vertical position.
3908 LayoutUnit logicalTopPos = logicalTopValue + marginBeforeAlias;
3909 computeLogicalTopPositionedOffset(logicalTopPos, this, computedValues.m_extent, containerBlock, containerLogicalHeight);
3910 computedValues.m_position = logicalTopPos;
3913 LayoutRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, LayoutUnit* extraWidthToEndOfLine)
3915 // VisiblePositions at offsets inside containers either a) refer to the positions before/after
3916 // those containers (tables and select elements) or b) refer to the position inside an empty block.
3917 // They never refer to children.
3918 // FIXME: Paint the carets inside empty blocks differently than the carets before/after elements.
3920 LayoutRect rect(location(), LayoutSize(caretWidth, height()));
3921 bool ltr = box ? box->isLeftToRightDirection() : style()->isLeftToRightDirection();
3923 if ((!caretOffset) ^ ltr)
3924 rect.move(LayoutSize(width() - caretWidth, 0));
3927 RootInlineBox& rootBox = box->root();
3928 LayoutUnit top = rootBox.lineTop();
3930 rect.setHeight(rootBox.lineBottom() - top);
3933 // If height of box is smaller than font height, use the latter one,
3934 // otherwise the caret might become invisible.
3936 // Also, if the box is not a replaced element, always use the font height.
3937 // This prevents the "big caret" bug described in:
3938 // <rdar://problem/3777804> Deleting all content in a document can result in giant tall-as-window insertion point
3940 // FIXME: ignoring :first-line, missing good reason to take care of
3941 LayoutUnit fontHeight = style()->fontMetrics().height();
3942 if (fontHeight > rect.height() || (!isReplaced() && !isTable()))
3943 rect.setHeight(fontHeight);
3945 if (extraWidthToEndOfLine)
3946 *extraWidthToEndOfLine = x() + width() - rect.maxX();
3948 // Move to local coords
3949 rect.moveBy(-location());
3951 // FIXME: Border/padding should be added for all elements but this workaround
3952 // is needed because we use offsets inside an "atomic" element to represent
3953 // positions before and after the element in deprecated editing offsets.
3954 if (node() && !(editingIgnoresContent(node()) || isRenderedTableElement(node()))) {
3955 rect.setX(rect.x() + borderLeft() + paddingLeft());
3956 rect.setY(rect.y() + paddingTop() + borderTop());
3959 if (!isHorizontalWritingMode())
3960 return rect.transposedRect();
3965 PositionWithAffinity RenderBox::positionForPoint(const LayoutPoint& point)
3967 // no children...return this render object's element, if there is one, and offset 0
3968 RenderObject* firstChild = slowFirstChild();
3970 return createPositionWithAffinity(nonPseudoNode() ? firstPositionInOrBeforeNode(nonPseudoNode()) : Position());
3972 if (isTable() && nonPseudoNode()) {
3973 LayoutUnit right = contentWidth() + borderAndPaddingWidth();
3974 LayoutUnit bottom = contentHeight() + borderAndPaddingHeight();
3976 if (point.x() < 0 || point.x() > right || point.y() < 0 || point.y() > bottom) {
3977 if (point.x() <= right / 2)
3978 return createPositionWithAffinity(firstPositionInOrBeforeNode(nonPseudoNode()));
3979 return createPositionWithAffinity(lastPositionInOrAfterNode(nonPseudoNode()));
3983 // Pass off to the closest child.
3984 LayoutUnit minDist = LayoutUnit::max();
3985 RenderBox* closestRenderer = 0;
3986 LayoutPoint adjustedPoint = point;
3988 adjustedPoint.moveBy(location());
3990 for (RenderObject* renderObject = firstChild; renderObject; renderObject = renderObject->nextSibling()) {
3991 if ((!renderObject->slowFirstChild() && !renderObject->isInline() && !renderObject->isRenderBlockFlow() )
3992 || renderObject->style()->visibility() != VISIBLE)
3995 if (!renderObject->isBox())
3998 RenderBox* renderer = toRenderBox(renderObject);
4000 LayoutUnit top = renderer->borderTop() + renderer->paddingTop() + (isTableRow() ? LayoutUnit() : renderer->y());
4001 LayoutUnit bottom = top + renderer->contentHeight();
4002 LayoutUnit left = renderer->borderLeft() + renderer->paddingLeft() + (isTableRow() ? LayoutUnit() : renderer->x());
4003 LayoutUnit right = left + renderer->contentWidth();
4005 if (point.x() <= right && point.x() >= left && point.y() <= top && point.y() >= bottom) {
4006 if (renderer->isTableRow())
4007 return renderer->positionForPoint(point + adjustedPoint - renderer->locationOffset());
4008 return renderer->positionForPoint(point - renderer->locationOffset());
4011 // Find the distance from (x, y) to the box. Split the space around the box into 8 pieces
4012 // and use a different compare depending on which piece (x, y) is in.
4014 if (point.x() > right) {
4015 if (point.y() < top)
4016 cmp = LayoutPoint(right, top);
4017 else if (point.y() > bottom)
4018 cmp = LayoutPoint(right, bottom);
4020 cmp = LayoutPoint(right, point.y());
4021 } else if (point.x() < left) {
4022 if (point.y() < top)
4023 cmp = LayoutPoint(left, top);
4024 else if (point.y() > bottom)
4025 cmp = LayoutPoint(left, bottom);
4027 cmp = LayoutPoint(left, point.y());
4029 if (point.y() < top)
4030 cmp = LayoutPoint(point.x(), top);
4032 cmp = LayoutPoint(point.x(), bottom);
4035 LayoutSize difference = cmp - point;
4037 LayoutUnit dist = difference.width() * difference.width() + difference.height() * difference.height();
4038 if (dist < minDist) {
4039 closestRenderer = renderer;
4044 if (closestRenderer)
4045 return closestRenderer->positionForPoint(adjustedPoint - closestRenderer->locationOffset());
4046 return createPositionWithAffinity(firstPositionInOrBeforeNode(nonPseudoNode()));
4049 bool RenderBox::shrinkToAvoidFloats() const
4051 // Floating objects don't shrink. Objects that don't avoid floats don't shrink. Marquees don't shrink.
4052 if ((isInline() && !isMarquee()) || !avoidsFloats() || isFloating())
4055 // Only auto width objects can possibly shrink to avoid floats.
4056 return style()->width().isAuto();
4059 static bool isReplacedElement(Node* node)
4061 // Checkboxes and radioboxes are not isReplaced() nor do they have their own renderer in which to override avoidFloats().
4062 return node && node->isElementNode() && toElement(node)->isFormControlElement();
4065 bool RenderBox::avoidsFloats() const
4067 return isReplaced() || isReplacedElement(node()) || hasOverflowClip() || isHR() || isLegend() || isWritingModeRoot() || isFlexItemIncludingDeprecated();
4070 InvalidationReason RenderBox::getPaintInvalidationReason(const RenderLayerModelObject& paintInvalidationContainer,
4071 const LayoutRect& oldBounds, const LayoutPoint& oldLocation, const LayoutRect& newBounds, const LayoutPoint& newLocation)
4073 InvalidationReason invalidationReason = RenderBoxModelObject::getPaintInvalidationReason(paintInvalidationContainer, oldBounds, oldLocation, newBounds, newLocation);
4074 if (invalidationReason != InvalidationNone && invalidationReason != InvalidationIncremental)
4075 return invalidationReason;
4077 if (!style()->hasBackground() && !style()->hasBoxDecorations())
4078 return invalidationReason;
4080 LayoutSize oldBorderBoxSize;
4081 if (m_rareData && m_rareData->m_previousBorderBoxSize.width() != -1) {
4082 oldBorderBoxSize = m_rareData->m_previousBorderBoxSize;
4084 // We didn't save the old border box size because it was the same as the size of oldBounds.
4085 oldBorderBoxSize = oldBounds.size();
4088 LayoutSize newBorderBoxSize = size();
4090 if (oldBorderBoxSize == newBorderBoxSize)
4091 return invalidationReason;
4093 if (oldBorderBoxSize.width() != newBorderBoxSize.width() && mustInvalidateBackgroundOrBorderPaintOnWidthChange())
4094 return InvalidationBorderBoxChange;
4095 if (oldBorderBoxSize.height() != newBorderBoxSize.height() && mustInvalidateBackgroundOrBorderPaintOnHeightChange())
4096 return InvalidationBorderBoxChange;
4098 // If size of repaint rect equals to size of border box, RenderObject::incrementallyInvalidatePaint()
4099 // is good for boxes having background without box decorations.
4100 if (oldBorderBoxSize == oldBounds.size() && newBorderBoxSize == newBounds.size() && !style()->hasBoxDecorations())
4101 return invalidationReason;
4103 // FIXME: Since we have accurate old border box size, we could do more accurate
4104 // incremental invalidation instead of full invalidation.
4105 return InvalidationBorderBoxChange;
4108 void RenderBox::markForPaginationRelayoutIfNeeded(SubtreeLayoutScope& layoutScope)
4110 ASSERT(!needsLayout());
4111 // If fragmentation height has changed, we need to lay out. No need to enter the renderer if it
4112 // is childless, though.
4113 if (view()->layoutState()->pageLogicalHeightChanged() && slowFirstChild())
4114 layoutScope.setChildNeedsLayout(this);
4117 void RenderBox::addVisualEffectOverflow()
4119 if (!style()->hasVisualOverflowingEffect())
4122 // Add in the final overflow with shadows, outsets and outline combined.
4123 LayoutRect visualEffectOverflow = borderBoxRect();
4124 visualEffectOverflow.expand(computeVisualEffectOverflowExtent());
4125 addVisualOverflow(visualEffectOverflow);
4128 LayoutBoxExtent RenderBox::computeVisualEffectOverflowExtent() const
4130 ASSERT(style()->hasVisualOverflowingEffect());
4137 if (style()->boxShadow()) {
4138 style()->getBoxShadowExtent(top, right, bottom, left);
4140 // Box shadow extent's top and left are negative when extend to left and top direction, respectively.
4141 // Negate to make them positive.
4146 if (style()->hasBorderImageOutsets()) {
4147 LayoutBoxExtent borderOutsets = style()->borderImageOutsets();
4148 top = std::max(top, borderOutsets.top());
4149 right = std::max(right, borderOutsets.right());
4150 bottom = std::max(bottom, borderOutsets.bottom());
4151 left = std::max(left, borderOutsets.left());
4154 RenderStyle* outlineStyle = this->outlineStyle();
4155 if (outlineStyle->hasOutline()) {
4156 if (outlineStyle->outlineStyleIsAuto()) {
4157 // The result focus ring rects are in coordinates of this object's border box.
4158 Vector<IntRect> focusRingRects;
4159 addFocusRingRects(focusRingRects, LayoutPoint(), this);
4160 IntRect rect = unionRect(focusRingRects);
4162 int outlineSize = GraphicsContext::focusRingOutsetExtent(outlineStyle->outlineOffset(), outlineStyle->outlineWidth());
4163 top = std::max<LayoutUnit>(top, -rect.y() + outlineSize);
4164 right = std::max<LayoutUnit>(right, rect.maxX() - width() + outlineSize);
4165 bottom = std::max<LayoutUnit>(bottom, rect.maxY() - height() + outlineSize);
4166 left = std::max<LayoutUnit>(left, -rect.x() + outlineSize);
4168 LayoutUnit outlineSize = outlineStyle->outlineSize();
4169 top = std::max(top, outlineSize);
4170 right = std::max(right, outlineSize);
4171 bottom = std::max(bottom, outlineSize);
4172 left = std::max(left, outlineSize);
4176 return LayoutBoxExtent(top, right, bottom, left);
4179 void RenderBox::addOverflowFromChild(RenderBox* child, const LayoutSize& delta)
4181 // Never allow flow threads to propagate overflow up to a parent.
4182 if (child->isRenderFlowThread())
4185 // Only propagate layout overflow from the child if the child isn't clipping its overflow. If it is, then
4186 // its overflow is internal to it, and we don't care about it. layoutOverflowRectForPropagation takes care of this
4187 // and just propagates the border box rect instead.
4188 LayoutRect childLayoutOverflowRect = child->layoutOverflowRectForPropagation(style());
4189 childLayoutOverflowRect.move(delta);
4190 addLayoutOverflow(childLayoutOverflowRect);
4192 // Add in visual overflow from the child. Even if the child clips its overflow, it may still
4193 // have visual overflow of its own set from box shadows or reflections. It is unnecessary to propagate this
4194 // overflow if we are clipping our own overflow.
4195 if (child->hasSelfPaintingLayer())
4197 LayoutRect childVisualOverflowRect = child->visualOverflowRectForPropagation(style());
4198 childVisualOverflowRect.move(delta);
4199 addContentsVisualOverflow(childVisualOverflowRect);
4202 void RenderBox::addLayoutOverflow(const LayoutRect& rect)
4204 LayoutRect clientBox = noOverflowRect();
4205 if (clientBox.contains(rect) || rect.isEmpty())
4208 // For overflow clip objects, we don't want to propagate overflow into unreachable areas.
4209 LayoutRect overflowRect(rect);
4210 if (hasOverflowClip() || isRenderView()) {
4211 // Overflow is in the block's coordinate space and thus is flipped for horizontal-bt and vertical-rl
4212 // writing modes. At this stage that is actually a simplification, since we can treat horizontal-tb/bt as the same
4213 // and vertical-lr/rl as the same.
4214 bool hasTopOverflow = !style()->isLeftToRightDirection() && !isHorizontalWritingMode();
4215 bool hasLeftOverflow = !style()->isLeftToRightDirection() && isHorizontalWritingMode();
4216 if (isFlexibleBox() && style()->isReverseFlexDirection()) {
4217 RenderFlexibleBox* flexibleBox = toRenderFlexibleBox(this);
4218 if (flexibleBox->isHorizontalFlow())
4219 hasLeftOverflow = true;
4221 hasTopOverflow = true;
4224 if (!hasTopOverflow)
4225 overflowRect.shiftYEdgeTo(std::max(overflowRect.y(), clientBox.y()));
4227 overflowRect.shiftMaxYEdgeTo(std::min(overflowRect.maxY(), clientBox.maxY()));
4228 if (!hasLeftOverflow)
4229 overflowRect.shiftXEdgeTo(std::max(overflowRect.x(), clientBox.x()));
4231 overflowRect.shiftMaxXEdgeTo(std::min(overflowRect.maxX(), clientBox.maxX()));
4233 // Now re-test with the adjusted rectangle and see if it has become unreachable or fully
4235 if (clientBox.contains(overflowRect) || overflowRect.isEmpty())
4240 m_overflow = adoptPtr(new RenderOverflow(clientBox, borderBoxRect()));
4242 m_overflow->addLayoutOverflow(overflowRect);
4245 void RenderBox::addVisualOverflow(const LayoutRect& rect)
4247 LayoutRect borderBox = borderBoxRect();
4248 if (borderBox.contains(rect) || rect.isEmpty())
4252 m_overflow = adoptPtr(new RenderOverflow(noOverflowRect(), borderBox));
4254 m_overflow->addVisualOverflow(rect);
4257 void RenderBox::addContentsVisualOverflow(const LayoutRect& rect)
4259 if (!hasOverflowClip()) {
4260 addVisualOverflow(rect);
4265 m_overflow = adoptPtr(new RenderOverflow(noOverflowRect(), borderBoxRect()));
4266 m_overflow->addContentsVisualOverflow(rect);
4269 void RenderBox::clearLayoutOverflow()
4274 if (!hasVisualOverflow() && contentsVisualOverflowRect().isEmpty()) {
4275 clearAllOverflows();
4279 m_overflow->setLayoutOverflow(noOverflowRect());
4282 inline static bool percentageLogicalHeightIsResolvable(const RenderBox* box)
4284 return RenderBox::percentageLogicalHeightIsResolvableFromBlock(box->containingBlock(), box->isOutOfFlowPositioned());
4287 bool RenderBox::percentageLogicalHeightIsResolvableFromBlock(const RenderBlock* containingBlock, bool isOutOfFlowPositioned)
4289 // In quirks mode, blocks with auto height are skipped, and we keep looking for an enclosing
4290 // block that may have a specified height and then use it. In strict mode, this violates the
4291 // specification, which states that percentage heights just revert to auto if the containing
4292 // block has an auto height. We still skip anonymous containing blocks in both modes, though, and look
4293 // only at explicit containers.
4294 const RenderBlock* cb = containingBlock;
4295 bool inQuirksMode = cb->document().inQuirksMode();
4296 while (!cb->isRenderView() && !cb->isBody() && !cb->isTableCell() && !cb->isOutOfFlowPositioned() && cb->style()->logicalHeight().isAuto()) {
4297 if (!inQuirksMode && !cb->isAnonymousBlock())
4299 cb = cb->containingBlock();
4302 // A positioned element that specified both top/bottom or that specifies height should be treated as though it has a height
4303 // explicitly specified that can be used for any percentage computations.
4304 // FIXME: We can't just check top/bottom here.
4305 // https://bugs.webkit.org/show_bug.cgi?id=46500
4306 bool isOutOfFlowPositionedWithSpecifiedHeight = cb->isOutOfFlowPositioned() && (!cb->style()->logicalHeight().isAuto() || (!cb->style()->top().isAuto() && !cb->style()->bottom().isAuto()));
4308 // Table cells violate what the CSS spec says to do with heights. Basically we
4309 // don't care if the cell specified a height or not. We just always make ourselves
4310 // be a percentage of the cell's current content height.
4311 if (cb->isTableCell())
4314 // Otherwise we only use our percentage height if our containing block had a specified
4316 if (cb->style()->logicalHeight().isFixed())
4318 if (cb->style()->logicalHeight().isPercent() && !isOutOfFlowPositionedWithSpecifiedHeight)
4319 return percentageLogicalHeightIsResolvableFromBlock(cb->containingBlock(), cb->isOutOfFlowPositioned());
4320 if (cb->isRenderView() || inQuirksMode || isOutOfFlowPositionedWithSpecifiedHeight)
4322 if (cb->isDocumentElement() && isOutOfFlowPositioned) {
4323 // Match the positioned objects behavior, which is that positioned objects will fill their viewport
4324 // always. Note we could only hit this case by recurring into computePercentageLogicalHeight on a positioned containing block.
4331 bool RenderBox::hasUnsplittableScrollingOverflow() const
4333 // We will paginate as long as we don't scroll overflow in the pagination direction.
4334 bool isHorizontal = isHorizontalWritingMode();
4335 if ((isHorizontal && !scrollsOverflowY()) || (!isHorizontal && !scrollsOverflowX()))
4338 // We do have overflow. We'll still be willing to paginate as long as the block
4339 // has auto logical height, auto or undefined max-logical-height and a zero or auto min-logical-height.
4340 // Note this is just a heuristic, and it's still possible to have overflow under these
4341 // conditions, but it should work out to be good enough for common cases. Paginating overflow
4342 // with scrollbars present is not the end of the world and is what we used to do in the old model anyway.
4343 return !style()->logicalHeight().isIntrinsicOrAuto()
4344 || (!style()->logicalMaxHeight().isIntrinsicOrAuto() && !style()->logicalMaxHeight().isUndefined() && (!style()->logicalMaxHeight().isPercent() || percentageLogicalHeightIsResolvable(this)))
4345 || (!style()->logicalMinHeight().isIntrinsicOrAuto() && style()->logicalMinHeight().isPositive() && (!style()->logicalMinHeight().isPercent() || percentageLogicalHeightIsResolvable(this)));
4348 bool RenderBox::isUnsplittableForPagination() const
4350 return isReplaced() || hasUnsplittableScrollingOverflow() || (parent() && isWritingModeRoot());
4353 LayoutUnit RenderBox::lineHeight(bool /*firstLine*/, LineDirectionMode direction, LinePositionMode /*linePositionMode*/) const
4356 return direction == HorizontalLine ? m_marginBox.top() + height() + m_marginBox.bottom() : m_marginBox.right() + width() + m_marginBox.left();
4360 int RenderBox::baselinePosition(FontBaseline baselineType, bool /*firstLine*/, LineDirectionMode direction, LinePositionMode linePositionMode) const
4362 ASSERT(linePositionMode == PositionOnContainingLine);
4364 int result = direction == HorizontalLine ? m_marginBox.top() + height() + m_marginBox.bottom() : m_marginBox.right() + width() + m_marginBox.left();
4365 if (baselineType == AlphabeticBaseline)
4367 return result - result / 2;
4373 RenderLayer* RenderBox::enclosingFloatPaintingLayer() const
4375 const RenderObject* curr = this;
4377 RenderLayer* layer = curr->hasLayer() && curr->isBox() ? toRenderBox(curr)->layer() : 0;
4378 if (layer && layer->isSelfPaintingLayer())
4380 curr = curr->parent();
4385 LayoutRect RenderBox::logicalVisualOverflowRectForPropagation(RenderStyle* parentStyle) const
4387 LayoutRect rect = visualOverflowRectForPropagation(parentStyle);
4388 if (!parentStyle->isHorizontalWritingMode())
4389 return rect.transposedRect();
4393 LayoutRect RenderBox::visualOverflowRectForPropagation(RenderStyle* parentStyle) const
4395 // If the writing modes of the child and parent match, then we don't have to
4396 // do anything fancy. Just return the result.
4397 LayoutRect rect = visualOverflowRect();
4398 if (parentStyle->writingMode() == style()->writingMode())
4401 // We are putting ourselves into our parent's coordinate space. If there is a flipped block mismatch
4402 // in a particular axis, then we have to flip the rect along that axis.
4403 if (style()->writingMode() == RightToLeftWritingMode || parentStyle->writingMode() == RightToLeftWritingMode)
4404 rect.setX(width() - rect.maxX());
4405 else if (style()->writingMode() == BottomToTopWritingMode || parentStyle->writingMode() == BottomToTopWritingMode)
4406 rect.setY(height() - rect.maxY());
4411 LayoutRect RenderBox::logicalLayoutOverflowRectForPropagation(RenderStyle* parentStyle) const
4413 LayoutRect rect = layoutOverflowRectForPropagation(parentStyle);
4414 if (!parentStyle->isHorizontalWritingMode())
4415 return rect.transposedRect();
4419 LayoutRect RenderBox::layoutOverflowRectForPropagation(RenderStyle* parentStyle) const
4421 // Only propagate interior layout overflow if we don't clip it.
4422 LayoutRect rect = borderBoxRect();
4423 // We want to include the margin, but only when it adds height. Quirky margins don't contribute height
4424 // nor do the margins of self-collapsing blocks.
4425 if (!style()->hasMarginAfterQuirk() && !isSelfCollapsingBlock())
4426 rect.expand(isHorizontalWritingMode() ? LayoutSize(LayoutUnit(), marginAfter()) : LayoutSize(marginAfter(), LayoutUnit()));
4428 if (!hasOverflowClip())
4429 rect.unite(layoutOverflowRect());
4431 bool hasTransform = hasLayer() && layer()->transform();
4432 if (isRelPositioned() || hasTransform) {
4433 // If we are relatively positioned or if we have a transform, then we have to convert
4434 // this rectangle into physical coordinates, apply relative positioning and transforms
4435 // to it, and then convert it back.
4436 flipForWritingMode(rect);
4439 rect = layer()->currentTransform().mapRect(rect);
4441 if (isRelPositioned())
4442 rect.move(offsetForInFlowPosition());
4444 // Now we need to flip back.
4445 flipForWritingMode(rect);
4448 // If the writing modes of the child and parent match, then we don't have to
4449 // do anything fancy. Just return the result.
4450 if (parentStyle->writingMode() == style()->writingMode())
4453 // We are putting ourselves into our parent's coordinate space. If there is a flipped block mismatch
4454 // in a particular axis, then we have to flip the rect along that axis.
4455 if (style()->writingMode() == RightToLeftWritingMode || parentStyle->writingMode() == RightToLeftWritingMode)
4456 rect.setX(width() - rect.maxX());
4457 else if (style()->writingMode() == BottomToTopWritingMode || parentStyle->writingMode() == BottomToTopWritingMode)
4458 rect.setY(height() - rect.maxY());
4463 LayoutRect RenderBox::noOverflowRect() const
4465 // Because of the special coordinate system used for overflow rectangles and many other
4466 // rectangles (not quite logical, not quite physical), we need to flip the block progression
4467 // coordinate in vertical-rl and horizontal-bt writing modes. In other words, the rectangle
4468 // returned is physical, except for the block direction progression coordinate (y in horizontal
4469 // writing modes, x in vertical writing modes), which is always "logical top". Apart from the
4470 // flipping, this method does the same as clientBoxRect().
4472 const int scrollBarWidth = verticalScrollbarWidth();
4473 const int scrollBarHeight = horizontalScrollbarHeight();
4474 LayoutUnit left = borderLeft() + (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft() ? scrollBarWidth : 0);
4475 LayoutUnit top = borderTop();
4476 LayoutUnit right = borderRight();
4477 LayoutUnit bottom = borderBottom();
4478 LayoutRect rect(left, top, width() - left - right, height() - top - bottom);
4479 flipForWritingMode(rect);
4480 // Subtract space occupied by scrollbars. Order is important here: first flip, then subtract
4481 // scrollbars. This may seem backwards and weird, since one would think that a horizontal
4482 // scrollbar at the physical bottom in horizontal-bt ought to be at the logical top (physical
4483 // bottom), between the logical top (physical bottom) border and the logical top (physical
4484 // bottom) padding. But this is how the rest of the code expects us to behave. This is highly
4485 // related to https://bugs.webkit.org/show_bug.cgi?id=76129
4486 // FIXME: when the above mentioned bug is fixed, it should hopefully be possible to call
4487 // clientBoxRect() or paddingBoxRect() in this method, rather than fiddling with the edges on
4489 if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
4490 rect.contract(0, scrollBarHeight);
4492 rect.contract(scrollBarWidth, scrollBarHeight);
4496 LayoutRect RenderBox::overflowRectForPaintRejection() const
4498 LayoutRect overflowRect = visualOverflowRect();
4499 if (!m_overflow || !usesCompositedScrolling())
4500 return overflowRect;
4502 overflowRect.unite(layoutOverflowRect());
4503 overflowRect.move(-scrolledContentOffset());
4504 return overflowRect;
4507 LayoutUnit RenderBox::offsetLeft() const
4509 return adjustedPositionRelativeToOffsetParent(topLeftLocation()).x();
4512 LayoutUnit RenderBox::offsetTop() const
4514 return adjustedPositionRelativeToOffsetParent(topLeftLocation()).y();
4517 LayoutPoint RenderBox::flipForWritingModeForChild(const RenderBox* child, const LayoutPoint& point) const
4519 if (!style()->isFlippedBlocksWritingMode())
4522 // The child is going to add in its x() and y(), so we have to make sure it ends up in
4524 if (isHorizontalWritingMode())
4525 return LayoutPoint(point.x(), point.y() + height() - child->height() - (2 * child->y()));
4526 return LayoutPoint(point.x() + width() - child->width() - (2 * child->x()), point.y());
4529 void RenderBox::flipForWritingMode(LayoutRect& rect) const
4531 if (!style()->isFlippedBlocksWritingMode())
4534 if (isHorizontalWritingMode())
4535 rect.setY(height() - rect.maxY());
4537 rect.setX(width() - rect.maxX());
4540 LayoutUnit RenderBox::flipForWritingMode(LayoutUnit position) const
4542 if (!style()->isFlippedBlocksWritingMode())
4544 return logicalHeight() - position;
4547 LayoutPoint RenderBox::flipForWritingMode(const LayoutPoint& position) const
4549 if (!style()->isFlippedBlocksWritingMode())
4551 return isHorizontalWritingMode() ? LayoutPoint(position.x(), height() - position.y()) : LayoutPoint(width() - position.x(), position.y());
4554 LayoutPoint RenderBox::flipForWritingModeIncludingColumns(const LayoutPoint& point) const
4556 if (!hasColumns() || !style()->isFlippedBlocksWritingMode())
4557 return flipForWritingMode(point);
4558 return toRenderBlock(this)->flipForWritingModeIncludingColumns(point);
4561 LayoutSize RenderBox::flipForWritingMode(const LayoutSize& offset) const
4563 if (!style()->isFlippedBlocksWritingMode())
4565 return isHorizontalWritingMode() ? LayoutSize(offset.width(), height() - offset.height()) : LayoutSize(width() - offset.width(), offset.height());
4568 FloatPoint RenderBox::flipForWritingMode(const FloatPoint& position) const
4570 if (!style()->isFlippedBlocksWritingMode())
4572 return isHorizontalWritingMode() ? FloatPoint(position.x(), height() - position.y()) : FloatPoint(width() - position.x(), position.y());
4575 void RenderBox::flipForWritingMode(FloatRect& rect) const
4577 if (!style()->isFlippedBlocksWritingMode())
4580 if (isHorizontalWritingMode())
4581 rect.setY(height() - rect.maxY());
4583 rect.setX(width() - rect.maxX());
4586 LayoutPoint RenderBox::topLeftLocation() const
4588 RenderBlock* containerBlock = containingBlock();
4589 if (!containerBlock || containerBlock == this)
4591 return containerBlock->flipForWritingModeForChild(this, location());
4594 LayoutSize RenderBox::topLeftLocationOffset() const
4596 RenderBlock* containerBlock = containingBlock();
4597 if (!containerBlock || containerBlock == this)
4598 return locationOffset();
4600 LayoutRect rect(frameRect());
4601 containerBlock->flipForWritingMode(rect); // FIXME: This is wrong if we are an absolutely positioned object enclosed by a relative-positioned inline.
4602 return LayoutSize(rect.x(), rect.y());
4605 bool RenderBox::hasRelativeLogicalHeight() const
4607 return style()->logicalHeight().isPercent()
4608 || style()->logicalMinHeight().isPercent()
4609 || style()->logicalMaxHeight().isPercent();
4612 static void markBoxForRelayoutAfterSplit(RenderBox* box)
4614 // FIXME: The table code should handle that automatically. If not,
4615 // we should fix it and remove the table part checks.
4616 if (box->isTable()) {
4617 // Because we may have added some sections with already computed column structures, we need to
4618 // sync the table structure with them now. This avoids crashes when adding new cells to the table.
4619 toRenderTable(box)->forceSectionsRecalc();
4620 } else if (box->isTableSection())
4621 toRenderTableSection(box)->setNeedsCellRecalc();
4623 box->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
4626 RenderObject* RenderBox::splitAnonymousBoxesAroundChild(RenderObject* beforeChild)
4628 bool didSplitParentAnonymousBoxes = false;
4630 while (beforeChild->parent() != this) {
4631 RenderBox* boxToSplit = toRenderBox(beforeChild->parent());
4632 if (boxToSplit->slowFirstChild() != beforeChild && boxToSplit->isAnonymous()) {
4633 didSplitParentAnonymousBoxes = true;
4635 // We have to split the parent box into two boxes and move children
4636 // from |beforeChild| to end into the new post box.
4637 RenderBox* postBox = boxToSplit->createAnonymousBoxWithSameTypeAs(this);
4638 postBox->setChildrenInline(boxToSplit->childrenInline());
4639 RenderBox* parentBox = toRenderBox(boxToSplit->parent());
4640 // We need to invalidate the |parentBox| before inserting the new node
4641 // so that the table repainting logic knows the structure is dirty.
4642 // See for example RenderTableCell:clippedOverflowRectForPaintInvalidation.
4643 markBoxForRelayoutAfterSplit(parentBox);
4644 parentBox->virtualChildren()->insertChildNode(parentBox, postBox, boxToSplit->nextSibling());
4645 boxToSplit->moveChildrenTo(postBox, beforeChild, 0, true);
4647 markBoxForRelayoutAfterSplit(boxToSplit);
4648 markBoxForRelayoutAfterSplit(postBox);
4650 beforeChild = postBox;
4652 beforeChild = boxToSplit;
4655 if (didSplitParentAnonymousBoxes)
4656 markBoxForRelayoutAfterSplit(this);
4658 ASSERT(beforeChild->parent() == this);
4662 LayoutUnit RenderBox::offsetFromLogicalTopOfFirstPage() const
4664 LayoutState* layoutState = view()->layoutState();
4665 if (layoutState && !layoutState->isPaginated())
4668 if (!layoutState && !flowThreadContainingBlock())
4671 RenderBlock* containerBlock = containingBlock();
4672 return containerBlock->offsetFromLogicalTopOfFirstPage() + logicalTop();
4675 void RenderBox::savePreviousBorderBoxSizeIfNeeded()
4677 // If m_rareData is already created, always save.
4679 LayoutSize paintInvalidationSize = previousPaintInvalidationRect().size();
4681 // Don't save old border box size if the paint rect is empty because we'll
4682 // full invalidate once the paint rect becomes non-empty.
4683 if (paintInvalidationSize.isEmpty())
4686 // Don't save old border box size if we can use size of the old paint rect
4687 // as the old border box size in the next invalidation.
4688 if (paintInvalidationSize == size())
4691 // We need the old border box size only when the box has background or box decorations.
4692 if (!style()->hasBackground() && !style()->hasBoxDecorations())
4696 ensureRareData().m_previousBorderBoxSize = size();
4699 RenderBox::BoxDecorationData::BoxDecorationData(const RenderStyle& style)
4701 backgroundColor = style.visitedDependentColor(CSSPropertyBackgroundColor);
4702 hasBackground = backgroundColor.alpha() || style.hasBackgroundImage();
4703 ASSERT(hasBackground == style.hasBackground());
4704 hasBorder = style.hasBorder();
4705 hasAppearance = style.hasAppearance();
4708 } // namespace blink