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 #if PLATFORM(ANDROID)
   1566         // Strangely, the slider is get overrided as width 0 on youtube.com
   1567         // The wrong width will cause the touch hit test for the slider failed.
   1568         // This WAR should be safe since it is only targeted to slider.
   1569         // TODO: root cause this and see if any webkit update fix this.
   1570         if (!(isSlider() &&  overrideSize() == 0))
   1571 #endif
   1572         setLogicalWidth(overrideSize());
   1573         return;
   1574     }
   1575 
   1576     // FIXME: Account for block-flow in flexible boxes.
   1577     // https://bugs.webkit.org/show_bug.cgi?id=46418
   1578     bool inVerticalBox = parent()->isFlexibleBox() && (parent()->style()->boxOrient() == VERTICAL);
   1579     bool stretching = (parent()->style()->boxAlign() == BSTRETCH);
   1580     bool treatAsReplaced = shouldComputeSizeAsReplaced() && (!inVerticalBox || !stretching);
   1581 
   1582     Length logicalWidthLength = (treatAsReplaced) ? Length(computeReplacedLogicalWidth(), Fixed) : style()->logicalWidth();
   1583 
   1584     RenderBlock* cb = containingBlock();
   1585     int containerLogicalWidth = max(0, containingBlockLogicalWidthForContent());
   1586     bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHorizontalWritingMode();
   1587     int containerWidthInInlineDirection = containerLogicalWidth;
   1588     if (hasPerpendicularContainingBlock)
   1589         containerWidthInInlineDirection = perpendicularContainingBlockLogicalHeight();
   1590 
   1591     if (isInline() && !isInlineBlockOrInlineTable()) {
   1592         // just calculate margins
   1593         setMarginStart(style()->marginStart().calcMinValue(containerLogicalWidth));
   1594         setMarginEnd(style()->marginEnd().calcMinValue(containerLogicalWidth));
   1595 #ifdef ANDROID_LAYOUT
   1596         if (treatAsReplaced) {
   1597 #else
   1598         if (treatAsReplaced)
   1599 #endif
   1600             setLogicalWidth(max(logicalWidthLength.value() + borderAndPaddingLogicalWidth(), minPreferredLogicalWidth()));
   1601 
   1602 #ifdef ANDROID_LAYOUT
   1603             // in SSR mode with replaced box, if the box width is wider than the container width,
   1604             // it will be shrinked to fit to the container.
   1605             if (containerLogicalWidth && (width() + m_marginLeft + m_marginRight) > containerLogicalWidth &&
   1606                     document()->frame()->settings()->layoutAlgorithm() == Settings::kLayoutSSR) {
   1607                 m_marginLeft = m_marginRight = 0;
   1608                 setWidth(containerLogicalWidth);
   1609                 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = containerLogicalWidth;
   1610             }
   1611         }
   1612 #endif
   1613         return;
   1614     }
   1615 
   1616     // Width calculations
   1617     if (treatAsReplaced)
   1618         setLogicalWidth(logicalWidthLength.value() + borderAndPaddingLogicalWidth());
   1619     else {
   1620         // Calculate LogicalWidth
   1621         setLogicalWidth(computeLogicalWidthUsing(LogicalWidth, containerWidthInInlineDirection));
   1622 
   1623         // Calculate MaxLogicalWidth
   1624         if (!style()->logicalMaxWidth().isUndefined()) {
   1625             int maxLogicalWidth = computeLogicalWidthUsing(MaxLogicalWidth, containerWidthInInlineDirection);
   1626             if (logicalWidth() > maxLogicalWidth) {
   1627                 setLogicalWidth(maxLogicalWidth);
   1628                 logicalWidthLength = style()->logicalMaxWidth();
   1629             }
   1630         }
   1631 
   1632         // Calculate MinLogicalWidth
   1633         int minLogicalWidth = computeLogicalWidthUsing(MinLogicalWidth, containerWidthInInlineDirection);
   1634         if (logicalWidth() < minLogicalWidth) {
   1635             setLogicalWidth(minLogicalWidth);
   1636             logicalWidthLength = style()->logicalMinWidth();
   1637         }
   1638     }
   1639 
   1640     // Fieldsets are currently the only objects that stretch to their minimum width.
   1641     if (stretchesToMinIntrinsicLogicalWidth()) {
   1642         setLogicalWidth(max(logicalWidth(), minPreferredLogicalWidth()));
   1643         logicalWidthLength = Length(logicalWidth(), Fixed);
   1644     }
   1645 
   1646     // Margin calculations.
   1647     if (logicalWidthLength.isAuto() || hasPerpendicularContainingBlock || isFloating() || isInline()) {
   1648         setMarginStart(style()->marginStart().calcMinValue(containerLogicalWidth));
   1649         setMarginEnd(style()->marginEnd().calcMinValue(containerLogicalWidth));
   1650     } else
   1651         computeInlineDirectionMargins(cb, containerLogicalWidth, logicalWidth());
   1652 
   1653 #ifdef ANDROID_LAYOUT
   1654     // in SSR mode with non-replaced box, we use ANDROID_SSR_MARGIN_PADDING for left/right margin.
   1655     // If the box width is wider than the container width, it will be shrinked to fit to the container.
   1656     if (containerLogicalWidth && !treatAsReplaced &&
   1657             document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR) {
   1658         setWidth(width() + m_marginLeft + m_marginRight);
   1659         m_marginLeft = m_marginLeft > ANDROID_SSR_MARGIN_PADDING ? ANDROID_SSR_MARGIN_PADDING : m_marginLeft;
   1660         m_marginRight = m_marginRight > ANDROID_SSR_MARGIN_PADDING ? ANDROID_SSR_MARGIN_PADDING : m_marginRight;
   1661         if (width() > containerLogicalWidth) {
   1662             m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = containerLogicalWidth-(m_marginLeft + m_marginRight);
   1663             setWidth(m_minPreferredLogicalWidth);
   1664         } else
   1665             setWidth(width() -(m_marginLeft + m_marginRight));
   1666     }
   1667 #endif
   1668 
   1669     if (!hasPerpendicularContainingBlock && containerLogicalWidth && containerLogicalWidth != (logicalWidth() + marginStart() + marginEnd())
   1670             && !isFloating() && !isInline() && !cb->isFlexibleBox())
   1671         cb->setMarginEndForChild(this, containerLogicalWidth - logicalWidth() - cb->marginStartForChild(this));
   1672 }
   1673 
   1674 int RenderBox::computeLogicalWidthUsing(LogicalWidthType widthType, int availableLogicalWidth)
   1675 {
   1676     int logicalWidthResult = logicalWidth();
   1677     Length logicalWidth;
   1678     if (widthType == LogicalWidth)
   1679         logicalWidth = style()->logicalWidth();
   1680     else if (widthType == MinLogicalWidth)
   1681         logicalWidth = style()->logicalMinWidth();
   1682     else
   1683         logicalWidth = style()->logicalMaxWidth();
   1684 
   1685     if (logicalWidth.isIntrinsicOrAuto()) {
   1686         int marginStart = style()->marginStart().calcMinValue(availableLogicalWidth);
   1687         int marginEnd = style()->marginEnd().calcMinValue(availableLogicalWidth);
   1688         if (availableLogicalWidth)
   1689             logicalWidthResult = availableLogicalWidth - marginStart - marginEnd;
   1690 
   1691         if (sizesToIntrinsicLogicalWidth(widthType)) {
   1692             logicalWidthResult = max(logicalWidthResult, minPreferredLogicalWidth());
   1693             logicalWidthResult = min(logicalWidthResult, maxPreferredLogicalWidth());
   1694         }
   1695     } else // FIXME: If the containing block flow is perpendicular to our direction we need to use the available logical height instead.
   1696         logicalWidthResult = computeBorderBoxLogicalWidth(logicalWidth.calcValue(availableLogicalWidth));
   1697 
   1698     return logicalWidthResult;
   1699 }
   1700 
   1701 bool RenderBox::sizesToIntrinsicLogicalWidth(LogicalWidthType widthType) const
   1702 {
   1703     // Marquees in WinIE are like a mixture of blocks and inline-blocks.  They size as though they're blocks,
   1704     // but they allow text to sit on the same line as the marquee.
   1705     if (isFloating() || (isInlineBlockOrInlineTable() && !isHTMLMarquee()))
   1706         return true;
   1707 
   1708     // This code may look a bit strange.  Basically width:intrinsic should clamp the size when testing both
   1709     // min-width and width.  max-width is only clamped if it is also intrinsic.
   1710     Length logicalWidth = (widthType == MaxLogicalWidth) ? style()->logicalMaxWidth() : style()->logicalWidth();
   1711     if (logicalWidth.type() == Intrinsic)
   1712         return true;
   1713 
   1714     // Children of a horizontal marquee do not fill the container by default.
   1715     // FIXME: Need to deal with MAUTO value properly.  It could be vertical.
   1716     // FIXME: Think about block-flow here.  Need to find out how marquee direction relates to
   1717     // block-flow (as well as how marquee overflow should relate to block flow).
   1718     // https://bugs.webkit.org/show_bug.cgi?id=46472
   1719     if (parent()->style()->overflowX() == OMARQUEE) {
   1720         EMarqueeDirection dir = parent()->style()->marqueeDirection();
   1721         if (dir == MAUTO || dir == MFORWARD || dir == MBACKWARD || dir == MLEFT || dir == MRIGHT)
   1722             return true;
   1723     }
   1724 
   1725     // Flexible horizontal boxes lay out children at their intrinsic widths.  Also vertical boxes
   1726     // that don't stretch their kids lay out their children at their intrinsic widths.
   1727     // FIXME: Think about block-flow here.
   1728     // https://bugs.webkit.org/show_bug.cgi?id=46473
   1729     if (parent()->isFlexibleBox()
   1730             && (parent()->style()->boxOrient() == HORIZONTAL || parent()->style()->boxAlign() != BSTRETCH))
   1731         return true;
   1732 
   1733     // Button, input, select, textarea, legend and datagrid treat
   1734     // width value of 'auto' as 'intrinsic' unless it's in a
   1735     // stretching vertical flexbox.
   1736     // FIXME: Think about block-flow here.
   1737     // https://bugs.webkit.org/show_bug.cgi?id=46473
   1738     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)))
   1739         return true;
   1740 
   1741     return false;
   1742 }
   1743 
   1744 void RenderBox::computeInlineDirectionMargins(RenderBlock* containingBlock, int containerWidth, int childWidth)
   1745 {
   1746     const RenderStyle* containingBlockStyle = containingBlock->style();
   1747     Length marginStartLength = style()->marginStartUsing(containingBlockStyle);
   1748     Length marginEndLength = style()->marginEndUsing(containingBlockStyle);
   1749 
   1750     // Case One: The object is being centered in the containing block's available logical width.
   1751     if ((marginStartLength.isAuto() && marginEndLength.isAuto() && childWidth < containerWidth)
   1752         || (!marginStartLength.isAuto() && !marginEndLength.isAuto() && containingBlock->style()->textAlign() == WEBKIT_CENTER)) {
   1753         containingBlock->setMarginStartForChild(this, max(0, (containerWidth - childWidth) / 2));
   1754         containingBlock->setMarginEndForChild(this, containerWidth - childWidth - containingBlock->marginStartForChild(this));
   1755         return;
   1756     }
   1757 
   1758     // Case Two: The object is being pushed to the start of the containing block's available logical width.
   1759     if (marginEndLength.isAuto() && childWidth < containerWidth) {
   1760         containingBlock->setMarginStartForChild(this, marginStartLength.calcValue(containerWidth));
   1761         containingBlock->setMarginEndForChild(this, containerWidth - childWidth - containingBlock->marginStartForChild(this));
   1762         return;
   1763     }
   1764 
   1765     // Case Three: The object is being pushed to the end of the containing block's available logical width.
   1766     bool pushToEndFromTextAlign = !marginEndLength.isAuto() && ((!containingBlockStyle->isLeftToRightDirection() && containingBlockStyle->textAlign() == WEBKIT_LEFT)
   1767         || (containingBlockStyle->isLeftToRightDirection() && containingBlockStyle->textAlign() == WEBKIT_RIGHT));
   1768     if ((marginStartLength.isAuto() && childWidth < containerWidth) || pushToEndFromTextAlign) {
   1769         containingBlock->setMarginEndForChild(this, marginEndLength.calcValue(containerWidth));
   1770         containingBlock->setMarginStartForChild(this, containerWidth - childWidth - containingBlock->marginEndForChild(this));
   1771         return;
   1772     }
   1773 
   1774     // Case Four: Either no auto margins, or our width is >= the container width (css2.1, 10.3.3).  In that case
   1775     // auto margins will just turn into 0.
   1776     containingBlock->setMarginStartForChild(this, marginStartLength.calcMinValue(containerWidth));
   1777     containingBlock->setMarginEndForChild(this, marginEndLength.calcMinValue(containerWidth));
   1778 }
   1779 
   1780 void RenderBox::computeLogicalHeight()
   1781 {
   1782     // Cell height is managed by the table and inline non-replaced elements do not support a height property.
   1783     if (isTableCell() || (isInline() && !isReplaced()))
   1784         return;
   1785 
   1786     Length h;
   1787     if (isPositioned()) {
   1788         // FIXME: This calculation is not patched for block-flow yet.
   1789         // https://bugs.webkit.org/show_bug.cgi?id=46500
   1790         computePositionedLogicalHeight();
   1791     } else {
   1792         RenderBlock* cb = containingBlock();
   1793         bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHorizontalWritingMode();
   1794 
   1795         if (!hasPerpendicularContainingBlock)
   1796             computeBlockDirectionMargins(cb);
   1797 
   1798         // For tables, calculate margins only.
   1799         if (isTable()) {
   1800             if (hasPerpendicularContainingBlock)
   1801                 computeInlineDirectionMargins(cb, containingBlockLogicalWidthForContent(), logicalHeight());
   1802             return;
   1803         }
   1804 
   1805         // FIXME: Account for block-flow in flexible boxes.
   1806         // https://bugs.webkit.org/show_bug.cgi?id=46418
   1807         bool inHorizontalBox = parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL;
   1808         bool stretching = parent()->style()->boxAlign() == BSTRETCH;
   1809         bool treatAsReplaced = shouldComputeSizeAsReplaced() && (!inHorizontalBox || !stretching);
   1810         bool checkMinMaxHeight = false;
   1811 
   1812         // The parent box is flexing us, so it has increased or decreased our height.  We have to
   1813         // grab our cached flexible height.
   1814         // FIXME: Account for block-flow in flexible boxes.
   1815         // https://bugs.webkit.org/show_bug.cgi?id=46418
   1816         if (hasOverrideSize() && parent()->isFlexibleBox() && parent()->style()->boxOrient() == VERTICAL
   1817                 && parent()->isFlexingChildren())
   1818             h = Length(overrideSize() - borderAndPaddingLogicalHeight(), Fixed);
   1819         else if (treatAsReplaced)
   1820             h = Length(computeReplacedLogicalHeight(), Fixed);
   1821         else {
   1822             h = style()->logicalHeight();
   1823             checkMinMaxHeight = true;
   1824         }
   1825 
   1826         // Block children of horizontal flexible boxes fill the height of the box.
   1827         // FIXME: Account for block-flow in flexible boxes.
   1828         // https://bugs.webkit.org/show_bug.cgi?id=46418
   1829         if (h.isAuto() && parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
   1830                 && parent()->isStretchingChildren()) {
   1831             h = Length(parentBox()->contentLogicalHeight() - marginBefore() - marginAfter() - borderAndPaddingLogicalHeight(), Fixed);
   1832             checkMinMaxHeight = false;
   1833         }
   1834 
   1835         int heightResult;
   1836         if (checkMinMaxHeight) {
   1837 #ifdef ANDROID_LAYOUT
   1838             // in SSR mode, ignore CSS height as layout is so different
   1839             if (document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR)
   1840                 heightResult = -1;
   1841             else
   1842 #endif
   1843             heightResult = computeLogicalHeightUsing(style()->logicalHeight());
   1844             if (heightResult == -1)
   1845                 heightResult = logicalHeight();
   1846             int minH = computeLogicalHeightUsing(style()->logicalMinHeight()); // Leave as -1 if unset.
   1847             int maxH = style()->logicalMaxHeight().isUndefined() ? heightResult : computeLogicalHeightUsing(style()->logicalMaxHeight());
   1848             if (maxH == -1)
   1849                 maxH = heightResult;
   1850             heightResult = min(maxH, heightResult);
   1851             heightResult = max(minH, heightResult);
   1852         } else {
   1853             // The only times we don't check min/max height are when a fixed length has
   1854             // been given as an override.  Just use that.  The value has already been adjusted
   1855             // for box-sizing.
   1856             heightResult = h.value() + borderAndPaddingLogicalHeight();
   1857         }
   1858 
   1859         setLogicalHeight(heightResult);
   1860 
   1861         if (hasPerpendicularContainingBlock)
   1862             computeInlineDirectionMargins(cb, containingBlockLogicalWidthForContent(), heightResult);
   1863     }
   1864 
   1865     // WinIE quirk: The <html> block always fills the entire canvas in quirks mode.  The <body> always fills the
   1866     // <html> block in quirks mode.  Only apply this quirk if the block is normal flow and no height
   1867     // is specified. When we're printing, we also need this quirk if the body or root has a percentage
   1868     // height since we don't set a height in RenderView when we're printing. So without this quirk, the
   1869     // height has nothing to be a percentage of, and it ends up being 0. That is bad.
   1870     bool paginatedContentNeedsBaseHeight = document()->printing() && h.isPercent()
   1871         && (isRoot() || (isBody() && document()->documentElement()->renderer()->style()->logicalHeight().isPercent()));
   1872     if (stretchesToViewport() || paginatedContentNeedsBaseHeight) {
   1873         // FIXME: Finish accounting for block flow here.
   1874         // https://bugs.webkit.org/show_bug.cgi?id=46603
   1875         int margins = collapsedMarginBefore() + collapsedMarginAfter();
   1876         int visHeight;
   1877         if (document()->printing())
   1878             visHeight = static_cast<int>(view()->pageLogicalHeight());
   1879         else  {
   1880             if (isHorizontalWritingMode())
   1881                 visHeight = view()->viewHeight();
   1882             else
   1883                 visHeight = view()->viewWidth();
   1884         }
   1885         if (isRoot())
   1886             setLogicalHeight(max(logicalHeight(), visHeight - margins));
   1887         else {
   1888             int marginsBordersPadding = margins + parentBox()->marginBefore() + parentBox()->marginAfter() + parentBox()->borderAndPaddingLogicalHeight();
   1889             setLogicalHeight(max(logicalHeight(), visHeight - marginsBordersPadding));
   1890         }
   1891     }
   1892 }
   1893 
   1894 int RenderBox::computeLogicalHeightUsing(const Length& h)
   1895 {
   1896     int logicalHeight = -1;
   1897     if (!h.isAuto()) {
   1898         if (h.isFixed())
   1899             logicalHeight = h.value();
   1900         else if (h.isPercent())
   1901             logicalHeight = computePercentageLogicalHeight(h);
   1902         if (logicalHeight != -1) {
   1903             logicalHeight = computeBorderBoxLogicalHeight(logicalHeight);
   1904             return logicalHeight;
   1905         }
   1906     }
   1907     return logicalHeight;
   1908 }
   1909 
   1910 int RenderBox::computePercentageLogicalHeight(const Length& height)
   1911 {
   1912     int result = -1;
   1913 
   1914     // In quirks mode, blocks with auto height are skipped, and we keep looking for an enclosing
   1915     // block that may have a specified height and then use it. In strict mode, this violates the
   1916     // specification, which states that percentage heights just revert to auto if the containing
   1917     // block has an auto height. We still skip anonymous containing blocks in both modes, though, and look
   1918     // only at explicit containers.
   1919     bool skippedAutoHeightContainingBlock = false;
   1920     RenderBlock* cb = containingBlock();
   1921     while (!cb->isRenderView() && !cb->isBody() && !cb->isTableCell() && !cb->isPositioned() && cb->style()->logicalHeight().isAuto()) {
   1922         if (!document()->inQuirksMode() && !cb->isAnonymousBlock())
   1923             break;
   1924         skippedAutoHeightContainingBlock = true;
   1925         cb = cb->containingBlock();
   1926         cb->addPercentHeightDescendant(this);
   1927     }
   1928 
   1929     // A positioned element that specified both top/bottom or that specifies height should be treated as though it has a height
   1930     // explicitly specified that can be used for any percentage computations.
   1931     // FIXME: We can't just check top/bottom here.
   1932     // https://bugs.webkit.org/show_bug.cgi?id=46500
   1933     bool isPositionedWithSpecifiedHeight = cb->isPositioned() && (!cb->style()->logicalHeight().isAuto() || (!cb->style()->top().isAuto() && !cb->style()->bottom().isAuto()));
   1934 
   1935     bool includeBorderPadding = isTable();
   1936 
   1937     // Table cells violate what the CSS spec says to do with heights.  Basically we
   1938     // don't care if the cell specified a height or not.  We just always make ourselves
   1939     // be a percentage of the cell's current content height.
   1940     if (cb->isTableCell()) {
   1941         if (!skippedAutoHeightContainingBlock) {
   1942             result = cb->overrideSize();
   1943             if (result == -1) {
   1944                 // Normally we would let the cell size intrinsically, but scrolling overflow has to be
   1945                 // treated differently, since WinIE lets scrolled overflow regions shrink as needed.
   1946                 // While we can't get all cases right, we can at least detect when the cell has a specified
   1947                 // height or when the table has a specified height.  In these cases we want to initially have
   1948                 // no size and allow the flexing of the table or the cell to its specified height to cause us
   1949                 // to grow to fill the space.  This could end up being wrong in some cases, but it is
   1950                 // preferable to the alternative (sizing intrinsically and making the row end up too big).
   1951                 RenderTableCell* cell = toRenderTableCell(cb);
   1952                 if (scrollsOverflowY() && (!cell->style()->logicalHeight().isAuto() || !cell->table()->style()->logicalHeight().isAuto()))
   1953                     return 0;
   1954                 return -1;
   1955             }
   1956             includeBorderPadding = true;
   1957         }
   1958     }
   1959     // Otherwise we only use our percentage height if our containing block had a specified
   1960     // height.
   1961     else if (cb->style()->logicalHeight().isFixed())
   1962         result = cb->computeContentBoxLogicalHeight(cb->style()->logicalHeight().value());
   1963     else if (cb->style()->logicalHeight().isPercent() && !isPositionedWithSpecifiedHeight) {
   1964         // We need to recur and compute the percentage height for our containing block.
   1965         result = cb->computePercentageLogicalHeight(cb->style()->logicalHeight());
   1966         if (result != -1)
   1967             result = cb->computeContentBoxLogicalHeight(result);
   1968     } else if (cb->isRenderView() || (cb->isBody() && document()->inQuirksMode()) || isPositionedWithSpecifiedHeight) {
   1969         // Don't allow this to affect the block' height() member variable, since this
   1970         // can get called while the block is still laying out its kids.
   1971         int oldHeight = cb->logicalHeight();
   1972         cb->computeLogicalHeight();
   1973         result = cb->contentLogicalHeight();
   1974         cb->setLogicalHeight(oldHeight);
   1975     } else if (cb->isRoot() && isPositioned())
   1976         // Match the positioned objects behavior, which is that positioned objects will fill their viewport
   1977         // always.  Note we could only hit this case by recurring into computePercentageLogicalHeight on a positioned containing block.
   1978         result = cb->computeContentBoxLogicalHeight(cb->availableLogicalHeight());
   1979 
   1980     if (result != -1) {
   1981         result = height.calcValue(result);
   1982         if (includeBorderPadding) {
   1983             // It is necessary to use the border-box to match WinIE's broken
   1984             // box model.  This is essential for sizing inside
   1985             // table cells using percentage heights.
   1986             result -= borderAndPaddingLogicalHeight();
   1987             result = max(0, result);
   1988         }
   1989     }
   1990     return result;
   1991 }
   1992 
   1993 int RenderBox::computeReplacedLogicalWidth(bool includeMaxWidth) const
   1994 {
   1995     int logicalWidth = computeReplacedLogicalWidthUsing(style()->logicalWidth());
   1996     int minLogicalWidth = computeReplacedLogicalWidthUsing(style()->logicalMinWidth());
   1997     int maxLogicalWidth = !includeMaxWidth || style()->logicalMaxWidth().isUndefined() ? logicalWidth : computeReplacedLogicalWidthUsing(style()->logicalMaxWidth());
   1998 
   1999     return max(minLogicalWidth, min(logicalWidth, maxLogicalWidth));
   2000 }
   2001 
   2002 int RenderBox::computeReplacedLogicalWidthUsing(Length logicalWidth) const
   2003 {
   2004     switch (logicalWidth.type()) {
   2005         case Fixed:
   2006             return computeContentBoxLogicalWidth(logicalWidth.value());
   2007         case Percent: {
   2008             // FIXME: containingBlockLogicalWidthForContent() is wrong if the replaced element's block-flow is perpendicular to the
   2009             // containing block's block-flow.
   2010             // https://bugs.webkit.org/show_bug.cgi?id=46496
   2011             const int cw = isPositioned() ? containingBlockLogicalWidthForPositioned(toRenderBoxModelObject(container())) : containingBlockLogicalWidthForContent();
   2012             if (cw > 0)
   2013                 return computeContentBoxLogicalWidth(logicalWidth.calcMinValue(cw));
   2014         }
   2015         // fall through
   2016         default:
   2017             return intrinsicLogicalWidth();
   2018      }
   2019 }
   2020 
   2021 int RenderBox::computeReplacedLogicalHeight() const
   2022 {
   2023     int logicalHeight = computeReplacedLogicalHeightUsing(style()->logicalHeight());
   2024     int minLogicalHeight = computeReplacedLogicalHeightUsing(style()->logicalMinHeight());
   2025     int maxLogicalHeight = style()->logicalMaxHeight().isUndefined() ? logicalHeight : computeReplacedLogicalHeightUsing(style()->logicalMaxHeight());
   2026 
   2027     return max(minLogicalHeight, min(logicalHeight, maxLogicalHeight));
   2028 }
   2029 
   2030 int RenderBox::computeReplacedLogicalHeightUsing(Length logicalHeight) const
   2031 {
   2032     switch (logicalHeight.type()) {
   2033         case Fixed:
   2034             return computeContentBoxLogicalHeight(logicalHeight.value());
   2035         case Percent:
   2036         {
   2037             RenderObject* cb = isPositioned() ? container() : containingBlock();
   2038             while (cb->isAnonymous()) {
   2039                 cb = cb->containingBlock();
   2040                 toRenderBlock(cb)->addPercentHeightDescendant(const_cast<RenderBox*>(this));
   2041             }
   2042 
   2043             // FIXME: This calculation is not patched for block-flow yet.
   2044             // https://bugs.webkit.org/show_bug.cgi?id=46500
   2045             if (cb->isPositioned() && cb->style()->height().isAuto() && !(cb->style()->top().isAuto() || cb->style()->bottom().isAuto())) {
   2046                 ASSERT(cb->isRenderBlock());
   2047                 RenderBlock* block = toRenderBlock(cb);
   2048                 int oldHeight = block->height();
   2049                 block->computeLogicalHeight();
   2050                 int newHeight = block->computeContentBoxLogicalHeight(block->contentHeight());
   2051                 block->setHeight(oldHeight);
   2052                 return computeContentBoxLogicalHeight(logicalHeight.calcValue(newHeight));
   2053             }
   2054 
   2055             // FIXME: availableLogicalHeight() is wrong if the replaced element's block-flow is perpendicular to the
   2056             // containing block's block-flow.
   2057             // https://bugs.webkit.org/show_bug.cgi?id=46496
   2058             int availableHeight = isPositioned() ? containingBlockLogicalHeightForPositioned(toRenderBoxModelObject(cb)) : toRenderBox(cb)->availableLogicalHeight();
   2059 
   2060             // It is necessary to use the border-box to match WinIE's broken
   2061             // box model.  This is essential for sizing inside
   2062             // table cells using percentage heights.
   2063             // FIXME: This needs to be made block-flow-aware.  If the cell and image are perpendicular block-flows, this isn't right.
   2064             // https://bugs.webkit.org/show_bug.cgi?id=46997
   2065             if (cb->isTableCell() && (cb->style()->logicalHeight().isAuto() || cb->style()->logicalHeight().isPercent())) {
   2066                 // Don't let table cells squeeze percent-height replaced elements
   2067                 // <http://bugs.webkit.org/show_bug.cgi?id=15359>
   2068                 availableHeight = max(availableHeight, intrinsicLogicalHeight());
   2069                 return logicalHeight.calcValue(availableHeight - borderAndPaddingLogicalHeight());
   2070             }
   2071 
   2072             return computeContentBoxLogicalHeight(logicalHeight.calcValue(availableHeight));
   2073         }
   2074         default:
   2075             return intrinsicLogicalHeight();
   2076     }
   2077 }
   2078 
   2079 int RenderBox::availableLogicalHeight() const
   2080 {
   2081     return availableLogicalHeightUsing(style()->logicalHeight());
   2082 }
   2083 
   2084 int RenderBox::availableLogicalHeightUsing(const Length& h) const
   2085 {
   2086     if (h.isFixed())
   2087         return computeContentBoxLogicalHeight(h.value());
   2088 
   2089     if (isRenderView())
   2090         return isHorizontalWritingMode() ? toRenderView(this)->frameView()->visibleHeight() : toRenderView(this)->frameView()->visibleWidth();
   2091 
   2092     // We need to stop here, since we don't want to increase the height of the table
   2093     // artificially.  We're going to rely on this cell getting expanded to some new
   2094     // height, and then when we lay out again we'll use the calculation below.
   2095     if (isTableCell() && (h.isAuto() || h.isPercent()))
   2096         return overrideSize() - borderAndPaddingLogicalWidth();
   2097 
   2098     if (h.isPercent())
   2099        return computeContentBoxLogicalHeight(h.calcValue(containingBlock()->availableLogicalHeight()));
   2100 
   2101     // FIXME: We can't just check top/bottom here.
   2102     // https://bugs.webkit.org/show_bug.cgi?id=46500
   2103     if (isRenderBlock() && isPositioned() && style()->height().isAuto() && !(style()->top().isAuto() || style()->bottom().isAuto())) {
   2104         RenderBlock* block = const_cast<RenderBlock*>(toRenderBlock(this));
   2105         int oldHeight = block->logicalHeight();
   2106         block->computeLogicalHeight();
   2107         int newHeight = block->computeContentBoxLogicalHeight(block->contentLogicalHeight());
   2108         block->setLogicalHeight(oldHeight);
   2109         return computeContentBoxLogicalHeight(newHeight);
   2110     }
   2111 
   2112     return containingBlock()->availableLogicalHeight();
   2113 }
   2114 
   2115 void RenderBox::computeBlockDirectionMargins(RenderBlock* containingBlock)
   2116 {
   2117     if (isTableCell()) {
   2118         // FIXME: Not right if we allow cells to have different directionality than the table.  If we do allow this, though,
   2119         // we may just do it with an extra anonymous block inside the cell.
   2120         setMarginBefore(0);
   2121         setMarginAfter(0);
   2122         return;
   2123     }
   2124 
   2125     // Margins are calculated with respect to the logical width of
   2126     // the containing block (8.3)
   2127     int cw = containingBlockLogicalWidthForContent();
   2128 
   2129     RenderStyle* containingBlockStyle = containingBlock->style();
   2130     containingBlock->setMarginBeforeForChild(this, style()->marginBeforeUsing(containingBlockStyle).calcMinValue(cw));
   2131     containingBlock->setMarginAfterForChild(this, style()->marginAfterUsing(containingBlockStyle).calcMinValue(cw));
   2132 }
   2133 
   2134 int RenderBox::containingBlockLogicalWidthForPositioned(const RenderBoxModelObject* containingBlock, bool checkForPerpendicularWritingMode) const
   2135 {
   2136 #if PLATFORM(ANDROID)
   2137     // Fixed element's position should be decided by the visible screen size.
   2138     // That is in the doc coordindate.
   2139     if (style()->position() == FixedPosition && containingBlock->isRenderView()) {
   2140         const RenderView* view = toRenderView(containingBlock);
   2141         return PlatformBridge::screenWidthInDocCoord(view->frameView());
   2142     }
   2143 #endif
   2144 
   2145     if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWritingMode() != isHorizontalWritingMode())
   2146         return containingBlockLogicalHeightForPositioned(containingBlock, false);
   2147 
   2148     if (containingBlock->isBox())
   2149         return toRenderBox(containingBlock)->clientLogicalWidth();
   2150 
   2151     ASSERT(containingBlock->isRenderInline() && containingBlock->isRelPositioned());
   2152 
   2153     const RenderInline* flow = toRenderInline(containingBlock);
   2154     InlineFlowBox* first = flow->firstLineBox();
   2155     InlineFlowBox* last = flow->lastLineBox();
   2156 
   2157     // If the containing block is empty, return a width of 0.
   2158     if (!first || !last)
   2159         return 0;
   2160 
   2161     int fromLeft;
   2162     int fromRight;
   2163     if (containingBlock->style()->isLeftToRightDirection()) {
   2164         fromLeft = first->logicalLeft() + first->borderLogicalLeft();
   2165         fromRight = last->logicalLeft() + last->logicalWidth() - last->borderLogicalRight();
   2166     } else {
   2167         fromRight = first->logicalLeft() + first->logicalWidth() - first->borderLogicalRight();
   2168         fromLeft = last->logicalLeft() + last->borderLogicalLeft();
   2169     }
   2170 
   2171     return max(0, (fromRight - fromLeft));
   2172 }
   2173 
   2174 int RenderBox::containingBlockLogicalHeightForPositioned(const RenderBoxModelObject* containingBlock, bool checkForPerpendicularWritingMode) const
   2175 {
   2176 #if PLATFORM(ANDROID)
   2177     // Fixed element's position should be decided by the visible screen size.
   2178     // That is in the doc coordindate.
   2179     if (style()->position() == FixedPosition && containingBlock->isRenderView()) {
   2180         const RenderView* view = toRenderView(containingBlock);
   2181         return PlatformBridge::screenHeightInDocCoord(view->frameView());
   2182     }
   2183 #endif
   2184 
   2185     if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWritingMode() != isHorizontalWritingMode())
   2186         return containingBlockLogicalWidthForPositioned(containingBlock, false);
   2187 
   2188     if (containingBlock->isBox())
   2189         return toRenderBox(containingBlock)->clientLogicalHeight();
   2190 
   2191     ASSERT(containingBlock->isRenderInline() && containingBlock->isRelPositioned());
   2192 
   2193     const RenderInline* flow = toRenderInline(containingBlock);
   2194     InlineFlowBox* first = flow->firstLineBox();
   2195     InlineFlowBox* last = flow->lastLineBox();
   2196 
   2197     // If the containing block is empty, return a height of 0.
   2198     if (!first || !last)
   2199         return 0;
   2200 
   2201     int heightResult;
   2202     IntRect boundingBox = flow->linesBoundingBox();
   2203     if (containingBlock->isHorizontalWritingMode())
   2204         heightResult = boundingBox.height();
   2205     else
   2206         heightResult = boundingBox.width();
   2207     heightResult -= (containingBlock->borderBefore() + containingBlock->borderAfter());
   2208     return heightResult;
   2209 }
   2210 
   2211 static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRight, const RenderBox* child, const RenderBoxModelObject* containerBlock, int containerLogicalWidth,
   2212                                         TextDirection containerDirection)
   2213 {
   2214     if (!logicalLeft.isAuto() || !logicalRight.isAuto())
   2215         return;
   2216 
   2217     // FIXME: The static distance computation has not been patched for mixed writing modes yet.
   2218     if (containerDirection == LTR) {
   2219         int staticPosition = child->layer()->staticInlinePosition() - containerBlock->borderLogicalLeft();
   2220         for (RenderObject* curr = child->parent(); curr && curr != containerBlock; curr = curr->container()) {
   2221             if (curr->isBox())
   2222                 staticPosition += toRenderBox(curr)->logicalLeft();
   2223         }
   2224         logicalLeft.setValue(Fixed, staticPosition);
   2225     } else {
   2226         RenderBox* enclosingBox = child->parent()->enclosingBox();
   2227         int staticPosition = child->layer()->staticInlinePosition() + containerLogicalWidth + containerBlock->borderLogicalRight();
   2228         staticPosition -= enclosingBox->logicalWidth();
   2229         for (RenderObject* curr = enclosingBox; curr && curr != containerBlock; curr = curr->container()) {
   2230             if (curr->isBox())
   2231                 staticPosition -= toRenderBox(curr)->logicalLeft();
   2232         }
   2233         logicalRight.setValue(Fixed, staticPosition);
   2234     }
   2235 }
   2236 
   2237 void RenderBox::computePositionedLogicalWidth()
   2238 {
   2239     if (isReplaced()) {
   2240         computePositionedLogicalWidthReplaced();
   2241         return;
   2242     }
   2243 
   2244     // QUESTIONS
   2245     // FIXME 1: Which RenderObject's 'direction' property should used: the
   2246     // containing block (cb) as the spec seems to imply, the parent (parent()) as
   2247     // was previously done in calculating the static distances, or ourself, which
   2248     // was also previously done for deciding what to override when you had
   2249     // over-constrained margins?  Also note that the container block is used
   2250     // in similar situations in other parts of the RenderBox class (see computeLogicalWidth()
   2251     // and computeMarginsInContainingBlockInlineDirection()). For now we are using the parent for quirks
   2252     // mode and the containing block for strict mode.
   2253 
   2254     // FIXME 2: Should we still deal with these the cases of 'left' or 'right' having
   2255     // the type 'static' in determining whether to calculate the static distance?
   2256     // NOTE: 'static' is not a legal value for 'left' or 'right' as of CSS 2.1.
   2257 
   2258     // FIXME 3: Can perhaps optimize out cases when max-width/min-width are greater
   2259     // than or less than the computed width().  Be careful of box-sizing and
   2260     // percentage issues.
   2261 
   2262     // The following is based off of the W3C Working Draft from April 11, 2006 of
   2263     // CSS 2.1: Section 10.3.7 "Absolutely positioned, non-replaced elements"
   2264     // <http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width>
   2265     // (block-style-comments in this function and in computePositionedLogicalWidthUsing()
   2266     // correspond to text from the spec)
   2267 
   2268 
   2269     // We don't use containingBlock(), since we may be positioned by an enclosing
   2270     // relative positioned inline.
   2271     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
   2272 
   2273     const int containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock);
   2274 
   2275     // To match WinIE, in quirks mode use the parent's 'direction' property
   2276     // instead of the the container block's.
   2277     TextDirection containerDirection = (document()->inQuirksMode()) ? parent()->style()->direction() : containerBlock->style()->direction();
   2278 
   2279     bool isHorizontal = isHorizontalWritingMode();
   2280     const int bordersPlusPadding = borderAndPaddingLogicalWidth();
   2281     const Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->marginTop();
   2282     const Length marginLogicalRight = isHorizontal ? style()->marginRight() : style()->marginBottom();
   2283     int& marginLogicalLeftAlias = isHorizontal ? m_marginLeft : m_marginTop;
   2284     int& marginLogicalRightAlias = isHorizontal ? m_marginRight : m_marginBottom;
   2285 
   2286     Length logicalLeft = style()->logicalLeft();
   2287     Length logicalRight = style()->logicalRight();
   2288 
   2289     /*---------------------------------------------------------------------------*\
   2290      * For the purposes of this section and the next, the term "static position"
   2291      * (of an element) refers, roughly, to the position an element would have had
   2292      * in the normal flow. More precisely:
   2293      *
   2294      * * The static position for 'left' is the distance from the left edge of the
   2295      *   containing block to the left margin edge of a hypothetical box that would
   2296      *   have been the first box of the element if its 'position' property had
   2297      *   been 'static' and 'float' had been 'none'. The value is negative if the
   2298      *   hypothetical box is to the left of the containing block.
   2299      * * The static position for 'right' is the distance from the right edge of the
   2300      *   containing block to the right margin edge of the same hypothetical box as
   2301      *   above. The value is positive if the hypothetical box is to the left of the
   2302      *   containing block's edge.
   2303      *
   2304      * But rather than actually calculating the dimensions of that hypothetical box,
   2305      * user agents are free to make a guess at its probable position.
   2306      *
   2307      * For the purposes of calculating the static position, the containing block of
   2308      * fixed positioned elements is the initial containing block instead of the
   2309      * viewport, and all scrollable boxes should be assumed to be scrolled to their
   2310      * origin.
   2311     \*---------------------------------------------------------------------------*/
   2312 
   2313     // see FIXME 2
   2314     // Calculate the static distance if needed.
   2315     computeInlineStaticDistance(logicalLeft, logicalRight, this, containerBlock, containerLogicalWidth, containerDirection);
   2316 
   2317     // Calculate constraint equation values for 'width' case.
   2318     int logicalWidthResult;
   2319     int logicalLeftResult;
   2320     computePositionedLogicalWidthUsing(style()->logicalWidth(), containerBlock, containerDirection,
   2321                                        containerLogicalWidth, bordersPlusPadding,
   2322                                        logicalLeft, logicalRight, marginLogicalLeft, marginLogicalRight,
   2323                                        logicalWidthResult, marginLogicalLeftAlias, marginLogicalRightAlias, logicalLeftResult);
   2324     setLogicalWidth(logicalWidthResult);
   2325     setLogicalLeft(logicalLeftResult);
   2326 
   2327     // Calculate constraint equation values for 'max-width' case.
   2328     if (!style()->logicalMaxWidth().isUndefined()) {
   2329         int maxLogicalWidth;
   2330         int maxMarginLogicalLeft;
   2331         int maxMarginLogicalRight;
   2332         int maxLogicalLeftPos;
   2333 
   2334         computePositionedLogicalWidthUsing(style()->logicalMaxWidth(), containerBlock, containerDirection,
   2335                                            containerLogicalWidth, bordersPlusPadding,
   2336                                            logicalLeft, logicalRight, marginLogicalLeft, marginLogicalRight,
   2337                                            maxLogicalWidth, maxMarginLogicalLeft, maxMarginLogicalRight, maxLogicalLeftPos);
   2338 
   2339         if (logicalWidth() > maxLogicalWidth) {
   2340             setLogicalWidth(maxLogicalWidth);
   2341             marginLogicalLeftAlias = maxMarginLogicalLeft;
   2342             marginLogicalRightAlias = maxMarginLogicalRight;
   2343             setLogicalLeft(maxLogicalLeftPos);
   2344         }
   2345     }
   2346 
   2347     // Calculate constraint equation values for 'min-width' case.
   2348     if (!style()->logicalMinWidth().isZero()) {
   2349         int minLogicalWidth;
   2350         int minMarginLogicalLeft;
   2351         int minMarginLogicalRight;
   2352         int minLogicalLeftPos;
   2353 
   2354         computePositionedLogicalWidthUsing(style()->logicalMinWidth(), containerBlock, containerDirection,
   2355                                            containerLogicalWidth, bordersPlusPadding,
   2356                                            logicalLeft, logicalRight, marginLogicalLeft, marginLogicalRight,
   2357                                            minLogicalWidth, minMarginLogicalLeft, minMarginLogicalRight, minLogicalLeftPos);
   2358 
   2359         if (logicalWidth() < minLogicalWidth) {
   2360             setLogicalWidth(minLogicalWidth);
   2361             marginLogicalLeftAlias = minMarginLogicalLeft;
   2362             marginLogicalRightAlias = minMarginLogicalRight;
   2363             setLogicalLeft(minLogicalLeftPos);
   2364         }
   2365     }
   2366 
   2367     if (stretchesToMinIntrinsicLogicalWidth() && logicalWidth() < minPreferredLogicalWidth() - bordersPlusPadding) {
   2368         computePositionedLogicalWidthUsing(Length(minPreferredLogicalWidth() - bordersPlusPadding, Fixed), containerBlock, containerDirection,
   2369                                            containerLogicalWidth, bordersPlusPadding,
   2370                                            logicalLeft, logicalRight, marginLogicalLeft, marginLogicalRight,
   2371                                            logicalWidthResult, marginLogicalLeftAlias, marginLogicalRightAlias, logicalLeftResult);
   2372         setLogicalWidth(logicalWidthResult);
   2373         setLogicalLeft(logicalLeftResult);
   2374     }
   2375 
   2376     // Put logicalWidth() into correct form.
   2377     setLogicalWidth(logicalWidth() + bordersPlusPadding);
   2378 }
   2379 
   2380 static void computeLogicalLeftPositionedOffset(int& logicalLeftPos, const RenderBox* child, int logicalWidthValue, const RenderBoxModelObject* containerBlock, int containerLogicalWidth)
   2381 {
   2382     // Deal with differing writing modes here.  Our offset needs to be in the containing block's coordinate space. If the containing block is flipped
   2383     // 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.
   2384     if (containerBlock->isHorizontalWritingMode() != child->isHorizontalWritingMode() && containerBlock->style()->isFlippedBlocksWritingMode()) {
   2385         logicalLeftPos = containerLogicalWidth - logicalWidthValue - logicalLeftPos;
   2386         logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->borderRight() : containerBlock->borderBottom());
   2387     } else
   2388         logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->borderLeft() : containerBlock->borderTop());
   2389 }
   2390 
   2391 void RenderBox::computePositionedLogicalWidthUsing(Length logicalWidth, const RenderBoxModelObject* containerBlock, TextDirection containerDirection,
   2392                                                    int containerLogicalWidth, int bordersPlusPadding,
   2393                                                    Length logicalLeft, Length logicalRight, Length marginLogicalLeft, Length marginLogicalRight,
   2394                                                    int& logicalWidthValue, int& marginLogicalLeftValue, int& marginLogicalRightValue, int& logicalLeftPos)
   2395 {
   2396     // 'left' and 'right' cannot both be 'auto' because one would of been
   2397     // converted to the static position already
   2398     ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto()));
   2399 
   2400     int logicalLeftValue = 0;
   2401 
   2402     bool logicalWidthIsAuto = logicalWidth.isIntrinsicOrAuto();
   2403     bool logicalLeftIsAuto = logicalLeft.isAuto();
   2404     bool logicalRightIsAuto = logicalRight.isAuto();
   2405 
   2406     if (!logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) {
   2407         /*-----------------------------------------------------------------------*\
   2408          * If none of the three is 'auto': If both 'margin-left' and 'margin-
   2409          * right' are 'auto', solve the equation under the extra constraint that
   2410          * the two margins get equal values, unless this would make them negative,
   2411          * in which case when direction of the containing block is 'ltr' ('rtl'),
   2412          * set 'margin-left' ('margin-right') to zero and solve for 'margin-right'
   2413          * ('margin-left'). If one of 'margin-left' or 'margin-right' is 'auto',
   2414          * solve the equation for that value. If the values are over-constrained,
   2415          * ignore the value for 'left' (in case the 'direction' property of the
   2416          * containing block is 'rtl') or 'right' (in case 'direction' is 'ltr')
   2417          * and solve for that value.
   2418         \*-----------------------------------------------------------------------*/
   2419         // NOTE:  It is not necessary to solve for 'right' in the over constrained
   2420         // case because the value is not used for any further calculations.
   2421 
   2422         logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2423         logicalWidthValue = computeContentBoxLogicalWidth(logicalWidth.calcValue(containerLogicalWidth));
   2424 
   2425         const int availableSpace = containerLogicalWidth - (logicalLeftValue + logicalWidthValue + logicalRight.calcValue(containerLogicalWidth) + bordersPlusPadding);
   2426 
   2427         // Margins are now the only unknown
   2428         if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) {
   2429             // Both margins auto, solve for equality
   2430             if (availableSpace >= 0) {
   2431                 marginLogicalLeftValue = availableSpace / 2; // split the difference
   2432                 marginLogicalRightValue = availableSpace - marginLogicalLeftValue; // account for odd valued differences
   2433             } else {
   2434                 // see FIXME 1
   2435                 if (containerDirection == LTR) {
   2436                     marginLogicalLeftValue = 0;
   2437                     marginLogicalRightValue = availableSpace; // will be negative
   2438                 } else {
   2439                     marginLogicalLeftValue = availableSpace; // will be negative
   2440                     marginLogicalRightValue = 0;
   2441                 }
   2442             }
   2443         } else if (marginLogicalLeft.isAuto()) {
   2444             // Solve for left margin
   2445             marginLogicalRightValue = marginLogicalRight.calcValue(containerLogicalWidth);
   2446             marginLogicalLeftValue = availableSpace - marginLogicalRightValue;
   2447         } else if (marginLogicalRight.isAuto()) {
   2448             // Solve for right margin
   2449             marginLogicalLeftValue = marginLogicalLeft.calcValue(containerLogicalWidth);
   2450             marginLogicalRightValue = availableSpace - marginLogicalLeftValue;
   2451         } else {
   2452             // Over-constrained, solve for left if direction is RTL
   2453             marginLogicalLeftValue = marginLogicalLeft.calcValue(containerLogicalWidth);
   2454             marginLogicalRightValue = marginLogicalRight.calcValue(containerLogicalWidth);
   2455 
   2456             // see FIXME 1 -- used to be "this->style()->direction()"
   2457             if (containerDirection == RTL)
   2458                 logicalLeftValue = (availableSpace + logicalLeftValue) - marginLogicalLeftValue - marginLogicalRightValue;
   2459         }
   2460     } else {
   2461         /*--------------------------------------------------------------------*\
   2462          * Otherwise, set 'auto' values for 'margin-left' and 'margin-right'
   2463          * to 0, and pick the one of the following six rules that applies.
   2464          *
   2465          * 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the
   2466          *    width is shrink-to-fit. Then solve for 'left'
   2467          *
   2468          *              OMIT RULE 2 AS IT SHOULD NEVER BE HIT
   2469          * ------------------------------------------------------------------
   2470          * 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if
   2471          *    the 'direction' property of the containing block is 'ltr' set
   2472          *    'left' to the static position, otherwise set 'right' to the
   2473          *    static position. Then solve for 'left' (if 'direction is 'rtl')
   2474          *    or 'right' (if 'direction' is 'ltr').
   2475          * ------------------------------------------------------------------
   2476          *
   2477          * 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the
   2478          *    width is shrink-to-fit . Then solve for 'right'
   2479          * 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve
   2480          *    for 'left'
   2481          * 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve
   2482          *    for 'width'
   2483          * 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve
   2484          *    for 'right'
   2485          *
   2486          * Calculation of the shrink-to-fit width is similar to calculating the
   2487          * width of a table cell using the automatic table layout algorithm.
   2488          * Roughly: calculate the preferred width by formatting the content
   2489          * without breaking lines other than where explicit line breaks occur,
   2490          * and also calculate the preferred minimum width, e.g., by trying all
   2491          * possible line breaks. CSS 2.1 does not define the exact algorithm.
   2492          * Thirdly, calculate the available width: this is found by solving
   2493          * for 'width' after setting 'left' (in case 1) or 'right' (in case 3)
   2494          * to 0.
   2495          *
   2496          * Then the shrink-to-fit width is:
   2497          * min(max(preferred minimum width, available width), preferred width).
   2498         \*--------------------------------------------------------------------*/
   2499         // NOTE: For rules 3 and 6 it is not necessary to solve for 'right'
   2500         // because the value is not used for any further calculations.
   2501 
   2502         // Calculate margins, 'auto' margins are ignored.
   2503         marginLogicalLeftValue = marginLogicalLeft.calcMinValue(containerLogicalWidth);
   2504         marginLogicalRightValue = marginLogicalRight.calcMinValue(containerLogicalWidth);
   2505 
   2506         const int availableSpace = containerLogicalWidth - (marginLogicalLeftValue + marginLogicalRightValue + bordersPlusPadding);
   2507 
   2508         // FIXME: Is there a faster way to find the correct case?
   2509         // Use rule/case that applies.
   2510         if (logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAuto) {
   2511             // RULE 1: (use shrink-to-fit for width, and solve of left)
   2512             int logicalRightValue = logicalRight.calcValue(containerLogicalWidth);
   2513 
   2514             // FIXME: would it be better to have shrink-to-fit in one step?
   2515             int preferredWidth = maxPreferredLogicalWidth() - bordersPlusPadding;
   2516             int preferredMinWidth = minPreferredLogicalWidth() - bordersPlusPadding;
   2517             int availableWidth = availableSpace - logicalRightValue;
   2518             logicalWidthValue = min(max(preferredMinWidth, availableWidth), preferredWidth);
   2519             logicalLeftValue = availableSpace - (logicalWidthValue + logicalRightValue);
   2520         } else if (!logicalLeftIsAuto && logicalWidthIsAuto && logicalRightIsAuto) {
   2521             // RULE 3: (use shrink-to-fit for width, and no need solve of right)
   2522             logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2523 
   2524             // FIXME: would it be better to have shrink-to-fit in one step?
   2525             int preferredWidth = maxPreferredLogicalWidth() - bordersPlusPadding;
   2526             int preferredMinWidth = minPreferredLogicalWidth() - bordersPlusPadding;
   2527             int availableWidth = availableSpace - logicalLeftValue;
   2528             logicalWidthValue = min(max(preferredMinWidth, availableWidth), preferredWidth);
   2529         } else if (logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) {
   2530             // RULE 4: (solve for left)
   2531             logicalWidthValue = computeContentBoxLogicalWidth(logicalWidth.calcValue(containerLogicalWidth));
   2532             logicalLeftValue = availableSpace - (logicalWidthValue + logicalRight.calcValue(containerLogicalWidth));
   2533         } else if (!logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAuto) {
   2534             // RULE 5: (solve for width)
   2535             logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2536             logicalWidthValue = availableSpace - (logicalLeftValue + logicalRight.calcValue(containerLogicalWidth));
   2537         } else if (!logicalLeftIsAuto && !logicalWidthIsAuto && logicalRightIsAuto) {
   2538             // RULE 6: (no need solve for right)
   2539             logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2540             logicalWidthValue = computeContentBoxLogicalWidth(logicalWidth.calcValue(containerLogicalWidth));
   2541         }
   2542     }
   2543 
   2544     // Use computed values to calculate the horizontal position.
   2545 
   2546     // FIXME: This hack is needed to calculate the  logical left position for a 'rtl' relatively
   2547     // positioned, inline because right now, it is using the logical left position
   2548     // of the first line box when really it should use the last line box.  When
   2549     // this is fixed elsewhere, this block should be removed.
   2550     if (containerBlock->isRenderInline() && !containerBlock->style()->isLeftToRightDirection()) {
   2551         const RenderInline* flow = toRenderInline(containerBlock);
   2552         InlineFlowBox* firstLine = flow->firstLineBox();
   2553         InlineFlowBox* lastLine = flow->lastLineBox();
   2554         if (firstLine && lastLine && firstLine != lastLine) {
   2555             logicalLeftPos = logicalLeftValue + marginLogicalLeftValue + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logicalLeft());
   2556             return;
   2557         }
   2558     }
   2559 
   2560     logicalLeftPos = logicalLeftValue + marginLogicalLeftValue;
   2561     computeLogicalLeftPositionedOffset(logicalLeftPos, this, logicalWidthValue, containerBlock, containerLogicalWidth);
   2562 }
   2563 
   2564 static void computeBlockStaticDistance(Length& logicalTop, Length& logicalBottom, const RenderBox* child, const RenderBoxModelObject* containerBlock)
   2565 {
   2566     if (!logicalTop.isAuto() || !logicalBottom.isAuto())
   2567         return;
   2568 
   2569     // FIXME: The static distance computation has not been patched for mixed writing modes.
   2570     int staticLogicalTop = child->layer()->staticBlockPosition() - containerBlock->borderBefore();
   2571     for (RenderObject* curr = child->parent(); curr && curr != containerBlock; curr = curr->container()) {
   2572         if (curr->isBox() && !curr->isTableRow())
   2573             staticLogicalTop += toRenderBox(curr)->logicalTop();
   2574     }
   2575     logicalTop.setValue(Fixed, staticLogicalTop);
   2576 }
   2577 
   2578 void RenderBox::computePositionedLogicalHeight()
   2579 {
   2580     if (isReplaced()) {
   2581         computePositionedLogicalHeightReplaced();
   2582         return;
   2583     }
   2584 
   2585     // The following is based off of the W3C Working Draft from April 11, 2006 of
   2586     // CSS 2.1: Section 10.6.4 "Absolutely positioned, non-replaced elements"
   2587     // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-non-replaced-height>
   2588     // (block-style-comments in this function and in computePositionedLogicalHeightUsing()
   2589     // correspond to text from the spec)
   2590 
   2591 
   2592     // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
   2593     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
   2594 
   2595     const int containerLogicalHeight = containingBlockLogicalHeightForPositioned(containerBlock);
   2596 
   2597     bool isHorizontal = isHorizontalWritingMode();
   2598     bool isFlipped = style()->isFlippedBlocksWritingMode();
   2599     const int bordersPlusPadding = borderAndPaddingLogicalHeight();
   2600     const Length marginBefore = style()->marginBefore();
   2601     const Length marginAfter = style()->marginAfter();
   2602     int& marginBeforeAlias = isHorizontal ? (isFlipped ? m_marginBottom : m_marginTop) : (isFlipped ? m_marginRight: m_marginLeft);
   2603     int& marginAfterAlias = isHorizontal ? (isFlipped ? m_marginTop : m_marginBottom) : (isFlipped ? m_marginLeft: m_marginRight);
   2604 
   2605     Length logicalTop = style()->logicalTop();
   2606     Length logicalBottom = style()->logicalBottom();
   2607 
   2608     /*---------------------------------------------------------------------------*\
   2609      * For the purposes of this section and the next, the term "static position"
   2610      * (of an element) refers, roughly, to the position an element would have had
   2611      * in the normal flow. More precisely, the static position for 'top' is the
   2612      * distance from the top edge of the containing block to the top margin edge
   2613      * of a hypothetical box that would have been the first box of the element if
   2614      * its 'position' property had been 'static' and 'float' had been 'none'. The
   2615      * value is negative if the hypothetical box is above the containing block.
   2616      *
   2617      * But rather than actually calculating the dimensions of that hypothetical
   2618      * box, user agents are free to make a guess at its probable position.
   2619      *
   2620      * For the purposes of calculating the static position, the containing block
   2621      * of fixed positioned elements is the initial containing block instead of
   2622      * the viewport.
   2623     \*---------------------------------------------------------------------------*/
   2624 
   2625     // see FIXME 2
   2626     // Calculate the static distance if needed.
   2627     computeBlockStaticDistance(logicalTop, logicalBottom, this, containerBlock);
   2628 
   2629     int logicalHeightResult; // Needed to compute overflow.
   2630     int logicalTopPos;
   2631 
   2632     // Calculate constraint equation values for 'height' case.
   2633     computePositionedLogicalHeightUsing(style()->logicalHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding,
   2634                                         logicalTop, logicalBottom, marginBefore, marginAfter,
   2635                                         logicalHeightResult, marginBeforeAlias, marginAfterAlias, logicalTopPos);
   2636     setLogicalTop(logicalTopPos);
   2637 
   2638     // Avoid doing any work in the common case (where the values of min-height and max-height are their defaults).
   2639     // see FIXME 3
   2640 
   2641     // Calculate constraint equation values for 'max-height' case.
   2642     if (!style()->logicalMaxHeight().isUndefined()) {
   2643         int maxLogicalHeight;
   2644         int maxMarginBefore;
   2645         int maxMarginAfter;
   2646         int maxLogicalTopPos;
   2647 
   2648         computePositionedLogicalHeightUsing(style()->logicalMaxHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding,
   2649                                             logicalTop, logicalBottom, marginBefore, marginAfter,
   2650                                             maxLogicalHeight, maxMarginBefore, maxMarginAfter, maxLogicalTopPos);
   2651 
   2652         if (logicalHeightResult > maxLogicalHeight) {
   2653             logicalHeightResult = maxLogicalHeight;
   2654             marginBeforeAlias = maxMarginBefore;
   2655             marginAfterAlias = maxMarginAfter;
   2656             setLogicalTop(maxLogicalTopPos);
   2657         }
   2658     }
   2659 
   2660     // Calculate constraint equation values for 'min-height' case.
   2661     if (!style()->logicalMinHeight().isZero()) {
   2662         int minLogicalHeight;
   2663         int minMarginBefore;
   2664         int minMarginAfter;
   2665         int minLogicalTopPos;
   2666 
   2667         computePositionedLogicalHeightUsing(style()->logicalMinHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding,
   2668                                             logicalTop, logicalBottom, marginBefore, marginAfter,
   2669                                             minLogicalHeight, minMarginBefore, minMarginAfter, minLogicalTopPos);
   2670 
   2671         if (logicalHeightResult < minLogicalHeight) {
   2672             logicalHeightResult = minLogicalHeight;
   2673             marginBeforeAlias = minMarginBefore;
   2674             marginAfterAlias = minMarginAfter;
   2675             setLogicalTop(minLogicalTopPos);
   2676         }
   2677     }
   2678 
   2679     // Set final height value.
   2680     setLogicalHeight(logicalHeightResult + bordersPlusPadding);
   2681 }
   2682 
   2683 static void computeLogicalTopPositionedOffset(int& logicalTopPos, const RenderBox* child, int logicalHeightValue, const RenderBoxModelObject* containerBlock, int containerLogicalHeight)
   2684 {
   2685     // Deal with differing writing modes here.  Our offset needs to be in the containing block's coordinate space. If the containing block is flipped
   2686     // 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.
   2687     if ((child->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() != containerBlock->isHorizontalWritingMode())
   2688         || (child->style()->isFlippedBlocksWritingMode() != containerBlock->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode()))
   2689         logicalTopPos = containerLogicalHeight - logicalHeightValue - logicalTopPos;
   2690 
   2691     // Our offset is from the logical bottom edge in a flipped environment, e.g., right for vertical-rl and bottom for horizontal-bt.
   2692     if (containerBlock->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode()) {
   2693         if (child->isHorizontalWritingMode())
   2694             logicalTopPos += containerBlock->borderBottom();
   2695         else
   2696             logicalTopPos += containerBlock->borderRight();
   2697     } else {
   2698         if (child->isHorizontalWritingMode())
   2699             logicalTopPos += containerBlock->borderTop();
   2700         else
   2701             logicalTopPos += containerBlock->borderLeft();
   2702     }
   2703 }
   2704 
   2705 void RenderBox::computePositionedLogicalHeightUsing(Length logicalHeightLength, const RenderBoxModelObject* containerBlock,
   2706                                                     int containerLogicalHeight, int bordersPlusPadding,
   2707                                                     Length logicalTop, Length logicalBottom, Length marginBefore, Length marginAfter,
   2708                                                     int& logicalHeightValue, int& marginBeforeValue, int& marginAfterValue, int& logicalTopPos)
   2709 {
   2710     // 'top' and 'bottom' cannot both be 'auto' because 'top would of been
   2711     // converted to the static position in computePositionedLogicalHeight()
   2712     ASSERT(!(logicalTop.isAuto() && logicalBottom.isAuto()));
   2713 
   2714     int contentLogicalHeight = logicalHeight() - bordersPlusPadding;
   2715 
   2716     int logicalTopValue = 0;
   2717 
   2718     bool logicalHeightIsAuto = logicalHeightLength.isAuto();
   2719     bool logicalTopIsAuto = logicalTop.isAuto();
   2720     bool logicalBottomIsAuto = logicalBottom.isAuto();
   2721 
   2722     // Height is never unsolved for tables.
   2723     if (isTable()) {
   2724         logicalHeightLength.setValue(Fixed, contentLogicalHeight);
   2725         logicalHeightIsAuto = false;
   2726     }
   2727 
   2728     if (!logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsAuto) {
   2729         /*-----------------------------------------------------------------------*\
   2730          * If none of the three are 'auto': If both 'margin-top' and 'margin-
   2731          * bottom' are 'auto', solve the equation under the extra constraint that
   2732          * the two margins get equal values. If one of 'margin-top' or 'margin-
   2733          * bottom' is 'auto', solve the equation for that value. If the values
   2734          * are over-constrained, ignore the value for 'bottom' and solve for that
   2735          * value.
   2736         \*-----------------------------------------------------------------------*/
   2737         // NOTE:  It is not necessary to solve for 'bottom' in the over constrained
   2738         // case because the value is not used for any further calculations.
   2739 
   2740         logicalHeightValue = computeContentBoxLogicalHeight(logicalHeightLength.calcValue(containerLogicalHeight));
   2741         logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   2742 
   2743         const int availableSpace = containerLogicalHeight - (logicalTopValue + logicalHeightValue + logicalBottom.calcValue(containerLogicalHeight) + bordersPlusPadding);
   2744 
   2745         // Margins are now the only unknown
   2746         if (marginBefore.isAuto() && marginAfter.isAuto()) {
   2747             // Both margins auto, solve for equality
   2748             // NOTE: This may result in negative values.
   2749             marginBeforeValue = availableSpace / 2; // split the difference
   2750             marginAfterValue = availableSpace - marginBeforeValue; // account for odd valued differences
   2751         } else if (marginBefore.isAuto()) {
   2752             // Solve for top margin
   2753             marginAfterValue = marginAfter.calcValue(containerLogicalHeight);
   2754             marginBeforeValue = availableSpace - marginAfterValue;
   2755         } else if (marginAfter.isAuto()) {
   2756             // Solve for bottom margin
   2757             marginBeforeValue = marginBefore.calcValue(containerLogicalHeight);
   2758             marginAfterValue = availableSpace - marginBeforeValue;
   2759         } else {
   2760             // Over-constrained, (no need solve for bottom)
   2761             marginBeforeValue = marginBefore.calcValue(containerLogicalHeight);
   2762             marginAfterValue = marginAfter.calcValue(containerLogicalHeight);
   2763         }
   2764     } else {
   2765         /*--------------------------------------------------------------------*\
   2766          * Otherwise, set 'auto' values for 'margin-top' and 'margin-bottom'
   2767          * to 0, and pick the one of the following six rules that applies.
   2768          *
   2769          * 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then
   2770          *    the height is based on the content, and solve for 'top'.
   2771          *
   2772          *              OMIT RULE 2 AS IT SHOULD NEVER BE HIT
   2773          * ------------------------------------------------------------------
   2774          * 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then
   2775          *    set 'top' to the static position, and solve for 'bottom'.
   2776          * ------------------------------------------------------------------
   2777          *
   2778          * 3. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then
   2779          *    the height is based on the content, and solve for 'bottom'.
   2780          * 4. 'top' is 'auto', 'height' and 'bottom' are not 'auto', and
   2781          *    solve for 'top'.
   2782          * 5. 'height' is 'auto', 'top' and 'bottom' are not 'auto', and
   2783          *    solve for 'height'.
   2784          * 6. 'bottom' is 'auto', 'top' and 'height' are not 'auto', and
   2785          *    solve for 'bottom'.
   2786         \*--------------------------------------------------------------------*/
   2787         // NOTE: For rules 3 and 6 it is not necessary to solve for 'bottom'
   2788         // because the value is not used for any further calculations.
   2789 
   2790         // Calculate margins, 'auto' margins are ignored.
   2791         marginBeforeValue = marginBefore.calcMinValue(containerLogicalHeight);
   2792         marginAfterValue = marginAfter.calcMinValue(containerLogicalHeight);
   2793 
   2794         const int availableSpace = containerLogicalHeight - (marginBeforeValue + marginAfterValue + bordersPlusPadding);
   2795 
   2796         // Use rule/case that applies.
   2797         if (logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) {
   2798             // RULE 1: (height is content based, solve of top)
   2799             logicalHeightValue = contentLogicalHeight;
   2800             logicalTopValue = availableSpace - (logicalHeightValue + logicalBottom.calcValue(containerLogicalHeight));
   2801         } else if (!logicalTopIsAuto && logicalHeightIsAuto && logicalBottomIsAuto) {
   2802             // RULE 3: (height is content based, no need solve of bottom)
   2803             logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   2804             logicalHeightValue = contentLogicalHeight;
   2805         } else if (logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsAuto) {
   2806             // RULE 4: (solve of top)
   2807             logicalHeightValue = computeContentBoxLogicalHeight(logicalHeightLength.calcValue(containerLogicalHeight));
   2808             logicalTopValue = availableSpace - (logicalHeightValue + logicalBottom.calcValue(containerLogicalHeight));
   2809         } else if (!logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) {
   2810             // RULE 5: (solve of height)
   2811             logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   2812             logicalHeightValue = max(0, availableSpace - (logicalTopValue + logicalBottom.calcValue(containerLogicalHeight)));
   2813         } else if (!logicalTopIsAuto && !logicalHeightIsAuto && logicalBottomIsAuto) {
   2814             // RULE 6: (no need solve of bottom)
   2815             logicalHeightValue = computeContentBoxLogicalHeight(logicalHeightLength.calcValue(containerLogicalHeight));
   2816             logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   2817         }
   2818     }
   2819 
   2820     // Use computed values to calculate the vertical position.
   2821     logicalTopPos = logicalTopValue + marginBeforeValue;
   2822     computeLogicalTopPositionedOffset(logicalTopPos, this, logicalHeightValue, containerBlock, containerLogicalHeight);
   2823 }
   2824 
   2825 void RenderBox::computePositionedLogicalWidthReplaced()
   2826 {
   2827     // The following is based off of the W3C Working Draft from April 11, 2006 of
   2828     // CSS 2.1: Section 10.3.8 "Absolutely positioned, replaced elements"
   2829     // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-width>
   2830     // (block-style-comments in this function correspond to text from the spec and
   2831     // the numbers correspond to numbers in spec)
   2832 
   2833     // We don't use containingBlock(), since we may be positioned by an enclosing
   2834     // relative positioned inline.
   2835     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
   2836 
   2837     const int containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock);
   2838 
   2839     // To match WinIE, in quirks mode use the parent's 'direction' property
   2840     // instead of the the container block's.
   2841     TextDirection containerDirection = (document()->inQuirksMode()) ? parent()->style()->direction() : containerBlock->style()->direction();
   2842 
   2843     // Variables to solve.
   2844     bool isHorizontal = isHorizontalWritingMode();
   2845     Length logicalLeft = style()->logicalLeft();
   2846     Length logicalRight = style()->logicalRight();
   2847     Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->marginTop();
   2848     Length marginLogicalRight = isHorizontal ? style()->marginRight() : style()->marginBottom();
   2849     int& marginLogicalLeftAlias = isHorizontal ? m_marginLeft : m_marginTop;
   2850     int& marginLogicalRightAlias = isHorizontal ? m_marginRight : m_marginBottom;
   2851 
   2852     /*-----------------------------------------------------------------------*\
   2853      * 1. The used value of 'width' is determined as for inline replaced
   2854      *    elements.
   2855     \*-----------------------------------------------------------------------*/
   2856     // NOTE: This value of width is FINAL in that the min/max width calculations
   2857     // are dealt with in computeReplacedWidth().  This means that the steps to produce
   2858     // correct max/min in the non-replaced version, are not necessary.
   2859     setLogicalWidth(computeReplacedLogicalWidth() + borderAndPaddingLogicalWidth());
   2860     const int availableSpace = containerLogicalWidth - logicalWidth();
   2861 
   2862     /*-----------------------------------------------------------------------*\
   2863      * 2. If both 'left' and 'right' have the value 'auto', then if 'direction'
   2864      *    of the containing block is 'ltr', set 'left' to the static position;
   2865      *    else if 'direction' is 'rtl', set 'right' to the static position.
   2866     \*-----------------------------------------------------------------------*/
   2867     // see FIXME 2
   2868     computeInlineStaticDistance(logicalLeft, logicalRight, this, containerBlock, containerLogicalWidth, containerDirection);
   2869 
   2870     /*-----------------------------------------------------------------------*\
   2871      * 3. If 'left' or 'right' are 'auto', replace any 'auto' on 'margin-left'
   2872      *    or 'margin-right' with '0'.
   2873     \*-----------------------------------------------------------------------*/
   2874     if (logicalLeft.isAuto() || logicalRight.isAuto()) {
   2875         if (marginLogicalLeft.isAuto())
   2876             marginLogicalLeft.setValue(Fixed, 0);
   2877         if (marginLogicalRight.isAuto())
   2878             marginLogicalRight.setValue(Fixed, 0);
   2879     }
   2880 
   2881     /*-----------------------------------------------------------------------*\
   2882      * 4. If at this point both 'margin-left' and 'margin-right' are still
   2883      *    'auto', solve the equation under the extra constraint that the two
   2884      *    margins must get equal values, unless this would make them negative,
   2885      *    in which case when the direction of the containing block is 'ltr'
   2886      *    ('rtl'), set 'margin-left' ('margin-right') to zero and solve for
   2887      *    'margin-right' ('margin-left').
   2888     \*-----------------------------------------------------------------------*/
   2889     int logicalLeftValue = 0;
   2890     int logicalRightValue = 0;
   2891 
   2892     if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) {
   2893         // 'left' and 'right' cannot be 'auto' due to step 3
   2894         ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto()));
   2895 
   2896         logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2897         logicalRightValue = logicalRight.calcValue(containerLogicalWidth);
   2898 
   2899         int difference = availableSpace - (logicalLeftValue + logicalRightValue);
   2900         if (difference > 0) {
   2901             marginLogicalLeftAlias = difference / 2; // split the difference
   2902             marginLogicalRightAlias = difference - marginLogicalLeftAlias; // account for odd valued differences
   2903         } else {
   2904             // see FIXME 1
   2905             if (containerDirection == LTR) {
   2906                 marginLogicalLeftAlias = 0;
   2907                 marginLogicalRightAlias = difference; // will be negative
   2908             } else {
   2909                 marginLogicalLeftAlias = difference; // will be negative
   2910                 marginLogicalRightAlias = 0;
   2911             }
   2912         }
   2913 
   2914     /*-----------------------------------------------------------------------*\
   2915      * 5. If at this point there is an 'auto' left, solve the equation for
   2916      *    that value.
   2917     \*-----------------------------------------------------------------------*/
   2918     } else if (logicalLeft.isAuto()) {
   2919         marginLogicalLeftAlias = marginLogicalLeft.calcValue(containerLogicalWidth);
   2920         marginLogicalRightAlias = marginLogicalRight.calcValue(containerLogicalWidth);
   2921         logicalRightValue = logicalRight.calcValue(containerLogicalWidth);
   2922 
   2923         // Solve for 'left'
   2924         logicalLeftValue = availableSpace - (logicalRightValue + marginLogicalLeftAlias + marginLogicalRightAlias);
   2925     } else if (logicalRight.isAuto()) {
   2926         marginLogicalLeftAlias = marginLogicalLeft.calcValue(containerLogicalWidth);
   2927         marginLogicalRightAlias = marginLogicalRight.calcValue(containerLogicalWidth);
   2928         logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2929 
   2930         // Solve for 'right'
   2931         logicalRightValue = availableSpace - (logicalLeftValue + marginLogicalLeftAlias + marginLogicalRightAlias);
   2932     } else if (marginLogicalLeft.isAuto()) {
   2933         marginLogicalRightAlias = marginLogicalRight.calcValue(containerLogicalWidth);
   2934         logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2935         logicalRightValue = logicalRight.calcValue(containerLogicalWidth);
   2936 
   2937         // Solve for 'margin-left'
   2938         marginLogicalLeftAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalRightAlias);
   2939     } else if (marginLogicalRight.isAuto()) {
   2940         marginLogicalLeftAlias = marginLogicalLeft.calcValue(containerLogicalWidth);
   2941         logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2942         logicalRightValue = logicalRight.calcValue(containerLogicalWidth);
   2943 
   2944         // Solve for 'margin-right'
   2945         marginLogicalRightAlias = availableSpace - (logicalLeftValue + logicalRightValue + marginLogicalLeftAlias);
   2946     } else {
   2947         // Nothing is 'auto', just calculate the values.
   2948         marginLogicalLeftAlias = marginLogicalLeft.calcValue(containerLogicalWidth);
   2949         marginLogicalRightAlias = marginLogicalRight.calcValue(containerLogicalWidth);
   2950         logicalRightValue = logicalRight.calcValue(containerLogicalWidth);
   2951         logicalLeftValue = logicalLeft.calcValue(containerLogicalWidth);
   2952     }
   2953 
   2954     /*-----------------------------------------------------------------------*\
   2955      * 6. If at this point the values are over-constrained, ignore the value
   2956      *    for either 'left' (in case the 'direction' property of the
   2957      *    containing block is 'rtl') or 'right' (in case 'direction' is
   2958      *    'ltr') and solve for that value.
   2959     \*-----------------------------------------------------------------------*/
   2960     // NOTE:  It is not necessary to solve for 'right' when the direction is
   2961     // LTR because the value is not used.
   2962     int totalLogicalWidth = logicalWidth() + logicalLeftValue + logicalRightValue +  marginLogicalLeftAlias + marginLogicalRightAlias;
   2963     if (totalLogicalWidth > containerLogicalWidth && (containerDirection == RTL))
   2964         logicalLeftValue = containerLogicalWidth - (totalLogicalWidth - logicalLeftValue);
   2965 
   2966     // FIXME: Deal with differing writing modes here.  Our offset needs to be in the containing block's coordinate space, so that
   2967     // can make the result here rather complicated to compute.
   2968 
   2969     // Use computed values to calculate the horizontal position.
   2970 
   2971     // FIXME: This hack is needed to calculate the logical left position for a 'rtl' relatively
   2972     // positioned, inline containing block because right now, it is using the logical left position
   2973     // of the first line box when really it should use the last line box.  When
   2974     // this is fixed elsewhere, this block should be removed.
   2975     if (containerBlock->isRenderInline() && !containerBlock->style()->isLeftToRightDirection()) {
   2976         const RenderInline* flow = toRenderInline(containerBlock);
   2977         InlineFlowBox* firstLine = flow->firstLineBox();
   2978         InlineFlowBox* lastLine = flow->lastLineBox();
   2979         if (firstLine && lastLine && firstLine != lastLine) {
   2980             setLogicalLeft(logicalLeftValue + marginLogicalLeftAlias + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logicalLeft()));
   2981             return;
   2982         }
   2983     }
   2984 
   2985     int logicalLeftPos = logicalLeftValue + marginLogicalLeftAlias;
   2986     computeLogicalLeftPositionedOffset(logicalLeftPos, this, logicalWidth(), containerBlock, containerLogicalWidth);
   2987     setLogicalLeft(logicalLeftPos);
   2988 }
   2989 
   2990 void RenderBox::computePositionedLogicalHeightReplaced()
   2991 {
   2992     // The following is based off of the W3C Working Draft from April 11, 2006 of
   2993     // CSS 2.1: Section 10.6.5 "Absolutely positioned, replaced elements"
   2994     // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-height>
   2995     // (block-style-comments in this function correspond to text from the spec and
   2996     // the numbers correspond to numbers in spec)
   2997 
   2998     // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
   2999     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
   3000 
   3001     const int containerLogicalHeight = containingBlockLogicalHeightForPositioned(containerBlock);
   3002 
   3003     // Variables to solve.
   3004     bool isHorizontal = isHorizontalWritingMode();
   3005     bool isFlipped = style()->isFlippedBlocksWritingMode();
   3006     Length marginBefore = style()->marginBefore();
   3007     Length marginAfter = style()->marginAfter();
   3008     int& marginBeforeAlias = isHorizontal ? (isFlipped ? m_marginBottom : m_marginTop) : (isFlipped ? m_marginRight: m_marginLeft);
   3009     int& marginAfterAlias = isHorizontal ? (isFlipped ? m_marginTop : m_marginBottom) : (isFlipped ? m_marginLeft: m_marginRight);
   3010 
   3011     Length logicalTop = style()->logicalTop();
   3012     Length logicalBottom = style()->logicalBottom();
   3013 
   3014     /*-----------------------------------------------------------------------*\
   3015      * 1. The used value of 'height' is determined as for inline replaced
   3016      *    elements.
   3017     \*-----------------------------------------------------------------------*/
   3018     // NOTE: This value of height is FINAL in that the min/max height calculations
   3019     // are dealt with in computeReplacedHeight().  This means that the steps to produce
   3020     // correct max/min in the non-replaced version, are not necessary.
   3021     setLogicalHeight(computeReplacedLogicalHeight() + borderAndPaddingLogicalHeight());
   3022     const int availableSpace = containerLogicalHeight - logicalHeight();
   3023 
   3024     /*-----------------------------------------------------------------------*\
   3025      * 2. If both 'top' and 'bottom' have the value 'auto', replace 'top'
   3026      *    with the element's static position.
   3027     \*-----------------------------------------------------------------------*/
   3028     // see FIXME 2
   3029     computeBlockStaticDistance(logicalTop, logicalBottom, this, containerBlock);
   3030 
   3031     /*-----------------------------------------------------------------------*\
   3032      * 3. If 'bottom' is 'auto', replace any 'auto' on 'margin-top' or
   3033      *    'margin-bottom' with '0'.
   3034     \*-----------------------------------------------------------------------*/
   3035     // FIXME: The spec. says that this step should only be taken when bottom is
   3036     // auto, but if only top is auto, this makes step 4 impossible.
   3037     if (logicalTop.isAuto() || logicalBottom.isAuto()) {
   3038         if (marginBefore.isAuto())
   3039             marginBefore.setValue(Fixed, 0);
   3040         if (marginAfter.isAuto())
   3041             marginAfter.setValue(Fixed, 0);
   3042     }
   3043 
   3044     /*-----------------------------------------------------------------------*\
   3045      * 4. If at this point both 'margin-top' and 'margin-bottom' are still
   3046      *    'auto', solve the equation under the extra constraint that the two
   3047      *    margins must get equal values.
   3048     \*-----------------------------------------------------------------------*/
   3049     int logicalTopValue = 0;
   3050     int logicalBottomValue = 0;
   3051 
   3052     if (marginBefore.isAuto() && marginAfter.isAuto()) {
   3053         // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combined.
   3054         ASSERT(!(logicalTop.isAuto() || logicalBottom.isAuto()));
   3055 
   3056         logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   3057         logicalBottomValue = logicalBottom.calcValue(containerLogicalHeight);
   3058 
   3059         int difference = availableSpace - (logicalTopValue + logicalBottomValue);
   3060         // NOTE: This may result in negative values.
   3061         marginBeforeAlias =  difference / 2; // split the difference
   3062         marginAfterAlias = difference - marginBeforeAlias; // account for odd valued differences
   3063 
   3064     /*-----------------------------------------------------------------------*\
   3065      * 5. If at this point there is only one 'auto' left, solve the equation
   3066      *    for that value.
   3067     \*-----------------------------------------------------------------------*/
   3068     } else if (logicalTop.isAuto()) {
   3069         marginBeforeAlias = marginBefore.calcValue(containerLogicalHeight);
   3070         marginAfterAlias = marginAfter.calcValue(containerLogicalHeight);
   3071         logicalBottomValue = logicalBottom.calcValue(containerLogicalHeight);
   3072 
   3073         // Solve for 'top'
   3074         logicalTopValue = availableSpace - (logicalBottomValue + marginBeforeAlias + marginAfterAlias);
   3075     } else if (logicalBottom.isAuto()) {
   3076         marginBeforeAlias = marginBefore.calcValue(containerLogicalHeight);
   3077         marginAfterAlias = marginAfter.calcValue(containerLogicalHeight);
   3078         logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   3079 
   3080         // Solve for 'bottom'
   3081         // NOTE: It is not necessary to solve for 'bottom' because we don't ever
   3082         // use the value.
   3083     } else if (marginBefore.isAuto()) {
   3084         marginAfterAlias = marginAfter.calcValue(containerLogicalHeight);
   3085         logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   3086         logicalBottomValue = logicalBottom.calcValue(containerLogicalHeight);
   3087 
   3088         // Solve for 'margin-top'
   3089         marginBeforeAlias = availableSpace - (logicalTopValue + logicalBottomValue + marginAfterAlias);
   3090     } else if (marginAfter.isAuto()) {
   3091         marginBeforeAlias = marginBefore.calcValue(containerLogicalHeight);
   3092         logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   3093         logicalBottomValue = logicalBottom.calcValue(containerLogicalHeight);
   3094 
   3095         // Solve for 'margin-bottom'
   3096         marginAfterAlias = availableSpace - (logicalTopValue + logicalBottomValue + marginBeforeAlias);
   3097     } else {
   3098         // Nothing is 'auto', just calculate the values.
   3099         marginBeforeAlias = marginBefore.calcValue(containerLogicalHeight);
   3100         marginAfterAlias = marginAfter.calcValue(containerLogicalHeight);
   3101         logicalTopValue = logicalTop.calcValue(containerLogicalHeight);
   3102         // NOTE: It is not necessary to solve for 'bottom' because we don't ever
   3103         // use the value.
   3104      }
   3105 
   3106     /*-----------------------------------------------------------------------*\
   3107      * 6. If at this point the values are over-constrained, ignore the value
   3108      *    for 'bottom' and solve for that value.
   3109     \*-----------------------------------------------------------------------*/
   3110     // NOTE: It is not necessary to do this step because we don't end up using
   3111     // the value of 'bottom' regardless of whether the values are over-constrained
   3112     // or not.
   3113 
   3114     // Use computed values to calculate the vertical position.
   3115     int logicalTopPos = logicalTopValue + marginBeforeAlias;
   3116     computeLogicalTopPositionedOffset(logicalTopPos, this, logicalHeight(), containerBlock, containerLogicalHeight);
   3117     setLogicalTop(logicalTopPos);
   3118 }
   3119 
   3120 IntRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, int* extraWidthToEndOfLine)
   3121 {
   3122     // VisiblePositions at offsets inside containers either a) refer to the positions before/after
   3123     // those containers (tables and select elements) or b) refer to the position inside an empty block.
   3124     // They never refer to children.
   3125     // FIXME: Paint the carets inside empty blocks differently than the carets before/after elements.
   3126 
   3127     // FIXME: What about border and padding?
   3128     IntRect rect(x(), y(), caretWidth, height());
   3129     bool ltr = box ? box->isLeftToRightDirection() : style()->isLeftToRightDirection();
   3130 
   3131     if ((!caretOffset) ^ ltr)
   3132         rect.move(IntSize(width() - caretWidth, 0));
   3133 
   3134     if (box) {
   3135         RootInlineBox* rootBox = box->root();
   3136         int top = rootBox->lineTop();
   3137         rect.setY(top);
   3138         rect.setHeight(rootBox->lineBottom() - top);
   3139     }
   3140 
   3141     // If height of box is smaller than font height, use the latter one,
   3142     // otherwise the caret might become invisible.
   3143     //
   3144     // Also, if the box is not a replaced element, always use the font height.
   3145     // This prevents the "big caret" bug described in:
   3146     // <rdar://problem/3777804> Deleting all content in a document can result in giant tall-as-window insertion point
   3147     //
   3148     // FIXME: ignoring :first-line, missing good reason to take care of
   3149     int fontHeight = style()->fontMetrics().height();
   3150     if (fontHeight > rect.height() || (!isReplaced() && !isTable()))
   3151         rect.setHeight(fontHeight);
   3152 
   3153     if (extraWidthToEndOfLine)
   3154         *extraWidthToEndOfLine = x() + width() - rect.maxX();
   3155 
   3156     // Move to local coords
   3157     rect.move(-x(), -y());
   3158     return rect;
   3159 }
   3160 
   3161 VisiblePosition RenderBox::positionForPoint(const IntPoint& point)
   3162 {
   3163     // no children...return this render object's element, if there is one, and offset 0
   3164     if (!firstChild())
   3165         return createVisiblePosition(node() ? firstPositionInOrBeforeNode(node()) : Position(0, 0));
   3166 
   3167     int xPos = point.x();
   3168     int yPos = point.y();
   3169 
   3170     if (isTable() && node()) {
   3171         int right = contentWidth() + borderAndPaddingWidth();
   3172         int bottom = contentHeight() + borderAndPaddingHeight();
   3173 
   3174         if (xPos < 0 || xPos > right || yPos < 0 || yPos > bottom) {
   3175             if (xPos <= right / 2)
   3176                 return createVisiblePosition(firstPositionInOrBeforeNode(node()));
   3177             return createVisiblePosition(lastPositionInOrAfterNode(node()));
   3178         }
   3179     }
   3180 
   3181     // Pass off to the closest child.
   3182     int minDist = INT_MAX;
   3183     RenderBox* closestRenderer = 0;
   3184     int newX = xPos;
   3185     int newY = yPos;
   3186     if (isTableRow()) {
   3187         newX += x();
   3188         newY += y();
   3189     }
   3190     for (RenderObject* renderObject = firstChild(); renderObject; renderObject = renderObject->nextSibling()) {
   3191         if ((!renderObject->firstChild() && !renderObject->isInline() && !renderObject->isBlockFlow() )
   3192             || renderObject->style()->visibility() != VISIBLE)
   3193             continue;
   3194 
   3195         if (!renderObject->isBox())
   3196             continue;
   3197 
   3198         RenderBox* renderer = toRenderBox(renderObject);
   3199 
   3200         int top = renderer->borderTop() + renderer->paddingTop() + (isTableRow() ? 0 : renderer->y());
   3201         int bottom = top + renderer->contentHeight();
   3202         int left = renderer->borderLeft() + renderer->paddingLeft() + (isTableRow() ? 0 : renderer->x());
   3203         int right = left + renderer->contentWidth();
   3204 
   3205         if (xPos <= right && xPos >= left && yPos <= top && yPos >= bottom) {
   3206             if (renderer->isTableRow())
   3207                 return renderer->positionForCoordinates(xPos + newX - renderer->x(), yPos + newY - renderer->y());
   3208             return renderer->positionForCoordinates(xPos - renderer->x(), yPos - renderer->y());
   3209         }
   3210 
   3211         // Find the distance from (x, y) to the box.  Split the space around the box into 8 pieces
   3212         // and use a different compare depending on which piece (x, y) is in.
   3213         IntPoint cmp;
   3214         if (xPos > right) {
   3215             if (yPos < top)
   3216                 cmp = IntPoint(right, top);
   3217             else if (yPos > bottom)
   3218                 cmp = IntPoint(right, bottom);
   3219             else
   3220                 cmp = IntPoint(right, yPos);
   3221         } else if (xPos < left) {
   3222             if (yPos < top)
   3223                 cmp = IntPoint(left, top);
   3224             else if (yPos > bottom)
   3225                 cmp = IntPoint(left, bottom);
   3226             else
   3227                 cmp = IntPoint(left, yPos);
   3228         } else {
   3229             if (yPos < top)
   3230                 cmp = IntPoint(xPos, top);
   3231             else
   3232                 cmp = IntPoint(xPos, bottom);
   3233         }
   3234 
   3235         int x1minusx2 = cmp.x() - xPos;
   3236         int y1minusy2 = cmp.y() - yPos;
   3237 
   3238         int dist = x1minusx2 * x1minusx2 + y1minusy2 * y1minusy2;
   3239         if (dist < minDist) {
   3240             closestRenderer = renderer;
   3241             minDist = dist;
   3242         }
   3243     }
   3244 
   3245     if (closestRenderer)
   3246         return closestRenderer->positionForCoordinates(newX - closestRenderer->x(), newY - closestRenderer->y());
   3247 
   3248     return createVisiblePosition(firstPositionInOrBeforeNode(node()));
   3249 }
   3250 
   3251 bool RenderBox::shrinkToAvoidFloats() const
   3252 {
   3253     // Floating objects don't shrink.  Objects that don't avoid floats don't shrink.  Marquees don't shrink.
   3254     if ((isInline() && !isHTMLMarquee()) || !avoidsFloats() || isFloating())
   3255         return false;
   3256 
   3257     // All auto-width objects that avoid floats should always use lineWidth.
   3258     return style()->width().isAuto();
   3259 }
   3260 
   3261 bool RenderBox::avoidsFloats() const
   3262 {
   3263     return isReplaced() || hasOverflowClip() || isHR() || isLegend() || isWritingModeRoot();
   3264 }
   3265 
   3266 void RenderBox::addShadowOverflow()
   3267 {
   3268     int shadowLeft;
   3269     int shadowRight;
   3270     int shadowTop;
   3271     int shadowBottom;
   3272     style()->getBoxShadowExtent(shadowTop, shadowRight, shadowBottom, shadowLeft);
   3273     IntRect borderBox = borderBoxRect();
   3274     int overflowLeft = borderBox.x() + shadowLeft;
   3275     int overflowRight = borderBox.maxX() + shadowRight;
   3276     int overflowTop = borderBox.y() + shadowTop;
   3277     int overflowBottom = borderBox.maxY() + shadowBottom;
   3278     addVisualOverflow(IntRect(overflowLeft, overflowTop, overflowRight - overflowLeft, overflowBottom - overflowTop));
   3279 }
   3280 
   3281 void RenderBox::addOverflowFromChild(RenderBox* child, const IntSize& delta)
   3282 {
   3283     // Only propagate layout overflow from the child if the child isn't clipping its overflow.  If it is, then
   3284     // its overflow is internal to it, and we don't care about it.  layoutOverflowRectForPropagation takes care of this
   3285     // and just propagates the border box rect instead.
   3286     IntRect childLayoutOverflowRect = child->layoutOverflowRectForPropagation(style());
   3287     childLayoutOverflowRect.move(delta);
   3288     addLayoutOverflow(childLayoutOverflowRect);
   3289 
   3290     // Add in visual overflow from the child.  Even if the child clips its overflow, it may still
   3291     // have visual overflow of its own set from box shadows or reflections.  It is unnecessary to propagate this
   3292     // overflow if we are clipping our own overflow.
   3293     if (child->hasSelfPaintingLayer() || hasOverflowClip())
   3294         return;
   3295     IntRect childVisualOverflowRect = child->visualOverflowRectForPropagation(style());
   3296     childVisualOverflowRect.move(delta);
   3297     addVisualOverflow(childVisualOverflowRect);
   3298 }
   3299 
   3300 void RenderBox::addLayoutOverflow(const IntRect& rect)
   3301 {
   3302     IntRect clientBox = clientBoxRect();
   3303     if (clientBox.contains(rect) || rect.isEmpty())
   3304         return;
   3305 
   3306     // For overflow clip objects, we don't want to propagate overflow into unreachable areas.
   3307     IntRect overflowRect(rect);
   3308     if (hasOverflowClip() || isRenderView()) {
   3309         // Overflow is in the block's coordinate space and thus is flipped for horizontal-bt and vertical-rl
   3310         // writing modes.  At this stage that is actually a simplification, since we can treat horizontal-tb/bt as the same
   3311         // and vertical-lr/rl as the same.
   3312         bool hasTopOverflow = !style()->isLeftToRightDirection() && !isHorizontalWritingMode();
   3313         bool hasLeftOverflow = !style()->isLeftToRightDirection() && isHorizontalWritingMode();
   3314 
   3315         if (!hasTopOverflow)
   3316             overflowRect.shiftYEdgeTo(max(overflowRect.y(), clientBox.y()));
   3317         else
   3318             overflowRect.shiftMaxYEdgeTo(min(overflowRect.maxY(), clientBox.maxY()));
   3319         if (!hasLeftOverflow)
   3320             overflowRect.shiftXEdgeTo(max(overflowRect.x(), clientBox.x()));
   3321         else
   3322             overflowRect.shiftMaxXEdgeTo(min(overflowRect.maxX(), clientBox.maxX()));
   3323 
   3324         // Now re-test with the adjusted rectangle and see if it has become unreachable or fully
   3325         // contained.
   3326         if (clientBox.contains(overflowRect) || overflowRect.isEmpty())
   3327             return;
   3328     }
   3329 
   3330     if (!m_overflow)
   3331         m_overflow.set(new RenderOverflow(clientBox, borderBoxRect()));
   3332 
   3333     m_overflow->addLayoutOverflow(overflowRect);
   3334 }
   3335 
   3336 void RenderBox::addVisualOverflow(const IntRect& rect)
   3337 {
   3338     IntRect borderBox = borderBoxRect();
   3339     if (borderBox.contains(rect) || rect.isEmpty())
   3340         return;
   3341 
   3342     if (!m_overflow)
   3343         m_overflow.set(new RenderOverflow(clientBoxRect(), borderBox));
   3344 
   3345     m_overflow->addVisualOverflow(rect);
   3346 }
   3347 
   3348 void RenderBox::clearLayoutOverflow()
   3349 {
   3350     if (!m_overflow)
   3351         return;
   3352 
   3353     if (visualOverflowRect() == borderBoxRect()) {
   3354         m_overflow.clear();
   3355         return;
   3356     }
   3357 
   3358     m_overflow->resetLayoutOverflow(borderBoxRect());
   3359 }
   3360 
   3361 int RenderBox::lineHeight(bool /*firstLine*/, LineDirectionMode direction, LinePositionMode /*linePositionMode*/) const
   3362 {
   3363     if (isReplaced())
   3364         return direction == HorizontalLine ? m_marginTop + height() + m_marginBottom : m_marginRight + width() + m_marginLeft;
   3365     return 0;
   3366 }
   3367 
   3368 int RenderBox::baselinePosition(FontBaseline baselineType, bool /*firstLine*/, LineDirectionMode direction, LinePositionMode /*linePositionMode*/) const
   3369 {
   3370     if (isReplaced()) {
   3371         int result = direction == HorizontalLine ? m_marginTop + height() + m_marginBottom : m_marginRight + width() + m_marginLeft;
   3372         if (baselineType == AlphabeticBaseline)
   3373             return result;
   3374         return result - result / 2;
   3375     }
   3376     return 0;
   3377 }
   3378 
   3379 
   3380 RenderLayer* RenderBox::enclosingFloatPaintingLayer() const
   3381 {
   3382     const RenderObject* curr = this;
   3383     while (curr) {
   3384         RenderLayer* layer = curr->hasLayer() && curr->isBox() ? toRenderBoxModelObject(curr)->layer() : 0;
   3385         if (layer && layer->isSelfPaintingLayer())
   3386             return layer;
   3387         curr = curr->parent();
   3388     }
   3389     return 0;
   3390 }
   3391 
   3392 IntRect RenderBox::logicalVisualOverflowRectForPropagation(RenderStyle* parentStyle) const
   3393 {
   3394     IntRect rect = visualOverflowRectForPropagation(parentStyle);
   3395     if (!parentStyle->isHorizontalWritingMode())
   3396         return rect.transposedRect();
   3397     return rect;
   3398 }
   3399 
   3400 IntRect RenderBox::visualOverflowRectForPropagation(RenderStyle* parentStyle) const
   3401 {
   3402     // If the writing modes of the child and parent match, then we don't have to
   3403     // do anything fancy. Just return the result.
   3404     IntRect rect = visualOverflowRect();
   3405     if (parentStyle->writingMode() == style()->writingMode())
   3406         return rect;
   3407 
   3408     // We are putting ourselves into our parent's coordinate space.  If there is a flipped block mismatch
   3409     // in a particular axis, then we have to flip the rect along that axis.
   3410     if (style()->writingMode() == RightToLeftWritingMode || parentStyle->writingMode() == RightToLeftWritingMode)
   3411         rect.setX(width() - rect.maxX());
   3412     else if (style()->writingMode() == BottomToTopWritingMode || parentStyle->writingMode() == BottomToTopWritingMode)
   3413         rect.setY(height() - rect.maxY());
   3414 
   3415     return rect;
   3416 }
   3417 
   3418 IntRect RenderBox::logicalLayoutOverflowRectForPropagation(RenderStyle* parentStyle) const
   3419 {
   3420     IntRect rect = layoutOverflowRectForPropagation(parentStyle);
   3421     if (!parentStyle->isHorizontalWritingMode())
   3422         return rect.transposedRect();
   3423     return rect;
   3424 }
   3425 
   3426 IntRect RenderBox::layoutOverflowRectForPropagation(RenderStyle* parentStyle) const
   3427 {
   3428     // Only propagate interior layout overflow if we don't clip it.
   3429     IntRect rect = borderBoxRect();
   3430     if (!hasOverflowClip())
   3431         rect.unite(layoutOverflowRect());
   3432 
   3433     bool hasTransform = hasLayer() && layer()->transform();
   3434     if (isRelPositioned() || hasTransform) {
   3435         // If we are relatively positioned or if we have a transform, then we have to convert
   3436         // this rectangle into physical coordinates, apply relative positioning and transforms
   3437         // to it, and then convert it back.
   3438         flipForWritingMode(rect);
   3439 
   3440         if (hasTransform)
   3441             rect = layer()->currentTransform().mapRect(rect);
   3442 
   3443         if (isRelPositioned())
   3444             rect.move(relativePositionOffsetX(), relativePositionOffsetY());
   3445 
   3446         // Now we need to flip back.
   3447         flipForWritingMode(rect);
   3448     }
   3449 
   3450     // If the writing modes of the child and parent match, then we don't have to
   3451     // do anything fancy. Just return the result.
   3452     if (parentStyle->writingMode() == style()->writingMode())
   3453         return rect;
   3454 
   3455     // We are putting ourselves into our parent's coordinate space.  If there is a flipped block mismatch
   3456     // in a particular axis, then we have to flip the rect along that axis.
   3457     if (style()->writingMode() == RightToLeftWritingMode || parentStyle->writingMode() == RightToLeftWritingMode)
   3458         rect.setX(width() - rect.maxX());
   3459     else if (style()->writingMode() == BottomToTopWritingMode || parentStyle->writingMode() == BottomToTopWritingMode)
   3460         rect.setY(height() - rect.maxY());
   3461 
   3462     return rect;
   3463 }
   3464 
   3465 IntPoint RenderBox::flipForWritingMode(const RenderBox* child, const IntPoint& point, FlippingAdjustment adjustment) const
   3466 {
   3467     if (!style()->isFlippedBlocksWritingMode())
   3468         return point;
   3469 
   3470     // The child is going to add in its x() and y(), so we have to make sure it ends up in
   3471     // the right place.
   3472     if (isHorizontalWritingMode())
   3473         return IntPoint(point.x(), point.y() + height() - child->height() - child->y() - (adjustment == ParentToChildFlippingAdjustment ? child->y() : 0));
   3474     return IntPoint(point.x() + width() - child->width() - child->x() - (adjustment == ParentToChildFlippingAdjustment ? child->x() : 0), point.y());
   3475 }
   3476 
   3477 void RenderBox::flipForWritingMode(IntRect& rect) const
   3478 {
   3479     if (!style()->isFlippedBlocksWritingMode())
   3480         return;
   3481 
   3482     if (isHorizontalWritingMode())
   3483         rect.setY(height() - rect.maxY());
   3484     else
   3485         rect.setX(width() - rect.maxX());
   3486 }
   3487 
   3488 int RenderBox::flipForWritingMode(int position) const
   3489 {
   3490     if (!style()->isFlippedBlocksWritingMode())
   3491         return position;
   3492     return logicalHeight() - position;
   3493 }
   3494 
   3495 IntPoint RenderBox::flipForWritingMode(const IntPoint& position) const
   3496 {
   3497     if (!style()->isFlippedBlocksWritingMode())
   3498         return position;
   3499     return isHorizontalWritingMode() ? IntPoint(position.x(), height() - position.y()) : IntPoint(width() - position.x(), position.y());
   3500 }
   3501 
   3502 IntPoint RenderBox::flipForWritingModeIncludingColumns(const IntPoint& point) const
   3503 {
   3504     if (!hasColumns() || !style()->isFlippedBlocksWritingMode())
   3505         return flipForWritingMode(point);
   3506     return toRenderBlock(this)->flipForWritingModeIncludingColumns(point);
   3507 }
   3508 
   3509 IntSize RenderBox::flipForWritingMode(const IntSize& offset) const
   3510 {
   3511     if (!style()->isFlippedBlocksWritingMode())
   3512         return offset;
   3513     return isHorizontalWritingMode() ? IntSize(offset.width(), height() - offset.height()) : IntSize(width() - offset.width(), offset.height());
   3514 }
   3515 
   3516 FloatPoint RenderBox::flipForWritingMode(const FloatPoint& position) const
   3517 {
   3518     if (!style()->isFlippedBlocksWritingMode())
   3519         return position;
   3520     return isHorizontalWritingMode() ? FloatPoint(position.x(), height() - position.y()) : FloatPoint(width() - position.x(), position.y());
   3521 }
   3522 
   3523 void RenderBox::flipForWritingMode(FloatRect& rect) const
   3524 {
   3525     if (!style()->isFlippedBlocksWritingMode())
   3526         return;
   3527 
   3528     if (isHorizontalWritingMode())
   3529         rect.setY(height() - rect.maxY());
   3530     else
   3531         rect.setX(width() - rect.maxX());
   3532 }
   3533 
   3534 IntSize RenderBox::locationOffsetIncludingFlipping() const
   3535 {
   3536     RenderBlock* containerBlock = containingBlock();
   3537     if (!containerBlock || containerBlock == this)
   3538         return locationOffset();
   3539 
   3540     IntRect rect(frameRect());
   3541     containerBlock->flipForWritingMode(rect); // FIXME: This is wrong if we are an absolutely positioned object enclosed by a relative-positioned inline.
   3542     return IntSize(rect.x(), rect.y());
   3543 }
   3544 
   3545 } // namespace WebCore
   3546