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