khtml Library API Documentation

render_container.cpp

00001 
00026 //#define DEBUG_LAYOUT
00027 
00028 #include "render_container.h"
00029 #include "render_table.h"
00030 #include "render_text.h"
00031 #include "render_image.h"
00032 #include "render_root.h"
00033 
00034 #include <kdebug.h>
00035 #include <assert.h>
00036 
00037 using namespace khtml;
00038 
00039 RenderContainer::RenderContainer(DOM::NodeImpl* node)
00040     : RenderObject(node)
00041 {
00042     m_first = 0;
00043     m_last = 0;
00044 }
00045 
00046 
00047 RenderContainer::~RenderContainer()
00048 {
00049     RenderObject* next;
00050     for(RenderObject* n = m_first; n; n = next ) {
00051         n->removeFromSpecialObjects();
00052         n->setParent(0);
00053         next = n->nextSibling();
00054         n->detach();
00055     }
00056     m_first = 0;
00057     m_last = 0;
00058 }
00059 
00060 void RenderContainer::addChild(RenderObject *newChild, RenderObject *beforeChild)
00061 {
00062 #ifdef DEBUG_LAYOUT
00063     kdDebug( 6040 ) << this << ": " <<  renderName() << "(RenderObject)::addChild( " << newChild << ": " <<
00064         newChild->renderName() << ", " << (beforeChild ? beforeChild->renderName() : "0") << " )" << endl;
00065 #endif
00066 
00067     bool needsTable = false;
00068 
00069     if(!newChild->isText() && !newChild->isReplaced()) {
00070         switch(newChild->style()->display()) {
00071         case INLINE:
00072         case BLOCK:
00073         case LIST_ITEM:
00074         case RUN_IN:
00075         case INLINE_BLOCK:
00076         case TABLE:
00077         case INLINE_TABLE:
00078         case TABLE_COLUMN:
00079             break;
00080         case TABLE_COLUMN_GROUP:
00081         case TABLE_CAPTION:
00082         case TABLE_ROW_GROUP:
00083         case TABLE_HEADER_GROUP:
00084         case TABLE_FOOTER_GROUP:
00085 
00086             //kdDebug( 6040 ) << "adding section" << endl;
00087             if ( !isTable() )
00088                 needsTable = true;
00089             break;
00090         case TABLE_ROW:
00091             //kdDebug( 6040 ) << "adding row" << endl;
00092             if ( !isTableSection() )
00093                 needsTable = true;
00094             break;
00095         case TABLE_CELL:
00096             //kdDebug( 6040 ) << "adding cell" << endl;
00097             if ( !isTableRow() )
00098                 needsTable = true;
00099             break;
00100         case NONE:
00101             KHTMLAssert(false);
00102             break;
00103         }
00104     }
00105 
00106     if ( needsTable ) {
00107         RenderTable *table;
00108         RenderObject *last = beforeChild ? beforeChild->previousSibling() : lastChild();
00109         if ( last && last->isTable() && last->isAnonymousBox() ) {
00110             table = static_cast<RenderTable *>(last);
00111         } else {
00112             //kdDebug( 6040 ) << "creating anonymous table, before=" << beforeChild << endl;
00113             table = new RenderTable(0 /* is anonymous */);
00114             RenderStyle *newStyle = new RenderStyle();
00115             newStyle->inheritFrom(style());
00116             newStyle->setDisplay( TABLE );
00117             newStyle->setFlowAroundFloats( true );
00118             table->setStyle(newStyle);
00119             table->setIsAnonymousBox(true);
00120             addChild(table, beforeChild);
00121         }
00122         table->addChild(newChild);
00123     } else {
00124         // just add it...
00125         insertChildNode(newChild, beforeChild);
00126     }
00127     newChild->setLayouted( false );
00128     newChild->setMinMaxKnown( false );
00129 }
00130 
00131 RenderObject* RenderContainer::removeChildNode(RenderObject* oldChild)
00132 {
00133     KHTMLAssert(oldChild->parent() == this);
00134 
00135     // if oldChild is the start or end of the selection, then clear the selection to
00136     // avoid problems of invalid pointers
00137 
00138     // ### This is not the "proper" solution... ideally the selection should be maintained
00139     // based on DOM Nodes and a Range, which gets adjusted appropriately when nodes are
00140     // deleted/inserted near etc. But this at least prevents crashes caused when the start
00141     // or end of the selection is deleted and then accessed when the user next selects
00142     // something.
00143 
00144     if (oldChild->isSelectionBorder()) {
00145         RenderObject *root = oldChild;
00146         while (root && root->parent())
00147             root = root->parent();
00148         if (root->isRoot()) {
00149             static_cast<RenderRoot*>(root)->clearSelection();
00150         }
00151     }
00152 
00153     // remove the child
00154     if (oldChild->previousSibling())
00155         oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
00156     if (oldChild->nextSibling())
00157         oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
00158 
00159     if (m_first == oldChild)
00160         m_first = oldChild->nextSibling();
00161     if (m_last == oldChild)
00162         m_last = oldChild->previousSibling();
00163 
00164     oldChild->setPreviousSibling(0);
00165     oldChild->setNextSibling(0);
00166     oldChild->setParent(0);
00167 
00168     setLayouted( false );
00169     setMinMaxKnown( false );
00170 
00171     if ( isAnonymousBox() && !firstChild() ) {
00172         // we are an empty anonymous box. There is no reason for us to continue living.
00173         detach();
00174     }
00175 
00176     return oldChild;
00177 }
00178 
00179 void RenderContainer::insertPseudoChild(RenderStyle::PseudoId type, RenderObject* child, RenderObject* beforeChild)
00180 {
00181 
00182     if (child->isText())
00183         return;
00184 
00185     RenderStyle* pseudo = child->style()->getPseudoStyle(type);
00186 
00187     if (pseudo) {
00188         pseudo->ref();
00189         if (pseudo->display() != NONE && pseudo->contentType()==CONTENT_TEXT)
00190         {
00191             RenderObject* po = new RenderFlow(0 /* anonymous box */);
00192             po->setStyle(pseudo);
00193 
00194             addChild(po, beforeChild);
00195 
00196             RenderText* t = new RenderText(0 /*anonymous object */, pseudo->contentText());
00197             t->setStyle(pseudo);
00198 
00199 //            kdDebug() << DOM::DOMString(pseudo->contentText()).string() << endl;
00200 
00201             po->addChild(t);
00202 
00203             t->close();
00204             po->close();
00205         }
00206         else if (pseudo->display() != NONE && pseudo->contentType()==CONTENT_OBJECT)
00207         {
00208             RenderObject* po = new RenderImage(0);
00209             po->setStyle(pseudo);
00210             addChild(po, beforeChild);
00211             po->close();
00212         }
00213         pseudo->deref();
00214     }
00215 }
00216 
00217 
00218 void RenderContainer::appendChildNode(RenderObject* newChild)
00219 {
00220     KHTMLAssert(newChild->parent() == 0);
00221 
00222     newChild->setParent(this);
00223     RenderObject* lChild = lastChild();
00224 
00225     if(lChild)
00226     {
00227         newChild->setPreviousSibling(lChild);
00228         lChild->setNextSibling(newChild);
00229     }
00230     else
00231         setFirstChild(newChild);
00232 
00233     setLastChild(newChild);
00234     newChild->setLayouted( false );
00235     newChild->setMinMaxKnown( false );
00236 }
00237 
00238 void RenderContainer::insertChildNode(RenderObject* child, RenderObject* beforeChild)
00239 {
00240     if(!beforeChild) {
00241         appendChildNode(child);
00242         return;
00243     }
00244 
00245     KHTMLAssert(!child->parent());
00246     while ( beforeChild->parent() != this && beforeChild->parent()->isAnonymousBox() )
00247         beforeChild = beforeChild->parent();
00248     KHTMLAssert(beforeChild->parent() == this);
00249 
00250     if(beforeChild == firstChild())
00251         setFirstChild(child);
00252 
00253     RenderObject* prev = beforeChild->previousSibling();
00254     child->setNextSibling(beforeChild);
00255     beforeChild->setPreviousSibling(child);
00256     if(prev) prev->setNextSibling(child);
00257     child->setPreviousSibling(prev);
00258 
00259     child->setParent(this);
00260     child->setLayouted( false );
00261     child->setMinMaxKnown( false );
00262 }
00263 
00264 
00265 void RenderContainer::layout()
00266 {
00267     KHTMLAssert( !layouted() );
00268     KHTMLAssert( minMaxKnown() );
00269 
00270     RenderObject *child = firstChild();
00271     while( child ) {
00272         if( !child->layouted() )
00273             child->layout();
00274         child = child->nextSibling();
00275     }
00276     setLayouted();
00277 }
00278 
00279 void RenderContainer::removeLeftoverAnonymousBoxes()
00280 {
00281     // we have to go over all child nodes and remove anonymous boxes, that do _not_
00282     // have inline children to keep the tree flat
00283     RenderObject *child = firstChild();
00284     while( child ) {
00285         RenderObject *next = child->nextSibling();
00286 
00287         if ( child->isFlow() && child->isAnonymousBox() &&
00288              !child->childrenInline() && !child->isTableCell() ) {
00289             RenderObject *firstAnChild = child->firstChild();
00290             RenderObject *lastAnChild = child->lastChild();
00291             if ( firstAnChild ) {
00292                 RenderObject *o = firstAnChild;
00293                 while( o ) {
00294                     o->setParent( this );
00295                     o = o->nextSibling();
00296                 }
00297                 firstAnChild->setPreviousSibling( child->previousSibling() );
00298                 lastAnChild->setNextSibling( child->nextSibling() );
00299                 if ( child->previousSibling() )
00300                     child->previousSibling()->setNextSibling( firstAnChild );
00301                 if ( child->nextSibling() )
00302                     child->nextSibling()->setPreviousSibling( lastAnChild );
00303             } else {
00304                 if ( child->previousSibling() )
00305                     child->previousSibling()->setNextSibling( child->nextSibling() );
00306                 if ( child->nextSibling() )
00307                     child->nextSibling()->setPreviousSibling( child->previousSibling() );
00308 
00309             }
00310             if ( child == firstChild() )
00311                 m_first = firstAnChild;
00312             if ( child == lastChild() )
00313                 m_last = lastAnChild;
00314             child->setParent( 0 );
00315             child->setPreviousSibling( 0 );
00316             child->setNextSibling( 0 );
00317             if ( !child->isText() ) {
00318                 RenderContainer *c = static_cast<RenderContainer *>(child);
00319                 c->m_first = 0;
00320                 c->m_next = 0;
00321             }
00322             delete child;
00323         }
00324         child = next;
00325     }
00326     if ( parent() )
00327         parent()->removeLeftoverAnonymousBoxes();
00328 }
00329 
00330 #undef DEBUG_LAYOUT
KDE Logo
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:31 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001