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  *
      8  * This library is free software; you can redistribute it and/or
      9  * modify it under the terms of the GNU Library General Public
     10  * License as published by the Free Software Foundation; either
     11  * version 2 of the License, or (at your option) any later version.
     12  *
     13  * This library is distributed in the hope that it will be useful,
     14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     16  * Library General Public License for more details.
     17  *
     18  * You should have received a copy of the GNU Library General Public License
     19  * along with this library; see the file COPYING.LIB.  If not, write to
     20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     21  * Boston, MA 02110-1301, USA.
     22  *
     23  */
     24 
     25 #include "config.h"
     26 #include "RenderBox.h"
     27 
     28 #include "CachedImage.h"
     29 #include "Chrome.h"
     30 #include "ChromeClient.h"
     31 #include "Document.h"
     32 #include "FrameView.h"
     33 #include "GraphicsContext.h"
     34 #include "HitTestResult.h"
     35 #include "htmlediting.h"
     36 #include "HTMLElement.h"
     37 #include "HTMLNames.h"
     38 #include "ImageBuffer.h"
     39 #include "FloatQuad.h"
     40 #include "Frame.h"
     41 #include "Page.h"
     42 #include "PaintInfo.h"
     43 #include "RenderArena.h"
     44 #include "RenderFlexibleBox.h"
     45 #include "RenderInline.h"
     46 #include "RenderLayer.h"
     47 #include "RenderTableCell.h"
     48 #include "RenderTheme.h"
     49 #ifdef ANDROID_LAYOUT
     50 #include "Settings.h"
     51 #endif
     52 #include "RenderView.h"
     53 #include "ScrollbarTheme.h"
     54 #include "TransformState.h"
     55 #include <algorithm>
     56 #include <math.h>
     57 
     58 #if ENABLE(WML)
     59 #include "WMLNames.h"
     60 #endif
     61 
     62 #if PLATFORM(ANDROID)
     63 #include "PlatformBridge.h"
     64 #endif
     65 
     66 using namespace std;
     67 
     68 namespace WebCore {
     69 
     70 using namespace HTMLNames;
     71 
     72 // Used by flexible boxes when flexing this element.
     73 typedef WTF::HashMap<const RenderBox*, int> OverrideSizeMap;
     74 static OverrideSizeMap* gOverrideSizeMap = 0;
     75 
     76 bool RenderBox::s_hadOverflowClip = false;
     77 
     78 RenderBox::RenderBox(Node* node)
     79     : RenderBoxModelObject(node)
     80     , m_marginLeft(0)
     81     , m_marginRight(0)
     82     , m_marginTop(0)
     83     , m_marginBottom(0)
     84     , m_minPreferredLogicalWidth(-1)
     85     , m_maxPreferredLogicalWidth(-1)
     86     , m_inlineBoxWrapper(0)
     87 #ifdef ANDROID_LAYOUT
     88     , m_visibleWidth(0)
     89     , m_isVisibleWidthChangedBeforeLayout(false)
     90 #endif
     91 {
     92     setIsBox();
     93 }
     94 
     95 RenderBox::~RenderBox()
     96 {
     97 }
     98 
     99 int RenderBox::marginBefore() const
    100 {
    101     switch (style()->writingMode()) {
    102     case TopToBottomWritingMode:
    103         return m_marginTop;
    104     case BottomToTopWritingMode:
    105         return m_marginBottom;
    106     case LeftToRightWritingMode:
    107         return m_marginLeft;
    108     case RightToLeftWritingMode:
    109         return m_marginRight;
    110     }
    111     ASSERT_NOT_REACHED();
    112     return m_marginTop;
    113 }
    114 
    115 int RenderBox::marginAfter() const
    116 {
    117     switch (style()->writingMode()) {
    118     case TopToBottomWritingMode:
    119         return m_marginBottom;
    120     case BottomToTopWritingMode:
    121         return m_marginTop;
    122     case LeftToRightWritingMode:
    123         return m_marginRight;
    124     case RightToLeftWritingMode:
    125         return m_marginLeft;
    126     }
    127     ASSERT_NOT_REACHED();
    128     return m_marginBottom;
    129 }
    130 
    131 int RenderBox::marginStart() const
    132 {
    133     if (isHorizontalWritingMode())
    134         return style()->isLeftToRightDirection() ? m_marginLeft : m_marginRight;
    135     return style()->isLeftToRightDirection() ? m_marginTop : m_marginBottom;
    136 }
    137 
    138 int RenderBox::marginEnd() const
    139 {
    140     if (isHorizontalWritingMode())
    141         return style()->isLeftToRightDirection() ? m_marginRight : m_marginLeft;
    142     return style()->isLeftToRightDirection() ? m_marginBottom : m_marginTop;
    143 }
    144 
    145 void RenderBox::setMarginStart(int margin)
    146 {
    147     if (isHorizontalWritingMode()) {
    148         if (style()->isLeftToRightDirection())
    149             m_marginLeft = margin;
    150         else
    151             m_marginRight = margin;
    152     } else {
    153         if (style()->isLeftToRightDirection())
    154             m_marginTop = margin;
    155         else
    156             m_marginBottom = margin;
    157     }
    158 }
    159 
    160 void RenderBox::setMarginEnd(int margin)
    161 {
    162     if (isHorizontalWritingMode()) {
    163         if (style()->isLeftToRightDirection())
    164             m_marginRight = margin;
    165         else
    166             m_marginLeft = margin;
    167     } else {
    168         if (style()->isLeftToRightDirection())
    169             m_marginBottom = margin;
    170         else
    171             m_marginTop = margin;
    172     }
    173 }
    174 
    175 void RenderBox::setMarginBefore(int margin)
    176 {
    177     switch (style()->writingMode()) {
    178     case TopToBottomWritingMode:
    179         m_marginTop = margin;
    180         break;
    181     case BottomToTopWritingMode:
    182         m_marginBottom = margin;
    183         break;
    184     case LeftToRightWritingMode:
    185         m_marginLeft = margin;
    186         break;
    187     case RightToLeftWritingMode:
    188         m_marginRight = margin;
    189         break;
    190     }
    191 }
    192 
    193 void RenderBox::setMarginAfter(int margin)
    194 {
    195     switch (style()->writingMode()) {
    196     case TopToBottomWritingMode:
    197         m_marginBottom = margin;
    198         break;
    199     case BottomToTopWritingMode:
    200         m_marginTop = margin;
    201         break;
    202     case LeftToRightWritingMode:
    203         m_marginRight = margin;
    204         break;
    205     case RightToLeftWritingMode:
    206         m_marginLeft = margin;
    207         break;
    208     }
    209 }
    210 
    211 void RenderBox::destroy()
    212 {
    213     // A lot of the code in this function is just pasted into
    214     // RenderWidget::destroy. If anything in this function changes,
    215     // be sure to fix RenderWidget::destroy() as well.
    216     if (hasOverrideSize())
    217         gOverrideSizeMap->remove(this);
    218 
    219     if (style() && (style()->logicalHeight().isPercent() || style()->logicalMinHeight().isPercent() || style()->logicalMaxHeight().isPercent()))
    220         RenderBlock::removePercentHeightDescendant(this);
    221 
    222     RenderBoxModelObject::destroy();
    223 }
    224 
    225 void RenderBox::removeFloatingOrPositionedChildFromBlockLists()
    226 {
    227     ASSERT(isFloatingOrPositioned());
    228 
    229     if (documentBeingDestroyed())
    230         return;
    231 
    232     if (isFloating()) {
    233         RenderBlock* parentBlock = 0;
    234         for (RenderObject* curr = parent(); curr && !curr->isRenderView(); curr = curr->parent()) {
    235             if (curr->isRenderBlock()) {
    236                 RenderBlock* currBlock = toRenderBlock(curr);
    237                 if (!parentBlock || currBlock->containsFloat(this))
    238                     parentBlock = currBlock;
    239             }
    240         }
    241 
    242         if (parentBlock) {
    243             RenderObject* parent = parentBlock->parent();
    244             if (parent && parent->isFlexibleBox())
    245                 parentBlock = toRenderBlock(parent);
    246 
    247             parentBlock->markAllDescendantsWithFloatsForLayout(this, false);
    248         }
    249     }
    250 
    251     if (isPositioned()) {
    252         for (RenderObject* curr = parent(); curr; curr = curr->parent()) {
    253             if (curr->isRenderBlock())
    254                 toRenderBlock(curr)->removePositionedObject(this);
    255         }
    256     }
    257 }
    258 
    259 void RenderBox::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
    260 {
    261     s_hadOverflowClip = hasOverflowClip();
    262 
    263     if (style()) {
    264         // The background of the root element or the body element could propagate up to
    265         // the canvas.  Just dirty the entire canvas when our style changes substantially.
    266         if (diff >= StyleDifferenceRepaint && node() &&
    267                 (node()->hasTagName(htmlTag) || node()->hasTagName(bodyTag)))
    268             view()->repaint();
    269 
    270         // When a layout hint happens and an object's position style changes, we have to do a layout
    271         // to dirty the render tree using the old position value now.
    272         if (diff == StyleDifferenceLayout && parent() && style()->position() != newStyle->position()) {
    273             markContainingBlocksForLayout();
    274             if (style()->position() == StaticPosition)
    275                 repaint();
    276             else if (newStyle->position() == AbsolutePosition || newStyle->position() == FixedPosition)
    277                 parent()->setChildNeedsLayout(true);
    278             if (isFloating() && !isPositioned() && (newStyle->position() == AbsolutePosition || newStyle->position() == FixedPosition))
    279                 removeFloatingOrPositionedChildFromBlockLists();
    280         }
    281     } else if (newStyle && isBody())
    282         view()->repaint();
    283 
    284     if (FrameView *frameView = view()->frameView()) {
    285         bool newStyleIsFixed = newStyle && newStyle->position() == FixedPosition;
    286         bool oldStyleIsFixed = style() && style()->position() == FixedPosition;
    287         if (newStyleIsFixed != oldStyleIsFixed) {
    288             if (newStyleIsFixed)
    289                 frameView->addFixedObject();
    290             else
    291                 frameView->removeFixedObject();
    292         }
    293     }
    294 
    295     RenderBoxModelObject::styleWillChange(diff, newStyle);
    296 }
    297 
    298 void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
    299 {
    300     RenderBoxModelObject::styleDidChange(diff, oldStyle);
    301 
    302     if (needsLayout() && oldStyle) {
    303         if (oldStyle && (oldStyle->logicalHeight().isPercent() || oldStyle->logicalMinHeight().isPercent() || oldStyle->logicalMaxHeight().isPercent()))
    304             RenderBlock::removePercentHeightDescendant(this);
    305 
    306         // Normally we can do optimized positioning layout for absolute/fixed positioned objects. There is one special case, however, which is
    307         // 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
    308         // to determine the new static position.
    309         if (isPositioned() && style()->hasStaticBlockPosition(isHorizontalWritingMode()) && oldStyle->marginBefore() != style()->marginBefore()
    310             && parent() && !parent()->normalChildNeedsLayout())
    311             parent()->setChildNeedsLayout(true);
    312     }
    313 
    314     // If our zoom factor changes and we have a defined scrollLeft/Top, we need to adjust that value into the
    315     // new zoomed coordinate space.
    316     if (hasOverflowClip() && oldStyle && style() && oldStyle->effectiveZoom() != style()->effectiveZoom()) {
    317         if (int left = layer()->scrollXOffset()) {
    318             left = (left / oldStyle->effectiveZoom()) * style()->effectiveZoom();
    319             layer()->scrollToXOffset(left);
    320         }
    321         if (int top = layer()->scrollYOffset()) {
    322             top = (top / oldStyle->effectiveZoom()) * style()->effectiveZoom();
    323             layer()->scrollToYOffset(top);
    324         }
    325     }
    326 
    327     bool isBodyRenderer = isBody();
    328     bool isRootRenderer = isRoot();
    329 
    330     // Set the text color if we're the body.
    331     if (isBodyRenderer)
    332         document()->setTextColor(style()->visitedDependentColor(CSSPropertyColor));
    333 
    334     if (isRootRenderer || isBodyRenderer) {
    335         // Propagate the new writing mode and direction up to the RenderView.
    336         RenderView* viewRenderer = view();
    337         RenderStyle* viewStyle = viewRenderer->style();
    338         if (viewStyle->direction() != style()->direction() && (isRootRenderer || !document()->directionSetOnDocumentElement())) {
    339             viewStyle->setDirection(style()->direction());
    340             if (isBodyRenderer)
    341                 document()->documentElement()->renderer()->style()->setDirection(style()->direction());
    342             setNeedsLayoutAndPrefWidthsRecalc();
    343         }
    344 
    345         if (viewStyle->writingMode() != style()->writingMode() && (isRootRenderer || !document()->writingModeSetOnDocumentElement())) {
    346             viewStyle->setWritingMode(style()->writingMode());
    347             viewRenderer->setHorizontalWritingMode(style()->isHorizontalWritingMode());
    348             if (isBodyRenderer) {
    349                 document()->documentElement()->renderer()->style()->setWritingMode(style()->writingMode());
    350                 document()->documentElement()->renderer()->setHorizontalWritingMode(style()->isHorizontalWritingMode());
    351             }
    352             setNeedsLayoutAndPrefWidthsRecalc();
    353         }
    354     }
    355 }
    356 
    357 void RenderBox::updateBoxModelInfoFromStyle()
    358 {
    359     RenderBoxModelObject::updateBoxModelInfoFromStyle();
    360 
    361     bool isRootObject = isRoot();
    362     bool isViewObject = isRenderView();
    363 
    364     // The root and the RenderView always paint their backgrounds/borders.
    365     if (isRootObject || isViewObject)
    366         setHasBoxDecorations(true);
    367 
    368     setPositioned(style()->position() == AbsolutePosition || style()->position() == FixedPosition);
    369     setFloating(!isPositioned() && style()->isFloating());
    370 
    371     // We also handle <body> and <html>, whose overflow applies to the viewport.
    372     if (style()->overflowX() != OVISIBLE && !isRootObject && (isRenderBlock() || isTableRow() || isTableSection())) {
    373         bool boxHasOverflowClip = true;
    374         if (isBody()) {
    375             // Overflow on the body can propagate to the viewport under the following conditions.
    376             // (1) The root element is <html>.
    377             // (2) We are the primary <body> (can be checked by looking at document.body).
    378             // (3) The root element has visible overflow.
    379             if (document()->documentElement()->hasTagName(htmlTag) &&
    380                 document()->body() == node() &&
    381                 document()->documentElement()->renderer()->style()->overflowX() == OVISIBLE)
    382                 boxHasOverflowClip = false;
    383         }
    384 
    385         // Check for overflow clip.
    386         // It's sufficient to just check one direction, since it's illegal to have visible on only one overflow value.
    387         if (boxHasOverflowClip) {
    388             if (!s_hadOverflowClip)
    389                 // Erase the overflow
    390                 repaint();
    391             setHasOverflowClip();
    392         }
    393     }
    394 
    395     setHasTransform(style()->hasTransformRelatedProperty());
    396     setHasReflection(style()->boxReflect());
    397 }
    398 
    399 void RenderBox::layout()
    400 {
    401     ASSERT(needsLayout());
    402 
    403     RenderObject* child = firstChild();
    404     if (!child) {
    405         setNeedsLayout(false);
    406         return;
    407     }
    408 
    409     LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), style()->isFlippedBlocksWritingMode());
    410     while (child) {
    411         child->layoutIfNeeded();
    412         ASSERT(!child->needsLayout());
    413         child = child->nextSibling();
    414     }
    415     statePusher.pop();
    416     setNeedsLayout(false);
    417 }
    418 
    419 // More IE extensions.  clientWidth and clientHeight represent the interior of an object
    420 // excluding border and scrollbar.
    421 int RenderBox::clientWidth() const
    422 {
    423     return width() - borderLeft() - borderRight() - verticalScrollbarWidth();
    424 }
    425 
    426 int RenderBox::clientHeight() const
    427 {
    428     return height() - borderTop() - borderBottom() - horizontalScrollbarHeight();
    429 }
    430 
    431 int RenderBox::scrollWidth() const
    432 {
    433     if (hasOverflowClip())
    434         return layer()->scrollWidth();
    435     // For objects with visible overflow, this matches IE.
    436     // FIXME: Need to work right with writing modes.
    437     if (style()->isLeftToRightDirection())
    438         return max(clientWidth(), maxXLayoutOverflow() - borderLeft());
    439     return clientWidth() - min(0, minXLayoutOverflow() - borderLeft());
    440 }
    441 
    442 int RenderBox::scrollHeight() const
    443 {
    444     if (hasOverflowClip())
    445         return layer()->scrollHeight();
    446     // For objects with visible overflow, this matches IE.
    447     // FIXME: Need to work right with writing modes.
    448     return max(clientHeight(), maxYLayoutOverflow() - borderTop());
    449 }
    450 
    451 int RenderBox::scrollLeft() const
    452 {
    453     return hasOverflowClip() ? layer()->scrollXOffset() : 0;
    454 }
    455 
    456 int RenderBox::scrollTop() const
    457 {
    458     return hasOverflowClip() ? layer()->scrollYOffset() : 0;
    459 }
    460 
    461 void RenderBox::setScrollLeft(int newLeft)
    462 {
    463     if (hasOverflowClip())
    464         layer()->scrollToXOffset(newLeft);
    465 }
    466 
    467 void RenderBox::setScrollTop(int newTop)
    468 {
    469     if (hasOverflowClip())
    470         layer()->scrollToYOffset(newTop);
    471 }
    472 
    473 void RenderBox::absoluteRects(Vector<IntRect>& rects, int tx, int ty)
    474 {
    475     rects.append(IntRect(tx, ty, width(), height()));
    476 }
    477 
    478 void RenderBox::absoluteQuads(Vector<FloatQuad>& quads)
    479 {
    480     quads.append(localToAbsoluteQuad(FloatRect(0, 0, width(), height())));
    481 }
    482 
    483 void RenderBox::updateLayerTransform()
    484 {
    485     // Transform-origin depends on box size, so we need to update the layer transform after layout.
    486     if (hasLayer())
    487         layer()->updateTransform();
    488 }
    489 
    490 IntRect RenderBox::absoluteContentBox() const
    491 {
    492     IntRect rect = contentBoxRect();
    493     FloatPoint absPos = localToAbsolute(FloatPoint());
    494     rect.move(absPos.x(), absPos.y());
    495     return rect;
    496 }
    497 
    498 FloatQuad RenderBox::absoluteContentQuad() const
    499 {
    500     IntRect rect = contentBoxRect();
    501     return localToAbsoluteQuad(FloatRect(rect));
    502 }
    503 
    504 IntRect RenderBox::outlineBoundsForRepaint(RenderBoxModelObject* repaintContainer, IntPoint* cachedOffsetToRepaintContainer) const
    505 {
    506     IntRect box = borderBoundingBox();
    507     adjustRectForOutlineAndShadow(box);
    508 
    509     FloatQuad containerRelativeQuad = FloatRect(box);
    510     if (cachedOffsetToRepaintContainer)
    511         containerRelativeQuad.move(cachedOffsetToRepaintContainer->x(), cachedOffsetToRepaintContainer->y());
    512     else
    513         containerRelativeQuad = localToContainerQuad(containerRelativeQuad, repaintContainer);
    514 
    515     box = containerRelativeQuad.enclosingBoundingBox();
    516 
    517     // FIXME: layoutDelta needs to be applied in parts before/after transforms and
    518     // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
    519     box.move(view()->layoutDelta());
    520 
    521     return box;
    522 }
    523 
    524 void RenderBox::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty)
    525 {
    526     if (width() && height())
    527         rects.append(IntRect(tx, ty, width(), height()));
    528 }
    529 
    530 IntRect RenderBox::reflectionBox() const
    531 {
    532     IntRect result;
    533     if (!style()->boxReflect())
    534         return result;
    535     IntRect box = borderBoxRect();
    536     result = box;
    537     switch (style()->boxReflect()->direction()) {
    538         case ReflectionBelow:
    539             result.move(0, box.height() + reflectionOffset());
    540             break;
    541         case ReflectionAbove:
    542             result.move(0, -box.height() - reflectionOffset());
    543             break;
    544         case ReflectionLeft:
    545             result.move(-box.width() - reflectionOffset(), 0);
    546             break;
    547         case ReflectionRight:
    548             result.move(box.width() + reflectionOffset(), 0);
    549             break;
    550     }
    551     return result;
    552 }
    553 
    554 int RenderBox::reflectionOffset() const
    555 {
    556     if (!style()->boxReflect())
    557         return 0;
    558     if (style()->boxReflect()->direction() == ReflectionLeft || style()->boxReflect()->direction() == ReflectionRight)
    559         return style()->boxReflect()->offset().calcValue(borderBoxRect().width());
    560     return style()->boxReflect()->offset().calcValue(borderBoxRect().height());
    561 }
    562 
    563 IntRect RenderBox::reflectedRect(const IntRect& r) const
    564 {
    565     if (!style()->boxReflect())
    566         return IntRect();
    567 
    568     IntRect box = borderBoxRect();
    569     IntRect result = r;
    570     switch (style()->boxReflect()->direction()) {
    571         case ReflectionBelow:
    572             result.setY(box.maxY() + reflectionOffset() + (box.maxY() - r.maxY()));
    573             break;
    574         case ReflectionAbove:
    575             result.setY(box.y() - reflectionOffset() - box.height() + (box.maxY() - r.maxY()));
    576             break;
    577         case ReflectionLeft:
    578             result.setX(box.x() - reflectionOffset() - box.width() + (box.maxX() - r.maxX()));
    579             break;
    580         case ReflectionRight:
    581             result.setX(box.maxX() + reflectionOffset() + (box.maxX() - r.maxX()));
    582             break;
    583     }
    584     return result;
    585 }
    586 
    587 bool RenderBox::includeVerticalScrollbarSize() const
    588 {
    589     return hasOverflowClip() && !layer()->hasOverlayScrollbars()
    590         && (style()->overflowY() == OSCROLL || style()->overflowY() == OAUTO);
    591 }
    592 
    593 bool RenderBox::includeHorizontalScrollbarSize() const
    594 {
    595     return hasOverflowClip() && !layer()->hasOverlayScrollbars()
    596         && (style()->overflowX() == OSCROLL || style()->overflowX() == OAUTO);
    597 }
    598 
    599 int RenderBox::verticalScrollbarWidth() const
    600 {
    601     return includeVerticalScrollbarSize() ? layer()->verticalScrollbarWidth() : 0;
    602 }
    603 
    604 int RenderBox::horizontalScrollbarHeight() const
    605 {
    606     return includeHorizontalScrollbarSize() ? layer()->horizontalScrollbarHeight() : 0;
    607 }
    608 
    609 bool RenderBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
    610 {
    611     RenderLayer* l = layer();
    612     if (l && l->scroll(direction, granularity, multiplier)) {
    613         if (stopNode)
    614             *stopNode = node();
    615         return true;
    616     }
    617 
    618     if (stopNode && *stopNode && *stopNode == node())
    619         return true;
    620 
    621     RenderBlock* b = containingBlock();
    622     if (b && !b->isRenderView())
    623         return b->scroll(direction, granularity, multiplier, stopNode);
    624     return false;
    625 }
    626 
    627 bool RenderBox::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
    628 {
    629     bool scrolled = false;
    630 
    631     RenderLayer* l = layer();
    632     if (l) {
    633 #if PLATFORM(MAC)
    634         // On Mac only we reset the inline direction position when doing a document scroll (e.g., hitting Home/End).
    635         if (granularity == ScrollByDocument)
    636             scrolled = l->scroll(logicalToPhysical(ScrollInlineDirectionBackward, isHorizontalWritingMode(), style()->isFlippedBlocksWritingMode()), ScrollByDocument, multiplier);
    637 #endif
    638         if (l->scroll(logicalToPhysical(direction, isHorizontalWritingMode(), style()->isFlippedBlocksWritingMode()), granularity, multiplier))
    639             scrolled = true;
    640 
    641         if (scrolled) {
    642             if (stopNode)
    643                 *stopNode = node();
    644             return true;
    645         }
    646     }
    647 
    648     if (stopNode && *stopNode && *stopNode == node())
    649         return true;
    650 
    651     RenderBlock* b = containingBlock();
    652     if (b && !b->isRenderView())
    653         return b->logicalScroll(direction, granularity, multiplier, stopNode);
    654     return false;
    655 }
    656 
    657 bool RenderBox::canBeScrolledAndHasScrollableArea() const
    658 {
    659     return canBeProgramaticallyScrolled(false) && (scrollHeight() != clientHeight() || scrollWidth() != clientWidth());
    660 }
    661 
    662 bool RenderBox::canBeProgramaticallyScrolled(bool) const
    663 {
    664     return (hasOverflowClip() && (scrollsOverflow() || (node() && node()->rendererIsEditable()))) || (node() && node()->isDocumentNode());
    665 }
    666 
    667 void RenderBox::autoscroll()
    668 {
    669     if (layer())
    670         layer()->autoscroll();
    671 }
    672 
    673 void RenderBox::panScroll(const IntPoint& source)
    674 {
    675     if (layer())
    676         layer()->panScrollFromPoint(source);
    677 }
    678 
    679 int RenderBox::minPreferredLogicalWidth() const
    680 {
    681     if (preferredLogicalWidthsDirty())
    682         const_cast<RenderBox*>(this)->computePreferredLogicalWidths();
    683 
    684     return m_minPreferredLogicalWidth;
    685 }
    686 
    687 int RenderBox::maxPreferredLogicalWidth() const
    688 {
    689     if (preferredLogicalWidthsDirty())
    690         const_cast<RenderBox*>(this)->computePreferredLogicalWidths();
    691 
    692     return m_maxPreferredLogicalWidth;
    693 }
    694 
    695 int RenderBox::overrideSize() const
    696 {
    697     if (!hasOverrideSize())
    698         return -1;
    699     return gOverrideSizeMap->get(this);
    700 }
    701 
    702 void RenderBox::setOverrideSize(int s)
    703 {
    704     if (s == -1) {
    705         if (hasOverrideSize()) {
    706             setHasOverrideSize(false);
    707             gOverrideSizeMap->remove(this);
    708         }
    709     } else {
    710         if (!gOverrideSizeMap)
    711             gOverrideSizeMap = new OverrideSizeMap();
    712         setHasOverrideSize(true);
    713         gOverrideSizeMap->set(this, s);
    714     }
    715 }
    716 
    717 int RenderBox::overrideWidth() const
    718 {
    719     return hasOverrideSize() ? overrideSize() : width();
    720 }
    721 
    722 int RenderBox::overrideHeight() const
    723 {
    724     return hasOverrideSize() ? overrideSize() : height();
    725 }
    726 
    727 int RenderBox::computeBorderBoxLogicalWidth(int width) const
    728 {
    729     int bordersPlusPadding = borderAndPaddingLogicalWidth();
    730     if (style()->boxSizing() == CONTENT_BOX)
    731         return width + bordersPlusPadding;
    732     return max(width, bordersPlusPadding);
    733 }
    734 
    735 int RenderBox::computeBorderBoxLogicalHeight(int height) const
    736 {
    737     int bordersPlusPadding = borderAndPaddingLogicalHeight();
    738     if (style()->boxSizing() == CONTENT_BOX)
    739         return height + bordersPlusPadding;
    740     return max(height, bordersPlusPadding);
    741 }
    742 
    743 int RenderBox::computeContentBoxLogicalWidth(int width) const
    744 {
    745     if (style()->boxSizing() == BORDER_BOX)
    746         width -= borderAndPaddingLogicalWidth();
    747     return max(0, width);
    748 }
    749 
    750 int RenderBox::computeContentBoxLogicalHeight(int height) const
    751 {
    752     if (style()->boxSizing() == BORDER_BOX)
    753         height -= borderAndPaddingLogicalHeight();
    754     return max(0, height);
    755 }
    756 
    757 // Hit Testing
    758 bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int xPos, int yPos, int tx, int ty, HitTestAction action)
    759 {
    760     tx += x();
    761     ty += y();
    762 
    763     // Check kids first.
    764     for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
    765         if (!child->hasLayer() && child->nodeAtPoint(request, result, xPos, yPos, tx, ty, action)) {
    766             updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty));
    767             return true;
    768         }
    769     }
    770 
    771     // Check our bounds next. For this purpose always assume that we can only be hit in the
    772     // foreground phase (which is true for replaced elements like images).
    773     IntRect boundsRect = IntRect(tx, ty, width(), height());
    774     if (visibleToHitTesting() && action == HitTestForeground && boundsRect.intersects(result.rectForPoint(xPos, yPos))) {
    775         updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty));
    776         if (!result.addNodeToRectBasedTestResult(node(), xPos, yPos, boundsRect))
    777             return true;
    778     }
    779 
    780     return false;
    781 }
    782 
    783 // --------------------- painting stuff -------------------------------
    784 
    785 void RenderBox::paint(PaintInfo& paintInfo, int tx, int ty)
    786 {
    787     tx += x();
    788     ty += y();
    789 
    790     // default implementation. Just pass paint through to the children
    791     PaintInfo childInfo(paintInfo);
    792     childInfo.updatePaintingRootForChildren(this);
    793     for (RenderObject* child = firstChild(); child; child = child->nextSibling())
    794         child->paint(childInfo, tx, ty);
    795 }
    796 
    797 void RenderBox::paintRootBoxFillLayers(const PaintInfo& paintInfo)
    798 {
    799     const FillLayer* bgLayer = style()->backgroundLayers();
    800     Color bgColor = style()->visitedDependentColor(CSSPropertyBackgroundColor);
    801     RenderObject* bodyObject = 0;
    802     if (!hasBackground() && node() && node()->hasTagName(HTMLNames::htmlTag)) {
    803         // Locate the <body> element using the DOM.  This is easier than trying
    804         // to crawl around a render tree with potential :before/:after content and
    805         // anonymous blocks created by inline <body> tags etc.  We can locate the <body>
    806         // render object very easily via the DOM.
    807         HTMLElement* body = document()->body();
    808         bodyObject = (body && body->hasLocalName(bodyTag)) ? body->renderer() : 0;
    809         if (bodyObject) {
    810             bgLayer = bodyObject->style()->backgroundLayers();
    811             bgColor = bodyObject->style()->visitedDependentColor(CSSPropertyBackgroundColor);
    812         }
    813     }
    814 
    815     // The background of the box generated by the root element covers the entire canvas, so just use
    816     // the RenderView's docTop/Left/Width/Height accessors.
    817     paintFillLayers(paintInfo, bgColor, bgLayer, view()->docLeft(), view()->docTop(), view()->docWidth(), view()->docHeight(), CompositeSourceOver, bodyObject);
    818 }
    819 
    820 void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
    821 {
    822     if (!paintInfo.shouldPaintWithinRoot(this))
    823         return;
    824     return paintBoxDecorationsWithSize(paintInfo, tx, ty, width(), height());
    825 }
    826 
    827 void RenderBox::paintBoxDecorationsWithSize(PaintInfo& paintInfo, int tx, int ty, int width, int height)
    828 {
    829     // border-fit can adjust where we paint our border and background.  If set, we snugly fit our line box descendants.  (The iChat
    830     // balloon layout is an example of this).
    831     borderFitAdjust(tx, width);
    832 
    833     // FIXME: Should eventually give the theme control over whether the box shadow should paint, since controls could have
    834     // custom shadows of their own.
    835     paintBoxShadow(paintInfo.context, tx, ty, width, height, style(), Normal);
    836 
    837     // If we have a native theme appearance, paint that before painting our background.
    838     // The theme will tell us whether or not we should also paint the CSS background.
    839     bool themePainted = style()->hasAppearance() && !theme()->paint(this, paintInfo, IntRect(tx, ty, width, height));
    840     if (!themePainted) {
    841         if (isRoot())
    842             paintRootBoxFillLayers(paintInfo);
    843         else if (!isBody() || document()->documentElement()->renderer()->hasBackground()) {
    844             // The <body> only paints its background if the root element has defined a background
    845             // independent of the body.
    846 #if PLATFORM(ANDROID)
    847             // If we only want to draw the decorations, don't draw
    848             // the background
    849             if (paintInfo.phase != PaintPhaseBlockBackgroundDecorations)
    850 #endif
    851             paintFillLayers(paintInfo, style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), tx, ty, width, height);
    852         }
    853         if (style()->hasAppearance())
    854             theme()->paintDecorations(this, paintInfo, IntRect(tx, ty, width, height));
    855     }
    856     paintBoxShadow(paintInfo.context, tx, ty, width, height, style(), Inset);
    857 
    858     // The theme will tell us whether or not we should also paint the CSS border.
    859     if ((!style()->hasAppearance() || (!themePainted && theme()->paintBorderOnly(this, paintInfo, IntRect(tx, ty, width, height)))) && style()->hasBorder())
    860         paintBorder(paintInfo.context, tx, ty, width, height, style());
    861 }
    862 
    863 void RenderBox::paintMask(PaintInfo& paintInfo, int tx, int ty)
    864 {
    865     if (!paintInfo.shouldPaintWithinRoot(this) || style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask || paintInfo.context->paintingDisabled())
    866         return;
    867 
    868     int w = width();
    869     int h = height();
    870 
    871     // border-fit can adjust where we paint our border and background.  If set, we snugly fit our line box descendants.  (The iChat
    872     // balloon layout is an example of this).
    873     borderFitAdjust(tx, w);
    874 
    875     paintMaskImages(paintInfo, tx, ty, w, h);
    876 }
    877 
    878 void RenderBox::paintMaskImages(const PaintInfo& paintInfo, int tx, int ty, int w, int h)
    879 {
    880     // Figure out if we need to push a transparency layer to render our mask.
    881     bool pushTransparencyLayer = false;
    882     bool compositedMask = hasLayer() && layer()->hasCompositedMask();
    883     CompositeOperator compositeOp = CompositeSourceOver;
    884 
    885     bool allMaskImagesLoaded = true;
    886 
    887     if (!compositedMask) {
    888         // If the context has a rotation, scale or skew, then use a transparency layer to avoid
    889         // pixel cruft around the edge of the mask.
    890         const AffineTransform& currentCTM = paintInfo.context->getCTM();
    891         pushTransparencyLayer = !currentCTM.isIdentityOrTranslationOrFlipped();
    892 
    893         StyleImage* maskBoxImage = style()->maskBoxImage().image();
    894         const FillLayer* maskLayers = style()->maskLayers();
    895 
    896         // Don't render a masked element until all the mask images have loaded, to prevent a flash of unmasked content.
    897         if (maskBoxImage)
    898             allMaskImagesLoaded &= maskBoxImage->isLoaded();
    899 
    900         if (maskLayers)
    901             allMaskImagesLoaded &= maskLayers->imagesAreLoaded();
    902 
    903         // Before all images have loaded, just use an empty transparency layer as the mask.
    904         if (!allMaskImagesLoaded)
    905             pushTransparencyLayer = true;
    906 
    907         if (maskBoxImage && maskLayers->hasImage()) {
    908             // We have a mask-box-image and mask-image, so need to composite them together before using the result as a mask.
    909             pushTransparencyLayer = true;
    910         } else {
    911             // We have to use an extra image buffer to hold the mask. Multiple mask images need
    912             // to composite together using source-over so that they can then combine into a single unified mask that
    913             // can be composited with the content using destination-in.  SVG images need to be able to set compositing modes
    914             // as they draw images contained inside their sub-document, so we paint all our images into a separate buffer
    915             // and composite that buffer as the mask.
    916             // We have to check that the mask images to be rendered contain at least one image that can be actually used in rendering
    917             // before pushing the transparency layer.
    918             for (const FillLayer* fillLayer = maskLayers->next(); fillLayer; fillLayer = fillLayer->next()) {
    919                 if (fillLayer->hasImage() && fillLayer->image()->canRender(style()->effectiveZoom())) {
    920                     pushTransparencyLayer = true;
    921                     // We found one image that can be used in rendering, exit the loop
    922                     break;
    923                 }
    924             }
    925         }
    926 
    927         compositeOp = CompositeDestinationIn;
    928         if (pushTransparencyLayer) {
    929             paintInfo.context->setCompositeOperation(CompositeDestinationIn);
    930             paintInfo.context->beginTransparencyLayer(1.0f);
    931             compositeOp = CompositeSourceOver;
    932         }
    933     }
    934 
    935     if (allMaskImagesLoaded) {
    936         paintFillLayers(paintInfo, Color(), style()->maskLayers(), tx, ty, w, h, compositeOp);
    937         paintNinePieceImage(paintInfo.context, tx, ty, w, h, style(), style()->maskBoxImage(), compositeOp);
    938     }
    939 
    940     if (pushTransparencyLayer)
    941         paintInfo.context->endTransparencyLayer();
    942 }
    943 
    944 IntRect RenderBox::maskClipRect()
    945 {
    946     IntRect bbox = borderBoxRect();
    947     if (style()->maskBoxImage().image())
    948         return bbox;
    949 
    950     IntRect result;
    951     for (const FillLayer* maskLayer = style()->maskLayers(); maskLayer; maskLayer = maskLayer->next()) {
    952         if (maskLayer->image()) {
    953             IntRect maskRect;
    954             IntPoint phase;
    955             IntSize tileSize;
    956             calculateBackgroundImageGeometry(maskLayer, bbox.x(), bbox.y(), bbox.width(), bbox.height(), maskRect, phase, tileSize);
    957             result.unite(maskRect);
    958         }
    959     }
    960     return result;
    961 }
    962 
    963 void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int width, int height, CompositeOperator op, RenderObject* backgroundObject)
    964 {
    965     if (!fillLayer)
    966         return;
    967 
    968     paintFillLayers(paintInfo, c, fillLayer->next(), tx, ty, width, height, op, backgroundObject);
    969     paintFillLayer(paintInfo, c, fillLayer, tx, ty, width, height, op, backgroundObject);
    970 }
    971 
    972 void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int width, int height, CompositeOperator op, RenderObject* backgroundObject)
    973 {
    974     paintFillLayerExtended(paintInfo, c, fillLayer, tx, ty, width, height, 0, 0, 0, op, backgroundObject);
    975 }
    976 
    977 #if USE(ACCELERATED_COMPOSITING)
    978 static bool layersUseImage(WrappedImagePtr image, const FillLayer* layers)
    979 {
    980     for (const FillLayer* curLayer = layers; curLayer; curLayer = curLayer->next()) {
    981         if (curLayer->image() && image == curLayer->image()->data())
    982             return true;
    983     }
    984 
    985     return false;
    986 }
    987 #endif
    988 
    989 void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*)
    990 {
    991     if (!parent())
    992         return;
    993 
    994     if ((style()->borderImage().image() && style()->borderImage().image()->data() == image) ||
    995         (style()->maskBoxImage().image() && style()->maskBoxImage().image()->data() == image)) {
    996         repaint();
    997         return;
    998     }
    999 
   1000     bool didFullRepaint = repaintLayerRectsForImage(image, style()->backgroundLayers(), true);
   1001     if (!didFullRepaint)
   1002         repaintLayerRectsForImage(image, style()->maskLayers(), false);
   1003 
   1004 
   1005 #if USE(ACCELERATED_COMPOSITING)
   1006     if (hasLayer() && layer()->hasCompositedMask() && layersUseImage(image, style()->maskLayers()))
   1007         layer()->contentChanged(RenderLayer::MaskImageChanged);
   1008 #endif
   1009 }
   1010 
   1011 bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer* layers, bool drawingBackground)
   1012 {
   1013     IntRect rendererRect;
   1014     RenderBox* layerRenderer = 0;
   1015 
   1016     for (const FillLayer* curLayer = layers; curLayer; curLayer = curLayer->next()) {
   1017         if (curLayer->image() && image == curLayer->image()->data() && curLayer->image()->canRender(style()->effectiveZoom())) {
   1018             // Now that we know this image is being used, compute the renderer and the rect
   1019             // if we haven't already
   1020             if (!layerRenderer) {
   1021                 bool drawingRootBackground = drawingBackground && (isRoot() || (isBody() && !document()->documentElement()->renderer()->hasBackground()));
   1022                 if (drawingRootBackground) {
   1023                     layerRenderer = view();
   1024 
   1025                     int rw;
   1026                     int rh;
   1027 
   1028                     if (FrameView* frameView = toRenderView(layerRenderer)->frameView()) {
   1029                         rw = frameView->contentsWidth();
   1030                         rh = frameView->contentsHeight();
   1031                     } else {
   1032                         rw = layerRenderer->width();
   1033                         rh = layerRenderer->height();
   1034                     }
   1035                     rendererRect = IntRect(-layerRenderer->marginLeft(),
   1036                         -layerRenderer->marginTop(),
   1037                         max(layerRenderer->width() + layerRenderer->marginLeft() + layerRenderer->marginRight() + layerRenderer->borderLeft() + layerRenderer->borderRight(), rw),
   1038                         max(layerRenderer->height() + layerRenderer->marginTop() + layerRenderer->marginBottom() + layerRenderer->borderTop() + layerRenderer->borderBottom(), rh));
   1039                 } else {
   1040                     layerRenderer = this;
   1041                     rendererRect = borderBoxRect();
   1042                 }
   1043             }
   1044 
   1045             IntRect repaintRect;
   1046             IntPoint phase;
   1047             IntSize tileSize;
   1048             layerRenderer->calculateBackgroundImageGeometry(curLayer, rendererRect.x(), rendererRect.y(), rendererRect.width(), rendererRect.height(), repaintRect, phase, tileSize);
   1049             layerRenderer->repaintRectangle(repaintRect);
   1050             if (repaintRect == rendererRect)
   1051                 return true;
   1052         }
   1053     }
   1054     return false;
   1055 }
   1056 
   1057 #if PLATFORM(MAC)
   1058 
   1059 void RenderBox::paintCustomHighlight(int tx, int ty, const AtomicString& type, bool behindText)
   1060 {
   1061     Frame* frame = this->frame();
   1062     if (!frame)
   1063         return;
   1064     Page* page = frame->page();
   1065     if (!page)
   1066         return;
   1067 
   1068     InlineBox* boxWrap = inlineBoxWrapper();
   1069     RootInlineBox* r = boxWrap ? boxWrap->root() : 0;
   1070     if (r) {
   1071         FloatRect rootRect(tx + r->x(), ty + r->selectionTop(), r->logicalWidth(), r->selectionHeight());
   1072         FloatRect imageRect(tx + x(), rootRect.y(), width(), rootRect.height());
   1073         page->chrome()->client()->paintCustomHighlight(node(), type, imageRect, rootRect, behindText, false);
   1074     } else {
   1075         FloatRect imageRect(tx + x(), ty + y(), width(), height());
   1076         page->chrome()->client()->paintCustomHighlight(node(), type, imageRect, imageRect, behindText, false);
   1077     }
   1078 }
   1079 
   1080 #endif
   1081 
   1082 bool RenderBox::pushContentsClip(PaintInfo& paintInfo, int tx, int ty)
   1083 {
   1084     if (paintInfo.phase == PaintPhaseBlockBackground || paintInfo.phase == PaintPhaseSelfOutline || paintInfo.phase == PaintPhaseMask)
   1085         return false;
   1086 
   1087     bool isControlClip = hasControlClip();
   1088     bool isOverflowClip = hasOverflowClip() && !layer()->isSelfPaintingLayer();
   1089 
   1090     if (!isControlClip && !isOverflowClip)
   1091         return false;
   1092 
   1093     if (paintInfo.phase == PaintPhaseOutline)
   1094         paintInfo.phase = PaintPhaseChildOutlines;
   1095     else if (paintInfo.phase == PaintPhaseChildBlockBackground) {
   1096         paintInfo.phase = PaintPhaseBlockBackground;
   1097         paintObject(paintInfo, tx, ty);
   1098         paintInfo.phase = PaintPhaseChildBlockBackgrounds;
   1099     }
   1100     IntRect clipRect(isControlClip ? controlClipRect(tx, ty) : overflowClipRect(tx, ty));
   1101     paintInfo.context->save();
   1102     if (style()->hasBorderRadius())
   1103         paintInfo.context->addRoundedRectClip(style()->getRoundedBorderFor(IntRect(tx, ty, width(), height())));
   1104     paintInfo.context->clip(clipRect);
   1105     return true;
   1106 }
   1107 
   1108 void RenderBox::popContentsClip(PaintInfo& paintInfo, PaintPhase originalPhase, int tx, int ty)
   1109 {
   1110     ASSERT(hasControlClip() || (hasOverflowClip() && !layer()->isSelfPaintingLayer()));
   1111 
   1112     paintInfo.context->restore();
   1113     if (originalPhase == PaintPhaseOutline) {
   1114         paintInfo.phase = PaintPhaseSelfOutline;
   1115         paintObject(paintInfo, tx, ty);
   1116         paintInfo.phase = originalPhase;
   1117     } else if (originalPhase == PaintPhaseChildBlockBackground)
   1118         paintInfo.phase = originalPhase;
   1119 }
   1120 
   1121 IntRect RenderBox::overflowClipRect(int tx, int ty, OverlayScrollbarSizeRelevancy relevancy)
   1122 {
   1123     // FIXME: When overflow-clip (CSS3) is implemented, we'll obtain the property
   1124     // here.
   1125 
   1126     int bLeft = borderLeft();
   1127     int bTop = borderTop();
   1128 
   1129     int clipX = tx + bLeft;
   1130     int clipY = ty + bTop;
   1131     int clipWidth = width() - bLeft - borderRight();
   1132     int clipHeight = height() - bTop - borderBottom();
   1133 
   1134     // Subtract out scrollbars if we have them.
   1135     if (layer()) {
   1136         clipWidth -= layer()->verticalScrollbarWidth(relevancy);
   1137         clipHeight -= layer()->horizontalScrollbarHeight(relevancy);
   1138     }
   1139 
   1140     return IntRect(clipX, clipY, clipWidth, clipHeight);
   1141 }
   1142 
   1143 IntRect RenderBox::clipRect(int tx, int ty)
   1144 {
   1145     int clipX = tx;
   1146     int clipY = ty;
   1147     int clipWidth = width();
   1148     int clipHeight = height();
   1149 
   1150     if (!style()->clipLeft().isAuto()) {
   1151         int c = style()->clipLeft().calcValue(width());
   1152         clipX += c;
   1153         clipWidth -= c;
   1154     }
   1155 
   1156     if (!style()->clipRight().isAuto())
   1157         clipWidth -= width() - style()->clipRight().calcValue(width());
   1158 
   1159     if (!style()->clipTop().isAuto()) {
   1160         int c = style()->clipTop().calcValue(height());
   1161         clipY += c;
   1162         clipHeight -= c;
   1163     }
   1164 
   1165     if (!style()->clipBottom().isAuto())
   1166         clipHeight -= height() - style()->clipBottom().calcValue(height());
   1167 
   1168     return IntRect(clipX, clipY, clipWidth, clipHeight);
   1169 }
   1170 
   1171 int RenderBox::containingBlockLogicalWidthForContent() const
   1172 {
   1173     RenderBlock* cb = containingBlock();
   1174     if (shrinkToAvoidFloats())
   1175         return cb->availableLogicalWidthForLine(y(), false);
   1176     return cb->availableLogicalWidth();
   1177 }
   1178 
   1179 int RenderBox::perpendicularContainingBlockLogicalHeight() const
   1180 {
   1181     RenderBlock* cb = containingBlock();
   1182     RenderStyle* containingBlockStyle = cb->style();
   1183     Length logicalHeightLength = containingBlockStyle->logicalHeight();
   1184 
   1185     // FIXME: For now just support fixed heights.  Eventually should support percentage heights as well.
   1186     if (!logicalHeightLength.isFixed()) {
   1187         // Rather than making the child be completely unconstrained, WinIE uses the viewport width and height
   1188         // as a constraint.  We do that for now as well even though it's likely being unconstrained is what the spec
   1189         // will decide.
   1190         return containingBlockStyle->isHorizontalWritingMode() ? view()->frameView()->visibleHeight() : view()->frameView()->visibleWidth();
   1191     }
   1192 
   1193     // Use the content box logical height as specified by the style.
   1194     return cb->computeContentBoxLogicalHeight(logicalHeightLength.value());
   1195 }
   1196 
   1197 void RenderBox::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState) const
   1198 {
   1199     if (repaintContainer == this)
   1200         return;
   1201 
   1202     if (RenderView* v = view()) {
   1203         if (v->layoutStateEnabled() && !repaintContainer) {
   1204             LayoutState* layoutState = v->layoutState();
   1205             IntSize offset = layoutState->m_paintOffset;
   1206             offset.expand(x(), y());
   1207             if (style()->position() == RelativePosition && layer())
   1208                 offset += layer()->relativePositionOffset();
   1209             transformState.move(offset);
   1210             return;
   1211         }
   1212     }
   1213 
   1214     bool containerSkipped;
   1215     RenderObject* o = container(repaintContainer, &containerSkipped);
   1216     if (!o)
   1217         return;
   1218 
   1219     bool isFixedPos = style()->position() == FixedPosition;
   1220     bool hasTransform = hasLayer() && layer()->transform();
   1221     if (hasTransform) {
   1222         // If this box has a transform, it acts as a fixed position container for fixed descendants,
   1223         // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
   1224         fixed &= isFixedPos;
   1225     } else
   1226         fixed |= isFixedPos;
   1227 
   1228     IntSize containerOffset = offsetFromContainer(o, roundedIntPoint(transformState.mappedPoint()));
   1229 
   1230     bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
   1231     if (useTransforms && shouldUseTransformFromContainer(o)) {
   1232         TransformationMatrix t;
   1233         getTransformFromContainer(o, containerOffset, t);
   1234         transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
   1235     } else
   1236         transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
   1237 
   1238     if (containerSkipped) {
   1239         // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
   1240         // to just subtract the delta between the repaintContainer and o.
   1241         IntSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
   1242         transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
   1243         return;
   1244     }
   1245 
   1246     o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState);
   1247 }
   1248 
   1249 void RenderBox::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState& transformState) const
   1250 {
   1251     // We don't expect absoluteToLocal() to be called during layout (yet)
   1252     ASSERT(!view() || !view()->layoutStateEnabled());
   1253 
   1254     bool isFixedPos = style()->position() == FixedPosition;
   1255     bool hasTransform = hasLayer() && layer()->transform();
   1256     if (hasTransform) {
   1257         // If this box has a transform, it acts as a fixed position container for fixed descendants,
   1258         // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
   1259         fixed &= isFixedPos;
   1260     } else
   1261         fixed |= isFixedPos;
   1262 
   1263     RenderObject* o = container();
   1264     if (!o)
   1265         return;
   1266 
   1267     o->mapAbsoluteToLocalPoint(fixed, useTransforms, transformState);
   1268 
   1269     IntSize containerOffset = offsetFromContainer(o, IntPoint());
   1270 
   1271     bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
   1272     if (useTransforms && shouldUseTransformFromContainer(o)) {
   1273         TransformationMatrix t;
   1274         getTransformFromContainer(o, containerOffset, t);
   1275         transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
   1276     } else
   1277         transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
   1278 }
   1279 
   1280 IntSize RenderBox::offsetFromContainer(RenderObject* o, const IntPoint& point) const
   1281 {
   1282     ASSERT(o == container());
   1283 
   1284     IntSize offset;
   1285     if (isRelPositioned())
   1286         offset += relativePositionOffset();
   1287 
   1288     if (!isInline() || isReplaced()) {
   1289         if (style()->position() != AbsolutePosition && style()->position() != FixedPosition) {
   1290             if (o->hasColumns()) {
   1291                 IntRect columnRect(frameRect());
   1292                 toRenderBlock(o)->flipForWritingModeIncludingColumns(columnRect);
   1293                 offset += IntSize(columnRect.location().x(), columnRect.location().y());
   1294                 columnRect.move(point.x(), point.y());
   1295                 o->adjustForColumns(offset, columnRect.location());
   1296             } else
   1297                 offset += locationOffsetIncludingFlipping();
   1298         } else
   1299             offset += locationOffsetIncludingFlipping();
   1300     }
   1301 
   1302     if (o->hasOverflowClip())
   1303         offset -= toRenderBox(o)->layer()->scrolledContentOffset();
   1304 
   1305     if (style()->position() == AbsolutePosition && o->isRelPositioned() && o->isRenderInline())
   1306         offset += toRenderInline(o)->relativePositionedInlineOffset(this);
   1307 
   1308     return offset;
   1309 }
   1310 
   1311 InlineBox* RenderBox::createInlineBox()
   1312 {
   1313     return new (renderArena()) InlineBox(this);
   1314 }
   1315 
   1316 void RenderBox::dirtyLineBoxes(bool fullLayout)
   1317 {
   1318     if (m_inlineBoxWrapper) {
   1319         if (fullLayout) {
   1320             m_inlineBoxWrapper->destroy(renderArena());
   1321             m_inlineBoxWrapper = 0;
   1322         } else
   1323             m_inlineBoxWrapper->dirtyLineBoxes();
   1324     }
   1325 }
   1326 
   1327 void RenderBox::positionLineBox(InlineBox* box)
   1328 {
   1329     if (isPositioned()) {
   1330         // Cache the x position only if we were an INLINE type originally.
   1331         bool wasInline = style()->isOriginalDisplayInlineType();
   1332         if (wasInline) {
   1333             // The value is cached in the xPos of the box.  We only need this value if
   1334             // our object was inline originally, since otherwise it would have ended up underneath
   1335             // the inlines.
   1336             layer()->setStaticInlinePosition(lroundf(box->logicalLeft()));
   1337             if (style()->hasStaticInlinePosition(box->isHorizontal()))
   1338                 setChildNeedsLayout(true, false); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
   1339         } else {
   1340             // Our object was a block originally, so we make our normal flow position be
   1341             // just below the line box (as though all the inlines that came before us got
   1342             // wrapped in an anonymous block, which is what would have happened had we been
   1343             // in flow).  This value was cached in the y() of the box.
   1344             layer()->setStaticBlockPosition(box->logicalTop());
   1345             if (style()->hasStaticBlockPosition(box->isHorizontal()))
   1346                 setChildNeedsLayout(true, false); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
   1347         }
   1348 
   1349         // Nuke the box.
   1350         box->remove();
   1351         box->destroy(renderArena());
   1352     } else if (isReplaced()) {
   1353         setLocation(lroundf(box->x()), lroundf(box->y()));
   1354         m_inlineBoxWrapper = box;
   1355     }
   1356 }
   1357 
   1358 void RenderBox::deleteLineBoxWrapper()
   1359 {
   1360     if (m_inlineBoxWrapper) {
   1361         if (!documentBeingDestroyed())
   1362             m_inlineBoxWrapper->remove();
   1363         m_inlineBoxWrapper->destroy(renderArena());
   1364         m_inlineBoxWrapper = 0;
   1365     }
   1366 }
   1367 
   1368 IntRect RenderBox::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
   1369 {
   1370     if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent())
   1371         return IntRect();
   1372 
   1373     IntRect r = visualOverflowRect();
   1374 
   1375     RenderView* v = view();
   1376     if (v) {
   1377         // FIXME: layoutDelta needs to be applied in parts before/after transforms and
   1378         // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
   1379         r.move(v->layoutDelta());
   1380     }
   1381 
   1382     if (style()) {
   1383         if (style()->hasAppearance())
   1384             // The theme may wish to inflate the rect used when repainting.
   1385             theme()->adjustRepaintRect(this, r);
   1386 
   1387         // We have to use maximalOutlineSize() because a child might have an outline
   1388         // that projects outside of our overflowRect.
   1389         if (v) {
   1390             ASSERT(style()->outlineSize() <= v->maximalOutlineSize());
   1391             r.inflate(v->maximalOutlineSize());
   1392         }
   1393     }
   1394 
   1395     computeRectForRepaint(repaintContainer, r);
   1396     return r;
   1397 }
   1398 
   1399 void RenderBox::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& rect, bool fixed)
   1400 {
   1401     // The rect we compute at each step is shifted by our x/y offset in the parent container's coordinate space.
   1402     // Only when we cross a writing mode boundary will we have to possibly flipForWritingMode (to convert into a more appropriate
   1403     // offset corner for the enclosing container).  This allows for a fully RL or BT document to repaint
   1404     // properly even during layout, since the rect remains flipped all the way until the end.
   1405     //
   1406     // RenderView::computeRectForRepaint then converts the rect to physical coordinates.  We also convert to
   1407     // physical when we hit a repaintContainer boundary.  Therefore the final rect returned is always in the
   1408     // physical coordinate space of the repaintContainer.
   1409     if (RenderView* v = view()) {
   1410         // LayoutState is only valid for root-relative repainting
   1411         if (v->layoutStateEnabled() && !repaintContainer) {
   1412             LayoutState* layoutState = v->layoutState();
   1413 
   1414             if (layer() && layer()->transform())
   1415                 rect = layer()->transform()->mapRect(rect);
   1416 
   1417             if (style()->position() == RelativePosition && layer())
   1418                 rect.move(layer()->relativePositionOffset());
   1419 
   1420             rect.move(x(), y());
   1421             rect.move(layoutState->m_paintOffset);
   1422             if (layoutState->m_clipped)
   1423                 rect.intersect(layoutState->m_clipRect);
   1424             return;
   1425         }
   1426     }
   1427 
   1428     if (hasReflection())
   1429         rect.unite(reflectedRect(rect));
   1430 
   1431     if (repaintContainer == this) {
   1432         if (repaintContainer->style()->isFlippedBlocksWritingMode())
   1433             flipForWritingMode(rect);
   1434         return;
   1435     }
   1436 
   1437     bool containerSkipped;
   1438     RenderObject* o = container(repaintContainer, &containerSkipped);
   1439     if (!o)
   1440         return;
   1441 
   1442     if (isWritingModeRoot() && !isPositioned())
   1443         flipForWritingMode(rect);
   1444     IntPoint topLeft = rect.location();
   1445     topLeft.move(x(), y());
   1446 
   1447     EPosition position = style()->position();
   1448 
   1449     // We are now in our parent container's coordinate space.  Apply our transform to obtain a bounding box
   1450     // in the parent's coordinate space that encloses us.
   1451     if (layer() && layer()->transform()) {
   1452         fixed = position == FixedPosition;
   1453         rect = layer()->transform()->mapRect(rect);
   1454         topLeft = rect.location();
   1455         topLeft.move(x(), y());
   1456     } else if (position == FixedPosition)
   1457         fixed = true;
   1458 
   1459     if (position == AbsolutePosition && o->isRelPositioned() && o->isRenderInline())
   1460         topLeft += toRenderInline(o)->relativePositionedInlineOffset(this);
   1461     else if (position == RelativePosition && layer()) {
   1462         // Apply the relative position offset when invalidating a rectangle.  The layer
   1463         // is translated, but the render box isn't, so we need to do this to get the
   1464         // right dirty rect.  Since this is called from RenderObject::setStyle, the relative position
   1465         // flag on the RenderObject has been cleared, so use the one on the style().
   1466         topLeft += layer()->relativePositionOffset();
   1467     }
   1468 
   1469     if (o->isBlockFlow() && position != AbsolutePosition && position != FixedPosition) {
   1470         RenderBlock* cb = toRenderBlock(o);
   1471         if (cb->hasColumns()) {
   1472             IntRect repaintRect(topLeft, rect.size());
   1473             cb->adjustRectForColumns(repaintRect);
   1474             topLeft = repaintRect.location();
   1475             rect = repaintRect;
   1476         }
   1477     }
   1478 
   1479     // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
   1480     // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
   1481     if (o->hasOverflowClip()) {
   1482         RenderBox* containerBox = toRenderBox(o);
   1483 
   1484         // o->height() is inaccurate if we're in the middle of a layout of |o|, so use the
   1485         // layer's size instead.  Even if the layer's size is wrong, the layer itself will repaint
   1486         // anyway if its size does change.
   1487         topLeft -= containerBox->layer()->scrolledContentOffset(); // For overflow:auto/scroll/hidden.
   1488 
   1489         IntRect repaintRect(topLeft, rect.size());
   1490         IntRect boxRect(0, 0, containerBox->layer()->width(), containerBox->layer()->height());
   1491         rect = intersection(repaintRect, boxRect);
   1492         if (rect.isEmpty())
   1493             return;
   1494     } else
   1495         rect.setLocation(topLeft);
   1496 
   1497     if (containerSkipped) {
   1498         // If the repaintContainer is below o, then we need to map the rect into repaintContainer's coordinates.
   1499         IntSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
   1500         rect.move(-containerOffset);
   1501         return;
   1502     }
   1503 
   1504     o->computeRectForRepaint(repaintContainer, rect, fixed);
   1505 }
   1506 
   1507 void RenderBox::repaintDuringLayoutIfMoved(const IntRect& rect)
   1508 {
   1509     int newX = x();
   1510     int newY = y();
   1511     int newWidth = width();
   1512     int newHeight = height();
   1513     if (rect.x() != newX || rect.y() != newY) {
   1514         // The child moved.  Invalidate the object's old and new positions.  We have to do this
   1515         // since the object may not have gotten a layout.
   1516         m_frameRect = rect;
   1517         repaint();
   1518         repaintOverhangingFloats(true);
   1519         m_frameRect = IntRect(newX, newY, newWidth, newHeight);
   1520         repaint();
   1521         repaintOverhangingFloats(true);
   1522     }
   1523 }
   1524 
   1525 #ifdef ANDROID_LAYOUT
   1526 void RenderBox::setVisibleWidth(int newWidth) {
   1527     const Settings* settings = document()->settings();
   1528     ASSERT(settings);
   1529     if (settings->layoutAlgorithm() != Settings::kLayoutFitColumnToScreen
   1530         || m_visibleWidth == newWidth)
   1531         return;
   1532     m_isVisibleWidthChangedBeforeLayout = true;
   1533     m_visibleWidth = newWidth;
   1534 }
   1535 
   1536 bool RenderBox::checkAndSetRelayoutChildren(bool* relayoutChildren) {
   1537     if (m_isVisibleWidthChangedBeforeLayout) {
   1538         m_isVisibleWidthChangedBeforeLayout = false;
   1539         *relayoutChildren = true;
   1540         return true;
   1541     }
   1542     return false;
   1543 }
   1544 #endif
   1545 
   1546 void RenderBox::computeLogicalWidth()
   1547 {
   1548 #ifdef ANDROID_LAYOUT
   1549     if (view()->frameView())
   1550         setVisibleWidth(view()->frameView()->textWrapWidth());
   1551 #endif
   1552 
   1553     if (isPositioned()) {
   1554         // FIXME: This calculation is not patched for block-flow yet.
   1555         // https://bugs.webkit.org/show_bug.cgi?id=46500
   1556         computePositionedLogicalWidth();
   1557         return;
   1558     }
   1559 
   1560     // If layout is limited to a subtree, the subtree root's logical width does not change.
   1561     if (node() && view()->frameView() && view()->frameView()->layoutRoot(true) == this)
   1562         return;
   1563 
   1564     // The parent box is flexing us, so it has increased or decreased our
   1565     // width.  Use the width from the style context.
   1566     // FIXME: Account for block-flow in flexible boxes.
   1567     // https://bugs.webkit.org/show_bug.cgi?id=46418
   1568     if (hasOverrideSize() &&  parent()->style()->boxOrient() == HORIZONTAL
   1569             && parent()->isFlexibleBox() && parent()->isFlexingChildren()) {
   1570 #if PLATFORM(ANDROID)
   1571         // Strangely, the slider is get overrided as width 0 on youtube.com
   1572         // The wrong width will cause the touch hit test for the slider failed.
   1573         // This WAR should be safe since it is only targeted to slider.
   1574         // TODO: root cause this and see if any webkit update fix this.
   1575         if (!(isSlider() &&  overrideSize() == 0))
   1576 #endif
   1577         setLogicalWidth(overrideSize());
   1578         return;
   1579     }
   1580 
   1581     // FIXME: Account for block-flow in flexible boxes.
   1582     // https://bugs.webkit.org/show_bug.cgi?id=46418
   1583     bool inVerticalBox = parent()->isFlexibleBox() && (parent()->style()->boxOrient() == VERTICAL);
   1584     bool stretching = (parent()->style()->boxAlign() == BSTRETCH);
   1585     bool treatAsReplaced = shouldComputeSizeAsReplaced() && (!inVerticalBox || !stretching);
   1586 
   1587     Length logicalWidthLength = (treatAsReplaced) ? Length(computeReplacedLogicalWidth(), Fixed) : style()->logicalWidth();
   1588 
   1589     RenderBlock* cb = containingBlock();
   1590     int containerLogicalWidth = max(0, containingBlockLogicalWidthForContent());
   1591     bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHorizontalWritingMode();
   1592     int containerWidthInInlineDirection = containerLogicalWidth;
   1593     if (hasPerpendicularContainingBlock)
   1594         containerWidthInInlineDirection = perpendicularContainingBlockLogicalHeight();
   1595 
   1596     if (isInline() && !isInlineBlockOrInlineTable()) {
   1597         // just calculate margins
   1598         setMarginStart(style()->marginStart().calcMinValue(containerLogicalWidth));
   1599         setMarginEnd(style()->marginEnd().calcMinValue(containerLogicalWidth));
   1600 #ifdef ANDROID_LAYOUT
   1601         if (treatAsReplaced) {
   1602 #else
   1603         if (treatAsReplaced)
   1604 #endif
   1605             setLogicalWidth(max(logicalWidthLength.value() + borderAndPaddingLogicalWidth(), minPreferredLogicalWidth()));
   1606 
   1607 #ifdef ANDROID_LAYOUT
   1608             // in SSR mode with replaced box, if the box width is wider than the container width,
   1609             // it will be shrinked to fit to the container.
   1610             if (containerLogicalWidth && (width() + m_marginLeft + m_marginRight) > containerLogicalWidth &&
   1611                     document()->frame()->settings()->layoutAlgorithm() == Settings::kLayoutSSR) {
   1612                 m_marginLeft = m_marginRight = 0;
   1613                 setWidth(containerLogicalWidth);
   1614                 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = containerLogicalWidth;
   1615             }
   1616         }
   1617 #endif
   1618         return;
   1619     }
   1620 
   1621     // Width calculations
   1622     if (treatAsReplaced)
   1623         setLogicalWidth(logicalWidthLength.value() + borderAndPaddingLogicalWidth());
   1624     else {
   1625         // Calculate LogicalWidth
   1626         setLogicalWidth(computeLogicalWidthUsing(LogicalWidth, containerWidthInInlineDirection));
   1627 
   1628         // Calculate MaxLogicalWidth
   1629         if (!style()->logicalMaxWidth().isUndefined()) {
   1630             int maxLogicalWidth = computeLogicalWidthUsing(MaxLogicalWidth, containerWidthInInlineDirection);
   1631             if (logicalWidth() > maxLogicalWidth) {
   1632                 setLogicalWidth(maxLogicalWidth);
   1633                 logicalWidthLength = style()->logicalMaxWidth();
   1634             }
   1635         }
   1636 
   1637         // Calculate MinLogicalWidth
   1638         int minLogicalWidth = computeLogicalWidthUsing(MinLogicalWidth, containerWidthInInlineDirection);
   1639         if (logicalWidth() < minLogicalWidth) {
   1640             setLogicalWidth(minLogicalWidth);
   1641             logicalWidthLength = style()->logicalMinWidth();
   1642         }
   1643     }
   1644 
   1645     // Fieldsets are currently the only objects that stretch to their minimum width.
   1646     if (stretchesToMinIntrinsicLogicalWidth()) {
   1647         setLogicalWidth(max(logicalWidth(), minPreferredLogicalWidth()));
   1648         logicalWidthLength = Length(logicalWidth(), Fixed);
   1649     }
   1650 
   1651     // Margin calculations.
   1652     if (logicalWidthLength.isAuto() || hasPerpendicularContainingBlock || isFloating() || isInline()) {
   1653         setMarginStart(style()->marginStart().calcMinValue(containerLogicalWidth));
   1654         setMarginEnd(style()->marginEnd().calcMinValue(containerLogicalWidth));
   1655     } else
   1656         computeInlineDirectionMargins(cb, containerLogicalWidth, logicalWidth());
   1657 
   1658 #ifdef ANDROID_LAYOUT
   1659     // in SSR mode with non-replaced box, we use ANDROID_SSR_MARGIN_PADDING for left/right margin.
   1660     // If the box width is wider than the container width, it will be shrinked to fit to the container.
   1661     if (containerLogicalWidth && !treatAsReplaced &&
   1662             document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR) {
   1663         setWidth(width() + m_marginLeft + m_marginRight);
   1664         m_marginLeft = m_marginLeft > ANDROID_SSR_MARGIN_PADDING ? ANDROID_SSR_MARGIN_PADDING : m_marginLeft;
   1665         m_marginRight = m_marginRight > ANDROID_SSR_MARGIN_PADDING ? ANDROID_SSR_MARGIN_PADDING : m_marginRight;
   1666         if (width() > containerLogicalWidth) {
   1667             m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = containerLogicalWidth-(m_marginLeft + m_marginRight);
   1668             setWidth(m_minPreferredLogicalWidth);
   1669         } else
   1670             setWidth(width() -(m_marginLeft + m_marginRight));
   1671     }
   1672 #endif
   1673 
   1674     if (!hasPerpendicularContainingBlock && containerLogicalWidth && containerLogicalWidth != (logicalWidth() + marginStart() + marginEnd())
   1675             && !isFloating() && !isInline() && !cb->isFlexibleBox())
   1676         cb->setMarginEndForChild(this, containerLogicalWidth - logicalWidth() - cb->marginStartForChild(this));
   1677 }
   1678 
   1679 int RenderBox::computeLogicalWidthUsing(LogicalWidthType widthType, int availableLogicalWidth)
   1680 {
   1681     int logicalWidthResult = logicalWidth();
   1682     Length logicalWidth;
   1683     if (widthType == LogicalWidth)
   1684         logicalWidth = style()->logicalWidth();
   1685     else if (widthType == MinLogicalWidth)
   1686         logicalWidth = style()->logicalMinWidth();
   1687     else
   1688         logicalWidth = style()->logicalMaxWidth();
   1689 
   1690     if (logicalWidth.isIntrinsicOrAuto()) {
   1691         int marginStart = style()->marginStart().calcMinValue(availableLogicalWidth);
   1692         int marginEnd = style()->marginEnd().calcMinValue(availableLogicalWidth);
   1693         if (availableLogicalWidth)
   1694             logicalWidthResult = availableLogicalWidth - marginStart - marginEnd;
   1695 
   1696         if (sizesToIntrinsicLogicalWidth(widthType)) {
   1697             logicalWidthResult = max(logicalWidthResult, minPreferredLogicalWidth());
   1698             logicalWidthResult = min(logicalWidthResult, maxPreferredLogicalWidth());
   1699         }
   1700     } else // FIXME: If the containing block flow is perpendicular to our direction we need to use the available logical height instead.
   1701         logicalWidthResult = computeBorderBoxLogicalWidth(logicalWidth.calcValue(availableLogicalWidth));
   1702 
   1703     return logicalWidthResult;
   1704 }
   1705 
   1706 bool RenderBox::sizesToIntrinsicLogicalWidth(LogicalWidthType widthType) const
   1707 {
   1708     // Marquees in WinIE are like a mixture of blocks and inline-blocks.  They size as though they're blocks,
   1709     // but they allow text to sit on the same line as the marquee.
   1710     if (isFloating() || (isInlineBlockOrInlineTable() && !isHTMLMarquee()))
   1711         return true;
   1712 
   1713     // This code may look a bit strange.  Basically width:intrinsic should clamp the size when testing both
   1714     // min-width and width.  max-width is only clamped if it is also intrinsic.
   1715     Length logicalWidth = (widthType == MaxLogicalWidth) ? style()->logicalMaxWidth() : style()->logicalWidth();
   1716     if (logicalWidth.type() == Intrinsic)
   1717         return true;
   1718 
   1719     // Children of a horizontal marquee do not fill the container by default.
   1720     // FIXME: Need to deal with MAUTO value properly.  It could be vertical.
   1721     // FIXME: Think about block-flow here.  Need to find out how marquee direction relates to
   1722     // block-flow (as well as how marquee overflow should relate to block flow).
   1723     // https://bugs.webkit.org/show_bug.cgi?id=46472
   1724     if (parent()->style()->overflowX() == OMARQUEE) {
   1725         EMarqueeDirection dir = parent()->style()->marqueeDirection();
   1726         if (dir == MAUTO || dir == MFORWARD || dir == MBACKWARD || dir == MLEFT || dir == MRIGHT)
   1727             return true;
   1728     }
   1729 
   1730     // Flexible horizontal boxes lay out children at their intrinsic widths.  Also vertical boxes
   1731     // that don't stretch their kids lay out their children at their intrinsic widths.
   1732     // FIXME: Think about block-flow here.
   1733     // https://bugs.webkit.org/show_bug.cgi?id=46473
   1734     if (parent()->isFlexibleBox()
   1735             && (parent()->style()->boxOrient() == HORIZONTAL || parent()->style()->boxAlign() != BSTRETCH))
   1736         return true;
   1737 
   1738     // Button, input, select, textarea, legend and datagrid treat
   1739     // width value of 'auto' as 'intrinsic' unless it's in a
   1740     // stretching vertical flexbox.
   1741     // FIXME: Think about block-flow here.
   1742     // https://bugs.webkit.org/show_bug.cgi?id=46473
   1743     if (logicalWidth.type() == Auto && !(parent()->isFlexibleBox() && parent()->style()->boxOrient() == VERTICAL && parent()->style()->boxAlign() == BSTRETCH) && node() && (node()->hasTagName(inputTag) || node()->hasTagName(selectTag) || node()->hasTagName(buttonTag) || node()->hasTagName(textareaTag) || node()->hasTagName(legendTag) || node()->hasTagName(datagridTag)))
   1744         return true;
   1745 
   1746     return false;
   1747 }
   1748 
   1749 void RenderBox::computeInlineDirectionMargins(RenderBlock* containingBlock, int containerWidth, int childWidth)
   1750 {
   1751     const RenderStyle* containingBlockStyle = containingBlock->style();
   1752     Length marginStartLength = style()->marginStartUsing(containingBlockStyle);
   1753     Length marginEndLength = style()->marginEndUsing(containingBlockStyle);
   1754 
   1755     // Case One: The object is being centered in the containing block's available logical width.
   1756     if ((marginStartLength.isAuto() && marginEndLength.isAuto() && childWidth < containerWidth)
   1757         || (!marginStartLength.isAuto() && !marginEndLength.isAuto() && containingBlock->style()->textAlign() == WEBKIT_CENTER)) {
   1758         containingBlock->setMarginStartForChild(this, max(0, (containerWidth - childWidth) / 2));
   1759         containingBlock->setMarginEndForChild(this, containerWidth - childWidth - containingBlock->marginStartForChild(this));
   1760         return;
   1761     }
   1762 
   1763     // Case Two: The object is being pushed to the start of the containing block's available logical width.
   1764     if (marginEndLength.isAuto() && childWidth < containerWidth) {
   1765         containingBlock->setMarginStartForChild(this, marginStartLength.calcValue(containerWidth));
   1766         containingBlock->setMarginEndForChild(this, containerWidth - childWidth - containingBlock->marginStartForChild(this));
   1767         return;
   1768     }
   1769 
   1770     // Case Three: The object is being pushed to the end of the containing block's available logical width.
   1771     bool pushToEndFromTextAlign = !marginEndLength.isAuto() && ((!containingBlockStyle->isLeftToRightDirection() && containingBlockStyle->textAlign() == WEBKIT_LEFT)
   1772         || (containingBlockStyle->isLeftToRightDirection() && containingBlockStyle->textAlign() == WEBKIT_RIGHT));
   1773     if ((marginStartLength.isAuto() && childWidth < containerWidth) || pushToEndFromTextAlign) {
   1774         containingBlock->setMarginEndForChild(this, marginEndLength.calcValue(containerWidth));
   1775         containingBlock->setMarginStartForChild(this, containerWidth - childWidth - containingBlock->marginEndForChild(this));
   1776         return;
   1777     }
   1778 
   1779     // Case Four: Either no auto margins, or our width is >= the container width (css2.1, 10.3.3).  In that case
   1780     // auto margins will just turn into 0.
   1781     containingBlock->setMarginStartForChild(this, marginStartLength.calcMinValue(containerWidth));
   1782     containingBlock->setMarginEndForChild(this, marginEndLength.calcMinValue(containerWidth));
   1783 }
   1784 
   1785 void RenderBox::computeLogicalHeight()
   1786 {
   1787     // Cell height is managed by the table and inline non-replaced elements do not support a height property.
   1788     if (isTableCell() || (isInline() && !isReplaced()))
   1789         return;
   1790 
   1791     Length h;
   1792     if (isPositioned()) {
   1793         // FIXME: This calculation is not patched for block-flow yet.
   1794         // https://bugs.webkit.org/show_bug.cgi?id=46500
   1795         computePositionedLogicalHeight();
   1796     } else {
   1797         RenderBlock* cb = containingBlock();
   1798         bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHorizontalWritingMode();
   1799 
   1800         if (!hasPerpendicularContainingBlock)
   1801             computeBlockDirectionMargins(cb);
   1802 
   1803         // For tables, calculate margins only.
   1804         if (isTable()) {
   1805             if (hasPerpendicularContainingBlock)
   1806                 computeInlineDirectionMargins(cb, containingBlockLogicalWidthForContent(), logicalHeight());
   1807             return;
   1808         }
   1809 
   1810         // FIXME: Account for block-flow in flexible boxes.
   1811         // https://bugs.webkit.org/show_bug.cgi?id=46418
   1812         bool inHorizontalBox = parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL;
   1813         bool stretching = parent()->style()->boxAlign() == BSTRETCH;
   1814         bool treatAsReplaced = shouldComputeSizeAsReplaced() && (!inHorizontalBox || !stretching);
   1815         bool checkMinMaxHeight = false;
   1816 
   1817         // The parent box is flexing us, so it has increased or decreased our height.  We have to
   1818         // grab our cached flexible height.
   1819         // FIXME: Account for block-flow in flexible boxes.
   1820         // https://bugs.webkit.org/show_bug.cgi?id=46418
   1821         if (hasOverrideSize() && parent()->isFlexibleBox() && parent()->style()->boxOrient() == VERTICAL
   1822                 && parent()->isFlexingChildren())
   1823             h = Length(overrideSize() - borderAndPaddingLogicalHeight(), Fixed);
   1824         else if (treatAsReplaced)
   1825             h = Length(computeReplacedLogicalHeight(), Fixed);
   1826         else {
   1827             h = style()->logicalHeight();
   1828             checkMinMaxHeight = true;
   1829         }
   1830 
   1831         // Block children of horizontal flexible boxes fill the height of the box.
   1832         // FIXME: Account for block-flow in flexible boxes.
   1833         // https://bugs.webkit.org/show_bug.cgi?id=46418
   1834         if (h.isAuto() && parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
   1835                 && parent()->isStretchingChildren()) {
   1836             h = Length(parentBox()->contentLogicalHeight() - marginBefore() - marginAfter() - borderAndPaddingLogicalHeight(), Fixed);
   1837             checkMinMaxHeight = false;
   1838         }
   1839 
   1840         int heightResult;
   1841         if (checkMinMaxHeight) {
   1842 #ifdef ANDROID_LAYOUT
   1843             // in SSR mode, ignore CSS height as layout is so different
   1844             if (document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR)
   1845                 heightResult = -1;
   1846             else
   1847 #endif
   1848             heightResult = computeLogicalHeightUsing(style()->logicalHeight());
   1849             if (heightResult == -1)
   1850                 heightResult = logicalHeight();
   1851             int minH = computeLogicalHeightUsing(style()->logicalMinHeight()); // Leave as -1 if unset.
   1852             int maxH = style()->logicalMaxHeight().isUndefined() ? heightResult : computeLogicalHeightUsing(style()->logicalMaxHeight());
   1853             if (maxH == -1)
   1854                 maxH = heightResult;
   1855             heightResult = min(maxH, heightResult);
   1856             heightResult = max(minH, heightResult);
   1857         } else {
   1858             // The only times we don't check min/max height are when a fixed length has
   1859             // been given as an override.  Just use that.  The value has already been adjusted
   1860             // for box-sizing.
   1861             heightResult = h.value() + borderAndPaddingLogicalHeight();
   1862         }
   1863 
   1864         setLogicalHeight(heightResult);
   1865 
   1866         if (hasPerpendicularContainingBlock)
   1867             computeInlineDirectionMargins(cb, containingBlockLogicalWidthForContent(), heightResult);
   1868     }
   1869 
   1870     // WinIE quirk: The <html> block always fills the entire canvas in quirks mode.  The <body> always fills the
   1871     // <html> block in quirks mode.  Only apply this quirk if the block is normal flow and no height
   1872     // is specified. When we're printing, we also need this quirk if the body or root has a percentage
   1873     // height since we don't set a height in RenderView when we're printing. So without this quirk, the
   1874     // height has nothing to be a percentage of, and it ends up being 0. That is bad.
   1875     bool paginatedContentNeedsBaseHeight = document()->printing() && h.isPercent()
   1876         && (isRoot() || (isBody() && document()->documentElement()->renderer()->style()->logicalHeight().isPercent()));
   1877     if (stretchesToViewport() || paginatedContentNeedsBaseHeight) {
   1878         // FIXME: Finish accounting for block flow here.
   1879         // https://bugs.webkit.org/show_bug.cgi?id=46603
   1880         int margins = collapsedMarginBefore() + collapsedMarginAfter();
   1881         int visHeight;
   1882         if (document()->printing())
   1883             visHeight = static_cast<int>(view()->pageLogicalHeight());
   1884         else  {
   1885             if (isHorizontalWritingMode())
   1886                 visHeight = view()->viewHeight();
   1887             else
   1888                 visHeight = view()->viewWidth();
   1889         }
   1890         if (isRoot())
   1891             setLogicalHeight(max(logicalHeight(), visHeight - margins));
   1892         else {
   1893             int marginsBordersPadding = margins + parentBox()->marginBefore() + parentBox()->marginAfter() + parentBox()->borderAndPaddingLogicalHeight();
   1894             setLogicalHeight(max(logicalHeight(), visHeight - marginsBordersPadding));
   1895         }
   1896     }
   1897 }
   1898 
   1899 int RenderBox::computeLogicalHeightUsing(const Length& h)
   1900 {
   1901     int logicalHeight = -1;
   1902     if (!h.isAuto()) {
   1903         if (h.isFixed())
   1904             logicalHeight = h.value();
   1905         else if (h.isPercent())
   1906             logicalHeight = computePercentageLogicalHeight(h);
   1907         if (logicalHeight != -1) {
   1908             logicalHeight = computeBorderBoxLogicalHeight(logicalHeight);
   1909             return logicalHeight;
   1910         }
   1911     }
   1912     return logicalHeight;
   1913 }
   1914 
   1915 int RenderBox::computePercentageLogicalHeight(const Length& height)
   1916 {
   1917     int result = -1;
   1918 
   1919     // In quirks mode, blocks with auto height are skipped, and we keep looking for an enclosing
   1920     // block that may have a specified height and then use it. In strict mode, this violates the
   1921     // specification, which states that percentage heights just revert to auto if the containing
   1922     // block has an auto height. We still skip anonymous containing blocks in both modes, though, and look
   1923     // only at explicit containers.
   1924     bool skippedAutoHeightContainingBlock = false;
   1925     RenderBlock* cb = containingBlock();
   1926     while (!cb->isRenderView() && !cb->isBody() && !cb->isTableCell() && !cb->isPositioned() && cb->style()->logicalHeight().isAuto()) {
   1927         if (!document()->inQuirksMode() && !cb->isAnonymousBlock())
   1928             break;
   1929         skippedAutoHeightContainingBlock = true;
   1930         cb = cb->containingBlock();
   1931         cb->addPercentHeightDescendant(this);
   1932     }
   1933 
   1934     // A positioned element that specified both top/bottom or that specifies height should be treated as though it has a height
   1935     // explicitly specified that can be used for any percentage computations.
   1936     // FIXME: We can't just check top/bottom here.
   1937     // https://bugs.webkit.org/show_bug.cgi?id=46500
   1938     bool isPositionedWithSpecifiedHeight = cb->isPositioned() && (!cb->style()->logicalHeight().isAuto() || (!cb->style()->top().isAuto() && !cb->style()->bottom().isAuto()));
   1939 
   1940     bool includeBorderPadding = isTable();
   1941 
   1942     // Table cells violate what the CSS spec says to do with heights.  Basically we
   1943     // don't care if the cell specified a height or not.  We just always make ourselves
   1944     // be a percentage of the cell's current content height.
   1945     if (cb->isTableCell()) {
   1946         if (!skippedAutoHeightContainingBlock) {
   1947             result = cb->overrideSize();
   1948             if (result == -1) {
   1949                 // Normally we would let the cell size intrinsically, but scrolling overflow has to be
   1950                 // treated differently, since WinIE lets scrolled overflow regions shrink as needed.
   1951                 // While we can't get all cases right, we can at least detect when the cell has a specified
   1952                 // height or when the table has a specified height.  In these cases we want to initially have
   1953                 // no size and allow the flexing of the table or the cell to its specified height to cause us
   1954                 // to grow to fill the space.  This could end up being wrong in some cases, but it is
   1955                 // preferable to the alternative (sizing intrinsically and making the row end up too big).
   1956                 RenderTableCell* cell = toRenderTableCell(cb);
   1957                 if (scrollsOverflowY() && (!cell->style()->logicalHeight().isAuto() || !cell->table()->style()->logicalHeight().isAuto()))
   1958                     return 0;
   1959                 return -1;
   1960             }
   1961             includeBorderPadding = true;
   1962         }
   1963     }
   1964     // Otherwise we only use our percentage height if our containing block had a specified
   1965     // height.
   1966     else if (cb->style()->logicalHeight().isFixed())
   1967         result = cb->computeContentBoxLogicalHeight(cb->style()->logicalHeight().value());
   1968     else if (cb->style()->logicalHeight().isPercent() && !isPositionedWithSpecifiedHeight) {
   1969         // We need to recur and compute the percentage height for our containing block.
   1970         result = cb->computePercentageLogicalHeight(cb->style()->logicalHeight());
   1971         if (result != -1)
   1972             result = cb->computeContentBoxLogicalHeight(result);
   1973     } else if (cb->isRenderView() || (cb->isBody() && document()->inQuirksMode()) || isPositionedWithSpecifiedHeight) {
   1974         // Don't allow this to affect the block' height() member variable, since this
   1975         // can get called while the block is still laying out its kids.
   1976         int oldHeight = cb->logicalHeight();
   1977         cb->computeLogicalHeight();
   1978         result = cb->contentLogicalHeight();
   1979         cb->setLogicalHeight(oldHeight);
   1980     } else if (cb->isRoot() && isPositioned())
   1981         // Match the positioned objects behavior, which is that positioned objects will fill their viewport
   1982         // always.  Note we could only hit this case by recurring into computePercentageLogicalHeight on a positioned containing block.
   1983         result = cb->computeContentBoxLogicalHeight(cb->availableLogicalHeight());
   1984 
   1985     if (result != -1) {
   1986         result = height.calcValue(result);
   1987         if (includeBorderPadding) {
   1988             // It is necessary to use the border-box to match WinIE's broken
   1989             // box model.  This is essential for sizing inside
   1990             // table cells using percentage heights.
   1991             result -= borderAndPaddingLogicalHeight();
   1992             result = max(0, result);
   1993         }
   1994     }
   1995     return result;
   1996 }
   1997 
   1998 int RenderBox::computeReplacedLogicalWidth(bool includeMaxWidth) const
   1999 {
   2000     int logicalWidth = computeReplacedLogicalWidthUsing(style()->logicalWidth());
   2001     int minLogicalWidth = computeReplacedLogicalWidthUsing(style()->logicalMinWidth());
   2002     int maxLogicalWidth = !includeMaxWidth || style()->logicalMaxWidth().isUndefined() ? logicalWidth : computeReplacedLogicalWidthUsing(style()->logicalMaxWidth());
   2003 
   2004     return max(minLogicalWidth, min(logicalWidth, maxLogicalWidth));
   2005 }
   2006 
   2007 int RenderBox::computeReplacedLogicalWidthUsing(Length logicalWidth) const
   2008 {
   2009     switch (logicalWidth.type()) {
   2010         case Fixed:
   2011             return computeContentBoxLogicalWidth(logicalWidth.value());
   2012         case Percent: {
   2013             // FIXME: containingBlockLogicalWidthForContent() is wrong if the replaced element's block-flow is perpendicular to the
   2014             // containing block's block-flow.
   2015             // https://bugs.webkit.org/show_bug.cgi?id=46496
   2016             const int cw = isPositioned() ? containingBlockLogicalWidthForPositioned(toRenderBoxModelObject(container())) : containingBlockLogicalWidthForContent();
   2017             if (cw > 0)
   2018                 return computeContentBoxLogicalWidth(logicalWidth.calcMinValue(cw));
   2019         }
   2020         // fall through
   2021         default:
   2022             return intrinsicLogicalWidth();
   2023      }
   2024 }
   2025 
   2026 int RenderBox::computeReplacedLogicalHeight() const
   2027 {
   2028     int logicalHeight = computeReplacedLogicalHeightUsing(style()->logicalHeight());
   2029     int minLogicalHeight = computeReplacedLogicalHeightUsing(style()->logicalMinHeight());
   2030     int maxLogicalHeight = style()->logicalMaxHeight().isUndefined() ? logicalHeight : computeReplacedLogicalHeightUsing(style()->logicalMaxHeight());
   2031 
   2032     return max(minLogicalHeight, min(logicalHeight, maxLogicalHeight));
   2033 }
   2034 
   2035 int RenderBox::computeReplacedLogicalHeightUsing(Length logicalHeight) const
   2036 {
   2037     switch (logicalHeight.type()) {
   2038         case Fixed:
   2039             return computeContentBoxLogicalHeight(logicalHeight.value());
   2040         case Percent:
   2041         {
   2042             RenderObject* cb = isPositioned() ? container() : containingBlock();
   2043             while (cb->isAnonymous()) {
   2044                 cb = cb->containingBlock();
   2045                 toRenderBlock(cb)->addPercentHeightDescendant(const_cast<RenderBox*>(this));
   2046             }
   2047 
   2048             // FIXME: This calculation is not patched for block-flow yet.
   2049             // https://bugs.webkit.org/show_bug.cgi?id=46500
   2050             if (cb->isPositioned() && cb->style()->height().isAuto() && !(cb->style()->top().isAuto() || cb->style()->bottom().isAuto())) {
   2051                 ASSERT(cb->isRenderBlock());
   2052                 RenderBlock* block = toRenderBlock(cb);
   2053                 int oldHeight = block->height();
   2054                 block->computeLogicalHeight();
   2055                 int newHeight = block->computeContentBoxLogicalHeight(block->contentHeight());
   2056                 block->setHeight(oldHeight);
   2057                 return computeContentBoxLogicalHeight(logicalHeight.calcValue(newHeight));
   2058             }
   2059 
   2060             // FIXME: availableLogicalHeight() is wrong if the replaced element's block-flow is perpendicular to the
   2061             // containing block's block-flow.
   2062             // https://bugs.webkit.org/show_bug.cgi?id=46496
   2063             int availableHeight = isPositioned() ? containingBlockLogicalHeightForPositioned(toRenderBoxModelObject(cb)) : toRenderBox(cb)->availableLogicalHeight();
   2064 
   2065             // It is necessary to use the border-box to match WinIE's broken
   2066             // box model.  This is essential for sizing inside
   2067             // table cells using percentage heights.
   2068             // FIXME: This needs to be made block-flow-aware.  If the cell and image are perpendicular block-flows, this isn't right.
   2069             // https://bugs.webkit.org/show_bug.cgi?id=46997
   2070             if (cb->isTableCell() && (cb->style()->logicalHeight().isAuto() || cb->style()->logicalHeight().isPercent())) {
   2071                 // Don't let table cells squeeze percent-height replaced elements
   2072                 // <http://bugs.webkit.org/show_bug.cgi?id=15359>
   2073                 availableHeight = max(availableHeight, intrinsicLogicalHeight());
   2074                 return logicalHeight.calcValue(availableHeight - borderAndPaddingLogicalHeight());
   2075             }
   2076 
   2077             return computeContentBoxLogicalHeight(logicalHeight.calcValue(availableHeight));
   2078         }
   2079         default:
   2080             return intrinsicLogicalHeight();
   2081     }
   2082 }
   2083 
   2084 int RenderBox::availableLogicalHeight() const
   2085 {
   2086     return availableLogicalHeightUsing(style()->logicalHeight());
   2087 }
   2088 
   2089 int RenderBox::availableLogicalHeightUsing(const Length& h) const
   2090 {
   2091     if (h.isFixed())
   2092         return computeContentBoxLogicalHeight(h.value());
   2093 
   2094     if (isRenderView())
   2095         return isHorizontalWritingMode() ? toRenderView(this)->frameView()->visibleHeight() : toRenderView(this)->frameView()->visibleWidth();
   2096 
   2097     // We need to stop here, since we don't want to increase the height of the table
   2098     // artificially.  We're going to rely on this cell getting expanded to some new
   2099     // height, and then when we lay out again we'll use the calculation below.
   2100     if (isTableCell() && (h.isAuto() || h.isPercent()))
   2101         return overrideSize() - borderAndPaddingLogicalWidth();
   2102 
   2103     if (h.isPercent())
   2104        return computeContentBoxLogicalHeight(h.calcValue(containingBlock()->availableLogicalHeight()));
   2105 
   2106     // FIXME: We can't just check top/bottom here.
   2107     // https://bugs.webkit.org/show_bug.cgi?id=46500
   2108     if (isRenderBlock() && isPositioned() && style()->height().isAuto() && !(style()->top().isAuto() || style()->bottom().isAuto())) {
   2109         RenderBlock* block = const_cast<RenderBlock*>(toRenderBlock(this));
   2110         int oldHeight = block->logicalHeight();
   2111         block->computeLogicalHeight();
   2112         int newHeight = block->computeContentBoxLogicalHeight(block->contentLogicalHeight());
   2113         block->setLogicalHeight(oldHeight);
   2114         return computeContentBoxLogicalHeight(newHeight);
   2115     }
   2116 
   2117     return containingBlock()->availableLogicalHeight();
   2118 }
   2119 
   2120 void RenderBox::computeBlockDirectionMargins(RenderBlock* containingBlock)
   2121 {
   2122     if (isTableCell()) {
   2123         // FIXME: Not right if we allow cells to have different directionality than the table.  If we do allow this, though,
   2124         // we may just do it with an extra anonymous block inside the cell.
   2125         setMarginBefore(0);
   2126         setMarginAfter(0);
   2127         return;
   2128     }
   2129 
   2130     // Margins are calculated with respect to the logical width of
   2131     // the containing block (8.3)
   2132     int cw = containingBlockLogicalWidthForContent();
   2133 
   2134     RenderStyle* containingBlockStyle = containingBlock->style();
   2135     containingBlock->setMarginBeforeForChild(this, style()->marginBeforeUsing(containingBlockStyle).calcMinValue(cw));
   2136     containingBlock->setMarginAfterForChild(this, style()->marginAfterUsing(containingBlockStyle).calcMinValue(cw));
   2137 }
   2138 
   2139 int RenderBox::containingBlockLogicalWidthForPositioned(const RenderBoxModelObject* containingBlock, bool checkForPerpendicularWritingMode) const
   2140 {
   2141 #if PLATFORM(ANDROID)
   2142     // Fixed element's position should be decided by the visible screen size.
   2143     // That is in the doc coordindate.
   2144     if (style()->position() == FixedPosition && containingBlock->isRenderView()) {
   2145         const RenderView* view = toRenderView(containingBlock);
   2146         return PlatformBridge::screenWidthInDocCoord(view->frameView());
   2147     }
   2148 #endif
   2149 
   2150     if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWritingMode() != isHorizontalWritingMode())
   2151         return containingBlockLogicalHeightForPositioned(containingBlock, false);
   2152 
   2153     if (containingBlock->isBox())
   2154         return toRenderBox(containingBlock)->clientLogicalWidth();
   2155 
   2156     ASSERT(containingBlock->isRenderInline() && containingBlock->isRelPositioned());
   2157 
   2158     const RenderInline* flow = toRenderInline(containingBlock);
   2159     InlineFlowBox* first = flow->firstLineBox();
   2160     InlineFlowBox* last = flow->lastLineBox();
   2161 
   2162     // If the containing block is empty, return a width of 0.
   2163     if (!first || !last)
   2164         return 0;
   2165 
   2166     int fromLeft;
   2167     int fromRight;
   2168     if (containingBlock->style()->isLeftToRightDirection()) {
   2169         fromLeft = first->logicalLeft() + first->borderLogicalLeft();
   2170         fromRight = last->logicalLeft() + last->logicalWidth() - last->borderLogicalRight();
   2171     } else {
   2172         fromRight = first->logicalLeft() + first->logicalWidth() - first->borderLogicalRight();
   2173         fromLeft = last->logicalLeft() + last->borderLogicalLeft();
   2174     }
   2175 
   2176     return max(0, (fromRight - fromLeft));
   2177 }
   2178 
   2179 int RenderBox::containingBlockLogicalHeightForPositioned(const RenderBoxModelObject* containingBlock, bool checkForPerpendicularWritingMode) const
   2180 {
   2181 #if PLATFORM(ANDROID)
   2182     // Fixed element's position should be decided by the visible screen size.
   2183     // That is in the doc coordindate.
   2184     if (style()->position() == FixedPosition && containingBlock->isRenderView()) {
   2185         const RenderView* view = toRenderView(containingBlock);
   2186         return PlatformBridge::screenHeightInDocCoord(view->frameView());
   2187     }
   2188 #endif
   2189 
   2190     if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWritingMode() != isHorizontalWritingMode())
   2191         return containingBlockLogicalWidthForPositioned(containingBlock, false);
   2192 
   2193     if (containingBlock->isBox())
   2194         return toRenderBox(containingBlock)->clientLogicalHeight();
   2195 
   2196     ASSERT(containingBlock->isRenderInline() && containingBlock->isRelPositioned());
   2197 
   2198     const RenderInline* flow = toRenderInline(containingBlock);
   2199     InlineFlowBox* first = flow->firstLineBox();
   2200     InlineFlowBox* last = flow->lastLineBox();
   2201 
   2202     // If the containing block is empty, return a height of 0.
   2203     if (!first || !last)
   2204         return 0;
   2205 
   2206     int heightResult;
   2207     IntRect boundingBox = flow->linesBoundingBox();
   2208     if (containingBlock->isHorizontalWritingMode())
   2209         heightResult = boundingBox.height();
   2210     else
   2211         heightResult = boundingBox.width();
   2212     heightResult -= (containingBlock->borderBefore() + containingBlock->borderAfter());
   2213     return heightResult;
   2214 }
   2215 
   2216 static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRight, const RenderBox* child, const RenderBoxModelObject* containerBlock, int containerLogicalWidth,
   2217                                         TextDirection containerDirection)
   2218 {
   2219     if (!logicalLeft.isAuto() || !logicalRight.isAuto())
   2220         return;
   2221 
   2222     // FIXME: The static distance computation has not been patched for mixed writing modes yet.
   2223     if (containerDirection == LTR) {
   2224         int staticPosition = child->layer()->staticInlinePosition() - containerBlock->borderLogicalLeft();
   2225         for (RenderObject* curr = child->parent(); curr && curr != containerBlock; curr = curr->container()) {
   2226             if (curr->isBox())
   2227                 staticPosition += toRenderBox(curr)->logicalLeft();
   2228         }
   2229         logicalLeft.setValue(Fixed, staticPosition);
   2230     } else {
   2231         RenderBox* enclosingBox = child->parent()->enclosingBox();
   2232         int staticPosition = child->layer()->staticInlinePosition() + containerLogicalWidth + containerBlock->borderLogicalRight();
   2233         staticPosition -= enclosingBox->logicalWidth();
   2234         for (RenderObject* curr = enclosingBox; curr && curr != containerBlock; curr = curr->container()) {
   2235             if (curr->isBox())
   2236                 staticPosition -= toRenderBox(curr)->logicalLeft();
   2237         }
   2238         logicalRight.setValue(Fixed, staticPosition);
   2239     }
   2240 }
   2241 
   2242 void RenderBox::computePositionedLogicalWidth()
   2243 {
   2244     if (isReplaced()) {
   2245         computePositionedLogicalWidthReplaced();
   2246         return;
   2247     }
   2248 
   2249     // QUESTIONS
   2250     // FIXME 1: Which RenderObject's 'direction' property should used: the
   2251     // containing block (cb) as the spec seems to imply, the parent (parent()) as
   2252     // was previously done in calculating the static distances, or ourself, which
   2253     // was also previously done for deciding what to override when you had
   2254     // over-constrained margins?  Also note that the container block is used
   2255     // in similar situations in other parts of the RenderBox class (see computeLogicalWidth()
   2256     // and computeMarginsInContainingBlockInlineDirection()). For now we are using the parent for quirks
   2257     // mode and the containing block for strict mode.
   2258 
   2259     // FIXME 2: Should we still deal with these the cases of 'left' or 'right' having
   2260     // the type 'static' in determining whether to calculate the static distance?
   2261     // NOTE: 'static' is not a legal value for 'left' or 'right' as of CSS 2.1.
   2262 
   2263     // FIXME 3: Can perhaps optimize out cases when max-width/min-width are greater
   2264     // than or less than the computed width().  Be careful of box-sizing and
   2265     // percentage issues.
   2266 
   2267     // The following is based off of the W3C Working Draft from April 11, 2006 of
   2268     // CSS 2.1: Section 10.3.7 "Absolutely positioned, non-replaced elements"
   2269     // <http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width>
   2270     // (block-style-comments in this function and in computePositionedLogicalWidthUsing()
   2271     // correspond to text from the spec)
   2272 
   2273 
   2274     // We don't use containingBlock(), since we may be positioned by an enclosing
   2275     // relative positioned inline.
   2276     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
   2277 
   2278     const int containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock);
   2279 
   2280     // To match WinIE, in quirks mode use the parent's 'direction' property
   2281     // instead of the the container block's.
   2282     TextDirection containerDirection = (document()->inQuirksMode()) ? parent()->style()->direction() : containerBlock->style()->direction();
   2283 
   2284     bool isHorizontal = isHorizontalWritingMode();
   2285     const int bordersPlusPadding = borderAndPaddingLogicalWidth();
   2286     const Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->marginTop();
   2287     const Length marginLogicalRight = isHorizontal ? style()->marginRight() : style()->marginBottom();
   2288     int& marginLogicalLeftAlias = isHorizontal ? m_marginLeft : m_marginTop;
   2289     int& marginLogicalRightAlias = isHorizontal ? m_marginRight : m_marginBottom;
   2290 
   2291     Length logicalLeft = style()->logicalLeft();
   2292     Length logicalRight = style()->logicalRight();
   2293 
   2294     /*---------------------------------------------------------------------------*\
   2295      * For the purposes of this section and the next, the term "static position"
   2296      * (of an element) refers, roughly, to the position an element would have had
   2297      * in the normal flow. More precisely:
   2298      *
   2299      * * The static position for 'left' is the distance from the left edge of the
   2300      *   containing block to the left margin edge of a hypothetical box that would
   2301      *   have been the first box of the element if its 'position' property had
   2302      *   been 'static' and 'float' had been 'none'. The value is negative if the
   2303      *   hypothetical box is to the left of the containing block.
   2304      * * The static position for 'right' is the distance from the right edge of the
   2305      *   containing block to the right margin edge of the same hypothetical box as
   2306      *   above. The value is positive if the hypothetical box is to the left of the
   2307      *   containing block's edge.
   2308      *
   2309      * But rather than actually calculating the dimensions of that hypothetical box,
   2310      * user agents are free to make a guess at its probable position.
   2311      *
   2312      * For the purposes of calculating the static position, the containing block of
   2313      * fixed positioned elements is the initial containing block instead of the
   2314      * viewport, and all scrollable boxes should be assumed to be scrolled to their
   2315      * origin.
   2316     \*---------------------------------------------------------------------------*/
   2317 
   2318     // see FIXME 2
   2319     // Calculate the static distance if needed.
   2320     computeInlineStaticDistance(logicalLeft, logicalRight, this, containerBlock, containerLogicalWidth, containerDirection);
   2321 
   2322     // Calculate constraint equation values for 'width' case.
   2323     int logicalWidthResult;
   2324     int logicalLeftResult;
   2325     computePositionedLogicalWidthUsing(style()->logicalWidth(), containerBlock, containerDirection,
   2326                                        containerLogicalWidth, bordersPlusPadding,
   2327                                        logicalLeft, logicalRight, marginLogicalLeft, marginLogicalRight,
   2328                                        logicalWidthResult, marginLogicalLeftAlias, marginLogicalRightAlias, logicalLeftResult);
   2329     setLogicalWidth(logicalWidthResult);
   2330     setLogicalLeft(logicalLeftResult);
   2331 
   2332     // Calculate constraint equation values for 'max-width' case.
   2333     if (!style()->logicalMaxWidth().isUndefined()) {
   2334         int maxLogicalWidth;
   2335         int maxMarginLogicalLeft;
   2336         int maxMarginLogicalRight;
   2337         int maxLogicalLeftPos;
   2338 
   2339         computePositionedLogicalWidthUsing(style()->logicalMaxWidth(), containerBlock, containerDirection,
   2340                                            containerLogicalWidth, bordersPlusPadding,
   2341                                            logicalLeft, logicalRight, marginLogicalLeft, marginLogicalRight,
   2342                                            maxLogicalWidth, maxMarginLogicalLeft, maxMarginLogicalRight, maxLogicalLeftPos);
   2343 
   2344         if (logicalWidth() > maxLogicalWidth) {
   2345             setLogicalWidth(maxLogicalWidth);
   2346             marginLogicalLeftAlias = maxMarginLogicalLeft;
   2347             marginLogicalRightAlias = maxMarginLogicalRight;
   2348             setLogicalLeft(maxLogicalLeftPos);
   2349         }
   2350     }
   2351 
   2352     // Calculate constraint equation values for 'min-width' case.
   2353     if (!style()->logicalMinWidth().isZero()) {
   2354         int minLogicalWidth;
   2355         int minMarginLogicalLeft;
   2356         int minMarginLogicalRight;
   2357         int minLogicalLeftPos;
   2358 
   2359         computePositionedLogicalWidthUsing(style()->logicalMinWidth(), containerBlock, containerDirection,
   2360                                            containerLogicalWidth, bordersPlusPadding,
   2361                                            logicalLeft, logicalRight, marginLogicalLeft, marginLogicalRight,
   2362                                            minLogicalWidth, minMarginLogicalLeft, minMarginLogicalRight, minLogicalLeftPos);
   2363 
   2364         if (logicalWidth() < minLogicalWidth) {
   2365             setLogicalWidth(minLogicalWidth);
   2366             marginLogicalLeftAlias = minMarginLogicalLeft;
   2367             marginLogicalRightAlias = minMarginLogicalRight;
   2368             setLogicalLeft(minLogicalLeftPos);
   2369         }
   2370     }
   2371 
   2372     if (stretchesToMinIntrinsicLogicalWidth() && logicalWidth() < minPreferredLogicalWidth() - bordersPlusPadding) {
   2373         computePositionedLogicalWidthUsing(Length(minPreferredLogicalWidth() - bordersPlusPadding, Fixed), containerBlock, containerDirection,
   2374                                            containerLogicalWidth, bordersPlusPadding,
   2375                                            logicalLeft, logicalRight, marginLogicalLeft, marginLogicalRight,
   2376                                            logicalWidthResult, marginLogicalLeftAlias, marginLogicalRightAlias, logicalLeftResult);
   2377         setLogicalWidth(logicalWidthResult);
   2378         setLogicalLeft(logicalLeftResult);
   2379     }
   2380 
   2381     // Put logicalWidth() into correct form.
   2382     setLogicalWidth(logicalWidth() + bordersPlusPadding);
   2383 }
   2384 
   2385 static void computeLogicalLeftPositionedOffset(int& logicalLeftPos, const RenderBox* child, int logicalWidthValue, const RenderBoxModelObject* containerBlock, int containerLogicalWidth)
   2386 {
   2387     // Deal with differing writing modes here.  Our offset needs to be in the containing block's coordinate space. If the containing block is flipped
   2388     // 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.
   2389     if (containerBlock->isHorizontalWritingMode() != child->isHorizontalWritingMode() && containerBlock->style()->isFlippedBlocksWritingMode()) {
   2390         logicalLeftPos = containerLogicalWidth - logicalWidthValue - logicalLeftPos;
   2391         logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->borderRight() : containerBlock->borderBottom());
   2392     } else
   2393         logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->borderLeft() : containerBlock->borderTop());
   2394 }
   2395 
   2396 void RenderBox::computePositionedLogicalWidthUsing(Length logicalWidth, const RenderBoxModelObject* containerBlock, TextDirection containerDirection,
   2397                                                    int containerLogicalWidth, int bordersPlusPadding,
   2398                                                    Length logicalLeft, Length logicalRight, Length marginLogicalLeft, Length marginLogicalRight,
   2399                                                    int& logicalWidthValue, int& marginLogicalLeftValue, int& marginLogicalRightValue, int& logicalLeftPos)
   2400 {
   2401     // 'left' and 'right' cannot both be 'auto' because one would of been
   2402     // converted to the static position already
   2403     ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto()));
   2404 
   2405     int logicalLeftValue = 0;
   2406 
   2407     bool logicalWidthIsAuto = logicalWidth.isIntrinsicOrAuto();
   2408     bool logicalLeftIsAuto = logicalLeft.isAuto();
   2409     bool logicalRightIsAuto = logicalRight.isAuto();
   2410 
   2411     if (!logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) {
   2412         /*-----------------------------------------------------------------------*\
   2413          * If none of the three is 'auto': If both 'margin-left' and 'margin-
   2414          * right' are 'auto', solve the equation under the extra constraint that
   2415          * the two margins get equal values, unless this would make them negative,
   2416          * in which case when direction of the containing block is 'ltr' ('rtl'),
   2417          * set 'margin-left' ('margin-right') to zero and solve for 'margin-right'
   2418          * ('margin-left'). If one of 'margin-left' or 'margin-right' is 'auto',
   2419          * solve the equation for that value. If the values are over-constrained,
   2420          * ignore the value for 'left' (in case the 'direction' property of the
   2421          * containing block is 'rtl') or 'right' (in case 'direction' is 'ltr')
   2422          * and solve for that value.
   2423         \*-----------------------------------------------------------------------*/
   2424         // NOTE:  It is not necessary to solve for 'right' in the over constrained
   2425         // case because the value is not used for any further calculations.
   2426 
   2427         logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2428         logicalWidthValue = computeContentBoxLogicalWidth(logicalWidth.calcValue(containerLogicalWidth));
   2429 
   2430         const int availableSpace = containerLogicalWidth - (logicalLeftValue + logicalWidthValue + logicalRight.calcValue(containerLogicalWidth) + bordersPlusPadding);
   2431 
   2432         // Margins are now the only unknown
   2433         if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) {
   2434             // Both margins auto, solve for equality
   2435             if (availableSpace >= 0) {
   2436                 marginLogicalLeftValue = availableSpace / 2; // split the difference
   2437                 marginLogicalRightValue = availableSpace - marginLogicalLeftValue; // account for odd valued differences
   2438             } else {
   2439                 // see FIXME 1
   2440                 if (containerDirection == LTR) {
   2441                     marginLogicalLeftValue = 0;
   2442                     marginLogicalRightValue = availableSpace; // will be negative
   2443                 } else {
   2444                     marginLogicalLeftValue = availableSpace; // will be negative
   2445                     marginLogicalRightValue = 0;
   2446                 }
   2447             }
   2448         } else if (marginLogicalLeft.isAuto()) {
   2449             // Solve for left margin
   2450             marginLogicalRightValue = marginLogicalRight.calcValue(containerLogicalWidth);
   2451             marginLogicalLeftValue = availableSpace - marginLogicalRightValue;
   2452         } else if (marginLogicalRight.isAuto()) {
   2453             // Solve for right margin
   2454             marginLogicalLeftValue = marginLogicalLeft.calcValue(containerLogicalWidth);
   2455             marginLogicalRightValue = availableSpace - marginLogicalLeftValue;
   2456         } else {
   2457             // Over-constrained, solve for left if direction is RTL
   2458             marginLogicalLeftValue = marginLogicalLeft.calcValue(containerLogicalWidth);
   2459             marginLogicalRightValue = marginLogicalRight.calcValue(containerLogicalWidth);
   2460 
   2461             // see FIXME 1 -- used to be "this->style()->direction()"
   2462             if (containerDirection == RTL)
   2463                 logicalLeftValue = (availableSpace + logicalLeftValue) - marginLogicalLeftValue - marginLogicalRightValue;
   2464         }
   2465     } else {
   2466         /*--------------------------------------------------------------------*\
   2467          * Otherwise, set 'auto' values for 'margin-left' and 'margin-right'
   2468          * to 0, and pick the one of the following six rules that applies.
   2469          *
   2470          * 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the
   2471          *    width is shrink-to-fit. Then solve for 'left'
   2472          *
   2473          *              OMIT RULE 2 AS IT SHOULD NEVER BE HIT
   2474          * ------------------------------------------------------------------
   2475          * 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if
   2476          *    the 'direction' property of the containing block is 'ltr' set
   2477          *    'left' to the static position, otherwise set 'right' to the
   2478          *    static position. Then solve for 'left' (if 'direction is 'rtl')
   2479          *    or 'right' (if 'direction' is 'ltr').
   2480          * ------------------------------------------------------------------
   2481          *
   2482          * 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the
   2483          *    width is shrink-to-fit . Then solve for 'right'
   2484          * 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve
   2485          *    for 'left'
   2486          * 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve
   2487          *    for 'width'
   2488          * 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve
   2489          *    for 'right'
   2490          *
   2491          * Calculation of the shrink-to-fit width is similar to calculating the
   2492          * width of a table cell using the automatic table layout algorithm.
   2493          * Roughly: calculate the preferred width by formatting the content
   2494          * without breaking lines other than where explicit line breaks occur,
   2495          * and also calculate the preferred minimum width, e.g., by trying all
   2496          * possible line breaks. CSS 2.1 does not define the exact algorithm.
   2497          * Thirdly, calculate the available width: this is found by solving
   2498          * for 'width' after setting 'left' (in case 1) or 'right' (in case 3)
   2499          * to 0.
   2500          *
   2501          * Then the shrink-to-fit width is:
   2502          * min(max(preferred minimum width, available width), preferred width).
   2503         \*--------------------------------------------------------------------*/
   2504         // NOTE: For rules 3 and 6 it is not necessary to solve for 'right'
   2505         // because the value is not used for any further calculations.
   2506 
   2507         // Calculate margins, 'auto' margins are ignored.
   2508         marginLogicalLeftValue = marginLogicalLeft.calcMinValue(containerLogicalWidth);
   2509         marginLogicalRightValue = marginLogicalRight.calcMinValue(containerLogicalWidth);
   2510 
   2511         const int availableSpace = containerLogicalWidth - (marginLogicalLeftValue + marginLogicalRightValue + bordersPlusPadding);
   2512 
   2513         // FIXME: Is there a faster way to find the correct case?
   2514         // Use rule/case that applies.
   2515         if (logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAuto) {
   2516             // RULE 1: (use shrink-to-fit for width, and solve of left)
   2517             int logicalRightValue = logicalRight.calcValue(containerLogicalWidth);
   2518 
   2519             // FIXME: would it be better to have shrink-to-fit in one step?
   2520             int preferredWidth = maxPreferredLogicalWidth() - bordersPlusPadding;
   2521             int preferredMinWidth = minPreferredLogicalWidth() - bordersPlusPadding;
   2522             int availableWidth = availableSpace - logicalRightValue;
   2523             logicalWidthValue = min(max(preferredMinWidth, availableWidth), preferredWidth);
   2524             logicalLeftValue = availableSpace - (logicalWidthValue + logicalRightValue);
   2525         } else if (!logicalLeftIsAuto && logicalWidthIsAuto && logicalRightIsAuto) {
   2526             // RULE 3: (use shrink-to-fit for width, and no need solve of right)
   2527             logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2528 
   2529             // FIXME: would it be better to have shrink-to-fit in one step?
   2530             int preferredWidth = maxPreferredLogicalWidth() - bordersPlusPadding;
   2531             int preferredMinWidth = minPreferredLogicalWidth() - bordersPlusPadding;
   2532             int availableWidth = availableSpace - logicalLeftValue;
   2533             logicalWidthValue = min(max(preferredMinWidth, availableWidth), preferredWidth);
   2534         } else if (logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) {
   2535             // RULE 4: (solve for left)
   2536             logicalWidthValue = computeContentBoxLogicalWidth(logicalWidth.calcValue(containerLogicalWidth));
   2537             logicalLeftValue = availableSpace - (logicalWidthValue + logicalRight.calcValue(containerLogicalWidth));
   2538         } else if (!logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAuto) {
   2539             // RULE 5: (solve for width)
   2540             logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2541             logicalWidthValue = availableSpace - (logicalLeftValue + logicalRight.calcValue(containerLogicalWidth));
   2542         } else if (!logicalLeftIsAuto && !logicalWidthIsAuto && logicalRightIsAuto) {
   2543             // RULE 6: (no need solve for right)
   2544             logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2545             logicalWidthValue = computeContentBoxLogicalWidth(logicalWidth.calcValue(containerLogicalWidth));
   2546         }
   2547     }
   2548 
   2549     // Use computed values to calculate the horizontal position.
   2550 
   2551     // FIXME: This hack is needed to calculate the  logical left position for a 'rtl' relatively
   2552     // positioned, inline because right now, it is using the logical left position
   2553     // of the first line box when really it should use the last line box.  When
   2554     // this is fixed elsewhere, this block should be removed.
   2555     if (containerBlock->isRenderInline() && !containerBlock->style()->isLeftToRightDirection()) {
   2556         const RenderInline* flow = toRenderInline(containerBlock);
   2557         InlineFlowBox* firstLine = flow->firstLineBox();
   2558         InlineFlowBox* lastLine = flow->lastLineBox();
   2559         if (firstLine && lastLine && firstLine != lastLine) {
   2560             logicalLeftPos = logicalLeftValue + marginLogicalLeftValue + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logicalLeft());
   2561             return;
   2562         }
   2563     }
   2564 
   2565     logicalLeftPos = logicalLeftValue + marginLogicalLeftValue;
   2566     computeLogicalLeftPositionedOffset(logicalLeftPos, this, logicalWidthValue, containerBlock, containerLogicalWidth);
   2567 }
   2568 
   2569 static void computeBlockStaticDistance(Length& logicalTop, Length& logicalBottom, const RenderBox* child, const RenderBoxModelObject* containerBlock)
   2570 {
   2571     if (!logicalTop.isAuto() || !logicalBottom.isAuto())
   2572         return;
   2573 
   2574     // FIXME: The static distance computation has not been patched for mixed writing modes.
   2575     int staticLogicalTop = child->layer()->staticBlockPosition() - containerBlock->borderBefore();
   2576     for (RenderObject* curr = child->parent(); curr && curr != containerBlock; curr = curr->container()) {
   2577         if (curr->isBox() && !curr->isTableRow())
   2578             staticLogicalTop += toRenderBox(curr)->logicalTop();
   2579     }
   2580     logicalTop.setValue(Fixed, staticLogicalTop);
   2581 }
   2582 
   2583 void RenderBox::computePositionedLogicalHeight()
   2584 {
   2585     if (isReplaced()) {
   2586         computePositionedLogicalHeightReplaced();
   2587         return;
   2588     }
   2589 
   2590     // The following is based off of the W3C Working Draft from April 11, 2006 of
   2591     // CSS 2.1: Section 10.6.4 "Absolutely positioned, non-replaced elements"
   2592     // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-non-replaced-height>
   2593     // (block-style-comments in this function and in computePositionedLogicalHeightUsing()
   2594     // correspond to text from the spec)
   2595 
   2596 
   2597     // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
   2598     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
   2599 
   2600     const int containerLogicalHeight = containingBlockLogicalHeightForPositioned(containerBlock);
   2601 
   2602     bool isHorizontal = isHorizontalWritingMode();
   2603     bool isFlipped = style()->isFlippedBlocksWritingMode();
   2604     const int bordersPlusPadding = borderAndPaddingLogicalHeight();
   2605     const Length marginBefore = style()->marginBefore();
   2606     const Length marginAfter = style()->marginAfter();
   2607     int& marginBeforeAlias = isHorizontal ? (isFlipped ? m_marginBottom : m_marginTop) : (isFlipped ? m_marginRight: m_marginLeft);
   2608     int& marginAfterAlias = isHorizontal ? (isFlipped ? m_marginTop : m_marginBottom) : (isFlipped ? m_marginLeft: m_marginRight);
   2609 
   2610     Length logicalTop = style()->logicalTop();
   2611     Length logicalBottom = style()->logicalBottom();
   2612 
   2613     /*---------------------------------------------------------------------------*\
   2614      * For the purposes of this section and the next, the term "static position"
   2615      * (of an element) refers, roughly, to the position an element would have had
   2616      * in the normal flow. More precisely, the static position for 'top' is the
   2617      * distance from the top edge of the containing block to the top margin edge
   2618      * of a hypothetical box that would have been the first box of the element if
   2619      * its 'position' property had been 'static' and 'float' had been 'none'. The
   2620      * value is negative if the hypothetical box is above the containing block.
   2621      *
   2622      * But rather than actually calculating the dimensions of that hypothetical
   2623      * box, user agents are free to make a guess at its probable position.
   2624      *
   2625      * For the purposes of calculating the static position, the containing block
   2626      * of fixed positioned elements is the initial containing block instead of
   2627      * the viewport.
   2628     \*---------------------------------------------------------------------------*/
   2629 
   2630     // see FIXME 2
   2631     // Calculate the static distance if needed.
   2632     computeBlockStaticDistance(logicalTop, logicalBottom, this, containerBlock);
   2633 
   2634     int logicalHeightResult; // Needed to compute overflow.
   2635     int logicalTopPos;
   2636 
   2637     // Calculate constraint equation values for 'height' case.
   2638     computePositionedLogicalHeightUsing(style()->logicalHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding,
   2639                                         logicalTop, logicalBottom, marginBefore, marginAfter,
   2640                                         logicalHeightResult, marginBeforeAlias, marginAfterAlias, logicalTopPos);
   2641     setLogicalTop(logicalTopPos);
   2642 
   2643     // Avoid doing any work in the common case (where the values of min-height and max-height are their defaults).
   2644     // see FIXME 3
   2645 
   2646     // Calculate constraint equation values for 'max-height' case.
   2647     if (!style()->logicalMaxHeight().isUndefined()) {
   2648         int maxLogicalHeight;
   2649         int maxMarginBefore;
   2650         int maxMarginAfter;
   2651         int maxLogicalTopPos;
   2652 
   2653         computePositionedLogicalHeightUsing(style()->logicalMaxHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding,
   2654                                             logicalTop, logicalBottom, marginBefore, marginAfter,
   2655                                             maxLogicalHeight, maxMarginBefore, maxMarginAfter, maxLogicalTopPos);
   2656 
   2657         if (logicalHeightResult > maxLogicalHeight) {
   2658             logicalHeightResult = maxLogicalHeight;
   2659             marginBeforeAlias = maxMarginBefore;
   2660             marginAfterAlias = maxMarginAfter;
   2661             setLogicalTop(maxLogicalTopPos);
   2662         }
   2663     }
   2664 
   2665     // Calculate constraint equation values for 'min-height' case.
   2666     if (!style()->logicalMinHeight().isZero()) {
   2667         int minLogicalHeight;
   2668         int minMarginBefore;
   2669         int minMarginAfter;
   2670         int minLogicalTopPos;
   2671 
   2672         computePositionedLogicalHeightUsing(style()->logicalMinHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding,
   2673                                             logicalTop, logicalBottom, marginBefore, marginAfter,
   2674                                             minLogicalHeight, minMarginBefore, minMarginAfter, minLogicalTopPos);
   2675 
   2676         if (logicalHeightResult < minLogicalHeight) {
   2677             logicalHeightResult = minLogicalHeight;
   2678             marginBeforeAlias = minMarginBefore;
   2679             marginAfterAlias = minMarginAfter;
   2680             setLogicalTop(minLogicalTopPos);
   2681         }
   2682     }
   2683 
   2684     // Set final height value.
   2685     setLogicalHeight(logicalHeightResult + bordersPlusPadding);
   2686 }
   2687 
   2688 static void computeLogicalTopPositionedOffset(int& logicalTopPos, const RenderBox* child, int logicalHeightValue, const RenderBoxModelObject* containerBlock, int containerLogicalHeight)
   2689 {
   2690     // Deal with differing writing modes here.  Our offset needs to be in the containing block's coordinate space. If the containing block is flipped
   2691     // 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.
   2692     if ((child->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() != containerBlock->isHorizontalWritingMode())
   2693         || (child->style()->isFlippedBlocksWritingMode() != containerBlock->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode()))
   2694         logicalTopPos = containerLogicalHeight - logicalHeightValue - logicalTopPos;
   2695 
   2696     // Our offset is from the logical bottom edge in a flipped environment, e.g., right for vertical-rl and bottom for horizontal-bt.
   2697     if (containerBlock->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode()) {
   2698         if (child->isHorizontalWritingMode())
   2699             logicalTopPos += containerBlock->borderBottom();
   2700         else
   2701             logicalTopPos += containerBlock->borderRight();
   2702     } else {
   2703         if (child->isHorizontalWritingMode())
   2704             logicalTopPos += containerBlock->borderTop();
   2705         else
   2706             logicalTopPos += containerBlock->borderLeft();
   2707     }
   2708 }
   2709 
   2710 void RenderBox::computePositionedLogicalHeightUsing(Length logicalHeightLength, const RenderBoxModelObject* containerBlock,
   2711                                                     int containerLogicalHeight, int bordersPlusPadding,
   2712                                                     Length logicalTop, Length logicalBottom, Length marginBefore, Length marginAfter,
   2713                                                     int& logicalHeightValue, int& marginBeforeValue, int& marginAfterValue, int& logicalTopPos)
   2714 {
   2715     // 'top' and 'bottom' cannot both be 'auto' because 'top would of been
   2716     // converted to the static position in computePositionedLogicalHeight()
   2717     ASSERT(!(logicalTop.isAuto() && logicalBottom.isAuto()));
   2718 
   2719     int contentLogicalHeight = logicalHeight() - bordersPlusPadding;
   2720 
   2721     int logicalTopValue = 0;
   2722 
   2723     bool logicalHeightIsAuto = logicalHeightLength.isAuto();
   2724     bool logicalTopIsAuto = logicalTop.isAuto();
   2725     bool logicalBottomIsAuto = logicalBottom.isAuto();
   2726 
   2727     // Height is never unsolved for tables.
   2728     if (isTable()) {
   2729         logicalHeightLength.setValue(Fixed, contentLogicalHeight);
   2730         logicalHeightIsAuto = false;
   2731     }
   2732 
   2733     if (!logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsAuto) {
   2734         /*-----------------------------------------------------------------------*\
   2735          * If none of the three are 'auto': If both 'margin-top' and 'margin-
   2736          * bottom' are 'auto', solve the equation under the extra constraint that
   2737          * the two margins get equal values. If one of 'margin-top' or 'margin-
   2738          * bottom' is 'auto', solve the equation for that value. If the values
   2739          * are over-constrained, ignore the value for 'bottom' and solve for that
   2740          * value.
   2741         \*-----------------------------------------------------------------------*/
   2742         // NOTE:  It is not necessary to solve for 'bottom' in the over constrained
   2743         // case because the value is not used for any further calculations.
   2744 
   2745         logicalHeightValue = computeContentBoxLogicalHeight(logicalHeightLength.calcValue(containerLogicalHeight));
   2746         logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   2747 
   2748         const int availableSpace = containerLogicalHeight - (logicalTopValue + logicalHeightValue + logicalBottom.calcValue(containerLogicalHeight) + bordersPlusPadding);
   2749 
   2750         // Margins are now the only unknown
   2751         if (marginBefore.isAuto() && marginAfter.isAuto()) {
   2752             // Both margins auto, solve for equality
   2753             // NOTE: This may result in negative values.
   2754             marginBeforeValue = availableSpace / 2; // split the difference
   2755             marginAfterValue = availableSpace - marginBeforeValue; // account for odd valued differences
   2756         } else if (marginBefore.isAuto()) {
   2757             // Solve for top margin
   2758             marginAfterValue = marginAfter.calcValue(containerLogicalHeight);
   2759             marginBeforeValue = availableSpace - marginAfterValue;
   2760         } else if (marginAfter.isAuto()) {
   2761             // Solve for bottom margin
   2762             marginBeforeValue = marginBefore.calcValue(containerLogicalHeight);
   2763             marginAfterValue = availableSpace - marginBeforeValue;
   2764         } else {
   2765             // Over-constrained, (no need solve for bottom)
   2766             marginBeforeValue = marginBefore.calcValue(containerLogicalHeight);
   2767             marginAfterValue = marginAfter.calcValue(containerLogicalHeight);
   2768         }
   2769     } else {
   2770         /*--------------------------------------------------------------------*\
   2771          * Otherwise, set 'auto' values for 'margin-top' and 'margin-bottom'
   2772          * to 0, and pick the one of the following six rules that applies.
   2773          *
   2774          * 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then
   2775          *    the height is based on the content, and solve for 'top'.
   2776          *
   2777          *              OMIT RULE 2 AS IT SHOULD NEVER BE HIT
   2778          * ------------------------------------------------------------------
   2779          * 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then
   2780          *    set 'top' to the static position, and solve for 'bottom'.
   2781          * ------------------------------------------------------------------
   2782          *
   2783          * 3. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then
   2784          *    the height is based on the content, and solve for 'bottom'.
   2785          * 4. 'top' is 'auto', 'height' and 'bottom' are not 'auto', and
   2786          *    solve for 'top'.
   2787          * 5. 'height' is 'auto', 'top' and 'bottom' are not 'auto', and
   2788          *    solve for 'height'.
   2789          * 6. 'bottom' is 'auto', 'top' and 'height' are not 'auto', and
   2790          *    solve for 'bottom'.
   2791         \*--------------------------------------------------------------------*/
   2792         // NOTE: For rules 3 and 6 it is not necessary to solve for 'bottom'
   2793         // because the value is not used for any further calculations.
   2794 
   2795         // Calculate margins, 'auto' margins are ignored.
   2796         marginBeforeValue = marginBefore.calcMinValue(containerLogicalHeight);
   2797         marginAfterValue = marginAfter.calcMinValue(containerLogicalHeight);
   2798 
   2799         const int availableSpace = containerLogicalHeight - (marginBeforeValue + marginAfterValue + bordersPlusPadding);
   2800 
   2801         // Use rule/case that applies.
   2802         if (logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) {
   2803             // RULE 1: (height is content based, solve of top)
   2804             logicalHeightValue = contentLogicalHeight;
   2805             logicalTopValue = availableSpace - (logicalHeightValue + logicalBottom.calcValue(containerLogicalHeight));
   2806         } else if (!logicalTopIsAuto && logicalHeightIsAuto && logicalBottomIsAuto) {
   2807             // RULE 3: (height is content based, no need solve of bottom)
   2808             logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   2809             logicalHeightValue = contentLogicalHeight;
   2810         } else if (logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsAuto) {
   2811             // RULE 4: (solve of top)
   2812             logicalHeightValue = computeContentBoxLogicalHeight(logicalHeightLength.calcValue(containerLogicalHeight));
   2813             logicalTopValue = availableSpace - (logicalHeightValue + logicalBottom.calcValue(containerLogicalHeight));
   2814         } else if (!logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) {
   2815             // RULE 5: (solve of height)
   2816             logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   2817             logicalHeightValue = max(0, availableSpace - (logicalTopValue + logicalBottom.calcValue(containerLogicalHeight)));
   2818         } else if (!logicalTopIsAuto && !logicalHeightIsAuto && logicalBottomIsAuto) {
   2819             // RULE 6: (no need solve of bottom)
   2820             logicalHeightValue = computeContentBoxLogicalHeight(logicalHeightLength.calcValue(containerLogicalHeight));
   2821             logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   2822         }
   2823     }
   2824 
   2825     // Use computed values to calculate the vertical position.
   2826     logicalTopPos = logicalTopValue + marginBeforeValue;
   2827     computeLogicalTopPositionedOffset(logicalTopPos, this, logicalHeightValue, containerBlock, containerLogicalHeight);
   2828 }
   2829 
   2830 void RenderBox::computePositionedLogicalWidthReplaced()
   2831 {
   2832     // The following is based off of the W3C Working Draft from April 11, 2006 of
   2833     // CSS 2.1: Section 10.3.8 "Absolutely positioned, replaced elements"
   2834     // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-width>
   2835     // (block-style-comments in this function correspond to text from the spec and
   2836     // the numbers correspond to numbers in spec)
   2837 
   2838     // We don't use containingBlock(), since we may be positioned by an enclosing
   2839     // relative positioned inline.
   2840     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
   2841 
   2842     const int containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock);
   2843 
   2844     // To match WinIE, in quirks mode use the parent's 'direction' property
   2845     // instead of the the container block's.
   2846     TextDirection containerDirection = (document()->inQuirksMode()) ? parent()->style()->direction() : containerBlock->style()->direction();
   2847 
   2848     // Variables to solve.
   2849     bool isHorizontal = isHorizontalWritingMode();
   2850     Length logicalLeft = style()->logicalLeft();
   2851     Length logicalRight = style()->logicalRight();
   2852     Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->marginTop();
   2853     Length marginLogicalRight = isHorizontal ? style()->marginRight() : style()->marginBottom();
   2854     int& marginLogicalLeftAlias = isHorizontal ? m_marginLeft : m_marginTop;
   2855     int& marginLogicalRightAlias = isHorizontal ? m_marginRight : m_marginBottom;
   2856 
   2857     /*-----------------------------------------------------------------------*\
   2858      * 1. The used value of 'width' is determined as for inline replaced
   2859      *    elements.
   2860     \*-----------------------------------------------------------------------*/
   2861     // NOTE: This value of width is FINAL in that the min/max width calculations
   2862     // are dealt with in computeReplacedWidth().  This means that the steps to produce
   2863     // correct max/min in the non-replaced version, are not necessary.
   2864     setLogicalWidth(computeReplacedLogicalWidth() + borderAndPaddingLogicalWidth());
   2865     const int availableSpace = containerLogicalWidth - logicalWidth();
   2866 
   2867     /*-----------------------------------------------------------------------*\
   2868      * 2. If both 'left' and 'right' have the value 'auto', then if 'direction'
   2869      *    of the containing block is 'ltr', set 'left' to the static position;
   2870      *    else if 'direction' is 'rtl', set 'right' to the static position.
   2871     \*-----------------------------------------------------------------------*/
   2872     // see FIXME 2
   2873     computeInlineStaticDistance(logicalLeft, logicalRight, this, containerBlock, containerLogicalWidth, containerDirection);
   2874 
   2875     /*-----------------------------------------------------------------------*\
   2876      * 3. If 'left' or 'right' are 'auto', replace any 'auto' on 'margin-left'
   2877      *    or 'margin-right' with '0'.
   2878     \*-----------------------------------------------------------------------*/
   2879     if (logicalLeft.isAuto() || logicalRight.isAuto()) {
   2880         if (marginLogicalLeft.isAuto())
   2881             marginLogicalLeft.setValue(Fixed, 0);
   2882         if (marginLogicalRight.isAuto())
   2883             marginLogicalRight.setValue(Fixed, 0);
   2884     }
   2885 
   2886     /*-----------------------------------------------------------------------*\
   2887      * 4. If at this point both 'margin-left' and 'margin-right' are still
   2888      *    'auto', solve the equation under the extra constraint that the two
   2889      *    margins must get equal values, unless this would make them negative,
   2890      *    in which case when the direction of the containing block is 'ltr'
   2891      *    ('rtl'), set 'margin-left' ('margin-right') to zero and solve for
   2892      *    'margin-right' ('margin-left').
   2893     \*-----------------------------------------------------------------------*/
   2894     int logicalLeftValue = 0;
   2895     int logicalRightValue = 0;
   2896 
   2897     if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) {
   2898         // 'left' and 'right' cannot be 'auto' due to step 3
   2899         ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto()));
   2900 
   2901         logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2902         logicalRightValue = logicalRight.calcValue(containerLogicalWidth);
   2903 
   2904         int difference = availableSpace - (logicalLeftValue + logicalRightValue);
   2905         if (difference > 0) {
   2906             marginLogicalLeftAlias = difference / 2; // split the difference
   2907             marginLogicalRightAlias = difference - marginLogicalLeftAlias; // account for odd valued differences
   2908         } else {
   2909             // see FIXME 1
   2910             if (containerDirection == LTR) {
   2911                 marginLogicalLeftAlias = 0;
   2912                 marginLogicalRightAlias = difference; // will be negative
   2913             } else {
   2914                 marginLogicalLeftAlias = difference; // will be negative
   2915                 marginLogicalRightAlias = 0;
   2916             }
   2917         }
   2918 
   2919     /*-----------------------------------------------------------------------*\
   2920      * 5. If at this point there is an 'auto' left, solve the equation for
   2921      *    that value.
   2922     \*-----------------------------------------------------------------------*/
   2923     } else if (logicalLeft.isAuto()) {
   2924         marginLogicalLeftAlias = marginLogicalLeft.calcValue(containerLogicalWidth);
   2925         marginLogicalRightAlias = marginLogicalRight.calcValue(containerLogicalWidth);
   2926         logicalRightValue = logicalRight.calcValue(containerLogicalWidth);
   2927 
   2928         // Solve for 'left'
   2929         logicalLeftValue = availableSpace - (logicalRightValue + marginLogicalLeftAlias + marginLogicalRightAlias);
   2930     } else if (logicalRight.isAuto()) {
   2931         marginLogicalLeftAlias = marginLogicalLeft.calcValue(containerLogicalWidth);
   2932         marginLogicalRightAlias = marginLogicalRight.calcValue(containerLogicalWidth);
   2933         logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2934 
   2935         // Solve for 'right'
   2936         logicalRightValue = availableSpace - (logicalLeftValue + marginLogicalLeftAlias + marginLogicalRightAlias);
   2937     } else if (marginLogicalLeft.isAuto()) {
   2938         marginLogicalRightAlias = marginLogicalRight.calcValue(containerLogicalWidth);
   2939         logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2940         logicalRightValue = logicalRight.calcValue(containerLogicalWidth);
   2941 
   2942         // Solve for 'margin-left'
   2943         marginLogicalLeftAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalRightAlias);
   2944     } else if (marginLogicalRight.isAuto()) {
   2945         marginLogicalLeftAlias = marginLogicalLeft.calcValue(containerLogicalWidth);
   2946         logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2947         logicalRightValue = logicalRight.calcValue(containerLogicalWidth);
   2948 
   2949         // Solve for 'margin-right'
   2950         marginLogicalRightAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalLeftAlias);
   2951     } else {
   2952         // Nothing is 'auto', just calculate the values.
   2953         marginLogicalLeftAlias = marginLogicalLeft.calcValue(containerLogicalWidth);
   2954         marginLogicalRightAlias = marginLogicalRight.calcValue(containerLogicalWidth);
   2955         logicalRightValue = logicalRight.calcValue(containerLogicalWidth);
   2956         logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2957     }
   2958 
   2959     /*-----------------------------------------------------------------------*\
   2960      * 6. If at this point the values are over-constrained, ignore the value
   2961      *    for either 'left' (in case the 'direction' property of the
   2962      *    containing block is 'rtl') or 'right' (in case 'direction' is
   2963      *    'ltr') and solve for that value.
   2964     \*-----------------------------------------------------------------------*/
   2965     // NOTE:  It is not necessary to solve for 'right' when the direction is
   2966     // LTR because the value is not used.
   2967     int totalLogicalWidth = logicalWidth() + logicalLeftValue + logicalRightValue +  marginLogicalLeftAlias + marginLogicalRightAlias;
   2968     if (totalLogicalWidth > containerLogicalWidth && (containerDirection == RTL))
   2969         logicalLeftValue = containerLogicalWidth - (totalLogicalWidth - logicalLeftValue);
   2970 
   2971     // FIXME: Deal with differing writing modes here.  Our offset needs to be in the containing block's coordinate space, so that
   2972     // can make the result here rather complicated to compute.
   2973 
   2974     // Use computed values to calculate the horizontal position.
   2975 
   2976     // FIXME: This hack is needed to calculate the logical left position for a 'rtl' relatively
   2977     // positioned, inline containing block because right now, it is using the logical left position
   2978     // of the first line box when really it should use the last line box.  When
   2979     // this is fixed elsewhere, this block should be removed.
   2980     if (containerBlock->isRenderInline() && !containerBlock->style()->isLeftToRightDirection()) {
   2981         const RenderInline* flow = toRenderInline(containerBlock);
   2982         InlineFlowBox* firstLine = flow->firstLineBox();
   2983         InlineFlowBox* lastLine = flow->lastLineBox();
   2984         if (firstLine && lastLine && firstLine != lastLine) {
   2985             setLogicalLeft(logicalLeftValue + marginLogicalLeftAlias + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logicalLeft()));
   2986             return;
   2987         }
   2988     }
   2989 
   2990     int logicalLeftPos = logicalLeftValue + marginLogicalLeftAlias;
   2991     computeLogicalLeftPositionedOffset(logicalLeftPos, this, logicalWidth(), containerBlock, containerLogicalWidth);
   2992     setLogicalLeft(logicalLeftPos);
   2993 }
   2994 
   2995 void RenderBox::computePositionedLogicalHeightReplaced()
   2996 {
   2997     // The following is based off of the W3C Working Draft from April 11, 2006 of
   2998     // CSS 2.1: Section 10.6.5 "Absolutely positioned, replaced elements"
   2999     // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-height>
   3000     // (block-style-comments in this function correspond to text from the spec and
   3001     // the numbers correspond to numbers in spec)
   3002 
   3003     // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
   3004     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
   3005 
   3006     const int containerLogicalHeight = containingBlockLogicalHeightForPositioned(containerBlock);
   3007 
   3008     // Variables to solve.
   3009     bool isHorizontal = isHorizontalWritingMode();
   3010     bool isFlipped = style()->isFlippedBlocksWritingMode();
   3011     Length marginBefore = style()->marginBefore();
   3012     Length marginAfter = style()->marginAfter();
   3013     int& marginBeforeAlias = isHorizontal ? (isFlipped ? m_marginBottom : m_marginTop) : (isFlipped ? m_marginRight: m_marginLeft);
   3014     int& marginAfterAlias = isHorizontal ? (isFlipped ? m_marginTop : m_marginBottom) : (isFlipped ? m_marginLeft: m_marginRight);
   3015 
   3016     Length logicalTop = style()->logicalTop();
   3017     Length logicalBottom = style()->logicalBottom();
   3018 
   3019     /*-----------------------------------------------------------------------*\
   3020      * 1. The used value of 'height' is determined as for inline replaced
   3021      *    elements.
   3022     \*-----------------------------------------------------------------------*/
   3023     // NOTE: This value of height is FINAL in that the min/max height calculations
   3024     // are dealt with in computeReplacedHeight().  This means that the steps to produce
   3025     // correct max/min in the non-replaced version, are not necessary.
   3026     setLogicalHeight(computeReplacedLogicalHeight() + borderAndPaddingLogicalHeight());
   3027     const int availableSpace = containerLogicalHeight - logicalHeight();
   3028 
   3029     /*-----------------------------------------------------------------------*\
   3030      * 2. If both 'top' and 'bottom' have the value 'auto', replace 'top'
   3031      *    with the element's static position.
   3032     \*-----------------------------------------------------------------------*/
   3033     // see FIXME 2
   3034     computeBlockStaticDistance(logicalTop, logicalBottom, this, containerBlock);
   3035 
   3036     /*-----------------------------------------------------------------------*\
   3037      * 3. If 'bottom' is 'auto', replace any 'auto' on 'margin-top' or
   3038      *    'margin-bottom' with '0'.
   3039     \*-----------------------------------------------------------------------*/
   3040     // FIXME: The spec. says that this step should only be taken when bottom is
   3041     // auto, but if only top is auto, this makes step 4 impossible.
   3042     if (logicalTop.isAuto() || logicalBottom.isAuto()) {
   3043         if (marginBefore.isAuto())
   3044             marginBefore.setValue(Fixed, 0);
   3045         if (marginAfter.isAuto())
   3046             marginAfter.setValue(Fixed, 0);
   3047     }
   3048 
   3049     /*-----------------------------------------------------------------------*\
   3050      * 4. If at this point both 'margin-top' and 'margin-bottom' are still
   3051      *    'auto', solve the equation under the extra constraint that the two
   3052      *    margins must get equal values.
   3053     \*-----------------------------------------------------------------------*/
   3054     int logicalTopValue = 0;
   3055     int logicalBottomValue = 0;
   3056 
   3057     if (marginBefore.isAuto() && marginAfter.isAuto()) {
   3058         // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combined.
   3059         ASSERT(!(logicalTop.isAuto() || logicalBottom.isAuto()));
   3060 
   3061         logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   3062         logicalBottomValue = logicalBottom.calcValue(containerLogicalHeight);
   3063 
   3064         int difference = availableSpace - (logicalTopValue + logicalBottomValue);
   3065         // NOTE: This may result in negative values.
   3066         marginBeforeAlias =  difference / 2; // split the difference
   3067         marginAfterAlias = difference - marginBeforeAlias; // account for odd valued differences
   3068 
   3069     /*-----------------------------------------------------------------------*\
   3070      * 5. If at this point there is only one 'auto' left, solve the equation
   3071      *    for that value.
   3072     \*-----------------------------------------------------------------------*/
   3073     } else if (logicalTop.isAuto()) {
   3074         marginBeforeAlias = marginBefore.calcValue(containerLogicalHeight);
   3075         marginAfterAlias = marginAfter.calcValue(containerLogicalHeight);
   3076         logicalBottomValue = logicalBottom.calcValue(containerLogicalHeight);
   3077 
   3078         // Solve for 'top'
   3079         logicalTopValue = availableSpace - (logicalBottomValue + marginBeforeAlias + marginAfterAlias);
   3080     } else if (logicalBottom.isAuto()) {
   3081         marginBeforeAlias = marginBefore.calcValue(containerLogicalHeight);
   3082         marginAfterAlias = marginAfter.calcValue(containerLogicalHeight);
   3083         logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   3084 
   3085         // Solve for 'bottom'
   3086         // NOTE: It is not necessary to solve for 'bottom' because we don't ever
   3087         // use the value.
   3088     } else if (marginBefore.isAuto()) {
   3089         marginAfterAlias = marginAfter.calcValue(containerLogicalHeight);
   3090         logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   3091         logicalBottomValue = logicalBottom.calcValue(containerLogicalHeight);
   3092 
   3093         // Solve for 'margin-top'
   3094         marginBeforeAlias = availableSpace - (logicalTopValue + logicalBottomValue + marginAfterAlias);
   3095     } else if (marginAfter.isAuto()) {
   3096         marginBeforeAlias = marginBefore.calcValue(containerLogicalHeight);
   3097         logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   3098         logicalBottomValue = logicalBottom.calcValue(containerLogicalHeight);
   3099 
   3100         // Solve for 'margin-bottom'
   3101         marginAfterAlias = availableSpace - (logicalTopValue + logicalBottomValue + marginBeforeAlias);
   3102     } else {
   3103         // Nothing is 'auto', just calculate the values.
   3104         marginBeforeAlias = marginBefore.calcValue(containerLogicalHeight);
   3105         marginAfterAlias = marginAfter.calcValue(containerLogicalHeight);
   3106         logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   3107         // NOTE: It is not necessary to solve for 'bottom' because we don't ever
   3108         // use the value.
   3109      }
   3110 
   3111     /*-----------------------------------------------------------------------*\
   3112      * 6. If at this point the values are over-constrained, ignore the value
   3113      *    for 'bottom' and solve for that value.
   3114     \*-----------------------------------------------------------------------*/
   3115     // NOTE: It is not necessary to do this step because we don't end up using
   3116     // the value of 'bottom' regardless of whether the values are over-constrained
   3117     // or not.
   3118 
   3119     // Use computed values to calculate the vertical position.
   3120     int logicalTopPos = logicalTopValue + marginBeforeAlias;
   3121     computeLogicalTopPositionedOffset(logicalTopPos, this, logicalHeight(), containerBlock, containerLogicalHeight);
   3122     setLogicalTop(logicalTopPos);
   3123 }
   3124 
   3125 IntRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, int* extraWidthToEndOfLine)
   3126 {
   3127     // VisiblePositions at offsets inside containers either a) refer to the positions before/after
   3128     // those containers (tables and select elements) or b) refer to the position inside an empty block.
   3129     // They never refer to children.
   3130     // FIXME: Paint the carets inside empty blocks differently than the carets before/after elements.
   3131 
   3132     // FIXME: What about border and padding?
   3133     IntRect rect(x(), y(), caretWidth, height());
   3134     bool ltr = box ? box->isLeftToRightDirection() : style()->isLeftToRightDirection();
   3135 
   3136     if ((!caretOffset) ^ ltr)
   3137         rect.move(IntSize(width() - caretWidth, 0));
   3138 
   3139     if (box) {
   3140         RootInlineBox* rootBox = box->root();
   3141         int top = rootBox->lineTop();
   3142         rect.setY(top);
   3143         rect.setHeight(rootBox->lineBottom() - top);
   3144     }
   3145 
   3146     // If height of box is smaller than font height, use the latter one,
   3147     // otherwise the caret might become invisible.
   3148     //
   3149     // Also, if the box is not a replaced element, always use the font height.
   3150     // This prevents the "big caret" bug described in:
   3151     // <rdar://problem/3777804> Deleting all content in a document can result in giant tall-as-window insertion point
   3152     //
   3153     // FIXME: ignoring :first-line, missing good reason to take care of
   3154     int fontHeight = style()->fontMetrics().height();
   3155     if (fontHeight > rect.height() || (!isReplaced() && !isTable()))
   3156         rect.setHeight(fontHeight);
   3157 
   3158     if (extraWidthToEndOfLine)
   3159         *extraWidthToEndOfLine = x() + width() - rect.maxX();
   3160 
   3161     // Move to local coords
   3162     rect.move(-x(), -y());
   3163     return rect;
   3164 }
   3165 
   3166 VisiblePosition RenderBox::positionForPoint(const IntPoint& point)
   3167 {
   3168     // no children...return this render object's element, if there is one, and offset 0
   3169     if (!firstChild())
   3170         return createVisiblePosition(node() ? firstPositionInOrBeforeNode(node()) : Position(0, 0));
   3171 
   3172     int xPos = point.x();
   3173     int yPos = point.y();
   3174 
   3175     if (isTable() && node()) {
   3176         int right = contentWidth() + borderAndPaddingWidth();
   3177         int bottom = contentHeight() + borderAndPaddingHeight();
   3178 
   3179         if (xPos < 0 || xPos > right || yPos < 0 || yPos > bottom) {
   3180             if (xPos <= right / 2)
   3181                 return createVisiblePosition(firstPositionInOrBeforeNode(node()));
   3182             return createVisiblePosition(lastPositionInOrAfterNode(node()));
   3183         }
   3184     }
   3185 
   3186     // Pass off to the closest child.
   3187     int minDist = INT_MAX;
   3188     RenderBox* closestRenderer = 0;
   3189     int newX = xPos;
   3190     int newY = yPos;
   3191     if (isTableRow()) {
   3192         newX += x();
   3193         newY += y();
   3194     }
   3195     for (RenderObject* renderObject = firstChild(); renderObject; renderObject = renderObject->nextSibling()) {
   3196         if ((!renderObject->firstChild() && !renderObject->isInline() && !renderObject->isBlockFlow() )
   3197             || renderObject->style()->visibility() != VISIBLE)
   3198             continue;
   3199 
   3200         if (!renderObject->isBox())
   3201             continue;
   3202 
   3203         RenderBox* renderer = toRenderBox(renderObject);
   3204 
   3205         int top = renderer->borderTop() + renderer->paddingTop() + (isTableRow() ? 0 : renderer->y());
   3206         int bottom = top + renderer->contentHeight();
   3207         int left = renderer->borderLeft() + renderer->paddingLeft() + (isTableRow() ? 0 : renderer->x());
   3208         int right = left + renderer->contentWidth();
   3209 
   3210         if (xPos <= right && xPos >= left && yPos <= top && yPos >= bottom) {
   3211             if (renderer->isTableRow())
   3212                 return renderer->positionForCoordinates(xPos + newX - renderer->x(), yPos + newY - renderer->y());
   3213             return renderer->positionForCoordinates(xPos - renderer->x(), yPos - renderer->y());
   3214         }
   3215 
   3216         // Find the distance from (x, y) to the box.  Split the space around the box into 8 pieces
   3217         // and use a different compare depending on which piece (x, y) is in.
   3218         IntPoint cmp;
   3219         if (xPos > right) {
   3220             if (yPos < top)
   3221                 cmp = IntPoint(right, top);
   3222             else if (yPos > bottom)
   3223                 cmp = IntPoint(right, bottom);
   3224             else
   3225                 cmp = IntPoint(right, yPos);
   3226         } else if (xPos < left) {
   3227             if (yPos < top)
   3228                 cmp = IntPoint(left, top);
   3229             else if (yPos > bottom)
   3230                 cmp = IntPoint(left, bottom);
   3231             else
   3232                 cmp = IntPoint(left, yPos);
   3233         } else {
   3234             if (yPos < top)
   3235                 cmp = IntPoint(xPos, top);
   3236             else
   3237                 cmp = IntPoint(xPos, bottom);
   3238         }
   3239 
   3240         int x1minusx2 = cmp.x() - xPos;
   3241         int y1minusy2 = cmp.y() - yPos;
   3242 
   3243         int dist = x1minusx2 * x1minusx2 + y1minusy2 * y1minusy2;
   3244         if (dist < minDist) {
   3245             closestRenderer = renderer;
   3246             minDist = dist;
   3247         }
   3248     }
   3249 
   3250     if (closestRenderer)
   3251         return closestRenderer->positionForCoordinates(newX - closestRenderer->x(), newY - closestRenderer->y());
   3252 
   3253     return createVisiblePosition(firstPositionInOrBeforeNode(node()));
   3254 }
   3255 
   3256 bool RenderBox::shrinkToAvoidFloats() const
   3257 {
   3258     // Floating objects don't shrink.  Objects that don't avoid floats don't shrink.  Marquees don't shrink.
   3259     if ((isInline() && !isHTMLMarquee()) || !avoidsFloats() || isFloating())
   3260         return false;
   3261 
   3262     // All auto-width objects that avoid floats should always use lineWidth.
   3263     return style()->width().isAuto();
   3264 }
   3265 
   3266 bool RenderBox::avoidsFloats() const
   3267 {
   3268     return isReplaced() || hasOverflowClip() || isHR() || isLegend() || isWritingModeRoot() || isDeprecatedFlexItem();
   3269 }
   3270 
   3271 void RenderBox::addShadowOverflow()
   3272 {
   3273     int shadowLeft;
   3274     int shadowRight;
   3275     int shadowTop;
   3276     int shadowBottom;
   3277     style()->getBoxShadowExtent(shadowTop, shadowRight, shadowBottom, shadowLeft);
   3278     IntRect borderBox = borderBoxRect();
   3279     int overflowLeft = borderBox.x() + shadowLeft;
   3280     int overflowRight = borderBox.maxX() + shadowRight;
   3281     int overflowTop = borderBox.y() + shadowTop;
   3282     int overflowBottom = borderBox.maxY() + shadowBottom;
   3283     addVisualOverflow(IntRect(overflowLeft, overflowTop, overflowRight - overflowLeft, overflowBottom - overflowTop));
   3284 }
   3285 
   3286 void RenderBox::addOverflowFromChild(RenderBox* child, const IntSize& delta)
   3287 {
   3288     // Only propagate layout overflow from the child if the child isn't clipping its overflow.  If it is, then
   3289     // its overflow is internal to it, and we don't care about it.  layoutOverflowRectForPropagation takes care of this
   3290     // and just propagates the border box rect instead.
   3291     IntRect childLayoutOverflowRect = child->layoutOverflowRectForPropagation(style());
   3292     childLayoutOverflowRect.move(delta);
   3293     addLayoutOverflow(childLayoutOverflowRect);
   3294 
   3295     // Add in visual overflow from the child.  Even if the child clips its overflow, it may still
   3296     // have visual overflow of its own set from box shadows or reflections.  It is unnecessary to propagate this
   3297     // overflow if we are clipping our own overflow.
   3298     if (child->hasSelfPaintingLayer() || hasOverflowClip())
   3299         return;
   3300     IntRect childVisualOverflowRect = child->visualOverflowRectForPropagation(style());
   3301     childVisualOverflowRect.move(delta);
   3302     addVisualOverflow(childVisualOverflowRect);
   3303 }
   3304 
   3305 void RenderBox::addLayoutOverflow(const IntRect& rect)
   3306 {
   3307     IntRect clientBox = clientBoxRect();
   3308     if (clientBox.contains(rect) || rect.isEmpty())
   3309         return;
   3310 
   3311     // For overflow clip objects, we don't want to propagate overflow into unreachable areas.
   3312     IntRect overflowRect(rect);
   3313     if (hasOverflowClip() || isRenderView()) {
   3314         // Overflow is in the block's coordinate space and thus is flipped for horizontal-bt and vertical-rl
   3315         // writing modes.  At this stage that is actually a simplification, since we can treat horizontal-tb/bt as the same
   3316         // and vertical-lr/rl as the same.
   3317         bool hasTopOverflow = !style()->isLeftToRightDirection() && !isHorizontalWritingMode();
   3318         bool hasLeftOverflow = !style()->isLeftToRightDirection() && isHorizontalWritingMode();
   3319 
   3320         if (!hasTopOverflow)
   3321             overflowRect.shiftYEdgeTo(max(overflowRect.y(), clientBox.y()));
   3322         else
   3323             overflowRect.shiftMaxYEdgeTo(min(overflowRect.maxY(), clientBox.maxY()));
   3324         if (!hasLeftOverflow)
   3325             overflowRect.shiftXEdgeTo(max(overflowRect.x(), clientBox.x()));
   3326         else
   3327             overflowRect.shiftMaxXEdgeTo(min(overflowRect.maxX(), clientBox.maxX()));
   3328 
   3329         // Now re-test with the adjusted rectangle and see if it has become unreachable or fully
   3330         // contained.
   3331         if (clientBox.contains(overflowRect) || overflowRect.isEmpty())
   3332             return;
   3333     }
   3334 
   3335     if (!m_overflow)
   3336         m_overflow.set(new RenderOverflow(clientBox, borderBoxRect()));
   3337 
   3338     m_overflow->addLayoutOverflow(overflowRect);
   3339 }
   3340 
   3341 void RenderBox::addVisualOverflow(const IntRect& rect)
   3342 {
   3343     IntRect borderBox = borderBoxRect();
   3344     if (borderBox.contains(rect) || rect.isEmpty())
   3345         return;
   3346 
   3347     if (!m_overflow)
   3348         m_overflow.set(new RenderOverflow(clientBoxRect(), borderBox));
   3349 
   3350     m_overflow->addVisualOverflow(rect);
   3351 }
   3352 
   3353 void RenderBox::clearLayoutOverflow()
   3354 {
   3355     if (!m_overflow)
   3356         return;
   3357 
   3358     if (visualOverflowRect() == borderBoxRect()) {
   3359         m_overflow.clear();
   3360         return;
   3361     }
   3362 
   3363     m_overflow->resetLayoutOverflow(borderBoxRect());
   3364 }
   3365 
   3366 int RenderBox::lineHeight(bool /*firstLine*/, LineDirectionMode direction, LinePositionMode /*linePositionMode*/) const
   3367 {
   3368     if (isReplaced())
   3369         return direction == HorizontalLine ? m_marginTop + height() + m_marginBottom : m_marginRight + width() + m_marginLeft;
   3370     return 0;
   3371 }
   3372 
   3373 int RenderBox::baselinePosition(FontBaseline baselineType, bool /*firstLine*/, LineDirectionMode direction, LinePositionMode /*linePositionMode*/) const
   3374 {
   3375     if (isReplaced()) {
   3376         int result = direction == HorizontalLine ? m_marginTop + height() + m_marginBottom : m_marginRight + width() + m_marginLeft;
   3377         if (baselineType == AlphabeticBaseline)
   3378             return result;
   3379         return result - result / 2;
   3380     }
   3381     return 0;
   3382 }
   3383 
   3384 
   3385 RenderLayer* RenderBox::enclosingFloatPaintingLayer() const
   3386 {
   3387     const RenderObject* curr = this;
   3388     while (curr) {
   3389         RenderLayer* layer = curr->hasLayer() && curr->isBox() ? toRenderBoxModelObject(curr)->layer() : 0;
   3390         if (layer && layer->isSelfPaintingLayer())
   3391             return layer;
   3392         curr = curr->parent();
   3393     }
   3394     return 0;
   3395 }
   3396 
   3397 IntRect RenderBox::logicalVisualOverflowRectForPropagation(RenderStyle* parentStyle) const
   3398 {
   3399     IntRect rect = visualOverflowRectForPropagation(parentStyle);
   3400     if (!parentStyle->isHorizontalWritingMode())
   3401         return rect.transposedRect();
   3402     return rect;
   3403 }
   3404 
   3405 IntRect RenderBox::visualOverflowRectForPropagation(RenderStyle* parentStyle) const
   3406 {
   3407     // If the writing modes of the child and parent match, then we don't have to
   3408     // do anything fancy. Just return the result.
   3409     IntRect rect = visualOverflowRect();
   3410     if (parentStyle->writingMode() == style()->writingMode())
   3411         return rect;
   3412 
   3413     // We are putting ourselves into our parent's coordinate space.  If there is a flipped block mismatch
   3414     // in a particular axis, then we have to flip the rect along that axis.
   3415     if (style()->writingMode() == RightToLeftWritingMode || parentStyle->writingMode() == RightToLeftWritingMode)
   3416         rect.setX(width() - rect.maxX());
   3417     else if (style()->writingMode() == BottomToTopWritingMode || parentStyle->writingMode() == BottomToTopWritingMode)
   3418         rect.setY(height() - rect.maxY());
   3419 
   3420     return rect;
   3421 }
   3422 
   3423 IntRect RenderBox::logicalLayoutOverflowRectForPropagation(RenderStyle* parentStyle) const
   3424 {
   3425     IntRect rect = layoutOverflowRectForPropagation(parentStyle);
   3426     if (!parentStyle->isHorizontalWritingMode())
   3427         return rect.transposedRect();
   3428     return rect;
   3429 }
   3430 
   3431 IntRect RenderBox::layoutOverflowRectForPropagation(RenderStyle* parentStyle) const
   3432 {
   3433     // Only propagate interior layout overflow if we don't clip it.
   3434     IntRect rect = borderBoxRect();
   3435     if (!hasOverflowClip())
   3436         rect.unite(layoutOverflowRect());
   3437 
   3438     bool hasTransform = hasLayer() && layer()->transform();
   3439     if (isRelPositioned() || hasTransform) {
   3440         // If we are relatively positioned or if we have a transform, then we have to convert
   3441         // this rectangle into physical coordinates, apply relative positioning and transforms
   3442         // to it, and then convert it back.
   3443         flipForWritingMode(rect);
   3444 
   3445         if (hasTransform)
   3446             rect = layer()->currentTransform().mapRect(rect);
   3447 
   3448         if (isRelPositioned())
   3449             rect.move(relativePositionOffsetX(), relativePositionOffsetY());
   3450 
   3451         // Now we need to flip back.
   3452         flipForWritingMode(rect);
   3453     }
   3454 
   3455     // If the writing modes of the child and parent match, then we don't have to
   3456     // do anything fancy. Just return the result.
   3457     if (parentStyle->writingMode() == style()->writingMode())
   3458         return rect;
   3459 
   3460     // We are putting ourselves into our parent's coordinate space.  If there is a flipped block mismatch
   3461     // in a particular axis, then we have to flip the rect along that axis.
   3462     if (style()->writingMode() == RightToLeftWritingMode || parentStyle->writingMode() == RightToLeftWritingMode)
   3463         rect.setX(width() - rect.maxX());
   3464     else if (style()->writingMode() == BottomToTopWritingMode || parentStyle->writingMode() == BottomToTopWritingMode)
   3465         rect.setY(height() - rect.maxY());
   3466 
   3467     return rect;
   3468 }
   3469 
   3470 IntPoint RenderBox::flipForWritingMode(const RenderBox* child, const IntPoint& point, FlippingAdjustment adjustment) const
   3471 {
   3472     if (!style()->isFlippedBlocksWritingMode())
   3473         return point;
   3474 
   3475     // The child is going to add in its x() and y(), so we have to make sure it ends up in
   3476     // the right place.
   3477     if (isHorizontalWritingMode())
   3478         return IntPoint(point.x(), point.y() + height() - child->height() - child->y() - (adjustment == ParentToChildFlippingAdjustment ? child->y() : 0));
   3479     return IntPoint(point.x() + width() - child->width() - child->x() - (adjustment == ParentToChildFlippingAdjustment ? child->x() : 0), point.y());
   3480 }
   3481 
   3482 void RenderBox::flipForWritingMode(IntRect& rect) const
   3483 {
   3484     if (!style()->isFlippedBlocksWritingMode())
   3485         return;
   3486 
   3487     if (isHorizontalWritingMode())
   3488         rect.setY(height() - rect.maxY());
   3489     else
   3490         rect.setX(width() - rect.maxX());
   3491 }
   3492 
   3493 int RenderBox::flipForWritingMode(int position) const
   3494 {
   3495     if (!style()->isFlippedBlocksWritingMode())
   3496         return position;
   3497     return logicalHeight() - position;
   3498 }
   3499 
   3500 IntPoint RenderBox::flipForWritingMode(const IntPoint& position) const
   3501 {
   3502     if (!style()->isFlippedBlocksWritingMode())
   3503         return position;
   3504     return isHorizontalWritingMode() ? IntPoint(position.x(), height() - position.y()) : IntPoint(width() - position.x(), position.y());
   3505 }
   3506 
   3507 IntPoint RenderBox::flipForWritingModeIncludingColumns(const IntPoint& point) const
   3508 {
   3509     if (!hasColumns() || !style()->isFlippedBlocksWritingMode())
   3510         return flipForWritingMode(point);
   3511     return toRenderBlock(this)->flipForWritingModeIncludingColumns(point);
   3512 }
   3513 
   3514 IntSize RenderBox::flipForWritingMode(const IntSize& offset) const
   3515 {
   3516     if (!style()->isFlippedBlocksWritingMode())
   3517         return offset;
   3518     return isHorizontalWritingMode() ? IntSize(offset.width(), height() - offset.height()) : IntSize(width() - offset.width(), offset.height());
   3519 }
   3520 
   3521 FloatPoint RenderBox::flipForWritingMode(const FloatPoint& position) const
   3522 {
   3523     if (!style()->isFlippedBlocksWritingMode())
   3524         return position;
   3525     return isHorizontalWritingMode() ? FloatPoint(position.x(), height() - position.y()) : FloatPoint(width() - position.x(), position.y());
   3526 }
   3527 
   3528 void RenderBox::flipForWritingMode(FloatRect& rect) const
   3529 {
   3530     if (!style()->isFlippedBlocksWritingMode())
   3531         return;
   3532 
   3533     if (isHorizontalWritingMode())
   3534         rect.setY(height() - rect.maxY());
   3535     else
   3536         rect.setX(width() - rect.maxX());
   3537 }
   3538 
   3539 IntSize RenderBox::locationOffsetIncludingFlipping() const
   3540 {
   3541     RenderBlock* containerBlock = containingBlock();
   3542     if (!containerBlock || containerBlock == this)
   3543         return locationOffset();
   3544 
   3545     IntRect rect(frameRect());
   3546     containerBlock->flipForWritingMode(rect); // FIXME: This is wrong if we are an absolutely positioned object enclosed by a relative-positioned inline.
   3547     return IntSize(rect.x(), rect.y());
   3548 }
   3549 
   3550 } // namespace WebCore
   3551