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.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
26 #include "RenderBox.h"
28 #include "CachedImage.h"
30 #include "ChromeClient.h"
32 #include "FrameView.h"
33 #include "GraphicsContext.h"
34 #include "HitTestResult.h"
35 #include "htmlediting.h"
36 #include "HTMLElement.h"
37 #include "HTMLNames.h"
38 #include "ImageBuffer.h"
39 #include "FloatQuad.h"
42 #include "PaintInfo.h"
43 #include "RenderArena.h"
44 #include "RenderBoxRegionInfo.h"
45 #include "RenderFlexibleBox.h"
46 #include "RenderFlowThread.h"
47 #include "RenderGeometryMap.h"
48 #include "RenderInline.h"
49 #include "RenderLayer.h"
50 #include "RenderPart.h"
51 #include "RenderRegion.h"
52 #include "RenderTableCell.h"
53 #include "RenderTheme.h"
54 #include "RenderView.h"
55 #include "ScrollbarTheme.h"
56 #include "TransformState.h"
64 using namespace HTMLNames;
66 // Used by flexible boxes when flexing this element and by table cells.
67 typedef WTF::HashMap<const RenderBox*, LayoutUnit> OverrideSizeMap;
68 static OverrideSizeMap* gOverrideHeightMap = 0;
69 static OverrideSizeMap* gOverrideWidthMap = 0;
71 bool RenderBox::s_hadOverflowClip = false;
73 RenderBox::RenderBox(Node* node)
74 : RenderBoxModelObject(node)
75 , m_minPreferredLogicalWidth(-1)
76 , m_maxPreferredLogicalWidth(-1)
77 , m_inlineBoxWrapper(0)
82 RenderBox::~RenderBox()
86 LayoutRect RenderBox::borderBoxRectInRegion(RenderRegion* region, LayoutUnit offsetFromTopOfFirstPage, RenderBoxRegionInfoFlags cacheFlag) const
89 return borderBoxRect();
91 // Compute the logical width and placement in this region.
92 RenderBoxRegionInfo* boxInfo = renderBoxRegionInfo(region, offsetFromTopOfFirstPage, cacheFlag);
94 return borderBoxRect();
96 // We have cached insets.
97 LayoutUnit logicalWidth = boxInfo->logicalWidth();
98 LayoutUnit logicalLeft = boxInfo->logicalLeft();
100 // Now apply the parent inset since it is cumulative whenever anything in the containing block chain shifts.
101 // FIXME: Doesn't work right with perpendicular writing modes.
102 const RenderBlock* currentBox = containingBlock();
103 offsetFromTopOfFirstPage -= logicalTop();
104 RenderBoxRegionInfo* currentBoxInfo = currentBox->renderBoxRegionInfo(region, offsetFromTopOfFirstPage);
105 while (currentBoxInfo && currentBoxInfo->isShifted()) {
106 if (currentBox->style()->direction() == LTR)
107 logicalLeft += currentBoxInfo->logicalLeft();
109 logicalLeft -= (currentBox->logicalWidth() - currentBoxInfo->logicalWidth()) - currentBoxInfo->logicalLeft();
110 offsetFromTopOfFirstPage -= logicalTop();
111 currentBox = currentBox->containingBlock();
112 region = currentBox->clampToStartAndEndRegions(region);
113 currentBoxInfo = currentBox->renderBoxRegionInfo(region, offsetFromTopOfFirstPage);
116 if (cacheFlag == DoNotCacheRenderBoxRegionInfo)
119 if (isHorizontalWritingMode())
120 return LayoutRect(logicalLeft, 0, logicalWidth, height());
121 return LayoutRect(0, logicalLeft, width(), logicalWidth);
124 void RenderBox::clearRenderBoxRegionInfo()
126 if (!inRenderFlowThread() || isRenderFlowThread())
129 RenderFlowThread* flowThread = enclosingRenderFlowThread();
130 flowThread->removeRenderBoxRegionInfo(this);
133 void RenderBox::willBeDestroyed()
138 RenderBlock::removePercentHeightDescendantIfNeeded(this);
140 if (RenderView* view = this->view()) {
141 if (FrameView* frameView = view->frameView()) {
142 if (style()->position() == FixedPosition)
143 frameView->removeFixedObject(this);
148 RenderBoxModelObject::willBeDestroyed();
151 void RenderBox::removeFloatingOrPositionedChildFromBlockLists()
153 ASSERT(isFloatingOrOutOfFlowPositioned());
155 if (documentBeingDestroyed())
159 RenderBlock* parentBlock = 0;
160 for (RenderObject* curr = parent(); curr && !curr->isRenderView(); curr = curr->parent()) {
161 if (curr->isRenderBlock()) {
162 RenderBlock* currBlock = toRenderBlock(curr);
163 if (!parentBlock || currBlock->containsFloat(this))
164 parentBlock = currBlock;
169 RenderObject* parent = parentBlock->parent();
170 if (parent && parent->isFlexibleBoxIncludingDeprecated())
171 parentBlock = toRenderBlock(parent);
173 parentBlock->markSiblingsWithFloatsForLayout(this);
174 parentBlock->markAllDescendantsWithFloatsForLayout(this, false);
178 if (isOutOfFlowPositioned()) {
179 for (RenderObject* curr = parent(); curr; curr = curr->parent()) {
180 if (curr->isRenderBlock())
181 toRenderBlock(curr)->removePositionedObject(this);
186 void RenderBox::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
188 s_hadOverflowClip = hasOverflowClip();
190 RenderStyle* oldStyle = style();
192 // The background of the root element or the body element could propagate up to
193 // the canvas. Just dirty the entire canvas when our style changes substantially.
194 if (diff >= StyleDifferenceRepaint && node() &&
195 (node()->hasTagName(htmlTag) || node()->hasTagName(bodyTag)))
198 // When a layout hint happens and an object's position style changes, we have to do a layout
199 // to dirty the render tree using the old position value now.
200 if (diff == StyleDifferenceLayout && parent() && oldStyle->position() != newStyle->position()) {
201 markContainingBlocksForLayout();
202 if (oldStyle->position() == StaticPosition)
204 else if (newStyle->isOutOfFlowPositioned())
205 parent()->setChildNeedsLayout(true);
206 if (isFloating() && !isOutOfFlowPositioned() && newStyle->isOutOfFlowPositioned())
207 removeFloatingOrPositionedChildFromBlockLists();
209 } else if (newStyle && isBody())
212 if (FrameView *frameView = view()->frameView()) {
213 bool newStyleIsFixed = newStyle && newStyle->position() == FixedPosition;
214 bool oldStyleIsFixed = oldStyle && oldStyle->position() == FixedPosition;
215 if (newStyleIsFixed != oldStyleIsFixed) {
217 frameView->addFixedObject(this);
219 frameView->removeFixedObject(this);
223 RenderBoxModelObject::styleWillChange(diff, newStyle);
226 void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
228 // Horizontal writing mode definition is updated in RenderBoxModelObject::updateBoxModelInfoFromStyle,
229 // (as part of the RenderBoxModelObject::styleDidChange call below). So, we can safely cache the horizontal
230 // writing mode value before style change here.
231 bool oldHorizontalWritingMode = isHorizontalWritingMode();
233 RenderBoxModelObject::styleDidChange(diff, oldStyle);
235 RenderStyle* newStyle = style();
236 if (needsLayout() && oldStyle) {
237 RenderBlock::removePercentHeightDescendantIfNeeded(this);
239 // Normally we can do optimized positioning layout for absolute/fixed positioned objects. There is one special case, however, which is
240 // 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
241 // to determine the new static position.
242 if (isOutOfFlowPositioned() && newStyle->hasStaticBlockPosition(isHorizontalWritingMode()) && oldStyle->marginBefore() != newStyle->marginBefore()
243 && parent() && !parent()->normalChildNeedsLayout())
244 parent()->setChildNeedsLayout(true);
247 if (RenderBlock::hasPercentHeightContainerMap() && firstChild()
248 && oldHorizontalWritingMode != isHorizontalWritingMode())
249 RenderBlock::clearPercentHeightDescendantsFrom(this);
251 // If our zoom factor changes and we have a defined scrollLeft/Top, we need to adjust that value into the
252 // new zoomed coordinate space.
253 if (hasOverflowClip() && oldStyle && newStyle && oldStyle->effectiveZoom() != newStyle->effectiveZoom()) {
254 if (int left = layer()->scrollXOffset()) {
255 left = (left / oldStyle->effectiveZoom()) * newStyle->effectiveZoom();
256 layer()->scrollToXOffset(left);
258 if (int top = layer()->scrollYOffset()) {
259 top = (top / oldStyle->effectiveZoom()) * newStyle->effectiveZoom();
260 layer()->scrollToYOffset(top);
264 bool isBodyRenderer = isBody();
265 bool isRootRenderer = isRoot();
267 // Set the text color if we're the body.
269 document()->setTextColor(newStyle->visitedDependentColor(CSSPropertyColor));
271 if (isRootRenderer || isBodyRenderer) {
272 // Propagate the new writing mode and direction up to the RenderView.
273 RenderView* viewRenderer = view();
274 RenderStyle* viewStyle = viewRenderer->style();
275 if (viewStyle->direction() != newStyle->direction() && (isRootRenderer || !document()->directionSetOnDocumentElement())) {
276 viewStyle->setDirection(newStyle->direction());
278 document()->documentElement()->renderer()->style()->setDirection(newStyle->direction());
279 setNeedsLayoutAndPrefWidthsRecalc();
282 if (viewStyle->writingMode() != newStyle->writingMode() && (isRootRenderer || !document()->writingModeSetOnDocumentElement())) {
283 viewStyle->setWritingMode(newStyle->writingMode());
284 viewRenderer->setHorizontalWritingMode(newStyle->isHorizontalWritingMode());
285 if (isBodyRenderer) {
286 document()->documentElement()->renderer()->style()->setWritingMode(newStyle->writingMode());
287 document()->documentElement()->renderer()->setHorizontalWritingMode(newStyle->isHorizontalWritingMode());
289 setNeedsLayoutAndPrefWidthsRecalc();
292 frame()->view()->recalculateScrollbarOverlayStyle();
296 void RenderBox::updateBoxModelInfoFromStyle()
298 RenderBoxModelObject::updateBoxModelInfoFromStyle();
300 RenderStyle* styleToUse = style();
301 bool isRootObject = isRoot();
302 bool isViewObject = isRenderView();
304 // The root and the RenderView always paint their backgrounds/borders.
305 if (isRootObject || isViewObject)
306 setHasBoxDecorations(true);
308 setPositioned(styleToUse->isOutOfFlowPositioned());
309 setFloating(!isOutOfFlowPositioned() && styleToUse->isFloating());
311 // We also handle <body> and <html>, whose overflow applies to the viewport.
312 if (styleToUse->overflowX() != OVISIBLE && !isRootObject && (isRenderBlock() || isTableRow() || isTableSection())) {
313 bool boxHasOverflowClip = true;
315 // Overflow on the body can propagate to the viewport under the following conditions.
316 // (1) The root element is <html>.
317 // (2) We are the primary <body> (can be checked by looking at document.body).
318 // (3) The root element has visible overflow.
319 if (document()->documentElement()->hasTagName(htmlTag) &&
320 document()->body() == node() &&
321 document()->documentElement()->renderer()->style()->overflowX() == OVISIBLE)
322 boxHasOverflowClip = false;
325 // Check for overflow clip.
326 // It's sufficient to just check one direction, since it's illegal to have visible on only one overflow value.
327 if (boxHasOverflowClip) {
328 if (!s_hadOverflowClip)
329 // Erase the overflow
331 setHasOverflowClip();
335 setHasTransform(styleToUse->hasTransformRelatedProperty());
336 setHasReflection(styleToUse->boxReflect());
339 void RenderBox::layout()
341 ASSERT(needsLayout());
343 RenderObject* child = firstChild();
345 setNeedsLayout(false);
349 LayoutStateMaintainer statePusher(view(), this, locationOffset(), style()->isFlippedBlocksWritingMode());
351 child->layoutIfNeeded();
352 ASSERT(!child->needsLayout());
353 child = child->nextSibling();
356 setNeedsLayout(false);
359 // More IE extensions. clientWidth and clientHeight represent the interior of an object
360 // excluding border and scrollbar.
361 LayoutUnit RenderBox::clientWidth() const
363 return width() - borderLeft() - borderRight() - verticalScrollbarWidth();
366 LayoutUnit RenderBox::clientHeight() const
368 return height() - borderTop() - borderBottom() - horizontalScrollbarHeight();
371 int RenderBox::pixelSnappedClientWidth() const
373 return snapSizeToPixel(clientWidth(), x() + clientLeft());
376 int RenderBox::pixelSnappedClientHeight() const
378 return snapSizeToPixel(clientHeight(), y() + clientTop());
381 int RenderBox::scrollWidth() const
383 if (hasOverflowClip())
384 return layer()->scrollWidth();
385 // For objects with visible overflow, this matches IE.
386 // FIXME: Need to work right with writing modes.
387 if (style()->isLeftToRightDirection())
388 return snapSizeToPixel(max(clientWidth(), layoutOverflowRect().maxX() - borderLeft()), x() + clientLeft());
389 return clientWidth() - min(ZERO_LAYOUT_UNIT, layoutOverflowRect().x() - borderLeft());
392 int RenderBox::scrollHeight() const
394 if (hasOverflowClip())
395 return layer()->scrollHeight();
396 // For objects with visible overflow, this matches IE.
397 // FIXME: Need to work right with writing modes.
398 return snapSizeToPixel(max(clientHeight(), layoutOverflowRect().maxY() - borderTop()), y() + clientTop());
401 int RenderBox::scrollLeft() const
403 return hasOverflowClip() ? layer()->scrollXOffset() : 0;
406 int RenderBox::scrollTop() const
408 return hasOverflowClip() ? layer()->scrollYOffset() : 0;
411 void RenderBox::setScrollLeft(int newLeft)
413 if (hasOverflowClip())
414 layer()->scrollToXOffset(newLeft, RenderLayer::ScrollOffsetClamped);
417 void RenderBox::setScrollTop(int newTop)
419 if (hasOverflowClip())
420 layer()->scrollToYOffset(newTop, RenderLayer::ScrollOffsetClamped);
423 void RenderBox::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
425 rects.append(pixelSnappedIntRect(accumulatedOffset, size()));
428 void RenderBox::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
430 quads.append(localToAbsoluteQuad(FloatRect(0, 0, width(), height()), false, wasFixed));
433 void RenderBox::updateLayerTransform()
435 // Transform-origin depends on box size, so we need to update the layer transform after layout.
437 layer()->updateTransform();
440 IntRect RenderBox::absoluteContentBox() const
442 // This is wrong with transforms and flipped writing modes.
443 IntRect rect = pixelSnappedIntRect(contentBoxRect());
444 FloatPoint absPos = localToAbsolute(FloatPoint());
445 rect.move(absPos.x(), absPos.y());
449 FloatQuad RenderBox::absoluteContentQuad() const
451 LayoutRect rect = contentBoxRect();
452 return localToAbsoluteQuad(FloatRect(rect));
455 LayoutRect RenderBox::outlineBoundsForRepaint(RenderBoxModelObject* repaintContainer, LayoutPoint* cachedOffsetToRepaintContainer) const
457 LayoutRect box = borderBoundingBox();
458 adjustRectForOutlineAndShadow(box);
460 FloatQuad containerRelativeQuad = FloatRect(box);
461 if (cachedOffsetToRepaintContainer)
462 containerRelativeQuad.move(cachedOffsetToRepaintContainer->x(), cachedOffsetToRepaintContainer->y());
464 containerRelativeQuad = localToContainerQuad(containerRelativeQuad, repaintContainer);
466 box = containerRelativeQuad.enclosingBoundingBox();
468 // FIXME: layoutDelta needs to be applied in parts before/after transforms and
469 // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
470 box.move(view()->layoutDelta());
475 void RenderBox::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset)
477 if (!size().isEmpty())
478 rects.append(pixelSnappedIntRect(additionalOffset, size()));
481 LayoutRect RenderBox::reflectionBox() const
484 if (!style()->boxReflect())
486 LayoutRect box = borderBoxRect();
488 switch (style()->boxReflect()->direction()) {
489 case ReflectionBelow:
490 result.move(0, box.height() + reflectionOffset());
492 case ReflectionAbove:
493 result.move(0, -box.height() - reflectionOffset());
496 result.move(-box.width() - reflectionOffset(), 0);
498 case ReflectionRight:
499 result.move(box.width() + reflectionOffset(), 0);
505 int RenderBox::reflectionOffset() const
507 if (!style()->boxReflect())
509 RenderView* renderView = view();
510 if (style()->boxReflect()->direction() == ReflectionLeft || style()->boxReflect()->direction() == ReflectionRight)
511 return valueForLength(style()->boxReflect()->offset(), borderBoxRect().width(), renderView);
512 return valueForLength(style()->boxReflect()->offset(), borderBoxRect().height(), renderView);
515 LayoutRect RenderBox::reflectedRect(const LayoutRect& r) const
517 if (!style()->boxReflect())
520 LayoutRect box = borderBoxRect();
521 LayoutRect result = r;
522 switch (style()->boxReflect()->direction()) {
523 case ReflectionBelow:
524 result.setY(box.maxY() + reflectionOffset() + (box.maxY() - r.maxY()));
526 case ReflectionAbove:
527 result.setY(box.y() - reflectionOffset() - box.height() + (box.maxY() - r.maxY()));
530 result.setX(box.x() - reflectionOffset() - box.width() + (box.maxX() - r.maxX()));
532 case ReflectionRight:
533 result.setX(box.maxX() + reflectionOffset() + (box.maxX() - r.maxX()));
539 bool RenderBox::fixedElementLaysOutRelativeToFrame(Frame* frame, FrameView* frameView) const
541 return style() && style()->position() == FixedPosition && container()->isRenderView() && frame && frameView && frameView->fixedElementsLayoutRelativeToFrame();
544 bool RenderBox::includeVerticalScrollbarSize() const
546 return hasOverflowClip() && !layer()->hasOverlayScrollbars()
547 && (style()->overflowY() == OSCROLL || style()->overflowY() == OAUTO);
550 bool RenderBox::includeHorizontalScrollbarSize() const
552 return hasOverflowClip() && !layer()->hasOverlayScrollbars()
553 && (style()->overflowX() == OSCROLL || style()->overflowX() == OAUTO);
556 int RenderBox::verticalScrollbarWidth() const
558 return includeVerticalScrollbarSize() ? layer()->verticalScrollbarWidth() : 0;
561 int RenderBox::horizontalScrollbarHeight() const
563 return includeHorizontalScrollbarSize() ? layer()->horizontalScrollbarHeight() : 0;
566 bool RenderBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
568 RenderLayer* l = layer();
569 if (l && l->scroll(direction, granularity, multiplier)) {
575 if (stopNode && *stopNode && *stopNode == node())
578 RenderBlock* b = containingBlock();
579 if (b && !b->isRenderView())
580 return b->scroll(direction, granularity, multiplier, stopNode);
584 bool RenderBox::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
586 bool scrolled = false;
588 RenderLayer* l = layer();
591 // On Mac only we reset the inline direction position when doing a document scroll (e.g., hitting Home/End).
592 if (granularity == ScrollByDocument)
593 scrolled = l->scroll(logicalToPhysical(ScrollInlineDirectionBackward, isHorizontalWritingMode(), style()->isFlippedBlocksWritingMode()), ScrollByDocument, multiplier);
595 if (l->scroll(logicalToPhysical(direction, isHorizontalWritingMode(), style()->isFlippedBlocksWritingMode()), granularity, multiplier))
605 if (stopNode && *stopNode && *stopNode == node())
608 RenderBlock* b = containingBlock();
609 if (b && !b->isRenderView())
610 return b->logicalScroll(direction, granularity, multiplier, stopNode);
614 bool RenderBox::canBeScrolledAndHasScrollableArea() const
616 return canBeProgramaticallyScrolled() && (scrollHeight() != clientHeight() || scrollWidth() != clientWidth());
619 bool RenderBox::canBeProgramaticallyScrolled() const
621 return (hasOverflowClip() && (scrollsOverflow() || (node() && node()->rendererIsEditable()))) || (node() && node()->isDocumentNode());
624 void RenderBox::autoscroll()
627 layer()->autoscroll();
630 void RenderBox::panScroll(const IntPoint& source)
633 layer()->panScrollFromPoint(source);
636 bool RenderBox::needsPreferredWidthsRecalculation() const
638 return style()->paddingStart().isPercent() || style()->paddingEnd().isPercent();
641 IntSize RenderBox::scrolledContentOffset() const
643 ASSERT(hasOverflowClip());
645 return layer()->scrolledContentOffset();
648 LayoutSize RenderBox::cachedSizeForOverflowClip() const
650 ASSERT(hasOverflowClip());
652 return layer()->size();
655 LayoutUnit RenderBox::minPreferredLogicalWidth() const
657 if (preferredLogicalWidthsDirty())
658 const_cast<RenderBox*>(this)->computePreferredLogicalWidths();
660 return m_minPreferredLogicalWidth;
663 LayoutUnit RenderBox::maxPreferredLogicalWidth() const
665 if (preferredLogicalWidthsDirty())
666 const_cast<RenderBox*>(this)->computePreferredLogicalWidths();
668 return m_maxPreferredLogicalWidth;
671 bool RenderBox::hasOverrideHeight() const
673 return gOverrideHeightMap && gOverrideHeightMap->contains(this);
676 bool RenderBox::hasOverrideWidth() const
678 return gOverrideWidthMap && gOverrideWidthMap->contains(this);
681 void RenderBox::setOverrideLogicalContentHeight(LayoutUnit height)
683 if (!gOverrideHeightMap)
684 gOverrideHeightMap = new OverrideSizeMap();
685 gOverrideHeightMap->set(this, height);
688 void RenderBox::setOverrideLogicalContentWidth(LayoutUnit width)
690 if (!gOverrideWidthMap)
691 gOverrideWidthMap = new OverrideSizeMap();
692 gOverrideWidthMap->set(this, width);
695 void RenderBox::clearOverrideSize()
697 if (gOverrideHeightMap)
698 gOverrideHeightMap->remove(this);
699 if (gOverrideWidthMap)
700 gOverrideWidthMap->remove(this);
703 LayoutUnit RenderBox::overrideLogicalContentWidth() const
705 // FIXME: This should probably be returning contentLogicalWidth instead of contentWidth.
706 return hasOverrideWidth() ? gOverrideWidthMap->get(this) : contentWidth();
709 LayoutUnit RenderBox::overrideLogicalContentHeight() const
711 // FIXME: This should probably be returning contentLogicalHeight instead of contentHeight.
712 return hasOverrideHeight() ? gOverrideHeightMap->get(this) : contentHeight();
715 LayoutUnit RenderBox::computeBorderBoxLogicalWidth(LayoutUnit width) const
717 LayoutUnit bordersPlusPadding = borderAndPaddingLogicalWidth();
718 if (style()->boxSizing() == CONTENT_BOX)
719 return width + bordersPlusPadding;
720 return max(width, bordersPlusPadding);
723 LayoutUnit RenderBox::computeBorderBoxLogicalHeight(LayoutUnit height) const
725 LayoutUnit bordersPlusPadding = borderAndPaddingLogicalHeight();
726 if (style()->boxSizing() == CONTENT_BOX)
727 return height + bordersPlusPadding;
728 return max(height, bordersPlusPadding);
731 LayoutUnit RenderBox::computeContentBoxLogicalWidth(LayoutUnit width) const
733 if (style()->boxSizing() == BORDER_BOX)
734 width -= borderAndPaddingLogicalWidth();
735 return max<LayoutUnit>(0, width);
738 LayoutUnit RenderBox::computeContentBoxLogicalHeight(LayoutUnit height) const
740 if (style()->boxSizing() == BORDER_BOX)
741 height -= borderAndPaddingLogicalHeight();
742 return max<LayoutUnit>(0, height);
746 bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
748 LayoutPoint adjustedLocation = accumulatedOffset + location();
751 for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
752 if (!child->hasLayer() && child->nodeAtPoint(request, result, pointInContainer, adjustedLocation, action)) {
753 updateHitTestResult(result, pointInContainer.point() - toLayoutSize(adjustedLocation));
758 // Check our bounds next. For this purpose always assume that we can only be hit in the
759 // foreground phase (which is true for replaced elements like images).
760 LayoutRect boundsRect = borderBoxRectInRegion(pointInContainer.region());
761 boundsRect.moveBy(adjustedLocation);
762 if (visibleToHitTesting() && action == HitTestForeground && pointInContainer.intersects(boundsRect)) {
763 updateHitTestResult(result, pointInContainer.point() - toLayoutSize(adjustedLocation));
764 if (!result.addNodeToRectBasedTestResult(node(), pointInContainer, boundsRect))
771 // --------------------- painting stuff -------------------------------
773 void RenderBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
775 LayoutPoint adjustedPaintOffset = paintOffset + location();
776 // default implementation. Just pass paint through to the children
777 PaintInfo childInfo(paintInfo);
778 childInfo.updatePaintingRootForChildren(this);
779 for (RenderObject* child = firstChild(); child; child = child->nextSibling())
780 child->paint(childInfo, adjustedPaintOffset);
783 void RenderBox::paintRootBoxFillLayers(const PaintInfo& paintInfo)
785 RenderObject* rootBackgroundRenderer = rendererForRootBackground();
787 const FillLayer* bgLayer = rootBackgroundRenderer->style()->backgroundLayers();
788 Color bgColor = rootBackgroundRenderer->style()->visitedDependentColor(CSSPropertyBackgroundColor);
790 paintFillLayers(paintInfo, bgColor, bgLayer, view()->backgroundRect(this), BackgroundBleedNone, CompositeSourceOver, rootBackgroundRenderer);
793 BackgroundBleedAvoidance RenderBox::determineBackgroundBleedAvoidance(GraphicsContext* context) const
795 if (context->paintingDisabled())
796 return BackgroundBleedNone;
798 const RenderStyle* style = this->style();
800 if (!style->hasBackground() || !style->hasBorder() || !style->hasBorderRadius() || borderImageIsLoadedAndCanBeRendered())
801 return BackgroundBleedNone;
803 AffineTransform ctm = context->getCTM();
804 FloatSize contextScaling(static_cast<float>(ctm.xScale()), static_cast<float>(ctm.yScale()));
805 if (borderObscuresBackgroundEdge(contextScaling))
806 return BackgroundBleedShrinkBackground;
808 // FIXME: there is one more strategy possible, for opaque backgrounds and
809 // translucent borders. In that case we could avoid using a transparency layer,
810 // and paint the border first, and then paint the background clipped to the
811 // inside of the border.
813 return BackgroundBleedUseTransparencyLayer;
816 void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
818 if (!paintInfo.shouldPaintWithinRoot(this))
821 LayoutRect paintRect = borderBoxRectInRegion(paintInfo.renderRegion);
822 paintRect.moveBy(paintOffset);
824 // border-fit can adjust where we paint our border and background. If set, we snugly fit our line box descendants. (The iChat
825 // balloon layout is an example of this).
826 borderFitAdjust(paintRect);
828 BackgroundBleedAvoidance bleedAvoidance = determineBackgroundBleedAvoidance(paintInfo.context);
830 // FIXME: Should eventually give the theme control over whether the box shadow should paint, since controls could have
831 // custom shadows of their own.
832 if (!boxShadowShouldBeAppliedToBackground(bleedAvoidance))
833 paintBoxShadow(paintInfo, paintRect, style(), Normal);
835 GraphicsContextStateSaver stateSaver(*paintInfo.context, false);
836 if (bleedAvoidance == BackgroundBleedUseTransparencyLayer) {
837 // To avoid the background color bleeding out behind the border, we'll render background and border
838 // into a transparency layer, and then clip that in one go (which requires setting up the clip before
839 // beginning the layer).
840 RoundedRect border = style()->getRoundedBorderFor(paintRect, view());
842 paintInfo.context->addRoundedRectClip(border);
843 paintInfo.context->beginTransparencyLayer(1);
846 // If we have a native theme appearance, paint that before painting our background.
847 // The theme will tell us whether or not we should also paint the CSS background.
848 IntRect snappedPaintRect(pixelSnappedIntRect(paintRect));
849 bool themePainted = style()->hasAppearance() && !theme()->paint(this, paintInfo, snappedPaintRect);
851 paintBackground(paintInfo, paintRect, bleedAvoidance);
853 if (style()->hasAppearance())
854 theme()->paintDecorations(this, paintInfo, snappedPaintRect);
856 paintBoxShadow(paintInfo, paintRect, style(), Inset);
858 // The theme will tell us whether or not we should also paint the CSS border.
859 if ((!style()->hasAppearance() || (!themePainted && theme()->paintBorderOnly(this, paintInfo, snappedPaintRect))) && style()->hasBorder())
860 paintBorder(paintInfo, paintRect, style(), bleedAvoidance);
862 if (bleedAvoidance == BackgroundBleedUseTransparencyLayer)
863 paintInfo.context->endTransparencyLayer();
866 void RenderBox::paintBackground(const PaintInfo& paintInfo, const LayoutRect& paintRect, BackgroundBleedAvoidance bleedAvoidance)
869 paintRootBoxFillLayers(paintInfo);
871 || (document()->documentElement()->renderer() && document()->documentElement()->renderer()->hasBackground())
872 || (document()->documentElement()->renderer() != parent())) {
873 // The <body> only paints its background if the root element has defined a background independent of the body,
874 // or if the <body>'s parent is not the document element's renderer (e.g. inside SVG foreignObject).
875 if (!backgroundIsObscured())
876 paintFillLayers(paintInfo, style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), paintRect, bleedAvoidance);
880 void RenderBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
882 if (!paintInfo.shouldPaintWithinRoot(this) || style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask || paintInfo.context->paintingDisabled())
885 LayoutRect paintRect = LayoutRect(paintOffset, size());
887 // border-fit can adjust where we paint our border and background. If set, we snugly fit our line box descendants. (The iChat
888 // balloon layout is an example of this).
889 borderFitAdjust(paintRect);
891 paintMaskImages(paintInfo, paintRect);
894 void RenderBox::paintMaskImages(const PaintInfo& paintInfo, const LayoutRect& paintRect)
896 // Figure out if we need to push a transparency layer to render our mask.
897 bool pushTransparencyLayer = false;
898 bool compositedMask = hasLayer() && layer()->hasCompositedMask();
899 bool flattenCompositingLayers = view()->frameView() && view()->frameView()->paintBehavior() & PaintBehaviorFlattenCompositingLayers;
900 CompositeOperator compositeOp = CompositeSourceOver;
902 bool allMaskImagesLoaded = true;
904 if (!compositedMask || flattenCompositingLayers) {
905 pushTransparencyLayer = true;
906 StyleImage* maskBoxImage = style()->maskBoxImage().image();
907 const FillLayer* maskLayers = style()->maskLayers();
909 // Don't render a masked element until all the mask images have loaded, to prevent a flash of unmasked content.
911 allMaskImagesLoaded &= maskBoxImage->isLoaded();
914 allMaskImagesLoaded &= maskLayers->imagesAreLoaded();
916 paintInfo.context->setCompositeOperation(CompositeDestinationIn);
917 paintInfo.context->beginTransparencyLayer(1);
918 compositeOp = CompositeSourceOver;
921 if (allMaskImagesLoaded) {
922 paintFillLayers(paintInfo, Color(), style()->maskLayers(), paintRect, BackgroundBleedNone, compositeOp);
923 paintNinePieceImage(paintInfo.context, paintRect, style(), style()->maskBoxImage(), compositeOp);
926 if (pushTransparencyLayer)
927 paintInfo.context->endTransparencyLayer();
930 LayoutRect RenderBox::maskClipRect()
932 const NinePieceImage& maskBoxImage = style()->maskBoxImage();
933 if (maskBoxImage.image()) {
934 LayoutRect borderImageRect = borderBoxRect();
936 // Apply outsets to the border box.
937 borderImageRect.expand(style()->maskBoxImageOutsets());
938 return borderImageRect;
942 LayoutRect borderBox = borderBoxRect();
943 for (const FillLayer* maskLayer = style()->maskLayers(); maskLayer; maskLayer = maskLayer->next()) {
944 if (maskLayer->image()) {
945 BackgroundImageGeometry geometry;
946 calculateBackgroundImageGeometry(maskLayer, borderBox, geometry);
947 result.unite(geometry.destRect());
953 void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, const LayoutRect& rect,
954 BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderObject* backgroundObject)
959 paintFillLayers(paintInfo, c, fillLayer->next(), rect, bleedAvoidance, op, backgroundObject);
960 paintFillLayer(paintInfo, c, fillLayer, rect, bleedAvoidance, op, backgroundObject);
963 void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, const LayoutRect& rect,
964 BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderObject* backgroundObject)
966 paintFillLayerExtended(paintInfo, c, fillLayer, rect, bleedAvoidance, 0, LayoutSize(), op, backgroundObject);
969 #if USE(ACCELERATED_COMPOSITING)
970 static bool layersUseImage(WrappedImagePtr image, const FillLayer* layers)
972 for (const FillLayer* curLayer = layers; curLayer; curLayer = curLayer->next()) {
973 if (curLayer->image() && image == curLayer->image()->data())
981 void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*)
986 if ((style()->borderImage().image() && style()->borderImage().image()->data() == image) ||
987 (style()->maskBoxImage().image() && style()->maskBoxImage().image()->data() == image)) {
992 bool didFullRepaint = repaintLayerRectsForImage(image, style()->backgroundLayers(), true);
994 repaintLayerRectsForImage(image, style()->maskLayers(), false);
997 #if USE(ACCELERATED_COMPOSITING)
998 if (hasLayer() && layer()->hasCompositedMask() && layersUseImage(image, style()->maskLayers()))
999 layer()->contentChanged(MaskImageChanged);
1003 bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer* layers, bool drawingBackground)
1005 LayoutRect rendererRect;
1006 RenderBox* layerRenderer = 0;
1008 for (const FillLayer* curLayer = layers; curLayer; curLayer = curLayer->next()) {
1009 if (curLayer->image() && image == curLayer->image()->data() && curLayer->image()->canRender(this, style()->effectiveZoom())) {
1010 // Now that we know this image is being used, compute the renderer and the rect
1011 // if we haven't already
1012 if (!layerRenderer) {
1013 bool drawingRootBackground = drawingBackground && (isRoot() || (isBody() && !document()->documentElement()->renderer()->hasBackground()));
1014 if (drawingRootBackground) {
1015 layerRenderer = view();
1020 if (FrameView* frameView = toRenderView(layerRenderer)->frameView()) {
1021 rw = frameView->contentsWidth();
1022 rh = frameView->contentsHeight();
1024 rw = layerRenderer->width();
1025 rh = layerRenderer->height();
1027 rendererRect = LayoutRect(-layerRenderer->marginLeft(),
1028 -layerRenderer->marginTop(),
1029 max(layerRenderer->width() + layerRenderer->marginWidth() + layerRenderer->borderLeft() + layerRenderer->borderRight(), rw),
1030 max(layerRenderer->height() + layerRenderer->marginHeight() + layerRenderer->borderTop() + layerRenderer->borderBottom(), rh));
1032 layerRenderer = this;
1033 rendererRect = borderBoxRect();
1037 BackgroundImageGeometry geometry;
1038 layerRenderer->calculateBackgroundImageGeometry(curLayer, rendererRect, geometry);
1039 layerRenderer->repaintRectangle(geometry.destRect());
1040 if (geometry.destRect() == rendererRect)
1049 void RenderBox::paintCustomHighlight(const LayoutPoint& paintOffset, const AtomicString& type, bool behindText)
1051 Frame* frame = this->frame();
1054 Page* page = frame->page();
1058 InlineBox* boxWrap = inlineBoxWrapper();
1059 RootInlineBox* r = boxWrap ? boxWrap->root() : 0;
1061 FloatRect rootRect(paintOffset.x() + r->x(), paintOffset.y() + r->selectionTop(), r->logicalWidth(), r->selectionHeight());
1062 FloatRect imageRect(paintOffset.x() + x(), rootRect.y(), width(), rootRect.height());
1063 page->chrome()->client()->paintCustomHighlight(node(), type, imageRect, rootRect, behindText, false);
1065 FloatRect imageRect(paintOffset.x() + x(), paintOffset.y() + y(), width(), height());
1066 page->chrome()->client()->paintCustomHighlight(node(), type, imageRect, imageRect, behindText, false);
1072 bool RenderBox::pushContentsClip(PaintInfo& paintInfo, const LayoutPoint& accumulatedOffset)
1074 if (paintInfo.phase == PaintPhaseBlockBackground || paintInfo.phase == PaintPhaseSelfOutline || paintInfo.phase == PaintPhaseMask)
1077 bool isControlClip = hasControlClip();
1078 bool isOverflowClip = hasOverflowClip() && !layer()->isSelfPaintingLayer();
1080 if (!isControlClip && !isOverflowClip)
1083 if (paintInfo.phase == PaintPhaseOutline)
1084 paintInfo.phase = PaintPhaseChildOutlines;
1085 else if (paintInfo.phase == PaintPhaseChildBlockBackground) {
1086 paintInfo.phase = PaintPhaseBlockBackground;
1087 paintObject(paintInfo, accumulatedOffset);
1088 paintInfo.phase = PaintPhaseChildBlockBackgrounds;
1090 IntRect clipRect = pixelSnappedIntRect(isControlClip ? controlClipRect(accumulatedOffset) : overflowClipRect(accumulatedOffset, paintInfo.renderRegion));
1091 paintInfo.context->save();
1092 if (style()->hasBorderRadius())
1093 paintInfo.context->addRoundedRectClip(style()->getRoundedInnerBorderFor(LayoutRect(accumulatedOffset, size())));
1094 paintInfo.context->clip(clipRect);
1098 void RenderBox::popContentsClip(PaintInfo& paintInfo, PaintPhase originalPhase, const LayoutPoint& accumulatedOffset)
1100 ASSERT(hasControlClip() || (hasOverflowClip() && !layer()->isSelfPaintingLayer()));
1102 paintInfo.context->restore();
1103 if (originalPhase == PaintPhaseOutline) {
1104 paintInfo.phase = PaintPhaseSelfOutline;
1105 paintObject(paintInfo, accumulatedOffset);
1106 paintInfo.phase = originalPhase;
1107 } else if (originalPhase == PaintPhaseChildBlockBackground)
1108 paintInfo.phase = originalPhase;
1111 LayoutRect RenderBox::overflowClipRect(const LayoutPoint& location, RenderRegion* region, OverlayScrollbarSizeRelevancy relevancy)
1113 // FIXME: When overflow-clip (CSS3) is implemented, we'll obtain the property
1115 LayoutRect clipRect = borderBoxRectInRegion(region);
1116 clipRect.setLocation(location + clipRect.location() + LayoutSize(borderLeft(), borderTop()));
1117 clipRect.setSize(clipRect.size() - LayoutSize(borderLeft() + borderRight(), borderTop() + borderBottom()));
1119 // Subtract out scrollbars if we have them.
1121 if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
1122 clipRect.move(layer()->verticalScrollbarWidth(relevancy), 0);
1123 clipRect.contract(layer()->verticalScrollbarWidth(relevancy), layer()->horizontalScrollbarHeight(relevancy));
1129 LayoutRect RenderBox::clipRect(const LayoutPoint& location, RenderRegion* region)
1131 LayoutRect borderBoxRect = borderBoxRectInRegion(region);
1132 LayoutRect clipRect = LayoutRect(borderBoxRect.location() + location, borderBoxRect.size());
1133 RenderView* renderView = view();
1135 if (!style()->clipLeft().isAuto()) {
1136 LayoutUnit c = valueForLength(style()->clipLeft(), borderBoxRect.width(), renderView);
1137 clipRect.move(c, 0);
1138 clipRect.contract(c, 0);
1141 // We don't use the region-specific border box's width and height since clip offsets are (stupidly) specified
1142 // from the left and top edges. Therefore it's better to avoid constraining to smaller widths and heights.
1144 if (!style()->clipRight().isAuto())
1145 clipRect.contract(width() - valueForLength(style()->clipRight(), width(), renderView), 0);
1147 if (!style()->clipTop().isAuto()) {
1148 LayoutUnit c = valueForLength(style()->clipTop(), borderBoxRect.height(), renderView);
1149 clipRect.move(0, c);
1150 clipRect.contract(0, c);
1153 if (!style()->clipBottom().isAuto())
1154 clipRect.contract(0, height() - valueForLength(style()->clipBottom(), height(), renderView));
1159 LayoutUnit RenderBox::shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStart, LayoutUnit childMarginEnd, const RenderBlock* cb, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage)
1161 RenderRegion* containingBlockRegion = 0;
1162 LayoutUnit logicalTopPosition = logicalTop();
1163 LayoutUnit adjustedPageOffsetForContainingBlock = offsetFromLogicalTopOfFirstPage - logicalTop();
1165 LayoutUnit offsetFromLogicalTopOfRegion = region ? region->offsetFromLogicalTopOfFirstPage() - offsetFromLogicalTopOfFirstPage : ZERO_LAYOUT_UNIT;
1166 logicalTopPosition = max(logicalTopPosition, logicalTopPosition + offsetFromLogicalTopOfRegion);
1167 containingBlockRegion = cb->clampToStartAndEndRegions(region);
1170 LayoutUnit result = cb->availableLogicalWidthForLine(logicalTopPosition, false, containingBlockRegion, adjustedPageOffsetForContainingBlock) - childMarginStart - childMarginEnd;
1172 // We need to see if margins on either the start side or the end side can contain the floats in question. If they can,
1173 // then just using the line width is inaccurate. In the case where a float completely fits, we don't need to use the line
1174 // offset at all, but can instead push all the way to the content edge of the containing block. In the case where the float
1175 // 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
1176 // "consumed" by the float. Negative margins aren't consumed by the float, and so we ignore them.
1177 if (childMarginStart > 0) {
1178 LayoutUnit startContentSide = cb->startOffsetForContent(containingBlockRegion, adjustedPageOffsetForContainingBlock);
1179 LayoutUnit startContentSideWithMargin = startContentSide + childMarginStart;
1180 LayoutUnit startOffset = cb->startOffsetForLine(logicalTopPosition, false, containingBlockRegion, adjustedPageOffsetForContainingBlock);
1181 if (startOffset > startContentSideWithMargin)
1182 result += childMarginStart;
1184 result += startOffset - startContentSide;
1187 if (childMarginEnd > 0) {
1188 LayoutUnit endContentSide = cb->endOffsetForContent(containingBlockRegion, adjustedPageOffsetForContainingBlock);
1189 LayoutUnit endContentSideWithMargin = endContentSide + childMarginEnd;
1190 LayoutUnit endOffset = cb->endOffsetForLine(logicalTopPosition, false, containingBlockRegion, adjustedPageOffsetForContainingBlock);
1191 if (endOffset > endContentSideWithMargin)
1192 result += childMarginEnd;
1194 result += endOffset - endContentSide;
1200 LayoutUnit RenderBox::containingBlockLogicalWidthForContent() const
1202 RenderBlock* cb = containingBlock();
1203 return cb->availableLogicalWidth();
1206 LayoutUnit RenderBox::containingBlockLogicalWidthForContentInRegion(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
1209 return containingBlockLogicalWidthForContent();
1211 RenderBlock* cb = containingBlock();
1212 RenderRegion* containingBlockRegion = cb->clampToStartAndEndRegions(region);
1213 LayoutUnit result = cb->availableLogicalWidth();
1214 RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(containingBlockRegion, offsetFromLogicalTopOfFirstPage - logicalTop());
1217 return max<LayoutUnit>(0, result - (cb->logicalWidth() - boxInfo->logicalWidth()));
1220 LayoutUnit RenderBox::containingBlockAvailableLineWidthInRegion(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
1222 RenderBlock* cb = containingBlock();
1223 RenderRegion* containingBlockRegion = 0;
1224 LayoutUnit logicalTopPosition = logicalTop();
1225 LayoutUnit adjustedPageOffsetForContainingBlock = offsetFromLogicalTopOfFirstPage - logicalTop();
1227 LayoutUnit offsetFromLogicalTopOfRegion = region ? region->offsetFromLogicalTopOfFirstPage() - offsetFromLogicalTopOfFirstPage : ZERO_LAYOUT_UNIT;
1228 logicalTopPosition = max(logicalTopPosition, logicalTopPosition + offsetFromLogicalTopOfRegion);
1229 containingBlockRegion = cb->clampToStartAndEndRegions(region);
1231 return cb->availableLogicalWidthForLine(logicalTopPosition, false, containingBlockRegion, adjustedPageOffsetForContainingBlock, availableLogicalHeight());
1234 LayoutUnit RenderBox::perpendicularContainingBlockLogicalHeight() const
1236 RenderBlock* cb = containingBlock();
1237 if (cb->hasOverrideHeight())
1238 return cb->overrideLogicalContentHeight();
1240 RenderStyle* containingBlockStyle = cb->style();
1241 Length logicalHeightLength = containingBlockStyle->logicalHeight();
1243 // FIXME: For now just support fixed heights. Eventually should support percentage heights as well.
1244 if (!logicalHeightLength.isFixed()) {
1245 // Rather than making the child be completely unconstrained, WinIE uses the viewport width and height
1246 // as a constraint. We do that for now as well even though it's likely being unconstrained is what the spec
1248 return containingBlockStyle->isHorizontalWritingMode() ? view()->frameView()->visibleHeight() : view()->frameView()->visibleWidth();
1251 // Use the content box logical height as specified by the style.
1252 return cb->computeContentBoxLogicalHeight(logicalHeightLength.value());
1255 void RenderBox::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState, ApplyContainerFlipOrNot, bool* wasFixed) const
1257 if (repaintContainer == this)
1260 if (RenderView* v = view()) {
1261 if (v->layoutStateEnabled() && !repaintContainer) {
1262 LayoutState* layoutState = v->layoutState();
1263 LayoutSize offset = layoutState->m_paintOffset + locationOffset();
1264 if (style()->position() == RelativePosition && layer())
1265 offset += layer()->relativePositionOffset();
1266 transformState.move(offset);
1271 bool containerSkipped;
1272 RenderObject* o = container(repaintContainer, &containerSkipped);
1276 bool isFixedPos = style()->position() == FixedPosition;
1277 bool hasTransform = hasLayer() && layer()->transform();
1278 // If this box has a transform, it acts as a fixed position container for fixed descendants,
1279 // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
1280 if (hasTransform && !isFixedPos)
1282 else if (isFixedPos)
1288 LayoutSize containerOffset = offsetFromContainer(o, roundedLayoutPoint(transformState.mappedPoint()));
1290 bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
1291 if (useTransforms && shouldUseTransformFromContainer(o)) {
1292 TransformationMatrix t;
1293 getTransformFromContainer(o, containerOffset, t);
1294 transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1296 transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1298 if (containerSkipped) {
1299 // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
1300 // to just subtract the delta between the repaintContainer and o.
1301 LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
1302 transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1306 if (o->isRenderFlowThread()) {
1307 // Transform from render flow coordinates into region coordinates.
1308 RenderRegion* region = toRenderFlowThread(o)->mapFromFlowToRegion(transformState);
1310 region->mapLocalToContainer(region->containerForRepaint(), fixed, useTransforms, transformState, DoNotApplyContainerFlip, wasFixed);
1314 o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState, DoNotApplyContainerFlip, wasFixed);
1317 const RenderObject* RenderBox::pushMappingToContainer(const RenderBoxModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const
1319 ASSERT(ancestorToStopAt != this);
1321 bool ancestorSkipped;
1322 RenderObject* container = this->container(ancestorToStopAt, &ancestorSkipped);
1326 bool isFixedPos = style()->position() == FixedPosition;
1327 bool hasTransform = hasLayer() && layer()->transform();
1329 LayoutSize adjustmentForSkippedAncestor;
1330 if (ancestorSkipped) {
1331 // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
1332 // to just subtract the delta between the ancestor and o.
1333 adjustmentForSkippedAncestor = -ancestorToStopAt->offsetFromAncestorContainer(container);
1336 bool offsetDependsOnPoint = false;
1337 LayoutSize containerOffset = offsetFromContainer(container, LayoutPoint(), &offsetDependsOnPoint);
1339 if (container->isRenderFlowThread())
1340 offsetDependsOnPoint = true;
1342 bool preserve3D = container->style()->preserves3D() || style()->preserves3D();
1343 if (shouldUseTransformFromContainer(container)) {
1344 TransformationMatrix t;
1345 getTransformFromContainer(container, containerOffset, t);
1346 t.translateRight(adjustmentForSkippedAncestor.width(), adjustmentForSkippedAncestor.height());
1348 geometryMap.push(this, t, preserve3D, offsetDependsOnPoint, isFixedPos, hasTransform);
1350 containerOffset += adjustmentForSkippedAncestor;
1351 geometryMap.push(this, containerOffset, preserve3D, offsetDependsOnPoint, isFixedPos, hasTransform);
1354 return ancestorSkipped ? ancestorToStopAt : container;
1357 void RenderBox::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState& transformState) const
1359 // We don't expect absoluteToLocal() to be called during layout (yet)
1360 ASSERT(!view() || !view()->layoutStateEnabled());
1362 bool isFixedPos = style()->position() == FixedPosition;
1363 bool hasTransform = hasLayer() && layer()->transform();
1365 // If this box has a transform, it acts as a fixed position container for fixed descendants,
1366 // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
1367 fixed &= isFixedPos;
1369 fixed |= isFixedPos;
1371 RenderBoxModelObject::mapAbsoluteToLocalPoint(fixed, useTransforms, transformState);
1374 LayoutSize RenderBox::offsetFromContainer(RenderObject* o, const LayoutPoint& point, bool* offsetDependsOnPoint) const
1376 ASSERT(o == container());
1379 if (isRelPositioned())
1380 offset += relativePositionOffset();
1382 if (!isInline() || isReplaced()) {
1383 if (!style()->isOutOfFlowPositioned() && o->hasColumns()) {
1384 RenderBlock* block = toRenderBlock(o);
1385 LayoutRect columnRect(frameRect());
1386 block->adjustStartEdgeForWritingModeIncludingColumns(columnRect);
1387 offset += toSize(columnRect.location());
1388 LayoutPoint columnPoint = block->flipForWritingModeIncludingColumns(point + offset);
1389 offset = toLayoutSize(block->flipForWritingModeIncludingColumns(toLayoutPoint(offset)));
1390 o->adjustForColumns(offset, columnPoint);
1391 offset = block->flipForWritingMode(offset);
1393 if (offsetDependsOnPoint)
1394 *offsetDependsOnPoint = true;
1396 offset += topLeftLocationOffset();
1399 if (o->hasOverflowClip())
1400 offset -= toRenderBox(o)->scrolledContentOffset();
1402 if (style()->position() == AbsolutePosition && o->isRelPositioned() && o->isRenderInline())
1403 offset += toRenderInline(o)->relativePositionedInlineOffset(this);
1408 InlineBox* RenderBox::createInlineBox()
1410 return new (renderArena()) InlineBox(this);
1413 void RenderBox::dirtyLineBoxes(bool fullLayout)
1415 if (m_inlineBoxWrapper) {
1417 m_inlineBoxWrapper->destroy(renderArena());
1418 m_inlineBoxWrapper = 0;
1420 m_inlineBoxWrapper->dirtyLineBoxes();
1424 void RenderBox::positionLineBox(InlineBox* box)
1426 if (isOutOfFlowPositioned()) {
1427 // Cache the x position only if we were an INLINE type originally.
1428 bool wasInline = style()->isOriginalDisplayInlineType();
1430 // The value is cached in the xPos of the box. We only need this value if
1431 // our object was inline originally, since otherwise it would have ended up underneath
1433 RootInlineBox* root = box->root();
1434 root->block()->setStaticInlinePositionForChild(this, root->lineTopWithLeading(), roundedLayoutUnit(box->logicalLeft()));
1435 if (style()->hasStaticInlinePosition(box->isHorizontal()))
1436 setChildNeedsLayout(true, MarkOnlyThis); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
1438 // Our object was a block originally, so we make our normal flow position be
1439 // just below the line box (as though all the inlines that came before us got
1440 // wrapped in an anonymous block, which is what would have happened had we been
1441 // in flow). This value was cached in the y() of the box.
1442 layer()->setStaticBlockPosition(box->logicalTop());
1443 if (style()->hasStaticBlockPosition(box->isHorizontal()))
1444 setChildNeedsLayout(true, MarkOnlyThis); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
1449 box->destroy(renderArena());
1450 } else if (isReplaced()) {
1451 setLocation(roundedLayoutPoint(box->topLeft()));
1452 // m_inlineBoxWrapper should already be 0. Deleting it is a safeguard against security issues.
1453 ASSERT(!m_inlineBoxWrapper);
1454 if (m_inlineBoxWrapper)
1455 deleteLineBoxWrapper();
1456 m_inlineBoxWrapper = box;
1460 void RenderBox::deleteLineBoxWrapper()
1462 if (m_inlineBoxWrapper) {
1463 if (!documentBeingDestroyed())
1464 m_inlineBoxWrapper->remove();
1465 m_inlineBoxWrapper->destroy(renderArena());
1466 m_inlineBoxWrapper = 0;
1470 LayoutRect RenderBox::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) const
1472 if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent())
1473 return LayoutRect();
1475 LayoutRect r = visualOverflowRect();
1477 RenderView* v = view();
1479 // FIXME: layoutDelta needs to be applied in parts before/after transforms and
1480 // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
1481 r.move(v->layoutDelta());
1485 // We have to use maximalOutlineSize() because a child might have an outline
1486 // that projects outside of our overflowRect.
1488 ASSERT(style()->outlineSize() <= v->maximalOutlineSize());
1489 r.inflate(v->maximalOutlineSize());
1493 computeRectForRepaint(repaintContainer, r);
1497 void RenderBox::computeRectForRepaint(RenderBoxModelObject* repaintContainer, LayoutRect& rect, bool fixed) const
1499 // The rect we compute at each step is shifted by our x/y offset in the parent container's coordinate space.
1500 // Only when we cross a writing mode boundary will we have to possibly flipForWritingMode (to convert into a more appropriate
1501 // offset corner for the enclosing container). This allows for a fully RL or BT document to repaint
1502 // properly even during layout, since the rect remains flipped all the way until the end.
1504 // RenderView::computeRectForRepaint then converts the rect to physical coordinates. We also convert to
1505 // physical when we hit a repaintContainer boundary. Therefore the final rect returned is always in the
1506 // physical coordinate space of the repaintContainer.
1507 RenderStyle* styleToUse = style();
1508 if (RenderView* v = view()) {
1509 // LayoutState is only valid for root-relative, non-fixed position repainting
1510 if (v->layoutStateEnabled() && !repaintContainer && styleToUse->position() != FixedPosition) {
1511 LayoutState* layoutState = v->layoutState();
1513 if (layer() && layer()->transform())
1514 rect = layer()->transform()->mapRect(rect);
1516 if (styleToUse->position() == RelativePosition && layer())
1517 rect.move(layer()->relativePositionOffset());
1519 rect.moveBy(location());
1520 rect.move(layoutState->m_paintOffset);
1521 if (layoutState->m_clipped)
1522 rect.intersect(layoutState->m_clipRect);
1527 if (hasReflection())
1528 rect.unite(reflectedRect(rect));
1530 if (repaintContainer == this) {
1531 if (repaintContainer->style()->isFlippedBlocksWritingMode())
1532 flipForWritingMode(rect);
1536 bool containerSkipped;
1537 RenderObject* o = container(repaintContainer, &containerSkipped);
1541 if (isWritingModeRoot() && !isOutOfFlowPositioned())
1542 flipForWritingMode(rect);
1544 LayoutPoint topLeft = rect.location();
1545 topLeft.move(locationOffset());
1547 EPosition position = styleToUse->position();
1549 // We are now in our parent container's coordinate space. Apply our transform to obtain a bounding box
1550 // in the parent's coordinate space that encloses us.
1551 if (layer() && layer()->transform()) {
1552 fixed = position == FixedPosition;
1553 rect = layer()->transform()->mapRect(rect);
1554 topLeft = rect.location();
1555 topLeft.move(locationOffset());
1556 } else if (position == FixedPosition)
1559 if (position == AbsolutePosition && o->isRelPositioned() && o->isRenderInline())
1560 topLeft += toRenderInline(o)->relativePositionedInlineOffset(this);
1561 else if (position == RelativePosition && layer()) {
1562 // Apply the relative position offset when invalidating a rectangle. The layer
1563 // is translated, but the render box isn't, so we need to do this to get the
1564 // right dirty rect. Since this is called from RenderObject::setStyle, the relative position
1565 // flag on the RenderObject has been cleared, so use the one on the style().
1566 topLeft += layer()->relativePositionOffset();
1569 if (o->isBlockFlow() && position != AbsolutePosition && position != FixedPosition) {
1570 RenderBlock* cb = toRenderBlock(o);
1571 if (cb->hasColumns()) {
1572 LayoutRect repaintRect(topLeft, rect.size());
1573 cb->adjustRectForColumns(repaintRect);
1574 topLeft = repaintRect.location();
1579 // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
1580 // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
1581 if (o->hasOverflowClip()) {
1582 RenderBox* containerBox = toRenderBox(o);
1584 // o->height() is inaccurate if we're in the middle of a layout of |o|, so use the
1585 // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint
1586 // anyway if its size does change.
1587 topLeft -= containerBox->scrolledContentOffset(); // For overflow:auto/scroll/hidden.
1589 #if ENABLE(TIZEN_CSS_OVERFLOW_SCROLL_ACCELERATION)
1590 if (containerBox->hasOverflowClip() && !containerBox->layer()->hasAcceleratedTouchScrolling()) {
1592 LayoutRect repaintRect(topLeft, rect.size());
1593 LayoutRect boxRect(LayoutPoint(), containerBox->cachedSizeForOverflowClip());
1594 rect = intersection(repaintRect, boxRect);
1597 #if ENABLE(TIZEN_CSS_OVERFLOW_SCROLL_ACCELERATION)
1599 rect.setLocation(topLeft);
1602 rect.setLocation(topLeft);
1604 if (containerSkipped) {
1605 // If the repaintContainer is below o, then we need to map the rect into repaintContainer's coordinates.
1606 LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
1607 rect.move(-containerOffset);
1611 o->computeRectForRepaint(repaintContainer, rect, fixed);
1614 void RenderBox::repaintDuringLayoutIfMoved(const LayoutRect& oldRect)
1616 if (oldRect.location() != m_frameRect.location()) {
1617 LayoutRect newRect = m_frameRect;
1618 // The child moved. Invalidate the object's old and new positions. We have to do this
1619 // since the object may not have gotten a layout.
1620 m_frameRect = oldRect;
1622 repaintOverhangingFloats(true);
1623 m_frameRect = newRect;
1625 repaintOverhangingFloats(true);
1629 void RenderBox::computeLogicalWidth()
1631 computeLogicalWidthInRegion();
1634 void RenderBox::computeLogicalWidthInRegion(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage)
1636 if (isOutOfFlowPositioned()) {
1637 // FIXME: This calculation is not patched for block-flow yet.
1638 // https://bugs.webkit.org/show_bug.cgi?id=46500
1639 computePositionedLogicalWidth(region, offsetFromLogicalTopOfFirstPage);
1643 // If layout is limited to a subtree, the subtree root's logical width does not change.
1644 if (node() && view()->frameView() && view()->frameView()->layoutRoot(true) == this)
1647 // The parent box is flexing us, so it has increased or decreased our
1648 // width. Use the width from the style context.
1649 // FIXME: Account for block-flow in flexible boxes.
1650 // https://bugs.webkit.org/show_bug.cgi?id=46418
1651 if (hasOverrideWidth() && parent()->isFlexibleBoxIncludingDeprecated()) {
1652 setLogicalWidth(overrideLogicalContentWidth() + borderAndPaddingLogicalWidth());
1656 // FIXME: Account for block-flow in flexible boxes.
1657 // https://bugs.webkit.org/show_bug.cgi?id=46418
1658 bool inVerticalBox = parent()->isDeprecatedFlexibleBox() && (parent()->style()->boxOrient() == VERTICAL);
1659 bool stretching = (parent()->style()->boxAlign() == BSTRETCH);
1660 bool treatAsReplaced = shouldComputeSizeAsReplaced() && (!inVerticalBox || !stretching);
1662 RenderStyle* styleToUse = style();
1663 Length logicalWidthLength = (treatAsReplaced) ? Length(computeReplacedLogicalWidth(), Fixed) : styleToUse->logicalWidth();
1665 RenderBlock* cb = containingBlock();
1666 LayoutUnit containerLogicalWidth = max<LayoutUnit>(0, containingBlockLogicalWidthForContentInRegion(region, offsetFromLogicalTopOfFirstPage));
1667 bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHorizontalWritingMode();
1668 LayoutUnit containerWidthInInlineDirection = containerLogicalWidth;
1669 if (hasPerpendicularContainingBlock)
1670 containerWidthInInlineDirection = perpendicularContainingBlockLogicalHeight();
1672 if (isInline() && !isInlineBlockOrInlineTable()) {
1673 // just calculate margins
1674 RenderView* renderView = view();
1675 setMarginStart(minimumValueForLength(styleToUse->marginStart(), containerLogicalWidth, renderView));
1676 setMarginEnd(minimumValueForLength(styleToUse->marginEnd(), containerLogicalWidth, renderView));
1677 if (treatAsReplaced)
1678 setLogicalWidth(max<LayoutUnit>(floatValueForLength(logicalWidthLength, 0) + borderAndPaddingLogicalWidth(), minPreferredLogicalWidth()));
1682 // Width calculations
1683 if (treatAsReplaced)
1684 setLogicalWidth(logicalWidthLength.value() + borderAndPaddingLogicalWidth());
1686 // Calculate LogicalWidth
1687 setLogicalWidth(computeLogicalWidthInRegionUsing(MainOrPreferredSize, containerWidthInInlineDirection, cb, region, offsetFromLogicalTopOfFirstPage));
1689 // Calculate MaxLogicalWidth
1690 if (!styleToUse->logicalMaxWidth().isUndefined()) {
1691 LayoutUnit maxLogicalWidth = computeLogicalWidthInRegionUsing(MaxSize, containerWidthInInlineDirection, cb, region, offsetFromLogicalTopOfFirstPage);
1692 if (logicalWidth() > maxLogicalWidth)
1693 setLogicalWidth(maxLogicalWidth);
1696 // Calculate MinLogicalWidth
1697 LayoutUnit minLogicalWidth = computeLogicalWidthInRegionUsing(MinSize, containerWidthInInlineDirection, cb, region, offsetFromLogicalTopOfFirstPage);
1698 if (logicalWidth() < minLogicalWidth)
1699 setLogicalWidth(minLogicalWidth);
1702 // Fieldsets are currently the only objects that stretch to their minimum width.
1703 if (stretchesToMinIntrinsicLogicalWidth())
1704 setLogicalWidth(max(logicalWidth(), minPreferredLogicalWidth()));
1706 // Margin calculations.
1707 if (hasPerpendicularContainingBlock || isFloating() || isInline()) {
1708 RenderView* renderView = view();
1709 setMarginStart(minimumValueForLength(styleToUse->marginStart(), containerLogicalWidth, renderView));
1710 setMarginEnd(minimumValueForLength(styleToUse->marginEnd(), containerLogicalWidth, renderView));
1712 LayoutUnit containerLogicalWidthForAutoMargins = containerLogicalWidth;
1713 if (avoidsFloats() && cb->containsFloats())
1714 containerLogicalWidthForAutoMargins = containingBlockAvailableLineWidthInRegion(region, offsetFromLogicalTopOfFirstPage);
1715 computeInlineDirectionMargins(cb, containerLogicalWidthForAutoMargins, logicalWidth());
1718 if (!hasPerpendicularContainingBlock && containerLogicalWidth && containerLogicalWidth != (logicalWidth() + marginStart() + marginEnd())
1719 && !isFloating() && !isInline() && !cb->isFlexibleBoxIncludingDeprecated())
1720 cb->setMarginEndForChild(this, containerLogicalWidth - logicalWidth() - cb->marginStartForChild(this));
1723 LayoutUnit RenderBox::computeLogicalWidthInRegionUsing(SizeType widthType, LayoutUnit availableLogicalWidth,
1724 const RenderBlock* cb, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage)
1726 RenderStyle* styleToUse = style();
1727 Length logicalWidth;
1728 if (widthType == MainOrPreferredSize)
1729 logicalWidth = styleToUse->logicalWidth();
1730 else if (widthType == MinSize)
1731 logicalWidth = styleToUse->logicalMinWidth();
1733 logicalWidth = styleToUse->logicalMaxWidth();
1735 ASSERT(!logicalWidth.isUndefined());
1737 if (widthType == MinSize && logicalWidth.isAuto())
1738 return computeBorderBoxLogicalWidth(0);
1740 if (!logicalWidth.isIntrinsicOrAuto()) {
1741 // FIXME: If the containing block flow is perpendicular to our direction we need to use the available logical height instead.
1742 return computeBorderBoxLogicalWidth(valueForLength(logicalWidth, availableLogicalWidth, view()));
1745 if (logicalWidth.type() == MinContent)
1746 return minPreferredLogicalWidth();
1747 if (logicalWidth.type() == MaxContent)
1748 return maxPreferredLogicalWidth();
1750 RenderView* renderView = view();
1751 LayoutUnit marginStart = minimumValueForLength(styleToUse->marginStart(), availableLogicalWidth, renderView);
1752 LayoutUnit marginEnd = minimumValueForLength(styleToUse->marginEnd(), availableLogicalWidth, renderView);
1753 LayoutUnit logicalWidthResult = availableLogicalWidth - marginStart - marginEnd;
1755 // shrinkToAvoidFloats() is only true for width: auto so the below code works correctly for
1756 // width: fill-available since no case matches and it returns the logicalWidthResult from above.
1757 if (shrinkToAvoidFloats() && cb->containsFloats())
1758 logicalWidthResult = min(logicalWidthResult, shrinkLogicalWidthToAvoidFloats(marginStart, marginEnd, cb, region, offsetFromLogicalTopOfFirstPage));
1760 #if ENABLE(TIZEN_ELEMENTS_NESTED_IN_FLATTENED_FRAME_FIX)
1761 if (!logicalWidth.isIntrinsicOrAuto()) {
1762 RenderBlock* cb = containingBlock();
1763 if (cb && cb->view() && cb->view()->frameView() && cb->view()->frameView()->inFlattenFrame() && logicalWidth.isPercent() && (logicalWidthResult > availableLogicalWidth))
1764 logicalWidthResult = availableLogicalWidth;
1768 if (logicalWidth.type() == FitContent || (logicalWidth.type() != FillAvailable && sizesLogicalWidthToFitContent(widthType)))
1769 return max(minPreferredLogicalWidth(), min(maxPreferredLogicalWidth(), logicalWidthResult));
1770 return logicalWidthResult;
1773 bool RenderBox::sizesLogicalWidthToFitContent(SizeType widthType) const
1775 // Marquees in WinIE are like a mixture of blocks and inline-blocks. They size as though they're blocks,
1776 // but they allow text to sit on the same line as the marquee.
1777 if (isFloating() || (isInlineBlockOrInlineTable() && !isHTMLMarquee()))
1780 // This code may look a bit strange. Basically width:intrinsic should clamp the size when testing both
1781 // min-width and width. max-width is only clamped if it is also intrinsic.
1782 Length logicalWidth = (widthType == MaxSize) ? style()->logicalMaxWidth() : style()->logicalWidth();
1783 if (logicalWidth.type() == Intrinsic)
1786 // Children of a horizontal marquee do not fill the container by default.
1787 // FIXME: Need to deal with MAUTO value properly. It could be vertical.
1788 // FIXME: Think about block-flow here. Need to find out how marquee direction relates to
1789 // block-flow (as well as how marquee overflow should relate to block flow).
1790 // https://bugs.webkit.org/show_bug.cgi?id=46472
1791 if (parent()->style()->overflowX() == OMARQUEE) {
1792 EMarqueeDirection dir = parent()->style()->marqueeDirection();
1793 if (dir == MAUTO || dir == MFORWARD || dir == MBACKWARD || dir == MLEFT || dir == MRIGHT)
1797 // Flexible box items should shrink wrap, so we lay them out at their intrinsic widths.
1798 // In the case of columns that have a stretch alignment, we go ahead and layout at the
1799 // stretched size to avoid an extra layout when applying alignment.
1800 if (parent()->isFlexibleBox()) {
1801 // For multiline columns, we need to apply align-content first, so we can't stretch now.
1802 if (!parent()->style()->isColumnFlexDirection() || parent()->style()->flexWrap() != FlexNoWrap)
1804 EAlignItems itemAlign = style()->alignSelf();
1805 if (itemAlign != AlignStretch && (itemAlign != AlignAuto || parent()->style()->alignItems() != AlignStretch))
1809 // Flexible horizontal boxes lay out children at their intrinsic widths. Also vertical boxes
1810 // that don't stretch their kids lay out their children at their intrinsic widths.
1811 // FIXME: Think about block-flow here.
1812 // https://bugs.webkit.org/show_bug.cgi?id=46473
1813 if (parent()->isDeprecatedFlexibleBox()
1814 && (parent()->style()->boxOrient() == HORIZONTAL || parent()->style()->boxAlign() != BSTRETCH))
1817 // Button, input, select, textarea, and legend treat
1818 // width value of 'auto' as 'intrinsic' unless it's in a
1819 // stretching vertical flexbox.
1820 // FIXME: Think about block-flow here.
1821 // https://bugs.webkit.org/show_bug.cgi?id=46473
1822 if (logicalWidth.type() == Auto && !(parent()->isDeprecatedFlexibleBox() && parent()->style()->boxOrient() == VERTICAL && parent()->style()->boxAlign() == BSTRETCH) && node() && (node()->hasTagName(inputTag) || node()->hasTagName(selectTag) || node()->hasTagName(buttonTag) || node()->hasTagName(textareaTag) || node()->hasTagName(legendTag)))
1825 if (isHorizontalWritingMode() != containingBlock()->isHorizontalWritingMode())
1831 void RenderBox::computeInlineDirectionMargins(RenderBlock* containingBlock, LayoutUnit containerWidth, LayoutUnit childWidth)
1833 const RenderStyle* containingBlockStyle = containingBlock->style();
1834 Length marginStartLength = style()->marginStartUsing(containingBlockStyle);
1835 Length marginEndLength = style()->marginEndUsing(containingBlockStyle);
1836 RenderView* renderView = view();
1838 if (isFloating() || isInline()) {
1839 // Inline blocks/tables and floats don't have their margins increased.
1840 containingBlock->setMarginStartForChild(this, minimumValueForLength(marginStartLength, containerWidth, renderView));
1841 containingBlock->setMarginEndForChild(this, minimumValueForLength(marginEndLength, containerWidth, renderView));
1845 // Case One: The object is being centered in the containing block's available logical width.
1846 if ((marginStartLength.isAuto() && marginEndLength.isAuto() && childWidth < containerWidth)
1847 || (!marginStartLength.isAuto() && !marginEndLength.isAuto() && containingBlock->style()->textAlign() == WEBKIT_CENTER)) {
1848 // Other browsers center the margin box for align=center elements so we match them here.
1849 LayoutUnit marginStartWidth = minimumValueForLength(marginStartLength, containerWidth, renderView);
1850 LayoutUnit marginEndWidth = minimumValueForLength(marginEndLength, containerWidth, renderView);
1851 LayoutUnit centeredMarginBoxStart = max<LayoutUnit>(0, (containerWidth - childWidth - marginStartWidth - marginEndWidth) / 2);
1852 containingBlock->setMarginStartForChild(this, centeredMarginBoxStart + marginStartWidth);
1853 containingBlock->setMarginEndForChild(this, containerWidth - childWidth - containingBlock->marginStartForChild(this) + marginEndWidth);
1857 // Case Two: The object is being pushed to the start of the containing block's available logical width.
1858 if (marginEndLength.isAuto() && childWidth < containerWidth) {
1859 containingBlock->setMarginStartForChild(this, valueForLength(marginStartLength, containerWidth, renderView));
1860 containingBlock->setMarginEndForChild(this, containerWidth - childWidth - containingBlock->marginStartForChild(this));
1864 // Case Three: The object is being pushed to the end of the containing block's available logical width.
1865 bool pushToEndFromTextAlign = !marginEndLength.isAuto() && ((!containingBlockStyle->isLeftToRightDirection() && containingBlockStyle->textAlign() == WEBKIT_LEFT)
1866 || (containingBlockStyle->isLeftToRightDirection() && containingBlockStyle->textAlign() == WEBKIT_RIGHT));
1867 if ((marginStartLength.isAuto() && childWidth < containerWidth) || pushToEndFromTextAlign) {
1868 containingBlock->setMarginEndForChild(this, valueForLength(marginEndLength, containerWidth, renderView));
1869 containingBlock->setMarginStartForChild(this, containerWidth - childWidth - containingBlock->marginEndForChild(this));
1873 // Case Four: Either no auto margins, or our width is >= the container width (css2.1, 10.3.3). In that case
1874 // auto margins will just turn into 0.
1875 containingBlock->setMarginStartForChild(this, minimumValueForLength(marginStartLength, containerWidth, renderView));
1876 containingBlock->setMarginEndForChild(this, minimumValueForLength(marginEndLength, containerWidth, renderView));
1879 RenderBoxRegionInfo* RenderBox::renderBoxRegionInfo(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage, RenderBoxRegionInfoFlags cacheFlag) const
1881 // Make sure nobody is trying to call this with a null region.
1885 // If we have computed our width in this region already, it will be cached, and we can
1887 RenderBoxRegionInfo* boxInfo = region->renderBoxRegionInfo(this);
1888 if (boxInfo && cacheFlag == CacheRenderBoxRegionInfo)
1891 // No cached value was found, so we have to compute our insets in this region.
1892 // FIXME: For now we limit this computation to normal RenderBlocks. Future patches will expand
1893 // support to cover all boxes.
1894 if (!inRenderFlowThread() || isFloating() || isReplaced() || isInline() || hasColumns()
1895 || isTableCell() || !isBlockFlow() || isRenderFlowThread())
1898 // FIXME: It's gross to cast away the const, but it would be a huge refactoring to
1899 // change all width computation to avoid updating any member variables, and it would be pretty lame to
1900 // make all the variables mutable as well.
1901 RenderFlowThread* flowThread = enclosingRenderFlowThread();
1902 if (flowThread->style()->writingMode() != style()->writingMode())
1905 LayoutUnit oldLogicalWidth = logicalWidth();
1906 LayoutUnit oldLogicalLeft = logicalLeft();
1907 LayoutUnit oldMarginStart = marginStart();
1908 LayoutUnit oldMarginEnd = marginEnd();
1910 RenderBox* mutableBox = const_cast<RenderBox*>(this);
1912 mutableBox->computeLogicalWidthInRegion(region, offsetFromLogicalTopOfFirstPage);
1914 // Now determine the insets based off where this object is supposed to be positioned.
1915 RenderBlock* cb = containingBlock();
1916 RenderRegion* clampedContainingBlockRegion = cb->clampToStartAndEndRegions(region);
1917 RenderBoxRegionInfo* containingBlockInfo = cb->renderBoxRegionInfo(clampedContainingBlockRegion,
1918 offsetFromLogicalTopOfFirstPage - logicalTop());
1919 LayoutUnit containingBlockLogicalWidth = cb->logicalWidth();
1920 LayoutUnit containingBlockLogicalWidthInRegion = containingBlockInfo ? containingBlockInfo->logicalWidth() : containingBlockLogicalWidth;
1922 LayoutUnit marginStartInRegion = marginStart();
1923 LayoutUnit startMarginDelta = marginStartInRegion - oldMarginStart;
1924 LayoutUnit logicalWidthInRegion = logicalWidth();
1925 LayoutUnit logicalLeftInRegion = logicalLeft();
1926 LayoutUnit widthDelta = logicalWidthInRegion - oldLogicalWidth;
1927 LayoutUnit logicalLeftDelta = isOutOfFlowPositioned() ? logicalLeftInRegion - oldLogicalLeft : startMarginDelta;
1928 LayoutUnit logicalRightInRegion = containingBlockLogicalWidthInRegion - (logicalLeftInRegion + logicalWidthInRegion);
1929 LayoutUnit oldLogicalRight = containingBlockLogicalWidth - (oldLogicalLeft + oldLogicalWidth);
1930 LayoutUnit logicalRightDelta = isOutOfFlowPositioned() ? logicalRightInRegion - oldLogicalRight : startMarginDelta;
1932 // Set our values back.
1933 mutableBox->setLogicalWidth(oldLogicalWidth);
1934 mutableBox->setLogicalLeft(oldLogicalLeft);
1935 mutableBox->setMarginStart(oldMarginStart);
1936 mutableBox->setMarginEnd(oldMarginEnd);
1938 LayoutUnit logicalLeftOffset = 0;
1940 if (!isOutOfFlowPositioned() && avoidsFloats() && cb->containsFloats()) {
1941 LayoutUnit startPositionDelta = cb->computeStartPositionDeltaForChildAvoidingFloats(this, marginStartInRegion, region, offsetFromLogicalTopOfFirstPage);
1942 if (cb->style()->isLeftToRightDirection())
1943 logicalLeftDelta += startPositionDelta;
1945 logicalRightDelta += startPositionDelta;
1948 if (cb->style()->isLeftToRightDirection())
1949 logicalLeftOffset += logicalLeftDelta;
1951 logicalLeftOffset -= (widthDelta + logicalRightDelta);
1953 LayoutUnit logicalRightOffset = logicalWidth() - (logicalLeftOffset + logicalWidthInRegion);
1954 bool isShifted = (containingBlockInfo && containingBlockInfo->isShifted())
1955 || (style()->isLeftToRightDirection() && logicalLeftOffset)
1956 || (!style()->isLeftToRightDirection() && logicalRightOffset);
1958 // FIXME: Although it's unlikely, these boxes can go outside our bounds, and so we will need to incorporate them into overflow.
1959 if (cacheFlag == CacheRenderBoxRegionInfo)
1960 return region->setRenderBoxRegionInfo(this, logicalLeftOffset, logicalWidthInRegion, isShifted);
1961 return new RenderBoxRegionInfo(logicalLeftOffset, logicalWidthInRegion, isShifted);
1964 void RenderBox::computeLogicalHeight()
1966 // Cell height is managed by the table and inline non-replaced elements do not support a height property.
1967 if (isTableCell() || (isInline() && !isReplaced()))
1971 if (isOutOfFlowPositioned())
1972 computePositionedLogicalHeight();
1974 RenderBlock* cb = containingBlock();
1975 bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHorizontalWritingMode();
1977 if (!hasPerpendicularContainingBlock)
1978 computeBlockDirectionMargins(cb);
1980 // For tables, calculate margins only.
1982 if (hasPerpendicularContainingBlock)
1983 computeInlineDirectionMargins(cb, containingBlockLogicalWidthForContent(), logicalHeight());
1987 // FIXME: Account for block-flow in flexible boxes.
1988 // https://bugs.webkit.org/show_bug.cgi?id=46418
1989 bool inHorizontalBox = parent()->isDeprecatedFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL;
1990 bool stretching = parent()->style()->boxAlign() == BSTRETCH;
1991 bool treatAsReplaced = shouldComputeSizeAsReplaced() && (!inHorizontalBox || !stretching);
1992 bool checkMinMaxHeight = false;
1994 // The parent box is flexing us, so it has increased or decreased our height. We have to
1995 // grab our cached flexible height.
1996 // FIXME: Account for block-flow in flexible boxes.
1997 // https://bugs.webkit.org/show_bug.cgi?id=46418
1998 RenderStyle* styleToUse = style();
1999 if (hasOverrideHeight() && parent()->isFlexibleBoxIncludingDeprecated())
2000 h = Length(overrideLogicalContentHeight(), Fixed);
2001 else if (treatAsReplaced)
2002 h = Length(computeReplacedLogicalHeight(), Fixed);
2004 h = styleToUse->logicalHeight();
2005 checkMinMaxHeight = true;
2008 // Block children of horizontal flexible boxes fill the height of the box.
2009 // FIXME: Account for block-flow in flexible boxes.
2010 // https://bugs.webkit.org/show_bug.cgi?id=46418
2011 if (h.isAuto() && parent()->isDeprecatedFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
2012 && parent()->isStretchingChildren()) {
2013 h = Length(parentBox()->contentLogicalHeight() - marginBefore() - marginAfter() - borderAndPaddingLogicalHeight(), Fixed);
2014 checkMinMaxHeight = false;
2017 LayoutUnit heightResult;
2018 if (checkMinMaxHeight) {
2019 heightResult = computeLogicalHeightUsing(MainOrPreferredSize, styleToUse->logicalHeight());
2020 if (heightResult == -1)
2021 heightResult = logicalHeight();
2022 LayoutUnit minH = computeLogicalHeightUsing(MinSize, styleToUse->logicalMinHeight()); // Leave as -1 if unset.
2023 LayoutUnit maxH = styleToUse->logicalMaxHeight().isUndefined() ? heightResult : computeLogicalHeightUsing(MaxSize, styleToUse->logicalMaxHeight());
2025 maxH = heightResult;
2026 heightResult = min(maxH, heightResult);
2027 heightResult = max(minH, heightResult);
2029 // The only times we don't check min/max height are when a fixed length has
2030 // been given as an override. Just use that. The value has already been adjusted
2032 heightResult = h.value() + borderAndPaddingLogicalHeight();
2035 setLogicalHeight(heightResult);
2037 if (hasPerpendicularContainingBlock)
2038 computeInlineDirectionMargins(cb, containingBlockLogicalWidthForContent(), heightResult);
2041 // WinIE quirk: The <html> block always fills the entire canvas in quirks mode. The <body> always fills the
2042 // <html> block in quirks mode. Only apply this quirk if the block is normal flow and no height
2043 // is specified. When we're printing, we also need this quirk if the body or root has a percentage
2044 // height since we don't set a height in RenderView when we're printing. So without this quirk, the
2045 // height has nothing to be a percentage of, and it ends up being 0. That is bad.
2046 bool paginatedContentNeedsBaseHeight = document()->printing() && h.isPercent()
2047 && (isRoot() || (isBody() && document()->documentElement()->renderer()->style()->logicalHeight().isPercent()));
2048 if (stretchesToViewport() || paginatedContentNeedsBaseHeight) {
2049 // FIXME: Finish accounting for block flow here.
2050 // https://bugs.webkit.org/show_bug.cgi?id=46603
2051 LayoutUnit margins = collapsedMarginBefore() + collapsedMarginAfter();
2052 LayoutUnit visHeight;
2053 if (document()->printing())
2054 visHeight = static_cast<LayoutUnit>(view()->pageLogicalHeight());
2056 if (isHorizontalWritingMode())
2057 visHeight = view()->viewHeight();
2059 visHeight = view()->viewWidth();
2062 setLogicalHeight(max(logicalHeight(), visHeight - margins));
2064 LayoutUnit marginsBordersPadding = margins + parentBox()->marginBefore() + parentBox()->marginAfter() + parentBox()->borderAndPaddingLogicalHeight();
2065 setLogicalHeight(max(logicalHeight(), visHeight - marginsBordersPadding));
2070 LayoutUnit RenderBox::computeLogicalHeightUsing(SizeType heightType, const Length& height)
2072 LayoutUnit logicalHeight = computeContentLogicalHeightUsing(heightType, height);
2073 if (logicalHeight != -1)
2074 logicalHeight = computeBorderBoxLogicalHeight(logicalHeight);
2075 return logicalHeight;
2078 LayoutUnit RenderBox::computeContentLogicalHeightUsing(SizeType heightType, const Length& height)
2080 if (height.isAuto())
2081 return heightType == MinSize ? 0 : -1;
2082 if (height.isFixed())
2083 return height.value();
2084 if (height.isPercent())
2085 return computePercentageLogicalHeight(height);
2086 if (height.isViewportPercentage())
2087 return valueForLength(height, 0, view());
2091 LayoutUnit RenderBox::computePercentageLogicalHeight(const Length& height)
2093 LayoutUnit result = -1;
2095 // In quirks mode, blocks with auto height are skipped, and we keep looking for an enclosing
2096 // block that may have a specified height and then use it. In strict mode, this violates the
2097 // specification, which states that percentage heights just revert to auto if the containing
2098 // block has an auto height. We still skip anonymous containing blocks in both modes, though, and look
2099 // only at explicit containers.
2100 bool skippedAutoHeightContainingBlock = false;
2101 RenderBlock* cb = containingBlock();
2102 while (!cb->isRenderView() && !cb->isBody() && !cb->isTableCell() && !cb->isOutOfFlowPositioned() && cb->style()->logicalHeight().isAuto()) {
2103 if (!document()->inQuirksMode() && !cb->isAnonymousBlock())
2105 skippedAutoHeightContainingBlock = true;
2106 cb = cb->containingBlock();
2107 cb->addPercentHeightDescendant(this);
2110 RenderStyle* cbstyle = cb->style();
2112 // A positioned element that specified both top/bottom or that specifies height should be treated as though it has a height
2113 // explicitly specified that can be used for any percentage computations.
2114 // FIXME: We can't just check top/bottom here.
2115 // https://bugs.webkit.org/show_bug.cgi?id=46500
2116 bool isOutOfFlowPositionedWithSpecifiedHeight = cb->isOutOfFlowPositioned() && (!cbstyle->logicalHeight().isAuto() || (!cbstyle->top().isAuto() && !cbstyle->bottom().isAuto()));
2118 bool includeBorderPadding = isTable();
2120 // Table cells violate what the CSS spec says to do with heights. Basically we
2121 // don't care if the cell specified a height or not. We just always make ourselves
2122 // be a percentage of the cell's current content height.
2123 if (cb->isTableCell()) {
2124 if (!skippedAutoHeightContainingBlock) {
2125 if (!cb->hasOverrideHeight()) {
2126 // Normally we would let the cell size intrinsically, but scrolling overflow has to be
2127 // treated differently, since WinIE lets scrolled overflow regions shrink as needed.
2128 // While we can't get all cases right, we can at least detect when the cell has a specified
2129 // height or when the table has a specified height. In these cases we want to initially have
2130 // no size and allow the flexing of the table or the cell to its specified height to cause us
2131 // to grow to fill the space. This could end up being wrong in some cases, but it is
2132 // preferable to the alternative (sizing intrinsically and making the row end up too big).
2133 RenderTableCell* cell = toRenderTableCell(cb);
2134 if (scrollsOverflowY() && (!cell->style()->logicalHeight().isAuto() || !cell->table()->style()->logicalHeight().isAuto()))
2138 result = cb->overrideLogicalContentHeight();
2139 includeBorderPadding = true;
2141 } else if (cbstyle->logicalHeight().isFixed()) {
2142 // Otherwise we only use our percentage height if our containing block had a specified height.
2143 LayoutUnit contentBoxHeightWithScrollbar = cb->computeContentBoxLogicalHeight(cbstyle->logicalHeight().value());
2144 result = max<LayoutUnit>(0, contentBoxHeightWithScrollbar - cb->scrollbarLogicalHeight());
2145 } else if (cbstyle->logicalHeight().isPercent() && !isOutOfFlowPositionedWithSpecifiedHeight) {
2146 // We need to recur and compute the percentage height for our containing block.
2147 result = cb->computePercentageLogicalHeight(cbstyle->logicalHeight());
2149 result = cb->computeContentBoxLogicalHeight(result);
2150 } else if (cb->isRenderView() || (cb->isBody() && document()->inQuirksMode()) || isOutOfFlowPositionedWithSpecifiedHeight) {
2151 // Don't allow this to affect the block' height() member variable, since this
2152 // can get called while the block is still laying out its kids.
2153 LayoutUnit oldHeight = cb->logicalHeight();
2154 cb->computeLogicalHeight();
2155 result = cb->contentLogicalHeight();
2156 cb->setLogicalHeight(oldHeight);
2157 } else if (cb->isRoot() && isOutOfFlowPositioned())
2158 // Match the positioned objects behavior, which is that positioned objects will fill their viewport
2159 // always. Note we could only hit this case by recurring into computePercentageLogicalHeight on a positioned containing block.
2160 result = cb->computeContentBoxLogicalHeight(cb->availableLogicalHeight());
2163 result = valueForLength(height, result);
2164 if (includeBorderPadding) {
2165 // It is necessary to use the border-box to match WinIE's broken
2166 // box model. This is essential for sizing inside
2167 // table cells using percentage heights.
2168 result -= borderAndPaddingLogicalHeight();
2169 result = max<LayoutUnit>(0, result);
2175 LayoutUnit RenderBox::computeReplacedLogicalWidth(bool includeMaxWidth) const
2177 return computeReplacedLogicalWidthRespectingMinMaxWidth(computeReplacedLogicalWidthUsing(MainOrPreferredSize, style()->logicalWidth()), includeMaxWidth);
2180 LayoutUnit RenderBox::computeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUnit logicalWidth, bool includeMaxWidth) const
2182 LayoutUnit minLogicalWidth = computeReplacedLogicalWidthUsing(MinSize, style()->logicalMinWidth());
2183 LayoutUnit maxLogicalWidth = !includeMaxWidth || style()->logicalMaxWidth().isUndefined() ? logicalWidth : computeReplacedLogicalWidthUsing(MaxSize, style()->logicalMaxWidth());
2184 return max(minLogicalWidth, min(logicalWidth, maxLogicalWidth));
2187 LayoutUnit RenderBox::computeReplacedLogicalWidthUsing(SizeType sizeType, Length logicalWidth) const
2189 if (sizeType == MinSize && logicalWidth.isAuto())
2190 return computeContentBoxLogicalWidth(0);
2192 switch (logicalWidth.type()) {
2194 return computeContentBoxLogicalWidth(logicalWidth.value());
2195 case ViewportPercentageWidth:
2196 case ViewportPercentageHeight:
2197 case ViewportPercentageMin:
2198 return computeContentBoxLogicalWidth(valueForLength(logicalWidth, 0, view()));
2201 // FIXME: containingBlockLogicalWidthForContent() is wrong if the replaced element's block-flow is perpendicular to the
2202 // containing block's block-flow.
2203 // https://bugs.webkit.org/show_bug.cgi?id=46496
2204 const LayoutUnit cw = isOutOfFlowPositioned() ? containingBlockLogicalWidthForPositioned(toRenderBoxModelObject(container())) : containingBlockLogicalWidthForContent();
2205 Length containerLogicalWidth = containingBlock()->style()->logicalWidth();
2206 // FIXME: Handle cases when containing block width is calculated or viewport percent.
2207 // https://bugs.webkit.org/show_bug.cgi?id=91071
2208 if (cw > 0 || (!cw && (containerLogicalWidth.isFixed() || containerLogicalWidth.isPercent())))
2209 return computeContentBoxLogicalWidth(minimumValueForLength(logicalWidth, cw));
2213 return intrinsicLogicalWidth();
2217 LayoutUnit RenderBox::computeReplacedLogicalHeight() const
2219 return computeReplacedLogicalHeightRespectingMinMaxHeight(computeReplacedLogicalHeightUsing(MainOrPreferredSize, style()->logicalHeight()));
2222 LayoutUnit RenderBox::computeReplacedLogicalHeightRespectingMinMaxHeight(LayoutUnit logicalHeight) const
2224 LayoutUnit minLogicalHeight = computeReplacedLogicalHeightUsing(MinSize, style()->logicalMinHeight());
2225 LayoutUnit maxLogicalHeight = style()->logicalMaxHeight().isUndefined() ? logicalHeight : computeReplacedLogicalHeightUsing(MaxSize, style()->logicalMaxHeight());
2226 return max(minLogicalHeight, min(logicalHeight, maxLogicalHeight));
2229 LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(SizeType sizeType, Length logicalHeight) const
2231 if (sizeType == MinSize && logicalHeight.isAuto())
2232 return computeContentBoxLogicalHeight(0);
2234 switch (logicalHeight.type()) {
2236 return computeContentBoxLogicalHeight(logicalHeight.value());
2240 RenderObject* cb = isOutOfFlowPositioned() ? container() : containingBlock();
2241 while (cb->isAnonymous()) {
2242 cb = cb->containingBlock();
2243 toRenderBlock(cb)->addPercentHeightDescendant(const_cast<RenderBox*>(this));
2246 // FIXME: This calculation is not patched for block-flow yet.
2247 // https://bugs.webkit.org/show_bug.cgi?id=46500
2248 if (cb->isOutOfFlowPositioned() && cb->style()->height().isAuto() && !(cb->style()->top().isAuto() || cb->style()->bottom().isAuto())) {
2249 ASSERT(cb->isRenderBlock());
2250 RenderBlock* block = toRenderBlock(cb);
2251 LayoutUnit oldHeight = block->height();
2252 block->computeLogicalHeight();
2253 LayoutUnit newHeight = block->computeContentBoxLogicalHeight(block->contentHeight());
2254 block->setHeight(oldHeight);
2255 return computeContentBoxLogicalHeight(valueForLength(logicalHeight, newHeight));
2258 // FIXME: availableLogicalHeight() is wrong if the replaced element's block-flow is perpendicular to the
2259 // containing block's block-flow.
2260 // https://bugs.webkit.org/show_bug.cgi?id=46496
2261 LayoutUnit availableHeight;
2262 if (isOutOfFlowPositioned())
2263 availableHeight = containingBlockLogicalHeightForPositioned(toRenderBoxModelObject(cb));
2265 availableHeight = toRenderBox(cb)->availableLogicalHeight();
2266 // It is necessary to use the border-box to match WinIE's broken
2267 // box model. This is essential for sizing inside
2268 // table cells using percentage heights.
2269 // FIXME: This needs to be made block-flow-aware. If the cell and image are perpendicular block-flows, this isn't right.
2270 // https://bugs.webkit.org/show_bug.cgi?id=46997
2271 while (cb && !cb->isRenderView() && (cb->style()->logicalHeight().isAuto() || cb->style()->logicalHeight().isPercent())) {
2272 if (cb->isTableCell()) {
2273 // Don't let table cells squeeze percent-height replaced elements
2274 // <http://bugs.webkit.org/show_bug.cgi?id=15359>
2275 availableHeight = max(availableHeight, intrinsicLogicalHeight());
2276 return valueForLength(logicalHeight, availableHeight - borderAndPaddingLogicalHeight());
2278 toRenderBlock(cb)->addPercentHeightDescendant(const_cast<RenderBox*>(this));
2279 cb = cb->containingBlock();
2282 availableHeight = computeContentBoxLogicalHeight(valueForLength(logicalHeight, availableHeight));
2283 if (cb->style()->logicalHeight().isFixed())
2284 availableHeight = max<LayoutUnit>(0, availableHeight - toRenderBox(cb)->scrollbarLogicalHeight());
2285 return availableHeight;
2287 case ViewportPercentageWidth:
2288 case ViewportPercentageHeight:
2289 case ViewportPercentageMin:
2290 return computeContentBoxLogicalHeight(valueForLength(logicalHeight, 0, view()));
2292 return intrinsicLogicalHeight();
2296 LayoutUnit RenderBox::availableLogicalHeight() const
2298 return availableLogicalHeightUsing(style()->logicalHeight());
2301 LayoutUnit RenderBox::availableLogicalHeightUsing(const Length& h) const
2304 return computeContentBoxLogicalHeight(h.value());
2307 return isHorizontalWritingMode() ? toRenderView(this)->frameView()->visibleHeight() : toRenderView(this)->frameView()->visibleWidth();
2309 // We need to stop here, since we don't want to increase the height of the table
2310 // artificially. We're going to rely on this cell getting expanded to some new
2311 // height, and then when we lay out again we'll use the calculation below.
2312 if (isTableCell() && (h.isAuto() || h.isPercent()))
2313 return overrideLogicalContentHeight();
2315 if (h.isPercent()) {
2316 LayoutUnit availableHeight;
2317 // https://bugs.webkit.org/show_bug.cgi?id=64046
2318 // For absolutely positioned elements whose containing block is based on a block-level element,
2319 // the percentage is calculated with respect to the height of the padding box of that element
2320 if (isOutOfFlowPositioned())
2321 availableHeight = containingBlockLogicalHeightForPositioned(containingBlock());
2323 availableHeight = containingBlock()->availableLogicalHeight();
2324 return computeContentBoxLogicalHeight(valueForLength(h, availableHeight));
2327 // FIXME: We can't just check top/bottom here.
2328 // https://bugs.webkit.org/show_bug.cgi?id=46500
2329 if (isRenderBlock() && isOutOfFlowPositioned() && style()->height().isAuto() && !(style()->top().isAuto() || style()->bottom().isAuto())) {
2330 RenderBlock* block = const_cast<RenderBlock*>(toRenderBlock(this));
2331 LayoutUnit oldHeight = block->logicalHeight();
2332 block->computeLogicalHeight();
2333 LayoutUnit newHeight = block->computeContentBoxLogicalHeight(block->contentLogicalHeight());
2334 block->setLogicalHeight(oldHeight);
2335 return computeContentBoxLogicalHeight(newHeight);
2338 return containingBlock()->availableLogicalHeight();
2341 void RenderBox::computeBlockDirectionMargins(const RenderBlock* containingBlock)
2343 if (isTableCell()) {
2344 // FIXME: Not right if we allow cells to have different directionality than the table. If we do allow this, though,
2345 // we may just do it with an extra anonymous block inside the cell.
2351 // Margins are calculated with respect to the logical width of
2352 // the containing block (8.3)
2353 LayoutUnit cw = containingBlockLogicalWidthForContent();
2354 RenderView* renderView = view();
2355 RenderStyle* containingBlockStyle = containingBlock->style();
2356 containingBlock->setMarginBeforeForChild(this, minimumValueForLength(style()->marginBeforeUsing(containingBlockStyle), cw, renderView));
2357 containingBlock->setMarginAfterForChild(this, minimumValueForLength(style()->marginAfterUsing(containingBlockStyle), cw, renderView));
2360 LayoutUnit RenderBox::containingBlockLogicalWidthForPositioned(const RenderBoxModelObject* containingBlock, RenderRegion* region,
2361 LayoutUnit offsetFromLogicalTopOfFirstPage, bool checkForPerpendicularWritingMode) const
2363 // Container for position:fixed is the frame.
2364 Frame* frame = view() ? view()->frame(): 0;
2365 FrameView* frameView = view() ? view()->frameView() : 0;
2366 if (fixedElementLaysOutRelativeToFrame(frame, frameView))
2367 return (view()->isHorizontalWritingMode() ? frameView->visibleWidth() : frameView->visibleHeight()) / frame->frameScaleFactor();
2369 if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWritingMode() != isHorizontalWritingMode())
2370 return containingBlockLogicalHeightForPositioned(containingBlock, false);
2372 if (containingBlock->isBox()) {
2373 const RenderBlock* cb = toRenderBlock(containingBlock);
2374 LayoutUnit result = cb->clientLogicalWidth();
2375 if (inRenderFlowThread()) {
2376 RenderBoxRegionInfo* boxInfo = 0;
2378 if (containingBlock->isRenderFlowThread() && !checkForPerpendicularWritingMode)
2379 return toRenderFlowThread(containingBlock)->contentLogicalWidthOfFirstRegion();
2380 if (isWritingModeRoot()) {
2381 LayoutUnit cbPageOffset = offsetFromLogicalTopOfFirstPage - logicalTop();
2382 RenderRegion* cbRegion = cb->regionAtBlockOffset(cbPageOffset);
2384 cbRegion = cb->clampToStartAndEndRegions(cbRegion);
2385 boxInfo = cb->renderBoxRegionInfo(cbRegion, cbPageOffset);
2388 } else if (region && enclosingRenderFlowThread()->isHorizontalWritingMode() == containingBlock->isHorizontalWritingMode()) {
2389 RenderRegion* containingBlockRegion = cb->clampToStartAndEndRegions(region);
2390 boxInfo = cb->renderBoxRegionInfo(containingBlockRegion, offsetFromLogicalTopOfFirstPage - logicalTop());
2393 return max<LayoutUnit>(0, result - (cb->logicalWidth() - boxInfo->logicalWidth()));
2398 ASSERT(containingBlock->isRenderInline() && containingBlock->isRelPositioned());
2400 const RenderInline* flow = toRenderInline(containingBlock);
2401 InlineFlowBox* first = flow->firstLineBox();
2402 InlineFlowBox* last = flow->lastLineBox();
2404 // If the containing block is empty, return a width of 0.
2405 if (!first || !last)
2408 LayoutUnit fromLeft;
2409 LayoutUnit fromRight;
2410 if (containingBlock->style()->isLeftToRightDirection()) {
2411 fromLeft = first->logicalLeft() + first->borderLogicalLeft();
2412 fromRight = last->logicalLeft() + last->logicalWidth() - last->borderLogicalRight();
2414 fromRight = first->logicalLeft() + first->logicalWidth() - first->borderLogicalRight();
2415 fromLeft = last->logicalLeft() + last->borderLogicalLeft();
2418 return max<LayoutUnit>(0, fromRight - fromLeft);
2421 LayoutUnit RenderBox::containingBlockLogicalHeightForPositioned(const RenderBoxModelObject* containingBlock, bool checkForPerpendicularWritingMode) const
2423 Frame* frame = view() ? view()->frame(): 0;
2424 FrameView* frameView = view() ? view()->frameView() : 0;
2425 if (fixedElementLaysOutRelativeToFrame(frame, frameView))
2426 return (view()->isHorizontalWritingMode() ? frameView->visibleHeight() : frameView->visibleWidth()) / frame->frameScaleFactor();
2428 if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWritingMode() != isHorizontalWritingMode())
2429 return containingBlockLogicalWidthForPositioned(containingBlock, 0, 0, false);
2431 if (containingBlock->isBox()) {
2432 const RenderBlock* cb = toRenderBlock(containingBlock);
2433 LayoutUnit result = cb->clientLogicalHeight();
2434 if (inRenderFlowThread() && containingBlock->isRenderFlowThread() && enclosingRenderFlowThread()->isHorizontalWritingMode() == containingBlock->isHorizontalWritingMode())
2435 return toRenderFlowThread(containingBlock)->contentLogicalHeightOfFirstRegion();
2439 ASSERT(containingBlock->isRenderInline() && containingBlock->isRelPositioned());
2441 const RenderInline* flow = toRenderInline(containingBlock);
2442 InlineFlowBox* first = flow->firstLineBox();
2443 InlineFlowBox* last = flow->lastLineBox();
2445 // If the containing block is empty, return a height of 0.
2446 if (!first || !last)
2449 LayoutUnit heightResult;
2450 LayoutRect boundingBox = flow->linesBoundingBox();
2451 if (containingBlock->isHorizontalWritingMode())
2452 heightResult = boundingBox.height();
2454 heightResult = boundingBox.width();
2455 heightResult -= (containingBlock->borderBefore() + containingBlock->borderAfter());
2456 return heightResult;
2459 static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRight, const RenderBox* child, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalWidth, RenderRegion* region)
2461 if (!logicalLeft.isAuto() || !logicalRight.isAuto())
2464 // FIXME: The static distance computation has not been patched for mixed writing modes yet.
2465 if (child->parent()->style()->direction() == LTR) {
2466 LayoutUnit staticPosition = child->layer()->staticInlinePosition() - containerBlock->borderLogicalLeft();
2467 for (RenderObject* curr = child->parent(); curr && curr != containerBlock; curr = curr->container()) {
2468 if (curr->isBox()) {
2469 staticPosition += toRenderBox(curr)->logicalLeft();
2470 if (region && curr->isRenderBlock()) {
2471 const RenderBlock* cb = toRenderBlock(curr);
2472 region = cb->clampToStartAndEndRegions(region);
2473 RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(region, region->offsetFromLogicalTopOfFirstPage());
2475 staticPosition += boxInfo->logicalLeft();
2479 logicalLeft.setValue(Fixed, staticPosition);
2481 RenderBox* enclosingBox = child->parent()->enclosingBox();
2482 LayoutUnit staticPosition = child->layer()->staticInlinePosition() + containerLogicalWidth + containerBlock->borderLogicalLeft();
2483 for (RenderObject* curr = enclosingBox; curr; curr = curr->container()) {
2484 if (curr->isBox()) {
2485 if (curr != containerBlock)
2486 staticPosition -= toRenderBox(curr)->logicalLeft();
2487 if (curr == enclosingBox)
2488 staticPosition -= enclosingBox->logicalWidth();
2489 if (region && curr->isRenderBlock()) {
2490 const RenderBlock* cb = toRenderBlock(curr);
2491 region = cb->clampToStartAndEndRegions(region);
2492 RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(region, region->offsetFromLogicalTopOfFirstPage());
2494 if (curr != containerBlock)
2495 staticPosition -= cb->logicalWidth() - (boxInfo->logicalLeft() + boxInfo->logicalWidth());
2496 if (curr == enclosingBox)
2497 staticPosition += enclosingBox->logicalWidth() - boxInfo->logicalWidth();
2501 if (curr == containerBlock)
2504 logicalRight.setValue(Fixed, staticPosition);
2508 void RenderBox::computePositionedLogicalWidth(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage)
2511 computePositionedLogicalWidthReplaced(); // FIXME: Patch for regions when we add replaced element support.
2516 // FIXME 1: Should we still deal with these the cases of 'left' or 'right' having
2517 // the type 'static' in determining whether to calculate the static distance?
2518 // NOTE: 'static' is not a legal value for 'left' or 'right' as of CSS 2.1.
2520 // FIXME 2: Can perhaps optimize out cases when max-width/min-width are greater
2521 // than or less than the computed width(). Be careful of box-sizing and
2522 // percentage issues.
2524 // The following is based off of the W3C Working Draft from April 11, 2006 of
2525 // CSS 2.1: Section 10.3.7 "Absolutely positioned, non-replaced elements"
2526 // <http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width>
2527 // (block-style-comments in this function and in computePositionedLogicalWidthUsing()
2528 // correspond to text from the spec)
2531 // We don't use containingBlock(), since we may be positioned by an enclosing
2532 // relative positioned inline.
2533 const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
2535 const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, region, offsetFromLogicalTopOfFirstPage);
2537 // Use the container block's direction except when calculating the static distance
2538 // This conforms with the reference results for abspos-replaced-width-margin-000.htm
2539 // of the CSS 2.1 test suite
2540 TextDirection containerDirection = containerBlock->style()->direction();
2542 bool isHorizontal = isHorizontalWritingMode();
2543 const LayoutUnit bordersPlusPadding = borderAndPaddingLogicalWidth();
2544 const Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->marginTop();
2545 const Length marginLogicalRight = isHorizontal ? style()->marginRight() : style()->marginBottom();
2546 LayoutUnit& marginLogicalLeftAlias = m_marginBox.mutableLogicalLeft(style()->writingMode());
2547 LayoutUnit& marginLogicalRightAlias = m_marginBox.mutableLogicalRight(style()->writingMode());
2549 Length logicalLeftLength = style()->logicalLeft();
2550 Length logicalRightLength = style()->logicalRight();
2552 /*---------------------------------------------------------------------------*\
2553 * For the purposes of this section and the next, the term "static position"
2554 * (of an element) refers, roughly, to the position an element would have had
2555 * in the normal flow. More precisely:
2557 * * The static position for 'left' is the distance from the left edge of the
2558 * containing block to the left margin edge of a hypothetical box that would
2559 * have been the first box of the element if its 'position' property had
2560 * been 'static' and 'float' had been 'none'. The value is negative if the
2561 * hypothetical box is to the left of the containing block.
2562 * * The static position for 'right' is the distance from the right edge of the
2563 * containing block to the right margin edge of the same hypothetical box as
2564 * above. The value is positive if the hypothetical box is to the left of the
2565 * containing block's edge.
2567 * But rather than actually calculating the dimensions of that hypothetical box,
2568 * user agents are free to make a guess at its probable position.
2570 * For the purposes of calculating the static position, the containing block of
2571 * fixed positioned elements is the initial containing block instead of the
2572 * viewport, and all scrollable boxes should be assumed to be scrolled to their
2574 \*---------------------------------------------------------------------------*/
2577 // Calculate the static distance if needed.
2578 computeInlineStaticDistance(logicalLeftLength, logicalRightLength, this, containerBlock, containerLogicalWidth, region);
2580 // Calculate constraint equation values for 'width' case.
2581 LayoutUnit logicalWidthResult;
2582 LayoutUnit logicalLeftResult;
2583 computePositionedLogicalWidthUsing(MainOrPreferredSize, style()->logicalWidth(), containerBlock, containerDirection,
2584 containerLogicalWidth, bordersPlusPadding,
2585 logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight,
2586 logicalWidthResult, marginLogicalLeftAlias, marginLogicalRightAlias, logicalLeftResult);
2587 setLogicalWidth(logicalWidthResult);
2588 setLogicalLeft(logicalLeftResult);
2590 // Calculate constraint equation values for 'max-width' case.
2591 if (!style()->logicalMaxWidth().isUndefined()) {
2592 LayoutUnit maxLogicalWidth;
2593 LayoutUnit maxMarginLogicalLeft;
2594 LayoutUnit maxMarginLogicalRight;
2595 LayoutUnit maxLogicalLeftPos;
2597 computePositionedLogicalWidthUsing(MaxSize, style()->logicalMaxWidth(), containerBlock, containerDirection,
2598 containerLogicalWidth, bordersPlusPadding,
2599 logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight,
2600 maxLogicalWidth, maxMarginLogicalLeft, maxMarginLogicalRight, maxLogicalLeftPos);
2602 if (logicalWidth() > maxLogicalWidth) {
2603 setLogicalWidth(maxLogicalWidth);
2604 marginLogicalLeftAlias = maxMarginLogicalLeft;
2605 marginLogicalRightAlias = maxMarginLogicalRight;
2606 setLogicalLeft(maxLogicalLeftPos);
2610 // Calculate constraint equation values for 'min-width' case.
2611 if (!style()->logicalMinWidth().isZero()) {
2612 LayoutUnit minLogicalWidth;
2613 LayoutUnit minMarginLogicalLeft;
2614 LayoutUnit minMarginLogicalRight;
2615 LayoutUnit minLogicalLeftPos;
2617 computePositionedLogicalWidthUsing(MinSize, style()->logicalMinWidth(), containerBlock, containerDirection,
2618 containerLogicalWidth, bordersPlusPadding,
2619 logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight,
2620 minLogicalWidth, minMarginLogicalLeft, minMarginLogicalRight, minLogicalLeftPos);
2622 if (logicalWidth() < minLogicalWidth) {
2623 setLogicalWidth(minLogicalWidth);
2624 marginLogicalLeftAlias = minMarginLogicalLeft;
2625 marginLogicalRightAlias = minMarginLogicalRight;
2626 setLogicalLeft(minLogicalLeftPos);
2630 if (stretchesToMinIntrinsicLogicalWidth() && logicalWidth() < minPreferredLogicalWidth() - bordersPlusPadding) {
2631 computePositionedLogicalWidthUsing(MainOrPreferredSize, Length(minPreferredLogicalWidth() - bordersPlusPadding, Fixed), containerBlock, containerDirection,
2632 containerLogicalWidth, bordersPlusPadding,
2633 logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight,
2634 logicalWidthResult, marginLogicalLeftAlias, marginLogicalRightAlias, logicalLeftResult);
2635 setLogicalWidth(logicalWidthResult);
2636 setLogicalLeft(logicalLeftResult);
2639 // Put logicalWidth() into correct form.
2640 setLogicalWidth(logicalWidth() + bordersPlusPadding);
2642 // Adjust logicalLeft if we need to for the flipped version of our writing mode in regions.
2643 if (inRenderFlowThread() && !region && isWritingModeRoot() && isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode()) {
2644 LayoutUnit logicalLeftPos = logicalLeft();
2645 const RenderBlock* cb = toRenderBlock(containerBlock);
2646 LayoutUnit cbPageOffset = offsetFromLogicalTopOfFirstPage - logicalTop();
2647 RenderRegion* cbRegion = cb->regionAtBlockOffset(cbPageOffset);
2649 cbRegion = cb->clampToStartAndEndRegions(cbRegion);
2650 RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(cbRegion, cbPageOffset);
2652 logicalLeftPos += boxInfo->logicalLeft();
2653 setLogicalLeft(logicalLeftPos);
2659 static void computeLogicalLeftPositionedOffset(LayoutUnit& logicalLeftPos, const RenderBox* child, LayoutUnit logicalWidthValue, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalWidth)
2661 // Deal with differing writing modes here. Our offset needs to be in the containing block's coordinate space. If the containing block is flipped
2662 // 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.
2663 if (containerBlock->isHorizontalWritingMode() != child->isHorizontalWritingMode() && containerBlock->style()->isFlippedBlocksWritingMode()) {
2664 logicalLeftPos = containerLogicalWidth - logicalWidthValue - logicalLeftPos;
2665 logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->borderRight() : containerBlock->borderBottom());
2667 logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->borderLeft() : containerBlock->borderTop());
2670 void RenderBox::computePositionedLogicalWidthUsing(SizeType widthSizeType, Length logicalWidth, const RenderBoxModelObject* containerBlock, TextDirection containerDirection,
2671 LayoutUnit containerLogicalWidth, LayoutUnit bordersPlusPadding,
2672 Length logicalLeft, Length logicalRight, Length marginLogicalLeft, Length marginLogicalRight,
2673 LayoutUnit& logicalWidthValue, LayoutUnit& marginLogicalLeftValue, LayoutUnit& marginLogicalRightValue, LayoutUnit& logicalLeftPos)
2675 if (widthSizeType == MinSize && logicalWidth.isAuto())
2676 logicalWidth = Length(0, Fixed);
2678 // 'left' and 'right' cannot both be 'auto' because one would of been
2679 // converted to the static position already
2680 ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto()));
2682 LayoutUnit logicalLeftValue = 0;
2684 bool logicalWidthIsAuto = logicalWidth.isIntrinsicOrAuto();
2685 bool logicalLeftIsAuto = logicalLeft.isAuto();
2686 bool logicalRightIsAuto = logicalRight.isAuto();
2687 RenderView* renderView = view();
2689 if (!logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) {
2690 /*-----------------------------------------------------------------------*\
2691 * If none of the three is 'auto': If both 'margin-left' and 'margin-
2692 * right' are 'auto', solve the equation under the extra constraint that
2693 * the two margins get equal values, unless this would make them negative,
2694 * in which case when direction of the containing block is 'ltr' ('rtl'),
2695 * set 'margin-left' ('margin-right') to zero and solve for 'margin-right'
2696 * ('margin-left'). If one of 'margin-left' or 'margin-right' is 'auto',
2697 * solve the equation for that value. If the values are over-constrained,
2698 * ignore the value for 'left' (in case the 'direction' property of the
2699 * containing block is 'rtl') or 'right' (in case 'direction' is 'ltr')
2700 * and solve for that value.
2701 \*-----------------------------------------------------------------------*/
2702 // NOTE: It is not necessary to solve for 'right' in the over constrained
2703 // case because the value is not used for any further calculations.
2705 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
2706 logicalWidthValue = computeContentBoxLogicalWidth(valueForLength(logicalWidth, containerLogicalWidth, renderView));
2708 const LayoutUnit availableSpace = containerLogicalWidth - (logicalLeftValue + logicalWidthValue + valueForLength(logicalRight, containerLogicalWidth, renderView) + bordersPlusPadding);
2710 // Margins are now the only unknown
2711 if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) {
2712 // Both margins auto, solve for equality
2713 if (availableSpace >= 0) {
2714 marginLogicalLeftValue = availableSpace / 2; // split the difference
2715 marginLogicalRightValue = availableSpace - marginLogicalLeftValue; // account for odd valued differences
2717 // Use the containing block's direction rather than the parent block's
2718 // per CSS 2.1 reference test abspos-non-replaced-width-margin-000.
2719 if (containerDirection == LTR) {
2720 marginLogicalLeftValue = 0;
2721 marginLogicalRightValue = availableSpace; // will be negative
2723 marginLogicalLeftValue = availableSpace; // will be negative
2724 marginLogicalRightValue = 0;
2727 } else if (marginLogicalLeft.isAuto()) {
2728 // Solve for left margin
2729 marginLogicalRightValue = valueForLength(marginLogicalRight, containerLogicalWidth, renderView);
2730 marginLogicalLeftValue = availableSpace - marginLogicalRightValue;
2731 } else if (marginLogicalRight.isAuto()) {
2732 // Solve for right margin
2733 marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerLogicalWidth, renderView);
2734 marginLogicalRightValue = availableSpace - marginLogicalLeftValue;
2736 // Over-constrained, solve for left if direction is RTL
2737 marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerLogicalWidth, renderView);
2738 marginLogicalRightValue = valueForLength(marginLogicalRight, containerLogicalWidth, renderView);
2740 // Use the containing block's direction rather than the parent block's
2741 // per CSS 2.1 reference test abspos-non-replaced-width-margin-000.
2742 if (containerDirection == RTL)
2743 logicalLeftValue = (availableSpace + logicalLeftValue) - marginLogicalLeftValue - marginLogicalRightValue;
2746 /*--------------------------------------------------------------------*\
2747 * Otherwise, set 'auto' values for 'margin-left' and 'margin-right'
2748 * to 0, and pick the one of the following six rules that applies.
2750 * 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the
2751 * width is shrink-to-fit. Then solve for 'left'
2753 * OMIT RULE 2 AS IT SHOULD NEVER BE HIT
2754 * ------------------------------------------------------------------
2755 * 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if
2756 * the 'direction' property of the containing block is 'ltr' set
2757 * 'left' to the static position, otherwise set 'right' to the
2758 * static position. Then solve for 'left' (if 'direction is 'rtl')
2759 * or 'right' (if 'direction' is 'ltr').
2760 * ------------------------------------------------------------------
2762 * 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the
2763 * width is shrink-to-fit . Then solve for 'right'
2764 * 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve
2766 * 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve
2768 * 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve
2771 * Calculation of the shrink-to-fit width is similar to calculating the
2772 * width of a table cell using the automatic table layout algorithm.
2773 * Roughly: calculate the preferred width by formatting the content
2774 * without breaking lines other than where explicit line breaks occur,
2775 * and also calculate the preferred minimum width, e.g., by trying all
2776 * possible line breaks. CSS 2.1 does not define the exact algorithm.
2777 * Thirdly, calculate the available width: this is found by solving
2778 * for 'width' after setting 'left' (in case 1) or 'right' (in case 3)
2781 * Then the shrink-to-fit width is:
2782 * min(max(preferred minimum width, available width), preferred width).
2783 \*--------------------------------------------------------------------*/
2784 // NOTE: For rules 3 and 6 it is not necessary to solve for 'right'
2785 // because the value is not used for any further calculations.
2787 // Calculate margins, 'auto' margins are ignored.
2788 marginLogicalLeftValue = minimumValueForLength(marginLogicalLeft, containerLogicalWidth, renderView);
2789 marginLogicalRightValue = minimumValueForLength(marginLogicalRight, containerLogicalWidth, renderView);
2791 const LayoutUnit availableSpace = containerLogicalWidth - (marginLogicalLeftValue + marginLogicalRightValue + bordersPlusPadding);
2793 // FIXME: Is there a faster way to find the correct case?
2794 // Use rule/case that applies.
2795 if (logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAuto) {
2796 // RULE 1: (use shrink-to-fit for width, and solve of left)
2797 LayoutUnit logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView);
2799 // FIXME: would it be better to have shrink-to-fit in one step?
2800 LayoutUnit preferredWidth = maxPreferredLogicalWidth() - bordersPlusPadding;
2801 LayoutUnit preferredMinWidth = minPreferredLogicalWidth() - bordersPlusPadding;
2802 LayoutUnit availableWidth = availableSpace - logicalRightValue;
2803 logicalWidthValue = min(max(preferredMinWidth, availableWidth), preferredWidth);
2804 logicalLeftValue = availableSpace - (logicalWidthValue + logicalRightValue);
2805 } else if (!logicalLeftIsAuto && logicalWidthIsAuto && logicalRightIsAuto) {
2806 // RULE 3: (use shrink-to-fit for width, and no need solve of right)
2807 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
2809 // FIXME: would it be better to have shrink-to-fit in one step?
2810 LayoutUnit preferredWidth = maxPreferredLogicalWidth() - bordersPlusPadding;
2811 LayoutUnit preferredMinWidth = minPreferredLogicalWidth() - bordersPlusPadding;
2812 LayoutUnit availableWidth = availableSpace - logicalLeftValue;
2813 logicalWidthValue = min(max(preferredMinWidth, availableWidth), preferredWidth);
2814 } else if (logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) {
2815 // RULE 4: (solve for left)
2816 logicalWidthValue = computeContentBoxLogicalWidth(valueForLength(logicalWidth, containerLogicalWidth, renderView));
2817 logicalLeftValue = availableSpace - (logicalWidthValue + valueForLength(logicalRight, containerLogicalWidth, renderView));
2818 } else if (!logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAuto) {
2819 // RULE 5: (solve for width)
2820 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
2821 logicalWidthValue = availableSpace - (logicalLeftValue + valueForLength(logicalRight, containerLogicalWidth, renderView));
2822 } else if (!logicalLeftIsAuto && !logicalWidthIsAuto && logicalRightIsAuto) {
2823 // RULE 6: (no need solve for right)
2824 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
2825 logicalWidthValue = computeContentBoxLogicalWidth(valueForLength(logicalWidth, containerLogicalWidth, renderView));
2829 // Use computed values to calculate the horizontal position.
2831 // FIXME: This hack is needed to calculate the logical left position for a 'rtl' relatively
2832 // positioned, inline because right now, it is using the logical left position
2833 // of the first line box when really it should use the last line box. When
2834 // this is fixed elsewhere, this block should be removed.
2835 if (containerBlock->isRenderInline() && !containerBlock->style()->isLeftToRightDirection()) {
2836 const RenderInline* flow = toRenderInline(containerBlock);
2837 InlineFlowBox* firstLine = flow->firstLineBox();
2838 InlineFlowBox* lastLine = flow->lastLineBox();
2839 if (firstLine && lastLine && firstLine != lastLine) {
2840 logicalLeftPos = logicalLeftValue + marginLogicalLeftValue + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logicalLeft());
2845 logicalLeftPos = logicalLeftValue + marginLogicalLeftValue;
2846 computeLogicalLeftPositionedOffset(logicalLeftPos, this, logicalWidthValue, containerBlock, containerLogicalWidth);
2849 static void computeBlockStaticDistance(Length& logicalTop, Length& logicalBottom, const RenderBox* child, const RenderBoxModelObject* containerBlock)
2851 if (!logicalTop.isAuto() || !logicalBottom.isAuto())
2854 // FIXME: The static distance computation has not been patched for mixed writing modes.
2855 LayoutUnit staticLogicalTop = child->layer()->staticBlockPosition() - containerBlock->borderBefore();
2856 for (RenderObject* curr = child->parent(); curr && curr != containerBlock; curr = curr->container()) {
2857 if (curr->isBox() && !curr->isTableRow())
2858 staticLogicalTop += toRenderBox(curr)->logicalTop();
2860 logicalTop.setValue(Fixed, staticLogicalTop);
2863 void RenderBox::computePositionedLogicalHeight()
2866 computePositionedLogicalHeightReplaced();
2870 // The following is based off of the W3C Working Draft from April 11, 2006 of
2871 // CSS 2.1: Section 10.6.4 "Absolutely positioned, non-replaced elements"
2872 // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-non-replaced-height>
2873 // (block-style-comments in this function and in computePositionedLogicalHeightUsing()
2874 // correspond to text from the spec)
2877 // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
2878 const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
2880 const LayoutUnit containerLogicalHeight = containingBlockLogicalHeightForPositioned(containerBlock);
2882 RenderStyle* styleToUse = style();
2883 const LayoutUnit bordersPlusPadding = borderAndPaddingLogicalHeight();
2884 const Length marginBefore = styleToUse->marginBefore();
2885 const Length marginAfter = styleToUse->marginAfter();
2886 LayoutUnit& marginBeforeAlias = m_marginBox.mutableBefore(styleToUse->writingMode());
2887 LayoutUnit& marginAfterAlias = m_marginBox.mutableAfter(styleToUse->writingMode());
2889 Length logicalTopLength = styleToUse->logicalTop();
2890 Length logicalBottomLength = styleToUse->logicalBottom();
2892 /*---------------------------------------------------------------------------*\
2893 * For the purposes of this section and the next, the term "static position"
2894 * (of an element) refers, roughly, to the position an element would have had
2895 * in the normal flow. More precisely, the static position for 'top' is the
2896 * distance from the top edge of the containing block to the top margin edge
2897 * of a hypothetical box that would have been the first box of the element if
2898 * its 'position' property had been 'static' and 'float' had been 'none'. The
2899 * value is negative if the hypothetical box is above the containing block.
2901 * But rather than actually calculating the dimensions of that hypothetical
2902 * box, user agents are free to make a guess at its probable position.
2904 * For the purposes of calculating the static position, the containing block
2905 * of fixed positioned elements is the initial containing block instead of
2907 \*---------------------------------------------------------------------------*/
2910 // Calculate the static distance if needed.
2911 computeBlockStaticDistance(logicalTopLength, logicalBottomLength, this, containerBlock);
2913 LayoutUnit logicalHeightResult; // Needed to compute overflow.
2914 LayoutUnit logicalTopPos;
2916 // Calculate constraint equation values for 'height' case.
2917 computePositionedLogicalHeightUsing(MainOrPreferredSize, styleToUse->logicalHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding,
2918 logicalTopLength, logicalBottomLength, marginBefore, marginAfter,
2919 logicalHeightResult, marginBeforeAlias, marginAfterAlias, logicalTopPos);
2920 setLogicalTop(logicalTopPos);
2922 // Avoid doing any work in the common case (where the values of min-height and max-height are their defaults).
2925 // Calculate constraint equation values for 'max-height' case.
2926 if (!styleToUse->logicalMaxHeight().isUndefined()) {
2927 LayoutUnit maxLogicalHeight;
2928 LayoutUnit maxMarginBefore;
2929 LayoutUnit maxMarginAfter;
2930 LayoutUnit maxLogicalTopPos;
2932 computePositionedLogicalHeightUsing(MaxSize, styleToUse->logicalMaxHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding,
2933 logicalTopLength, logicalBottomLength, marginBefore, marginAfter,
2934 maxLogicalHeight, maxMarginBefore, maxMarginAfter, maxLogicalTopPos);
2936 if (logicalHeightResult > maxLogicalHeight) {
2937 logicalHeightResult = maxLogicalHeight;
2938 marginBeforeAlias = maxMarginBefore;
2939 marginAfterAlias = maxMarginAfter;
2940 setLogicalTop(maxLogicalTopPos);
2944 // Calculate constraint equation values for 'min-height' case.
2945 if (!styleToUse->logicalMinHeight().isZero()) {
2946 LayoutUnit minLogicalHeight;
2947 LayoutUnit minMarginBefore;
2948 LayoutUnit minMarginAfter;
2949 LayoutUnit minLogicalTopPos;
2951 computePositionedLogicalHeightUsing(MinSize, styleToUse->logicalMinHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding,
2952 logicalTopLength, logicalBottomLength, marginBefore, marginAfter,
2953 minLogicalHeight, minMarginBefore, minMarginAfter, minLogicalTopPos);
2955 if (logicalHeightResult < minLogicalHeight) {
2956 logicalHeightResult = minLogicalHeight;
2957 marginBeforeAlias = minMarginBefore;
2958 marginAfterAlias = minMarginAfter;
2959 setLogicalTop(minLogicalTopPos);
2963 // Set final height value.
2964 setLogicalHeight(logicalHeightResult + bordersPlusPadding);
2966 // Adjust logicalTop if we need to for perpendicular writing modes in regions.
2967 if (inRenderFlowThread() && isHorizontalWritingMode() != containerBlock->isHorizontalWritingMode()) {
2968 LayoutUnit logicalTopPos = logicalTop();
2969 const RenderBlock* cb = toRenderBlock(containerBlock);
2970 LayoutUnit cbPageOffset = cb->offsetFromLogicalTopOfFirstPage() - logicalLeft();
2971 RenderRegion* cbRegion = cb->regionAtBlockOffset(cbPageOffset);
2973 cbRegion = cb->clampToStartAndEndRegions(cbRegion);
2974 RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(cbRegion, cbPageOffset);
2976 logicalTopPos += boxInfo->logicalLeft();
2977 setLogicalTop(logicalTopPos);
2983 static void computeLogicalTopPositionedOffset(LayoutUnit& logicalTopPos, const RenderBox* child, LayoutUnit logicalHeightValue, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalHeight)
2985 // Deal with differing writing modes here. Our offset needs to be in the containing block's coordinate space. If the containing block is flipped
2986 // 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.
2987 if ((child->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() != containerBlock->isHorizontalWritingMode())
2988 || (child->style()->isFlippedBlocksWritingMode() != containerBlock->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode()))
2989 logicalTopPos = containerLogicalHeight - logicalHeightValue - logicalTopPos;
2991 // Our offset is from the logical bottom edge in a flipped environment, e.g., right for vertical-rl and bottom for horizontal-bt.
2992 if (containerBlock->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode()) {
2993 if (child->isHorizontalWritingMode())
2994 logicalTopPos += containerBlock->borderBottom();
2996 logicalTopPos += containerBlock->borderRight();
2998 if (child->isHorizontalWritingMode())
2999 logicalTopPos += containerBlock->borderTop();
3001 logicalTopPos += containerBlock->borderLeft();
3005 void RenderBox::computePositionedLogicalHeightUsing(SizeType heightSizeType, Length logicalHeightLength, const RenderBoxModelObject* containerBlock,
3006 LayoutUnit containerLogicalHeight, LayoutUnit bordersPlusPadding,
3007 Length logicalTop, Length logicalBottom, Length marginBefore, Length marginAfter,
3008 LayoutUnit& logicalHeightValue, LayoutUnit& marginBeforeValue, LayoutUnit& marginAfterValue, LayoutUnit& logicalTopPos)
3010 if (heightSizeType == MinSize && logicalHeightLength.isAuto())
3011 logicalHeightLength = Length(0, Fixed);
3013 // 'top' and 'bottom' cannot both be 'auto' because 'top would of been
3014 // converted to the static position in computePositionedLogicalHeight()
3015 ASSERT(!(logicalTop.isAuto() && logicalBottom.isAuto()));
3017 LayoutUnit contentLogicalHeight = logicalHeight() - bordersPlusPadding;
3019 LayoutUnit logicalTopValue = 0;
3021 bool logicalHeightIsAuto = logicalHeightLength.isAuto();
3022 bool logicalTopIsAuto = logicalTop.isAuto();
3023 bool logicalBottomIsAuto = logicalBottom.isAuto();
3024 RenderView* renderView = view();
3026 // Height is never unsolved for tables.
3028 logicalHeightLength.setValue(Fixed, contentLogicalHeight);
3029 logicalHeightIsAuto = false;
3032 if (!logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsAuto) {
3033 /*-----------------------------------------------------------------------*\
3034 * If none of the three are 'auto': If both 'margin-top' and 'margin-
3035 * bottom' are 'auto', solve the equation under the extra constraint that
3036 * the two margins get equal values. If one of 'margin-top' or 'margin-
3037 * bottom' is 'auto', solve the equation for that value. If the values
3038 * are over-constrained, ignore the value for 'bottom' and solve for that
3040 \*-----------------------------------------------------------------------*/
3041 // NOTE: It is not necessary to solve for 'bottom' in the over constrained
3042 // case because the value is not used for any further calculations.
3044 logicalHeightValue = computeContentBoxLogicalHeight(valueForLength(logicalHeightLength, containerLogicalHeight, renderView));
3045 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
3047 const LayoutUnit availableSpace = containerLogicalHeight - (logicalTopValue + logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight, renderView) + bordersPlusPadding);
3049 // Margins are now the only unknown
3050 if (marginBefore.isAuto() && marginAfter.isAuto()) {
3051 // Both margins auto, solve for equality
3052 // NOTE: This may result in negative values.
3053 marginBeforeValue = availableSpace / 2; // split the difference
3054 marginAfterValue = availableSpace - marginBeforeValue; // account for odd valued differences
3055 } else if (marginBefore.isAuto()) {
3056 // Solve for top margin
3057 marginAfterValue = valueForLength(marginAfter, containerLogicalHeight, renderView);
3058 marginBeforeValue = availableSpace - marginAfterValue;
3059 } else if (marginAfter.isAuto()) {
3060 // Solve for bottom margin
3061 marginBeforeValue = valueForLength(marginBefore, containerLogicalHeight, renderView);
3062 marginAfterValue = availableSpace - marginBeforeValue;
3064 // Over-constrained, (no need solve for bottom)
3065 marginBeforeValue = valueForLength(marginBefore, containerLogicalHeight, renderView);
3066 marginAfterValue = valueForLength(marginAfter, containerLogicalHeight, renderView);
3069 /*--------------------------------------------------------------------*\
3070 * Otherwise, set 'auto' values for 'margin-top' and 'margin-bottom'
3071 * to 0, and pick the one of the following six rules that applies.
3073 * 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then
3074 * the height is based on the content, and solve for 'top'.
3076 * OMIT RULE 2 AS IT SHOULD NEVER BE HIT
3077 * ------------------------------------------------------------------
3078 * 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then
3079 * set 'top' to the static position, and solve for 'bottom'.
3080 * ------------------------------------------------------------------
3082 * 3. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then
3083 * the height is based on the content, and solve for 'bottom'.
3084 * 4. 'top' is 'auto', 'height' and 'bottom' are not 'auto', and
3086 * 5. 'height' is 'auto', 'top' and 'bottom' are not 'auto', and
3087 * solve for 'height'.
3088 * 6. 'bottom' is 'auto', 'top' and 'height' are not 'auto', and
3089 * solve for 'bottom'.
3090 \*--------------------------------------------------------------------*/
3091 // NOTE: For rules 3 and 6 it is not necessary to solve for 'bottom'
3092 // because the value is not used for any further calculations.
3094 // Calculate margins, 'auto' margins are ignored.
3095 marginBeforeValue = minimumValueForLength(marginBefore, containerLogicalHeight, renderView);
3096 marginAfterValue = minimumValueForLength(marginAfter, containerLogicalHeight, renderView);
3098 const LayoutUnit availableSpace = containerLogicalHeight - (marginBeforeValue + marginAfterValue + bordersPlusPadding);
3100 // Use rule/case that applies.
3101 if (logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) {
3102 // RULE 1: (height is content based, solve of top)
3103 logicalHeightValue = contentLogicalHeight;
3104 logicalTopValue = availableSpace - (logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight, renderView));
3105 } else if (!logicalTopIsAuto && logicalHeightIsAuto && logicalBottomIsAuto) {
3106 // RULE 3: (height is content based, no need solve of bottom)
3107 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
3108 logicalHeightValue = contentLogicalHeight;
3109 } else if (logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsAuto) {
3110 // RULE 4: (solve of top)
3111 logicalHeightValue = computeContentBoxLogicalHeight(valueForLength(logicalHeightLength, containerLogicalHeight, renderView));
3112 logicalTopValue = availableSpace - (logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight, renderView));
3113 } else if (!logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) {
3114 // RULE 5: (solve of height)
3115 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
3116 logicalHeightValue = max<LayoutUnit>(0, availableSpace - (logicalTopValue + valueForLength(logicalBottom, containerLogicalHeight, renderView)));
3117 } else if (!logicalTopIsAuto && !logicalHeightIsAuto && logicalBottomIsAuto) {
3118 // RULE 6: (no need solve of bottom)
3119 logicalHeightValue = computeContentBoxLogicalHeight(valueForLength(logicalHeightLength, containerLogicalHeight, renderView));
3120 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
3124 // Use computed values to calculate the vertical position.
3125 logicalTopPos = logicalTopValue + marginBeforeValue;
3126 computeLogicalTopPositionedOffset(logicalTopPos, this, logicalHeightValue, containerBlock, containerLogicalHeight);
3129 void RenderBox::computePositionedLogicalWidthReplaced()
3131 // The following is based off of the W3C Working Draft from April 11, 2006 of
3132 // CSS 2.1: Section 10.3.8 "Absolutely positioned, replaced elements"
3133 // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-width>
3134 // (block-style-comments in this function correspond to text from the spec and
3135 // the numbers correspond to numbers in spec)
3137 // We don't use containingBlock(), since we may be positioned by an enclosing
3138 // relative positioned inline.
3139 const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
3141 const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock);
3143 // To match WinIE, in quirks mode use the parent's 'direction' property
3144 // instead of the the container block's.
3145 TextDirection containerDirection = containerBlock->style()->direction();
3147 // Variables to solve.
3148 bool isHorizontal = isHorizontalWritingMode();
3149 Length logicalLeft = style()->logicalLeft();
3150 Length logicalRight = style()->logicalRight();
3151 Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->marginTop();
3152 Length marginLogicalRight = isHorizontal ? style()->marginRight() : style()->marginBottom();
3153 LayoutUnit& marginLogicalLeftAlias = m_marginBox.mutableLogicalLeft(style()->writingMode());
3154 LayoutUnit& marginLogicalRightAlias = m_marginBox.mutableLogicalRight(style()->writingMode());
3156 /*-----------------------------------------------------------------------*\
3157 * 1. The used value of 'width' is determined as for inline replaced
3159 \*-----------------------------------------------------------------------*/
3160 // NOTE: This value of width is FINAL in that the min/max width calculations
3161 // are dealt with in computeReplacedWidth(). This means that the steps to produce
3162 // correct max/min in the non-replaced version, are not necessary.
3163 setLogicalWidth(computeReplacedLogicalWidth() + borderAndPaddingLogicalWidth());
3165 const LayoutUnit availableSpace = containerLogicalWidth - logicalWidth();
3167 /*-----------------------------------------------------------------------*\
3168 * 2. If both 'left' and 'right' have the value 'auto', then if 'direction'
3169 * of the containing block is 'ltr', set 'left' to the static position;
3170 * else if 'direction' is 'rtl', set 'right' to the static position.
3171 \*-----------------------------------------------------------------------*/
3173 computeInlineStaticDistance(logicalLeft, logicalRight, this, containerBlock, containerLogicalWidth, 0); // FIXME: Pass the region.
3175 /*-----------------------------------------------------------------------*\
3176 * 3. If 'left' or 'right' are 'auto', replace any 'auto' on 'margin-left'
3177 * or 'margin-right' with '0'.
3178 \*-----------------------------------------------------------------------*/
3179 if (logicalLeft.isAuto() || logicalRight.isAuto()) {
3180 if (marginLogicalLeft.isAuto())
3181 marginLogicalLeft.setValue(Fixed, 0);
3182 if (marginLogicalRight.isAuto())
3183 marginLogicalRight.setValue(Fixed, 0);
3186 /*-----------------------------------------------------------------------*\
3187 * 4. If at this point both 'margin-left' and 'margin-right' are still
3188 * 'auto', solve the equation under the extra constraint that the two
3189 * margins must get equal values, unless this would make them negative,
3190 * in which case when the direction of the containing block is 'ltr'
3191 * ('rtl'), set 'margin-left' ('margin-right') to zero and solve for
3192 * 'margin-right' ('margin-left').
3193 \*-----------------------------------------------------------------------*/
3194 LayoutUnit logicalLeftValue = 0;
3195 LayoutUnit logicalRightValue = 0;
3196 RenderView* renderView = view();
3198 if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) {
3199 // 'left' and 'right' cannot be 'auto' due to step 3
3200 ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto()));
3202 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
3203 logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView);
3205 LayoutUnit difference = availableSpace - (logicalLeftValue + logicalRightValue);
3206 if (difference > 0) {
3207 marginLogicalLeftAlias = difference / 2; // split the difference
3208 marginLogicalRightAlias = difference - marginLogicalLeftAlias; // account for odd valued differences
3210 // Use the containing block's direction rather than the parent block's
3211 // per CSS 2.1 reference test abspos-replaced-width-margin-000.
3212 if (containerDirection == LTR) {
3213 marginLogicalLeftAlias = 0;
3214 marginLogicalRightAlias = difference; // will be negative
3216 marginLogicalLeftAlias = difference; // will be negative
3217 marginLogicalRightAlias = 0;
3221 /*-----------------------------------------------------------------------*\
3222 * 5. If at this point there is an 'auto' left, solve the equation for
3224 \*-----------------------------------------------------------------------*/
3225 } else if (logicalLeft.isAuto()) {
3226 marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerLogicalWidth, renderView);
3227 marginLogicalRightAlias = valueForLength(marginLogicalRight, containerLogicalWidth, renderView);
3228 logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView);
3231 logicalLeftValue = availableSpace - (logicalRightValue + marginLogicalLeftAlias + marginLogicalRightAlias);
3232 } else if (logicalRight.isAuto()) {
3233 marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerLogicalWidth, renderView);
3234 marginLogicalRightAlias = valueForLength(marginLogicalRight, containerLogicalWidth, renderView);
3235 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
3237 // Solve for 'right'
3238 logicalRightValue = availableSpace - (logicalLeftValue + marginLogicalLeftAlias + marginLogicalRightAlias);
3239 } else if (marginLogicalLeft.isAuto()) {
3240 marginLogicalRightAlias = valueForLength(marginLogicalRight, containerLogicalWidth, renderView);
3241 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
3242 logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView);
3244 // Solve for 'margin-left'
3245 marginLogicalLeftAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalRightAlias);
3246 } else if (marginLogicalRight.isAuto()) {
3247 marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerLogicalWidth, renderView);
3248 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
3249 logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView);
3251 // Solve for 'margin-right'
3252 marginLogicalRightAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalLeftAlias);
3254 // Nothing is 'auto', just calculate the values.
3255 marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerLogicalWidth, renderView);
3256 marginLogicalRightAlias = valueForLength(marginLogicalRight, containerLogicalWidth, renderView);
3257 logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView);
3258 logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
3259 // If the containing block is right-to-left, then push the left position as far to the right as possible
3260 if (containerDirection == RTL) {
3261 int totalLogicalWidth = logicalWidth() + logicalLeftValue + logicalRightValue + marginLogicalLeftAlias + marginLogicalRightAlias;
3262 logicalLeftValue = containerLogicalWidth - (totalLogicalWidth - logicalLeftValue);
3266 /*-----------------------------------------------------------------------*\
3267 * 6. If at this point the values are over-constrained, ignore the value
3268 * for either 'left' (in case the 'direction' property of the
3269 * containing block is 'rtl') or 'right' (in case 'direction' is
3270 * 'ltr') and solve for that value.
3271 \*-----------------------------------------------------------------------*/
3272 // NOTE: Constraints imposed by the width of the containing block and its content have already been accounted for above.
3274 // FIXME: Deal with differing writing modes here. Our offset needs to be in the containing block's coordinate space, so that
3275 // can make the result here rather complicated to compute.
3277 // Use computed values to calculate the horizontal position.
3279 // FIXME: This hack is needed to calculate the logical left position for a 'rtl' relatively
3280 // positioned, inline containing block because right now, it is using the logical left position
3281 // of the first line box when really it should use the last line box. When
3282 // this is fixed elsewhere, this block should be removed.
3283 if (containerBlock->isRenderInline() && !containerBlock->style()->isLeftToRightDirection()) {
3284 const RenderInline* flow = toRenderInline(containerBlock);
3285 InlineFlowBox* firstLine = flow->firstLineBox();
3286 InlineFlowBox* lastLine = flow->lastLineBox();
3287 if (firstLine && lastLine && firstLine != lastLine) {
3288 setLogicalLeft(logicalLeftValue + marginLogicalLeftAlias + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logicalLeft()));
3293 LayoutUnit logicalLeftPos = logicalLeftValue + marginLogicalLeftAlias;
3294 computeLogicalLeftPositionedOffset(logicalLeftPos, this, logicalWidth(), containerBlock, containerLogicalWidth);
3295 setLogicalLeft(logicalLeftPos.round());
3298 void RenderBox::computePositionedLogicalHeightReplaced()
3300 // The following is based off of the W3C Working Draft from April 11, 2006 of
3301 // CSS 2.1: Section 10.6.5 "Absolutely positioned, replaced elements"
3302 // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-height>
3303 // (block-style-comments in this function correspond to text from the spec and
3304 // the numbers correspond to numbers in spec)
3306 // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
3307 const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
3309 const LayoutUnit containerLogicalHeight = containingBlockLogicalHeightForPositioned(containerBlock);
3311 // Variables to solve.
3312 Length marginBefore = style()->marginBefore();
3313 Length marginAfter = style()->marginAfter();
3314 LayoutUnit& marginBeforeAlias = m_marginBox.mutableBefore(style()->writingMode());
3315 LayoutUnit& marginAfterAlias = m_marginBox.mutableAfter(style()->writingMode());
3317 Length logicalTop = style()->logicalTop();
3318 Length logicalBottom = style()->logicalBottom();
3319 RenderView* renderView = view();
3321 /*-----------------------------------------------------------------------*\
3322 * 1. The used value of 'height' is determined as for inline replaced
3324 \*-----------------------------------------------------------------------*/
3325 // NOTE: This value of height is FINAL in that the min/max height calculations
3326 // are dealt with in computeReplacedHeight(). This means that the steps to produce
3327 // correct max/min in the non-replaced version, are not necessary.
3328 setLogicalHeight(computeReplacedLogicalHeight() + borderAndPaddingLogicalHeight());
3329 const LayoutUnit availableSpace = containerLogicalHeight - logicalHeight();
3331 /*-----------------------------------------------------------------------*\
3332 * 2. If both 'top' and 'bottom' have the value 'auto', replace 'top'
3333 * with the element's static position.
3334 \*-----------------------------------------------------------------------*/
3336 computeBlockStaticDistance(logicalTop, logicalBottom, this, containerBlock);
3338 /*-----------------------------------------------------------------------*\
3339 * 3. If 'bottom' is 'auto', replace any 'auto' on 'margin-top' or
3340 * 'margin-bottom' with '0'.
3341 \*-----------------------------------------------------------------------*/
3342 // FIXME: The spec. says that this step should only be taken when bottom is
3343 // auto, but if only top is auto, this makes step 4 impossible.
3344 if (logicalTop.isAuto() || logicalBottom.isAuto()) {
3345 if (marginBefore.isAuto())
3346 marginBefore.setValue(Fixed, 0);
3347 if (marginAfter.isAuto())
3348 marginAfter.setValue(Fixed, 0);
3351 /*-----------------------------------------------------------------------*\
3352 * 4. If at this point both 'margin-top' and 'margin-bottom' are still
3353 * 'auto', solve the equation under the extra constraint that the two
3354 * margins must get equal values.
3355 \*-----------------------------------------------------------------------*/
3356 LayoutUnit logicalTopValue = 0;
3357 LayoutUnit logicalBottomValue = 0;
3359 if (marginBefore.isAuto() && marginAfter.isAuto()) {
3360 // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combined.
3361 ASSERT(!(logicalTop.isAuto() || logicalBottom.isAuto()));
3363 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
3364 logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight, renderView);
3366 LayoutUnit difference = availableSpace - (logicalTopValue + logicalBottomValue);
3367 // NOTE: This may result in negative values.
3368 marginBeforeAlias = difference / 2; // split the difference
3369 marginAfterAlias = difference - marginBeforeAlias; // account for odd valued differences
3371 /*-----------------------------------------------------------------------*\
3372 * 5. If at this point there is only one 'auto' left, solve the equation
3374 \*-----------------------------------------------------------------------*/
3375 } else if (logicalTop.isAuto()) {
3376 marginBeforeAlias = valueForLength(marginBefore, containerLogicalHeight, renderView);
3377 marginAfterAlias = valueForLength(marginAfter, containerLogicalHeight, renderView);
3378 logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight, renderView);
3381 logicalTopValue = availableSpace - (logicalBottomValue + marginBeforeAlias + marginAfterAlias);
3382 } else if (logicalBottom.isAuto()) {
3383 marginBeforeAlias = valueForLength(marginBefore, containerLogicalHeight, renderView);
3384 marginAfterAlias = valueForLength(marginAfter, containerLogicalHeight, renderView);
3385 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
3387 // Solve for 'bottom'
3388 // NOTE: It is not necessary to solve for 'bottom' because we don't ever
3390 } else if (marginBefore.isAuto()) {
3391 marginAfterAlias = valueForLength(marginAfter, containerLogicalHeight, renderView);
3392 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
3393 logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight, renderView);
3395 // Solve for 'margin-top'
3396 marginBeforeAlias = availableSpace - (logicalTopValue + logicalBottomValue + marginAfterAlias);
3397 } else if (marginAfter.isAuto()) {
3398 marginBeforeAlias = valueForLength(marginBefore, containerLogicalHeight, renderView);
3399 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
3400 logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight, renderView);
3402 // Solve for 'margin-bottom'
3403 marginAfterAlias = availableSpace - (logicalTopValue + logicalBottomValue + marginBeforeAlias);
3405 // Nothing is 'auto', just calculate the values.
3406 marginBeforeAlias = valueForLength(marginBefore, containerLogicalHeight, renderView);
3407 marginAfterAlias = valueForLength(marginAfter, containerLogicalHeight, renderView);
3408 logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
3409 // NOTE: It is not necessary to solve for 'bottom' because we don't ever
3413 /*-----------------------------------------------------------------------*\
3414 * 6. If at this point the values are over-constrained, ignore the value
3415 * for 'bottom' and solve for that value.
3416 \*-----------------------------------------------------------------------*/
3417 // NOTE: It is not necessary to do this step because we don't end up using
3418 // the value of 'bottom' regardless of whether the values are over-constrained
3421 // Use computed values to calculate the vertical position.
3422 LayoutUnit logicalTopPos = logicalTopValue + marginBeforeAlias;
3423 computeLogicalTopPositionedOffset(logicalTopPos, this, logicalHeight(), containerBlock, containerLogicalHeight);
3424 setLogicalTop(logicalTopPos.round());
3427 LayoutRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, LayoutUnit* extraWidthToEndOfLine)
3429 // VisiblePositions at offsets inside containers either a) refer to the positions before/after
3430 // those containers (tables and select elements) or b) refer to the position inside an empty block.
3431 // They never refer to children.
3432 // FIXME: Paint the carets inside empty blocks differently than the carets before/after elements.
3434 // FIXME: What about border and padding?
3435 LayoutRect rect(location(), LayoutSize(caretWidth, height()));
3436 bool ltr = box ? box->isLeftToRightDirection() : style()->isLeftToRightDirection();
3438 if ((!caretOffset) ^ ltr)
3439 rect.move(LayoutSize(width() - caretWidth, 0));
3442 RootInlineBox* rootBox = box->root();
3443 LayoutUnit top = rootBox->lineTop();
3445 rect.setHeight(rootBox->lineBottom() - top);
3448 // If height of box is smaller than font height, use the latter one,
3449 // otherwise the caret might become invisible.
3451 // Also, if the box is not a replaced element, always use the font height.
3452 // This prevents the "big caret" bug described in:
3453 // <rdar://problem/3777804> Deleting all content in a document can result in giant tall-as-window insertion point
3455 // FIXME: ignoring :first-line, missing good reason to take care of
3456 LayoutUnit fontHeight = style()->fontMetrics().height();
3457 if (fontHeight > rect.height() || (!isReplaced() && !isTable()))
3458 rect.setHeight(fontHeight);
3460 if (extraWidthToEndOfLine)
3461 *extraWidthToEndOfLine = x() + width() - rect.maxX();
3463 // Move to local coords
3464 rect.moveBy(-location());
3468 VisiblePosition RenderBox::positionForPoint(const LayoutPoint& point)
3470 // no children...return this render object's element, if there is one, and offset 0
3472 return createVisiblePosition(node() ? firstPositionInOrBeforeNode(node()) : Position());
3474 if (isTable() && node()) {
3475 LayoutUnit right = contentWidth() + borderAndPaddingWidth();
3476 LayoutUnit bottom = contentHeight() + borderAndPaddingHeight();
3478 if (point.x() < 0 || point.x() > right || point.y() < 0 || point.y() > bottom) {
3479 if (point.x() <= right / 2)
3480 return createVisiblePosition(firstPositionInOrBeforeNode(node()));
3481 return createVisiblePosition(lastPositionInOrAfterNode(node()));
3485 // Pass off to the closest child.
3486 LayoutUnit minDist = MAX_LAYOUT_UNIT;
3487 RenderBox* closestRenderer = 0;
3488 LayoutPoint adjustedPoint = point;
3490 adjustedPoint.moveBy(location());
3492 for (RenderObject* renderObject = firstChild(); renderObject; renderObject = renderObject->nextSibling()) {
3493 if ((!renderObject->firstChild() && !renderObject->isInline() && !renderObject->isBlockFlow() )
3494 || renderObject->style()->visibility() != VISIBLE)
3497 if (!renderObject->isBox())
3500 RenderBox* renderer = toRenderBox(renderObject);
3502 LayoutUnit top = renderer->borderTop() + renderer->paddingTop() + (isTableRow() ? ZERO_LAYOUT_UNIT : renderer->y());
3503 LayoutUnit bottom = top + renderer->contentHeight();
3504 LayoutUnit left = renderer->borderLeft() + renderer->paddingLeft() + (isTableRow() ? ZERO_LAYOUT_UNIT : renderer->x());
3505 LayoutUnit right = left + renderer->contentWidth();
3507 if (point.x() <= right && point.x() >= left && point.y() <= top && point.y() >= bottom) {
3508 if (renderer->isTableRow())
3509 return renderer->positionForPoint(point + adjustedPoint - renderer->locationOffset());
3510 return renderer->positionForPoint(point - renderer->locationOffset());
3513 // Find the distance from (x, y) to the box. Split the space around the box into 8 pieces
3514 // and use a different compare depending on which piece (x, y) is in.
3516 if (point.x() > right) {
3517 if (point.y() < top)
3518 cmp = LayoutPoint(right, top);
3519 else if (point.y() > bottom)
3520 cmp = LayoutPoint(right, bottom);
3522 cmp = LayoutPoint(right, point.y());
3523 } else if (point.x() < left) {
3524 if (point.y() < top)
3525 cmp = LayoutPoint(left, top);
3526 else if (point.y() > bottom)
3527 cmp = LayoutPoint(left, bottom);
3529 cmp = LayoutPoint(left, point.y());
3531 if (point.y() < top)
3532 cmp = LayoutPoint(point.x(), top);
3534 cmp = LayoutPoint(point.x(), bottom);
3537 LayoutSize difference = cmp - point;
3539 LayoutUnit dist = difference.width() * difference.width() + difference.height() * difference.height();
3540 if (dist < minDist) {
3541 closestRenderer = renderer;
3546 if (closestRenderer)
3547 return closestRenderer->positionForPoint(adjustedPoint - closestRenderer->locationOffset());
3549 return createVisiblePosition(firstPositionInOrBeforeNode(node()));
3552 bool RenderBox::shrinkToAvoidFloats() const
3554 // Floating objects don't shrink. Objects that don't avoid floats don't shrink. Marquees don't shrink.
3555 if ((isInline() && !isHTMLMarquee()) || !avoidsFloats() || isFloating())
3558 // Only auto width objects can possibly shrink to avoid floats.
3559 return style()->width().isAuto();
3562 bool RenderBox::avoidsFloats() const
3564 return isReplaced() || hasOverflowClip() || isHR() || isLegend() || isWritingModeRoot() || isDeprecatedFlexItem();
3567 void RenderBox::addVisualEffectOverflow()
3569 if (!style()->boxShadow() && !style()->hasBorderImageOutsets())
3572 bool isFlipped = style()->isFlippedBlocksWritingMode();
3573 bool isHorizontal = isHorizontalWritingMode();
3575 LayoutRect borderBox = borderBoxRect();
3576 LayoutUnit overflowMinX = borderBox.x();
3577 LayoutUnit overflowMaxX = borderBox.maxX();
3578 LayoutUnit overflowMinY = borderBox.y();
3579 LayoutUnit overflowMaxY = borderBox.maxY();
3581 // Compute box-shadow overflow first.
3582 if (style()->boxShadow()) {
3583 LayoutUnit shadowLeft;
3584 LayoutUnit shadowRight;
3585 LayoutUnit shadowTop;
3586 LayoutUnit shadowBottom;
3587 style()->getBoxShadowExtent(shadowTop, shadowRight, shadowBottom, shadowLeft);
3589 // In flipped blocks writing modes such as vertical-rl, the physical right shadow value is actually at the lower x-coordinate.
3590 overflowMinX = borderBox.x() + ((!isFlipped || isHorizontal) ? shadowLeft : -shadowRight);
3591 overflowMaxX = borderBox.maxX() + ((!isFlipped || isHorizontal) ? shadowRight : -shadowLeft);
3592 overflowMinY = borderBox.y() + ((!isFlipped || !isHorizontal) ? shadowTop : -shadowBottom);
3593 overflowMaxY = borderBox.maxY() + ((!isFlipped || !isHorizontal) ? shadowBottom : -shadowTop);
3596 // Now compute border-image-outset overflow.
3597 if (style()->hasBorderImageOutsets()) {
3598 LayoutBoxExtent borderOutsets = style()->borderImageOutsets();
3600 // In flipped blocks writing modes, the physical sides are inverted. For example in vertical-rl, the right
3601 // border is at the lower x coordinate value.
3602 overflowMinX = min(overflowMinX, borderBox.x() - ((!isFlipped || isHorizontal) ? borderOutsets.left() : borderOutsets.right()));
3603 overflowMaxX = max(overflowMaxX, borderBox.maxX() + ((!isFlipped || isHorizontal) ? borderOutsets.right() : borderOutsets.left()));
3604 overflowMinY = min(overflowMinY, borderBox.y() - ((!isFlipped || !isHorizontal) ? borderOutsets.top() : borderOutsets.bottom()));
3605 overflowMaxY = max(overflowMaxY, borderBox.maxY() + ((!isFlipped || !isHorizontal) ? borderOutsets.bottom() : borderOutsets.top()));
3608 // Add in the final overflow with shadows and outsets combined.
3609 addVisualOverflow(LayoutRect(overflowMinX, overflowMinY, overflowMaxX - overflowMinX, overflowMaxY - overflowMinY));
3612 void RenderBox::addOverflowFromChild(RenderBox* child, const LayoutSize& delta)
3614 // Only propagate layout overflow from the child if the child isn't clipping its overflow. If it is, then
3615 // its overflow is internal to it, and we don't care about it. layoutOverflowRectForPropagation takes care of this
3616 // and just propagates the border box rect instead.
3617 LayoutRect childLayoutOverflowRect = child->layoutOverflowRectForPropagation(style());
3618 childLayoutOverflowRect.move(delta);
3619 addLayoutOverflow(childLayoutOverflowRect);
3621 // Add in visual overflow from the child. Even if the child clips its overflow, it may still
3622 // have visual overflow of its own set from box shadows or reflections. It is unnecessary to propagate this
3623 // overflow if we are clipping our own overflow.
3624 if (child->hasSelfPaintingLayer() || hasOverflowClip())
3626 LayoutRect childVisualOverflowRect = child->visualOverflowRectForPropagation(style());
3627 childVisualOverflowRect.move(delta);
3628 addVisualOverflow(childVisualOverflowRect);
3631 void RenderBox::addLayoutOverflow(const LayoutRect& rect)
3633 LayoutRect clientBox = clientBoxRect();
3634 if (clientBox.contains(rect) || rect.isEmpty())
3637 // For overflow clip objects, we don't want to propagate overflow into unreachable areas.
3638 LayoutRect overflowRect(rect);
3639 if (hasOverflowClip() || isRenderView()) {
3640 // Overflow is in the block's coordinate space and thus is flipped for horizontal-bt and vertical-rl
3641 // writing modes. At this stage that is actually a simplification, since we can treat horizontal-tb/bt as the same
3642 // and vertical-lr/rl as the same.
3643 bool hasTopOverflow = !style()->isLeftToRightDirection() && !isHorizontalWritingMode();
3644 bool hasLeftOverflow = !style()->isLeftToRightDirection() && isHorizontalWritingMode();
3645 if (isFlexibleBox() && style()->isReverseFlexDirection()) {
3646 RenderFlexibleBox* flexibleBox = static_cast<RenderFlexibleBox*>(this);
3647 if (flexibleBox->isHorizontalFlow())
3648 hasLeftOverflow = true;
3650 hasTopOverflow = true;
3653 if (hasColumns() && style()->columnProgression() == ReverseColumnProgression) {
3654 if (isHorizontalWritingMode() ^ !style()->hasInlineColumnAxis())
3655 hasLeftOverflow = !hasLeftOverflow;
3657 hasTopOverflow = !hasTopOverflow;
3660 if (!hasTopOverflow)
3661 overflowRect.shiftYEdgeTo(max(overflowRect.y(), clientBox.y()));
3663 overflowRect.shiftMaxYEdgeTo(min(overflowRect.maxY(), clientBox.maxY()));
3664 if (!hasLeftOverflow)
3665 overflowRect.shiftXEdgeTo(max(overflowRect.x(), clientBox.x()));
3667 overflowRect.shiftMaxXEdgeTo(min(overflowRect.maxX(), clientBox.maxX()));
3669 // Now re-test with the adjusted rectangle and see if it has become unreachable or fully
3671 if (clientBox.contains(overflowRect) || overflowRect.isEmpty())
3676 m_overflow = adoptPtr(new RenderOverflow(clientBox, borderBoxRect()));
3678 m_overflow->addLayoutOverflow(overflowRect);
3681 void RenderBox::addVisualOverflow(const LayoutRect& rect)
3683 LayoutRect borderBox = borderBoxRect();
3684 if (borderBox.contains(rect) || rect.isEmpty())
3688 m_overflow = adoptPtr(new RenderOverflow(clientBoxRect(), borderBox));
3690 m_overflow->addVisualOverflow(rect);
3693 void RenderBox::clearLayoutOverflow()
3698 if (visualOverflowRect() == borderBoxRect()) {
3703 m_overflow->setLayoutOverflow(borderBoxRect());
3706 static bool percentageLogicalHeightIsResolvable(const RenderBox* box)
3708 // In quirks mode, blocks with auto height are skipped, and we keep looking for an enclosing
3709 // block that may have a specified height and then use it. In strict mode, this violates the
3710 // specification, which states that percentage heights just revert to auto if the containing
3711 // block has an auto height. We still skip anonymous containing blocks in both modes, though, and look
3712 // only at explicit containers.
3713 const RenderBlock* cb = box->containingBlock();
3714 while (!cb->isRenderView() && !cb->isBody() && !cb->isTableCell() && !cb->isOutOfFlowPositioned() && cb->style()->logicalHeight().isAuto()) {
3715 if (!box->document()->inQuirksMode() && !cb->isAnonymousBlock())
3717 cb = cb->containingBlock();
3720 // A positioned element that specified both top/bottom or that specifies height should be treated as though it has a height
3721 // explicitly specified that can be used for any percentage computations.
3722 // FIXME: We can't just check top/bottom here.
3723 // https://bugs.webkit.org/show_bug.cgi?id=46500
3724 bool isOutOfFlowPositionedWithSpecifiedHeight = cb->isOutOfFlowPositioned() && (!cb->style()->logicalHeight().isAuto() || (!cb->style()->top().isAuto() && !cb->style()->bottom().isAuto()));
3726 // Table cells violate what the CSS spec says to do with heights. Basically we
3727 // don't care if the cell specified a height or not. We just always make ourselves
3728 // be a percentage of the cell's current content height.
3729 if (cb->isTableCell())
3732 // Otherwise we only use our percentage height if our containing block had a specified
3734 if (cb->style()->logicalHeight().isFixed())
3736 if (cb->style()->logicalHeight().isPercent() && !isOutOfFlowPositionedWithSpecifiedHeight)
3737 return percentageLogicalHeightIsResolvable(cb);
3738 if (cb->isRenderView() || (cb->isBody() && box->document()->inQuirksMode()) || isOutOfFlowPositionedWithSpecifiedHeight)
3740 if (cb->isRoot() && box->isOutOfFlowPositioned()) {
3741 // Match the positioned objects behavior, which is that positioned objects will fill their viewport
3742 // always. Note we could only hit this case by recurring into computePercentageLogicalHeight on a positioned containing block.
3749 bool RenderBox::hasUnsplittableScrollingOverflow() const
3751 // We will paginate as long as we don't scroll overflow in the pagination direction.
3752 bool isHorizontal = isHorizontalWritingMode();
3753 if ((isHorizontal && !scrollsOverflowY()) || (!isHorizontal && !scrollsOverflowX()))
3756 // We do have overflow. We'll still be willing to paginate as long as the block
3757 // has auto logical height, auto or undefined max-logical-height and a zero or auto min-logical-height.
3758 // Note this is just a heuristic, and it's still possible to have overflow under these
3759 // conditions, but it should work out to be good enough for common cases. Paginating overflow
3760 // with scrollbars present is not the end of the world and is what we used to do in the old model anyway.
3761 return !style()->logicalHeight().isIntrinsicOrAuto()
3762 || (!style()->logicalMaxHeight().isIntrinsicOrAuto() && !style()->logicalMaxHeight().isUndefined() && (!style()->logicalMaxHeight().isPercent() || percentageLogicalHeightIsResolvable(this)))
3763 || (!style()->logicalMinHeight().isIntrinsicOrAuto() && style()->logicalMinHeight().isPositive() && (!style()->logicalMinHeight().isPercent() || percentageLogicalHeightIsResolvable(this)));
3766 bool RenderBox::isUnsplittableForPagination() const
3768 return isReplaced() || hasUnsplittableScrollingOverflow() || (parent() && isWritingModeRoot());
3771 LayoutUnit RenderBox::lineHeight(bool /*firstLine*/, LineDirectionMode direction, LinePositionMode /*linePositionMode*/) const
3774 return direction == HorizontalLine ? m_marginBox.top() + height() + m_marginBox.bottom() : m_marginBox.right() + width() + m_marginBox.left();
3778 LayoutUnit RenderBox::baselinePosition(FontBaseline baselineType, bool /*firstLine*/, LineDirectionMode direction, LinePositionMode /*linePositionMode*/) const
3781 LayoutUnit result = direction == HorizontalLine ? m_marginBox.top() + height() + m_marginBox.bottom() : m_marginBox.right() + width() + m_marginBox.left();
3782 if (baselineType == AlphabeticBaseline)
3784 return result - result / 2;
3790 RenderLayer* RenderBox::enclosingFloatPaintingLayer() const
3792 const RenderObject* curr = this;
3794 RenderLayer* layer = curr->hasLayer() && curr->isBox() ? toRenderBoxModelObject(curr)->layer() : 0;
3795 if (layer && layer->isSelfPaintingLayer())
3797 curr = curr->parent();
3802 LayoutRect RenderBox::logicalVisualOverflowRectForPropagation(RenderStyle* parentStyle) const
3804 LayoutRect rect = visualOverflowRectForPropagation(parentStyle);
3805 if (!parentStyle->isHorizontalWritingMode())
3806 return rect.transposedRect();
3810 LayoutRect RenderBox::visualOverflowRectForPropagation(RenderStyle* parentStyle) const
3812 // If the writing modes of the child and parent match, then we don't have to
3813 // do anything fancy. Just return the result.
3814 LayoutRect rect = visualOverflowRect();
3815 if (parentStyle->writingMode() == style()->writingMode())
3818 // We are putting ourselves into our parent's coordinate space. If there is a flipped block mismatch
3819 // in a particular axis, then we have to flip the rect along that axis.
3820 if (style()->writingMode() == RightToLeftWritingMode || parentStyle->writingMode() == RightToLeftWritingMode)
3821 rect.setX(width() - rect.maxX());
3822 else if (style()->writingMode() == BottomToTopWritingMode || parentStyle->writingMode() == BottomToTopWritingMode)
3823 rect.setY(height() - rect.maxY());
3828 LayoutRect RenderBox::logicalLayoutOverflowRectForPropagation(RenderStyle* parentStyle) const
3830 LayoutRect rect = layoutOverflowRectForPropagation(parentStyle);
3831 if (!parentStyle->isHorizontalWritingMode())
3832 return rect.transposedRect();
3836 LayoutRect RenderBox::layoutOverflowRectForPropagation(RenderStyle* parentStyle) const
3838 // Only propagate interior layout overflow if we don't clip it.
3839 LayoutRect rect = borderBoxRect();
3840 if (!hasOverflowClip())
3841 rect.unite(layoutOverflowRect());
3843 bool hasTransform = hasLayer() && layer()->transform();
3844 if (isRelPositioned() || hasTransform) {
3845 // If we are relatively positioned or if we have a transform, then we have to convert
3846 // this rectangle into physical coordinates, apply relative positioning and transforms
3847 // to it, and then convert it back.
3848 flipForWritingMode(rect);
3851 rect = layer()->currentTransform().mapRect(rect);
3853 if (isRelPositioned())
3854 rect.move(relativePositionOffset());
3856 // Now we need to flip back.
3857 flipForWritingMode(rect);
3860 // If the writing modes of the child and parent match, then we don't have to
3861 // do anything fancy. Just return the result.
3862 if (parentStyle->writingMode() == style()->writingMode())
3865 // We are putting ourselves into our parent's coordinate space. If there is a flipped block mismatch
3866 // in a particular axis, then we have to flip the rect along that axis.
3867 if (style()->writingMode() == RightToLeftWritingMode || parentStyle->writingMode() == RightToLeftWritingMode)
3868 rect.setX(width() - rect.maxX());
3869 else if (style()->writingMode() == BottomToTopWritingMode || parentStyle->writingMode() == BottomToTopWritingMode)
3870 rect.setY(height() - rect.maxY());
3875 LayoutUnit RenderBox::offsetLeft() const
3877 return adjustedPositionRelativeToOffsetParent(topLeftLocation()).x();
3880 LayoutUnit RenderBox::offsetTop() const
3882 return adjustedPositionRelativeToOffsetParent(topLeftLocation()).y();
3885 LayoutPoint RenderBox::flipForWritingModeForChild(const RenderBox* child, const LayoutPoint& point) const
3887 if (!style()->isFlippedBlocksWritingMode())
3890 // The child is going to add in its x() and y(), so we have to make sure it ends up in
3892 if (isHorizontalWritingMode())
3893 return LayoutPoint(point.x(), point.y() + height() - child->height() - (2 * child->y()));
3894 return LayoutPoint(point.x() + width() - child->width() - (2 * child->x()), point.y());
3897 void RenderBox::flipForWritingMode(LayoutRect& rect) const
3899 if (!style()->isFlippedBlocksWritingMode())
3902 if (isHorizontalWritingMode())
3903 rect.setY(height() - rect.maxY());
3905 rect.setX(width() - rect.maxX());
3908 LayoutUnit RenderBox::flipForWritingMode(LayoutUnit position) const
3910 if (!style()->isFlippedBlocksWritingMode())
3912 return logicalHeight() - position;
3915 LayoutPoint RenderBox::flipForWritingMode(const LayoutPoint& position) const
3917 if (!style()->isFlippedBlocksWritingMode())
3919 return isHorizontalWritingMode() ? LayoutPoint(position.x(), height() - position.y()) : LayoutPoint(width() - position.x(), position.y());
3922 LayoutPoint RenderBox::flipForWritingModeIncludingColumns(const LayoutPoint& point) const
3924 if (!hasColumns() || !style()->isFlippedBlocksWritingMode())
3925 return flipForWritingMode(point);
3926 return toRenderBlock(this)->flipForWritingModeIncludingColumns(point);
3929 LayoutSize RenderBox::flipForWritingMode(const LayoutSize& offset) const
3931 if (!style()->isFlippedBlocksWritingMode())
3933 return isHorizontalWritingMode() ? LayoutSize(offset.width(), height() - offset.height()) : LayoutSize(width() - offset.width(), offset.height());
3936 FloatPoint RenderBox::flipForWritingMode(const FloatPoint& position) const
3938 if (!style()->isFlippedBlocksWritingMode())
3940 return isHorizontalWritingMode() ? FloatPoint(position.x(), height() - position.y()) : FloatPoint(width() - position.x(), position.y());
3943 void RenderBox::flipForWritingMode(FloatRect& rect) const
3945 if (!style()->isFlippedBlocksWritingMode())
3948 if (isHorizontalWritingMode())
3949 rect.setY(height() - rect.maxY());
3951 rect.setX(width() - rect.maxX());
3954 LayoutPoint RenderBox::topLeftLocation() const
3956 RenderBlock* containerBlock = containingBlock();
3957 if (!containerBlock || containerBlock == this)
3959 return containerBlock->flipForWritingModeForChild(this, location());
3962 LayoutSize RenderBox::topLeftLocationOffset() const
3964 RenderBlock* containerBlock = containingBlock();
3965 if (!containerBlock || containerBlock == this)
3966 return locationOffset();
3968 LayoutRect rect(frameRect());
3969 if (containerBlock->style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
3970 rect.move(containerBlock->verticalScrollbarWidth(), 0);
3971 containerBlock->flipForWritingMode(rect); // FIXME: This is wrong if we are an absolutely positioned object enclosed by a relative-positioned inline.
3972 return LayoutSize(rect.x(), rect.y());
3975 bool RenderBox::hasRelativeDimensions() const
3977 return style()->height().isPercent() || style()->width().isPercent()
3978 || style()->maxHeight().isPercent() || style()->maxWidth().isPercent()
3979 || style()->minHeight().isPercent() || style()->minWidth().isPercent();
3982 bool RenderBox::hasRelativeLogicalHeight() const
3984 return style()->logicalHeight().isPercent()
3985 || style()->logicalMinHeight().isPercent()
3986 || style()->logicalMaxHeight().isPercent();
3989 static void markBoxForRelayoutAfterSplit(RenderBox* box)
3991 // FIXME: The table code should handle that automatically. If not,
3992 // we should fix it and remove the table part checks.
3993 if (box->isTable()) {
3994 // Because we may have added some sections with already computed column structures, we need to
3995 // sync the table structure with them now. This avoids crashes when adding new cells to the table.
3996 toRenderTable(box)->forceSectionsRecalc();
3997 } else if (box->isTableSection())
3998 toRenderTableSection(box)->setNeedsCellRecalc();
4000 box->setNeedsLayoutAndPrefWidthsRecalc();
4003 RenderObject* RenderBox::splitAnonymousBoxesAroundChild(RenderObject* beforeChild)
4005 bool didSplitParentAnonymousBoxes = false;
4007 while (beforeChild->parent() != this) {
4008 RenderBox* boxToSplit = toRenderBox(beforeChild->parent());
4009 if (boxToSplit->firstChild() != beforeChild && boxToSplit->isAnonymous()) {
4010 didSplitParentAnonymousBoxes = true;
4012 // We have to split the parent box into two boxes and move children
4013 // from |beforeChild| to end into the new post box.
4014 RenderBox* postBox = boxToSplit->createAnonymousBoxWithSameTypeAs(this);
4015 postBox->setChildrenInline(boxToSplit->childrenInline());
4016 RenderBox* parentBox = toRenderBox(boxToSplit->parent());
4017 parentBox->virtualChildren()->insertChildNode(parentBox, postBox, boxToSplit->nextSibling());
4018 boxToSplit->moveChildrenTo(postBox, beforeChild, 0, true);
4020 markBoxForRelayoutAfterSplit(boxToSplit);
4021 markBoxForRelayoutAfterSplit(postBox);
4023 beforeChild = postBox;
4025 beforeChild = boxToSplit;
4028 if (didSplitParentAnonymousBoxes)
4029 markBoxForRelayoutAfterSplit(this);
4031 ASSERT(beforeChild->parent() == this);
4035 } // namespace WebCore