2009-01-31 David Hyatt <hyatt@apple.com>
[WebKit-https.git] / 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 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 "ChromeClient.h"
30 #include "Document.h"
31 #include "FrameView.h"
32 #include "GraphicsContext.h"
33 #include "HTMLElement.h"
34 #include "HTMLNames.h"
35 #include "ImageBuffer.h"
36 #include "FloatQuad.h"
37 #include "Frame.h"
38 #include "Page.h"
39 #include "RenderArena.h"
40 #include "RenderFlexibleBox.h"
41 #include "RenderInline.h"
42 #include "RenderLayer.h"
43 #include "RenderTableCell.h"
44 #include "RenderTheme.h"
45 #include "RenderView.h"
46 #include <algorithm>
47 #include <math.h>
48
49 #if ENABLE(WML)
50 #include "WMLNames.h"
51 #endif
52
53 using namespace std;
54
55 namespace WebCore {
56
57 using namespace HTMLNames;
58
59 // Used by flexible boxes when flexing this element.
60 typedef WTF::HashMap<const RenderBox*, int> OverrideSizeMap;
61 static OverrideSizeMap* gOverrideSizeMap = 0;
62
63 bool RenderBox::s_wasFloating = false;
64 bool RenderBox::s_hadOverflowClip = false;
65
66 RenderBox::RenderBox(Node* node)
67     : RenderObject(node)
68     , m_marginLeft(0)
69     , m_marginRight(0)
70     , m_marginTop(0)
71     , m_marginBottom(0)
72     , m_minPrefWidth(-1)
73     , m_maxPrefWidth(-1)
74     , m_layer(0)
75     , m_inlineBoxWrapper(0)
76 {
77     setIsBox();
78 }
79
80 RenderBox::~RenderBox()
81 {
82 }
83
84 void RenderBox::destroy()
85 {
86     // A lot of the code in this function is just pasted into
87     // RenderWidget::destroy. If anything in this function changes,
88     // be sure to fix RenderWidget::destroy() as well.
89     if (hasOverrideSize())
90         gOverrideSizeMap->remove(this);
91
92     // This must be done before we destroy the RenderObject.
93     if (m_layer)
94         m_layer->clearClipRects();
95
96     if (style() && (style()->height().isPercent() || style()->minHeight().isPercent() || style()->maxHeight().isPercent()))
97         RenderBlock::removePercentHeightDescendant(this);
98
99     RenderObject::destroy();
100 }
101
102 void RenderBox::styleWillChange(RenderStyle::Diff diff, const RenderStyle* newStyle)
103 {
104     s_wasFloating = isFloating();
105     s_hadOverflowClip = hasOverflowClip();
106
107     if (style()) {
108         // If our z-index changes value or our visibility changes,
109         // we need to dirty our stacking context's z-order list.
110         if (newStyle) {
111             if (hasLayer() && (style()->hasAutoZIndex() != newStyle->hasAutoZIndex() ||
112                                style()->zIndex() != newStyle->zIndex() ||
113                                style()->visibility() != newStyle->visibility())) {
114                 layer()->dirtyStackingContextZOrderLists();
115                 if (style()->hasAutoZIndex() != newStyle->hasAutoZIndex() || style()->visibility() != newStyle->visibility())
116                     layer()->dirtyZOrderLists();
117             }
118         }
119         
120         // The background of the root element or the body element could propagate up to
121         // the canvas.  Just dirty the entire canvas when our style changes substantially.
122         if (diff >= RenderStyle::Repaint && element() &&
123                 (element()->hasTagName(htmlTag) || element()->hasTagName(bodyTag)))
124             view()->repaint();
125         else if (parent() && !isText()) {
126             // Do a repaint with the old style first, e.g., for example if we go from
127             // having an outline to not having an outline.
128             if (diff == RenderStyle::RepaintLayer) {
129                 layer()->repaintIncludingDescendants();
130                 if (!(style()->clip() == newStyle->clip()))
131                     layer()->clearClipRectsIncludingDescendants();
132             } else if (diff == RenderStyle::Repaint || newStyle->outlineSize() < style()->outlineSize())
133                 repaint();
134         }
135
136         if (diff == RenderStyle::Layout) {
137             // When a layout hint happens, we go ahead and do a repaint of the layer, since the layer could
138             // end up being destroyed.
139             if (hasLayer()) {
140                 if (style()->position() != newStyle->position() ||
141                     style()->zIndex() != newStyle->zIndex() ||
142                     style()->hasAutoZIndex() != newStyle->hasAutoZIndex() ||
143                     !(style()->clip() == newStyle->clip()) ||
144                     style()->hasClip() != newStyle->hasClip() ||
145                     style()->opacity() != newStyle->opacity() ||
146                     style()->transform() != newStyle->transform())
147                 layer()->repaintIncludingDescendants();
148             } else if (newStyle->hasTransform() || newStyle->opacity() < 1) {
149                 // If we don't have a layer yet, but we are going to get one because of transform or opacity,
150                 //  then we need to repaint the old position of the object.
151                 repaint();
152             }
153         
154             // When a layout hint happens and an object's position style changes, we have to do a layout
155             // to dirty the render tree using the old position value now.
156             if (parent() && style()->position() != newStyle->position()) {
157                 markContainingBlocksForLayout();
158                 if (style()->position() == StaticPosition)
159                     repaint();
160                 if (isFloating() && !isPositioned() && (newStyle->position() == AbsolutePosition || newStyle->position() == FixedPosition))
161                     removeFromObjectLists();
162             }
163         }
164     }
165
166     RenderObject::styleWillChange(diff, newStyle);
167 }
168
169 void RenderBox::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
170 {
171     // We need to ensure that view->maximalOutlineSize() is valid for any repaints that happen
172     // during the style change (it's used by clippedOverflowRectForRepaint()).
173     if (style()->outlineWidth() > 0 && style()->outlineSize() > maximalOutlineSize(PaintPhaseOutline))
174         toRenderView(document()->renderer())->setMaximalOutlineSize(style()->outlineSize());
175
176     RenderObject::styleDidChange(diff, oldStyle);
177
178     if (needsLayout() && oldStyle && (oldStyle->height().isPercent() || oldStyle->minHeight().isPercent() || oldStyle->maxHeight().isPercent()))
179         RenderBlock::removePercentHeightDescendant(this);
180
181     bool isRootObject = isRoot();
182     bool isViewObject = isRenderView();
183
184     // The root and the RenderView always paint their backgrounds/borders.
185     if (isRootObject || isViewObject)
186         setHasBoxDecorations(true);
187
188     setInline(style()->isDisplayInlineType());
189
190     switch (style()->position()) {
191         case AbsolutePosition:
192         case FixedPosition:
193             setPositioned(true);
194             break;
195         default:
196             setPositioned(false);
197
198             if (style()->isFloating())
199                 setFloating(true);
200
201             if (style()->position() == RelativePosition)
202                 setRelPositioned(true);
203             break;
204     }
205
206     // We also handle <body> and <html>, whose overflow applies to the viewport.
207     if (style()->overflowX() != OVISIBLE && !isRootObject && (isRenderBlock() || isTableRow() || isTableSection())) {
208         bool boxHasOverflowClip = true;
209         if (isBody()) {
210             // Overflow on the body can propagate to the viewport under the following conditions.
211             // (1) The root element is <html>.
212             // (2) We are the primary <body> (can be checked by looking at document.body).
213             // (3) The root element has visible overflow.
214             if (document()->documentElement()->hasTagName(htmlTag) &&
215                 document()->body() == element() &&
216                 document()->documentElement()->renderer()->style()->overflowX() == OVISIBLE)
217                 boxHasOverflowClip = false;
218         }
219         
220         // Check for overflow clip.
221         // It's sufficient to just check one direction, since it's illegal to have visible on only one overflow value.
222         if (boxHasOverflowClip) {
223             if (!s_hadOverflowClip)
224                 // Erase the overflow
225                 repaint();
226             setHasOverflowClip();
227         }
228     }
229
230     // FIXME: we should make transforms really work on inline flows eventually.
231     if (!isInline() || isReplaced())
232         setHasTransform(style()->hasTransform());
233     setHasReflection(style()->boxReflect());
234
235     if (requiresLayer()) {
236         if (!m_layer) {
237             if (s_wasFloating && isFloating())
238                 setChildNeedsLayout(true);
239             m_layer = new (renderArena()) RenderLayer(this);
240             setHasLayer(true);
241             m_layer->insertOnlyThisLayer();
242             if (parent() && !needsLayout() && containingBlock())
243                 m_layer->updateLayerPositions();
244         }
245     } else if (m_layer && !isRootObject && !isViewObject) {
246         ASSERT(m_layer->parent());
247         RenderLayer* layer = m_layer;
248         m_layer = 0;
249         setHasLayer(false);
250         setHasTransform(false); // Either a transform wasn't specified or the object doesn't support transforms, so just null out the bit.
251         setHasReflection(false);
252         layer->removeOnlyThisLayer();
253         if (s_wasFloating && isFloating())
254             setChildNeedsLayout(true);
255     }
256
257     // If our zoom factor changes and we have a defined scrollLeft/Top, we need to adjust that value into the
258     // new zoomed coordinate space.
259     if (hasOverflowClip() && oldStyle && style() && oldStyle->effectiveZoom() != style()->effectiveZoom()) {
260         int left = scrollLeft();
261         if (left) {
262             left = (left / oldStyle->effectiveZoom()) * style()->effectiveZoom();
263             setScrollLeft(left);
264         }
265         int top = scrollTop();
266         if (top) {
267             top = (top / oldStyle->effectiveZoom()) * style()->effectiveZoom();
268             setScrollTop(top);
269         }
270     }
271
272     if (m_layer)
273         m_layer->styleChanged(diff, oldStyle);
274
275     // Set the text color if we're the body.
276     if (isBody())
277         document()->setTextColor(style()->color());
278 }
279
280 void RenderBox::layout()
281 {
282     ASSERT(needsLayout());
283
284     RenderObject* child = firstChild();
285     if (!child) {
286         setNeedsLayout(false);
287         return;
288     }
289
290     LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()));
291     while (child) {
292         child->layoutIfNeeded();
293         ASSERT(!child->needsLayout());
294         child = child->nextSibling();
295     }
296     statePusher.pop();
297     setNeedsLayout(false);
298 }
299
300 int RenderBox::offsetLeft() const
301 {
302     RenderBox* offsetPar = offsetParent();
303     if (!offsetPar)
304         return 0;
305     int xPos = x() - offsetPar->borderLeft();
306     if (!isPositioned()) {
307         if (isRelPositioned())
308             xPos += relativePositionOffsetX();
309         RenderObject* curr = parent();
310         while (curr && curr != offsetPar) {
311             // FIXME: What are we supposed to do inside SVG content?
312             if (curr->isBox() && !curr->isTableRow())
313                 xPos += toRenderBox(curr)->x();
314             curr = curr->parent();
315         }
316         if (offsetPar->isBody() && !offsetPar->isRelPositioned() && !offsetPar->isPositioned())
317             xPos += offsetPar->x();
318     }
319     return xPos;
320 }
321
322 int RenderBox::offsetTop() const
323 {
324     RenderBox* offsetPar = offsetParent();
325     if (!offsetPar)
326         return 0;
327     int yPos = y() - offsetPar->borderTop();
328     if (!isPositioned()) {
329         if (isRelPositioned())
330             yPos += relativePositionOffsetY();
331         RenderObject* curr = parent();
332         while (curr && curr != offsetPar) {
333             // FIXME: What are we supposed to do inside SVG content?
334             if (curr->isBox() && !curr->isTableRow())
335                 yPos += toRenderBox(curr)->y();
336             curr = curr->parent();
337         }
338         if (offsetPar->isBody() && !offsetPar->isRelPositioned() && !offsetPar->isPositioned())
339             yPos += offsetPar->y();
340     }
341     return yPos;
342 }
343
344 RenderBox* RenderBox::offsetParent() const
345 {
346     // FIXME: It feels like this function could almost be written using containing blocks.
347     if (isBody())
348         return 0;
349
350     bool skipTables = isPositioned() || isRelPositioned();
351     float currZoom = style()->effectiveZoom();
352     RenderObject* curr = parent();
353     while (curr && (!curr->element() ||
354                     (!curr->isPositioned() && !curr->isRelPositioned() && !curr->isBody()))) {
355         Node* element = curr->element();
356         if (!skipTables && element) {
357             bool isTableElement = element->hasTagName(tableTag) ||
358                                   element->hasTagName(tdTag) ||
359                                   element->hasTagName(thTag);
360
361 #if ENABLE(WML)
362             if (!isTableElement && element->isWMLElement())
363                 isTableElement = element->hasTagName(WMLNames::tableTag) ||
364                                  element->hasTagName(WMLNames::tdTag);
365 #endif
366
367             if (isTableElement)
368                 break;
369         }
370
371         float newZoom = curr->style()->effectiveZoom();
372         if (currZoom != newZoom)
373             break;
374         currZoom = newZoom;
375         curr = curr->parent();
376     }
377     return curr && curr->isBox() ? toRenderBox(curr) : 0;
378 }
379
380 // More IE extensions.  clientWidth and clientHeight represent the interior of an object
381 // excluding border and scrollbar.
382 int RenderBox::clientWidth() const
383 {
384     if (isRenderInline())
385         return 0;
386     return width() - borderLeft() - borderRight() - verticalScrollbarWidth();
387 }
388
389 int RenderBox::clientHeight() const
390 {
391     if (isRenderInline())
392         return 0;
393     return height() - borderTop() - borderBottom() - horizontalScrollbarHeight();
394 }
395
396 // scrollWidth/scrollHeight will be the same as clientWidth/clientHeight unless the
397 // object has overflow:hidden/scroll/auto specified and also has overflow.
398 int RenderBox::scrollWidth() const
399 {
400     return hasOverflowClip() ? m_layer->scrollWidth() : overflowWidth();
401 }
402
403 int RenderBox::scrollHeight() const
404 {
405     return hasOverflowClip() ? m_layer->scrollHeight() : overflowHeight();
406 }
407
408 int RenderBox::scrollLeft() const
409 {
410     return hasOverflowClip() ? m_layer->scrollXOffset() : 0;
411 }
412
413 int RenderBox::scrollTop() const
414 {
415     return hasOverflowClip() ? m_layer->scrollYOffset() : 0;
416 }
417
418 void RenderBox::setScrollLeft(int newLeft)
419 {
420     if (hasOverflowClip())
421         m_layer->scrollToXOffset(newLeft);
422 }
423
424 void RenderBox::setScrollTop(int newTop)
425 {
426     if (hasOverflowClip())
427         m_layer->scrollToYOffset(newTop);
428 }
429
430 int RenderBox::paddingTop(bool) const
431 {
432     int w = 0;
433     Length padding = style()->paddingTop();
434     if (padding.isPercent())
435         w = containingBlock()->availableWidth();
436     return padding.calcMinValue(w);
437 }
438
439 int RenderBox::paddingBottom(bool) const
440 {
441     int w = 0;
442     Length padding = style()->paddingBottom();
443     if (padding.isPercent())
444         w = containingBlock()->availableWidth();
445     return padding.calcMinValue(w);
446 }
447
448 int RenderBox::paddingLeft(bool) const
449 {
450     int w = 0;
451     Length padding = style()->paddingLeft();
452     if (padding.isPercent())
453         w = containingBlock()->availableWidth();
454     return padding.calcMinValue(w);
455 }
456
457 int RenderBox::paddingRight(bool) const
458 {
459     int w = 0;
460     Length padding = style()->paddingRight();
461     if (padding.isPercent())
462         w = containingBlock()->availableWidth();
463     return padding.calcMinValue(w);
464 }
465
466 void RenderBox::absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool)
467 {
468     rects.append(IntRect(tx, ty, width(), height()));
469 }
470
471 void RenderBox::absoluteQuads(Vector<FloatQuad>& quads, bool)
472 {
473     quads.append(localToAbsoluteQuad(FloatRect(0, 0, width(), height())));
474 }
475
476 IntRect RenderBox::absoluteContentBox() const
477 {
478     IntRect rect = contentBoxRect();
479     FloatPoint absPos = localToAbsolute(FloatPoint());
480     rect.move(absPos.x(), absPos.y());
481     return rect;
482 }
483
484 FloatQuad RenderBox::absoluteContentQuad() const
485 {
486     IntRect rect = contentBoxRect();
487     return localToAbsoluteQuad(FloatRect(rect));
488 }
489
490
491 IntRect RenderBox::outlineBoundsForRepaint(RenderBox* /*repaintContainer*/) const
492 {
493     IntRect box = borderBoundingBox();
494     adjustRectForOutlineAndShadow(box);
495
496     FloatQuad absOutlineQuad = localToAbsoluteQuad(FloatRect(box));
497     box = absOutlineQuad.enclosingBoundingBox();
498
499     // FIXME: layoutDelta needs to be applied in parts before/after transforms and
500     // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
501     box.move(view()->layoutDelta());
502
503     return box;
504 }
505
506 void RenderBox::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty)
507 {
508     graphicsContext->addFocusRingRect(IntRect(tx, ty, width(), height()));
509 }
510
511
512 IntRect RenderBox::reflectionBox() const
513 {
514     IntRect result;
515     if (!style()->boxReflect())
516         return result;
517     IntRect box = borderBoxRect();
518     result = box;
519     switch (style()->boxReflect()->direction()) {
520         case ReflectionBelow:
521             result.move(0, box.height() + reflectionOffset());
522             break;
523         case ReflectionAbove:
524             result.move(0, -box.height() - reflectionOffset());
525             break;
526         case ReflectionLeft:
527             result.move(-box.width() - reflectionOffset(), 0);
528             break;
529         case ReflectionRight:
530             result.move(box.width() + reflectionOffset(), 0);
531             break;
532     }
533     return result;
534 }
535
536 int RenderBox::reflectionOffset() const
537 {
538     if (!style()->boxReflect())
539         return 0;
540     if (style()->boxReflect()->direction() == ReflectionLeft || style()->boxReflect()->direction() == ReflectionRight)
541         return style()->boxReflect()->offset().calcValue(borderBoxRect().width());
542     return style()->boxReflect()->offset().calcValue(borderBoxRect().height());
543 }
544
545 IntRect RenderBox::reflectedRect(const IntRect& r) const
546 {
547     if (!style()->boxReflect())
548         return IntRect();
549
550     IntRect box = borderBoxRect();
551     IntRect result = r;
552     switch (style()->boxReflect()->direction()) {
553         case ReflectionBelow:
554             result.setY(box.bottom() + reflectionOffset() + (box.bottom() - r.bottom()));
555             break;
556         case ReflectionAbove:
557             result.setY(box.y() - reflectionOffset() - box.height() + (box.bottom() - r.bottom()));
558             break;
559         case ReflectionLeft:
560             result.setX(box.x() - reflectionOffset() - box.width() + (box.right() - r.right()));
561             break;
562         case ReflectionRight:
563             result.setX(box.right() + reflectionOffset() + (box.right() - r.right()));
564             break;
565     }
566     return result;
567 }
568
569 int RenderBox::verticalScrollbarWidth() const
570 {
571     return includeVerticalScrollbarSize() ? layer()->verticalScrollbarWidth() : 0;
572 }
573
574 int RenderBox::horizontalScrollbarHeight() const
575 {
576     return includeHorizontalScrollbarSize() ? layer()->horizontalScrollbarHeight() : 0;
577 }
578
579 bool RenderBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
580 {
581     RenderLayer* l = layer();
582     if (l && l->scroll(direction, granularity, multiplier))
583         return true;
584     RenderBlock* b = containingBlock();
585     if (b && !b->isRenderView())
586         return b->scroll(direction, granularity, multiplier);
587     return false;
588 }
589     
590 bool RenderBox::canBeProgramaticallyScrolled(bool) const
591 {
592     return (hasOverflowClip() && (scrollsOverflow() || (node() && node()->isContentEditable()))) || (node() && node()->isDocumentNode());
593 }
594
595 void RenderBox::autoscroll()
596 {
597     if (layer())
598         layer()->autoscroll();
599 }
600
601 void RenderBox::panScroll(const IntPoint& source)
602 {
603     if (layer())
604         layer()->panScrollFromPoint(source);
605 }
606
607 int RenderBox::minPrefWidth() const
608 {
609     if (prefWidthsDirty())
610         const_cast<RenderBox*>(this)->calcPrefWidths();
611         
612     return m_minPrefWidth;
613 }
614
615 int RenderBox::maxPrefWidth() const
616 {
617     if (prefWidthsDirty())
618         const_cast<RenderBox*>(this)->calcPrefWidths();
619         
620     return m_maxPrefWidth;
621 }
622
623 int RenderBox::overrideSize() const
624 {
625     if (!hasOverrideSize())
626         return -1;
627     return gOverrideSizeMap->get(this);
628 }
629
630 void RenderBox::setOverrideSize(int s)
631 {
632     if (s == -1) {
633         if (hasOverrideSize()) {
634             setHasOverrideSize(false);
635             gOverrideSizeMap->remove(this);
636         }
637     } else {
638         if (!gOverrideSizeMap)
639             gOverrideSizeMap = new OverrideSizeMap();
640         setHasOverrideSize(true);
641         gOverrideSizeMap->set(this, s);
642     }
643 }
644
645 int RenderBox::overrideWidth() const
646 {
647     return hasOverrideSize() ? overrideSize() : width();
648 }
649
650 int RenderBox::overrideHeight() const
651 {
652     return hasOverrideSize() ? overrideSize() : height();
653 }
654
655 int RenderBox::calcBorderBoxWidth(int width) const
656 {
657     int bordersPlusPadding = borderLeft() + borderRight() + paddingLeft() + paddingRight();
658     if (style()->boxSizing() == CONTENT_BOX)
659         return width + bordersPlusPadding;
660     return max(width, bordersPlusPadding);
661 }
662
663 int RenderBox::calcBorderBoxHeight(int height) const
664 {
665     int bordersPlusPadding = borderTop() + borderBottom() + paddingTop() + paddingBottom();
666     if (style()->boxSizing() == CONTENT_BOX)
667         return height + bordersPlusPadding;
668     return max(height, bordersPlusPadding);
669 }
670
671 int RenderBox::calcContentBoxWidth(int width) const
672 {
673     if (style()->boxSizing() == BORDER_BOX)
674         width -= (borderLeft() + borderRight() + paddingLeft() + paddingRight());
675     return max(0, width);
676 }
677
678 int RenderBox::calcContentBoxHeight(int height) const
679 {
680     if (style()->boxSizing() == BORDER_BOX)
681         height -= (borderTop() + borderBottom() + paddingTop() + paddingBottom());
682     return max(0, height);
683 }
684
685 // Hit Testing
686 bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int xPos, int yPos, int tx, int ty, HitTestAction action)
687 {
688     tx += x();
689     ty += y();
690
691     // Check kids first.
692     for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
693         // FIXME: We have to skip over inline flows, since they can show up inside table rows
694         // at the moment (a demoted inline <form> for example). If we ever implement a
695         // table-specific hit-test method (which we should do for performance reasons anyway),
696         // then we can remove this check.
697         if (!child->hasLayer() && !child->isRenderInline() && child->nodeAtPoint(request, result, xPos, yPos, tx, ty, action)) {
698             updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty));
699             return true;
700         }
701     }
702
703     // Check our bounds next. For this purpose always assume that we can only be hit in the
704     // foreground phase (which is true for replaced elements like images).
705     if (visibleToHitTesting() && action == HitTestForeground && IntRect(tx, ty, width(), height()).contains(xPos, yPos)) {
706         updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty));
707         return true;
708     }
709
710     return false;
711 }
712
713 // --------------------- painting stuff -------------------------------
714
715 void RenderBox::paint(PaintInfo& paintInfo, int tx, int ty)
716 {
717     tx += x();
718     ty += y();
719
720     // default implementation. Just pass paint through to the children
721     PaintInfo childInfo(paintInfo);
722     childInfo.paintingRoot = paintingRootForChildren(paintInfo);
723     for (RenderObject* child = firstChild(); child; child = child->nextSibling())
724         child->paint(childInfo, tx, ty);
725 }
726
727 void RenderBox::paintRootBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
728 {
729     const FillLayer* bgLayer = style()->backgroundLayers();
730     Color bgColor = style()->backgroundColor();
731     if (!style()->hasBackground() && element() && element()->hasTagName(HTMLNames::htmlTag)) {
732         // Locate the <body> element using the DOM.  This is easier than trying
733         // to crawl around a render tree with potential :before/:after content and
734         // anonymous blocks created by inline <body> tags etc.  We can locate the <body>
735         // render object very easily via the DOM.
736         HTMLElement* body = document()->body();
737         RenderObject* bodyObject = (body && body->hasLocalName(bodyTag)) ? body->renderer() : 0;
738         if (bodyObject) {
739             bgLayer = bodyObject->style()->backgroundLayers();
740             bgColor = bodyObject->style()->backgroundColor();
741         }
742     }
743
744     int w = width();
745     int h = height();
746
747     int rw;
748     int rh;
749     if (view()->frameView()) {
750         rw = view()->frameView()->contentsWidth();
751         rh = view()->frameView()->contentsHeight();
752     } else {
753         rw = view()->width();
754         rh = view()->height();
755     }
756
757     // CSS2 14.2:
758     // The background of the box generated by the root element covers the entire canvas including
759     // its margins.
760     int bx = tx - marginLeft();
761     int by = ty - marginTop();
762     int bw = max(w + marginLeft() + marginRight() + borderLeft() + borderRight(), rw);
763     int bh = max(h + marginTop() + marginBottom() + borderTop() + borderBottom(), rh);
764
765     int my = max(by, paintInfo.rect.y());
766
767     paintFillLayers(paintInfo, bgColor, bgLayer, my, paintInfo.rect.height(), bx, by, bw, bh);
768
769     if (style()->hasBorder() && style()->display() != INLINE)
770         paintBorder(paintInfo.context, tx, ty, w, h, style());
771 }
772
773 void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
774 {
775     if (!shouldPaintWithinRoot(paintInfo))
776         return;
777
778     if (isRoot()) {
779         paintRootBoxDecorations(paintInfo, tx, ty);
780         return;
781     }
782
783     int w = width();
784     int h = height();
785
786     // border-fit can adjust where we paint our border and background.  If set, we snugly fit our line box descendants.  (The iChat
787     // balloon layout is an example of this).
788     borderFitAdjust(tx, w);
789
790     int my = max(ty, paintInfo.rect.y());
791     int mh;
792     if (ty < paintInfo.rect.y())
793         mh = max(0, h - (paintInfo.rect.y() - ty));
794     else
795         mh = min(paintInfo.rect.height(), h);
796
797     // FIXME: Should eventually give the theme control over whether the box shadow should paint, since controls could have
798     // custom shadows of their own.
799     paintBoxShadow(paintInfo.context, tx, ty, w, h, style());
800
801     // If we have a native theme appearance, paint that before painting our background.
802     // The theme will tell us whether or not we should also paint the CSS background.
803     bool themePainted = style()->hasAppearance() && !theme()->paint(this, paintInfo, IntRect(tx, ty, w, h));
804     if (!themePainted) {
805         // The <body> only paints its background if the root element has defined a background
806         // independent of the body.  Go through the DOM to get to the root element's render object,
807         // since the root could be inline and wrapped in an anonymous block.
808         if (!isBody() || document()->documentElement()->renderer()->style()->hasBackground())
809             paintFillLayers(paintInfo, style()->backgroundColor(), style()->backgroundLayers(), my, mh, tx, ty, w, h);
810         if (style()->hasAppearance())
811             theme()->paintDecorations(this, paintInfo, IntRect(tx, ty, w, h));
812     }
813
814     // The theme will tell us whether or not we should also paint the CSS border.
815     if ((!style()->hasAppearance() || (!themePainted && theme()->paintBorderOnly(this, paintInfo, IntRect(tx, ty, w, h)))) && style()->hasBorder())
816         paintBorder(paintInfo.context, tx, ty, w, h, style());
817 }
818
819 void RenderBox::paintMask(PaintInfo& paintInfo, int tx, int ty)
820 {
821     if (!shouldPaintWithinRoot(paintInfo) || style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
822         return;
823
824     int w = width();
825     int h = height();
826
827     // border-fit can adjust where we paint our border and background.  If set, we snugly fit our line box descendants.  (The iChat
828     // balloon layout is an example of this).
829     borderFitAdjust(tx, w);
830
831     int my = max(ty, paintInfo.rect.y());
832     int mh;
833     if (ty < paintInfo.rect.y())
834         mh = max(0, h - (paintInfo.rect.y() - ty));
835     else
836         mh = min(paintInfo.rect.height(), h);
837
838     paintMaskImages(paintInfo, my, mh, tx, ty, w, h);
839 }
840
841 void RenderBox::paintMaskImages(const PaintInfo& paintInfo, int my, int mh, int tx, int ty, int w, int h)
842 {
843     // Figure out if we need to push a transparency layer to render our mask.
844     bool pushTransparencyLayer = false;
845     StyleImage* maskBoxImage = style()->maskBoxImage().image();
846     if ((maskBoxImage && style()->maskLayers()->hasImage()) || style()->maskLayers()->next())
847         // We have to use an extra image buffer to hold the mask. Multiple mask images need
848         // to composite together using source-over so that they can then combine into a single unified mask that
849         // can be composited with the content using destination-in.  SVG images need to be able to set compositing modes
850         // as they draw images contained inside their sub-document, so we paint all our images into a separate buffer
851         // and composite that buffer as the mask.
852         pushTransparencyLayer = true;
853     
854     CompositeOperator compositeOp = CompositeDestinationIn;
855     if (pushTransparencyLayer) {
856         paintInfo.context->setCompositeOperation(CompositeDestinationIn);
857         paintInfo.context->beginTransparencyLayer(1.0f);
858         compositeOp = CompositeSourceOver;
859     }
860
861     paintFillLayers(paintInfo, Color(), style()->maskLayers(), my, mh, tx, ty, w, h, compositeOp);
862     paintNinePieceImage(paintInfo.context, tx, ty, w, h, style(), style()->maskBoxImage(), compositeOp);
863     
864     if (pushTransparencyLayer)
865         paintInfo.context->endTransparencyLayer();
866 }
867
868 IntRect RenderBox::maskClipRect()
869 {
870     IntRect bbox = borderBoxRect();
871     if (style()->maskBoxImage().image())
872         return bbox;
873     
874     IntRect result;
875     for (const FillLayer* maskLayer = style()->maskLayers(); maskLayer; maskLayer = maskLayer->next()) {
876         if (maskLayer->image()) {
877             IntRect maskRect;
878             IntPoint phase;
879             IntSize tileSize;
880             calculateBackgroundImageGeometry(maskLayer, bbox.x(), bbox.y(), bbox.width(), bbox.height(), maskRect, phase, tileSize);
881             result.unite(maskRect);
882         }
883     }
884     return result;
885 }
886
887 void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer,
888                                 int clipY, int clipH, int tx, int ty, int width, int height, CompositeOperator op)
889 {
890     if (!fillLayer)
891         return;
892
893     paintFillLayers(paintInfo, c, fillLayer->next(), clipY, clipH, tx, ty, width, height, op);
894     paintFillLayer(paintInfo, c, fillLayer, clipY, clipH, tx, ty, width, height, op);
895 }
896
897 void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer,
898                                int clipY, int clipH, int tx, int ty, int width, int height, CompositeOperator op)
899 {
900     paintFillLayerExtended(paintInfo, c, fillLayer, clipY, clipH, tx, ty, width, height, 0, op);
901 }
902
903 IntSize RenderBox::calculateBackgroundSize(const FillLayer* bgLayer, int scaledWidth, int scaledHeight) const
904 {
905     StyleImage* bg = bgLayer->image();
906     bg->setImageContainerSize(IntSize(scaledWidth, scaledHeight)); // Use the box established by background-origin.
907
908     if (bgLayer->isSizeSet()) {
909         int w = scaledWidth;
910         int h = scaledHeight;
911         Length bgWidth = bgLayer->size().width();
912         Length bgHeight = bgLayer->size().height();
913
914         if (bgWidth.isFixed())
915             w = bgWidth.value();
916         else if (bgWidth.isPercent())
917             w = bgWidth.calcValue(scaledWidth);
918         
919         if (bgHeight.isFixed())
920             h = bgHeight.value();
921         else if (bgHeight.isPercent())
922             h = bgHeight.calcValue(scaledHeight);
923         
924         // If one of the values is auto we have to use the appropriate
925         // scale to maintain our aspect ratio.
926         if (bgWidth.isAuto() && !bgHeight.isAuto())
927             w = bg->imageSize(this, style()->effectiveZoom()).width() * h / bg->imageSize(this, style()->effectiveZoom()).height();        
928         else if (!bgWidth.isAuto() && bgHeight.isAuto())
929             h = bg->imageSize(this, style()->effectiveZoom()).height() * w / bg->imageSize(this, style()->effectiveZoom()).width();
930         else if (bgWidth.isAuto() && bgHeight.isAuto()) {
931             // If both width and height are auto, we just want to use the image's
932             // intrinsic size.
933             w = bg->imageSize(this, style()->effectiveZoom()).width();
934             h = bg->imageSize(this, style()->effectiveZoom()).height();
935         }
936         
937         return IntSize(max(1, w), max(1, h));
938     } else
939         return bg->imageSize(this, style()->effectiveZoom());
940 }
941
942 void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*)
943 {
944     if (!parent())
945         return;
946
947     if (isRenderInline() || style()->borderImage().image() && style()->borderImage().image()->data() == image ||
948         style()->maskBoxImage().image() && style()->maskBoxImage().image()->data() == image) {
949         repaint();
950         return;
951     }
952
953     bool didFullRepaint = repaintLayerRectsForImage(image, style()->backgroundLayers(), true);
954     if (!didFullRepaint) {
955         repaintLayerRectsForImage(image, style()->maskLayers(), false);
956     }
957 }
958
959 bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer* layers, bool drawingBackground)
960 {
961     IntRect rendererRect;
962     RenderBox* layerRenderer = 0;
963
964     for (const FillLayer* curLayer = layers; curLayer; curLayer = curLayer->next()) {
965         if (curLayer->image() && image == curLayer->image()->data() && curLayer->image()->canRender(style()->effectiveZoom())) {
966             // Now that we know this image is being used, compute the renderer and the rect
967             // if we haven't already
968             if (!layerRenderer) {
969                 bool drawingRootBackground = drawingBackground && (isRoot() || (isBody() && !document()->documentElement()->renderer()->style()->hasBackground()));
970                 if (drawingRootBackground) {
971                     layerRenderer = view();
972
973                     int rw;
974                     int rh;
975
976                     if (FrameView* frameView = toRenderView(layerRenderer)->frameView()) {
977                         rw = frameView->contentsWidth();
978                         rh = frameView->contentsHeight();
979                     } else {
980                         rw = layerRenderer->width();
981                         rh = layerRenderer->height();
982                     }
983                     rendererRect = IntRect(-layerRenderer->marginLeft(),
984                         -layerRenderer->marginTop(),
985                         max(layerRenderer->width() + layerRenderer->marginLeft() + layerRenderer->marginRight() + layerRenderer->borderLeft() + layerRenderer->borderRight(), rw),
986                         max(layerRenderer->height() + layerRenderer->marginTop() + layerRenderer->marginBottom() + layerRenderer->borderTop() + layerRenderer->borderBottom(), rh));
987                 } else {
988                     layerRenderer = this;
989                     rendererRect = borderBoxRect();
990                 }
991             }
992
993             IntRect repaintRect;
994             IntPoint phase;
995             IntSize tileSize;
996             layerRenderer->calculateBackgroundImageGeometry(curLayer, rendererRect.x(), rendererRect.y(), rendererRect.width(), rendererRect.height(), repaintRect, phase, tileSize);
997             layerRenderer->repaintRectangle(repaintRect);
998             if (repaintRect == rendererRect)
999                 return true;
1000         }
1001     }
1002     return false;
1003 }
1004
1005 void RenderBox::calculateBackgroundImageGeometry(const FillLayer* bgLayer, int tx, int ty, int w, int h, IntRect& destRect, IntPoint& phase, IntSize& tileSize)
1006 {
1007     int pw;
1008     int ph;
1009     int left = 0;
1010     int right = 0;
1011     int top = 0;
1012     int bottom = 0;
1013     int cx;
1014     int cy;
1015     int rw = 0;
1016     int rh = 0;
1017
1018     // CSS2 chapter 14.2.1
1019
1020     if (bgLayer->attachment()) {
1021         // Scroll
1022         if (bgLayer->origin() != BorderFillBox) {
1023             left = borderLeft();
1024             right = borderRight();
1025             top = borderTop();
1026             bottom = borderBottom();
1027             if (bgLayer->origin() == ContentFillBox) {
1028                 left += paddingLeft();
1029                 right += paddingRight();
1030                 top += paddingTop();
1031                 bottom += paddingBottom();
1032             }
1033         }
1034         
1035         // The background of the box generated by the root element covers the entire canvas including
1036         // its margins.  Since those were added in already, we have to factor them out when computing the
1037         // box used by background-origin/size/position.
1038         if (isRoot()) {
1039             rw = width() - left - right;
1040             rh = height() - top - bottom; 
1041             left += marginLeft();
1042             right += marginRight();
1043             top += marginTop();
1044             bottom += marginBottom();
1045         }
1046         cx = tx;
1047         cy = ty;
1048         pw = w - left - right;
1049         ph = h - top - bottom;
1050     } else {
1051         // Fixed
1052         IntRect vr = viewRect();
1053         cx = vr.x();
1054         cy = vr.y();
1055         pw = vr.width();
1056         ph = vr.height();
1057     }
1058
1059     int sx = 0;
1060     int sy = 0;
1061     int cw;
1062     int ch;
1063
1064     IntSize scaledImageSize;
1065     if (isRoot() && bgLayer->attachment())
1066         scaledImageSize = calculateBackgroundSize(bgLayer, rw, rh);
1067     else
1068         scaledImageSize = calculateBackgroundSize(bgLayer, pw, ph);
1069         
1070     int scaledImageWidth = scaledImageSize.width();
1071     int scaledImageHeight = scaledImageSize.height();
1072
1073     EFillRepeat backgroundRepeat = bgLayer->repeat();
1074     
1075     int xPosition;
1076     if (isRoot() && bgLayer->attachment())
1077         xPosition = bgLayer->xPosition().calcMinValue(rw - scaledImageWidth, true);
1078     else
1079         xPosition = bgLayer->xPosition().calcMinValue(pw - scaledImageWidth, true);
1080     if (backgroundRepeat == RepeatFill || backgroundRepeat == RepeatXFill) {
1081         cw = pw + left + right;
1082         sx = scaledImageWidth ? scaledImageWidth - (xPosition + left) % scaledImageWidth : 0;
1083     } else {
1084         cx += max(xPosition + left, 0);
1085         sx = -min(xPosition + left, 0);
1086         cw = scaledImageWidth + min(xPosition + left, 0);
1087     }
1088     
1089     int yPosition;
1090     if (isRoot() && bgLayer->attachment())
1091         yPosition = bgLayer->yPosition().calcMinValue(rh - scaledImageHeight, true);
1092     else 
1093         yPosition = bgLayer->yPosition().calcMinValue(ph - scaledImageHeight, true);
1094     if (backgroundRepeat == RepeatFill || backgroundRepeat == RepeatYFill) {
1095         ch = ph + top + bottom;
1096         sy = scaledImageHeight ? scaledImageHeight - (yPosition + top) % scaledImageHeight : 0;
1097     } else {
1098         cy += max(yPosition + top, 0);
1099         sy = -min(yPosition + top, 0);
1100         ch = scaledImageHeight + min(yPosition + top, 0);
1101     }
1102
1103     if (!bgLayer->attachment()) {
1104         sx += max(tx - cx, 0);
1105         sy += max(ty - cy, 0);
1106     }
1107
1108     destRect = IntRect(cx, cy, cw, ch);
1109     destRect.intersect(IntRect(tx, ty, w, h));
1110     phase = IntPoint(sx, sy);
1111     tileSize = IntSize(scaledImageWidth, scaledImageHeight);
1112 }
1113
1114 void RenderBox::paintFillLayerExtended(const PaintInfo& paintInfo, const Color& c, const FillLayer* bgLayer, int clipY, int clipH,
1115                                        int tx, int ty, int w, int h, InlineFlowBox* box, CompositeOperator op)
1116 {
1117     GraphicsContext* context = paintInfo.context;
1118     bool includeLeftEdge = box ? box->includeLeftEdge() : true;
1119     bool includeRightEdge = box ? box->includeRightEdge() : true;
1120     int bLeft = includeLeftEdge ? borderLeft() : 0;
1121     int bRight = includeRightEdge ? borderRight() : 0;
1122     int pLeft = includeLeftEdge ? paddingLeft() : 0;
1123     int pRight = includeRightEdge ? paddingRight() : 0;
1124
1125     bool clippedToBorderRadius = false;
1126     if (style()->hasBorderRadius() && (includeLeftEdge || includeRightEdge)) {
1127         context->save();
1128         context->addRoundedRectClip(IntRect(tx, ty, w, h),
1129             includeLeftEdge ? style()->borderTopLeftRadius() : IntSize(),
1130             includeRightEdge ? style()->borderTopRightRadius() : IntSize(),
1131             includeLeftEdge ? style()->borderBottomLeftRadius() : IntSize(),
1132             includeRightEdge ? style()->borderBottomRightRadius() : IntSize());
1133         clippedToBorderRadius = true;
1134     }
1135
1136     if (bgLayer->clip() == PaddingFillBox || bgLayer->clip() == ContentFillBox) {
1137         // Clip to the padding or content boxes as necessary.
1138         bool includePadding = bgLayer->clip() == ContentFillBox;
1139         int x = tx + bLeft + (includePadding ? pLeft : 0);
1140         int y = ty + borderTop() + (includePadding ? paddingTop() : 0);
1141         int width = w - bLeft - bRight - (includePadding ? pLeft + pRight : 0);
1142         int height = h - borderTop() - borderBottom() - (includePadding ? paddingTop() + paddingBottom() : 0);
1143         context->save();
1144         context->clip(IntRect(x, y, width, height));
1145     } else if (bgLayer->clip() == TextFillBox) {
1146         // We have to draw our text into a mask that can then be used to clip background drawing.
1147         // First figure out how big the mask has to be.  It should be no bigger than what we need
1148         // to actually render, so we should intersect the dirty rect with the border box of the background.
1149         IntRect maskRect(tx, ty, w, h);
1150         maskRect.intersect(paintInfo.rect);
1151         
1152         // Now create the mask.
1153         auto_ptr<ImageBuffer> maskImage = ImageBuffer::create(maskRect.size(), false);
1154         if (!maskImage.get())
1155             return;
1156         
1157         GraphicsContext* maskImageContext = maskImage->context();
1158         maskImageContext->translate(-maskRect.x(), -maskRect.y());
1159         
1160         // Now add the text to the clip.  We do this by painting using a special paint phase that signals to
1161         // InlineTextBoxes that they should just add their contents to the clip.
1162         PaintInfo info(maskImageContext, maskRect, PaintPhaseTextClip, true, 0, 0);
1163         if (box)
1164             box->paint(info, tx - box->xPos(), ty - box->yPos());
1165         else
1166             paint(info, tx, ty);
1167             
1168         // The mask has been created.  Now we just need to clip to it.
1169         context->save();
1170         context->clipToImageBuffer(maskRect, maskImage.get());
1171     }
1172     
1173     StyleImage* bg = bgLayer->image();
1174     bool shouldPaintBackgroundImage = bg && bg->canRender(style()->effectiveZoom());
1175     Color bgColor = c;
1176
1177     // When this style flag is set, change existing background colors and images to a solid white background.
1178     // If there's no bg color or image, leave it untouched to avoid affecting transparency.
1179     // We don't try to avoid loading the background images, because this style flag is only set
1180     // when printing, and at that point we've already loaded the background images anyway. (To avoid
1181     // loading the background images we'd have to do this check when applying styles rather than
1182     // while rendering.)
1183     if (style()->forceBackgroundsToWhite()) {
1184         // Note that we can't reuse this variable below because the bgColor might be changed
1185         bool shouldPaintBackgroundColor = !bgLayer->next() && bgColor.isValid() && bgColor.alpha() > 0;
1186         if (shouldPaintBackgroundImage || shouldPaintBackgroundColor) {
1187             bgColor = Color::white;
1188             shouldPaintBackgroundImage = false;
1189         }
1190     }
1191
1192     // Only fill with a base color (e.g., white) if we're the root document, since iframes/frames with
1193     // no background in the child document should show the parent's background.
1194     bool isTransparent = false;
1195     if (!bgLayer->next() && isRoot() && !(bgColor.isValid() && bgColor.alpha() > 0) && view()->frameView()) {
1196         Node* elt = document()->ownerElement();
1197         if (elt) {
1198             if (!elt->hasTagName(frameTag)) {
1199                 // Locate the <body> element using the DOM.  This is easier than trying
1200                 // to crawl around a render tree with potential :before/:after content and
1201                 // anonymous blocks created by inline <body> tags etc.  We can locate the <body>
1202                 // render object very easily via the DOM.
1203                 HTMLElement* body = document()->body();
1204                 isTransparent = !body || !body->hasLocalName(framesetTag); // Can't scroll a frameset document anyway.
1205             }
1206         } else
1207             isTransparent = view()->frameView()->isTransparent();
1208
1209         // FIXME: This needs to be dynamic.  We should be able to go back to blitting if we ever stop being transparent.
1210         if (isTransparent)
1211             view()->frameView()->setUseSlowRepaints(); // The parent must show behind the child.
1212     }
1213
1214     // Paint the color first underneath all images.
1215     if (!bgLayer->next()) {
1216         IntRect rect(tx, clipY, w, clipH);
1217         // If we have an alpha and we are painting the root element, go ahead and blend with the base background color.
1218         if (isRoot() && (!bgColor.isValid() || bgColor.alpha() < 0xFF) && !isTransparent) {
1219             Color baseColor = view()->frameView()->baseBackgroundColor();
1220             if (baseColor.alpha() > 0) {
1221                 context->save();
1222                 context->setCompositeOperation(CompositeCopy);
1223                 context->fillRect(rect, baseColor);
1224                 context->restore();
1225             } else
1226                 context->clearRect(rect);
1227         }
1228
1229         if (bgColor.isValid() && bgColor.alpha() > 0)
1230             context->fillRect(rect, bgColor);
1231     }
1232
1233     // no progressive loading of the background image
1234     if (shouldPaintBackgroundImage) {
1235         IntRect destRect;
1236         IntPoint phase;
1237         IntSize tileSize;
1238
1239         calculateBackgroundImageGeometry(bgLayer, tx, ty, w, h, destRect, phase, tileSize);
1240         if (!destRect.isEmpty()) {
1241             CompositeOperator compositeOp = op == CompositeSourceOver ? bgLayer->composite() : op;
1242             context->drawTiledImage(bg->image(this, tileSize), destRect, phase, tileSize, compositeOp);
1243         }
1244     }
1245
1246     if (bgLayer->clip() != BorderFillBox)
1247         // Undo the background clip
1248         context->restore();
1249
1250     if (clippedToBorderRadius)
1251         // Undo the border radius clip
1252         context->restore();
1253 }
1254
1255 #if PLATFORM(MAC)
1256
1257 void RenderBox::paintCustomHighlight(int tx, int ty, const AtomicString& type, bool behindText)
1258 {
1259     Frame* frame = document()->frame();
1260     if (!frame)
1261         return;
1262     Page* page = frame->page();
1263     if (!page)
1264         return;
1265
1266     InlineBox* boxWrap = inlineBoxWrapper();
1267     RootInlineBox* r = boxWrap ? boxWrap->root() : 0;
1268     if (r) {
1269         FloatRect rootRect(tx + r->xPos(), ty + r->selectionTop(), r->width(), r->selectionHeight());
1270         FloatRect imageRect(tx + x(), rootRect.y(), width(), rootRect.height());
1271         page->chrome()->client()->paintCustomHighlight(node(), type, imageRect, rootRect, behindText, false);
1272     } else {
1273         FloatRect imageRect(tx + x(), ty + y(), width(), height());
1274         page->chrome()->client()->paintCustomHighlight(node(), type, imageRect, imageRect, behindText, false);
1275     }
1276 }
1277
1278 #endif
1279
1280 IntRect RenderBox::getOverflowClipRect(int tx, int ty)
1281 {
1282     // FIXME: When overflow-clip (CSS3) is implemented, we'll obtain the property
1283     // here.
1284
1285     int bLeft = borderLeft();
1286     int bTop = borderTop();
1287
1288     int clipX = tx + bLeft;
1289     int clipY = ty + bTop;
1290     int clipWidth = width() - bLeft - borderRight();
1291     int clipHeight = height() - bTop - borderBottom();
1292
1293     // Subtract out scrollbars if we have them.
1294     if (m_layer) {
1295         clipWidth -= m_layer->verticalScrollbarWidth();
1296         clipHeight -= m_layer->horizontalScrollbarHeight();
1297     }
1298
1299     return IntRect(clipX, clipY, clipWidth, clipHeight);
1300 }
1301
1302 IntRect RenderBox::getClipRect(int tx, int ty)
1303 {
1304     int clipX = tx;
1305     int clipY = ty;
1306     int clipWidth = width();
1307     int clipHeight = height();
1308
1309     if (!style()->clipLeft().isAuto()) {
1310         int c = style()->clipLeft().calcValue(width());
1311         clipX += c;
1312         clipWidth -= c;
1313     }
1314
1315     if (!style()->clipRight().isAuto())
1316         clipWidth -= width() - style()->clipRight().calcValue(width());
1317
1318     if (!style()->clipTop().isAuto()) {
1319         int c = style()->clipTop().calcValue(height());
1320         clipY += c;
1321         clipHeight -= c;
1322     }
1323
1324     if (!style()->clipBottom().isAuto())
1325         clipHeight -= height() - style()->clipBottom().calcValue(height());
1326
1327     return IntRect(clipX, clipY, clipWidth, clipHeight);
1328 }
1329
1330 int RenderBox::containingBlockWidth() const
1331 {
1332     RenderBlock* cb = containingBlock();
1333     if (!cb)
1334         return 0;
1335     if (shrinkToAvoidFloats())
1336         return cb->lineWidth(y(), false);
1337     return cb->availableWidth();
1338 }
1339
1340 FloatPoint RenderBox::localToAbsolute(FloatPoint localPoint, bool fixed, bool useTransforms) const
1341 {
1342     if (RenderView* v = view()) {
1343         if (v->layoutStateEnabled()) {
1344             LayoutState* layoutState = v->layoutState();
1345             IntSize offset = layoutState->m_offset;
1346             offset.expand(x(), y());
1347             localPoint += offset;
1348             if (style()->position() == RelativePosition && m_layer)
1349                 localPoint += m_layer->relativePositionOffset();
1350             return localPoint;
1351         }
1352     }
1353
1354     if (style()->position() == FixedPosition)
1355         fixed = true;
1356
1357     RenderObject* o = container();
1358     if (o) {
1359         if (useTransforms && m_layer && m_layer->transform()) {
1360             fixed = false;  // Elements with transforms act as a containing block for fixed position descendants
1361             localPoint = m_layer->transform()->mapPoint(localPoint);
1362         }
1363
1364         localPoint += offsetFromContainer(o);
1365
1366         return o->localToAbsolute(localPoint, fixed, useTransforms);
1367     }
1368     
1369     return FloatPoint();
1370 }
1371
1372 FloatPoint RenderBox::absoluteToLocal(FloatPoint containerPoint, bool fixed, bool useTransforms) const
1373 {
1374     // We don't expect absoluteToLocal() to be called during layout (yet)
1375     ASSERT(!view() || !view()->layoutStateEnabled());
1376     
1377     if (style()->position() == FixedPosition)
1378         fixed = true;
1379
1380     if (useTransforms && m_layer && m_layer->transform())
1381         fixed = false;
1382     
1383     RenderObject* o = container();
1384     if (o) {
1385         FloatPoint localPoint = o->absoluteToLocal(containerPoint, fixed, useTransforms);
1386         localPoint -= offsetFromContainer(o);
1387         if (useTransforms && m_layer && m_layer->transform())
1388             localPoint = m_layer->transform()->inverse().mapPoint(localPoint);
1389         return localPoint;
1390     }
1391     
1392     return FloatPoint();
1393 }
1394
1395 FloatQuad RenderBox::localToContainerQuad(const FloatQuad& localQuad, RenderBox* repaintContainer, bool fixed) const
1396 {
1397     if (repaintContainer == this)
1398         return localQuad;
1399
1400     if (style()->position() == FixedPosition)
1401         fixed = true;
1402
1403     RenderObject* o = container();
1404     if (o) {
1405         FloatQuad quad = localQuad;
1406         if (m_layer && m_layer->transform()) {
1407             fixed = false;  // Elements with transforms act as a containing block for fixed position descendants
1408             quad = m_layer->transform()->mapQuad(quad);
1409         }
1410         quad += offsetFromContainer(o);
1411         return o->localToContainerQuad(quad, repaintContainer, fixed);
1412     }
1413     
1414     return FloatQuad();
1415 }
1416
1417 IntSize RenderBox::offsetFromContainer(RenderObject* o) const
1418 {
1419     ASSERT(o == container());
1420
1421     IntSize offset;    
1422     if (isRelPositioned())
1423         offset += relativePositionOffset();
1424
1425     if (!isInline() || isReplaced()) {
1426         RenderBlock* cb;
1427         if (o->isBlockFlow() && style()->position() != AbsolutePosition && style()->position() != FixedPosition
1428                 && (cb = toRenderBlock(o))->hasColumns()) {
1429             IntRect rect(x(), y(), 1, 1);
1430             cb->adjustRectForColumns(rect);
1431             offset.expand(rect.x(), rect.y());
1432         } else
1433             offset.expand(x(), y());
1434     }
1435
1436     if (o->hasOverflowClip())
1437         offset -= toRenderBox(o)->layer()->scrolledContentOffset();
1438
1439     if (style()->position() == AbsolutePosition && o->isRelPositioned() && o->isRenderInline())
1440         offset += toRenderInline(o)->relativePositionedInlineOffset(this);
1441
1442     return offset;
1443 }
1444
1445 void RenderBox::dirtyLineBoxes(bool fullLayout, bool /*isRootLineBox*/)
1446 {
1447     if (m_inlineBoxWrapper) {
1448         if (fullLayout) {
1449             m_inlineBoxWrapper->destroy(renderArena());
1450             m_inlineBoxWrapper = 0;
1451         } else
1452             m_inlineBoxWrapper->dirtyLineBoxes();
1453     }
1454 }
1455
1456 void RenderBox::position(InlineBox* box)
1457 {
1458     if (isPositioned()) {
1459         // Cache the x position only if we were an INLINE type originally.
1460         bool wasInline = style()->isOriginalDisplayInlineType();
1461         if (wasInline && hasStaticX()) {
1462             // The value is cached in the xPos of the box.  We only need this value if
1463             // our object was inline originally, since otherwise it would have ended up underneath
1464             // the inlines.
1465             setStaticX(box->xPos());
1466             setChildNeedsLayout(true, false); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
1467         } else if (!wasInline && hasStaticY()) {
1468             // Our object was a block originally, so we make our normal flow position be
1469             // just below the line box (as though all the inlines that came before us got
1470             // wrapped in an anonymous block, which is what would have happened had we been
1471             // in flow).  This value was cached in the yPos() of the box.
1472             setStaticY(box->yPos());
1473             setChildNeedsLayout(true, false); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
1474         }
1475
1476         // Nuke the box.
1477         box->remove();
1478         box->destroy(renderArena());
1479     } else if (isReplaced()) {
1480         setLocation(box->xPos(), box->yPos());
1481         m_inlineBoxWrapper = box;
1482     }
1483 }
1484
1485 void RenderBox::deleteLineBoxWrapper()
1486 {
1487     if (m_inlineBoxWrapper) {
1488         if (!documentBeingDestroyed())
1489             m_inlineBoxWrapper->remove();
1490         m_inlineBoxWrapper->destroy(renderArena());
1491         m_inlineBoxWrapper = 0;
1492     }
1493 }
1494
1495 IntRect RenderBox::clippedOverflowRectForRepaint(RenderBox* repaintContainer)
1496 {
1497     if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent())
1498         return IntRect();
1499
1500     IntRect r = overflowRect(false);
1501
1502     RenderView* v = view();
1503     if (v) {
1504         // FIXME: layoutDelta needs to be applied in parts before/after transforms and
1505         // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
1506         r.move(v->layoutDelta());
1507     }
1508     
1509     if (style()) {
1510         if (style()->hasAppearance())
1511             // The theme may wish to inflate the rect used when repainting.
1512             theme()->adjustRepaintRect(this, r);
1513
1514         // We have to use maximalOutlineSize() because a child might have an outline
1515         // that projects outside of our overflowRect.
1516         if (v) {
1517             ASSERT(style()->outlineSize() <= v->maximalOutlineSize());
1518             r.inflate(v->maximalOutlineSize());
1519         }
1520     }
1521     computeRectForRepaint(repaintContainer, r);
1522     return r;
1523 }
1524
1525 void RenderBox::computeRectForRepaint(RenderBox* repaintContainer, IntRect& rect, bool fixed)
1526 {
1527     if (RenderView* v = view()) {
1528         // LayoutState is only valid for root-relative repainting
1529         if (v->layoutStateEnabled() && !repaintContainer) {
1530             LayoutState* layoutState = v->layoutState();
1531             if (style()->position() == RelativePosition && m_layer)
1532                 rect.move(m_layer->relativePositionOffset());
1533
1534             rect.move(x(), y());
1535             rect.move(layoutState->m_offset);
1536             if (layoutState->m_clipped)
1537                 rect.intersect(layoutState->m_clipRect);
1538             return;
1539         }
1540     }
1541
1542     if (hasReflection())
1543         rect.unite(reflectedRect(rect));
1544
1545     if (repaintContainer == this)
1546         return;
1547
1548     RenderObject* o = container();
1549     if (!o)
1550         return;
1551
1552     IntPoint topLeft = rect.location();
1553     topLeft.move(x(), y());
1554
1555     if (style()->position() == FixedPosition)
1556         fixed = true;
1557
1558     if (o->isBlockFlow() && style()->position() != AbsolutePosition && style()->position() != FixedPosition) {
1559         RenderBlock* cb = toRenderBlock(o);
1560         if (cb->hasColumns()) {
1561             IntRect repaintRect(topLeft, rect.size());
1562             cb->adjustRectForColumns(repaintRect);
1563             topLeft = repaintRect.location();
1564             rect = repaintRect;
1565         }
1566     }
1567
1568     // We are now in our parent container's coordinate space.  Apply our transform to obtain a bounding box
1569     // in the parent's coordinate space that encloses us.
1570     if (m_layer && m_layer->transform()) {
1571         fixed = false;
1572         rect = m_layer->transform()->mapRect(rect);
1573         // FIXME: this clobbers topLeft adjustment done for multicol above
1574         topLeft = rect.location();
1575         topLeft.move(x(), y());
1576     }
1577
1578     if (style()->position() == AbsolutePosition && o->isRelPositioned() && o->isRenderInline())
1579         topLeft += toRenderInline(o)->relativePositionedInlineOffset(this);
1580     else if (style()->position() == RelativePosition && m_layer) {
1581         // Apply the relative position offset when invalidating a rectangle.  The layer
1582         // is translated, but the render box isn't, so we need to do this to get the
1583         // right dirty rect.  Since this is called from RenderObject::setStyle, the relative position
1584         // flag on the RenderObject has been cleared, so use the one on the style().
1585         topLeft += m_layer->relativePositionOffset();
1586     }
1587     
1588     // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
1589     // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
1590     if (o->hasOverflowClip()) {
1591         RenderBox* containerBox = toRenderBox(o);
1592
1593         // o->height() is inaccurate if we're in the middle of a layout of |o|, so use the
1594         // layer's size instead.  Even if the layer's size is wrong, the layer itself will repaint
1595         // anyway if its size does change.
1596         topLeft -= containerBox->layer()->scrolledContentOffset(); // For overflow:auto/scroll/hidden.
1597
1598         IntRect repaintRect(topLeft, rect.size());
1599         IntRect boxRect(0, 0, containerBox->layer()->width(), containerBox->layer()->height());
1600         rect = intersection(repaintRect, boxRect);
1601         if (rect.isEmpty())
1602             return;
1603     } else
1604         rect.setLocation(topLeft);
1605     
1606     o->computeRectForRepaint(repaintContainer, rect, fixed);
1607 }
1608
1609 void RenderBox::repaintDuringLayoutIfMoved(const IntRect& rect)
1610 {
1611     int newX = x();
1612     int newY = y();
1613     int newWidth = width();
1614     int newHeight = height();
1615     if (rect.x() != newX || rect.y() != newY) {
1616         // The child moved.  Invalidate the object's old and new positions.  We have to do this
1617         // since the object may not have gotten a layout.
1618         m_frameRect = rect;
1619         repaint();
1620         repaintOverhangingFloats(true);
1621         m_frameRect = IntRect(newX, newY, newWidth, newHeight);
1622         repaint();
1623         repaintOverhangingFloats(true);
1624     }
1625 }
1626
1627 int RenderBox::relativePositionOffsetX() const
1628 {
1629     if (!style()->left().isAuto()) {
1630         if (!style()->right().isAuto() && containingBlock()->style()->direction() == RTL)
1631             return -style()->right().calcValue(containingBlockWidth());
1632         return style()->left().calcValue(containingBlockWidth());
1633     }
1634     if (!style()->right().isAuto())
1635         return -style()->right().calcValue(containingBlockWidth());
1636     return 0;
1637 }
1638
1639 int RenderBox::relativePositionOffsetY() const
1640 {
1641     if (!style()->top().isAuto()) {
1642         if (!style()->top().isPercent() || containingBlock()->style()->height().isFixed())
1643             return style()->top().calcValue(containingBlockHeight());
1644     } else if (!style()->bottom().isAuto()) {
1645         if (!style()->bottom().isPercent() || containingBlock()->style()->height().isFixed())
1646             return -style()->bottom().calcValue(containingBlockHeight());
1647     }
1648     return 0;
1649 }
1650
1651 void RenderBox::calcWidth()
1652 {
1653     if (isPositioned()) {
1654         calcAbsoluteHorizontal();
1655         return;
1656     }
1657
1658     // If layout is limited to a subtree, the subtree root's width does not change.
1659     if (node() && view()->frameView() && view()->frameView()->layoutRoot(true) == this)
1660         return;
1661
1662     // The parent box is flexing us, so it has increased or decreased our
1663     // width.  Use the width from the style context.
1664     if (hasOverrideSize() &&  parent()->style()->boxOrient() == HORIZONTAL
1665             && parent()->isFlexibleBox() && parent()->isFlexingChildren()) {
1666         setWidth(overrideSize());
1667         return;
1668     }
1669
1670     bool inVerticalBox = parent()->isFlexibleBox() && (parent()->style()->boxOrient() == VERTICAL);
1671     bool stretching = (parent()->style()->boxAlign() == BSTRETCH);
1672     bool treatAsReplaced = shouldCalculateSizeAsReplaced() && (!inVerticalBox || !stretching);
1673
1674     Length w = (treatAsReplaced) ? Length(calcReplacedWidth(), Fixed) : style()->width();
1675
1676     RenderBlock* cb = containingBlock();
1677     int containerWidth = max(0, containingBlockWidth());
1678
1679     Length marginLeft = style()->marginLeft();
1680     Length marginRight = style()->marginRight();
1681
1682     if (isInline() && !isInlineBlockOrInlineTable()) {
1683         // just calculate margins
1684         m_marginLeft = marginLeft.calcMinValue(containerWidth);
1685         m_marginRight = marginRight.calcMinValue(containerWidth);
1686         if (treatAsReplaced)
1687             setWidth(max(w.value() + borderLeft() + borderRight() + paddingLeft() + paddingRight(), minPrefWidth()));
1688
1689         return;
1690     }
1691
1692     // Width calculations
1693     if (treatAsReplaced)
1694         setWidth(w.value() + borderLeft() + borderRight() + paddingLeft() + paddingRight());
1695     else {
1696         // Calculate Width
1697         setWidth(calcWidthUsing(Width, containerWidth));
1698
1699         // Calculate MaxWidth
1700         if (!style()->maxWidth().isUndefined()) {
1701             int maxW = calcWidthUsing(MaxWidth, containerWidth);
1702             if (width() > maxW) {
1703                 setWidth(maxW);
1704                 w = style()->maxWidth();
1705             }
1706         }
1707
1708         // Calculate MinWidth
1709         int minW = calcWidthUsing(MinWidth, containerWidth);
1710         if (width() < minW) {
1711             setWidth(minW);
1712             w = style()->minWidth();
1713         }
1714     }
1715
1716     if (stretchesToMinIntrinsicWidth()) {
1717         setWidth(max(width(), minPrefWidth()));
1718         w = Length(width(), Fixed);
1719     }
1720
1721     // Margin calculations
1722     if (w.isAuto()) {
1723         m_marginLeft = marginLeft.calcMinValue(containerWidth);
1724         m_marginRight = marginRight.calcMinValue(containerWidth);
1725     } else {
1726         m_marginLeft = 0;
1727         m_marginRight = 0;
1728         calcHorizontalMargins(marginLeft, marginRight, containerWidth);
1729     }
1730
1731     if (containerWidth && containerWidth != (width() + m_marginLeft + m_marginRight)
1732             && !isFloating() && !isInline() && !cb->isFlexibleBox()) {
1733         if (cb->style()->direction() == LTR)
1734             m_marginRight = containerWidth - width() - m_marginLeft;
1735         else
1736             m_marginLeft = containerWidth - width() - m_marginRight;
1737     }
1738 }
1739
1740 int RenderBox::calcWidthUsing(WidthType widthType, int cw)
1741 {
1742     int widthResult = width();
1743     Length w;
1744     if (widthType == Width)
1745         w = style()->width();
1746     else if (widthType == MinWidth)
1747         w = style()->minWidth();
1748     else
1749         w = style()->maxWidth();
1750
1751     if (w.isIntrinsicOrAuto()) {
1752         int marginLeft = style()->marginLeft().calcMinValue(cw);
1753         int marginRight = style()->marginRight().calcMinValue(cw);
1754         if (cw)
1755             widthResult = cw - marginLeft - marginRight;
1756
1757         if (sizesToIntrinsicWidth(widthType)) {
1758             widthResult = max(widthResult, minPrefWidth());
1759             widthResult = min(widthResult, maxPrefWidth());
1760         }
1761     } else
1762         widthResult = calcBorderBoxWidth(w.calcValue(cw));
1763
1764     return widthResult;
1765 }
1766
1767 bool RenderBox::sizesToIntrinsicWidth(WidthType widthType) const
1768 {
1769     // Marquees in WinIE are like a mixture of blocks and inline-blocks.  They size as though they're blocks,
1770     // but they allow text to sit on the same line as the marquee.
1771     if (isFloating() || (isInlineBlockOrInlineTable() && !isHTMLMarquee()))
1772         return true;
1773
1774     // This code may look a bit strange.  Basically width:intrinsic should clamp the size when testing both
1775     // min-width and width.  max-width is only clamped if it is also intrinsic.
1776     Length width = (widthType == MaxWidth) ? style()->maxWidth() : style()->width();
1777     if (width.type() == Intrinsic)
1778         return true;
1779
1780     // Children of a horizontal marquee do not fill the container by default.
1781     // FIXME: Need to deal with MAUTO value properly.  It could be vertical.
1782     if (parent()->style()->overflowX() == OMARQUEE) {
1783         EMarqueeDirection dir = parent()->style()->marqueeDirection();
1784         if (dir == MAUTO || dir == MFORWARD || dir == MBACKWARD || dir == MLEFT || dir == MRIGHT)
1785             return true;
1786     }
1787
1788     // Flexible horizontal boxes lay out children at their intrinsic widths.  Also vertical boxes
1789     // that don't stretch their kids lay out their children at their intrinsic widths.
1790     if (parent()->isFlexibleBox()
1791             && (parent()->style()->boxOrient() == HORIZONTAL || parent()->style()->boxAlign() != BSTRETCH))
1792         return true;
1793
1794     return false;
1795 }
1796
1797 void RenderBox::calcHorizontalMargins(const Length& marginLeft, const Length& marginRight, int containerWidth)
1798 {
1799     if (isFloating() || isInline()) {
1800         // Inline blocks/tables and floats don't have their margins increased.
1801         m_marginLeft = marginLeft.calcMinValue(containerWidth);
1802         m_marginRight = marginRight.calcMinValue(containerWidth);
1803         return;
1804     }
1805
1806     if ((marginLeft.isAuto() && marginRight.isAuto() && width() < containerWidth)
1807             || (!marginLeft.isAuto() && !marginRight.isAuto() && containingBlock()->style()->textAlign() == WEBKIT_CENTER)) {
1808         m_marginLeft = max(0, (containerWidth - width()) / 2);
1809         m_marginRight = containerWidth - width() - m_marginLeft;
1810     } else if ((marginRight.isAuto() && width() < containerWidth)
1811             || (!marginLeft.isAuto() && containingBlock()->style()->direction() == RTL && containingBlock()->style()->textAlign() == WEBKIT_LEFT)) {
1812         m_marginLeft = marginLeft.calcValue(containerWidth);
1813         m_marginRight = containerWidth - width() - m_marginLeft;
1814     } else if ((marginLeft.isAuto() && width() < containerWidth)
1815             || (!marginRight.isAuto() && containingBlock()->style()->direction() == LTR && containingBlock()->style()->textAlign() == WEBKIT_RIGHT)) {
1816         m_marginRight = marginRight.calcValue(containerWidth);
1817         m_marginLeft = containerWidth - width() - m_marginRight;
1818     } else {
1819         // This makes auto margins 0 if we failed a width() < containerWidth test above (css2.1, 10.3.3).
1820         m_marginLeft = marginLeft.calcMinValue(containerWidth);
1821         m_marginRight = marginRight.calcMinValue(containerWidth);
1822     }
1823 }
1824
1825 void RenderBox::calcHeight()
1826 {
1827     // Cell height is managed by the table and inline non-replaced elements do not support a height property.
1828     if (isTableCell() || (isInline() && !isReplaced()))
1829         return;
1830
1831     if (isPositioned())
1832         calcAbsoluteVertical();
1833     else {
1834         calcVerticalMargins();
1835
1836         // For tables, calculate margins only.
1837         if (isTable())
1838             return;
1839
1840         Length h;
1841         bool inHorizontalBox = parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL;
1842         bool stretching = parent()->style()->boxAlign() == BSTRETCH;
1843         bool treatAsReplaced = shouldCalculateSizeAsReplaced() && (!inHorizontalBox || !stretching);
1844         bool checkMinMaxHeight = false;
1845
1846         // The parent box is flexing us, so it has increased or decreased our height.  We have to
1847         // grab our cached flexible height.
1848         if (hasOverrideSize() && parent()->isFlexibleBox() && parent()->style()->boxOrient() == VERTICAL
1849                 && parent()->isFlexingChildren())
1850             h = Length(overrideSize() - borderTop() - borderBottom() - paddingTop() - paddingBottom(), Fixed);
1851         else if (treatAsReplaced)
1852             h = Length(calcReplacedHeight(), Fixed);
1853         else {
1854             h = style()->height();
1855             checkMinMaxHeight = true;
1856         }
1857
1858         // Block children of horizontal flexible boxes fill the height of the box.
1859         if (h.isAuto() && parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
1860                 && parent()->isStretchingChildren()) {
1861             h = Length(parentBox()->contentHeight() - marginTop() - marginBottom() -
1862                        borderTop() - paddingTop() - borderBottom() - paddingBottom(), Fixed);
1863             checkMinMaxHeight = false;
1864         }
1865
1866         int heightResult;
1867         if (checkMinMaxHeight) {
1868             heightResult = calcHeightUsing(style()->height());
1869             if (heightResult == -1)
1870                 heightResult = height();
1871             int minH = calcHeightUsing(style()->minHeight()); // Leave as -1 if unset.
1872             int maxH = style()->maxHeight().isUndefined() ? heightResult : calcHeightUsing(style()->maxHeight());
1873             if (maxH == -1)
1874                 maxH = heightResult;
1875             heightResult = min(maxH, heightResult);
1876             heightResult = max(minH, heightResult);
1877         } else
1878             // The only times we don't check min/max height are when a fixed length has
1879             // been given as an override.  Just use that.  The value has already been adjusted
1880             // for box-sizing.
1881             heightResult = h.value() + borderTop() + borderBottom() + paddingTop() + paddingBottom();
1882
1883             setHeight(heightResult);
1884         }
1885
1886     // WinIE quirk: The <html> block always fills the entire canvas in quirks mode.  The <body> always fills the
1887     // <html> block in quirks mode.  Only apply this quirk if the block is normal flow and no height
1888     // is specified.
1889     if (stretchesToViewHeight() && !document()->printing()) {
1890         int margins = collapsedMarginTop() + collapsedMarginBottom();
1891         int visHeight = view()->viewHeight();
1892         if (isRoot())
1893             setHeight(max(height(), visHeight - margins));
1894         else {
1895             int marginsBordersPadding = margins + parentBox()->marginTop() + parentBox()->marginBottom()
1896                 + parentBox()->borderTop() + parentBox()->borderBottom()
1897                 + parentBox()->paddingTop() + parentBox()->paddingBottom();
1898             setHeight(max(height(), visHeight - marginsBordersPadding));
1899         }
1900     }
1901 }
1902
1903 int RenderBox::calcHeightUsing(const Length& h)
1904 {
1905     int height = -1;
1906     if (!h.isAuto()) {
1907         if (h.isFixed())
1908             height = h.value();
1909         else if (h.isPercent())
1910             height = calcPercentageHeight(h);
1911         if (height != -1) {
1912             height = calcBorderBoxHeight(height);
1913             return height;
1914         }
1915     }
1916     return height;
1917 }
1918
1919 int RenderBox::calcPercentageHeight(const Length& height)
1920 {
1921     int result = -1;
1922     bool includeBorderPadding = isTable();
1923     RenderBlock* cb = containingBlock();
1924     if (style()->htmlHacks()) {
1925         // In quirks mode, blocks with auto height are skipped, and we keep looking for an enclosing
1926         // block that may have a specified height and then use it.  In strict mode, this violates the
1927         // specification, which states that percentage heights just revert to auto if the containing
1928         // block has an auto height.
1929         while (!cb->isRenderView() && !cb->isBody() && !cb->isTableCell() && !cb->isPositioned() && cb->style()->height().isAuto()) {
1930             cb = cb->containingBlock();
1931             cb->addPercentHeightDescendant(this);
1932         }
1933     }
1934
1935     // A positioned element that specified both top/bottom or that specifies height should be treated as though it has a height
1936     // explicitly specified that can be used for any percentage computations.
1937     bool isPositionedWithSpecifiedHeight = cb->isPositioned() && (!cb->style()->height().isAuto() || (!cb->style()->top().isAuto() && !cb->style()->bottom().isAuto()));
1938
1939     // Table cells violate what the CSS spec says to do with heights.  Basically we
1940     // don't care if the cell specified a height or not.  We just always make ourselves
1941     // be a percentage of the cell's current content height.
1942     if (cb->isTableCell()) {
1943         result = cb->overrideSize();
1944         if (result == -1) {
1945             // Normally we would let the cell size intrinsically, but scrolling overflow has to be
1946             // treated differently, since WinIE lets scrolled overflow regions shrink as needed.
1947             // While we can't get all cases right, we can at least detect when the cell has a specified
1948             // height or when the table has a specified height.  In these cases we want to initially have
1949             // no size and allow the flexing of the table or the cell to its specified height to cause us
1950             // to grow to fill the space.  This could end up being wrong in some cases, but it is
1951             // preferable to the alternative (sizing intrinsically and making the row end up too big).
1952             RenderTableCell* cell = static_cast<RenderTableCell*>(cb);
1953             if (scrollsOverflowY() && (!cell->style()->height().isAuto() || !cell->table()->style()->height().isAuto()))
1954                 return 0;
1955             return -1;
1956         }
1957         includeBorderPadding = true;
1958     }
1959     // Otherwise we only use our percentage height if our containing block had a specified
1960     // height.
1961     else if (cb->style()->height().isFixed())
1962         result = cb->calcContentBoxHeight(cb->style()->height().value());
1963     else if (cb->style()->height().isPercent() && !isPositionedWithSpecifiedHeight) {
1964         // We need to recur and compute the percentage height for our containing block.
1965         result = cb->calcPercentageHeight(cb->style()->height());
1966         if (result != -1)
1967             result = cb->calcContentBoxHeight(result);
1968     } else if (cb->isRenderView() || (cb->isBody() && style()->htmlHacks()) || isPositionedWithSpecifiedHeight) {
1969         // Don't allow this to affect the block' height() member variable, since this
1970         // can get called while the block is still laying out its kids.
1971         int oldHeight = cb->height();
1972         cb->calcHeight();
1973         result = cb->contentHeight();
1974         cb->setHeight(oldHeight);
1975     } else if (cb->isRoot() && isPositioned())
1976         // Match the positioned objects behavior, which is that positioned objects will fill their viewport
1977         // always.  Note we could only hit this case by recurring into calcPercentageHeight on a positioned containing block.
1978         result = cb->calcContentBoxHeight(cb->availableHeight());
1979
1980     if (result != -1) {
1981         result = height.calcValue(result);
1982         if (includeBorderPadding) {
1983             // It is necessary to use the border-box to match WinIE's broken
1984             // box model.  This is essential for sizing inside
1985             // table cells using percentage heights.
1986             result -= (borderTop() + paddingTop() + borderBottom() + paddingBottom());
1987             result = max(0, result);
1988         }
1989     }
1990     return result;
1991 }
1992
1993 int RenderBox::calcReplacedWidth(bool includeMaxWidth) const
1994 {
1995     int width = calcReplacedWidthUsing(style()->width());
1996     int minW = calcReplacedWidthUsing(style()->minWidth());
1997     int maxW = !includeMaxWidth || style()->maxWidth().isUndefined() ? width : calcReplacedWidthUsing(style()->maxWidth());
1998
1999     return max(minW, min(width, maxW));
2000 }
2001
2002 int RenderBox::calcReplacedWidthUsing(Length width) const
2003 {
2004     switch (width.type()) {
2005         case Fixed:
2006             return calcContentBoxWidth(width.value());
2007         case Percent: {
2008             const int cw = isPositioned() ? containingBlockWidthForPositioned(container()) : containingBlockWidth();
2009             if (cw > 0)
2010                 return calcContentBoxWidth(width.calcMinValue(cw));
2011         }
2012         // fall through
2013         default:
2014             return intrinsicSize().width();
2015      }
2016  }
2017
2018 int RenderBox::calcReplacedHeight() const
2019 {
2020     int height = calcReplacedHeightUsing(style()->height());
2021     int minH = calcReplacedHeightUsing(style()->minHeight());
2022     int maxH = style()->maxHeight().isUndefined() ? height : calcReplacedHeightUsing(style()->maxHeight());
2023
2024     return max(minH, min(height, maxH));
2025 }
2026
2027 int RenderBox::calcReplacedHeightUsing(Length height) const
2028 {
2029     switch (height.type()) {
2030         case Fixed:
2031             return calcContentBoxHeight(height.value());
2032         case Percent:
2033         {
2034             RenderObject* cb = isPositioned() ? container() : containingBlock();
2035             while (cb->isAnonymous()) {
2036                 cb = cb->containingBlock();
2037                 toRenderBlock(cb)->addPercentHeightDescendant(const_cast<RenderBox*>(this));
2038             }
2039
2040             if (cb->isPositioned() && cb->style()->height().isAuto() && !(cb->style()->top().isAuto() || cb->style()->bottom().isAuto())) {
2041                 ASSERT(cb->isRenderBlock());
2042                 RenderBlock* block = toRenderBlock(cb);
2043                 int oldHeight = block->height();
2044                 block->calcHeight();
2045                 int newHeight = block->calcContentBoxHeight(block->contentHeight());
2046                 block->setHeight(oldHeight);
2047                 return calcContentBoxHeight(height.calcValue(newHeight));
2048             }
2049             
2050             int availableHeight = isPositioned() ? containingBlockHeightForPositioned(cb) : toRenderBox(cb)->availableHeight();
2051
2052             // It is necessary to use the border-box to match WinIE's broken
2053             // box model.  This is essential for sizing inside
2054             // table cells using percentage heights.
2055             if (cb->isTableCell() && (cb->style()->height().isAuto() || cb->style()->height().isPercent())) {
2056                 // Don't let table cells squeeze percent-height replaced elements
2057                 // <http://bugs.webkit.org/show_bug.cgi?id=15359>
2058                 availableHeight = max(availableHeight, intrinsicSize().height());
2059                 return height.calcValue(availableHeight - (borderTop() + borderBottom()
2060                     + paddingTop() + paddingBottom()));
2061             }
2062
2063             return calcContentBoxHeight(height.calcValue(availableHeight));
2064         }
2065         default:
2066             return intrinsicSize().height();
2067     }
2068 }
2069
2070 int RenderBox::availableHeight() const
2071 {
2072     return availableHeightUsing(style()->height());
2073 }
2074
2075 int RenderBox::availableHeightUsing(const Length& h) const
2076 {
2077     if (h.isFixed())
2078         return calcContentBoxHeight(h.value());
2079
2080     if (isRenderView())
2081         return toRenderView(this)->frameView()->visibleHeight();
2082
2083     // We need to stop here, since we don't want to increase the height of the table
2084     // artificially.  We're going to rely on this cell getting expanded to some new
2085     // height, and then when we lay out again we'll use the calculation below.
2086     if (isTableCell() && (h.isAuto() || h.isPercent()))
2087         return overrideSize() - (borderLeft() + borderRight() + paddingLeft() + paddingRight());
2088
2089     if (h.isPercent())
2090        return calcContentBoxHeight(h.calcValue(containingBlock()->availableHeight()));
2091
2092     if (isRenderBlock() && isPositioned() && style()->height().isAuto() && !(style()->top().isAuto() || style()->bottom().isAuto())) {
2093         RenderBlock* block = const_cast<RenderBlock*>(static_cast<const RenderBlock*>(this));
2094         int oldHeight = block->height();
2095         block->calcHeight();
2096         int newHeight = block->calcContentBoxHeight(block->contentHeight());
2097         block->setHeight(oldHeight);
2098         return calcContentBoxHeight(newHeight);
2099     }
2100
2101     return containingBlock()->availableHeight();
2102 }
2103
2104 void RenderBox::calcVerticalMargins()
2105 {
2106     if (isTableCell()) {
2107         m_marginTop = 0;
2108         m_marginBottom = 0;
2109         return;
2110     }
2111
2112     // margins are calculated with respect to the _width_ of
2113     // the containing block (8.3)
2114     int cw = containingBlock()->contentWidth();
2115
2116     m_marginTop = style()->marginTop().calcMinValue(cw);
2117     m_marginBottom = style()->marginBottom().calcMinValue(cw);
2118 }
2119
2120 int RenderBox::staticX() const
2121 {
2122     return m_layer ? m_layer->staticX() : 0;
2123 }
2124
2125 int RenderBox::staticY() const
2126 {
2127     return m_layer ? m_layer->staticY() : 0;
2128 }
2129
2130 void RenderBox::setStaticX(int staticX)
2131 {
2132     ASSERT(isPositioned() || isRelPositioned());
2133     m_layer->setStaticX(staticX);
2134 }
2135
2136 void RenderBox::setStaticY(int staticY)
2137 {
2138     ASSERT(isPositioned() || isRelPositioned());
2139     
2140     if (staticY == m_layer->staticY())
2141         return;
2142     
2143     m_layer->setStaticY(staticY);
2144     setChildNeedsLayout(true, false);
2145 }
2146
2147 int RenderBox::containingBlockWidthForPositioned(const RenderObject* containingBlock) const
2148 {
2149     if (containingBlock->isRenderInline()) {
2150         ASSERT(containingBlock->isRelPositioned());
2151
2152         const RenderInline* flow = toRenderInline(containingBlock);
2153         InlineFlowBox* first = flow->firstLineBox();
2154         InlineFlowBox* last = flow->lastLineBox();
2155
2156         // If the containing block is empty, return a width of 0.
2157         if (!first || !last)
2158             return 0;
2159
2160         int fromLeft;
2161         int fromRight;
2162         if (containingBlock->style()->direction() == LTR) {
2163             fromLeft = first->xPos() + first->borderLeft();
2164             fromRight = last->xPos() + last->width() - last->borderRight();
2165         } else {
2166             fromRight = first->xPos() + first->width() - first->borderRight();
2167             fromLeft = last->xPos() + last->borderLeft();
2168         }
2169
2170         return max(0, (fromRight - fromLeft));
2171     }
2172
2173     const RenderBox* containingBlockBox = toRenderBox(containingBlock);
2174     return containingBlockBox->width() - containingBlockBox->borderLeft() - containingBlockBox->borderRight() - containingBlockBox->verticalScrollbarWidth();
2175 }
2176
2177 int RenderBox::containingBlockHeightForPositioned(const RenderObject* containingBlock) const
2178 {
2179     const RenderBox* containingBlockBox = toRenderBox(containingBlock);
2180     
2181     int heightResult;
2182     if (containingBlock->isRenderInline()) {
2183         ASSERT(containingBlock->isRelPositioned());
2184         heightResult = toRenderInline(containingBlock)->linesBoundingBox().height();
2185     } else
2186         heightResult = containingBlockBox->height();
2187     
2188     return heightResult - containingBlockBox->borderTop() - containingBlockBox->borderBottom();
2189 }
2190
2191 void RenderBox::calcAbsoluteHorizontal()
2192 {
2193     if (isReplaced()) {
2194         calcAbsoluteHorizontalReplaced();
2195         return;
2196     }
2197
2198     // QUESTIONS
2199     // FIXME 1: Which RenderObject's 'direction' property should used: the
2200     // containing block (cb) as the spec seems to imply, the parent (parent()) as
2201     // was previously done in calculating the static distances, or ourself, which
2202     // was also previously done for deciding what to override when you had
2203     // over-constrained margins?  Also note that the container block is used
2204     // in similar situations in other parts of the RenderBox class (see calcWidth()
2205     // and calcHorizontalMargins()). For now we are using the parent for quirks
2206     // mode and the containing block for strict mode.
2207
2208     // FIXME 2: Should we still deal with these the cases of 'left' or 'right' having
2209     // the type 'static' in determining whether to calculate the static distance?
2210     // NOTE: 'static' is not a legal value for 'left' or 'right' as of CSS 2.1.
2211
2212     // FIXME 3: Can perhaps optimize out cases when max-width/min-width are greater
2213     // than or less than the computed width().  Be careful of box-sizing and
2214     // percentage issues.
2215
2216     // The following is based off of the W3C Working Draft from April 11, 2006 of
2217     // CSS 2.1: Section 10.3.7 "Absolutely positioned, non-replaced elements"
2218     // <http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width>
2219     // (block-style-comments in this function and in calcAbsoluteHorizontalValues()
2220     // correspond to text from the spec)
2221
2222
2223     // We don't use containingBlock(), since we may be positioned by an enclosing
2224     // relative positioned inline.
2225     const RenderBox* containerBlock = toRenderBox(container());
2226     
2227     const int containerWidth = containingBlockWidthForPositioned(containerBlock);
2228
2229     // To match WinIE, in quirks mode use the parent's 'direction' property
2230     // instead of the the container block's.
2231     TextDirection containerDirection = (style()->htmlHacks()) ? parent()->style()->direction() : containerBlock->style()->direction();
2232
2233     const int bordersPlusPadding = borderLeft() + borderRight() + paddingLeft() + paddingRight();
2234     const Length marginLeft = style()->marginLeft();
2235     const Length marginRight = style()->marginRight();
2236     Length left = style()->left();
2237     Length right = style()->right();
2238
2239     /*---------------------------------------------------------------------------*\
2240      * For the purposes of this section and the next, the term "static position"
2241      * (of an element) refers, roughly, to the position an element would have had
2242      * in the normal flow. More precisely:
2243      *
2244      * * The static position for 'left' is the distance from the left edge of the
2245      *   containing block to the left margin edge of a hypothetical box that would
2246      *   have been the first box of the element if its 'position' property had
2247      *   been 'static' and 'float' had been 'none'. The value is negative if the
2248      *   hypothetical box is to the left of the containing block.
2249      * * The static position for 'right' is the distance from the right edge of the
2250      *   containing block to the right margin edge of the same hypothetical box as
2251      *   above. The value is positive if the hypothetical box is to the left of the
2252      *   containing block's edge.
2253      *
2254      * But rather than actually calculating the dimensions of that hypothetical box,
2255      * user agents are free to make a guess at its probable position.
2256      *
2257      * For the purposes of calculating the static position, the containing block of
2258      * fixed positioned elements is the initial containing block instead of the
2259      * viewport, and all scrollable boxes should be assumed to be scrolled to their
2260      * origin.
2261     \*---------------------------------------------------------------------------*/
2262
2263     // see FIXME 2
2264     // Calculate the static distance if needed.
2265     if (left.isAuto() && right.isAuto()) {
2266         if (containerDirection == LTR) {
2267             // 'staticX' should already have been set through layout of the parent.
2268             int staticPosition = staticX() - containerBlock->borderLeft();
2269             for (RenderBox* po = parentBox(); po && po != containerBlock; po = po->parentBox())
2270                 staticPosition += po->x();
2271             left.setValue(Fixed, staticPosition);
2272         } else {
2273             RenderBox* po = parentBox();
2274             // 'staticX' should already have been set through layout of the parent.
2275             int staticPosition = staticX() + containerWidth + containerBlock->borderRight() - po->width();
2276             for (; po && po != containerBlock; po = po->parentBox())
2277                 staticPosition -= po->x();
2278             right.setValue(Fixed, staticPosition);
2279         }
2280     }
2281
2282     // Calculate constraint equation values for 'width' case.
2283     int widthResult;
2284     int xResult;
2285     calcAbsoluteHorizontalValues(style()->width(), containerBlock, containerDirection,
2286                                  containerWidth, bordersPlusPadding,
2287                                  left, right, marginLeft, marginRight,
2288                                  widthResult, m_marginLeft, m_marginRight, xResult);
2289     setWidth(widthResult);
2290     setX(xResult);
2291
2292     // Calculate constraint equation values for 'max-width' case.
2293     if (!style()->maxWidth().isUndefined()) {
2294         int maxWidth;
2295         int maxMarginLeft;
2296         int maxMarginRight;
2297         int maxXPos;
2298
2299         calcAbsoluteHorizontalValues(style()->maxWidth(), containerBlock, containerDirection,
2300                                      containerWidth, bordersPlusPadding,
2301                                      left, right, marginLeft, marginRight,
2302                                      maxWidth, maxMarginLeft, maxMarginRight, maxXPos);
2303
2304         if (width() > maxWidth) {
2305             setWidth(maxWidth);
2306             m_marginLeft = maxMarginLeft;
2307             m_marginRight = maxMarginRight;
2308             m_frameRect.setX(maxXPos);
2309         }
2310     }
2311
2312     // Calculate constraint equation values for 'min-width' case.
2313     if (!style()->minWidth().isZero()) {
2314         int minWidth;
2315         int minMarginLeft;
2316         int minMarginRight;
2317         int minXPos;
2318
2319         calcAbsoluteHorizontalValues(style()->minWidth(), containerBlock, containerDirection,
2320                                      containerWidth, bordersPlusPadding,
2321                                      left, right, marginLeft, marginRight,
2322                                      minWidth, minMarginLeft, minMarginRight, minXPos);
2323
2324         if (width() < minWidth) {
2325             setWidth(minWidth);
2326             m_marginLeft = minMarginLeft;
2327             m_marginRight = minMarginRight;
2328             m_frameRect.setX(minXPos);
2329         }
2330     }
2331
2332     if (stretchesToMinIntrinsicWidth() && width() < minPrefWidth() - bordersPlusPadding) {
2333         calcAbsoluteHorizontalValues(Length(minPrefWidth() - bordersPlusPadding, Fixed), containerBlock, containerDirection,
2334                                      containerWidth, bordersPlusPadding,
2335                                      left, right, marginLeft, marginRight,
2336                                      widthResult, m_marginLeft, m_marginRight, xResult);
2337         setWidth(widthResult);
2338         setX(xResult);
2339     }
2340
2341     // Put width() into correct form.
2342     setWidth(width() + bordersPlusPadding);
2343 }
2344
2345 void RenderBox::calcAbsoluteHorizontalValues(Length width, const RenderBox* containerBlock, TextDirection containerDirection,
2346                                              const int containerWidth, const int bordersPlusPadding,
2347                                              const Length left, const Length right, const Length marginLeft, const Length marginRight,
2348                                              int& widthValue, int& marginLeftValue, int& marginRightValue, int& xPos)
2349 {
2350     // 'left' and 'right' cannot both be 'auto' because one would of been
2351     // converted to the static postion already
2352     ASSERT(!(left.isAuto() && right.isAuto()));
2353
2354     int leftValue = 0;
2355
2356     bool widthIsAuto = width.isIntrinsicOrAuto();
2357     bool leftIsAuto = left.isAuto();
2358     bool rightIsAuto = right.isAuto();
2359
2360     if (!leftIsAuto && !widthIsAuto && !rightIsAuto) {
2361         /*-----------------------------------------------------------------------*\
2362          * If none of the three is 'auto': If both 'margin-left' and 'margin-
2363          * right' are 'auto', solve the equation under the extra constraint that
2364          * the two margins get equal values, unless this would make them negative,
2365          * in which case when direction of the containing block is 'ltr' ('rtl'),
2366          * set 'margin-left' ('margin-right') to zero and solve for 'margin-right'
2367          * ('margin-left'). If one of 'margin-left' or 'margin-right' is 'auto',
2368          * solve the equation for that value. If the values are over-constrained,
2369          * ignore the value for 'left' (in case the 'direction' property of the
2370          * containing block is 'rtl') or 'right' (in case 'direction' is 'ltr')
2371          * and solve for that value.
2372         \*-----------------------------------------------------------------------*/
2373         // NOTE:  It is not necessary to solve for 'right' in the over constrained
2374         // case because the value is not used for any further calculations.
2375
2376         leftValue = left.calcValue(containerWidth);
2377         widthValue = calcContentBoxWidth(width.calcValue(containerWidth));
2378
2379         const int availableSpace = containerWidth - (leftValue + widthValue + right.calcValue(containerWidth) + bordersPlusPadding);
2380
2381         // Margins are now the only unknown
2382         if (marginLeft.isAuto() && marginRight.isAuto()) {
2383             // Both margins auto, solve for equality
2384             if (availableSpace >= 0) {
2385                 marginLeftValue = availableSpace / 2; // split the diference
2386                 marginRightValue = availableSpace - marginLeftValue;  // account for odd valued differences
2387             } else {
2388                 // see FIXME 1
2389                 if (containerDirection == LTR) {
2390                     marginLeftValue = 0;
2391                     marginRightValue = availableSpace; // will be negative
2392                 } else {
2393                     marginLeftValue = availableSpace; // will be negative
2394                     marginRightValue = 0;
2395                 }
2396             }
2397         } else if (marginLeft.isAuto()) {
2398             // Solve for left margin
2399             marginRightValue = marginRight.calcValue(containerWidth);
2400             marginLeftValue = availableSpace - marginRightValue;
2401         } else if (marginRight.isAuto()) {
2402             // Solve for right margin
2403             marginLeftValue = marginLeft.calcValue(containerWidth);
2404             marginRightValue = availableSpace - marginLeftValue;
2405         } else {
2406             // Over-constrained, solve for left if direction is RTL
2407             marginLeftValue = marginLeft.calcValue(containerWidth);
2408             marginRightValue = marginRight.calcValue(containerWidth);
2409
2410             // see FIXME 1 -- used to be "this->style()->direction()"
2411             if (containerDirection == RTL)
2412                 leftValue = (availableSpace + leftValue) - marginLeftValue - marginRightValue;
2413         }
2414     } else {
2415         /*--------------------------------------------------------------------*\
2416          * Otherwise, set 'auto' values for 'margin-left' and 'margin-right'
2417          * to 0, and pick the one of the following six rules that applies.
2418          *
2419          * 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the
2420          *    width is shrink-to-fit. Then solve for 'left'
2421          *
2422          *              OMIT RULE 2 AS IT SHOULD NEVER BE HIT
2423          * ------------------------------------------------------------------
2424          * 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if
2425          *    the 'direction' property of the containing block is 'ltr' set
2426          *    'left' to the static position, otherwise set 'right' to the
2427          *    static position. Then solve for 'left' (if 'direction is 'rtl')
2428          *    or 'right' (if 'direction' is 'ltr').
2429          * ------------------------------------------------------------------
2430          *
2431          * 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the
2432          *    width is shrink-to-fit . Then solve for 'right'
2433          * 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve
2434          *    for 'left'
2435          * 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve
2436          *    for 'width'
2437          * 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve
2438          *    for 'right'
2439          *
2440          * Calculation of the shrink-to-fit width is similar to calculating the
2441          * width of a table cell using the automatic table layout algorithm.
2442          * Roughly: calculate the preferred width by formatting the content
2443          * without breaking lines other than where explicit line breaks occur,
2444          * and also calculate the preferred minimum width, e.g., by trying all
2445          * possible line breaks. CSS 2.1 does not define the exact algorithm.
2446          * Thirdly, calculate the available width: this is found by solving
2447          * for 'width' after setting 'left' (in case 1) or 'right' (in case 3)
2448          * to 0.
2449          *
2450          * Then the shrink-to-fit width is:
2451          * min(max(preferred minimum width, available width), preferred width).
2452         \*--------------------------------------------------------------------*/
2453         // NOTE: For rules 3 and 6 it is not necessary to solve for 'right'
2454         // because the value is not used for any further calculations.
2455
2456         // Calculate margins, 'auto' margins are ignored.
2457         marginLeftValue = marginLeft.calcMinValue(containerWidth);
2458         marginRightValue = marginRight.calcMinValue(containerWidth);
2459
2460         const int availableSpace = containerWidth - (marginLeftValue + marginRightValue + bordersPlusPadding);
2461
2462         // FIXME: Is there a faster way to find the correct case?
2463         // Use rule/case that applies.
2464         if (leftIsAuto && widthIsAuto && !rightIsAuto) {
2465             // RULE 1: (use shrink-to-fit for width, and solve of left)
2466             int rightValue = right.calcValue(containerWidth);
2467
2468             // FIXME: would it be better to have shrink-to-fit in one step?
2469             int preferredWidth = maxPrefWidth() - bordersPlusPadding;
2470             int preferredMinWidth = minPrefWidth() - bordersPlusPadding;
2471             int availableWidth = availableSpace - rightValue;
2472             widthValue = min(max(preferredMinWidth, availableWidth), preferredWidth);
2473             leftValue = availableSpace - (widthValue + rightValue);
2474         } else if (!leftIsAuto && widthIsAuto && rightIsAuto) {
2475             // RULE 3: (use shrink-to-fit for width, and no need solve of right)
2476             leftValue = left.calcValue(containerWidth);
2477
2478             // FIXME: would it be better to have shrink-to-fit in one step?
2479             int preferredWidth = maxPrefWidth() - bordersPlusPadding;
2480             int preferredMinWidth = minPrefWidth() - bordersPlusPadding;
2481             int availableWidth = availableSpace - leftValue;
2482             widthValue = min(max(preferredMinWidth, availableWidth), preferredWidth);
2483         } else if (leftIsAuto && !width.isAuto() && !rightIsAuto) {
2484             // RULE 4: (solve for left)
2485             widthValue = calcContentBoxWidth(width.calcValue(containerWidth));
2486             leftValue = availableSpace - (widthValue + right.calcValue(containerWidth));
2487         } else if (!leftIsAuto && widthIsAuto && !rightIsAuto) {
2488             // RULE 5: (solve for width)
2489             leftValue = left.calcValue(containerWidth);
2490             widthValue = availableSpace - (leftValue + right.calcValue(containerWidth));
2491         } else if (!leftIsAuto&& !widthIsAuto && rightIsAuto) {
2492             // RULE 6: (no need solve for right)
2493             leftValue = left.calcValue(containerWidth);
2494             widthValue = calcContentBoxWidth(width.calcValue(containerWidth));
2495         }
2496     }
2497
2498     // Use computed values to calculate the horizontal position.
2499
2500     // FIXME: This hack is needed to calculate the xPos for a 'rtl' relatively
2501     // positioned, inline because right now, it is using the xPos
2502     // of the first line box when really it should use the last line box.  When
2503     // this is fixed elsewhere, this block should be removed.
2504     if (containerBlock->isInline() && containerBlock->style()->direction() == RTL) {
2505         const RenderInline* flow = toRenderInline(containerBlock);
2506         InlineFlowBox* firstLine = flow->firstLineBox();
2507         InlineFlowBox* lastLine = flow->lastLineBox();
2508         if (firstLine && lastLine && firstLine != lastLine) {
2509             xPos = leftValue + marginLeftValue + lastLine->borderLeft() + (lastLine->xPos() - firstLine->xPos());
2510             return;
2511         }
2512     }
2513
2514     xPos = leftValue + marginLeftValue + containerBlock->borderLeft();
2515 }
2516
2517 void RenderBox::calcAbsoluteVertical()
2518 {
2519     if (isReplaced()) {
2520         calcAbsoluteVerticalReplaced();
2521         return;
2522     }
2523
2524     // The following is based off of the W3C Working Draft from April 11, 2006 of
2525     // CSS 2.1: Section 10.6.4 "Absolutely positioned, non-replaced elements"
2526     // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-non-replaced-height>
2527     // (block-style-comments in this function and in calcAbsoluteVerticalValues()
2528     // correspond to text from the spec)
2529
2530
2531     // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
2532     const RenderBox* containerBlock = toRenderBox(container());
2533
2534     const int containerHeight = containingBlockHeightForPositioned(containerBlock);
2535
2536     const int bordersPlusPadding = borderTop() + borderBottom() + paddingTop() + paddingBottom();
2537     const Length marginTop = style()->marginTop();
2538     const Length marginBottom = style()->marginBottom();
2539     Length top = style()->top();
2540     Length bottom = style()->bottom();
2541
2542     /*---------------------------------------------------------------------------*\
2543      * For the purposes of this section and the next, the term "static position"
2544      * (of an element) refers, roughly, to the position an element would have had
2545      * in the normal flow. More precisely, the static position for 'top' is the
2546      * distance from the top edge of the containing block to the top margin edge
2547      * of a hypothetical box that would have been the first box of the element if
2548      * its 'position' property had been 'static' and 'float' had been 'none'. The
2549      * value is negative if the hypothetical box is above the containing block.
2550      *
2551      * But rather than actually calculating the dimensions of that hypothetical
2552      * box, user agents are free to make a guess at its probable position.
2553      *
2554      * For the purposes of calculating the static position, the containing block
2555      * of fixed positioned elements is the initial containing block instead of
2556      * the viewport.
2557     \*---------------------------------------------------------------------------*/
2558
2559     // see FIXME 2
2560     // Calculate the static distance if needed.
2561     if (top.isAuto() && bottom.isAuto()) {
2562         // staticY should already have been set through layout of the parent()
2563         int staticTop = staticY() - containerBlock->borderTop();
2564         for (RenderBox* po = parentBox(); po && po != containerBlock; po = po->parentBox()) {
2565             if (!po->isTableRow())
2566                 staticTop += po->y();
2567         }
2568         top.setValue(Fixed, staticTop);
2569     }
2570
2571
2572     int h; // Needed to compute overflow.
2573     int y;
2574
2575     // Calculate constraint equation values for 'height' case.
2576     calcAbsoluteVerticalValues(style()->height(), containerBlock, containerHeight, bordersPlusPadding,
2577                                top, bottom, marginTop, marginBottom,
2578                                h, m_marginTop, m_marginBottom, y);
2579     setY(y);
2580
2581     // Avoid doing any work in the common case (where the values of min-height and max-height are their defaults).
2582     // see FIXME 3
2583
2584     // Calculate constraint equation values for 'max-height' case.
2585     if (!style()->maxHeight().isUndefined()) {
2586         int maxHeight;
2587         int maxMarginTop;
2588         int maxMarginBottom;
2589         int maxYPos;
2590
2591         calcAbsoluteVerticalValues(style()->maxHeight(), containerBlock, containerHeight, bordersPlusPadding,
2592                                    top, bottom, marginTop, marginBottom,
2593                                    maxHeight, maxMarginTop, maxMarginBottom, maxYPos);
2594
2595         if (h > maxHeight) {
2596             h = maxHeight;
2597             m_marginTop = maxMarginTop;
2598             m_marginBottom = maxMarginBottom;
2599             m_frameRect.setY(maxYPos);
2600         }
2601     }
2602
2603     // Calculate constraint equation values for 'min-height' case.
2604     if (!style()->minHeight().isZero()) {
2605         int minHeight;
2606         int minMarginTop;
2607         int minMarginBottom;
2608         int minYPos;
2609
2610         calcAbsoluteVerticalValues(style()->minHeight(), containerBlock, containerHeight, bordersPlusPadding,
2611                                    top, bottom, marginTop, marginBottom,
2612                                    minHeight, minMarginTop, minMarginBottom, minYPos);
2613
2614         if (h < minHeight) {
2615             h = minHeight;
2616             m_marginTop = minMarginTop;
2617             m_marginBottom = minMarginBottom;
2618             m_frameRect.setY(minYPos);
2619         }
2620     }
2621
2622     // Set final height value.
2623     setHeight(h + bordersPlusPadding);
2624 }
2625
2626 void RenderBox::calcAbsoluteVerticalValues(Length h, const RenderBox* containerBlock,
2627                                            const int containerHeight, const int bordersPlusPadding,
2628                                            const Length top, const Length bottom, const Length marginTop, const Length marginBottom,
2629                                            int& heightValue, int& marginTopValue, int& marginBottomValue, int& yPos)
2630 {
2631     // 'top' and 'bottom' cannot both be 'auto' because 'top would of been
2632     // converted to the static position in calcAbsoluteVertical()
2633     ASSERT(!(top.isAuto() && bottom.isAuto()));
2634
2635     int contentHeight = height() - bordersPlusPadding;
2636
2637     int topValue = 0;
2638
2639     bool heightIsAuto = h.isAuto();
2640     bool topIsAuto = top.isAuto();
2641     bool bottomIsAuto = bottom.isAuto();
2642
2643     // Height is never unsolved for tables.
2644     if (isTable()) {
2645         h.setValue(Fixed, contentHeight);
2646         heightIsAuto = false;
2647     }
2648
2649     if (!topIsAuto && !heightIsAuto && !bottomIsAuto) {
2650         /*-----------------------------------------------------------------------*\
2651          * If none of the three are 'auto': If both 'margin-top' and 'margin-
2652          * bottom' are 'auto', solve the equation under the extra constraint that
2653          * the two margins get equal values. If one of 'margin-top' or 'margin-
2654          * bottom' is 'auto', solve the equation for that value. If the values
2655          * are over-constrained, ignore the value for 'bottom' and solve for that
2656          * value.
2657         \*-----------------------------------------------------------------------*/
2658         // NOTE:  It is not necessary to solve for 'bottom' in the over constrained
2659         // case because the value is not used for any further calculations.
2660
2661         heightValue = calcContentBoxHeight(h.calcValue(containerHeight));
2662         topValue = top.calcValue(containerHeight);
2663
2664         const int availableSpace = containerHeight - (topValue + heightValue + bottom.calcValue(containerHeight) + bordersPlusPadding);
2665
2666         // Margins are now the only unknown
2667         if (marginTop.isAuto() && marginBottom.isAuto()) {
2668             // Both margins auto, solve for equality
2669             // NOTE: This may result in negative values.
2670             marginTopValue = availableSpace / 2; // split the diference
2671             marginBottomValue = availableSpace - marginTopValue; // account for odd valued differences
2672         } else if (marginTop.isAuto()) {
2673             // Solve for top margin
2674             marginBottomValue = marginBottom.calcValue(containerHeight);
2675             marginTopValue = availableSpace - marginBottomValue;
2676         } else if (marginBottom.isAuto()) {
2677             // Solve for bottom margin
2678             marginTopValue = marginTop.calcValue(containerHeight);
2679             marginBottomValue = availableSpace - marginTopValue;
2680         } else {
2681             // Over-constrained, (no need solve for bottom)
2682             marginTopValue = marginTop.calcValue(containerHeight);
2683             marginBottomValue = marginBottom.calcValue(containerHeight);
2684         }
2685     } else {
2686         /*--------------------------------------------------------------------*\
2687          * Otherwise, set 'auto' values for 'margin-top' and 'margin-bottom'
2688          * to 0, and pick the one of the following six rules that applies.
2689          *
2690          * 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then
2691          *    the height is based on the content, and solve for 'top'.
2692          *
2693          *              OMIT RULE 2 AS IT SHOULD NEVER BE HIT
2694          * ------------------------------------------------------------------
2695          * 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then
2696          *    set 'top' to the static position, and solve for 'bottom'.
2697          * ------------------------------------------------------------------
2698          *
2699          * 3. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then
2700          *    the height is based on the content, and solve for 'bottom'.
2701          * 4. 'top' is 'auto', 'height' and 'bottom' are not 'auto', and
2702          *    solve for 'top'.
2703          * 5. 'height' is 'auto', 'top' and 'bottom' are not 'auto', and
2704          *    solve for 'height'.
2705          * 6. 'bottom' is 'auto', 'top' and 'height' are not 'auto', and
2706          *    solve for 'bottom'.
2707         \*--------------------------------------------------------------------*/
2708         // NOTE: For rules 3 and 6 it is not necessary to solve for 'bottom'
2709         // because the value is not used for any further calculations.
2710
2711         // Calculate margins, 'auto' margins are ignored.
2712         marginTopValue = marginTop.calcMinValue(containerHeight);
2713         marginBottomValue = marginBottom.calcMinValue(containerHeight);
2714
2715         const int availableSpace = containerHeight - (marginTopValue + marginBottomValue + bordersPlusPadding);
2716
2717         // Use rule/case that applies.
2718         if (topIsAuto && heightIsAuto && !bottomIsAuto) {
2719             // RULE 1: (height is content based, solve of top)
2720             heightValue = contentHeight;
2721             topValue = availableSpace - (heightValue + bottom.calcValue(containerHeight));
2722         } else if (!topIsAuto && heightIsAuto && bottomIsAuto) {
2723             // RULE 3: (height is content based, no need solve of bottom)
2724             topValue = top.calcValue(containerHeight);
2725             heightValue = contentHeight;
2726         } else if (topIsAuto && !heightIsAuto && !bottomIsAuto) {
2727             // RULE 4: (solve of top)
2728             heightValue = calcContentBoxHeight(h.calcValue(containerHeight));
2729             topValue = availableSpace - (heightValue + bottom.calcValue(containerHeight));
2730         } else if (!topIsAuto && heightIsAuto && !bottomIsAuto) {
2731             // RULE 5: (solve of height)
2732             topValue = top.calcValue(containerHeight);
2733             heightValue = max(0, availableSpace - (topValue + bottom.calcValue(containerHeight)));
2734         } else if (!topIsAuto && !heightIsAuto && bottomIsAuto) {
2735             // RULE 6: (no need solve of bottom)
2736             heightValue = calcContentBoxHeight(h.calcValue(containerHeight));
2737             topValue = top.calcValue(containerHeight);
2738         }
2739     }
2740
2741     // Use computed values to calculate the vertical position.
2742     yPos = topValue + marginTopValue + containerBlock->borderTop();
2743 }
2744
2745 void RenderBox::calcAbsoluteHorizontalReplaced()
2746 {
2747     // The following is based off of the W3C Working Draft from April 11, 2006 of
2748     // CSS 2.1: Section 10.3.8 "Absolutly positioned, replaced elements"
2749     // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-width>
2750     // (block-style-comments in this function correspond to text from the spec and
2751     // the numbers correspond to numbers in spec)
2752
2753     // We don't use containingBlock(), since we may be positioned by an enclosing
2754     // relative positioned inline.
2755     const RenderBox* containerBlock = toRenderBox(container());
2756
2757     const int containerWidth = containingBlockWidthForPositioned(containerBlock);
2758
2759     // To match WinIE, in quirks mode use the parent's 'direction' property
2760     // instead of the the container block's.
2761     TextDirection containerDirection = (style()->htmlHacks()) ? parent()->style()->direction() : containerBlock->style()->direction();
2762
2763     // Variables to solve.
2764     Length left = style()->left();
2765     Length right = style()->right();
2766     Length marginLeft = style()->marginLeft();
2767     Length marginRight = style()->marginRight();
2768
2769
2770     /*-----------------------------------------------------------------------*\
2771      * 1. The used value of 'width' is determined as for inline replaced
2772      *    elements.
2773     \*-----------------------------------------------------------------------*/
2774     // NOTE: This value of width is FINAL in that the min/max width calculations
2775     // are dealt with in calcReplacedWidth().  This means that the steps to produce
2776     // correct max/min in the non-replaced version, are not necessary.
2777     setWidth(calcReplacedWidth() + borderLeft() + borderRight() + paddingLeft() + paddingRight());
2778     const int availableSpace = containerWidth - width();
2779
2780     /*-----------------------------------------------------------------------*\
2781      * 2. If both 'left' and 'right' have the value 'auto', then if 'direction'
2782      *    of the containing block is 'ltr', set 'left' to the static position;
2783      *    else if 'direction' is 'rtl', set 'right' to the static position.
2784     \*-----------------------------------------------------------------------*/
2785     // see FIXME 2
2786     if (left.isAuto() && right.isAuto()) {
2787         // see FIXME 1
2788         if (containerDirection == LTR) {
2789             // 'staticX' should already have been set through layout of the parent.
2790             int staticPosition = staticX() - containerBlock->borderLeft();
2791             for (RenderBox* po = parentBox(); po && po != containerBlock; po = po->parentBox())
2792                 staticPosition += po->x();
2793             left.setValue(Fixed, staticPosition);
2794         } else {
2795             RenderBox* po = parentBox();
2796             // 'staticX' should already have been set through layout of the parent.
2797             int staticPosition = staticX() + containerWidth + containerBlock->borderRight() - po->width();
2798             for (; po && po != containerBlock; po = po->parentBox())
2799                 staticPosition -= po->x();
2800             right.setValue(Fixed, staticPosition);
2801         }
2802     }
2803
2804     /*-----------------------------------------------------------------------*\
2805      * 3. If 'left' or 'right' are 'auto', replace any 'auto' on 'margin-left'
2806      *    or 'margin-right' with '0'.
2807     \*-----------------------------------------------------------------------*/
2808     if (left.isAuto() || right.isAuto()) {
2809         if (marginLeft.isAuto())
2810             marginLeft.setValue(Fixed, 0);
2811         if (marginRight.isAuto())
2812             marginRight.setValue(Fixed, 0);
2813     }
2814
2815     /*-----------------------------------------------------------------------*\
2816      * 4. If at this point both 'margin-left' and 'margin-right' are still
2817      *    'auto', solve the equation under the extra constraint that the two
2818      *    margins must get equal values, unless this would make them negative,
2819      *    in which case when the direction of the containing block is 'ltr'
2820      *    ('rtl'), set 'margin-left' ('margin-right') to zero and solve for
2821      *    'margin-right' ('margin-left').
2822     \*-----------------------------------------------------------------------*/
2823     int leftValue = 0;
2824     int rightValue = 0;
2825
2826     if (marginLeft.isAuto() && marginRight.isAuto()) {
2827         // 'left' and 'right' cannot be 'auto' due to step 3
2828         ASSERT(!(left.isAuto() && right.isAuto()));
2829
2830         leftValue = left.calcValue(containerWidth);
2831         rightValue = right.calcValue(containerWidth);
2832
2833         int difference = availableSpace - (leftValue + rightValue);
2834         if (difference > 0) {
2835             m_marginLeft = difference / 2; // split the diference
2836             m_marginRight = difference - m_marginLeft; // account for odd valued differences
2837         } else {
2838             // see FIXME 1
2839             if (containerDirection == LTR) {
2840                 m_marginLeft = 0;
2841                 m_marginRight = difference;  // will be negative
2842             } else {
2843                 m_marginLeft = difference;  // will be negative
2844                 m_marginRight = 0;
2845             }
2846         }
2847
2848     /*-----------------------------------------------------------------------*\
2849      * 5. If at this point there is an 'auto' left, solve the equation for
2850      *    that value.
2851     \*-----------------------------------------------------------------------*/
2852     } else if (left.isAuto()) {
2853         m_marginLeft = marginLeft.calcValue(containerWidth);
2854         m_marginRight = marginRight.calcValue(containerWidth);
2855         rightValue = right.calcValue(containerWidth);
2856
2857         // Solve for 'left'
2858         leftValue = availableSpace - (rightValue + m_marginLeft + m_marginRight);
2859     } else if (right.isAuto()) {
2860         m_marginLeft = marginLeft.calcValue(containerWidth);
2861         m_marginRight = marginRight.calcValue(containerWidth);
2862         leftValue = left.calcValue(containerWidth);
2863
2864         // Solve for 'right'
2865         rightValue = availableSpace - (leftValue + m_marginLeft + m_marginRight);
2866     } else if (marginLeft.isAuto()) {
2867         m_marginRight = marginRight.calcValue(containerWidth);
2868         leftValue = left.calcValue(containerWidth);
2869         rightValue = right.calcValue(containerWidth);
2870
2871         // Solve for 'margin-left'
2872         m_marginLeft = availableSpace - (leftValue + rightValue + m_marginRight);
2873     } else if (marginRight.isAuto()) {
2874         m_marginLeft = marginLeft.calcValue(containerWidth);
2875         leftValue = left.calcValue(containerWidth);
2876         rightValue = right.calcValue(containerWidth);
2877
2878         // Solve for 'margin-right'
2879         m_marginRight = availableSpace - (leftValue + rightValue + m_marginLeft);
2880     } else {
2881         // Nothing is 'auto', just calculate the values.
2882         m_marginLeft = marginLeft.calcValue(containerWidth);
2883         m_marginRight = marginRight.calcValue(containerWidth);
2884         rightValue = right.calcValue(containerWidth);
2885         leftValue = left.calcValue(containerWidth);
2886     }
2887
2888     /*-----------------------------------------------------------------------*\
2889      * 6. If at this point the values are over-constrained, ignore the value
2890      *    for either 'left' (in case the 'direction' property of the
2891      *    containing block is 'rtl') or 'right' (in case 'direction' is
2892      *    'ltr') and solve for that value.
2893     \*-----------------------------------------------------------------------*/
2894     // NOTE:  It is not necessary to solve for 'right' when the direction is
2895     // LTR because the value is not used.
2896     int totalWidth = width() + leftValue + rightValue +  m_marginLeft + m_marginRight;
2897     if (totalWidth > containerWidth && (containerDirection == RTL))
2898         leftValue = containerWidth - (totalWidth - leftValue);
2899
2900     // Use computed values to calculate the horizontal position.
2901
2902     // FIXME: This hack is needed to calculate the xPos for a 'rtl' relatively
2903     // positioned, inline containing block because right now, it is using the xPos
2904     // of the first line box when really it should use the last line box.  When
2905     // this is fixed elsewhere, this block should be removed.
2906     if (containerBlock->isInline() && containerBlock->style()->direction() == RTL) {
2907         const RenderInline* flow = toRenderInline(containerBlock);
2908         InlineFlowBox* firstLine = flow->firstLineBox();
2909         InlineFlowBox* lastLine = flow->lastLineBox();
2910         if (firstLine && lastLine && firstLine != lastLine) {
2911             m_frameRect.setX(leftValue + m_marginLeft + lastLine->borderLeft() + (lastLine->xPos() - firstLine->xPos()));
2912             return;
2913         }
2914     }
2915
2916     m_frameRect.setX(leftValue + m_marginLeft + containerBlock->borderLeft());
2917 }
2918
2919 void RenderBox::calcAbsoluteVerticalReplaced()
2920 {
2921     // The following is based off of the W3C Working Draft from April 11, 2006 of
2922     // CSS 2.1: Section 10.6.5 "Absolutly positioned, replaced elements"
2923     // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-height>
2924     // (block-style-comments in this function correspond to text from the spec and
2925     // the numbers correspond to numbers in spec)
2926
2927     // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
2928     const RenderBox* containerBlock = toRenderBox(container());
2929
2930     const int containerHeight = containingBlockHeightForPositioned(containerBlock);
2931
2932     // Variables to solve.
2933     Length top = style()->top();
2934     Length bottom = style()->bottom();
2935     Length marginTop = style()->marginTop();
2936     Length marginBottom = style()->marginBottom();
2937
2938
2939     /*-----------------------------------------------------------------------*\
2940      * 1. The used value of 'height' is determined as for inline replaced
2941      *    elements.
2942     \*-----------------------------------------------------------------------*/
2943     // NOTE: This value of height is FINAL in that the min/max height calculations
2944     // are dealt with in calcReplacedHeight().  This means that the steps to produce
2945     // correct max/min in the non-replaced version, are not necessary.
2946     setHeight(calcReplacedHeight() + borderTop() + borderBottom() + paddingTop() + paddingBottom());
2947     const int availableSpace = containerHeight - height();
2948
2949     /*-----------------------------------------------------------------------*\
2950      * 2. If both 'top' and 'bottom' have the value 'auto', replace 'top'
2951      *    with the element's static position.
2952     \*-----------------------------------------------------------------------*/
2953     // see FIXME 2
2954     if (top.isAuto() && bottom.isAuto()) {
2955         // staticY should already have been set through layout of the parent().
2956         int staticTop = staticY() - containerBlock->borderTop();
2957         for (RenderBox* po = parentBox(); po && po != containerBlock; po = po->parentBox()) {
2958             if (!po->isTableRow())
2959                 staticTop += po->y();
2960         }
2961         top.setValue(Fixed, staticTop);
2962     }
2963
2964     /*-----------------------------------------------------------------------*\
2965      * 3. If 'bottom' is 'auto', replace any 'auto' on 'margin-top' or
2966      *    'margin-bottom' with '0'.
2967     \*-----------------------------------------------------------------------*/
2968     // FIXME: The spec. says that this step should only be taken when bottom is
2969     // auto, but if only top is auto, this makes step 4 impossible.
2970     if (top.isAuto() || bottom.isAuto()) {
2971         if (marginTop.isAuto())
2972             marginTop.setValue(Fixed, 0);
2973         if (marginBottom.isAuto())
2974             marginBottom.setValue(Fixed, 0);
2975     }
2976
2977     /*-----------------------------------------------------------------------*\
2978      * 4. If at this point both 'margin-top' and 'margin-bottom' are still
2979      *    'auto', solve the equation under the extra constraint that the two
2980      *    margins must get equal values.
2981     \*-----------------------------------------------------------------------*/
2982     int topValue = 0;
2983     int bottomValue = 0;
2984
2985     if (marginTop.isAuto() && marginBottom.isAuto()) {
2986         // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combinded.
2987         ASSERT(!(top.isAuto() || bottom.isAuto()));
2988
2989         topValue = top.calcValue(containerHeight);
2990         bottomValue = bottom.calcValue(containerHeight);
2991
2992         int difference = availableSpace - (topValue + bottomValue);
2993         // NOTE: This may result in negative values.
2994         m_marginTop =  difference / 2; // split the difference
2995         m_marginBottom = difference - m_marginTop; // account for odd valued differences
2996
2997     /*-----------------------------------------------------------------------*\
2998      * 5. If at this point there is only one 'auto' left, solve the equation
2999      *    for that value.
3000     \*-----------------------------------------------------------------------*/
3001     } else if (top.isAuto()) {
3002         m_marginTop = marginTop.calcValue(containerHeight);
3003         m_marginBottom = marginBottom.calcValue(containerHeight);
3004         bottomValue = bottom.calcValue(containerHeight);
3005
3006         // Solve for 'top'
3007         topValue = availableSpace - (bottomValue + m_marginTop + m_marginBottom);
3008     } else if (bottom.isAuto()) {
3009         m_marginTop = marginTop.calcValue(containerHeight);
3010         m_marginBottom = marginBottom.calcValue(containerHeight);
3011         topValue = top.calcValue(containerHeight);
3012
3013         // Solve for 'bottom'
3014         // NOTE: It is not necessary to solve for 'bottom' because we don't ever
3015         // use the value.
3016     } else if (marginTop.isAuto()) {
3017         m_marginBottom = marginBottom.calcValue(containerHeight);
3018         topValue = top.calcValue(containerHeight);
3019         bottomValue = bottom.calcValue(containerHeight);
3020
3021         // Solve for 'margin-top'
3022         m_marginTop = availableSpace - (topValue + bottomValue + m_marginBottom);
3023     } else if (marginBottom.isAuto()) {
3024         m_marginTop = marginTop.calcValue(containerHeight);
3025         topValue = top.calcValue(containerHeight);
3026         bottomValue = bottom.calcValue(containerHeight);
3027
3028         // Solve for 'margin-bottom'
3029         m_marginBottom = availableSpace - (topValue + bottomValue + m_marginTop);
3030     } else {
3031         // Nothing is 'auto', just calculate the values.
3032         m_marginTop = marginTop.calcValue(containerHeight);
3033         m_marginBottom = marginBottom.calcValue(containerHeight);
3034         topValue = top.calcValue(containerHeight);
3035         // NOTE: It is not necessary to solve for 'bottom' because we don't ever
3036         // use the value.
3037      }
3038
3039     /*-----------------------------------------------------------------------*\
3040      * 6. If at this point the values are over-constrained, ignore the value
3041      *    for 'bottom' and solve for that value.
3042     \*-----------------------------------------------------------------------*/
3043     // NOTE: It is not necessary to do this step because we don't end up using
3044     // the value of 'bottom' regardless of whether the values are over-constrained
3045     // or not.
3046
3047     // Use computed values to calculate the vertical position.
3048     m_frameRect.setY(topValue + m_marginTop + containerBlock->borderTop());
3049 }
3050
3051 IntRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, int* extraWidthToEndOfLine)
3052 {
3053     // VisiblePositions at offsets inside containers either a) refer to the positions before/after
3054     // those containers (tables and select elements) or b) refer to the position inside an empty block.
3055     // They never refer to children.
3056     // FIXME: Paint the carets inside empty blocks differently than the carets before/after elements.
3057
3058     // FIXME: What about border and padding?
3059     const int caretWidth = 1;
3060     IntRect rect(x(), y(), caretWidth, height());
3061     TextDirection direction = box ? box->direction() : style()->direction();
3062
3063     if ((!caretOffset) ^ (direction == LTR))
3064         rect.move(IntSize(width() - caretWidth, 0));
3065
3066     if (box) {
3067         RootInlineBox* rootBox = box->root();
3068         int top = rootBox->topOverflow();
3069         rect.setY(top);
3070         rect.setHeight(rootBox->bottomOverflow() - top);
3071     }
3072
3073     // If height of box is smaller than font height, use the latter one,
3074     // otherwise the caret might become invisible.
3075     //
3076     // Also, if the box is not a replaced element, always use the font height.
3077     // This prevents the "big caret" bug described in:
3078     // <rdar://problem/3777804> Deleting all content in a document can result in giant tall-as-window insertion point
3079     //
3080     // FIXME: ignoring :first-line, missing good reason to take care of
3081     int fontHeight = style()->font().height();
3082     if (fontHeight > rect.height() || !isReplaced() && !isTable())
3083         rect.setHeight(fontHeight);
3084
3085     if (extraWidthToEndOfLine)
3086         *extraWidthToEndOfLine = x() + width() - rect.right();
3087
3088     // Move to local coords
3089     rect.move(-x(), -y());
3090     return rect;
3091 }
3092
3093 int RenderBox::lowestPosition(bool /*includeOverflowInterior*/, bool includeSelf) const
3094 {
3095     if (!includeSelf || !width())
3096         return 0;
3097     int bottom = height();
3098     if (isRelPositioned())
3099         bottom += relativePositionOffsetY();
3100     return bottom;
3101 }
3102
3103 int RenderBox::rightmostPosition(bool /*includeOverflowInterior*/, bool includeSelf) const
3104 {
3105     if (!includeSelf || !height())
3106         return 0;
3107     int right = width();
3108     if (isRelPositioned())
3109         right += relativePositionOffsetX();
3110     return right;
3111 }
3112
3113 int RenderBox::leftmostPosition(bool /*includeOverflowInterior*/, bool includeSelf) const
3114 {
3115     if (!includeSelf || !height())
3116         return width();
3117     int left = 0;
3118     if (isRelPositioned())
3119         left += relativePositionOffsetX();
3120     return left;
3121 }
3122
3123 #if ENABLE(SVG)
3124
3125 TransformationMatrix RenderBox::localTransform() const
3126 {
3127     return TransformationMatrix(1, 0, 0, 1, x(), y());
3128 }
3129
3130 #endif
3131
3132 } // namespace WebCore