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