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