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