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