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