d71aee05dcc3aab5f5a19f967b9abed86d8cea7c
[WebKit-https.git] / Source / WebCore / 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  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  */
24
25 #include "config.h"
26 #include "RenderBox.h"
27
28 #include "Chrome.h"
29 #include "ChromeClient.h"
30 #include "Document.h"
31 #include "FloatQuad.h"
32 #include "Frame.h"
33 #include "FrameView.h"
34 #include "GraphicsContext.h"
35 #include "HTMLElement.h"
36 #include "HTMLFrameOwnerElement.h"
37 #include "HTMLInputElement.h"
38 #include "HTMLNames.h"
39 #include "HTMLTextAreaElement.h"
40 #include "HitTestResult.h"
41 #include "Page.h"
42 #include "PaintInfo.h"
43 #include "RenderArena.h"
44 #include "RenderBoxRegionInfo.h"
45 #include "RenderFlexibleBox.h"
46 #include "RenderFlowThread.h"
47 #include "RenderGeometryMap.h"
48 #include "RenderInline.h"
49 #include "RenderLayer.h"
50 #include "RenderRegion.h"
51 #include "RenderTableCell.h"
52 #include "RenderTheme.h"
53 #include "RenderView.h"
54 #include "TransformState.h"
55 #include "htmlediting.h"
56 #include <algorithm>
57 #include <math.h>
58 #include <wtf/StackStats.h>
59
60 #if USE(ACCELERATED_COMPOSITING)
61 #include "RenderLayerCompositor.h"
62 #endif
63
64 using namespace std;
65
66 namespace WebCore {
67
68 using namespace HTMLNames;
69
70 // Used by flexible boxes when flexing this element and by table cells.
71 typedef WTF::HashMap<const RenderBox*, LayoutUnit> OverrideSizeMap;
72 static OverrideSizeMap* gOverrideHeightMap = 0;
73 static OverrideSizeMap* gOverrideWidthMap = 0;
74
75 // Used by grid elements to properly size their grid items.
76 static OverrideSizeMap* gOverrideContainingBlockLogicalHeightMap = 0;
77 static OverrideSizeMap* gOverrideContainingBlockLogicalWidthMap = 0;
78
79
80 // Size of border belt for autoscroll. When mouse pointer in border belt,
81 // autoscroll is started.
82 static const int autoscrollBeltSize = 20;
83 static const unsigned backgroundObscurationTestMaxDepth = 4;
84
85 bool RenderBox::s_hadOverflowClip = false;
86
87 static bool skipBodyBackground(const RenderBox* bodyElementRenderer)
88 {
89     ASSERT(bodyElementRenderer->isBody());
90     // The <body> only paints its background if the root element has defined a background independent of the body,
91     // or if the <body>'s parent is not the document element's renderer (e.g. inside SVG foreignObject).
92     RenderObject* documentElementRenderer = bodyElementRenderer->document().documentElement()->renderer();
93     return documentElementRenderer
94         && !documentElementRenderer->hasBackground()
95         && (documentElementRenderer == bodyElementRenderer->parent());
96 }
97
98 RenderBox::RenderBox(Element* element, unsigned baseTypeFlags)
99     : RenderBoxModelObject(element, baseTypeFlags)
100     , m_minPreferredLogicalWidth(-1)
101     , m_maxPreferredLogicalWidth(-1)
102     , m_inlineBoxWrapper(0)
103 {
104     setIsBox();
105 }
106
107 RenderBox::~RenderBox()
108 {
109 }
110
111 RenderRegion* RenderBox::clampToStartAndEndRegions(RenderRegion* region) const
112 {
113     RenderFlowThread* flowThread = flowThreadContainingBlock();
114
115     ASSERT(isRenderView() || (region && flowThread));
116     if (isRenderView())
117         return region;
118
119     // We need to clamp to the block, since we want any lines or blocks that overflow out of the
120     // logical top or logical bottom of the block to size as though the border box in the first and
121     // last regions extended infinitely. Otherwise the lines are going to size according to the regions
122     // they overflow into, which makes no sense when this block doesn't exist in |region| at all.
123     RenderRegion* startRegion = 0;
124     RenderRegion* endRegion = 0;
125     flowThread->getRegionRangeForBox(this, startRegion, endRegion);
126
127     if (startRegion && region->logicalTopForFlowThreadContent() < startRegion->logicalTopForFlowThreadContent())
128         return startRegion;
129     if (endRegion && region->logicalTopForFlowThreadContent() > endRegion->logicalTopForFlowThreadContent())
130         return endRegion;
131
132     return region;
133 }
134
135 LayoutRect RenderBox::clientBoxRectInRegion(RenderRegion* region) const
136 {
137     if (!region)
138         return clientBoxRect();
139
140     LayoutRect clientBox = borderBoxRectInRegion(region);
141     clientBox.setLocation(clientBox.location() + LayoutSize(borderLeft(), borderTop()));
142     clientBox.setSize(clientBox.size() - LayoutSize(borderLeft() + borderRight() + verticalScrollbarWidth(), borderTop() + borderBottom() + horizontalScrollbarHeight()));
143
144     return clientBox;
145 }
146
147 LayoutRect RenderBox::borderBoxRectInRegion(RenderRegion* region, RenderBoxRegionInfoFlags cacheFlag) const
148 {
149     if (!region)
150         return borderBoxRect();
151
152     RenderFlowThread* flowThread = flowThreadContainingBlock();
153     if (!flowThread)
154         return borderBoxRect();
155
156     RenderRegion* startRegion = 0;
157     RenderRegion* endRegion = 0;
158     flowThread->getRegionRangeForBox(this, startRegion, endRegion);
159
160     // FIXME: In a perfect world this condition should never happen.
161     if (!startRegion || !endRegion)
162         return borderBoxRect();
163
164     // FIXME: Once overflow is implemented this assertion needs to be enabled. Right now the overflow content is painted
165     // in regions outside the box range so the assert is disabled.
166     // ASSERT(clampToStartAndEndRegions(region) == region);
167
168     // FIXME: Remove once boxes are painted inside their region range.
169     region = clampToStartAndEndRegions(region);
170
171     // Compute the logical width and placement in this region.
172     RenderBoxRegionInfo* boxInfo = renderBoxRegionInfo(region, cacheFlag);
173     if (!boxInfo)
174         return borderBoxRect();
175
176     // We have cached insets.
177     LayoutUnit logicalWidth = boxInfo->logicalWidth();
178     LayoutUnit logicalLeft = boxInfo->logicalLeft();
179         
180     // Now apply the parent inset since it is cumulative whenever anything in the containing block chain shifts.
181     // FIXME: Doesn't work right with perpendicular writing modes.
182     const RenderBlock* currentBox = containingBlock();
183     RenderBoxRegionInfo* currentBoxInfo = currentBox->renderBoxRegionInfo(region);
184     while (currentBoxInfo && currentBoxInfo->isShifted()) {
185         if (currentBox->style()->direction() == LTR)
186             logicalLeft += currentBoxInfo->logicalLeft();
187         else
188             logicalLeft -= (currentBox->logicalWidth() - currentBoxInfo->logicalWidth()) - currentBoxInfo->logicalLeft();
189         currentBox = currentBox->containingBlock();
190         region = currentBox->clampToStartAndEndRegions(region);
191         currentBoxInfo = currentBox->renderBoxRegionInfo(region);
192     }
193     
194     if (cacheFlag == DoNotCacheRenderBoxRegionInfo)
195         delete boxInfo;
196
197     if (isHorizontalWritingMode())
198         return LayoutRect(logicalLeft, 0, logicalWidth, height());
199     return LayoutRect(0, logicalLeft, width(), logicalWidth);
200 }
201
202 void RenderBox::clearRenderBoxRegionInfo()
203 {
204     if (isRenderFlowThread())
205         return;
206
207     RenderFlowThread* flowThread = flowThreadContainingBlock();
208     if (flowThread)
209         flowThread->removeRenderBoxRegionInfo(this);
210 }
211
212 void RenderBox::willBeDestroyed()
213 {
214     clearOverrideSize();
215     clearContainingBlockOverrideSize();
216
217     RenderBlock::removePercentHeightDescendantIfNeeded(this);
218
219 #if ENABLE(CSS_SHAPES)
220     ShapeOutsideInfo::removeInfo(this);
221 #endif
222
223     RenderBoxModelObject::willBeDestroyed();
224 }
225
226 RenderBlockFlow* RenderBox::outermostBlockContainingFloatingObject()
227 {
228     ASSERT(isFloating());
229     RenderBlockFlow* parentBlock = 0;
230     for (RenderObject* curr = parent(); curr && !curr->isRenderView(); curr = curr->parent()) {
231         if (curr->isRenderBlockFlow()) {
232             RenderBlockFlow* currBlock = toRenderBlockFlow(curr);
233             if (!parentBlock || currBlock->containsFloat(this))
234                 parentBlock = currBlock;
235         }
236     }
237     return parentBlock;
238 }
239
240 void RenderBox::removeFloatingOrPositionedChildFromBlockLists()
241 {
242     ASSERT(isFloatingOrOutOfFlowPositioned());
243
244     if (documentBeingDestroyed())
245         return;
246
247     if (isFloating()) {
248         if (RenderBlockFlow* parentBlock = outermostBlockContainingFloatingObject()) {
249             parentBlock->markSiblingsWithFloatsForLayout(this);
250             parentBlock->markAllDescendantsWithFloatsForLayout(this, false);
251         }
252     }
253
254     if (isOutOfFlowPositioned())
255         RenderBlock::removePositionedObject(this);
256 }
257
258 void RenderBox::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
259 {
260     s_hadOverflowClip = hasOverflowClip();
261
262     RenderStyle* oldStyle = style();
263     if (oldStyle) {
264         // The background of the root element or the body element could propagate up to
265         // the canvas. Issue full repaint, when our style changes substantially.
266         if (diff >= StyleDifferenceRepaint && (isRoot() || isBody())) {
267             view().repaintRootContents();
268 #if USE(ACCELERATED_COMPOSITING)
269             if (oldStyle->hasEntirelyFixedBackground() != newStyle->hasEntirelyFixedBackground())
270                 view().compositor().rootFixedBackgroundsChanged();
271 #endif
272         }
273         
274         // When a layout hint happens and an object's position style changes, we have to do a layout
275         // to dirty the render tree using the old position value now.
276         if (diff == StyleDifferenceLayout && parent() && oldStyle->position() != newStyle->position()) {
277             markContainingBlocksForLayout();
278             if (oldStyle->position() == StaticPosition)
279                 repaint();
280             else if (newStyle->hasOutOfFlowPosition())
281                 parent()->setChildNeedsLayout();
282             if (isFloating() && !isOutOfFlowPositioned() && newStyle->hasOutOfFlowPosition())
283                 removeFloatingOrPositionedChildFromBlockLists();
284         }
285     } else if (newStyle && isBody())
286         view().repaintRootContents();
287
288     RenderBoxModelObject::styleWillChange(diff, newStyle);
289 }
290
291 void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
292 {
293     // Horizontal writing mode definition is updated in RenderBoxModelObject::updateFromStyle,
294     // (as part of the RenderBoxModelObject::styleDidChange call below). So, we can safely cache the horizontal
295     // writing mode value before style change here.
296     bool oldHorizontalWritingMode = isHorizontalWritingMode();
297
298     RenderBoxModelObject::styleDidChange(diff, oldStyle);
299
300     RenderStyle* newStyle = style();
301     if (needsLayout() && oldStyle) {
302         RenderBlock::removePercentHeightDescendantIfNeeded(this);
303
304         // Normally we can do optimized positioning layout for absolute/fixed positioned objects. There is one special case, however, which is
305         // 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
306         // to determine the new static position.
307         if (isOutOfFlowPositioned() && newStyle->hasStaticBlockPosition(isHorizontalWritingMode()) && oldStyle->marginBefore() != newStyle->marginBefore()
308             && parent() && !parent()->normalChildNeedsLayout())
309             parent()->setChildNeedsLayout();
310     }
311
312     if (RenderBlock::hasPercentHeightContainerMap() && firstChild()
313         && oldHorizontalWritingMode != isHorizontalWritingMode())
314         RenderBlock::clearPercentHeightDescendantsFrom(this);
315
316     // If our zoom factor changes and we have a defined scrollLeft/Top, we need to adjust that value into the
317     // new zoomed coordinate space.
318     if (hasOverflowClip() && oldStyle && newStyle && oldStyle->effectiveZoom() != newStyle->effectiveZoom()) {
319         if (int left = layer()->scrollXOffset()) {
320             left = (left / oldStyle->effectiveZoom()) * newStyle->effectiveZoom();
321             layer()->scrollToXOffset(left);
322         }
323         if (int top = layer()->scrollYOffset()) {
324             top = (top / oldStyle->effectiveZoom()) * newStyle->effectiveZoom();
325             layer()->scrollToYOffset(top);
326         }
327     }
328
329     // Our opaqueness might have changed without triggering layout.
330     if (diff >= StyleDifferenceRepaint && diff <= StyleDifferenceRepaintLayer) {
331         RenderObject* parentToInvalidate = parent();
332         for (unsigned i = 0; i < backgroundObscurationTestMaxDepth && parentToInvalidate; ++i) {
333             parentToInvalidate->invalidateBackgroundObscurationStatus();
334             parentToInvalidate = parentToInvalidate->parent();
335         }
336     }
337
338     bool isBodyRenderer = isBody();
339     bool isRootRenderer = isRoot();
340
341     // Set the text color if we're the body.
342     if (isBodyRenderer)
343         document().setTextColor(newStyle->visitedDependentColor(CSSPropertyColor));
344
345     if (isRootRenderer || isBodyRenderer) {
346         // Propagate the new writing mode and direction up to the RenderView.
347         RenderStyle* viewStyle = view().style();
348         bool viewChangedWritingMode = false;
349         if (viewStyle->direction() != newStyle->direction() && (isRootRenderer || !document().directionSetOnDocumentElement())) {
350             viewStyle->setDirection(newStyle->direction());
351             if (isBodyRenderer)
352                 document().documentElement()->renderer()->style()->setDirection(newStyle->direction());
353             setNeedsLayoutAndPrefWidthsRecalc();
354         }
355
356         if (viewStyle->writingMode() != newStyle->writingMode() && (isRootRenderer || !document().writingModeSetOnDocumentElement())) {
357             viewStyle->setWritingMode(newStyle->writingMode());
358             viewChangedWritingMode = true;
359             view().setHorizontalWritingMode(newStyle->isHorizontalWritingMode());
360             view().markAllDescendantsWithFloatsForLayout();
361             if (isBodyRenderer) {
362                 document().documentElement()->renderer()->style()->setWritingMode(newStyle->writingMode());
363                 document().documentElement()->renderer()->setHorizontalWritingMode(newStyle->isHorizontalWritingMode());
364             }
365             setNeedsLayoutAndPrefWidthsRecalc();
366         }
367
368         view().frameView().recalculateScrollbarOverlayStyle();
369         
370         const Pagination& pagination = view().frameView().pagination();
371         if (viewChangedWritingMode && pagination.mode != Pagination::Unpaginated) {
372             viewStyle->setColumnStylesFromPaginationMode(pagination.mode);
373             if (view().hasColumns())
374                 view().updateColumnInfoFromStyle(viewStyle);
375         }
376     }
377
378 #if ENABLE(CSS_SHAPES)
379     updateShapeOutsideInfoAfterStyleChange(*style(), oldStyle);
380 #endif
381 }
382
383 #if ENABLE(CSS_SHAPES)
384 void RenderBox::updateShapeOutsideInfoAfterStyleChange(const RenderStyle& style, const RenderStyle* oldStyle)
385 {
386     ShapeValue* shapeOutside = style.shapeOutside();
387     ShapeValue* oldShapeOutside = oldStyle ? oldStyle->shapeOutside() : nullptr;
388
389     float shapeImageThreshold = style.shapeImageThreshold();
390     float oldShapeImageThreshold = oldStyle ? oldStyle->shapeImageThreshold() : RenderStyle::initialShapeImageThreshold();
391
392     // FIXME: A future optimization would do a deep comparison for equality. (bug 100811)
393     if (shapeOutside == oldShapeOutside && shapeImageThreshold == oldShapeImageThreshold)
394         return;
395
396     if (!shapeOutside)
397         ShapeOutsideInfo::removeInfo(this);
398     else
399         ShapeOutsideInfo::ensureInfo(this)->dirtyShapeSize();
400
401     if (shapeOutside || shapeOutside != oldShapeOutside)
402         markShapeOutsideDependentsForLayout();
403 }
404 #endif
405
406 void RenderBox::updateFromStyle()
407 {
408     RenderBoxModelObject::updateFromStyle();
409
410     RenderStyle* styleToUse = style();
411     bool isRootObject = isRoot();
412     bool isViewObject = isRenderView();
413
414     // The root and the RenderView always paint their backgrounds/borders.
415     if (isRootObject || isViewObject)
416         setHasBoxDecorations(true);
417
418     setFloating(!isOutOfFlowPositioned() && styleToUse->isFloating());
419
420     // We also handle <body> and <html>, whose overflow applies to the viewport.
421     if (styleToUse->overflowX() != OVISIBLE && !isRootObject && isRenderBlock()) {
422         bool boxHasOverflowClip = true;
423         if (isBody()) {
424             // Overflow on the body can propagate to the viewport under the following conditions.
425             // (1) The root element is <html>.
426             // (2) We are the primary <body> (can be checked by looking at document.body).
427             // (3) The root element has visible overflow.
428             if (document().documentElement()->hasTagName(htmlTag)
429                 && document().body() == element()
430                 && document().documentElement()->renderer()->style()->overflowX() == OVISIBLE) {
431                 boxHasOverflowClip = false;
432             }
433         }
434         
435         // Check for overflow clip.
436         // It's sufficient to just check one direction, since it's illegal to have visible on only one overflow value.
437         if (boxHasOverflowClip) {
438             if (!s_hadOverflowClip)
439                 // Erase the overflow
440                 repaint();
441             setHasOverflowClip();
442         }
443     }
444
445     setHasTransform(styleToUse->hasTransformRelatedProperty());
446     setHasReflection(styleToUse->boxReflect());
447 }
448
449 void RenderBox::layout()
450 {
451     StackStats::LayoutCheckPoint layoutCheckPoint;
452     ASSERT(needsLayout());
453
454     RenderObject* child = firstChild();
455     if (!child) {
456         clearNeedsLayout();
457         return;
458     }
459
460     LayoutStateMaintainer statePusher(&view(), this, locationOffset(), style()->isFlippedBlocksWritingMode());
461     while (child) {
462         if (child->needsLayout())
463             toRenderElement(child)->layout();
464         ASSERT(!child->needsLayout());
465         child = child->nextSibling();
466     }
467     statePusher.pop();
468     invalidateBackgroundObscurationStatus();
469     clearNeedsLayout();
470 }
471
472 // More IE extensions.  clientWidth and clientHeight represent the interior of an object
473 // excluding border and scrollbar.
474 LayoutUnit RenderBox::clientWidth() const
475 {
476     return width() - borderLeft() - borderRight() - verticalScrollbarWidth();
477 }
478
479 LayoutUnit RenderBox::clientHeight() const
480 {
481     return height() - borderTop() - borderBottom() - horizontalScrollbarHeight();
482 }
483
484 int RenderBox::pixelSnappedClientWidth() const
485 {
486     return snapSizeToPixel(clientWidth(), x() + clientLeft());
487 }
488
489 int RenderBox::pixelSnappedClientHeight() const
490 {
491     return snapSizeToPixel(clientHeight(), y() + clientTop());
492 }
493
494 int RenderBox::pixelSnappedOffsetWidth() const
495 {
496     return snapSizeToPixel(offsetWidth(), x() + clientLeft());
497 }
498
499 int RenderBox::pixelSnappedOffsetHeight() const
500 {
501     return snapSizeToPixel(offsetHeight(), y() + clientTop());
502 }
503
504 int RenderBox::scrollWidth() const
505 {
506     if (hasOverflowClip())
507         return layer()->scrollWidth();
508     // For objects with visible overflow, this matches IE.
509     // FIXME: Need to work right with writing modes.
510     if (style()->isLeftToRightDirection())
511         return snapSizeToPixel(max(clientWidth(), layoutOverflowRect().maxX() - borderLeft()), x() + clientLeft());
512     return clientWidth() - min<LayoutUnit>(0, layoutOverflowRect().x() - borderLeft());
513 }
514
515 int RenderBox::scrollHeight() const
516 {
517     if (hasOverflowClip())
518         return layer()->scrollHeight();
519     // For objects with visible overflow, this matches IE.
520     // FIXME: Need to work right with writing modes.
521     return snapSizeToPixel(max(clientHeight(), layoutOverflowRect().maxY() - borderTop()), y() + clientTop());
522 }
523
524 int RenderBox::scrollLeft() const
525 {
526     return hasOverflowClip() ? layer()->scrollXOffset() : 0;
527 }
528
529 int RenderBox::scrollTop() const
530 {
531     return hasOverflowClip() ? layer()->scrollYOffset() : 0;
532 }
533
534 void RenderBox::setScrollLeft(int newLeft)
535 {
536     if (hasOverflowClip())
537         layer()->scrollToXOffset(newLeft, RenderLayer::ScrollOffsetClamped);
538 }
539
540 void RenderBox::setScrollTop(int newTop)
541 {
542     if (hasOverflowClip())
543         layer()->scrollToYOffset(newTop, RenderLayer::ScrollOffsetClamped);
544 }
545
546 void RenderBox::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
547 {
548     rects.append(pixelSnappedIntRect(accumulatedOffset, size()));
549 }
550
551 void RenderBox::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
552 {
553     quads.append(localToAbsoluteQuad(FloatRect(0, 0, width(), height()), 0 /* mode */, wasFixed));
554 }
555
556 void RenderBox::updateLayerTransform()
557 {
558     // Transform-origin depends on box size, so we need to update the layer transform after layout.
559     if (hasLayer())
560         layer()->updateTransform();
561 }
562
563 LayoutUnit RenderBox::constrainLogicalWidthInRegionByMinMax(LayoutUnit logicalWidth, LayoutUnit availableWidth, RenderBlock* cb, RenderRegion* region) const
564 {
565     RenderStyle* styleToUse = style();
566     if (!styleToUse->logicalMaxWidth().isUndefined())
567         logicalWidth = min(logicalWidth, computeLogicalWidthInRegionUsing(MaxSize, styleToUse->logicalMaxWidth(), availableWidth, cb, region));
568     return max(logicalWidth, computeLogicalWidthInRegionUsing(MinSize, styleToUse->logicalMinWidth(), availableWidth, cb, region));
569 }
570
571 LayoutUnit RenderBox::constrainLogicalHeightByMinMax(LayoutUnit logicalHeight) const
572 {
573     RenderStyle* styleToUse = style();
574     if (!styleToUse->logicalMaxHeight().isUndefined()) {
575         LayoutUnit maxH = computeLogicalHeightUsing(styleToUse->logicalMaxHeight());
576         if (maxH != -1)
577             logicalHeight = min(logicalHeight, maxH);
578     }
579     return max(logicalHeight, computeLogicalHeightUsing(styleToUse->logicalMinHeight()));
580 }
581
582 LayoutUnit RenderBox::constrainContentBoxLogicalHeightByMinMax(LayoutUnit logicalHeight) const
583 {
584     RenderStyle* styleToUse = style();
585     if (!styleToUse->logicalMaxHeight().isUndefined()) {
586         LayoutUnit maxH = computeContentLogicalHeight(styleToUse->logicalMaxHeight());
587         if (maxH != -1)
588             logicalHeight = min(logicalHeight, maxH);
589     }
590     return max(logicalHeight, computeContentLogicalHeight(styleToUse->logicalMinHeight()));
591 }
592
593 IntRect RenderBox::absoluteContentBox() const
594 {
595     // This is wrong with transforms and flipped writing modes.
596     IntRect rect = pixelSnappedIntRect(contentBoxRect());
597     FloatPoint absPos = localToAbsolute();
598     rect.move(absPos.x(), absPos.y());
599     return rect;
600 }
601
602 FloatQuad RenderBox::absoluteContentQuad() const
603 {
604     LayoutRect rect = contentBoxRect();
605     return localToAbsoluteQuad(FloatRect(rect));
606 }
607
608 LayoutRect RenderBox::outlineBoundsForRepaint(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap) const
609 {
610     LayoutRect box = borderBoundingBox();
611     adjustRectForOutlineAndShadow(box);
612
613     if (repaintContainer != this) {
614         FloatQuad containerRelativeQuad;
615         if (geometryMap)
616             containerRelativeQuad = geometryMap->mapToContainer(box, repaintContainer);
617         else
618             containerRelativeQuad = localToContainerQuad(FloatRect(box), repaintContainer);
619
620         box = containerRelativeQuad.enclosingBoundingBox();
621     }
622     
623     // FIXME: layoutDelta needs to be applied in parts before/after transforms and
624     // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
625     box.move(view().layoutDelta());
626
627     return box;
628 }
629
630 void RenderBox::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*)
631 {
632     if (!size().isEmpty())
633         rects.append(pixelSnappedIntRect(additionalOffset, size()));
634 }
635
636 LayoutRect RenderBox::reflectionBox() const
637 {
638     LayoutRect result;
639     if (!style()->boxReflect())
640         return result;
641     LayoutRect box = borderBoxRect();
642     result = box;
643     switch (style()->boxReflect()->direction()) {
644         case ReflectionBelow:
645             result.move(0, box.height() + reflectionOffset());
646             break;
647         case ReflectionAbove:
648             result.move(0, -box.height() - reflectionOffset());
649             break;
650         case ReflectionLeft:
651             result.move(-box.width() - reflectionOffset(), 0);
652             break;
653         case ReflectionRight:
654             result.move(box.width() + reflectionOffset(), 0);
655             break;
656     }
657     return result;
658 }
659
660 int RenderBox::reflectionOffset() const
661 {
662     if (!style()->boxReflect())
663         return 0;
664     if (style()->boxReflect()->direction() == ReflectionLeft || style()->boxReflect()->direction() == ReflectionRight)
665         return valueForLength(style()->boxReflect()->offset(), borderBoxRect().width());
666     return valueForLength(style()->boxReflect()->offset(), borderBoxRect().height());
667 }
668
669 LayoutRect RenderBox::reflectedRect(const LayoutRect& r) const
670 {
671     if (!style()->boxReflect())
672         return LayoutRect();
673
674     LayoutRect box = borderBoxRect();
675     LayoutRect result = r;
676     switch (style()->boxReflect()->direction()) {
677         case ReflectionBelow:
678             result.setY(box.maxY() + reflectionOffset() + (box.maxY() - r.maxY()));
679             break;
680         case ReflectionAbove:
681             result.setY(box.y() - reflectionOffset() - box.height() + (box.maxY() - r.maxY()));
682             break;
683         case ReflectionLeft:
684             result.setX(box.x() - reflectionOffset() - box.width() + (box.maxX() - r.maxX()));
685             break;
686         case ReflectionRight:
687             result.setX(box.maxX() + reflectionOffset() + (box.maxX() - r.maxX()));
688             break;
689     }
690     return result;
691 }
692
693 bool RenderBox::fixedElementLaysOutRelativeToFrame(const FrameView& frameView) const
694 {
695     return style() && style()->position() == FixedPosition && container()->isRenderView() && frameView.fixedElementsLayoutRelativeToFrame();
696 }
697
698 bool RenderBox::includeVerticalScrollbarSize() const
699 {
700     return hasOverflowClip() && !layer()->hasOverlayScrollbars()
701         && (style()->overflowY() == OSCROLL || style()->overflowY() == OAUTO);
702 }
703
704 bool RenderBox::includeHorizontalScrollbarSize() const
705 {
706     return hasOverflowClip() && !layer()->hasOverlayScrollbars()
707         && (style()->overflowX() == OSCROLL || style()->overflowX() == OAUTO);
708 }
709
710 int RenderBox::verticalScrollbarWidth() const
711 {
712     return includeVerticalScrollbarSize() ? layer()->verticalScrollbarWidth() : 0;
713 }
714
715 int RenderBox::horizontalScrollbarHeight() const
716 {
717     return includeHorizontalScrollbarSize() ? layer()->horizontalScrollbarHeight() : 0;
718 }
719
720 int RenderBox::instrinsicScrollbarLogicalWidth() const
721 {
722     if (!hasOverflowClip())
723         return 0;
724
725     if (isHorizontalWritingMode() && style()->overflowY() == OSCROLL) {
726         ASSERT(layer()->hasVerticalScrollbar());
727         return verticalScrollbarWidth();
728     }
729
730     if (!isHorizontalWritingMode() && style()->overflowX() == OSCROLL) {
731         ASSERT(layer()->hasHorizontalScrollbar());
732         return horizontalScrollbarHeight();
733     }
734
735     return 0;
736 }
737
738 bool RenderBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier, Element** stopElement)
739 {
740     RenderLayer* l = layer();
741     if (l && l->scroll(direction, granularity, multiplier)) {
742         if (stopElement)
743             *stopElement = element();
744         return true;
745     }
746
747     if (stopElement && *stopElement && *stopElement == element())
748         return true;
749
750     RenderBlock* b = containingBlock();
751     if (b && !b->isRenderView())
752         return b->scroll(direction, granularity, multiplier, stopElement);
753     return false;
754 }
755
756 bool RenderBox::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity, float multiplier, Element** stopElement)
757 {
758     bool scrolled = false;
759     
760     RenderLayer* l = layer();
761     if (l) {
762 #if PLATFORM(MAC)
763         // On Mac only we reset the inline direction position when doing a document scroll (e.g., hitting Home/End).
764         if (granularity == ScrollByDocument)
765             scrolled = l->scroll(logicalToPhysical(ScrollInlineDirectionBackward, isHorizontalWritingMode(), style()->isFlippedBlocksWritingMode()), ScrollByDocument, multiplier);
766 #endif
767         if (l->scroll(logicalToPhysical(direction, isHorizontalWritingMode(), style()->isFlippedBlocksWritingMode()), granularity, multiplier))
768             scrolled = true;
769         
770         if (scrolled) {
771             if (stopElement)
772                 *stopElement = element();
773             return true;
774         }
775     }
776
777     if (stopElement && *stopElement && *stopElement == element())
778         return true;
779
780     RenderBlock* b = containingBlock();
781     if (b && !b->isRenderView())
782         return b->logicalScroll(direction, granularity, multiplier, stopElement);
783     return false;
784 }
785
786 bool RenderBox::canBeScrolledAndHasScrollableArea() const
787 {
788     return canBeProgramaticallyScrolled() && (scrollHeight() != clientHeight() || scrollWidth() != clientWidth());
789 }
790     
791 bool RenderBox::canBeProgramaticallyScrolled() const
792 {
793     if (isRenderView())
794         return true;
795
796     if (!hasOverflowClip())
797         return false;
798
799     bool hasScrollableOverflow = hasScrollableOverflowX() || hasScrollableOverflowY();
800     if (scrollsOverflow() && hasScrollableOverflow)
801         return true;
802
803     return element() && element()->rendererIsEditable();
804 }
805
806 bool RenderBox::usesCompositedScrolling() const
807 {
808     return hasOverflowClip() && hasLayer() && layer()->usesCompositedScrolling();
809 }
810
811 void RenderBox::autoscroll(const IntPoint& position)
812 {
813     if (layer())
814         layer()->autoscroll(position);
815 }
816
817 // There are two kinds of renderer that can autoscroll.
818 bool RenderBox::canAutoscroll() const
819 {
820     if (isRenderView())
821         return view().frameView().isScrollable();
822
823     // Check for a box that can be scrolled in its own right.
824     if (canBeScrolledAndHasScrollableArea())
825         return true;
826
827     return false;
828 }
829
830 // If specified point is in border belt, returned offset denotes direction of
831 // scrolling.
832 IntSize RenderBox::calculateAutoscrollDirection(const IntPoint& windowPoint) const
833 {
834     IntRect box(absoluteBoundingBoxRect());
835     box.move(view().frameView().scrollOffset());
836     IntRect windowBox = view().frameView().contentsToWindow(box);
837
838     IntPoint windowAutoscrollPoint = windowPoint;
839
840     if (windowAutoscrollPoint.x() < windowBox.x() + autoscrollBeltSize)
841         windowAutoscrollPoint.move(-autoscrollBeltSize, 0);
842     else if (windowAutoscrollPoint.x() > windowBox.maxX() - autoscrollBeltSize)
843         windowAutoscrollPoint.move(autoscrollBeltSize, 0);
844
845     if (windowAutoscrollPoint.y() < windowBox.y() + autoscrollBeltSize)
846         windowAutoscrollPoint.move(0, -autoscrollBeltSize);
847     else if (windowAutoscrollPoint.y() > windowBox.maxY() - autoscrollBeltSize)
848         windowAutoscrollPoint.move(0, autoscrollBeltSize);
849
850     return windowAutoscrollPoint - windowPoint;
851 }
852
853 RenderBox* RenderBox::findAutoscrollable(RenderObject* renderer)
854 {
855     while (renderer && !(renderer->isBox() && toRenderBox(renderer)->canAutoscroll())) {
856         if (renderer->isRenderView() && renderer->document().ownerElement())
857             renderer = renderer->document().ownerElement()->renderer();
858         else
859             renderer = renderer->parent();
860     }
861
862     return renderer && renderer->isBox() ? toRenderBox(renderer) : 0;
863 }
864
865 void RenderBox::panScroll(const IntPoint& source)
866 {
867     if (layer())
868         layer()->panScrollFromPoint(source);
869 }
870
871 bool RenderBox::needsPreferredWidthsRecalculation() const
872 {
873     return style()->paddingStart().isPercent() || style()->paddingEnd().isPercent();
874 }
875
876 IntSize RenderBox::scrolledContentOffset() const
877 {
878     ASSERT(hasOverflowClip());
879     ASSERT(hasLayer());
880     return layer()->scrolledContentOffset();
881 }
882
883 LayoutSize RenderBox::cachedSizeForOverflowClip() const
884 {
885     ASSERT(hasOverflowClip());
886     ASSERT(hasLayer());
887     return layer()->size();
888 }
889
890 void RenderBox::applyCachedClipAndScrollOffsetForRepaint(LayoutRect& paintRect) const
891 {
892     flipForWritingMode(paintRect);
893     paintRect.move(-scrolledContentOffset()); // For overflow:auto/scroll/hidden.
894
895     // Do not clip scroll layer contents to reduce the number of repaints while scrolling.
896     if (usesCompositedScrolling()) {
897         flipForWritingMode(paintRect);
898         return;
899     }
900
901     // height() is inaccurate if we're in the middle of a layout of this RenderBox, so use the
902     // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint
903     // anyway if its size does change.
904     LayoutRect clipRect(LayoutPoint(), cachedSizeForOverflowClip());
905     paintRect = intersection(paintRect, clipRect);
906     flipForWritingMode(paintRect);
907 }
908
909 void RenderBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
910 {
911     minLogicalWidth = minPreferredLogicalWidth() - borderAndPaddingLogicalWidth();
912     maxLogicalWidth = maxPreferredLogicalWidth() - borderAndPaddingLogicalWidth();
913 }
914
915 LayoutUnit RenderBox::minPreferredLogicalWidth() const
916 {
917     if (preferredLogicalWidthsDirty()) {
918 #ifndef NDEBUG
919         SetLayoutNeededForbiddenScope layoutForbiddenScope(const_cast<RenderBox*>(this));
920 #endif
921         const_cast<RenderBox*>(this)->computePreferredLogicalWidths();
922     }
923         
924     return m_minPreferredLogicalWidth;
925 }
926
927 LayoutUnit RenderBox::maxPreferredLogicalWidth() const
928 {
929     if (preferredLogicalWidthsDirty()) {
930 #ifndef NDEBUG
931         SetLayoutNeededForbiddenScope layoutForbiddenScope(const_cast<RenderBox*>(this));
932 #endif
933         const_cast<RenderBox*>(this)->computePreferredLogicalWidths();
934     }
935         
936     return m_maxPreferredLogicalWidth;
937 }
938
939 bool RenderBox::hasOverrideHeight() const
940 {
941     return gOverrideHeightMap && gOverrideHeightMap->contains(this);
942 }
943
944 bool RenderBox::hasOverrideWidth() const
945 {
946     return gOverrideWidthMap && gOverrideWidthMap->contains(this);
947 }
948
949 void RenderBox::setOverrideLogicalContentHeight(LayoutUnit height)
950 {
951     if (!gOverrideHeightMap)
952         gOverrideHeightMap = new OverrideSizeMap();
953     gOverrideHeightMap->set(this, height);
954 }
955
956 void RenderBox::setOverrideLogicalContentWidth(LayoutUnit width)
957 {
958     if (!gOverrideWidthMap)
959         gOverrideWidthMap = new OverrideSizeMap();
960     gOverrideWidthMap->set(this, width);
961 }
962
963 void RenderBox::clearOverrideLogicalContentHeight()
964 {
965     if (gOverrideHeightMap)
966         gOverrideHeightMap->remove(this);
967 }
968
969 void RenderBox::clearOverrideLogicalContentWidth()
970 {
971     if (gOverrideWidthMap)
972         gOverrideWidthMap->remove(this);
973 }
974
975 void RenderBox::clearOverrideSize()
976 {
977     clearOverrideLogicalContentHeight();
978     clearOverrideLogicalContentWidth();
979 }
980
981 LayoutUnit RenderBox::overrideLogicalContentWidth() const
982 {
983     ASSERT(hasOverrideWidth());
984     return gOverrideWidthMap->get(this);
985 }
986
987 LayoutUnit RenderBox::overrideLogicalContentHeight() const
988 {
989     ASSERT(hasOverrideHeight());
990     return gOverrideHeightMap->get(this);
991 }
992
993 LayoutUnit RenderBox::overrideContainingBlockContentLogicalWidth() const
994 {
995     ASSERT(hasOverrideContainingBlockLogicalWidth());
996     return gOverrideContainingBlockLogicalWidthMap->get(this);
997 }
998
999 LayoutUnit RenderBox::overrideContainingBlockContentLogicalHeight() const
1000 {
1001     ASSERT(hasOverrideContainingBlockLogicalHeight());
1002     return gOverrideContainingBlockLogicalHeightMap->get(this);
1003 }
1004
1005 bool RenderBox::hasOverrideContainingBlockLogicalWidth() const
1006 {
1007     return gOverrideContainingBlockLogicalWidthMap && gOverrideContainingBlockLogicalWidthMap->contains(this);
1008 }
1009
1010 bool RenderBox::hasOverrideContainingBlockLogicalHeight() const
1011 {
1012     return gOverrideContainingBlockLogicalHeightMap && gOverrideContainingBlockLogicalHeightMap->contains(this);
1013 }
1014
1015 void RenderBox::setOverrideContainingBlockContentLogicalWidth(LayoutUnit logicalWidth)
1016 {
1017     if (!gOverrideContainingBlockLogicalWidthMap)
1018         gOverrideContainingBlockLogicalWidthMap = new OverrideSizeMap;
1019     gOverrideContainingBlockLogicalWidthMap->set(this, logicalWidth);
1020 }
1021
1022 void RenderBox::setOverrideContainingBlockContentLogicalHeight(LayoutUnit logicalHeight)
1023 {
1024     if (!gOverrideContainingBlockLogicalHeightMap)
1025         gOverrideContainingBlockLogicalHeightMap = new OverrideSizeMap;
1026     gOverrideContainingBlockLogicalHeightMap->set(this, logicalHeight);
1027 }
1028
1029 void RenderBox::clearContainingBlockOverrideSize()
1030 {
1031     if (gOverrideContainingBlockLogicalWidthMap)
1032         gOverrideContainingBlockLogicalWidthMap->remove(this);
1033     clearOverrideContainingBlockContentLogicalHeight();
1034 }
1035
1036 void RenderBox::clearOverrideContainingBlockContentLogicalHeight()
1037 {
1038     if (gOverrideContainingBlockLogicalHeightMap)
1039         gOverrideContainingBlockLogicalHeightMap->remove(this);
1040 }
1041
1042 LayoutUnit RenderBox::adjustBorderBoxLogicalWidthForBoxSizing(LayoutUnit width) const
1043 {
1044     LayoutUnit bordersPlusPadding = borderAndPaddingLogicalWidth();
1045     if (style()->boxSizing() == CONTENT_BOX)
1046         return width + bordersPlusPadding;
1047     return max(width, bordersPlusPadding);
1048 }
1049
1050 LayoutUnit RenderBox::adjustBorderBoxLogicalHeightForBoxSizing(LayoutUnit height) const
1051 {
1052     LayoutUnit bordersPlusPadding = borderAndPaddingLogicalHeight();
1053     if (style()->boxSizing() == CONTENT_BOX)
1054         return height + bordersPlusPadding;
1055     return max(height, bordersPlusPadding);
1056 }
1057
1058 LayoutUnit RenderBox::adjustContentBoxLogicalWidthForBoxSizing(LayoutUnit width) const
1059 {
1060     if (style()->boxSizing() == BORDER_BOX)
1061         width -= borderAndPaddingLogicalWidth();
1062     return max<LayoutUnit>(0, width);
1063 }
1064
1065 LayoutUnit RenderBox::adjustContentBoxLogicalHeightForBoxSizing(LayoutUnit height) const
1066 {
1067     if (style()->boxSizing() == BORDER_BOX)
1068         height -= borderAndPaddingLogicalHeight();
1069     return max<LayoutUnit>(0, height);
1070 }
1071
1072 // Hit Testing
1073 bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
1074 {
1075     LayoutPoint adjustedLocation = accumulatedOffset + location();
1076
1077     // Check kids first.
1078     for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
1079         if (!child->hasLayer() && child->nodeAtPoint(request, result, locationInContainer, adjustedLocation, action)) {
1080             updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation));
1081             return true;
1082         }
1083     }
1084
1085     // Check our bounds next. For this purpose always assume that we can only be hit in the
1086     // foreground phase (which is true for replaced elements like images).
1087     LayoutRect boundsRect = borderBoxRectInRegion(locationInContainer.region());
1088     boundsRect.moveBy(adjustedLocation);
1089     if (visibleToHitTesting() && action == HitTestForeground && locationInContainer.intersects(boundsRect)) {
1090         updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation));
1091         if (!result.addNodeToRectBasedTestResult(element(), request, locationInContainer, boundsRect))
1092             return true;
1093     }
1094
1095     return false;
1096 }
1097
1098 // --------------------- painting stuff -------------------------------
1099
1100 void RenderBox::paintRootBoxFillLayers(const PaintInfo& paintInfo)
1101 {
1102     if (paintInfo.skipRootBackground())
1103         return;
1104
1105     RenderElement* rootBackgroundRenderer = rendererForRootBackground();
1106     
1107     const FillLayer* bgLayer = rootBackgroundRenderer->style()->backgroundLayers();
1108     Color bgColor = rootBackgroundRenderer->style()->visitedDependentColor(CSSPropertyBackgroundColor);
1109
1110     paintFillLayers(paintInfo, bgColor, bgLayer, view().backgroundRect(this), BackgroundBleedNone, CompositeSourceOver, rootBackgroundRenderer);
1111 }
1112
1113 BackgroundBleedAvoidance RenderBox::determineBackgroundBleedAvoidance(GraphicsContext* context) const
1114 {
1115     if (context->paintingDisabled())
1116         return BackgroundBleedNone;
1117
1118     const RenderStyle* style = this->style();
1119
1120     if (!style->hasBackground() || !style->hasBorder() || !style->hasBorderRadius() || borderImageIsLoadedAndCanBeRendered())
1121         return BackgroundBleedNone;
1122
1123     AffineTransform ctm = context->getCTM();
1124     FloatSize contextScaling(static_cast<float>(ctm.xScale()), static_cast<float>(ctm.yScale()));
1125
1126     // Because RoundedRect uses IntRect internally the inset applied by the 
1127     // BackgroundBleedShrinkBackground strategy cannot be less than one integer
1128     // layout coordinate, even with subpixel layout enabled. To take that into
1129     // account, we clamp the contextScaling to 1.0 for the following test so
1130     // that borderObscuresBackgroundEdge can only return true if the border
1131     // widths are greater than 2 in both layout coordinates and screen
1132     // coordinates.
1133     // This precaution will become obsolete if RoundedRect is ever promoted to
1134     // a sub-pixel representation.
1135     if (contextScaling.width() > 1) 
1136         contextScaling.setWidth(1);
1137     if (contextScaling.height() > 1) 
1138         contextScaling.setHeight(1);
1139
1140     if (borderObscuresBackgroundEdge(contextScaling))
1141         return BackgroundBleedShrinkBackground;
1142     if (!style->hasAppearance() && borderObscuresBackground() && backgroundHasOpaqueTopLayer())
1143         return BackgroundBleedBackgroundOverBorder;
1144
1145     return BackgroundBleedUseTransparencyLayer;
1146 }
1147
1148 void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1149 {
1150     if (!paintInfo.shouldPaintWithinRoot(*this))
1151         return;
1152
1153     LayoutRect paintRect = borderBoxRectInRegion(paintInfo.renderRegion);
1154     paintRect.moveBy(paintOffset);
1155
1156     BackgroundBleedAvoidance bleedAvoidance = determineBackgroundBleedAvoidance(paintInfo.context);
1157
1158     // FIXME: Should eventually give the theme control over whether the box shadow should paint, since controls could have
1159     // custom shadows of their own.
1160     if (!boxShadowShouldBeAppliedToBackground(bleedAvoidance))
1161         paintBoxShadow(paintInfo, paintRect, style(), Normal);
1162
1163     GraphicsContextStateSaver stateSaver(*paintInfo.context, false);
1164     if (bleedAvoidance == BackgroundBleedUseTransparencyLayer) {
1165         // To avoid the background color bleeding out behind the border, we'll render background and border
1166         // into a transparency layer, and then clip that in one go (which requires setting up the clip before
1167         // beginning the layer).
1168         RoundedRect border = style()->getRoundedBorderFor(paintRect, &view());
1169         stateSaver.save();
1170         paintInfo.context->clipRoundedRect(border);
1171         paintInfo.context->beginTransparencyLayer(1);
1172     }
1173
1174     // If we have a native theme appearance, paint that before painting our background.
1175     // The theme will tell us whether or not we should also paint the CSS background.
1176     IntRect snappedPaintRect(pixelSnappedIntRect(paintRect));
1177     bool themePainted = style()->hasAppearance() && !theme()->paint(this, paintInfo, snappedPaintRect);
1178     if (!themePainted) {
1179         if (bleedAvoidance == BackgroundBleedBackgroundOverBorder)
1180             paintBorder(paintInfo, paintRect, style(), bleedAvoidance);
1181
1182         paintBackground(paintInfo, paintRect, bleedAvoidance);
1183
1184         if (style()->hasAppearance())
1185             theme()->paintDecorations(this, paintInfo, snappedPaintRect);
1186     }
1187     paintBoxShadow(paintInfo, paintRect, style(), Inset);
1188
1189     // The theme will tell us whether or not we should also paint the CSS border.
1190     if (bleedAvoidance != BackgroundBleedBackgroundOverBorder && (!style()->hasAppearance() || (!themePainted && theme()->paintBorderOnly(this, paintInfo, snappedPaintRect))) && style()->hasBorder())
1191         paintBorder(paintInfo, paintRect, style(), bleedAvoidance);
1192
1193     if (bleedAvoidance == BackgroundBleedUseTransparencyLayer)
1194         paintInfo.context->endTransparencyLayer();
1195 }
1196
1197 void RenderBox::paintBackground(const PaintInfo& paintInfo, const LayoutRect& paintRect, BackgroundBleedAvoidance bleedAvoidance)
1198 {
1199     if (isRoot()) {
1200         paintRootBoxFillLayers(paintInfo);
1201         return;
1202     }
1203     if (isBody() && skipBodyBackground(this))
1204         return;
1205     if (backgroundIsKnownToBeObscured() && !boxShadowShouldBeAppliedToBackground(bleedAvoidance))
1206         return;
1207     paintFillLayers(paintInfo, style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), paintRect, bleedAvoidance);
1208 }
1209
1210 bool RenderBox::getBackgroundPaintedExtent(LayoutRect& paintedExtent) const
1211 {
1212     ASSERT(hasBackground());
1213     LayoutRect backgroundRect = pixelSnappedIntRect(borderBoxRect());
1214
1215     Color backgroundColor = style()->visitedDependentColor(CSSPropertyBackgroundColor);
1216     if (backgroundColor.isValid() && backgroundColor.alpha()) {
1217         paintedExtent = backgroundRect;
1218         return true;
1219     }
1220
1221     if (!style()->backgroundLayers()->image() || style()->backgroundLayers()->next()) {
1222         paintedExtent =  backgroundRect;
1223         return true;
1224     }
1225
1226     BackgroundImageGeometry geometry;
1227     calculateBackgroundImageGeometry(0, style()->backgroundLayers(), backgroundRect, geometry);
1228     paintedExtent = geometry.destRect();
1229     return !geometry.hasNonLocalGeometry();
1230 }
1231
1232 bool RenderBox::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const
1233 {
1234     if (isBody() && skipBodyBackground(this))
1235         return false;
1236
1237     Color backgroundColor = style()->visitedDependentColor(CSSPropertyBackgroundColor);
1238     if (!backgroundColor.isValid() || backgroundColor.hasAlpha())
1239         return false;
1240
1241     // If the element has appearance, it might be painted by theme.
1242     // We cannot be sure if theme paints the background opaque.
1243     // In this case it is safe to not assume opaqueness.
1244     // FIXME: May be ask theme if it paints opaque.
1245     if (style()->hasAppearance())
1246         return false;
1247     // FIXME: Check the opaqueness of background images.
1248
1249     // FIXME: Use rounded rect if border radius is present.
1250     if (style()->hasBorderRadius())
1251         return false;
1252     // FIXME: The background color clip is defined by the last layer.
1253     if (style()->backgroundLayers()->next())
1254         return false;
1255     LayoutRect backgroundRect;
1256     switch (style()->backgroundClip()) {
1257     case BorderFillBox:
1258         backgroundRect = borderBoxRect();
1259         break;
1260     case PaddingFillBox:
1261         backgroundRect = paddingBoxRect();
1262         break;
1263     case ContentFillBox:
1264         backgroundRect = contentBoxRect();
1265         break;
1266     default:
1267         break;
1268     }
1269     return backgroundRect.contains(localRect);
1270 }
1271
1272 static bool isCandidateForOpaquenessTest(RenderBox* childBox)
1273 {
1274     RenderStyle* childStyle = childBox->style();
1275     if (childStyle->position() != StaticPosition && childBox->containingBlock() != childBox->parent())
1276         return false;
1277     if (childStyle->visibility() != VISIBLE)
1278         return false;
1279 #if ENABLE(CSS_SHAPES)
1280     if (childStyle->shapeOutside())
1281         return false;
1282 #endif
1283     if (!childBox->width() || !childBox->height())
1284         return false;
1285     if (RenderLayer* childLayer = childBox->layer()) {
1286 #if USE(ACCELERATED_COMPOSITING)
1287         if (childLayer->isComposited())
1288             return false;
1289 #endif
1290         // FIXME: Deal with z-index.
1291         if (!childStyle->hasAutoZIndex())
1292             return false;
1293         if (childLayer->hasTransform() || childLayer->isTransparent() || childLayer->hasFilter())
1294             return false;
1295     }
1296     return true;
1297 }
1298
1299 bool RenderBox::foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, unsigned maxDepthToTest) const
1300 {
1301     if (!maxDepthToTest)
1302         return false;
1303     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
1304         if (!child->isBox())
1305             continue;
1306         RenderBox* childBox = toRenderBox(child);
1307         if (!isCandidateForOpaquenessTest(childBox))
1308             continue;
1309         LayoutPoint childLocation = childBox->location();
1310         if (childBox->isRelPositioned())
1311             childLocation.move(childBox->relativePositionOffset());
1312         LayoutRect childLocalRect = localRect;
1313         childLocalRect.moveBy(-childLocation);
1314         if (childLocalRect.y() < 0 || childLocalRect.x() < 0) {
1315             // If there is unobscured area above/left of a static positioned box then the rect is probably not covered.
1316             if (childBox->style()->position() == StaticPosition)
1317                 return false;
1318             continue;
1319         }
1320         if (childLocalRect.maxY() > childBox->height() || childLocalRect.maxX() > childBox->width())
1321             continue;
1322         if (childBox->backgroundIsKnownToBeOpaqueInRect(childLocalRect))
1323             return true;
1324         if (childBox->foregroundIsKnownToBeOpaqueInRect(childLocalRect, maxDepthToTest - 1))
1325             return true;
1326     }
1327     return false;
1328 }
1329
1330 bool RenderBox::computeBackgroundIsKnownToBeObscured()
1331 {
1332     // Test to see if the children trivially obscure the background.
1333     // FIXME: This test can be much more comprehensive.
1334     if (!hasBackground())
1335         return false;
1336     // Table and root background painting is special.
1337     if (isTable() || isRoot())
1338         return false;
1339
1340     LayoutRect backgroundRect;
1341     if (!getBackgroundPaintedExtent(backgroundRect))
1342         return false;
1343     return foregroundIsKnownToBeOpaqueInRect(backgroundRect, backgroundObscurationTestMaxDepth);
1344 }
1345
1346 bool RenderBox::backgroundHasOpaqueTopLayer() const
1347 {
1348     const FillLayer* fillLayer = style()->backgroundLayers();
1349     if (!fillLayer || fillLayer->clip() != BorderFillBox)
1350         return false;
1351
1352     // Clipped with local scrolling
1353     if (hasOverflowClip() && fillLayer->attachment() == LocalBackgroundAttachment)
1354         return false;
1355
1356     if (fillLayer->hasOpaqueImage(this) && fillLayer->hasRepeatXY() && fillLayer->image()->canRender(this, style()->effectiveZoom()))
1357         return true;
1358
1359     // If there is only one layer and no image, check whether the background color is opaque
1360     if (!fillLayer->next() && !fillLayer->hasImage()) {
1361         Color bgColor = style()->visitedDependentColor(CSSPropertyBackgroundColor);
1362         if (bgColor.isValid() && bgColor.alpha() == 255)
1363             return true;
1364     }
1365
1366     return false;
1367 }
1368
1369 void RenderBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1370 {
1371     if (!paintInfo.shouldPaintWithinRoot(*this) || style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask || paintInfo.context->paintingDisabled())
1372         return;
1373
1374     LayoutRect paintRect = LayoutRect(paintOffset, size());
1375     paintMaskImages(paintInfo, paintRect);
1376 }
1377
1378 void RenderBox::paintMaskImages(const PaintInfo& paintInfo, const LayoutRect& paintRect)
1379 {
1380     // Figure out if we need to push a transparency layer to render our mask.
1381     bool pushTransparencyLayer = false;
1382     bool compositedMask = hasLayer() && layer()->hasCompositedMask();
1383     bool flattenCompositingLayers = view().frameView().paintBehavior() & PaintBehaviorFlattenCompositingLayers;
1384     CompositeOperator compositeOp = CompositeSourceOver;
1385
1386     bool allMaskImagesLoaded = true;
1387     
1388     if (!compositedMask || flattenCompositingLayers) {
1389         pushTransparencyLayer = true;
1390         StyleImage* maskBoxImage = style()->maskBoxImage().image();
1391         const FillLayer* maskLayers = style()->maskLayers();
1392
1393         // Don't render a masked element until all the mask images have loaded, to prevent a flash of unmasked content.
1394         if (maskBoxImage)
1395             allMaskImagesLoaded &= maskBoxImage->isLoaded();
1396
1397         if (maskLayers)
1398             allMaskImagesLoaded &= maskLayers->imagesAreLoaded();
1399
1400         paintInfo.context->setCompositeOperation(CompositeDestinationIn);
1401         paintInfo.context->beginTransparencyLayer(1);
1402         compositeOp = CompositeSourceOver;
1403     }
1404
1405     if (allMaskImagesLoaded) {
1406         paintFillLayers(paintInfo, Color(), style()->maskLayers(), paintRect, BackgroundBleedNone, compositeOp);
1407         paintNinePieceImage(paintInfo.context, paintRect, style(), style()->maskBoxImage(), compositeOp);
1408     }
1409     
1410     if (pushTransparencyLayer)
1411         paintInfo.context->endTransparencyLayer();
1412 }
1413
1414 LayoutRect RenderBox::maskClipRect()
1415 {
1416     const NinePieceImage& maskBoxImage = style()->maskBoxImage();
1417     if (maskBoxImage.image()) {
1418         LayoutRect borderImageRect = borderBoxRect();
1419         
1420         // Apply outsets to the border box.
1421         borderImageRect.expand(style()->maskBoxImageOutsets());
1422         return borderImageRect;
1423     }
1424     
1425     LayoutRect result;
1426     LayoutRect borderBox = borderBoxRect();
1427     for (const FillLayer* maskLayer = style()->maskLayers(); maskLayer; maskLayer = maskLayer->next()) {
1428         if (maskLayer->image()) {
1429             BackgroundImageGeometry geometry;
1430             // Masks should never have fixed attachment, so it's OK for paintContainer to be null.
1431             calculateBackgroundImageGeometry(0, maskLayer, borderBox, geometry);
1432             result.unite(geometry.destRect());
1433         }
1434     }
1435     return result;
1436 }
1437
1438 void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, const LayoutRect& rect,
1439     BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderElement* backgroundObject)
1440 {
1441     Vector<const FillLayer*, 8> layers;
1442     const FillLayer* curLayer = fillLayer;
1443     bool shouldDrawBackgroundInSeparateBuffer = false;
1444     while (curLayer) {
1445         layers.append(curLayer);
1446         // Stop traversal when an opaque layer is encountered.
1447         // FIXME : It would be possible for the following occlusion culling test to be more aggressive 
1448         // on layers with no repeat by testing whether the image covers the layout rect.
1449         // Testing that here would imply duplicating a lot of calculations that are currently done in
1450         // RenderBoxModelObject::paintFillLayerExtended. A more efficient solution might be to move
1451         // the layer recursion into paintFillLayerExtended, or to compute the layer geometry here
1452         // and pass it down.
1453
1454         if (!shouldDrawBackgroundInSeparateBuffer && curLayer->blendMode() != BlendModeNormal)
1455             shouldDrawBackgroundInSeparateBuffer = true;
1456
1457         // The clipOccludesNextLayers condition must be evaluated first to avoid short-circuiting.
1458         if (curLayer->clipOccludesNextLayers(curLayer == fillLayer) && curLayer->hasOpaqueImage(this) && curLayer->image()->canRender(this, style()->effectiveZoom()) && curLayer->hasRepeatXY() && curLayer->blendMode() == BlendModeNormal)
1459             break;
1460         curLayer = curLayer->next();
1461     }
1462
1463     GraphicsContext* context = paintInfo.context;
1464     if (!context)
1465         shouldDrawBackgroundInSeparateBuffer = false;
1466     if (shouldDrawBackgroundInSeparateBuffer)
1467         context->beginTransparencyLayer(1);
1468
1469     Vector<const FillLayer*>::const_reverse_iterator topLayer = layers.rend();
1470     for (Vector<const FillLayer*>::const_reverse_iterator it = layers.rbegin(); it != topLayer; ++it)
1471         paintFillLayer(paintInfo, c, *it, rect, bleedAvoidance, op, backgroundObject);
1472
1473     if (shouldDrawBackgroundInSeparateBuffer)
1474         context->endTransparencyLayer();
1475 }
1476
1477 void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, const LayoutRect& rect,
1478     BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderElement* backgroundObject)
1479 {
1480     paintFillLayerExtended(paintInfo, c, fillLayer, rect, bleedAvoidance, 0, LayoutSize(), op, backgroundObject);
1481 }
1482
1483 #if USE(ACCELERATED_COMPOSITING)
1484 static bool layersUseImage(WrappedImagePtr image, const FillLayer* layers)
1485 {
1486     for (const FillLayer* curLayer = layers; curLayer; curLayer = curLayer->next()) {
1487         if (curLayer->image() && image == curLayer->image()->data())
1488             return true;
1489     }
1490
1491     return false;
1492 }
1493 #endif
1494
1495 void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*)
1496 {
1497     if (!parent())
1498         return;
1499
1500     if ((style()->borderImage().image() && style()->borderImage().image()->data() == image) ||
1501         (style()->maskBoxImage().image() && style()->maskBoxImage().image()->data() == image)) {
1502         repaint();
1503         return;
1504     }
1505
1506     bool didFullRepaint = repaintLayerRectsForImage(image, style()->backgroundLayers(), true);
1507     if (!didFullRepaint)
1508         repaintLayerRectsForImage(image, style()->maskLayers(), false);
1509
1510
1511 #if USE(ACCELERATED_COMPOSITING)
1512     if (!isComposited())
1513         return;
1514
1515     if (layer()->hasCompositedMask() && layersUseImage(image, style()->maskLayers()))
1516         layer()->contentChanged(MaskImageChanged);
1517     if (layersUseImage(image, style()->backgroundLayers()))
1518         layer()->contentChanged(BackgroundImageChanged);
1519 #endif
1520 }
1521
1522 bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer* layers, bool drawingBackground)
1523 {
1524     LayoutRect rendererRect;
1525     RenderBox* layerRenderer = 0;
1526
1527     for (const FillLayer* curLayer = layers; curLayer; curLayer = curLayer->next()) {
1528         if (curLayer->image() && image == curLayer->image()->data() && curLayer->image()->canRender(this, style()->effectiveZoom())) {
1529             // Now that we know this image is being used, compute the renderer and the rect if we haven't already.
1530             if (!layerRenderer) {
1531                 bool drawingRootBackground = drawingBackground && (isRoot() || (isBody() && !document().documentElement()->renderer()->hasBackground()));
1532                 if (drawingRootBackground) {
1533                     layerRenderer = &view();
1534
1535                     LayoutUnit rw = toRenderView(*layerRenderer).frameView().contentsWidth();
1536                     LayoutUnit rh = toRenderView(*layerRenderer).frameView().contentsHeight();
1537
1538                     rendererRect = LayoutRect(-layerRenderer->marginLeft(),
1539                         -layerRenderer->marginTop(),
1540                         max(layerRenderer->width() + layerRenderer->marginWidth() + layerRenderer->borderLeft() + layerRenderer->borderRight(), rw),
1541                         max(layerRenderer->height() + layerRenderer->marginHeight() + layerRenderer->borderTop() + layerRenderer->borderBottom(), rh));
1542                 } else {
1543                     layerRenderer = this;
1544                     rendererRect = borderBoxRect();
1545                 }
1546             }
1547
1548             BackgroundImageGeometry geometry;
1549             layerRenderer->calculateBackgroundImageGeometry(0, curLayer, rendererRect, geometry);
1550             if (geometry.hasNonLocalGeometry()) {
1551                 // Rather than incur the costs of computing the paintContainer for renderers with fixed backgrounds
1552                 // in order to get the right destRect, just repaint the entire renderer.
1553                 layerRenderer->repaint();
1554                 return true;
1555             }
1556             
1557             layerRenderer->repaintRectangle(geometry.destRect());
1558             if (geometry.destRect() == rendererRect)
1559                 return true;
1560         }
1561     }
1562     return false;
1563 }
1564
1565 #if PLATFORM(MAC)
1566
1567 void RenderBox::paintCustomHighlight(const LayoutPoint& paintOffset, const AtomicString& type, bool behindText)
1568 {
1569     Page* page = frame().page();
1570     if (!page)
1571         return;
1572
1573     InlineBox* boxWrap = inlineBoxWrapper();
1574     RootInlineBox* r = boxWrap ? &boxWrap->root() : 0;
1575     if (r) {
1576         FloatRect rootRect(paintOffset.x() + r->x(), paintOffset.y() + r->selectionTop(), r->logicalWidth(), r->selectionHeight());
1577         FloatRect imageRect(paintOffset.x() + x(), rootRect.y(), width(), rootRect.height());
1578         page->chrome().client().paintCustomHighlight(element(), type, imageRect, rootRect, behindText, false);
1579     } else {
1580         FloatRect imageRect(paintOffset.x() + x(), paintOffset.y() + y(), width(), height());
1581         page->chrome().client().paintCustomHighlight(element(), type, imageRect, imageRect, behindText, false);
1582     }
1583 }
1584
1585 #endif
1586
1587 bool RenderBox::pushContentsClip(PaintInfo& paintInfo, const LayoutPoint& accumulatedOffset)
1588 {
1589     if (paintInfo.phase == PaintPhaseBlockBackground || paintInfo.phase == PaintPhaseSelfOutline || paintInfo.phase == PaintPhaseMask)
1590         return false;
1591         
1592     bool isControlClip = hasControlClip();
1593     bool isOverflowClip = hasOverflowClip() && !layer()->isSelfPaintingLayer();
1594     
1595     if (!isControlClip && !isOverflowClip)
1596         return false;
1597     
1598     if (paintInfo.phase == PaintPhaseOutline)
1599         paintInfo.phase = PaintPhaseChildOutlines;
1600     else if (paintInfo.phase == PaintPhaseChildBlockBackground) {
1601         paintInfo.phase = PaintPhaseBlockBackground;
1602         paintObject(paintInfo, accumulatedOffset);
1603         paintInfo.phase = PaintPhaseChildBlockBackgrounds;
1604     }
1605     IntRect clipRect = pixelSnappedIntRect(isControlClip ? controlClipRect(accumulatedOffset) : overflowClipRect(accumulatedOffset, paintInfo.renderRegion, IgnoreOverlayScrollbarSize, paintInfo.phase));
1606     paintInfo.context->save();
1607     if (style()->hasBorderRadius())
1608         paintInfo.context->clipRoundedRect(style()->getRoundedInnerBorderFor(LayoutRect(accumulatedOffset, size())));
1609     paintInfo.context->clip(clipRect);
1610     return true;
1611 }
1612
1613 void RenderBox::popContentsClip(PaintInfo& paintInfo, PaintPhase originalPhase, const LayoutPoint& accumulatedOffset)
1614 {
1615     ASSERT(hasControlClip() || (hasOverflowClip() && !layer()->isSelfPaintingLayer()));
1616
1617     paintInfo.context->restore();
1618     if (originalPhase == PaintPhaseOutline) {
1619         paintInfo.phase = PaintPhaseSelfOutline;
1620         paintObject(paintInfo, accumulatedOffset);
1621         paintInfo.phase = originalPhase;
1622     } else if (originalPhase == PaintPhaseChildBlockBackground)
1623         paintInfo.phase = originalPhase;
1624 }
1625
1626 LayoutRect RenderBox::overflowClipRect(const LayoutPoint& location, RenderRegion* region, OverlayScrollbarSizeRelevancy relevancy, PaintPhase)
1627 {
1628     // FIXME: When overflow-clip (CSS3) is implemented, we'll obtain the property
1629     // here.
1630     LayoutRect clipRect = borderBoxRectInRegion(region);
1631     clipRect.setLocation(location + clipRect.location() + LayoutSize(borderLeft(), borderTop()));
1632     clipRect.setSize(clipRect.size() - LayoutSize(borderLeft() + borderRight(), borderTop() + borderBottom()));
1633
1634     // Subtract out scrollbars if we have them.
1635      if (layer()) {
1636         if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
1637             clipRect.move(layer()->verticalScrollbarWidth(relevancy), 0);
1638         clipRect.contract(layer()->verticalScrollbarWidth(relevancy), layer()->horizontalScrollbarHeight(relevancy));
1639      }
1640
1641     return clipRect;
1642 }
1643
1644 LayoutRect RenderBox::clipRect(const LayoutPoint& location, RenderRegion* region)
1645 {
1646     LayoutRect borderBoxRect = borderBoxRectInRegion(region);
1647     LayoutRect clipRect = LayoutRect(borderBoxRect.location() + location, borderBoxRect.size());
1648
1649     if (!style()->clipLeft().isAuto()) {
1650         LayoutUnit c = valueForLength(style()->clipLeft(), borderBoxRect.width());
1651         clipRect.move(c, 0);
1652         clipRect.contract(c, 0);
1653     }
1654
1655     // We don't use the region-specific border box's width and height since clip offsets are (stupidly) specified
1656     // from the left and top edges. Therefore it's better to avoid constraining to smaller widths and heights.
1657
1658     if (!style()->clipRight().isAuto())
1659         clipRect.contract(width() - valueForLength(style()->clipRight(), width()), 0);
1660
1661     if (!style()->clipTop().isAuto()) {
1662         LayoutUnit c = valueForLength(style()->clipTop(), borderBoxRect.height());
1663         clipRect.move(0, c);
1664         clipRect.contract(0, c);
1665     }
1666
1667     if (!style()->clipBottom().isAuto())
1668         clipRect.contract(0, height() - valueForLength(style()->clipBottom(), height()));
1669
1670     return clipRect;
1671 }
1672
1673 LayoutUnit RenderBox::shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStart, LayoutUnit childMarginEnd, const RenderBlock* cb, RenderRegion* region) const
1674 {    
1675     RenderRegion* containingBlockRegion = 0;
1676     LayoutUnit logicalTopPosition = logicalTop();
1677     if (region) {
1678         LayoutUnit offsetFromLogicalTopOfRegion = region ? region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage() : LayoutUnit();
1679         logicalTopPosition = max(logicalTopPosition, logicalTopPosition + offsetFromLogicalTopOfRegion);
1680         containingBlockRegion = cb->clampToStartAndEndRegions(region);
1681     }
1682
1683     LayoutUnit result = cb->availableLogicalWidthForLine(logicalTopPosition, false, containingBlockRegion) - childMarginStart - childMarginEnd;
1684
1685     // We need to see if margins on either the start side or the end side can contain the floats in question. If they can,
1686     // then just using the line width is inaccurate. In the case where a float completely fits, we don't need to use the line
1687     // offset at all, but can instead push all the way to the content edge of the containing block. In the case where the float
1688     // 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
1689     // "consumed" by the float. Negative margins aren't consumed by the float, and so we ignore them.
1690     if (childMarginStart > 0) {
1691         LayoutUnit startContentSide = cb->startOffsetForContent(containingBlockRegion);
1692         LayoutUnit startContentSideWithMargin = startContentSide + childMarginStart;
1693         LayoutUnit startOffset = cb->startOffsetForLine(logicalTopPosition, false, containingBlockRegion);
1694         if (startOffset > startContentSideWithMargin)
1695             result += childMarginStart;
1696         else
1697             result += startOffset - startContentSide;
1698     }
1699     
1700     if (childMarginEnd > 0) {
1701         LayoutUnit endContentSide = cb->endOffsetForContent(containingBlockRegion);
1702         LayoutUnit endContentSideWithMargin = endContentSide + childMarginEnd;
1703         LayoutUnit endOffset = cb->endOffsetForLine(logicalTopPosition, false, containingBlockRegion);
1704         if (endOffset > endContentSideWithMargin)
1705             result += childMarginEnd;
1706         else
1707             result += endOffset - endContentSide;
1708     }
1709
1710     return result;
1711 }
1712
1713 LayoutUnit RenderBox::containingBlockLogicalWidthForContent() const
1714 {
1715     if (hasOverrideContainingBlockLogicalWidth())
1716         return overrideContainingBlockContentLogicalWidth();
1717
1718     RenderBlock* cb = containingBlock();
1719     return cb->availableLogicalWidth();
1720 }
1721
1722 LayoutUnit RenderBox::containingBlockLogicalHeightForContent(AvailableLogicalHeightType heightType) const
1723 {
1724     if (hasOverrideContainingBlockLogicalHeight())
1725         return overrideContainingBlockContentLogicalHeight();
1726
1727     RenderBlock* cb = containingBlock();
1728     return cb->availableLogicalHeight(heightType);
1729 }
1730
1731 LayoutUnit RenderBox::containingBlockLogicalWidthForContentInRegion(RenderRegion* region) const
1732 {
1733     if (!region)
1734         return containingBlockLogicalWidthForContent();
1735
1736     RenderBlock* cb = containingBlock();
1737     RenderRegion* containingBlockRegion = cb->clampToStartAndEndRegions(region);
1738     // FIXME: It's unclear if a region's content should use the containing block's override logical width.
1739     // If it should, the following line should call containingBlockLogicalWidthForContent.
1740     LayoutUnit result = cb->availableLogicalWidth();
1741     RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(containingBlockRegion);
1742     if (!boxInfo)
1743         return result;
1744     return max<LayoutUnit>(0, result - (cb->logicalWidth() - boxInfo->logicalWidth()));
1745 }
1746
1747 LayoutUnit RenderBox::containingBlockAvailableLineWidthInRegion(RenderRegion* region) const
1748 {
1749     RenderBlock* cb = containingBlock();
1750     RenderRegion* containingBlockRegion = 0;
1751     LayoutUnit logicalTopPosition = logicalTop();
1752     if (region) {
1753         LayoutUnit offsetFromLogicalTopOfRegion = region ? region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage() : LayoutUnit();
1754         logicalTopPosition = max(logicalTopPosition, logicalTopPosition + offsetFromLogicalTopOfRegion);
1755         containingBlockRegion = cb->clampToStartAndEndRegions(region);
1756     }
1757     return cb->availableLogicalWidthForLine(logicalTopPosition, false, containingBlockRegion, availableLogicalHeight(IncludeMarginBorderPadding));
1758 }
1759
1760 LayoutUnit RenderBox::perpendicularContainingBlockLogicalHeight() const
1761 {
1762     if (hasOverrideContainingBlockLogicalHeight())
1763         return overrideContainingBlockContentLogicalHeight();
1764
1765     RenderBlock* cb = containingBlock();
1766     if (cb->hasOverrideHeight())
1767         return cb->overrideLogicalContentHeight();
1768
1769     RenderStyle* containingBlockStyle = cb->style();
1770     Length logicalHeightLength = containingBlockStyle->logicalHeight();
1771
1772     // FIXME: For now just support fixed heights.  Eventually should support percentage heights as well.
1773     if (!logicalHeightLength.isFixed()) {
1774         LayoutUnit fillFallbackExtent = containingBlockStyle->isHorizontalWritingMode() ? view().frameView().visibleHeight() : view().frameView().visibleWidth();
1775         LayoutUnit fillAvailableExtent = containingBlock()->availableLogicalHeight(ExcludeMarginBorderPadding);
1776         return min(fillAvailableExtent, fillFallbackExtent);
1777     }
1778
1779     // Use the content box logical height as specified by the style.
1780     return cb->adjustContentBoxLogicalHeightForBoxSizing(logicalHeightLength.value());
1781 }
1782
1783 void RenderBox::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const
1784 {
1785     if (repaintContainer == this)
1786         return;
1787
1788     if (view().layoutStateEnabled() && !repaintContainer) {
1789         LayoutState* layoutState = view().layoutState();
1790         LayoutSize offset = layoutState->m_paintOffset + locationOffset();
1791         if (style()->hasInFlowPosition() && layer())
1792             offset += layer()->offsetForInFlowPosition();
1793         transformState.move(offset);
1794         return;
1795     }
1796
1797     bool containerSkipped;
1798     RenderElement* o = container(repaintContainer, &containerSkipped);
1799     if (!o)
1800         return;
1801
1802     bool isFixedPos = style()->position() == FixedPosition;
1803     bool hasTransform = hasLayer() && layer()->transform();
1804     // If this box has a transform, it acts as a fixed position container for fixed descendants,
1805     // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
1806     if (hasTransform && !isFixedPos)
1807         mode &= ~IsFixed;
1808     else if (isFixedPos)
1809         mode |= IsFixed;
1810
1811     if (wasFixed)
1812         *wasFixed = mode & IsFixed;
1813     
1814     LayoutSize containerOffset = offsetFromContainer(o, roundedLayoutPoint(transformState.mappedPoint()));
1815     
1816     bool preserve3D = mode & UseTransforms && (o->style()->preserves3D() || style()->preserves3D());
1817     if (mode & UseTransforms && shouldUseTransformFromContainer(o)) {
1818         TransformationMatrix t;
1819         getTransformFromContainer(o, containerOffset, t);
1820         transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1821     } else
1822         transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1823
1824     if (containerSkipped) {
1825         // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
1826         // to just subtract the delta between the repaintContainer and o.
1827         LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
1828         transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1829         return;
1830     }
1831
1832     mode &= ~ApplyContainerFlip;
1833
1834     // For fixed positioned elements inside out-of-flow named flows, we do not want to
1835     // map their position further to regions based on their coordinates inside the named flows.
1836     if (!o->isOutOfFlowRenderFlowThread() || !fixedPositionedWithNamedFlowContainingBlock())
1837         o->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed);
1838     else
1839         o->mapLocalToContainer(toRenderLayerModelObject(o), transformState, mode, wasFixed);
1840 }
1841
1842 const RenderObject* RenderBox::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const
1843 {
1844     ASSERT(ancestorToStopAt != this);
1845
1846     bool ancestorSkipped;
1847     RenderElement* container = this->container(ancestorToStopAt, &ancestorSkipped);
1848     if (!container)
1849         return 0;
1850
1851     bool isFixedPos = style()->position() == FixedPosition;
1852     bool hasTransform = hasLayer() && layer()->transform();
1853
1854     LayoutSize adjustmentForSkippedAncestor;
1855     if (ancestorSkipped) {
1856         // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
1857         // to just subtract the delta between the ancestor and o.
1858         adjustmentForSkippedAncestor = -ancestorToStopAt->offsetFromAncestorContainer(container);
1859     }
1860
1861     bool offsetDependsOnPoint = false;
1862     LayoutSize containerOffset = offsetFromContainer(container, LayoutPoint(), &offsetDependsOnPoint);
1863
1864     bool preserve3D = container->style()->preserves3D() || style()->preserves3D();
1865     if (shouldUseTransformFromContainer(container)) {
1866         TransformationMatrix t;
1867         getTransformFromContainer(container, containerOffset, t);
1868         t.translateRight(adjustmentForSkippedAncestor.width(), adjustmentForSkippedAncestor.height());
1869         
1870         geometryMap.push(this, t, preserve3D, offsetDependsOnPoint, isFixedPos, hasTransform);
1871     } else {
1872         containerOffset += adjustmentForSkippedAncestor;
1873         geometryMap.push(this, containerOffset, preserve3D, offsetDependsOnPoint, isFixedPos, hasTransform);
1874     }
1875     
1876     return ancestorSkipped ? ancestorToStopAt : container;
1877 }
1878
1879 void RenderBox::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState& transformState) const
1880 {
1881     bool isFixedPos = style()->position() == FixedPosition;
1882     bool hasTransform = hasLayer() && layer()->transform();
1883     if (hasTransform && !isFixedPos) {
1884         // If this box has a transform, it acts as a fixed position container for fixed descendants,
1885         // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
1886         mode &= ~IsFixed;
1887     } else if (isFixedPos)
1888         mode |= IsFixed;
1889
1890     RenderBoxModelObject::mapAbsoluteToLocalPoint(mode, transformState);
1891 }
1892
1893 LayoutSize RenderBox::offsetFromContainer(RenderObject* o, const LayoutPoint& point, bool* offsetDependsOnPoint) const
1894 {
1895     // A region "has" boxes inside it without being their container. 
1896     ASSERT(o == container() || o->isRenderRegion());
1897
1898     LayoutSize offset;    
1899     if (isInFlowPositioned())
1900         offset += offsetForInFlowPosition();
1901
1902     if (!isInline() || isReplaced()) {
1903         if (!style()->hasOutOfFlowPosition() && o->hasColumns()) {
1904             RenderBlock* block = toRenderBlock(o);
1905             LayoutRect columnRect(frameRect());
1906             block->adjustStartEdgeForWritingModeIncludingColumns(columnRect);
1907             offset += toSize(columnRect.location());
1908             LayoutPoint columnPoint = block->flipForWritingModeIncludingColumns(point + offset);
1909             offset = toLayoutSize(block->flipForWritingModeIncludingColumns(toLayoutPoint(offset)));
1910             o->adjustForColumns(offset, columnPoint);
1911             offset = block->flipForWritingMode(offset);
1912
1913             if (offsetDependsOnPoint)
1914                 *offsetDependsOnPoint = true;
1915         } else
1916             offset += topLeftLocationOffset();
1917     }
1918
1919     if (o->hasOverflowClip())
1920         offset -= toRenderBox(o)->scrolledContentOffset();
1921
1922     if (style()->position() == AbsolutePosition && o->isInFlowPositioned() && o->isRenderInline())
1923         offset += toRenderInline(o)->offsetForInFlowPositionedInline(this);
1924
1925     if (offsetDependsOnPoint)
1926         *offsetDependsOnPoint |= o->isRenderFlowThread();
1927
1928     return offset;
1929 }
1930
1931 InlineBox* RenderBox::createInlineBox()
1932 {
1933     return new (renderArena()) InlineBox(*this);
1934 }
1935
1936 void RenderBox::dirtyLineBoxes(bool fullLayout)
1937 {
1938     if (m_inlineBoxWrapper) {
1939         if (fullLayout) {
1940             m_inlineBoxWrapper->destroy(renderArena());
1941             m_inlineBoxWrapper = 0;
1942         } else
1943             m_inlineBoxWrapper->dirtyLineBoxes();
1944     }
1945 }
1946
1947 void RenderBox::positionLineBox(InlineBox* box)
1948 {
1949     if (isOutOfFlowPositioned()) {
1950         // Cache the x position only if we were an INLINE type originally.
1951         bool wasInline = style()->isOriginalDisplayInlineType();
1952         if (wasInline) {
1953             // The value is cached in the xPos of the box.  We only need this value if
1954             // our object was inline originally, since otherwise it would have ended up underneath
1955             // the inlines.
1956             RootInlineBox& rootBox = box->root();
1957             rootBox.block().setStaticInlinePositionForChild(this, rootBox.lineTopWithLeading(), roundedLayoutUnit(box->logicalLeft()));
1958             if (style()->hasStaticInlinePosition(box->isHorizontal()))
1959                 setChildNeedsLayout(MarkOnlyThis); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
1960         } else {
1961             // Our object was a block originally, so we make our normal flow position be
1962             // just below the line box (as though all the inlines that came before us got
1963             // wrapped in an anonymous block, which is what would have happened had we been
1964             // in flow).  This value was cached in the y() of the box.
1965             layer()->setStaticBlockPosition(box->logicalTop());
1966             if (style()->hasStaticBlockPosition(box->isHorizontal()))
1967                 setChildNeedsLayout(MarkOnlyThis); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
1968         }
1969
1970         // Nuke the box.
1971         box->remove();
1972         box->destroy(renderArena());
1973     } else if (isReplaced()) {
1974         setLocation(roundedLayoutPoint(box->topLeft()));
1975         // m_inlineBoxWrapper should already be 0. Deleting it is a safeguard against security issues.
1976         ASSERT(!m_inlineBoxWrapper);
1977         if (m_inlineBoxWrapper)
1978             deleteLineBoxWrapper();
1979         m_inlineBoxWrapper = box;
1980     }
1981 }
1982
1983 void RenderBox::deleteLineBoxWrapper()
1984 {
1985     if (m_inlineBoxWrapper) {
1986         if (!documentBeingDestroyed())
1987             m_inlineBoxWrapper->remove();
1988         m_inlineBoxWrapper->destroy(renderArena());
1989         m_inlineBoxWrapper = 0;
1990     }
1991 }
1992
1993 LayoutRect RenderBox::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const
1994 {
1995     if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent())
1996         return LayoutRect();
1997
1998     LayoutRect r = visualOverflowRect();
1999
2000     // FIXME: layoutDelta needs to be applied in parts before/after transforms and
2001     // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
2002     r.move(view().layoutDelta());
2003     
2004     if (style()) {
2005         // We have to use maximalOutlineSize() because a child might have an outline
2006         // that projects outside of our overflowRect.
2007         ASSERT(style()->outlineSize() <= view().maximalOutlineSize());
2008         r.inflate(view().maximalOutlineSize());
2009     }
2010     
2011     computeRectForRepaint(repaintContainer, r);
2012     return r;
2013 }
2014
2015 void RenderBox::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& rect, bool fixed) const
2016 {
2017     // The rect we compute at each step is shifted by our x/y offset in the parent container's coordinate space.
2018     // Only when we cross a writing mode boundary will we have to possibly flipForWritingMode (to convert into a more appropriate
2019     // offset corner for the enclosing container).  This allows for a fully RL or BT document to repaint
2020     // properly even during layout, since the rect remains flipped all the way until the end.
2021     //
2022     // RenderView::computeRectForRepaint then converts the rect to physical coordinates.  We also convert to
2023     // physical when we hit a repaintContainer boundary.  Therefore the final rect returned is always in the
2024     // physical coordinate space of the repaintContainer.
2025     RenderStyle* styleToUse = style();
2026     // LayoutState is only valid for root-relative, non-fixed position repainting
2027     if (view().layoutStateEnabled() && !repaintContainer && styleToUse->position() != FixedPosition) {
2028         LayoutState* layoutState = view().layoutState();
2029
2030         if (layer() && layer()->transform())
2031             rect = layer()->transform()->mapRect(pixelSnappedIntRect(rect));
2032
2033         // We can't trust the bits on RenderObject, because this might be called while re-resolving style.
2034         if (styleToUse->hasInFlowPosition() && layer())
2035             rect.move(layer()->offsetForInFlowPosition());
2036
2037         rect.moveBy(location());
2038         rect.move(layoutState->m_paintOffset);
2039         if (layoutState->m_clipped)
2040             rect.intersect(layoutState->m_clipRect);
2041         return;
2042     }
2043
2044     if (hasReflection())
2045         rect.unite(reflectedRect(rect));
2046
2047     if (repaintContainer == this) {
2048         if (repaintContainer->style()->isFlippedBlocksWritingMode())
2049             flipForWritingMode(rect);
2050         return;
2051     }
2052
2053     bool containerSkipped;
2054     RenderElement* o = container(repaintContainer, &containerSkipped);
2055     if (!o)
2056         return;
2057
2058     if (isWritingModeRoot() && !isOutOfFlowPositioned())
2059         flipForWritingMode(rect);
2060
2061     LayoutPoint topLeft = rect.location();
2062     topLeft.move(locationOffset());
2063
2064     EPosition position = styleToUse->position();
2065
2066     // We are now in our parent container's coordinate space.  Apply our transform to obtain a bounding box
2067     // in the parent's coordinate space that encloses us.
2068     if (hasLayer() && layer()->transform()) {
2069         fixed = position == FixedPosition;
2070         rect = layer()->transform()->mapRect(pixelSnappedIntRect(rect));
2071         topLeft = rect.location();
2072         topLeft.move(locationOffset());
2073     } else if (position == FixedPosition)
2074         fixed = true;
2075
2076     if (position == AbsolutePosition && o->isInFlowPositioned() && o->isRenderInline())
2077         topLeft += toRenderInline(o)->offsetForInFlowPositionedInline(this);
2078     else if (styleToUse->hasInFlowPosition() && layer()) {
2079         // Apply the relative position offset when invalidating a rectangle.  The layer
2080         // is translated, but the render box isn't, so we need to do this to get the
2081         // right dirty rect.  Since this is called from RenderObject::setStyle, the relative position
2082         // flag on the RenderObject has been cleared, so use the one on the style().
2083         topLeft += layer()->offsetForInFlowPosition();
2084     }
2085     
2086     if (position != AbsolutePosition && position != FixedPosition && o->hasColumns() && o->isRenderBlockFlow()) {
2087         LayoutRect repaintRect(topLeft, rect.size());
2088         toRenderBlock(o)->adjustRectForColumns(repaintRect);
2089         topLeft = repaintRect.location();
2090         rect = repaintRect;
2091     }
2092
2093     // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
2094     // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
2095     rect.setLocation(topLeft);
2096     if (o->hasOverflowClip()) {
2097         RenderBox* containerBox = toRenderBox(o);
2098         containerBox->applyCachedClipAndScrollOffsetForRepaint(rect);
2099         if (rect.isEmpty())
2100             return;
2101     }
2102
2103     if (containerSkipped) {
2104         // If the repaintContainer is below o, then we need to map the rect into repaintContainer's coordinates.
2105         LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
2106         rect.move(-containerOffset);
2107         return;
2108     }
2109
2110     o->computeRectForRepaint(repaintContainer, rect, fixed);
2111 }
2112
2113 void RenderBox::repaintDuringLayoutIfMoved(const LayoutRect& oldRect)
2114 {
2115     if (oldRect.location() != m_frameRect.location()) {
2116         LayoutRect newRect = m_frameRect;
2117         // The child moved.  Invalidate the object's old and new positions.  We have to do this
2118         // since the object may not have gotten a layout.
2119         m_frameRect = oldRect;
2120         repaint();
2121         repaintOverhangingFloats(true);
2122         m_frameRect = newRect;
2123         repaint();
2124         repaintOverhangingFloats(true);
2125     }
2126 }
2127
2128 void RenderBox::repaintOverhangingFloats(bool)
2129 {
2130 }
2131
2132 void RenderBox::updateLogicalWidth()
2133 {
2134     LogicalExtentComputedValues computedValues;
2135     computeLogicalWidthInRegion(computedValues);
2136
2137     setLogicalWidth(computedValues.m_extent);
2138     setLogicalLeft(computedValues.m_position);
2139     setMarginStart(computedValues.m_margins.m_start);
2140     setMarginEnd(computedValues.m_margins.m_end);
2141 }
2142
2143 void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& computedValues, RenderRegion* region) const
2144 {
2145     computedValues.m_extent = logicalWidth();
2146     computedValues.m_position = logicalLeft();
2147     computedValues.m_margins.m_start = marginStart();
2148     computedValues.m_margins.m_end = marginEnd();
2149
2150     if (isOutOfFlowPositioned()) {
2151         // FIXME: This calculation is not patched for block-flow yet.
2152         // https://bugs.webkit.org/show_bug.cgi?id=46500
2153         computePositionedLogicalWidth(computedValues, region);
2154         return;
2155     }
2156
2157     // If layout is limited to a subtree, the subtree root's logical width does not change.
2158     if (element() && view().frameView().layoutRoot(true) == this)
2159         return;
2160
2161     // The parent box is flexing us, so it has increased or decreased our
2162     // width.  Use the width from the style context.
2163     // FIXME: Account for block-flow in flexible boxes.
2164     // https://bugs.webkit.org/show_bug.cgi?id=46418
2165     if (hasOverrideWidth() && (style()->borderFit() == BorderFitLines || parent()->isFlexibleBoxIncludingDeprecated())) {
2166         computedValues.m_extent = overrideLogicalContentWidth() + borderAndPaddingLogicalWidth();
2167         return;
2168     }
2169
2170     // FIXME: Account for block-flow in flexible boxes.
2171     // https://bugs.webkit.org/show_bug.cgi?id=46418
2172     bool inVerticalBox = parent()->isDeprecatedFlexibleBox() && (parent()->style()->boxOrient() == VERTICAL);
2173     bool stretching = (parent()->style()->boxAlign() == BSTRETCH);
2174     bool treatAsReplaced = shouldComputeSizeAsReplaced() && (!inVerticalBox || !stretching);
2175
2176     RenderStyle* styleToUse = style();
2177     Length logicalWidthLength = treatAsReplaced ? Length(computeReplacedLogicalWidth(), Fixed) : styleToUse->logicalWidth();
2178
2179     RenderBlock* cb = containingBlock();
2180     LayoutUnit containerLogicalWidth = max<LayoutUnit>(0, containingBlockLogicalWidthForContentInRegion(region));
2181     bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHorizontalWritingMode();
2182     
2183     if (isInline() && !isInlineBlockOrInlineTable()) {
2184         // just calculate margins
2185         computedValues.m_margins.m_start = minimumValueForLength(styleToUse->marginStart(), containerLogicalWidth);
2186         computedValues.m_margins.m_end = minimumValueForLength(styleToUse->marginEnd(), containerLogicalWidth);
2187         if (treatAsReplaced)
2188             computedValues.m_extent = max<LayoutUnit>(floatValueForLength(logicalWidthLength, 0) + borderAndPaddingLogicalWidth(), minPreferredLogicalWidth());
2189         return;
2190     }
2191
2192     // Width calculations
2193     if (treatAsReplaced)
2194         computedValues.m_extent = logicalWidthLength.value() + borderAndPaddingLogicalWidth();
2195     else {
2196         LayoutUnit containerWidthInInlineDirection = containerLogicalWidth;
2197         if (hasPerpendicularContainingBlock)
2198             containerWidthInInlineDirection = perpendicularContainingBlockLogicalHeight();
2199         LayoutUnit preferredWidth = computeLogicalWidthInRegionUsing(MainOrPreferredSize, styleToUse->logicalWidth(), containerWidthInInlineDirection, cb, region);
2200         computedValues.m_extent = constrainLogicalWidthInRegionByMinMax(preferredWidth, containerWidthInInlineDirection, cb, region);
2201     }
2202
2203     // Margin calculations.
2204     if (hasPerpendicularContainingBlock || isFloating() || isInline()) {
2205         computedValues.m_margins.m_start = minimumValueForLength(styleToUse->marginStart(), containerLogicalWidth);
2206         computedValues.m_margins.m_end = minimumValueForLength(styleToUse->marginEnd(), containerLogicalWidth);
2207     } else {
2208         LayoutUnit containerLogicalWidthForAutoMargins = containerLogicalWidth;
2209         if (avoidsFloats() && cb->containsFloats())
2210             containerLogicalWidthForAutoMargins = containingBlockAvailableLineWidthInRegion(region);
2211         bool hasInvertedDirection = cb->style()->isLeftToRightDirection() != style()->isLeftToRightDirection();
2212         computeInlineDirectionMargins(cb, containerLogicalWidthForAutoMargins, computedValues.m_extent,
2213             hasInvertedDirection ? computedValues.m_margins.m_end : computedValues.m_margins.m_start,
2214             hasInvertedDirection ? computedValues.m_margins.m_start : computedValues.m_margins.m_end);
2215     }
2216     
2217     if (!hasPerpendicularContainingBlock && containerLogicalWidth && containerLogicalWidth != (computedValues.m_extent + computedValues.m_margins.m_start + computedValues.m_margins.m_end)
2218         && !isFloating() && !isInline() && !cb->isFlexibleBoxIncludingDeprecated() && !cb->isRenderGrid()) {
2219         LayoutUnit newMargin = containerLogicalWidth - computedValues.m_extent - cb->marginStartForChild(this);
2220         bool hasInvertedDirection = cb->style()->isLeftToRightDirection() != style()->isLeftToRightDirection();
2221         if (hasInvertedDirection)
2222             computedValues.m_margins.m_start = newMargin;
2223         else
2224             computedValues.m_margins.m_end = newMargin;
2225     }
2226 }
2227
2228 LayoutUnit RenderBox::fillAvailableMeasure(LayoutUnit availableLogicalWidth) const
2229 {
2230     LayoutUnit marginStart = 0;
2231     LayoutUnit marginEnd = 0;
2232     return fillAvailableMeasure(availableLogicalWidth, marginStart, marginEnd);
2233 }
2234
2235 LayoutUnit RenderBox::fillAvailableMeasure(LayoutUnit availableLogicalWidth, LayoutUnit& marginStart, LayoutUnit& marginEnd) const
2236 {
2237     marginStart = minimumValueForLength(style()->marginStart(), availableLogicalWidth);
2238     marginEnd = minimumValueForLength(style()->marginEnd(), availableLogicalWidth);
2239     return availableLogicalWidth - marginStart - marginEnd;
2240 }
2241
2242 LayoutUnit RenderBox::computeIntrinsicLogicalWidthUsing(Length logicalWidthLength, LayoutUnit availableLogicalWidth, LayoutUnit borderAndPadding) const
2243 {
2244     if (logicalWidthLength.type() == FillAvailable)
2245         return fillAvailableMeasure(availableLogicalWidth);
2246
2247     LayoutUnit minLogicalWidth = 0;
2248     LayoutUnit maxLogicalWidth = 0;
2249     computeIntrinsicLogicalWidths(minLogicalWidth, maxLogicalWidth);
2250
2251     if (logicalWidthLength.type() == MinContent)
2252         return minLogicalWidth + borderAndPadding;
2253
2254     if (logicalWidthLength.type() == MaxContent)
2255         return maxLogicalWidth + borderAndPadding;
2256
2257     if (logicalWidthLength.type() == FitContent) {
2258         minLogicalWidth += borderAndPadding;
2259         maxLogicalWidth += borderAndPadding;
2260         return max(minLogicalWidth, min(maxLogicalWidth, fillAvailableMeasure(availableLogicalWidth)));
2261     }
2262
2263     ASSERT_NOT_REACHED();
2264     return 0;
2265 }
2266
2267 LayoutUnit RenderBox::computeLogicalWidthInRegionUsing(SizeType widthType, Length logicalWidth, LayoutUnit availableLogicalWidth,
2268     const RenderBlock* cb, RenderRegion* region) const
2269 {
2270     if (!logicalWidth.isIntrinsicOrAuto()) {
2271         // FIXME: If the containing block flow is perpendicular to our direction we need to use the available logical height instead.
2272         return adjustBorderBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, availableLogicalWidth));
2273     }
2274
2275     if (logicalWidth.isIntrinsic())
2276         return computeIntrinsicLogicalWidthUsing(logicalWidth, availableLogicalWidth, borderAndPaddingLogicalWidth());
2277
2278     LayoutUnit marginStart = 0;
2279     LayoutUnit marginEnd = 0;
2280     LayoutUnit logicalWidthResult = fillAvailableMeasure(availableLogicalWidth, marginStart, marginEnd);
2281
2282     if (shrinkToAvoidFloats() && cb->containsFloats())
2283         logicalWidthResult = min(logicalWidthResult, shrinkLogicalWidthToAvoidFloats(marginStart, marginEnd, cb, region));        
2284
2285     if (widthType == MainOrPreferredSize && sizesLogicalWidthToFitContent(widthType))
2286         return max(minPreferredLogicalWidth(), min(maxPreferredLogicalWidth(), logicalWidthResult));
2287     return logicalWidthResult;
2288 }
2289
2290 static bool flexItemHasStretchAlignment(const RenderObject* flexitem)
2291 {
2292     RenderObject* parent = flexitem->parent();
2293     return flexitem->style()->alignSelf() == AlignStretch || (flexitem->style()->alignSelf() == AlignAuto && parent->style()->alignItems() == AlignStretch);
2294 }
2295
2296 static bool isStretchingColumnFlexItem(const RenderObject* flexitem)
2297 {
2298     RenderObject* parent = flexitem->parent();
2299     if (parent->isDeprecatedFlexibleBox() && parent->style()->boxOrient() == VERTICAL && parent->style()->boxAlign() == BSTRETCH)
2300         return true;
2301
2302     // We don't stretch multiline flexboxes because they need to apply line spacing (align-content) first.
2303     if (parent->isFlexibleBox() && parent->style()->flexWrap() == FlexNoWrap && parent->style()->isColumnFlexDirection() && flexItemHasStretchAlignment(flexitem))
2304         return true;
2305     return false;
2306 }
2307
2308 bool RenderBox::sizesLogicalWidthToFitContent(SizeType widthType) const
2309 {
2310     // Marquees in WinIE are like a mixture of blocks and inline-blocks.  They size as though they're blocks,
2311     // but they allow text to sit on the same line as the marquee.
2312     if (isFloating() || (isInlineBlockOrInlineTable() && !isHTMLMarquee()))
2313         return true;
2314
2315     // This code may look a bit strange.  Basically width:intrinsic should clamp the size when testing both
2316     // min-width and width.  max-width is only clamped if it is also intrinsic.
2317     Length logicalWidth = (widthType == MaxSize) ? style()->logicalMaxWidth() : style()->logicalWidth();
2318     if (logicalWidth.type() == Intrinsic)
2319         return true;
2320
2321     // Children of a horizontal marquee do not fill the container by default.
2322     // FIXME: Need to deal with MAUTO value properly.  It could be vertical.
2323     // FIXME: Think about block-flow here.  Need to find out how marquee direction relates to
2324     // block-flow (as well as how marquee overflow should relate to block flow).
2325     // https://bugs.webkit.org/show_bug.cgi?id=46472
2326     if (parent()->style()->overflowX() == OMARQUEE) {
2327         EMarqueeDirection dir = parent()->style()->marqueeDirection();
2328         if (dir == MAUTO || dir == MFORWARD || dir == MBACKWARD || dir == MLEFT || dir == MRIGHT)
2329             return true;
2330     }
2331
2332     // Flexible box items should shrink wrap, so we lay them out at their intrinsic widths.
2333     // In the case of columns that have a stretch alignment, we go ahead and layout at the
2334     // stretched size to avoid an extra layout when applying alignment.
2335     if (parent()->isFlexibleBox()) {
2336         // For multiline columns, we need to apply align-content first, so we can't stretch now.
2337         if (!parent()->style()->isColumnFlexDirection() || parent()->style()->flexWrap() != FlexNoWrap)
2338             return true;
2339         if (!flexItemHasStretchAlignment(this))
2340             return true;
2341     }
2342
2343     // Flexible horizontal boxes lay out children at their intrinsic widths.  Also vertical boxes
2344     // that don't stretch their kids lay out their children at their intrinsic widths.
2345     // FIXME: Think about block-flow here.
2346     // https://bugs.webkit.org/show_bug.cgi?id=46473
2347     if (parent()->isDeprecatedFlexibleBox() && (parent()->style()->boxOrient() == HORIZONTAL || parent()->style()->boxAlign() != BSTRETCH))
2348         return true;
2349
2350     // Button, input, select, textarea, and legend treat width value of 'auto' as 'intrinsic' unless it's in a
2351     // stretching column flexbox.
2352     // FIXME: Think about block-flow here.
2353     // https://bugs.webkit.org/show_bug.cgi?id=46473
2354     if (logicalWidth.type() == Auto && !isStretchingColumnFlexItem(this) && element() && (isHTMLInputElement(element()) || element()->hasTagName(selectTag) || element()->hasTagName(buttonTag) || isHTMLTextAreaElement(element()) || element()->hasTagName(legendTag)))
2355         return true;
2356
2357     if (isHorizontalWritingMode() != containingBlock()->isHorizontalWritingMode())
2358         return true;
2359
2360     return false;
2361 }
2362
2363 void RenderBox::computeInlineDirectionMargins(RenderBlock* containingBlock, LayoutUnit containerWidth, LayoutUnit childWidth, LayoutUnit& marginStart, LayoutUnit& marginEnd) const
2364 {
2365     const RenderStyle* containingBlockStyle = containingBlock->style();
2366     Length marginStartLength = style()->marginStartUsing(containingBlockStyle);
2367     Length marginEndLength = style()->marginEndUsing(containingBlockStyle);
2368
2369     if (isFloating() || isInline()) {
2370         // Inline blocks/tables and floats don't have their margins increased.
2371         marginStart = minimumValueForLength(marginStartLength, containerWidth);
2372         marginEnd = minimumValueForLength(marginEndLength, containerWidth);
2373         return;
2374     }
2375
2376     // Case One: The object is being centered in the containing block's available logical width.
2377     if ((marginStartLength.isAuto() && marginEndLength.isAuto() && childWidth < containerWidth)
2378         || (!marginStartLength.isAuto() && !marginEndLength.isAuto() && containingBlock->style()->textAlign() == WEBKIT_CENTER)) {
2379         // Other browsers center the margin box for align=center elements so we match them here.
2380         LayoutUnit marginStartWidth = minimumValueForLength(marginStartLength, containerWidth);
2381         LayoutUnit marginEndWidth = minimumValueForLength(marginEndLength, containerWidth);
2382         LayoutUnit centeredMarginBoxStart = max<LayoutUnit>(0, (containerWidth - childWidth - marginStartWidth - marginEndWidth) / 2);
2383         marginStart = centeredMarginBoxStart + marginStartWidth;
2384         marginEnd = containerWidth - childWidth - marginStart + marginEndWidth;
2385         return;
2386     } 
2387     
2388     // Case Two: The object is being pushed to the start of the containing block's available logical width.
2389     if (marginEndLength.isAuto() && childWidth < containerWidth) {
2390         marginStart = valueForLength(marginStartLength, containerWidth);
2391         marginEnd = containerWidth - childWidth - marginStart;
2392         return;
2393     } 
2394     
2395     // Case Three: The object is being pushed to the end of the containing block's available logical width.
2396     bool pushToEndFromTextAlign = !marginEndLength.isAuto() && ((!containingBlockStyle->isLeftToRightDirection() && containingBlockStyle->textAlign() == WEBKIT_LEFT)
2397         || (containingBlockStyle->isLeftToRightDirection() && containingBlockStyle->textAlign() == WEBKIT_RIGHT));
2398     if ((marginStartLength.isAuto() && childWidth < containerWidth) || pushToEndFromTextAlign) {
2399         marginEnd = valueForLength(marginEndLength, containerWidth);
2400         marginStart = containerWidth - childWidth - marginEnd;
2401         return;
2402     } 
2403     
2404     // Case Four: Either no auto margins, or our width is >= the container width (css2.1, 10.3.3).  In that case
2405     // auto margins will just turn into 0.
2406     marginStart = minimumValueForLength(marginStartLength, containerWidth);
2407     marginEnd = minimumValueForLength(marginEndLength, containerWidth);
2408 }
2409
2410 RenderBoxRegionInfo* RenderBox::renderBoxRegionInfo(RenderRegion* region, RenderBoxRegionInfoFlags cacheFlag) const
2411 {
2412     // Make sure nobody is trying to call this with a null region.
2413     if (!region)
2414         return 0;
2415
2416     // If we have computed our width in this region already, it will be cached, and we can
2417     // just return it.
2418     RenderBoxRegionInfo* boxInfo = region->renderBoxRegionInfo(this);
2419     if (boxInfo && cacheFlag == CacheRenderBoxRegionInfo)
2420         return boxInfo;
2421
2422     // No cached value was found, so we have to compute our insets in this region.
2423     // FIXME: For now we limit this computation to normal RenderBlocks. Future patches will expand
2424     // support to cover all boxes.
2425     RenderFlowThread* flowThread = flowThreadContainingBlock();
2426     if (isRenderFlowThread() || !flowThread || !canHaveBoxInfoInRegion() || flowThread->style()->writingMode() != style()->writingMode())
2427         return 0;
2428
2429     LogicalExtentComputedValues computedValues;
2430     computeLogicalWidthInRegion(computedValues, region);
2431
2432     // Now determine the insets based off where this object is supposed to be positioned.
2433     RenderBlock* cb = containingBlock();
2434     RenderRegion* clampedContainingBlockRegion = cb->clampToStartAndEndRegions(region);
2435     RenderBoxRegionInfo* containingBlockInfo = cb->renderBoxRegionInfo(clampedContainingBlockRegion);
2436     LayoutUnit containingBlockLogicalWidth = cb->logicalWidth();
2437     LayoutUnit containingBlockLogicalWidthInRegion = containingBlockInfo ? containingBlockInfo->logicalWidth() : containingBlockLogicalWidth;
2438     
2439     LayoutUnit marginStartInRegion = computedValues.m_margins.m_start;
2440     LayoutUnit startMarginDelta = marginStartInRegion - marginStart();
2441     LayoutUnit logicalWidthInRegion = computedValues.m_extent;
2442     LayoutUnit logicalLeftInRegion = computedValues.m_position;
2443     LayoutUnit widthDelta = logicalWidthInRegion - logicalWidth();
2444     LayoutUnit logicalLeftDelta = isOutOfFlowPositioned() ? logicalLeftInRegion - logicalLeft() : startMarginDelta;
2445     LayoutUnit logicalRightInRegion = containingBlockLogicalWidthInRegion - (logicalLeftInRegion + logicalWidthInRegion);
2446     LayoutUnit oldLogicalRight = containingBlockLogicalWidth - (logicalLeft() + logicalWidth());
2447     LayoutUnit logicalRightDelta = isOutOfFlowPositioned() ? logicalRightInRegion - oldLogicalRight : startMarginDelta;
2448
2449     LayoutUnit logicalLeftOffset = 0;
2450     
2451     if (!isOutOfFlowPositioned() && avoidsFloats() && cb->containsFloats()) {
2452         LayoutUnit startPositionDelta = cb->computeStartPositionDeltaForChildAvoidingFloats(this, marginStartInRegion, region);
2453         if (cb->style()->isLeftToRightDirection())
2454             logicalLeftDelta += startPositionDelta;
2455         else
2456             logicalRightDelta += startPositionDelta;
2457     }
2458
2459     if (cb->style()->isLeftToRightDirection())
2460         logicalLeftOffset += logicalLeftDelta;
2461     else
2462         logicalLeftOffset -= (widthDelta + logicalRightDelta);
2463     
2464     LayoutUnit logicalRightOffset = logicalWidth() - (logicalLeftOffset + logicalWidthInRegion);
2465     bool isShifted = (containingBlockInfo && containingBlockInfo->isShifted())
2466             || (style()->isLeftToRightDirection() && logicalLeftOffset)
2467             || (!style()->isLeftToRightDirection() && logicalRightOffset);
2468
2469     // FIXME: Although it's unlikely, these boxes can go outside our bounds, and so we will need to incorporate them into overflow.
2470     if (cacheFlag == CacheRenderBoxRegionInfo)
2471         return region->setRenderBoxRegionInfo(this, logicalLeftOffset, logicalWidthInRegion, isShifted);
2472     return new RenderBoxRegionInfo(logicalLeftOffset, logicalWidthInRegion, isShifted);
2473 }
2474
2475 static bool shouldFlipBeforeAfterMargins(const RenderStyle* containingBlockStyle, const RenderStyle* childStyle)
2476 {
2477     ASSERT(containingBlockStyle->isHorizontalWritingMode() != childStyle->isHorizontalWritingMode());
2478     WritingMode childWritingMode = childStyle->writingMode();
2479     bool shouldFlip = false;
2480     switch (containingBlockStyle->writingMode()) {
2481     case TopToBottomWritingMode:
2482         shouldFlip = (childWritingMode == RightToLeftWritingMode);
2483         break;
2484     case BottomToTopWritingMode:
2485         shouldFlip = (childWritingMode == RightToLeftWritingMode);
2486         break;
2487     case RightToLeftWritingMode:
2488         shouldFlip = (childWritingMode == BottomToTopWritingMode);
2489         break;
2490     case LeftToRightWritingMode:
2491         shouldFlip = (childWritingMode == BottomToTopWritingMode);
2492         break;
2493     }
2494
2495     if (!containingBlockStyle->isLeftToRightDirection())
2496         shouldFlip = !shouldFlip;
2497
2498     return shouldFlip;
2499 }
2500
2501 void RenderBox::updateLogicalHeight()
2502 {
2503     LogicalExtentComputedValues computedValues;
2504     computeLogicalHeight(logicalHeight(), logicalTop(), computedValues);
2505
2506     setLogicalHeight(computedValues.m_extent);
2507     setLogicalTop(computedValues.m_position);
2508     setMarginBefore(computedValues.m_margins.m_before);
2509     setMarginAfter(computedValues.m_margins.m_after);
2510 }
2511
2512 void RenderBox::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const
2513 {
2514     computedValues.m_extent = logicalHeight;
2515     computedValues.m_position = logicalTop;
2516
2517     // Cell height is managed by the table and inline non-replaced elements do not support a height property.
2518     if (isTableCell() || (isInline() && !isReplaced()))
2519         return;
2520
2521     Length h;
2522     if (isOutOfFlowPositioned())
2523         computePositionedLogicalHeight(computedValues);
2524     else {
2525         RenderBlock* cb = containingBlock();
2526         bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHorizontalWritingMode();
2527     
2528         if (!hasPerpendicularContainingBlock) {
2529             bool shouldFlipBeforeAfter = cb->style()->writingMode() != style()->writingMode();
2530             computeBlockDirectionMargins(cb,
2531                 shouldFlipBeforeAfter ? computedValues.m_margins.m_after : computedValues.m_margins.m_before,
2532                 shouldFlipBeforeAfter ? computedValues.m_margins.m_before : computedValues.m_margins.m_after);
2533         }
2534
2535         // For tables, calculate margins only.
2536         if (isTable()) {
2537             if (hasPerpendicularContainingBlock) {
2538                 bool shouldFlipBeforeAfter = shouldFlipBeforeAfterMargins(cb->style(), style());
2539                 computeInlineDirectionMargins(cb, containingBlockLogicalWidthForContent(), computedValues.m_extent,
2540                     shouldFlipBeforeAfter ? computedValues.m_margins.m_after : computedValues.m_margins.m_before,
2541                     shouldFlipBeforeAfter ? computedValues.m_margins.m_before : computedValues.m_margins.m_after);
2542             }
2543             return;
2544         }
2545
2546         // FIXME: Account for block-flow in flexible boxes.
2547         // https://bugs.webkit.org/show_bug.cgi?id=46418
2548         bool inHorizontalBox = parent()->isDeprecatedFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL;
2549         bool stretching = parent()->style()->boxAlign() == BSTRETCH;
2550         bool treatAsReplaced = shouldComputeSizeAsReplaced() && (!inHorizontalBox || !stretching);
2551         bool checkMinMaxHeight = false;
2552
2553         // The parent box is flexing us, so it has increased or decreased our height.  We have to
2554         // grab our cached flexible height.
2555         // FIXME: Account for block-flow in flexible boxes.
2556         // https://bugs.webkit.org/show_bug.cgi?id=46418
2557         if (hasOverrideHeight() && parent()->isFlexibleBoxIncludingDeprecated())
2558             h = Length(overrideLogicalContentHeight(), Fixed);
2559         else if (treatAsReplaced)
2560             h = Length(computeReplacedLogicalHeight(), Fixed);
2561         else {
2562             h = style()->logicalHeight();
2563             checkMinMaxHeight = true;
2564         }
2565
2566         // Block children of horizontal flexible boxes fill the height of the box.
2567         // FIXME: Account for block-flow in flexible boxes.
2568         // https://bugs.webkit.org/show_bug.cgi?id=46418
2569         if (h.isAuto() && parent()->isDeprecatedFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
2570                 && parent()->isStretchingChildren()) {
2571             h = Length(parentBox()->contentLogicalHeight() - marginBefore() - marginAfter() - borderAndPaddingLogicalHeight(), Fixed);
2572             checkMinMaxHeight = false;
2573         }
2574
2575         LayoutUnit heightResult;
2576         if (checkMinMaxHeight) {
2577             heightResult = computeLogicalHeightUsing(style()->logicalHeight());
2578             if (heightResult == -1)
2579                 heightResult = computedValues.m_extent;
2580             heightResult = constrainLogicalHeightByMinMax(heightResult);
2581         } else {
2582             // The only times we don't check min/max height are when a fixed length has
2583             // been given as an override.  Just use that.  The value has already been adjusted
2584             // for box-sizing.
2585             heightResult = h.value() + borderAndPaddingLogicalHeight();
2586         }
2587
2588         computedValues.m_extent = heightResult;
2589         
2590         if (hasPerpendicularContainingBlock) {
2591             bool shouldFlipBeforeAfter = shouldFlipBeforeAfterMargins(cb->style(), style());
2592             computeInlineDirectionMargins(cb, containingBlockLogicalWidthForContent(), heightResult,
2593                     shouldFlipBeforeAfter ? computedValues.m_margins.m_after : computedValues.m_margins.m_before,
2594                     shouldFlipBeforeAfter ? computedValues.m_margins.m_before : computedValues.m_margins.m_after);
2595         }
2596     }
2597
2598     // WinIE quirk: The <html> block always fills the entire canvas in quirks mode.  The <body> always fills the
2599     // <html> block in quirks mode.  Only apply this quirk if the block is normal flow and no height
2600     // is specified. When we're printing, we also need this quirk if the body or root has a percentage 
2601     // height since we don't set a height in RenderView when we're printing. So without this quirk, the 
2602     // height has nothing to be a percentage of, and it ends up being 0. That is bad.
2603     bool paginatedContentNeedsBaseHeight = document().printing() && h.isPercent()
2604         && (isRoot() || (isBody() && document().documentElement()->renderer()->style()->logicalHeight().isPercent())) && !isInline();
2605     if (stretchesToViewport() || paginatedContentNeedsBaseHeight) {
2606         LayoutUnit margins = collapsedMarginBefore() + collapsedMarginAfter();
2607         LayoutUnit visibleHeight = view().pageOrViewLogicalHeight();
2608         if (isRoot())
2609             computedValues.m_extent = max(computedValues.m_extent, visibleHeight - margins);
2610         else {
2611             LayoutUnit marginsBordersPadding = margins + parentBox()->marginBefore() + parentBox()->marginAfter() + parentBox()->borderAndPaddingLogicalHeight();
2612             computedValues.m_extent = max(computedValues.m_extent, visibleHeight - marginsBordersPadding);
2613         }
2614     }
2615 }
2616
2617 LayoutUnit RenderBox::computeLogicalHeightUsing(const Length& height) const
2618 {
2619     LayoutUnit logicalHeight = computeContentAndScrollbarLogicalHeightUsing(height);
2620     if (logicalHeight != -1)
2621         logicalHeight = adjustBorderBoxLogicalHeightForBoxSizing(logicalHeight);
2622     return logicalHeight;
2623 }
2624
2625 LayoutUnit RenderBox::computeContentLogicalHeight(const Length& height) const
2626 {
2627     LayoutUnit heightIncludingScrollbar = computeContentAndScrollbarLogicalHeightUsing(height);
2628     if (heightIncludingScrollbar == -1)
2629         return -1;
2630     return std::max<LayoutUnit>(0, adjustContentBoxLogicalHeightForBoxSizing(heightIncludingScrollbar) - scrollbarLogicalHeight());
2631 }
2632
2633 LayoutUnit RenderBox::computeContentAndScrollbarLogicalHeightUsing(const Length& height) const
2634 {
2635     if (height.isFixed())
2636         return height.value();
2637     if (height.isPercent())
2638         return computePercentageLogicalHeight(height);
2639     if (height.isViewportPercentage())
2640         return valueForLength(height, 0);
2641     return -1;
2642 }
2643
2644 bool RenderBox::skipContainingBlockForPercentHeightCalculation(const RenderBox* containingBlock) const
2645 {
2646     // For quirks mode and anonymous blocks, we skip auto-height containingBlocks when computing percentages.
2647     // For standards mode, we treat the percentage as auto if it has an auto-height containing block.
2648     if (!document().inQuirksMode() && !containingBlock->isAnonymousBlock())
2649         return false;
2650     return !containingBlock->isTableCell() && !containingBlock->isOutOfFlowPositioned() && containingBlock->style()->logicalHeight().isAuto() && isHorizontalWritingMode() == containingBlock->isHorizontalWritingMode();
2651 }
2652
2653 LayoutUnit RenderBox::computePercentageLogicalHeight(const Length& height) const
2654 {
2655     LayoutUnit availableHeight = -1;
2656     
2657     bool skippedAutoHeightContainingBlock = false;
2658     RenderBlock* cb = containingBlock();
2659     const RenderBox* containingBlockChild = this;
2660     LayoutUnit rootMarginBorderPaddingHeight = 0;
2661     while (!cb->isRenderView() && skipContainingBlockForPercentHeightCalculation(cb)) {
2662         if (cb->isBody() || cb->isRoot())
2663             rootMarginBorderPaddingHeight += cb->marginBefore() + cb->marginAfter() + cb->borderAndPaddingLogicalHeight();
2664         skippedAutoHeightContainingBlock = true;
2665         containingBlockChild = cb;
2666         cb = cb->containingBlock();
2667         cb->addPercentHeightDescendant(const_cast<RenderBox*>(this));
2668     }
2669
2670     RenderStyle* cbstyle = cb->style();
2671
2672     // A positioned element that specified both top/bottom or that specifies height should be treated as though it has a height
2673     // explicitly specified that can be used for any percentage computations.
2674     bool isOutOfFlowPositionedWithSpecifiedHeight = cb->isOutOfFlowPositioned() && (!cbstyle->logicalHeight().isAuto() || (!cbstyle->logicalTop().isAuto() && !cbstyle->logicalBottom().isAuto()));
2675
2676     bool includeBorderPadding = isTable();
2677
2678     if (isHorizontalWritingMode() != cb->isHorizontalWritingMode())
2679         availableHeight = containingBlockChild->containingBlockLogicalWidthForContent();
2680     else if (hasOverrideContainingBlockLogicalHeight())
2681         availableHeight = overrideContainingBlockContentLogicalHeight();
2682     else if (cb->isTableCell()) {
2683         if (!skippedAutoHeightContainingBlock) {
2684             // Table cells violate what the CSS spec says to do with heights. Basically we
2685             // don't care if the cell specified a height or not. We just always make ourselves
2686             // be a percentage of the cell's current content height.
2687             if (!cb->hasOverrideHeight()) {
2688                 // Normally we would let the cell size intrinsically, but scrolling overflow has to be
2689                 // treated differently, since WinIE lets scrolled overflow regions shrink as needed.
2690                 // While we can't get all cases right, we can at least detect when the cell has a specified
2691                 // height or when the table has a specified height. In these cases we want to initially have
2692                 // no size and allow the flexing of the table or the cell to its specified height to cause us
2693                 // to grow to fill the space. This could end up being wrong in some cases, but it is
2694                 // preferable to the alternative (sizing intrinsically and making the row end up too big).
2695                 RenderTableCell* cell = toRenderTableCell(cb);
2696                 if (scrollsOverflowY() && (!cell->style()->logicalHeight().isAuto() || !cell->table()->style()->logicalHeight().isAuto()))
2697                     return 0;
2698                 return -1;
2699             }
2700             availableHeight = cb->overrideLogicalContentHeight();
2701             includeBorderPadding = true;
2702         }
2703     } else if (cbstyle->logicalHeight().isFixed()) {
2704         LayoutUnit contentBoxHeight = cb->adjustContentBoxLogicalHeightForBoxSizing(cbstyle->logicalHeight().value());
2705         availableHeight = max<LayoutUnit>(0, cb->constrainContentBoxLogicalHeightByMinMax(contentBoxHeight - cb->scrollbarLogicalHeight()));
2706     } else if (cbstyle->logicalHeight().isPercent() && !isOutOfFlowPositionedWithSpecifiedHeight) {
2707         // We need to recur and compute the percentage height for our containing block.
2708         LayoutUnit heightWithScrollbar = cb->computePercentageLogicalHeight(cbstyle->logicalHeight());
2709         if (heightWithScrollbar != -1) {
2710             LayoutUnit contentBoxHeightWithScrollbar = cb->adjustContentBoxLogicalHeightForBoxSizing(heightWithScrollbar);
2711             // We need to adjust for min/max height because this method does not
2712             // handle the min/max of the current block, its caller does. So the
2713             // return value from the recursive call will not have been adjusted
2714             // yet.
2715             LayoutUnit contentBoxHeight = cb->constrainContentBoxLogicalHeightByMinMax(contentBoxHeightWithScrollbar - cb->scrollbarLogicalHeight());
2716             availableHeight = max<LayoutUnit>(0, contentBoxHeight);
2717         }
2718     } else if (isOutOfFlowPositionedWithSpecifiedHeight) {
2719         // Don't allow this to affect the block' height() member variable, since this
2720         // can get called while the block is still laying out its kids.
2721         LogicalExtentComputedValues computedValues;
2722         cb->computeLogicalHeight(cb->logicalHeight(), 0, computedValues);
2723         availableHeight = computedValues.m_extent - cb->borderAndPaddingLogicalHeight() - cb->scrollbarLogicalHeight();
2724     } else if (cb->isRenderView())
2725         availableHeight = view().pageOrViewLogicalHeight();
2726
2727     if (availableHeight == -1)
2728         return availableHeight;
2729
2730     availableHeight -= rootMarginBorderPaddingHeight;
2731
2732     LayoutUnit result = valueForLength(height, availableHeight);
2733     if (includeBorderPadding) {
2734         // FIXME: Table cells should default to box-sizing: border-box so we can avoid this hack.
2735         // It is necessary to use the border-box to match WinIE's broken
2736         // box model. This is essential for sizing inside
2737         // table cells using percentage heights.
2738         result -= borderAndPaddingLogicalHeight();
2739         return max<LayoutUnit>(0, result);
2740     }
2741     return result;
2742 }
2743
2744 LayoutUnit RenderBox::computeReplacedLogicalWidth(ShouldComputePreferred shouldComputePreferred) const
2745 {
2746     return computeReplacedLogicalWidthRespectingMinMaxWidth(computeReplacedLogicalWidthUsing(style()->logicalWidth()), shouldComputePreferred);
2747 }
2748
2749 LayoutUnit RenderBox::computeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUnit logicalWidth, ShouldComputePreferred shouldComputePreferred) const
2750 {
2751     LayoutUnit minLogicalWidth = (shouldComputePreferred == ComputePreferred && style()->logicalMinWidth().isPercent()) || style()->logicalMinWidth().isUndefined() ? logicalWidth : computeReplacedLogicalWidthUsing(style()->logicalMinWidth());
2752     LayoutUnit maxLogicalWidth = (shouldComputePreferred == ComputePreferred && style()->logicalMaxWidth().isPercent()) || style()->logicalMaxWidth().isUndefined() ? logicalWidth : computeReplacedLogicalWidthUsing(style()->logicalMaxWidth());
2753     return max(minLogicalWidth, min(logicalWidth, maxLogicalWidth));
2754 }
2755
2756 LayoutUnit RenderBox::computeReplacedLogicalWidthUsing(Length logicalWidth) const
2757 {
2758     switch (logicalWidth.type()) {
2759         case Fixed:
2760             return adjustContentBoxLogicalWidthForBoxSizing(logicalWidth.value());
2761         case MinContent:
2762         case MaxContent: {
2763             // MinContent/MaxContent don't need the availableLogicalWidth argument.
2764             LayoutUnit availableLogicalWidth = 0;
2765             return computeIntrinsicLogicalWidthUsing(logicalWidth, availableLogicalWidth, borderAndPaddingLogicalWidth()) - borderAndPaddingLogicalWidth();
2766         }
2767         case ViewportPercentageWidth:
2768         case ViewportPercentageHeight:
2769         case ViewportPercentageMin:
2770         case ViewportPercentageMax:
2771             return adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, 0));
2772         case FitContent:
2773         case FillAvailable:
2774         case Percent: 
2775         case Calculated: {
2776             // FIXME: containingBlockLogicalWidthForContent() is wrong if the replaced element's block-flow is perpendicular to the
2777             // containing block's block-flow.
2778             // https://bugs.webkit.org/show_bug.cgi?id=46496
2779             const LayoutUnit cw = isOutOfFlowPositioned() ? containingBlockLogicalWidthForPositioned(toRenderBoxModelObject(container())) : containingBlockLogicalWidthForContent();
2780             Length containerLogicalWidth = containingBlock()->style()->logicalWidth();
2781             // FIXME: Handle cases when containing block width is calculated or viewport percent.
2782             // https://bugs.webkit.org/show_bug.cgi?id=91071
2783             if (logicalWidth.isIntrinsic())
2784                 return computeIntrinsicLogicalWidthUsing(logicalWidth, cw, borderAndPaddingLogicalWidth()) - borderAndPaddingLogicalWidth();
2785             if (cw > 0 || (!cw && (containerLogicalWidth.isFixed() || containerLogicalWidth.isPercent())))
2786                 return adjustContentBoxLogicalWidthForBoxSizing(minimumValueForLength(logicalWidth, cw));
2787         }
2788         // fall through
2789         case Intrinsic:
2790         case MinIntrinsic:
2791         case Auto:
2792         case Relative:
2793         case Undefined:
2794             return intrinsicLogicalWidth();
2795     }
2796
2797     ASSERT_NOT_REACHED();
2798     return 0;
2799 }
2800
2801 LayoutUnit RenderBox::computeReplacedLogicalHeight() const
2802 {
2803     return computeReplacedLogicalHeightRespectingMinMaxHeight(computeReplacedLogicalHeightUsing(style()->logicalHeight()));
2804 }
2805
2806 LayoutUnit RenderBox::computeReplacedLogicalHeightRespectingMinMaxHeight(LayoutUnit logicalHeight) const
2807 {
2808     LayoutUnit minLogicalHeight = computeReplacedLogicalHeightUsing(style()->logicalMinHeight());
2809     LayoutUnit maxLogicalHeight = style()->logicalMaxHeight().isUndefined() ? logicalHeight : computeReplacedLogicalHeightUsing(style()->logicalMaxHeight());
2810     return max(minLogicalHeight, min(logicalHeight, maxLogicalHeight));
2811 }
2812
2813 LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(Length logicalHeight) const
2814 {
2815     switch (logicalHeight.type()) {
2816         case Fixed:
2817             return adjustContentBoxLogicalHeightForBoxSizing(logicalHeight.value());
2818         case Percent:
2819         case Calculated:
2820         {
2821             RenderObject* cb = isOutOfFlowPositioned() ? container() : containingBlock();
2822             while (cb->isAnonymous() && !cb->isRenderView()) {
2823                 cb = cb->containingBlock();
2824                 toRenderBlock(cb)->addPercentHeightDescendant(const_cast<RenderBox*>(this));
2825             }
2826
2827             // FIXME: This calculation is not patched for block-flow yet.
2828             // https://bugs.webkit.org/show_bug.cgi?id=46500
2829             if (cb->isOutOfFlowPositioned() && cb->style()->height().isAuto() && !(cb->style()->top().isAuto() || cb->style()->bottom().isAuto())) {
2830                 ASSERT_WITH_SECURITY_IMPLICATION(cb->isRenderBlock());
2831                 RenderBlock* block = toRenderBlock(cb);
2832                 LogicalExtentComputedValues computedValues;
2833                 block->computeLogicalHeight(block->logicalHeight(), 0, computedValues);
2834                 LayoutUnit newContentHeight = computedValues.m_extent - block->borderAndPaddingLogicalHeight() - block->scrollbarLogicalHeight();
2835                 LayoutUnit newHeight = block->adjustContentBoxLogicalHeightForBoxSizing(newContentHeight);
2836                 return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeight, newHeight));
2837             }
2838             
2839             // FIXME: availableLogicalHeight() is wrong if the replaced element's block-flow is perpendicular to the
2840             // containing block's block-flow.
2841             // https://bugs.webkit.org/show_bug.cgi?id=46496
2842             LayoutUnit availableHeight;
2843             if (isOutOfFlowPositioned())
2844                 availableHeight = containingBlockLogicalHeightForPositioned(toRenderBoxModelObject(cb));
2845             else {
2846                 availableHeight = containingBlockLogicalHeightForContent(IncludeMarginBorderPadding);
2847                 // It is necessary to use the border-box to match WinIE's broken
2848                 // box model.  This is essential for sizing inside
2849                 // table cells using percentage heights.
2850                 // FIXME: This needs to be made block-flow-aware.  If the cell and image are perpendicular block-flows, this isn't right.
2851                 // https://bugs.webkit.org/show_bug.cgi?id=46997
2852                 while (cb && !cb->isRenderView() && (cb->style()->logicalHeight().isAuto() || cb->style()->logicalHeight().isPercent())) {
2853                     if (cb->isTableCell()) {
2854                         // Don't let table cells squeeze percent-height replaced elements
2855                         // <http://bugs.webkit.org/show_bug.cgi?id=15359>
2856                         availableHeight = max(availableHeight, intrinsicLogicalHeight());
2857                         return valueForLength(logicalHeight, availableHeight - borderAndPaddingLogicalHeight());
2858                     }
2859                     toRenderBlock(cb)->addPercentHeightDescendant(const_cast<RenderBox*>(this));
2860                     cb = cb->containingBlock();
2861                 }
2862             }
2863             return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeight, availableHeight));
2864         }
2865         case ViewportPercentageWidth:
2866         case ViewportPercentageHeight:
2867         case ViewportPercentageMin:
2868         case ViewportPercentageMax:
2869             return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeight, 0));
2870         default:
2871             return intrinsicLogicalHeight();
2872     }
2873 }
2874
2875 LayoutUnit RenderBox::availableLogicalHeight(AvailableLogicalHeightType heightType) const
2876 {
2877     return constrainLogicalHeightByMinMax(availableLogicalHeightUsing(style()->logicalHeight(), heightType));
2878 }
2879
2880 LayoutUnit RenderBox::availableLogicalHeightUsing(const Length& h, AvailableLogicalHeightType heightType) const
2881 {
2882     // We need to stop here, since we don't want to increase the height of the table
2883     // artificially.  We're going to rely on this cell getting expanded to some new
2884     // height, and then when we lay out again we'll use the calculation below.
2885     if (isTableCell() && (h.isAuto() || h.isPercent())) {
2886         if (hasOverrideHeight())
2887             return overrideLogicalContentHeight();
2888         return logicalHeight() - borderAndPaddingLogicalHeight();
2889     }
2890
2891     if (h.isPercent() && isOutOfFlowPositioned() && !isRenderFlowThread()) {
2892         // FIXME: This is wrong if the containingBlock has a perpendicular writing mode.
2893         LayoutUnit availableHeight = containingBlockLogicalHeightForPositioned(containingBlock());
2894         return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(h, availableHeight));
2895     }
2896
2897     LayoutUnit heightIncludingScrollbar = computeContentAndScrollbarLogicalHeightUsing(h);
2898     if (heightIncludingScrollbar != -1)
2899         return std::max<LayoutUnit>(0, adjustContentBoxLogicalHeightForBoxSizing(heightIncludingScrollbar) - scrollbarLogicalHeight());
2900
2901     // FIXME: Check logicalTop/logicalBottom here to correctly handle vertical writing-mode.
2902     // https://bugs.webkit.org/show_bug.cgi?id=46500
2903     if (isRenderBlock() && isOutOfFlowPositioned() && style()->height().isAuto() && !(style()->top().isAuto() || style()->bottom().isAuto())) {
2904         RenderBlock* block = const_cast<RenderBlock*>(toRenderBlock(this));
2905         LogicalExtentComputedValues computedValues;
2906         block->computeLogicalHeight(block->logicalHeight(), 0, computedValues);
2907         LayoutUnit newContentHeight = computedValues.m_extent - block->borderAndPaddingLogicalHeight() - block->scrollbarLogicalHeight();
2908         return adjustContentBoxLogicalHeightForBoxSizing(newContentHeight);
2909     }
2910
2911     // FIXME: This is wrong if the containingBlock has a perpendicular writing mode.
2912     LayoutUnit availableHeight = containingBlockLogicalHeightForContent(heightType);
2913     if (heightType == ExcludeMarginBorderPadding) {
2914         // FIXME: Margin collapsing hasn't happened yet, so this incorrectly removes collapsed margins.
2915         availableHeight -= marginBefore() + marginAfter() + borderAndPaddingLogicalHeight();
2916     }
2917     return availableHeight;
2918 }
2919
2920 void RenderBox::computeBlockDirectionMargins(const RenderBlock* containingBlock, LayoutUnit& marginBefore, LayoutUnit& marginAfter) const
2921 {
2922     if (isTableCell()) {
2923         // FIXME: Not right if we allow cells to have different directionality than the table.  If we do allow this, though,
2924         // we may just do it with an extra anonymous block inside the cell.
2925         marginBefore = 0;
2926         marginAfter = 0;
2927         return;
2928     }
2929
2930     // Margins are calculated with respect to the logical width of
2931     // the containing block (8.3)
2932     LayoutUnit cw = containingBlockLogicalWidthForContent();
2933     RenderStyle* containingBlockStyle = containingBlock->style();
2934     marginBefore = minimumValueForLength(style()->marginBeforeUsing(containingBlockStyle), cw);
2935     marginAfter = minimumValueForLength(style()->marginAfterUsing(containingBlockStyle), cw);
2936 }
2937
2938 void RenderBox::computeAndSetBlockDirectionMargins(const RenderBlock* containingBlock)
2939 {
2940     LayoutUnit marginBefore;
2941     LayoutUnit marginAfter;
2942     computeBlockDirectionMargins(containingBlock, marginBefore, marginAfter);
2943     containingBlock->setMarginBeforeForChild(this, marginBefore);
2944     containingBlock->setMarginAfterForChild(this, marginAfter);
2945 }
2946
2947 LayoutUnit RenderBox::containingBlockLogicalWidthForPositioned(const RenderBoxModelObject* containingBlock, RenderRegion* region, bool checkForPerpendicularWritingMode) const
2948 {
2949     // Container for position:fixed is the frame.
2950     const FrameView& frameView = view().frameView();
2951     if (fixedElementLaysOutRelativeToFrame(frameView))
2952         return (view().isHorizontalWritingMode() ? frameView.visibleWidth() : frameView.visibleHeight()) / frameView.frame().frameScaleFactor();
2953
2954     if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWritingMode() != isHorizontalWritingMode())
2955         return containingBlockLogicalHeightForPositioned(containingBlock, false);
2956
2957     if (containingBlock->isBox()) {
2958         RenderFlowThread* flowThread = flowThreadContainingBlock();
2959         if (!flowThread)
2960             return toRenderBox(containingBlock)->clientLogicalWidth();
2961
2962         if (containingBlock->isRenderNamedFlowThread() && style()->position() == FixedPosition)
2963             return containingBlock->view().clientLogicalWidth();
2964
2965         const RenderBlock* cb = toRenderBlock(containingBlock);
2966         RenderBoxRegionInfo* boxInfo = 0;
2967         if (!region) {
2968             if (containingBlock->isRenderFlowThread() && !checkForPerpendicularWritingMode)
2969                 return toRenderFlowThread(containingBlock)->contentLogicalWidthOfFirstRegion();
2970             if (isWritingModeRoot()) {
2971                 LayoutUnit cbPageOffset = cb->offsetFromLogicalTopOfFirstPage();
2972                 RenderRegion* cbRegion = cb->regionAtBlockOffset(cbPageOffset);
2973                 if (cbRegion)
2974                     boxInfo = cb->renderBoxRegionInfo(cbRegion);
2975             }
2976         } else if (region && flowThread->isHorizontalWritingMode() == containingBlock->isHorizontalWritingMode()) {
2977             RenderRegion* containingBlockRegion = cb->clampToStartAndEndRegions(region);
2978             boxInfo = cb->renderBoxRegionInfo(containingBlockRegion);
2979         }
2980         return (boxInfo) ? max<LayoutUnit>(0, cb->clientLogicalWidth() - (cb->logicalWidth() - boxInfo->logicalWidth())) : cb->clientLogicalWidth();
2981     }
2982
2983     ASSERT(containingBlock->isRenderInline() && containingBlock->isInFlowPositioned());
2984
2985     const RenderInline* flow = toRenderInline(containingBlock);
2986     InlineFlowBox* first = flow->firstLineBox();
2987     InlineFlowBox* last = flow->lastLineBox();
2988
2989     // If the containing block is empty, return a width of 0.
2990     if (!first || !last)
2991         return 0;
2992
2993     LayoutUnit fromLeft;
2994     LayoutUnit fromRight;
2995     if (containingBlock->style()->isLeftToRightDirection()) {
2996         fromLeft = first->logicalLeft() + first->borderLogicalLeft();
2997         fromRight = last->logicalLeft() + last->logicalWidth() - last->borderLogicalRight();
2998     } else {
2999         fromRight = first->logicalLeft() + first->logicalWidth() - first->borderLogicalRight();
3000         fromLeft = last->logicalLeft() + last->borderLogicalLeft();
3001     }
3002
3003     return max<LayoutUnit>(0, fromRight - fromLeft);
3004 }
3005
3006 LayoutUnit RenderBox::containingBlockLogicalHeightForPositioned(const RenderBoxModelObject* containingBlock, bool checkForPerpendicularWritingMode) const
3007 {
3008     const FrameView& frameView = view().frameView();
3009     if (fixedElementLaysOutRelativeToFrame(frameView))
3010         return (view().isHorizontalWritingMode() ? frameView.visibleHeight() : frameView.visibleWidth()) / frameView.frame().frameScaleFactor();
3011
3012     if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWritingMode() != isHorizontalWritingMode())
3013         return containingBlockLogicalWidthForPositioned(containingBlock, 0, false);
3014
3015     if (containingBlock->isBox()) {
3016         const RenderBlock* cb = toRenderBlock(containingBlock);
3017         LayoutUnit result = cb->clientLogicalHeight();
3018         RenderFlowThread* flowThread = flowThreadContainingBlock();
3019         if (flowThread && containingBlock->isRenderFlowThread() && flowThread->isHorizontalWritingMode() == containingBlock->isHorizontalWritingMode()) {
3020             if (containingBlock->isRenderNamedFlowThread() && style()->position() == FixedPosition)
3021                 return containingBlock->view().clientLogicalHeight();
3022             return toRenderFlowThread(containingBlock)->contentLogicalHeightOfFirstRegion();
3023         }
3024         return result;
3025     }
3026         
3027     ASSERT(containingBlock->isRenderInline() && containingBlock->isInFlowPositioned());
3028
3029     const RenderInline* flow = toRenderInline(containingBlock);
3030     InlineFlowBox* first = flow->firstLineBox();
3031     InlineFlowBox* last = flow->lastLineBox();
3032
3033     // If the containing block is empty, return a height of 0.
3034     if (!first || !last)
3035         return 0;
3036
3037     LayoutUnit heightResult;
3038     LayoutRect boundingBox = flow->linesBoundingBox();
3039     if (containingBlock->isHorizontalWritingMode())
3040         heightResult = boundingBox.height();
3041     else
3042         heightResult = boundingBox.width();
3043     heightResult -= (containingBlock->borderBefore() + containingBlock->borderAfter());
3044     return heightResult;
3045 }
3046
3047 static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRight, const RenderBox* child, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalWidth, RenderRegion* region)
3048 {
3049     if (!logicalLeft.isAuto() || !logicalRight.isAuto())
3050         return;
3051
3052     // FIXME: The static distance computation has not been patched for mixed writing modes yet.
3053     if (child->parent()->style()->direction() == LTR) {
3054         LayoutUnit staticPosition = child->layer()->staticInlinePosition() - containerBlock->borderLogicalLeft();
3055         for (RenderElement* curr = child->parent(); curr && curr != containerBlock; curr = curr->container()) {
3056             if (curr->isBox()) {
3057                 staticPosition += toRenderBox(curr)->logicalLeft();
3058                 if (region && curr->isRenderBlock()) {
3059                     const RenderBlock* cb = toRenderBlock(curr);
3060                     region = cb->clampToStartAndEndRegions(region);
3061                     RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(region);
3062                     if (boxInfo)
3063                         staticPosition += boxInfo->logicalLeft();
3064                 }
3065             }
3066         }
3067         logicalLeft.setValue(Fixed, staticPosition);
3068     } else {
3069         RenderBox* enclosingBox = child->parent()->enclosingBox();
3070         LayoutUnit staticPosition = child->layer()->staticInlinePosition() + containerLogicalWidth + containerBlock->borderLogicalLeft();
3071         for (RenderElement* curr = enclosingBox; curr; curr = curr->container()) {
3072             if (curr->isBox()) {
3073                 if (curr != containerBlock)
3074                     staticPosition -= toRenderBox(curr)->logicalLeft();
3075                 if (curr == enclosingBox)
3076                     staticPosition -= enclosingBox->logicalWidth();
3077                 if (region && curr->isRenderBlock()) {
3078                     const RenderBlock* cb = toRenderBlock(curr);
3079                     region = cb->clampToStartAndEndRegions(region);
3080                     RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(region);
3081                     if (boxInfo) {
3082                         if (curr != containerBlock)
3083                             staticPosition -= cb->logicalWidth() - (boxInfo->logicalLeft() + boxInfo->logicalWidth());
3084                         if (curr == enclosingBox)
3085                             staticPosition += enclosingBox->logicalWidth() - boxInfo->logicalWidth();
3086                     }
3087                 }
3088             }
3089             if (curr == containerBlock)
3090                 break;
3091         }
3092         logicalRight.setValue(Fixed, staticPosition);
3093     }
3094 }
3095
3096 void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& computedValues, RenderRegion* region) const
3097 {
3098     if (isReplaced()) {
3099         // FIXME: Positioned replaced elements inside a flow thread are not working properly
3100         // with variable width regions (see https://bugs.webkit.org/show_bug.cgi?id=69896 ).
3101         computePositionedLogicalWidthReplaced(computedValues);
3102         return;
3103     }
3104
3105     // QUESTIONS
3106     // FIXME 1: Should we still deal with these the cases of 'left' or 'right' having
3107     // the type 'static' in determining whether to calculate the static distance?
3108     // NOTE: 'static' is not a legal value for 'left' or 'right' as of CSS 2.1.
3109
3110     // FIXME 2: Can perhaps optimize out cases when max-width/min-width are greater
3111     // than or less than the computed width().  Be careful of box-sizing and
3112     // percentage issues.
3113
3114     // The following is based off of the W3C Working Draft from April 11, 2006 of
3115     // CSS 2.1: Section 10.3.7 "Absolutely positioned, non-replaced elements"
3116     // <http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width>
3117     // (block-style-comments in this function and in computePositionedLogicalWidthUsing()
3118     // correspond to text from the spec)
3119
3120
3121     // We don't use containingBlock(), since we may be positioned by an enclosing
3122     // relative positioned inline.
3123     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
3124     
3125     const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, region);
3126
3127     // Use the container block's direction except when calculating the static distance
3128     // This conforms with the reference results for abspos-replaced-width-margin-000.htm
3129     // of the CSS 2.1 test suite
3130     TextDirection containerDirection = containerBlock->style()->direction();
3131
3132     bool isHorizontal = isHorizontalWritingMode();
3133     const LayoutUnit bordersPlusPadding = borderAndPaddingLogicalWidth();
3134     const Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->marginTop();
3135     const Length marginLogicalRight = isHorizontal ? style()->marginRight() : style()->marginBottom();
3136
3137     Length logicalLeftLength = style()->logicalLeft();
3138     Length logicalRightLength = style()->logicalRight();
3139
3140     /*---------------------------------------------------------------------------*\
3141      * For the purposes of this section and the next, the term "static position"
3142      * (of an element) refers, roughly, to the position an element would have had
3143      * in the normal flow. More precisely:
3144      *
3145      * * The static position for 'left' is the distance from the left edge of the
3146      *   containing block to the left margin edge of a hypothetical box that would
3147      *   have been the first box of the element if its 'position' property had
3148      *   been 'static' and 'float' had been 'none'. The value is negative if the
3149      *   hypothetical box is to the left of the containing block.
3150      * * The static position for 'right' is the distance from the right edge of the
3151      *   containing block to the right margin edge of the same hypothetical box as
3152      *   above. The value is positive if the hypothetical box is to the left of the
3153      *   containing block's edge.
3154      *
3155      * But rather than actually calculating the dimensions of that hypothetical box,
3156      * user agents are free to make a guess at its probable position.
3157      *
3158      * For the purposes of calculating the static position, the containing block of
3159      * fixed positioned elements is the initial containing block instead of the
3160      * viewport, and all scrollable boxes should be assumed to be scrolled to their
3161      * origin.
3162     \*---------------------------------------------------------------------------*/
3163
3164     // see FIXME 1
3165     // Calculate the static distance if needed.
3166     computeInlineStaticDistance(logicalLeftLength, logicalRightLength, this, containerBlock, containerLogicalWidth, region);
3167     
3168     // Calculate constraint equation values for 'width' case.
3169     computePositionedLogicalWidthUsing(style()->logicalWidth(), containerBlock, containerDirection,
3170                                        containerLogicalWidth, bordersPlusPadding,
3171                                        logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight,
3172                                        computedValues);
3173
3174     // Calculate constraint equation values for 'max-width' case.
3175     if (!style()->logicalMaxWidth().isUndefined()) {
3176         LogicalExtentComputedValues maxValues;
3177
3178         computePositionedLogicalWidthUsing(style()->logicalMaxWidth(), containerBlock, containerDirection,
3179                                            containerLogicalWidth, bordersPlusPadding,
3180                                            logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight,
3181                                            maxValues);
3182
3183         if (computedValues.m_extent > maxValues.m_extent) {
3184             computedValues.m_extent = maxValues.m_extent;
3185             computedValues.m_position = maxValues.m_position;
3186             computedValues.m_margins.m_start = maxValues.m_margins.m_start;
3187             computedValues.m_margins.m_end = maxValues.m_margins.m_end;
3188         }
3189     }
3190
3191     // Calculate constraint equation values for 'min-width' case.
3192     if (!style()->logicalMinWidth().isZero() || style()->logicalMinWidth().isIntrinsic()) {
3193         LogicalExtentComputedValues minValues;
3194
3195         computePositionedLogicalWidthUsing(style()->logicalMinWidth(), containerBlock, containerDirection,
3196                                            containerLogicalWidth, bordersPlusPadding,
3197                                            logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight,
3198                                            minValues);
3199
3200         if (computedValues.m_extent < minValues.m_extent) {
3201             computedValues.m_extent = minValues.m_extent;
3202             computedValues.m_position = minValues.m_position;
3203             computedValues.m_margins.m_start = minValues.m_margins.m_start;
3204             computedValues.m_margins.m_end = minValues.m_margins.m_end;
3205         }
3206     }
3207
3208     computedValues.m_extent += bordersPlusPadding;
3209     
3210     // Adjust logicalLeft if we need to for the flipped version of our writing mode in regions.
3211     // FIXME: Add support for other types of objects as containerBlock, not only RenderBlock.
3212     RenderFlowThread* flowThread = flowThreadContainingBlock();
3213     if (flowThread && !region && isWritingModeRoot() && isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode() && containerBlock->isRenderBlock()) {
3214         ASSERT(containerBlock->canHaveBoxInfoInRegion());
3215         LayoutUnit logicalLeftPos = computedValues.m_position;
3216         const RenderBlock* cb = toRenderBlock(containerBlock);
3217         LayoutUnit cbPageOffset = cb->offsetFromLogicalTopOfFirstPage();
3218         RenderRegion* cbRegion = cb->regionAtBlockOffset(cbPageOffset);
3219         if (cbRegion) {
3220             RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(cbRegion);
3221             if (boxInfo) {
3222                 logicalLeftPos += boxInfo->logicalLeft();
3223                 computedValues.m_position = logicalLeftPos;
3224             }
3225         }
3226     }
3227 }
3228
3229 static void computeLogicalLeftPositionedOffset(LayoutUnit& logicalLeftPos, const RenderBox* child, LayoutUnit logicalWidthValue, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalWidth)
3230 {
3231     // Deal with differing writing modes here.  Our offset needs to be in the containing block's coordinate space. If the containing block is flipped
3232     // 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.
3233     if (containerBlock->isHorizontalWritingMode() != child->isHorizontalWritingMode() && containerBlock->style()->isFlippedBlocksWritingMode()) {
3234         logicalLeftPos = containerLogicalWidth - logicalWidthValue - logicalLeftPos;
3235         logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->borderRight() : containerBlock->borderBottom());
3236     } else
3237         logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->borderLeft() : containerBlock->borderTop());
3238 }
3239
3240 void RenderBox::computePositionedLogicalWidthUsing(Length logicalWidth, const RenderBoxModelObject* containerBlock, TextDirection containerDirection,
3241                                                    LayoutUnit containerLogicalWidth, LayoutUnit bordersPlusPadding,
3242                                                    Length logicalLeft, Length logicalRight, Length marginLogicalLeft, Length marginLogicalRight,
3243                                                    LogicalExtentComputedValues& computedValues) const
3244 {
3245     if (logicalWidth.isIntrinsic())
3246         logicalWidth = Length(computeIntrinsicLogicalWidthUsing(logicalWidth, containerLogicalWidth, bordersPlusPadding) - bordersPlusPadding, Fixed);
3247
3248     // 'left' and 'right' cannot both be 'auto' because one would of been
3249     // converted to the static position already
3250     ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto()));
3251
3252     LayoutUnit logicalLeftValue = 0;
3253
3254     const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, 0, false);
3255
3256     bool logicalWidthIsAuto = logicalWidth.isIntrinsicOrAuto();
3257     bool logicalLeftIsAuto = logicalLeft.isAuto();
3258     bool logicalRightIsAuto = logicalRight.isAuto();
3259     LayoutUnit& marginLogicalLeftValue = style()->isLeftToRightDirection() ? computedValues.m_margins.m_start : computedValues.m_margins.m_end;
3260     LayoutUnit& marginLogicalRightValue = style()->isLeftToRightDirection() ? computedValues.m_margins.m_end : computedValues.m_margins.m_start;
3261
3262     if (!logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) {
3263         /*-----------------------------------------------------------------------*\
3264          * If none of the three is 'auto': If both 'margin-left' and 'margin-
3265          * right' are 'auto', solve the equation under the extra constraint that
3266          * the two margins get equal values, unless this would make them negative,
3267          * in which case when direction of the containing block is 'ltr' ('rtl'),
3268          * set 'margin-left' ('margin-right') to zero and solve for 'margin-right'
3269          * ('margin-left'). If one of 'margin-left' or 'margin-right' is 'auto',
3270          * solve the equation for that value. If the values are over-constrained,
3271          * ignore the value for 'left' (in case the 'direction' property of the
3272          * containing block is 'rtl') or 'right' (in case 'direction' is 'ltr')
3273          * and solve for that value.
3274         \*-----------------------------------------------------------------------*/
3275         // NOTE:  It is not necessary to solve for 'right' in the over constrained
3276         // case because the value is not used for any further calculations.
3277
3278         logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3279         computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, containerLogicalWidth));
3280
3281         const LayoutUnit availableSpace = containerLogicalWidth - (logicalLeftValue + computedValues.m_extent + valueForLength(logicalRight, containerLogicalWidth) + bordersPlusPadding);
3282
3283         // Margins are now the only unknown
3284         if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) {
3285             // Both margins auto, solve for equality
3286             if (availableSpace >= 0) {
3287                 marginLogicalLeftValue = availableSpace / 2; // split the difference
3288                 marginLogicalRightValue = availableSpace - marginLogicalLeftValue; // account for odd valued differences
3289             } else {
3290                 // Use the containing block's direction rather than the parent block's
3291                 // per CSS 2.1 reference test abspos-non-replaced-width-margin-000.
3292                 if (containerDirection == LTR) {
3293                     marginLogicalLeftValue = 0;
3294                     marginLogicalRightValue = availableSpace; // will be negative
3295                 } else {
3296                     marginLogicalLeftValue = availableSpace; // will be negative
3297                     marginLogicalRightValue = 0;
3298                 }
3299             }
3300         } else if (marginLogicalLeft.isAuto()) {
3301             // Solve for left margin
3302             marginLogicalRightValue = valueForLength(marginLogicalRight, containerRelativeLogicalWidth);
3303             marginLogicalLeftValue = availableSpace - marginLogicalRightValue;
3304         } else if (marginLogicalRight.isAuto()) {
3305             // Solve for right margin
3306             marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth);
3307             marginLogicalRightValue = availableSpace - marginLogicalLeftValue;
3308         } else {
3309             // Over-constrained, solve for left if direction is RTL
3310             marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth);
3311             marginLogicalRightValue = valueForLength(marginLogicalRight, containerRelativeLogicalWidth);
3312
3313             // Use the containing block's direction rather than the parent block's
3314             // per CSS 2.1 reference test abspos-non-replaced-width-margin-000.
3315             if (containerDirection == RTL)
3316                 logicalLeftValue = (availableSpace + logicalLeftValue) - marginLogicalLeftValue - marginLogicalRightValue;
3317         }
3318     } else {
3319         /*--------------------------------------------------------------------*\
3320          * Otherwise, set 'auto' values for 'margin-left' and 'margin-right'
3321          * to 0, and pick the one of the following six rules that applies.
3322          *
3323          * 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the
3324          *    width is shrink-to-fit. Then solve for 'left'
3325          *
3326          *              OMIT RULE 2 AS IT SHOULD NEVER BE HIT
3327          * ------------------------------------------------------------------
3328          * 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if
3329          *    the 'direction' property of the containing block is 'ltr' set
3330          *    'left' to the static position, otherwise set 'right' to the
3331          *    static position. Then solve for 'left' (if 'direction is 'rtl')
3332          *    or 'right' (if 'direction' is 'ltr').
3333          * ------------------------------------------------------------------
3334          *
3335          * 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the
3336          *    width is shrink-to-fit . Then solve for 'right'
3337          * 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve
3338          *    for 'left'
3339          * 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve
3340          *    for 'width'
3341          * 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve
3342          *    for 'right'
3343          *
3344          * Calculation of the shrink-to-fit width is similar to calculating the
3345          * width of a table cell using the automatic table layout algorithm.
3346          * Roughly: calculate the preferred width by formatting the content
3347          * without breaking lines other than where explicit line breaks occur,
3348          * and also calculate the preferred minimum width, e.g., by trying all
3349          * possible line breaks. CSS 2.1 does not define the exact algorithm.
3350          * Thirdly, calculate the available width: this is found by solving
3351          * for 'width' after setting 'left' (in case 1) or 'right' (in case 3)
3352          * to 0.
3353          *
3354          * Then the shrink-to-fit width is:
3355          * min(max(preferred minimum width, available width), preferred width).
3356         \*--------------------------------------------------------------------*/
3357         // NOTE: For rules 3 and 6 it is not necessary to solve for 'right'
3358         // because the value is not used for any further calculations.
3359
3360         // Calculate margins, 'auto' margins are ignored.
3361         marginLogicalLeftValue = minimumValueForLength(marginLogicalLeft, containerRelativeLogicalWidth);
3362         marginLogicalRightValue = minimumValueForLength(marginLogicalRight, containerRelativeLogicalWidth);
3363
3364         const LayoutUnit availableSpace = containerLogicalWidth - (marginLogicalLeftValue + marginLogicalRightValue + bordersPlusPadding);
3365
3366         // FIXME: Is there a faster way to find the correct case?
3367         // Use rule/case that applies.
3368         if (logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAuto) {
3369             // RULE 1: (use shrink-to-fit for width, and solve of left)
3370             LayoutUnit logicalRightValue = valueForLength(logicalRight, containerLogicalWidth);
3371
3372             // FIXME: would it be better to have shrink-to-fit in one step?
3373             LayoutUnit preferredWidth = maxPreferredLogicalWidth() - bordersPlusPadding;
3374             LayoutUnit preferredMinWidth = minPreferredLogicalWidth() - bordersPlusPadding;
3375             LayoutUnit availableWidth = availableSpace - logicalRightValue;
3376             computedValues.m_extent = min(max(preferredMinWidth, availableWidth), preferredWidth);
3377             logicalLeftValue = availableSpace - (computedValues.m_extent + logicalRightValue);
3378         } else if (!logicalLeftIsAuto && logicalWidthIsAuto && logicalRightIsAuto) {
3379             // RULE 3: (use shrink-to-fit for width, and no need solve of right)
3380             logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3381
3382             // FIXME: would it be better to have shrink-to-fit in one step?
3383             LayoutUnit preferredWidth = maxPreferredLogicalWidth() - bordersPlusPadding;
3384             LayoutUnit preferredMinWidth = minPreferredLogicalWidth() - bordersPlusPadding;
3385             LayoutUnit availableWidth = availableSpace - logicalLeftValue;
3386             computedValues.m_extent = min(max(preferredMinWidth, availableWidth), preferredWidth);
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             computedValues.m_extent = availableSpace - (logicalLeftValue + valueForLength(logicalRight, containerLogicalWidth));
3395         } else if (!logicalLeftIsAuto && !logicalWidthIsAuto && logicalRightIsAuto) {
3396             // RULE 6: (no need solve for right)
3397             logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3398             computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, containerLogicalWidth));
3399         }
3400     }
3401
3402     // Use computed values to calculate the horizontal position.
3403
3404     // FIXME: This hack is needed to calculate the  logical left position for a 'rtl' relatively
3405     // positioned, inline because right now, it is using the logical left position
3406     // of the first line box when really it should use the last line box.  When
3407     // this is fixed elsewhere, this block should be removed.
3408     if (containerBlock->isRenderInline() && !containerBlock->style()->isLeftToRightDirection()) {
3409         const RenderInline* flow = toRenderInline(containerBlock);
3410         InlineFlowBox* firstLine = flow->firstLineBox();
3411         InlineFlowBox* lastLine = flow->lastLineBox();
3412         if (firstLine && lastLine && firstLine != lastLine) {
3413             computedValues.m_position = logicalLeftValue + marginLogicalLeftValue + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logicalLeft());
3414             return;
3415         }
3416     }
3417
3418     computedValues.m_position = logicalLeftValue + marginLogicalLeftValue;
3419     computeLogicalLeftPositionedOffset(computedValues.m_position, this, computedValues.m_extent, containerBlock, containerLogicalWidth);
3420 }
3421
3422 static void computeBlockStaticDistance(Length& logicalTop, Length& logicalBottom, const RenderBox* child, const RenderBoxModelObject* containerBlock)
3423 {
3424     if (!logicalTop.isAuto() || !logicalBottom.isAuto())
3425         return;
3426     
3427     // FIXME: The static distance computation has not been patched for mixed writing modes.
3428     LayoutUnit staticLogicalTop = child->layer()->staticBlockPosition() - containerBlock->borderBefore();
3429     for (RenderElement* curr = child->parent(); curr && curr != containerBlock; curr = curr->container()) {
3430         if (curr->isBox() && !curr->isTableRow())
3431             staticLogicalTop += toRenderBox(curr)->logicalTop();
3432     }
3433     logicalTop.setValue(Fixed, staticLogicalTop);
3434 }
3435
3436 void RenderBox::computePositionedLogicalHeight(LogicalExtentComputedValues& computedValues) const
3437 {
3438     if (isReplaced()) {
3439         computePositionedLogicalHeightReplaced(computedValues);
3440         return;
3441     }
3442
3443     // The following is based off of the W3C Working Draft from April 11, 2006 of
3444     // CSS 2.1: Section 10.6.4 "Absolutely positioned, non-replaced elements"
3445     // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-non-replaced-height>
3446     // (block-style-comments in this function and in computePositionedLogicalHeightUsing()
3447     // correspond to text from the spec)
3448
3449
3450     // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
3451     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
3452
3453     const LayoutUnit containerLogicalHeight = containingBlockLogicalHeightForPositioned(containerBlock);
3454
3455     RenderStyle* styleToUse = style();
3456     const LayoutUnit bordersPlusPadding = borderAndPaddingLogicalHeight();
3457     const Length marginBefore = styleToUse->marginBefore();
3458     const Length marginAfter = styleToUse->marginAfter();
3459     Length logicalTopLength = styleToUse->logicalTop();
3460     Length logicalBottomLength = styleToUse->logicalBottom();
3461
3462     /*---------------------------------------------------------------------------*\
3463      * For the purposes of this section and the next, the term "static position"
3464      * (of an element) refers, roughly, to the position an element would have had
3465      * in the normal flow. More precisely, the static position for 'top' is the
3466      * distance from the top edge of the containing block to the top margin edge
3467      * of a hypothetical box that would have been the first box of the element if
3468      * its 'position' property had been 'static' and 'float' had been 'none'. The
3469      * value is negative if the hypothetical box is above the containing block.
3470      *
3471      * But rather than actually calculating the dimensions of that hypothetical
3472      * box, user agents are free to make a guess at its probable position.
3473      *
3474      * For the purposes of calculating the static position, the containing block
3475      * of fixed positioned elements is the initial containing block instead of
3476      * the viewport.
3477     \*---------------------------------------------------------------------------*/
3478
3479     // see FIXME 1
3480     // Calculate the static distance if needed.
3481     computeBlockStaticDistance(logicalTopLength, logicalBottomLength, this, containerBlock);
3482
3483     // Calculate constraint equation values for 'height' case.
3484     LayoutUnit logicalHeight = computedValues.m_extent;
3485     computePositionedLogicalHeightUsing(styleToUse->logicalHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight,
3486                                         logicalTopLength, logicalBottomLength, marginBefore, marginAfter,
3487                                         computedValues);
3488
3489     // Avoid doing any work in the common case (where the values of min-height and max-height are their defaults).
3490     // see FIXME 2
3491
3492     // Calculate constraint equation values for 'max-height' case.
3493     if (!styleToUse->logicalMaxHeight().isUndefined()) {
3494         LogicalExtentComputedValues maxValues;
3495
3496         computePositionedLogicalHeightUsing(styleToUse->logicalMaxHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight,
3497                                             logicalTopLength, logicalBottomLength, marginBefore, marginAfter,
3498                                             maxValues);
3499
3500         if (computedValues.m_extent > maxValues.m_extent) {
3501             computedValues.m_extent = maxValues.m_extent;
3502             computedValues.m_position = maxValues.m_position;
3503             computedValues.m_margins.m_before = maxValues.m_margins.m_before;
3504             computedValues.m_margins.m_after = maxValues.m_margins.m_after;
3505         }
3506     }
3507
3508     // Calculate constraint equation values for 'min-height' case.
3509     if (!styleToUse->logicalMinHeight().isZero()) {
3510         LogicalExtentComputedValues minValues;
3511
3512         computePositionedLogicalHeightUsing(styleToUse->logicalMinHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalHeight,
3513                                             logicalTopLength, logicalBottomLength, marginBefore, marginAfter,
3514                                             minValues);
3515
3516         if (computedValues.m_extent < minValues.m_extent) {
3517             computedValues.m_extent = minValues.m_extent;
3518             computedValues.m_position = minValues.m_position;
3519             computedValues.m_margins.m_before = minValues.m_margins.m_before;
3520             computedValues.m_margins.m_after = minValues.m_margins.m_after;
3521         }
3522     }
3523
3524     // Set final height value.
3525     computedValues.m_extent += bordersPlusPadding;
3526     
3527     // Adjust logicalTop if we need to for perpendicular writing modes in regions.
3528     // FIXME: Add support for other types of objects as containerBlock, not only RenderBlock.
3529     RenderFlowThread* flowThread = flowThreadContainingBlock();
3530     if (flowThread && isHorizontalWritingMode() != containerBlock->isHorizontalWritingMode() && containerBlock->isRenderBlock()) {
3531         ASSERT(containerBlock->canHaveBoxInfoInRegion());
3532         LayoutUnit logicalTopPos = computedValues.m_position;
3533         const RenderBlock* cb = toRenderBlock(containerBlock);
3534         LayoutUnit cbPageOffset = cb->offsetFromLogicalTopOfFirstPage() - logicalLeft();
3535         RenderRegion* cbRegion = cb->regionAtBlockOffset(cbPageOffset);
3536         if (cbRegion) {
3537             RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(cbRegion);
3538             if (boxInfo) {
3539                 logicalTopPos += boxInfo->logicalLeft();
3540                 computedValues.m_position = logicalTopPos;
3541             }
3542         }
3543     }
3544 }
3545
3546 static void computeLogicalTopPositionedOffset(LayoutUnit& logicalTopPos, const RenderBox* child, LayoutUnit logicalHeightValue, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalHeight)
3547 {
3548     // Deal with differing writing modes here.  Our offset needs to be in the containing block's coordinate space. If the containing block is flipped
3549     // 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.
3550     if ((child->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() != containerBlock->isHorizontalWritingMode())
3551         || (child->style()->isFlippedBlocksWritingMode() != containerBlock->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode()))
3552         logicalTopPos = containerLogicalHeight - logicalHeightValue - logicalTopPos;
3553
3554     // Our offset is from the logical bottom edge in a flipped environment, e.g., right for vertical-rl and bottom for horizontal-bt.
3555     if (containerBlock->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode()) {
3556         if (child->isHorizontalWritingMode())
3557             logicalTopPos += containerBlock->borderBottom();
3558         else
3559             logicalTopPos += containerBlock->borderRight();
3560     } else {
3561         if (child->isHorizontalWritingMode())
3562             logicalTopPos += containerBlock->borderTop();
3563         else
3564             logicalTopPos += containerBlock->borderLeft();
3565     }
3566 }
3567
3568 void RenderBox::computePositionedLogicalHeightUsing(Length logicalHeightLength, const RenderBoxModelObject* containerBlock,
3569                                                     LayoutUnit containerLogicalHeight, LayoutUnit bordersPlusPadding, LayoutUnit logicalHeight,
3570                                                     Length logicalTop, Length logicalBottom, Length marginBefore, Length marginAfter,
3571                                                     LogicalExtentComputedValues& computedValues) const
3572 {
3573     // 'top' and 'bottom' cannot both be 'auto' because 'top would of been
3574     // converted to the static position in computePositionedLogicalHeight()
3575     ASSERT(!(logicalTop.isAuto() && logicalBottom.isAuto()));
3576
3577     LayoutUnit logicalHeightValue;
3578     LayoutUnit contentLogicalHeight = logicalHeight - bordersPlusPadding;
3579
3580     const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, 0, false);
3581
3582     LayoutUnit logicalTopValue = 0;
3583
3584     bool logicalHeightIsAuto = logicalHeightLength.isAuto();
3585     bool logicalTopIsAuto = logicalTop.isAuto();
3586     bool logicalBottomIsAuto = logicalBottom.isAuto();
3587
3588     // Height is never unsolved for tables.
3589     if (isTable()) {
3590         logicalHeightLength.setValue(Fixed, contentLogicalHeight);
3591         logicalHeightIsAuto = false;
3592     }
3593
3594     if (!logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsAuto) {
3595         /*-----------------------------------------------------------------------*\
3596          * If none of the three are 'auto': If both 'margin-top' and 'margin-
3597          * bottom' are 'auto', solve the equation under the extra constraint that
3598          * the two margins get equal values. If one of 'margin-top' or 'margin-
3599          * bottom' is 'auto', solve the equation for that value. If the values
3600          * are over-constrained, ignore the value for 'bottom' and solve for that
3601          * value.
3602         \*-----------------------------------------------------------------------*/
3603         // NOTE:  It is not necessary to solve for 'bottom' in the over constrained
3604         // case because the value is not used for any further calculations.
3605
3606         logicalHeightValue = adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeightLength, containerLogicalHeight));
3607         logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3608
3609         const LayoutUnit availableSpace = containerLogicalHeight - (logicalTopValue + logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight) + bordersPlusPadding);
3610
3611         // Margins are now the only unknown
3612         if (marginBefore.isAuto() && marginAfter.isAuto()) {
3613             // Both margins auto, solve for equality
3614             // NOTE: This may result in negative values.
3615             computedValues.m_margins.m_before = availableSpace / 2; // split the difference
3616             computedValues.m_margins.m_after = availableSpace - computedValues.m_margins.m_before; // account for odd valued differences
3617         } else if (marginBefore.isAuto()) {
3618             // Solve for top margin
3619             computedValues.m_margins.m_after = valueForLength(marginAfter, containerRelativeLogicalWidth);
3620             computedValues.m_margins.m_before = availableSpace - computedValues.m_margins.m_after;
3621         } else if (marginAfter.isAuto()) {
3622             // Solve for bottom margin
3623             computedValues.m_margins.m_before = valueForLength(marginBefore, containerRelativeLogicalWidth);
3624             computedValues.m_margins.m_after = availableSpace - computedValues.m_margins.m_before;
3625         } else {
3626             // Over-constrained, (no need solve for bottom)
3627             computedValues.m_margins.m_before = valueForLength(marginBefore, containerRelativeLogicalWidth);
3628             computedValues.m_margins.m_after = valueForLength(marginAfter, containerRelativeLogicalWidth);
3629         }
3630     } else {
3631         /*--------------------------------------------------------------------*\
3632          * Otherwise, set 'auto' values for 'margin-top' and 'margin-bottom'
3633          * to 0, and pick the one of the following six rules that applies.
3634          *
3635          * 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then
3636          *    the height is based on the content, and solve for 'top'.
3637          *
3638          *              OMIT RULE 2 AS IT SHOULD NEVER BE HIT
3639          * ------------------------------------------------------------------
3640          * 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then
3641          *    set 'top' to the static position, and solve for 'bottom'.
3642          * ------------------------------------------------------------------
3643          *
3644          * 3. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then
3645          *    the height is based on the content, and solve for 'bottom'.
3646          * 4. 'top' is 'auto', 'height' and 'bottom' are not 'auto', and
3647          *    solve for 'top'.
3648          * 5. 'height' is 'auto', 'top' and 'bottom' are not 'auto', and
3649          *    solve for 'height'.
3650          * 6. 'bottom' is 'auto', 'top' and 'height' are not 'auto', and
3651          *    solve for 'bottom'.
3652         \*--------------------------------------------------------------------*/
3653         // NOTE: For rules 3 and 6 it is not necessary to solve for 'bottom'
3654         // because the value is not used for any further calculations.
3655
3656         // Calculate margins, 'auto' margins are ignored.
3657         computedValues.m_margins.m_before = minimumValueForLength(marginBefore, containerRelativeLogicalWidth);
3658         computedValues.m_margins.m_after = minimumValueForLength(marginAfter, containerRelativeLogicalWidth);
3659
3660         const LayoutUnit availableSpace = containerLogicalHeight - (computedValues.m_margins.m_before + computedValues.m_margins.m_after + bordersPlusPadding);
3661
3662         // Use rule/case that applies.
3663         if (logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) {
3664             // RULE 1: (height is content based, solve of top)
3665             logicalHeightValue = contentLogicalHeight;
3666             logicalTopValue = availableSpace - (logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight));
3667         } else if (!logicalTopIsAuto && logicalHeightIsAuto && logicalBottomIsAuto) {
3668             // RULE 3: (height is content based, no need solve of bottom)
3669             logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3670             logicalHeightValue = contentLogicalHeight;
3671         } else if (logicalTopIsAuto && !logicalHeightIsAuto && !logicalBottomIsAuto) {
3672             // RULE 4: (solve of top)
3673             logicalHeightValue = adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeightLength, containerLogicalHeight));
3674             logicalTopValue = availableSpace - (logicalHeightValue + valueForLength(logicalBottom, containerLogicalHeight));
3675         } else if (!logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) {
3676             // RULE 5: (solve of height)
3677             logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3678             logicalHeightValue = max<LayoutUnit>(0, availableSpace - (logicalTopValue + valueForLength(logicalBottom, containerLogicalHeight)));
3679         } else if (!logicalTopIsAuto && !logicalHeightIsAuto && logicalBottomIsAuto) {
3680             // RULE 6: (no need solve of bottom)
3681             logicalHeightValue = adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeightLength, containerLogicalHeight));
3682             logicalTopValue = valueForLength(logicalTop, containerLogicalHeight);
3683         }
3684     }
3685     computedValues.m_extent = logicalHeightValue;
3686
3687     // Use computed values to calculate the vertical position.
3688     computedValues.m_position = logicalTopValue + computedValues.m_margins.m_before;
3689     computeLogicalTopPositionedOffset(computedValues.m_position, this, logicalHeightValue, containerBlock, containerLogicalHeight);
3690 }
3691
3692 void RenderBox::computePositionedLogicalWidthReplaced(LogicalExtentComputedValues& computedValues) const
3693 {
3694     // The following is based off of the W3C Working Draft from April 11, 2006 of
3695     // CSS 2.1: Section 10.3.8 "Absolutely positioned, replaced elements"
3696     // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-width>
3697     // (block-style-comments in this function correspond to text from the spec and
3698     // the numbers correspond to numbers in spec)
3699
3700     // We don't use containingBlock(), since we may be positioned by an enclosing
3701     // relative positioned inline.
3702     const RenderBoxModelObject* containerBlock = toRenderBoxModelObject(container());
3703
3704     const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock);
3705     const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, 0, false);
3706
3707     // To match WinIE, in quirks mode use the parent's 'direction' property
3708     // instead of the the container block's.
3709     TextDirection containerDirection = containerBlock->style()->direction();
3710
3711     // Variables to solve.
3712     bool isHorizontal = isHorizontalWritingMode();
3713     Length logicalLeft = style()->logicalLeft();
3714     Length logicalRight = style()->logicalRight();
3715     Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->marginTop();
3716     Length marginLogicalRight = isHorizontal ? style()->marginRight() : style()->marginBottom();
3717     LayoutUnit& marginLogicalLeftAlias = style()->isLeftToRightDirection() ? computedValues.m_margins.m_start : computedValues.m_margins.m_end;
3718     LayoutUnit& marginLogicalRightAlias = style()->isLeftToRightDirection() ? computedValues.m_margins.m_end : computedValues.m_margins.m_start;
3719
3720     /*-----------------------------------------------------------------------*\
3721      * 1. The used value of 'width' is determined as for inline replaced
3722      *    elements.
3723     \*-----------------------------------------------------------------------*/
3724     // NOTE: This value of width is FINAL in that the min/max width calculations
3725     // are dealt with in computeReplacedWidth().  This means that the steps to produce
3726     // correct max/min in the non-replaced version, are not necessary.
3727     computedValues.m_extent = computeReplacedLogicalWidth() + borderAndPaddingLogicalWidth();
3728
3729     const LayoutUnit availableSpace = containerLogicalWidth - computedValues.m_extent;
3730
3731     /*-----------------------------------------------------------------------*\
3732      * 2. If both 'left' and 'right' have the value 'auto', then if 'direction'
3733      *    of the containing block is 'ltr', set 'left' to the static position;
3734      *    else if 'direction' is 'rtl', set 'right' to the static position.
3735     \*-----------------------------------------------------------------------*/
3736     // see FIXME 1
3737     computeInlineStaticDistance(logicalLeft, logicalRight, this, containerBlock, containerLogicalWidth, 0); // FIXME: Pass the region.
3738
3739     /*-----------------------------------------------------------------------*\
3740      * 3. If 'left' or 'right' are 'auto', replace any 'auto' on 'margin-left'
3741      *    or 'margin-right' with '0'.
3742     \*-----------------------------------------------------------------------*/
3743     if (logicalLeft.isAuto() || logicalRight.isAuto()) {
3744         if (marginLogicalLeft.isAuto())
3745             marginLogicalLeft.setValue(Fixed, 0);
3746         if (marginLogicalRight.isAuto())
3747             marginLogicalRight.setValue(Fixed, 0);
3748     }
3749
3750     /*-----------------------------------------------------------------------*\
3751      * 4. If at this point both 'margin-left' and 'margin-right' are still
3752      *    'auto', solve the equation under the extra constraint that the two
3753      *    margins must get equal values, unless this would make them negative,
3754      *    in which case when the direction of the containing block is 'ltr'
3755      *    ('rtl'), set 'margin-left' ('margin-right') to zero and solve for
3756      *    'margin-right' ('margin-left').
3757     \*-----------------------------------------------------------------------*/
3758     LayoutUnit logicalLeftValue = 0;
3759     LayoutUnit logicalRightValue = 0;
3760
3761     if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) {
3762         // 'left' and 'right' cannot be 'auto' due to step 3
3763         ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto()));
3764
3765         logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3766         logicalRightValue = valueForLength(logicalRight, containerLogicalWidth);
3767
3768         LayoutUnit difference = availableSpace - (logicalLeftValue + logicalRightValue);
3769         if (difference > 0) {
3770             marginLogicalLeftAlias = difference / 2; // split the difference
3771             marginLogicalRightAlias = difference - marginLogicalLeftAlias; // account for odd valued differences
3772         } else {
3773             // Use the containing block's direction rather than the parent block's
3774             // per CSS 2.1 reference test abspos-replaced-width-margin-000.
3775             if (containerDirection == LTR) {
3776                 marginLogicalLeftAlias = 0;
3777                 marginLogicalRightAlias = difference; // will be negative
3778             } else {
3779                 marginLogicalLeftAlias = difference; // will be negative
3780                 marginLogicalRightAlias = 0;
3781             }
3782         }
3783
3784     /*-----------------------------------------------------------------------*\
3785      * 5. If at this point there is an 'auto' left, solve the equation for
3786      *    that value.
3787     \*-----------------------------------------------------------------------*/
3788     } else if (logicalLeft.isAuto()) {
3789         marginLogicalLeftAlias = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth);
3790         marginLogicalRightAlias =