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             paintFillLayers(paintInfo, style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), tx, ty, width, height);
    847         }
    848         if (style()->hasAppearance())
    849             theme()->paintDecorations(this, paintInfo, IntRect(tx, ty, width, height));
    850     }
    851     paintBoxShadow(paintInfo.context, tx, ty, width, height, style(), Inset);
    852 
    853     // The theme will tell us whether or not we should also paint the CSS border.
    854     if ((!style()->hasAppearance() || (!themePainted && theme()->paintBorderOnly(this, paintInfo, IntRect(tx, ty, width, height)))) && style()->hasBorder())
    855         paintBorder(paintInfo.context, tx, ty, width, height, style());
    856 }
    857 
    858 void RenderBox::paintMask(PaintInfo& paintInfo, int tx, int ty)
    859 {
    860     if (!paintInfo.shouldPaintWithinRoot(this) || style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask || paintInfo.context->paintingDisabled())
    861         return;
    862 
    863     int w = width();
    864     int h = height();
    865 
    866     // border-fit can adjust where we paint our border and background.  If set, we snugly fit our line box descendants.  (The iChat
    867     // balloon layout is an example of this).
    868     borderFitAdjust(tx, w);
    869 
    870     paintMaskImages(paintInfo, tx, ty, w, h);
    871 }
    872 
    873 void RenderBox::paintMaskImages(const PaintInfo& paintInfo, int tx, int ty, int w, int h)
    874 {
    875     // Figure out if we need to push a transparency layer to render our mask.
    876     bool pushTransparencyLayer = false;
    877     bool compositedMask = hasLayer() && layer()->hasCompositedMask();
    878     CompositeOperator compositeOp = CompositeSourceOver;
    879 
    880     bool allMaskImagesLoaded = true;
    881 
    882     if (!compositedMask) {
    883         // If the context has a rotation, scale or skew, then use a transparency layer to avoid
    884         // pixel cruft around the edge of the mask.
    885         const AffineTransform& currentCTM = paintInfo.context->getCTM();
    886         pushTransparencyLayer = !currentCTM.isIdentityOrTranslationOrFlipped();
    887 
    888         StyleImage* maskBoxImage = style()->maskBoxImage().image();
    889         const FillLayer* maskLayers = style()->maskLayers();
    890 
    891         // Don't render a masked element until all the mask images have loaded, to prevent a flash of unmasked content.
    892         if (maskBoxImage)
    893             allMaskImagesLoaded &= maskBoxImage->isLoaded();
    894 
    895         if (maskLayers)
    896             allMaskImagesLoaded &= maskLayers->imagesAreLoaded();
    897 
    898         // Before all images have loaded, just use an empty transparency layer as the mask.
    899         if (!allMaskImagesLoaded)
    900             pushTransparencyLayer = true;
    901 
    902         if (maskBoxImage && maskLayers->hasImage()) {
    903             // We have a mask-box-image and mask-image, so need to composite them together before using the result as a mask.
    904             pushTransparencyLayer = true;
    905         } else {
    906             // We have to use an extra image buffer to hold the mask. Multiple mask images need
    907             // to composite together using source-over so that they can then combine into a single unified mask that
    908             // can be composited with the content using destination-in.  SVG images need to be able to set compositing modes
    909             // as they draw images contained inside their sub-document, so we paint all our images into a separate buffer
    910             // and composite that buffer as the mask.
    911             // We have to check that the mask images to be rendered contain at least one image that can be actually used in rendering
    912             // before pushing the transparency layer.
    913             for (const FillLayer* fillLayer = maskLayers->next(); fillLayer; fillLayer = fillLayer->next()) {
    914                 if (fillLayer->hasImage() && fillLayer->image()->canRender(style()->effectiveZoom())) {
    915                     pushTransparencyLayer = true;
    916                     // We found one image that can be used in rendering, exit the loop
    917                     break;
    918                 }
    919             }
    920         }
    921 
    922         compositeOp = CompositeDestinationIn;
    923         if (pushTransparencyLayer) {
    924             paintInfo.context->setCompositeOperation(CompositeDestinationIn);
    925             paintInfo.context->beginTransparencyLayer(1.0f);
    926             compositeOp = CompositeSourceOver;
    927         }
    928     }
    929 
    930     if (allMaskImagesLoaded) {
    931         paintFillLayers(paintInfo, Color(), style()->maskLayers(), tx, ty, w, h, compositeOp);
    932         paintNinePieceImage(paintInfo.context, tx, ty, w, h, style(), style()->maskBoxImage(), compositeOp);
    933     }
    934 
    935     if (pushTransparencyLayer)
    936         paintInfo.context->endTransparencyLayer();
    937 }
    938 
    939 IntRect RenderBox::maskClipRect()
    940 {
    941     IntRect bbox = borderBoxRect();
    942     if (style()->maskBoxImage().image())
    943         return bbox;
    944 
    945     IntRect result;
    946     for (const FillLayer* maskLayer = style()->maskLayers(); maskLayer; maskLayer = maskLayer->next()) {
    947         if (maskLayer->image()) {
    948             IntRect maskRect;
    949             IntPoint phase;
    950             IntSize tileSize;
    951             calculateBackgroundImageGeometry(maskLayer, bbox.x(), bbox.y(), bbox.width(), bbox.height(), maskRect, phase, tileSize);
    952             result.unite(maskRect);
    953         }
    954     }
    955     return result;
    956 }
    957 
    958 void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int width, int height, CompositeOperator op, RenderObject* backgroundObject)
    959 {
    960     if (!fillLayer)
    961         return;
    962 
    963     paintFillLayers(paintInfo, c, fillLayer->next(), tx, ty, width, height, op, backgroundObject);
    964     paintFillLayer(paintInfo, c, fillLayer, tx, ty, width, height, op, backgroundObject);
    965 }
    966 
    967 void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int width, int height, CompositeOperator op, RenderObject* backgroundObject)
    968 {
    969     paintFillLayerExtended(paintInfo, c, fillLayer, tx, ty, width, height, 0, 0, 0, op, backgroundObject);
    970 }
    971 
    972 #if USE(ACCELERATED_COMPOSITING)
    973 static bool layersUseImage(WrappedImagePtr image, const FillLayer* layers)
    974 {
    975     for (const FillLayer* curLayer = layers; curLayer; curLayer = curLayer->next()) {
    976         if (curLayer->image() && image == curLayer->image()->data())
    977             return true;
    978     }
    979 
    980     return false;
    981 }
    982 #endif
    983 
    984 void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*)
    985 {
    986     if (!parent())
    987         return;
    988 
    989     if ((style()->borderImage().image() && style()->borderImage().image()->data() == image) ||
    990         (style()->maskBoxImage().image() && style()->maskBoxImage().image()->data() == image)) {
    991         repaint();
    992         return;
    993     }
    994 
    995     bool didFullRepaint = repaintLayerRectsForImage(image, style()->backgroundLayers(), true);
    996     if (!didFullRepaint)
    997         repaintLayerRectsForImage(image, style()->maskLayers(), false);
    998 
    999 
   1000 #if USE(ACCELERATED_COMPOSITING)
   1001     if (hasLayer() && layer()->hasCompositedMask() && layersUseImage(image, style()->maskLayers()))
   1002         layer()->contentChanged(RenderLayer::MaskImageChanged);
   1003 #endif
   1004 }
   1005 
   1006 bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer* layers, bool drawingBackground)
   1007 {
   1008     IntRect rendererRect;
   1009     RenderBox* layerRenderer = 0;
   1010 
   1011     for (const FillLayer* curLayer = layers; curLayer; curLayer = curLayer->next()) {
   1012         if (curLayer->image() && image == curLayer->image()->data() && curLayer->image()->canRender(style()->effectiveZoom())) {
   1013             // Now that we know this image is being used, compute the renderer and the rect
   1014             // if we haven't already
   1015             if (!layerRenderer) {
   1016                 bool drawingRootBackground = drawingBackground && (isRoot() || (isBody() && !document()->documentElement()->renderer()->hasBackground()));
   1017                 if (drawingRootBackground) {
   1018                     layerRenderer = view();
   1019 
   1020                     int rw;
   1021                     int rh;
   1022 
   1023                     if (FrameView* frameView = toRenderView(layerRenderer)->frameView()) {
   1024                         rw = frameView->contentsWidth();
   1025                         rh = frameView->contentsHeight();
   1026                     } else {
   1027                         rw = layerRenderer->width();
   1028                         rh = layerRenderer->height();
   1029                     }
   1030                     rendererRect = IntRect(-layerRenderer->marginLeft(),
   1031                         -layerRenderer->marginTop(),
   1032                         max(layerRenderer->width() + layerRenderer->marginLeft() + layerRenderer->marginRight() + layerRenderer->borderLeft() + layerRenderer->borderRight(), rw),
   1033                         max(layerRenderer->height() + layerRenderer->marginTop() + layerRenderer->marginBottom() + layerRenderer->borderTop() + layerRenderer->borderBottom(), rh));
   1034                 } else {
   1035                     layerRenderer = this;
   1036                     rendererRect = borderBoxRect();
   1037                 }
   1038             }
   1039 
   1040             IntRect repaintRect;
   1041             IntPoint phase;
   1042             IntSize tileSize;
   1043             layerRenderer->calculateBackgroundImageGeometry(curLayer, rendererRect.x(), rendererRect.y(), rendererRect.width(), rendererRect.height(), repaintRect, phase, tileSize);
   1044             layerRenderer->repaintRectangle(repaintRect);
   1045             if (repaintRect == rendererRect)
   1046                 return true;
   1047         }
   1048     }
   1049     return false;
   1050 }
   1051 
   1052 #if PLATFORM(MAC)
   1053 
   1054 void RenderBox::paintCustomHighlight(int tx, int ty, const AtomicString& type, bool behindText)
   1055 {
   1056     Frame* frame = this->frame();
   1057     if (!frame)
   1058         return;
   1059     Page* page = frame->page();
   1060     if (!page)
   1061         return;
   1062 
   1063     InlineBox* boxWrap = inlineBoxWrapper();
   1064     RootInlineBox* r = boxWrap ? boxWrap->root() : 0;
   1065     if (r) {
   1066         FloatRect rootRect(tx + r->x(), ty + r->selectionTop(), r->logicalWidth(), r->selectionHeight());
   1067         FloatRect imageRect(tx + x(), rootRect.y(), width(), rootRect.height());
   1068         page->chrome()->client()->paintCustomHighlight(node(), type, imageRect, rootRect, behindText, false);
   1069     } else {
   1070         FloatRect imageRect(tx + x(), ty + y(), width(), height());
   1071         page->chrome()->client()->paintCustomHighlight(node(), type, imageRect, imageRect, behindText, false);
   1072     }
   1073 }
   1074 
   1075 #endif
   1076 
   1077 bool RenderBox::pushContentsClip(PaintInfo& paintInfo, int tx, int ty)
   1078 {
   1079     if (paintInfo.phase == PaintPhaseBlockBackground || paintInfo.phase == PaintPhaseSelfOutline || paintInfo.phase == PaintPhaseMask)
   1080         return false;
   1081 
   1082     bool isControlClip = hasControlClip();
   1083     bool isOverflowClip = hasOverflowClip() && !layer()->isSelfPaintingLayer();
   1084 
   1085     if (!isControlClip && !isOverflowClip)
   1086         return false;
   1087 
   1088     if (paintInfo.phase == PaintPhaseOutline)
   1089         paintInfo.phase = PaintPhaseChildOutlines;
   1090     else if (paintInfo.phase == PaintPhaseChildBlockBackground) {
   1091         paintInfo.phase = PaintPhaseBlockBackground;
   1092         paintObject(paintInfo, tx, ty);
   1093         paintInfo.phase = PaintPhaseChildBlockBackgrounds;
   1094     }
   1095     IntRect clipRect(isControlClip ? controlClipRect(tx, ty) : overflowClipRect(tx, ty));
   1096     paintInfo.context->save();
   1097     if (style()->hasBorderRadius())
   1098         paintInfo.context->addRoundedRectClip(style()->getRoundedBorderFor(IntRect(tx, ty, width(), height())));
   1099     paintInfo.context->clip(clipRect);
   1100     return true;
   1101 }
   1102 
   1103 void RenderBox::popContentsClip(PaintInfo& paintInfo, PaintPhase originalPhase, int tx, int ty)
   1104 {
   1105     ASSERT(hasControlClip() || (hasOverflowClip() && !layer()->isSelfPaintingLayer()));
   1106 
   1107     paintInfo.context->restore();
   1108     if (originalPhase == PaintPhaseOutline) {
   1109         paintInfo.phase = PaintPhaseSelfOutline;
   1110         paintObject(paintInfo, tx, ty);
   1111         paintInfo.phase = originalPhase;
   1112     } else if (originalPhase == PaintPhaseChildBlockBackground)
   1113         paintInfo.phase = originalPhase;
   1114 }
   1115 
   1116 IntRect RenderBox::overflowClipRect(int tx, int ty, OverlayScrollbarSizeRelevancy relevancy)
   1117 {
   1118     // FIXME: When overflow-clip (CSS3) is implemented, we'll obtain the property
   1119     // here.
   1120 
   1121     int bLeft = borderLeft();
   1122     int bTop = borderTop();
   1123 
   1124     int clipX = tx + bLeft;
   1125     int clipY = ty + bTop;
   1126     int clipWidth = width() - bLeft - borderRight();
   1127     int clipHeight = height() - bTop - borderBottom();
   1128 
   1129     // Subtract out scrollbars if we have them.
   1130     if (layer()) {
   1131         clipWidth -= layer()->verticalScrollbarWidth(relevancy);
   1132         clipHeight -= layer()->horizontalScrollbarHeight(relevancy);
   1133     }
   1134 
   1135     return IntRect(clipX, clipY, clipWidth, clipHeight);
   1136 }
   1137 
   1138 IntRect RenderBox::clipRect(int tx, int ty)
   1139 {
   1140     int clipX = tx;
   1141     int clipY = ty;
   1142     int clipWidth = width();
   1143     int clipHeight = height();
   1144 
   1145     if (!style()->clipLeft().isAuto()) {
   1146         int c = style()->clipLeft().calcValue(width());
   1147         clipX += c;
   1148         clipWidth -= c;
   1149     }
   1150 
   1151     if (!style()->clipRight().isAuto())
   1152         clipWidth -= width() - style()->clipRight().calcValue(width());
   1153 
   1154     if (!style()->clipTop().isAuto()) {
   1155         int c = style()->clipTop().calcValue(height());
   1156         clipY += c;
   1157         clipHeight -= c;
   1158     }
   1159 
   1160     if (!style()->clipBottom().isAuto())
   1161         clipHeight -= height() - style()->clipBottom().calcValue(height());
   1162 
   1163     return IntRect(clipX, clipY, clipWidth, clipHeight);
   1164 }
   1165 
   1166 int RenderBox::containingBlockLogicalWidthForContent() const
   1167 {
   1168     RenderBlock* cb = containingBlock();
   1169     if (shrinkToAvoidFloats())
   1170         return cb->availableLogicalWidthForLine(y(), false);
   1171     return cb->availableLogicalWidth();
   1172 }
   1173 
   1174 int RenderBox::perpendicularContainingBlockLogicalHeight() const
   1175 {
   1176     RenderBlock* cb = containingBlock();
   1177     RenderStyle* containingBlockStyle = cb->style();
   1178     Length logicalHeightLength = containingBlockStyle->logicalHeight();
   1179 
   1180     // FIXME: For now just support fixed heights.  Eventually should support percentage heights as well.
   1181     if (!logicalHeightLength.isFixed()) {
   1182         // Rather than making the child be completely unconstrained, WinIE uses the viewport width and height
   1183         // as a constraint.  We do that for now as well even though it's likely being unconstrained is what the spec
   1184         // will decide.
   1185         return containingBlockStyle->isHorizontalWritingMode() ? view()->frameView()->visibleHeight() : view()->frameView()->visibleWidth();
   1186     }
   1187 
   1188     // Use the content box logical height as specified by the style.
   1189     return cb->computeContentBoxLogicalHeight(logicalHeightLength.value());
   1190 }
   1191 
   1192 void RenderBox::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState) const
   1193 {
   1194     if (repaintContainer == this)
   1195         return;
   1196 
   1197     if (RenderView* v = view()) {
   1198         if (v->layoutStateEnabled() && !repaintContainer) {
   1199             LayoutState* layoutState = v->layoutState();
   1200             IntSize offset = layoutState->m_paintOffset;
   1201             offset.expand(x(), y());
   1202             if (style()->position() == RelativePosition && layer())
   1203                 offset += layer()->relativePositionOffset();
   1204             transformState.move(offset);
   1205             return;
   1206         }
   1207     }
   1208 
   1209     bool containerSkipped;
   1210     RenderObject* o = container(repaintContainer, &containerSkipped);
   1211     if (!o)
   1212         return;
   1213 
   1214     bool isFixedPos = style()->position() == FixedPosition;
   1215     bool hasTransform = hasLayer() && layer()->transform();
   1216     if (hasTransform) {
   1217         // If this box has a transform, it acts as a fixed position container for fixed descendants,
   1218         // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
   1219         fixed &= isFixedPos;
   1220     } else
   1221         fixed |= isFixedPos;
   1222 
   1223     IntSize containerOffset = offsetFromContainer(o, roundedIntPoint(transformState.mappedPoint()));
   1224 
   1225     bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
   1226     if (useTransforms && shouldUseTransformFromContainer(o)) {
   1227         TransformationMatrix t;
   1228         getTransformFromContainer(o, containerOffset, t);
   1229         transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
   1230     } else
   1231         transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
   1232 
   1233     if (containerSkipped) {
   1234         // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
   1235         // to just subtract the delta between the repaintContainer and o.
   1236         IntSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
   1237         transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
   1238         return;
   1239     }
   1240 
   1241     o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState);
   1242 }
   1243 
   1244 void RenderBox::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState& transformState) const
   1245 {
   1246     // We don't expect absoluteToLocal() to be called during layout (yet)
   1247     ASSERT(!view() || !view()->layoutStateEnabled());
   1248 
   1249     bool isFixedPos = style()->position() == FixedPosition;
   1250     bool hasTransform = hasLayer() && layer()->transform();
   1251     if (hasTransform) {
   1252         // If this box has a transform, it acts as a fixed position container for fixed descendants,
   1253         // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
   1254         fixed &= isFixedPos;
   1255     } else
   1256         fixed |= isFixedPos;
   1257 
   1258     RenderObject* o = container();
   1259     if (!o)
   1260         return;
   1261 
   1262     o->mapAbsoluteToLocalPoint(fixed, useTransforms, transformState);
   1263 
   1264     IntSize containerOffset = offsetFromContainer(o, IntPoint());
   1265 
   1266     bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
   1267     if (useTransforms && shouldUseTransformFromContainer(o)) {
   1268         TransformationMatrix t;
   1269         getTransformFromContainer(o, containerOffset, t);
   1270         transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
   1271     } else
   1272         transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
   1273 }
   1274 
   1275 IntSize RenderBox::offsetFromContainer(RenderObject* o, const IntPoint& point) const
   1276 {
   1277     ASSERT(o == container());
   1278 
   1279     IntSize offset;
   1280     if (isRelPositioned())
   1281         offset += relativePositionOffset();
   1282 
   1283     if (!isInline() || isReplaced()) {
   1284         if (style()->position() != AbsolutePosition && style()->position() != FixedPosition) {
   1285             if (o->hasColumns()) {
   1286                 IntRect columnRect(frameRect());
   1287                 toRenderBlock(o)->flipForWritingModeIncludingColumns(columnRect);
   1288                 offset += IntSize(columnRect.location().x(), columnRect.location().y());
   1289                 columnRect.move(point.x(), point.y());
   1290                 o->adjustForColumns(offset, columnRect.location());
   1291             } else
   1292                 offset += locationOffsetIncludingFlipping();
   1293         } else
   1294             offset += locationOffsetIncludingFlipping();
   1295     }
   1296 
   1297     if (o->hasOverflowClip())
   1298         offset -= toRenderBox(o)->layer()->scrolledContentOffset();
   1299 
   1300     if (style()->position() == AbsolutePosition && o->isRelPositioned() && o->isRenderInline())
   1301         offset += toRenderInline(o)->relativePositionedInlineOffset(this);
   1302 
   1303     return offset;
   1304 }
   1305 
   1306 InlineBox* RenderBox::createInlineBox()
   1307 {
   1308     return new (renderArena()) InlineBox(this);
   1309 }
   1310 
   1311 void RenderBox::dirtyLineBoxes(bool fullLayout)
   1312 {
   1313     if (m_inlineBoxWrapper) {
   1314         if (fullLayout) {
   1315             m_inlineBoxWrapper->destroy(renderArena());
   1316             m_inlineBoxWrapper = 0;
   1317         } else
   1318             m_inlineBoxWrapper->dirtyLineBoxes();
   1319     }
   1320 }
   1321 
   1322 void RenderBox::positionLineBox(InlineBox* box)
   1323 {
   1324     if (isPositioned()) {
   1325         // Cache the x position only if we were an INLINE type originally.
   1326         bool wasInline = style()->isOriginalDisplayInlineType();
   1327         if (wasInline) {
   1328             // The value is cached in the xPos of the box.  We only need this value if
   1329             // our object was inline originally, since otherwise it would have ended up underneath
   1330             // the inlines.
   1331             layer()->setStaticInlinePosition(lroundf(box->logicalLeft()));
   1332             if (style()->hasStaticInlinePosition(box->isHorizontal()))
   1333                 setChildNeedsLayout(true, false); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
   1334         } else {
   1335             // Our object was a block originally, so we make our normal flow position be
   1336             // just below the line box (as though all the inlines that came before us got
   1337             // wrapped in an anonymous block, which is what would have happened had we been
   1338             // in flow).  This value was cached in the y() of the box.
   1339             layer()->setStaticBlockPosition(box->logicalTop());
   1340             if (style()->hasStaticBlockPosition(box->isHorizontal()))
   1341                 setChildNeedsLayout(true, false); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
   1342         }
   1343 
   1344         // Nuke the box.
   1345         box->remove();
   1346         box->destroy(renderArena());
   1347     } else if (isReplaced()) {
   1348         setLocation(lroundf(box->x()), lroundf(box->y()));
   1349         m_inlineBoxWrapper = box;
   1350     }
   1351 }
   1352 
   1353 void RenderBox::deleteLineBoxWrapper()
   1354 {
   1355     if (m_inlineBoxWrapper) {
   1356         if (!documentBeingDestroyed())
   1357             m_inlineBoxWrapper->remove();
   1358         m_inlineBoxWrapper->destroy(renderArena());
   1359         m_inlineBoxWrapper = 0;
   1360     }
   1361 }
   1362 
   1363 IntRect RenderBox::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
   1364 {
   1365     if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent())
   1366         return IntRect();
   1367 
   1368     IntRect r = visualOverflowRect();
   1369 
   1370     RenderView* v = view();
   1371     if (v) {
   1372         // FIXME: layoutDelta needs to be applied in parts before/after transforms and
   1373         // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
   1374         r.move(v->layoutDelta());
   1375     }
   1376 
   1377     if (style()) {
   1378         if (style()->hasAppearance())
   1379             // The theme may wish to inflate the rect used when repainting.
   1380             theme()->adjustRepaintRect(this, r);
   1381 
   1382         // We have to use maximalOutlineSize() because a child might have an outline
   1383         // that projects outside of our overflowRect.
   1384         if (v) {
   1385             ASSERT(style()->outlineSize() <= v->maximalOutlineSize());
   1386             r.inflate(v->maximalOutlineSize());
   1387         }
   1388     }
   1389 
   1390     computeRectForRepaint(repaintContainer, r);
   1391     return r;
   1392 }
   1393 
   1394 void RenderBox::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& rect, bool fixed)
   1395 {
   1396     // The rect we compute at each step is shifted by our x/y offset in the parent container's coordinate space.
   1397     // Only when we cross a writing mode boundary will we have to possibly flipForWritingMode (to convert into a more appropriate
   1398     // offset corner for the enclosing container).  This allows for a fully RL or BT document to repaint
   1399     // properly even during layout, since the rect remains flipped all the way until the end.
   1400     //
   1401     // RenderView::computeRectForRepaint then converts the rect to physical coordinates.  We also convert to
   1402     // physical when we hit a repaintContainer boundary.  Therefore the final rect returned is always in the
   1403     // physical coordinate space of the repaintContainer.
   1404     if (RenderView* v = view()) {
   1405         // LayoutState is only valid for root-relative repainting
   1406         if (v->layoutStateEnabled() && !repaintContainer) {
   1407             LayoutState* layoutState = v->layoutState();
   1408 
   1409             if (layer() && layer()->transform())
   1410                 rect = layer()->transform()->mapRect(rect);
   1411 
   1412             if (style()->position() == RelativePosition && layer())
   1413                 rect.move(layer()->relativePositionOffset());
   1414 
   1415             rect.move(x(), y());
   1416             rect.move(layoutState->m_paintOffset);
   1417             if (layoutState->m_clipped)
   1418                 rect.intersect(layoutState->m_clipRect);
   1419             return;
   1420         }
   1421     }
   1422 
   1423     if (hasReflection())
   1424         rect.unite(reflectedRect(rect));
   1425 
   1426     if (repaintContainer == this) {
   1427         if (repaintContainer->style()->isFlippedBlocksWritingMode())
   1428             flipForWritingMode(rect);
   1429         return;
   1430     }
   1431 
   1432     bool containerSkipped;
   1433     RenderObject* o = container(repaintContainer, &containerSkipped);
   1434     if (!o)
   1435         return;
   1436 
   1437     if (isWritingModeRoot() && !isPositioned())
   1438         flipForWritingMode(rect);
   1439     IntPoint topLeft = rect.location();
   1440     topLeft.move(x(), y());
   1441 
   1442     EPosition position = style()->position();
   1443 
   1444     // We are now in our parent container's coordinate space.  Apply our transform to obtain a bounding box
   1445     // in the parent's coordinate space that encloses us.
   1446     if (layer() && layer()->transform()) {
   1447         fixed = position == FixedPosition;
   1448         rect = layer()->transform()->mapRect(rect);
   1449         topLeft = rect.location();
   1450         topLeft.move(x(), y());
   1451     } else if (position == FixedPosition)
   1452         fixed = true;
   1453 
   1454     if (position == AbsolutePosition && o->isRelPositioned() && o->isRenderInline())
   1455         topLeft += toRenderInline(o)->relativePositionedInlineOffset(this);
   1456     else if (position == RelativePosition && layer()) {
   1457         // Apply the relative position offset when invalidating a rectangle.  The layer
   1458         // is translated, but the render box isn't, so we need to do this to get the
   1459         // right dirty rect.  Since this is called from RenderObject::setStyle, the relative position
   1460         // flag on the RenderObject has been cleared, so use the one on the style().
   1461         topLeft += layer()->relativePositionOffset();
   1462     }
   1463 
   1464     if (o->isBlockFlow() && position != AbsolutePosition && position != FixedPosition) {
   1465         RenderBlock* cb = toRenderBlock(o);
   1466         if (cb->hasColumns()) {
   1467             IntRect repaintRect(topLeft, rect.size());
   1468             cb->adjustRectForColumns(repaintRect);
   1469             topLeft = repaintRect.location();
   1470             rect = repaintRect;
   1471         }
   1472     }
   1473 
   1474     // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
   1475     // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
   1476     if (o->hasOverflowClip()) {
   1477         RenderBox* containerBox = toRenderBox(o);
   1478 
   1479         // o->height() is inaccurate if we're in the middle of a layout of |o|, so use the
   1480         // layer's size instead.  Even if the layer's size is wrong, the layer itself will repaint
   1481         // anyway if its size does change.
   1482         topLeft -= containerBox->layer()->scrolledContentOffset(); // For overflow:auto/scroll/hidden.
   1483 
   1484         IntRect repaintRect(topLeft, rect.size());
   1485         IntRect boxRect(0, 0, containerBox->layer()->width(), containerBox->layer()->height());
   1486         rect = intersection(repaintRect, boxRect);
   1487         if (rect.isEmpty())
   1488             return;
   1489     } else
   1490         rect.setLocation(topLeft);
   1491 
   1492     if (containerSkipped) {
   1493         // If the repaintContainer is below o, then we need to map the rect into repaintContainer's coordinates.
   1494         IntSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
   1495         rect.move(-containerOffset);
   1496         return;
   1497     }
   1498 
   1499     o->computeRectForRepaint(repaintContainer, rect, fixed);
   1500 }
   1501 
   1502 void RenderBox::repaintDuringLayoutIfMoved(const IntRect& rect)
   1503 {
   1504     int newX = x();
   1505     int newY = y();
   1506     int newWidth = width();
   1507     int newHeight = height();
   1508     if (rect.x() != newX || rect.y() != newY) {
   1509         // The child moved.  Invalidate the object's old and new positions.  We have to do this
   1510         // since the object may not have gotten a layout.
   1511         m_frameRect = rect;
   1512         repaint();
   1513         repaintOverhangingFloats(true);
   1514         m_frameRect = IntRect(newX, newY, newWidth, newHeight);
   1515         repaint();
   1516         repaintOverhangingFloats(true);
   1517     }
   1518 }
   1519 
   1520 #ifdef ANDROID_LAYOUT
   1521 void RenderBox::setVisibleWidth(int newWidth) {
   1522     const Settings* settings = document()->settings();
   1523     ASSERT(settings);
   1524     if (settings->layoutAlgorithm() != Settings::kLayoutFitColumnToScreen
   1525         || m_visibleWidth == newWidth)
   1526         return;
   1527     m_isVisibleWidthChangedBeforeLayout = true;
   1528     m_visibleWidth = newWidth;
   1529 }
   1530 
   1531 bool RenderBox::checkAndSetRelayoutChildren(bool* relayoutChildren) {
   1532     if (m_isVisibleWidthChangedBeforeLayout) {
   1533         m_isVisibleWidthChangedBeforeLayout = false;
   1534         *relayoutChildren = true;
   1535         return true;
   1536     }
   1537     return false;
   1538 }
   1539 #endif
   1540 
   1541 void RenderBox::computeLogicalWidth()
   1542 {
   1543 #ifdef ANDROID_LAYOUT
   1544     if (view()->frameView())
   1545         setVisibleWidth(view()->frameView()->textWrapWidth());
   1546 #endif
   1547 
   1548     if (isPositioned()) {
   1549         // FIXME: This calculation is not patched for block-flow yet.
   1550         // https://bugs.webkit.org/show_bug.cgi?id=46500
   1551         computePositionedLogicalWidth();
   1552         return;
   1553     }
   1554 
   1555     // If layout is limited to a subtree, the subtree root's logical width does not change.
   1556     if (node() && view()->frameView() && view()->frameView()->layoutRoot(true) == this)
   1557         return;
   1558 
   1559     // The parent box is flexing us, so it has increased or decreased our
   1560     // width.  Use the width from the style context.
   1561     // FIXME: Account for block-flow in flexible boxes.
   1562     // https://bugs.webkit.org/show_bug.cgi?id=46418
   1563     if (hasOverrideSize() &&  parent()->style()->boxOrient() == HORIZONTAL
   1564             && parent()->isFlexibleBox() && parent()->isFlexingChildren()) {
   1565         setLogicalWidth(overrideSize());
   1566         return;
   1567     }
   1568 
   1569     // FIXME: Account for block-flow in flexible boxes.
   1570     // https://bugs.webkit.org/show_bug.cgi?id=46418
   1571     bool inVerticalBox = parent()->isFlexibleBox() && (parent()->style()->boxOrient() == VERTICAL);
   1572     bool stretching = (parent()->style()->boxAlign() == BSTRETCH);
   1573     bool treatAsReplaced = shouldComputeSizeAsReplaced() && (!inVerticalBox || !stretching);
   1574 
   1575     Length logicalWidthLength = (treatAsReplaced) ? Length(computeReplacedLogicalWidth(), Fixed) : style()->logicalWidth();
   1576 
   1577     RenderBlock* cb = containingBlock();
   1578     int containerLogicalWidth = max(0, containingBlockLogicalWidthForContent());
   1579     bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHorizontalWritingMode();
   1580     int containerWidthInInlineDirection = containerLogicalWidth;
   1581     if (hasPerpendicularContainingBlock)
   1582         containerWidthInInlineDirection = perpendicularContainingBlockLogicalHeight();
   1583 
   1584     if (isInline() && !isInlineBlockOrInlineTable()) {
   1585         // just calculate margins
   1586         setMarginStart(style()->marginStart().calcMinValue(containerLogicalWidth));
   1587         setMarginEnd(style()->marginEnd().calcMinValue(containerLogicalWidth));
   1588 #ifdef ANDROID_LAYOUT
   1589         if (treatAsReplaced) {
   1590 #else
   1591         if (treatAsReplaced)
   1592 #endif
   1593             setLogicalWidth(max(logicalWidthLength.value() + borderAndPaddingLogicalWidth(), minPreferredLogicalWidth()));
   1594 
   1595 #ifdef ANDROID_LAYOUT
   1596             // in SSR mode with replaced box, if the box width is wider than the container width,
   1597             // it will be shrinked to fit to the container.
   1598             if (containerLogicalWidth && (width() + m_marginLeft + m_marginRight) > containerLogicalWidth &&
   1599                     document()->frame()->settings()->layoutAlgorithm() == Settings::kLayoutSSR) {
   1600                 m_marginLeft = m_marginRight = 0;
   1601                 setWidth(containerLogicalWidth);
   1602                 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = containerLogicalWidth;
   1603             }
   1604         }
   1605 #endif
   1606         return;
   1607     }
   1608 
   1609     // Width calculations
   1610     if (treatAsReplaced)
   1611         setLogicalWidth(logicalWidthLength.value() + borderAndPaddingLogicalWidth());
   1612     else {
   1613         // Calculate LogicalWidth
   1614         setLogicalWidth(computeLogicalWidthUsing(LogicalWidth, containerWidthInInlineDirection));
   1615 
   1616         // Calculate MaxLogicalWidth
   1617         if (!style()->logicalMaxWidth().isUndefined()) {
   1618             int maxLogicalWidth = computeLogicalWidthUsing(MaxLogicalWidth, containerWidthInInlineDirection);
   1619             if (logicalWidth() > maxLogicalWidth) {
   1620                 setLogicalWidth(maxLogicalWidth);
   1621                 logicalWidthLength = style()->logicalMaxWidth();
   1622             }
   1623         }
   1624 
   1625         // Calculate MinLogicalWidth
   1626         int minLogicalWidth = computeLogicalWidthUsing(MinLogicalWidth, containerWidthInInlineDirection);
   1627         if (logicalWidth() < minLogicalWidth) {
   1628             setLogicalWidth(minLogicalWidth);
   1629             logicalWidthLength = style()->logicalMinWidth();
   1630         }
   1631     }
   1632 
   1633     // Fieldsets are currently the only objects that stretch to their minimum width.
   1634     if (stretchesToMinIntrinsicLogicalWidth()) {
   1635         setLogicalWidth(max(logicalWidth(), minPreferredLogicalWidth()));
   1636         logicalWidthLength = Length(logicalWidth(), Fixed);
   1637     }
   1638 
   1639     // Margin calculations.
   1640     if (logicalWidthLength.isAuto() || hasPerpendicularContainingBlock || isFloating() || isInline()) {
   1641         setMarginStart(style()->marginStart().calcMinValue(containerLogicalWidth));
   1642         setMarginEnd(style()->marginEnd().calcMinValue(containerLogicalWidth));
   1643     } else
   1644         computeInlineDirectionMargins(cb, containerLogicalWidth, logicalWidth());
   1645 
   1646 #ifdef ANDROID_LAYOUT
   1647     // in SSR mode with non-replaced box, we use ANDROID_SSR_MARGIN_PADDING for left/right margin.
   1648     // If the box width is wider than the container width, it will be shrinked to fit to the container.
   1649     if (containerLogicalWidth && !treatAsReplaced &&
   1650             document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR) {
   1651         setWidth(width() + m_marginLeft + m_marginRight);
   1652         m_marginLeft = m_marginLeft > ANDROID_SSR_MARGIN_PADDING ? ANDROID_SSR_MARGIN_PADDING : m_marginLeft;
   1653         m_marginRight = m_marginRight > ANDROID_SSR_MARGIN_PADDING ? ANDROID_SSR_MARGIN_PADDING : m_marginRight;
   1654         if (width() > containerLogicalWidth) {
   1655             m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = containerLogicalWidth-(m_marginLeft + m_marginRight);
   1656             setWidth(m_minPreferredLogicalWidth);
   1657         } else
   1658             setWidth(width() -(m_marginLeft + m_marginRight));
   1659     }
   1660 #endif
   1661 
   1662     if (!hasPerpendicularContainingBlock && containerLogicalWidth && containerLogicalWidth != (logicalWidth() + marginStart() + marginEnd())
   1663             && !isFloating() && !isInline() && !cb->isFlexibleBox())
   1664         cb->setMarginEndForChild(this, containerLogicalWidth - logicalWidth() - cb->marginStartForChild(this));
   1665 }
   1666 
   1667 int RenderBox::computeLogicalWidthUsing(LogicalWidthType widthType, int availableLogicalWidth)
   1668 {
   1669     int logicalWidthResult = logicalWidth();
   1670     Length logicalWidth;
   1671     if (widthType == LogicalWidth)
   1672         logicalWidth = style()->logicalWidth();
   1673     else if (widthType == MinLogicalWidth)
   1674         logicalWidth = style()->logicalMinWidth();
   1675     else
   1676         logicalWidth = style()->logicalMaxWidth();
   1677 
   1678     if (logicalWidth.isIntrinsicOrAuto()) {
   1679         int marginStart = style()->marginStart().calcMinValue(availableLogicalWidth);
   1680         int marginEnd = style()->marginEnd().calcMinValue(availableLogicalWidth);
   1681         if (availableLogicalWidth)
   1682             logicalWidthResult = availableLogicalWidth - marginStart - marginEnd;
   1683 
   1684         if (sizesToIntrinsicLogicalWidth(widthType)) {
   1685             logicalWidthResult = max(logicalWidthResult, minPreferredLogicalWidth());
   1686             logicalWidthResult = min(logicalWidthResult, maxPreferredLogicalWidth());
   1687         }
   1688     } else // FIXME: If the containing block flow is perpendicular to our direction we need to use the available logical height instead.
   1689         logicalWidthResult = computeBorderBoxLogicalWidth(logicalWidth.calcValue(availableLogicalWidth));
   1690 
   1691     return logicalWidthResult;
   1692 }
   1693 
   1694 bool RenderBox::sizesToIntrinsicLogicalWidth(LogicalWidthType widthType) const
   1695 {
   1696     // Marquees in WinIE are like a mixture of blocks and inline-blocks.  They size as though they're blocks,
   1697     // but they allow text to sit on the same line as the marquee.
   1698     if (isFloating() || (isInlineBlockOrInlineTable() && !isHTMLMarquee()))
   1699         return true;
   1700 
   1701     // This code may look a bit strange.  Basically width:intrinsic should clamp the size when testing both
   1702     // min-width and width.  max-width is only clamped if it is also intrinsic.
   1703     Length logicalWidth = (widthType == MaxLogicalWidth) ? style()->logicalMaxWidth() : style()->logicalWidth();
   1704     if (logicalWidth.type() == Intrinsic)
   1705         return true;
   1706 
   1707     // Children of a horizontal marquee do not fill the container by default.
   1708     // FIXME: Need to deal with MAUTO value properly.  It could be vertical.
   1709     // FIXME: Think about block-flow here.  Need to find out how marquee direction relates to
   1710     // block-flow (as well as how marquee overflow should relate to block flow).
   1711     // https://bugs.webkit.org/show_bug.cgi?id=46472
   1712     if (parent()->style()->overflowX() == OMARQUEE) {
   1713         EMarqueeDirection dir = parent()->style()->marqueeDirection();
   1714         if (dir == MAUTO || dir == MFORWARD || dir == MBACKWARD || dir == MLEFT || dir == MRIGHT)
   1715             return true;
   1716     }
   1717 
   1718     // Flexible horizontal boxes lay out children at their intrinsic widths.  Also vertical boxes
   1719     // that don't stretch their kids lay out their children at their intrinsic widths.
   1720     // FIXME: Think about block-flow here.
   1721     // https://bugs.webkit.org/show_bug.cgi?id=46473
   1722     if (parent()->isFlexibleBox()
   1723             && (parent()->style()->boxOrient() == HORIZONTAL || parent()->style()->boxAlign() != BSTRETCH))
   1724         return true;
   1725 
   1726     // Button, input, select, textarea, legend and datagrid treat
   1727     // width value of 'auto' as 'intrinsic' unless it's in a
   1728     // stretching vertical flexbox.
   1729     // FIXME: Think about block-flow here.
   1730     // https://bugs.webkit.org/show_bug.cgi?id=46473
   1731     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)))
   1732         return true;
   1733 
   1734     return false;
   1735 }
   1736 
   1737 void RenderBox::computeInlineDirectionMargins(RenderBlock* containingBlock, int containerWidth, int childWidth)
   1738 {
   1739     const RenderStyle* containingBlockStyle = containingBlock->style();
   1740     Length marginStartLength = style()->marginStartUsing(containingBlockStyle);
   1741     Length marginEndLength = style()->marginEndUsing(containingBlockStyle);
   1742 
   1743     // Case One: The object is being centered in the containing block's available logical width.
   1744     if ((marginStartLength.isAuto() && marginEndLength.isAuto() && childWidth < containerWidth)
   1745         || (!marginStartLength.isAuto() && !marginEndLength.isAuto() && containingBlock->style()->textAlign() == WEBKIT_CENTER)) {
   1746         containingBlock->setMarginStartForChild(this, max(0, (containerWidth - childWidth) / 2));
   1747         containingBlock->setMarginEndForChild(this, containerWidth - childWidth - containingBlock->marginStartForChild(this));
   1748         return;
   1749     }
   1750 
   1751     // Case Two: The object is being pushed to the start of the containing block's available logical width.
   1752     if (marginEndLength.isAuto() && childWidth < containerWidth) {
   1753         containingBlock->setMarginStartForChild(this, marginStartLength.calcValue(containerWidth));
   1754         containingBlock->setMarginEndForChild(this, containerWidth - childWidth - containingBlock->marginStartForChild(this));
   1755         return;
   1756     }
   1757 
   1758     // Case Three: The object is being pushed to the end of the containing block's available logical width.
   1759     bool pushToEndFromTextAlign = !marginEndLength.isAuto() && ((!containingBlockStyle->isLeftToRightDirection() && containingBlockStyle->textAlign() == WEBKIT_LEFT)
   1760         || (containingBlockStyle->isLeftToRightDirection() && containingBlockStyle->textAlign() == WEBKIT_RIGHT));
   1761     if ((marginStartLength.isAuto() && childWidth < containerWidth) || pushToEndFromTextAlign) {
   1762         containingBlock->setMarginEndForChild(this, marginEndLength.calcValue(containerWidth));
   1763         containingBlock->setMarginStartForChild(this, containerWidth - childWidth - containingBlock->marginEndForChild(this));
   1764         return;
   1765     }
   1766 
   1767     // Case Four: Either no auto margins, or our width is >= the container width (css2.1, 10.3.3).  In that case
   1768     // auto margins will just turn into 0.
   1769     containingBlock->setMarginStartForChild(this, marginStartLength.calcMinValue(containerWidth));
   1770     containingBlock->setMarginEndForChild(this, marginEndLength.calcMinValue(containerWidth));
   1771 }
   1772 
   1773 void RenderBox::computeLogicalHeight()
   1774 {
   1775     // Cell height is managed by the table and inline non-replaced elements do not support a height property.
   1776     if (isTableCell() || (isInline() && !isReplaced()))
   1777         return;
   1778 
   1779     Length h;
   1780     if (isPositioned()) {
   1781         // FIXME: This calculation is not patched for block-flow yet.
   1782         // https://bugs.webkit.org/show_bug.cgi?id=46500
   1783         computePositionedLogicalHeight();
   1784     } else {
   1785         RenderBlock* cb = containingBlock();
   1786         bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHorizontalWritingMode();
   1787 
   1788         if (!hasPerpendicularContainingBlock)
   1789             computeBlockDirectionMargins(cb);
   1790 
   1791         // For tables, calculate margins only.
   1792         if (isTable()) {
   1793             if (hasPerpendicularContainingBlock)
   1794                 computeInlineDirectionMargins(cb, containingBlockLogicalWidthForContent(), logicalHeight());
   1795             return;
   1796         }
   1797 
   1798         // FIXME: Account for block-flow in flexible boxes.
   1799         // https://bugs.webkit.org/show_bug.cgi?id=46418
   1800         bool inHorizontalBox = parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL;
   1801         bool stretching = parent()->style()->boxAlign() == BSTRETCH;
   1802         bool treatAsReplaced = shouldComputeSizeAsReplaced() && (!inHorizontalBox || !stretching);
   1803         bool checkMinMaxHeight = false;
   1804 
   1805         // The parent box is flexing us, so it has increased or decreased our height.  We have to
   1806         // grab our cached flexible height.
   1807         // FIXME: Account for block-flow in flexible boxes.
   1808         // https://bugs.webkit.org/show_bug.cgi?id=46418
   1809         if (hasOverrideSize() && parent()->isFlexibleBox() && parent()->style()->boxOrient() == VERTICAL
   1810                 && parent()->isFlexingChildren())
   1811             h = Length(overrideSize() - borderAndPaddingLogicalHeight(), Fixed);
   1812         else if (treatAsReplaced)
   1813             h = Length(computeReplacedLogicalHeight(), Fixed);
   1814         else {
   1815             h = style()->logicalHeight();
   1816             checkMinMaxHeight = true;
   1817         }
   1818 
   1819         // Block children of horizontal flexible boxes fill the height of the box.
   1820         // FIXME: Account for block-flow in flexible boxes.
   1821         // https://bugs.webkit.org/show_bug.cgi?id=46418
   1822         if (h.isAuto() && parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
   1823                 && parent()->isStretchingChildren()) {
   1824             h = Length(parentBox()->contentLogicalHeight() - marginBefore() - marginAfter() - borderAndPaddingLogicalHeight(), Fixed);
   1825             checkMinMaxHeight = false;
   1826         }
   1827 
   1828         int heightResult;
   1829         if (checkMinMaxHeight) {
   1830 #ifdef ANDROID_LAYOUT
   1831             // in SSR mode, ignore CSS height as layout is so different
   1832             if (document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR)
   1833                 heightResult = -1;
   1834             else
   1835 #endif
   1836             heightResult = computeLogicalHeightUsing(style()->logicalHeight());
   1837             if (heightResult == -1)
   1838                 heightResult = logicalHeight();
   1839             int minH = computeLogicalHeightUsing(style()->logicalMinHeight()); // Leave as -1 if unset.
   1840             int maxH = style()->logicalMaxHeight().isUndefined() ? heightResult : computeLogicalHeightUsing(style()->logicalMaxHeight());
   1841             if (maxH == -1)
   1842                 maxH = heightResult;
   1843             heightResult = min(maxH, heightResult);
   1844             heightResult = max(minH, heightResult);
   1845         } else {
   1846             // The only times we don't check min/max height are when a fixed length has
   1847             // been given as an override.  Just use that.  The value has already been adjusted
   1848             // for box-sizing.
   1849             heightResult = h.value() + borderAndPaddingLogicalHeight();
   1850         }
   1851 
   1852         setLogicalHeight(heightResult);
   1853 
   1854         if (hasPerpendicularContainingBlock)
   1855             computeInlineDirectionMargins(cb, containingBlockLogicalWidthForContent(), heightResult);
   1856     }
   1857 
   1858     // WinIE quirk: The <html> block always fills the entire canvas in quirks mode.  The <body> always fills the
   1859     // <html> block in quirks mode.  Only apply this quirk if the block is normal flow and no height
   1860     // is specified. When we're printing, we also need this quirk if the body or root has a percentage
   1861     // height since we don't set a height in RenderView when we're printing. So without this quirk, the
   1862     // height has nothing to be a percentage of, and it ends up being 0. That is bad.
   1863     bool paginatedContentNeedsBaseHeight = document()->printing() && h.isPercent()
   1864         && (isRoot() || (isBody() && document()->documentElement()->renderer()->style()->logicalHeight().isPercent()));
   1865     if (stretchesToViewport() || paginatedContentNeedsBaseHeight) {
   1866         // FIXME: Finish accounting for block flow here.
   1867         // https://bugs.webkit.org/show_bug.cgi?id=46603
   1868         int margins = collapsedMarginBefore() + collapsedMarginAfter();
   1869         int visHeight;
   1870         if (document()->printing())
   1871             visHeight = static_cast<int>(view()->pageLogicalHeight());
   1872         else  {
   1873             if (isHorizontalWritingMode())
   1874                 visHeight = view()->viewHeight();
   1875             else
   1876                 visHeight = view()->viewWidth();
   1877         }
   1878         if (isRoot())
   1879             setLogicalHeight(max(logicalHeight(), visHeight - margins));
   1880         else {
   1881             int marginsBordersPadding = margins + parentBox()->marginBefore() + parentBox()->marginAfter() + parentBox()->borderAndPaddingLogicalHeight();
   1882             setLogicalHeight(max(logicalHeight(), visHeight - marginsBordersPadding));
   1883         }
   1884     }
   1885 }
   1886 
   1887 int RenderBox::computeLogicalHeightUsing(const Length& h)
   1888 {
   1889     int logicalHeight = -1;
   1890     if (!h.isAuto()) {
   1891         if (h.isFixed())
   1892             logicalHeight = h.value();
   1893         else if (h.isPercent())
   1894             logicalHeight = computePercentageLogicalHeight(h);
   1895         if (logicalHeight != -1) {
   1896             logicalHeight = computeBorderBoxLogicalHeight(logicalHeight);
   1897             return logicalHeight;
   1898         }
   1899     }
   1900     return logicalHeight;
   1901 }
   1902 
   1903 int RenderBox::computePercentageLogicalHeight(const Length& height)
   1904 {
   1905     int result = -1;
   1906 
   1907     // In quirks mode, blocks with auto height are skipped, and we keep looking for an enclosing
   1908     // block that may have a specified height and then use it. In strict mode, this violates the
   1909     // specification, which states that percentage heights just revert to auto if the containing
   1910     // block has an auto height. We still skip anonymous containing blocks in both modes, though, and look
   1911     // only at explicit containers.
   1912     bool skippedAutoHeightContainingBlock = false;
   1913     RenderBlock* cb = containingBlock();
   1914     while (!cb->isRenderView() && !cb->isBody() && !cb->isTableCell() && !cb->isPositioned() && cb->style()->logicalHeight().isAuto()) {
   1915         if (!document()->inQuirksMode() && !cb->isAnonymousBlock())
   1916             break;
   1917         skippedAutoHeightContainingBlock = true;
   1918         cb = cb->containingBlock();
   1919         cb->addPercentHeightDescendant(this);
   1920     }
   1921 
   1922     // A positioned element that specified both top/bottom or that specifies height should be treated as though it has a height
   1923     // explicitly specified that can be used for any percentage computations.
   1924     // FIXME: We can't just check top/bottom here.
   1925     // https://bugs.webkit.org/show_bug.cgi?id=46500
   1926     bool isPositionedWithSpecifiedHeight = cb->isPositioned() && (!cb->style()->logicalHeight().isAuto() || (!cb->style()->top().isAuto() && !cb->style()->bottom().isAuto()));
   1927 
   1928     bool includeBorderPadding = isTable();
   1929 
   1930     // Table cells violate what the CSS spec says to do with heights.  Basically we
   1931     // don't care if the cell specified a height or not.  We just always make ourselves
   1932     // be a percentage of the cell's current content height.
   1933     if (cb->isTableCell()) {
   1934         if (!skippedAutoHeightContainingBlock) {
   1935             result = cb->overrideSize();
   1936             if (result == -1) {
   1937                 // Normally we would let the cell size intrinsically, but scrolling overflow has to be
   1938                 // treated differently, since WinIE lets scrolled overflow regions shrink as needed.
   1939                 // While we can't get all cases right, we can at least detect when the cell has a specified
   1940                 // height or when the table has a specified height.  In these cases we want to initially have
   1941                 // no size and allow the flexing of the table or the cell to its specified height to cause us
   1942                 // to grow to fill the space.  This could end up being wrong in some cases, but it is
   1943                 // preferable to the alternative (sizing intrinsically and making the row end up too big).
   1944                 RenderTableCell* cell = toRenderTableCell(cb);
   1945                 if (scrollsOverflowY() && (!cell->style()->logicalHeight().isAuto() || !cell->table()->style()->logicalHeight().isAuto()))
   1946                     return 0;
   1947                 return -1;
   1948             }
   1949             includeBorderPadding = true;
   1950         }
   1951     }
   1952     // Otherwise we only use our percentage height if our containing block had a specified
   1953     // height.
   1954     else if (cb->style()->logicalHeight().isFixed())
   1955         result = cb->computeContentBoxLogicalHeight(cb->style()->logicalHeight().value());
   1956     else if (cb->style()->logicalHeight().isPercent() && !isPositionedWithSpecifiedHeight) {
   1957         // We need to recur and compute the percentage height for our containing block.
   1958         result = cb->computePercentageLogicalHeight(cb->style()->logicalHeight());
   1959         if (result != -1)
   1960             result = cb->computeContentBoxLogicalHeight(result);
   1961     } else if (cb->isRenderView() || (cb->isBody() && document()->inQuirksMode()) || isPositionedWithSpecifiedHeight) {
   1962         // Don't allow this to affect the block' height() member variable, since this
   1963         // can get called while the block is still laying out its kids.
   1964         int oldHeight = cb->logicalHeight();
   1965         cb->computeLogicalHeight();
   1966         result = cb->contentLogicalHeight();
   1967         cb->setLogicalHeight(oldHeight);
   1968     } else if (cb->isRoot() && isPositioned())
   1969         // Match the positioned objects behavior, which is that positioned objects will fill their viewport
   1970         // always.  Note we could only hit this case by recurring into computePercentageLogicalHeight on a positioned containing block.
   1971         result = cb->computeContentBoxLogicalHeight(cb->availableLogicalHeight());
   1972 
   1973     if (result != -1) {
   1974         result = height.calcValue(result);
   1975         if (includeBorderPadding) {
   1976             // It is necessary to use the border-box to match WinIE's broken
   1977             // box model.  This is essential for sizing inside
   1978             // table cells using percentage heights.
   1979             result -= borderAndPaddingLogicalHeight();
   1980             result = max(0, result);
   1981         }
   1982     }
   1983     return result;
   1984 }
   1985 
   1986 int RenderBox::computeReplacedLogicalWidth(bool includeMaxWidth) const
   1987 {
   1988     int logicalWidth = computeReplacedLogicalWidthUsing(style()->logicalWidth());
   1989     int minLogicalWidth = computeReplacedLogicalWidthUsing(style()->logicalMinWidth());
   1990     int maxLogicalWidth = !includeMaxWidth || style()->logicalMaxWidth().isUndefined() ? logicalWidth : computeReplacedLogicalWidthUsing(style()->logicalMaxWidth());
   1991 
   1992     return max(minLogicalWidth, min(logicalWidth, maxLogicalWidth));
   1993 }
   1994 
   1995 int RenderBox::computeReplacedLogicalWidthUsing(Length logicalWidth) const
   1996 {
   1997     switch (logicalWidth.type()) {
   1998         case Fixed:
   1999             return computeContentBoxLogicalWidth(logicalWidth.value());
   2000         case Percent: {
   2001             // FIXME: containingBlockLogicalWidthForContent() is wrong if the replaced element's block-flow is perpendicular to the
   2002             // containing block's block-flow.
   2003             // https://bugs.webkit.org/show_bug.cgi?id=46496
   2004             const int cw = isPositioned() ? containingBlockLogicalWidthForPositioned(toRenderBoxModelObject(container())) : containingBlockLogicalWidthForContent();
   2005             if (cw > 0)
   2006                 return computeContentBoxLogicalWidth(logicalWidth.calcMinValue(cw));
   2007         }
   2008         // fall through
   2009         default:
   2010             return intrinsicLogicalWidth();
   2011      }
   2012 }
   2013 
   2014 int RenderBox::computeReplacedLogicalHeight() const
   2015 {
   2016     int logicalHeight = computeReplacedLogicalHeightUsing(style()->logicalHeight());
   2017     int minLogicalHeight = computeReplacedLogicalHeightUsing(style()->logicalMinHeight());
   2018     int maxLogicalHeight = style()->logicalMaxHeight().isUndefined() ? logicalHeight : computeReplacedLogicalHeightUsing(style()->logicalMaxHeight());
   2019 
   2020     return max(minLogicalHeight, min(logicalHeight, maxLogicalHeight));
   2021 }
   2022 
   2023 int RenderBox::computeReplacedLogicalHeightUsing(Length logicalHeight) const
   2024 {
   2025     switch (logicalHeight.type()) {
   2026         case Fixed:
   2027             return computeContentBoxLogicalHeight(logicalHeight.value());
   2028         case Percent:
   2029         {
   2030             RenderObject* cb = isPositioned() ? container() : containingBlock();
   2031             while (cb->isAnonymous()) {
   2032                 cb = cb->containingBlock();
   2033                 toRenderBlock(cb)->addPercentHeightDescendant(const_cast<RenderBox*>(this));
   2034             }
   2035 
   2036             // FIXME: This calculation is not patched for block-flow yet.
   2037             // https://bugs.webkit.org/show_bug.cgi?id=46500
   2038             if (cb->isPositioned() && cb->style()->height().isAuto() && !(cb->style()->top().isAuto() || cb->style()->bottom().isAuto())) {
   2039                 ASSERT(cb->isRenderBlock());
   2040                 RenderBlock* block = toRenderBlock(cb);
   2041                 int oldHeight = block->height();
   2042                 block->computeLogicalHeight();
   2043                 int newHeight = block->computeContentBoxLogicalHeight(block->contentHeight());
   2044                 block->setHeight(oldHeight);
   2045                 return computeContentBoxLogicalHeight(logicalHeight.calcValue(newHeight));
   2046             }
   2047 
   2048             // FIXME: availableLogicalHeight() is wrong if the replaced element's block-flow is perpendicular to the
   2049             // containing block's block-flow.
   2050             // https://bugs.webkit.org/show_bug.cgi?id=46496
   2051             int availableHeight = isPositioned() ? containingBlockLogicalHeightForPositioned(toRenderBoxModelObject(cb)) : toRenderBox(cb)->availableLogicalHeight();
   2052 
   2053             // It is necessary to use the border-box to match WinIE's broken
   2054             // box model.  This is essential for sizing inside
   2055             // table cells using percentage heights.
   2056             // FIXME: This needs to be made block-flow-aware.  If the cell and image are perpendicular block-flows, this isn't right.
   2057             // https://bugs.webkit.org/show_bug.cgi?id=46997
   2058             if (cb->isTableCell() && (cb->style()->logicalHeight().isAuto() || cb->style()->logicalHeight().isPercent())) {
   2059                 // Don't let table cells squeeze percent-height replaced elements
   2060                 // <http://bugs.webkit.org/show_bug.cgi?id=15359>
   2061                 availableHeight = max(availableHeight, intrinsicLogicalHeight());
   2062                 return logicalHeight.calcValue(availableHeight - borderAndPaddingLogicalHeight());
   2063             }
   2064 
   2065             return computeContentBoxLogicalHeight(logicalHeight.calcValue(availableHeight));
   2066         }
   2067         default:
   2068             return intrinsicLogicalHeight();
   2069     }
   2070 }
   2071 
   2072 int RenderBox::availableLogicalHeight() const
   2073 {
   2074     return availableLogicalHeightUsing(style()->logicalHeight());
   2075 }
   2076 
   2077 int RenderBox::availableLogicalHeightUsing(const Length& h) const
   2078 {
   2079     if (h.isFixed())
   2080         return computeContentBoxLogicalHeight(h.value());
   2081 
   2082     if (isRenderView())
   2083         return isHorizontalWritingMode() ? toRenderView(this)->frameView()->visibleHeight() : toRenderView(this)->frameView()->visibleWidth();
   2084 
   2085     // We need to stop here, since we don't want to increase the height of the table
   2086     // artificially.  We're going to rely on this cell getting expanded to some new
   2087     // height, and then when we lay out again we'll use the calculation below.
   2088     if (isTableCell() && (h.isAuto() || h.isPercent()))
   2089         return overrideSize() - borderAndPaddingLogicalWidth();
   2090 
   2091     if (h.isPercent())
   2092        return computeContentBoxLogicalHeight(h.calcValue(containingBlock()->availableLogicalHeight()));
   2093 
   2094     // FIXME: We can't just check top/bottom here.
   2095     // https://bugs.webkit.org/show_bug.cgi?id=46500
   2096     if (isRenderBlock() && isPositioned() && style()->height().isAuto() && !(style()->top().isAuto() || style()->bottom().isAuto())) {
   2097         RenderBlock* block = const_cast<RenderBlock*>(toRenderBlock(this));
   2098         int oldHeight = block->logicalHeight();
   2099         block->computeLogicalHeight();
   2100         int newHeight = block->computeContentBoxLogicalHeight(block->contentLogicalHeight());
   2101         block->setLogicalHeight(oldHeight);
   2102         return computeContentBoxLogicalHeight(newHeight);
   2103     }
   2104 
   2105     return containingBlock()->availableLogicalHeight();
   2106 }
   2107 
   2108 void RenderBox::computeBlockDirectionMargins(RenderBlock* containingBlock)
   2109 {
   2110     if (isTableCell()) {
   2111         // FIXME: Not right if we allow cells to have different directionality than the table.  If we do allow this, though,
   2112         // we may just do it with an extra anonymous block inside the cell.
   2113         setMarginBefore(0);
   2114         setMarginAfter(0);
   2115         return;
   2116     }
   2117 
   2118     // Margins are calculated with respect to the logical width of
   2119     // the containing block (8.3)
   2120     int cw = containingBlockLogicalWidthForContent();
   2121 
   2122     RenderStyle* containingBlockStyle = containingBlock->style();
   2123     containingBlock->setMarginBeforeForChild(this, style()->marginBeforeUsing(containingBlockStyle).calcMinValue(cw));
   2124     containingBlock->setMarginAfterForChild(this, style()->marginAfterUsing(containingBlockStyle).calcMinValue(cw));
   2125 }
   2126 
   2127 int RenderBox::containingBlockLogicalWidthForPositioned(const RenderBoxModelObject* containingBlock, bool checkForPerpendicularWritingMode) const
   2128 {
   2129 #if PLATFORM(ANDROID)
   2130     // Fixed element's position should be decided by the visible screen size.
   2131     // That is in the doc coordindate.
   2132     if (style()->position() == FixedPosition && containingBlock->isRenderView()) {
   2133         const RenderView* view = toRenderView(containingBlock);
   2134         return PlatformBridge::screenWidthInDocCoord(view->frameView());
   2135     }
   2136 #endif
   2137 
   2138     if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWritingMode() != isHorizontalWritingMode())
   2139         return containingBlockLogicalHeightForPositioned(containingBlock, false);
   2140 
   2141     if (containingBlock->isBox())
   2142         return toRenderBox(containingBlock)->clientLogicalWidth();
   2143 
   2144     ASSERT(containingBlock->isRenderInline() && containingBlock->isRelPositioned());
   2145 
   2146     const RenderInline* flow = toRenderInline(containingBlock);
   2147     InlineFlowBox* first = flow->firstLineBox();
   2148     InlineFlowBox* last = flow->lastLineBox();
   2149 
   2150     // If the containing block is empty, return a width of 0.
   2151     if (!first || !last)
   2152         return 0;
   2153 
   2154     int fromLeft;
   2155     int fromRight;
   2156     if (containingBlock->style()->isLeftToRightDirection()) {
   2157         fromLeft = first->logicalLeft() + first->borderLogicalLeft();
   2158         fromRight = last->logicalLeft() + last->logicalWidth() - last->borderLogicalRight();
   2159     } else {
   2160         fromRight = first->logicalLeft() + first->logicalWidth() - first->borderLogicalRight();
   2161         fromLeft = last->logicalLeft() + last->borderLogicalLeft();
   2162     }
   2163 
   2164     return max(0, (fromRight - fromLeft));
   2165 }
   2166 
   2167 int RenderBox::containingBlockLogicalHeightForPositioned(const RenderBoxModelObject* containingBlock, bool checkForPerpendicularWritingMode) const
   2168 {
   2169 #if PLATFORM(ANDROID)
   2170     // Fixed element's position should be decided by the visible screen size.
   2171     // That is in the doc coordindate.
   2172     if (style()->position() == FixedPosition && containingBlock->isRenderView()) {
   2173         const RenderView* view = toRenderView(containingBlock);
   2174         return PlatformBridge::screenHeightInDocCoord(view->frameView());
   2175     }
   2176 #endif
   2177 
   2178     if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWritingMode() != isHorizontalWritingMode())
   2179         return containingBlockLogicalWidthForPositioned(containingBlock, false);
   2180 
   2181     if (containingBlock->isBox())
   2182         return toRenderBox(containingBlock)->clientLogicalHeight();
   2183 
   2184     ASSERT(containingBlock->isRenderInline() && containingBlock->isRelPositioned());
   2185 
   2186     const RenderInline* flow = toRenderInline(containingBlock);
   2187     InlineFlowBox* first = flow->firstLineBox();
   2188     InlineFlowBox* last = flow->lastLineBox();
   2189 
   2190     // If the containing block is empty, return a height of 0.
   2191     if (!first || !last)
   2192         return 0;
   2193 
   2194     int heightResult;
   2195     IntRect boundingBox = flow->linesBoundingBox();
   2196     if (containingBlock->isHorizontalWritingMode())
   2197         heightResult = boundingBox.height();
   2198     else
   2199         heightResult = boundingBox.width();
   2200     heightResult -= (containingBlock->borderBefore() + containingBlock->borderAfter());
   2201     return heightResult;
   2202 }
   2203 
   2204 static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRight, const RenderBox* child, const RenderBoxModelObject* containerBlock, int containerLogicalWidth,
   2205                                         TextDirection containerDirection)
   2206 {
   2207     if (!logicalLeft.isAuto() || !logicalRight.isAuto())
   2208         return;
   2209 
   2210     // FIXME: The static distance computation has not been patched for mixed writing modes yet.
   2211     if (containerDirection == LTR) {
   2212         int staticPosition = child->layer()->staticInlinePosition() - containerBlock->borderLogicalLeft();
   2213         for (RenderObject* curr = child->parent(); curr && curr != containerBlock; curr = curr->container()) {
   2214             if (curr->isBox())
   2215                 staticPosition += toRenderBox(curr)->logicalLeft();
   2216         }
   2217         logicalLeft.setValue(Fixed, staticPosition);
   2218     } else {
   2219         RenderBox* enclosingBox = child->parent()->enclosingBox();
   2220         int staticPosition = child->layer()->staticInlinePosition() + containerLogicalWidth + containerBlock->borderLogicalRight();
   2221         staticPosition -= enclosingBox->logicalWidth();
   2222         for (RenderObject* curr = enclosingBox; curr && curr != containerBlock; curr = curr->container()) {
   2223             if (curr->isBox())
   2224                 staticPosition -= toRenderBox(curr)->logicalLeft();
   2225         }
   2226         logicalRight.setValue(Fixed, staticPosition);
   2227     }
   2228 }
   2229 
   2230 void RenderBox::computePositionedLogicalWidth()
   2231 {
   2232     if (isReplaced()) {
   2233         computePositionedLogicalWidthReplaced();
   2234         return;
   2235     }
   2236 
   2237     // QUESTIONS
   2238     // FIXME 1: Which RenderObject's 'direction' property should used: the
   2239     // containing block (cb) as the spec seems to imply, the parent (parent()) as
   2240     // was previously done in calculating the static distances, or ourself, which
   2241     // was also previously done for deciding what to override when you had
   2242     // over-constrained margins?  Also note that the container block is used
   2243     // in similar situations in other parts of the RenderBox class (see computeLogicalWidth()
   2244     // and computeMarginsInContainingBlockInlineDirection()). For now we are using the parent for quirks
   2245     // mode and the containing block for strict mode.
   2246 
   2247     // FIXME 2: Should we still deal with these the cases of 'left' or 'right' having
   2248     // the type 'static' in determining whether to calculate the static distance?
   2249     // NOTE: 'static' is not a legal value for 'left' or 'right' as of CSS 2.1.
   2250 
   2251     // FIXME 3: Can perhaps optimize out cases when max-width/min-width are greater
   2252     // than or less than the computed width().  Be careful of box-sizing and
   2253     // percentage issues.
   2254 
   2255     // The following is based off of the W3C Working Draft from April 11, 2006 of
   2256     // CSS 2.1: Section 10.3.7 "Absolutely positioned, non-replaced elements"
   2257     // <http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width>
   2258     // (block-style-comments in this function and in computePositionedLogicalWidthUsing()
   2259     // correspond to text from the spec)
   2260 
   2261 
   2262     // We don't use containingBlock(), since we may be positioned by an enclosing
   2263     // relative positioned inline.
   2264     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
   2265 
   2266     const int containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock);
   2267 
   2268     // To match WinIE, in quirks mode use the parent's 'direction' property
   2269     // instead of the the container block's.
   2270     TextDirection containerDirection = (document()->inQuirksMode()) ? parent()->style()->direction() : containerBlock->style()->direction();
   2271 
   2272     bool isHorizontal = isHorizontalWritingMode();
   2273     const int bordersPlusPadding = borderAndPaddingLogicalWidth();
   2274     const Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->marginTop();
   2275     const Length marginLogicalRight = isHorizontal ? style()->marginRight() : style()->marginBottom();
   2276     int& marginLogicalLeftAlias = isHorizontal ? m_marginLeft : m_marginTop;
   2277     int& marginLogicalRightAlias = isHorizontal ? m_marginRight : m_marginBottom;
   2278 
   2279     Length logicalLeft = style()->logicalLeft();
   2280     Length logicalRight = style()->logicalRight();
   2281 
   2282     /*---------------------------------------------------------------------------*\
   2283      * For the purposes of this section and the next, the term "static position"
   2284      * (of an element) refers, roughly, to the position an element would have had
   2285      * in the normal flow. More precisely:
   2286      *
   2287      * * The static position for 'left' is the distance from the left edge of the
   2288      *   containing block to the left margin edge of a hypothetical box that would
   2289      *   have been the first box of the element if its 'position' property had
   2290      *   been 'static' and 'float' had been 'none'. The value is negative if the
   2291      *   hypothetical box is to the left of the containing block.
   2292      * * The static position for 'right' is the distance from the right edge of the
   2293      *   containing block to the right margin edge of the same hypothetical box as
   2294      *   above. The value is positive if the hypothetical box is to the left of the
   2295      *   containing block's edge.
   2296      *
   2297      * But rather than actually calculating the dimensions of that hypothetical box,
   2298      * user agents are free to make a guess at its probable position.
   2299      *
   2300      * For the purposes of calculating the static position, the containing block of
   2301      * fixed positioned elements is the initial containing block instead of the
   2302      * viewport, and all scrollable boxes should be assumed to be scrolled to their
   2303      * origin.
   2304     \*---------------------------------------------------------------------------*/
   2305 
   2306     // see FIXME 2
   2307     // Calculate the static distance if needed.
   2308     computeInlineStaticDistance(logicalLeft, logicalRight, this, containerBlock, containerLogicalWidth, containerDirection);
   2309 
   2310     // Calculate constraint equation values for 'width' case.
   2311     int logicalWidthResult;
   2312     int logicalLeftResult;
   2313     computePositionedLogicalWidthUsing(style()->logicalWidth(), containerBlock, containerDirection,
   2314                                        containerLogicalWidth, bordersPlusPadding,
   2315                                        logicalLeft, logicalRight, marginLogicalLeft, marginLogicalRight,
   2316                                        logicalWidthResult, marginLogicalLeftAlias, marginLogicalRightAlias, logicalLeftResult);
   2317     setLogicalWidth(logicalWidthResult);
   2318     setLogicalLeft(logicalLeftResult);
   2319 
   2320     // Calculate constraint equation values for 'max-width' case.
   2321     if (!style()->logicalMaxWidth().isUndefined()) {
   2322         int maxLogicalWidth;
   2323         int maxMarginLogicalLeft;
   2324         int maxMarginLogicalRight;
   2325         int maxLogicalLeftPos;
   2326 
   2327         computePositionedLogicalWidthUsing(style()->logicalMaxWidth(), containerBlock, containerDirection,
   2328                                            containerLogicalWidth, bordersPlusPadding,
   2329                                            logicalLeft, logicalRight, marginLogicalLeft, marginLogicalRight,
   2330                                            maxLogicalWidth, maxMarginLogicalLeft, maxMarginLogicalRight, maxLogicalLeftPos);
   2331 
   2332         if (logicalWidth() > maxLogicalWidth) {
   2333             setLogicalWidth(maxLogicalWidth);
   2334             marginLogicalLeftAlias = maxMarginLogicalLeft;
   2335             marginLogicalRightAlias = maxMarginLogicalRight;
   2336             setLogicalLeft(maxLogicalLeftPos);
   2337         }
   2338     }
   2339 
   2340     // Calculate constraint equation values for 'min-width' case.
   2341     if (!style()->logicalMinWidth().isZero()) {
   2342         int minLogicalWidth;
   2343         int minMarginLogicalLeft;
   2344         int minMarginLogicalRight;
   2345         int minLogicalLeftPos;
   2346 
   2347         computePositionedLogicalWidthUsing(style()->logicalMinWidth(), containerBlock, containerDirection,
   2348                                            containerLogicalWidth, bordersPlusPadding,
   2349                                            logicalLeft, logicalRight, marginLogicalLeft, marginLogicalRight,
   2350                                            minLogicalWidth, minMarginLogicalLeft, minMarginLogicalRight, minLogicalLeftPos);
   2351 
   2352         if (logicalWidth() < minLogicalWidth) {
   2353             setLogicalWidth(minLogicalWidth);
   2354             marginLogicalLeftAlias = minMarginLogicalLeft;
   2355             marginLogicalRightAlias = minMarginLogicalRight;
   2356             setLogicalLeft(minLogicalLeftPos);
   2357         }
   2358     }
   2359 
   2360     if (stretchesToMinIntrinsicLogicalWidth() && logicalWidth() < minPreferredLogicalWidth() - bordersPlusPadding) {
   2361         computePositionedLogicalWidthUsing(Length(minPreferredLogicalWidth() - bordersPlusPadding, Fixed), containerBlock, containerDirection,
   2362                                            containerLogicalWidth, bordersPlusPadding,
   2363                                            logicalLeft, logicalRight, marginLogicalLeft, marginLogicalRight,
   2364                                            logicalWidthResult, marginLogicalLeftAlias, marginLogicalRightAlias, logicalLeftResult);
   2365         setLogicalWidth(logicalWidthResult);
   2366         setLogicalLeft(logicalLeftResult);
   2367     }
   2368 
   2369     // Put logicalWidth() into correct form.
   2370     setLogicalWidth(logicalWidth() + bordersPlusPadding);
   2371 }
   2372 
   2373 static void computeLogicalLeftPositionedOffset(int& logicalLeftPos, const RenderBox* child, int logicalWidthValue, const RenderBoxModelObject* containerBlock, int containerLogicalWidth)
   2374 {
   2375     // Deal with differing writing modes here.  Our offset needs to be in the containing block's coordinate space. If the containing block is flipped
   2376     // 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.
   2377     if (containerBlock->isHorizontalWritingMode() != child->isHorizontalWritingMode() && containerBlock->style()->isFlippedBlocksWritingMode()) {
   2378         logicalLeftPos = containerLogicalWidth - logicalWidthValue - logicalLeftPos;
   2379         logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->borderRight() : containerBlock->borderBottom());
   2380     } else
   2381         logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->borderLeft() : containerBlock->borderTop());
   2382 }
   2383 
   2384 void RenderBox::computePositionedLogicalWidthUsing(Length logicalWidth, const RenderBoxModelObject* containerBlock, TextDirection containerDirection,
   2385                                                    int containerLogicalWidth, int bordersPlusPadding,
   2386                                                    Length logicalLeft, Length logicalRight, Length marginLogicalLeft, Length marginLogicalRight,
   2387                                                    int& logicalWidthValue, int& marginLogicalLeftValue, int& marginLogicalRightValue, int& logicalLeftPos)
   2388 {
   2389     // 'left' and 'right' cannot both be 'auto' because one would of been
   2390     // converted to the static position already
   2391     ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto()));
   2392 
   2393     int logicalLeftValue = 0;
   2394 
   2395     bool logicalWidthIsAuto = logicalWidth.isIntrinsicOrAuto();
   2396     bool logicalLeftIsAuto = logicalLeft.isAuto();
   2397     bool logicalRightIsAuto = logicalRight.isAuto();
   2398 
   2399     if (!logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) {
   2400         /*-----------------------------------------------------------------------*\
   2401          * If none of the three is 'auto': If both 'margin-left' and 'margin-
   2402          * right' are 'auto', solve the equation under the extra constraint that
   2403          * the two margins get equal values, unless this would make them negative,
   2404          * in which case when direction of the containing block is 'ltr' ('rtl'),
   2405          * set 'margin-left' ('margin-right') to zero and solve for 'margin-right'
   2406          * ('margin-left'). If one of 'margin-left' or 'margin-right' is 'auto',
   2407          * solve the equation for that value. If the values are over-constrained,
   2408          * ignore the value for 'left' (in case the 'direction' property of the
   2409          * containing block is 'rtl') or 'right' (in case 'direction' is 'ltr')
   2410          * and solve for that value.
   2411         \*-----------------------------------------------------------------------*/
   2412         // NOTE:  It is not necessary to solve for 'right' in the over constrained
   2413         // case because the value is not used for any further calculations.
   2414 
   2415         logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2416         logicalWidthValue = computeContentBoxLogicalWidth(logicalWidth.calcValue(containerLogicalWidth));
   2417 
   2418         const int availableSpace = containerLogicalWidth - (logicalLeftValue + logicalWidthValue + logicalRight.calcValue(containerLogicalWidth) + bordersPlusPadding);
   2419 
   2420         // Margins are now the only unknown
   2421         if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) {
   2422             // Both margins auto, solve for equality
   2423             if (availableSpace >= 0) {
   2424                 marginLogicalLeftValue = availableSpace / 2; // split the difference
   2425                 marginLogicalRightValue = availableSpace - marginLogicalLeftValue; // account for odd valued differences
   2426             } else {
   2427                 // see FIXME 1
   2428                 if (containerDirection == LTR) {
   2429                     marginLogicalLeftValue = 0;
   2430                     marginLogicalRightValue = availableSpace; // will be negative
   2431                 } else {
   2432                     marginLogicalLeftValue = availableSpace; // will be negative
   2433                     marginLogicalRightValue = 0;
   2434                 }
   2435             }
   2436         } else if (marginLogicalLeft.isAuto()) {
   2437             // Solve for left margin
   2438             marginLogicalRightValue = marginLogicalRight.calcValue(containerLogicalWidth);
   2439             marginLogicalLeftValue = availableSpace - marginLogicalRightValue;
   2440         } else if (marginLogicalRight.isAuto()) {
   2441             // Solve for right margin
   2442             marginLogicalLeftValue = marginLogicalLeft.calcValue(containerLogicalWidth);
   2443             marginLogicalRightValue = availableSpace - marginLogicalLeftValue;
   2444         } else {
   2445             // Over-constrained, solve for left if direction is RTL
   2446             marginLogicalLeftValue = marginLogicalLeft.calcValue(containerLogicalWidth);
   2447             marginLogicalRightValue = marginLogicalRight.calcValue(containerLogicalWidth);
   2448 
   2449             // see FIXME 1 -- used to be "this->style()->direction()"
   2450             if (containerDirection == RTL)
   2451                 logicalLeftValue = (availableSpace + logicalLeftValue) - marginLogicalLeftValue - marginLogicalRightValue;
   2452         }
   2453     } else {
   2454         /*--------------------------------------------------------------------*\
   2455          * Otherwise, set 'auto' values for 'margin-left' and 'margin-right'
   2456          * to 0, and pick the one of the following six rules that applies.
   2457          *
   2458          * 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the
   2459          *    width is shrink-to-fit. Then solve for 'left'
   2460          *
   2461          *              OMIT RULE 2 AS IT SHOULD NEVER BE HIT
   2462          * ------------------------------------------------------------------
   2463          * 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if
   2464          *    the 'direction' property of the containing block is 'ltr' set
   2465          *    'left' to the static position, otherwise set 'right' to the
   2466          *    static position. Then solve for 'left' (if 'direction is 'rtl')
   2467          *    or 'right' (if 'direction' is 'ltr').
   2468          * ------------------------------------------------------------------
   2469          *
   2470          * 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the
   2471          *    width is shrink-to-fit . Then solve for 'right'
   2472          * 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve
   2473          *    for 'left'
   2474          * 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve
   2475          *    for 'width'
   2476          * 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve
   2477          *    for 'right'
   2478          *
   2479          * Calculation of the shrink-to-fit width is similar to calculating the
   2480          * width of a table cell using the automatic table layout algorithm.
   2481          * Roughly: calculate the preferred width by formatting the content
   2482          * without breaking lines other than where explicit line breaks occur,
   2483          * and also calculate the preferred minimum width, e.g., by trying all
   2484          * possible line breaks. CSS 2.1 does not define the exact algorithm.
   2485          * Thirdly, calculate the available width: this is found by solving
   2486          * for 'width' after setting 'left' (in case 1) or 'right' (in case 3)
   2487          * to 0.
   2488          *
   2489          * Then the shrink-to-fit width is:
   2490          * min(max(preferred minimum width, available width), preferred width).
   2491         \*--------------------------------------------------------------------*/
   2492         // NOTE: For rules 3 and 6 it is not necessary to solve for 'right'
   2493         // because the value is not used for any further calculations.
   2494 
   2495         // Calculate margins, 'auto' margins are ignored.
   2496         marginLogicalLeftValue = marginLogicalLeft.calcMinValue(containerLogicalWidth);
   2497         marginLogicalRightValue = marginLogicalRight.calcMinValue(containerLogicalWidth);
   2498 
   2499         const int availableSpace = containerLogicalWidth - (marginLogicalLeftValue + marginLogicalRightValue + bordersPlusPadding);
   2500 
   2501         // FIXME: Is there a faster way to find the correct case?
   2502         // Use rule/case that applies.
   2503         if (logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAuto) {
   2504             // RULE 1: (use shrink-to-fit for width, and solve of left)
   2505             int logicalRightValue = logicalRight.calcValue(containerLogicalWidth);
   2506 
   2507             // FIXME: would it be better to have shrink-to-fit in one step?
   2508             int preferredWidth = maxPreferredLogicalWidth() - bordersPlusPadding;
   2509             int preferredMinWidth = minPreferredLogicalWidth() - bordersPlusPadding;
   2510             int availableWidth = availableSpace - logicalRightValue;
   2511             logicalWidthValue = min(max(preferredMinWidth, availableWidth), preferredWidth);
   2512             logicalLeftValue = availableSpace - (logicalWidthValue + logicalRightValue);
   2513         } else if (!logicalLeftIsAuto && logicalWidthIsAuto && logicalRightIsAuto) {
   2514             // RULE 3: (use shrink-to-fit for width, and no need solve of right)
   2515             logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2516 
   2517             // FIXME: would it be better to have shrink-to-fit in one step?
   2518             int preferredWidth = maxPreferredLogicalWidth() - bordersPlusPadding;
   2519             int preferredMinWidth = minPreferredLogicalWidth() - bordersPlusPadding;
   2520             int availableWidth = availableSpace - logicalLeftValue;
   2521             logicalWidthValue = min(max(preferredMinWidth, availableWidth), preferredWidth);
   2522         } else if (logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) {
   2523             // RULE 4: (solve for left)
   2524             logicalWidthValue = computeContentBoxLogicalWidth(logicalWidth.calcValue(containerLogicalWidth));
   2525             logicalLeftValue = availableSpace - (logicalWidthValue + logicalRight.calcValue(containerLogicalWidth));
   2526         } else if (!logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAuto) {
   2527             // RULE 5: (solve for width)
   2528             logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2529             logicalWidthValue = availableSpace - (logicalLeftValue + logicalRight.calcValue(containerLogicalWidth));
   2530         } else if (!logicalLeftIsAuto && !logicalWidthIsAuto && logicalRightIsAuto) {
   2531             // RULE 6: (no need solve for right)
   2532             logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2533             logicalWidthValue = computeContentBoxLogicalWidth(logicalWidth.calcValue(containerLogicalWidth));
   2534         }
   2535     }
   2536 
   2537     // Use computed values to calculate the horizontal position.
   2538 
   2539     // FIXME: This hack is needed to calculate the  logical left position for a 'rtl' relatively
   2540     // positioned, inline because right now, it is using the logical left position
   2541     // of the first line box when really it should use the last line box.  When
   2542     // this is fixed elsewhere, this block should be removed.
   2543     if (containerBlock->isRenderInline() && !containerBlock->style()->isLeftToRightDirection()) {
   2544         const RenderInline* flow = toRenderInline(containerBlock);
   2545         InlineFlowBox* firstLine = flow->firstLineBox();
   2546         InlineFlowBox* lastLine = flow->lastLineBox();
   2547         if (firstLine && lastLine && firstLine != lastLine) {
   2548             logicalLeftPos = logicalLeftValue + marginLogicalLeftValue + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logicalLeft());
   2549             return;
   2550         }
   2551     }
   2552 
   2553     logicalLeftPos = logicalLeftValue + marginLogicalLeftValue;
   2554     computeLogicalLeftPositionedOffset(logicalLeftPos, this, logicalWidthValue, containerBlock, containerLogicalWidth);
   2555 }
   2556 
   2557 static void computeBlockStaticDistance(Length& logicalTop, Length& logicalBottom, const RenderBox* child, const RenderBoxModelObject* containerBlock)
   2558 {
   2559     if (!logicalTop.isAuto() || !logicalBottom.isAuto())
   2560         return;
   2561 
   2562     // FIXME: The static distance computation has not been patched for mixed writing modes.
   2563     int staticLogicalTop = child->layer()->staticBlockPosition() - containerBlock->borderBefore();
   2564     for (RenderObject* curr = child->parent(); curr && curr != containerBlock; curr = curr->container()) {
   2565         if (curr->isBox() && !curr->isTableRow())
   2566             staticLogicalTop += toRenderBox(curr)->logicalTop();
   2567     }
   2568     logicalTop.setValue(Fixed, staticLogicalTop);
   2569 }
   2570 
   2571 void RenderBox::computePositionedLogicalHeight()
   2572 {
   2573     if (isReplaced()) {
   2574         computePositionedLogicalHeightReplaced();
   2575         return;
   2576     }
   2577 
   2578     // The following is based off of the W3C Working Draft from April 11, 2006 of
   2579     // CSS 2.1: Section 10.6.4 "Absolutely positioned, non-replaced elements"
   2580     // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-non-replaced-height>
   2581     // (block-style-comments in this function and in computePositionedLogicalHeightUsing()
   2582     // correspond to text from the spec)
   2583 
   2584 
   2585     // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
   2586     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
   2587 
   2588     const int containerLogicalHeight = containingBlockLogicalHeightForPositioned(containerBlock);
   2589 
   2590     bool isHorizontal = isHorizontalWritingMode();
   2591     bool isFlipped = style()->isFlippedBlocksWritingMode();
   2592     const int bordersPlusPadding = borderAndPaddingLogicalHeight();
   2593     const Length marginBefore = style()->marginBefore();
   2594     const Length marginAfter = style()->marginAfter();
   2595     int& marginBeforeAlias = isHorizontal ? (isFlipped ? m_marginBottom : m_marginTop) : (isFlipped ? m_marginRight: m_marginLeft);
   2596     int& marginAfterAlias = isHorizontal ? (isFlipped ? m_marginTop : m_marginBottom) : (isFlipped ? m_marginLeft: m_marginRight);
   2597 
   2598     Length logicalTop = style()->logicalTop();
   2599     Length logicalBottom = style()->logicalBottom();
   2600 
   2601     /*---------------------------------------------------------------------------*\
   2602      * For the purposes of this section and the next, the term "static position"
   2603      * (of an element) refers, roughly, to the position an element would have had
   2604      * in the normal flow. More precisely, the static position for 'top' is the
   2605      * distance from the top edge of the containing block to the top margin edge
   2606      * of a hypothetical box that would have been the first box of the element if
   2607      * its 'position' property had been 'static' and 'float' had been 'none'. The
   2608      * value is negative if the hypothetical box is above the containing block.
   2609      *
   2610      * But rather than actually calculating the dimensions of that hypothetical
   2611      * box, user agents are free to make a guess at its probable position.
   2612      *
   2613      * For the purposes of calculating the static position, the containing block
   2614      * of fixed positioned elements is the initial containing block instead of
   2615      * the viewport.
   2616     \*---------------------------------------------------------------------------*/
   2617 
   2618     // see FIXME 2
   2619     // Calculate the static distance if needed.
   2620     computeBlockStaticDistance(logicalTop, logicalBottom, this, containerBlock);
   2621 
   2622     int logicalHeightResult; // Needed to compute overflow.
   2623     int logicalTopPos;
   2624 
   2625     // Calculate constraint equation values for 'height' case.
   2626     computePositionedLogicalHeightUsing(style()->logicalHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding,
   2627                                         logicalTop, logicalBottom, marginBefore, marginAfter,
   2628                                         logicalHeightResult, marginBeforeAlias, marginAfterAlias, logicalTopPos);
   2629     setLogicalTop(logicalTopPos);
   2630 
   2631     // Avoid doing any work in the common case (where the values of min-height and max-height are their defaults).
   2632     // see FIXME 3
   2633 
   2634     // Calculate constraint equation values for 'max-height' case.
   2635     if (!style()->logicalMaxHeight().isUndefined()) {
   2636         int maxLogicalHeight;
   2637         int maxMarginBefore;
   2638         int maxMarginAfter;
   2639         int maxLogicalTopPos;
   2640 
   2641         computePositionedLogicalHeightUsing(style()->logicalMaxHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding,
   2642                                             logicalTop, logicalBottom, marginBefore, marginAfter,
   2643                                             maxLogicalHeight, maxMarginBefore, maxMarginAfter, maxLogicalTopPos);
   2644 
   2645         if (logicalHeightResult > maxLogicalHeight) {
   2646             logicalHeightResult = maxLogicalHeight;
   2647             marginBeforeAlias = maxMarginBefore;
   2648             marginAfterAlias = maxMarginAfter;
   2649             setLogicalTop(maxLogicalTopPos);
   2650         }
   2651     }
   2652 
   2653     // Calculate constraint equation values for 'min-height' case.
   2654     if (!style()->logicalMinHeight().isZero()) {
   2655         int minLogicalHeight;
   2656         int minMarginBefore;
   2657         int minMarginAfter;
   2658         int minLogicalTopPos;
   2659 
   2660         computePositionedLogicalHeightUsing(style()->logicalMinHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding,
   2661                                             logicalTop, logicalBottom, marginBefore, marginAfter,
   2662                                             minLogicalHeight, minMarginBefore, minMarginAfter, minLogicalTopPos);
   2663 
   2664         if (logicalHeightResult < minLogicalHeight) {
   2665             logicalHeightResult = minLogicalHeight;
   2666             marginBeforeAlias = minMarginBefore;
   2667             marginAfterAlias = minMarginAfter;
   2668             setLogicalTop(minLogicalTopPos);
   2669         }
   2670     }
   2671 
   2672     // Set final height value.
   2673     setLogicalHeight(logicalHeightResult + bordersPlusPadding);
   2674 }
   2675 
   2676 static void computeLogicalTopPositionedOffset(int& logicalTopPos, const RenderBox* child, int logicalHeightValue, const RenderBoxModelObject* containerBlock, int containerLogicalHeight)
   2677 {
   2678     // Deal with differing writing modes here.  Our offset needs to be in the containing block's coordinate space. If the containing block is flipped
   2679     // 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.
   2680     if ((child->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() != containerBlock->isHorizontalWritingMode())
   2681         || (child->style()->isFlippedBlocksWritingMode() != containerBlock->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode()))
   2682         logicalTopPos = containerLogicalHeight - logicalHeightValue - logicalTopPos;
   2683 
   2684     // Our offset is from the logical bottom edge in a flipped environment, e.g., right for vertical-rl and bottom for horizontal-bt.
   2685     if (containerBlock->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode()) {
   2686         if (child->isHorizontalWritingMode())
   2687             logicalTopPos += containerBlock->borderBottom();
   2688         else
   2689             logicalTopPos += containerBlock->borderRight();
   2690     } else {
   2691         if (child->isHorizontalWritingMode())
   2692             logicalTopPos += containerBlock->borderTop();
   2693         else
   2694             logicalTopPos += containerBlock->borderLeft();
   2695     }
   2696 }
   2697 
   2698 void RenderBox::computePositionedLogicalHeightUsing(Length logicalHeightLength, const RenderBoxModelObject* containerBlock,
   2699                                                     int containerLogicalHeight, int bordersPlusPadding,
   2700                                                     Length logicalTop, Length logicalBottom, Length marginBefore, Length marginAfter,
   2701                                                     int& logicalHeightValue, int& marginBeforeValue, int& marginAfterValue, int& logicalTopPos)
   2702 {
   2703     // 'top' and 'bottom' cannot both be 'auto' because 'top would of been
   2704     // converted to the static position in computePositionedLogicalHeight()
   2705     ASSERT(!(logicalTop.isAuto() && logicalBottom.isAuto()));
   2706 
   2707     int contentLogicalHeight = logicalHeight() - bordersPlusPadding;
   2708 
   2709     int logicalTopValue = 0;
   2710 
   2711     bool logicalHeightIsAuto = logicalHeightLength.isAuto();
   2712     bool logicalTopIsAuto = logicalTop.isAuto();
   2713     bool logicalBottomIsAuto = logicalBottom.isAuto();
   2714 
   2715     // Height is never unsolved for tables.
   2716     if (isTable()) {
   2717         logicalHeightLength.setValue(Fixed, contentLogicalHeight);
   2718         logicalHeightIsAuto = false;
   2719     }
   2720 
   2721     if (!logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsAuto) {
   2722         /*-----------------------------------------------------------------------*\
   2723          * If none of the three are 'auto': If both 'margin-top' and 'margin-
   2724          * bottom' are 'auto', solve the equation under the extra constraint that
   2725          * the two margins get equal values. If one of 'margin-top' or 'margin-
   2726          * bottom' is 'auto', solve the equation for that value. If the values
   2727          * are over-constrained, ignore the value for 'bottom' and solve for that
   2728          * value.
   2729         \*-----------------------------------------------------------------------*/
   2730         // NOTE:  It is not necessary to solve for 'bottom' in the over constrained
   2731         // case because the value is not used for any further calculations.
   2732 
   2733         logicalHeightValue = computeContentBoxLogicalHeight(logicalHeightLength.calcValue(containerLogicalHeight));
   2734         logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   2735 
   2736         const int availableSpace = containerLogicalHeight - (logicalTopValue + logicalHeightValue + logicalBottom.calcValue(containerLogicalHeight) + bordersPlusPadding);
   2737 
   2738         // Margins are now the only unknown
   2739         if (marginBefore.isAuto() && marginAfter.isAuto()) {
   2740             // Both margins auto, solve for equality
   2741             // NOTE: This may result in negative values.
   2742             marginBeforeValue = availableSpace / 2; // split the difference
   2743             marginAfterValue = availableSpace - marginBeforeValue; // account for odd valued differences
   2744         } else if (marginBefore.isAuto()) {
   2745             // Solve for top margin
   2746             marginAfterValue = marginAfter.calcValue(containerLogicalHeight);
   2747             marginBeforeValue = availableSpace - marginAfterValue;
   2748         } else if (marginAfter.isAuto()) {
   2749             // Solve for bottom margin
   2750             marginBeforeValue = marginBefore.calcValue(containerLogicalHeight);
   2751             marginAfterValue = availableSpace - marginBeforeValue;
   2752         } else {
   2753             // Over-constrained, (no need solve for bottom)
   2754             marginBeforeValue = marginBefore.calcValue(containerLogicalHeight);
   2755             marginAfterValue = marginAfter.calcValue(containerLogicalHeight);
   2756         }
   2757     } else {
   2758         /*--------------------------------------------------------------------*\
   2759          * Otherwise, set 'auto' values for 'margin-top' and 'margin-bottom'
   2760          * to 0, and pick the one of the following six rules that applies.
   2761          *
   2762          * 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then
   2763          *    the height is based on the content, and solve for 'top'.
   2764          *
   2765          *              OMIT RULE 2 AS IT SHOULD NEVER BE HIT
   2766          * ------------------------------------------------------------------
   2767          * 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then
   2768          *    set 'top' to the static position, and solve for 'bottom'.
   2769          * ------------------------------------------------------------------
   2770          *
   2771          * 3. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then
   2772          *    the height is based on the content, and solve for 'bottom'.
   2773          * 4. 'top' is 'auto', 'height' and 'bottom' are not 'auto', and
   2774          *    solve for 'top'.
   2775          * 5. 'height' is 'auto', 'top' and 'bottom' are not 'auto', and
   2776          *    solve for 'height'.
   2777          * 6. 'bottom' is 'auto', 'top' and 'height' are not 'auto', and
   2778          *    solve for 'bottom'.
   2779         \*--------------------------------------------------------------------*/
   2780         // NOTE: For rules 3 and 6 it is not necessary to solve for 'bottom'
   2781         // because the value is not used for any further calculations.
   2782 
   2783         // Calculate margins, 'auto' margins are ignored.
   2784         marginBeforeValue = marginBefore.calcMinValue(containerLogicalHeight);
   2785         marginAfterValue = marginAfter.calcMinValue(containerLogicalHeight);
   2786 
   2787         const int availableSpace = containerLogicalHeight - (marginBeforeValue + marginAfterValue + bordersPlusPadding);
   2788 
   2789         // Use rule/case that applies.
   2790         if (logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) {
   2791             // RULE 1: (height is content based, solve of top)
   2792             logicalHeightValue = contentLogicalHeight;
   2793             logicalTopValue = availableSpace - (logicalHeightValue + logicalBottom.calcValue(containerLogicalHeight));
   2794         } else if (!logicalTopIsAuto && logicalHeightIsAuto && logicalBottomIsAuto) {
   2795             // RULE 3: (height is content based, no need solve of bottom)
   2796             logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   2797             logicalHeightValue = contentLogicalHeight;
   2798         } else if (logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsAuto) {
   2799             // RULE 4: (solve of top)
   2800             logicalHeightValue = computeContentBoxLogicalHeight(logicalHeightLength.calcValue(containerLogicalHeight));
   2801             logicalTopValue = availableSpace - (logicalHeightValue + logicalBottom.calcValue(containerLogicalHeight));
   2802         } else if (!logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) {
   2803             // RULE 5: (solve of height)
   2804             logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   2805             logicalHeightValue = max(0, availableSpace - (logicalTopValue + logicalBottom.calcValue(containerLogicalHeight)));
   2806         } else if (!logicalTopIsAuto && !logicalHeightIsAuto && logicalBottomIsAuto) {
   2807             // RULE 6: (no need solve of bottom)
   2808             logicalHeightValue = computeContentBoxLogicalHeight(logicalHeightLength.calcValue(containerLogicalHeight));
   2809             logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   2810         }
   2811     }
   2812 
   2813     // Use computed values to calculate the vertical position.
   2814     logicalTopPos = logicalTopValue + marginBeforeValue;
   2815     computeLogicalTopPositionedOffset(logicalTopPos, this, logicalHeightValue, containerBlock, containerLogicalHeight);
   2816 }
   2817 
   2818 void RenderBox::computePositionedLogicalWidthReplaced()
   2819 {
   2820     // The following is based off of the W3C Working Draft from April 11, 2006 of
   2821     // CSS 2.1: Section 10.3.8 "Absolutely positioned, replaced elements"
   2822     // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-width>
   2823     // (block-style-comments in this function correspond to text from the spec and
   2824     // the numbers correspond to numbers in spec)
   2825 
   2826     // We don't use containingBlock(), since we may be positioned by an enclosing
   2827     // relative positioned inline.
   2828     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
   2829 
   2830     const int containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock);
   2831 
   2832     // To match WinIE, in quirks mode use the parent's 'direction' property
   2833     // instead of the the container block's.
   2834     TextDirection containerDirection = (document()->inQuirksMode()) ? parent()->style()->direction() : containerBlock->style()->direction();
   2835 
   2836     // Variables to solve.
   2837     bool isHorizontal = isHorizontalWritingMode();
   2838     Length logicalLeft = style()->logicalLeft();
   2839     Length logicalRight = style()->logicalRight();
   2840     Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->marginTop();
   2841     Length marginLogicalRight = isHorizontal ? style()->marginRight() : style()->marginBottom();
   2842     int& marginLogicalLeftAlias = isHorizontal ? m_marginLeft : m_marginTop;
   2843     int& marginLogicalRightAlias = isHorizontal ? m_marginRight : m_marginBottom;
   2844 
   2845     /*-----------------------------------------------------------------------*\
   2846      * 1. The used value of 'width' is determined as for inline replaced
   2847      *    elements.
   2848     \*-----------------------------------------------------------------------*/
   2849     // NOTE: This value of width is FINAL in that the min/max width calculations
   2850     // are dealt with in computeReplacedWidth().  This means that the steps to produce
   2851     // correct max/min in the non-replaced version, are not necessary.
   2852     setLogicalWidth(computeReplacedLogicalWidth() + borderAndPaddingLogicalWidth());
   2853     const int availableSpace = containerLogicalWidth - logicalWidth();
   2854 
   2855     /*-----------------------------------------------------------------------*\
   2856      * 2. If both 'left' and 'right' have the value 'auto', then if 'direction'
   2857      *    of the containing block is 'ltr', set 'left' to the static position;
   2858      *    else if 'direction' is 'rtl', set 'right' to the static position.
   2859     \*-----------------------------------------------------------------------*/
   2860     // see FIXME 2
   2861     computeInlineStaticDistance(logicalLeft, logicalRight, this, containerBlock, containerLogicalWidth, containerDirection);
   2862 
   2863     /*-----------------------------------------------------------------------*\
   2864      * 3. If 'left' or 'right' are 'auto', replace any 'auto' on 'margin-left'
   2865      *    or 'margin-right' with '0'.
   2866     \*-----------------------------------------------------------------------*/
   2867     if (logicalLeft.isAuto() || logicalRight.isAuto()) {
   2868         if (marginLogicalLeft.isAuto())
   2869             marginLogicalLeft.setValue(Fixed, 0);
   2870         if (marginLogicalRight.isAuto())
   2871             marginLogicalRight.setValue(Fixed, 0);
   2872     }
   2873 
   2874     /*-----------------------------------------------------------------------*\
   2875      * 4. If at this point both 'margin-left' and 'margin-right' are still
   2876      *    'auto', solve the equation under the extra constraint that the two
   2877      *    margins must get equal values, unless this would make them negative,
   2878      *    in which case when the direction of the containing block is 'ltr'
   2879      *    ('rtl'), set 'margin-left' ('margin-right') to zero and solve for
   2880      *    'margin-right' ('margin-left').
   2881     \*-----------------------------------------------------------------------*/
   2882     int logicalLeftValue = 0;
   2883     int logicalRightValue = 0;
   2884 
   2885     if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) {
   2886         // 'left' and 'right' cannot be 'auto' due to step 3
   2887         ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto()));
   2888 
   2889         logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2890         logicalRightValue = logicalRight.calcValue(containerLogicalWidth);
   2891 
   2892         int difference = availableSpace - (logicalLeftValue + logicalRightValue);
   2893         if (difference > 0) {
   2894             marginLogicalLeftAlias = difference / 2; // split the difference
   2895             marginLogicalRightAlias = difference - marginLogicalLeftAlias; // account for odd valued differences
   2896         } else {
   2897             // see FIXME 1
   2898             if (containerDirection == LTR) {
   2899                 marginLogicalLeftAlias = 0;
   2900                 marginLogicalRightAlias = difference; // will be negative
   2901             } else {
   2902                 marginLogicalLeftAlias = difference; // will be negative
   2903                 marginLogicalRightAlias = 0;
   2904             }
   2905         }
   2906 
   2907     /*-----------------------------------------------------------------------*\
   2908      * 5. If at this point there is an 'auto' left, solve the equation for
   2909      *    that value.
   2910     \*-----------------------------------------------------------------------*/
   2911     } else if (logicalLeft.isAuto()) {
   2912         marginLogicalLeftAlias = marginLogicalLeft.calcValue(containerLogicalWidth);
   2913         marginLogicalRightAlias = marginLogicalRight.calcValue(containerLogicalWidth);
   2914         logicalRightValue = logicalRight.calcValue(containerLogicalWidth);
   2915 
   2916         // Solve for 'left'
   2917         logicalLeftValue = availableSpace - (logicalRightValue + marginLogicalLeftAlias + marginLogicalRightAlias);
   2918     } else if (logicalRight.isAuto()) {
   2919         marginLogicalLeftAlias = marginLogicalLeft.calcValue(containerLogicalWidth);
   2920         marginLogicalRightAlias = marginLogicalRight.calcValue(containerLogicalWidth);
   2921         logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2922 
   2923         // Solve for 'right'
   2924         logicalRightValue = availableSpace - (logicalLeftValue + marginLogicalLeftAlias + marginLogicalRightAlias);
   2925     } else if (marginLogicalLeft.isAuto()) {
   2926         marginLogicalRightAlias = marginLogicalRight.calcValue(containerLogicalWidth);
   2927         logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2928         logicalRightValue = logicalRight.calcValue(containerLogicalWidth);
   2929 
   2930         // Solve for 'margin-left'
   2931         marginLogicalLeftAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalRightAlias);
   2932     } else if (marginLogicalRight.isAuto()) {
   2933         marginLogicalLeftAlias = marginLogicalLeft.calcValue(containerLogicalWidth);
   2934         logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2935         logicalRightValue = logicalRight.calcValue(containerLogicalWidth);
   2936 
   2937         // Solve for 'margin-right'
   2938         marginLogicalRightAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalLeftAlias);
   2939     } else {
   2940         // Nothing is 'auto', just calculate the values.
   2941         marginLogicalLeftAlias = marginLogicalLeft.calcValue(containerLogicalWidth);
   2942         marginLogicalRightAlias = marginLogicalRight.calcValue(containerLogicalWidth);
   2943         logicalRightValue = logicalRight.calcValue(containerLogicalWidth);
   2944         logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2945     }
   2946 
   2947     /*-----------------------------------------------------------------------*\
   2948      * 6. If at this point the values are over-constrained, ignore the value
   2949      *    for either 'left' (in case the 'direction' property of the
   2950      *    containing block is 'rtl') or 'right' (in case 'direction' is
   2951      *    'ltr') and solve for that value.
   2952     \*-----------------------------------------------------------------------*/
   2953     // NOTE:  It is not necessary to solve for 'right' when the direction is
   2954     // LTR because the value is not used.
   2955     int totalLogicalWidth = logicalWidth() + logicalLeftValue + logicalRightValue +  marginLogicalLeftAlias + marginLogicalRightAlias;
   2956     if (totalLogicalWidth > containerLogicalWidth && (containerDirection == RTL))
   2957         logicalLeftValue = containerLogicalWidth - (totalLogicalWidth - logicalLeftValue);
   2958 
   2959     // FIXME: Deal with differing writing modes here.  Our offset needs to be in the containing block's coordinate space, so that
   2960     // can make the result here rather complicated to compute.
   2961 
   2962     // Use computed values to calculate the horizontal position.
   2963 
   2964     // FIXME: This hack is needed to calculate the logical left position for a 'rtl' relatively
   2965     // positioned, inline containing block because right now, it is using the logical left position
   2966     // of the first line box when really it should use the last line box.  When
   2967     // this is fixed elsewhere, this block should be removed.
   2968     if (containerBlock->isRenderInline() && !containerBlock->style()->isLeftToRightDirection()) {
   2969         const RenderInline* flow = toRenderInline(containerBlock);
   2970         InlineFlowBox* firstLine = flow->firstLineBox();
   2971         InlineFlowBox* lastLine = flow->lastLineBox();
   2972         if (firstLine && lastLine && firstLine != lastLine) {
   2973             setLogicalLeft(logicalLeftValue + marginLogicalLeftAlias + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logicalLeft()));
   2974             return;
   2975         }
   2976     }
   2977 
   2978     int logicalLeftPos = logicalLeftValue + marginLogicalLeftAlias;
   2979     computeLogicalLeftPositionedOffset(logicalLeftPos, this, logicalWidth(), containerBlock, containerLogicalWidth);
   2980     setLogicalLeft(logicalLeftPos);
   2981 }
   2982 
   2983 void RenderBox::computePositionedLogicalHeightReplaced()
   2984 {
   2985     // The following is based off of the W3C Working Draft from April 11, 2006 of
   2986     // CSS 2.1: Section 10.6.5 "Absolutely positioned, replaced elements"
   2987     // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-height>
   2988     // (block-style-comments in this function correspond to text from the spec and
   2989     // the numbers correspond to numbers in spec)
   2990 
   2991     // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
   2992     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
   2993 
   2994     const int containerLogicalHeight = containingBlockLogicalHeightForPositioned(containerBlock);
   2995 
   2996     // Variables to solve.
   2997     bool isHorizontal = isHorizontalWritingMode();
   2998     bool isFlipped = style()->isFlippedBlocksWritingMode();
   2999     Length marginBefore = style()->marginBefore();
   3000     Length marginAfter = style()->marginAfter();
   3001     int& marginBeforeAlias = isHorizontal ? (isFlipped ? m_marginBottom : m_marginTop) : (isFlipped ? m_marginRight: m_marginLeft);
   3002     int& marginAfterAlias = isHorizontal ? (isFlipped ? m_marginTop : m_marginBottom) : (isFlipped ? m_marginLeft: m_marginRight);
   3003 
   3004     Length logicalTop = style()->logicalTop();
   3005     Length logicalBottom = style()->logicalBottom();
   3006 
   3007     /*-----------------------------------------------------------------------*\
   3008      * 1. The used value of 'height' is determined as for inline replaced
   3009      *    elements.
   3010     \*-----------------------------------------------------------------------*/
   3011     // NOTE: This value of height is FINAL in that the min/max height calculations
   3012     // are dealt with in computeReplacedHeight().  This means that the steps to produce
   3013     // correct max/min in the non-replaced version, are not necessary.
   3014     setLogicalHeight(computeReplacedLogicalHeight() + borderAndPaddingLogicalHeight());
   3015     const int availableSpace = containerLogicalHeight - logicalHeight();
   3016 
   3017     /*-----------------------------------------------------------------------*\
   3018      * 2. If both 'top' and 'bottom' have the value 'auto', replace 'top'
   3019      *    with the element's static position.
   3020     \*-----------------------------------------------------------------------*/
   3021     // see FIXME 2
   3022     computeBlockStaticDistance(logicalTop, logicalBottom, this, containerBlock);
   3023 
   3024     /*-----------------------------------------------------------------------*\
   3025      * 3. If 'bottom' is 'auto', replace any 'auto' on 'margin-top' or
   3026      *    'margin-bottom' with '0'.
   3027     \*-----------------------------------------------------------------------*/
   3028     // FIXME: The spec. says that this step should only be taken when bottom is
   3029     // auto, but if only top is auto, this makes step 4 impossible.
   3030     if (logicalTop.isAuto() || logicalBottom.isAuto()) {
   3031         if (marginBefore.isAuto())
   3032             marginBefore.setValue(Fixed, 0);
   3033         if (marginAfter.isAuto())
   3034             marginAfter.setValue(Fixed, 0);
   3035     }
   3036 
   3037     /*-----------------------------------------------------------------------*\
   3038      * 4. If at this point both 'margin-top' and 'margin-bottom' are still
   3039      *    'auto', solve the equation under the extra constraint that the two
   3040      *    margins must get equal values.
   3041     \*-----------------------------------------------------------------------*/
   3042     int logicalTopValue = 0;
   3043     int logicalBottomValue = 0;
   3044 
   3045     if (marginBefore.isAuto() && marginAfter.isAuto()) {
   3046         // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combined.
   3047         ASSERT(!(logicalTop.isAuto() || logicalBottom.isAuto()));
   3048 
   3049         logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   3050         logicalBottomValue = logicalBottom.calcValue(containerLogicalHeight);
   3051 
   3052         int difference = availableSpace - (logicalTopValue + logicalBottomValue);
   3053         // NOTE: This may result in negative values.
   3054         marginBeforeAlias =  difference / 2; // split the difference
   3055         marginAfterAlias = difference - marginBeforeAlias; // account for odd valued differences
   3056 
   3057     /*-----------------------------------------------------------------------*\
   3058      * 5. If at this point there is only one 'auto' left, solve the equation
   3059      *    for that value.
   3060     \*-----------------------------------------------------------------------*/
   3061     } else if (logicalTop.isAuto()) {
   3062         marginBeforeAlias = marginBefore.calcValue(containerLogicalHeight);
   3063         marginAfterAlias = marginAfter.calcValue(containerLogicalHeight);
   3064         logicalBottomValue = logicalBottom.calcValue(containerLogicalHeight);
   3065 
   3066         // Solve for 'top'
   3067         logicalTopValue = availableSpace - (logicalBottomValue + marginBeforeAlias + marginAfterAlias);
   3068     } else if (logicalBottom.isAuto()) {
   3069         marginBeforeAlias = marginBefore.calcValue(containerLogicalHeight);
   3070         marginAfterAlias = marginAfter.calcValue(containerLogicalHeight);
   3071         logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   3072 
   3073         // Solve for 'bottom'
   3074         // NOTE: It is not necessary to solve for 'bottom' because we don't ever
   3075         // use the value.
   3076     } else if (marginBefore.isAuto()) {
   3077         marginAfterAlias = marginAfter.calcValue(containerLogicalHeight);
   3078         logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   3079         logicalBottomValue = logicalBottom.calcValue(containerLogicalHeight);
   3080 
   3081         // Solve for 'margin-top'
   3082         marginBeforeAlias = availableSpace - (logicalTopValue + logicalBottomValue + marginAfterAlias);
   3083     } else if (marginAfter.isAuto()) {
   3084         marginBeforeAlias = marginBefore.calcValue(containerLogicalHeight);
   3085         logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   3086         logicalBottomValue = logicalBottom.calcValue(containerLogicalHeight);
   3087 
   3088         // Solve for 'margin-bottom'
   3089         marginAfterAlias = availableSpace - (logicalTopValue + logicalBottomValue + marginBeforeAlias);
   3090     } else {
   3091         // Nothing is 'auto', just calculate the values.
   3092         marginBeforeAlias = marginBefore.calcValue(containerLogicalHeight);
   3093         marginAfterAlias = marginAfter.calcValue(containerLogicalHeight);
   3094         logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   3095         // NOTE: It is not necessary to solve for 'bottom' because we don't ever
   3096         // use the value.
   3097      }
   3098 
   3099     /*-----------------------------------------------------------------------*\
   3100      * 6. If at this point the values are over-constrained, ignore the value
   3101      *    for 'bottom' and solve for that value.
   3102     \*-----------------------------------------------------------------------*/
   3103     // NOTE: It is not necessary to do this step because we don't end up using
   3104     // the value of 'bottom' regardless of whether the values are over-constrained
   3105     // or not.
   3106 
   3107     // Use computed values to calculate the vertical position.
   3108     int logicalTopPos = logicalTopValue + marginBeforeAlias;
   3109     computeLogicalTopPositionedOffset(logicalTopPos, this, logicalHeight(), containerBlock, containerLogicalHeight);
   3110     setLogicalTop(logicalTopPos);
   3111 }
   3112 
   3113 IntRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, int* extraWidthToEndOfLine)
   3114 {
   3115     // VisiblePositions at offsets inside containers either a) refer to the positions before/after
   3116     // those containers (tables and select elements) or b) refer to the position inside an empty block.
   3117     // They never refer to children.
   3118     // FIXME: Paint the carets inside empty blocks differently than the carets before/after elements.
   3119 
   3120     // FIXME: What about border and padding?
   3121     IntRect rect(x(), y(), caretWidth, height());
   3122     bool ltr = box ? box->isLeftToRightDirection() : style()->isLeftToRightDirection();
   3123 
   3124     if ((!caretOffset) ^ ltr)
   3125         rect.move(IntSize(width() - caretWidth, 0));
   3126 
   3127     if (box) {
   3128         RootInlineBox* rootBox = box->root();
   3129         int top = rootBox->lineTop();
   3130         rect.setY(top);
   3131         rect.setHeight(rootBox->lineBottom() - top);
   3132     }
   3133 
   3134     // If height of box is smaller than font height, use the latter one,
   3135     // otherwise the caret might become invisible.
   3136     //
   3137     // Also, if the box is not a replaced element, always use the font height.
   3138     // This prevents the "big caret" bug described in:
   3139     // <rdar://problem/3777804> Deleting all content in a document can result in giant tall-as-window insertion point
   3140     //
   3141     // FIXME: ignoring :first-line, missing good reason to take care of
   3142     int fontHeight = style()->fontMetrics().height();
   3143     if (fontHeight > rect.height() || (!isReplaced() && !isTable()))
   3144         rect.setHeight(fontHeight);
   3145 
   3146     if (extraWidthToEndOfLine)
   3147         *extraWidthToEndOfLine = x() + width() - rect.maxX();
   3148 
   3149     // Move to local coords
   3150     rect.move(-x(), -y());
   3151     return rect;
   3152 }
   3153 
   3154 VisiblePosition RenderBox::positionForPoint(const IntPoint& point)
   3155 {
   3156     // no children...return this render object's element, if there is one, and offset 0
   3157     if (!firstChild())
   3158         return createVisiblePosition(node() ? firstPositionInOrBeforeNode(node()) : Position(0, 0));
   3159 
   3160     int xPos = point.x();
   3161     int yPos = point.y();
   3162 
   3163     if (isTable() && node()) {
   3164         int right = contentWidth() + borderAndPaddingWidth();
   3165         int bottom = contentHeight() + borderAndPaddingHeight();
   3166 
   3167         if (xPos < 0 || xPos > right || yPos < 0 || yPos > bottom) {
   3168             if (xPos <= right / 2)
   3169                 return createVisiblePosition(firstPositionInOrBeforeNode(node()));
   3170             return createVisiblePosition(lastPositionInOrAfterNode(node()));
   3171         }
   3172     }
   3173 
   3174     // Pass off to the closest child.
   3175     int minDist = INT_MAX;
   3176     RenderBox* closestRenderer = 0;
   3177     int newX = xPos;
   3178     int newY = yPos;
   3179     if (isTableRow()) {
   3180         newX += x();
   3181         newY += y();
   3182     }
   3183     for (RenderObject* renderObject = firstChild(); renderObject; renderObject = renderObject->nextSibling()) {
   3184         if ((!renderObject->firstChild() && !renderObject->isInline() && !renderObject->isBlockFlow() )
   3185             || renderObject->style()->visibility() != VISIBLE)
   3186             continue;
   3187 
   3188         if (!renderObject->isBox())
   3189             continue;
   3190 
   3191         RenderBox* renderer = toRenderBox(renderObject);
   3192 
   3193         int top = renderer->borderTop() + renderer->paddingTop() + (isTableRow() ? 0 : renderer->y());
   3194         int bottom = top + renderer->contentHeight();
   3195         int left = renderer->borderLeft() + renderer->paddingLeft() + (isTableRow() ? 0 : renderer->x());
   3196         int right = left + renderer->contentWidth();
   3197 
   3198         if (xPos <= right && xPos >= left && yPos <= top && yPos >= bottom) {
   3199             if (renderer->isTableRow())
   3200                 return renderer->positionForCoordinates(xPos + newX - renderer->x(), yPos + newY - renderer->y());
   3201             return renderer->positionForCoordinates(xPos - renderer->x(), yPos - renderer->y());
   3202         }
   3203 
   3204         // Find the distance from (x, y) to the box.  Split the space around the box into 8 pieces
   3205         // and use a different compare depending on which piece (x, y) is in.
   3206         IntPoint cmp;
   3207         if (xPos > right) {
   3208             if (yPos < top)
   3209                 cmp = IntPoint(right, top);
   3210             else if (yPos > bottom)
   3211                 cmp = IntPoint(right, bottom);
   3212             else
   3213                 cmp = IntPoint(right, yPos);
   3214         } else if (xPos < left) {
   3215             if (yPos < top)
   3216                 cmp = IntPoint(left, top);
   3217             else if (yPos > bottom)
   3218                 cmp = IntPoint(left, bottom);
   3219             else
   3220                 cmp = IntPoint(left, yPos);
   3221         } else {
   3222             if (yPos < top)
   3223                 cmp = IntPoint(xPos, top);
   3224             else
   3225                 cmp = IntPoint(xPos, bottom);
   3226         }
   3227 
   3228         int x1minusx2 = cmp.x() - xPos;
   3229         int y1minusy2 = cmp.y() - yPos;
   3230 
   3231         int dist = x1minusx2 * x1minusx2 + y1minusy2 * y1minusy2;
   3232         if (dist < minDist) {
   3233             closestRenderer = renderer;
   3234             minDist = dist;
   3235         }
   3236     }
   3237 
   3238     if (closestRenderer)
   3239         return closestRenderer->positionForCoordinates(newX - closestRenderer->x(), newY - closestRenderer->y());
   3240 
   3241     return createVisiblePosition(firstPositionInOrBeforeNode(node()));
   3242 }
   3243 
   3244 bool RenderBox::shrinkToAvoidFloats() const
   3245 {
   3246     // Floating objects don't shrink.  Objects that don't avoid floats don't shrink.  Marquees don't shrink.
   3247     if ((isInline() && !isHTMLMarquee()) || !avoidsFloats() || isFloating())
   3248         return false;
   3249 
   3250     // All auto-width objects that avoid floats should always use lineWidth.
   3251     return style()->width().isAuto();
   3252 }
   3253 
   3254 bool RenderBox::avoidsFloats() const
   3255 {
   3256     return isReplaced() || hasOverflowClip() || isHR() || isLegend() || isWritingModeRoot();
   3257 }
   3258 
   3259 void RenderBox::addShadowOverflow()
   3260 {
   3261     int shadowLeft;
   3262     int shadowRight;
   3263     int shadowTop;
   3264     int shadowBottom;
   3265     style()->getBoxShadowExtent(shadowTop, shadowRight, shadowBottom, shadowLeft);
   3266     IntRect borderBox = borderBoxRect();
   3267     int overflowLeft = borderBox.x() + shadowLeft;
   3268     int overflowRight = borderBox.maxX() + shadowRight;
   3269     int overflowTop = borderBox.y() + shadowTop;
   3270     int overflowBottom = borderBox.maxY() + shadowBottom;
   3271     addVisualOverflow(IntRect(overflowLeft, overflowTop, overflowRight - overflowLeft, overflowBottom - overflowTop));
   3272 }
   3273 
   3274 void RenderBox::addOverflowFromChild(RenderBox* child, const IntSize& delta)
   3275 {
   3276     // Only propagate layout overflow from the child if the child isn't clipping its overflow.  If it is, then
   3277     // its overflow is internal to it, and we don't care about it.  layoutOverflowRectForPropagation takes care of this
   3278     // and just propagates the border box rect instead.
   3279     IntRect childLayoutOverflowRect = child->layoutOverflowRectForPropagation(style());
   3280     childLayoutOverflowRect.move(delta);
   3281     addLayoutOverflow(childLayoutOverflowRect);
   3282 
   3283     // Add in visual overflow from the child.  Even if the child clips its overflow, it may still
   3284     // have visual overflow of its own set from box shadows or reflections.  It is unnecessary to propagate this
   3285     // overflow if we are clipping our own overflow.
   3286     if (child->hasSelfPaintingLayer() || hasOverflowClip())
   3287         return;
   3288     IntRect childVisualOverflowRect = child->visualOverflowRectForPropagation(style());
   3289     childVisualOverflowRect.move(delta);
   3290     addVisualOverflow(childVisualOverflowRect);
   3291 }
   3292 
   3293 void RenderBox::addLayoutOverflow(const IntRect& rect)
   3294 {
   3295     IntRect clientBox = clientBoxRect();
   3296     if (clientBox.contains(rect) || rect.isEmpty())
   3297         return;
   3298 
   3299     // For overflow clip objects, we don't want to propagate overflow into unreachable areas.
   3300     IntRect overflowRect(rect);
   3301     if (hasOverflowClip() || isRenderView()) {
   3302         // Overflow is in the block's coordinate space and thus is flipped for horizontal-bt and vertical-rl
   3303         // writing modes.  At this stage that is actually a simplification, since we can treat horizontal-tb/bt as the same
   3304         // and vertical-lr/rl as the same.
   3305         bool hasTopOverflow = !style()->isLeftToRightDirection() && !isHorizontalWritingMode();
   3306         bool hasLeftOverflow = !style()->isLeftToRightDirection() && isHorizontalWritingMode();
   3307 
   3308         if (!hasTopOverflow)
   3309             overflowRect.shiftYEdgeTo(max(overflowRect.y(), clientBox.y()));
   3310         else
   3311             overflowRect.shiftMaxYEdgeTo(min(overflowRect.maxY(), clientBox.maxY()));
   3312         if (!hasLeftOverflow)
   3313             overflowRect.shiftXEdgeTo(max(overflowRect.x(), clientBox.x()));
   3314         else
   3315             overflowRect.shiftMaxXEdgeTo(min(overflowRect.maxX(), clientBox.maxX()));
   3316 
   3317         // Now re-test with the adjusted rectangle and see if it has become unreachable or fully
   3318         // contained.
   3319         if (clientBox.contains(overflowRect) || overflowRect.isEmpty())
   3320             return;
   3321     }
   3322 
   3323     if (!m_overflow)
   3324         m_overflow.set(new RenderOverflow(clientBox, borderBoxRect()));
   3325 
   3326     m_overflow->addLayoutOverflow(overflowRect);
   3327 }
   3328 
   3329 void RenderBox::addVisualOverflow(const IntRect& rect)
   3330 {
   3331     IntRect borderBox = borderBoxRect();
   3332     if (borderBox.contains(rect) || rect.isEmpty())
   3333         return;
   3334 
   3335     if (!m_overflow)
   3336         m_overflow.set(new RenderOverflow(clientBoxRect(), borderBox));
   3337 
   3338     m_overflow->addVisualOverflow(rect);
   3339 }
   3340 
   3341 void RenderBox::clearLayoutOverflow()
   3342 {
   3343     if (!m_overflow)
   3344         return;
   3345 
   3346     if (visualOverflowRect() == borderBoxRect()) {
   3347         m_overflow.clear();
   3348         return;
   3349     }
   3350 
   3351     m_overflow->resetLayoutOverflow(borderBoxRect());
   3352 }
   3353 
   3354 int RenderBox::lineHeight(bool /*firstLine*/, LineDirectionMode direction, LinePositionMode /*linePositionMode*/) const
   3355 {
   3356     if (isReplaced())
   3357         return direction == HorizontalLine ? m_marginTop + height() + m_marginBottom : m_marginRight + width() + m_marginLeft;
   3358     return 0;
   3359 }
   3360 
   3361 int RenderBox::baselinePosition(FontBaseline baselineType, bool /*firstLine*/, LineDirectionMode direction, LinePositionMode /*linePositionMode*/) const
   3362 {
   3363     if (isReplaced()) {
   3364         int result = direction == HorizontalLine ? m_marginTop + height() + m_marginBottom : m_marginRight + width() + m_marginLeft;
   3365         if (baselineType == AlphabeticBaseline)
   3366             return result;
   3367         return result - result / 2;
   3368     }
   3369     return 0;
   3370 }
   3371 
   3372 
   3373 RenderLayer* RenderBox::enclosingFloatPaintingLayer() const
   3374 {
   3375     const RenderObject* curr = this;
   3376     while (curr) {
   3377         RenderLayer* layer = curr->hasLayer() && curr->isBox() ? toRenderBoxModelObject(curr)->layer() : 0;
   3378         if (layer && layer->isSelfPaintingLayer())
   3379             return layer;
   3380         curr = curr->parent();
   3381     }
   3382     return 0;
   3383 }
   3384 
   3385 IntRect RenderBox::logicalVisualOverflowRectForPropagation(RenderStyle* parentStyle) const
   3386 {
   3387     IntRect rect = visualOverflowRectForPropagation(parentStyle);
   3388     if (!parentStyle->isHorizontalWritingMode())
   3389         return rect.transposedRect();
   3390     return rect;
   3391 }
   3392 
   3393 IntRect RenderBox::visualOverflowRectForPropagation(RenderStyle* parentStyle) const
   3394 {
   3395     // If the writing modes of the child and parent match, then we don't have to
   3396     // do anything fancy. Just return the result.
   3397     IntRect rect = visualOverflowRect();
   3398     if (parentStyle->writingMode() == style()->writingMode())
   3399         return rect;
   3400 
   3401     // We are putting ourselves into our parent's coordinate space.  If there is a flipped block mismatch
   3402     // in a particular axis, then we have to flip the rect along that axis.
   3403     if (style()->writingMode() == RightToLeftWritingMode || parentStyle->writingMode() == RightToLeftWritingMode)
   3404         rect.setX(width() - rect.maxX());
   3405     else if (style()->writingMode() == BottomToTopWritingMode || parentStyle->writingMode() == BottomToTopWritingMode)
   3406         rect.setY(height() - rect.maxY());
   3407 
   3408     return rect;
   3409 }
   3410 
   3411 IntRect RenderBox::logicalLayoutOverflowRectForPropagation(RenderStyle* parentStyle) const
   3412 {
   3413     IntRect rect = layoutOverflowRectForPropagation(parentStyle);
   3414     if (!parentStyle->isHorizontalWritingMode())
   3415         return rect.transposedRect();
   3416     return rect;
   3417 }
   3418 
   3419 IntRect RenderBox::layoutOverflowRectForPropagation(RenderStyle* parentStyle) const
   3420 {
   3421     // Only propagate interior layout overflow if we don't clip it.
   3422     IntRect rect = borderBoxRect();
   3423     if (!hasOverflowClip())
   3424         rect.unite(layoutOverflowRect());
   3425 
   3426     bool hasTransform = hasLayer() && layer()->transform();
   3427     if (isRelPositioned() || hasTransform) {
   3428         // If we are relatively positioned or if we have a transform, then we have to convert
   3429         // this rectangle into physical coordinates, apply relative positioning and transforms
   3430         // to it, and then convert it back.
   3431         flipForWritingMode(rect);
   3432 
   3433         if (hasTransform)
   3434             rect = layer()->currentTransform().mapRect(rect);
   3435 
   3436         if (isRelPositioned())
   3437             rect.move(relativePositionOffsetX(), relativePositionOffsetY());
   3438 
   3439         // Now we need to flip back.
   3440         flipForWritingMode(rect);
   3441     }
   3442 
   3443     // If the writing modes of the child and parent match, then we don't have to
   3444     // do anything fancy. Just return the result.
   3445     if (parentStyle->writingMode() == style()->writingMode())
   3446         return rect;
   3447 
   3448     // We are putting ourselves into our parent's coordinate space.  If there is a flipped block mismatch
   3449     // in a particular axis, then we have to flip the rect along that axis.
   3450     if (style()->writingMode() == RightToLeftWritingMode || parentStyle->writingMode() == RightToLeftWritingMode)
   3451         rect.setX(width() - rect.maxX());
   3452     else if (style()->writingMode() == BottomToTopWritingMode || parentStyle->writingMode() == BottomToTopWritingMode)
   3453         rect.setY(height() - rect.maxY());
   3454 
   3455     return rect;
   3456 }
   3457 
   3458 IntPoint RenderBox::flipForWritingMode(const RenderBox* child, const IntPoint& point, FlippingAdjustment adjustment) const
   3459 {
   3460     if (!style()->isFlippedBlocksWritingMode())
   3461         return point;
   3462 
   3463     // The child is going to add in its x() and y(), so we have to make sure it ends up in
   3464     // the right place.
   3465     if (isHorizontalWritingMode())
   3466         return IntPoint(point.x(), point.y() + height() - child->height() - child->y() - (adjustment == ParentToChildFlippingAdjustment ? child->y() : 0));
   3467     return IntPoint(point.x() + width() - child->width() - child->x() - (adjustment == ParentToChildFlippingAdjustment ? child->x() : 0), point.y());
   3468 }
   3469 
   3470 void RenderBox::flipForWritingMode(IntRect& rect) const
   3471 {
   3472     if (!style()->isFlippedBlocksWritingMode())
   3473         return;
   3474 
   3475     if (isHorizontalWritingMode())
   3476         rect.setY(height() - rect.maxY());
   3477     else
   3478         rect.setX(width() - rect.maxX());
   3479 }
   3480 
   3481 int RenderBox::flipForWritingMode(int position) const
   3482 {
   3483     if (!style()->isFlippedBlocksWritingMode())
   3484         return position;
   3485     return logicalHeight() - position;
   3486 }
   3487 
   3488 IntPoint RenderBox::flipForWritingMode(const IntPoint& position) const
   3489 {
   3490     if (!style()->isFlippedBlocksWritingMode())
   3491         return position;
   3492     return isHorizontalWritingMode() ? IntPoint(position.x(), height() - position.y()) : IntPoint(width() - position.x(), position.y());
   3493 }
   3494 
   3495 IntPoint RenderBox::flipForWritingModeIncludingColumns(const IntPoint& point) const
   3496 {
   3497     if (!hasColumns() || !style()->isFlippedBlocksWritingMode())
   3498         return flipForWritingMode(point);
   3499     return toRenderBlock(this)->flipForWritingModeIncludingColumns(point);
   3500 }
   3501 
   3502 IntSize RenderBox::flipForWritingMode(const IntSize& offset) const
   3503 {
   3504     if (!style()->isFlippedBlocksWritingMode())
   3505         return offset;
   3506     return isHorizontalWritingMode() ? IntSize(offset.width(), height() - offset.height()) : IntSize(width() - offset.width(), offset.height());
   3507 }
   3508 
   3509 FloatPoint RenderBox::flipForWritingMode(const FloatPoint& position) const
   3510 {
   3511     if (!style()->isFlippedBlocksWritingMode())
   3512         return position;
   3513     return isHorizontalWritingMode() ? FloatPoint(position.x(), height() - position.y()) : FloatPoint(width() - position.x(), position.y());
   3514 }
   3515 
   3516 void RenderBox::flipForWritingMode(FloatRect& rect) const
   3517 {
   3518     if (!style()->isFlippedBlocksWritingMode())
   3519         return;
   3520 
   3521     if (isHorizontalWritingMode())
   3522         rect.setY(height() - rect.maxY());
   3523     else
   3524         rect.setX(width() - rect.maxX());
   3525 }
   3526 
   3527 IntSize RenderBox::locationOffsetIncludingFlipping() const
   3528 {
   3529     RenderBlock* containerBlock = containingBlock();
   3530     if (!containerBlock || containerBlock == this)
   3531         return locationOffset();
   3532 
   3533     IntRect rect(frameRect());
   3534     containerBlock->flipForWritingMode(rect); // FIXME: This is wrong if we are an absolutely positioned object enclosed by a relative-positioned inline.
   3535     return IntSize(rect.x(), rect.y());
   3536 }
   3537 
   3538 } // namespace WebCore
   3539