khtml Library API Documentation

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
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