khtml Library API Documentation

render_box.cpp

00001 
00024 // -------------------------------------------------------------------------
00025 //#define DEBUG_LAYOUT
00026 //#define CLIP_DEBUG
00027 
00028 
00029 #include <qpainter.h>
00030 
00031 #include "rendering/render_box.h"
00032 #include "rendering/render_replaced.h"
00033 #include "rendering/render_root.h"
00034 #include "misc/htmlhashes.h"
00035 #include "xml/dom_nodeimpl.h"
00036 
00037 #include <khtmlview.h>
00038 #include <kdebug.h>
00039 #include <kglobal.h>
00040 #include <assert.h>
00041 
00042 
00043 using namespace DOM;
00044 using namespace khtml;
00045 
00046 #define TABLECELLMARGIN -0x4000
00047 
00048 RenderBox::RenderBox(DOM::NodeImpl* node)
00049     : RenderContainer(node)
00050 {
00051     m_minWidth = -1;
00052     m_maxWidth = -1;
00053     m_width = m_height = 0;
00054     m_x = 0;
00055     m_y = 0;
00056     m_marginTop = 0;
00057     m_marginBottom = 0;
00058     m_marginLeft = 0;
00059     m_marginRight = 0;
00060 }
00061 
00062 void RenderBox::setStyle(RenderStyle *_style)
00063 {
00064     RenderObject::setStyle(_style);
00065 
00066     switch(_style->position())
00067     {
00068     case ABSOLUTE:
00069     case FIXED:
00070         setPositioned(true);
00071         break;
00072     default:
00073         setPositioned(false);
00074         if(!isTableCell() && _style->isFloating()) {
00075             setFloating(true);
00076         } else {
00077             if(_style->position() == RELATIVE)
00078                 setRelPositioned(true);
00079         }
00080     }
00081 }
00082 
00083 RenderBox::~RenderBox()
00084 {
00085     //kdDebug( 6040 ) << "Element destructor: this=" << nodeName().string() << endl;
00086 }
00087 
00088 short RenderBox::contentWidth() const
00089 {
00090     short w = m_width - style()->borderLeftWidth() - style()->borderRightWidth();
00091     w -= paddingLeft() + paddingRight();
00092 
00093     //kdDebug( 6040 ) << "RenderBox::contentWidth(2) = " << w << endl;
00094     return w;
00095 }
00096 
00097 int RenderBox::contentHeight() const
00098 {
00099     int h = m_height - style()->borderTopWidth() - style()->borderBottomWidth();
00100     h -= paddingTop() + paddingBottom();
00101 
00102     return h;
00103 }
00104 
00105 void RenderBox::setPos( int xPos, int yPos )
00106 {
00107     m_x = xPos; m_y = yPos;
00108 }
00109 
00110 short RenderBox::width() const
00111 {
00112     return m_width;
00113 }
00114 
00115 int RenderBox::height() const
00116 {
00117     return m_height;
00118 }
00119 
00120 
00121 // --------------------- painting stuff -------------------------------
00122 
00123 void RenderBox::paint(QPainter *p, int _x, int _y, int _w, int _h,
00124                                   int _tx, int _ty)
00125 {
00126     _tx += m_x;
00127     _ty += m_y;
00128 
00129     // default implementation. Just pass things through to the children
00130     RenderObject *child = firstChild();
00131     while(child != 0)
00132     {
00133         child->paint(p, _x, _y, _w, _h, _tx, _ty);
00134         child = child->nextSibling();
00135     }
00136 }
00137 
00138 void RenderBox::setPixmap(const QPixmap &, const QRect&, CachedImage *image)
00139 {
00140     if(image && image->pixmap_size() == image->valid_rect().size() && parent())
00141         repaint();      //repaint bg when it finished loading
00142 }
00143 
00144 
00145 void RenderBox::paintBoxDecorations(QPainter *p,int, int _y,
00146                                        int, int _h, int _tx, int _ty)
00147 {
00148     //kdDebug( 6040 ) << renderName() << "::paintDecorations()" << endl;
00149 
00150     int w = width();
00151     int h = height() + borderTopExtra() + borderBottomExtra();
00152     _ty -= borderTopExtra();
00153 
00154     int my = QMAX(_ty,_y);
00155     int end = QMIN( _y + _h,  _ty + h );
00156     int mh = end - my;
00157 
00158     paintBackground(p, style()->backgroundColor(), style()->backgroundImage(), my, mh, _tx, _ty, w, h);
00159 
00160     if(style()->hasBorder())
00161         paintBorder(p, _tx, _ty, w, h, style());
00162 }
00163 
00164 void RenderBox::paintBackground(QPainter *p, const QColor &c, CachedImage *bg, int clipy, int cliph, int _tx, int _ty, int w, int h)
00165 {
00166     if ( cliph < 0 )
00167     return;
00168 
00169     if(c.isValid())
00170         p->fillRect(_tx, clipy, w, cliph, c);
00171     // no progressive loading of the background image
00172     if(bg && bg->pixmap_size() == bg->valid_rect().size() && !bg->isTransparent() && !bg->isErrorImage()) {
00173         //kdDebug( 6040 ) << "painting bgimage at " << _tx << "/" << _ty << endl;
00174         // ### might need to add some correct offsets
00175         // ### use paddingX/Y
00176 
00177         //hacky stuff
00178         RenderStyle* sptr = style();
00179         if ( isHtml() && firstChild() && !style()->backgroundImage() )
00180             sptr = firstChild()->style();
00181 
00182         int sx = 0;
00183         int sy = 0;
00184         int cw,ch;
00185         int cx,cy;
00186         int vpab = borderRight() + borderLeft();
00187         int hpab = borderTop() + borderBottom();
00188 
00189         // CSS2 chapter 14.2.1
00190 
00191     int pixw = bg->pixmap_size().width();
00192     int pixh = bg->pixmap_size().height();
00193         if (sptr->backgroundAttachment())
00194         {
00195             //scroll
00196             int pw = m_width - vpab;
00197             int ph = m_height - hpab;
00198             EBackgroundRepeat bgr = sptr->backgroundRepeat();
00199             if( (bgr == NO_REPEAT || bgr == REPEAT_Y) && w > pixw ) {
00200                 cw = pixw;
00201                 cx = _tx + sptr->backgroundXPosition().minWidth(pw-pixw);
00202             } else {
00203                 cw = w-vpab;
00204                 cx = _tx;
00205                 sx =  pixw - ((sptr->backgroundXPosition().minWidth(pw-pixw)) % pixw );
00206             }
00207 
00208             cx += borderLeft();
00209 
00210             if( (bgr == NO_REPEAT || bgr == REPEAT_X) && h > pixh ) {
00211                 ch = pixh;
00212                 cy = _ty + sptr->backgroundYPosition().minWidth(ph-pixh);
00213             } else {
00214                 ch = h-hpab;
00215                 cy = _ty;
00216                 sy = pixh - ((sptr->backgroundYPosition().minWidth(ph-pixh)) % pixh );
00217             }
00218 
00219             cy += borderTop();
00220         }
00221         else
00222         {
00223             //fixed
00224             QRect vr = viewRect();
00225             int pw = vr.width();
00226             int ph = vr.height();
00227 
00228             EBackgroundRepeat bgr = sptr->backgroundRepeat();
00229             if( (bgr == NO_REPEAT || bgr == REPEAT_Y) && w > pixw ) {
00230                 cw = pixw;
00231                 cx = vr.x() + sptr->backgroundXPosition().minWidth(pw-pixw);
00232             } else {
00233                 cw = pw;
00234                 cx = vr.x();
00235                 sx =  pixw - ((sptr->backgroundXPosition().minWidth(pw-pixw)) % pixw );
00236             }
00237 
00238             if( (bgr == NO_REPEAT || bgr == REPEAT_X) && h > pixh ) {
00239                 ch = pixh;
00240                 cy = vr.y() + sptr->backgroundYPosition().minWidth(ph-pixh);
00241             } else {
00242                 ch = ph;
00243                 cy = vr.y();
00244                 sy = pixh - ((sptr->backgroundYPosition().minWidth(ph-pixh)) % pixh );
00245             }
00246 
00247             QRect fix(cx,cy,cw,ch);
00248             QRect ele(_tx+borderLeft(),_ty+borderTop(),w-vpab,h-hpab);
00249             QRect b = fix.intersect(ele);
00250             sx+=b.x()-cx;
00251             sy+=b.y()-cy;
00252             cx=b.x();cy=b.y();cw=b.width();ch=b.height();
00253         }
00254 
00255 
00256         //kdDebug() << "cy="<<cy<< " ch="<<ch << " clipy=" << clipy << " cliph=" << cliph << " sx="<<sx << " sy="<<sy << endl;
00257     int diff = clipy - cy;
00258     if ( diff > 0 ) {
00259         cy += diff;
00260         sy += diff;
00261         sy %= pixh;
00262         ch -= diff;
00263     }
00264     ch = QMIN( ch, clipy + cliph - cy );
00265     //kdDebug() << "clip="<<cx << " cy="<<cy<< " cw="<<cw << " ch="<<ch << " sx="<<sx << " sy="<<sy << endl;
00266 
00267         if (cw>0 && ch>0)
00268             p->drawTiledPixmap(cx, cy, cw, ch, bg->tiled_pixmap(c), sx, sy);
00269 //            p->drawTiledPixmap(cx, cy, cw, ch, bg->pixmap(), sx, sy);
00270 
00271     }
00272 }
00273 
00274 void RenderBox::outlineBox(QPainter *p, int _tx, int _ty, const char *color)
00275 {
00276     p->setPen(QPen(QColor(color), 1, Qt::DotLine));
00277     p->setBrush( Qt::NoBrush );
00278     p->drawRect(_tx, _ty, m_width, m_height);
00279 }
00280 
00281 
00282 void RenderBox::calcClip(QPainter* p, int tx, int ty)
00283 {
00284     int clipw = m_width;
00285     int cliph = m_height;
00286 
00287     bool rtl = (style()->direction() == RTL);
00288 
00289     int clipleft = 0;
00290     int clipright = clipw;
00291     int cliptop = 0;
00292     int clipbottom = cliph;
00293 
00294     if ( style()->clipSpecified() && style()->position() == ABSOLUTE ) {
00295     // the only case we use the clip property according to CSS 2.1
00296     if (!style()->clipLeft().isVariable()) {
00297         int c = style()->clipLeft().width(clipw);
00298         if ( rtl )
00299         clipleft = clipw - c;
00300         else
00301         clipleft = c;
00302     }
00303     if (!style()->clipRight().isVariable()) {
00304         int w = style()->clipRight().width(clipw);
00305         if ( rtl ) {
00306         clipright = clipw - w;
00307         } else {
00308         clipright = w;
00309         }
00310     }
00311     if (!style()->clipTop().isVariable())
00312         cliptop = style()->clipTop().width(cliph);
00313     if (!style()->clipBottom().isVariable())
00314         clipbottom = style()->clipBottom().width(cliph);
00315     }
00316     int clipx = tx + clipleft;
00317     int clipy = ty + cliptop;
00318     clipw = clipright-clipleft;
00319     cliph = clipbottom-cliptop;
00320 
00321 
00322     QRect cr(clipx,clipy,clipw,cliph);
00323     cr = p->xForm(cr);
00324     QRegion creg(cr);
00325     QRegion old = p->clipRegion();
00326     if (!old.isNull())
00327         creg = old.intersect(creg);
00328 
00329 #ifdef CLIP_DEBUG
00330     kdDebug( 6040 ) << renderName() << ":" << this << ": setting clip("<<clipx<<","<<clipy<<","<<clipw<<","<<cliph<<") tx="<<tx<<" ty="<<ty<<endl;
00331     p->setPen(QPen(Qt::red, 1, Qt::DotLine));
00332     p->setBrush( Qt::NoBrush );
00333     p->drawRect(clipx, clipy, clipw, cliph);
00334 #endif
00335 
00336     p->save();
00337     p->setClipRegion(creg);
00338 }
00339 
00340 void RenderBox::close()
00341 {
00342     setMinMaxKnown(false);
00343     setLayouted( false );
00344 }
00345 
00346 short RenderBox::containingBlockWidth() const
00347 {
00348     if ( ( style()->htmlHacks() || isTable() ) && style()->flowAroundFloats() && containingBlock()->isFlow()
00349             && style()->width().isVariable())
00350         return static_cast<RenderFlow*>(containingBlock())->lineWidth(m_y);
00351     else
00352         return containingBlock()->contentWidth();
00353 }
00354 
00355 bool RenderBox::absolutePosition(int &xPos, int &yPos, bool f)
00356 {
00357     if ( style()->position() == FIXED )
00358     f = true;
00359     RenderObject *o = container();
00360     if( o && o->absolutePosition(xPos, yPos, f))
00361     {
00362         if(!isInline() || isReplaced())
00363             xPos += m_x, yPos += m_y;
00364 
00365         if(isRelPositioned())
00366             relativePositionOffset(xPos, yPos);
00367         return true;
00368     }
00369     else
00370     {
00371         xPos = yPos = 0;
00372         return false;
00373     }
00374 }
00375 
00376 void RenderBox::position(int x, int y, int, int, int, bool, bool, int)
00377 {
00378     m_x = x + marginLeft();
00379     m_y = y;
00380     // ### paddings
00381     //m_width = width;
00382 }
00383 
00384 void RenderBox::repaint()
00385 {
00386     //kdDebug( 6040 ) << "repaint!" << endl;
00387     int ow = style() ? style()->outlineWidth() : 0;
00388     repaintRectangle(-ow, -ow, m_width+ow*2, m_height+ow*2);
00389 }
00390 
00391 void RenderBox::repaintRectangle(int x, int y, int w, int h, bool f)
00392 {
00393     x += m_x;
00394     y += m_y;
00395 
00396     if (style()->position()==FIXED) f=true;
00397 
00398     // kdDebug( 6040 ) << "RenderBox(" << renderName() << ")::repaintRectangle (" << x << "/" << y << ") (" << w << "/" << h << ")" << endl;
00399     RenderObject *o = container();
00400     if( o ) o->repaintRectangle(x, y, w, h, f);
00401 }
00402 
00403 void RenderBox::relativePositionOffset(int &tx, int &ty)
00404 {
00405     if(!style()->left().isVariable())
00406         tx += style()->left().width(containingBlockWidth());
00407     else if(!style()->right().isVariable())
00408         tx -= style()->right().width(containingBlockWidth());
00409     if(!style()->top().isVariable())
00410     {
00411         if (!style()->top().isPercent()
00412                 || containingBlock()->style()->height().isFixed())
00413             ty += style()->top().width(containingBlockHeight());
00414     }
00415     else if(!style()->bottom().isVariable())
00416     {
00417         if (!style()->bottom().isPercent()
00418                 || containingBlock()->style()->height().isFixed())
00419             ty -= style()->bottom().width(containingBlockHeight());
00420     }
00421 }
00422 
00423 void RenderBox::calcWidth()
00424 {
00425 #ifdef DEBUG_LAYOUT
00426     kdDebug( 6040 ) << "RenderBox("<<renderName()<<")::calcWidth()" << endl;
00427 #endif
00428     if (isPositioned())
00429     {
00430         calcAbsoluteHorizontal();
00431     }
00432     else
00433     {
00434         Length w;
00435         if ( isReplaced () )
00436             w = Length( calcReplacedWidth(), Fixed );
00437         else
00438             w = style()->width();
00439 
00440         Length ml = style()->marginLeft();
00441         Length mr = style()->marginRight();
00442 
00443         int cw;
00444     RenderObject *cb = containingBlock();
00445     if ( style()->flowAroundFloats() && cb->isFlow() )
00446         cw = static_cast<RenderFlow *>(cb)->lineWidth( m_y );
00447     else
00448         cw = cb->contentWidth();
00449 
00450         if (cw<0) cw = 0;
00451 
00452         m_marginLeft = 0;
00453         m_marginRight = 0;
00454 
00455         if (isInline())
00456         {
00457             // just calculate margins
00458             m_marginLeft = ml.minWidth(cw);
00459             m_marginRight = mr.minWidth(cw);
00460             if (isReplaced())
00461             {
00462                 m_width = w.width(cw);
00463                 m_width += paddingLeft() + paddingRight() + style()->borderLeftWidth() + style()->borderRightWidth();
00464 
00465                 if(m_width < m_minWidth) m_width = m_minWidth;
00466             }
00467 
00468             return;
00469         }
00470         else if (w.type == Variable)
00471         {
00472 //          kdDebug( 6040 ) << "variable" << endl;
00473             m_marginLeft = ml.minWidth(cw);
00474             m_marginRight = mr.minWidth(cw);
00475             if (cw) m_width = cw - m_marginLeft - m_marginRight;
00476 
00477 //          kdDebug( 6040 ) <<  m_width <<"," << cw <<"," <<
00478 //              m_marginLeft <<"," <<  m_marginRight << endl;
00479 
00480             if (isFloating()) {
00481                 if(m_width < m_minWidth) m_width = m_minWidth;
00482                 if(m_width > m_maxWidth) m_width = m_maxWidth;
00483             }
00484         }
00485         else
00486         {
00487 //          kdDebug( 6040 ) << "non-variable " << w.type << ","<< w.value << endl;
00488             m_width = w.width(cw);
00489             m_width += paddingLeft() + paddingRight() + style()->borderLeftWidth() + style()->borderRightWidth();
00490 
00491             calcHorizontalMargins(ml,mr,cw);
00492         }
00493 
00494         if (cw && cw != m_width + m_marginLeft + m_marginRight && !isFloating() && !isInline())
00495         {
00496             if (style()->direction()==LTR)
00497                 m_marginRight = cw - m_width - m_marginLeft;
00498             else
00499                 m_marginLeft = cw - m_width - m_marginRight;
00500         }
00501     }
00502 
00503 #ifdef DEBUG_LAYOUT
00504     kdDebug( 6040 ) << "RenderBox::calcWidth(): m_width=" << m_width << " containingBlockWidth()=" << containingBlockWidth() << endl;
00505     kdDebug( 6040 ) << "m_marginLeft=" << m_marginLeft << " m_marginRight=" << m_marginRight << endl;
00506 #endif
00507 }
00508 
00509 void RenderBox::calcHorizontalMargins(const Length& ml, const Length& mr, int cw)
00510 {
00511     if (isFloating())
00512     {
00513         m_marginLeft = ml.minWidth(cw);
00514         m_marginRight = mr.minWidth(cw);
00515     }
00516     else
00517     {
00518         if ( (ml.type == Variable && mr.type == Variable) ||
00519              (!(ml.type == Variable) &&
00520                 containingBlock()->style()->textAlign() == KONQ_CENTER) )
00521         {
00522             m_marginLeft = (cw - m_width)/2;
00523             if (m_marginLeft<0) m_marginLeft=0;
00524             m_marginRight = cw - m_width - m_marginLeft;
00525         }
00526         else if (mr.type == Variable)
00527         {
00528             m_marginLeft = ml.width(cw);
00529             m_marginRight = cw - m_width - m_marginLeft;
00530         }
00531         else if (ml.type == Variable)
00532         {
00533             m_marginRight = mr.width(cw);
00534             m_marginLeft = cw - m_width - m_marginRight;
00535         }
00536         else
00537         {
00538             m_marginLeft = ml.minWidth(cw);
00539             m_marginRight = mr.minWidth(cw);
00540         }
00541     }
00542 }
00543 
00544 void RenderBox::calcHeight()
00545 {
00546 
00547 #ifdef DEBUG_LAYOUT
00548     kdDebug( 6040 ) << "RenderBox::calcHeight()" << endl;
00549 #endif
00550 
00551     //cell height is managed by table, inline elements do not have a height property.
00552     if ( isTableCell() || (isInline() && !isReplaced()) )
00553         return;
00554 
00555     if (isPositioned())
00556         calcAbsoluteVertical();
00557     else
00558     {
00559         Length h;
00560         if ( isReplaced() && !isFlow() )
00561             h = Length( calcReplacedHeight(), Fixed );
00562         else
00563             h = style()->height();
00564 
00565         calcVerticalMargins();
00566 
00567         // for tables, calculate margins only
00568         if (isTable())
00569             return;
00570 
00571         if (!h.isVariable())
00572         {
00573             int fh=-1;
00574             if (h.isFixed())
00575                 fh = h.value + borderTop() + paddingTop() + borderBottom() + paddingBottom();
00576             else if (h.isPercent()) {
00577                 Length ch = containingBlock()->style()->height();
00578                 if (ch.isFixed())
00579                     fh = h.width(ch.value) + borderTop() + paddingTop() + borderBottom() + paddingBottom();
00580             }
00581             if (fh!=-1)
00582             {
00583                 if (fh<m_height && !overhangingContents() && style()->overflow()==OVISIBLE)
00584                     setOverhangingContents();
00585 
00586                 m_height = fh;
00587             }
00588         }
00589     }
00590 }
00591 
00592 short RenderBox::calcReplacedWidth() const
00593 {
00594     Length w = style()->width();
00595 
00596     switch( w.type ) {
00597     case Fixed:
00598         return w.value;
00599     case Percent:
00600     {
00601         const int cw = containingBlockWidth();
00602         if (cw > 0)
00603             return w.minWidth(cw);
00604     }
00605     // fall through
00606     default:
00607         return intrinsicWidth();
00608     }
00609 }
00610 
00611 int RenderBox::calcReplacedHeight() const
00612 {
00613     const Length& h = style()->height();
00614     switch( h.type ) {
00615     case Percent:
00616         return availableHeight();
00617     case Fixed:
00618         return h.value;
00619     default:
00620         return intrinsicHeight();
00621     };
00622 }
00623 
00624 int RenderBox::availableHeight() const
00625 {
00626     Length h = style()->height();
00627 
00628     if (h.isFixed())
00629         return h.value;
00630 
00631     if (isRoot())
00632         return static_cast<const RenderRoot*>(this)->viewportHeight();
00633 
00634     if (h.isPercent())
00635         return h.width(containingBlock()->availableHeight());
00636 
00637     return containingBlock()->availableHeight();
00638 }
00639 
00640 void RenderBox::calcVerticalMargins()
00641 {
00642     if( isTableCell() ) {
00643     // table margins are basically infinite
00644     m_marginTop = TABLECELLMARGIN;
00645     m_marginBottom = TABLECELLMARGIN;
00646     return;
00647     }
00648 
00649     Length tm = style()->marginTop();
00650     Length bm = style()->marginBottom();
00651 
00652     // margins are calculated with respect to the _width_ of
00653     // the containing block (8.3)
00654     int cw = containingBlock()->contentWidth();
00655 
00656     m_marginTop = tm.minWidth(cw);
00657     m_marginBottom = bm.minWidth(cw);
00658 }
00659 
00660 void RenderBox::calcAbsoluteHorizontal()
00661 {
00662     const int AUTO = -666666;
00663     int l,r,w,ml,mr,cw;
00664 
00665     RenderObject* cb = containingBlock();
00666     int pab = borderLeft()+ borderRight()+ paddingLeft()+ paddingRight();
00667 
00668     l=r=ml=mr=w=AUTO;
00669     cw = containingBlock()->width();
00670 
00671     if(!style()->left().isVariable())
00672         l = style()->left().width(cw) + cb->borderLeft();
00673     if(!style()->right().isVariable())
00674         r = style()->right().width(cw) + cb->borderRight();
00675     if(!style()->width().isVariable())
00676         w = style()->width().width(cw);
00677     else if (isReplaced())
00678         w = intrinsicWidth();
00679     if(!style()->marginLeft().isVariable())
00680         ml = style()->marginLeft().width(cw);
00681     if(!style()->marginRight().isVariable())
00682         mr = style()->marginRight().width(cw);
00683 
00684 
00685     //qDebug("h1: w=%d, l=%d, r=%d, ml=%d, mr=%d",w,l,r,ml,mr);
00686 
00687     int static_distance=0;
00688     if ((style()->direction()==LTR && (l==AUTO && r==AUTO ))
00689             || style()->left().isStatic())
00690     {
00691         // calc hypothetical location in the normal flow
00692         // used for 1) left=static-position
00693         //          2) left, right, width are all auto -> calc top -> 3.
00694         //          3) precalc for case 2 below
00695 
00696         // all positioned elements are blocks, so that
00697         // would be at the left edge
00698         for (RenderObject* po = parent(); po && po != cb; po = po->parent())
00699             static_distance += po->xPos();
00700 
00701         static_distance += parent()->paddingLeft() + parent()->borderLeft();
00702 
00703         if (l==AUTO || style()->left().isStatic())
00704             l = static_distance;
00705     }
00706 
00707     else if ((style()->direction()==RTL && (l==AUTO && r==AUTO ))
00708             || style()->right().isStatic())
00709     {
00710         static_distance = cw - parent()->width();
00711 
00712         for (RenderObject* po = parent(); po && po != cb; po = po->parent())
00713             static_distance -= po->xPos();
00714 
00715         static_distance -= parent()->paddingRight() + parent()->borderRight();
00716         if (r==AUTO || style()->right().isStatic())
00717             r = static_distance;
00718     }
00719 
00720 
00721     if (l!=AUTO && w!=AUTO && r!=AUTO)
00722     {
00723         // left, width, right all given, play with margins
00724         int ot = l + w + r + pab;
00725 
00726         if (ml==AUTO && mr==AUTO)
00727         {
00728             // both margins auto, solve for equality
00729             ml = (cw - ot)/2;
00730             mr = cw - ot - ml;
00731         }
00732         else if (ml==AUTO)
00733             // solve for left margin
00734             ml = cw - ot - mr;
00735         else if (mr==AUTO)
00736             // solve for right margin
00737             mr = cw - ot - ml;
00738         else
00739         {
00740             // overconstrained, solve according to dir
00741             if (style()->direction()==LTR)
00742                 r = cw - ( l + w + ml + mr + pab);
00743             else
00744                 l = cw - ( r + w + ml + mr + pab);
00745         }
00746     }
00747     else
00748     {
00749         // one or two of (left, width, right) missing, solve
00750 
00751         // auto margins are ignored
00752         if (ml==AUTO) ml = 0;
00753         if (mr==AUTO) mr = 0;
00754 
00755         //1. solve left & width.
00756         if (l==AUTO && w==AUTO && r!=AUTO) {
00757             w = kMin( int ( m_maxWidth ), kMax(cw - ( r + ml + mr + pab), int ( m_minWidth ) ));
00758             l = cw - ( r + w + ml + mr + pab);
00759         }
00760         else
00761         //2. solve left & right. use static positioning.
00762         if (l==AUTO && w!=AUTO && r==AUTO) {
00763             if (style()->direction()==RTL) {
00764                 r = static_distance;
00765                 l = cw - ( r + w + ml + mr + pab);
00766             }
00767             else {
00768                 l = static_distance;
00769                 r = cw - ( l + w + ml + mr + pab);
00770             }
00771         }
00772         else
00773         //3. solve width & right.
00774         if (l!=AUTO && w==AUTO && r==AUTO) {
00775             w = kMin(int ( m_maxWidth ), kMax( int ( m_minWidth ), cw - ( l + ml + mr + pab)));
00776             r = cw - ( l + w + ml + mr + pab);
00777         }
00778         else
00779 
00780         //4. solve left
00781         if (l==AUTO && w!=AUTO && r!=AUTO)
00782             l = cw - ( r + w + ml + mr + pab);
00783         else
00784 
00785         //5. solve width
00786         if (l!=AUTO && w==AUTO && r!=AUTO)
00787             w = cw - ( r + l + ml + mr + pab);
00788         else
00789 
00790         //6. solve right
00791         if (l!=AUTO && w!=AUTO && r==AUTO)
00792             r = cw - ( l + w + ml + mr + pab);
00793     }
00794 
00795     m_width = w + pab;
00796     m_marginLeft = ml;
00797     m_marginRight = mr;
00798     m_x = l + ml;
00799 
00800     //qDebug("h: w=%d, l=%d, r=%d, ml=%d, mr=%d",w,l,r,ml,mr);
00801 }
00802 
00803 
00804 void RenderBox::calcAbsoluteVertical()
00805 {
00806     // css2 spec 10.6.4 & 10.6.5
00807 
00808     // based on
00809     // http://www.w3.org/Style/css2-updates/REC-CSS2-19980512-errata
00810     // (actually updated 2000-10-24)
00811     // that introduces static-position value for top, left & right
00812 
00813     const int AUTO = -666666;
00814     int t,b,h,mt,mb,ch;
00815 
00816     t=b=h=mt=mb=AUTO;
00817 
00818     int pab = borderTop()+borderBottom()+paddingTop()+paddingBottom();
00819     RenderObject* cb = containingBlock();
00820 
00821     Length hl = cb->style()->height();
00822     if (hl.isFixed())
00823         ch = hl.value + cb->paddingTop() + cb->paddingBottom()
00824          + cb->borderTop() + cb->borderBottom();
00825     else if (cb->isHtml())
00826         ch = cb->availableHeight();
00827     else
00828         ch = cb->height();
00829 
00830     if(!style()->top().isVariable())
00831         t = style()->top().width(ch) + cb->borderTop();
00832     if(!style()->bottom().isVariable())
00833         b = style()->bottom().width(ch) + cb->borderBottom();
00834     if(!style()->height().isVariable())
00835     {
00836         h = style()->height().width(ch);
00837         if (m_height-pab>h)
00838             h=m_height-pab;
00839     }
00840     else if (isReplaced())
00841         h = intrinsicHeight();
00842 
00843     if(!style()->marginTop().isVariable())
00844         mt = style()->marginTop().width(ch);
00845     if(!style()->marginBottom().isVariable())
00846         mb = style()->marginBottom().width(ch);
00847 
00848     int static_top=0;
00849     if ((t==AUTO && b==AUTO ) || style()->top().isStatic())
00850     {
00851         // calc hypothetical location in the normal flow
00852         // used for 1) top=static-position
00853         //          2) top, bottom, height are all auto -> calc top -> 3.
00854         //          3) precalc for case 2 below
00855 
00856         RenderObject* ro = previousSibling();
00857         while ( ro && ro->isPositioned())
00858             ro = ro->previousSibling();
00859 
00860         if (ro)
00861             static_top = ro->yPos()+ro->marginBottom()+ro->height();
00862         else {
00863             // we're only dealing with blocklevel positioned elements
00864             // currently, so this is easy
00865             for (RenderObject* po = parent(); po && po != cb; po = po->parent())
00866                 static_top += po->yPos();
00867 
00868             static_top += parent()->paddingTop() + parent()->borderTop();
00869         }
00870 
00871         if (h==AUTO || style()->top().isStatic())
00872             t = static_top;
00873     }
00874 
00875     if (t!=AUTO && h!=AUTO && b!=AUTO)
00876     {
00877         // top, height, bottom all given, play with margins
00878         int ot = h + t + b + pab;
00879 
00880         if (mt==AUTO && mb==AUTO)
00881         {
00882             // both margins auto, solve for equality
00883             mt = (ch - ot)/2;
00884             mb = ch - ot - mt;
00885         }
00886         else if (mt==AUTO)
00887             // solve for top margin
00888             mt = ch - ot - mb;
00889         else if (mb==AUTO)
00890             // solve for bottom margin
00891             mb = ch - ot - mt;
00892         else
00893             // overconstrained, solve for bottom
00894             b = ch - ( h+t+mt+mb+pab);
00895     }
00896     else
00897     {
00898         // one or two of (top, height, bottom) missing, solve
00899 
00900         // auto margins are ignored
00901         if (mt==AUTO) mt = 0;
00902         if (mb==AUTO) mb = 0;
00903 
00904         //1. solve top & height. use content height.
00905         if (t==AUTO && h==AUTO && b!=AUTO)
00906         {
00907             h = m_height-pab;
00908             t = ch - ( h+b+mt+mb+pab);
00909         }
00910         else
00911 
00912         //2. solve top & bottom. use static positioning.
00913         if (t==AUTO && h!=AUTO && b==AUTO)
00914         {
00915             t = static_top;
00916             b = ch - ( h+t+mt+mb+pab);
00917         }
00918         else
00919 
00920         //3. solve height & bottom. use content height.
00921         if (t!=AUTO && h==AUTO && b==AUTO)
00922         {
00923             h = m_height-pab;
00924             b = ch - ( h+t+mt+mb+pab);
00925         }
00926         else
00927 
00928         //4. solve top
00929         if (t==AUTO && h!=AUTO && b!=AUTO)
00930             t = ch - ( h+b+mt+mb+pab);
00931         else
00932 
00933         //5. solve height
00934         if (t!=AUTO && h==AUTO && b!=AUTO)
00935             h = ch - ( t+b+mt+mb+pab);
00936         else
00937 
00938         //6. solve bottom
00939         if (t!=AUTO && h!=AUTO && b==AUTO)
00940             b = ch - ( h+t+mt+mb+pab);
00941     }
00942 
00943 
00944     if (m_height<h+pab) //content must still fit
00945         m_height = h+pab;
00946 
00947     m_marginTop = mt;
00948     m_marginBottom = mb;
00949     m_y = t + mt;
00950 
00951     //paintf("v: h=%d, t=%d, b=%d, mt=%d, mb=%d, m_y=%d\n",h,t,b,mt,mb,m_y);
00952 
00953 }
00954 
00955 
00956 int RenderBox::lowestPosition() const
00957 {
00958     return m_height + marginBottom();
00959 }
00960 
00961 int RenderBox::rightmostPosition() const
00962 {
00963     return m_width;
00964 }
00965 
00966 #undef DEBUG_LAYOUT
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.0.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Oct 8 12:22:42 2003 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2001