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