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 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 "htmlediting.h"
     35 #include "HTMLElement.h"
     36 #include "HTMLNames.h"
     37 #include "ImageBuffer.h"
     38 #include "FloatQuad.h"
     39 #include "Frame.h"
     40 #include "Page.h"
     41 #include "RenderArena.h"
     42 #include "RenderFlexibleBox.h"
     43 #include "RenderInline.h"
     44 #include "RenderLayer.h"
     45 #include "RenderTableCell.h"
     46 #include "RenderTheme.h"
     47 #ifdef ANDROID_LAYOUT
     48 #include "Settings.h"
     49 #endif
     50 #include "RenderView.h"
     51 #include "TransformState.h"
     52 #include <algorithm>
     53 #include <math.h>
     54 
     55 #if ENABLE(WML)
     56 #include "WMLNames.h"
     57 #endif
     58 
     59 using namespace std;
     60 
     61 namespace WebCore {
     62 
     63 using namespace HTMLNames;
     64 
     65 // Used by flexible boxes when flexing this element.
     66 typedef WTF::HashMap<const RenderBox*, int> OverrideSizeMap;
     67 static OverrideSizeMap* gOverrideSizeMap = 0;
     68 
     69 bool RenderBox::s_hadOverflowClip = false;
     70 
     71 RenderBox::RenderBox(Node* node)
     72     : RenderBoxModelObject(node)
     73 #ifdef ANDROID_LAYOUT
     74     , m_visibleWidth(0)
     75 #endif
     76     , m_marginLeft(0)
     77     , m_marginRight(0)
     78     , m_marginTop(0)
     79     , m_marginBottom(0)
     80     , m_minPrefWidth(-1)
     81     , m_maxPrefWidth(-1)
     82     , m_inlineBoxWrapper(0)
     83 {
     84     setIsBox();
     85 }
     86 
     87 RenderBox::~RenderBox()
     88 {
     89 }
     90 
     91 void RenderBox::destroy()
     92 {
     93     // A lot of the code in this function is just pasted into
     94     // RenderWidget::destroy. If anything in this function changes,
     95     // be sure to fix RenderWidget::destroy() as well.
     96     if (hasOverrideSize())
     97         gOverrideSizeMap->remove(this);
     98 
     99     if (style() && (style()->height().isPercent() || style()->minHeight().isPercent() || style()->maxHeight().isPercent()))
    100         RenderBlock::removePercentHeightDescendant(this);
    101 
    102     RenderBoxModelObject::destroy();
    103 }
    104 
    105 void RenderBox::removeFloatingOrPositionedChildFromBlockLists()
    106 {
    107     ASSERT(isFloatingOrPositioned());
    108 
    109     if (documentBeingDestroyed())
    110         return;
    111 
    112     if (isFloating()) {
    113         RenderBlock* outermostBlock = containingBlock();
    114         for (RenderBlock* p = outermostBlock; p && !p->isRenderView(); p = p->containingBlock()) {
    115             if (p->containsFloat(this))
    116                 outermostBlock = p;
    117         }
    118 
    119         if (outermostBlock)
    120             outermostBlock->markAllDescendantsWithFloatsForLayout(this, false);
    121     }
    122 
    123     if (isPositioned()) {
    124         RenderObject* p;
    125         for (p = parent(); p; p = p->parent()) {
    126             if (p->isRenderBlock())
    127                 toRenderBlock(p)->removePositionedObject(this);
    128         }
    129     }
    130 }
    131 
    132 void RenderBox::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
    133 {
    134     s_hadOverflowClip = hasOverflowClip();
    135 
    136     if (style()) {
    137         // The background of the root element or the body element could propagate up to
    138         // the canvas.  Just dirty the entire canvas when our style changes substantially.
    139         if (diff >= StyleDifferenceRepaint && node() &&
    140                 (node()->hasTagName(htmlTag) || node()->hasTagName(bodyTag)))
    141             view()->repaint();
    142 
    143         // When a layout hint happens and an object's position style changes, we have to do a layout
    144         // to dirty the render tree using the old position value now.
    145         if (diff == StyleDifferenceLayout && parent() && style()->position() != newStyle->position()) {
    146             markContainingBlocksForLayout();
    147             if (style()->position() == StaticPosition)
    148                 repaint();
    149             else if (newStyle->position() == AbsolutePosition || newStyle->position() == FixedPosition)
    150                 parent()->setChildNeedsLayout(true);
    151             if (isFloating() && !isPositioned() && (newStyle->position() == AbsolutePosition || newStyle->position() == FixedPosition))
    152                 removeFloatingOrPositionedChildFromBlockLists();
    153         }
    154     }
    155 
    156     RenderBoxModelObject::styleWillChange(diff, newStyle);
    157 }
    158 
    159 void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
    160 {
    161     RenderBoxModelObject::styleDidChange(diff, oldStyle);
    162 
    163     if (needsLayout() && oldStyle && (oldStyle->height().isPercent() || oldStyle->minHeight().isPercent() || oldStyle->maxHeight().isPercent()))
    164         RenderBlock::removePercentHeightDescendant(this);
    165 
    166     // If our zoom factor changes and we have a defined scrollLeft/Top, we need to adjust that value into the
    167     // new zoomed coordinate space.
    168     if (hasOverflowClip() && oldStyle && style() && oldStyle->effectiveZoom() != style()->effectiveZoom()) {
    169         int left = scrollLeft();
    170         if (left) {
    171             left = (left / oldStyle->effectiveZoom()) * style()->effectiveZoom();
    172             setScrollLeft(left);
    173         }
    174         int top = scrollTop();
    175         if (top) {
    176             top = (top / oldStyle->effectiveZoom()) * style()->effectiveZoom();
    177             setScrollTop(top);
    178         }
    179     }
    180 
    181     // Set the text color if we're the body.
    182     if (isBody())
    183         document()->setTextColor(style()->color());
    184 }
    185 
    186 void RenderBox::updateBoxModelInfoFromStyle()
    187 {
    188     RenderBoxModelObject::updateBoxModelInfoFromStyle();
    189 
    190     bool isRootObject = isRoot();
    191     bool isViewObject = isRenderView();
    192 
    193     // The root and the RenderView always paint their backgrounds/borders.
    194     if (isRootObject || isViewObject)
    195         setHasBoxDecorations(true);
    196 
    197     setPositioned(style()->position() == AbsolutePosition || style()->position() == FixedPosition);
    198     setFloating(!isPositioned() && style()->isFloating());
    199 
    200     // We also handle <body> and <html>, whose overflow applies to the viewport.
    201     if (style()->overflowX() != OVISIBLE && !isRootObject && (isRenderBlock() || isTableRow() || isTableSection())) {
    202         bool boxHasOverflowClip = true;
    203         if (isBody()) {
    204             // Overflow on the body can propagate to the viewport under the following conditions.
    205             // (1) The root element is <html>.
    206             // (2) We are the primary <body> (can be checked by looking at document.body).
    207             // (3) The root element has visible overflow.
    208             if (document()->documentElement()->hasTagName(htmlTag) &&
    209                 document()->body() == node() &&
    210                 document()->documentElement()->renderer()->style()->overflowX() == OVISIBLE)
    211                 boxHasOverflowClip = false;
    212         }
    213 
    214         // Check for overflow clip.
    215         // It's sufficient to just check one direction, since it's illegal to have visible on only one overflow value.
    216         if (boxHasOverflowClip) {
    217             if (!s_hadOverflowClip)
    218                 // Erase the overflow
    219                 repaint();
    220             setHasOverflowClip();
    221         }
    222     }
    223 
    224     setHasTransform(style()->hasTransformRelatedProperty());
    225     setHasReflection(style()->boxReflect());
    226 }
    227 
    228 void RenderBox::layout()
    229 {
    230     ASSERT(needsLayout());
    231 
    232     RenderObject* child = firstChild();
    233     if (!child) {
    234         setNeedsLayout(false);
    235         return;
    236     }
    237 
    238     LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()));
    239     while (child) {
    240         child->layoutIfNeeded();
    241         ASSERT(!child->needsLayout());
    242         child = child->nextSibling();
    243     }
    244     statePusher.pop();
    245     setNeedsLayout(false);
    246 }
    247 
    248 // More IE extensions.  clientWidth and clientHeight represent the interior of an object
    249 // excluding border and scrollbar.
    250 int RenderBox::clientWidth() const
    251 {
    252     return width() - borderLeft() - borderRight() - verticalScrollbarWidth();
    253 }
    254 
    255 int RenderBox::clientHeight() const
    256 {
    257     return height() - borderTop() - borderBottom() - horizontalScrollbarHeight();
    258 }
    259 
    260 int RenderBox::scrollWidth() const
    261 {
    262     if (hasOverflowClip())
    263         return layer()->scrollWidth();
    264     // For objects with visible overflow, this matches IE.
    265     if (style()->direction() == LTR)
    266         return max(clientWidth(), rightmostPosition(true, false) - borderLeft());
    267     return clientWidth() - min(0, leftmostPosition(true, false) - borderLeft());
    268 }
    269 
    270 int RenderBox::scrollHeight() const
    271 {
    272     if (hasOverflowClip())
    273         return layer()->scrollHeight();
    274     // For objects with visible overflow, this matches IE.
    275     return max(clientHeight(), lowestPosition(true, false) - borderTop());
    276 }
    277 
    278 int RenderBox::scrollLeft() const
    279 {
    280     return hasOverflowClip() ? layer()->scrollXOffset() : 0;
    281 }
    282 
    283 int RenderBox::scrollTop() const
    284 {
    285     return hasOverflowClip() ? layer()->scrollYOffset() : 0;
    286 }
    287 
    288 void RenderBox::setScrollLeft(int newLeft)
    289 {
    290     if (hasOverflowClip())
    291         layer()->scrollToXOffset(newLeft);
    292 }
    293 
    294 void RenderBox::setScrollTop(int newTop)
    295 {
    296     if (hasOverflowClip())
    297         layer()->scrollToYOffset(newTop);
    298 }
    299 
    300 void RenderBox::absoluteRects(Vector<IntRect>& rects, int tx, int ty)
    301 {
    302     rects.append(IntRect(tx, ty, width(), height()));
    303 }
    304 
    305 void RenderBox::absoluteQuads(Vector<FloatQuad>& quads)
    306 {
    307     quads.append(localToAbsoluteQuad(FloatRect(0, 0, width(), height())));
    308 }
    309 
    310 IntRect RenderBox::absoluteContentBox() const
    311 {
    312     IntRect rect = contentBoxRect();
    313     FloatPoint absPos = localToAbsolute(FloatPoint());
    314     rect.move(absPos.x(), absPos.y());
    315     return rect;
    316 }
    317 
    318 FloatQuad RenderBox::absoluteContentQuad() const
    319 {
    320     IntRect rect = contentBoxRect();
    321     return localToAbsoluteQuad(FloatRect(rect));
    322 }
    323 
    324 IntRect RenderBox::outlineBoundsForRepaint(RenderBoxModelObject* repaintContainer) const
    325 {
    326     IntRect box = borderBoundingBox();
    327     adjustRectForOutlineAndShadow(box);
    328 
    329     FloatQuad containerRelativeQuad = localToContainerQuad(FloatRect(box), repaintContainer);
    330     box = containerRelativeQuad.enclosingBoundingBox();
    331 
    332     // FIXME: layoutDelta needs to be applied in parts before/after transforms and
    333     // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
    334     box.move(view()->layoutDelta());
    335 
    336     return box;
    337 }
    338 
    339 void RenderBox::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty)
    340 {
    341     if (width() && height())
    342         rects.append(IntRect(tx, ty, width(), height()));
    343 }
    344 
    345 IntRect RenderBox::reflectionBox() const
    346 {
    347     IntRect result;
    348     if (!style()->boxReflect())
    349         return result;
    350     IntRect box = borderBoxRect();
    351     result = box;
    352     switch (style()->boxReflect()->direction()) {
    353         case ReflectionBelow:
    354             result.move(0, box.height() + reflectionOffset());
    355             break;
    356         case ReflectionAbove:
    357             result.move(0, -box.height() - reflectionOffset());
    358             break;
    359         case ReflectionLeft:
    360             result.move(-box.width() - reflectionOffset(), 0);
    361             break;
    362         case ReflectionRight:
    363             result.move(box.width() + reflectionOffset(), 0);
    364             break;
    365     }
    366     return result;
    367 }
    368 
    369 int RenderBox::reflectionOffset() const
    370 {
    371     if (!style()->boxReflect())
    372         return 0;
    373     if (style()->boxReflect()->direction() == ReflectionLeft || style()->boxReflect()->direction() == ReflectionRight)
    374         return style()->boxReflect()->offset().calcValue(borderBoxRect().width());
    375     return style()->boxReflect()->offset().calcValue(borderBoxRect().height());
    376 }
    377 
    378 IntRect RenderBox::reflectedRect(const IntRect& r) const
    379 {
    380     if (!style()->boxReflect())
    381         return IntRect();
    382 
    383     IntRect box = borderBoxRect();
    384     IntRect result = r;
    385     switch (style()->boxReflect()->direction()) {
    386         case ReflectionBelow:
    387             result.setY(box.bottom() + reflectionOffset() + (box.bottom() - r.bottom()));
    388             break;
    389         case ReflectionAbove:
    390             result.setY(box.y() - reflectionOffset() - box.height() + (box.bottom() - r.bottom()));
    391             break;
    392         case ReflectionLeft:
    393             result.setX(box.x() - reflectionOffset() - box.width() + (box.right() - r.right()));
    394             break;
    395         case ReflectionRight:
    396             result.setX(box.right() + reflectionOffset() + (box.right() - r.right()));
    397             break;
    398     }
    399     return result;
    400 }
    401 
    402 int RenderBox::verticalScrollbarWidth() const
    403 {
    404     return includeVerticalScrollbarSize() ? layer()->verticalScrollbarWidth() : 0;
    405 }
    406 
    407 int RenderBox::horizontalScrollbarHeight() const
    408 {
    409     return includeHorizontalScrollbarSize() ? layer()->horizontalScrollbarHeight() : 0;
    410 }
    411 
    412 bool RenderBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
    413 {
    414     RenderLayer* l = layer();
    415     if (l && l->scroll(direction, granularity, multiplier)) {
    416         if (stopNode)
    417             *stopNode = node();
    418         return true;
    419     }
    420 
    421     if (stopNode && *stopNode && *stopNode == node())
    422         return true;
    423 
    424     RenderBlock* b = containingBlock();
    425     if (b && !b->isRenderView())
    426         return b->scroll(direction, granularity, multiplier, stopNode);
    427     return false;
    428 }
    429 
    430 bool RenderBox::canBeScrolledAndHasScrollableArea() const
    431 {
    432    return canBeProgramaticallyScrolled(false) && (scrollHeight() != clientHeight() || scrollWidth() != clientWidth());
    433 }
    434 
    435 bool RenderBox::canBeProgramaticallyScrolled(bool) const
    436 {
    437     return (hasOverflowClip() && (scrollsOverflow() || (node() && node()->isContentEditable()))) || (node() && node()->isDocumentNode());
    438 }
    439 
    440 void RenderBox::autoscroll()
    441 {
    442     if (layer())
    443         layer()->autoscroll();
    444 }
    445 
    446 void RenderBox::panScroll(const IntPoint& source)
    447 {
    448     if (layer())
    449         layer()->panScrollFromPoint(source);
    450 }
    451 
    452 int RenderBox::minPrefWidth() const
    453 {
    454     if (prefWidthsDirty())
    455         const_cast<RenderBox*>(this)->calcPrefWidths();
    456 
    457     return m_minPrefWidth;
    458 }
    459 
    460 int RenderBox::maxPrefWidth() const
    461 {
    462     if (prefWidthsDirty())
    463         const_cast<RenderBox*>(this)->calcPrefWidths();
    464 
    465     return m_maxPrefWidth;
    466 }
    467 
    468 int RenderBox::overrideSize() const
    469 {
    470     if (!hasOverrideSize())
    471         return -1;
    472     return gOverrideSizeMap->get(this);
    473 }
    474 
    475 void RenderBox::setOverrideSize(int s)
    476 {
    477     if (s == -1) {
    478         if (hasOverrideSize()) {
    479             setHasOverrideSize(false);
    480             gOverrideSizeMap->remove(this);
    481         }
    482     } else {
    483         if (!gOverrideSizeMap)
    484             gOverrideSizeMap = new OverrideSizeMap();
    485         setHasOverrideSize(true);
    486         gOverrideSizeMap->set(this, s);
    487     }
    488 }
    489 
    490 int RenderBox::overrideWidth() const
    491 {
    492     return hasOverrideSize() ? overrideSize() : width();
    493 }
    494 
    495 int RenderBox::overrideHeight() const
    496 {
    497     return hasOverrideSize() ? overrideSize() : height();
    498 }
    499 
    500 int RenderBox::calcBorderBoxWidth(int width) const
    501 {
    502     int bordersPlusPadding = borderLeft() + borderRight() + paddingLeft() + paddingRight();
    503     if (style()->boxSizing() == CONTENT_BOX)
    504         return width + bordersPlusPadding;
    505     return max(width, bordersPlusPadding);
    506 }
    507 
    508 int RenderBox::calcBorderBoxHeight(int height) const
    509 {
    510     int bordersPlusPadding = borderTop() + borderBottom() + paddingTop() + paddingBottom();
    511     if (style()->boxSizing() == CONTENT_BOX)
    512         return height + bordersPlusPadding;
    513     return max(height, bordersPlusPadding);
    514 }
    515 
    516 int RenderBox::calcContentBoxWidth(int width) const
    517 {
    518     if (style()->boxSizing() == BORDER_BOX)
    519         width -= (borderLeft() + borderRight() + paddingLeft() + paddingRight());
    520     return max(0, width);
    521 }
    522 
    523 int RenderBox::calcContentBoxHeight(int height) const
    524 {
    525     if (style()->boxSizing() == BORDER_BOX)
    526         height -= (borderTop() + borderBottom() + paddingTop() + paddingBottom());
    527     return max(0, height);
    528 }
    529 
    530 // Hit Testing
    531 bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int xPos, int yPos, int tx, int ty, HitTestAction action)
    532 {
    533     tx += x();
    534     ty += y();
    535 
    536     // Check kids first.
    537     for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
    538         if (!child->hasLayer() && child->nodeAtPoint(request, result, xPos, yPos, tx, ty, action)) {
    539             updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty));
    540             return true;
    541         }
    542     }
    543 
    544     // Check our bounds next. For this purpose always assume that we can only be hit in the
    545     // foreground phase (which is true for replaced elements like images).
    546     if (visibleToHitTesting() && action == HitTestForeground && IntRect(tx, ty, width(), height()).contains(xPos, yPos)) {
    547         updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty));
    548         return true;
    549     }
    550 
    551     return false;
    552 }
    553 
    554 // --------------------- painting stuff -------------------------------
    555 
    556 void RenderBox::paint(PaintInfo& paintInfo, int tx, int ty)
    557 {
    558     tx += x();
    559     ty += y();
    560 
    561     // default implementation. Just pass paint through to the children
    562     PaintInfo childInfo(paintInfo);
    563     childInfo.paintingRoot = paintingRootForChildren(paintInfo);
    564     for (RenderObject* child = firstChild(); child; child = child->nextSibling())
    565         child->paint(childInfo, tx, ty);
    566 }
    567 
    568 void RenderBox::paintRootBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
    569 {
    570     const FillLayer* bgLayer = style()->backgroundLayers();
    571     Color bgColor = style()->backgroundColor();
    572     RenderObject* bodyObject = 0;
    573     if (!style()->hasBackground() && node() && node()->hasTagName(HTMLNames::htmlTag)) {
    574         // Locate the <body> element using the DOM.  This is easier than trying
    575         // to crawl around a render tree with potential :before/:after content and
    576         // anonymous blocks created by inline <body> tags etc.  We can locate the <body>
    577         // render object very easily via the DOM.
    578         HTMLElement* body = document()->body();
    579         bodyObject = (body && body->hasLocalName(bodyTag)) ? body->renderer() : 0;
    580         if (bodyObject) {
    581             bgLayer = bodyObject->style()->backgroundLayers();
    582             bgColor = bodyObject->style()->backgroundColor();
    583         }
    584     }
    585 
    586     int w = width();
    587     int h = height();
    588 
    589     int rw;
    590     int rh;
    591     if (view()->frameView()) {
    592         rw = view()->frameView()->contentsWidth();
    593         rh = view()->frameView()->contentsHeight();
    594     } else {
    595         rw = view()->width();
    596         rh = view()->height();
    597     }
    598 
    599     // CSS2 14.2:
    600     // The background of the box generated by the root element covers the entire canvas including
    601     // its margins.
    602     int bx = tx - marginLeft();
    603     int by = ty - marginTop();
    604     int bw = max(w + marginLeft() + marginRight() + borderLeft() + borderRight(), rw);
    605     int bh = max(h + marginTop() + marginBottom() + borderTop() + borderBottom(), rh);
    606 
    607     paintFillLayers(paintInfo, bgColor, bgLayer, bx, by, bw, bh, CompositeSourceOver, bodyObject);
    608 
    609     if (style()->hasBorder() && style()->display() != INLINE)
    610         paintBorder(paintInfo.context, tx, ty, w, h, style());
    611 }
    612 
    613 void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
    614 {
    615     if (!shouldPaintWithinRoot(paintInfo))
    616         return;
    617 
    618     if (isRoot()) {
    619         paintRootBoxDecorations(paintInfo, tx, ty);
    620         return;
    621     }
    622 
    623     int w = width();
    624     int h = height();
    625 
    626     // border-fit can adjust where we paint our border and background.  If set, we snugly fit our line box descendants.  (The iChat
    627     // balloon layout is an example of this).
    628     borderFitAdjust(tx, w);
    629 
    630     // FIXME: Should eventually give the theme control over whether the box shadow should paint, since controls could have
    631     // custom shadows of their own.
    632     paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Normal);
    633 
    634     // If we have a native theme appearance, paint that before painting our background.
    635     // The theme will tell us whether or not we should also paint the CSS background.
    636     bool themePainted = style()->hasAppearance() && !theme()->paint(this, paintInfo, IntRect(tx, ty, w, h));
    637     if (!themePainted) {
    638         // The <body> only paints its background if the root element has defined a background
    639         // independent of the body.  Go through the DOM to get to the root element's render object,
    640         // since the root could be inline and wrapped in an anonymous block.
    641         if (!isBody() || document()->documentElement()->renderer()->style()->hasBackground())
    642             paintFillLayers(paintInfo, style()->backgroundColor(), style()->backgroundLayers(), tx, ty, w, h);
    643         if (style()->hasAppearance())
    644             theme()->paintDecorations(this, paintInfo, IntRect(tx, ty, w, h));
    645     }
    646     paintBoxShadow(paintInfo.context, tx, ty, w, h, style(), Inset);
    647 
    648     // The theme will tell us whether or not we should also paint the CSS border.
    649     if ((!style()->hasAppearance() || (!themePainted && theme()->paintBorderOnly(this, paintInfo, IntRect(tx, ty, w, h)))) && style()->hasBorder())
    650         paintBorder(paintInfo.context, tx, ty, w, h, style());
    651 }
    652 
    653 void RenderBox::paintMask(PaintInfo& paintInfo, int tx, int ty)
    654 {
    655     if (!shouldPaintWithinRoot(paintInfo) || style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
    656         return;
    657 
    658     int w = width();
    659     int h = height();
    660 
    661     // border-fit can adjust where we paint our border and background.  If set, we snugly fit our line box descendants.  (The iChat
    662     // balloon layout is an example of this).
    663     borderFitAdjust(tx, w);
    664 
    665     paintMaskImages(paintInfo, tx, ty, w, h);
    666 }
    667 
    668 void RenderBox::paintMaskImages(const PaintInfo& paintInfo, int tx, int ty, int w, int h)
    669 {
    670     // Figure out if we need to push a transparency layer to render our mask.
    671     bool pushTransparencyLayer = false;
    672     bool compositedMask = hasLayer() && layer()->hasCompositedMask();
    673     CompositeOperator compositeOp = CompositeSourceOver;
    674 
    675     bool allMaskImagesLoaded = true;
    676 
    677     if (!compositedMask) {
    678         StyleImage* maskBoxImage = style()->maskBoxImage().image();
    679         const FillLayer* maskLayers = style()->maskLayers();
    680 
    681         // Don't render a masked element until all the mask images have loaded, to prevent a flash of unmasked content.
    682         if (maskBoxImage)
    683             allMaskImagesLoaded &= maskBoxImage->isLoaded();
    684 
    685         if (maskLayers)
    686             allMaskImagesLoaded &= maskLayers->imagesAreLoaded();
    687 
    688         // Before all images have loaded, just use an empty transparency layer as the mask.
    689         if (!allMaskImagesLoaded)
    690             pushTransparencyLayer = true;
    691 
    692         if (maskBoxImage && maskLayers->hasImage()) {
    693             // We have a mask-box-image and mask-image, so need to composite them together before using the result as a mask.
    694             pushTransparencyLayer = true;
    695         } else {
    696             // We have to use an extra image buffer to hold the mask. Multiple mask images need
    697             // to composite together using source-over so that they can then combine into a single unified mask that
    698             // can be composited with the content using destination-in.  SVG images need to be able to set compositing modes
    699             // as they draw images contained inside their sub-document, so we paint all our images into a separate buffer
    700             // and composite that buffer as the mask.
    701             // We have to check that the mask images to be rendered contain at least one image that can be actually used in rendering
    702             // before pushing the transparency layer.
    703             for (const FillLayer* fillLayer = maskLayers->next(); fillLayer; fillLayer = fillLayer->next()) {
    704                 if (fillLayer->hasImage() && fillLayer->image()->canRender(style()->effectiveZoom())) {
    705                     pushTransparencyLayer = true;
    706                     // We found one image that can be used in rendering, exit the loop
    707                     break;
    708                 }
    709             }
    710         }
    711 
    712         compositeOp = CompositeDestinationIn;
    713         if (pushTransparencyLayer) {
    714             paintInfo.context->setCompositeOperation(CompositeDestinationIn);
    715             paintInfo.context->beginTransparencyLayer(1.0f);
    716             compositeOp = CompositeSourceOver;
    717         }
    718     }
    719 
    720     if (allMaskImagesLoaded) {
    721         paintFillLayers(paintInfo, Color(), style()->maskLayers(), tx, ty, w, h, compositeOp);
    722         paintNinePieceImage(paintInfo.context, tx, ty, w, h, style(), style()->maskBoxImage(), compositeOp);
    723     }
    724 
    725     if (pushTransparencyLayer)
    726         paintInfo.context->endTransparencyLayer();
    727 }
    728 
    729 IntRect RenderBox::maskClipRect()
    730 {
    731     IntRect bbox = borderBoxRect();
    732     if (style()->maskBoxImage().image())
    733         return bbox;
    734 
    735     IntRect result;
    736     for (const FillLayer* maskLayer = style()->maskLayers(); maskLayer; maskLayer = maskLayer->next()) {
    737         if (maskLayer->image()) {
    738             IntRect maskRect;
    739             IntPoint phase;
    740             IntSize tileSize;
    741             calculateBackgroundImageGeometry(maskLayer, bbox.x(), bbox.y(), bbox.width(), bbox.height(), maskRect, phase, tileSize);
    742             result.unite(maskRect);
    743         }
    744     }
    745     return result;
    746 }
    747 
    748 void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int width, int height, CompositeOperator op, RenderObject* backgroundObject)
    749 {
    750     if (!fillLayer)
    751         return;
    752 
    753     paintFillLayers(paintInfo, c, fillLayer->next(), tx, ty, width, height, op, backgroundObject);
    754     paintFillLayer(paintInfo, c, fillLayer, tx, ty, width, height, op, backgroundObject);
    755 }
    756 
    757 void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int width, int height, CompositeOperator op, RenderObject* backgroundObject)
    758 {
    759     paintFillLayerExtended(paintInfo, c, fillLayer, tx, ty, width, height, 0, op, backgroundObject);
    760 }
    761 
    762 void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*)
    763 {
    764     if (!parent())
    765         return;
    766 
    767     if ((style()->borderImage().image() && style()->borderImage().image()->data() == image) ||
    768         (style()->maskBoxImage().image() && style()->maskBoxImage().image()->data() == image)) {
    769         repaint();
    770         return;
    771     }
    772 
    773     bool didFullRepaint = repaintLayerRectsForImage(image, style()->backgroundLayers(), true);
    774     if (!didFullRepaint)
    775         repaintLayerRectsForImage(image, style()->maskLayers(), false);
    776 }
    777 
    778 bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer* layers, bool drawingBackground)
    779 {
    780     IntRect rendererRect;
    781     RenderBox* layerRenderer = 0;
    782 
    783     for (const FillLayer* curLayer = layers; curLayer; curLayer = curLayer->next()) {
    784         if (curLayer->image() && image == curLayer->image()->data() && curLayer->image()->canRender(style()->effectiveZoom())) {
    785             // Now that we know this image is being used, compute the renderer and the rect
    786             // if we haven't already
    787             if (!layerRenderer) {
    788                 bool drawingRootBackground = drawingBackground && (isRoot() || (isBody() && !document()->documentElement()->renderer()->style()->hasBackground()));
    789                 if (drawingRootBackground) {
    790                     layerRenderer = view();
    791 
    792                     int rw;
    793                     int rh;
    794 
    795                     if (FrameView* frameView = toRenderView(layerRenderer)->frameView()) {
    796                         rw = frameView->contentsWidth();
    797                         rh = frameView->contentsHeight();
    798                     } else {
    799                         rw = layerRenderer->width();
    800                         rh = layerRenderer->height();
    801                     }
    802                     rendererRect = IntRect(-layerRenderer->marginLeft(),
    803                         -layerRenderer->marginTop(),
    804                         max(layerRenderer->width() + layerRenderer->marginLeft() + layerRenderer->marginRight() + layerRenderer->borderLeft() + layerRenderer->borderRight(), rw),
    805                         max(layerRenderer->height() + layerRenderer->marginTop() + layerRenderer->marginBottom() + layerRenderer->borderTop() + layerRenderer->borderBottom(), rh));
    806                 } else {
    807                     layerRenderer = this;
    808                     rendererRect = borderBoxRect();
    809                 }
    810             }
    811 
    812             IntRect repaintRect;
    813             IntPoint phase;
    814             IntSize tileSize;
    815             layerRenderer->calculateBackgroundImageGeometry(curLayer, rendererRect.x(), rendererRect.y(), rendererRect.width(), rendererRect.height(), repaintRect, phase, tileSize);
    816             layerRenderer->repaintRectangle(repaintRect);
    817             if (repaintRect == rendererRect)
    818                 return true;
    819         }
    820     }
    821     return false;
    822 }
    823 
    824 #if PLATFORM(MAC)
    825 
    826 void RenderBox::paintCustomHighlight(int tx, int ty, const AtomicString& type, bool behindText)
    827 {
    828     Frame* frame = document()->frame();
    829     if (!frame)
    830         return;
    831     Page* page = frame->page();
    832     if (!page)
    833         return;
    834 
    835     InlineBox* boxWrap = inlineBoxWrapper();
    836     RootInlineBox* r = boxWrap ? boxWrap->root() : 0;
    837     if (r) {
    838         FloatRect rootRect(tx + r->x(), ty + r->selectionTop(), r->width(), r->selectionHeight());
    839         FloatRect imageRect(tx + x(), rootRect.y(), width(), rootRect.height());
    840         page->chrome()->client()->paintCustomHighlight(node(), type, imageRect, rootRect, behindText, false);
    841     } else {
    842         FloatRect imageRect(tx + x(), ty + y(), width(), height());
    843         page->chrome()->client()->paintCustomHighlight(node(), type, imageRect, imageRect, behindText, false);
    844     }
    845 }
    846 
    847 #endif
    848 
    849 bool RenderBox::pushContentsClip(PaintInfo& paintInfo, int tx, int ty)
    850 {
    851     if (paintInfo.phase == PaintPhaseBlockBackground || paintInfo.phase == PaintPhaseSelfOutline || paintInfo.phase == PaintPhaseMask)
    852         return false;
    853 
    854     bool isControlClip = hasControlClip();
    855     bool isOverflowClip = hasOverflowClip() && !layer()->isSelfPaintingLayer();
    856 
    857     if (!isControlClip && !isOverflowClip)
    858         return false;
    859 
    860     if (paintInfo.phase == PaintPhaseOutline)
    861         paintInfo.phase = PaintPhaseChildOutlines;
    862     else if (paintInfo.phase == PaintPhaseChildBlockBackground) {
    863         paintInfo.phase = PaintPhaseBlockBackground;
    864         paintObject(paintInfo, tx, ty);
    865         paintInfo.phase = PaintPhaseChildBlockBackgrounds;
    866     }
    867     IntRect clipRect(isControlClip ? controlClipRect(tx, ty) : overflowClipRect(tx, ty));
    868     paintInfo.context->save();
    869     if (style()->hasBorderRadius()) {
    870         IntSize topLeft, topRight, bottomLeft, bottomRight;
    871         IntRect borderRect = IntRect(tx, ty, width(), height());
    872         style()->getBorderRadiiForRect(borderRect, topLeft, topRight, bottomLeft, bottomRight);
    873 
    874         paintInfo.context->addRoundedRectClip(borderRect, topLeft, topRight, bottomLeft, bottomRight);
    875     }
    876 
    877     paintInfo.context->clip(clipRect);
    878     return true;
    879 }
    880 
    881 void RenderBox::popContentsClip(PaintInfo& paintInfo, PaintPhase originalPhase, int tx, int ty)
    882 {
    883     ASSERT(hasControlClip() || (hasOverflowClip() && !layer()->isSelfPaintingLayer()));
    884 
    885     paintInfo.context->restore();
    886     if (originalPhase == PaintPhaseOutline) {
    887         paintInfo.phase = PaintPhaseSelfOutline;
    888         paintObject(paintInfo, tx, ty);
    889         paintInfo.phase = originalPhase;
    890     } else if (originalPhase == PaintPhaseChildBlockBackground)
    891         paintInfo.phase = originalPhase;
    892 }
    893 
    894 IntRect RenderBox::overflowClipRect(int tx, int ty)
    895 {
    896     // FIXME: When overflow-clip (CSS3) is implemented, we'll obtain the property
    897     // here.
    898 
    899     int bLeft = borderLeft();
    900     int bTop = borderTop();
    901 
    902     int clipX = tx + bLeft;
    903     int clipY = ty + bTop;
    904     int clipWidth = width() - bLeft - borderRight();
    905     int clipHeight = height() - bTop - borderBottom();
    906 
    907     // Subtract out scrollbars if we have them.
    908     if (layer()) {
    909         clipWidth -= layer()->verticalScrollbarWidth();
    910         clipHeight -= layer()->horizontalScrollbarHeight();
    911     }
    912 
    913     return IntRect(clipX, clipY, clipWidth, clipHeight);
    914 }
    915 
    916 IntRect RenderBox::clipRect(int tx, int ty)
    917 {
    918     int clipX = tx;
    919     int clipY = ty;
    920     int clipWidth = width();
    921     int clipHeight = height();
    922 
    923     if (!style()->clipLeft().isAuto()) {
    924         int c = style()->clipLeft().calcValue(width());
    925         clipX += c;
    926         clipWidth -= c;
    927     }
    928 
    929     if (!style()->clipRight().isAuto())
    930         clipWidth -= width() - style()->clipRight().calcValue(width());
    931 
    932     if (!style()->clipTop().isAuto()) {
    933         int c = style()->clipTop().calcValue(height());
    934         clipY += c;
    935         clipHeight -= c;
    936     }
    937 
    938     if (!style()->clipBottom().isAuto())
    939         clipHeight -= height() - style()->clipBottom().calcValue(height());
    940 
    941     return IntRect(clipX, clipY, clipWidth, clipHeight);
    942 }
    943 
    944 int RenderBox::containingBlockWidthForContent() const
    945 {
    946     RenderBlock* cb = containingBlock();
    947     if (shrinkToAvoidFloats())
    948         return cb->lineWidth(y(), false);
    949     return cb->availableWidth();
    950 }
    951 
    952 void RenderBox::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState) const
    953 {
    954     if (repaintContainer == this)
    955         return;
    956 
    957     if (RenderView* v = view()) {
    958         if (v->layoutStateEnabled() && !repaintContainer) {
    959             LayoutState* layoutState = v->layoutState();
    960             IntSize offset = layoutState->m_offset;
    961             offset.expand(x(), y());
    962             if (style()->position() == RelativePosition && layer())
    963                 offset += layer()->relativePositionOffset();
    964             transformState.move(offset);
    965             return;
    966         }
    967     }
    968 
    969     bool containerSkipped;
    970     RenderObject* o = container(repaintContainer, &containerSkipped);
    971     if (!o)
    972         return;
    973 
    974     bool isFixedPos = style()->position() == FixedPosition;
    975     bool hasTransform = hasLayer() && layer()->transform();
    976     if (hasTransform) {
    977         // If this box has a transform, it acts as a fixed position container for fixed descendants,
    978         // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
    979         fixed &= isFixedPos;
    980     } else
    981         fixed |= isFixedPos;
    982 
    983     IntSize containerOffset = offsetFromContainer(o);
    984 
    985     bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
    986     if (useTransforms && shouldUseTransformFromContainer(o)) {
    987         TransformationMatrix t;
    988         getTransformFromContainer(o, containerOffset, t);
    989         transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
    990     } else
    991         transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
    992 
    993     if (containerSkipped) {
    994         // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
    995         // to just subtract the delta between the repaintContainer and o.
    996         IntSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
    997         transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
    998         return;
    999     }
   1000 
   1001     o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState);
   1002 }
   1003 
   1004 void RenderBox::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState& transformState) const
   1005 {
   1006     // We don't expect absoluteToLocal() to be called during layout (yet)
   1007     ASSERT(!view() || !view()->layoutStateEnabled());
   1008 
   1009     bool isFixedPos = style()->position() == FixedPosition;
   1010     bool hasTransform = hasLayer() && layer()->transform();
   1011     if (hasTransform) {
   1012         // If this box has a transform, it acts as a fixed position container for fixed descendants,
   1013         // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
   1014         fixed &= isFixedPos;
   1015     } else
   1016         fixed |= isFixedPos;
   1017 
   1018     RenderObject* o = container();
   1019     if (!o)
   1020         return;
   1021 
   1022     o->mapAbsoluteToLocalPoint(fixed, useTransforms, transformState);
   1023 
   1024     IntSize containerOffset = offsetFromContainer(o);
   1025 
   1026     bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
   1027     if (useTransforms && shouldUseTransformFromContainer(o)) {
   1028         TransformationMatrix t;
   1029         getTransformFromContainer(o, containerOffset, t);
   1030         transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
   1031     } else
   1032         transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
   1033 }
   1034 
   1035 IntSize RenderBox::offsetFromContainer(RenderObject* o) const
   1036 {
   1037     ASSERT(o == container());
   1038 
   1039     IntSize offset;
   1040     if (isRelPositioned())
   1041         offset += relativePositionOffset();
   1042 
   1043     if (!isInline() || isReplaced()) {
   1044         RenderBlock* cb;
   1045         if (o->isBlockFlow() && style()->position() != AbsolutePosition && style()->position() != FixedPosition
   1046                 && (cb = toRenderBlock(o))->hasColumns()) {
   1047             IntRect rect(x(), y(), 1, 1);
   1048             cb->adjustRectForColumns(rect);
   1049             offset.expand(rect.x(), rect.y());
   1050         } else
   1051             offset.expand(x(), y());
   1052     }
   1053 
   1054     if (o->hasOverflowClip())
   1055         offset -= toRenderBox(o)->layer()->scrolledContentOffset();
   1056 
   1057     if (style()->position() == AbsolutePosition && o->isRelPositioned() && o->isRenderInline())
   1058         offset += toRenderInline(o)->relativePositionedInlineOffset(this);
   1059 
   1060     return offset;
   1061 }
   1062 
   1063 InlineBox* RenderBox::createInlineBox()
   1064 {
   1065     return new (renderArena()) InlineBox(this);
   1066 }
   1067 
   1068 void RenderBox::dirtyLineBoxes(bool fullLayout)
   1069 {
   1070     if (m_inlineBoxWrapper) {
   1071         if (fullLayout) {
   1072             m_inlineBoxWrapper->destroy(renderArena());
   1073             m_inlineBoxWrapper = 0;
   1074         } else
   1075             m_inlineBoxWrapper->dirtyLineBoxes();
   1076     }
   1077 }
   1078 
   1079 void RenderBox::positionLineBox(InlineBox* box)
   1080 {
   1081     if (isPositioned()) {
   1082         // Cache the x position only if we were an INLINE type originally.
   1083         bool wasInline = style()->isOriginalDisplayInlineType();
   1084         if (wasInline && style()->hasStaticX()) {
   1085             // The value is cached in the xPos of the box.  We only need this value if
   1086             // our object was inline originally, since otherwise it would have ended up underneath
   1087             // the inlines.
   1088             layer()->setStaticX(box->x());
   1089             setChildNeedsLayout(true, false); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
   1090         } else if (!wasInline && style()->hasStaticY()) {
   1091             // Our object was a block originally, so we make our normal flow position be
   1092             // just below the line box (as though all the inlines that came before us got
   1093             // wrapped in an anonymous block, which is what would have happened had we been
   1094             // in flow).  This value was cached in the y() of the box.
   1095             layer()->setStaticY(box->y());
   1096             setChildNeedsLayout(true, false); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
   1097         }
   1098 
   1099         // Nuke the box.
   1100         box->remove();
   1101         box->destroy(renderArena());
   1102     } else if (isReplaced()) {
   1103         setLocation(box->x(), box->y());
   1104         m_inlineBoxWrapper = box;
   1105     }
   1106 }
   1107 
   1108 void RenderBox::deleteLineBoxWrapper()
   1109 {
   1110     if (m_inlineBoxWrapper) {
   1111         if (!documentBeingDestroyed())
   1112             m_inlineBoxWrapper->remove();
   1113         m_inlineBoxWrapper->destroy(renderArena());
   1114         m_inlineBoxWrapper = 0;
   1115     }
   1116 }
   1117 
   1118 IntRect RenderBox::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
   1119 {
   1120     if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent())
   1121         return IntRect();
   1122 
   1123     IntRect r = visibleOverflowRect();
   1124 
   1125     RenderView* v = view();
   1126     if (v) {
   1127         // FIXME: layoutDelta needs to be applied in parts before/after transforms and
   1128         // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
   1129         r.move(v->layoutDelta());
   1130     }
   1131 
   1132     if (style()) {
   1133         if (style()->hasAppearance())
   1134             // The theme may wish to inflate the rect used when repainting.
   1135             theme()->adjustRepaintRect(this, r);
   1136 
   1137         // We have to use maximalOutlineSize() because a child might have an outline
   1138         // that projects outside of our overflowRect.
   1139         if (v) {
   1140             ASSERT(style()->outlineSize() <= v->maximalOutlineSize());
   1141             r.inflate(v->maximalOutlineSize());
   1142         }
   1143     }
   1144     computeRectForRepaint(repaintContainer, r);
   1145     return r;
   1146 }
   1147 
   1148 void RenderBox::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& rect, bool fixed)
   1149 {
   1150     if (RenderView* v = view()) {
   1151         // LayoutState is only valid for root-relative repainting
   1152         if (v->layoutStateEnabled() && !repaintContainer) {
   1153             LayoutState* layoutState = v->layoutState();
   1154 
   1155             if (layer() && layer()->transform())
   1156                 rect = layer()->transform()->mapRect(rect);
   1157 
   1158             if (style()->position() == RelativePosition && layer())
   1159                 rect.move(layer()->relativePositionOffset());
   1160 
   1161             rect.move(x(), y());
   1162             rect.move(layoutState->m_offset);
   1163             if (layoutState->m_clipped)
   1164                 rect.intersect(layoutState->m_clipRect);
   1165             return;
   1166         }
   1167     }
   1168 
   1169     if (hasReflection())
   1170         rect.unite(reflectedRect(rect));
   1171 
   1172     if (repaintContainer == this)
   1173         return;
   1174 
   1175     bool containerSkipped;
   1176     RenderObject* o = container(repaintContainer, &containerSkipped);
   1177     if (!o)
   1178         return;
   1179 
   1180     IntPoint topLeft = rect.location();
   1181     topLeft.move(x(), y());
   1182 
   1183     if (style()->position() == FixedPosition)
   1184         fixed = true;
   1185 
   1186     if (o->isBlockFlow() && style()->position() != AbsolutePosition && style()->position() != FixedPosition) {
   1187         RenderBlock* cb = toRenderBlock(o);
   1188         if (cb->hasColumns()) {
   1189             IntRect repaintRect(topLeft, rect.size());
   1190             cb->adjustRectForColumns(repaintRect);
   1191             topLeft = repaintRect.location();
   1192             rect = repaintRect;
   1193         }
   1194     }
   1195 
   1196     // We are now in our parent container's coordinate space.  Apply our transform to obtain a bounding box
   1197     // in the parent's coordinate space that encloses us.
   1198     if (layer() && layer()->transform()) {
   1199         fixed = false;
   1200         rect = layer()->transform()->mapRect(rect);
   1201         // FIXME: this clobbers topLeft adjustment done for multicol above
   1202         topLeft = rect.location();
   1203         topLeft.move(x(), y());
   1204     }
   1205 
   1206     if (style()->position() == AbsolutePosition && o->isRelPositioned() && o->isRenderInline())
   1207         topLeft += toRenderInline(o)->relativePositionedInlineOffset(this);
   1208     else if (style()->position() == RelativePosition && layer()) {
   1209         // Apply the relative position offset when invalidating a rectangle.  The layer
   1210         // is translated, but the render box isn't, so we need to do this to get the
   1211         // right dirty rect.  Since this is called from RenderObject::setStyle, the relative position
   1212         // flag on the RenderObject has been cleared, so use the one on the style().
   1213         topLeft += layer()->relativePositionOffset();
   1214     }
   1215 
   1216     // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
   1217     // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
   1218     if (o->hasOverflowClip()) {
   1219         RenderBox* containerBox = toRenderBox(o);
   1220 
   1221         // o->height() is inaccurate if we're in the middle of a layout of |o|, so use the
   1222         // layer's size instead.  Even if the layer's size is wrong, the layer itself will repaint
   1223         // anyway if its size does change.
   1224         topLeft -= containerBox->layer()->scrolledContentOffset(); // For overflow:auto/scroll/hidden.
   1225 
   1226         IntRect repaintRect(topLeft, rect.size());
   1227         IntRect boxRect(0, 0, containerBox->layer()->width(), containerBox->layer()->height());
   1228         rect = intersection(repaintRect, boxRect);
   1229         if (rect.isEmpty())
   1230             return;
   1231     } else
   1232         rect.setLocation(topLeft);
   1233 
   1234     if (containerSkipped) {
   1235         // If the repaintContainer is below o, then we need to map the rect into repaintContainer's coordinates.
   1236         IntSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
   1237         rect.move(-containerOffset);
   1238         return;
   1239     }
   1240 
   1241     o->computeRectForRepaint(repaintContainer, rect, fixed);
   1242 }
   1243 
   1244 void RenderBox::repaintDuringLayoutIfMoved(const IntRect& rect)
   1245 {
   1246     int newX = x();
   1247     int newY = y();
   1248     int newWidth = width();
   1249     int newHeight = height();
   1250     if (rect.x() != newX || rect.y() != newY) {
   1251         // The child moved.  Invalidate the object's old and new positions.  We have to do this
   1252         // since the object may not have gotten a layout.
   1253         m_frameRect = rect;
   1254         repaint();
   1255         repaintOverhangingFloats(true);
   1256         m_frameRect = IntRect(newX, newY, newWidth, newHeight);
   1257         repaint();
   1258         repaintOverhangingFloats(true);
   1259     }
   1260 }
   1261 
   1262 void RenderBox::calcWidth()
   1263 {
   1264 #ifdef ANDROID_LAYOUT
   1265     if (view()->frameView()) {
   1266         const Settings* settings = document()->settings();
   1267         ASSERT(settings);
   1268         if (settings->layoutAlgorithm() == Settings::kLayoutFitColumnToScreen) {
   1269             m_visibleWidth = view()->frameView()->screenWidth();
   1270         }
   1271     }
   1272 #endif
   1273 
   1274     if (isPositioned()) {
   1275         calcAbsoluteHorizontal();
   1276         return;
   1277     }
   1278 
   1279     // If layout is limited to a subtree, the subtree root's width does not change.
   1280     if (node() && view()->frameView() && view()->frameView()->layoutRoot(true) == this)
   1281         return;
   1282 
   1283     // The parent box is flexing us, so it has increased or decreased our
   1284     // width.  Use the width from the style context.
   1285     if (hasOverrideSize() &&  parent()->style()->boxOrient() == HORIZONTAL
   1286             && parent()->isFlexibleBox() && parent()->isFlexingChildren()) {
   1287         setWidth(overrideSize());
   1288         return;
   1289     }
   1290 
   1291     bool inVerticalBox = parent()->isFlexibleBox() && (parent()->style()->boxOrient() == VERTICAL);
   1292     bool stretching = (parent()->style()->boxAlign() == BSTRETCH);
   1293     bool treatAsReplaced = shouldCalculateSizeAsReplaced() && (!inVerticalBox || !stretching);
   1294 
   1295     Length w = (treatAsReplaced) ? Length(calcReplacedWidth(), Fixed) : style()->width();
   1296 
   1297     RenderBlock* cb = containingBlock();
   1298     int containerWidth = max(0, containingBlockWidthForContent());
   1299 
   1300     Length marginLeft = style()->marginLeft();
   1301     Length marginRight = style()->marginRight();
   1302 
   1303     if (isInline() && !isInlineBlockOrInlineTable()) {
   1304         // just calculate margins
   1305         m_marginLeft = marginLeft.calcMinValue(containerWidth);
   1306         m_marginRight = marginRight.calcMinValue(containerWidth);
   1307 #ifdef ANDROID_LAYOUT
   1308         if (treatAsReplaced) {
   1309 #else
   1310         if (treatAsReplaced)
   1311 #endif
   1312             setWidth(max(w.value() + borderLeft() + borderRight() + paddingLeft() + paddingRight(), minPrefWidth()));
   1313 
   1314 #ifdef ANDROID_LAYOUT
   1315             // in SSR mode with replaced box, if the box width is wider than the container width,
   1316             // it will be shrinked to fit to the container.
   1317             if (containerWidth && (width() + m_marginLeft + m_marginRight) > containerWidth &&
   1318                     document()->frame()->settings()->layoutAlgorithm() == Settings::kLayoutSSR) {
   1319                 m_marginLeft = m_marginRight = 0;
   1320                 setWidth(containerWidth);
   1321                 m_minPrefWidth = m_maxPrefWidth = containerWidth;
   1322             }
   1323         }
   1324 #endif
   1325         return;
   1326     }
   1327 
   1328     // Width calculations
   1329     if (treatAsReplaced)
   1330         setWidth(w.value() + borderLeft() + borderRight() + paddingLeft() + paddingRight());
   1331     else {
   1332         // Calculate Width
   1333         setWidth(calcWidthUsing(Width, containerWidth));
   1334 
   1335         // Calculate MaxWidth
   1336         if (!style()->maxWidth().isUndefined()) {
   1337             int maxW = calcWidthUsing(MaxWidth, containerWidth);
   1338             if (width() > maxW) {
   1339                 setWidth(maxW);
   1340                 w = style()->maxWidth();
   1341             }
   1342         }
   1343 
   1344         // Calculate MinWidth
   1345         int minW = calcWidthUsing(MinWidth, containerWidth);
   1346         if (width() < minW) {
   1347             setWidth(minW);
   1348             w = style()->minWidth();
   1349         }
   1350     }
   1351 
   1352     if (stretchesToMinIntrinsicWidth()) {
   1353         setWidth(max(width(), minPrefWidth()));
   1354         w = Length(width(), Fixed);
   1355     }
   1356 
   1357     // Margin calculations
   1358     if (w.isAuto()) {
   1359         m_marginLeft = marginLeft.calcMinValue(containerWidth);
   1360         m_marginRight = marginRight.calcMinValue(containerWidth);
   1361     } else {
   1362         m_marginLeft = 0;
   1363         m_marginRight = 0;
   1364         calcHorizontalMargins(marginLeft, marginRight, containerWidth);
   1365     }
   1366 #ifdef ANDROID_LAYOUT
   1367     // in SSR mode with non-replaced box, we use ANDROID_SSR_MARGIN_PADDING for left/right margin.
   1368     // If the box width is wider than the container width, it will be shrinked to fit to the container.
   1369     if (containerWidth && !treatAsReplaced &&
   1370             document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR) {
   1371         setWidth(width() + m_marginLeft + m_marginRight);
   1372         m_marginLeft = m_marginLeft > ANDROID_SSR_MARGIN_PADDING ? ANDROID_SSR_MARGIN_PADDING : m_marginLeft;
   1373         m_marginRight = m_marginRight > ANDROID_SSR_MARGIN_PADDING ? ANDROID_SSR_MARGIN_PADDING : m_marginRight;
   1374         if (width() > containerWidth) {
   1375             m_minPrefWidth = m_maxPrefWidth = containerWidth-(m_marginLeft + m_marginRight);
   1376             setWidth(m_minPrefWidth);
   1377         } else
   1378             setWidth(width() -(m_marginLeft + m_marginRight));
   1379     }
   1380 #endif
   1381 
   1382     if (containerWidth && containerWidth != (width() + m_marginLeft + m_marginRight)
   1383             && !isFloating() && !isInline() && !cb->isFlexibleBox()) {
   1384         if (cb->style()->direction() == LTR)
   1385             m_marginRight = containerWidth - width() - m_marginLeft;
   1386         else
   1387             m_marginLeft = containerWidth - width() - m_marginRight;
   1388     }
   1389 }
   1390 
   1391 int RenderBox::calcWidthUsing(WidthType widthType, int cw)
   1392 {
   1393     int widthResult = width();
   1394     Length w;
   1395     if (widthType == Width)
   1396         w = style()->width();
   1397     else if (widthType == MinWidth)
   1398         w = style()->minWidth();
   1399     else
   1400         w = style()->maxWidth();
   1401 
   1402     if (w.isIntrinsicOrAuto()) {
   1403         int marginLeft = style()->marginLeft().calcMinValue(cw);
   1404         int marginRight = style()->marginRight().calcMinValue(cw);
   1405         if (cw)
   1406             widthResult = cw - marginLeft - marginRight;
   1407 
   1408         if (sizesToIntrinsicWidth(widthType)) {
   1409             widthResult = max(widthResult, minPrefWidth());
   1410             widthResult = min(widthResult, maxPrefWidth());
   1411         }
   1412     } else
   1413         widthResult = calcBorderBoxWidth(w.calcValue(cw));
   1414 
   1415     return widthResult;
   1416 }
   1417 
   1418 bool RenderBox::sizesToIntrinsicWidth(WidthType widthType) const
   1419 {
   1420     // Marquees in WinIE are like a mixture of blocks and inline-blocks.  They size as though they're blocks,
   1421     // but they allow text to sit on the same line as the marquee.
   1422     if (isFloating() || (isInlineBlockOrInlineTable() && !isHTMLMarquee()))
   1423         return true;
   1424 
   1425     // This code may look a bit strange.  Basically width:intrinsic should clamp the size when testing both
   1426     // min-width and width.  max-width is only clamped if it is also intrinsic.
   1427     Length width = (widthType == MaxWidth) ? style()->maxWidth() : style()->width();
   1428     if (width.type() == Intrinsic)
   1429         return true;
   1430 
   1431     // Children of a horizontal marquee do not fill the container by default.
   1432     // FIXME: Need to deal with MAUTO value properly.  It could be vertical.
   1433     if (parent()->style()->overflowX() == OMARQUEE) {
   1434         EMarqueeDirection dir = parent()->style()->marqueeDirection();
   1435         if (dir == MAUTO || dir == MFORWARD || dir == MBACKWARD || dir == MLEFT || dir == MRIGHT)
   1436             return true;
   1437     }
   1438 
   1439     // Flexible horizontal boxes lay out children at their intrinsic widths.  Also vertical boxes
   1440     // that don't stretch their kids lay out their children at their intrinsic widths.
   1441     if (parent()->isFlexibleBox()
   1442             && (parent()->style()->boxOrient() == HORIZONTAL || parent()->style()->boxAlign() != BSTRETCH))
   1443         return true;
   1444 
   1445     return false;
   1446 }
   1447 
   1448 void RenderBox::calcHorizontalMargins(const Length& marginLeft, const Length& marginRight, int containerWidth)
   1449 {
   1450     if (isFloating() || isInline()) {
   1451         // Inline blocks/tables and floats don't have their margins increased.
   1452         m_marginLeft = marginLeft.calcMinValue(containerWidth);
   1453         m_marginRight = marginRight.calcMinValue(containerWidth);
   1454         return;
   1455     }
   1456 
   1457     if ((marginLeft.isAuto() && marginRight.isAuto() && width() < containerWidth)
   1458             || (!marginLeft.isAuto() && !marginRight.isAuto() && containingBlock()->style()->textAlign() == WEBKIT_CENTER)) {
   1459         m_marginLeft = max(0, (containerWidth - width()) / 2);
   1460         m_marginRight = containerWidth - width() - m_marginLeft;
   1461     } else if ((marginRight.isAuto() && width() < containerWidth)
   1462             || (!marginLeft.isAuto() && containingBlock()->style()->direction() == RTL && containingBlock()->style()->textAlign() == WEBKIT_LEFT)) {
   1463         m_marginLeft = marginLeft.calcValue(containerWidth);
   1464         m_marginRight = containerWidth - width() - m_marginLeft;
   1465     } else if ((marginLeft.isAuto() && width() < containerWidth)
   1466             || (!marginRight.isAuto() && containingBlock()->style()->direction() == LTR && containingBlock()->style()->textAlign() == WEBKIT_RIGHT)) {
   1467         m_marginRight = marginRight.calcValue(containerWidth);
   1468         m_marginLeft = containerWidth - width() - m_marginRight;
   1469     } else {
   1470         // This makes auto margins 0 if we failed a width() < containerWidth test above (css2.1, 10.3.3).
   1471         m_marginLeft = marginLeft.calcMinValue(containerWidth);
   1472         m_marginRight = marginRight.calcMinValue(containerWidth);
   1473     }
   1474 }
   1475 
   1476 void RenderBox::calcHeight()
   1477 {
   1478     // Cell height is managed by the table and inline non-replaced elements do not support a height property.
   1479     if (isTableCell() || (isInline() && !isReplaced()))
   1480         return;
   1481 
   1482     Length h;
   1483     if (isPositioned())
   1484         calcAbsoluteVertical();
   1485     else {
   1486         calcVerticalMargins();
   1487 
   1488         // For tables, calculate margins only.
   1489         if (isTable())
   1490             return;
   1491 
   1492         bool inHorizontalBox = parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL;
   1493         bool stretching = parent()->style()->boxAlign() == BSTRETCH;
   1494         bool treatAsReplaced = shouldCalculateSizeAsReplaced() && (!inHorizontalBox || !stretching);
   1495         bool checkMinMaxHeight = false;
   1496 
   1497         // The parent box is flexing us, so it has increased or decreased our height.  We have to
   1498         // grab our cached flexible height.
   1499         if (hasOverrideSize() && parent()->isFlexibleBox() && parent()->style()->boxOrient() == VERTICAL
   1500                 && parent()->isFlexingChildren())
   1501             h = Length(overrideSize() - borderTop() - borderBottom() - paddingTop() - paddingBottom(), Fixed);
   1502         else if (treatAsReplaced)
   1503             h = Length(calcReplacedHeight(), Fixed);
   1504         else {
   1505             h = style()->height();
   1506             checkMinMaxHeight = true;
   1507         }
   1508 
   1509         // Block children of horizontal flexible boxes fill the height of the box.
   1510         if (h.isAuto() && parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
   1511                 && parent()->isStretchingChildren()) {
   1512             h = Length(parentBox()->contentHeight() - marginTop() - marginBottom() -
   1513                        borderTop() - paddingTop() - borderBottom() - paddingBottom(), Fixed);
   1514             checkMinMaxHeight = false;
   1515         }
   1516 
   1517         int heightResult;
   1518         if (checkMinMaxHeight) {
   1519 #ifdef ANDROID_LAYOUT
   1520             // in SSR mode, ignore CSS height as layout is so different
   1521             if (document()->settings()->layoutAlgorithm() == Settings::kLayoutSSR)
   1522                 heightResult = -1;
   1523             else
   1524 #endif
   1525             heightResult = calcHeightUsing(style()->height());
   1526             if (heightResult == -1)
   1527                 heightResult = height();
   1528             int minH = calcHeightUsing(style()->minHeight()); // Leave as -1 if unset.
   1529             int maxH = style()->maxHeight().isUndefined() ? heightResult : calcHeightUsing(style()->maxHeight());
   1530             if (maxH == -1)
   1531                 maxH = heightResult;
   1532             heightResult = min(maxH, heightResult);
   1533             heightResult = max(minH, heightResult);
   1534         } else {
   1535             // The only times we don't check min/max height are when a fixed length has
   1536             // been given as an override.  Just use that.  The value has already been adjusted
   1537             // for box-sizing.
   1538             heightResult = h.value() + borderTop() + borderBottom() + paddingTop() + paddingBottom();
   1539         }
   1540 
   1541         setHeight(heightResult);
   1542     }
   1543 
   1544     // WinIE quirk: The <html> block always fills the entire canvas in quirks mode.  The <body> always fills the
   1545     // <html> block in quirks mode.  Only apply this quirk if the block is normal flow and no height
   1546     // is specified. When we're printing, we also need this quirk if the body or root has a percentage
   1547     // height since we don't set a height in RenderView when we're printing. So without this quirk, the
   1548     // height has nothing to be a percentage of, and it ends up being 0. That is bad.
   1549     bool printingNeedsBaseHeight = document()->printing() && h.isPercent()
   1550         && (isRoot() || (isBody() && document()->documentElement()->renderer()->style()->height().isPercent()));
   1551     if (stretchesToViewHeight() || printingNeedsBaseHeight) {
   1552         int margins = collapsedMarginTop() + collapsedMarginBottom();
   1553         int visHeight = document()->printing() ? view()->frameView()->visibleHeight() : view()->viewHeight();
   1554         if (isRoot())
   1555             setHeight(max(height(), visHeight - margins));
   1556         else {
   1557             int marginsBordersPadding = margins + parentBox()->marginTop() + parentBox()->marginBottom()
   1558                 + parentBox()->borderTop() + parentBox()->borderBottom()
   1559                 + parentBox()->paddingTop() + parentBox()->paddingBottom();
   1560             setHeight(max(height(), visHeight - marginsBordersPadding));
   1561         }
   1562     }
   1563 }
   1564 
   1565 int RenderBox::calcHeightUsing(const Length& h)
   1566 {
   1567     int height = -1;
   1568     if (!h.isAuto()) {
   1569         if (h.isFixed())
   1570             height = h.value();
   1571         else if (h.isPercent())
   1572             height = calcPercentageHeight(h);
   1573         if (height != -1) {
   1574             height = calcBorderBoxHeight(height);
   1575             return height;
   1576         }
   1577     }
   1578     return height;
   1579 }
   1580 
   1581 int RenderBox::calcPercentageHeight(const Length& height)
   1582 {
   1583     int result = -1;
   1584     bool skippedAutoHeightContainingBlock = false;
   1585     RenderBlock* cb = containingBlock();
   1586     if (style()->htmlHacks()) {
   1587         // In quirks mode, blocks with auto height are skipped, and we keep looking for an enclosing
   1588         // block that may have a specified height and then use it.  In strict mode, this violates the
   1589         // specification, which states that percentage heights just revert to auto if the containing
   1590         // block has an auto height.
   1591         while (!cb->isRenderView() && !cb->isBody() && !cb->isTableCell() && !cb->isPositioned() && cb->style()->height().isAuto()) {
   1592             skippedAutoHeightContainingBlock = true;
   1593             cb = cb->containingBlock();
   1594             cb->addPercentHeightDescendant(this);
   1595         }
   1596     }
   1597 
   1598     // A positioned element that specified both top/bottom or that specifies height should be treated as though it has a height
   1599     // explicitly specified that can be used for any percentage computations.
   1600     bool isPositionedWithSpecifiedHeight = cb->isPositioned() && (!cb->style()->height().isAuto() || (!cb->style()->top().isAuto() && !cb->style()->bottom().isAuto()));
   1601 
   1602     bool includeBorderPadding = isTable();
   1603 
   1604     // Table cells violate what the CSS spec says to do with heights.  Basically we
   1605     // don't care if the cell specified a height or not.  We just always make ourselves
   1606     // be a percentage of the cell's current content height.
   1607     if (cb->isTableCell()) {
   1608         if (!skippedAutoHeightContainingBlock) {
   1609             result = cb->overrideSize();
   1610             if (result == -1) {
   1611                 // Normally we would let the cell size intrinsically, but scrolling overflow has to be
   1612                 // treated differently, since WinIE lets scrolled overflow regions shrink as needed.
   1613                 // While we can't get all cases right, we can at least detect when the cell has a specified
   1614                 // height or when the table has a specified height.  In these cases we want to initially have
   1615                 // no size and allow the flexing of the table or the cell to its specified height to cause us
   1616                 // to grow to fill the space.  This could end up being wrong in some cases, but it is
   1617                 // preferable to the alternative (sizing intrinsically and making the row end up too big).
   1618                 RenderTableCell* cell = toRenderTableCell(cb);
   1619                 if (scrollsOverflowY() && (!cell->style()->height().isAuto() || !cell->table()->style()->height().isAuto()))
   1620                     return 0;
   1621                 return -1;
   1622             }
   1623             includeBorderPadding = true;
   1624         }
   1625     }
   1626     // Otherwise we only use our percentage height if our containing block had a specified
   1627     // height.
   1628     else if (cb->style()->height().isFixed())
   1629         result = cb->calcContentBoxHeight(cb->style()->height().value());
   1630     else if (cb->style()->height().isPercent() && !isPositionedWithSpecifiedHeight) {
   1631         // We need to recur and compute the percentage height for our containing block.
   1632         result = cb->calcPercentageHeight(cb->style()->height());
   1633         if (result != -1)
   1634             result = cb->calcContentBoxHeight(result);
   1635     } else if (cb->isRenderView() || (cb->isBody() && style()->htmlHacks()) || isPositionedWithSpecifiedHeight) {
   1636         // Don't allow this to affect the block' height() member variable, since this
   1637         // can get called while the block is still laying out its kids.
   1638         int oldHeight = cb->height();
   1639         cb->calcHeight();
   1640         result = cb->contentHeight();
   1641         cb->setHeight(oldHeight);
   1642     } else if (cb->isRoot() && isPositioned())
   1643         // Match the positioned objects behavior, which is that positioned objects will fill their viewport
   1644         // always.  Note we could only hit this case by recurring into calcPercentageHeight on a positioned containing block.
   1645         result = cb->calcContentBoxHeight(cb->availableHeight());
   1646 
   1647     if (result != -1) {
   1648         result = height.calcValue(result);
   1649         if (includeBorderPadding) {
   1650             // It is necessary to use the border-box to match WinIE's broken
   1651             // box model.  This is essential for sizing inside
   1652             // table cells using percentage heights.
   1653             result -= (borderTop() + paddingTop() + borderBottom() + paddingBottom());
   1654             result = max(0, result);
   1655         }
   1656     }
   1657     return result;
   1658 }
   1659 
   1660 int RenderBox::calcReplacedWidth(bool includeMaxWidth) const
   1661 {
   1662     int width = calcReplacedWidthUsing(style()->width());
   1663     int minW = calcReplacedWidthUsing(style()->minWidth());
   1664     int maxW = !includeMaxWidth || style()->maxWidth().isUndefined() ? width : calcReplacedWidthUsing(style()->maxWidth());
   1665 
   1666     return max(minW, min(width, maxW));
   1667 }
   1668 
   1669 int RenderBox::calcReplacedWidthUsing(Length width) const
   1670 {
   1671     switch (width.type()) {
   1672         case Fixed:
   1673             return calcContentBoxWidth(width.value());
   1674         case Percent: {
   1675             const int cw = isPositioned() ? containingBlockWidthForPositioned(toRenderBoxModelObject(container())) : containingBlockWidthForContent();
   1676             if (cw > 0)
   1677                 return calcContentBoxWidth(width.calcMinValue(cw));
   1678         }
   1679         // fall through
   1680         default:
   1681             return intrinsicSize().width();
   1682      }
   1683 }
   1684 
   1685 int RenderBox::calcReplacedHeight() const
   1686 {
   1687     int height = calcReplacedHeightUsing(style()->height());
   1688     int minH = calcReplacedHeightUsing(style()->minHeight());
   1689     int maxH = style()->maxHeight().isUndefined() ? height : calcReplacedHeightUsing(style()->maxHeight());
   1690 
   1691     return max(minH, min(height, maxH));
   1692 }
   1693 
   1694 int RenderBox::calcReplacedHeightUsing(Length height) const
   1695 {
   1696     switch (height.type()) {
   1697         case Fixed:
   1698             return calcContentBoxHeight(height.value());
   1699         case Percent:
   1700         {
   1701             RenderObject* cb = isPositioned() ? container() : containingBlock();
   1702             while (cb->isAnonymous()) {
   1703                 cb = cb->containingBlock();
   1704                 toRenderBlock(cb)->addPercentHeightDescendant(const_cast<RenderBox*>(this));
   1705             }
   1706 
   1707             if (cb->isPositioned() && cb->style()->height().isAuto() && !(cb->style()->top().isAuto() || cb->style()->bottom().isAuto())) {
   1708                 ASSERT(cb->isRenderBlock());
   1709                 RenderBlock* block = toRenderBlock(cb);
   1710                 int oldHeight = block->height();
   1711                 block->calcHeight();
   1712                 int newHeight = block->calcContentBoxHeight(block->contentHeight());
   1713                 block->setHeight(oldHeight);
   1714                 return calcContentBoxHeight(height.calcValue(newHeight));
   1715             }
   1716 
   1717             int availableHeight = isPositioned() ? containingBlockHeightForPositioned(toRenderBoxModelObject(cb)) : toRenderBox(cb)->availableHeight();
   1718 
   1719             // It is necessary to use the border-box to match WinIE's broken
   1720             // box model.  This is essential for sizing inside
   1721             // table cells using percentage heights.
   1722             if (cb->isTableCell() && (cb->style()->height().isAuto() || cb->style()->height().isPercent())) {
   1723                 // Don't let table cells squeeze percent-height replaced elements
   1724                 // <http://bugs.webkit.org/show_bug.cgi?id=15359>
   1725                 availableHeight = max(availableHeight, intrinsicSize().height());
   1726                 return height.calcValue(availableHeight - (borderTop() + borderBottom()
   1727                     + paddingTop() + paddingBottom()));
   1728             }
   1729 
   1730             return calcContentBoxHeight(height.calcValue(availableHeight));
   1731         }
   1732         default:
   1733             return intrinsicSize().height();
   1734     }
   1735 }
   1736 
   1737 int RenderBox::availableHeight() const
   1738 {
   1739     return availableHeightUsing(style()->height());
   1740 }
   1741 
   1742 int RenderBox::availableHeightUsing(const Length& h) const
   1743 {
   1744     if (h.isFixed())
   1745         return calcContentBoxHeight(h.value());
   1746 
   1747     if (isRenderView())
   1748         return toRenderView(this)->frameView()->visibleHeight();
   1749 
   1750     // We need to stop here, since we don't want to increase the height of the table
   1751     // artificially.  We're going to rely on this cell getting expanded to some new
   1752     // height, and then when we lay out again we'll use the calculation below.
   1753     if (isTableCell() && (h.isAuto() || h.isPercent()))
   1754         return overrideSize() - (borderLeft() + borderRight() + paddingLeft() + paddingRight());
   1755 
   1756     if (h.isPercent())
   1757        return calcContentBoxHeight(h.calcValue(containingBlock()->availableHeight()));
   1758 
   1759     if (isRenderBlock() && isPositioned() && style()->height().isAuto() && !(style()->top().isAuto() || style()->bottom().isAuto())) {
   1760         RenderBlock* block = const_cast<RenderBlock*>(toRenderBlock(this));
   1761         int oldHeight = block->height();
   1762         block->calcHeight();
   1763         int newHeight = block->calcContentBoxHeight(block->contentHeight());
   1764         block->setHeight(oldHeight);
   1765         return calcContentBoxHeight(newHeight);
   1766     }
   1767 
   1768     return containingBlock()->availableHeight();
   1769 }
   1770 
   1771 void RenderBox::calcVerticalMargins()
   1772 {
   1773     if (isTableCell()) {
   1774         m_marginTop = 0;
   1775         m_marginBottom = 0;
   1776         return;
   1777     }
   1778 
   1779     // margins are calculated with respect to the _width_ of
   1780     // the containing block (8.3)
   1781     int cw = containingBlock()->contentWidth();
   1782 
   1783     m_marginTop = style()->marginTop().calcMinValue(cw);
   1784     m_marginBottom = style()->marginBottom().calcMinValue(cw);
   1785 }
   1786 
   1787 int RenderBox::containingBlockWidthForPositioned(const RenderBoxModelObject* containingBlock) const
   1788 {
   1789     if (containingBlock->isBox()) {
   1790         const RenderBox* containingBlockBox = toRenderBox(containingBlock);
   1791         return containingBlockBox->width() - containingBlockBox->borderLeft() - containingBlockBox->borderRight() - containingBlockBox->verticalScrollbarWidth();
   1792     }
   1793 
   1794     ASSERT(containingBlock->isRenderInline() && containingBlock->isRelPositioned());
   1795 
   1796     const RenderInline* flow = toRenderInline(containingBlock);
   1797     InlineFlowBox* first = flow->firstLineBox();
   1798     InlineFlowBox* last = flow->lastLineBox();
   1799 
   1800     // If the containing block is empty, return a width of 0.
   1801     if (!first || !last)
   1802         return 0;
   1803 
   1804     int fromLeft;
   1805     int fromRight;
   1806     if (containingBlock->style()->direction() == LTR) {
   1807         fromLeft = first->x() + first->borderLeft();
   1808         fromRight = last->x() + last->width() - last->borderRight();
   1809     } else {
   1810         fromRight = first->x() + first->width() - first->borderRight();
   1811         fromLeft = last->x() + last->borderLeft();
   1812     }
   1813 
   1814     return max(0, (fromRight - fromLeft));
   1815 }
   1816 
   1817 int RenderBox::containingBlockHeightForPositioned(const RenderBoxModelObject* containingBlock) const
   1818 {
   1819     int heightResult = 0;
   1820     if (containingBlock->isBox())
   1821          heightResult = toRenderBox(containingBlock)->height();
   1822     else if (containingBlock->isRenderInline()) {
   1823         ASSERT(containingBlock->isRelPositioned());
   1824         heightResult = toRenderInline(containingBlock)->linesBoundingBox().height();
   1825     }
   1826     return heightResult - containingBlock->borderTop() - containingBlock->borderBottom();
   1827 }
   1828 
   1829 void RenderBox::calcAbsoluteHorizontal()
   1830 {
   1831     if (isReplaced()) {
   1832         calcAbsoluteHorizontalReplaced();
   1833         return;
   1834     }
   1835 
   1836     // QUESTIONS
   1837     // FIXME 1: Which RenderObject's 'direction' property should used: the
   1838     // containing block (cb) as the spec seems to imply, the parent (parent()) as
   1839     // was previously done in calculating the static distances, or ourself, which
   1840     // was also previously done for deciding what to override when you had
   1841     // over-constrained margins?  Also note that the container block is used
   1842     // in similar situations in other parts of the RenderBox class (see calcWidth()
   1843     // and calcHorizontalMargins()). For now we are using the parent for quirks
   1844     // mode and the containing block for strict mode.
   1845 
   1846     // FIXME 2: Should we still deal with these the cases of 'left' or 'right' having
   1847     // the type 'static' in determining whether to calculate the static distance?
   1848     // NOTE: 'static' is not a legal value for 'left' or 'right' as of CSS 2.1.
   1849 
   1850     // FIXME 3: Can perhaps optimize out cases when max-width/min-width are greater
   1851     // than or less than the computed width().  Be careful of box-sizing and
   1852     // percentage issues.
   1853 
   1854     // The following is based off of the W3C Working Draft from April 11, 2006 of
   1855     // CSS 2.1: Section 10.3.7 "Absolutely positioned, non-replaced elements"
   1856     // <http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width>
   1857     // (block-style-comments in this function and in calcAbsoluteHorizontalValues()
   1858     // correspond to text from the spec)
   1859 
   1860 
   1861     // We don't use containingBlock(), since we may be positioned by an enclosing
   1862     // relative positioned inline.
   1863     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
   1864 
   1865     const int containerWidth = containingBlockWidthForPositioned(containerBlock);
   1866 
   1867     // To match WinIE, in quirks mode use the parent's 'direction' property
   1868     // instead of the the container block's.
   1869     TextDirection containerDirection = (style()->htmlHacks()) ? parent()->style()->direction() : containerBlock->style()->direction();
   1870 
   1871     const int bordersPlusPadding = borderLeft() + borderRight() + paddingLeft() + paddingRight();
   1872     const Length marginLeft = style()->marginLeft();
   1873     const Length marginRight = style()->marginRight();
   1874     Length left = style()->left();
   1875     Length right = style()->right();
   1876 
   1877     /*---------------------------------------------------------------------------*\
   1878      * For the purposes of this section and the next, the term "static position"
   1879      * (of an element) refers, roughly, to the position an element would have had
   1880      * in the normal flow. More precisely:
   1881      *
   1882      * * The static position for 'left' is the distance from the left edge of the
   1883      *   containing block to the left margin edge of a hypothetical box that would
   1884      *   have been the first box of the element if its 'position' property had
   1885      *   been 'static' and 'float' had been 'none'. The value is negative if the
   1886      *   hypothetical box is to the left of the containing block.
   1887      * * The static position for 'right' is the distance from the right edge of the
   1888      *   containing block to the right margin edge of the same hypothetical box as
   1889      *   above. The value is positive if the hypothetical box is to the left of the
   1890      *   containing block's edge.
   1891      *
   1892      * But rather than actually calculating the dimensions of that hypothetical box,
   1893      * user agents are free to make a guess at its probable position.
   1894      *
   1895      * For the purposes of calculating the static position, the containing block of
   1896      * fixed positioned elements is the initial containing block instead of the
   1897      * viewport, and all scrollable boxes should be assumed to be scrolled to their
   1898      * origin.
   1899     \*---------------------------------------------------------------------------*/
   1900 
   1901     // see FIXME 2
   1902     // Calculate the static distance if needed.
   1903     if (left.isAuto() && right.isAuto()) {
   1904         if (containerDirection == LTR) {
   1905             // 'staticX' should already have been set through layout of the parent.
   1906             int staticPosition = layer()->staticX() - containerBlock->borderLeft();
   1907             for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) {
   1908                 if (po->isBox())
   1909                     staticPosition += toRenderBox(po)->x();
   1910             }
   1911             left.setValue(Fixed, staticPosition);
   1912         } else {
   1913             RenderObject* po = parent();
   1914             // 'staticX' should already have been set through layout of the parent.
   1915             int staticPosition = layer()->staticX() + containerWidth + containerBlock->borderRight();
   1916             if (po->isBox())
   1917                 staticPosition -= toRenderBox(po)->width();
   1918             for (; po && po != containerBlock; po = po->parent()) {
   1919                 if (po->isBox())
   1920                     staticPosition -= toRenderBox(po)->x();
   1921             }
   1922             right.setValue(Fixed, staticPosition);
   1923         }
   1924     }
   1925 
   1926     // Calculate constraint equation values for 'width' case.
   1927     int widthResult;
   1928     int xResult;
   1929     calcAbsoluteHorizontalValues(style()->width(), containerBlock, containerDirection,
   1930                                  containerWidth, bordersPlusPadding,
   1931                                  left, right, marginLeft, marginRight,
   1932                                  widthResult, m_marginLeft, m_marginRight, xResult);
   1933     setWidth(widthResult);
   1934     setX(xResult);
   1935 
   1936     // Calculate constraint equation values for 'max-width' case.
   1937     if (!style()->maxWidth().isUndefined()) {
   1938         int maxWidth;
   1939         int maxMarginLeft;
   1940         int maxMarginRight;
   1941         int maxXPos;
   1942 
   1943         calcAbsoluteHorizontalValues(style()->maxWidth(), containerBlock, containerDirection,
   1944                                      containerWidth, bordersPlusPadding,
   1945                                      left, right, marginLeft, marginRight,
   1946                                      maxWidth, maxMarginLeft, maxMarginRight, maxXPos);
   1947 
   1948         if (width() > maxWidth) {
   1949             setWidth(maxWidth);
   1950             m_marginLeft = maxMarginLeft;
   1951             m_marginRight = maxMarginRight;
   1952             m_frameRect.setX(maxXPos);
   1953         }
   1954     }
   1955 
   1956     // Calculate constraint equation values for 'min-width' case.
   1957     if (!style()->minWidth().isZero()) {
   1958         int minWidth;
   1959         int minMarginLeft;
   1960         int minMarginRight;
   1961         int minXPos;
   1962 
   1963         calcAbsoluteHorizontalValues(style()->minWidth(), containerBlock, containerDirection,
   1964                                      containerWidth, bordersPlusPadding,
   1965                                      left, right, marginLeft, marginRight,
   1966                                      minWidth, minMarginLeft, minMarginRight, minXPos);
   1967 
   1968         if (width() < minWidth) {
   1969             setWidth(minWidth);
   1970             m_marginLeft = minMarginLeft;
   1971             m_marginRight = minMarginRight;
   1972             m_frameRect.setX(minXPos);
   1973         }
   1974     }
   1975 
   1976     if (stretchesToMinIntrinsicWidth() && width() < minPrefWidth() - bordersPlusPadding) {
   1977         calcAbsoluteHorizontalValues(Length(minPrefWidth() - bordersPlusPadding, Fixed), containerBlock, containerDirection,
   1978                                      containerWidth, bordersPlusPadding,
   1979                                      left, right, marginLeft, marginRight,
   1980                                      widthResult, m_marginLeft, m_marginRight, xResult);
   1981         setWidth(widthResult);
   1982         setX(xResult);
   1983     }
   1984 
   1985     // Put width() into correct form.
   1986     setWidth(width() + bordersPlusPadding);
   1987 }
   1988 
   1989 void RenderBox::calcAbsoluteHorizontalValues(Length width, const RenderBoxModelObject* containerBlock, TextDirection containerDirection,
   1990                                              const int containerWidth, const int bordersPlusPadding,
   1991                                              const Length left, const Length right, const Length marginLeft, const Length marginRight,
   1992                                              int& widthValue, int& marginLeftValue, int& marginRightValue, int& xPos)
   1993 {
   1994     // 'left' and 'right' cannot both be 'auto' because one would of been
   1995     // converted to the static position already
   1996     ASSERT(!(left.isAuto() && right.isAuto()));
   1997 
   1998     int leftValue = 0;
   1999 
   2000     bool widthIsAuto = width.isIntrinsicOrAuto();
   2001     bool leftIsAuto = left.isAuto();
   2002     bool rightIsAuto = right.isAuto();
   2003 
   2004     if (!leftIsAuto && !widthIsAuto && !rightIsAuto) {
   2005         /*-----------------------------------------------------------------------*\
   2006          * If none of the three is 'auto': If both 'margin-left' and 'margin-
   2007          * right' are 'auto', solve the equation under the extra constraint that
   2008          * the two margins get equal values, unless this would make them negative,
   2009          * in which case when direction of the containing block is 'ltr' ('rtl'),
   2010          * set 'margin-left' ('margin-right') to zero and solve for 'margin-right'
   2011          * ('margin-left'). If one of 'margin-left' or 'margin-right' is 'auto',
   2012          * solve the equation for that value. If the values are over-constrained,
   2013          * ignore the value for 'left' (in case the 'direction' property of the
   2014          * containing block is 'rtl') or 'right' (in case 'direction' is 'ltr')
   2015          * and solve for that value.
   2016         \*-----------------------------------------------------------------------*/
   2017         // NOTE:  It is not necessary to solve for 'right' in the over constrained
   2018         // case because the value is not used for any further calculations.
   2019 
   2020         leftValue = left.calcValue(containerWidth);
   2021         widthValue = calcContentBoxWidth(width.calcValue(containerWidth));
   2022 
   2023         const int availableSpace = containerWidth - (leftValue + widthValue + right.calcValue(containerWidth) + bordersPlusPadding);
   2024 
   2025         // Margins are now the only unknown
   2026         if (marginLeft.isAuto() && marginRight.isAuto()) {
   2027             // Both margins auto, solve for equality
   2028             if (availableSpace >= 0) {
   2029                 marginLeftValue = availableSpace / 2; // split the difference
   2030                 marginRightValue = availableSpace - marginLeftValue;  // account for odd valued differences
   2031             } else {
   2032                 // see FIXME 1
   2033                 if (containerDirection == LTR) {
   2034                     marginLeftValue = 0;
   2035                     marginRightValue = availableSpace; // will be negative
   2036                 } else {
   2037                     marginLeftValue = availableSpace; // will be negative
   2038                     marginRightValue = 0;
   2039                 }
   2040             }
   2041         } else if (marginLeft.isAuto()) {
   2042             // Solve for left margin
   2043             marginRightValue = marginRight.calcValue(containerWidth);
   2044             marginLeftValue = availableSpace - marginRightValue;
   2045         } else if (marginRight.isAuto()) {
   2046             // Solve for right margin
   2047             marginLeftValue = marginLeft.calcValue(containerWidth);
   2048             marginRightValue = availableSpace - marginLeftValue;
   2049         } else {
   2050             // Over-constrained, solve for left if direction is RTL
   2051             marginLeftValue = marginLeft.calcValue(containerWidth);
   2052             marginRightValue = marginRight.calcValue(containerWidth);
   2053 
   2054             // see FIXME 1 -- used to be "this->style()->direction()"
   2055             if (containerDirection == RTL)
   2056                 leftValue = (availableSpace + leftValue) - marginLeftValue - marginRightValue;
   2057         }
   2058     } else {
   2059         /*--------------------------------------------------------------------*\
   2060          * Otherwise, set 'auto' values for 'margin-left' and 'margin-right'
   2061          * to 0, and pick the one of the following six rules that applies.
   2062          *
   2063          * 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the
   2064          *    width is shrink-to-fit. Then solve for 'left'
   2065          *
   2066          *              OMIT RULE 2 AS IT SHOULD NEVER BE HIT
   2067          * ------------------------------------------------------------------
   2068          * 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if
   2069          *    the 'direction' property of the containing block is 'ltr' set
   2070          *    'left' to the static position, otherwise set 'right' to the
   2071          *    static position. Then solve for 'left' (if 'direction is 'rtl')
   2072          *    or 'right' (if 'direction' is 'ltr').
   2073          * ------------------------------------------------------------------
   2074          *
   2075          * 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the
   2076          *    width is shrink-to-fit . Then solve for 'right'
   2077          * 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve
   2078          *    for 'left'
   2079          * 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve
   2080          *    for 'width'
   2081          * 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve
   2082          *    for 'right'
   2083          *
   2084          * Calculation of the shrink-to-fit width is similar to calculating the
   2085          * width of a table cell using the automatic table layout algorithm.
   2086          * Roughly: calculate the preferred width by formatting the content
   2087          * without breaking lines other than where explicit line breaks occur,
   2088          * and also calculate the preferred minimum width, e.g., by trying all
   2089          * possible line breaks. CSS 2.1 does not define the exact algorithm.
   2090          * Thirdly, calculate the available width: this is found by solving
   2091          * for 'width' after setting 'left' (in case 1) or 'right' (in case 3)
   2092          * to 0.
   2093          *
   2094          * Then the shrink-to-fit width is:
   2095          * min(max(preferred minimum width, available width), preferred width).
   2096         \*--------------------------------------------------------------------*/
   2097         // NOTE: For rules 3 and 6 it is not necessary to solve for 'right'
   2098         // because the value is not used for any further calculations.
   2099 
   2100         // Calculate margins, 'auto' margins are ignored.
   2101         marginLeftValue = marginLeft.calcMinValue(containerWidth);
   2102         marginRightValue = marginRight.calcMinValue(containerWidth);
   2103 
   2104         const int availableSpace = containerWidth - (marginLeftValue + marginRightValue + bordersPlusPadding);
   2105 
   2106         // FIXME: Is there a faster way to find the correct case?
   2107         // Use rule/case that applies.
   2108         if (leftIsAuto && widthIsAuto && !rightIsAuto) {
   2109             // RULE 1: (use shrink-to-fit for width, and solve of left)
   2110             int rightValue = right.calcValue(containerWidth);
   2111 
   2112             // FIXME: would it be better to have shrink-to-fit in one step?
   2113             int preferredWidth = maxPrefWidth() - bordersPlusPadding;
   2114             int preferredMinWidth = minPrefWidth() - bordersPlusPadding;
   2115             int availableWidth = availableSpace - rightValue;
   2116             widthValue = min(max(preferredMinWidth, availableWidth), preferredWidth);
   2117             leftValue = availableSpace - (widthValue + rightValue);
   2118         } else if (!leftIsAuto && widthIsAuto && rightIsAuto) {
   2119             // RULE 3: (use shrink-to-fit for width, and no need solve of right)
   2120             leftValue = left.calcValue(containerWidth);
   2121 
   2122             // FIXME: would it be better to have shrink-to-fit in one step?
   2123             int preferredWidth = maxPrefWidth() - bordersPlusPadding;
   2124             int preferredMinWidth = minPrefWidth() - bordersPlusPadding;
   2125             int availableWidth = availableSpace - leftValue;
   2126             widthValue = min(max(preferredMinWidth, availableWidth), preferredWidth);
   2127         } else if (leftIsAuto && !width.isAuto() && !rightIsAuto) {
   2128             // RULE 4: (solve for left)
   2129             widthValue = calcContentBoxWidth(width.calcValue(containerWidth));
   2130             leftValue = availableSpace - (widthValue + right.calcValue(containerWidth));
   2131         } else if (!leftIsAuto && widthIsAuto && !rightIsAuto) {
   2132             // RULE 5: (solve for width)
   2133             leftValue = left.calcValue(containerWidth);
   2134             widthValue = availableSpace - (leftValue + right.calcValue(containerWidth));
   2135         } else if (!leftIsAuto&& !widthIsAuto && rightIsAuto) {
   2136             // RULE 6: (no need solve for right)
   2137             leftValue = left.calcValue(containerWidth);
   2138             widthValue = calcContentBoxWidth(width.calcValue(containerWidth));
   2139         }
   2140     }
   2141 
   2142     // Use computed values to calculate the horizontal position.
   2143 
   2144     // FIXME: This hack is needed to calculate the xPos for a 'rtl' relatively
   2145     // positioned, inline because right now, it is using the xPos
   2146     // of the first line box when really it should use the last line box.  When
   2147     // this is fixed elsewhere, this block should be removed.
   2148     if (containerBlock->isRenderInline() && containerBlock->style()->direction() == RTL) {
   2149         const RenderInline* flow = toRenderInline(containerBlock);
   2150         InlineFlowBox* firstLine = flow->firstLineBox();
   2151         InlineFlowBox* lastLine = flow->lastLineBox();
   2152         if (firstLine && lastLine && firstLine != lastLine) {
   2153             xPos = leftValue + marginLeftValue + lastLine->borderLeft() + (lastLine->x() - firstLine->x());
   2154             return;
   2155         }
   2156     }
   2157 
   2158     xPos = leftValue + marginLeftValue + containerBlock->borderLeft();
   2159 }
   2160 
   2161 void RenderBox::calcAbsoluteVertical()
   2162 {
   2163     if (isReplaced()) {
   2164         calcAbsoluteVerticalReplaced();
   2165         return;
   2166     }
   2167 
   2168     // The following is based off of the W3C Working Draft from April 11, 2006 of
   2169     // CSS 2.1: Section 10.6.4 "Absolutely positioned, non-replaced elements"
   2170     // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-non-replaced-height>
   2171     // (block-style-comments in this function and in calcAbsoluteVerticalValues()
   2172     // correspond to text from the spec)
   2173 
   2174 
   2175     // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
   2176     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
   2177 
   2178     const int containerHeight = containingBlockHeightForPositioned(containerBlock);
   2179 
   2180     const int bordersPlusPadding = borderTop() + borderBottom() + paddingTop() + paddingBottom();
   2181     const Length marginTop = style()->marginTop();
   2182     const Length marginBottom = style()->marginBottom();
   2183     Length top = style()->top();
   2184     Length bottom = style()->bottom();
   2185 
   2186     /*---------------------------------------------------------------------------*\
   2187      * For the purposes of this section and the next, the term "static position"
   2188      * (of an element) refers, roughly, to the position an element would have had
   2189      * in the normal flow. More precisely, the static position for 'top' is the
   2190      * distance from the top edge of the containing block to the top margin edge
   2191      * of a hypothetical box that would have been the first box of the element if
   2192      * its 'position' property had been 'static' and 'float' had been 'none'. The
   2193      * value is negative if the hypothetical box is above the containing block.
   2194      *
   2195      * But rather than actually calculating the dimensions of that hypothetical
   2196      * box, user agents are free to make a guess at its probable position.
   2197      *
   2198      * For the purposes of calculating the static position, the containing block
   2199      * of fixed positioned elements is the initial containing block instead of
   2200      * the viewport.
   2201     \*---------------------------------------------------------------------------*/
   2202 
   2203     // see FIXME 2
   2204     // Calculate the static distance if needed.
   2205     if (top.isAuto() && bottom.isAuto()) {
   2206         // staticY should already have been set through layout of the parent()
   2207         int staticTop = layer()->staticY() - containerBlock->borderTop();
   2208         for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) {
   2209             if (po->isBox() && !po->isTableRow())
   2210                 staticTop += toRenderBox(po)->y();
   2211         }
   2212         top.setValue(Fixed, staticTop);
   2213     }
   2214 
   2215 
   2216     int h; // Needed to compute overflow.
   2217     int y;
   2218 
   2219     // Calculate constraint equation values for 'height' case.
   2220     calcAbsoluteVerticalValues(style()->height(), containerBlock, containerHeight, bordersPlusPadding,
   2221                                top, bottom, marginTop, marginBottom,
   2222                                h, m_marginTop, m_marginBottom, y);
   2223     setY(y);
   2224 
   2225     // Avoid doing any work in the common case (where the values of min-height and max-height are their defaults).
   2226     // see FIXME 3
   2227 
   2228     // Calculate constraint equation values for 'max-height' case.
   2229     if (!style()->maxHeight().isUndefined()) {
   2230         int maxHeight;
   2231         int maxMarginTop;
   2232         int maxMarginBottom;
   2233         int maxYPos;
   2234 
   2235         calcAbsoluteVerticalValues(style()->maxHeight(), containerBlock, containerHeight, bordersPlusPadding,
   2236                                    top, bottom, marginTop, marginBottom,
   2237                                    maxHeight, maxMarginTop, maxMarginBottom, maxYPos);
   2238 
   2239         if (h > maxHeight) {
   2240             h = maxHeight;
   2241             m_marginTop = maxMarginTop;
   2242             m_marginBottom = maxMarginBottom;
   2243             m_frameRect.setY(maxYPos);
   2244         }
   2245     }
   2246 
   2247     // Calculate constraint equation values for 'min-height' case.
   2248     if (!style()->minHeight().isZero()) {
   2249         int minHeight;
   2250         int minMarginTop;
   2251         int minMarginBottom;
   2252         int minYPos;
   2253 
   2254         calcAbsoluteVerticalValues(style()->minHeight(), containerBlock, containerHeight, bordersPlusPadding,
   2255                                    top, bottom, marginTop, marginBottom,
   2256                                    minHeight, minMarginTop, minMarginBottom, minYPos);
   2257 
   2258         if (h < minHeight) {
   2259             h = minHeight;
   2260             m_marginTop = minMarginTop;
   2261             m_marginBottom = minMarginBottom;
   2262             m_frameRect.setY(minYPos);
   2263         }
   2264     }
   2265 
   2266     // Set final height value.
   2267     setHeight(h + bordersPlusPadding);
   2268 }
   2269 
   2270 void RenderBox::calcAbsoluteVerticalValues(Length h, const RenderBoxModelObject* containerBlock,
   2271                                            const int containerHeight, const int bordersPlusPadding,
   2272                                            const Length top, const Length bottom, const Length marginTop, const Length marginBottom,
   2273                                            int& heightValue, int& marginTopValue, int& marginBottomValue, int& yPos)
   2274 {
   2275     // 'top' and 'bottom' cannot both be 'auto' because 'top would of been
   2276     // converted to the static position in calcAbsoluteVertical()
   2277     ASSERT(!(top.isAuto() && bottom.isAuto()));
   2278 
   2279     int contentHeight = height() - bordersPlusPadding;
   2280 
   2281     int topValue = 0;
   2282 
   2283     bool heightIsAuto = h.isAuto();
   2284     bool topIsAuto = top.isAuto();
   2285     bool bottomIsAuto = bottom.isAuto();
   2286 
   2287     // Height is never unsolved for tables.
   2288     if (isTable()) {
   2289         h.setValue(Fixed, contentHeight);
   2290         heightIsAuto = false;
   2291     }
   2292 
   2293     if (!topIsAuto && !heightIsAuto && !bottomIsAuto) {
   2294         /*-----------------------------------------------------------------------*\
   2295          * If none of the three are 'auto': If both 'margin-top' and 'margin-
   2296          * bottom' are 'auto', solve the equation under the extra constraint that
   2297          * the two margins get equal values. If one of 'margin-top' or 'margin-
   2298          * bottom' is 'auto', solve the equation for that value. If the values
   2299          * are over-constrained, ignore the value for 'bottom' and solve for that
   2300          * value.
   2301         \*-----------------------------------------------------------------------*/
   2302         // NOTE:  It is not necessary to solve for 'bottom' in the over constrained
   2303         // case because the value is not used for any further calculations.
   2304 
   2305         heightValue = calcContentBoxHeight(h.calcValue(containerHeight));
   2306         topValue = top.calcValue(containerHeight);
   2307 
   2308         const int availableSpace = containerHeight - (topValue + heightValue + bottom.calcValue(containerHeight) + bordersPlusPadding);
   2309 
   2310         // Margins are now the only unknown
   2311         if (marginTop.isAuto() && marginBottom.isAuto()) {
   2312             // Both margins auto, solve for equality
   2313             // NOTE: This may result in negative values.
   2314             marginTopValue = availableSpace / 2; // split the difference
   2315             marginBottomValue = availableSpace - marginTopValue; // account for odd valued differences
   2316         } else if (marginTop.isAuto()) {
   2317             // Solve for top margin
   2318             marginBottomValue = marginBottom.calcValue(containerHeight);
   2319             marginTopValue = availableSpace - marginBottomValue;
   2320         } else if (marginBottom.isAuto()) {
   2321             // Solve for bottom margin
   2322             marginTopValue = marginTop.calcValue(containerHeight);
   2323             marginBottomValue = availableSpace - marginTopValue;
   2324         } else {
   2325             // Over-constrained, (no need solve for bottom)
   2326             marginTopValue = marginTop.calcValue(containerHeight);
   2327             marginBottomValue = marginBottom.calcValue(containerHeight);
   2328         }
   2329     } else {
   2330         /*--------------------------------------------------------------------*\
   2331          * Otherwise, set 'auto' values for 'margin-top' and 'margin-bottom'
   2332          * to 0, and pick the one of the following six rules that applies.
   2333          *
   2334          * 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then
   2335          *    the height is based on the content, and solve for 'top'.
   2336          *
   2337          *              OMIT RULE 2 AS IT SHOULD NEVER BE HIT
   2338          * ------------------------------------------------------------------
   2339          * 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then
   2340          *    set 'top' to the static position, and solve for 'bottom'.
   2341          * ------------------------------------------------------------------
   2342          *
   2343          * 3. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then
   2344          *    the height is based on the content, and solve for 'bottom'.
   2345          * 4. 'top' is 'auto', 'height' and 'bottom' are not 'auto', and
   2346          *    solve for 'top'.
   2347          * 5. 'height' is 'auto', 'top' and 'bottom' are not 'auto', and
   2348          *    solve for 'height'.
   2349          * 6. 'bottom' is 'auto', 'top' and 'height' are not 'auto', and
   2350          *    solve for 'bottom'.
   2351         \*--------------------------------------------------------------------*/
   2352         // NOTE: For rules 3 and 6 it is not necessary to solve for 'bottom'
   2353         // because the value is not used for any further calculations.
   2354 
   2355         // Calculate margins, 'auto' margins are ignored.
   2356         marginTopValue = marginTop.calcMinValue(containerHeight);
   2357         marginBottomValue = marginBottom.calcMinValue(containerHeight);
   2358 
   2359         const int availableSpace = containerHeight - (marginTopValue + marginBottomValue + bordersPlusPadding);
   2360 
   2361         // Use rule/case that applies.
   2362         if (topIsAuto && heightIsAuto && !bottomIsAuto) {
   2363             // RULE 1: (height is content based, solve of top)
   2364             heightValue = contentHeight;
   2365             topValue = availableSpace - (heightValue + bottom.calcValue(containerHeight));
   2366         } else if (!topIsAuto && heightIsAuto && bottomIsAuto) {
   2367             // RULE 3: (height is content based, no need solve of bottom)
   2368             topValue = top.calcValue(containerHeight);
   2369             heightValue = contentHeight;
   2370         } else if (topIsAuto && !heightIsAuto && !bottomIsAuto) {
   2371             // RULE 4: (solve of top)
   2372             heightValue = calcContentBoxHeight(h.calcValue(containerHeight));
   2373             topValue = availableSpace - (heightValue + bottom.calcValue(containerHeight));
   2374         } else if (!topIsAuto && heightIsAuto && !bottomIsAuto) {
   2375             // RULE 5: (solve of height)
   2376             topValue = top.calcValue(containerHeight);
   2377             heightValue = max(0, availableSpace - (topValue + bottom.calcValue(containerHeight)));
   2378         } else if (!topIsAuto && !heightIsAuto && bottomIsAuto) {
   2379             // RULE 6: (no need solve of bottom)
   2380             heightValue = calcContentBoxHeight(h.calcValue(containerHeight));
   2381             topValue = top.calcValue(containerHeight);
   2382         }
   2383     }
   2384 
   2385     // Use computed values to calculate the vertical position.
   2386     yPos = topValue + marginTopValue + containerBlock->borderTop();
   2387 }
   2388 
   2389 void RenderBox::calcAbsoluteHorizontalReplaced()
   2390 {
   2391     // The following is based off of the W3C Working Draft from April 11, 2006 of
   2392     // CSS 2.1: Section 10.3.8 "Absolutely positioned, replaced elements"
   2393     // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-width>
   2394     // (block-style-comments in this function correspond to text from the spec and
   2395     // the numbers correspond to numbers in spec)
   2396 
   2397     // We don't use containingBlock(), since we may be positioned by an enclosing
   2398     // relative positioned inline.
   2399     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
   2400 
   2401     const int containerWidth = containingBlockWidthForPositioned(containerBlock);
   2402 
   2403     // To match WinIE, in quirks mode use the parent's 'direction' property
   2404     // instead of the the container block's.
   2405     TextDirection containerDirection = (style()->htmlHacks()) ? parent()->style()->direction() : containerBlock->style()->direction();
   2406 
   2407     // Variables to solve.
   2408     Length left = style()->left();
   2409     Length right = style()->right();
   2410     Length marginLeft = style()->marginLeft();
   2411     Length marginRight = style()->marginRight();
   2412 
   2413 
   2414     /*-----------------------------------------------------------------------*\
   2415      * 1. The used value of 'width' is determined as for inline replaced
   2416      *    elements.
   2417     \*-----------------------------------------------------------------------*/
   2418     // NOTE: This value of width is FINAL in that the min/max width calculations
   2419     // are dealt with in calcReplacedWidth().  This means that the steps to produce
   2420     // correct max/min in the non-replaced version, are not necessary.
   2421     setWidth(calcReplacedWidth() + borderLeft() + borderRight() + paddingLeft() + paddingRight());
   2422     const int availableSpace = containerWidth - width();
   2423 
   2424     /*-----------------------------------------------------------------------*\
   2425      * 2. If both 'left' and 'right' have the value 'auto', then if 'direction'
   2426      *    of the containing block is 'ltr', set 'left' to the static position;
   2427      *    else if 'direction' is 'rtl', set 'right' to the static position.
   2428     \*-----------------------------------------------------------------------*/
   2429     // see FIXME 2
   2430     if (left.isAuto() && right.isAuto()) {
   2431         // see FIXME 1
   2432         if (containerDirection == LTR) {
   2433             // 'staticX' should already have been set through layout of the parent.
   2434             int staticPosition = layer()->staticX() - containerBlock->borderLeft();
   2435             for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) {
   2436                 if (po->isBox())
   2437                     staticPosition += toRenderBox(po)->x();
   2438             }
   2439             left.setValue(Fixed, staticPosition);
   2440         } else {
   2441             RenderObject* po = parent();
   2442             // 'staticX' should already have been set through layout of the parent.
   2443             int staticPosition = layer()->staticX() + containerWidth + containerBlock->borderRight();
   2444             for ( ; po && po != containerBlock; po = po->parent()) {
   2445                 if (po->isBox())
   2446                     staticPosition += toRenderBox(po)->x();
   2447             }
   2448             right.setValue(Fixed, staticPosition);
   2449         }
   2450     }
   2451 
   2452     /*-----------------------------------------------------------------------*\
   2453      * 3. If 'left' or 'right' are 'auto', replace any 'auto' on 'margin-left'
   2454      *    or 'margin-right' with '0'.
   2455     \*-----------------------------------------------------------------------*/
   2456     if (left.isAuto() || right.isAuto()) {
   2457         if (marginLeft.isAuto())
   2458             marginLeft.setValue(Fixed, 0);
   2459         if (marginRight.isAuto())
   2460             marginRight.setValue(Fixed, 0);
   2461     }
   2462 
   2463     /*-----------------------------------------------------------------------*\
   2464      * 4. If at this point both 'margin-left' and 'margin-right' are still
   2465      *    'auto', solve the equation under the extra constraint that the two
   2466      *    margins must get equal values, unless this would make them negative,
   2467      *    in which case when the direction of the containing block is 'ltr'
   2468      *    ('rtl'), set 'margin-left' ('margin-right') to zero and solve for
   2469      *    'margin-right' ('margin-left').
   2470     \*-----------------------------------------------------------------------*/
   2471     int leftValue = 0;
   2472     int rightValue = 0;
   2473 
   2474     if (marginLeft.isAuto() && marginRight.isAuto()) {
   2475         // 'left' and 'right' cannot be 'auto' due to step 3
   2476         ASSERT(!(left.isAuto() && right.isAuto()));
   2477 
   2478         leftValue = left.calcValue(containerWidth);
   2479         rightValue = right.calcValue(containerWidth);
   2480 
   2481         int difference = availableSpace - (leftValue + rightValue);
   2482         if (difference > 0) {
   2483             m_marginLeft = difference / 2; // split the difference
   2484             m_marginRight = difference - m_marginLeft; // account for odd valued differences
   2485         } else {
   2486             // see FIXME 1
   2487             if (containerDirection == LTR) {
   2488                 m_marginLeft = 0;
   2489                 m_marginRight = difference;  // will be negative
   2490             } else {
   2491                 m_marginLeft = difference;  // will be negative
   2492                 m_marginRight = 0;
   2493             }
   2494         }
   2495 
   2496     /*-----------------------------------------------------------------------*\
   2497      * 5. If at this point there is an 'auto' left, solve the equation for
   2498      *    that value.
   2499     \*-----------------------------------------------------------------------*/
   2500     } else if (left.isAuto()) {
   2501         m_marginLeft = marginLeft.calcValue(containerWidth);
   2502         m_marginRight = marginRight.calcValue(containerWidth);
   2503         rightValue = right.calcValue(containerWidth);
   2504 
   2505         // Solve for 'left'
   2506         leftValue = availableSpace - (rightValue + m_marginLeft + m_marginRight);
   2507     } else if (right.isAuto()) {
   2508         m_marginLeft = marginLeft.calcValue(containerWidth);
   2509         m_marginRight = marginRight.calcValue(containerWidth);
   2510         leftValue = left.calcValue(containerWidth);
   2511 
   2512         // Solve for 'right'
   2513         rightValue = availableSpace - (leftValue + m_marginLeft + m_marginRight);
   2514     } else if (marginLeft.isAuto()) {
   2515         m_marginRight = marginRight.calcValue(containerWidth);
   2516         leftValue = left.calcValue(containerWidth);
   2517         rightValue = right.calcValue(containerWidth);
   2518 
   2519         // Solve for 'margin-left'
   2520         m_marginLeft = availableSpace - (leftValue + rightValue + m_marginRight);
   2521     } else if (marginRight.isAuto()) {
   2522         m_marginLeft = marginLeft.calcValue(containerWidth);
   2523         leftValue = left.calcValue(containerWidth);
   2524         rightValue = right.calcValue(containerWidth);
   2525 
   2526         // Solve for 'margin-right'
   2527         m_marginRight = availableSpace - (leftValue + rightValue + m_marginLeft);
   2528     } else {
   2529         // Nothing is 'auto', just calculate the values.
   2530         m_marginLeft = marginLeft.calcValue(containerWidth);
   2531         m_marginRight = marginRight.calcValue(containerWidth);
   2532         rightValue = right.calcValue(containerWidth);
   2533         leftValue = left.calcValue(containerWidth);
   2534     }
   2535 
   2536     /*-----------------------------------------------------------------------*\
   2537      * 6. If at this point the values are over-constrained, ignore the value
   2538      *    for either 'left' (in case the 'direction' property of the
   2539      *    containing block is 'rtl') or 'right' (in case 'direction' is
   2540      *    'ltr') and solve for that value.
   2541     \*-----------------------------------------------------------------------*/
   2542     // NOTE:  It is not necessary to solve for 'right' when the direction is
   2543     // LTR because the value is not used.
   2544     int totalWidth = width() + leftValue + rightValue +  m_marginLeft + m_marginRight;
   2545     if (totalWidth > containerWidth && (containerDirection == RTL))
   2546         leftValue = containerWidth - (totalWidth - leftValue);
   2547 
   2548     // Use computed values to calculate the horizontal position.
   2549 
   2550     // FIXME: This hack is needed to calculate the xPos for a 'rtl' relatively
   2551     // positioned, inline containing block because right now, it is using the xPos
   2552     // of the first line box when really it should use the last line box.  When
   2553     // this is fixed elsewhere, this block should be removed.
   2554     if (containerBlock->isRenderInline() && containerBlock->style()->direction() == RTL) {
   2555         const RenderInline* flow = toRenderInline(containerBlock);
   2556         InlineFlowBox* firstLine = flow->firstLineBox();
   2557         InlineFlowBox* lastLine = flow->lastLineBox();
   2558         if (firstLine && lastLine && firstLine != lastLine) {
   2559             m_frameRect.setX(leftValue + m_marginLeft + lastLine->borderLeft() + (lastLine->x() - firstLine->x()));
   2560             return;
   2561         }
   2562     }
   2563 
   2564     m_frameRect.setX(leftValue + m_marginLeft + containerBlock->borderLeft());
   2565 }
   2566 
   2567 void RenderBox::calcAbsoluteVerticalReplaced()
   2568 {
   2569     // The following is based off of the W3C Working Draft from April 11, 2006 of
   2570     // CSS 2.1: Section 10.6.5 "Absolutely positioned, replaced elements"
   2571     // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-height>
   2572     // (block-style-comments in this function correspond to text from the spec and
   2573     // the numbers correspond to numbers in spec)
   2574 
   2575     // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
   2576     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
   2577 
   2578     const int containerHeight = containingBlockHeightForPositioned(containerBlock);
   2579 
   2580     // Variables to solve.
   2581     Length top = style()->top();
   2582     Length bottom = style()->bottom();
   2583     Length marginTop = style()->marginTop();
   2584     Length marginBottom = style()->marginBottom();
   2585 
   2586 
   2587     /*-----------------------------------------------------------------------*\
   2588      * 1. The used value of 'height' is determined as for inline replaced
   2589      *    elements.
   2590     \*-----------------------------------------------------------------------*/
   2591     // NOTE: This value of height is FINAL in that the min/max height calculations
   2592     // are dealt with in calcReplacedHeight().  This means that the steps to produce
   2593     // correct max/min in the non-replaced version, are not necessary.
   2594     setHeight(calcReplacedHeight() + borderTop() + borderBottom() + paddingTop() + paddingBottom());
   2595     const int availableSpace = containerHeight - height();
   2596 
   2597     /*-----------------------------------------------------------------------*\
   2598      * 2. If both 'top' and 'bottom' have the value 'auto', replace 'top'
   2599      *    with the element's static position.
   2600     \*-----------------------------------------------------------------------*/
   2601     // see FIXME 2
   2602     if (top.isAuto() && bottom.isAuto()) {
   2603         // staticY should already have been set through layout of the parent().
   2604         int staticTop = layer()->staticY() - containerBlock->borderTop();
   2605         for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) {
   2606             if (po->isBox() && !po->isTableRow())
   2607                 staticTop += toRenderBox(po)->y();
   2608         }
   2609         top.setValue(Fixed, staticTop);
   2610     }
   2611 
   2612     /*-----------------------------------------------------------------------*\
   2613      * 3. If 'bottom' is 'auto', replace any 'auto' on 'margin-top' or
   2614      *    'margin-bottom' with '0'.
   2615     \*-----------------------------------------------------------------------*/
   2616     // FIXME: The spec. says that this step should only be taken when bottom is
   2617     // auto, but if only top is auto, this makes step 4 impossible.
   2618     if (top.isAuto() || bottom.isAuto()) {
   2619         if (marginTop.isAuto())
   2620             marginTop.setValue(Fixed, 0);
   2621         if (marginBottom.isAuto())
   2622             marginBottom.setValue(Fixed, 0);
   2623     }
   2624 
   2625     /*-----------------------------------------------------------------------*\
   2626      * 4. If at this point both 'margin-top' and 'margin-bottom' are still
   2627      *    'auto', solve the equation under the extra constraint that the two
   2628      *    margins must get equal values.
   2629     \*-----------------------------------------------------------------------*/
   2630     int topValue = 0;
   2631     int bottomValue = 0;
   2632 
   2633     if (marginTop.isAuto() && marginBottom.isAuto()) {
   2634         // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combined.
   2635         ASSERT(!(top.isAuto() || bottom.isAuto()));
   2636 
   2637         topValue = top.calcValue(containerHeight);
   2638         bottomValue = bottom.calcValue(containerHeight);
   2639 
   2640         int difference = availableSpace - (topValue + bottomValue);
   2641         // NOTE: This may result in negative values.
   2642         m_marginTop =  difference / 2; // split the difference
   2643         m_marginBottom = difference - m_marginTop; // account for odd valued differences
   2644 
   2645     /*-----------------------------------------------------------------------*\
   2646      * 5. If at this point there is only one 'auto' left, solve the equation
   2647      *    for that value.
   2648     \*-----------------------------------------------------------------------*/
   2649     } else if (top.isAuto()) {
   2650         m_marginTop = marginTop.calcValue(containerHeight);
   2651         m_marginBottom = marginBottom.calcValue(containerHeight);
   2652         bottomValue = bottom.calcValue(containerHeight);
   2653 
   2654         // Solve for 'top'
   2655         topValue = availableSpace - (bottomValue + m_marginTop + m_marginBottom);
   2656     } else if (bottom.isAuto()) {
   2657         m_marginTop = marginTop.calcValue(containerHeight);
   2658         m_marginBottom = marginBottom.calcValue(containerHeight);
   2659         topValue = top.calcValue(containerHeight);
   2660 
   2661         // Solve for 'bottom'
   2662         // NOTE: It is not necessary to solve for 'bottom' because we don't ever
   2663         // use the value.
   2664     } else if (marginTop.isAuto()) {
   2665         m_marginBottom = marginBottom.calcValue(containerHeight);
   2666         topValue = top.calcValue(containerHeight);
   2667         bottomValue = bottom.calcValue(containerHeight);
   2668 
   2669         // Solve for 'margin-top'
   2670         m_marginTop = availableSpace - (topValue + bottomValue + m_marginBottom);
   2671     } else if (marginBottom.isAuto()) {
   2672         m_marginTop = marginTop.calcValue(containerHeight);
   2673         topValue = top.calcValue(containerHeight);
   2674         bottomValue = bottom.calcValue(containerHeight);
   2675 
   2676         // Solve for 'margin-bottom'
   2677         m_marginBottom = availableSpace - (topValue + bottomValue + m_marginTop);
   2678     } else {
   2679         // Nothing is 'auto', just calculate the values.
   2680         m_marginTop = marginTop.calcValue(containerHeight);
   2681         m_marginBottom = marginBottom.calcValue(containerHeight);
   2682         topValue = top.calcValue(containerHeight);
   2683         // NOTE: It is not necessary to solve for 'bottom' because we don't ever
   2684         // use the value.
   2685      }
   2686 
   2687     /*-----------------------------------------------------------------------*\
   2688      * 6. If at this point the values are over-constrained, ignore the value
   2689      *    for 'bottom' and solve for that value.
   2690     \*-----------------------------------------------------------------------*/
   2691     // NOTE: It is not necessary to do this step because we don't end up using
   2692     // the value of 'bottom' regardless of whether the values are over-constrained
   2693     // or not.
   2694 
   2695     // Use computed values to calculate the vertical position.
   2696     m_frameRect.setY(topValue + m_marginTop + containerBlock->borderTop());
   2697 }
   2698 
   2699 IntRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, int* extraWidthToEndOfLine)
   2700 {
   2701     // VisiblePositions at offsets inside containers either a) refer to the positions before/after
   2702     // those containers (tables and select elements) or b) refer to the position inside an empty block.
   2703     // They never refer to children.
   2704     // FIXME: Paint the carets inside empty blocks differently than the carets before/after elements.
   2705 
   2706     // FIXME: What about border and padding?
   2707     IntRect rect(x(), y(), caretWidth, height());
   2708     TextDirection direction = box ? box->direction() : style()->direction();
   2709 
   2710     if ((!caretOffset) ^ (direction == LTR))
   2711         rect.move(IntSize(width() - caretWidth, 0));
   2712 
   2713     if (box) {
   2714         RootInlineBox* rootBox = box->root();
   2715         int top = rootBox->lineTop();
   2716         rect.setY(top);
   2717         rect.setHeight(rootBox->lineBottom() - top);
   2718     }
   2719 
   2720     // If height of box is smaller than font height, use the latter one,
   2721     // otherwise the caret might become invisible.
   2722     //
   2723     // Also, if the box is not a replaced element, always use the font height.
   2724     // This prevents the "big caret" bug described in:
   2725     // <rdar://problem/3777804> Deleting all content in a document can result in giant tall-as-window insertion point
   2726     //
   2727     // FIXME: ignoring :first-line, missing good reason to take care of
   2728     int fontHeight = style()->font().height();
   2729     if (fontHeight > rect.height() || (!isReplaced() && !isTable()))
   2730         rect.setHeight(fontHeight);
   2731 
   2732     if (extraWidthToEndOfLine)
   2733         *extraWidthToEndOfLine = x() + width() - rect.right();
   2734 
   2735     // Move to local coords
   2736     rect.move(-x(), -y());
   2737     return rect;
   2738 }
   2739 
   2740 int RenderBox::lowestPosition(bool /*includeOverflowInterior*/, bool includeSelf) const
   2741 {
   2742     if (!includeSelf || !width())
   2743         return 0;
   2744     int bottom = height();
   2745     if (isRelPositioned())
   2746         bottom += relativePositionOffsetY();
   2747     return bottom;
   2748 }
   2749 
   2750 int RenderBox::rightmostPosition(bool /*includeOverflowInterior*/, bool includeSelf) const
   2751 {
   2752     if (!includeSelf || !height())
   2753         return 0;
   2754     int right = width();
   2755     if (isRelPositioned())
   2756         right += relativePositionOffsetX();
   2757     return right;
   2758 }
   2759 
   2760 int RenderBox::leftmostPosition(bool /*includeOverflowInterior*/, bool includeSelf) const
   2761 {
   2762     if (!includeSelf || !height())
   2763         return width();
   2764     int left = 0;
   2765     if (isRelPositioned())
   2766         left += relativePositionOffsetX();
   2767     return left;
   2768 }
   2769 
   2770 VisiblePosition RenderBox::positionForPoint(const IntPoint& point)
   2771 {
   2772     // no children...return this render object's element, if there is one, and offset 0
   2773     if (!firstChild())
   2774         return createVisiblePosition(node() ? firstDeepEditingPositionForNode(node()) : Position(0, 0));
   2775 
   2776     int xPos = point.x();
   2777     int yPos = point.y();
   2778 
   2779     if (isTable() && node()) {
   2780         int right = contentWidth() + borderRight() + paddingRight() + borderLeft() + paddingLeft();
   2781         int bottom = contentHeight() + borderTop() + paddingTop() + borderBottom() + paddingBottom();
   2782 
   2783         if (xPos < 0 || xPos > right || yPos < 0 || yPos > bottom) {
   2784             if (xPos <= right / 2)
   2785                 return createVisiblePosition(firstDeepEditingPositionForNode(node()));
   2786             return createVisiblePosition(lastDeepEditingPositionForNode(node()));
   2787         }
   2788     }
   2789 
   2790     // Pass off to the closest child.
   2791     int minDist = INT_MAX;
   2792     RenderBox* closestRenderer = 0;
   2793     int newX = xPos;
   2794     int newY = yPos;
   2795     if (isTableRow()) {
   2796         newX += x();
   2797         newY += y();
   2798     }
   2799     for (RenderObject* renderObject = firstChild(); renderObject; renderObject = renderObject->nextSibling()) {
   2800         if ((!renderObject->firstChild() && !renderObject->isInline() && !renderObject->isBlockFlow() )
   2801             || renderObject->style()->visibility() != VISIBLE)
   2802             continue;
   2803 
   2804         if (!renderObject->isBox())
   2805             continue;
   2806 
   2807         RenderBox* renderer = toRenderBox(renderObject);
   2808 
   2809         int top = renderer->borderTop() + renderer->paddingTop() + (isTableRow() ? 0 : renderer->y());
   2810         int bottom = top + renderer->contentHeight();
   2811         int left = renderer->borderLeft() + renderer->paddingLeft() + (isTableRow() ? 0 : renderer->x());
   2812         int right = left + renderer->contentWidth();
   2813 
   2814         if (xPos <= right && xPos >= left && yPos <= top && yPos >= bottom) {
   2815             if (renderer->isTableRow())
   2816                 return renderer->positionForCoordinates(xPos + newX - renderer->x(), yPos + newY - renderer->y());
   2817             return renderer->positionForCoordinates(xPos - renderer->x(), yPos - renderer->y());
   2818         }
   2819 
   2820         // Find the distance from (x, y) to the box.  Split the space around the box into 8 pieces
   2821         // and use a different compare depending on which piece (x, y) is in.
   2822         IntPoint cmp;
   2823         if (xPos > right) {
   2824             if (yPos < top)
   2825                 cmp = IntPoint(right, top);
   2826             else if (yPos > bottom)
   2827                 cmp = IntPoint(right, bottom);
   2828             else
   2829                 cmp = IntPoint(right, yPos);
   2830         } else if (xPos < left) {
   2831             if (yPos < top)
   2832                 cmp = IntPoint(left, top);
   2833             else if (yPos > bottom)
   2834                 cmp = IntPoint(left, bottom);
   2835             else
   2836                 cmp = IntPoint(left, yPos);
   2837         } else {
   2838             if (yPos < top)
   2839                 cmp = IntPoint(xPos, top);
   2840             else
   2841                 cmp = IntPoint(xPos, bottom);
   2842         }
   2843 
   2844         int x1minusx2 = cmp.x() - xPos;
   2845         int y1minusy2 = cmp.y() - yPos;
   2846 
   2847         int dist = x1minusx2 * x1minusx2 + y1minusy2 * y1minusy2;
   2848         if (dist < minDist) {
   2849             closestRenderer = renderer;
   2850             minDist = dist;
   2851         }
   2852     }
   2853 
   2854     if (closestRenderer)
   2855         return closestRenderer->positionForCoordinates(newX - closestRenderer->x(), newY - closestRenderer->y());
   2856 
   2857     return createVisiblePosition(firstDeepEditingPositionForNode(node()));
   2858 }
   2859 
   2860 bool RenderBox::shrinkToAvoidFloats() const
   2861 {
   2862     // FIXME: Technically we should be able to shrink replaced elements on a line, but this is difficult to accomplish, since this
   2863     // involves doing a relayout during findNextLineBreak and somehow overriding the containingBlockWidth method to return the
   2864     // current remaining width on a line.
   2865     if ((isInline() && !isHTMLMarquee()) || !avoidsFloats())
   2866         return false;
   2867 
   2868     // All auto-width objects that avoid floats should always use lineWidth.
   2869     return style()->width().isAuto();
   2870 }
   2871 
   2872 bool RenderBox::avoidsFloats() const
   2873 {
   2874     return isReplaced() || hasOverflowClip() || isHR();
   2875 }
   2876 
   2877 void RenderBox::addShadowOverflow()
   2878 {
   2879     int shadowLeft;
   2880     int shadowRight;
   2881     int shadowTop;
   2882     int shadowBottom;
   2883     style()->getBoxShadowExtent(shadowTop, shadowRight, shadowBottom, shadowLeft);
   2884     IntRect borderBox = borderBoxRect();
   2885     int overflowLeft = borderBox.x() + shadowLeft;
   2886     int overflowRight = borderBox.right() + shadowRight;
   2887     int overflowTop = borderBox.y() + shadowTop;
   2888     int overflowBottom = borderBox.bottom() + shadowBottom;
   2889     addVisualOverflow(IntRect(overflowLeft, overflowTop, overflowRight - overflowLeft, overflowBottom - overflowTop));
   2890 }
   2891 
   2892 void RenderBox::addOverflowFromChild(RenderBox* child, const IntSize& delta)
   2893 {
   2894     // Update our overflow in case the child spills out the block, but only if we were going to paint
   2895     // the child block ourselves.
   2896     if (child->hasSelfPaintingLayer())
   2897         return;
   2898 
   2899     // Only propagate layout overflow from the child if the child isn't clipping its overflow.  If it is, then
   2900     // its overflow is internal to it, and we don't care about it.
   2901     IntRect childLayoutOverflowRect = child->hasOverflowClip() ? child->borderBoxRect() : child->layoutOverflowRect();
   2902     childLayoutOverflowRect.move(delta);
   2903     addLayoutOverflow(childLayoutOverflowRect);
   2904 
   2905     // Add in visual overflow from the child.  Even if the child clips its overflow, it may still
   2906     // have visual overflow of its own set from box shadows or reflections.  It is unnecessary to propagate this
   2907     // overflow if we are clipping our own overflow.
   2908     if (hasOverflowClip())
   2909         return;
   2910     IntRect childVisualOverflowRect = child->visualOverflowRect();
   2911     childVisualOverflowRect.move(delta);
   2912     addVisualOverflow(childVisualOverflowRect);
   2913 }
   2914 
   2915 void RenderBox::addLayoutOverflow(const IntRect& rect)
   2916 {
   2917     IntRect borderBox = borderBoxRect();
   2918     if (borderBox.contains(rect))
   2919         return;
   2920 
   2921     if (!m_overflow)
   2922         m_overflow.set(new RenderOverflow(borderBox));
   2923 
   2924     m_overflow->addLayoutOverflow(rect);
   2925 }
   2926 
   2927 void RenderBox::addVisualOverflow(const IntRect& rect)
   2928 {
   2929     IntRect borderBox = borderBoxRect();
   2930     if (borderBox.contains(rect))
   2931         return;
   2932 
   2933     if (!m_overflow)
   2934         m_overflow.set(new RenderOverflow(borderBox));
   2935 
   2936     m_overflow->addVisualOverflow(rect);
   2937 }
   2938 
   2939 void RenderBox::clearLayoutOverflow()
   2940 {
   2941     if (!m_overflow)
   2942         return;
   2943 
   2944     if (visualOverflowRect() == borderBoxRect()) {
   2945         m_overflow.clear();
   2946         return;
   2947     }
   2948 
   2949     m_overflow->resetLayoutOverflow(borderBoxRect());
   2950 }
   2951 
   2952 #if ENABLE(SVG)
   2953 
   2954 AffineTransform RenderBox::localTransform() const
   2955 {
   2956     return AffineTransform(1, 0, 0, 1, x(), y());
   2957 }
   2958 
   2959 #endif
   2960 
   2961 } // namespace WebCore
   2962