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