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