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