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