render_flow.cpp Source File (khtml Library)

| # khtml Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# render_flow.cpp

    00001
    00023 // -------------------------------------------------------------------------
    00024 //#define DEBUG
    00025 //#define DEBUG_LAYOUT
    00026 //#define BOX_DEBUG
    00027 //#define FLOAT_DEBUG
    00028
    00029 #include <kdebug.h>
    00030 #include <assert.h>
    00031 #include <qpainter.h>
    00032 #include <kglobal.h>
    00033 #include <limits.h>
    00034
    00035 #include "rendering/render_flow.h"
    00036 #include "rendering/render_text.h"
    00037 #include "rendering/render_table.h"
    00038 #include "rendering/render_root.h"
    00039 #include "xml/dom_nodeimpl.h"
    00040 #include "khtmlview.h"
    00041 using namespace DOM;
    00042 using namespace khtml;
    00043
    00044 #define TABLECELLMARGIN -0x4000
    00045
    00046
    00047 static inline int collapseMargins(int a, int b)
    00048 {
    00049     if ( a == TABLECELLMARGIN || b == TABLECELLMARGIN ) return TABLECELLMARGIN;
    00050     if(a >= 0 && b >= 0) return (a > b ? a : b );
    00051     if(a > 0 && b < 0) return a + b;
    00052     if(a < 0 && b > 0) return b + a;
    00053     return ( a > b ? b : a);
    00054 }
    00055
    00056
    00057 bool RenderFlow::SpecialObject::operator < ( const RenderFlow::SpecialObject &o ) const
    00058 {
    00059     int zIndex1 = node->style()->zIndex();
    00060     int zIndex2 = o.node->style()->zIndex();
    00061     // we need to make sure floating items come first, as positioned ones are always on top of them.
    00062     if ( !node->isPositioned() )
    00063         zIndex1 = -INT_MAX;
    00064     if ( !o.node->isPositioned() )
    00065         zIndex2 = -INT_MAX;
    00066     if(zIndex1 == zIndex2)
    00067         return count < o.count;
    00068     return zIndex1 < zIndex2;
    00069 }
    00070
    00071
    00072 RenderFlow::RenderFlow(DOM::NodeImpl* node)
    00073     : RenderBox(node)
    00074 {
    00075     m_childrenInline = true;
    00076     m_pre = false;
    00077     firstLine = false;
    00078     m_clearStatus = CNONE;
    00079
    00080     specialObjects = 0;
    00081 }
    00082
    00083 void RenderFlow::setStyle(RenderStyle *_style)
    00084 {
    00085
    00086 //    kdDebug( 6040 ) << (void*)this<< " renderFlow(" << renderName() << ")::setstyle()" << endl;
    00087
    00088     RenderBox::setStyle(_style);
    00089
    00090     if(isPositioned())
    00091         setInline(false);
    00092
    00093     if(isFloating() || !style()->display() == INLINE)
    00094         setInline(false);
    00095
    00096     if (isInline() && !m_childrenInline)
    00097         setInline(false);
    00098
    00099     m_pre = (style()->whiteSpace() == PRE);
    00100     // ### we could save this call when the change only affected
    00101     // non inherited properties
    00102     RenderObject*child = firstChild();
    00103     RenderStyle* newStyle;
    00104     if (!isInline() && child &&
    00105         ( newStyle=style()->getPseudoStyle(RenderStyle::FIRST_LETTER) ) ) {
    00106         child->setStyle(newStyle);
    00107         child = child->nextSibling();
    00108     }
    00109
    00110     while(child != 0)
    00111     {
    00112         if(child->isAnonymousBox())
    00113         {
    00114             RenderStyle* newStyle = new RenderStyle();
    00115             newStyle->inheritFrom(style());
    00116             newStyle->setDisplay(BLOCK);
    00117             child->setStyle(newStyle);
    00118             child->setIsAnonymousBox(true);
    00119         }
    00120         child = child->nextSibling();
    00121     }
    00122 }
    00123
    00124 RenderFlow::~RenderFlow()
    00125 {
    00126     delete specialObjects;
    00127 }
    00128
    00129 FindSelectionResult RenderFlow::checkSelectionPoint( int _x, int _y, int _tx, int _ty, DOM::NodeImpl*& node, int & offset )
    00130 {
    00131     int lastOffset=0;
    00132     int off = offset;
    00133     DOM::NodeImpl* nod = node;
    00134     DOM::NodeImpl* lastNode = 0;
    00135     for (RenderObject *child = firstChild(); child; child=child->nextSibling()) {
    00136         khtml::FindSelectionResult pos = child->checkSelectionPoint(_x, _y, _tx+xPos(), _ty+yPos(), nod, off);
    00137         //kdDebug(6030) << this << " child->findSelectionNode returned result=" << pos << " nod=" << nod << " off=" << off << endl;
    00138         switch(pos) {
    00139         case SelectionPointBeforeInLine:
    00140         case SelectionPointAfterInLine:
    00141         case SelectionPointInside:
    00142             //kdDebug(6030) << "RenderObject::checkSelectionPoint " << this << " returning SelectionPointInside offset=" << offset << endl;
    00143             node = nod;
    00144             offset = off;
    00145             return SelectionPointInside;
    00146         case SelectionPointBefore:
    00147             //x,y is before this element -> stop here
    00148             if ( lastNode ) {
    00149                 node = lastNode;
    00150                 offset = lastOffset;
    00151                 //kdDebug(6030) << "RenderObject::checkSelectionPoint " << this << " before this child "
    00152                 //              << node << "-> returning SelectionPointInside, offset=" << offset << endl;
    00153                 return SelectionPointInside;
    00154             } else {
    00155                 node = nod;
    00156                 offset = off;
    00157                 //kdDebug(6030) << "RenderObject::checkSelectionPoint " << this << " before us -> returning SelectionPointBefore " << node << "/" << offset << endl;
    00158                 return SelectionPointBefore;
    00159             }
    00160             break;
    00161         case SelectionPointAfter:
    00162             //kdDebug(6030) << "RenderObject::checkSelectionPoint: selection after: " << nod << " offset: " << off << endl;
    00163             lastNode = nod;
    00164             lastOffset = off;
    00165             // No "return" here, obviously. We must keep looking into the children.
    00166             break;
    00167         }
    00168     }
    00169     // If we are after the last child, return lastNode/lastOffset
    00170     // But lastNode can be 0L if there is no child, for instance.
    00171     if ( lastNode )
    00172     {
    00173         node = lastNode;
    00174         offset = lastOffset;
    00175     }
    00176     //kdDebug(6030) << "fallback - SelectionPointAfter  node=" << node << " offset=" << offset << endl;
    00177     return SelectionPointAfter;
    00178 }
    00179
    00180 void RenderFlow::paint(QPainter *p, int _x, int _y, int _w, int _h,
    00181                                  int _tx, int _ty)
    00182 {
    00183
    00184 #ifdef DEBUG_LAYOUT
    00185 //    kdDebug( 6040 ) << renderName() << "(RenderFlow) " << this << " ::paint() x/y/w/h = ("  << xPos() << "/" << yPos() << "/" << width() << "/" << height()  << ")" << endl;
    00186 #endif
    00187
    00188     if(!isInline())
    00189     {
    00190         _tx += m_x;
    00191         _ty += m_y;
    00192     }
    00193
    00194     // check if we need to do anything at all...
    00195     if(!isInline() && !overhangingContents() && !isRelPositioned() && !isPositioned() )
    00196     {
    00197         int h = m_height;
    00198         if(specialObjects && floatBottom() > h) h = floatBottom();
    00199         if((_ty > _y + _h) || (_ty + h < _y))
    00200         {
    00201             //kdDebug( 6040 ) << "cut!" << endl;
    00202             return;
    00203         }
    00204     }
    00205
    00206     paintObject(p, _x, _y, _w, _h, _tx, _ty);
    00207 }
    00208
    00209 void RenderFlow::paintObject(QPainter *p, int _x, int _y,
    00210                                        int _w, int _h, int _tx, int _ty)
    00211 {
    00212     if(isRelPositioned())
    00213         relativePositionOffset(_tx, _ty);
    00214
    00215     bool clipped = false;
    00216     // overflow: hidden
    00217     if (style()->overflow()==OHIDDEN || (style()->position() == ABSOLUTE && style()->clipSpecified()) ) {
    00218         calcClip(p, _tx, _ty);
    00219         clipped = true;
    00220     }
    00221
    00222     // 1. paint background, borders etc
    00223     if(hasSpecialObjects() && !isInline() && style()->visibility() == VISIBLE )
    00224         paintBoxDecorations(p, _x, _y, _w, _h, _tx, _ty);
    00225
    00226     // 2. paint contents
    00227     for ( RenderObject* child = firstChild(); child; child = child->nextSibling() )
    00228         if(!child->isSpecial())
    00229             child->paint(p, _x, _y, _w, _h, _tx, _ty);
    00230
    00231     // 3. paint floats and other non-flow objects
    00232     if(specialObjects)
    00233         paintSpecialObjects( p,  _x, _y, _w, _h, _tx , _ty);
    00234
    00235     // overflow: hidden
    00236     // restore clip region
    00237     if ( clipped ) {
    00238         p->restore();
    00239     }
    00240
    00241     if(!isInline() && !childrenInline() && style()->outlineWidth())
    00242         paintOutline(p, _tx, _ty, width(), height(), style());
    00243
    00244 #ifdef BOX_DEBUG
    00245     if ( style() && style()->visibility() == VISIBLE ) {
    00246         if(isAnonymousBox())
    00247             outlineBox(p, _tx, _ty, "green");
    00248         if(isFloating())
    00249             outlineBox(p, _tx, _ty, "yellow");
    00250         else
    00251             outlineBox(p, _tx, _ty);
    00252     }
    00253 #endif
    00254
    00255 }
    00256
    00257 void RenderFlow::paintSpecialObjects( QPainter *p, int x, int y, int w, int h, int tx, int ty)
    00258 {
    00259     SpecialObject* r;
    00260     QPtrListIterator<SpecialObject> it(*specialObjects);
    00261     for ( ; (r = it.current()); ++it ) {
    00262         // A special object may be registered with several different objects... so we only paint the
    00263         // object if we are its containing block
    00264        if (r->node->isPositioned() && r->node->containingBlock() == this) {
    00265            r->node->paint(p, x, y, w, h, tx , ty);
    00266        } else if ( ( r->node->isFloating() && !r->noPaint ) ) {
    00267             r->node->paint(p, x, y, w, h, tx + r->left - r->node->xPos() + r->node->marginLeft(),
    00268                            ty + r->startY - r->node->yPos() + r->node->marginTop() );
    00269         }
    00270 #ifdef FLOAT_DEBUG
    00271         p->save();
    00272         if ( r->node->isPositioned() )
    00273             p->setPen( QPen( Qt::red, 4) );
    00274         else
    00275             p->setPen( QPen( Qt::magenta, 4) );
    00276         p->setBrush( QPainter::NoBrush );
    00277         qDebug("(%p): special object at (%d/%d-%d/%d)", this, r->left, r->startY, r->width, r->endY - r->startY );
    00278         p->drawRect( QRect( r->left+tx, r->startY+ty, r->width, r->endY - r->startY) );
    00279         p->restore();
    00280 #endif
    00281     }
    00282 }
    00283
    00284
    00285 void RenderFlow::layout()
    00286 {
    00287 //    kdDebug( 6040 ) << renderName() << " " << this << "::layout() start" << endl;
    00288 //     QTime t;
    00289 //     t.start();
    00290
    00291     KHTMLAssert( !layouted() );
    00292     KHTMLAssert( minMaxKnown() );
    00293     KHTMLAssert(!isInline());
    00294
    00295     int oldWidth = m_width;
    00296
    00297     calcWidth();
    00298
    00299     bool relayoutChildren = false;
    00300     if ( oldWidth != m_width )
    00301         relayoutChildren = true;
    00302
    00303     // need a small hack here, as tables are done a bit differently
    00304     if ( isTableCell() ) //&& static_cast<RenderTableCell *>(this)->widthChanged() )
    00305         relayoutChildren = true;
    00306
    00307 //     kdDebug( 6040 ) << specialObjects << "," << oldWidth << ","
    00308 //                     << m_width << ","<< layouted() << "," << isAnonymousBox() << ","
    00309 //                     << overhangingContents() << "," << isPositioned() << endl;
    00310
    00311 #ifdef DEBUG_LAYOUT
    00312     kdDebug( 6040 ) << renderName() << "(RenderFlow) " << this << " ::layout() width=" << m_width << ", layouted=" << layouted() << endl;
    00313     if(containingBlock() == static_cast<RenderObject *>(this))
    00314         kdDebug( 6040 ) << renderName() << ": containingBlock == this" << endl;
    00315 #endif
    00316
    00317     if(m_width<=0 && !isPositioned() && !overhangingContents()) {
    00318         if(m_y < 0) m_y = 0;
    00319         setLayouted();
    00320         return;
    00321     }
    00322
    00323     clearFloats();
    00324
    00325     m_height = 0;
    00326     m_clearStatus = CNONE;
    00327
    00328 //    kdDebug( 6040 ) << "childrenInline()=" << childrenInline() << endl;
    00329     if(childrenInline())
    00330         layoutInlineChildren( relayoutChildren );
    00331     else
    00332         layoutBlockChildren( relayoutChildren );
    00333
    00334     int oldHeight = m_height;
    00335     calcHeight();
    00336     if ( oldHeight != m_height )
    00337         relayoutChildren = true;
    00338
    00339     if ( isTableCell() && lastChild() && lastChild()->hasOverhangingFloats() ) {
    00340         m_height = lastChild()->yPos() + static_cast<RenderFlow*>(lastChild())->floatBottom();
    00341         m_height += borderBottom() + paddingBottom();
    00342     }
    00343     if( hasOverhangingFloats() && (isFloating() || isTableCell()) ) {
    00344         m_height = floatBottom();
    00345         m_height += borderBottom() + paddingBottom();
    00346     }
    00347
    00348     layoutSpecialObjects( relayoutChildren );
    00349
    00350     //kdDebug() << renderName() << " layout width=" << m_width << " height=" << m_height << endl;
    00351
    00352     setLayouted();
    00353 }
    00354
    00355 void RenderFlow::layoutSpecialObjects( bool relayoutChildren )
    00356 {
    00357     if(specialObjects) {
    00358         //kdDebug( 6040 ) << renderName() << " " << this << "::layoutSpecialObjects() start" << endl;
    00359         SpecialObject* r;
    00360         QPtrListIterator<SpecialObject> it(*specialObjects);
    00361         for ( ; (r = it.current()); ++it ) {
    00362             //kdDebug(6040) << "   have a positioned object" << endl;
    00363             if (r->type == SpecialObject::Positioned) {
    00364                 if ( relayoutChildren ) {
    00365                     r->node->setLayoutedLocal( false );
    00366                 }
    00367                 if ( !r->node->layouted() )
    00368                     r->node->layout();
    00369             }
    00370         }
    00371         specialObjects->sort();
    00372     }
    00373 }
    00374
    00375 void RenderFlow::layoutBlockChildren( bool relayoutChildren )
    00376 {
    00377 #ifdef DEBUG_LAYOUT
    00378     kdDebug( 6040 ) << renderName() << " layoutBlockChildren( " << this <<" ), relayoutChildren="<< relayoutChildren << endl;
    00379 #endif
    00380
    00381     int xPos = 0;
    00382     int toAdd = 0;
    00383
    00384     m_height = 0;
    00385
    00386     xPos += borderLeft() + paddingLeft();
    00387     m_height += borderTop() + paddingTop();
    00388     toAdd += borderBottom() + paddingBottom();
    00389
    00390     if( style()->direction() == RTL ) {
    00391         xPos = marginLeft() + m_width - paddingRight() - borderRight();
    00392     }
    00393
    00394     RenderObject *child = firstChild();
    00395     RenderFlow *prevFlow = 0;
    00396
    00397     int prevMargin = 0;
    00398     if(isTableCell() ) {
    00399         prevMargin = TABLECELLMARGIN;
    00400     } else if ( m_height == 0 ) {
    00401         // the elements and childs margin collapse if there is no border and padding.
    00402         prevMargin = marginTop();
    00403         if ( parent() )
    00404             prevMargin = collapseMargins( prevMargin, parent()->marginTop() );
    00405         if ( prevMargin != TABLECELLMARGIN )
    00406             m_height = -prevMargin;
    00407     }
    00408     //kdDebug() << "RenderFlow::layoutBlockChildren " << prevMargin << endl;
    00409
    00410 //     QTime t;
    00411 //     t.start();
    00412
    00413     while( child != 0 )
    00414     {
    00415
    00416         // make sure we relayout children if we need it,
    00417         // like inherited floats or percentage based widths.
    00418         if ( relayoutChildren || floatBottom() > m_height ||
    00419              ( ( child->isReplaced() || child->isFloating() ) &&
    00420                ( child->style()->width().isPercent() || child->style()->height().isPercent() ) )
    00421             )
    00422             child->setLayouted(false);
    00423
    00424         if ( child->style()->flowAroundFloats() && !child->isFloating() &&
    00425              style()->width().isFixed() ) {
    00426             // flow around floats only flows around the ones on the left side (right side if direction==RTL)
    00427             int available = style()->direction() == LTR
    00428                             ? m_width - leftOffset( m_height )
    00429                             : rightOffset( m_height );
    00430             if ( child->minWidth() > available ) {
    00431                 // ## this might be a little to far.
    00432                 m_height = QMAX( m_height, style()->direction() == LTR ? leftBottom() : rightBottom() );
    00433                 prevMargin = 0;
    00434             }
    00435         }
    00436
    00437 //         kdDebug( 6040 ) << "   " << child->renderName() << " loop " << child << ", " << child->isInline() << ", " << child->layouted() <<" float="<< child->isFloating() << " y=" << m_height << endl;
    00438 //         kdDebug( 6040 ) << t.elapsed() << endl;
    00439         // ### might be some layouts are done two times... FIX that.
    00440
    00441         if (child->isPositioned())
    00442         {
    00443             static_cast<RenderFlow*>(child->containingBlock())->insertSpecialObject(child);
    00444             //kdDebug() << "RenderFlow::layoutBlockChildren inserting positioned into " << child->containingBlock()->renderName() << endl;
    00445             child = child->nextSibling();
    00446             continue;
    00447         } else if ( child->isReplaced() ) {
    00448             if ( !child->layouted() )
    00449                 child->layout();
    00450         } else if ( child->isFloating() ) {
    00451             if ( !child->layouted() )
    00452                 child->layout();
    00453             // margins of floats and other objects do not collapse. The hack below assures this.
    00454             if ( prevMargin != TABLECELLMARGIN )
    00455                 m_height += prevMargin;
    00456             insertSpecialObject( child );
    00457             positionNewFloats();
    00458 //          kdDebug() << "RenderFlow::layoutBlockChildren inserting float at "<< m_height <<" prevMargin="<<prevMargin << endl;
    00459             if ( prevMargin != TABLECELLMARGIN )
    00460                 m_height -= prevMargin;
    00461             child = child->nextSibling();
    00462             continue;
    00463         }
    00464
    00465         child->calcVerticalMargins();
    00466
    00467         if(checkClear(child)) prevMargin = 0; // ### should only be 0
    00468         // if oldHeight+prevMargin < newHeight
    00469
    00470         int margin = child->marginTop();
    00471         //kdDebug(0) << "margin = " << margin << " prevMargin = " << prevMargin << endl;
    00472         margin = collapseMargins(margin, prevMargin);
    00473
    00474         if ( margin != TABLECELLMARGIN )
    00475             m_height += margin;
    00476
    00477         //kdDebug(0) << "margin = " << margin << " yPos = " << m_height << endl;
    00478
    00479         if(prevFlow)
    00480         {
    00481             if (prevFlow->yPos()+prevFlow->floatBottom() > m_height)
    00482                 child->setLayouted(false);
    00483             else
    00484                 prevFlow=0;
    00485         }
    00486
    00487         // #### ugly and hacky, as we calculate width twice, but works for now.
    00488         // really need to fix this after 3.1
    00489         int owidth = child->width();
    00490         child->calcWidth();
    00491         int chPos = xPos;
    00492
    00493         if(style()->direction() == LTR) {
    00494             // html blocks flow around floats
    00495             if ( ( style()->htmlHacks() || child->isTable() ) && child->style()->flowAroundFloats() )
    00496                 chPos = leftOffset(m_height);
    00497             chPos += child->marginLeft();
    00498         } else {
    00499             if ( ( style()->htmlHacks() || child->isTable() ) && child->style()->flowAroundFloats() )
    00500                 chPos = rightOffset(m_height);
    00501             chPos -= child->width() + child->marginRight();
    00502         }
    00503         child->setWidth( owidth );
    00504         child->setPos(chPos, m_height);
    00505
    00506         if ( !child->layouted() )
    00507             child->layout();
    00508
    00509         m_height += child->height();
    00510
    00511         prevMargin = child->marginBottom();
    00512
    00513         if (child->isFlow())
    00514             prevFlow = static_cast<RenderFlow*>(child);
    00515
    00516         if ( child->hasOverhangingFloats() ) {
    00517             // need to add the float to our special objects
    00518             addOverHangingFloats( static_cast<RenderFlow *>(child), -child->xPos(), -child->yPos(), true );
    00519         }
    00520
    00521         child = child->nextSibling();
    00522     }
    00523
    00524     if( !isTableCell() && toAdd != 0 )
    00525         m_height += prevMargin;
    00526     if ( isPositioned() || isRelPositioned() )
    00527         m_height = QMAX( m_height,  floatBottom() );
    00528     m_height += toAdd;
    00529
    00530     setLayouted();
    00531
    00532     // kdDebug( 6040 ) << "layouted = " << layouted_ << endl;
    00533 }
    00534
    00535 bool RenderFlow::checkClear(RenderObject *child)
    00536 {
    00537     //kdDebug( 6040 ) << "checkClear oldheight=" << m_height << endl;
    00538     int bottom = 0;
    00539     switch(child->style()->clear())
    00540     {
    00541     case CNONE:
    00542         return false;
    00543     case CLEFT:
    00544         bottom = leftBottom();
    00545         break;
    00546     case CRIGHT:
    00547         bottom = rightBottom();
    00548         break;
    00549     case CBOTH:
    00550         bottom = floatBottom();
    00551         break;
    00552     }
    00553     if(m_height < bottom)
    00554         m_height = bottom;
    00555     return true;
    00556 }
    00557
    00558 void RenderFlow::insertSpecialObject(RenderObject *o)
    00559 {
    00560     // Create the list of special objects if we don't aleady have one
    00561     if (!specialObjects) {
    00562         specialObjects = new QSortedList<SpecialObject>;
    00563         specialObjects->setAutoDelete(true);
    00564     }
    00565     else {
    00566         // Don't insert the object again if it's already in the list
    00567         QPtrListIterator<SpecialObject> it(*specialObjects);
    00568         SpecialObject *f;
    00569         while ( (f = it.current()) ) {
    00570             if (f->node == o) return;
    00571             ++it;
    00572         }
    00573     }
    00574
    00575     // Create the special object entry & append it to the list
    00576
    00577     SpecialObject *newObj = 0;
    00578     if (o->isPositioned()) {
    00579         // positioned object
    00580         newObj = new SpecialObject(SpecialObject::Positioned);
    00581         setOverhangingContents();
    00582     }
    00583     else if (o->isFloating()) {
    00584         // floating object
    00585         if ( !o->layouted() )
    00586             o->layout();
    00587
    00588         if(o->style()->floating() == FLEFT)
    00589             newObj = new SpecialObject(SpecialObject::FloatLeft);
    00590         else
    00591             newObj = new SpecialObject(SpecialObject::FloatRight);
    00592
    00593         newObj->startY = -1;
    00594         newObj->endY = -1;
    00595         newObj->width = o->width() + o->marginLeft() + o->marginRight();
    00596     }
    00597     else {
    00598         // We should never get here, as insertSpecialObject() should only ever be called with positioned or floating
    00599         // objects.
    00600         KHTMLAssert(newObj);
    00601     }
    00602
    00603     newObj->count = specialObjects->count();
    00604     newObj->node = o;
    00605
    00606     specialObjects->append(newObj);
    00607 }
    00608
    00609 void RenderFlow::removeSpecialObject(RenderObject *o)
    00610 {
    00611     if (specialObjects) {
    00612         QPtrListIterator<SpecialObject> it(*specialObjects);
    00613         while (it.current()) {
    00614             if (it.current()->node == o)
    00615                 specialObjects->removeRef(it.current());
    00616             ++it;
    00617         }
    00618     }
    00619 }
    00620
    00621 void RenderFlow::positionNewFloats()
    00622 {
    00623     if(!specialObjects) return;
    00624     SpecialObject *f = specialObjects->getLast();
    00625     if(!f || f->startY != -1) return;
    00626     SpecialObject *lastFloat;
    00627     while(1)
    00628     {
    00629         lastFloat = specialObjects->prev();
    00630         if(!lastFloat || (lastFloat->startY != -1 && !(lastFloat->type==SpecialObject::Positioned) )) {
    00631             specialObjects->next();
    00632             break;
    00633         }
    00634         f = lastFloat;
    00635     }
    00636
    00637
    00638     int y = m_height;
    00639
    00640
    00641     // the float can not start above the y position of the last positioned float.
    00642     if(lastFloat && lastFloat->startY > y)
    00643         y = lastFloat->startY;
    00644
    00645     while(f)
    00646     {
    00647         //skip elements copied from elsewhere and positioned elements
    00648         if (f->node->containingBlock()!=this || f->type==SpecialObject::Positioned)
    00649         {
    00650             f = specialObjects->next();
    00651             continue;
    00652         }
    00653
    00654         RenderObject *o = f->node;
    00655         int _height = o->height() + o->marginTop() + o->marginBottom();
    00656
    00657         int ro = rightOffset(); // Constant part of right offset.
    00658         int lo = leftOffset(); // Constat part of left offset.
    00659         int fwidth = f->width; // The width we look for.
    00660         //kdDebug( 6040 ) << " Object width: " << fwidth << " available width: " << ro - lo << endl;
    00661         if (ro - lo < fwidth)
    00662             fwidth = ro - lo; // Never look for more than what will be available.
    00663         if (o->style()->floating() == FLEFT)
    00664         {
    00665             if ( o->style()->clear() & CLEFT )
    00666                 y = QMAX( leftBottom(), y );
    00667             int heightRemainingLeft = 1;
    00668             int heightRemainingRight = 1;
    00669             int fx = leftRelOffset(y,lo, &heightRemainingLeft);
    00670             while (rightRelOffset(y,ro, &heightRemainingRight)-fx < fwidth)
    00671             {
    00672                 y += QMIN( heightRemainingLeft, heightRemainingRight );
    00673                 fx = leftRelOffset(y,lo, &heightRemainingLeft);
    00674             }
    00675             if (fx<0) fx=0;
    00676             f->left = fx;
    00677             //kdDebug( 6040 ) << "positioning left aligned float at (" << fx + o->marginLeft()  << "/" << y + o->marginTop() << ") fx=" << fx << endl;
    00678             o->setPos(fx + o->marginLeft(), y + o->marginTop());
    00679         }
    00680         else
    00681         {
    00682             if ( o->style()->clear() & CRIGHT )
    00683                 y = QMAX( rightBottom(), y );
    00684             int heightRemainingLeft = 1;
    00685             int heightRemainingRight = 1;
    00686             int fx = rightRelOffset(y,ro, &heightRemainingRight);
    00687             while (fx - leftRelOffset(y,lo, &heightRemainingLeft) < fwidth)
    00688             {
    00689                 y += QMIN(heightRemainingLeft, heightRemainingRight);
    00690                 fx = rightRelOffset(y,ro, &heightRemainingRight);
    00691             }
    00692             if (fx<f->width) fx=f->width;
    00693             f->left = fx - f->width;
    00694             //kdDebug( 6040 ) << "positioning right aligned float at (" << fx - o->marginRight() - o->width() << "/" << y + o->marginTop() << ")" << endl;
    00695             o->setPos(fx - o->marginRight() - o->width(), y + o->marginTop());
    00696         }
    00697         f->startY = y;
    00698         f->endY = f->startY + _height;
    00699
    00700
    00701         //kdDebug( 6040 ) << "specialObject x/y= (" << f->left << "/" << f->startY << "-" << f->width << "/" << f->endY - f->startY << ")" << endl;
    00702
    00703         f = specialObjects->next();
    00704     }
    00705 }
    00706
    00707 void RenderFlow::newLine()
    00708 {
    00709     positionNewFloats();
    00710     // set y position
    00711     int newY = 0;
    00712     switch(m_clearStatus)
    00713     {
    00714     case CLEFT:
    00715         newY = leftBottom();
    00716         break;
    00717     case CRIGHT:
    00718         newY = rightBottom();
    00719         break;
    00720     case CBOTH:
    00721         newY = floatBottom();
    00722     default:
    00723         break;
    00724     }
    00725     if(m_height < newY)
    00726     {
    00727 //      kdDebug( 6040 ) << "adjusting y position" << endl;
    00728         m_height = newY;
    00729     }
    00730     m_clearStatus = CNONE;
    00731 }
    00732
    00733
    00734 int
    00735 RenderFlow::leftOffset() const
    00736 {
    00737     int left = 0;
    00738
    00739     left += borderLeft() + paddingLeft();
    00740
    00741     if ( firstLine && style()->direction() == LTR ) {
    00742         int cw=0;
    00743         if (style()->textIndent().isPercent())
    00744             cw = containingBlock()->contentWidth();
    00745         left += style()->textIndent().minWidth(cw);
    00746     }
    00747
    00748     return left;
    00749 }
    00750
    00751 int
    00752 RenderFlow::leftRelOffset(int y, int fixedOffset, int *heightRemaining ) const
    00753 {
    00754     int left = fixedOffset;
    00755     if(!specialObjects)
    00756         return left;
    00757
    00758     if ( heightRemaining ) *heightRemaining = 1;
    00759     SpecialObject* r;
    00760     QPtrListIterator<SpecialObject> it(*specialObjects);
    00761     for ( ; (r = it.current()); ++it )
    00762     {
    00763         //kdDebug( 6040 ) <<(void *)this << " left: sy, ey, x, w " << r->startY << "," << r->endY << "," << r->left << "," << r->width << " " << endl;
    00764         if (r->startY <= y && r->endY > y &&
    00765             r->type == SpecialObject::FloatLeft &&
    00766             r->left + r->width > left) {
    00767             left = r->left + r->width;
    00768             if ( heightRemaining ) *heightRemaining = r->endY - y;
    00769         }
    00770     }
    00771     //kdDebug( 6040 ) << "leftOffset(" << y << ") = " << left << endl;
    00772     return left;
    00773 }
    00774
    00775 int
    00776 RenderFlow::rightOffset() const
    00777 {
    00778     int right = m_width;
    00779
    00780     right -= borderRight() + paddingRight();
    00781
    00782     if ( firstLine && style()->direction() == RTL ) {
    00783         int cw=0;
    00784         if (style()->textIndent().isPercent())
    00785             cw = containingBlock()->contentWidth();
    00786         right += style()->textIndent().minWidth(cw);
    00787     }
    00788
    00789     return right;
    00790 }
    00791
    00792 int
    00793 RenderFlow::rightRelOffset(int y, int fixedOffset, int *heightRemaining ) const
    00794 {
    00795     int right = fixedOffset;
    00796
    00797     if (!specialObjects) return right;
    00798
    00799     if (heightRemaining) *heightRemaining = 1;
    00800     SpecialObject* r;
    00801     QPtrListIterator<SpecialObject> it(*specialObjects);
    00802     for ( ; (r = it.current()); ++it )
    00803     {
    00804         //kdDebug( 6040 ) << "right: sy, ey, x, w " << r->startY << "," << r->endY << "," << r->left << "," << r->width << " " << endl;
    00805         if (r->startY <= y && r->endY > y &&
    00806             r->type == SpecialObject::FloatRight &&
    00807             r->left < right) {
    00808             right = r->left;
    00809             if ( heightRemaining ) *heightRemaining = r->endY - y;
    00810         }
    00811     }
    00812     //kdDebug( 6040 ) << "rightOffset(" << y << ") = " << right << endl;
    00813     return right;
    00814 }
    00815
    00816 short
    00817 RenderFlow::lineWidth(int y) const
    00818 {
    00819     //kdDebug( 6040 ) << "lineWidth(" << y << ")=" << rightOffset(y) - leftOffset(y) << endl;
    00820     return rightOffset(y) - leftOffset(y);
    00821 }
    00822
    00823 int
    00824 RenderFlow::floatBottom() const
    00825 {
    00826     if (!specialObjects) return 0;
    00827     int bottom=0;
    00828     SpecialObject* r;
    00829     QPtrListIterator<SpecialObject> it(*specialObjects);
    00830     for ( ; (r = it.current()); ++it )
    00831         if (r->endY>bottom && (int)r->type <= (int)SpecialObject::FloatRight)
    00832             bottom=r->endY;
    00833     return bottom;
    00834 }
    00835
    00836 int
    00837 RenderFlow::lowestPosition() const
    00838 {
    00839     int bottom = RenderBox::lowestPosition();
    00840     //kdDebug(0) << renderName() << "("<<this<<") lowest = " << bottom << endl;
    00841     int lp = 0;
    00842     if ( !m_childrenInline ) {
    00843         RenderObject *last = lastChild();
    00844         while( last && (last->isPositioned() || last->isFloating()) )
    00845             last = last->previousSibling();
    00846         if( last )
    00847             lp = last->yPos() + last->lowestPosition();
    00848     }
    00849
    00850     if(  lp > bottom )
    00851         bottom = lp;
    00852
    00853     //kdDebug(0) << "     bottom = " << bottom << endl;
    00854
    00855     if (specialObjects) {
    00856         SpecialObject* r;
    00857         QPtrListIterator<SpecialObject> it(*specialObjects);
    00858         for ( ; (r = it.current()); ++it ) {
    00859             lp = 0;
    00860             if ( r->type == SpecialObject::FloatLeft || r->type == SpecialObject::FloatRight ){
    00861                 lp = r->startY + r->node->lowestPosition();
    00862                 //kdDebug(0) << r->node->renderName() << " lp = " << lp << "startY=" << r->startY << endl;
    00863             } else if ( r->type == SpecialObject::Positioned ) {
    00864                 lp = r->node->yPos() + r->node->lowestPosition();
    00865             }
    00866             if( lp > bottom)
    00867                 bottom = lp;
    00868         }
    00869     }
    00870
    00871     if ( overhangingContents() ) {
    00872         RenderObject *child = firstChild();
    00873         while( child ) {
    00874             if ( child->overhangingContents() ) {
    00875                 int lp = child->yPos() + child->lowestPosition();
    00876                 if ( lp > bottom ) bottom = lp;
    00877             }
    00878             child = child->nextSibling();
    00879         }
    00880     }
    00881
    00882     //kdDebug(0) << renderName() << "      bottom final = " << bottom << endl;
    00883     return bottom;
    00884 }
    00885
    00886 int RenderFlow::rightmostPosition() const
    00887 {
    00888     int right = RenderBox::rightmostPosition();
    00889
    00890     RenderObject *c;
    00891     for (c = firstChild(); c; c = c->nextSibling()) {
    00892         if (!c->isPositioned() && !c->isFloating()) {
    00893             int childRight = c->xPos() + c->rightmostPosition();
    00894             if (childRight > right)
    00895                 right = childRight;
    00896         }
    00897     }
    00898
    00899     if (specialObjects) {
    00900         SpecialObject* r;
    00901         QPtrListIterator<SpecialObject> it(*specialObjects);
    00902         for ( ; (r = it.current()); ++it ) {
    00903             int specialRight=0;
    00904             if ( r->type == SpecialObject::FloatLeft || r->type == SpecialObject::FloatRight ){
    00905                 specialRight = r->left + r->node->rightmostPosition();
    00906             } else if ( r->type == SpecialObject::Positioned ) {
    00907                 specialRight = r->node->xPos() + r->node->rightmostPosition();
    00908             }
    00909             if (specialRight > right)
    00910                         right = specialRight;
    00911         }
    00912     }
    00913
    00914     if ( overhangingContents() ) {
    00915         RenderObject *child = firstChild();
    00916         while( child ) {
    00917             if ( child->overhangingContents() ) {
    00918                 int r = child->xPos() + child->rightmostPosition();
    00919                 if ( r > right ) right = r;
    00920             }
    00921             child = child->nextSibling();
    00922         }
    00923     }
    00924
    00925     return right;
    00926 }
    00927
    00928
    00929 int
    00930 RenderFlow::leftBottom()
    00931 {
    00932     if (!specialObjects) return 0;
    00933     int bottom=0;
    00934     SpecialObject* r;
    00935     QPtrListIterator<SpecialObject> it(*specialObjects);
    00936     for ( ; (r = it.current()); ++it )
    00937         if (r->endY>bottom && r->type == SpecialObject::FloatLeft)
    00938             bottom=r->endY;
    00939
    00940     return bottom;
    00941 }
    00942
    00943 int
    00944 RenderFlow::rightBottom()
    00945 {
    00946     if (!specialObjects) return 0;
    00947     int bottom=0;
    00948     SpecialObject* r;
    00949     QPtrListIterator<SpecialObject> it(*specialObjects);
    00950     for ( ; (r = it.current()); ++it )
    00951         if (r->endY>bottom && r->type == SpecialObject::FloatRight)
    00952             bottom=r->endY;
    00953
    00954     return bottom;
    00955 }
    00956
    00957 void
    00958 RenderFlow::clearFloats()
    00959 {
    00960     //kdDebug( 6040 ) << this <<" clearFloats" << endl;
    00961
    00962     if (specialObjects) {
    00963         if( overhangingContents() ) {
    00964             specialObjects->first();
    00965             while ( specialObjects->current()) {
    00966                 if ( !(specialObjects->current()->type == SpecialObject::Positioned) )
    00967                     specialObjects->remove();
    00968                 else
    00969                     specialObjects->next();
    00970             }
    00971         } else
    00972             specialObjects->clear();
    00973     }
    00974
    00975     if (isFloating() || isPositioned()) return;
    00976
    00977     RenderObject *prev = previousSibling();
    00978
    00979     // find the element to copy the floats from
    00980     // pass non-flows
    00981     // pass fAF's unless they contain overhanging stuff
    00982     bool parentHasFloats = false;
    00983     while (prev) {
    00984         if (!prev->isFlow() || prev->isFloating() ||
    00985             (prev->style()->flowAroundFloats() &&
    00986              (static_cast<RenderFlow *>(prev)->floatBottom()+prev->yPos() < m_y ))) {
    00987             if ( prev->isFloating() && parent()->isFlow() ) {
    00988                 parentHasFloats = true;
    00989             }
    00990             prev = prev->previousSibling();
    00991         } else
    00992             break;
    00993     }
    00994
    00995     int offset = m_y;
    00996
    00997     if ( parentHasFloats ) {
    00998         addOverHangingFloats( static_cast<RenderFlow *>( parent() ), parent()->borderLeft() + parent()->paddingLeft() , offset, false );
    00999     }
    01000
    01001     if(prev ) {
    01002         if(prev->isTableCell()) return;
    01003
    01004         offset -= prev->yPos();
    01005     } else {
    01006         prev = parent();
    01007         if(!prev) return;
    01008     }
    01009     //kdDebug() << "RenderFlow::clearFloats found previous "<< (void *)this << " prev=" << (void *)prev<< endl;
    01010
    01011     // add overhanging special objects from the previous RenderFlow
    01012     if(!prev->isFlow()) return;
    01013     RenderFlow * flow = static_cast<RenderFlow *>(prev);
    01014     if(!flow->specialObjects) return;
    01015     if( ( style()->htmlHacks() || isTable() ) && style()->flowAroundFloats())
    01016         return; //html tables and lists flow as blocks
    01017
    01018     if(flow->floatBottom() > offset) {
    01019         int xoff = flow == parent() ? xPos() : xPos() - flow->xPos();
    01020         addOverHangingFloats( flow, xoff, offset );
    01021     }
    01022 }
    01023
    01024 void RenderFlow::addOverHangingFloats( RenderFlow *flow, int xoff, int offset, bool child )
    01025 {
    01026 #ifdef DEBUG_LAYOUT
    01027     kdDebug( 6040 ) << (void *)this << ": adding overhanging floats xoff=" << xoff << "  offset=" << offset << " child=" << child << endl;
    01028 #endif
    01029     if ( !flow->specialObjects )
    01030         return;
    01031
    01032     // we have overhanging floats
    01033     if(!specialObjects) {
    01034         specialObjects = new QSortedList<SpecialObject>;
    01035         specialObjects->setAutoDelete(true);
    01036     }
    01037
    01038     QPtrListIterator<SpecialObject> it(*flow->specialObjects);
    01039     SpecialObject *r;
    01040     for ( ; (r = it.current()); ++it ) {
    01041         if ( (int)r->type <= (int)SpecialObject::FloatRight &&
    01042              ( ( !child && r->endY > offset ) ||
    01043                ( child && flow->yPos() + r->endY > height() ) ) ) {
    01044
    01045             if ( child )
    01046                 r->noPaint = true;
    01047
    01048             SpecialObject* f = 0;
    01049             // don't insert it twice!
    01050             QPtrListIterator<SpecialObject> it(*specialObjects);
    01051             while ( (f = it.current()) ) {
    01052                 if (f->node == r->node) break;
    01053                 ++it;
    01054             }
    01055             if ( !f ) {
    01056                 SpecialObject *special = new SpecialObject(r->type);
    01057                 special->count = specialObjects->count();
    01058                 special->startY = r->startY - offset;
    01059                 special->endY = r->endY - offset;
    01060                 special->left = r->left - xoff;
    01061                 if ( !child ) {
    01062                     special->left -= marginLeft();
    01063                     special->noPaint = true;
    01064                 }
    01065                 special->width = r->width;
    01066                 special->node = r->node;
    01067                 specialObjects->append(special);
    01068 #ifdef DEBUG_LAYOUT
    01069         kdDebug( 6040 ) << "addOverHangingFloats x/y= (" << special->left << "/" << special->startY << "-" << special->width << "/" << special->endY - special->startY << ")" << endl;
    01070 #endif
    01071             }
    01072         }
    01073     }
    01074 }
    01075
    01076
    01077 static inline RenderObject *next(RenderObject *par, RenderObject *current)
    01078 {
    01079     RenderObject *next = 0;
    01080     while(current != 0)
    01081     {
    01082         //kdDebug( 6040 ) << "current = " << current << endl;
    01083         if(!current->isFloating() && !current->isReplaced() && !current->isPositioned())
    01084             next = current->firstChild();
    01085         if(!next) {
    01086             while(current && current != par) {
    01087                 next = current->nextSibling();
    01088                 if(next) break;
    01089                 current = current->parent();
    01090             }
    01091         }
    01092
    01093         if(!next) break;
    01094
    01095         if(next->isText() || next->isBR() || next->isFloating() || next->isReplaced() || next->isPositioned())
    01096             break;
    01097         current = next;
    01098     }
    01099     return next;
    01100 }
    01101
    01102
    01103 void RenderFlow::calcMinMaxWidth()
    01104 {
    01105     KHTMLAssert( !minMaxKnown() );
    01106
    01107 #ifdef DEBUG_LAYOUT
    01108     kdDebug( 6040 ) << renderName() << "(RenderBox)::calcMinMaxWidth() this=" << this << endl;
    01109 #endif
    01110
    01111     m_minWidth = 0;
    01112     m_maxWidth = 0;
    01113
    01114     if (isInline()) {
    01115         setMinMaxKnown();
    01116         return;
    01117     }
    01118
    01119     int cw = containingBlock()->contentWidth();
    01120     // "style()->width().isVariable()" in the contition below gives more mozilla like behaviour, the current
    01121     // condition is more IE like.
    01122     bool tableCell = (isTableCell() && !style()->width().isFixed());
    01123
    01124     // ## maybe we should replace the noWrap stuff in RenderTable by CSS.
    01125     bool nowrap = style()->whiteSpace() == NOWRAP ||
    01126                   ( tableCell && static_cast<RenderTableCell *>(this)->noWrap() );
    01127
    01128     // non breaking space
    01129     const QChar nbsp = 0xa0;
    01130
    01131     RenderObject *child = firstChild();
    01132     RenderObject *prevchild = 0;
    01133
    01134     if(childrenInline()) {
    01135         int inlineMax=0;
    01136         int currentMin=0;
    01137         int inlineMin=0;
    01138         bool noBreak=false;
    01139
    01140         while(child != 0) {
    01141             // positioned children don't affect the minmaxwidth
    01142             if (child->isPositioned()) {
    01143                 child = next(this, child);
    01144                 continue;
    01145             }
    01146
    01147             if( !child->isBR() ) {
    01148                 RenderStyle* cstyle = child->style();
    01149                 int margins = 0;
    01150                 LengthType type = cstyle->marginLeft().type();
    01151                 if ( ! ( type == Variable ) )
    01152                     margins += (type == Fixed ? cstyle->marginLeft().value() : child->marginLeft());
    01153                 type = cstyle->marginRight().type();
    01154                 if ( ! ( type == Variable ) )
    01155                     margins += (type == Fixed ? cstyle->marginRight().value() : child->marginRight());
    01156                 int childMin = child->minWidth() + margins;
    01157                 int childMax = child->maxWidth() + margins;
    01158 //              qDebug("child min=%d, max=%d, currentMin=%d, inlineMin=%d",  childMin,  childMax, currentMin, inlineMin );
    01159                 if (child->isText() && static_cast<RenderText *>(child)->stringLength() > 0) {
    01160
    01161                     int ti = cstyle->textIndent().minWidth(cw);
    01162                     childMin+=ti;
    01163                     childMax+=ti;
    01164
    01165                     RenderText* t = static_cast<RenderText *>(child);
    01166 //                  qDebug("child is text, startMin=%d, endMin=%d", t->startMin(),  t->endMin() );
    01167                     if (noBreak || t->text()[0] == nbsp) { //inline starts with nbsp
    01168                         currentMin += t->startMin();
    01169 //                      qDebug("added startMin to currentMin, currentMin=%d", currentMin );
    01170                     }
    01171                     noBreak = false;
    01172                     if ( t->hasBreakableChar() ) {
    01173                         inlineMin = QMAX( inlineMin, currentMin );
    01174                         currentMin = t->endMin();
    01175                     }
    01176                     if ( t->text()[t->stringLength()-1]==nbsp ) { //inline ends with nbsp
    01177                         noBreak = true;
    01178                     }
    01179 //                  qDebug("noBreak = %d, currentMin = %d", noBreak,  currentMin );
    01180                 } else if (noBreak || tableCell ||
    01181                     (prevchild && prevchild->isFloating() && child->isFloating())) {
    01182                     currentMin += childMin;
    01183                     noBreak = false;
    01184                 }
    01185                 inlineMin = QMAX( inlineMin, childMin );
    01186                 inlineMax += childMax;
    01187             }
    01188             else
    01189             {
    01190                 inlineMin = QMAX( currentMin, inlineMin );
    01191                 if(m_minWidth < inlineMin) m_minWidth = inlineMin;
    01192                 if(m_maxWidth < inlineMax) m_maxWidth = inlineMax;
    01193                 inlineMin = currentMin = inlineMax = 0;
    01194             }
    01195             prevchild = child;
    01196             child = next(this, child);
    01197         }
    01198         inlineMin = QMAX( currentMin, inlineMin );
    01199         if(m_minWidth < inlineMin) m_minWidth = inlineMin;
    01200         if(m_maxWidth < inlineMax) m_maxWidth = inlineMax;
    01201 //          kdDebug( 6040 ) << "m_minWidth=" << m_minWidth
    01202 //                      << " m_maxWidth=" << m_maxWidth << endl;
    01203         if ( nowrap )
    01204             m_minWidth = m_maxWidth;
    01205     }
    01206     else
    01207     {
    01208         while(child != 0)
    01209         {
    01210             // positioned children don't affect the minmaxwidth
    01211             if (child->isPositioned())
    01212             {
    01213                 child = child->nextSibling();
    01214                 continue;
    01215             }
    01216
    01217             int margin=0;
    01218             //  auto margins don't affect minwidth
    01219
    01220             Length ml = child->style()->marginLeft();
    01221             Length mr = child->style()->marginRight();
    01222
    01223             if (style()->textAlign() == KONQ_CENTER)
    01224             {
    01225                 if (ml.isFixed()) margin+=ml.value();
    01226                 if (mr.isFixed()) margin+=mr.value();
    01227             }
    01228             else
    01229             {
    01230                 if (!ml.isVariable() && !mr.isVariable())
    01231                 {
    01232                     if (!(child->style()->width().isVariable()))
    01233                     {
    01234                         if (child->style()->direction()==LTR)
    01235                             margin = child->marginLeft();
    01236                         else
    01237                             margin = child->marginRight();
    01238                     }
    01239                     else
    01240                         margin = child->marginLeft()+child->marginRight();
    01241
    01242                 }
    01243                 else if (!ml.isVariable())
    01244                     margin = child->marginLeft();
    01245                 else if (!mr.isVariable())
    01246                     margin = child->marginRight();
    01247             }
    01248
    01249             if (margin<0) margin=0;
    01250
    01251             int w = child->minWidth() + margin;
    01252             if(m_minWidth < w) m_minWidth = w;
    01253             // IE ignores tables for calculation of nowrap. Makes some sense.
    01254             if ( nowrap && !child->isTable() && m_maxWidth < w )
    01255                 m_maxWidth = w;
    01256             w = child->maxWidth() + margin;
    01257             if(m_maxWidth < w) m_maxWidth = w;
    01258             child = child->nextSibling();
    01259         }
    01260     }
    01261     if(m_maxWidth < m_minWidth) m_maxWidth = m_minWidth;
    01262
    01263     if (style()->width().isFixed() && style()->width().value() > 0)
    01264         m_maxWidth = KMAX(m_minWidth,short(style()->width().value()));
    01265
    01266     int toAdd = 0;
    01267     toAdd = borderLeft() + borderRight() + paddingLeft() + paddingRight();
    01268
    01269     m_minWidth += toAdd;
    01270     m_maxWidth += toAdd;
    01271
    01272     setMinMaxKnown();
    01273
    01274     //kdDebug( 6040 ) << "Text::calcMinMaxWidth(" << this << "): min = " << m_minWidth << " max = " << m_maxWidth << endl;
    01275     // ### compare with min/max width set in style sheet...
    01276 }
    01277
    01278 void RenderFlow::close()
    01279 {
    01280     if(lastChild() && lastChild()->isAnonymousBox()) {
    01281         lastChild()->close();
    01282     }
    01283
    01284     RenderBox::close();
    01285 }
    01286
    01287 void RenderFlow::addChild(RenderObject *newChild, RenderObject *beforeChild)
    01288 {
    01289 #ifdef DEBUG_LAYOUT
    01290     kdDebug( 6040 ) << renderName() << "(RenderFlow)::addChild( " << newChild->renderName() <<
    01291                        ", " << (beforeChild ? beforeChild->renderName() : "0") << " )" << endl;
    01292     kdDebug( 6040 ) << "current height = " << m_height << endl;
    01293 #endif
    01294     setLayouted( false );
    01295
    01296     bool madeBoxesNonInline = FALSE;
    01297
    01298     RenderStyle* pseudoStyle=0;
    01299     if ( !isInline() && ( !firstChild() || firstChild() == beforeChild )
    01300         && ( pseudoStyle=style()->getPseudoStyle(RenderStyle::FIRST_LETTER) ) )
    01301     {
    01302
    01303         if (newChild->isText() && !newChild->isBR()) {
    01304             RenderText* newTextChild = static_cast<RenderText*>(newChild);
    01305
    01306             //kdDebug( 6040 ) << "first letter" << endl;
    01307
    01308             RenderFlow* firstLetter = new RenderFlow(0 /* anonymous box */);
    01309             pseudoStyle->setDisplay( INLINE );
    01310             firstLetter->setStyle(pseudoStyle);
    01311             firstLetter->setIsAnonymousBox(true);
    01312
    01313             addChild(firstLetter);
    01314
    01315             DOMStringImpl* oldText = newTextChild->string();
    01316
    01317             if(oldText->l >= 1) {
    01318                 unsigned int length = 0;
    01319                 while ( length < oldText->l &&
    01320                         ( (oldText->s+length)->isSpace() || (oldText->s+length)->isPunct() ) )
    01321                     length++;
    01322                 length++;
    01323                 RenderText* letter = new RenderText(0 /* anonymous object */, oldText->substring(0,length));
    01324                 RenderStyle* newStyle = new RenderStyle();
    01325                 newStyle->inheritFrom(pseudoStyle);
    01326                 letter->setStyle(newStyle);
    01327                 letter->setIsAnonymousBox(true);
    01328                 firstLetter->addChild(letter);
    01329                 newTextChild->setText(oldText->substring(length,oldText->l-length));
    01330             }
    01331             firstLetter->close();
    01332
    01333         }
    01334     }
    01335
    01336     insertPseudoChild(RenderStyle::BEFORE, newChild, beforeChild);
    01337
    01338     // If the requested beforeChild is not one of our children, then this is most likely because
    01339     // there is an anonymous block box within this object that contains the beforeChild. So
    01340     // just insert the child into the anonymous block box instead of here.
    01341     if (beforeChild && beforeChild->parent() != this) {
    01342         KHTMLAssert(beforeChild->parent());
    01343         KHTMLAssert(beforeChild->parent()->isAnonymousBox());
    01344         KHTMLAssert(beforeChild->parent()->parent() == this);
    01345
    01346         if (newChild->isInline()) {
    01347             beforeChild->parent()->addChild(newChild,beforeChild);
    01348             newChild->setLayouted( false );
    01349             newChild->setMinMaxKnown( false );
    01350             return;
    01351         }
    01352         else {
    01353             // Trying to insert a block child into an anonymous block box which contains only
    01354             // inline elements... move all of the anonymous box's inline children into other
    01355             // anonymous boxes which become children of this
    01356
    01357             RenderObject *anonBox = beforeChild->parent();
    01358             KHTMLAssert (anonBox->isFlow()); // ### RenderTableSection the only exception - should never happen here
    01359
    01360
    01361             if ( anonBox->childrenInline() ) {
    01362                 static_cast<RenderFlow*>(anonBox)->makeChildrenNonInline(beforeChild);
    01363                 madeBoxesNonInline = true;
    01364             }
    01365             beforeChild = beforeChild->parent();
    01366
    01367             // prevent deletion of anonymous box by render_container.cpp
    01368             anonBox->setIsAnonymousBox(false);
    01369
    01370             RenderObject *child;
    01371             while ((child = anonBox->firstChild()) != 0) {
    01372                 anonBox->removeChild(child);
    01373                 addChild(child,anonBox);
    01374             }
    01375             anonBox->setIsAnonymousBox(true);
    01376             removeChildNode(anonBox);
    01377             anonBox->detach(); // does necessary cleanup & deletes anonBox
    01378             KHTMLAssert(beforeChild->parent() == this);
    01379
    01380         }
    01381     }
    01382
    01383     // prevent non-layouted elements from getting painted by pushing them far above the top of the
    01384     // page
    01385     if (!newChild->isInline())
    01386         newChild->setPos(newChild->xPos(), -500000);
    01387
    01388     if (!newChild->isText())
    01389     {
    01390         if (newChild->style()->position() != STATIC)
    01391             setOverhangingContents();
    01392     }
    01393
    01394     // RenderFlow has to either have all of its children inline, or all of its children as blocks.
    01395     // So, if our children are currently inline and a block child has to be inserted, we move all our
    01396     // inline children into anonymous block boxes
    01397     if ( m_childrenInline && !newChild->isInline() && !newChild->isSpecial() )
    01398     {
    01399         if ( m_childrenInline ) {
    01400             makeChildrenNonInline(beforeChild);
    01401             madeBoxesNonInline = true;
    01402         }
    01403         if (beforeChild) {
    01404             if ( beforeChild->parent() != this ) {
    01405                 beforeChild = beforeChild->parent();
    01406                 KHTMLAssert(beforeChild->isAnonymousBox());
    01407                 KHTMLAssert(beforeChild->parent() == this);
    01408             }
    01409         }
    01410     }
    01411     else if (!m_childrenInline)
    01412     {
    01413         // If we're inserting an inline child but all of our children are blocks, then we have to make sure
    01414         // it is put into an anomyous block box. We try to use an existing anonymous box if possible, otherwise
    01415         // a new one is created and inserted into our list of children in the appropriate position.
    01416         if(newChild->isInline()) {
    01417             if (beforeChild) {
    01418                 if (beforeChild->previousSibling() && beforeChild->previousSibling()->isAnonymousBox()) {
    01419                     beforeChild->previousSibling()->addChild(newChild);
    01420                     newChild->setLayouted( false );
    01421                     newChild->setMinMaxKnown( false );
    01422                     return;
    01423                 }
    01424             }
    01425             else{
    01426                 if (m_last && m_last->isAnonymousBox()) {
    01427                     m_last->addChild(newChild);
    01428                     newChild->setLayouted( false );
    01429                     newChild->setMinMaxKnown( false );
    01430                     return;
    01431                 }
    01432             }
    01433
    01434             // no suitable existing anonymous box - create a new one
    01435             RenderStyle *newStyle = new RenderStyle();
    01436             newStyle->inheritFrom(style());
    01437             newStyle->setDisplay(BLOCK);
    01438
    01439             RenderFlow *newBox = new RenderFlow(0 /* anonymous box */);
    01440             newBox->setStyle(newStyle);
    01441             newBox->setIsAnonymousBox(true);
    01442
    01443             RenderBox::addChild(newBox,beforeChild);
    01444             newBox->addChild(newChild);
    01445             newBox->setPos(newBox->xPos(), -500000);
    01446
    01447             newChild->setLayouted( false );
    01448             newChild->setMinMaxKnown( false );
    01449             return;
    01450         }
    01451         else {
    01452             // We are adding another block child... if the current last child is an anonymous box
    01453             // then it needs to be closed.
    01454             // ### get rid of the closing thing altogether this will only work during initial parsing
    01455             if (lastChild() && lastChild()->isAnonymousBox()) {
    01456                 lastChild()->close();
    01457             }
    01458         }
    01459     }
    01460
    01461     if(!newChild->isInline() && !newChild->isPositioned()) // block child
    01462     {
    01463         // If we are inline ourselves and have become block, we have to make sure our parent
    01464         // makes the necessary adjustments so that all of its other children are moved into
    01465         // anonymous block boxes where necessary
    01466         if (style()->display() == INLINE)
    01467         {
    01468             setInline(false); // inline can't contain blocks
    01469             RenderObject *p = parent();
    01470             if (p && p->isFlow() && p->childrenInline() ) {
    01471                 static_cast<RenderFlow*>(p)->makeChildrenNonInline();
    01472                 madeBoxesNonInline = true;
    01473             }
    01474         }
    01475     }
    01476
    01477     RenderBox::addChild(newChild,beforeChild);
    01478     // ### care about aligned stuff
    01479
    01480     newChild->setLayouted( false );
    01481     newChild->setMinMaxKnown( false );
    01482     insertPseudoChild(RenderStyle::AFTER, newChild, beforeChild);
    01483
    01484     if ( madeBoxesNonInline )
    01485         removeLeftoverAnonymousBoxes();
    01486 }
    01487
    01488 void RenderFlow::makeChildrenNonInline(RenderObject *box2Start)
    01489 {
    01490     KHTMLAssert(!box2Start || box2Start->parent() == this);
    01491
    01492     m_childrenInline = false;
    01493
    01494     RenderObject *child = firstChild();
    01495     RenderObject *next;
    01496     RenderObject *boxFirst = 0;
    01497     RenderObject *boxLast = 0;
    01498     while (child) {
    01499         next = child->nextSibling();
    01500
    01501         if (child->isInline()) {
    01502             if ( !boxFirst )
    01503                 boxFirst = child;
    01504             boxLast = child;
    01505         }
    01506
    01507         if ( boxFirst &&
    01508              ( !child->isInline() || !next || child == box2Start ) ) {
    01509             // Create a new anonymous box containing all children starting from boxFirst
    01510             // and up to (but not including) boxLast, and put it in place of the children
    01511             RenderStyle *newStyle = new RenderStyle();
    01512             newStyle->inheritFrom(style());
    01513             newStyle->setDisplay(BLOCK);
    01514
    01515             RenderFlow *box = new RenderFlow(0 /* anonymous box */);
    01516             box->setStyle(newStyle);
    01517             box->setIsAnonymousBox(true);
    01518             // ### the children have a wrong style!!!
    01519             // They get exactly the style of this element, not of the anonymous box
    01520             // might be important for bg colors!
    01521
    01522             insertChildNode(box, boxFirst);
    01523             RenderObject* o = boxFirst;
    01524             while(o && o != boxLast)
    01525             {
    01526                 RenderObject* no = o;
    01527                 o = no->nextSibling();
    01528                 box->appendChildNode(removeChildNode(no));
    01529             }
    01530             box->appendChildNode(removeChildNode(boxLast));
    01531             box->close();
    01532             box->setPos(box->xPos(), -500000);
    01533             box->setLayouted(false);
    01534             boxFirst = boxLast = next;
    01535         }
    01536
    01537         child = next;
    01538     }
    01539
    01540     if (isInline()) {
    01541         setInline(false);
    01542         if (parent()->isFlow()) {
    01543             KHTMLAssert(parent()->childrenInline());
    01544             static_cast<RenderFlow *>(parent())->makeChildrenNonInline();
    01545         }
    01546     }
    01547
    01548     setLayouted(false);
    01549 }
    01550
    01551 bool RenderFlow::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty)
    01552 {
    01553     bool inBox = false;
    01554     if (specialObjects) {
    01555         int stx = _tx + xPos();
    01556         int sty = _ty + yPos();
    01557         if (isRelPositioned())
    01558             static_cast<RenderBox*>(this)->relativePositionOffset(stx, sty);
    01559         // special case - special objects in root are relative to viewport
    01560         if (isRoot()) {
    01561             stx += static_cast<RenderRoot*>(this)->view()->contentsX();
    01562             sty += static_cast<RenderRoot*>(this)->view()->contentsY();
    01563         }
    01564         SpecialObject* o;
    01565         QPtrListIterator<SpecialObject> it(*specialObjects);
    01566         for (it.toLast(); (o = it.current()); --it)
    01567             if ( o->node->isPositioned() && o->node->containingBlock() == this)
    01568                 inBox |= o->node->nodeAtPoint(info, _x, _y, stx, sty);
    01569             else if ( o->node->isFloating() && !o->noPaint )
    01570                 inBox |= o->node->nodeAtPoint( info, _x, _y,
    01571                                                stx + o->left + o->node->marginLeft() - o->node->xPos(),
    01572                                                sty + o->startY + o->node->marginTop() - o->node->yPos() );
    01573     }
    01574
    01575     inBox |= RenderBox::nodeAtPoint(info, _x, _y, _tx, _ty);
    01576     return inBox;
    01577 }
    01578
    01579 #ifndef NDEBUG
    01580 void RenderFlow::printTree(int indent) const
    01581 {
    01582     RenderBox::printTree(indent);
    01583
    01584     if(specialObjects)
    01585     {
    01586         QPtrListIterator<SpecialObject> it(*specialObjects);
    01587         SpecialObject *r;
    01588         for ( ; (r = it.current()); ++it )
    01589         {
    01590             QString s;
    01591             s.fill(' ', indent);
    01592             kdDebug() << s << renderName() << ":  " <<
    01593                 (r->type == SpecialObject::FloatLeft ? "FloatLeft" : (r->type == SpecialObject::FloatRight ? "FloatRight" : "Positioned"))  <<
    01594                 "[" << r->node->renderName() << ": " << (void*)r->node << "] (" << r->startY << " - " << r->endY << ")" <<
    01595                 (r->noPaint ? " noPaint " : " ") << "left: " << r->left << " width: " << r->width <<
    01596                 endl;
    01597         }
    01598     }
    01599 }
    01600
    01601 void RenderFlow::dump(QTextStream *stream, QString ind) const
    01602 {
    01603     if (m_childrenInline) { *stream << " childrenInline"; }
    01604     if (m_pre) { *stream << " pre"; }
    01605     if (firstLine) { *stream << " firstLine"; }
    01606
    01607     if(specialObjects && !specialObjects->isEmpty())
    01608     {
    01609         *stream << " special(";
    01610         QPtrListIterator<SpecialObject> it(*specialObjects);
    01611         SpecialObject *r;
    01612         bool first = true;
    01613         for ( ; (r = it.current()); ++it )
    01614         {
    01615             if (!first)
    01616                 *stream << ",";
    01617             *stream << r->node->renderName();
    01618             first = false;
    01619         }
    01620         *stream << ")";
    01621     }
    01622
    01623     // ### EClear m_clearStatus
    01624
    01625     RenderBox::dump(stream,ind);
    01626 }
    01627 #endif
    01628
    01629 #undef DEBUG
    01630 #undef DEBUG_LAYOUT
    01631 #undef BOX_DEBUG

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:34:33 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001