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