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