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