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