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