Home | History | Annotate | Download | only in rendering
      1 /*
      2  * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  *           (C) 1999 Antti Koivisto (koivisto (at) kde.org)
      4  *           (C) 2005 Allan Sandfeld Jensen (kde (at) carewolf.com)
      5  *           (C) 2005, 2006 Samuel Weinig (sam.weinig (at) gmail.com)
      6  * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
      7  * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
      8  *
      9  * This library is free software; you can redistribute it and/or
     10  * modify it under the terms of the GNU Library General Public
     11  * License as published by the Free Software Foundation; either
     12  * version 2 of the License, or (at your option) any later version.
     13  *
     14  * This library is distributed in the hope that it will be useful,
     15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     17  * Library General Public License for more details.
     18  *
     19  * You should have received a copy of the GNU Library General Public License
     20  * along with this library; see the file COPYING.LIB.  If not, write to
     21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     22  * Boston, MA 02110-1301, USA.
     23  *
     24  */
     25 
     26 #include "config.h"
     27 #include "core/rendering/RenderBox.h"
     28 
     29 #include <math.h>
     30 #include <algorithm>
     31 #include "HTMLNames.h"
     32 #include "core/dom/Document.h"
     33 #include "core/editing/htmlediting.h"
     34 #include "core/html/HTMLElement.h"
     35 #include "core/html/HTMLFrameOwnerElement.h"
     36 #include "core/html/HTMLHtmlElement.h"
     37 #include "core/html/HTMLTextAreaElement.h"
     38 #include "core/page/Frame.h"
     39 #include "core/page/FrameView.h"
     40 #include "core/page/Page.h"
     41 #include "core/platform/graphics/FloatQuad.h"
     42 #include "core/platform/graphics/GraphicsContextStateSaver.h"
     43 #include "core/platform/graphics/transforms/TransformState.h"
     44 #include "core/rendering/HitTestResult.h"
     45 #include "core/rendering/PaintInfo.h"
     46 #include "core/rendering/RenderBoxRegionInfo.h"
     47 #include "core/rendering/RenderFlexibleBox.h"
     48 #include "core/rendering/RenderFlowThread.h"
     49 #include "core/rendering/RenderGeometryMap.h"
     50 #include "core/rendering/RenderGrid.h"
     51 #include "core/rendering/RenderInline.h"
     52 #include "core/rendering/RenderLayer.h"
     53 #include "core/rendering/RenderLayerCompositor.h"
     54 #include "core/rendering/RenderListMarker.h"
     55 #include "core/rendering/RenderRegion.h"
     56 #include "core/rendering/RenderTableCell.h"
     57 #include "core/rendering/RenderTheme.h"
     58 #include "core/rendering/RenderView.h"
     59 
     60 using namespace std;
     61 
     62 namespace WebCore {
     63 
     64 using namespace HTMLNames;
     65 
     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;
     70 
     71 // Used by grid elements to properly size their grid items.
     72 static OverrideSizeMap* gOverrideContainingBlockLogicalHeightMap = 0;
     73 static OverrideSizeMap* gOverrideContainingBlockLogicalWidthMap = 0;
     74 
     75 
     76 // Size of border belt for autoscroll. When mouse pointer in border belt,
     77 // autoscroll is started.
     78 static const int autoscrollBeltSize = 20;
     79 static const unsigned backgroundObscurationTestMaxDepth = 4;
     80 
     81 bool RenderBox::s_hadOverflowClip = false;
     82 
     83 static bool skipBodyBackground(const RenderBox* bodyElementRenderer)
     84 {
     85     ASSERT(bodyElementRenderer->isBody());
     86     // The <body> only paints its background if the root element has defined a background independent of the body,
     87     // or if the <body>'s parent is not the document element's renderer (e.g. inside SVG foreignObject).
     88     RenderObject* documentElementRenderer = bodyElementRenderer->document()->documentElement()->renderer();
     89     return documentElementRenderer
     90         && !documentElementRenderer->hasBackground()
     91         && (documentElementRenderer == bodyElementRenderer->parent());
     92 }
     93 
     94 RenderBox::RenderBox(ContainerNode* node)
     95     : RenderBoxModelObject(node)
     96     , m_minPreferredLogicalWidth(-1)
     97     , m_maxPreferredLogicalWidth(-1)
     98     , m_intrinsicContentLogicalHeight(-1)
     99     , m_inlineBoxWrapper(0)
    100 {
    101     setIsBox();
    102 }
    103 
    104 RenderBox::~RenderBox()
    105 {
    106 }
    107 
    108 LayoutRect RenderBox::borderBoxRectInRegion(RenderRegion* region, LayoutUnit offsetFromTopOfFirstPage, RenderBoxRegionInfoFlags cacheFlag) const
    109 {
    110     if (!region)
    111         return borderBoxRect();
    112 
    113     // Compute the logical width and placement in this region.
    114     RenderBoxRegionInfo* boxInfo = renderBoxRegionInfo(region, offsetFromTopOfFirstPage, cacheFlag);
    115     if (!boxInfo)
    116         return borderBoxRect();
    117 
    118     // We have cached insets.
    119     LayoutUnit logicalWidth = boxInfo->logicalWidth();
    120     LayoutUnit logicalLeft = boxInfo->logicalLeft();
    121 
    122     // Now apply the parent inset since it is cumulative whenever anything in the containing block chain shifts.
    123     // FIXME: Doesn't work right with perpendicular writing modes.
    124     const RenderBlock* currentBox = containingBlock();
    125     offsetFromTopOfFirstPage -= logicalTop();
    126     RenderBoxRegionInfo* currentBoxInfo = currentBox->renderBoxRegionInfo(region, offsetFromTopOfFirstPage);
    127     while (currentBoxInfo && currentBoxInfo->isShifted()) {
    128         if (currentBox->style()->direction() == LTR)
    129             logicalLeft += currentBoxInfo->logicalLeft();
    130         else
    131             logicalLeft -= (currentBox->logicalWidth() - currentBoxInfo->logicalWidth()) - currentBoxInfo->logicalLeft();
    132         offsetFromTopOfFirstPage -= logicalTop();
    133         currentBox = currentBox->containingBlock();
    134         region = currentBox->clampToStartAndEndRegions(region);
    135         currentBoxInfo = currentBox->renderBoxRegionInfo(region, offsetFromTopOfFirstPage);
    136     }
    137 
    138     if (cacheFlag == DoNotCacheRenderBoxRegionInfo)
    139         delete boxInfo;
    140 
    141     if (isHorizontalWritingMode())
    142         return LayoutRect(logicalLeft, 0, logicalWidth, height());
    143     return LayoutRect(0, logicalLeft, width(), logicalWidth);
    144 }
    145 
    146 void RenderBox::clearRenderBoxRegionInfo()
    147 {
    148     if (isRenderFlowThread())
    149         return;
    150 
    151     RenderFlowThread* flowThread = flowThreadContainingBlock();
    152     if (flowThread)
    153         flowThread->removeRenderBoxRegionInfo(this);
    154 }
    155 
    156 void RenderBox::willBeDestroyed()
    157 {
    158     clearOverrideSize();
    159     clearContainingBlockOverrideSize();
    160 
    161     RenderBlock::removePercentHeightDescendantIfNeeded(this);
    162 
    163     ShapeOutsideInfo::removeInfo(this);
    164 
    165     RenderBoxModelObject::willBeDestroyed();
    166 }
    167 
    168 void RenderBox::removeFloatingOrPositionedChildFromBlockLists()
    169 {
    170     ASSERT(isFloatingOrOutOfFlowPositioned());
    171 
    172     if (documentBeingDestroyed())
    173         return;
    174 
    175     if (isFloating()) {
    176         RenderBlock* parentBlock = 0;
    177         for (RenderObject* curr = parent(); curr && !curr->isRenderView(); curr = curr->parent()) {
    178             if (curr->isRenderBlock()) {
    179                 RenderBlock* currBlock = toRenderBlock(curr);
    180                 if (!parentBlock || currBlock->containsFloat(this))
    181                     parentBlock = currBlock;
    182             }
    183         }
    184 
    185         if (parentBlock) {
    186             RenderObject* parent = parentBlock->parent();
    187             if (parent && parent->isFlexibleBoxIncludingDeprecated())
    188                 parentBlock = toRenderBlock(parent);
    189 
    190             parentBlock->markSiblingsWithFloatsForLayout(this);
    191             parentBlock->markAllDescendantsWithFloatsForLayout(this, false);
    192         }
    193     }
    194 
    195     if (isOutOfFlowPositioned())
    196         RenderBlock::removePositionedObject(this);
    197 }
    198 
    199 void RenderBox::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
    200 {
    201     s_hadOverflowClip = hasOverflowClip();
    202 
    203     RenderStyle* oldStyle = style();
    204     if (oldStyle) {
    205         // The background of the root element or the body element could propagate up to
    206         // the canvas.  Just dirty the entire canvas when our style changes substantially.
    207         if (diff >= StyleDifferenceRepaint && node() &&
    208             (isHTMLHtmlElement(node()) || node()->hasTagName(bodyTag))) {
    209             view()->repaint();
    210 
    211             if (oldStyle->hasEntirelyFixedBackground() != newStyle->hasEntirelyFixedBackground())
    212                 view()->compositor()->rootFixedBackgroundsChanged();
    213         }
    214 
    215         // When a layout hint happens and an object's position style changes, we have to do a layout
    216         // to dirty the render tree using the old position value now.
    217         if (diff == StyleDifferenceLayout && parent() && oldStyle->position() != newStyle->position()) {
    218             markContainingBlocksForLayout();
    219             if (oldStyle->position() == StaticPosition)
    220                 repaint();
    221             else if (newStyle->hasOutOfFlowPosition())
    222                 parent()->setChildNeedsLayout();
    223             if (isFloating() && !isOutOfFlowPositioned() && newStyle->hasOutOfFlowPosition())
    224                 removeFloatingOrPositionedChildFromBlockLists();
    225         }
    226     } else if (newStyle && isBody())
    227         view()->repaint();
    228 
    229     RenderBoxModelObject::styleWillChange(diff, newStyle);
    230 }
    231 
    232 void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
    233 {
    234     // Horizontal writing mode definition is updated in RenderBoxModelObject::updateFromStyle,
    235     // (as part of the RenderBoxModelObject::styleDidChange call below). So, we can safely cache the horizontal
    236     // writing mode value before style change here.
    237     bool oldHorizontalWritingMode = isHorizontalWritingMode();
    238 
    239     RenderBoxModelObject::styleDidChange(diff, oldStyle);
    240 
    241     RenderStyle* newStyle = style();
    242     if (needsLayout() && oldStyle) {
    243         RenderBlock::removePercentHeightDescendantIfNeeded(this);
    244 
    245         // Normally we can do optimized positioning layout for absolute/fixed positioned objects. There is one special case, however, which is
    246         // 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
    247         // to determine the new static position.
    248         if (isOutOfFlowPositioned() && newStyle->hasStaticBlockPosition(isHorizontalWritingMode()) && oldStyle->marginBefore() != newStyle->marginBefore()
    249             && parent() && !parent()->normalChildNeedsLayout())
    250             parent()->setChildNeedsLayout();
    251     }
    252 
    253     if (RenderBlock::hasPercentHeightContainerMap() && firstChild()
    254         && oldHorizontalWritingMode != isHorizontalWritingMode())
    255         RenderBlock::clearPercentHeightDescendantsFrom(this);
    256 
    257     // If our zoom factor changes and we have a defined scrollLeft/Top, we need to adjust that value into the
    258     // new zoomed coordinate space.
    259     if (hasOverflowClip() && oldStyle && newStyle && oldStyle->effectiveZoom() != newStyle->effectiveZoom()) {
    260         if (int left = layer()->scrollXOffset()) {
    261             left = (left / oldStyle->effectiveZoom()) * newStyle->effectiveZoom();
    262             layer()->scrollToXOffset(left);
    263         }
    264         if (int top = layer()->scrollYOffset()) {
    265             top = (top / oldStyle->effectiveZoom()) * newStyle->effectiveZoom();
    266             layer()->scrollToYOffset(top);
    267         }
    268     }
    269 
    270     // Our opaqueness might have changed without triggering layout.
    271     if (diff == StyleDifferenceRepaint || diff == StyleDifferenceRepaintIfText || diff == StyleDifferenceRepaintLayer) {
    272         RenderObject* parentToInvalidate = parent();
    273         for (unsigned i = 0; i < backgroundObscurationTestMaxDepth && parentToInvalidate; ++i) {
    274             parentToInvalidate->invalidateBackgroundObscurationStatus();
    275             parentToInvalidate = parentToInvalidate->parent();
    276         }
    277     }
    278 
    279     bool isBodyRenderer = isBody();
    280     bool isRootRenderer = isRoot();
    281 
    282     if (isRootRenderer || isBodyRenderer) {
    283         // Propagate the new writing mode and direction up to the RenderView.
    284         RenderView* viewRenderer = view();
    285         RenderStyle* viewStyle = viewRenderer->style();
    286         if (viewStyle->direction() != newStyle->direction() && (isRootRenderer || !document()->directionSetOnDocumentElement())) {
    287             viewStyle->setDirection(newStyle->direction());
    288             if (isBodyRenderer)
    289                 document()->documentElement()->renderer()->style()->setDirection(newStyle->direction());
    290             setNeedsLayoutAndPrefWidthsRecalc();
    291         }
    292 
    293         if (viewStyle->writingMode() != newStyle->writingMode() && (isRootRenderer || !document()->writingModeSetOnDocumentElement())) {
    294             viewStyle->setWritingMode(newStyle->writingMode());
    295             viewRenderer->setHorizontalWritingMode(newStyle->isHorizontalWritingMode());
    296             viewRenderer->markAllDescendantsWithFloatsForLayout();
    297             if (isBodyRenderer) {
    298                 document()->documentElement()->renderer()->style()->setWritingMode(newStyle->writingMode());
    299                 document()->documentElement()->renderer()->setHorizontalWritingMode(newStyle->isHorizontalWritingMode());
    300             }
    301             setNeedsLayoutAndPrefWidthsRecalc();
    302         }
    303 
    304         frame()->view()->recalculateScrollbarOverlayStyle();
    305     }
    306 
    307     updateShapeOutsideInfoAfterStyleChange(style()->shapeOutside(), oldStyle ? oldStyle->shapeOutside() : 0);
    308     updateGridPositionAfterStyleChange(oldStyle);
    309 }
    310 
    311 void RenderBox::updateShapeOutsideInfoAfterStyleChange(const ShapeValue* shapeOutside, const ShapeValue* oldShapeOutside)
    312 {
    313     // FIXME: A future optimization would do a deep comparison for equality. (bug 100811)
    314     if (shapeOutside == oldShapeOutside)
    315         return;
    316 
    317     if (shapeOutside) {
    318         ShapeOutsideInfo* shapeOutsideInfo = ShapeOutsideInfo::ensureInfo(this);
    319         shapeOutsideInfo->dirtyShapeSize();
    320     } else {
    321         ShapeOutsideInfo::removeInfo(this);
    322     }
    323 }
    324 
    325 void RenderBox::updateGridPositionAfterStyleChange(const RenderStyle* oldStyle)
    326 {
    327     if (!oldStyle || !parent() || !parent()->isRenderGrid())
    328         return;
    329 
    330     if (oldStyle->gridColumnStart() == style()->gridColumnStart()
    331         && oldStyle->gridColumnEnd() == style()->gridColumnEnd()
    332         && oldStyle->gridRowStart() == style()->gridRowStart()
    333         && oldStyle->gridRowEnd() == style()->gridRowEnd()
    334         && oldStyle->order() == style()->order())
    335         return;
    336 
    337     // It should be possible to not dirty the grid in some cases (like moving an explicitly placed grid item).
    338     // For now, it's more simple to just always recompute the grid.
    339     toRenderGrid(parent())->dirtyGrid();
    340 }
    341 
    342 void RenderBox::updateFromStyle()
    343 {
    344     RenderBoxModelObject::updateFromStyle();
    345 
    346     RenderStyle* styleToUse = style();
    347     bool isRootObject = isRoot();
    348     bool isViewObject = isRenderView();
    349 
    350     // The root and the RenderView always paint their backgrounds/borders.
    351     if (isRootObject || isViewObject)
    352         setHasBoxDecorations(true);
    353 
    354     setFloating(!isOutOfFlowPositioned() && styleToUse->isFloating());
    355 
    356     // We also handle <body> and <html>, whose overflow applies to the viewport.
    357     if (styleToUse->overflowX() != OVISIBLE && !isRootObject && isRenderBlock()) {
    358         bool boxHasOverflowClip = true;
    359         if (isBody()) {
    360             // Overflow on the body can propagate to the viewport under the following conditions.
    361             // (1) The root element is <html>.
    362             // (2) We are the primary <body> (can be checked by looking at document.body).
    363             // (3) The root element has visible overflow.
    364             if (isHTMLHtmlElement(document()->documentElement())
    365                 && document()->body() == node()
    366                 && document()->documentElement()->renderer()->style()->overflowX() == OVISIBLE)
    367                 boxHasOverflowClip = false;
    368         }
    369 
    370         // Check for overflow clip.
    371         // It's sufficient to just check one direction, since it's illegal to have visible on only one overflow value.
    372         if (boxHasOverflowClip) {
    373             if (!s_hadOverflowClip)
    374                 // Erase the overflow
    375                 repaint();
    376             setHasOverflowClip();
    377         }
    378     }
    379 
    380     setHasTransform(styleToUse->hasTransformRelatedProperty());
    381     setHasReflection(styleToUse->boxReflect());
    382 }
    383 
    384 void RenderBox::layout()
    385 {
    386     StackStats::LayoutCheckPoint layoutCheckPoint;
    387     ASSERT(needsLayout());
    388 
    389     RenderObject* child = firstChild();
    390     if (!child) {
    391         clearNeedsLayout();
    392         return;
    393     }
    394 
    395     LayoutStateMaintainer statePusher(view(), this, locationOffset(), style()->isFlippedBlocksWritingMode());
    396     while (child) {
    397         child->layoutIfNeeded();
    398         ASSERT(!child->needsLayout());
    399         child = child->nextSibling();
    400     }
    401     statePusher.pop();
    402     invalidateBackgroundObscurationStatus();
    403     clearNeedsLayout();
    404 }
    405 
    406 // More IE extensions.  clientWidth and clientHeight represent the interior of an object
    407 // excluding border and scrollbar.
    408 LayoutUnit RenderBox::clientWidth() const
    409 {
    410     return width() - borderLeft() - borderRight() - verticalScrollbarWidth();
    411 }
    412 
    413 LayoutUnit RenderBox::clientHeight() const
    414 {
    415     return height() - borderTop() - borderBottom() - horizontalScrollbarHeight();
    416 }
    417 
    418 int RenderBox::pixelSnappedClientWidth() const
    419 {
    420     return snapSizeToPixel(clientWidth(), x() + clientLeft());
    421 }
    422 
    423 int RenderBox::pixelSnappedClientHeight() const
    424 {
    425     return snapSizeToPixel(clientHeight(), y() + clientTop());
    426 }
    427 
    428 int RenderBox::pixelSnappedOffsetWidth() const
    429 {
    430     return snapSizeToPixel(offsetWidth(), x() + clientLeft());
    431 }
    432 
    433 int RenderBox::pixelSnappedOffsetHeight() const
    434 {
    435     return snapSizeToPixel(offsetHeight(), y() + clientTop());
    436 }
    437 
    438 bool RenderBox::requiresLayoutToDetermineWidth() const
    439 {
    440    // This optimization unfortunately doesn't work:
    441    // https://code.google.com/p/chromium/issues/detail?id=290399
    442    // So we've disabled it for M30 until it can be fixed on trunk.
    443    // Attempting to revert the original change or trying to fix
    444    // it on trunk and merge over to M30 is too risky so we just
    445    // force code which uses this to always use the "slow" (correct) path
    446    // instead of the (broken) optimization returning false would allow.
    447    return true;
    448 
    449    RenderStyle* style = this->style();
    450     return !style->width().isFixed()
    451         || !style->minWidth().isFixed()
    452         || (!style->maxWidth().isUndefined() && !style->maxWidth().isFixed())
    453         || !style->paddingLeft().isFixed()
    454         || !style->paddingRight().isFixed()
    455         || style->resize() != RESIZE_NONE
    456         || style->boxSizing() == BORDER_BOX
    457         || !isRenderBlock()
    458         || !isBlockFlow()
    459         || isFlexItemIncludingDeprecated();
    460 }
    461 
    462 LayoutUnit RenderBox::fixedOffsetWidth() const
    463 {
    464     ASSERT(!requiresLayoutToDetermineWidth());
    465 
    466     RenderStyle* style = this->style();
    467 
    468     LayoutUnit width = std::max(LayoutUnit(style->minWidth().value()), LayoutUnit(style->width().value()));
    469     if (style->maxWidth().isFixed())
    470         width = std::min(LayoutUnit(style->maxWidth().value()), width);
    471 
    472     LayoutUnit borderLeft = style->borderLeft().nonZero() ? style->borderLeft().width() : 0;
    473     LayoutUnit borderRight = style->borderRight().nonZero() ? style->borderRight().width() : 0;
    474 
    475     return width + borderLeft + borderRight + style->paddingLeft().value() + style->paddingRight().value();
    476 }
    477 
    478 int RenderBox::scrollWidth() const
    479 {
    480     if (hasOverflowClip())
    481         return layer()->scrollWidth();
    482     // For objects with visible overflow, this matches IE.
    483     // FIXME: Need to work right with writing modes.
    484     if (style()->isLeftToRightDirection())
    485         return snapSizeToPixel(max(clientWidth(), layoutOverflowRect().maxX() - borderLeft()), x() + clientLeft());
    486     return clientWidth() - min<LayoutUnit>(0, layoutOverflowRect().x() - borderLeft());
    487 }
    488 
    489 int RenderBox::scrollHeight() const
    490 {
    491     if (hasOverflowClip())
    492         return layer()->scrollHeight();
    493     // For objects with visible overflow, this matches IE.
    494     // FIXME: Need to work right with writing modes.
    495     return snapSizeToPixel(max(clientHeight(), layoutOverflowRect().maxY() - borderTop()), y() + clientTop());
    496 }
    497 
    498 int RenderBox::scrollLeft() const
    499 {
    500     return hasOverflowClip() ? layer()->scrollXOffset() : 0;
    501 }
    502 
    503 int RenderBox::scrollTop() const
    504 {
    505     return hasOverflowClip() ? layer()->scrollYOffset() : 0;
    506 }
    507 
    508 void RenderBox::setScrollLeft(int newLeft)
    509 {
    510     if (hasOverflowClip())
    511         layer()->scrollToXOffset(newLeft, RenderLayer::ScrollOffsetClamped);
    512 }
    513 
    514 void RenderBox::setScrollTop(int newTop)
    515 {
    516     if (hasOverflowClip())
    517         layer()->scrollToYOffset(newTop, RenderLayer::ScrollOffsetClamped);
    518 }
    519 
    520 void RenderBox::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
    521 {
    522     rects.append(pixelSnappedIntRect(accumulatedOffset, size()));
    523 }
    524 
    525 void RenderBox::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
    526 {
    527     quads.append(localToAbsoluteQuad(FloatRect(0, 0, width(), height()), 0 /* mode */, wasFixed));
    528 }
    529 
    530 void RenderBox::updateLayerTransform()
    531 {
    532     // Transform-origin depends on box size, so we need to update the layer transform after layout.
    533     if (hasLayer())
    534         layer()->updateTransform();
    535 }
    536 
    537 LayoutUnit RenderBox::constrainLogicalWidthInRegionByMinMax(LayoutUnit logicalWidth, LayoutUnit availableWidth, RenderBlock* cb, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
    538 {
    539     RenderStyle* styleToUse = style();
    540     if (!styleToUse->logicalMaxWidth().isUndefined())
    541         logicalWidth = min(logicalWidth, computeLogicalWidthInRegionUsing(MaxSize, styleToUse->logicalMaxWidth(), availableWidth, cb, region, offsetFromLogicalTopOfFirstPage));
    542     return max(logicalWidth, computeLogicalWidthInRegionUsing(MinSize, styleToUse->logicalMinWidth(), availableWidth, cb, region, offsetFromLogicalTopOfFirstPage));
    543 }
    544 
    545 LayoutUnit RenderBox::constrainLogicalHeightByMinMax(LayoutUnit logicalHeight, LayoutUnit intrinsicContentHeight) const
    546 {
    547     RenderStyle* styleToUse = style();
    548     if (!styleToUse->logicalMaxHeight().isUndefined()) {
    549         LayoutUnit maxH = computeLogicalHeightUsing(styleToUse->logicalMaxHeight(), intrinsicContentHeight);
    550         if (maxH != -1)
    551             logicalHeight = min(logicalHeight, maxH);
    552     }
    553     return max(logicalHeight, computeLogicalHeightUsing(styleToUse->logicalMinHeight(), intrinsicContentHeight));
    554 }
    555 
    556 LayoutUnit RenderBox::constrainContentBoxLogicalHeightByMinMax(LayoutUnit logicalHeight, LayoutUnit intrinsicContentHeight) const
    557 {
    558     RenderStyle* styleToUse = style();
    559     if (!styleToUse->logicalMaxHeight().isUndefined()) {
    560         LayoutUnit maxH = computeContentLogicalHeight(styleToUse->logicalMaxHeight(), intrinsicContentHeight);
    561         if (maxH != -1)
    562             logicalHeight = min(logicalHeight, maxH);
    563     }
    564     return max(logicalHeight, computeContentLogicalHeight(styleToUse->logicalMinHeight(), intrinsicContentHeight));
    565 }
    566 
    567 IntRect RenderBox::absoluteContentBox() const
    568 {
    569     // This is wrong with transforms and flipped writing modes.
    570     IntRect rect = pixelSnappedIntRect(contentBoxRect());
    571     FloatPoint absPos = localToAbsolute();
    572     rect.move(absPos.x(), absPos.y());
    573     return rect;
    574 }
    575 
    576 FloatQuad RenderBox::absoluteContentQuad() const
    577 {
    578     LayoutRect rect = contentBoxRect();
    579     return localToAbsoluteQuad(FloatRect(rect));
    580 }
    581 
    582 LayoutRect RenderBox::outlineBoundsForRepaint(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap) const
    583 {
    584     LayoutRect box = borderBoundingBox();
    585     adjustRectForOutlineAndShadow(box);
    586 
    587     if (repaintContainer != this) {
    588         FloatQuad containerRelativeQuad;
    589         if (geometryMap)
    590             containerRelativeQuad = geometryMap->mapToContainer(box, repaintContainer);
    591         else
    592             containerRelativeQuad = localToContainerQuad(FloatRect(box), repaintContainer);
    593 
    594         box = containerRelativeQuad.enclosingBoundingBox();
    595     }
    596 
    597     // FIXME: layoutDelta needs to be applied in parts before/after transforms and
    598     // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
    599     box.move(view()->layoutDelta());
    600 
    601     return box;
    602 }
    603 
    604 void RenderBox::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*)
    605 {
    606     if (!size().isEmpty())
    607         rects.append(pixelSnappedIntRect(additionalOffset, size()));
    608 }
    609 
    610 void RenderBox::addLayerHitTestRects(LayerHitTestRects& layerRects, const RenderLayer* currentLayer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const
    611 {
    612     LayoutPoint adjustedLayerOffset = layerOffset + locationOffset();
    613     RenderBoxModelObject::addLayerHitTestRects(layerRects, currentLayer, adjustedLayerOffset, containerRect);
    614 }
    615 
    616 void RenderBox::computeSelfHitTestRects(Vector<LayoutRect>& rects, const LayoutPoint& layerOffset) const
    617 {
    618     if (!size().isEmpty())
    619         rects.append(LayoutRect(layerOffset, size()));
    620 }
    621 
    622 LayoutRect RenderBox::reflectionBox() const
    623 {
    624     LayoutRect result;
    625     if (!style()->boxReflect())
    626         return result;
    627     LayoutRect box = borderBoxRect();
    628     result = box;
    629     switch (style()->boxReflect()->direction()) {
    630         case ReflectionBelow:
    631             result.move(0, box.height() + reflectionOffset());
    632             break;
    633         case ReflectionAbove:
    634             result.move(0, -box.height() - reflectionOffset());
    635             break;
    636         case ReflectionLeft:
    637             result.move(-box.width() - reflectionOffset(), 0);
    638             break;
    639         case ReflectionRight:
    640             result.move(box.width() + reflectionOffset(), 0);
    641             break;
    642     }
    643     return result;
    644 }
    645 
    646 int RenderBox::reflectionOffset() const
    647 {
    648     if (!style()->boxReflect())
    649         return 0;
    650     RenderView* renderView = view();
    651     if (style()->boxReflect()->direction() == ReflectionLeft || style()->boxReflect()->direction() == ReflectionRight)
    652         return valueForLength(style()->boxReflect()->offset(), borderBoxRect().width(), renderView);
    653     return valueForLength(style()->boxReflect()->offset(), borderBoxRect().height(), renderView);
    654 }
    655 
    656 LayoutRect RenderBox::reflectedRect(const LayoutRect& r) const
    657 {
    658     if (!style()->boxReflect())
    659         return LayoutRect();
    660 
    661     LayoutRect box = borderBoxRect();
    662     LayoutRect result = r;
    663     switch (style()->boxReflect()->direction()) {
    664         case ReflectionBelow:
    665             result.setY(box.maxY() + reflectionOffset() + (box.maxY() - r.maxY()));
    666             break;
    667         case ReflectionAbove:
    668             result.setY(box.y() - reflectionOffset() - box.height() + (box.maxY() - r.maxY()));
    669             break;
    670         case ReflectionLeft:
    671             result.setX(box.x() - reflectionOffset() - box.width() + (box.maxX() - r.maxX()));
    672             break;
    673         case ReflectionRight:
    674             result.setX(box.maxX() + reflectionOffset() + (box.maxX() - r.maxX()));
    675             break;
    676     }
    677     return result;
    678 }
    679 
    680 bool RenderBox::includeVerticalScrollbarSize() const
    681 {
    682     return hasOverflowClip() && !layer()->hasOverlayScrollbars()
    683         && (style()->overflowY() == OSCROLL || style()->overflowY() == OAUTO);
    684 }
    685 
    686 bool RenderBox::includeHorizontalScrollbarSize() const
    687 {
    688     return hasOverflowClip() && !layer()->hasOverlayScrollbars()
    689         && (style()->overflowX() == OSCROLL || style()->overflowX() == OAUTO);
    690 }
    691 
    692 int RenderBox::verticalScrollbarWidth() const
    693 {
    694     return includeVerticalScrollbarSize() ? layer()->verticalScrollbarWidth() : 0;
    695 }
    696 
    697 int RenderBox::horizontalScrollbarHeight() const
    698 {
    699     return includeHorizontalScrollbarSize() ? layer()->horizontalScrollbarHeight() : 0;
    700 }
    701 
    702 int RenderBox::instrinsicScrollbarLogicalWidth() const
    703 {
    704     if (!hasOverflowClip())
    705         return 0;
    706 
    707     if (isHorizontalWritingMode() && style()->overflowY() == OSCROLL) {
    708         ASSERT(layer()->hasVerticalScrollbar());
    709         return verticalScrollbarWidth();
    710     }
    711 
    712     if (!isHorizontalWritingMode() && style()->overflowX() == OSCROLL) {
    713         ASSERT(layer()->hasHorizontalScrollbar());
    714         return horizontalScrollbarHeight();
    715     }
    716 
    717     return 0;
    718 }
    719 
    720 bool RenderBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
    721 {
    722     RenderLayer* l = layer();
    723     if (l && l->scroll(direction, granularity, multiplier)) {
    724         if (stopNode)
    725             *stopNode = node();
    726         return true;
    727     }
    728 
    729     if (stopNode && *stopNode && *stopNode == node())
    730         return true;
    731 
    732     RenderBlock* b = containingBlock();
    733     if (b && !b->isRenderView())
    734         return b->scroll(direction, granularity, multiplier, stopNode);
    735     return false;
    736 }
    737 
    738 bool RenderBox::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
    739 {
    740     bool scrolled = false;
    741 
    742     RenderLayer* l = layer();
    743     if (l) {
    744         if (l->scroll(logicalToPhysical(direction, isHorizontalWritingMode(), style()->isFlippedBlocksWritingMode()), granularity, multiplier))
    745             scrolled = true;
    746 
    747         if (scrolled) {
    748             if (stopNode)
    749                 *stopNode = node();
    750             return true;
    751         }
    752     }
    753 
    754     if (stopNode && *stopNode && *stopNode == node())
    755         return true;
    756 
    757     RenderBlock* b = containingBlock();
    758     if (b && !b->isRenderView())
    759         return b->logicalScroll(direction, granularity, multiplier, stopNode);
    760     return false;
    761 }
    762 
    763 bool RenderBox::canBeScrolledAndHasScrollableArea() const
    764 {
    765     return canBeProgramaticallyScrolled() && (scrollHeight() != clientHeight() || scrollWidth() != clientWidth());
    766 }
    767 
    768 bool RenderBox::canBeProgramaticallyScrolled() const
    769 {
    770     return (hasOverflowClip() && (scrollsOverflow() || (node() && node()->rendererIsEditable()))) || (node() && node()->isDocumentNode());
    771 }
    772 
    773 bool RenderBox::usesCompositedScrolling() const
    774 {
    775     return hasOverflowClip() && hasLayer() && layer()->usesCompositedScrolling();
    776 }
    777 
    778 void RenderBox::autoscroll(const IntPoint& position)
    779 {
    780     if (layer())
    781         layer()->autoscroll(position);
    782 }
    783 
    784 bool RenderBox::autoscrollInProgress() const
    785 {
    786     return frame() && frame()->page() && frame()->page()->autoscrollInProgress(this);
    787 }
    788 
    789 // There are two kinds of renderer that can autoscroll.
    790 bool RenderBox::canAutoscroll() const
    791 {
    792     // Check for a box that can be scrolled in its own right.
    793     if (canBeScrolledAndHasScrollableArea())
    794         return true;
    795 
    796     // Check for a box that represents the top level of a web page.
    797     if (node() != document())
    798         return false;
    799     Frame* frame = this->frame();
    800     if (!frame)
    801         return false;
    802     Page* page = frame->page();
    803     return page && page->mainFrame() == frame && frame->view()->isScrollable();
    804 }
    805 
    806 // If specified point is in border belt, returned offset denotes direction of
    807 // scrolling.
    808 IntSize RenderBox::calculateAutoscrollDirection(const IntPoint& windowPoint) const
    809 {
    810     if (!frame())
    811         return IntSize();
    812 
    813     FrameView* frameView = frame()->view();
    814     if (!frameView)
    815         return IntSize();
    816 
    817     IntSize offset;
    818     IntPoint point = frameView->windowToContents(windowPoint);
    819     IntRect box(absoluteBoundingBoxRect());
    820 
    821     if (point.x() < box.x() + autoscrollBeltSize)
    822         point.move(-autoscrollBeltSize, 0);
    823     else if (point.x() > box.maxX() - autoscrollBeltSize)
    824         point.move(autoscrollBeltSize, 0);
    825 
    826     if (point.y() < box.y() + autoscrollBeltSize)
    827         point.move(0, -autoscrollBeltSize);
    828     else if (point.y() > box.maxY() - autoscrollBeltSize)
    829         point.move(0, autoscrollBeltSize);
    830     return frameView->contentsToWindow(point) - windowPoint;
    831 }
    832 
    833 RenderBox* RenderBox::findAutoscrollable(RenderObject* renderer)
    834 {
    835     while (renderer && !(renderer->isBox() && toRenderBox(renderer)->canAutoscroll())) {
    836         if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document()->ownerElement())
    837             renderer = renderer->document()->ownerElement()->renderer();
    838         else
    839             renderer = renderer->parent();
    840     }
    841 
    842     return renderer && renderer->isBox() ? toRenderBox(renderer) : 0;
    843 }
    844 
    845 void RenderBox::panScroll(const IntPoint& source)
    846 {
    847     if (layer())
    848         layer()->panScrollFromPoint(source);
    849 }
    850 
    851 bool RenderBox::needsPreferredWidthsRecalculation() const
    852 {
    853     return style()->paddingStart().isPercent() || style()->paddingEnd().isPercent();
    854 }
    855 
    856 IntSize RenderBox::scrolledContentOffset() const
    857 {
    858     ASSERT(hasOverflowClip());
    859     ASSERT(hasLayer());
    860     return layer()->scrolledContentOffset();
    861 }
    862 
    863 LayoutSize RenderBox::cachedSizeForOverflowClip() const
    864 {
    865     ASSERT(hasOverflowClip());
    866     ASSERT(hasLayer());
    867     return layer()->size();
    868 }
    869 
    870 void RenderBox::applyCachedClipAndScrollOffsetForRepaint(LayoutRect& paintRect) const
    871 {
    872     paintRect.move(-scrolledContentOffset()); // For overflow:auto/scroll/hidden.
    873 
    874     // Do not clip scroll layer contents to reduce the number of repaints while scrolling.
    875     if (usesCompositedScrolling())
    876         return;
    877 
    878     // height() is inaccurate if we're in the middle of a layout of this RenderBox, so use the
    879     // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint
    880     // anyway if its size does change.
    881     LayoutRect clipRect(LayoutPoint(), cachedSizeForOverflowClip());
    882     paintRect = intersection(paintRect, clipRect);
    883 }
    884 
    885 void RenderBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
    886 {
    887     minLogicalWidth = minPreferredLogicalWidth() - borderAndPaddingLogicalWidth();
    888     maxLogicalWidth = maxPreferredLogicalWidth() - borderAndPaddingLogicalWidth();
    889 }
    890 
    891 LayoutUnit RenderBox::minPreferredLogicalWidth() const
    892 {
    893     if (preferredLogicalWidthsDirty()) {
    894 #ifndef NDEBUG
    895         SetLayoutNeededForbiddenScope layoutForbiddenScope(const_cast<RenderBox*>(this));
    896 #endif
    897         const_cast<RenderBox*>(this)->computePreferredLogicalWidths();
    898     }
    899 
    900     return m_minPreferredLogicalWidth;
    901 }
    902 
    903 LayoutUnit RenderBox::maxPreferredLogicalWidth() const
    904 {
    905     if (preferredLogicalWidthsDirty()) {
    906 #ifndef NDEBUG
    907         SetLayoutNeededForbiddenScope layoutForbiddenScope(const_cast<RenderBox*>(this));
    908 #endif
    909         const_cast<RenderBox*>(this)->computePreferredLogicalWidths();
    910     }
    911 
    912     return m_maxPreferredLogicalWidth;
    913 }
    914 
    915 bool RenderBox::hasOverrideHeight() const
    916 {
    917     return gOverrideHeightMap && gOverrideHeightMap->contains(this);
    918 }
    919 
    920 bool RenderBox::hasOverrideWidth() const
    921 {
    922     return gOverrideWidthMap && gOverrideWidthMap->contains(this);
    923 }
    924 
    925 void RenderBox::setOverrideLogicalContentHeight(LayoutUnit height)
    926 {
    927     if (!gOverrideHeightMap)
    928         gOverrideHeightMap = new OverrideSizeMap();
    929     gOverrideHeightMap->set(this, height);
    930 }
    931 
    932 void RenderBox::setOverrideLogicalContentWidth(LayoutUnit width)
    933 {
    934     if (!gOverrideWidthMap)
    935         gOverrideWidthMap = new OverrideSizeMap();
    936     gOverrideWidthMap->set(this, width);
    937 }
    938 
    939 void RenderBox::clearOverrideLogicalContentHeight()
    940 {
    941     if (gOverrideHeightMap)
    942         gOverrideHeightMap->remove(this);
    943 }
    944 
    945 void RenderBox::clearOverrideLogicalContentWidth()
    946 {
    947     if (gOverrideWidthMap)
    948         gOverrideWidthMap->remove(this);
    949 }
    950 
    951 void RenderBox::clearOverrideSize()
    952 {
    953     clearOverrideLogicalContentHeight();
    954     clearOverrideLogicalContentWidth();
    955 }
    956 
    957 LayoutUnit RenderBox::overrideLogicalContentWidth() const
    958 {
    959     ASSERT(hasOverrideWidth());
    960     return gOverrideWidthMap->get(this);
    961 }
    962 
    963 LayoutUnit RenderBox::overrideLogicalContentHeight() const
    964 {
    965     ASSERT(hasOverrideHeight());
    966     return gOverrideHeightMap->get(this);
    967 }
    968 
    969 LayoutUnit RenderBox::overrideContainingBlockContentLogicalWidth() const
    970 {
    971     ASSERT(hasOverrideContainingBlockLogicalWidth());
    972     return gOverrideContainingBlockLogicalWidthMap->get(this);
    973 }
    974 
    975 LayoutUnit RenderBox::overrideContainingBlockContentLogicalHeight() const
    976 {
    977     ASSERT(hasOverrideContainingBlockLogicalHeight());
    978     return gOverrideContainingBlockLogicalHeightMap->get(this);
    979 }
    980 
    981 bool RenderBox::hasOverrideContainingBlockLogicalWidth() const
    982 {
    983     return gOverrideContainingBlockLogicalWidthMap && gOverrideContainingBlockLogicalWidthMap->contains(this);
    984 }
    985 
    986 bool RenderBox::hasOverrideContainingBlockLogicalHeight() const
    987 {
    988     return gOverrideContainingBlockLogicalHeightMap && gOverrideContainingBlockLogicalHeightMap->contains(this);
    989 }
    990 
    991 void RenderBox::setOverrideContainingBlockContentLogicalWidth(LayoutUnit logicalWidth)
    992 {
    993     if (!gOverrideContainingBlockLogicalWidthMap)
    994         gOverrideContainingBlockLogicalWidthMap = new OverrideSizeMap;
    995     gOverrideContainingBlockLogicalWidthMap->set(this, logicalWidth);
    996 }
    997 
    998 void RenderBox::setOverrideContainingBlockContentLogicalHeight(LayoutUnit logicalHeight)
    999 {
   1000     if (!gOverrideContainingBlockLogicalHeightMap)
   1001         gOverrideContainingBlockLogicalHeightMap = new OverrideSizeMap;
   1002     gOverrideContainingBlockLogicalHeightMap->set(this, logicalHeight);
   1003 }
   1004 
   1005 void RenderBox::clearContainingBlockOverrideSize()
   1006 {
   1007     if (gOverrideContainingBlockLogicalWidthMap)
   1008         gOverrideContainingBlockLogicalWidthMap->remove(this);
   1009     clearOverrideContainingBlockContentLogicalHeight();
   1010 }
   1011 
   1012 void RenderBox::clearOverrideContainingBlockContentLogicalHeight()
   1013 {
   1014     if (gOverrideContainingBlockLogicalHeightMap)
   1015         gOverrideContainingBlockLogicalHeightMap->remove(this);
   1016 }
   1017 
   1018 LayoutUnit RenderBox::adjustBorderBoxLogicalWidthForBoxSizing(LayoutUnit width) const
   1019 {
   1020     LayoutUnit bordersPlusPadding = borderAndPaddingLogicalWidth();
   1021     if (style()->boxSizing() == CONTENT_BOX)
   1022         return width + bordersPlusPadding;
   1023     return max(width, bordersPlusPadding);
   1024 }
   1025 
   1026 LayoutUnit RenderBox::adjustBorderBoxLogicalHeightForBoxSizing(LayoutUnit height) const
   1027 {
   1028     LayoutUnit bordersPlusPadding = borderAndPaddingLogicalHeight();
   1029     if (style()->boxSizing() == CONTENT_BOX)
   1030         return height + bordersPlusPadding;
   1031     return max(height, bordersPlusPadding);
   1032 }
   1033 
   1034 LayoutUnit RenderBox::adjustContentBoxLogicalWidthForBoxSizing(LayoutUnit width) const
   1035 {
   1036     if (style()->boxSizing() == BORDER_BOX)
   1037         width -= borderAndPaddingLogicalWidth();
   1038     return max<LayoutUnit>(0, width);
   1039 }
   1040 
   1041 LayoutUnit RenderBox::adjustContentBoxLogicalHeightForBoxSizing(LayoutUnit height) const
   1042 {
   1043     if (style()->boxSizing() == BORDER_BOX)
   1044         height -= borderAndPaddingLogicalHeight();
   1045     return max<LayoutUnit>(0, height);
   1046 }
   1047 
   1048 // Hit Testing
   1049 bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
   1050 {
   1051     LayoutPoint adjustedLocation = accumulatedOffset + location();
   1052 
   1053     // Check kids first.
   1054     for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
   1055         if (!child->hasLayer() && child->nodeAtPoint(request, result, locationInContainer, adjustedLocation, action)) {
   1056             updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation));
   1057             return true;
   1058         }
   1059     }
   1060 
   1061     // Check our bounds next. For this purpose always assume that we can only be hit in the
   1062     // foreground phase (which is true for replaced elements like images).
   1063     LayoutRect boundsRect = borderBoxRectInRegion(locationInContainer.region());
   1064     boundsRect.moveBy(adjustedLocation);
   1065     if (visibleToHitTestRequest(request) && action == HitTestForeground && locationInContainer.intersects(boundsRect)) {
   1066         updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation));
   1067         if (!result.addNodeToRectBasedTestResult(node(), request, locationInContainer, boundsRect))
   1068             return true;
   1069     }
   1070 
   1071     return false;
   1072 }
   1073 
   1074 // --------------------- painting stuff -------------------------------
   1075 
   1076 void RenderBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
   1077 {
   1078     LayoutPoint adjustedPaintOffset = paintOffset + location();
   1079     // default implementation. Just pass paint through to the children
   1080     PaintInfo childInfo(paintInfo);
   1081     childInfo.updatePaintingRootForChildren(this);
   1082     for (RenderObject* child = firstChild(); child; child = child->nextSibling())
   1083         child->paint(childInfo, adjustedPaintOffset);
   1084 }
   1085 
   1086 void RenderBox::paintRootBoxFillLayers(const PaintInfo& paintInfo)
   1087 {
   1088     if (paintInfo.skipRootBackground())
   1089         return;
   1090 
   1091     RenderObject* rootBackgroundRenderer = rendererForRootBackground();
   1092 
   1093     const FillLayer* bgLayer = rootBackgroundRenderer->style()->backgroundLayers();
   1094     Color bgColor = rootBackgroundRenderer->resolveColor(CSSPropertyBackgroundColor);
   1095 
   1096     paintFillLayers(paintInfo, bgColor, bgLayer, view()->backgroundRect(this), BackgroundBleedNone, CompositeSourceOver, rootBackgroundRenderer);
   1097 }
   1098 
   1099 BackgroundBleedAvoidance RenderBox::determineBackgroundBleedAvoidance(GraphicsContext* context) const
   1100 {
   1101     if (context->paintingDisabled())
   1102         return BackgroundBleedNone;
   1103 
   1104     const RenderStyle* style = this->style();
   1105 
   1106     if (!style->hasBackground() || !style->hasBorder() || !style->hasBorderRadius() || borderImageIsLoadedAndCanBeRendered())
   1107         return BackgroundBleedNone;
   1108 
   1109     AffineTransform ctm = context->getCTM();
   1110     FloatSize contextScaling(static_cast<float>(ctm.xScale()), static_cast<float>(ctm.yScale()));
   1111 
   1112     // Because RoundedRect uses IntRect internally the inset applied by the
   1113     // BackgroundBleedShrinkBackground strategy cannot be less than one integer
   1114     // layout coordinate, even with subpixel layout enabled. To take that into
   1115     // account, we clamp the contextScaling to 1.0 for the following test so
   1116     // that borderObscuresBackgroundEdge can only return true if the border
   1117     // widths are greater than 2 in both layout coordinates and screen
   1118     // coordinates.
   1119     // This precaution will become obsolete if RoundedRect is ever promoted to
   1120     // a sub-pixel representation.
   1121     if (contextScaling.width() > 1)
   1122         contextScaling.setWidth(1);
   1123     if (contextScaling.height() > 1)
   1124         contextScaling.setHeight(1);
   1125 
   1126     if (borderObscuresBackgroundEdge(contextScaling))
   1127         return BackgroundBleedShrinkBackground;
   1128     if (!style->hasAppearance() && borderObscuresBackground() && backgroundHasOpaqueTopLayer())
   1129         return BackgroundBleedBackgroundOverBorder;
   1130 
   1131     return BackgroundBleedUseTransparencyLayer;
   1132 }
   1133 
   1134 void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
   1135 {
   1136     if (!paintInfo.shouldPaintWithinRoot(this))
   1137         return;
   1138 
   1139     LayoutRect paintRect = borderBoxRectInRegion(paintInfo.renderRegion);
   1140     paintRect.moveBy(paintOffset);
   1141 
   1142     BackgroundBleedAvoidance bleedAvoidance = determineBackgroundBleedAvoidance(paintInfo.context);
   1143 
   1144     // FIXME: Should eventually give the theme control over whether the box shadow should paint, since controls could have
   1145     // custom shadows of their own.
   1146     if (!boxShadowShouldBeAppliedToBackground(bleedAvoidance))
   1147         paintBoxShadow(paintInfo, paintRect, style(), Normal);
   1148 
   1149     GraphicsContextStateSaver stateSaver(*paintInfo.context, false);
   1150     if (bleedAvoidance == BackgroundBleedUseTransparencyLayer) {
   1151         // To avoid the background color bleeding out behind the border, we'll render background and border
   1152         // into a transparency layer, and then clip that in one go (which requires setting up the clip before
   1153         // beginning the layer).
   1154         RoundedRect border = style()->getRoundedBorderFor(paintRect, view());
   1155         stateSaver.save();
   1156         paintInfo.context->clipRoundedRect(border);
   1157         paintInfo.context->beginTransparencyLayer(1);
   1158     }
   1159 
   1160     // If we have a native theme appearance, paint that before painting our background.
   1161     // The theme will tell us whether or not we should also paint the CSS background.
   1162     IntRect snappedPaintRect(pixelSnappedIntRect(paintRect));
   1163     bool themePainted = style()->hasAppearance() && !theme()->paint(this, paintInfo, snappedPaintRect);
   1164     if (!themePainted) {
   1165         if (bleedAvoidance == BackgroundBleedBackgroundOverBorder)
   1166             paintBorder(paintInfo, paintRect, style(), bleedAvoidance);
   1167 
   1168         paintBackground(paintInfo, paintRect, bleedAvoidance);
   1169 
   1170         if (style()->hasAppearance())
   1171             theme()->paintDecorations(this, paintInfo, snappedPaintRect);
   1172     }
   1173     paintBoxShadow(paintInfo, paintRect, style(), Inset);
   1174 
   1175     // The theme will tell us whether or not we should also paint the CSS border.
   1176     if (bleedAvoidance != BackgroundBleedBackgroundOverBorder && (!style()->hasAppearance() || (!themePainted && theme()->paintBorderOnly(this, paintInfo, snappedPaintRect))) && style()->hasBorder())
   1177         paintBorder(paintInfo, paintRect, style(), bleedAvoidance);
   1178 
   1179     if (bleedAvoidance == BackgroundBleedUseTransparencyLayer)
   1180         paintInfo.context->endTransparencyLayer();
   1181 }
   1182 
   1183 void RenderBox::paintBackground(const PaintInfo& paintInfo, const LayoutRect& paintRect, BackgroundBleedAvoidance bleedAvoidance)
   1184 {
   1185     if (isRoot()) {
   1186         paintRootBoxFillLayers(paintInfo);
   1187         return;
   1188     }
   1189     if (isBody() && skipBodyBackground(this))
   1190         return;
   1191     if (backgroundIsKnownToBeObscured())
   1192         return;
   1193     paintFillLayers(paintInfo, resolveColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), paintRect, bleedAvoidance);
   1194 }
   1195 
   1196 LayoutRect RenderBox::backgroundPaintedExtent() const
   1197 {
   1198     ASSERT(hasBackground());
   1199     LayoutRect backgroundRect = pixelSnappedIntRect(borderBoxRect());
   1200 
   1201     StyleColor backgroundColor = resolveStyleColor(CSSPropertyBackgroundColor);
   1202     if (backgroundColor.isValid() && backgroundColor.alpha())
   1203         return backgroundRect;
   1204     if (!style()->backgroundLayers()->image() || style()->backgroundLayers()->next())
   1205         return backgroundRect;
   1206     BackgroundImageGeometry geometry;
   1207     const_cast<RenderBox*>(this)->calculateBackgroundImageGeometry(style()->backgroundLayers(), backgroundRect, geometry);
   1208     return geometry.destRect();
   1209 }
   1210 
   1211 bool RenderBox::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const
   1212 {
   1213     if (isBody() && skipBodyBackground(this))
   1214         return false;
   1215 
   1216     StyleColor backgroundColor = resolveStyleColor(CSSPropertyBackgroundColor);
   1217     if (!backgroundColor.isValid() || backgroundColor.hasAlpha())
   1218         return false;
   1219 
   1220     // If the element has appearance, it might be painted by theme.
   1221     // We cannot be sure if theme paints the background opaque.
   1222     // In this case it is safe to not assume opaqueness.
   1223     // FIXME: May be ask theme if it paints opaque.
   1224     if (style()->hasAppearance())
   1225         return false;
   1226     // FIXME: Check the opaqueness of background images.
   1227 
   1228     // FIXME: Use rounded rect if border radius is present.
   1229     if (style()->hasBorderRadius())
   1230         return false;
   1231     // FIXME: The background color clip is defined by the last layer.
   1232     if (style()->backgroundLayers()->next())
   1233         return false;
   1234     LayoutRect backgroundRect;
   1235     switch (style()->backgroundClip()) {
   1236     case BorderFillBox:
   1237         backgroundRect = borderBoxRect();
   1238         break;
   1239     case PaddingFillBox:
   1240         backgroundRect = paddingBoxRect();
   1241         break;
   1242     case ContentFillBox:
   1243         backgroundRect = contentBoxRect();
   1244         break;
   1245     default:
   1246         break;
   1247     }
   1248     return backgroundRect.contains(localRect);
   1249 }
   1250 
   1251 static bool isCandidateForOpaquenessTest(RenderBox* childBox)
   1252 {
   1253     RenderStyle* childStyle = childBox->style();
   1254     if (childStyle->position() != StaticPosition && childBox->containingBlock() != childBox->parent())
   1255         return false;
   1256     if (childStyle->visibility() != VISIBLE || childStyle->shapeOutside())
   1257         return false;
   1258     if (!childBox->width() || !childBox->height())
   1259         return false;
   1260     if (RenderLayer* childLayer = childBox->layer()) {
   1261         if (childLayer->isComposited())
   1262             return false;
   1263         // FIXME: Deal with z-index.
   1264         if (!childStyle->hasAutoZIndex())
   1265             return false;
   1266         if (childLayer->hasTransform() || childLayer->isTransparent() || childLayer->hasFilter())
   1267             return false;
   1268     }
   1269     return true;
   1270 }
   1271 
   1272 bool RenderBox::foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, unsigned maxDepthToTest) const
   1273 {
   1274     if (!maxDepthToTest)
   1275         return false;
   1276     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
   1277         if (!child->isBox())
   1278             continue;
   1279         RenderBox* childBox = toRenderBox(child);
   1280         if (!isCandidateForOpaquenessTest(childBox))
   1281             continue;
   1282         LayoutPoint childLocation = childBox->location();
   1283         if (childBox->isRelPositioned())
   1284             childLocation.move(childBox->relativePositionOffset());
   1285         LayoutRect childLocalRect = localRect;
   1286         childLocalRect.moveBy(-childLocation);
   1287         if (childLocalRect.y() < 0 || childLocalRect.x() < 0) {
   1288             // If there is unobscured area above/left of a static positioned box then the rect is probably not covered.
   1289             if (childBox->style()->position() == StaticPosition)
   1290                 return false;
   1291             continue;
   1292         }
   1293         if (childLocalRect.maxY() > childBox->height() || childLocalRect.maxX() > childBox->width())
   1294             continue;
   1295         if (childBox->backgroundIsKnownToBeOpaqueInRect(childLocalRect))
   1296             return true;
   1297         if (childBox->foregroundIsKnownToBeOpaqueInRect(childLocalRect, maxDepthToTest - 1))
   1298             return true;
   1299     }
   1300     return false;
   1301 }
   1302 
   1303 bool RenderBox::computeBackgroundIsKnownToBeObscured()
   1304 {
   1305     // Test to see if the children trivially obscure the background.
   1306     // FIXME: This test can be much more comprehensive.
   1307     if (!hasBackground())
   1308         return false;
   1309     // Table and root background painting is special.
   1310     if (isTable() || isRoot())
   1311         return false;
   1312     // FIXME: box-shadow is painted while background painting.
   1313     if (style()->boxShadow())
   1314         return false;
   1315     LayoutRect backgroundRect = backgroundPaintedExtent();
   1316     return foregroundIsKnownToBeOpaqueInRect(backgroundRect, backgroundObscurationTestMaxDepth);
   1317 }
   1318 
   1319 bool RenderBox::backgroundHasOpaqueTopLayer() const
   1320 {
   1321     const FillLayer* fillLayer = style()->backgroundLayers();
   1322     if (!fillLayer || fillLayer->clip() != BorderFillBox)
   1323         return false;
   1324 
   1325     // Clipped with local scrolling
   1326     if (hasOverflowClip() && fillLayer->attachment() == LocalBackgroundAttachment)
   1327         return false;
   1328 
   1329     if (fillLayer->hasOpaqueImage(this) && fillLayer->hasRepeatXY() && fillLayer->image()->canRender(this, style()->effectiveZoom()))
   1330         return true;
   1331 
   1332     // If there is only one layer and no image, check whether the background color is opaque
   1333     if (!fillLayer->next() && !fillLayer->hasImage()) {
   1334         StyleColor bgColor = resolveStyleColor(CSSPropertyBackgroundColor);
   1335         if (bgColor.isValid() && bgColor.alpha() == 255)
   1336             return true;
   1337     }
   1338 
   1339     return false;
   1340 }
   1341 
   1342 void RenderBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
   1343 {
   1344     if (!paintInfo.shouldPaintWithinRoot(this) || style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask || paintInfo.context->paintingDisabled())
   1345         return;
   1346 
   1347     LayoutRect paintRect = LayoutRect(paintOffset, size());
   1348     paintMaskImages(paintInfo, paintRect);
   1349 }
   1350 
   1351 void RenderBox::paintMaskImages(const PaintInfo& paintInfo, const LayoutRect& paintRect)
   1352 {
   1353     // Figure out if we need to push a transparency layer to render our mask.
   1354     bool pushTransparencyLayer = false;
   1355     bool compositedMask = hasLayer() && layer()->hasCompositedMask();
   1356     bool flattenCompositingLayers = view()->frameView() && view()->frameView()->paintBehavior() & PaintBehaviorFlattenCompositingLayers;
   1357     CompositeOperator compositeOp = CompositeSourceOver;
   1358 
   1359     bool allMaskImagesLoaded = true;
   1360 
   1361     if (!compositedMask || flattenCompositingLayers) {
   1362         pushTransparencyLayer = true;
   1363         StyleImage* maskBoxImage = style()->maskBoxImage().image();
   1364         const FillLayer* maskLayers = style()->maskLayers();
   1365 
   1366         // Don't render a masked element until all the mask images have loaded, to prevent a flash of unmasked content.
   1367         if (maskBoxImage)
   1368             allMaskImagesLoaded &= maskBoxImage->isLoaded();
   1369 
   1370         if (maskLayers)
   1371             allMaskImagesLoaded &= maskLayers->imagesAreLoaded();
   1372 
   1373         paintInfo.context->setCompositeOperation(CompositeDestinationIn);
   1374         paintInfo.context->beginTransparencyLayer(1);
   1375         compositeOp = CompositeSourceOver;
   1376     }
   1377 
   1378     if (allMaskImagesLoaded) {
   1379         paintFillLayers(paintInfo, Color(), style()->maskLayers(), paintRect, BackgroundBleedNone, compositeOp);
   1380         paintNinePieceImage(paintInfo.context, paintRect, style(), style()->maskBoxImage(), compositeOp);
   1381     }
   1382 
   1383     if (pushTransparencyLayer)
   1384         paintInfo.context->endTransparencyLayer();
   1385 }
   1386 
   1387 LayoutRect RenderBox::maskClipRect()
   1388 {
   1389     const NinePieceImage& maskBoxImage = style()->maskBoxImage();
   1390     if (maskBoxImage.image()) {
   1391         LayoutRect borderImageRect = borderBoxRect();
   1392 
   1393         // Apply outsets to the border box.
   1394         borderImageRect.expand(style()->maskBoxImageOutsets());
   1395         return borderImageRect;
   1396     }
   1397 
   1398     LayoutRect result;
   1399     LayoutRect borderBox = borderBoxRect();
   1400     for (const FillLayer* maskLayer = style()->maskLayers(); maskLayer; maskLayer = maskLayer->next()) {
   1401         if (maskLayer->image()) {
   1402             BackgroundImageGeometry geometry;
   1403             calculateBackgroundImageGeometry(maskLayer, borderBox, geometry);
   1404             result.unite(geometry.destRect());
   1405         }
   1406     }
   1407     return result;
   1408 }
   1409 
   1410 void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, const LayoutRect& rect,
   1411     BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderObject* backgroundObject)
   1412 {
   1413     Vector<const FillLayer*, 8> layers;
   1414     const FillLayer* curLayer = fillLayer;
   1415     bool shouldDrawBackgroundInSeparateBuffer = false;
   1416     while (curLayer) {
   1417         layers.append(curLayer);
   1418         // Stop traversal when an opaque layer is encountered.
   1419         // FIXME : It would be possible for the following occlusion culling test to be more aggressive
   1420         // on layers with no repeat by testing whether the image covers the layout rect.
   1421         // Testing that here would imply duplicating a lot of calculations that are currently done in
   1422         // RenderBoxModelObject::paintFillLayerExtended. A more efficient solution might be to move
   1423         // the layer recursion into paintFillLayerExtended, or to compute the layer geometry here
   1424         // and pass it down.
   1425 
   1426         if (!shouldDrawBackgroundInSeparateBuffer && curLayer->blendMode() != BlendModeNormal)
   1427             shouldDrawBackgroundInSeparateBuffer = true;
   1428 
   1429         // The clipOccludesNextLayers condition must be evaluated first to avoid short-circuiting.
   1430         if (curLayer->clipOccludesNextLayers(curLayer == fillLayer) && curLayer->hasOpaqueImage(this) && curLayer->image()->canRender(this, style()->effectiveZoom()) && curLayer->hasRepeatXY() && curLayer->blendMode() == BlendModeNormal)
   1431             break;
   1432         curLayer = curLayer->next();
   1433     }
   1434 
   1435     GraphicsContext* context = paintInfo.context;
   1436     if (!context)
   1437         shouldDrawBackgroundInSeparateBuffer = false;
   1438     if (shouldDrawBackgroundInSeparateBuffer)
   1439         context->beginTransparencyLayer(1);
   1440 
   1441     Vector<const FillLayer*>::const_reverse_iterator topLayer = layers.rend();
   1442     for (Vector<const FillLayer*>::const_reverse_iterator it = layers.rbegin(); it != topLayer; ++it)
   1443         paintFillLayer(paintInfo, c, *it, rect, bleedAvoidance, op, backgroundObject);
   1444 
   1445     if (shouldDrawBackgroundInSeparateBuffer)
   1446         context->endTransparencyLayer();
   1447 }
   1448 
   1449 void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, const LayoutRect& rect,
   1450     BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderObject* backgroundObject)
   1451 {
   1452     paintFillLayerExtended(paintInfo, c, fillLayer, rect, bleedAvoidance, 0, LayoutSize(), op, backgroundObject);
   1453 }
   1454 
   1455 static bool layersUseImage(WrappedImagePtr image, const FillLayer* layers)
   1456 {
   1457     for (const FillLayer* curLayer = layers; curLayer; curLayer = curLayer->next()) {
   1458         if (curLayer->image() && image == curLayer->image()->data())
   1459             return true;
   1460     }
   1461 
   1462     return false;
   1463 }
   1464 
   1465 void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*)
   1466 {
   1467     if (!parent())
   1468         return;
   1469 
   1470     if ((style()->borderImage().image() && style()->borderImage().image()->data() == image) ||
   1471         (style()->maskBoxImage().image() && style()->maskBoxImage().image()->data() == image)) {
   1472         repaint();
   1473         return;
   1474     }
   1475 
   1476     bool didFullRepaint = repaintLayerRectsForImage(image, style()->backgroundLayers(), true);
   1477     if (!didFullRepaint)
   1478         repaintLayerRectsForImage(image, style()->maskLayers(), false);
   1479 
   1480 
   1481     if (hasLayer() && layer()->hasCompositedMask() && layersUseImage(image, style()->maskLayers()))
   1482         layer()->contentChanged(MaskImageChanged);
   1483 }
   1484 
   1485 bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer* layers, bool drawingBackground)
   1486 {
   1487     LayoutRect rendererRect;
   1488     RenderBox* layerRenderer = 0;
   1489 
   1490     for (const FillLayer* curLayer = layers; curLayer; curLayer = curLayer->next()) {
   1491         if (curLayer->image() && image == curLayer->image()->data() && curLayer->image()->canRender(this, style()->effectiveZoom())) {
   1492             // Now that we know this image is being used, compute the renderer and the rect
   1493             // if we haven't already
   1494             if (!layerRenderer) {
   1495                 bool drawingRootBackground = drawingBackground && (isRoot() || (isBody() && !document()->documentElement()->renderer()->hasBackground()));
   1496                 if (drawingRootBackground) {
   1497                     layerRenderer = view();
   1498 
   1499                     LayoutUnit rw;
   1500                     LayoutUnit rh;
   1501 
   1502                     if (FrameView* frameView = toRenderView(layerRenderer)->frameView()) {
   1503                         rw = frameView->contentsWidth();
   1504                         rh = frameView->contentsHeight();
   1505                     } else {
   1506                         rw = layerRenderer->width();
   1507                         rh = layerRenderer->height();
   1508                     }
   1509                     rendererRect = LayoutRect(-layerRenderer->marginLeft(),
   1510                         -layerRenderer->marginTop(),
   1511                         max(layerRenderer->width() + layerRenderer->marginWidth() + layerRenderer->borderLeft() + layerRenderer->borderRight(), rw),
   1512                         max(layerRenderer->height() + layerRenderer->marginHeight() + layerRenderer->borderTop() + layerRenderer->borderBottom(), rh));
   1513                 } else {
   1514                     layerRenderer = this;
   1515                     rendererRect = borderBoxRect();
   1516                 }
   1517             }
   1518 
   1519             BackgroundImageGeometry geometry;
   1520             layerRenderer->calculateBackgroundImageGeometry(curLayer, rendererRect, geometry);
   1521             layerRenderer->repaintRectangle(geometry.destRect());
   1522             if (geometry.destRect() == rendererRect)
   1523                 return true;
   1524         }
   1525     }
   1526     return false;
   1527 }
   1528 
   1529 bool RenderBox::pushContentsClip(PaintInfo& paintInfo, const LayoutPoint& accumulatedOffset, ContentsClipBehavior contentsClipBehavior)
   1530 {
   1531     if (paintInfo.phase == PaintPhaseBlockBackground || paintInfo.phase == PaintPhaseSelfOutline || paintInfo.phase == PaintPhaseMask)
   1532         return false;
   1533 
   1534     bool isControlClip = hasControlClip();
   1535     bool isOverflowClip = hasOverflowClip() && !layer()->isSelfPaintingLayer();
   1536 
   1537     if (!isControlClip && !isOverflowClip)
   1538         return false;
   1539 
   1540     LayoutRect clipRect = isControlClip ? controlClipRect(accumulatedOffset) : overflowClipRect(accumulatedOffset, paintInfo.renderRegion);
   1541     RoundedRect clipRoundedRect(0, 0, 0, 0);
   1542     bool hasBorderRadius = style()->hasBorderRadius();
   1543     if (hasBorderRadius)
   1544         clipRoundedRect = style()->getRoundedInnerBorderFor(LayoutRect(accumulatedOffset, size()));
   1545 
   1546     if (contentsClipBehavior == SkipContentsClipIfPossible) {
   1547         LayoutRect contentsVisualOverflow = contentsVisualOverflowRect();
   1548         if (contentsVisualOverflow.isEmpty())
   1549             return false;
   1550 
   1551         // FIXME: Get rid of this slop from here and elsewhere.
   1552         // Instead, properly include the outline in visual overflow.
   1553         if (RenderView* view = this->view())
   1554             contentsVisualOverflow.inflate(view->maximalOutlineSize());
   1555 
   1556         LayoutRect conservativeClipRect = clipRect;
   1557         if (hasBorderRadius)
   1558             conservativeClipRect.intersect(clipRoundedRect.radiusCenterRect());
   1559         conservativeClipRect.moveBy(-accumulatedOffset);
   1560         if (hasLayer())
   1561             conservativeClipRect.move(scrolledContentOffset());
   1562         if (conservativeClipRect.contains(contentsVisualOverflow))
   1563             return false;
   1564     }
   1565 
   1566     if (paintInfo.phase == PaintPhaseOutline)
   1567         paintInfo.phase = PaintPhaseChildOutlines;
   1568     else if (paintInfo.phase == PaintPhaseChildBlockBackground) {
   1569         paintInfo.phase = PaintPhaseBlockBackground;
   1570         paintObject(paintInfo, accumulatedOffset);
   1571         paintInfo.phase = PaintPhaseChildBlockBackgrounds;
   1572     }
   1573     paintInfo.context->save();
   1574     if (hasBorderRadius)
   1575         paintInfo.context->clipRoundedRect(clipRoundedRect);
   1576     paintInfo.context->clip(pixelSnappedIntRect(clipRect));
   1577     return true;
   1578 }
   1579 
   1580 void RenderBox::popContentsClip(PaintInfo& paintInfo, PaintPhase originalPhase, const LayoutPoint& accumulatedOffset)
   1581 {
   1582     ASSERT(hasControlClip() || (hasOverflowClip() && !layer()->isSelfPaintingLayer()));
   1583 
   1584     paintInfo.context->restore();
   1585     if (originalPhase == PaintPhaseOutline) {
   1586         paintInfo.phase = PaintPhaseSelfOutline;
   1587         paintObject(paintInfo, accumulatedOffset);
   1588         paintInfo.phase = originalPhase;
   1589     } else if (originalPhase == PaintPhaseChildBlockBackground)
   1590         paintInfo.phase = originalPhase;
   1591 }
   1592 
   1593 LayoutRect RenderBox::overflowClipRect(const LayoutPoint& location, RenderRegion* region, OverlayScrollbarSizeRelevancy relevancy)
   1594 {
   1595     // FIXME: When overflow-clip (CSS3) is implemented, we'll obtain the property
   1596     // here.
   1597     LayoutRect clipRect = borderBoxRectInRegion(region);
   1598     clipRect.setLocation(location + clipRect.location() + LayoutSize(borderLeft(), borderTop()));
   1599     clipRect.setSize(clipRect.size() - LayoutSize(borderLeft() + borderRight(), borderTop() + borderBottom()));
   1600 
   1601     // Subtract out scrollbars if we have them.
   1602      if (layer()) {
   1603         if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
   1604             clipRect.move(layer()->verticalScrollbarWidth(relevancy), 0);
   1605         clipRect.contract(layer()->verticalScrollbarWidth(relevancy), layer()->horizontalScrollbarHeight(relevancy));
   1606      }
   1607 
   1608     return clipRect;
   1609 }
   1610 
   1611 LayoutRect RenderBox::clipRect(const LayoutPoint& location, RenderRegion* region)
   1612 {
   1613     LayoutRect borderBoxRect = borderBoxRectInRegion(region);
   1614     LayoutRect clipRect = LayoutRect(borderBoxRect.location() + location, borderBoxRect.size());
   1615     RenderView* renderView = view();
   1616 
   1617     if (!style()->clipLeft().isAuto()) {
   1618         LayoutUnit c = valueForLength(style()->clipLeft(), borderBoxRect.width(), renderView);
   1619         clipRect.move(c, 0);
   1620         clipRect.contract(c, 0);
   1621     }
   1622 
   1623     // We don't use the region-specific border box's width and height since clip offsets are (stupidly) specified
   1624     // from the left and top edges. Therefore it's better to avoid constraining to smaller widths and heights.
   1625 
   1626     if (!style()->clipRight().isAuto())
   1627         clipRect.contract(width() - valueForLength(style()->clipRight(), width(), renderView), 0);
   1628 
   1629     if (!style()->clipTop().isAuto()) {
   1630         LayoutUnit c = valueForLength(style()->clipTop(), borderBoxRect.height(), renderView);
   1631         clipRect.move(0, c);
   1632         clipRect.contract(0, c);
   1633     }
   1634 
   1635     if (!style()->clipBottom().isAuto())
   1636         clipRect.contract(0, height() - valueForLength(style()->clipBottom(), height(), renderView));
   1637 
   1638     return clipRect;
   1639 }
   1640 
   1641 LayoutUnit RenderBox::shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStart, LayoutUnit childMarginEnd, const RenderBlock* cb, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
   1642 {
   1643     RenderRegion* containingBlockRegion = 0;
   1644     LayoutUnit logicalTopPosition = logicalTop();
   1645     LayoutUnit adjustedPageOffsetForContainingBlock = offsetFromLogicalTopOfFirstPage - logicalTop();
   1646     if (region) {
   1647         LayoutUnit offsetFromLogicalTopOfRegion = region ? region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage : LayoutUnit();
   1648         logicalTopPosition = max(logicalTopPosition, logicalTopPosition + offsetFromLogicalTopOfRegion);
   1649         containingBlockRegion = cb->clampToStartAndEndRegions(region);
   1650     }
   1651 
   1652     LayoutUnit result = cb->availableLogicalWidthForLine(logicalTopPosition, false, containingBlockRegion, adjustedPageOffsetForContainingBlock) - childMarginStart - childMarginEnd;
   1653 
   1654     // We need to see if margins on either the start side or the end side can contain the floats in question. If they can,
   1655     // then just using the line width is inaccurate. In the case where a float completely fits, we don't need to use the line
   1656     // offset at all, but can instead push all the way to the content edge of the containing block. In the case where the float
   1657     // 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
   1658     // "consumed" by the float. Negative margins aren't consumed by the float, and so we ignore them.
   1659     if (childMarginStart > 0) {
   1660         LayoutUnit startContentSide = cb->startOffsetForContent(containingBlockRegion, adjustedPageOffsetForContainingBlock);
   1661         LayoutUnit startContentSideWithMargin = startContentSide + childMarginStart;
   1662         LayoutUnit startOffset = cb->startOffsetForLine(logicalTopPosition, false, containingBlockRegion, adjustedPageOffsetForContainingBlock);
   1663         if (startOffset > startContentSideWithMargin)
   1664             result += childMarginStart;
   1665         else
   1666             result += startOffset - startContentSide;
   1667     }
   1668 
   1669     if (childMarginEnd > 0) {
   1670         LayoutUnit endContentSide = cb->endOffsetForContent(containingBlockRegion, adjustedPageOffsetForContainingBlock);
   1671         LayoutUnit endContentSideWithMargin = endContentSide + childMarginEnd;
   1672         LayoutUnit endOffset = cb->endOffsetForLine(logicalTopPosition, false, containingBlockRegion, adjustedPageOffsetForContainingBlock);
   1673         if (endOffset > endContentSideWithMargin)
   1674             result += childMarginEnd;
   1675         else
   1676             result += endOffset - endContentSide;
   1677     }
   1678 
   1679     return result;
   1680 }
   1681 
   1682 LayoutUnit RenderBox::containingBlockLogicalWidthForContent() const
   1683 {
   1684     if (hasOverrideContainingBlockLogicalWidth())
   1685         return overrideContainingBlockContentLogicalWidth();
   1686 
   1687     RenderBlock* cb = containingBlock();
   1688     return cb->availableLogicalWidth();
   1689 }
   1690 
   1691 LayoutUnit RenderBox::containingBlockLogicalHeightForContent(AvailableLogicalHeightType heightType) const
   1692 {
   1693     if (hasOverrideContainingBlockLogicalHeight())
   1694         return overrideContainingBlockContentLogicalHeight();
   1695 
   1696     RenderBlock* cb = containingBlock();
   1697     return cb->availableLogicalHeight(heightType);
   1698 }
   1699 
   1700 LayoutUnit RenderBox::containingBlockLogicalWidthForContentInRegion(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
   1701 {
   1702     if (!region)
   1703         return containingBlockLogicalWidthForContent();
   1704 
   1705     RenderBlock* cb = containingBlock();
   1706     RenderRegion* containingBlockRegion = cb->clampToStartAndEndRegions(region);
   1707     // FIXME: It's unclear if a region's content should use the containing block's override logical width.
   1708     // If it should, the following line should call containingBlockLogicalWidthForContent.
   1709     LayoutUnit result = cb->availableLogicalWidth();
   1710     RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(containingBlockRegion, offsetFromLogicalTopOfFirstPage - logicalTop());
   1711     if (!boxInfo)
   1712         return result;
   1713     return max<LayoutUnit>(0, result - (cb->logicalWidth() - boxInfo->logicalWidth()));
   1714 }
   1715 
   1716 LayoutUnit RenderBox::containingBlockAvailableLineWidthInRegion(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
   1717 {
   1718     RenderBlock* cb = containingBlock();
   1719     RenderRegion* containingBlockRegion = 0;
   1720     LayoutUnit logicalTopPosition = logicalTop();
   1721     LayoutUnit adjustedPageOffsetForContainingBlock = offsetFromLogicalTopOfFirstPage - logicalTop();
   1722     if (region) {
   1723         LayoutUnit offsetFromLogicalTopOfRegion = region ? region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage : LayoutUnit();
   1724         logicalTopPosition = max(logicalTopPosition, logicalTopPosition + offsetFromLogicalTopOfRegion);
   1725         containingBlockRegion = cb->clampToStartAndEndRegions(region);
   1726     }
   1727     return cb->availableLogicalWidthForLine(logicalTopPosition, false, containingBlockRegion, adjustedPageOffsetForContainingBlock, availableLogicalHeight(IncludeMarginBorderPadding));
   1728 }
   1729 
   1730 LayoutUnit RenderBox::perpendicularContainingBlockLogicalHeight() const
   1731 {
   1732     if (hasOverrideContainingBlockLogicalHeight())
   1733         return overrideContainingBlockContentLogicalHeight();
   1734 
   1735     RenderBlock* cb = containingBlock();
   1736     if (cb->hasOverrideHeight())
   1737         return cb->overrideLogicalContentHeight();
   1738 
   1739     RenderStyle* containingBlockStyle = cb->style();
   1740     Length logicalHeightLength = containingBlockStyle->logicalHeight();
   1741 
   1742     // FIXME: For now just support fixed heights.  Eventually should support percentage heights as well.
   1743     if (!logicalHeightLength.isFixed()) {
   1744         LayoutUnit fillFallbackExtent = containingBlockStyle->isHorizontalWritingMode() ? view()->frameView()->visibleHeight() : view()->frameView()->visibleWidth();
   1745         LayoutUnit fillAvailableExtent = containingBlock()->availableLogicalHeight(ExcludeMarginBorderPadding);
   1746         return min(fillAvailableExtent, fillFallbackExtent);
   1747     }
   1748 
   1749     // Use the content box logical height as specified by the style.
   1750     return cb->adjustContentBoxLogicalHeightForBoxSizing(logicalHeightLength.value());
   1751 }
   1752 
   1753 void RenderBox::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const
   1754 {
   1755     if (repaintContainer == this)
   1756         return;
   1757 
   1758     if (RenderView* v = view()) {
   1759         if (v->layoutStateEnabled() && !repaintContainer) {
   1760             LayoutState* layoutState = v->layoutState();
   1761             LayoutSize offset = layoutState->m_paintOffset + locationOffset();
   1762             if (style()->hasInFlowPosition() && layer())
   1763                 offset += layer()->offsetForInFlowPosition();
   1764             transformState.move(offset);
   1765             return;
   1766         }
   1767     }
   1768 
   1769     bool containerSkipped;
   1770     RenderObject* o = container(repaintContainer, &containerSkipped);
   1771     if (!o)
   1772         return;
   1773 
   1774     bool isFixedPos = style()->position() == FixedPosition;
   1775     bool hasTransform = hasLayer() && layer()->transform();
   1776     // If this box has a transform, it acts as a fixed position container for fixed descendants,
   1777     // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
   1778     if (hasTransform && !isFixedPos)
   1779         mode &= ~IsFixed;
   1780     else if (isFixedPos)
   1781         mode |= IsFixed;
   1782 
   1783     if (wasFixed)
   1784         *wasFixed = mode & IsFixed;
   1785 
   1786     LayoutSize containerOffset = offsetFromContainer(o, roundedLayoutPoint(transformState.mappedPoint()));
   1787 
   1788     bool preserve3D = mode & UseTransforms && (o->style()->preserves3D() || style()->preserves3D());
   1789     if (mode & UseTransforms && shouldUseTransformFromContainer(o)) {
   1790         TransformationMatrix t;
   1791         getTransformFromContainer(o, containerOffset, t);
   1792         transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
   1793     } else
   1794         transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
   1795 
   1796     if (containerSkipped) {
   1797         // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
   1798         // to just subtract the delta between the repaintContainer and o.
   1799         LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
   1800         transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
   1801         return;
   1802     }
   1803 
   1804     mode &= ~ApplyContainerFlip;
   1805 
   1806     o->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed);
   1807 }
   1808 
   1809 void RenderBox::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState& transformState) const
   1810 {
   1811     // We don't expect to be called during layout.
   1812     ASSERT(!view() || !view()->layoutStateEnabled());
   1813 
   1814     bool isFixedPos = style()->position() == FixedPosition;
   1815     bool hasTransform = hasLayer() && layer()->transform();
   1816     if (hasTransform && !isFixedPos) {
   1817         // If this box has a transform, it acts as a fixed position container for fixed descendants,
   1818         // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
   1819         mode &= ~IsFixed;
   1820     } else if (isFixedPos)
   1821         mode |= IsFixed;
   1822 
   1823     RenderBoxModelObject::mapAbsoluteToLocalPoint(mode, transformState);
   1824 }
   1825 
   1826 LayoutSize RenderBox::offsetFromContainer(RenderObject* o, const LayoutPoint& point, bool* offsetDependsOnPoint) const
   1827 {
   1828     // A region "has" boxes inside it without being their container.
   1829     // FIXME: change container() / containingBlock() to count for boxes being positioned relative to the region, not the
   1830     // FlowThread. This requires a separate patch as a simple test with such a change in container() causes 129 out of
   1831     // 337 regions tests to fail.
   1832     ASSERT(o == container() || o->isRenderRegion());
   1833 
   1834     LayoutSize offset;
   1835     if (isInFlowPositioned())
   1836         offset += offsetForInFlowPosition();
   1837 
   1838     if (!isInline() || isReplaced()) {
   1839         if (!style()->hasOutOfFlowPosition() && o->hasColumns()) {
   1840             RenderBlock* block = toRenderBlock(o);
   1841             LayoutRect columnRect(frameRect());
   1842             block->adjustStartEdgeForWritingModeIncludingColumns(columnRect);
   1843             offset += toSize(columnRect.location());
   1844             LayoutPoint columnPoint = block->flipForWritingModeIncludingColumns(point + offset);
   1845             offset = toLayoutSize(block->flipForWritingModeIncludingColumns(toLayoutPoint(offset)));
   1846             o->adjustForColumns(offset, columnPoint);
   1847             offset = block->flipForWritingMode(offset);
   1848 
   1849             if (offsetDependsOnPoint)
   1850                 *offsetDependsOnPoint = true;
   1851         } else
   1852             offset += topLeftLocationOffset();
   1853     }
   1854 
   1855     if (o->hasOverflowClip())
   1856         offset -= toRenderBox(o)->scrolledContentOffset();
   1857 
   1858     if (style()->position() == AbsolutePosition && o->isInFlowPositioned() && o->isRenderInline())
   1859         offset += toRenderInline(o)->offsetForInFlowPositionedInline(this);
   1860 
   1861     if (offsetDependsOnPoint)
   1862         *offsetDependsOnPoint |= o->isRenderFlowThread();
   1863 
   1864     return offset;
   1865 }
   1866 
   1867 InlineBox* RenderBox::createInlineBox()
   1868 {
   1869     return new InlineBox(this);
   1870 }
   1871 
   1872 void RenderBox::dirtyLineBoxes(bool fullLayout)
   1873 {
   1874     if (m_inlineBoxWrapper) {
   1875         if (fullLayout) {
   1876             m_inlineBoxWrapper->destroy();
   1877             m_inlineBoxWrapper = 0;
   1878         } else
   1879             m_inlineBoxWrapper->dirtyLineBoxes();
   1880     }
   1881 }
   1882 
   1883 void RenderBox::positionLineBox(InlineBox* box)
   1884 {
   1885     if (isOutOfFlowPositioned()) {
   1886         // Cache the x position only if we were an INLINE type originally.
   1887         bool wasInline = style()->isOriginalDisplayInlineType();
   1888         if (wasInline) {
   1889             // The value is cached in the xPos of the box.  We only need this value if
   1890             // our object was inline originally, since otherwise it would have ended up underneath
   1891             // the inlines.
   1892             RootInlineBox* root = box->root();
   1893             root->block()->setStaticInlinePositionForChild(this, root->lineTopWithLeading(), LayoutUnit::fromFloatRound(box->logicalLeft()));
   1894             if (style()->hasStaticInlinePosition(box->isHorizontal()))
   1895                 setChildNeedsLayout(MarkOnlyThis); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
   1896         } else {
   1897             // Our object was a block originally, so we make our normal flow position be
   1898             // just below the line box (as though all the inlines that came before us got
   1899             // wrapped in an anonymous block, which is what would have happened had we been
   1900             // in flow).  This value was cached in the y() of the box.
   1901             layer()->setStaticBlockPosition(box->logicalTop());
   1902             if (style()->hasStaticBlockPosition(box->isHorizontal()))
   1903                 setChildNeedsLayout(MarkOnlyThis); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
   1904         }
   1905 
   1906         // Nuke the box.
   1907         box->remove();
   1908         box->destroy();
   1909     } else if (isReplaced()) {
   1910         setLocation(roundedLayoutPoint(box->topLeft()));
   1911         setInlineBoxWrapper(box);
   1912     }
   1913 }
   1914 
   1915 void RenderBox::deleteLineBoxWrapper()
   1916 {
   1917     if (m_inlineBoxWrapper) {
   1918         if (!documentBeingDestroyed())
   1919             m_inlineBoxWrapper->remove();
   1920         m_inlineBoxWrapper->destroy();
   1921         m_inlineBoxWrapper = 0;
   1922     }
   1923 }
   1924 
   1925 LayoutRect RenderBox::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const
   1926 {
   1927     if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent())
   1928         return LayoutRect();
   1929 
   1930     LayoutRect r = visualOverflowRect();
   1931 
   1932     RenderView* v = view();
   1933     if (v) {
   1934         // FIXME: layoutDelta needs to be applied in parts before/after transforms and
   1935         // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
   1936         r.move(v->layoutDelta());
   1937     }
   1938 
   1939     if (style()) {
   1940         // We have to use maximalOutlineSize() because a child might have an outline
   1941         // that projects outside of our overflowRect.
   1942         if (v) {
   1943             ASSERT(style()->outlineSize() <= v->maximalOutlineSize());
   1944             r.inflate(v->maximalOutlineSize());
   1945         }
   1946     }
   1947 
   1948     computeRectForRepaint(repaintContainer, r);
   1949     return r;
   1950 }
   1951 
   1952 void RenderBox::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& rect, bool fixed) const
   1953 {
   1954     // The rect we compute at each step is shifted by our x/y offset in the parent container's coordinate space.
   1955     // Only when we cross a writing mode boundary will we have to possibly flipForWritingMode (to convert into a more appropriate
   1956     // offset corner for the enclosing container).  This allows for a fully RL or BT document to repaint
   1957     // properly even during layout, since the rect remains flipped all the way until the end.
   1958     //
   1959     // RenderView::computeRectForRepaint then converts the rect to physical coordinates.  We also convert to
   1960     // physical when we hit a repaintContainer boundary.  Therefore the final rect returned is always in the
   1961     // physical coordinate space of the repaintContainer.
   1962     RenderStyle* styleToUse = style();
   1963     if (RenderView* v = view()) {
   1964         // LayoutState is only valid for root-relative, non-fixed position repainting
   1965         if (v->layoutStateEnabled() && !repaintContainer && styleToUse->position() != FixedPosition) {
   1966             LayoutState* layoutState = v->layoutState();
   1967 
   1968             if (layer() && layer()->transform())
   1969                 rect = layer()->transform()->mapRect(pixelSnappedIntRect(rect));
   1970 
   1971             // We can't trust the bits on RenderObject, because this might be called while re-resolving style.
   1972             if (styleToUse->hasInFlowPosition() && layer())
   1973                 rect.move(layer()->offsetForInFlowPosition());
   1974 
   1975             rect.moveBy(location());
   1976             rect.move(layoutState->m_paintOffset);
   1977             if (layoutState->m_clipped)
   1978                 rect.intersect(layoutState->m_clipRect);
   1979             return;
   1980         }
   1981     }
   1982 
   1983     if (hasReflection())
   1984         rect.unite(reflectedRect(rect));
   1985 
   1986     if (repaintContainer == this) {
   1987         if (repaintContainer->style()->isFlippedBlocksWritingMode())
   1988             flipForWritingMode(rect);
   1989         return;
   1990     }
   1991 
   1992     bool containerSkipped;
   1993     RenderObject* o = container(repaintContainer, &containerSkipped);
   1994     if (!o)
   1995         return;
   1996 
   1997     if (isWritingModeRoot() && !isOutOfFlowPositioned())
   1998         flipForWritingMode(rect);
   1999 
   2000     LayoutPoint topLeft = rect.location();
   2001     topLeft.move(locationOffset());
   2002 
   2003     EPosition position = styleToUse->position();
   2004 
   2005     // We are now in our parent container's coordinate space.  Apply our transform to obtain a bounding box
   2006     // in the parent's coordinate space that encloses us.
   2007     if (hasLayer() && layer()->transform()) {
   2008         fixed = position == FixedPosition;
   2009         rect = layer()->transform()->mapRect(pixelSnappedIntRect(rect));
   2010         topLeft = rect.location();
   2011         topLeft.move(locationOffset());
   2012     } else if (position == FixedPosition)
   2013         fixed = true;
   2014 
   2015     if (position == AbsolutePosition && o->isInFlowPositioned() && o->isRenderInline()) {
   2016         topLeft += toRenderInline(o)->offsetForInFlowPositionedInline(this);
   2017     } else if (styleToUse->hasInFlowPosition() && layer()) {
   2018         // Apply the relative position offset when invalidating a rectangle.  The layer
   2019         // is translated, but the render box isn't, so we need to do this to get the
   2020         // right dirty rect.  Since this is called from RenderObject::setStyle, the relative position
   2021         // flag on the RenderObject has been cleared, so use the one on the style().
   2022         topLeft += layer()->offsetForInFlowPosition();
   2023     }
   2024 
   2025     if (position != AbsolutePosition && position != FixedPosition && o->hasColumns() && o->isBlockFlow()) {
   2026         LayoutRect repaintRect(topLeft, rect.size());
   2027         toRenderBlock(o)->adjustRectForColumns(repaintRect);
   2028         topLeft = repaintRect.location();
   2029         rect = repaintRect;
   2030     }
   2031 
   2032     // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
   2033     // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
   2034     rect.setLocation(topLeft);
   2035     if (o->hasOverflowClip()) {
   2036         RenderBox* containerBox = toRenderBox(o);
   2037         containerBox->applyCachedClipAndScrollOffsetForRepaint(rect);
   2038         if (rect.isEmpty())
   2039             return;
   2040     }
   2041 
   2042     if (containerSkipped) {
   2043         // If the repaintContainer is below o, then we need to map the rect into repaintContainer's coordinates.
   2044         LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
   2045         rect.move(-containerOffset);
   2046         return;
   2047     }
   2048 
   2049     o->computeRectForRepaint(repaintContainer, rect, fixed);
   2050 }
   2051 
   2052 void RenderBox::repaintDuringLayoutIfMoved(const LayoutRect& oldRect)
   2053 {
   2054     if (oldRect.location() != m_frameRect.location()) {
   2055         LayoutRect newRect = m_frameRect;
   2056         // The child moved.  Invalidate the object's old and new positions.  We have to do this
   2057         // since the object may not have gotten a layout.
   2058         m_frameRect = oldRect;
   2059         repaint();
   2060         repaintOverhangingFloats(true);
   2061         m_frameRect = newRect;
   2062         repaint();
   2063         repaintOverhangingFloats(true);
   2064     }
   2065 }
   2066 
   2067 void RenderBox::repaintOverhangingFloats(bool)
   2068 {
   2069 }
   2070 
   2071 void RenderBox::updateLogicalWidth()
   2072 {
   2073     LogicalExtentComputedValues computedValues;
   2074     computeLogicalWidthInRegion(computedValues);
   2075 
   2076     setLogicalWidth(computedValues.m_extent);
   2077     setLogicalLeft(computedValues.m_position);
   2078     setMarginStart(computedValues.m_margins.m_start);
   2079     setMarginEnd(computedValues.m_margins.m_end);
   2080 }
   2081 
   2082 static float getMaxWidthListMarker(const RenderBox* renderer)
   2083 {
   2084 #ifndef NDEBUG
   2085     ASSERT(renderer);
   2086     Node* parentNode = renderer->generatingNode();
   2087     ASSERT(parentNode);
   2088     ASSERT(parentNode->hasTagName(olTag) || parentNode->hasTagName(ulTag));
   2089     ASSERT(renderer->style()->textAutosizingMultiplier() != 1);
   2090 #endif
   2091     float maxWidth = 0;
   2092     for (RenderObject* child = renderer->firstChild(); child; child = child->nextSibling()) {
   2093         if (!child->isListItem())
   2094             continue;
   2095 
   2096         RenderBox* listItem = toRenderBox(child);
   2097         for (RenderObject* itemChild = listItem->firstChild(); itemChild; itemChild = itemChild->nextSibling()) {
   2098             if (!itemChild->isListMarker())
   2099                 continue;
   2100             RenderBox* itemMarker = toRenderBox(itemChild);
   2101             if (itemMarker->requiresLayoutToDetermineWidth()) {
   2102                 // Make sure to compute the autosized width.
   2103                 itemMarker->layout();
   2104             }
   2105             maxWidth = max<float>(maxWidth, toRenderListMarker(itemMarker)->logicalWidth().toFloat());
   2106             break;
   2107         }
   2108     }
   2109     return maxWidth;
   2110 }
   2111 
   2112 void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& computedValues, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
   2113 {
   2114     computedValues.m_extent = logicalWidth();
   2115     computedValues.m_position = logicalLeft();
   2116     computedValues.m_margins.m_start = marginStart();
   2117     computedValues.m_margins.m_end = marginEnd();
   2118 
   2119     if (isOutOfFlowPositioned()) {
   2120         // FIXME: This calculation is not patched for block-flow yet.
   2121         // https://bugs.webkit.org/show_bug.cgi?id=46500
   2122         computePositionedLogicalWidth(computedValues, region, offsetFromLogicalTopOfFirstPage);
   2123         return;
   2124     }
   2125 
   2126     // If layout is limited to a subtree, the subtree root's logical width does not change.
   2127     if (node() && view()->frameView() && view()->frameView()->layoutRoot(true) == this)
   2128         return;
   2129 
   2130     // The parent box is flexing us, so it has increased or decreased our
   2131     // width.  Use the width from the style context.
   2132     // FIXME: Account for block-flow in flexible boxes.
   2133     // https://bugs.webkit.org/show_bug.cgi?id=46418
   2134     if (hasOverrideWidth() && (style()->borderFit() == BorderFitLines || parent()->isFlexibleBoxIncludingDeprecated())) {
   2135         computedValues.m_extent = overrideLogicalContentWidth() + borderAndPaddingLogicalWidth();
   2136         return;
   2137     }
   2138 
   2139     // FIXME: Account for block-flow in flexible boxes.
   2140     // https://bugs.webkit.org/show_bug.cgi?id=46418
   2141     bool inVerticalBox = parent()->isDeprecatedFlexibleBox() && (parent()->style()->boxOrient() == VERTICAL);
   2142     bool stretching = (parent()->style()->boxAlign() == BSTRETCH);
   2143     bool treatAsReplaced = shouldComputeSizeAsReplaced() && (!inVerticalBox || !stretching);
   2144 
   2145     RenderStyle* styleToUse = style();
   2146     Length logicalWidthLength = treatAsReplaced ? Length(computeReplacedLogicalWidth(), Fixed) : styleToUse->logicalWidth();
   2147 
   2148     RenderBlock* cb = containingBlock();
   2149     LayoutUnit containerLogicalWidth = max<LayoutUnit>(0, containingBlockLogicalWidthForContentInRegion(region, offsetFromLogicalTopOfFirstPage));
   2150     bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHorizontalWritingMode();
   2151 
   2152     if (isInline() && !isInlineBlockOrInlineTable()) {
   2153         // just calculate margins
   2154         RenderView* renderView = view();
   2155         computedValues.m_margins.m_start = minimumValueForLength(styleToUse->marginStart(), containerLogicalWidth, renderView);
   2156         computedValues.m_margins.m_end = minimumValueForLength(styleToUse->marginEnd(), containerLogicalWidth, renderView);
   2157         if (treatAsReplaced)
   2158             computedValues.m_extent = max<LayoutUnit>(floatValueForLength(logicalWidthLength, 0) + borderAndPaddingLogicalWidth(), minPreferredLogicalWidth());
   2159         return;
   2160     }
   2161 
   2162     // Width calculations
   2163     if (treatAsReplaced)
   2164         computedValues.m_extent = logicalWidthLength.value() + borderAndPaddingLogicalWidth();
   2165     else {
   2166         LayoutUnit containerWidthInInlineDirection = containerLogicalWidth;
   2167         if (hasPerpendicularContainingBlock)
   2168             containerWidthInInlineDirection = perpendicularContainingBlockLogicalHeight();
   2169         LayoutUnit preferredWidth = computeLogicalWidthInRegionUsing(MainOrPreferredSize, styleToUse->logicalWidth(), containerWidthInInlineDirection, cb, region, offsetFromLogicalTopOfFirstPage);
   2170         computedValues.m_extent = constrainLogicalWidthInRegionByMinMax(preferredWidth, containerWidthInInlineDirection, cb, region, offsetFromLogicalTopOfFirstPage);
   2171     }
   2172 
   2173     // Margin calculations.
   2174     if (hasPerpendicularContainingBlock || isFloating() || isInline()) {
   2175         RenderView* renderView = view();
   2176         computedValues.m_margins.m_start = minimumValueForLength(styleToUse->marginStart(), containerLogicalWidth, renderView);
   2177         computedValues.m_margins.m_end = minimumValueForLength(styleToUse->marginEnd(), containerLogicalWidth, renderView);
   2178     } else {
   2179         LayoutUnit containerLogicalWidthForAutoMargins = containerLogicalWidth;
   2180         if (avoidsFloats() && cb->containsFloats())
   2181             containerLogicalWidthForAutoMargins = containingBlockAvailableLineWidthInRegion(region, offsetFromLogicalTopOfFirstPage);
   2182         bool hasInvertedDirection = cb->style()->isLeftToRightDirection() != style()->isLeftToRightDirection();
   2183         computeInlineDirectionMargins(cb, containerLogicalWidthForAutoMargins, computedValues.m_extent,
   2184             hasInvertedDirection ? computedValues.m_margins.m_end : computedValues.m_margins.m_start,
   2185             hasInvertedDirection ? computedValues.m_margins.m_start : computedValues.m_margins.m_end);
   2186     }
   2187 
   2188     if (!hasPerpendicularContainingBlock && containerLogicalWidth && containerLogicalWidth != (computedValues.m_extent + computedValues.m_margins.m_start + computedValues.m_margins.m_end)
   2189         && !isFloating() && !isInline() && !cb->isFlexibleBoxIncludingDeprecated() && !cb->isRenderGrid()) {
   2190         LayoutUnit newMargin = containerLogicalWidth - computedValues.m_extent - cb->marginStartForChild(this);
   2191         bool hasInvertedDirection = cb->style()->isLeftToRightDirection() != style()->isLeftToRightDirection();
   2192         if (hasInvertedDirection)
   2193             computedValues.m_margins.m_start = newMargin;
   2194         else
   2195             computedValues.m_margins.m_end = newMargin;
   2196     }
   2197 
   2198     if (styleToUse->textAutosizingMultiplier() != 1 && styleToUse->marginStart().type() == Fixed) {
   2199         Node* parentNode = generatingNode();
   2200         if (parentNode && (parentNode->hasTagName(olTag) || parentNode->hasTagName(ulTag))) {
   2201             // Make sure the markers in a list are properly positioned (i.e. not chopped off) when autosized.
   2202             const float adjustedMargin = (1 - 1.0 / styleToUse->textAutosizingMultiplier()) * getMaxWidthListMarker(this);
   2203             bool hasInvertedDirection = cb->style()->isLeftToRightDirection() != style()->isLeftToRightDirection();
   2204             if (hasInvertedDirection)
   2205                 computedValues.m_margins.m_end += adjustedMargin;
   2206             else
   2207                 computedValues.m_margins.m_start += adjustedMargin;
   2208         }
   2209     }
   2210 }
   2211 
   2212 LayoutUnit RenderBox::fillAvailableMeasure(LayoutUnit availableLogicalWidth) const
   2213 {
   2214     LayoutUnit marginStart = 0;
   2215     LayoutUnit marginEnd = 0;
   2216     return fillAvailableMeasure(availableLogicalWidth, marginStart, marginEnd);
   2217 }
   2218 
   2219 LayoutUnit RenderBox::fillAvailableMeasure(LayoutUnit availableLogicalWidth, LayoutUnit& marginStart, LayoutUnit& marginEnd) const
   2220 {
   2221     RenderView* renderView = view();
   2222     marginStart = minimumValueForLength(style()->marginStart(), availableLogicalWidth, renderView);
   2223     marginEnd = minimumValueForLength(style()->marginEnd(), availableLogicalWidth, renderView);
   2224     return availableLogicalWidth - marginStart - marginEnd;
   2225 }
   2226 
   2227 LayoutUnit RenderBox::computeIntrinsicLogicalWidthUsing(Length logicalWidthLength, LayoutUnit availableLogicalWidth, LayoutUnit borderAndPadding) const
   2228 {
   2229     if (logicalWidthLength.type() == FillAvailable)
   2230         return fillAvailableMeasure(availableLogicalWidth);
   2231 
   2232     LayoutUnit minLogicalWidth = 0;
   2233     LayoutUnit maxLogicalWidth = 0;
   2234     computeIntrinsicLogicalWidths(minLogicalWidth, maxLogicalWidth);
   2235 
   2236     if (logicalWidthLength.type() == MinContent)
   2237         return minLogicalWidth + borderAndPadding;
   2238 
   2239     if (logicalWidthLength.type() == MaxContent)
   2240         return maxLogicalWidth + borderAndPadding;
   2241 
   2242     if (logicalWidthLength.type() == FitContent) {
   2243         minLogicalWidth += borderAndPadding;
   2244         maxLogicalWidth += borderAndPadding;
   2245         return max(minLogicalWidth, min(maxLogicalWidth, fillAvailableMeasure(availableLogicalWidth)));
   2246     }
   2247 
   2248     ASSERT_NOT_REACHED();
   2249     return 0;
   2250 }
   2251 
   2252 LayoutUnit RenderBox::computeLogicalWidthInRegionUsing(SizeType widthType, Length logicalWidth, LayoutUnit availableLogicalWidth,
   2253     const RenderBlock* cb, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
   2254 {
   2255     if (!logicalWidth.isIntrinsicOrAuto()) {
   2256         // FIXME: If the containing block flow is perpendicular to our direction we need to use the available logical height instead.
   2257         return adjustBorderBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, availableLogicalWidth, view()));
   2258     }
   2259 
   2260     if (logicalWidth.isIntrinsic())
   2261         return computeIntrinsicLogicalWidthUsing(logicalWidth, availableLogicalWidth, borderAndPaddingLogicalWidth());
   2262 
   2263     LayoutUnit marginStart = 0;
   2264     LayoutUnit marginEnd = 0;
   2265     LayoutUnit logicalWidthResult = fillAvailableMeasure(availableLogicalWidth, marginStart, marginEnd);
   2266 
   2267     if (shrinkToAvoidFloats() && cb->containsFloats())
   2268         logicalWidthResult = min(logicalWidthResult, shrinkLogicalWidthToAvoidFloats(marginStart, marginEnd, cb, region, offsetFromLogicalTopOfFirstPage));
   2269 
   2270     if (widthType == MainOrPreferredSize && sizesLogicalWidthToFitContent(widthType))
   2271         return max(minPreferredLogicalWidth(), min(maxPreferredLogicalWidth(), logicalWidthResult));
   2272     return logicalWidthResult;
   2273 }
   2274 
   2275 static bool columnFlexItemHasStretchAlignment(const RenderObject* flexitem)
   2276 {
   2277     RenderObject* parent = flexitem->parent();
   2278     // auto margins mean we don't stretch. Note that this function will only be used for
   2279     // widths, so we don't have to check marginBefore/marginAfter.
   2280     ASSERT(parent->style()->isColumnFlexDirection());
   2281     if (flexitem->style()->marginStart().isAuto() || flexitem->style()->marginEnd().isAuto())
   2282         return false;
   2283     return flexitem->style()->alignSelf() == AlignStretch || (flexitem->style()->alignSelf() == AlignAuto && parent->style()->alignItems() == AlignStretch);
   2284 }
   2285 
   2286 static bool isStretchingColumnFlexItem(const RenderObject* flexitem)
   2287 {
   2288     RenderObject* parent = flexitem->parent();
   2289     if (parent->isDeprecatedFlexibleBox() && parent->style()->boxOrient() == VERTICAL && parent->style()->boxAlign() == BSTRETCH)
   2290         return true;
   2291 
   2292     // We don't stretch multiline flexboxes because they need to apply line spacing (align-content) first.
   2293     if (parent->isFlexibleBox() && parent->style()->flexWrap() == FlexNoWrap && parent->style()->isColumnFlexDirection() && columnFlexItemHasStretchAlignment(flexitem))
   2294         return true;
   2295     return false;
   2296 }
   2297 
   2298 bool RenderBox::sizesLogicalWidthToFitContent(SizeType widthType) const
   2299 {
   2300     // Marquees in WinIE are like a mixture of blocks and inline-blocks.  They size as though they're blocks,
   2301     // but they allow text to sit on the same line as the marquee.
   2302     if (isFloating() || (isInlineBlockOrInlineTable() && !isMarquee()))
   2303         return true;
   2304 
   2305     // This code may look a bit strange.  Basically width:intrinsic should clamp the size when testing both
   2306     // min-width and width.  max-width is only clamped if it is also intrinsic.
   2307     Length logicalWidth = (widthType == MaxSize) ? style()->logicalMaxWidth() : style()->logicalWidth();
   2308     if (logicalWidth.type() == Intrinsic)
   2309         return true;
   2310 
   2311     // Children of a horizontal marquee do not fill the container by default.
   2312     // FIXME: Need to deal with MAUTO value properly.  It could be vertical.
   2313     // FIXME: Think about block-flow here.  Need to find out how marquee direction relates to
   2314     // block-flow (as well as how marquee overflow should relate to block flow).
   2315     // https://bugs.webkit.org/show_bug.cgi?id=46472
   2316     if (parent()->isMarquee()) {
   2317         EMarqueeDirection dir = parent()->style()->marqueeDirection();
   2318         if (dir == MAUTO || dir == MFORWARD || dir == MBACKWARD || dir == MLEFT || dir == MRIGHT)
   2319             return true;
   2320     }
   2321 
   2322     // Flexible box items should shrink wrap, so we lay them out at their intrinsic widths.
   2323     // In the case of columns that have a stretch alignment, we go ahead and layout at the
   2324     // stretched size to avoid an extra layout when applying alignment.
   2325     if (parent()->isFlexibleBox()) {
   2326         // For multiline columns, we need to apply align-content first, so we can't stretch now.
   2327         if (!parent()->style()->isColumnFlexDirection() || parent()->style()->flexWrap() != FlexNoWrap)
   2328             return true;
   2329         if (!columnFlexItemHasStretchAlignment(this))
   2330             return true;
   2331     }
   2332 
   2333     // Flexible horizontal boxes lay out children at their intrinsic widths.  Also vertical boxes
   2334     // that don't stretch their kids lay out their children at their intrinsic widths.
   2335     // FIXME: Think about block-flow here.
   2336     // https://bugs.webkit.org/show_bug.cgi?id=46473
   2337     if (parent()->isDeprecatedFlexibleBox() && (parent()->style()->boxOrient() == HORIZONTAL || parent()->style()->boxAlign() != BSTRETCH))
   2338         return true;
   2339 
   2340     // Button, input, select, textarea, and legend treat width value of 'auto' as 'intrinsic' unless it's in a
   2341     // stretching column flexbox.
   2342     // FIXME: Think about block-flow here.
   2343     // https://bugs.webkit.org/show_bug.cgi?id=46473
   2344     if (logicalWidth.type() == Auto && !isStretchingColumnFlexItem(this) && node() && (node()->hasTagName(inputTag)
   2345         || node()->hasTagName(selectTag) || node()->hasTagName(buttonTag) || isHTMLTextAreaElement(node()) || node()->hasTagName(legendTag)))
   2346         return true;
   2347 
   2348     if (isHorizontalWritingMode() != containingBlock()->isHorizontalWritingMode())
   2349         return true;
   2350 
   2351     return false;
   2352 }
   2353 
   2354 void RenderBox::computeInlineDirectionMargins(RenderBlock* containingBlock, LayoutUnit containerWidth, LayoutUnit childWidth, LayoutUnit& marginStart, LayoutUnit& marginEnd) const
   2355 {
   2356     const RenderStyle* containingBlockStyle = containingBlock->style();
   2357     Length marginStartLength = style()->marginStartUsing(containingBlockStyle);
   2358     Length marginEndLength = style()->marginEndUsing(containingBlockStyle);
   2359     RenderView* renderView = view();
   2360 
   2361     if (isFloating() || isInline()) {
   2362         // Inline blocks/tables and floats don't have their margins increased.
   2363         marginStart = minimumValueForLength(marginStartLength, containerWidth, renderView);
   2364         marginEnd = minimumValueForLength(marginEndLength, containerWidth, renderView);
   2365         return;
   2366     }
   2367 
   2368     if (containingBlock->isFlexibleBox()) {
   2369         // We need to let flexbox handle the margin adjustment - otherwise, flexbox
   2370         // will think we're wider than we actually are and calculate line sizes wrong.
   2371         // See also http://dev.w3.org/csswg/css-flexbox/#auto-margins
   2372         if (marginStartLength.isAuto())
   2373             marginStartLength.setValue(0);
   2374         if (marginEndLength.isAuto())
   2375             marginEndLength.setValue(0);
   2376     }
   2377 
   2378     // Case One: The object is being centered in the containing block's available logical width.
   2379     if ((marginStartLength.isAuto() && marginEndLength.isAuto() && childWidth < containerWidth)
   2380         || (!marginStartLength.isAuto() && !marginEndLength.isAuto() && containingBlock->style()->textAlign() == WEBKIT_CENTER)) {
   2381         // Other browsers center the margin box for align=center elements so we match them here.
   2382         LayoutUnit marginStartWidth = minimumValueForLength(marginStartLength, containerWidth, renderView);
   2383         LayoutUnit marginEndWidth = minimumValueForLength(marginEndLength, containerWidth, renderView);
   2384         LayoutUnit centeredMarginBoxStart = max<LayoutUnit>(0, (containerWidth - childWidth - marginStartWidth - marginEndWidth) / 2);
   2385         marginStart = centeredMarginBoxStart + marginStartWidth;
   2386         marginEnd = containerWidth - childWidth - marginStart + marginEndWidth;
   2387         return;
   2388     }
   2389 
   2390     // Case Two: The object is being pushed to the start of the containing block's available logical width.
   2391     if (marginEndLength.isAuto() && childWidth < containerWidth) {
   2392         marginStart = valueForLength(marginStartLength, containerWidth, renderView);
   2393         marginEnd = containerWidth - childWidth - marginStart;
   2394         return;
   2395     }
   2396 
   2397     // Case Three: The object is being pushed to the end of the containing block's available logical width.
   2398     bool pushToEndFromTextAlign = !marginEndLength.isAuto() && ((!containingBlockStyle->isLeftToRightDirection() && containingBlockStyle->textAlign() == WEBKIT_LEFT)
   2399         || (containingBlockStyle->isLeftToRightDirection() && containingBlockStyle->textAlign() == WEBKIT_RIGHT));
   2400     if ((marginStartLength.isAuto() && childWidth < containerWidth) || pushToEndFromTextAlign) {
   2401         marginEnd = valueForLength(marginEndLength, containerWidth, renderView);
   2402         marginStart = containerWidth - childWidth - marginEnd;
   2403         return;
   2404     }
   2405 
   2406     // Case Four: Either no auto margins, or our width is >= the container width (css2.1, 10.3.3).  In that case
   2407     // auto margins will just turn into 0.
   2408     marginStart = minimumValueForLength(marginStartLength, containerWidth, renderView);
   2409     marginEnd = minimumValueForLength(marginEndLength, containerWidth, renderView);
   2410 }
   2411 
   2412 RenderBoxRegionInfo* RenderBox::renderBoxRegionInfo(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage, RenderBoxRegionInfoFlags cacheFlag) const
   2413 {
   2414     // Make sure nobody is trying to call this with a null region.
   2415     if (!region)
   2416         return 0;
   2417 
   2418     // If we have computed our width in this region already, it will be cached, and we can
   2419     // just return it.
   2420     RenderBoxRegionInfo* boxInfo = region->renderBoxRegionInfo(this);
   2421     if (boxInfo && cacheFlag == CacheRenderBoxRegionInfo)
   2422         return boxInfo;
   2423 
   2424     // No cached value was found, so we have to compute our insets in this region.
   2425     // FIXME: For now we limit this computation to normal RenderBlocks. Future patches will expand
   2426     // support to cover all boxes.
   2427     RenderFlowThread* flowThread = flowThreadContainingBlock();
   2428     if (isRenderFlowThread() || !flowThread || !canHaveBoxInfoInRegion() || flowThread->style()->writingMode() != style()->writingMode())
   2429         return 0;
   2430 
   2431     LogicalExtentComputedValues computedValues;
   2432     computeLogicalWidthInRegion(computedValues, region, offsetFromLogicalTopOfFirstPage);
   2433 
   2434     // Now determine the insets based off where this object is supposed to be positioned.
   2435     RenderBlock* cb = containingBlock();
   2436     RenderRegion* clampedContainingBlockRegion = cb->clampToStartAndEndRegions(region);
   2437     RenderBoxRegionInfo* containingBlockInfo = cb->renderBoxRegionInfo(clampedContainingBlockRegion,
   2438         offsetFromLogicalTopOfFirstPage - logicalTop());
   2439     LayoutUnit containingBlockLogicalWidth = cb->logicalWidth();
   2440     LayoutUnit containingBlockLogicalWidthInRegion = containingBlockInfo ? containingBlockInfo->logicalWidth() : containingBlockLogicalWidth;
   2441 
   2442     LayoutUnit marginStartInRegion = computedValues.m_margins.m_start;
   2443     LayoutUnit startMarginDelta = marginStartInRegion - marginStart();
   2444     LayoutUnit logicalWidthInRegion = computedValues.m_extent;
   2445     LayoutUnit logicalLeftInRegion = computedValues.m_position;
   2446     LayoutUnit widthDelta = logicalWidthInRegion - logicalWidth();
   2447     LayoutUnit logicalLeftDelta = isOutOfFlowPositioned() ? logicalLeftInRegion - logicalLeft() : startMarginDelta;
   2448     LayoutUnit logicalRightInRegion = containingBlockLogicalWidthInRegion - (logicalLeftInRegion + logicalWidthInRegion);
   2449     LayoutUnit oldLogicalRight = containingBlockLogicalWidth - (logicalLeft() + logicalWidth());
   2450     LayoutUnit logicalRightDelta = isOutOfFlowPositioned() ? logicalRightInRegion - oldLogicalRight : startMarginDelta;
   2451 
   2452     LayoutUnit logicalLeftOffset = 0;
   2453 
   2454     if (!isOutOfFlowPositioned() && avoidsFloats() && cb->containsFloats()) {
   2455         LayoutUnit startPositionDelta = cb->computeStartPositionDeltaForChildAvoidingFloats(this, marginStartInRegion, region, offsetFromLogicalTopOfFirstPage);
   2456         if (cb->style()->isLeftToRightDirection())
   2457             logicalLeftDelta += startPositionDelta;
   2458         else
   2459             logicalRightDelta += startPositionDelta;
   2460     }
   2461 
   2462     if (cb->style()->isLeftToRightDirection())
   2463         logicalLeftOffset += logicalLeftDelta;
   2464     else
   2465         logicalLeftOffset -= (widthDelta + logicalRightDelta);
   2466 
   2467     LayoutUnit logicalRightOffset = logicalWidth() - (logicalLeftOffset + logicalWidthInRegion);
   2468     bool isShifted = (containingBlockInfo && containingBlockInfo->isShifted())
   2469             || (style()->isLeftToRightDirection() && logicalLeftOffset)
   2470             || (!style()->isLeftToRightDirection() && logicalRightOffset);
   2471 
   2472     // FIXME: Although it's unlikely, these boxes can go outside our bounds, and so we will need to incorporate them into overflow.
   2473     if (cacheFlag == CacheRenderBoxRegionInfo)
   2474         return region->setRenderBoxRegionInfo(this, logicalLeftOffset, logicalWidthInRegion, isShifted);
   2475     return new RenderBoxRegionInfo(logicalLeftOffset, logicalWidthInRegion, isShifted);
   2476 }
   2477 
   2478 static bool shouldFlipBeforeAfterMargins(const RenderStyle* containingBlockStyle, const RenderStyle* childStyle)
   2479 {
   2480     ASSERT(containingBlockStyle->isHorizontalWritingMode() != childStyle->isHorizontalWritingMode());
   2481     WritingMode childWritingMode = childStyle->writingMode();
   2482     bool shouldFlip = false;
   2483     switch (containingBlockStyle->writingMode()) {
   2484     case TopToBottomWritingMode:
   2485         shouldFlip = (childWritingMode == RightToLeftWritingMode);
   2486         break;
   2487     case BottomToTopWritingMode:
   2488         shouldFlip = (childWritingMode == RightToLeftWritingMode);
   2489         break;
   2490     case RightToLeftWritingMode:
   2491         shouldFlip = (childWritingMode == BottomToTopWritingMode);
   2492         break;
   2493     case LeftToRightWritingMode:
   2494         shouldFlip = (childWritingMode == BottomToTopWritingMode);
   2495         break;
   2496     }
   2497 
   2498     if (!containingBlockStyle->isLeftToRightDirection())
   2499         shouldFlip = !shouldFlip;
   2500 
   2501     return shouldFlip;
   2502 }
   2503 
   2504 void RenderBox::updateLogicalHeight()
   2505 {
   2506     m_intrinsicContentLogicalHeight = contentLogicalHeight();
   2507 
   2508     LogicalExtentComputedValues computedValues;
   2509     computeLogicalHeight(logicalHeight(), logicalTop(), computedValues);
   2510 
   2511     setLogicalHeight(computedValues.m_extent);
   2512     setLogicalTop(computedValues.m_position);
   2513     setMarginBefore(computedValues.m_margins.m_before);
   2514     setMarginAfter(computedValues.m_margins.m_after);
   2515 }
   2516 
   2517 void RenderBox::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const
   2518 {
   2519     computedValues.m_extent = logicalHeight;
   2520     computedValues.m_position = logicalTop;
   2521 
   2522     // Cell height is managed by the table and inline non-replaced elements do not support a height property.
   2523     if (isTableCell() || (isInline() && !isReplaced()))
   2524         return;
   2525 
   2526     Length h;
   2527     if (isOutOfFlowPositioned())
   2528         computePositionedLogicalHeight(computedValues);
   2529     else {
   2530         RenderBlock* cb = containingBlock();
   2531         bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHorizontalWritingMode();
   2532 
   2533         if (!hasPerpendicularContainingBlock) {
   2534             bool shouldFlipBeforeAfter = cb->style()->writingMode() != style()->writingMode();
   2535             computeBlockDirectionMargins(cb,
   2536                 shouldFlipBeforeAfter ? computedValues.m_margins.m_after : computedValues.m_margins.m_before,
   2537                 shouldFlipBeforeAfter ? computedValues.m_margins.m_before : computedValues.m_margins.m_after);
   2538         }
   2539 
   2540         // For tables, calculate margins only.
   2541         if (isTable()) {
   2542             if (hasPerpendicularContainingBlock) {
   2543                 bool shouldFlipBeforeAfter = shouldFlipBeforeAfterMargins(cb->style(), style());
   2544                 computeInlineDirectionMargins(cb, containingBlockLogicalWidthForContent(), computedValues.m_extent,
   2545                     shouldFlipBeforeAfter ? computedValues.m_margins.m_after : computedValues.m_margins.m_before,
   2546                     shouldFlipBeforeAfter ? computedValues.m_margins.m_before : computedValues.m_margins.m_after);
   2547             }
   2548             return;
   2549         }
   2550 
   2551         // FIXME: Account for block-flow in flexible boxes.
   2552         // https://bugs.webkit.org/show_bug.cgi?id=46418
   2553         bool inHorizontalBox = parent()->isDeprecatedFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL;
   2554         bool stretching = parent()->style()->boxAlign() == BSTRETCH;
   2555         bool treatAsReplaced = shouldComputeSizeAsReplaced() && (!inHorizontalBox || !stretching);
   2556         bool checkMinMaxHeight = false;
   2557 
   2558         // The parent box is flexing us, so it has increased or decreased our height.  We have to
   2559         // grab our cached flexible height.
   2560         // FIXME: Account for block-flow in flexible boxes.
   2561         // https://bugs.webkit.org/show_bug.cgi?id=46418
   2562         if (hasOverrideHeight() && parent()->isFlexibleBoxIncludingDeprecated())
   2563             h = Length(overrideLogicalContentHeight(), Fixed);
   2564         else if (treatAsReplaced)
   2565             h = Length(computeReplacedLogicalHeight(), Fixed);
   2566         else {
   2567             h = style()->logicalHeight();
   2568             checkMinMaxHeight = true;
   2569         }
   2570 
   2571         // Block children of horizontal flexible boxes fill the height of the box.
   2572         // FIXME: Account for block-flow in flexible boxes.
   2573         // https://bugs.webkit.org/show_bug.cgi?id=46418
   2574         if (h.isAuto() && parent()->isDeprecatedFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
   2575                 && parent()->isStretchingChildren()) {
   2576             h = Length(parentBox()->contentLogicalHeight() - marginBefore() - marginAfter() - borderAndPaddingLogicalHeight(), Fixed);
   2577             checkMinMaxHeight = false;
   2578         }
   2579 
   2580         LayoutUnit heightResult;
   2581         if (checkMinMaxHeight) {
   2582             heightResult = computeLogicalHeightUsing(style()->logicalHeight(), computedValues.m_extent - borderAndPaddingLogicalHeight());
   2583             if (heightResult == -1)
   2584                 heightResult = computedValues.m_extent;
   2585             heightResult = constrainLogicalHeightByMinMax(heightResult, computedValues.m_extent - borderAndPaddingLogicalHeight());
   2586         } else {
   2587             // The only times we don't check min/max height are when a fixed length has
   2588             // been given as an override.  Just use that.  The value has already been adjusted
   2589             // for box-sizing.
   2590             ASSERT(h.isFixed());
   2591             heightResult = h.value() + borderAndPaddingLogicalHeight();
   2592         }
   2593 
   2594         computedValues.m_extent = heightResult;
   2595 
   2596         if (hasPerpendicularContainingBlock) {
   2597             bool shouldFlipBeforeAfter = shouldFlipBeforeAfterMargins(cb->style(), style());
   2598             computeInlineDirectionMargins(cb, containingBlockLogicalWidthForContent(), heightResult,
   2599                     shouldFlipBeforeAfter ? computedValues.m_margins.m_after : computedValues.m_margins.m_before,
   2600                     shouldFlipBeforeAfter ? computedValues.m_margins.m_before : computedValues.m_margins.m_after);
   2601         }
   2602     }
   2603 
   2604     // WinIE quirk: The <html> block always fills the entire canvas in quirks mode.  The <body> always fills the
   2605     // <html> block in quirks mode.  Only apply this quirk if the block is normal flow and no height
   2606     // is specified. When we're printing, we also need this quirk if the body or root has a percentage
   2607     // height since we don't set a height in RenderView when we're printing. So without this quirk, the
   2608     // height has nothing to be a percentage of, and it ends up being 0. That is bad.
   2609     bool paginatedContentNeedsBaseHeight = document()->printing() && h.isPercent()
   2610         && (isRoot() || (isBody() && document()->documentElement()->renderer()->style()->logicalHeight().isPercent())) && !isInline();
   2611     if (stretchesToViewport() || paginatedContentNeedsBaseHeight) {
   2612         LayoutUnit margins = collapsedMarginBefore() + collapsedMarginAfter();
   2613         LayoutUnit visibleHeight = viewLogicalHeightForPercentages();
   2614         if (isRoot())
   2615             computedValues.m_extent = max(computedValues.m_extent, visibleHeight - margins);
   2616         else {
   2617             LayoutUnit marginsBordersPadding = margins + parentBox()->marginBefore() + parentBox()->marginAfter() + parentBox()->borderAndPaddingLogicalHeight();
   2618             computedValues.m_extent = max(computedValues.m_extent, visibleHeight - marginsBordersPadding);
   2619         }
   2620     }
   2621 }
   2622 
   2623 LayoutUnit RenderBox::viewLogicalHeightForPercentages() const
   2624 {
   2625     if (document()->printing())
   2626         return static_cast<LayoutUnit>(view()->pageLogicalHeight());
   2627     return view()->viewLogicalHeight();
   2628 }
   2629 
   2630 LayoutUnit RenderBox::computeLogicalHeightUsing(const Length& height, LayoutUnit intrinsicContentHeight) const
   2631 {
   2632     LayoutUnit logicalHeight = computeContentAndScrollbarLogicalHeightUsing(height, intrinsicContentHeight);
   2633     if (logicalHeight != -1)
   2634         logicalHeight = adjustBorderBoxLogicalHeightForBoxSizing(logicalHeight);
   2635     return logicalHeight;
   2636 }
   2637 
   2638 LayoutUnit RenderBox::computeContentLogicalHeight(const Length& height, LayoutUnit intrinsicContentHeight) const
   2639 {
   2640     LayoutUnit heightIncludingScrollbar = computeContentAndScrollbarLogicalHeightUsing(height, intrinsicContentHeight);
   2641     if (heightIncludingScrollbar == -1)
   2642         return -1;
   2643     return std::max<LayoutUnit>(0, adjustContentBoxLogicalHeightForBoxSizing(heightIncludingScrollbar) - scrollbarLogicalHeight());
   2644 }
   2645 
   2646 LayoutUnit RenderBox::computeIntrinsicLogicalContentHeightUsing(Length logicalHeightLength, LayoutUnit intrinsicContentHeight, LayoutUnit borderAndPadding) const
   2647 {
   2648     // FIXME(cbiesinger): The css-sizing spec is considering changing what min-content/max-content should resolve to.
   2649     // If that happens, this code will have to change.
   2650     if (logicalHeightLength.isMinContent() || logicalHeightLength.isMaxContent() || logicalHeightLength.isFitContent()) {
   2651         if (isReplaced())
   2652             return intrinsicSize().height();
   2653         if (m_intrinsicContentLogicalHeight != -1)
   2654             return m_intrinsicContentLogicalHeight;
   2655         return intrinsicContentHeight;
   2656     }
   2657     if (logicalHeightLength.isFillAvailable())
   2658         return containingBlock()->availableLogicalHeight(ExcludeMarginBorderPadding) - borderAndPadding;
   2659     ASSERT_NOT_REACHED();
   2660     return 0;
   2661 }
   2662 
   2663 LayoutUnit RenderBox::computeContentAndScrollbarLogicalHeightUsing(const Length& height, LayoutUnit intrinsicContentHeight) const
   2664 {
   2665     // FIXME(cbiesinger): The css-sizing spec is considering changing what min-content/max-content should resolve to.
   2666     // If that happens, this code will have to change.
   2667     if (height.isIntrinsic()) {
   2668         if (intrinsicContentHeight == -1)
   2669             return -1; // Intrinsic height isn't available.
   2670         return computeIntrinsicLogicalContentHeightUsing(height, intrinsicContentHeight, borderAndPaddingLogicalHeight());
   2671     }
   2672     if (height.isFixed())
   2673         return height.value();
   2674     if (height.isPercent())
   2675         return computePercentageLogicalHeight(height);
   2676     if (height.isViewportPercentage())
   2677         return valueForLength(height, 0, view());
   2678     return -1;
   2679 }
   2680 
   2681 bool RenderBox::skipContainingBlockForPercentHeightCalculation(const RenderBox* containingBlock) const
   2682 {
   2683     // For quirks mode and anonymous blocks, we skip auto-height containingBlocks when computing percentages.
   2684     // For standards mode, we treat the percentage as auto if it has an auto-height containing block.
   2685     if (!document()->inQuirksMode() && !containingBlock->isAnonymousBlock())
   2686         return false;
   2687     return !containingBlock->isTableCell() && !containingBlock->isOutOfFlowPositioned() && containingBlock->style()->logicalHeight().isAuto() && isHorizontalWritingMode() == containingBlock->isHorizontalWritingMode();
   2688 }
   2689 
   2690 LayoutUnit RenderBox::computePercentageLogicalHeight(const Length& height) const
   2691 {
   2692     LayoutUnit availableHeight = -1;
   2693 
   2694     bool skippedAutoHeightContainingBlock = false;
   2695     RenderBlock* cb = containingBlock();
   2696     const RenderBox* containingBlockChild = this;
   2697     LayoutUnit rootMarginBorderPaddingHeight = 0;
   2698     while (!cb->isRenderView() && skipContainingBlockForPercentHeightCalculation(cb)) {
   2699         if (cb->isBody() || cb->isRoot())
   2700             rootMarginBorderPaddingHeight += cb->marginBefore() + cb->marginAfter() + cb->borderAndPaddingLogicalHeight();
   2701         skippedAutoHeightContainingBlock = true;
   2702         containingBlockChild = cb;
   2703         cb = cb->containingBlock();
   2704         cb->addPercentHeightDescendant(const_cast<RenderBox*>(this));
   2705     }
   2706 
   2707     RenderStyle* cbstyle = cb->style();
   2708 
   2709     // A positioned element that specified both top/bottom or that specifies height should be treated as though it has a height
   2710     // explicitly specified that can be used for any percentage computations.
   2711     bool isOutOfFlowPositionedWithSpecifiedHeight = cb->isOutOfFlowPositioned() && (!cbstyle->logicalHeight().isAuto() || (!cbstyle->logicalTop().isAuto() && !cbstyle->logicalBottom().isAuto()));
   2712 
   2713     bool includeBorderPadding = isTable();
   2714 
   2715     if (isHorizontalWritingMode() != cb->isHorizontalWritingMode())
   2716         availableHeight = containingBlockChild->containingBlockLogicalWidthForContent();
   2717     else if (hasOverrideContainingBlockLogicalHeight())
   2718         availableHeight = overrideContainingBlockContentLogicalHeight();
   2719     else if (cb->isTableCell()) {
   2720         if (!skippedAutoHeightContainingBlock) {
   2721             // Table cells violate what the CSS spec says to do with heights. Basically we
   2722             // don't care if the cell specified a height or not. We just always make ourselves
   2723             // be a percentage of the cell's current content height.
   2724             if (!cb->hasOverrideHeight()) {
   2725                 // Normally we would let the cell size intrinsically, but scrolling overflow has to be
   2726                 // treated differently, since WinIE lets scrolled overflow regions shrink as needed.
   2727                 // While we can't get all cases right, we can at least detect when the cell has a specified
   2728                 // height or when the table has a specified height. In these cases we want to initially have
   2729                 // no size and allow the flexing of the table or the cell to its specified height to cause us
   2730                 // to grow to fill the space. This could end up being wrong in some cases, but it is
   2731                 // preferable to the alternative (sizing intrinsically and making the row end up too big).
   2732                 RenderTableCell* cell = toRenderTableCell(cb);
   2733                 if (scrollsOverflowY() && (!cell->style()->logicalHeight().isAuto() || !cell->table()->style()->logicalHeight().isAuto()))
   2734                     return 0;
   2735                 return -1;
   2736             }
   2737             availableHeight = cb->overrideLogicalContentHeight();
   2738             includeBorderPadding = true;
   2739         }
   2740     } else if (cbstyle->logicalHeight().isFixed()) {
   2741         LayoutUnit contentBoxHeight = cb->adjustContentBoxLogicalHeightForBoxSizing(cbstyle->logicalHeight().value());
   2742         availableHeight = max<LayoutUnit>(0, cb->constrainContentBoxLogicalHeightByMinMax(contentBoxHeight - cb->scrollbarLogicalHeight(), -1));
   2743     } else if (cbstyle->logicalHeight().isPercent() && !isOutOfFlowPositionedWithSpecifiedHeight) {
   2744         // We need to recur and compute the percentage height for our containing block.
   2745         LayoutUnit heightWithScrollbar = cb->computePercentageLogicalHeight(cbstyle->logicalHeight());
   2746         if (heightWithScrollbar != -1) {
   2747             LayoutUnit contentBoxHeightWithScrollbar = cb->adjustContentBoxLogicalHeightForBoxSizing(heightWithScrollbar);
   2748             // We need to adjust for min/max height because this method does not
   2749             // handle the min/max of the current block, its caller does. So the
   2750             // return value from the recursive call will not have been adjusted
   2751             // yet.
   2752             LayoutUnit contentBoxHeight = cb->constrainContentBoxLogicalHeightByMinMax(contentBoxHeightWithScrollbar - cb->scrollbarLogicalHeight(), -1);
   2753             availableHeight = max<LayoutUnit>(0, contentBoxHeight);
   2754         }
   2755     } else if (isOutOfFlowPositionedWithSpecifiedHeight) {
   2756         // Don't allow this to affect the block' height() member variable, since this
   2757         // can get called while the block is still laying out its kids.
   2758         LogicalExtentComputedValues computedValues;
   2759         cb->computeLogicalHeight(cb->logicalHeight(), 0, computedValues);
   2760         availableHeight = computedValues.m_extent - cb->borderAndPaddingLogicalHeight() - cb->scrollbarLogicalHeight();
   2761     } else if (cb->isRenderView())
   2762         availableHeight = viewLogicalHeightForPercentages();
   2763 
   2764     if (availableHeight == -1)
   2765         return availableHeight;
   2766 
   2767     availableHeight -= rootMarginBorderPaddingHeight;
   2768 
   2769     LayoutUnit result = valueForLength(height, availableHeight);
   2770     if (includeBorderPadding) {
   2771         // FIXME: Table cells should default to box-sizing: border-box so we can avoid this hack.
   2772         // It is necessary to use the border-box to match WinIE's broken
   2773         // box model. This is essential for sizing inside
   2774         // table cells using percentage heights.
   2775         result -= borderAndPaddingLogicalHeight();
   2776         return max<LayoutUnit>(0, result);
   2777     }
   2778     return result;
   2779 }
   2780 
   2781 LayoutUnit RenderBox::computeReplacedLogicalWidth(ShouldComputePreferred shouldComputePreferred) const
   2782 {
   2783     return computeReplacedLogicalWidthRespectingMinMaxWidth(computeReplacedLogicalWidthUsing(style()->logicalWidth()), shouldComputePreferred);
   2784 }
   2785 
   2786 LayoutUnit RenderBox::computeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUnit logicalWidth, ShouldComputePreferred shouldComputePreferred) const
   2787 {
   2788     LayoutUnit minLogicalWidth = (shouldComputePreferred == ComputePreferred && style()->logicalMinWidth().isPercent()) || style()->logicalMinWidth().isUndefined() ? logicalWidth : computeReplacedLogicalWidthUsing(style()->logicalMinWidth());
   2789     LayoutUnit maxLogicalWidth = (shouldComputePreferred == ComputePreferred && style()->logicalMaxWidth().isPercent()) || style()->logicalMaxWidth().isUndefined() ? logicalWidth : computeReplacedLogicalWidthUsing(style()->logicalMaxWidth());
   2790     return max(minLogicalWidth, min(logicalWidth, maxLogicalWidth));
   2791 }
   2792 
   2793 LayoutUnit RenderBox::computeReplacedLogicalWidthUsing(Length logicalWidth) const
   2794 {
   2795     switch (logicalWidth.type()) {
   2796         case Fixed:
   2797             return adjustContentBoxLogicalWidthForBoxSizing(logicalWidth.value());
   2798         case MinContent:
   2799         case MaxContent: {
   2800             // MinContent/MaxContent don't need the availableLogicalWidth argument.
   2801             LayoutUnit availableLogicalWidth = 0;
   2802             return computeIntrinsicLogicalWidthUsing(logicalWidth, availableLogicalWidth, borderAndPaddingLogicalWidth()) - borderAndPaddingLogicalWidth();
   2803         }
   2804         case ViewportPercentageWidth:
   2805         case ViewportPercentageHeight:
   2806         case ViewportPercentageMin:
   2807         case ViewportPercentageMax:
   2808             return adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, 0, view()));
   2809         case FitContent:
   2810         case FillAvailable:
   2811         case Percent:
   2812         case Calculated: {
   2813             // FIXME: containingBlockLogicalWidthForContent() is wrong if the replaced element's block-flow is perpendicular to the
   2814             // containing block's block-flow.
   2815             // https://bugs.webkit.org/show_bug.cgi?id=46496
   2816             const LayoutUnit cw = isOutOfFlowPositioned() ? containingBlockLogicalWidthForPositioned(toRenderBoxModelObject(container())) : containingBlockLogicalWidthForContent();
   2817             Length containerLogicalWidth = containingBlock()->style()->logicalWidth();
   2818             // FIXME: Handle cases when containing block width is calculated or viewport percent.
   2819             // https://bugs.webkit.org/show_bug.cgi?id=91071
   2820             if (logicalWidth.isIntrinsic())
   2821                 return computeIntrinsicLogicalWidthUsing(logicalWidth, cw, borderAndPaddingLogicalWidth()) - borderAndPaddingLogicalWidth();
   2822             if (cw > 0 || (!cw && (containerLogicalWidth.isFixed() || containerLogicalWidth.isPercent())))
   2823                 return adjustContentBoxLogicalWidthForBoxSizing(minimumValueForLength(logicalWidth, cw));
   2824         }
   2825         // fall through
   2826         case Intrinsic:
   2827         case MinIntrinsic:
   2828         case Auto:
   2829         case Relative:
   2830         case ExtendToZoom:
   2831         case Undefined:
   2832             return intrinsicLogicalWidth();
   2833     }
   2834 
   2835     ASSERT_NOT_REACHED();
   2836     return 0;
   2837 }
   2838 
   2839 LayoutUnit RenderBox::computeReplacedLogicalHeight() const
   2840 {
   2841     return computeReplacedLogicalHeightRespectingMinMaxHeight(computeReplacedLogicalHeightUsing(style()->logicalHeight()));
   2842 }
   2843 
   2844 LayoutUnit RenderBox::computeReplacedLogicalHeightRespectingMinMaxHeight(LayoutUnit logicalHeight) const
   2845 {
   2846     LayoutUnit minLogicalHeight = computeReplacedLogicalHeightUsing(style()->logicalMinHeight());
   2847     LayoutUnit maxLogicalHeight = style()->logicalMaxHeight().isUndefined() ? logicalHeight : computeReplacedLogicalHeightUsing(style()->logicalMaxHeight());
   2848     return max(minLogicalHeight, min(logicalHeight, maxLogicalHeight));
   2849 }
   2850 
   2851 LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(Length logicalHeight) const
   2852 {
   2853     switch (logicalHeight.type()) {
   2854         case Fixed:
   2855             return adjustContentBoxLogicalHeightForBoxSizing(logicalHeight.value());
   2856         case Percent:
   2857         case Calculated:
   2858         {
   2859             RenderObject* cb = isOutOfFlowPositioned() ? container() : containingBlock();
   2860             while (cb->isAnonymous()) {
   2861                 cb = cb->containingBlock();
   2862                 toRenderBlock(cb)->addPercentHeightDescendant(const_cast<RenderBox*>(this));
   2863             }
   2864 
   2865             // FIXME: This calculation is not patched for block-flow yet.
   2866             // https://bugs.webkit.org/show_bug.cgi?id=46500
   2867             if (cb->isOutOfFlowPositioned() && cb->style()->height().isAuto() && !(cb->style()->top().isAuto() || cb->style()->bottom().isAuto())) {
   2868                 ASSERT_WITH_SECURITY_IMPLICATION(cb->isRenderBlock());
   2869                 RenderBlock* block = toRenderBlock(cb);
   2870                 LogicalExtentComputedValues computedValues;
   2871                 block->computeLogicalHeight(block->logicalHeight(), 0, computedValues);
   2872                 LayoutUnit newContentHeight = computedValues.m_extent - block->borderAndPaddingLogicalHeight() - block->scrollbarLogicalHeight();
   2873                 LayoutUnit newHeight = block->adjustContentBoxLogicalHeightForBoxSizing(newContentHeight);
   2874                 return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeight, newHeight));
   2875             }
   2876 
   2877             // FIXME: availableLogicalHeight() is wrong if the replaced element's block-flow is perpendicular to the
   2878             // containing block's block-flow.
   2879             // https://bugs.webkit.org/show_bug.cgi?id=46496
   2880             LayoutUnit availableHeight;
   2881             if (isOutOfFlowPositioned())
   2882                 availableHeight = containingBlockLogicalHeightForPositioned(toRenderBoxModelObject(cb));
   2883             else {
   2884                 availableHeight = containingBlockLogicalHeightForContent(IncludeMarginBorderPadding);
   2885                 // It is necessary to use the border-box to match WinIE's broken
   2886                 // box model.  This is essential for sizing inside
   2887                 // table cells using percentage heights.
   2888                 // FIXME: This needs to be made block-flow-aware.  If the cell and image are perpendicular block-flows, this isn't right.
   2889                 // https://bugs.webkit.org/show_bug.cgi?id=46997
   2890                 while (cb && !cb->isRenderView() && (cb->style()->logicalHeight().isAuto() || cb->style()->logicalHeight().isPercent())) {
   2891                     if (cb->isTableCell()) {
   2892                         // Don't let table cells squeeze percent-height replaced elements
   2893                         // <http://bugs.webkit.org/show_bug.cgi?id=15359>
   2894                         availableHeight = max(availableHeight, intrinsicLogicalHeight());
   2895                         return valueForLength(logicalHeight, availableHeight - borderAndPaddingLogicalHeight());
   2896                     }
   2897                     toRenderBlock(cb)->addPercentHeightDescendant(const_cast<RenderBox*>(this));
   2898                     cb = cb->containingBlock();
   2899                 }
   2900             }
   2901             return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeight, availableHeight));
   2902         }
   2903         case ViewportPercentageWidth:
   2904         case ViewportPercentageHeight:
   2905         case ViewportPercentageMin:
   2906         case ViewportPercentageMax:
   2907             return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeight, 0, view()));
   2908         case MinContent:
   2909         case MaxContent:
   2910         case FitContent:
   2911         case FillAvailable:
   2912             return adjustContentBoxLogicalHeightForBoxSizing(computeIntrinsicLogicalContentHeightUsing(logicalHeight, intrinsicLogicalHeight(), borderAndPaddingHeight()));
   2913         default:
   2914             return intrinsicLogicalHeight();
   2915     }
   2916 }
   2917 
   2918 LayoutUnit RenderBox::availableLogicalHeight(AvailableLogicalHeightType heightType) const
   2919 {
   2920     return constrainLogicalHeightByMinMax(availableLogicalHeightUsing(style()->logicalHeight(), heightType), -1);
   2921 }
   2922 
   2923 LayoutUnit RenderBox::availableLogicalHeightUsing(const Length& h, AvailableLogicalHeightType heightType) const
   2924 {
   2925     if (isRenderView())
   2926         return isHorizontalWritingMode() ? toRenderView(this)->frameView()->visibleHeight() : toRenderView(this)->frameView()->visibleWidth();
   2927 
   2928     // We need to stop here, since we don't want to increase the height of the table
   2929     // artificially.  We're going to rely on this cell getting expanded to some new
   2930     // height, and then when we lay out again we'll use the calculation below.
   2931     if (isTableCell() && (h.isAuto() || h.isPercent())) {
   2932         if (hasOverrideHeight())
   2933             return overrideLogicalContentHeight();
   2934         return logicalHeight() - borderAndPaddingLogicalHeight();
   2935     }
   2936 
   2937     if (h.isPercent() && isOutOfFlowPositioned()) {
   2938         // FIXME: This is wrong if the containingBlock has a perpendicular writing mode.
   2939         LayoutUnit availableHeight = containingBlockLogicalHeightForPositioned(containingBlock());
   2940         return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(h, availableHeight));
   2941     }
   2942 
   2943     LayoutUnit heightIncludingScrollbar = computeContentAndScrollbarLogicalHeightUsing(h, -1);
   2944     if (heightIncludingScrollbar != -1)
   2945         return std::max<LayoutUnit>(0, adjustContentBoxLogicalHeightForBoxSizing(heightIncludingScrollbar) - scrollbarLogicalHeight());
   2946 
   2947     // FIXME: Check logicalTop/logicalBottom here to correctly handle vertical writing-mode.
   2948     // https://bugs.webkit.org/show_bug.cgi?id=46500
   2949     if (isRenderBlock() && isOutOfFlowPositioned() && style()->height().isAuto() && !(style()->top().isAuto() || style()->bottom().isAuto())) {
   2950         RenderBlock* block = const_cast<RenderBlock*>(toRenderBlock(this));
   2951         LogicalExtentComputedValues computedValues;
   2952         block->computeLogicalHeight(block->logicalHeight(), 0, computedValues);
   2953         LayoutUnit newContentHeight = computedValues.m_extent - block->borderAndPaddingLogicalHeight() - block->scrollbarLogicalHeight();
   2954         return adjustContentBoxLogicalHeightForBoxSizing(newContentHeight);
   2955     }
   2956 
   2957     // FIXME: This is wrong if the containingBlock has a perpendicular writing mode.
   2958     LayoutUnit availableHeight = containingBlockLogicalHeightForContent(heightType);
   2959     if (heightType == ExcludeMarginBorderPadding) {
   2960         // FIXME: Margin collapsing hasn't happened yet, so this incorrectly removes collapsed margins.
   2961         availableHeight -= marginBefore() + marginAfter() + borderAndPaddingLogicalHeight();
   2962     }
   2963     return availableHeight;
   2964 }
   2965 
   2966 void RenderBox::computeBlockDirectionMargins(const RenderBlock* containingBlock, LayoutUnit& marginBefore, LayoutUnit& marginAfter) const
   2967 {
   2968     if (isTableCell()) {
   2969         // FIXME: Not right if we allow cells to have different directionality than the table.  If we do allow this, though,
   2970         // we may just do it with an extra anonymous block inside the cell.
   2971         marginBefore = 0;
   2972         marginAfter = 0;
   2973         return;
   2974     }
   2975 
   2976     // Margins are calculated with respect to the logical width of
   2977     // the containing block (8.3)
   2978     LayoutUnit cw = containingBlockLogicalWidthForContent();
   2979     RenderView* renderView = view();
   2980     RenderStyle* containingBlockStyle = containingBlock->style();
   2981     marginBefore = minimumValueForLength(style()->marginBeforeUsing(containingBlockStyle), cw, renderView);
   2982     marginAfter = minimumValueForLength(style()->marginAfterUsing(containingBlockStyle), cw, renderView);
   2983 }
   2984 
   2985 void RenderBox::computeAndSetBlockDirectionMargins(const RenderBlock* containingBlock)
   2986 {
   2987     LayoutUnit marginBefore;
   2988     LayoutUnit marginAfter;
   2989     computeBlockDirectionMargins(containingBlock, marginBefore, marginAfter);
   2990     containingBlock->setMarginBeforeForChild(this, marginBefore);
   2991     containingBlock->setMarginAfterForChild(this, marginAfter);
   2992 }
   2993 
   2994 LayoutUnit RenderBox::containingBlockLogicalWidthForPositioned(const RenderBoxModelObject* containingBlock, RenderRegion* region,
   2995     LayoutUnit offsetFromLogicalTopOfFirstPage, bool checkForPerpendicularWritingMode) const
   2996 {
   2997     if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWritingMode() != isHorizontalWritingMode())
   2998         return containingBlockLogicalHeightForPositioned(containingBlock, false);
   2999 
   3000     // Use viewport as container for top-level fixed-position elements.
   3001     if (style()->position() == FixedPosition && containingBlock->isRenderView()) {
   3002         const RenderView* view = static_cast<const RenderView*>(containingBlock);
   3003         if (FrameView* frameView = view->frameView()) {
   3004             LayoutRect viewportRect = frameView->viewportConstrainedVisibleContentRect();
   3005             return containingBlock->isHorizontalWritingMode() ? viewportRect.width() : viewportRect.height();
   3006         }
   3007     }
   3008 
   3009     if (containingBlock->isBox()) {
   3010         RenderFlowThread* flowThread = flowThreadContainingBlock();
   3011         if (!flowThread)
   3012             return toRenderBox(containingBlock)->clientLogicalWidth();
   3013 
   3014         const RenderBlock* cb = toRenderBlock(containingBlock);
   3015         RenderBoxRegionInfo* boxInfo = 0;
   3016         if (!region) {
   3017             if (containingBlock->isRenderFlowThread() && !checkForPerpendicularWritingMode)
   3018                 return toRenderFlowThread(containingBlock)->contentLogicalWidthOfFirstRegion();
   3019             if (isWritingModeRoot()) {
   3020                 LayoutUnit cbPageOffset = offsetFromLogicalTopOfFirstPage - logicalTop();
   3021                 RenderRegion* cbRegion = cb->regionAtBlockOffset(cbPageOffset);
   3022                 if (cbRegion) {
   3023                     cbRegion = cb->clampToStartAndEndRegions(cbRegion);
   3024                     boxInfo = cb->renderBoxRegionInfo(cbRegion, cbPageOffset);
   3025                 }
   3026             }
   3027         } else if (region && flowThread->isHorizontalWritingMode() == containingBlock->isHorizontalWritingMode()) {
   3028             RenderRegion* containingBlockRegion = cb->clampToStartAndEndRegions(region);
   3029             boxInfo = cb->renderBoxRegionInfo(containingBlockRegion, offsetFromLogicalTopOfFirstPage - logicalTop());
   3030         }
   3031         return (boxInfo) ? max<LayoutUnit>(0, cb->clientLogicalWidth() - (cb->logicalWidth() - boxInfo->logicalWidth())) : cb->clientLogicalWidth();
   3032     }
   3033 
   3034     ASSERT(containingBlock->isRenderInline() && containingBlock->isInFlowPositioned());
   3035 
   3036     const RenderInline* flow = toRenderInline(containingBlock);
   3037     InlineFlowBox* first = flow->firstLineBox();
   3038     InlineFlowBox* last = flow->lastLineBox();
   3039 
   3040     // If the containing block is empty, return a width of 0.
   3041     if (!first || !last)
   3042         return 0;
   3043 
   3044     LayoutUnit fromLeft;
   3045     LayoutUnit fromRight;
   3046     if (containingBlock->style()->isLeftToRightDirection()) {
   3047         fromLeft = first->logicalLeft() + first->borderLogicalLeft();
   3048         fromRight = last->logicalLeft() + last->logicalWidth() - last->borderLogicalRight();
   3049     } else {
   3050         fromRight = first->logicalLeft() + first->logicalWidth() - first->borderLogicalRight();
   3051         fromLeft = last->logicalLeft() + last->borderLogicalLeft();
   3052     }
   3053 
   3054     return max<LayoutUnit>(0, fromRight - fromLeft);
   3055 }
   3056 
   3057 LayoutUnit RenderBox::containingBlockLogicalHeightForPositioned(const RenderBoxModelObject* containingBlock, bool checkForPerpendicularWritingMode) const
   3058 {
   3059     if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWritingMode() != isHorizontalWritingMode())
   3060         return containingBlockLogicalWidthForPositioned(containingBlock, 0, 0, false);
   3061 
   3062     // Use viewport as container for top-level fixed-position elements.
   3063     if (style()->position() == FixedPosition && containingBlock->isRenderView()) {
   3064         const RenderView* view = static_cast<const RenderView*>(containingBlock);
   3065         if (FrameView* frameView = view->frameView()) {
   3066             LayoutRect viewportRect = frameView->viewportConstrainedVisibleContentRect();
   3067             return containingBlock->isHorizontalWritingMode() ? viewportRect.height() : viewportRect.width();
   3068         }
   3069     }
   3070 
   3071     if (containingBlock->isBox()) {
   3072         const RenderBlock* cb = toRenderBlock(containingBlock);
   3073         LayoutUnit result = cb->clientLogicalHeight();
   3074         RenderFlowThread* flowThread = flowThreadContainingBlock();
   3075         if (flowThread && containingBlock->isRenderFlowThread() && flowThread->isHorizontalWritingMode() == containingBlock->isHorizontalWritingMode())
   3076             return toRenderFlowThread(containingBlock)->contentLogicalHeightOfFirstRegion();
   3077         return result;
   3078     }
   3079 
   3080     ASSERT(containingBlock->isRenderInline() && containingBlock->isInFlowPositioned());
   3081 
   3082     const RenderInline* flow = toRenderInline(containingBlock);
   3083     InlineFlowBox* first = flow->firstLineBox();
   3084     InlineFlowBox* last = flow->lastLineBox();
   3085 
   3086     // If the containing block is empty, return a height of 0.
   3087     if (!first || !last)
   3088         return 0;
   3089 
   3090     LayoutUnit heightResult;
   3091     LayoutRect boundingBox = flow->linesBoundingBox();
   3092     if (containingBlock->isHorizontalWritingMode())
   3093         heightResult = boundingBox.height();
   3094     else
   3095         heightResult = boundingBox.width();
   3096     heightResult -= (containingBlock->borderBefore() + containingBlock->borderAfter());
   3097     return heightResult;
   3098 }
   3099 
   3100 static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRight, const RenderBox* child, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalWidth, RenderRegion* region)
   3101 {
   3102     if (!logicalLeft.isAuto() || !logicalRight.isAuto())
   3103         return;
   3104 
   3105     // FIXME: The static distance computation has not been patched for mixed writing modes yet.
   3106     if (child->parent()->style()->direction() == LTR) {
   3107         LayoutUnit staticPosition = child->layer()->staticInlinePosition() - containerBlock->borderLogicalLeft();
   3108         for (RenderObject* curr = child->parent(); curr && curr != containerBlock; curr = curr->container()) {
   3109             if (curr->isBox()) {
   3110                 staticPosition += toRenderBox(curr)->logicalLeft();
   3111                 if (region && curr->isRenderBlock()) {
   3112                     const RenderBlock* cb = toRenderBlock(curr);
   3113                     region = cb->clampToStartAndEndRegions(region);
   3114                     RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(region, region->logicalTopForFlowThreadContent());
   3115                     if (boxInfo)
   3116                         staticPosition += boxInfo->logicalLeft();
   3117                 }
   3118             }
   3119         }
   3120         logicalLeft.setValue(Fixed, staticPosition);
   3121     } else {
   3122         RenderBox* enclosingBox = child->parent()->enclosingBox();
   3123         LayoutUnit staticPosition = child->layer()->staticInlinePosition() + containerLogicalWidth + containerBlock->borderLogicalLeft();
   3124         for (RenderObject* curr = enclosingBox; curr; curr = curr->container()) {
   3125             if (curr->isBox()) {
   3126                 if (curr != containerBlock)
   3127                     staticPosition -= toRenderBox(curr)->logicalLeft();
   3128                 if (curr == enclosingBox)
   3129                     staticPosition -= enclosingBox->logicalWidth();
   3130                 if (region && curr->isRenderBlock()) {
   3131                      const RenderBlock* cb = toRenderBlock(curr);
   3132                      region = cb->clampToStartAndEndRegions(region);
   3133                      RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(region, region->logicalTopForFlowThreadContent());
   3134                      if (boxInfo) {
   3135                         if (curr != containerBlock)
   3136                             staticPosition -= cb->logicalWidth() - (boxInfo->logicalLeft() + boxInfo->logicalWidth());
   3137                         if (curr == enclosingBox)
   3138                             staticPosition += enclosingBox->logicalWidth() - boxInfo->logicalWidth();
   3139                     }
   3140                 }
   3141             }
   3142             if (curr == containerBlock)
   3143                 break;
   3144         }
   3145         logicalRight.setValue(Fixed, staticPosition);
   3146     }
   3147 }
   3148 
   3149 void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& computedValues, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
   3150 {
   3151     if (isReplaced()) {
   3152         // FIXME: Positioned replaced elements inside a flow thread are not working properly
   3153         // with variable width regions (see https://bugs.webkit.org/show_bug.cgi?id=69896 ).
   3154         computePositionedLogicalWidthReplaced(computedValues);
   3155         return;
   3156     }
   3157 
   3158     // QUESTIONS
   3159     // FIXME 1: Should we still deal with these the cases of 'left' or 'right' having
   3160     // the type 'static' in determining whether to calculate the static distance?
   3161     // NOTE: 'static' is not a legal value for 'left' or 'right' as of CSS 2.1.
   3162 
   3163     // FIXME 2: Can perhaps optimize out cases when max-width/min-width are greater
   3164     // than or less than the computed width().  Be careful of box-sizing and
   3165     // percentage issues.
   3166 
   3167     // The following is based off of the W3C Working Draft from April 11, 2006 of
   3168     // CSS 2.1: Section 10.3.7 "Absolutely positioned, non-replaced elements"
   3169     // <http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width>
   3170     // (block-style-comments in this function and in computePositionedLogicalWidthUsing()
   3171     // correspond to text from the spec)
   3172 
   3173 
   3174     // We don't use containingBlock(), since we may be positioned by an enclosing
   3175     // relative positioned inline.
   3176     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
   3177 
   3178     const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, region, offsetFromLogicalTopOfFirstPage);
   3179 
   3180     // Use the container block's direction except when calculating the static distance
   3181     // This conforms with the reference results for abspos-replaced-width-margin-000.htm
   3182     // of the CSS 2.1 test suite
   3183     TextDirection containerDirection = containerBlock->style()->direction();
   3184 
   3185     bool isHorizontal = isHorizontalWritingMode();
   3186     const LayoutUnit bordersPlusPadding = borderAndPaddingLogicalWidth();
   3187     const Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->marginTop();
   3188     const Length marginLogicalRight = isHorizontal ? style()->marginRight() : style()->marginBottom();
   3189 
   3190     Length logicalLeftLength = style()->logicalLeft();
   3191     Length logicalRightLength = style()->logicalRight();
   3192 
   3193     /*---------------------------------------------------------------------------*\
   3194      * For the purposes of this section and the next, the term "static position"
   3195      * (of an element) refers, roughly, to the position an element would have had
   3196      * in the normal flow. More precisely:
   3197      *
   3198      * * The static position for 'left' is the distance from the left edge of the
   3199      *   containing block to the left margin edge of a hypothetical box that would
   3200      *   have been the first box of the element if its 'position' property had
   3201      *   been 'static' and 'float' had been 'none'. The value is negative if the
   3202      *   hypothetical box is to the left of the containing block.
   3203      * * The static position for 'right' is the distance from the right edge of the
   3204      *   containing block to the right margin edge of the same hypothetical box as
   3205      *   above. The value is positive if the hypothetical box is to the left of the
   3206      *   containing block's edge.
   3207      *
   3208      * But rather than actually calculating the dimensions of that hypothetical box,
   3209      * user agents are free to make a guess at its probable position.
   3210      *
   3211      * For the purposes of calculating the static position, the containing block of
   3212      * fixed positioned elements is the initial containing block instead of the
   3213      * viewport, and all scrollable boxes should be assumed to be scrolled to their
   3214      * origin.
   3215     \*---------------------------------------------------------------------------*/
   3216 
   3217     // see FIXME 1
   3218     // Calculate the static distance if needed.
   3219     computeInlineStaticDistance(logicalLeftLength, logicalRightLength, this, containerBlock, containerLogicalWidth, region);
   3220 
   3221     // Calculate constraint equation values for 'width' case.
   3222     computePositionedLogicalWidthUsing(style()->logicalWidth(), containerBlock, containerDirection,
   3223                                        containerLogicalWidth, bordersPlusPadding,
   3224                                        logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight,
   3225                                        computedValues);
   3226 
   3227     // Calculate constraint equation values for 'max-width' case.
   3228     if (!style()->logicalMaxWidth().isUndefined()) {
   3229         LogicalExtentComputedValues maxValues;
   3230 
   3231         computePositionedLogicalWidthUsing(style()->logicalMaxWidth(), containerBlock, containerDirection,
   3232                                            containerLogicalWidth, bordersPlusPadding,
   3233                                            logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight,
   3234                                            maxValues);
   3235 
   3236         if (computedValues.m_extent > maxValues.m_extent) {
   3237             computedValues.m_extent = maxValues.m_extent;
   3238             computedValues.m_position = maxValues.m_position;
   3239             computedValues.m_margins.m_start = maxValues.m_margins.m_start;
   3240             computedValues.m_margins.m_end = maxValues.m_margins.m_end;
   3241         }
   3242     }
   3243 
   3244     // Calculate constraint equation values for 'min-width' case.
   3245     if (!style()->logicalMinWidth().isZero() || style()->logicalMinWidth().isIntrinsic()) {
   3246         LogicalExtentComputedValues minValues;
   3247 
   3248         computePositionedLogicalWidthUsing(style()->logicalMinWidth(), containerBlock, containerDirection,
   3249                                            containerLogicalWidth, bordersPlusPadding,
   3250                                            logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight,
   3251                                            minValues);
   3252 
   3253         if (computedValues.m_extent < minValues.m_extent) {
   3254             computedValues.m_extent = minValues.m_extent;
   3255             computedValues.m_position = minValues.m_position;
   3256             computedValues.m_margins.m_start = minValues.m_margins.m_start;
   3257             computedValues.m_margins.m_end = minValues.m_margins.m_end;
   3258         }
   3259     }
   3260 
   3261     computedValues.m_extent += bordersPlusPadding;
   3262 
   3263     // Adjust logicalLeft if we need to for the flipped version of our writing mode in regions.
   3264     // FIXME: Add support for other types of objects as containerBlock, not only RenderBlock.
   3265     RenderFlowThread* flowThread = flowThreadContainingBlock();
   3266     if (flowThread && !region && isWritingModeRoot() && isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode() && containerBlock->isRenderBlock()) {
   3267         ASSERT(containerBlock->canHaveBoxInfoInRegion());
   3268         LayoutUnit logicalLeftPos = computedValues.m_position;
   3269         const RenderBlock* cb = toRenderBlock(containerBlock);
   3270         LayoutUnit cbPageOffset = offsetFromLogicalTopOfFirstPage - logicalTop();
   3271         RenderRegion* cbRegion = cb->regionAtBlockOffset(cbPageOffset);
   3272         if (cbRegion) {
   3273             cbRegion = cb->clampToStartAndEndRegions(cbRegion);
   3274             RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(cbRegion, cbPageOffset);
   3275             if (boxInfo) {
   3276                 logicalLeftPos += boxInfo->logicalLeft();
   3277                 computedValues.m_position = logicalLeftPos;
   3278             }
   3279         }
   3280     }
   3281 }
   3282 
   3283 static void computeLogicalLeftPositionedOffset(LayoutUnit& logicalLeftPos, const RenderBox* child, LayoutUnit logicalWidthValue, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalWidth)
   3284 {
   3285     // Deal with differing writing modes here.  Our offset needs to be in the containing block's coordinate space. If the containing block is flipped
   3286     // 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.
   3287     if (containerBlock->isHorizontalWritingMode() != child->isHorizontalWritingMode() && containerBlock->style()->isFlippedBlocksWritingMode()) {
   3288         logicalLeftPos = containerLogicalWidth - logicalWidthValue - logicalLeftPos;
   3289         logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->borderRight() : containerBlock->borderBottom());
   3290     } else
   3291         logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->borderLeft() : containerBlock->borderTop());
   3292 }
   3293 
   3294 void RenderBox::computePositionedLogicalWidthUsing(Length logicalWidth, const RenderBoxModelObject* containerBlock, TextDirection containerDirection,
   3295                                                    LayoutUnit containerLogicalWidth, LayoutUnit bordersPlusPadding,
   3296                                                    Length logicalLeft, Length logicalRight, Length marginLogicalLeft, Length marginLogicalRight,
   3297                                                    LogicalExtentComputedValues& computedValues) const
   3298 {
   3299     if (logicalWidth.isIntrinsic())
   3300         logicalWidth = Length(computeIntrinsicLogicalWidthUsing(logicalWidth, containerLogicalWidth, bordersPlusPadding) - bordersPlusPadding, Fixed);
   3301 
   3302     // 'left' and 'right' cannot both be 'auto' because one would of been
   3303     // converted to the static position already
   3304     ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto()));
   3305 
   3306     LayoutUnit logicalLeftValue = 0;
   3307 
   3308     const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, 0, 0, false);
   3309 
   3310     bool logicalWidthIsAuto = logicalWidth.isIntrinsicOrAuto();
   3311     bool logicalLeftIsAuto = logicalLeft.isAuto();
   3312     bool logicalRightIsAuto = logicalRight.isAuto();
   3313     RenderView* renderView = view();
   3314     LayoutUnit& marginLogicalLeftValue = style()->isLeftToRightDirection() ? computedValues.m_margins.m_start : computedValues.m_margins.m_end;
   3315     LayoutUnit& marginLogicalRightValue = style()->isLeftToRightDirection() ? computedValues.m_margins.m_end : computedValues.m_margins.m_start;
   3316 
   3317     if (!logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) {
   3318         /*-----------------------------------------------------------------------*\
   3319          * If none of the three is 'auto': If both 'margin-left' and 'margin-
   3320          * right' are 'auto', solve the equation under the extra constraint that
   3321          * the two margins get equal values, unless this would make them negative,
   3322          * in which case when direction of the containing block is 'ltr' ('rtl'),
   3323          * set 'margin-left' ('margin-right') to zero and solve for 'margin-right'
   3324          * ('margin-left'). If one of 'margin-left' or 'margin-right' is 'auto',
   3325          * solve the equation for that value. If the values are over-constrained,
   3326          * ignore the value for 'left' (in case the 'direction' property of the
   3327          * containing block is 'rtl') or 'right' (in case 'direction' is 'ltr')
   3328          * and solve for that value.
   3329         \*-----------------------------------------------------------------------*/
   3330         // NOTE:  It is not necessary to solve for 'right' in the over constrained
   3331         // case because the value is not used for any further calculations.
   3332 
   3333         logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
   3334         computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, containerLogicalWidth, renderView));
   3335 
   3336         const LayoutUnit availableSpace = containerLogicalWidth - (logicalLeftValue + computedValues.m_extent + valueForLength(logicalRight, containerLogicalWidth, renderView) + bordersPlusPadding);
   3337 
   3338         // Margins are now the only unknown
   3339         if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) {
   3340             // Both margins auto, solve for equality
   3341             if (availableSpace >= 0) {
   3342                 marginLogicalLeftValue = availableSpace / 2; // split the difference
   3343                 marginLogicalRightValue = availableSpace - marginLogicalLeftValue; // account for odd valued differences
   3344             } else {
   3345                 // Use the containing block's direction rather than the parent block's
   3346                 // per CSS 2.1 reference test abspos-non-replaced-width-margin-000.
   3347                 if (containerDirection == LTR) {
   3348                     marginLogicalLeftValue = 0;
   3349                     marginLogicalRightValue = availableSpace; // will be negative
   3350                 } else {
   3351                     marginLogicalLeftValue = availableSpace; // will be negative
   3352                     marginLogicalRightValue = 0;
   3353                 }
   3354             }
   3355         } else if (marginLogicalLeft.isAuto()) {
   3356             // Solve for left margin
   3357             marginLogicalRightValue = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView);
   3358             marginLogicalLeftValue = availableSpace - marginLogicalRightValue;
   3359         } else if (marginLogicalRight.isAuto()) {
   3360             // Solve for right margin
   3361             marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView);
   3362             marginLogicalRightValue = availableSpace - marginLogicalLeftValue;
   3363         } else {
   3364             // Over-constrained, solve for left if direction is RTL
   3365             marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView);
   3366             marginLogicalRightValue = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView);
   3367 
   3368             // Use the containing block's direction rather than the parent block's
   3369             // per CSS 2.1 reference test abspos-non-replaced-width-margin-000.
   3370             if (containerDirection == RTL)
   3371                 logicalLeftValue = (availableSpace + logicalLeftValue) - marginLogicalLeftValue - marginLogicalRightValue;
   3372         }
   3373     } else {
   3374         /*--------------------------------------------------------------------*\
   3375          * Otherwise, set 'auto' values for 'margin-left' and 'margin-right'
   3376          * to 0, and pick the one of the following six rules that applies.
   3377          *
   3378          * 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the
   3379          *    width is shrink-to-fit. Then solve for 'left'
   3380          *
   3381          *              OMIT RULE 2 AS IT SHOULD NEVER BE HIT
   3382          * ------------------------------------------------------------------
   3383          * 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if
   3384          *    the 'direction' property of the containing block is 'ltr' set
   3385          *    'left' to the static position, otherwise set 'right' to the
   3386          *    static position. Then solve for 'left' (if 'direction is 'rtl')
   3387          *    or 'right' (if 'direction' is 'ltr').
   3388          * ------------------------------------------------------------------
   3389          *
   3390          * 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the
   3391          *    width is shrink-to-fit . Then solve for 'right'
   3392          * 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve
   3393          *    for 'left'
   3394          * 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve
   3395          *    for 'width'
   3396          * 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve
   3397          *    for 'right'
   3398          *
   3399          * Calculation of the shrink-to-fit width is similar to calculating the
   3400          * width of a table cell using the automatic table layout algorithm.
   3401          * Roughly: calculate the preferred width by formatting the content
   3402          * without breaking lines other than where explicit line breaks occur,
   3403          * and also calculate the preferred minimum width, e.g., by trying all
   3404          * possible line breaks. CSS 2.1 does not define the exact algorithm.
   3405          * Thirdly, calculate the available width: this is found by solving
   3406          * for 'width' after setting 'left' (in case 1) or 'right' (in case 3)
   3407          * to 0.
   3408          *
   3409          * Then the shrink-to-fit width is:
   3410          * min(max(preferred minimum width, available width), preferred width).
   3411         \*--------------------------------------------------------------------*/
   3412         // NOTE: For rules 3 and 6 it is not necessary to solve for 'right'
   3413         // because the value is not used for any further calculations.
   3414 
   3415         // Calculate margins, 'auto' margins are ignored.
   3416         marginLogicalLeftValue = minimumValueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView);
   3417         marginLogicalRightValue = minimumValueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView);
   3418 
   3419         const LayoutUnit availableSpace = containerLogicalWidth - (marginLogicalLeftValue + marginLogicalRightValue + bordersPlusPadding);
   3420 
   3421         // FIXME: Is there a faster way to find the correct case?
   3422         // Use rule/case that applies.
   3423         if (logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAuto) {
   3424             // RULE 1: (use shrink-to-fit for width, and solve of left)
   3425             LayoutUnit logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView);
   3426 
   3427             // FIXME: would it be better to have shrink-to-fit in one step?
   3428             LayoutUnit preferredWidth = maxPreferredLogicalWidth() - bordersPlusPadding;
   3429             LayoutUnit preferredMinWidth = minPreferredLogicalWidth() - bordersPlusPadding;
   3430             LayoutUnit availableWidth = availableSpace - logicalRightValue;
   3431             computedValues.m_extent = min(max(preferredMinWidth, availableWidth), preferredWidth);
   3432             logicalLeftValue = availableSpace - (computedValues.m_extent + logicalRightValue);
   3433         } else if (!logicalLeftIsAuto && logicalWidthIsAuto && logicalRightIsAuto) {
   3434             // RULE 3: (use shrink-to-fit for width, and no need solve of right)
   3435             logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
   3436 
   3437             // FIXME: would it be better to have shrink-to-fit in one step?
   3438             LayoutUnit preferredWidth = maxPreferredLogicalWidth() - bordersPlusPadding;
   3439             LayoutUnit preferredMinWidth = minPreferredLogicalWidth() - bordersPlusPadding;
   3440             LayoutUnit availableWidth = availableSpace - logicalLeftValue;
   3441             computedValues.m_extent = min(max(preferredMinWidth, availableWidth), preferredWidth);
   3442         } else if (logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) {
   3443             // RULE 4: (solve for left)
   3444             computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, containerLogicalWidth, renderView));
   3445             logicalLeftValue = availableSpace - (computedValues.m_extent + valueForLength(logicalRight, containerLogicalWidth, renderView));
   3446         } else if (!logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAuto) {
   3447             // RULE 5: (solve for width)
   3448             logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
   3449             computedValues.m_extent = availableSpace - (logicalLeftValue + valueForLength(logicalRight, containerLogicalWidth, renderView));
   3450         } else if (!logicalLeftIsAuto && !logicalWidthIsAuto && logicalRightIsAuto) {
   3451             // RULE 6: (no need solve for right)
   3452             logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
   3453             computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, containerLogicalWidth, renderView));
   3454         }
   3455     }
   3456 
   3457     // Use computed values to calculate the horizontal position.
   3458 
   3459     // FIXME: This hack is needed to calculate the  logical left position for a 'rtl' relatively
   3460     // positioned, inline because right now, it is using the logical left position
   3461     // of the first line box when really it should use the last line box.  When
   3462     // this is fixed elsewhere, this block should be removed.
   3463     if (containerBlock->isRenderInline() && !containerBlock->style()->isLeftToRightDirection()) {
   3464         const RenderInline* flow = toRenderInline(containerBlock);
   3465         InlineFlowBox* firstLine = flow->firstLineBox();
   3466         InlineFlowBox* lastLine = flow->lastLineBox();
   3467         if (firstLine && lastLine && firstLine != lastLine) {
   3468             computedValues.m_position = logicalLeftValue + marginLogicalLeftValue + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logicalLeft());
   3469             return;
   3470         }
   3471     }
   3472 
   3473     computedValues.m_position = logicalLeftValue + marginLogicalLeftValue;
   3474     computeLogicalLeftPositionedOffset(computedValues.m_position, this, computedValues.m_extent, containerBlock, containerLogicalWidth);
   3475 }
   3476 
   3477 static void computeBlockStaticDistance(Length& logicalTop, Length& logicalBottom, const RenderBox* child, const RenderBoxModelObject* containerBlock)
   3478 {
   3479     if (!logicalTop.isAuto() || !logicalBottom.isAuto())
   3480         return;
   3481 
   3482     // FIXME: The static distance computation has not been patched for mixed writing modes.
   3483     LayoutUnit staticLogicalTop = child->layer()->staticBlockPosition() - containerBlock->borderBefore();
   3484     for (RenderObject* curr = child->parent(); curr && curr != containerBlock; curr = curr->container()) {
   3485         if (curr->isBox() && !curr->isTableRow())
   3486             staticLogicalTop += toRenderBox(curr)->logicalTop();
   3487     }
   3488     logicalTop.setValue(Fixed, staticLogicalTop);
   3489 }
   3490 
   3491 void RenderBox::computePositionedLogicalHeight(LogicalExtentComputedValues& computedValues) const
   3492 {
   3493     if (isReplaced()) {
   3494         computePositionedLogicalHeightReplaced(computedValues);
   3495         return;
   3496     }
   3497 
   3498     // The following is based off of the W3C Working Draft from April 11, 2006 of
   3499     // CSS 2.1: Section 10.6.4 "Absolutely positioned, non-replaced elements"
   3500     // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-non-replaced-height>
   3501     // (block-style-comments in this function and in computePositionedLogicalHeightUsing()
   3502     // correspond to text from the spec)
   3503 
   3504 
   3505     // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
   3506     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
   3507 
   3508     const LayoutUnit containerLogicalHeight = containingBlockLogicalHeightForPositioned(containerBlock);
   3509 
   3510     RenderStyle* styleToUse = style();
   3511     const LayoutUnit bordersPlusPadding = borderAndPaddingLogicalHeight();
   3512     const Length marginBefore = styleToUse->marginBefore();
   3513     const Length marginAfter = styleToUse->marginAfter();
   3514     Length logicalTopLength = styleToUse->logicalTop();
   3515     Length logicalBottomLength = styleToUse->logicalBottom();
   3516 
   3517     /*---------------------------------------------------------------------------*\
   3518      * For the purposes of this section and the next, the term "static position"
   3519      * (of an element) refers, roughly, to the position an element would have had
   3520      * in the normal flow. More precisely, the static position for 'top' is the
   3521      * distance from the top edge of the containing block to the top margin edge
   3522      * of a hypothetical box that would have been the first box of the element if
   3523      * its 'position' property had been 'static' and 'float' had been 'none'. The
   3524      * value is negative if the hypothetical box is above the containing block.
   3525      *
   3526      * But rather than actually calculating the dimensions of that hypothetical
   3527      * box, user agents are free to make a guess at its probable position.
   3528      *
   3529      * For the purposes of calculating the static position, the containing block
   3530      * of fixed positioned elements is the initial containing block instead of
   3531      * the viewport.
   3532     \*---------------------------------------------------------------------------*/
   3533 
   3534     // see FIXME 1
   3535     // Calculate the static distance if needed.
   3536     computeBlockStaticDistance(logicalTopLength, logicalBottomLength, this, containerBlock);
   3537 
   3538     // Calculate constraint equation values for 'height' case.
   3539     LayoutUnit logicalHeight = computedValues.m_extent;
   3540     computePositionedLogicalHeightUsing(styleToUse->logicalHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight,
   3541                                         logicalTopLength, logicalBottomLength, marginBefore, marginAfter,
   3542                                         computedValues);
   3543 
   3544     // Avoid doing any work in the common case (where the values of min-height and max-height are their defaults).
   3545     // see FIXME 2
   3546 
   3547     // Calculate constraint equation values for 'max-height' case.
   3548     if (!styleToUse->logicalMaxHeight().isUndefined()) {
   3549         LogicalExtentComputedValues maxValues;
   3550 
   3551         computePositionedLogicalHeightUsing(styleToUse->logicalMaxHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight,
   3552                                             logicalTopLength, logicalBottomLength, marginBefore, marginAfter,
   3553                                             maxValues);
   3554 
   3555         if (computedValues.m_extent > maxValues.m_extent) {
   3556             computedValues.m_extent = maxValues.m_extent;
   3557             computedValues.m_position = maxValues.m_position;
   3558             computedValues.m_margins.m_before = maxValues.m_margins.m_before;
   3559             computedValues.m_margins.m_after = maxValues.m_margins.m_after;
   3560         }
   3561     }
   3562 
   3563     // Calculate constraint equation values for 'min-height' case.
   3564     if (!styleToUse->logicalMinHeight().isZero() || styleToUse->logicalMinHeight().isIntrinsic()) {
   3565         LogicalExtentComputedValues minValues;
   3566 
   3567         computePositionedLogicalHeightUsing(styleToUse->logicalMinHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight,
   3568                                             logicalTopLength, logicalBottomLength, marginBefore, marginAfter,
   3569                                             minValues);
   3570 
   3571         if (computedValues.m_extent < minValues.m_extent) {
   3572             computedValues.m_extent = minValues.m_extent;
   3573             computedValues.m_position = minValues.m_position;
   3574             computedValues.m_margins.m_before = minValues.m_margins.m_before;
   3575             computedValues.m_margins.m_after = minValues.m_margins.m_after;
   3576         }
   3577     }
   3578 
   3579     // Set final height value.
   3580     computedValues.m_extent += bordersPlusPadding;
   3581 
   3582     // Adjust logicalTop if we need to for perpendicular writing modes in regions.
   3583     // FIXME: Add support for other types of objects as containerBlock, not only RenderBlock.
   3584     RenderFlowThread* flowThread = flowThreadContainingBlock();
   3585     if (flowThread && isHorizontalWritingMode() != containerBlock->isHorizontalWritingMode() && containerBlock->isRenderBlock()) {
   3586         ASSERT(containerBlock->canHaveBoxInfoInRegion());
   3587         LayoutUnit logicalTopPos = computedValues.m_position;
   3588         const RenderBlock* cb = toRenderBlock(containerBlock);
   3589         LayoutUnit cbPageOffset = cb->offsetFromLogicalTopOfFirstPage() - logicalLeft();
   3590         RenderRegion* cbRegion = cb->regionAtBlockOffset(cbPageOffset);
   3591         if (cbRegion) {
   3592             cbRegion = cb->clampToStartAndEndRegions(cbRegion);
   3593             RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(cbRegion, cbPageOffset);
   3594             if (boxInfo) {
   3595                 logicalTopPos += boxInfo->logicalLeft();
   3596                 computedValues.m_position = logicalTopPos;
   3597             }
   3598         }
   3599     }
   3600 }
   3601 
   3602 static void computeLogicalTopPositionedOffset(LayoutUnit& logicalTopPos, const RenderBox* child, LayoutUnit logicalHeightValue, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalHeight)
   3603 {
   3604     // Deal with differing writing modes here.  Our offset needs to be in the containing block's coordinate space. If the containing block is flipped
   3605     // 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.
   3606     if ((child->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() != containerBlock->isHorizontalWritingMode())
   3607         || (child->style()->isFlippedBlocksWritingMode() != containerBlock->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode()))
   3608         logicalTopPos = containerLogicalHeight - logicalHeightValue - logicalTopPos;
   3609 
   3610     // Our offset is from the logical bottom edge in a flipped environment, e.g., right for vertical-rl and bottom for horizontal-bt.
   3611     if (containerBlock->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode()) {
   3612         if (child->isHorizontalWritingMode())
   3613             logicalTopPos += containerBlock->borderBottom();
   3614         else
   3615             logicalTopPos += containerBlock->borderRight();
   3616     } else {
   3617         if (child->isHorizontalWritingMode())
   3618             logicalTopPos += containerBlock->borderTop();
   3619         else
   3620             logicalTopPos += containerBlock->borderLeft();
   3621     }
   3622 }
   3623 
   3624 void RenderBox::computePositionedLogicalHeightUsing(Length logicalHeightLength, const RenderBoxModelObject* containerBlock,
   3625                                                     LayoutUnit containerLogicalHeight, LayoutUnit bordersPlusPadding, LayoutUnit logicalHeight,
   3626                                                     Length logicalTop, Length logicalBottom, Length marginBefore, Length marginAfter,
   3627                                                     LogicalExtentComputedValues& computedValues) const
   3628 {
   3629     // 'top' and 'bottom' cannot both be 'auto' because 'top would of been
   3630     // converted to the static position in computePositionedLogicalHeight()
   3631     ASSERT(!(logicalTop.isAuto() && logicalBottom.isAuto()));
   3632 
   3633     LayoutUnit logicalHeightValue;
   3634     LayoutUnit contentLogicalHeight = logicalHeight - bordersPlusPadding;
   3635 
   3636     const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, 0, 0, false);
   3637 
   3638     LayoutUnit logicalTopValue = 0;
   3639 
   3640     bool logicalHeightIsAuto = logicalHeightLength.isAuto();
   3641     bool logicalTopIsAuto = logicalTop.isAuto();
   3642     bool logicalBottomIsAuto = logicalBottom.isAuto();
   3643     RenderView* renderView = view();
   3644 
   3645     // Height is never unsolved for tables.
   3646     if (isTable()) {
   3647         logicalHeightLength.setValue(Fixed, contentLogicalHeight);
   3648         logicalHeightIsAuto = false;
   3649     }
   3650 
   3651     LayoutUnit resolvedLogicalHeight;
   3652     if (logicalHeightLength.isIntrinsic())
   3653         resolvedLogicalHeight = computeIntrinsicLogicalContentHeightUsing(logicalHeightLength, contentLogicalHeight, bordersPlusPadding);
   3654     else
   3655         resolvedLogicalHeight = adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeightLength, containerLogicalHeight, renderView));
   3656 
   3657     if (!logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsAuto) {
   3658         /*-----------------------------------------------------------------------*\
   3659          * If none of the three are 'auto': If both 'margin-top' and 'margin-
   3660          * bottom' are 'auto', solve the equation under the extra constraint that
   3661          * the two margins get equal values. If one of 'margin-top' or 'margin-
   3662          * bottom' is 'auto', solve the equation for that value. If the values
   3663          * are over-constrained, ignore the value for 'bottom' and solve for that
   3664          * value.
   3665         \*-----------------------------------------------------------------------*/
   3666         // NOTE:  It is not necessary to solve for 'bottom' in the over constrained
   3667         // case because the value is not used for any further calculations.
   3668 
   3669         logicalHeightValue = resolvedLogicalHeight;
   3670         logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
   3671 
   3672         const LayoutUnit availableSpace = containerLogicalHeight - (logicalTopValue + logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight, renderView) + bordersPlusPadding);
   3673 
   3674         // Margins are now the only unknown
   3675         if (marginBefore.isAuto() && marginAfter.isAuto()) {
   3676             // Both margins auto, solve for equality
   3677             // NOTE: This may result in negative values.
   3678             computedValues.m_margins.m_before = availableSpace / 2; // split the difference
   3679             computedValues.m_margins.m_after = availableSpace - computedValues.m_margins.m_before; // account for odd valued differences
   3680         } else if (marginBefore.isAuto()) {
   3681             // Solve for top margin
   3682             computedValues.m_margins.m_after = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView);
   3683             computedValues.m_margins.m_before = availableSpace - computedValues.m_margins.m_after;
   3684         } else if (marginAfter.isAuto()) {
   3685             // Solve for bottom margin
   3686             computedValues.m_margins.m_before = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView);
   3687             computedValues.m_margins.m_after = availableSpace - computedValues.m_margins.m_before;
   3688         } else {
   3689             // Over-constrained, (no need solve for bottom)
   3690             computedValues.m_margins.m_before = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView);
   3691             computedValues.m_margins.m_after = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView);
   3692         }
   3693     } else {
   3694         /*--------------------------------------------------------------------*\
   3695          * Otherwise, set 'auto' values for 'margin-top' and 'margin-bottom'
   3696          * to 0, and pick the one of the following six rules that applies.
   3697          *
   3698          * 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then
   3699          *    the height is based on the content, and solve for 'top'.
   3700          *
   3701          *              OMIT RULE 2 AS IT SHOULD NEVER BE HIT
   3702          * ------------------------------------------------------------------
   3703          * 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then
   3704          *    set 'top' to the static position, and solve for 'bottom'.
   3705          * ------------------------------------------------------------------
   3706          *
   3707          * 3. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then
   3708          *    the height is based on the content, and solve for 'bottom'.
   3709          * 4. 'top' is 'auto', 'height' and 'bottom' are not 'auto', and
   3710          *    solve for 'top'.
   3711          * 5. 'height' is 'auto', 'top' and 'bottom' are not 'auto', and
   3712          *    solve for 'height'.
   3713          * 6. 'bottom' is 'auto', 'top' and 'height' are not 'auto', and
   3714          *    solve for 'bottom'.
   3715         \*--------------------------------------------------------------------*/
   3716         // NOTE: For rules 3 and 6 it is not necessary to solve for 'bottom'
   3717         // because the value is not used for any further calculations.
   3718 
   3719         // Calculate margins, 'auto' margins are ignored.
   3720         computedValues.m_margins.m_before = minimumValueForLength(marginBefore, containerRelativeLogicalWidth, renderView);
   3721         computedValues.m_margins.m_after = minimumValueForLength(marginAfter, containerRelativeLogicalWidth, renderView);
   3722 
   3723         const LayoutUnit availableSpace = containerLogicalHeight - (computedValues.m_margins.m_before + computedValues.m_margins.m_after + bordersPlusPadding);
   3724 
   3725         // Use rule/case that applies.
   3726         if (logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) {
   3727             // RULE 1: (height is content based, solve of top)
   3728             logicalHeightValue = contentLogicalHeight;
   3729             logicalTopValue = availableSpace - (logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight, renderView));
   3730         } else if (!logicalTopIsAuto && logicalHeightIsAuto && logicalBottomIsAuto) {
   3731             // RULE 3: (height is content based, no need solve of bottom)
   3732             logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
   3733             logicalHeightValue = contentLogicalHeight;
   3734         } else if (logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsAuto) {
   3735             // RULE 4: (solve of top)
   3736             logicalHeightValue = resolvedLogicalHeight;
   3737             logicalTopValue = availableSpace - (logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight, renderView));
   3738         } else if (!logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) {
   3739             // RULE 5: (solve of height)
   3740             logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
   3741             logicalHeightValue = max<LayoutUnit>(0, availableSpace - (logicalTopValue + valueForLength(logicalBottom, containerLogicalHeight, renderView)));
   3742         } else if (!logicalTopIsAuto && !logicalHeightIsAuto && logicalBottomIsAuto) {
   3743             // RULE 6: (no need solve of bottom)
   3744             logicalHeightValue = resolvedLogicalHeight;
   3745             logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
   3746         }
   3747     }
   3748     computedValues.m_extent = logicalHeightValue;
   3749 
   3750     // Use computed values to calculate the vertical position.
   3751     computedValues.m_position = logicalTopValue + computedValues.m_margins.m_before;
   3752     computeLogicalTopPositionedOffset(computedValues.m_position, this, logicalHeightValue, containerBlock, containerLogicalHeight);
   3753 }
   3754 
   3755 void RenderBox::computePositionedLogicalWidthReplaced(LogicalExtentComputedValues& computedValues) const
   3756 {
   3757     // The following is based off of the W3C Working Draft from April 11, 2006 of
   3758     // CSS 2.1: Section 10.3.8 "Absolutely positioned, replaced elements"
   3759     // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-width>
   3760     // (block-style-comments in this function correspond to text from the spec and
   3761     // the numbers correspond to numbers in spec)
   3762 
   3763     // We don't use containingBlock(), since we may be positioned by an enclosing
   3764     // relative positioned inline.
   3765     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
   3766 
   3767     const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock);
   3768     const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, 0, 0, false);
   3769 
   3770     // To match WinIE, in quirks mode use the parent's 'direction' property
   3771     // instead of the the container block's.
   3772     TextDirection containerDirection = containerBlock->style()->direction();
   3773 
   3774     // Variables to solve.
   3775     bool isHorizontal = isHorizontalWritingMode();
   3776     Length logicalLeft = style()->logicalLeft();
   3777     Length logicalRight = style()->logicalRight();
   3778     Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->marginTop();
   3779     Length marginLogicalRight = isHorizontal ? style()->marginRight() : style()->marginBottom();
   3780     LayoutUnit& marginLogicalLeftAlias = style()->isLeftToRightDirection() ? computedValues.m_margins.m_start : computedValues.m_margins.m_end;
   3781     LayoutUnit& marginLogicalRightAlias = style()->isLeftToRightDirection() ? computedValues.m_margins.m_end : computedValues.m_margins.m_start;
   3782 
   3783     /*-----------------------------------------------------------------------*\
   3784      * 1. The used value of 'width' is determined as for inline replaced
   3785      *    elements.
   3786     \*-----------------------------------------------------------------------*/
   3787     // NOTE: This value of width is FINAL in that the min/max width calculations
   3788     // are dealt with in computeReplacedWidth().  This means that the steps to produce
   3789     // correct max/min in the non-replaced version, are not necessary.
   3790     computedValues.m_extent = computeReplacedLogicalWidth() + borderAndPaddingLogicalWidth();
   3791 
   3792     const LayoutUnit availableSpace = containerLogicalWidth - computedValues.m_extent;
   3793 
   3794     /*-----------------------------------------------------------------------*\
   3795      * 2. If both 'left' and 'right' have the value 'auto', then if 'direction'
   3796      *    of the containing block is 'ltr', set 'left' to the static position;
   3797      *    else if 'direction' is 'rtl', set 'right' to the static position.
   3798     \*-----------------------------------------------------------------------*/
   3799     // see FIXME 1
   3800     computeInlineStaticDistance(logicalLeft, logicalRight, this, containerBlock, containerLogicalWidth, 0); // FIXME: Pass the region.
   3801 
   3802     /*-----------------------------------------------------------------------*\
   3803      * 3. If 'left' or 'right' are 'auto', replace any 'auto' on 'margin-left'
   3804      *    or 'margin-right' with '0'.
   3805     \*-----------------------------------------------------------------------*/
   3806     if (logicalLeft.isAuto() || logicalRight.isAuto()) {
   3807         if (marginLogicalLeft.isAuto())
   3808             marginLogicalLeft.setValue(Fixed, 0);
   3809         if (marginLogicalRight.isAuto())
   3810             marginLogicalRight.setValue(Fixed, 0);
   3811     }
   3812 
   3813     /*-----------------------------------------------------------------------*\
   3814      * 4. If at this point both 'margin-left' and 'margin-right' are still
   3815      *    'auto', solve the equation under the extra constraint that the two
   3816      *    margins must get equal values, unless this would make them negative,
   3817      *    in which case when the direction of the containing block is 'ltr'
   3818      *    ('rtl'), set 'margin-left' ('margin-right') to zero and solve for
   3819      *    'margin-right' ('margin-left').
   3820     \*-----------------------------------------------------------------------*/
   3821     LayoutUnit logicalLeftValue = 0;
   3822     LayoutUnit logicalRightValue = 0;
   3823     RenderView* renderView = view();
   3824 
   3825     if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) {
   3826         // 'left' and 'right' cannot be 'auto' due to step 3
   3827         ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto()));
   3828 
   3829         logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
   3830         logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView);
   3831 
   3832         LayoutUnit difference = availableSpace - (logicalLeftValue + logicalRightValue);
   3833         if (difference > 0) {
   3834             marginLogicalLeftAlias = difference / 2; // split the difference
   3835             marginLogicalRightAlias = difference - marginLogicalLeftAlias; // account for odd valued differences
   3836         } else {
   3837             // Use the containing block's direction rather than the parent block's
   3838             // per CSS 2.1 reference test abspos-replaced-width-margin-000.
   3839             if (containerDirection == LTR) {
   3840                 marginLogicalLeftAlias = 0;
   3841                 marginLogicalRightAlias = difference; // will be negative
   3842             } else {
   3843                 marginLogicalLeftAlias = difference; // will be negative
   3844                 marginLogicalRightAlias = 0;
   3845             }
   3846         }
   3847 
   3848     /*-----------------------------------------------------------------------*\
   3849      * 5. If at this point there is an 'auto' left, solve the equation for
   3850      *    that value.
   3851     \*-----------------------------------------------------------------------*/
   3852     } else if (logicalLeft.isAuto()) {
   3853         marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView);
   3854         marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView);
   3855         logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView);
   3856 
   3857         // Solve for 'left'
   3858         logicalLeftValue = availableSpace - (logicalRightValue + marginLogicalLeftAlias + marginLogicalRightAlias);
   3859     } else if (logicalRight.isAuto()) {
   3860         marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView);
   3861         marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView);
   3862         logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
   3863 
   3864         // Solve for 'right'
   3865         logicalRightValue = availableSpace - (logicalLeftValue + marginLogicalLeftAlias + marginLogicalRightAlias);
   3866     } else if (marginLogicalLeft.isAuto()) {
   3867         marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView);
   3868         logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
   3869         logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView);
   3870 
   3871         // Solve for 'margin-left'
   3872         marginLogicalLeftAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalRightAlias);
   3873     } else if (marginLogicalRight.isAuto()) {
   3874         marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView);
   3875         logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
   3876         logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView);
   3877 
   3878         // Solve for 'margin-right'
   3879         marginLogicalRightAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalLeftAlias);
   3880     } else {
   3881         // Nothing is 'auto', just calculate the values.
   3882         marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth, renderView);
   3883         marginLogicalRightAlias = valueForLength(marginLogicalRight, containerRelativeLogicalWidth, renderView);
   3884         logicalRightValue = valueForLength(logicalRight, containerLogicalWidth, renderView);
   3885         logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView);
   3886         // If the containing block is right-to-left, then push the left position as far to the right as possible
   3887         if (containerDirection == RTL) {
   3888             int totalLogicalWidth = computedValues.m_extent + logicalLeftValue + logicalRightValue +  marginLogicalLeftAlias + marginLogicalRightAlias;
   3889             logicalLeftValue = containerLogicalWidth - (totalLogicalWidth - logicalLeftValue);
   3890         }
   3891     }
   3892 
   3893     /*-----------------------------------------------------------------------*\
   3894      * 6. If at this point the values are over-constrained, ignore the value
   3895      *    for either 'left' (in case the 'direction' property of the
   3896      *    containing block is 'rtl') or 'right' (in case 'direction' is
   3897      *    'ltr') and solve for that value.
   3898     \*-----------------------------------------------------------------------*/
   3899     // NOTE: Constraints imposed by the width of the containing block and its content have already been accounted for above.
   3900 
   3901     // FIXME: Deal with differing writing modes here.  Our offset needs to be in the containing block's coordinate space, so that
   3902     // can make the result here rather complicated to compute.
   3903 
   3904     // Use computed values to calculate the horizontal position.
   3905 
   3906     // FIXME: This hack is needed to calculate the logical left position for a 'rtl' relatively
   3907     // positioned, inline containing block because right now, it is using the logical left position
   3908     // of the first line box when really it should use the last line box.  When
   3909     // this is fixed elsewhere, this block should be removed.
   3910     if (containerBlock->isRenderInline() && !containerBlock->style()->isLeftToRightDirection()) {
   3911         const RenderInline* flow = toRenderInline(containerBlock);
   3912         InlineFlowBox* firstLine = flow->firstLineBox();
   3913         InlineFlowBox* lastLine = flow->lastLineBox();
   3914         if (firstLine && lastLine && firstLine != lastLine) {
   3915             computedValues.m_position = logicalLeftValue + marginLogicalLeftAlias + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logicalLeft());
   3916             return;
   3917         }
   3918     }
   3919 
   3920     LayoutUnit logicalLeftPos = logicalLeftValue + marginLogicalLeftAlias;
   3921     computeLogicalLeftPositionedOffset(logicalLeftPos, this, computedValues.m_extent, containerBlock, containerLogicalWidth);
   3922     computedValues.m_position = logicalLeftPos;
   3923 }
   3924 
   3925 void RenderBox::computePositionedLogicalHeightReplaced(LogicalExtentComputedValues& computedValues) const
   3926 {
   3927     // The following is based off of the W3C Working Draft from April 11, 2006 of
   3928     // CSS 2.1: Section 10.6.5 "Absolutely positioned, replaced elements"
   3929     // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-height>
   3930     // (block-style-comments in this function correspond to text from the spec and
   3931     // the numbers correspond to numbers in spec)
   3932 
   3933     // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
   3934     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
   3935 
   3936     const LayoutUnit containerLogicalHeight = containingBlockLogicalHeightForPositioned(containerBlock);
   3937     const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, 0, 0, false);
   3938 
   3939     // Variables to solve.
   3940     Length marginBefore = style()->marginBefore();
   3941     Length marginAfter = style()->marginAfter();
   3942     LayoutUnit& marginBeforeAlias = computedValues.m_margins.m_before;
   3943     LayoutUnit& marginAfterAlias = computedValues.m_margins.m_after;
   3944 
   3945     Length logicalTop = style()->logicalTop();
   3946     Length logicalBottom = style()->logicalBottom();
   3947     RenderView* renderView = view();
   3948 
   3949     /*-----------------------------------------------------------------------*\
   3950      * 1. The used value of 'height' is determined as for inline replaced
   3951      *    elements.
   3952     \*-----------------------------------------------------------------------*/
   3953     // NOTE: This value of height is FINAL in that the min/max height calculations
   3954     // are dealt with in computeReplacedHeight().  This means that the steps to produce
   3955     // correct max/min in the non-replaced version, are not necessary.
   3956     computedValues.m_extent = computeReplacedLogicalHeight() + borderAndPaddingLogicalHeight();
   3957     const LayoutUnit availableSpace = containerLogicalHeight - computedValues.m_extent;
   3958 
   3959     /*-----------------------------------------------------------------------*\
   3960      * 2. If both 'top' and 'bottom' have the value 'auto', replace 'top'
   3961      *    with the element's static position.
   3962     \*-----------------------------------------------------------------------*/
   3963     // see FIXME 1
   3964     computeBlockStaticDistance(logicalTop, logicalBottom, this, containerBlock);
   3965 
   3966     /*-----------------------------------------------------------------------*\
   3967      * 3. If 'bottom' is 'auto', replace any 'auto' on 'margin-top' or
   3968      *    'margin-bottom' with '0'.
   3969     \*-----------------------------------------------------------------------*/
   3970     // FIXME: The spec. says that this step should only be taken when bottom is
   3971     // auto, but if only top is auto, this makes step 4 impossible.
   3972     if (logicalTop.isAuto() || logicalBottom.isAuto()) {
   3973         if (marginBefore.isAuto())
   3974             marginBefore.setValue(Fixed, 0);
   3975         if (marginAfter.isAuto())
   3976             marginAfter.setValue(Fixed, 0);
   3977     }
   3978 
   3979     /*-----------------------------------------------------------------------*\
   3980      * 4. If at this point both 'margin-top' and 'margin-bottom' are still
   3981      *    'auto', solve the equation under the extra constraint that the two
   3982      *    margins must get equal values.
   3983     \*-----------------------------------------------------------------------*/
   3984     LayoutUnit logicalTopValue = 0;
   3985     LayoutUnit logicalBottomValue = 0;
   3986 
   3987     if (marginBefore.isAuto() && marginAfter.isAuto()) {
   3988         // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combined.
   3989         ASSERT(!(logicalTop.isAuto() || logicalBottom.isAuto()));
   3990 
   3991         logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
   3992         logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight, renderView);
   3993 
   3994         LayoutUnit difference = availableSpace - (logicalTopValue + logicalBottomValue);
   3995         // NOTE: This may result in negative values.
   3996         marginBeforeAlias =  difference / 2; // split the difference
   3997         marginAfterAlias = difference - marginBeforeAlias; // account for odd valued differences
   3998 
   3999     /*-----------------------------------------------------------------------*\
   4000      * 5. If at this point there is only one 'auto' left, solve the equation
   4001      *    for that value.
   4002     \*-----------------------------------------------------------------------*/
   4003     } else if (logicalTop.isAuto()) {
   4004         marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView);
   4005         marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView);
   4006         logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight, renderView);
   4007 
   4008         // Solve for 'top'
   4009         logicalTopValue = availableSpace - (logicalBottomValue + marginBeforeAlias + marginAfterAlias);
   4010     } else if (logicalBottom.isAuto()) {
   4011         marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView);
   4012         marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView);
   4013         logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
   4014 
   4015         // Solve for 'bottom'
   4016         // NOTE: It is not necessary to solve for 'bottom' because we don't ever
   4017         // use the value.
   4018     } else if (marginBefore.isAuto()) {
   4019         marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView);
   4020         logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
   4021         logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight, renderView);
   4022 
   4023         // Solve for 'margin-top'
   4024         marginBeforeAlias = availableSpace - (logicalTopValue + logicalBottomValue + marginAfterAlias);
   4025     } else if (marginAfter.isAuto()) {
   4026         marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView);
   4027         logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
   4028         logicalBottomValue = valueForLength(logicalBottom, containerLogicalHeight, renderView);
   4029 
   4030         // Solve for 'margin-bottom'
   4031         marginAfterAlias = availableSpace - (logicalTopValue + logicalBottomValue + marginBeforeAlias);
   4032     } else {
   4033         // Nothing is 'auto', just calculate the values.
   4034         marginBeforeAlias = valueForLength(marginBefore, containerRelativeLogicalWidth, renderView);
   4035         marginAfterAlias = valueForLength(marginAfter, containerRelativeLogicalWidth, renderView);
   4036         logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView);
   4037         // NOTE: It is not necessary to solve for 'bottom' because we don't ever
   4038         // use the value.
   4039      }
   4040 
   4041     /*-----------------------------------------------------------------------*\
   4042      * 6. If at this point the values are over-constrained, ignore the value
   4043      *    for 'bottom' and solve for that value.
   4044     \*-----------------------------------------------------------------------*/
   4045     // NOTE: It is not necessary to do this step because we don't end up using
   4046     // the value of 'bottom' regardless of whether the values are over-constrained
   4047     // or not.
   4048 
   4049     // Use computed values to calculate the vertical position.
   4050     LayoutUnit logicalTopPos = logicalTopValue + marginBeforeAlias;
   4051     computeLogicalTopPositionedOffset(logicalTopPos, this, computedValues.m_extent, containerBlock, containerLogicalHeight);
   4052     computedValues.m_position = logicalTopPos;
   4053 }
   4054 
   4055 LayoutRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, LayoutUnit* extraWidthToEndOfLine)
   4056 {
   4057     // VisiblePositions at offsets inside containers either a) refer to the positions before/after
   4058     // those containers (tables and select elements) or b) refer to the position inside an empty block.
   4059     // They never refer to children.
   4060     // FIXME: Paint the carets inside empty blocks differently than the carets before/after elements.
   4061 
   4062     LayoutRect rect(location(), LayoutSize(caretWidth, height()));
   4063     bool ltr = box ? box->isLeftToRightDirection() : style()->isLeftToRightDirection();
   4064 
   4065     if ((!caretOffset) ^ ltr)
   4066         rect.move(LayoutSize(width() - caretWidth, 0));
   4067 
   4068     if (box) {
   4069         RootInlineBox* rootBox = box->root();
   4070         LayoutUnit top = rootBox->lineTop();
   4071         rect.setY(top);
   4072         rect.setHeight(rootBox->lineBottom() - top);
   4073     }
   4074 
   4075     // If height of box is smaller than font height, use the latter one,
   4076     // otherwise the caret might become invisible.
   4077     //
   4078     // Also, if the box is not a replaced element, always use the font height.
   4079     // This prevents the "big caret" bug described in:
   4080     // <rdar://problem/3777804> Deleting all content in a document can result in giant tall-as-window insertion point
   4081     //
   4082     // FIXME: ignoring :first-line, missing good reason to take care of
   4083     LayoutUnit fontHeight = style()->fontMetrics().height();
   4084     if (fontHeight > rect.height() || (!isReplaced() && !isTable()))
   4085         rect.setHeight(fontHeight);
   4086 
   4087     if (extraWidthToEndOfLine)
   4088         *extraWidthToEndOfLine = x() + width() - rect.maxX();
   4089 
   4090     // Move to local coords
   4091     rect.moveBy(-location());
   4092 
   4093     // FIXME: Border/padding should be added for all elements but this workaround
   4094     // is needed because we use offsets inside an "atomic" element to represent
   4095     // positions before and after the element in deprecated editing offsets.
   4096     if (node() && !(editingIgnoresContent(node()) || isTableElement(node()))) {
   4097         rect.setX(rect.x() + borderLeft() + paddingLeft());
   4098         rect.setY(rect.y() + paddingTop() + borderTop());
   4099     }
   4100 
   4101     if (!isHorizontalWritingMode())
   4102         return rect.transposedRect();
   4103 
   4104     return rect;
   4105 }
   4106 
   4107 PositionWithAffinity RenderBox::positionForPoint(const LayoutPoint& point)
   4108 {
   4109     // no children...return this render object's element, if there is one, and offset 0
   4110     if (!firstChild())
   4111         return createPositionWithAffinity(nonPseudoNode() ? firstPositionInOrBeforeNode(nonPseudoNode()) : Position());
   4112 
   4113     if (isTable() && nonPseudoNode()) {
   4114         LayoutUnit right = contentWidth() + borderAndPaddingWidth();
   4115         LayoutUnit bottom = contentHeight() + borderAndPaddingHeight();
   4116 
   4117         if (point.x() < 0 || point.x() > right || point.y() < 0 || point.y() > bottom) {
   4118             if (point.x() <= right / 2)
   4119                 return createPositionWithAffinity(firstPositionInOrBeforeNode(nonPseudoNode()));
   4120             return createPositionWithAffinity(lastPositionInOrAfterNode(nonPseudoNode()));
   4121         }
   4122     }
   4123 
   4124     // Pass off to the closest child.
   4125     LayoutUnit minDist = LayoutUnit::max();
   4126     RenderBox* closestRenderer = 0;
   4127     LayoutPoint adjustedPoint = point;
   4128     if (isTableRow())
   4129         adjustedPoint.moveBy(location());
   4130 
   4131     for (RenderObject* renderObject = firstChild(); renderObject; renderObject = renderObject->nextSibling()) {
   4132         if ((!renderObject->firstChild() && !renderObject->isInline() && !renderObject->isBlockFlow() )
   4133             || renderObject->style()->visibility() != VISIBLE)
   4134             continue;
   4135 
   4136         if (!renderObject->isBox())
   4137             continue;
   4138 
   4139         RenderBox* renderer = toRenderBox(renderObject);
   4140 
   4141         LayoutUnit top = renderer->borderTop() + renderer->paddingTop() + (isTableRow() ? LayoutUnit() : renderer->y());
   4142         LayoutUnit bottom = top + renderer->contentHeight();
   4143         LayoutUnit left = renderer->borderLeft() + renderer->paddingLeft() + (isTableRow() ? LayoutUnit() : renderer->x());
   4144         LayoutUnit right = left + renderer->contentWidth();
   4145 
   4146         if (point.x() <= right && point.x() >= left && point.y() <= top && point.y() >= bottom) {
   4147             if (renderer->isTableRow())
   4148                 return renderer->positionForPoint(point + adjustedPoint - renderer->locationOffset());
   4149             return renderer->positionForPoint(point - renderer->locationOffset());
   4150         }
   4151 
   4152         // Find the distance from (x, y) to the box.  Split the space around the box into 8 pieces
   4153         // and use a different compare depending on which piece (x, y) is in.
   4154         LayoutPoint cmp;
   4155         if (point.x() > right) {
   4156             if (point.y() < top)
   4157                 cmp = LayoutPoint(right, top);
   4158             else if (point.y() > bottom)
   4159                 cmp = LayoutPoint(right, bottom);
   4160             else
   4161                 cmp = LayoutPoint(right, point.y());
   4162         } else if (point.x() < left) {
   4163             if (point.y() < top)
   4164                 cmp = LayoutPoint(left, top);
   4165             else if (point.y() > bottom)
   4166                 cmp = LayoutPoint(left, bottom);
   4167             else
   4168                 cmp = LayoutPoint(left, point.y());
   4169         } else {
   4170             if (point.y() < top)
   4171                 cmp = LayoutPoint(point.x(), top);
   4172             else
   4173                 cmp = LayoutPoint(point.x(), bottom);
   4174         }
   4175 
   4176         LayoutSize difference = cmp - point;
   4177 
   4178         LayoutUnit dist = difference.width() * difference.width() + difference.height() * difference.height();
   4179         if (dist < minDist) {
   4180             closestRenderer = renderer;
   4181             minDist = dist;
   4182         }
   4183     }
   4184 
   4185     if (closestRenderer)
   4186         return closestRenderer->positionForPoint(adjustedPoint - closestRenderer->locationOffset());
   4187     return createPositionWithAffinity(firstPositionInOrBeforeNode(nonPseudoNode()));
   4188 }
   4189 
   4190 bool RenderBox::shrinkToAvoidFloats() const
   4191 {
   4192     // Floating objects don't shrink.  Objects that don't avoid floats don't shrink.  Marquees don't shrink.
   4193     if ((isInline() && !isMarquee()) || !avoidsFloats() || isFloating())
   4194         return false;
   4195 
   4196     // Only auto width objects can possibly shrink to avoid floats.
   4197     return style()->width().isAuto();
   4198 }
   4199 
   4200 bool RenderBox::avoidsFloats() const
   4201 {
   4202     return isReplaced() || hasOverflowClip() || isHR() || isLegend() || isWritingModeRoot() || isFlexItemIncludingDeprecated();
   4203 }
   4204 
   4205 void RenderBox::addVisualEffectOverflow()
   4206 {
   4207     if (!style()->boxShadow() && !style()->hasBorderImageOutsets())
   4208         return;
   4209 
   4210     bool isFlipped = style()->isFlippedBlocksWritingMode();
   4211     bool isHorizontal = isHorizontalWritingMode();
   4212 
   4213     LayoutRect borderBox = borderBoxRect();
   4214     LayoutUnit overflowMinX = borderBox.x();
   4215     LayoutUnit overflowMaxX = borderBox.maxX();
   4216     LayoutUnit overflowMinY = borderBox.y();
   4217     LayoutUnit overflowMaxY = borderBox.maxY();
   4218 
   4219     // Compute box-shadow overflow first.
   4220     if (style()->boxShadow()) {
   4221         LayoutUnit shadowLeft;
   4222         LayoutUnit shadowRight;
   4223         LayoutUnit shadowTop;
   4224         LayoutUnit shadowBottom;
   4225         style()->getBoxShadowExtent(shadowTop, shadowRight, shadowBottom, shadowLeft);
   4226 
   4227         // In flipped blocks writing modes such as vertical-rl, the physical right shadow value is actually at the lower x-coordinate.
   4228         overflowMinX = borderBox.x() + ((!isFlipped || isHorizontal) ? shadowLeft : -shadowRight);
   4229         overflowMaxX = borderBox.maxX() + ((!isFlipped || isHorizontal) ? shadowRight : -shadowLeft);
   4230         overflowMinY = borderBox.y() + ((!isFlipped || !isHorizontal) ? shadowTop : -shadowBottom);
   4231         overflowMaxY = borderBox.maxY() + ((!isFlipped || !isHorizontal) ? shadowBottom : -shadowTop);
   4232     }
   4233 
   4234     // Now compute border-image-outset overflow.
   4235     if (style()->hasBorderImageOutsets()) {
   4236         LayoutBoxExtent borderOutsets = style()->borderImageOutsets();
   4237 
   4238         // In flipped blocks writing modes, the physical sides are inverted. For example in vertical-rl, the right
   4239         // border is at the lower x coordinate value.
   4240         overflowMinX = min(overflowMinX, borderBox.x() - ((!isFlipped || isHorizontal) ? borderOutsets.left() : borderOutsets.right()));
   4241         overflowMaxX = max(overflowMaxX, borderBox.maxX() + ((!isFlipped || isHorizontal) ? borderOutsets.right() : borderOutsets.left()));
   4242         overflowMinY = min(overflowMinY, borderBox.y() - ((!isFlipped || !isHorizontal) ? borderOutsets.top() : borderOutsets.bottom()));
   4243         overflowMaxY = max(overflowMaxY, borderBox.maxY() + ((!isFlipped || !isHorizontal) ? borderOutsets.bottom() : borderOutsets.top()));
   4244     }
   4245 
   4246     // Add in the final overflow with shadows and outsets combined.
   4247     LayoutRect visualEffectOverflow(overflowMinX, overflowMinY, overflowMaxX - overflowMinX, overflowMaxY - overflowMinY);
   4248     addVisualOverflow(visualEffectOverflow);
   4249 }
   4250 
   4251 void RenderBox::addOverflowFromChild(RenderBox* child, const LayoutSize& delta)
   4252 {
   4253     // Never allow flow threads to propagate overflow up to a parent.
   4254     if (child->isRenderFlowThread())
   4255         return;
   4256 
   4257     // Only propagate layout overflow from the child if the child isn't clipping its overflow.  If it is, then
   4258     // its overflow is internal to it, and we don't care about it.  layoutOverflowRectForPropagation takes care of this
   4259     // and just propagates the border box rect instead.
   4260     LayoutRect childLayoutOverflowRect = child->layoutOverflowRectForPropagation(style());
   4261     childLayoutOverflowRect.move(delta);
   4262     addLayoutOverflow(childLayoutOverflowRect);
   4263 
   4264     // Add in visual overflow from the child.  Even if the child clips its overflow, it may still
   4265     // have visual overflow of its own set from box shadows or reflections.  It is unnecessary to propagate this
   4266     // overflow if we are clipping our own overflow.
   4267     if (child->hasSelfPaintingLayer())
   4268         return;
   4269     LayoutRect childVisualOverflowRect = child->visualOverflowRectForPropagation(style());
   4270     childVisualOverflowRect.move(delta);
   4271     addContentsVisualOverflow(childVisualOverflowRect);
   4272 }
   4273 
   4274 void RenderBox::addLayoutOverflow(const LayoutRect& rect)
   4275 {
   4276     LayoutRect clientBox = noOverflowRect();
   4277     if (clientBox.contains(rect) || rect.isEmpty())
   4278         return;
   4279 
   4280     // For overflow clip objects, we don't want to propagate overflow into unreachable areas.
   4281     LayoutRect overflowRect(rect);
   4282     if (hasOverflowClip() || isRenderView()) {
   4283         // Overflow is in the block's coordinate space and thus is flipped for horizontal-bt and vertical-rl
   4284         // writing modes.  At this stage that is actually a simplification, since we can treat horizontal-tb/bt as the same
   4285         // and vertical-lr/rl as the same.
   4286         bool hasTopOverflow = !style()->isLeftToRightDirection() && !isHorizontalWritingMode();
   4287         bool hasLeftOverflow = !style()->isLeftToRightDirection() && isHorizontalWritingMode();
   4288         if (isFlexibleBox() && style()->isReverseFlexDirection()) {
   4289             RenderFlexibleBox* flexibleBox = toRenderFlexibleBox(this);
   4290             if (flexibleBox->isHorizontalFlow())
   4291                 hasLeftOverflow = true;
   4292             else
   4293                 hasTopOverflow = true;
   4294         }
   4295 
   4296         if (hasColumns() && style()->columnProgression() == ReverseColumnProgression) {
   4297             if (isHorizontalWritingMode() ^ !style()->hasInlineColumnAxis())
   4298                 hasLeftOverflow = !hasLeftOverflow;
   4299             else
   4300                 hasTopOverflow = !hasTopOverflow;
   4301         }
   4302 
   4303         if (!hasTopOverflow)
   4304             overflowRect.shiftYEdgeTo(max(overflowRect.y(), clientBox.y()));
   4305         else
   4306             overflowRect.shiftMaxYEdgeTo(min(overflowRect.maxY(), clientBox.maxY()));
   4307         if (!hasLeftOverflow)
   4308             overflowRect.shiftXEdgeTo(max(overflowRect.x(), clientBox.x()));
   4309         else
   4310             overflowRect.shiftMaxXEdgeTo(min(overflowRect.maxX(), clientBox.maxX()));
   4311 
   4312         // Now re-test with the adjusted rectangle and see if it has become unreachable or fully
   4313         // contained.
   4314         if (clientBox.contains(overflowRect) || overflowRect.isEmpty())
   4315             return;
   4316     }
   4317 
   4318     if (!m_overflow)
   4319         m_overflow = adoptPtr(new RenderOverflow(clientBox, borderBoxRect()));
   4320 
   4321     m_overflow->addLayoutOverflow(overflowRect);
   4322 }
   4323 
   4324 void RenderBox::addVisualOverflow(const LayoutRect& rect)
   4325 {
   4326     LayoutRect borderBox = borderBoxRect();
   4327     if (borderBox.contains(rect) || rect.isEmpty())
   4328         return;
   4329 
   4330     if (!m_overflow)
   4331         m_overflow = adoptPtr(new RenderOverflow(noOverflowRect(), borderBox));
   4332 
   4333     m_overflow->addVisualOverflow(rect);
   4334 }
   4335 
   4336 void RenderBox::addContentsVisualOverflow(const LayoutRect& rect)
   4337 {
   4338     if (!hasOverflowClip()) {
   4339         addVisualOverflow(rect);
   4340         return;
   4341     }
   4342 
   4343     if (!m_overflow)
   4344         m_overflow = adoptPtr(new RenderOverflow(clientBoxRect(), borderBoxRect()));
   4345     m_overflow->addContentsVisualOverflow(rect);
   4346 }
   4347 
   4348 void RenderBox::clearLayoutOverflow()
   4349 {
   4350     if (!m_overflow)
   4351         return;
   4352 
   4353     if (!hasVisualOverflow() && contentsVisualOverflowRect().isEmpty()) {
   4354         m_overflow.clear();
   4355         return;
   4356     }
   4357 
   4358     m_overflow->setLayoutOverflow(noOverflowRect());
   4359 }
   4360 
   4361 inline static bool percentageLogicalHeightIsResolvable(const RenderBox* box)
   4362 {
   4363     return RenderBox::percentageLogicalHeightIsResolvableFromBlock(box->containingBlock(), box->isOutOfFlowPositioned());
   4364 }
   4365 
   4366 bool RenderBox::percentageLogicalHeightIsResolvableFromBlock(const RenderBlock* containingBlock, bool isOutOfFlowPositioned)
   4367 {
   4368     // In quirks mode, blocks with auto height are skipped, and we keep looking for an enclosing
   4369     // block that may have a specified height and then use it. In strict mode, this violates the
   4370     // specification, which states that percentage heights just revert to auto if the containing
   4371     // block has an auto height. We still skip anonymous containing blocks in both modes, though, and look
   4372     // only at explicit containers.
   4373     const RenderBlock* cb = containingBlock;
   4374     bool inQuirksMode = cb->document()->inQuirksMode();
   4375     while (!cb->isRenderView() && !cb->isBody() && !cb->isTableCell() && !cb->isOutOfFlowPositioned() && cb->style()->logicalHeight().isAuto()) {
   4376         if (!inQuirksMode && !cb->isAnonymousBlock())
   4377             break;
   4378         cb = cb->containingBlock();
   4379     }
   4380 
   4381     // A positioned element that specified both top/bottom or that specifies height should be treated as though it has a height
   4382     // explicitly specified that can be used for any percentage computations.
   4383     // FIXME: We can't just check top/bottom here.
   4384     // https://bugs.webkit.org/show_bug.cgi?id=46500
   4385     bool isOutOfFlowPositionedWithSpecifiedHeight = cb->isOutOfFlowPositioned() && (!cb->style()->logicalHeight().isAuto() || (!cb->style()->top().isAuto() && !cb->style()->bottom().isAuto()));
   4386 
   4387     // Table cells violate what the CSS spec says to do with heights.  Basically we
   4388     // don't care if the cell specified a height or not.  We just always make ourselves
   4389     // be a percentage of the cell's current content height.
   4390     if (cb->isTableCell())
   4391         return true;
   4392 
   4393     // Otherwise we only use our percentage height if our containing block had a specified
   4394     // height.
   4395     if (cb->style()->logicalHeight().isFixed())
   4396         return true;
   4397     if (cb->style()->logicalHeight().isPercent() && !isOutOfFlowPositionedWithSpecifiedHeight)
   4398         return percentageLogicalHeightIsResolvableFromBlock(cb->containingBlock(), cb->isOutOfFlowPositioned());
   4399     if (cb->isRenderView() || inQuirksMode || isOutOfFlowPositionedWithSpecifiedHeight)
   4400         return true;
   4401     if (cb->isRoot() && isOutOfFlowPositioned) {
   4402         // Match the positioned objects behavior, which is that positioned objects will fill their viewport
   4403         // always.  Note we could only hit this case by recurring into computePercentageLogicalHeight on a positioned containing block.
   4404         return true;
   4405     }
   4406 
   4407     return false;
   4408 }
   4409 
   4410 bool RenderBox::hasUnsplittableScrollingOverflow() const
   4411 {
   4412     // We will paginate as long as we don't scroll overflow in the pagination direction.
   4413     bool isHorizontal = isHorizontalWritingMode();
   4414     if ((isHorizontal && !scrollsOverflowY()) || (!isHorizontal && !scrollsOverflowX()))
   4415         return false;
   4416 
   4417     // We do have overflow. We'll still be willing to paginate as long as the block
   4418     // has auto logical height, auto or undefined max-logical-height and a zero or auto min-logical-height.
   4419     // Note this is just a heuristic, and it's still possible to have overflow under these
   4420     // conditions, but it should work out to be good enough for common cases. Paginating overflow
   4421     // with scrollbars present is not the end of the world and is what we used to do in the old model anyway.
   4422     return !style()->logicalHeight().isIntrinsicOrAuto()
   4423         || (!style()->logicalMaxHeight().isIntrinsicOrAuto() && !style()->logicalMaxHeight().isUndefined() && (!style()->logicalMaxHeight().isPercent() || percentageLogicalHeightIsResolvable(this)))
   4424         || (!style()->logicalMinHeight().isIntrinsicOrAuto() && style()->logicalMinHeight().isPositive() && (!style()->logicalMinHeight().isPercent() || percentageLogicalHeightIsResolvable(this)));
   4425 }
   4426 
   4427 bool RenderBox::isUnsplittableForPagination() const
   4428 {
   4429     return isReplaced() || hasUnsplittableScrollingOverflow() || (parent() && isWritingModeRoot());
   4430 }
   4431 
   4432 LayoutUnit RenderBox::lineHeight(bool /*firstLine*/, LineDirectionMode direction, LinePositionMode /*linePositionMode*/) const
   4433 {
   4434     if (isReplaced())
   4435         return direction == HorizontalLine ? m_marginBox.top() + height() + m_marginBox.bottom() : m_marginBox.right() + width() + m_marginBox.left();
   4436     return 0;
   4437 }
   4438 
   4439 int RenderBox::baselinePosition(FontBaseline baselineType, bool /*firstLine*/, LineDirectionMode direction, LinePositionMode linePositionMode) const
   4440 {
   4441     ASSERT(linePositionMode == PositionOnContainingLine);
   4442     if (isReplaced()) {
   4443         int result = direction == HorizontalLine ? m_marginBox.top() + height() + m_marginBox.bottom() : m_marginBox.right() + width() + m_marginBox.left();
   4444         if (baselineType == AlphabeticBaseline)
   4445             return result;
   4446         return result - result / 2;
   4447     }
   4448     return 0;
   4449 }
   4450 
   4451 
   4452 RenderLayer* RenderBox::enclosingFloatPaintingLayer() const
   4453 {
   4454     const RenderObject* curr = this;
   4455     while (curr) {
   4456         RenderLayer* layer = curr->hasLayer() && curr->isBox() ? toRenderBox(curr)->layer() : 0;
   4457         if (layer && layer->isSelfPaintingLayer())
   4458             return layer;
   4459         curr = curr->parent();
   4460     }
   4461     return 0;
   4462 }
   4463 
   4464 LayoutRect RenderBox::logicalVisualOverflowRectForPropagation(RenderStyle* parentStyle) const
   4465 {
   4466     LayoutRect rect = visualOverflowRectForPropagation(parentStyle);
   4467     if (!parentStyle->isHorizontalWritingMode())
   4468         return rect.transposedRect();
   4469     return rect;
   4470 }
   4471 
   4472 LayoutRect RenderBox::visualOverflowRectForPropagation(RenderStyle* parentStyle) const
   4473 {
   4474     // If the writing modes of the child and parent match, then we don't have to
   4475     // do anything fancy. Just return the result.
   4476     LayoutRect rect = visualOverflowRect();
   4477     if (parentStyle->writingMode() == style()->writingMode())
   4478         return rect;
   4479 
   4480     // We are putting ourselves into our parent's coordinate space.  If there is a flipped block mismatch
   4481     // in a particular axis, then we have to flip the rect along that axis.
   4482     if (style()->writingMode() == RightToLeftWritingMode || parentStyle->writingMode() == RightToLeftWritingMode)
   4483         rect.setX(width() - rect.maxX());
   4484     else if (style()->writingMode() == BottomToTopWritingMode || parentStyle->writingMode() == BottomToTopWritingMode)
   4485         rect.setY(height() - rect.maxY());
   4486 
   4487     return rect;
   4488 }
   4489 
   4490 LayoutRect RenderBox::logicalLayoutOverflowRectForPropagation(RenderStyle* parentStyle) const
   4491 {
   4492     LayoutRect rect = layoutOverflowRectForPropagation(parentStyle);
   4493     if (!parentStyle->isHorizontalWritingMode())
   4494         return rect.transposedRect();
   4495     return rect;
   4496 }
   4497 
   4498 LayoutRect RenderBox::layoutOverflowRectForPropagation(RenderStyle* parentStyle) const
   4499 {
   4500     // Only propagate interior layout overflow if we don't clip it.
   4501     LayoutRect rect = borderBoxRect();
   4502     if (!hasOverflowClip())
   4503         rect.unite(layoutOverflowRect());
   4504 
   4505     bool hasTransform = hasLayer() && layer()->transform();
   4506     if (isInFlowPositioned() || hasTransform) {
   4507         // If we are relatively positioned or if we have a transform, then we have to convert
   4508         // this rectangle into physical coordinates, apply relative positioning and transforms
   4509         // to it, and then convert it back.
   4510         flipForWritingMode(rect);
   4511 
   4512         if (hasTransform)
   4513             rect = layer()->currentTransform().mapRect(rect);
   4514 
   4515         if (isInFlowPositioned())
   4516             rect.move(offsetForInFlowPosition());
   4517 
   4518         // Now we need to flip back.
   4519         flipForWritingMode(rect);
   4520     }
   4521 
   4522     // If the writing modes of the child and parent match, then we don't have to
   4523     // do anything fancy. Just return the result.
   4524     if (parentStyle->writingMode() == style()->writingMode())
   4525         return rect;
   4526 
   4527     // We are putting ourselves into our parent's coordinate space.  If there is a flipped block mismatch
   4528     // in a particular axis, then we have to flip the rect along that axis.
   4529     if (style()->writingMode() == RightToLeftWritingMode || parentStyle->writingMode() == RightToLeftWritingMode)
   4530         rect.setX(width() - rect.maxX());
   4531     else if (style()->writingMode() == BottomToTopWritingMode || parentStyle->writingMode() == BottomToTopWritingMode)
   4532         rect.setY(height() - rect.maxY());
   4533 
   4534     return rect;
   4535 }
   4536 
   4537 LayoutRect RenderBox::noOverflowRect() const
   4538 {
   4539     // Because of the special coodinate system used for overflow rectangles and many other
   4540     // rectangles (not quite logical, not quite physical), we need to flip the block progression
   4541     // coordinate in vertical-rl and horizontal-bt writing modes. In other words, the rectangle
   4542     // returned is physical, except for the block direction progression coordinate (y in horizontal
   4543     // writing modes, x in vertical writing modes), which is always "logical top". Apart from the
   4544     // flipping, this method does the same as clientBoxRect().
   4545 
   4546     LayoutUnit left = borderLeft();
   4547     LayoutUnit top = borderTop();
   4548     LayoutUnit right = borderRight();
   4549     LayoutUnit bottom = borderBottom();
   4550     LayoutRect rect(left, top, width() - left - right, height() - top - bottom);
   4551     flipForWritingMode(rect);
   4552     // Subtract space occupied by scrollbars. Order is important here: first flip, then subtract
   4553     // scrollbars. This may seem backwards and weird, since one would think that a horizontal
   4554     // scrollbar at the physical bottom in horizontal-bt ought to be at the logical top (physical
   4555     // bottom), between the logical top (physical bottom) border and the logical top (physical
   4556     // bottom) padding. But this is how the rest of the code expects us to behave. This is highly
   4557     // related to https://bugs.webkit.org/show_bug.cgi?id=76129
   4558     // FIXME: when the above mentioned bug is fixed, it should hopefully be possible to call
   4559     // clientBoxRect() or paddingBoxRect() in this method, rather than fiddling with the edges on
   4560     // our own.
   4561     rect.contract(verticalScrollbarWidth(), horizontalScrollbarHeight());
   4562     return rect;
   4563 }
   4564 
   4565 LayoutRect RenderBox::overflowRectForPaintRejection() const
   4566 {
   4567     LayoutRect overflowRect = visualOverflowRect();
   4568     if (!m_overflow || !usesCompositedScrolling())
   4569         return overflowRect;
   4570 
   4571     overflowRect.unite(layoutOverflowRect());
   4572     overflowRect.move(-scrolledContentOffset());
   4573     return overflowRect;
   4574 }
   4575 
   4576 LayoutUnit RenderBox::offsetLeft() const
   4577 {
   4578     return adjustedPositionRelativeToOffsetParent(topLeftLocation()).x();
   4579 }
   4580 
   4581 LayoutUnit RenderBox::offsetTop() const
   4582 {
   4583     return adjustedPositionRelativeToOffsetParent(topLeftLocation()).y();
   4584 }
   4585 
   4586 LayoutPoint RenderBox::flipForWritingModeForChild(const RenderBox* child, const LayoutPoint& point) const
   4587 {
   4588     if (!style()->isFlippedBlocksWritingMode())
   4589         return point;
   4590 
   4591     // The child is going to add in its x() and y(), so we have to make sure it ends up in
   4592     // the right place.
   4593     if (isHorizontalWritingMode())
   4594         return LayoutPoint(point.x(), point.y() + height() - child->height() - (2 * child->y()));
   4595     return LayoutPoint(point.x() + width() - child->width() - (2 * child->x()), point.y());
   4596 }
   4597 
   4598 void RenderBox::flipForWritingMode(LayoutRect& rect) const
   4599 {
   4600     if (!style()->isFlippedBlocksWritingMode())
   4601         return;
   4602 
   4603     if (isHorizontalWritingMode())
   4604         rect.setY(height() - rect.maxY());
   4605     else
   4606         rect.setX(width() - rect.maxX());
   4607 }
   4608 
   4609 LayoutUnit RenderBox::flipForWritingMode(LayoutUnit position) const
   4610 {
   4611     if (!style()->isFlippedBlocksWritingMode())
   4612         return position;
   4613     return logicalHeight() - position;
   4614 }
   4615 
   4616 LayoutPoint RenderBox::flipForWritingMode(const LayoutPoint& position) const
   4617 {
   4618     if (!style()->isFlippedBlocksWritingMode())
   4619         return position;
   4620     return isHorizontalWritingMode() ? LayoutPoint(position.x(), height() - position.y()) : LayoutPoint(width() - position.x(), position.y());
   4621 }
   4622 
   4623 LayoutPoint RenderBox::flipForWritingModeIncludingColumns(const LayoutPoint& point) const
   4624 {
   4625     if (!hasColumns() || !style()->isFlippedBlocksWritingMode())
   4626         return flipForWritingMode(point);
   4627     return toRenderBlock(this)->flipForWritingModeIncludingColumns(point);
   4628 }
   4629 
   4630 LayoutSize RenderBox::flipForWritingMode(const LayoutSize& offset) const
   4631 {
   4632     if (!style()->isFlippedBlocksWritingMode())
   4633         return offset;
   4634     return isHorizontalWritingMode() ? LayoutSize(offset.width(), height() - offset.height()) : LayoutSize(width() - offset.width(), offset.height());
   4635 }
   4636 
   4637 FloatPoint RenderBox::flipForWritingMode(const FloatPoint& position) const
   4638 {
   4639     if (!style()->isFlippedBlocksWritingMode())
   4640         return position;
   4641     return isHorizontalWritingMode() ? FloatPoint(position.x(), height() - position.y()) : FloatPoint(width() - position.x(), position.y());
   4642 }
   4643 
   4644 void RenderBox::flipForWritingMode(FloatRect& rect) const
   4645 {
   4646     if (!style()->isFlippedBlocksWritingMode())
   4647         return;
   4648 
   4649     if (isHorizontalWritingMode())
   4650         rect.setY(height() - rect.maxY());
   4651     else
   4652         rect.setX(width() - rect.maxX());
   4653 }
   4654 
   4655 LayoutPoint RenderBox::topLeftLocation() const
   4656 {
   4657     RenderBlock* containerBlock = containingBlock();
   4658     if (!containerBlock || containerBlock == this)
   4659         return location();
   4660     return containerBlock->flipForWritingModeForChild(this, location());
   4661 }
   4662 
   4663 LayoutSize RenderBox::topLeftLocationOffset() const
   4664 {
   4665     RenderBlock* containerBlock = containingBlock();
   4666     if (!containerBlock || containerBlock == this)
   4667         return locationOffset();
   4668 
   4669     LayoutRect rect(frameRect());
   4670     containerBlock->flipForWritingMode(rect); // FIXME: This is wrong if we are an absolutely positioned object enclosed by a relative-positioned inline.
   4671     return LayoutSize(rect.x(), rect.y());
   4672 }
   4673 
   4674 bool RenderBox::hasRelativeDimensions() const
   4675 {
   4676     // FIXME: This should probably include viewport percentage heights as well.
   4677     return style()->height().isPercent() || style()->width().isPercent()
   4678         || style()->maxHeight().isPercent() || style()->maxWidth().isPercent()
   4679         || style()->minHeight().isPercent() || style()->minWidth().isPercent();
   4680 }
   4681 
   4682 bool RenderBox::hasRelativeLogicalHeight() const
   4683 {
   4684     return style()->logicalHeight().isPercent()
   4685         || style()->logicalMinHeight().isPercent()
   4686         || style()->logicalMaxHeight().isPercent()
   4687         || style()->logicalHeight().isViewportPercentage()
   4688         || style()->logicalMinHeight().isViewportPercentage()
   4689         || style()->logicalMaxHeight().isViewportPercentage();
   4690 }
   4691 
   4692 static void markBoxForRelayoutAfterSplit(RenderBox* box)
   4693 {
   4694     // FIXME: The table code should handle that automatically. If not,
   4695     // we should fix it and remove the table part checks.
   4696     if (box->isTable()) {
   4697         // Because we may have added some sections with already computed column structures, we need to
   4698         // sync the table structure with them now. This avoids crashes when adding new cells to the table.
   4699         toRenderTable(box)->forceSectionsRecalc();
   4700     } else if (box->isTableSection())
   4701         toRenderTableSection(box)->setNeedsCellRecalc();
   4702 
   4703     box->setNeedsLayoutAndPrefWidthsRecalc();
   4704 }
   4705 
   4706 RenderObject* RenderBox::splitAnonymousBoxesAroundChild(RenderObject* beforeChild)
   4707 {
   4708     bool didSplitParentAnonymousBoxes = false;
   4709 
   4710     while (beforeChild->parent() != this) {
   4711         RenderBox* boxToSplit = toRenderBox(beforeChild->parent());
   4712         if (boxToSplit->firstChild() != beforeChild && boxToSplit->isAnonymous()) {
   4713             didSplitParentAnonymousBoxes = true;
   4714 
   4715             // We have to split the parent box into two boxes and move children
   4716             // from |beforeChild| to end into the new post box.
   4717             RenderBox* postBox = boxToSplit->createAnonymousBoxWithSameTypeAs(this);
   4718             postBox->setChildrenInline(boxToSplit->childrenInline());
   4719             RenderBox* parentBox = toRenderBox(boxToSplit->parent());
   4720             // We need to invalidate the |parentBox| before inserting the new node
   4721             // so that the table repainting logic knows the structure is dirty.
   4722             // See for example RenderTableCell:clippedOverflowRectForRepaint.
   4723             markBoxForRelayoutAfterSplit(parentBox);
   4724             parentBox->virtualChildren()->insertChildNode(parentBox, postBox, boxToSplit->nextSibling());
   4725             boxToSplit->moveChildrenTo(postBox, beforeChild, 0, true);
   4726 
   4727             markBoxForRelayoutAfterSplit(boxToSplit);
   4728             markBoxForRelayoutAfterSplit(postBox);
   4729 
   4730             beforeChild = postBox;
   4731         } else
   4732             beforeChild = boxToSplit;
   4733     }
   4734 
   4735     if (didSplitParentAnonymousBoxes)
   4736         markBoxForRelayoutAfterSplit(this);
   4737 
   4738     ASSERT(beforeChild->parent() == this);
   4739     return beforeChild;
   4740 }
   4741 
   4742 } // namespace WebCore
   4743