9a43de1e7d9ffdc454dd71410432a65d6a85b73d
[WebKit-https.git] / WebCore / rendering / RenderBox.cpp
1 /**
2  * This file is part of the DOM implementation for KDE.
3  *
4  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
6  *           (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
7  *           (C) 2005 Samuel Weinig (sam.weinig@gmail.com)
8  * Copyright (C) 2005 Apple Computer, Inc.
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public License
21  * along with this library; see the file COPYING.LIB.  If not, write to
22  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23  * Boston, MA 02111-1307, USA.
24  *
25  */
26
27 #include "config.h"
28 #include "RenderBox.h"
29
30 #include "CachedImage.h"
31 #include "Document.h"
32 #include "FrameView.h"
33 #include "GraphicsContext.h"
34 #include "HTMLElement.h"
35 #include "RenderTableCell.h"
36 #include "HTMLNames.h"
37 #include "RenderArena.h"
38 #include "RenderCanvas.h"
39 #include "RenderFlexibleBox.h"
40 #include "RenderTheme.h"
41 #include <assert.h>
42 #include <math.h>
43
44 using namespace std;
45
46 namespace WebCore {
47
48 using namespace HTMLNames;
49
50 #define TABLECELLMARGIN -0x4000
51
52 RenderBox::RenderBox(WebCore::Node* node)
53     : RenderObject(node)
54 {
55     m_minWidth = -1;
56     m_maxWidth = -1;
57     m_overrideSize = -1;
58     m_width = m_height = 0;
59     m_x = 0;
60     m_y = 0;
61     m_marginTop = 0;
62     m_marginBottom = 0;
63     m_marginLeft = 0;
64     m_marginRight = 0;
65     m_staticX = 0;
66     m_staticY = 0;
67     m_layer = 0;
68     m_inlineBoxWrapper = 0;
69 }
70
71 void RenderBox::setStyle(RenderStyle *_style)
72 {
73     RenderObject::setStyle(_style);
74
75     // The root always paints its background/border.
76     if (isRoot())
77         setShouldPaintBackgroundOrBorder(true);
78
79     setInline(_style->isDisplayInlineType());
80
81     switch(_style->position())
82     {
83     case AbsolutePosition:
84     case FixedPosition:
85         setPositioned(true);
86         break;
87     default:
88         setPositioned(false);
89
90         if (_style->isFloating())
91             setFloating(true);
92
93         if (_style->position() == RelativePosition)
94             setRelPositioned(true);
95     }
96
97     // We also handle <body> and <html>, whose overflow applies to the viewport.
98     if (_style->overflow() != OVISIBLE && !isRoot() && (!isBody() || !document()->isHTMLDocument()) &&
99         (isRenderBlock() || isTableRow() || isTableSection()))
100         setHasOverflowClip();
101
102     if (requiresLayer()) {
103         if (!m_layer) {
104             m_layer = new (renderArena()) RenderLayer(this);
105             m_layer->insertOnlyThisLayer();
106             if (parent() && containingBlock())
107                 m_layer->updateLayerPositions();
108         }
109     }
110     else if (m_layer && !isRoot() && !isCanvas()) {
111         assert(m_layer->parent());
112         RenderLayer *layer = m_layer;
113         m_layer = 0;
114         layer->removeOnlyThisLayer();
115     }
116
117     if (m_layer)
118         m_layer->styleChanged();
119     
120     // Set the text color if we're the body.
121     if (isBody())
122         element()->document()->setTextColor(_style->color());
123     
124     if (style()->outlineWidth() > 0 && style()->outlineSize() > maximalOutlineSize(PaintPhaseOutline))
125         static_cast<RenderCanvas*>(document()->renderer())->setMaximalOutlineSize(style()->outlineSize());
126 }
127
128 RenderBox::~RenderBox()
129 {
130 }
131
132 void RenderBox::destroy()
133 {
134     // A lot of the code in this funtion is just pasted into
135     // RenderWidget::destroy. If anything in this function changes,
136     // be sure to fix RenderWidget::destroy() as well. 
137
138     RenderLayer* layer = m_layer;
139     RenderArena* arena = renderArena();
140     
141     // This must be done before we destroy the RenderObject.
142     if (layer)
143         layer->clearClipRect();
144
145     RenderObject::destroy();
146     
147     if (layer)
148         layer->destroy(arena);
149 }
150
151 int RenderBox::contentWidth() const
152 {
153     int w = m_width - borderLeft() - borderRight();
154     w -= paddingLeft() + paddingRight();
155
156     if (includeScrollbarSize())
157         w -= m_layer->verticalScrollbarWidth();
158     
159     return w;
160 }
161
162 int RenderBox::contentHeight() const
163 {
164     int h = m_height - borderTop() - borderBottom();
165     h -= paddingTop() + paddingBottom();
166
167     if (includeScrollbarSize())
168         h -= m_layer->horizontalScrollbarHeight();
169
170     return h;
171 }
172
173 int RenderBox::overrideWidth() const
174 {
175     return m_overrideSize == -1 ? m_width : m_overrideSize;
176 }
177
178 int RenderBox::overrideHeight() const
179 {
180     return m_overrideSize == -1 ? m_height : m_overrideSize;
181 }
182
183 void RenderBox::setPos( int xPos, int yPos )
184 {
185     if (xPos == m_x && yPos == m_y)
186         return; // Optimize for the case where we don't move at all.
187     
188     m_x = xPos; m_y = yPos;
189 }
190
191 int RenderBox::width() const
192 {
193     return m_width;
194 }
195
196 int RenderBox::height() const
197 {
198     return m_height;
199 }
200
201 int RenderBox::calcBorderBoxWidth(int w) const
202 {
203     int toAdd = borderLeft() + borderRight() + paddingLeft() + paddingRight();
204     if (style()->boxSizing() == CONTENT_BOX)
205         return w + toAdd;
206     return max(w, toAdd);
207 }
208
209 int RenderBox::calcBorderBoxHeight(int h) const
210 {
211     int toAdd = borderTop() + borderBottom() + paddingTop() + paddingBottom();
212     if (style()->boxSizing() == CONTENT_BOX)
213         return h + toAdd;
214     return max(h, toAdd);
215 }
216
217 int RenderBox::calcContentBoxWidth(int w) const
218 {
219     if (style()->boxSizing() == BORDER_BOX)
220         w -= (borderLeft() + borderRight() + paddingLeft() + paddingRight());
221     return max(0, w);
222 }
223
224 int RenderBox::calcContentBoxHeight(int h) const
225 {
226     if (style()->boxSizing() == BORDER_BOX)
227         h -= (borderTop() + borderBottom() + paddingTop() + paddingBottom());
228     return max(0, h);
229 }
230
231 // Hit Testing
232 bool RenderBox::nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty, HitTestAction action)
233 {
234     tx += m_x;
235     ty += m_y;
236
237     // Check kids first.
238     for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
239         // FIXME: We have to skip over inline flows, since they can show up inside table rows
240         // at the moment (a demoted inline <form> for example). If we ever implement a
241         // table-specific hit-test method (which we should do for performance reasons anyway),
242         // then we can remove this check.
243         if (!child->layer() && !child->isInlineFlow() && child->nodeAtPoint(info, x, y, tx, ty, action)) {
244             setInnerNode(info);
245             return true;
246         }
247     }
248     
249     // Check our bounds next. For this purpose always assume that we can only be hit in the
250     // foreground phase (which is true for replaced elements like images).
251     if (action == HitTestForeground && IntRect(tx, ty, m_width, m_height).contains(x, y)) {
252         setInnerNode(info);
253         return true;
254     }
255
256     return false;
257 }
258
259 // --------------------- painting stuff -------------------------------
260
261 void RenderBox::paint(PaintInfo& i, int _tx, int _ty)
262 {
263     _tx += m_x;
264     _ty += m_y;
265
266     // default implementation. Just pass paint through to the children
267     for (RenderObject* child = firstChild(); child; child = child->nextSibling())
268         child->paint(i, _tx, _ty);
269 }
270
271 void RenderBox::paintRootBoxDecorations(PaintInfo& i, int _tx, int _ty)
272 {
273     const BackgroundLayer* bgLayer = style()->backgroundLayers();
274     Color bgColor = style()->backgroundColor();
275     if (document()->isHTMLDocument() && !style()->hasBackground()) {
276         // Locate the <body> element using the DOM.  This is easier than trying
277         // to crawl around a render tree with potential :before/:after content and
278         // anonymous blocks created by inline <body> tags etc.  We can locate the <body>
279         // render object very easily via the DOM.
280         HTMLElement* body = document()->body();
281         RenderObject* bodyObject = (body && body->hasLocalName(bodyTag)) ? body->renderer() : 0;
282         if (bodyObject) {
283             bgLayer = bodyObject->style()->backgroundLayers();
284             bgColor = bodyObject->style()->backgroundColor();
285         }
286     }
287
288     int w = width();
289     int h = height();
290
291     int rw, rh;
292     if (canvas()->view()) {
293         rw = canvas()->view()->contentsWidth();
294         rh = canvas()->view()->contentsHeight();
295     }
296     else {
297         rw = canvas()->width();
298         rh = canvas()->height();
299     }
300     
301     int bx = _tx - marginLeft();
302     int by = _ty - marginTop();
303     int bw = max(w + marginLeft() + marginRight() + borderLeft() + borderRight(), rw);
304     int bh = max(h + marginTop() + marginBottom() + borderTop() + borderBottom(), rh);
305
306     // CSS2 14.2:
307     // " The background of the box generated by the root element covers the entire canvas."
308     // hence, paint the background even in the margin areas (unlike for every other element!)
309     // I just love these little inconsistencies .. :-( (Dirk)
310     int my = max(by, i.r.y());
311
312     paintBackgrounds(i.p, bgColor, bgLayer, my, i.r.height(), bx, by, bw, bh);
313
314     if (style()->hasBorder() && style()->display() != INLINE)
315         paintBorder( i.p, _tx, _ty, w, h, style() );
316 }
317
318 void RenderBox::paintBoxDecorations(PaintInfo& i, int _tx, int _ty)
319 {
320     if (!shouldPaintWithinRoot(i))
321         return;
322
323     if (isRoot())
324         return paintRootBoxDecorations(i, _tx, _ty);
325     
326     int w = width();
327     int h = height() + borderTopExtra() + borderBottomExtra();
328     _ty -= borderTopExtra();
329
330     int my = max(_ty, i.r.y());
331     int mh;
332     if (_ty < i.r.y())
333         mh = max(0, h - (i.r.y() - _ty));
334     else
335         mh = min(i.r.height(), h);
336
337     // If we have a native theme appearance, paint that before painting our background.  
338     // The theme will tell us whether or not we should also paint the CSS background.
339     bool themePainted = style()->hasAppearance() && !theme()->paint(this, i, IntRect(_tx, _ty, w, h));
340     if (!themePainted) {
341         // The <body> only paints its background if the root element has defined a background
342         // independent of the body.  Go through the DOM to get to the root element's render object,
343         // since the root could be inline and wrapped in an anonymous block.
344         if (!isBody() || !document()->isHTMLDocument() || document()->documentElement()->renderer()->style()->hasBackground())
345             paintBackgrounds(i.p, style()->backgroundColor(), style()->backgroundLayers(), my, mh, _tx, _ty, w, h);
346     }
347     
348     // The theme will tell us whether or not we should also paint the CSS border.
349     if ((!style()->hasAppearance() || (!themePainted && theme()->paintBorderOnly(this, i, IntRect(_tx, _ty, w, h)))) && style()->hasBorder())
350         paintBorder(i.p, _tx, _ty, w, h, style());
351 }
352
353 void RenderBox::paintBackgrounds(GraphicsContext* p, const Color& c, const BackgroundLayer* bgLayer, int clipy, int cliph, int _tx, int _ty, int w, int height)
354 {
355     if (!bgLayer) return;
356     paintBackgrounds(p, c, bgLayer->next(), clipy, cliph, _tx, _ty, w, height);
357     paintBackground(p, c, bgLayer, clipy, cliph, _tx, _ty, w, height);
358 }
359
360 void RenderBox::paintBackground(GraphicsContext* p, const Color& c, const BackgroundLayer* bgLayer, int clipy, int cliph, int _tx, int _ty, int w, int height)
361 {
362     paintBackgroundExtended(p, c, bgLayer, clipy, cliph, _tx, _ty, w, height,
363                             borderLeft(), borderRight(), paddingLeft(), paddingRight());
364 }
365
366 static void cacluateBackgroundSize(const BackgroundLayer* bgLayer, int& scaledWidth, int& scaledHeight)
367 {
368     CachedImage* bg = bgLayer->backgroundImage();
369     
370     if (bgLayer->isBackgroundSizeSet()) {
371         Length bgWidth = bgLayer->backgroundSize().width;
372         Length bgHeight = bgLayer->backgroundSize().height;
373         
374         if (bgWidth.isPercent())
375             scaledWidth = scaledWidth * bgWidth.value() / 100;
376         else if (bgWidth.isFixed())
377             scaledWidth = bgWidth.value();
378         else if (bgWidth.isAuto()) {
379             // If the width is auto and the height is not, we have to use the appropriate
380             // scale to maintain our aspect ratio.
381             if (bgHeight.isPercent()) {
382                 int scaledH = scaledHeight * bgHeight.value() / 100;
383                 scaledWidth = bg->imageSize().width() * scaledH / bg->imageSize().height();
384             } else if (bgHeight.isFixed())
385                 scaledWidth = bg->imageSize().width() * bgHeight.value() / bg->imageSize().height();
386         }
387             
388         if (bgHeight.isPercent())
389             scaledHeight = scaledHeight * bgHeight.value() / 100;
390         else if (bgHeight.isFixed())
391             scaledHeight = bgHeight.value();
392         else if (bgHeight.isAuto()) {
393             // If the height is auto and the width is not, we have to use the appropriate
394             // scale to maintain our aspect ratio.
395             if (bgWidth.isPercent())
396                 scaledHeight = bg->imageSize().height() * scaledWidth / bg->imageSize().width();
397             else if (bgWidth.isFixed())
398                 scaledHeight = bg->imageSize().height() * bgWidth.value() / bg->imageSize().width();
399             else if (bgWidth.isAuto()) {
400                 // If both width and height are auto, we just want to use the image's
401                 // intrinsic size.
402                 scaledWidth = bg->imageSize().width();
403                 scaledHeight = bg->imageSize().height();
404             }
405         }
406     } else {
407         scaledWidth = bg->imageSize().width();
408         scaledHeight = bg->imageSize().height();
409     }
410 }
411
412 void RenderBox::paintBackgroundExtended(GraphicsContext* p, const Color& c, const BackgroundLayer* bgLayer, int clipy, int cliph,
413                                         int _tx, int _ty, int w, int h,
414                                         int bleft, int bright, int pleft, int pright)
415 {
416     bool clippedToBorderRadius = false;
417     if (style()->hasBorderRadius()) {
418         p->save();
419         p->addRoundedRectClip(IntRect(_tx, _ty, w, h),
420             style()->borderTopLeftRadius(), style()->borderTopRightRadius(),
421             style()->borderBottomLeftRadius(), style()->borderBottomRightRadius());
422         clippedToBorderRadius = true;
423     }
424     
425     if (bgLayer->backgroundClip() != BGBORDER) {
426         // Clip to the padding or content boxes as necessary.
427         bool includePadding = bgLayer->backgroundClip() == BGCONTENT;
428         int x = _tx + bleft + (includePadding ? pleft : 0);
429         int y = _ty + borderTop() + (includePadding ? paddingTop() : 0);
430         int width = w - bleft - bright - (includePadding ? pleft + pright : 0);
431         int height = h - borderTop() - borderBottom() - (includePadding ? paddingTop() + paddingBottom() : 0);
432         p->save();
433         p->addClip(IntRect(x, y, width, height));
434     }
435
436     CachedImage* bg = bgLayer->backgroundImage();
437     bool shouldPaintBackgroundImage = bg && bg->canRender();
438     Color bgColor = c;
439     
440     // When this style flag is set, change existing background colors and images to a solid white background.
441     // If there's no bg color or image, leave it untouched to avoid affecting transparency.
442     // We don't try to avoid loading the background images, because this style flag is only set
443     // when printing, and at that point we've already loaded the background images anyway. (To avoid
444     // loading the background images we'd have to do this check when applying styles rather than
445     // while rendering.)
446     if (style()->forceBackgroundsToWhite()) {
447         // Note that we can't reuse this variable below because the bgColor might be changed
448         bool shouldPaintBackgroundColor = !bgLayer->next() && bgColor.isValid() && bgColor.alpha() > 0;
449         if (shouldPaintBackgroundImage || shouldPaintBackgroundColor) {
450             bgColor = Color::white;
451             shouldPaintBackgroundImage = false;
452         }
453     }
454
455     // Only fill with a base color (e.g., white) if we're the root document, since iframes/frames with
456     // no background in the child document should show the parent's background.
457     if (!bgLayer->next() && isRoot() && !(bgColor.isValid() && bgColor.alpha() > 0) && canvas()->view()) {
458         bool isTransparent;
459         WebCore::Node* elt = document()->ownerElement();
460         if (elt) {
461             if (elt->hasTagName(frameTag))
462                 isTransparent = false;
463             else {
464                 // Locate the <body> element using the DOM.  This is easier than trying
465                 // to crawl around a render tree with potential :before/:after content and
466                 // anonymous blocks created by inline <body> tags etc.  We can locate the <body>
467                 // render object very easily via the DOM.
468                 HTMLElement* body = document()->body();
469                 isTransparent = !body || !body->hasLocalName(framesetTag); // Can't scroll a frameset document anyway.
470             }
471         } else
472             isTransparent = canvas()->view()->isTransparent();
473         
474         if (isTransparent)
475             canvas()->view()->useSlowRepaints(); // The parent must show behind the child.
476         else
477             bgColor = Color::white;
478     }
479
480     // Paint the color first underneath all images.
481     if (!bgLayer->next() && bgColor.isValid() && bgColor.alpha() > 0) {
482         IntRect rect(_tx, clipy, w, cliph);
483         // If we have an alpha and we are painting the root element, go ahead and blend with white.
484         if (bgColor.alpha() < 0xFF && isRoot() && !canvas()->view()->isTransparent())
485             p->fillRect(rect, Color(Color::white));
486         p->fillRect(rect, bgColor);
487     }
488     
489     // no progressive loading of the background image
490     if (shouldPaintBackgroundImage) {
491         int sx = 0;
492         int sy = 0;
493         int cw,ch;
494         int cx,cy;
495         int scaledImageWidth, scaledImageHeight;
496
497         
498         // CSS2 chapter 14.2.1
499
500         if (bgLayer->backgroundAttachment()) {
501             // scroll
502             int hpab = 0, vpab = 0, left = 0, top = 0; // Init to 0 for background-origin of 'border'
503             if (bgLayer->backgroundOrigin() != BGBORDER) {
504                 hpab += bleft + bright;
505                 vpab += borderTop() + borderBottom();
506                 left += bleft;
507                 top += borderTop();
508                 if (bgLayer->backgroundOrigin() == BGCONTENT) {
509                     hpab += pleft + pright;
510                     vpab += paddingTop() + paddingBottom();
511                     left += pleft;
512                     top += paddingTop();
513                 }
514             }
515             
516             int pw = w - hpab;
517             int ph = h - vpab;
518             scaledImageWidth = pw;
519             scaledImageHeight = ph;
520             cacluateBackgroundSize(bgLayer, scaledImageWidth, scaledImageHeight);
521
522             EBackgroundRepeat bgr = bgLayer->backgroundRepeat();
523             if ((bgr == NO_REPEAT || bgr == REPEAT_Y) && w > scaledImageWidth) {
524                 cw = scaledImageWidth;
525                 int xPosition = bgLayer->backgroundXPosition().calcMinValue(pw - scaledImageWidth);
526                 if (xPosition >= 0)
527                     cx = _tx + xPosition;
528                 else {
529                     cx = _tx;
530                     if (scaledImageWidth > 0) {
531                         sx = -xPosition;
532                         cw += xPosition;
533                     }
534                 }
535                 cx += left;
536             } else {
537                 // repeat over x or background is wider than box
538                 cw = w;
539                 cx = _tx;
540                 if (scaledImageWidth > 0) {
541                     int xPosition = bgLayer->backgroundXPosition().calcMinValue(pw - scaledImageWidth);
542                     if ((xPosition > 0) && (bgr == NO_REPEAT)) {
543                         cx += xPosition;
544                         cw -= xPosition;
545                     } else {
546                         sx = scaledImageWidth - (xPosition % scaledImageWidth);
547                         sx -= left % scaledImageWidth;
548                     }
549                 }
550             }
551
552             if((bgr == NO_REPEAT || bgr == REPEAT_X) && h > scaledImageHeight) {
553                 ch = scaledImageHeight;
554                 int yPosition = bgLayer->backgroundYPosition().calcMinValue(ph - scaledImageHeight);
555                 if (yPosition >= 0)
556                     cy = _ty + yPosition;
557                 else {
558                     cy = _ty;
559                     if (scaledImageHeight > 0) {
560                         sy = -yPosition;
561                         ch += yPosition;
562                     }
563                 }
564                 
565                 cy += top;
566             } else {
567                 // repeat over y or background is taller than box
568                 ch = h;
569                 cy = _ty;
570                 if (scaledImageHeight > 0) {
571                     int yPosition = bgLayer->backgroundYPosition().calcMinValue(ph - scaledImageHeight);
572                     if ((yPosition > 0) && (bgr == NO_REPEAT)) {
573                         cy += yPosition;
574                         ch -= yPosition;
575                     } else {
576                         sy = scaledImageHeight - (yPosition % scaledImageHeight);
577                         sy -= top % scaledImageHeight;
578                     }
579                 }
580             }
581         }
582         else {
583             //fixed
584             IntRect vr = viewRect();
585             int pw = vr.width();
586             int ph = vr.height();
587             scaledImageWidth = pw;
588             scaledImageHeight = ph;
589             cacluateBackgroundSize(bgLayer, scaledImageWidth, scaledImageHeight);
590             EBackgroundRepeat bgr = bgLayer->backgroundRepeat();
591             
592             if ((bgr == NO_REPEAT || bgr == REPEAT_Y) && pw > scaledImageWidth) {
593                 cw = scaledImageWidth;
594                 cx = vr.x() + bgLayer->backgroundXPosition().calcMinValue(pw - scaledImageWidth);
595             } else {
596                 cw = pw;
597                 cx = vr.x();
598                 if (scaledImageWidth > 0)
599                     sx = scaledImageWidth - bgLayer->backgroundXPosition().calcMinValue(pw - scaledImageWidth) % scaledImageWidth;
600             }
601
602             if ((bgr == NO_REPEAT || bgr == REPEAT_X) && ph > scaledImageHeight) {
603                 ch = scaledImageHeight;
604                 cy = vr.y() + bgLayer->backgroundYPosition().calcMinValue(ph - scaledImageHeight);
605             } else {
606                 ch = ph;
607                 cy = vr.y();
608                 if (scaledImageHeight > 0)
609                     sy = scaledImageHeight - bgLayer->backgroundYPosition().calcMinValue(ph - scaledImageHeight) % scaledImageHeight;
610             }
611
612             IntRect b = intersection(IntRect(cx, cy, cw, ch), IntRect(_tx, _ty, w, h));
613             sx += b.x() - cx;
614             sy += b.y() - cy;
615             cx = b.x();
616             cy = b.y();
617             cw = b.width();
618             ch = b.height();
619         }
620
621         if (cw > 0 && ch > 0)
622             p->drawTiledImage(bg->image(), IntRect(cx, cy, cw, ch), IntPoint(sx, sy), IntSize(scaledImageWidth, scaledImageHeight));
623     }
624     
625     if (bgLayer->backgroundClip() != BGBORDER)
626         p->restore(); // Undo the background clip
627         
628     if (clippedToBorderRadius)
629         p->restore(); // Undo the border radius clip
630 }
631
632 void RenderBox::outlineBox(GraphicsContext* p, int _tx, int _ty, const char* color)
633 {
634     p->setPen(Pen(Color(color), 1, Pen::DotLine));
635     p->setFillColor(Color::transparent);
636     p->drawRect(IntRect(_tx, _ty, m_width, m_height));
637 }
638
639 IntRect RenderBox::getOverflowClipRect(int tx, int ty)
640 {
641     // XXX When overflow-clip (CSS3) is implemented, we'll obtain the property
642     // here.
643     int bl=borderLeft(),bt=borderTop(),bb=borderBottom(),br=borderRight();
644     int clipx = tx + bl;
645     int clipy = ty + bt;
646     int clipw = m_width - bl - br;
647     int cliph = m_height - bt - bb + borderTopExtra() + borderBottomExtra();
648
649     // Subtract out scrollbars if we have them.
650     if (m_layer) {
651         clipw -= m_layer->verticalScrollbarWidth();
652         cliph -= m_layer->horizontalScrollbarHeight();
653     }
654     return IntRect(clipx,clipy,clipw,cliph);
655 }
656
657 IntRect RenderBox::getClipRect(int tx, int ty)
658 {
659     int clipx = tx;
660     int clipy = ty;
661     int clipw = m_width;
662     int cliph = m_height;
663
664     if (!style()->clipLeft().isAuto()) {
665         int c = style()->clipLeft().calcValue(m_width);
666         clipx += c;
667         clipw -= c;
668     }
669         
670     if (!style()->clipRight().isAuto()) {
671         int w = style()->clipRight().calcValue(m_width);
672         clipw -= m_width - w;
673     }
674     
675     if (!style()->clipTop().isAuto()) {
676         int c = style()->clipTop().calcValue(m_height);
677         clipy += c;
678         cliph -= c;
679     }
680
681     if (!style()->clipBottom().isAuto()) {
682         int h = style()->clipBottom().calcValue(m_height);
683         cliph -= m_height - h;
684     }
685
686     return IntRect(clipx, clipy, clipw, cliph);
687 }
688
689 int RenderBox::containingBlockWidth() const
690 {
691     RenderBlock* cb = containingBlock();
692     if (!cb)
693         return 0;
694     if (usesLineWidth())
695         return cb->lineWidth(m_y);
696     else
697         return cb->contentWidth();
698 }
699
700 bool RenderBox::absolutePosition(int &xPos, int &yPos, bool f)
701 {
702     if (style()->position() == FixedPosition)
703         f = true;
704     RenderObject *o = container();
705     if (o && o->absolutePosition(xPos, yPos, f)) {
706         yPos += o->borderTopExtra();
707         if (style()->position() == AbsolutePosition && o->isRelPositioned() && o->isInlineFlow()) {
708             // When we have an enclosing relpositioned inline, we need to add in the offset of the first line
709             // box from the rest of the content, but only in the cases where we know we're positioned
710             // relative to the inline itself.
711             RenderFlow* flow = static_cast<RenderFlow*>(o);
712             int sx = 0;
713             int sy = 0;
714             if (flow->firstLineBox()) {
715                 sx = flow->firstLineBox()->xPos();
716                 sy = flow->firstLineBox()->yPos();
717             } else {
718                 sx = flow->staticX();
719                 sy = flow->staticY();
720             }
721             
722             bool isInlineType = style()->isOriginalDisplayInlineType();
723             
724             if (!hasStaticX())
725                 xPos += sx;
726             // This is not terribly intuitive, but we have to match other browsers.  Despite being a block display type inside
727             // an inline, we still keep our x locked to the left of the relative positioned inline.  Arguably the correct
728             // behavior would be to go flush left to the block that contains the inline, but that isn't what other browsers
729             // do.
730             if (hasStaticX() && !isInlineType)
731                 // Avoid adding in the left border/padding of the containing block twice.  Subtract it out.
732                 xPos += sx - (containingBlock()->borderLeft() + containingBlock()->paddingLeft());
733             
734             if (!hasStaticY())
735                 yPos += sy;
736         }
737         if (o->hasOverflowClip())
738             o->layer()->subtractScrollOffset(xPos, yPos); 
739             
740         if (!isInline() || isReplaced()) {
741             xPos += m_x;
742             yPos += m_y;
743         }
744
745         if (isRelPositioned())
746             relativePositionOffset(xPos, yPos);
747
748         return true;
749     }
750     else {
751         xPos = yPos = 0;
752         return false;
753     }
754 }
755
756 void RenderBox::dirtyLineBoxes(bool fullLayout, bool)
757 {
758     if (m_inlineBoxWrapper) {
759         if (fullLayout) {
760             m_inlineBoxWrapper->destroy(renderArena());
761             m_inlineBoxWrapper = 0;
762         }
763         else
764             m_inlineBoxWrapper->dirtyLineBoxes();
765     }
766 }
767
768 void RenderBox::position(InlineBox* box, int from, int len, bool reverse, bool override)
769 {
770     if (isPositioned()) {
771         // Cache the x position only if we were an INLINE type originally.
772         bool wasInline = style()->isOriginalDisplayInlineType();
773         if (wasInline && hasStaticX()) {
774             // The value is cached in the xPos of the box.  We only need this value if
775             // our object was inline originally, since otherwise it would have ended up underneath
776             // the inlines.
777             m_staticX = box->xPos();
778         }
779         else if (!wasInline && hasStaticY())
780             // Our object was a block originally, so we make our normal flow position be
781             // just below the line box (as though all the inlines that came before us got
782             // wrapped in an anonymous block, which is what would have happened had we been
783             // in flow).  This value was cached in the yPos() of the box.
784             m_staticY = box->yPos();
785
786         // Nuke the box.
787         box->remove();
788         box->destroy(renderArena());
789     }
790     else if (isReplaced()) {
791         m_x = box->xPos();
792         m_y = box->yPos();
793         m_inlineBoxWrapper = box;
794     }
795 }
796
797 // For inline replaced elements, this function returns the inline box that owns us.  Enables
798 // the replaced RenderObject to quickly determine what line it is contained on and to easily
799 // iterate over structures on the line.
800 InlineBox* RenderBox::inlineBoxWrapper() const
801 {
802     return m_inlineBoxWrapper;
803 }
804
805 void RenderBox::deleteLineBoxWrapper()
806 {
807     if (m_inlineBoxWrapper) {
808         if (!documentBeingDestroyed())
809             m_inlineBoxWrapper->remove();
810         m_inlineBoxWrapper->destroy(renderArena());
811         m_inlineBoxWrapper = 0;
812     }
813 }
814
815 void RenderBox::setInlineBoxWrapper(InlineBox* b)
816 {
817     m_inlineBoxWrapper = b;
818 }
819
820 IntRect RenderBox::getAbsoluteRepaintRect()
821 {
822     IntRect r = overflowRect(false);
823     if (style()) {
824         if (style()->hasAppearance())
825             // The theme may wish to inflate the rect used when repainting.
826             theme()->adjustRepaintRect(this, r);
827         r.inflate(style()->outlineSize()); // FIXME: Technically the outline inflation could fit within the theme inflation.
828     }
829     computeAbsoluteRepaintRect(r);
830     return r;
831 }
832
833 void RenderBox::computeAbsoluteRepaintRect(IntRect& r, bool f)
834 {
835     int x = r.x() + m_x;
836     int y = r.y() + m_y;
837      
838     // Apply the relative position offset when invalidating a rectangle.  The layer
839     // is translated, but the render box isn't, so we need to do this to get the
840     // right dirty rect.  Since this is called from RenderObject::setStyle, the relative position
841     // flag on the RenderObject has been cleared, so use the one on the style().
842     if (style()->position() == RelativePosition && m_layer)
843         m_layer->relativePositionOffset(x,y);
844     
845     if (style()->position()==FixedPosition)
846         f = true;
847
848     RenderObject* o = container();
849     if (o) {
850         if (style()->position() == AbsolutePosition && o->isRelPositioned() && o->isInlineFlow()) {
851             // When we have an enclosing relpositioned inline, we need to add in the offset of the first line
852             // box from the rest of the content, but only in the cases where we know we're positioned
853             // relative to the inline itself.
854             RenderFlow* flow = static_cast<RenderFlow*>(o);
855             int sx = 0;
856             int sy = 0;
857             if (flow->firstLineBox()) {
858                 sx = flow->firstLineBox()->xPos();
859                 sy = flow->firstLineBox()->yPos();
860             } else {
861                 sx = flow->staticX();
862                 sy = flow->staticY();
863             }
864             
865             bool isInlineType = style()->isOriginalDisplayInlineType();
866             
867             if (!hasStaticX())
868                 x += sx;
869             // This is not terribly intuitive, but we have to match other browsers.  Despite being a block display type inside
870             // an inline, we still keep our x locked to the left of the relative positioned inline.  Arguably the correct
871             // behavior would be to go flush left to the block that contains the inline, but that isn't what other browsers
872             // do.
873             if (hasStaticX() && !isInlineType)
874                 // Avoid adding in the left border/padding of the containing block twice.  Subtract it out.
875                 x += sx - (containingBlock()->borderLeft() + containingBlock()->paddingLeft());
876             
877             if (!hasStaticY())
878                 y += sy;
879         }
880         // <body> may not have overflow, since it might be applying its overflow value to the
881         // scrollbars.
882         if (o->hasOverflowClip()) {
883             // o->height() is inaccurate if we're in the middle of a layout of |o|, so use the
884             // layer's size instead.  Even if the layer's size is wrong, the layer itself will repaint
885             // anyway if its size does change.
886             IntRect boxRect(0, 0, o->layer()->width(), o->layer()->height());
887             o->layer()->subtractScrollOffset(x,y); // For overflow:auto/scroll/hidden.
888             IntRect repaintRect(x, y, r.width(), r.height());
889             r = intersection(repaintRect, boxRect);
890             if (r.isEmpty())
891                 return;
892         } else {
893             r.setX(x);
894             r.setY(y);
895         }
896         o->computeAbsoluteRepaintRect(r, f);
897     }
898 }
899
900 void RenderBox::repaintDuringLayoutIfMoved(int oldX, int oldY)
901 {
902     int newX = m_x;
903     int newY = m_y;
904     if (oldX != newX || oldY != newY) {
905         // The child moved.  Invalidate the object's old and new positions.  We have to do this
906         // since the object may not have gotten a layout.
907         m_x = oldX; m_y = oldY;
908         repaint();
909         repaintFloatingDescendants();
910         m_x = newX; m_y = newY;
911         repaint();
912         repaintFloatingDescendants();
913     }
914 }
915
916 void RenderBox::relativePositionOffset(int &tx, int &ty)
917 {
918     if(!style()->left().isAuto())
919         tx += style()->left().calcValue(containingBlockWidth());
920     else if(!style()->right().isAuto())
921         tx -= style()->right().calcValue(containingBlockWidth());
922     if(!style()->top().isAuto())
923     {
924         if (!style()->top().isPercent()
925                 || containingBlock()->style()->height().isFixed())
926             ty += style()->top().calcValue(containingBlockHeight());
927     }
928     else if(!style()->bottom().isAuto())
929     {
930         if (!style()->bottom().isPercent()
931                 || containingBlock()->style()->height().isFixed())
932             ty -= style()->bottom().calcValue(containingBlockHeight());
933     }
934 }
935
936 void RenderBox::calcWidth()
937 {
938     if (isPositioned())
939         calcAbsoluteHorizontal();
940     else
941     {
942         // The parent box is flexing us, so it has increased or decreased our width.  Use the width
943         // from the style context.
944         if (m_overrideSize != -1 && parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
945             && parent()->isFlexingChildren()) {
946             m_width = m_overrideSize;
947             return;
948         }
949
950         bool inVerticalBox = parent()->isFlexibleBox() && parent()->style()->boxOrient() == VERTICAL;
951         bool stretching = parent()->style()->boxAlign() == BSTRETCH;
952         bool treatAsReplaced = isReplaced() && !isInlineBlockOrInlineTable() &&
953             (!inVerticalBox || !stretching);
954         Length w;
955         if (treatAsReplaced)
956             w = Length( calcReplacedWidth(), Fixed );
957         else
958             w = style()->width();
959
960         Length ml = style()->marginLeft();
961         Length mr = style()->marginRight();
962
963         RenderBlock *cb = containingBlock();
964         int cw = containingBlockWidth();
965
966         if (cw<0) cw = 0;
967
968         m_marginLeft = 0;
969         m_marginRight = 0;
970
971         if (isInline() && !isInlineBlockOrInlineTable()) {
972             // just calculate margins
973             m_marginLeft = ml.calcMinValue(cw);
974             m_marginRight = mr.calcMinValue(cw);
975             if (treatAsReplaced) {
976                 m_width = w.calcValue(cw) + borderLeft() + borderRight() + paddingLeft() + paddingRight();
977                 m_width = max(m_width, m_minWidth);
978             }
979             return;
980         }
981         else {
982             LengthType widthType, minWidthType, maxWidthType;
983             if (treatAsReplaced) {
984                 m_width = w.calcValue(cw) + borderLeft() + borderRight() + paddingLeft() + paddingRight();
985                 widthType = w.type();
986             } else {
987                 m_width = calcWidthUsing(Width, cw, widthType);
988                 int minW = calcWidthUsing(MinWidth, cw, minWidthType);
989                 int maxW = style()->maxWidth().value() == undefinedLength
990                     ? m_width : calcWidthUsing(MaxWidth, cw, maxWidthType);
991                 
992                 if (m_width > maxW) {
993                     m_width = maxW;
994                     widthType = maxWidthType;
995                 }
996                 if (m_width < minW) {
997                     m_width = minW;
998                     widthType = minWidthType;
999                 }
1000             }
1001             
1002             if (widthType == Auto) {
1003                 m_marginLeft = ml.calcMinValue(cw);
1004                 m_marginRight = mr.calcMinValue(cw);
1005             }
1006             else
1007             {
1008                 calcHorizontalMargins(ml,mr,cw);
1009             }
1010         }
1011
1012         if (cw && cw != m_width + m_marginLeft + m_marginRight && !isFloating() && !isInline() &&
1013             !cb->isFlexibleBox())
1014         {
1015             if (cb->style()->direction()==LTR)
1016                 m_marginRight = cw - m_width - m_marginLeft;
1017             else
1018                 m_marginLeft = cw - m_width - m_marginRight;
1019         }
1020     }
1021 }
1022
1023 int RenderBox::calcWidthUsing(WidthType widthType, int cw, LengthType& lengthType)
1024 {
1025     int width = m_width;
1026     Length w;
1027     if (widthType == Width)
1028         w = style()->width();
1029     else if (widthType == MinWidth)
1030         w = style()->minWidth();
1031     else
1032         w = style()->maxWidth();
1033
1034     lengthType = w.type();
1035
1036     if (w.isIntrinsicOrAuto()) {
1037         int marginLeft = style()->marginLeft().calcMinValue(cw);
1038         int marginRight = style()->marginRight().calcMinValue(cw);
1039         if (cw) width = cw - marginLeft - marginRight;
1040         
1041         if (sizesToIntrinsicWidth(widthType)) {
1042             width = max(width, m_minWidth);
1043             width = min(width, m_maxWidth);
1044         }
1045     }
1046     else
1047         width = calcBorderBoxWidth(w.calcValue(cw));
1048     
1049     return width;
1050 }
1051
1052 bool RenderBox::sizesToIntrinsicWidth(WidthType widthType) const
1053 {
1054     // Marquees in WinIE are like a mixture of blocks and inline-blocks.  They size as though they're blocks,
1055     // but they allow text to sit on the same line as the marquee.
1056     if (isFloating() || (isCompact() && isInline()) || 
1057         (isInlineBlockOrInlineTable() && !isHTMLMarquee()))
1058         return true;
1059     
1060     // This code may look a bit strange.  Basically width:intrinsic should clamp the size when testing both
1061     // min-width and width.  max-width is only clamped if it is also intrinsic.
1062     Length width = widthType == MaxWidth ? style()->maxWidth() : style()->width();
1063     if (width.type() == Intrinsic)
1064         return true;
1065     
1066     // Children of a horizontal marquee do not fill the container by default.
1067     // FIXME: Need to deal with MAUTO value properly.  It could be vertical.
1068     if (parent()->style()->overflow() == OMARQUEE) {
1069         EMarqueeDirection dir = parent()->style()->marqueeDirection();
1070         if (dir == MAUTO || dir == MFORWARD || dir == MBACKWARD || dir == MLEFT || dir == MRIGHT)
1071             return true;
1072     }
1073     
1074     // Flexible horizontal boxes lay out children at their intrinsic widths.  Also vertical boxes
1075     // that don't stretch their kids lay out their children at their intrinsic widths.
1076     if (parent()->isFlexibleBox() &&
1077         (parent()->style()->boxOrient() == HORIZONTAL || parent()->style()->boxAlign() != BSTRETCH))
1078         return true;
1079
1080     return false;
1081 }
1082
1083 void RenderBox::calcHorizontalMargins(const Length& ml, const Length& mr, int cw)
1084 {
1085     if (isFloating() || isInline()) // Inline blocks/tables and floats don't have their margins increased.
1086     {
1087         m_marginLeft = ml.calcMinValue(cw);
1088         m_marginRight = mr.calcMinValue(cw);
1089     }
1090     else
1091     {
1092         if ( (ml.isAuto() && mr.isAuto() && m_width<cw) ||
1093              (!ml.isAuto() && !mr.isAuto() &&
1094                 containingBlock()->style()->textAlign() == KHTML_CENTER) )
1095         {
1096             m_marginLeft = (cw - m_width)/2;
1097             if (m_marginLeft<0) m_marginLeft=0;
1098             m_marginRight = cw - m_width - m_marginLeft;
1099         }
1100         else if ( (mr.isAuto() && m_width<cw) ||
1101                  (!ml.isAuto() && containingBlock()->style()->direction() == RTL &&
1102                   containingBlock()->style()->textAlign() == KHTML_LEFT))
1103         {
1104             m_marginLeft = ml.calcValue(cw);
1105             m_marginRight = cw - m_width - m_marginLeft;
1106         }
1107         else if ( (ml.isAuto() && m_width<cw) ||
1108                  (!mr.isAuto() && containingBlock()->style()->direction() == LTR &&
1109                   containingBlock()->style()->textAlign() == KHTML_RIGHT))
1110         {
1111             m_marginRight = mr.calcValue(cw);
1112             m_marginLeft = cw - m_width - m_marginRight;
1113         }
1114         else
1115         {
1116             // this makes auto margins 0 if we failed a m_width<cw test above (css2.1, 10.3.3)
1117             m_marginLeft = ml.calcMinValue(cw);
1118             m_marginRight = mr.calcMinValue(cw);
1119         }
1120     }
1121 }
1122
1123 void RenderBox::calcHeight()
1124 {
1125     // Cell height is managed by the table and inline non-replaced elements do not support a height property.
1126     if (isTableCell() || (isInline() && !isReplaced()))
1127         return;
1128
1129     if (isPositioned())
1130         calcAbsoluteVertical();
1131     else
1132     {
1133         calcVerticalMargins();
1134         
1135         // For tables, calculate margins only
1136         if (isTable())
1137             return;
1138         
1139         Length h;
1140         bool inHorizontalBox = parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL;
1141         bool stretching = parent()->style()->boxAlign() == BSTRETCH;
1142         bool treatAsReplaced = isReplaced() && !isInlineBlockOrInlineTable() && (!inHorizontalBox || !stretching);
1143         bool checkMinMaxHeight = false;
1144         
1145         // The parent box is flexing us, so it has increased or decreased our height.  We have to
1146         // grab our cached flexible height.
1147         if (m_overrideSize != -1 && parent()->isFlexibleBox() && parent()->style()->boxOrient() == VERTICAL
1148             && parent()->isFlexingChildren())
1149             h = Length(m_overrideSize - borderTop() - borderBottom() - paddingTop() - paddingBottom(), Fixed);
1150         else if (treatAsReplaced)
1151             h = Length(calcReplacedHeight(), Fixed);
1152         else {
1153             h = style()->height();
1154             checkMinMaxHeight = true;
1155         }
1156         
1157         // Block children of horizontal flexible boxes fill the height of the box.
1158         if (h.isAuto() && parent()->isFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
1159             && parent()->isStretchingChildren()) {
1160             h = Length(parent()->contentHeight() - marginTop() - marginBottom() -
1161                        borderTop() - paddingTop() - borderBottom() - paddingBottom(), Fixed);
1162             checkMinMaxHeight = false;
1163         }
1164
1165         int height;
1166         if (checkMinMaxHeight) {
1167             height = calcHeightUsing(style()->height());
1168             if (height == -1)
1169                 height = m_height;
1170             int minH = calcHeightUsing(style()->minHeight()); // Leave as -1 if unset.
1171             int maxH = style()->maxHeight().value() == undefinedLength ? height : calcHeightUsing(style()->maxHeight());
1172             if (maxH == -1)
1173                 maxH = height;
1174             height = min(maxH, height);
1175             height = max(minH, height);
1176         }
1177         else
1178             // The only times we don't check min/max height are when a fixed length has 
1179             // been given as an override.  Just use that.  The value has already been adjusted
1180             // for box-sizing.
1181             height = h.value() + borderTop() + borderBottom() + paddingTop() + paddingBottom();
1182
1183         m_height = height;
1184     }
1185     
1186     // Unfurling marquees override with the furled height.
1187     if (style()->overflow() == OMARQUEE && m_layer && m_layer->marquee() && 
1188         m_layer->marquee()->isUnfurlMarquee() && !m_layer->marquee()->isHorizontal()) {
1189         m_layer->marquee()->setEnd(m_height);
1190         m_height = min(m_height, m_layer->marquee()->unfurlPos());
1191     }
1192     
1193     // WinIE quirk: The <html> block always fills the entire canvas in quirks mode.  The <body> always fills the
1194     // <html> block in quirks mode.  Only apply this quirk if the block is normal flow and no height
1195     // is specified.
1196     if (style()->htmlHacks() && style()->height().isAuto() &&
1197         !isFloatingOrPositioned() && (isRoot() || isBody())) {
1198         int margins = collapsedMarginTop() + collapsedMarginBottom();
1199         int visHeight = canvas()->view()->visibleHeight();
1200         if (isRoot())
1201             m_height = max(m_height, visHeight - margins);
1202         else
1203             m_height = max(m_height, visHeight - 
1204                             (margins + parent()->marginTop() + parent()->marginBottom() + 
1205                              parent()->borderTop() + parent()->borderBottom() +
1206                              parent()->paddingTop() + parent()->paddingBottom()));
1207     }
1208 }
1209
1210 int RenderBox::calcHeightUsing(const Length& h)
1211 {
1212     int height = -1;
1213     if (!h.isAuto()) {
1214         if (h.isFixed())
1215             height = h.value();
1216         else if (h.isPercent())
1217             height = calcPercentageHeight(h);
1218         if (height != -1) {
1219             height = calcBorderBoxHeight(height);
1220             return height;
1221         }
1222     }
1223     return height;
1224 }
1225
1226 int RenderBox::calcPercentageHeight(const Length& height)
1227 {
1228     int result = -1;
1229     bool includeBorderPadding = isTable();
1230     RenderBlock* cb = containingBlock();
1231     if (style()->htmlHacks()) {
1232         // In quirks mode, blocks with auto height are skipped, and we keep looking for an enclosing
1233         // block that may have a specified height and then use it.  In strict mode, this violates the
1234         // specification, which states that percentage heights just revert to auto if the containing
1235         // block has an auto height.
1236         for ( ; !cb->isCanvas() && !cb->isBody() && !cb->isTableCell() && !cb->isPositioned() &&
1237                 cb->style()->height().isAuto(); cb = cb->containingBlock());
1238     }
1239
1240     // Table cells violate what the CSS spec says to do with heights.  Basically we
1241     // don't care if the cell specified a height or not.  We just always make ourselves
1242     // be a percentage of the cell's current content height.
1243     if (cb->isTableCell()) {
1244         result = cb->overrideSize();
1245         if (result == -1) {
1246             // Normally we would let the cell size intrinsically, but scrolling overflow has to be
1247             // treated differently, since WinIE lets scrolled overflow regions shrink as needed.
1248             // While we can't get all cases right, we can at least detect when the cell has a specified
1249             // height or when the table has a specified height.  In these cases we want to initially have
1250             // no size and allow the flexing of the table or the cell to its specified height to cause us
1251             // to grow to fill the space.  This could end up being wrong in some cases, but it is
1252             // preferable to the alternative (sizing intrinsically and making the row end up too big).
1253             RenderTableCell* cell = static_cast<RenderTableCell*>(cb);
1254             if (scrollsOverflow() && 
1255                 (!cell->style()->height().isAuto() || !cell->table()->style()->height().isAuto()))
1256                 return 0;
1257             return -1;
1258         }
1259         includeBorderPadding = true;
1260     }
1261
1262     // Otherwise we only use our percentage height if our containing block had a specified
1263     // height.
1264     else if (cb->style()->height().isFixed())
1265         result = cb->calcContentBoxHeight(cb->style()->height().value());
1266     else if (cb->style()->height().isPercent()) {
1267         // We need to recur and compute the percentage height for our containing block.
1268         result = cb->calcPercentageHeight(cb->style()->height());
1269         if (result != -1)
1270             result = cb->calcContentBoxHeight(result);
1271     }
1272     else if (cb->isCanvas() || (cb->isBody() && style()->htmlHacks())) {
1273         // Don't allow this to affect the block' m_height member variable, since this
1274         // can get called while the block is still laying out its kids.
1275         int oldHeight = cb->height();
1276         cb->calcHeight();
1277         result = cb->contentHeight();
1278         cb->setHeight(oldHeight);
1279     } else if (cb->isRoot() && isPositioned()) {
1280         // Match the positioned objects behavior, which is that positioned objects will fill their viewport
1281         // always.  Note we could only hit this case by recurring into calcPercentageHeight on a positioned containing block.
1282         result = cb->calcContentBoxHeight(cb->availableHeight());
1283     }
1284
1285     if (result != -1) {
1286         result = height.calcValue(result);
1287         if (includeBorderPadding) {
1288             // It is necessary to use the border-box to match WinIE's broken
1289             // box model.  This is essential for sizing inside
1290             // table cells using percentage heights.
1291             result -= (borderTop() + paddingTop() + borderBottom() + paddingBottom());
1292             result = max(0, result);
1293         }
1294     }
1295     return result;
1296 }
1297
1298 int RenderBox::calcReplacedWidth() const
1299 {
1300     int width = calcReplacedWidthUsing(Width);
1301     int minW = calcReplacedWidthUsing(MinWidth);
1302     int maxW = style()->maxWidth().value() == undefinedLength ? width : calcReplacedWidthUsing(MaxWidth);
1303
1304     return max(minW, min(width, maxW));
1305 }
1306
1307 int RenderBox::calcReplacedWidthUsing(WidthType widthType) const
1308 {
1309     Length w;
1310     if (widthType == Width)
1311         w = style()->width();
1312     else if (widthType == MinWidth)
1313         w = style()->minWidth();
1314     else
1315         w = style()->maxWidth();
1316     
1317     switch (w.type()) {
1318     case Fixed:
1319         return calcContentBoxWidth(w.value());
1320     case Percent: {
1321         const int cw = containingBlockWidth();
1322         if (cw > 0)
1323             return calcContentBoxWidth(w.calcMinValue(cw));
1324     }
1325     // fall through
1326     default:
1327         return intrinsicWidth();
1328     }
1329 }
1330
1331 int RenderBox::calcReplacedHeight() const
1332 {
1333     int height = calcReplacedHeightUsing(Height);
1334     int minH = calcReplacedHeightUsing(MinHeight);
1335     int maxH = style()->maxHeight().value() == undefinedLength ? height : calcReplacedHeightUsing(MaxHeight);
1336
1337     return max(minH, min(height, maxH));
1338 }
1339
1340 int RenderBox::calcReplacedHeightUsing(HeightType heightType) const
1341 {
1342     Length h;
1343     if (heightType == Height)
1344         h = style()->height();
1345     else if (heightType == MinHeight)
1346         h = style()->minHeight();
1347     else
1348         h = style()->maxHeight();
1349
1350     switch (h.type()) {
1351         case Fixed:
1352             return calcContentBoxHeight(h.value());
1353         case Percent:
1354             return calcContentBoxHeight(h.calcValue(containingBlock()->availableHeight()));
1355         default:
1356             return intrinsicHeight();
1357     }
1358 }
1359
1360 int RenderBox::availableHeight() const
1361 {
1362     return availableHeightUsing(style()->height());
1363 }
1364
1365 int RenderBox::availableHeightUsing(const Length& h) const
1366 {
1367     if (h.isFixed())
1368         return calcContentBoxHeight(h.value());
1369
1370     if (isCanvas())
1371         return static_cast<const RenderCanvas*>(this)->view()->visibleHeight();
1372
1373     // We need to stop here, since we don't want to increase the height of the table
1374     // artificially.  We're going to rely on this cell getting expanded to some new
1375     // height, and then when we lay out again we'll use the calculation below.
1376     if (isTableCell() && (h.isAuto() || h.isPercent()))
1377         return overrideSize() - (borderLeft() + borderRight() + paddingLeft() + paddingRight());
1378     
1379     if (h.isPercent())
1380        return calcContentBoxHeight(h.calcValue(containingBlock()->availableHeight()));
1381        
1382     return containingBlock()->availableHeight();
1383 }
1384
1385 void RenderBox::calcVerticalMargins()
1386 {
1387     if( isTableCell() ) {
1388         // table margins are basically infinite
1389         m_marginTop = TABLECELLMARGIN;
1390         m_marginBottom = TABLECELLMARGIN;
1391         return;
1392     }
1393
1394     Length tm = style()->marginTop();
1395     Length bm = style()->marginBottom();
1396
1397     // margins are calculated with respect to the _width_ of
1398     // the containing block (8.3)
1399     int cw = containingBlock()->contentWidth();
1400
1401     m_marginTop = tm.calcMinValue(cw);
1402     m_marginBottom = bm.calcMinValue(cw);
1403 }
1404
1405 void RenderBox::setStaticX(int staticX)
1406 {
1407     m_staticX = staticX;
1408 }
1409
1410 void RenderBox::setStaticY(int staticY)
1411 {
1412     m_staticY = staticY;
1413 }
1414
1415 void RenderBox::calcAbsoluteHorizontal()
1416 {
1417     const int AUTO = -666666;
1418     int l, r, cw;
1419
1420     int pab = borderLeft()+ borderRight()+ paddingLeft()+ paddingRight();
1421
1422     l = r = AUTO;
1423  
1424     // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
1425     RenderObject* cb = container();
1426     cw = containingBlockWidth() + cb->paddingLeft() + cb->paddingRight();
1427
1428     if (!style()->left().isAuto())
1429         l = style()->left().calcValue(cw);
1430     if (!style()->right().isAuto())
1431         r = style()->right().calcValue(cw);
1432
1433     int static_distance=0;
1434     if ((parent()->style()->direction()==LTR && (l == AUTO && r == AUTO))
1435             || style()->left().isStatic())
1436     {
1437         static_distance = m_staticX - cb->borderLeft(); // Should already have been set through layout of the parent().
1438         RenderObject* po = parent();
1439         for (; po && po != cb; po = po->parent())
1440             static_distance += po->xPos();
1441
1442         l = static_distance;
1443     }
1444
1445     else if ((parent()->style()->direction()==RTL && (l==AUTO && r==AUTO ))
1446             || style()->right().isStatic())
1447     {
1448         RenderObject* po = parent();
1449         static_distance = m_staticX + cw + cb->borderRight() - po->width(); // Should already have been set through layout of the parent().
1450         while (po && po!=containingBlock()) {
1451             static_distance -= po->xPos();
1452             po=po->parent();
1453         }
1454
1455         r = static_distance;
1456     }
1457
1458     calcAbsoluteHorizontalValues(Width, cb, cw, pab, static_distance, l, r, m_width, m_marginLeft, m_marginRight, m_x);
1459
1460     // Avoid doing any work in the common case (where the values of min-width and max-width are their defaults).
1461     int minW = m_width, minML, minMR, minX;
1462     calcAbsoluteHorizontalValues(MinWidth, cb, cw, pab, static_distance, l, r, minW, minML, minMR, minX);
1463
1464     int maxW = m_width, maxML, maxMR, maxX;
1465     if (style()->maxWidth().value() != undefinedLength)
1466         calcAbsoluteHorizontalValues(MaxWidth, cb, cw, static_distance, pab, l, r, maxW, maxML, maxMR, maxX);
1467
1468     if (m_width > maxW) {
1469         m_width = maxW;
1470         m_marginLeft = maxML;
1471         m_marginRight = maxMR;
1472         m_x = maxX;
1473     }
1474     
1475     if (m_width < minW) {
1476         m_width = minW;
1477         m_marginLeft = minML;
1478         m_marginRight = minMR;
1479         m_x = minX;
1480     }
1481 }
1482
1483 void RenderBox::calcAbsoluteHorizontalValues(WidthType widthType, RenderObject* cb, int cw, int pab, int static_distance,
1484                                              int l, int r, int& w, int& ml, int& mr, int& x)
1485 {
1486     const int AUTO = -666666;
1487     w = ml = mr = AUTO;
1488
1489     if (!style()->marginLeft().isAuto())
1490         ml = style()->marginLeft().calcValue(cw);
1491     if (!style()->marginRight().isAuto())
1492         mr = style()->marginRight().calcValue(cw);
1493
1494     Length width;
1495     if (widthType == Width)
1496         width = style()->width();
1497     else if (widthType == MinWidth)
1498         width = style()->minWidth();
1499     else
1500         width = style()->maxWidth();
1501
1502     if (!width.isIntrinsicOrAuto())
1503         w = calcContentBoxWidth(width.calcValue(cw));
1504     else if (isReplaced())
1505         w = calcReplacedWidth();
1506
1507     if (l != AUTO && w != AUTO && r != AUTO) {
1508         // left, width, right all given, play with margins
1509         int ot = l + w + r + pab;
1510
1511         if (ml==AUTO && mr==AUTO) {
1512             // both margins auto, solve for equality
1513             ml = (cw - ot)/2;
1514             mr = cw - ot - ml;
1515         }
1516         else if (ml==AUTO)
1517             // solve for left margin
1518             ml = cw - ot - mr;
1519         else if (mr==AUTO)
1520             // solve for right margin
1521             mr = cw - ot - ml;
1522         else {
1523             // overconstrained, solve according to dir
1524             if (style()->direction() == LTR)
1525                 r = cw - ( l + w + ml + mr + pab);
1526             else
1527                 l = cw - ( r + w + ml + mr + pab);
1528         }
1529     }
1530     else
1531     {
1532         // one or two of (left, width, right) missing, solve
1533
1534         // auto margins are ignored
1535         if (ml==AUTO) ml = 0;
1536         if (mr==AUTO) mr = 0;
1537
1538         //1. solve left & width.
1539         if (l == AUTO && w == AUTO && r != AUTO) {
1540             // From section 10.3.7 of the CSS2.1 specification.
1541             // "The shrink-to-fit width is: min(max(preferred minimum width, available width), preferred width)."
1542             w = min(max(m_minWidth - pab, cw - (r + ml + mr + pab)), m_maxWidth - pab);
1543             l = cw - (r + w + ml + mr + pab);
1544         }
1545         else
1546
1547         //2. solve left & right. use static positioning.
1548         if (l == AUTO && w != AUTO && r == AUTO) {
1549             if (style()->direction()==RTL) {
1550                 r = static_distance;
1551                 l = cw - (r + w + ml + mr + pab);
1552             }
1553             else {
1554                 l = static_distance;
1555                 r = cw - (l + w + ml + mr + pab);
1556             }
1557
1558         } //3. solve width & right.
1559         else if (l != AUTO && w == AUTO && r == AUTO) {
1560             // From section 10.3.7 of the CSS2.1 specification.
1561             // "The shrink-to-fit width is: min(max(preferred minimum width, available width), preferred width)."
1562             w = min(max(m_minWidth - pab, cw - (l + ml + mr + pab)), m_maxWidth - pab);
1563             r = cw - (l + w + ml + mr + pab);
1564         }
1565         else
1566
1567         //4. solve left
1568         if (l==AUTO && w!=AUTO && r!=AUTO)
1569             l = cw - (r + w + ml + mr + pab);
1570         else
1571         //5. solve width
1572         if (l!=AUTO && w==AUTO && r!=AUTO)
1573             w = cw - (r + l + ml + mr + pab);
1574         else
1575
1576         //6. solve right
1577         if (l!=AUTO && w!=AUTO && r==AUTO)
1578             r = cw - (l + w + ml + mr + pab);
1579     }
1580
1581     w += pab;
1582     x = l + ml + cb->borderLeft();
1583 }
1584
1585 void RenderBox::calcAbsoluteVertical()
1586 {
1587     // css2 spec 10.6.4 & 10.6.5
1588
1589     // based on
1590     // http://www.w3.org/Style/css2-updates/REC-CSS2-19980512-errata
1591     // (actually updated 2000-10-24)
1592     // that introduces static-position value for top, left & right
1593
1594     const int AUTO = -666666;
1595     int t, b, ch;
1596
1597     t = b = AUTO;
1598
1599     int pab = borderTop()+borderBottom()+paddingTop()+paddingBottom();
1600
1601     // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
1602     RenderObject* cb = container();
1603     if (cb->isRoot()) // Even in strict mode (where we don't grow the root to fill the viewport) other browsers
1604                       // position as though the root fills the viewport.
1605         ch = cb->availableHeight();
1606     else
1607         ch = cb->height() - cb->borderTop() - cb->borderBottom();
1608
1609     if (!style()->top().isAuto())
1610         t = style()->top().calcValue(ch);
1611     if (!style()->bottom().isAuto())
1612         b = style()->bottom().calcValue(ch);
1613
1614     int h, mt, mb, y;
1615     calcAbsoluteVerticalValues(Height, cb, ch, pab, t, b, h, mt, mb, y);
1616
1617     // Avoid doing any work in the common case (where the values of min-height and max-height are their defaults).
1618     int minH = h, minMT, minMB, minY;
1619     calcAbsoluteVerticalValues(MinHeight, cb, ch, pab, t, b, minH, minMT, minMB, minY);
1620
1621     int maxH = h, maxMT, maxMB, maxY;
1622     if (style()->maxHeight().value() != undefinedLength)
1623         calcAbsoluteVerticalValues(MaxHeight, cb, ch, pab, t, b, maxH, maxMT, maxMB, maxY);
1624
1625     if (h > maxH) {
1626         h = maxH;
1627         mt = maxMT;
1628         mb = maxMB;
1629         y = maxY;
1630     }
1631     
1632     if (h < minH) {
1633         h = minH;
1634         mt = minMT;
1635         mb = minMB;
1636         y = minY;
1637     }
1638     
1639     // If our natural height exceeds the new height once we've set it, then we need to make sure to update
1640     // overflow to track the spillout.
1641     if (m_height > h)
1642         setOverflowHeight(m_height);
1643         
1644     // Set our final values.
1645     m_height = h;
1646     m_marginTop = mt;
1647     m_marginBottom = mb;
1648     m_y = y;
1649 }
1650
1651 void RenderBox::calcAbsoluteVerticalValues(HeightType heightType, RenderObject* cb, int ch, int pab, 
1652                                            int t, int b, int& h, int& mt, int& mb, int& y)
1653 {
1654     const int AUTO = -666666;
1655     h = mt = mb = AUTO;
1656
1657     if (!style()->marginTop().isAuto())
1658         mt = style()->marginTop().calcValue(ch);
1659     if (!style()->marginBottom().isAuto())
1660         mb = style()->marginBottom().calcValue(ch);
1661
1662     Length height;
1663     if (heightType == Height)
1664         height = style()->height();
1665     else if (heightType == MinHeight)
1666         height = style()->minHeight();
1667     else
1668         height = style()->maxHeight();
1669
1670     int ourHeight = m_height;
1671
1672     if (isTable() && height.isAuto())
1673         // Height is never unsolved for tables. "auto" means shrink to fit.  Use our
1674         // height instead.
1675         h = ourHeight - pab;
1676     else if (!height.isAuto())
1677     {
1678         h = calcContentBoxHeight(height.calcValue(ch));
1679         if (ourHeight - pab > h)
1680             ourHeight = h + pab;
1681     }
1682     else if (isReplaced())
1683         h = calcReplacedHeight();
1684
1685     int static_top=0;
1686     if ((t == AUTO && b == AUTO) || style()->top().isStatic()) {
1687         // calc hypothetical location in the normal flow
1688         // used for 1) top=static-position
1689         //          2) top, bottom, height are all auto -> calc top -> 3.
1690         //          3) precalc for case 2 below
1691         static_top = m_staticY - cb->borderTop(); // Should already have been set through layout of the parent().
1692         RenderObject* po = parent();
1693         for (; po && po != cb; po = po->parent())
1694             if (!po->isTableRow())
1695                 static_top += po->yPos();
1696
1697         if (h == AUTO || style()->top().isStatic())
1698             t = static_top;
1699     }
1700
1701     if (t != AUTO && h != AUTO && b != AUTO) {
1702         // top, height, bottom all given, play with margins
1703         int ot = h + t + b + pab;
1704
1705         if (mt == AUTO && mb == AUTO) {
1706             // both margins auto, solve for equality
1707             mt = (ch - ot)/2;
1708             mb = ch - ot - mt;
1709         }
1710         else if (mt==AUTO)
1711             // solve for top margin
1712             mt = ch - ot - mb;
1713         else if (mb==AUTO)
1714             // solve for bottom margin
1715             mb = ch - ot - mt;
1716         else
1717             // overconstrained, solve for bottom
1718             b = ch - (h + t + mt + mb + pab);
1719     }
1720     else {
1721         // one or two of (top, height, bottom) missing, solve
1722
1723         // auto margins are ignored
1724         if (mt == AUTO)
1725             mt = 0;
1726         if (mb == AUTO)
1727             mb = 0;
1728
1729         //1. solve top & height. use content height.
1730         if (t == AUTO && h == AUTO && b != AUTO) {
1731             h = ourHeight - pab;
1732             t = ch - (h + b + mt + mb + pab);
1733         }
1734         else if (t == AUTO && h != AUTO && b == AUTO) //2. solve top & bottom. use static positioning.
1735         {
1736             t = static_top;
1737             b = ch - (h + t + mt + mb + pab);
1738         }
1739         else if (t != AUTO && h == AUTO && b == AUTO) //3. solve height & bottom. use content height.
1740         {
1741             h = ourHeight - pab;
1742             b = ch - (h + t + mt + mb + pab);
1743         }
1744         else
1745         //4. solve top
1746         if (t == AUTO && h != AUTO && b != AUTO)
1747             t = ch - (h + b + mt + mb + pab);
1748         else
1749
1750         //5. solve height
1751         if (t != AUTO && h == AUTO && b != AUTO)
1752             h = ch - (t + b + mt + mb + pab);
1753         else
1754
1755         //6. solve bottom
1756         if (t != AUTO && h != AUTO && b == AUTO)
1757             b = ch - (h + t + mt + mb + pab);
1758     }
1759
1760     if (ourHeight < h + pab) //content must still fit
1761         ourHeight = h + pab;
1762
1763     if (hasOverflowClip() && ourHeight > h + pab)
1764         ourHeight = h + pab;
1765     
1766     // Do not allow the height to be negative.  This can happen when someone specifies both top and bottom
1767     // but the containing block height is less than top, e.g., top:20px, bottom:0, containing block height 16.
1768     ourHeight = max(0, ourHeight);
1769     
1770     h = ourHeight;
1771     y = t + mt + cb->borderTop();
1772 }
1773
1774 IntRect RenderBox::caretRect(int offset, EAffinity affinity, int* extraWidthToEndOfLine)
1775 {
1776     // FIXME: Is it OK to check only first child instead of picking
1777     // right child based on offset? Is it OK to pass the same offset
1778     // along to the child instead of offset 0 or whatever?
1779
1780     // propagate it downwards to its children, someone will feel responsible
1781     if (RenderObject* child = firstChild()) {
1782         IntRect result = child->caretRect(offset, affinity, extraWidthToEndOfLine);
1783         if (!result.isEmpty())
1784             return result;
1785     }
1786
1787     // if not, use the extents of this box 
1788     // offset 0 means left, offset 1 means right
1789     // FIXME: What about border and padding?
1790     const int caretWidth = 1;
1791     IntRect rect(xPos(), yPos(), caretWidth, m_height);
1792     if (offset != 0)
1793         rect.move(IntSize(m_width - caretWidth, 0));
1794     if (InlineBox* box = inlineBoxWrapper()) {
1795         RootInlineBox* rootBox = box->root();
1796         int top = rootBox->topOverflow();
1797         rect.setY(top);
1798         rect.setHeight(rootBox->bottomOverflow() - top);
1799     }
1800
1801     // If height of box is smaller than font height, use the latter one,
1802     // otherwise the caret might become invisible.
1803     // 
1804     // Also, if the box is not a replaced element, always use the font height.
1805     // This prevents the "big caret" bug described in:
1806     // <rdar://problem/3777804> Deleting all content in a document can result in giant tall-as-window insertion point
1807     //
1808     // FIXME: ignoring :first-line, missing good reason to take care of
1809     int fontHeight = style()->font().height();
1810     if (fontHeight > rect.height() || !isReplaced())
1811         rect.setHeight(fontHeight);
1812
1813     RenderObject* cb = containingBlock();
1814     int cbx, cby;
1815     if (!cb || !cb->absolutePosition(cbx, cby))
1816         // No point returning a relative position.
1817         return IntRect();
1818
1819     if (extraWidthToEndOfLine)
1820         *extraWidthToEndOfLine = xPos() + m_width - rect.right();
1821
1822     rect.move(cbx, cby);
1823     return rect;
1824 }
1825
1826 int RenderBox::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
1827 {
1828     return includeSelf ? m_height : 0;
1829 }
1830
1831 int RenderBox::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
1832 {
1833     return includeSelf ? m_width : 0;
1834 }
1835
1836 int RenderBox::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
1837 {
1838     return includeSelf ? 0 : m_width;
1839 }
1840
1841 }