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