khtml Library API Documentation

render_table.cpp

00001 
00026 //#define TABLE_DEBUG
00027 //#define TABLE_PRINT
00028 //#define DEBUG_LAYOUT
00029 //#define BOX_DEBUG
00030 #include "rendering/render_table.h"
00031 #include "rendering/table_layout.h"
00032 #include "html/html_tableimpl.h"
00033 #include "misc/htmltags.h"
00034 
00035 #include <kglobal.h>
00036 
00037 #include <qapplication.h>
00038 #include <qstyle.h>
00039 
00040 #include <kdebug.h>
00041 #include <assert.h>
00042 
00043 using namespace khtml;
00044 
00045 RenderTable::RenderTable(DOM::NodeImpl* node)
00046     : RenderFlow(node)
00047 {
00048 
00049     tCaption = 0;
00050     head = 0;
00051     foot = 0;
00052     firstBody = 0;
00053 
00054     m_maxWidth = 0;
00055 
00056     tableLayout = 0;
00057 
00058     rules = None;
00059     frame = Void;
00060     has_col_elems = false;
00061     needSectionRecalc = false;
00062     padding = 0;
00063 
00064     columnPos.resize( 2 );
00065     columnPos.fill( 0 );
00066     columns.resize( 1 );
00067     columns.fill( ColumnStruct() );
00068 
00069     columnPos[0] = 0;
00070 }
00071 
00072 RenderTable::~RenderTable()
00073 {
00074     delete tableLayout;
00075 }
00076 
00077 void RenderTable::setStyle(RenderStyle *_style)
00078 {
00079     ETableLayout oldTableLayout = style() ? style()->tableLayout() : TAUTO;
00080     if ( _style->display() != INLINE_TABLE ) _style->setDisplay(TABLE);
00081     RenderFlow::setStyle(_style);
00082 
00083     // init RenderObject attributes
00084     setInline(style()->display()==INLINE_TABLE && !isPositioned());
00085     setReplaced(style()->display()==INLINE_TABLE);
00086 
00087     spacing = style()->borderSpacing();
00088     columnPos[0] = spacing;
00089 
00090     if ( !tableLayout || style()->tableLayout() != oldTableLayout ) {
00091     delete tableLayout;
00092 
00093     if (style()->tableLayout() == TFIXED ) {
00094         tableLayout = new FixedTableLayout(this);
00095 #ifdef DEBUG_LAYOUT
00096         kdDebug( 6040 ) << "using fixed table layout" << endl;
00097 #endif
00098     } else
00099         tableLayout = new AutoTableLayout(this);
00100     }
00101 }
00102 
00103 void RenderTable::position(int x, int y, int, int, int, bool, bool, int)
00104 {
00105     //for inline tables only
00106     m_x = x + marginLeft();
00107     m_y = y + marginTop();
00108 }
00109 
00110 void RenderTable::addChild(RenderObject *child, RenderObject *beforeChild)
00111 {
00112 #ifdef DEBUG_LAYOUT
00113     kdDebug( 6040 ) << renderName() << "(Table)::addChild( " << child->renderName() << ", " <<
00114                        (beforeChild ? beforeChild->renderName() : "0") << " )" << endl;
00115 #endif
00116     RenderObject *o = child;
00117 
00118     switch(child->style()->display())
00119     {
00120     case TABLE_CAPTION:
00121         tCaption = static_cast<RenderFlow *>(child);
00122         break;
00123     case TABLE_COLUMN:
00124     case TABLE_COLUMN_GROUP:
00125     RenderContainer::addChild(child,beforeChild);
00126     has_col_elems = true;
00127         return;
00128     case TABLE_HEADER_GROUP:
00129     if ( !head )
00130         head = static_cast<RenderTableSection *>(child);
00131         break;
00132     case TABLE_FOOTER_GROUP:
00133     if ( !foot )
00134         foot = static_cast<RenderTableSection *>(child);
00135         break;
00136     case TABLE_ROW_GROUP:
00137         if(!firstBody)
00138             firstBody = static_cast<RenderTableSection *>(child);
00139         break;
00140     default:
00141         if ( !beforeChild && lastChild() &&
00142          lastChild()->isTableSection() && lastChild()->isAnonymousBox() ) {
00143             o = lastChild();
00144         } else {
00145         RenderObject *lastBox = beforeChild;
00146         while ( lastBox && lastBox->parent()->isAnonymousBox() &&
00147             !lastBox->isTableSection() && lastBox->style()->display() != TABLE_CAPTION )
00148         lastBox = lastBox->parent();
00149         if ( lastBox && lastBox->isAnonymousBox() ) {
00150         lastBox->addChild( child, beforeChild );
00151         return;
00152         } else {
00153         if ( beforeChild && !beforeChild->isTableSection() )
00154             beforeChild = 0;
00155         //kdDebug( 6040 ) << this <<" creating anonymous table section beforeChild="<< beforeChild << endl;
00156         o = new RenderTableSection(0 /* anonymous */);
00157         RenderStyle *newStyle = new RenderStyle();
00158         newStyle->inheritFrom(style());
00159                 newStyle->setDisplay(TABLE_ROW_GROUP);
00160         o->setStyle(newStyle);
00161         o->setIsAnonymousBox(true);
00162         addChild(o, beforeChild);
00163         }
00164         }
00165         o->addChild(child);
00166     child->setLayouted( false );
00167     child->setMinMaxKnown( false );
00168         return;
00169     }
00170     RenderContainer::addChild(child,beforeChild);
00171 }
00172 
00173 
00174 
00175 void RenderTable::calcWidth()
00176 {
00177     if ( isPositioned() ) {
00178         calcAbsoluteHorizontal();
00179     }
00180 
00181     RenderObject *cb = containingBlock();
00182     int availableWidth = cb->contentWidth();
00183 
00184     LengthType widthType = style()->width().type;
00185     if(widthType > Relative && style()->width().value > 0) {
00186     // Percent or fixed table
00187         m_width = style()->width().minWidth( availableWidth );
00188         if(m_minWidth > m_width) m_width = m_minWidth;
00189     //kdDebug( 6040 ) << "1 width=" << m_width << " minWidth=" << m_minWidth << " availableWidth=" << availableWidth << " " << endl;
00190     } else {
00191         m_width = KMIN(short( availableWidth ),m_maxWidth);
00192     }
00193 
00194     // restrict width to what we really have in case we flow around floats
00195     if ( style()->flowAroundFloats() && cb->isFlow() ) {
00196     availableWidth = static_cast<RenderFlow *>(cb)->lineWidth( m_y );
00197     m_width = QMIN( availableWidth, m_width );
00198     }
00199 
00200     m_width = KMAX (m_width, m_minWidth);
00201 
00202     m_marginRight=0;
00203     m_marginLeft=0;
00204 
00205     calcHorizontalMargins(style()->marginLeft(),style()->marginRight(),availableWidth);
00206 }
00207 
00208 void RenderTable::layout()
00209 {
00210     KHTMLAssert( !layouted() );
00211     KHTMLAssert( minMaxKnown() );
00212     KHTMLAssert( !needSectionRecalc );
00213 
00214     //kdDebug( 6040 ) << renderName() << "(Table)"<< this << " ::layout0() width=" << width() << ", layouted=" << layouted() << endl;
00215 
00216     m_height = 0;
00217 
00218     //int oldWidth = m_width;
00219     calcWidth();
00220 
00221     // the optimisation below doesn't work since the internal table
00222     // layout could have changed.  we need to add a flag to the table
00223     // layout that tells us if something has changed in the min max
00224     // calculations to do it correctly.
00225 //     if ( oldWidth != m_width || columns.size() + 1 != columnPos.size() )
00226     tableLayout->layout();
00227 
00228 #ifdef DEBUG_LAYOUT
00229     kdDebug( 6040 ) << renderName() << "(Table)::layout1() width=" << width() << ", marginLeft=" << marginLeft() << " marginRight=" << marginRight() << endl;
00230 #endif
00231 
00232     setCellWidths();
00233 
00234     // layout child objects
00235     int calculatedHeight = 0;
00236 
00237     RenderObject *child = firstChild();
00238     while( child ) {
00239     if ( !child->layouted() )
00240         child->layout();
00241     if ( child->isTableSection() ) {
00242         static_cast<RenderTableSection *>(child)->calcRowHeight();
00243         calculatedHeight += static_cast<RenderTableSection *>(child)->layoutRows( 0 );
00244     }
00245     child = child->nextSibling();
00246     }
00247 
00248     // ### collapse caption margin
00249     if(tCaption && tCaption->style()->captionSide() != CAPBOTTOM) {
00250         tCaption->setPos(tCaption->marginLeft(), m_height);
00251         m_height += tCaption->height() + tCaption->marginTop() + tCaption->marginBottom();
00252     }
00253 
00254     m_height += borderTop();
00255 
00256     // html tables with percent height are relative to view
00257     Length h = style()->height();
00258     int th=0;
00259     if (h.isFixed())
00260         th = h.value;
00261     else if (h.isPercent()) {
00262         Length ch = containingBlock()->style()->height();
00263         if (ch.isFixed())
00264             th = h.width(ch.value);
00265         else {
00266             // check we or not inside a table
00267             RenderObject* ro = parent();
00268             for (; ro && !ro->isTableCell(); ro=ro->parent());
00269             if (!ro)
00270             {
00271         // we need to substract the bodys margins
00272         // ### fixme: use exact values here.
00273                 th = h.width(viewRect().height() - 20 );
00274                 // not really, but this way the view height change
00275                 // gets propagated correctly
00276                 setOverhangingContents();
00277             }
00278         }
00279     }
00280 
00281     // layout rows
00282     if ( th > calculatedHeight ) {
00283     // we have to redistribute that height to get the constraint correctly
00284     // just force the first body to the height needed
00285     // ### FIXME This should take height constraints on all table sections into account and distribute
00286     // accordingly. For now this should be good enough
00287         if (firstBody) {
00288             firstBody->calcRowHeight();
00289             firstBody->layoutRows( th - calculatedHeight );
00290         }
00291     }
00292     int bl = borderLeft();
00293 
00294     // position the table sections
00295     if ( head ) {
00296     head->setPos(bl, m_height);
00297     m_height += head->height();
00298     }
00299     RenderTableSection *body = firstBody;
00300     while ( body ) {
00301     body->setPos(bl, m_height);
00302     m_height += body->height();
00303     RenderObject *next = body->nextSibling();
00304     if ( next && next->isTableSection() && next != foot )
00305         body = static_cast<RenderTableSection *>(next);
00306     else
00307         body = 0;
00308     }
00309     if ( foot ) {
00310     foot->setPos(bl, m_height);
00311     m_height += foot->height();
00312     }
00313 
00314 
00315     m_height += borderBottom();
00316 
00317     if(tCaption && tCaption->style()->captionSide()==CAPBOTTOM) {
00318         tCaption->setPos(tCaption->marginLeft(), m_height);
00319         m_height += tCaption->height() + tCaption->marginTop() + tCaption->marginBottom();
00320     }
00321 
00322     //kdDebug(0) << "table height: " << m_height << endl;
00323 
00324     calcHeight();
00325 
00326     //kdDebug(0) << "table height: " << m_height << endl;
00327 
00328     // table can be containing block of positioned elements.
00329     // ### only pass true if width or height changed.
00330     layoutSpecialObjects( true );
00331 
00332     setLayouted();
00333 
00334 }
00335 
00336 void RenderTable::setCellWidths()
00337 {
00338 #ifdef DEBUG_LAYOUT
00339     kdDebug( 6040 ) << renderName() << "(Table, this=0x" << this << ")::setCellWidths()" << endl;
00340 #endif
00341 
00342     RenderObject *child = firstChild();
00343     while( child ) {
00344     if ( child->isTableSection() )
00345         static_cast<RenderTableSection *>(child)->setCellWidths();
00346     child = child->nextSibling();
00347     }
00348 }
00349 
00350 void RenderTable::paint( QPainter *p, int _x, int _y,
00351                                   int _w, int _h, int _tx, int _ty)
00352 {
00353 
00354     if(!layouted()) return;
00355 
00356     _tx += xPos();
00357     _ty += yPos();
00358 
00359     // add offset for relative positioning
00360     if(isRelPositioned())
00361         relativePositionOffset(_tx, _ty);
00362 
00363 
00364 #ifdef TABLE_PRINT
00365     kdDebug( 6040 ) << "RenderTable::paint() w/h = (" << width() << "/" << height() << ")" << endl;
00366 #endif
00367     if (!overhangingContents() && !isRelPositioned() && !isPositioned())
00368     {
00369         if((_ty > _y + _h) || (_ty + height() < _y)) return;
00370         if((_tx > _x + _w) || (_tx + width() < _x)) return;
00371     }
00372 
00373     bool clipped = false;
00374     // overflow: hidden
00375     if (style()->overflow()==OHIDDEN || (style()->position() == ABSOLUTE && style()->clipSpecified()) ) {
00376         calcClip(p, _tx, _ty);
00377     clipped = true;
00378     }
00379 
00380 #ifdef TABLE_PRINT
00381     kdDebug( 6040 ) << "RenderTable::paint(2) " << _tx << "/" << _ty << " (" << _y << "/" << _h << ")" << endl;
00382 #endif
00383 
00384     if(style()->visibility() == VISIBLE)
00385     paintBoxDecorations(p, _x, _y, _w, _h, _tx, _ty);
00386 
00387     RenderObject *child = firstChild();
00388     while( child ) {
00389     if ( child->isTableSection() || child == tCaption )
00390         child->paint( p, _x, _y, _w, _h, _tx, _ty );
00391     child = child->nextSibling();
00392     }
00393 
00394     if ( specialObjects )
00395     paintSpecialObjects( p, _x, _y, _w, _h, _tx, _ty);
00396 
00397 
00398     // overflow: hidden
00399     // restore clip region
00400     if ( clipped )
00401     p->restore();
00402 
00403 #ifdef BOX_DEBUG
00404     outlineBox(p, _tx, _ty, "blue");
00405 #endif
00406 }
00407 
00408 void RenderTable::calcMinMaxWidth()
00409 {
00410     KHTMLAssert( !minMaxKnown() );
00411 
00412     if ( needSectionRecalc )
00413     recalcSections();
00414 
00415 #ifdef DEBUG_LAYOUT
00416     kdDebug( 6040 ) << renderName() << "(Table " << this << ")::calcMinMaxWidth()" <<  endl;
00417 #endif
00418 
00419     tableLayout->calcMinMaxWidth();
00420 
00421     if (tCaption && tCaption->minWidth() > m_minWidth)
00422         m_minWidth = tCaption->minWidth();
00423 
00424     setMinMaxKnown();
00425 #ifdef DEBUG_LAYOUT
00426     kdDebug( 6040 ) << renderName() << " END: (Table " << this << ")::calcMinMaxWidth() min = " << m_minWidth << " max = " << m_maxWidth <<  endl;
00427 #endif
00428 }
00429 
00430 void RenderTable::close()
00431 {
00432 //    kdDebug( 6040 ) << "RenderTable::close()" << endl;
00433     setLayouted(false);
00434     setMinMaxKnown(false);
00435 }
00436 
00437 int RenderTable::borderTopExtra()
00438 {
00439     if (tCaption && tCaption->style()->captionSide()!=CAPBOTTOM)
00440         return -(tCaption->height() + tCaption->marginBottom() +  tCaption->marginTop());
00441     else
00442         return 0;
00443 
00444 }
00445 
00446 int RenderTable::borderBottomExtra()
00447 {
00448     if (tCaption && tCaption->style()->captionSide()==CAPBOTTOM)
00449         return -(tCaption->height() + tCaption->marginBottom() +  tCaption->marginTop());
00450     else
00451         return 0;
00452 }
00453 
00454 
00455 void RenderTable::splitColumn( int pos, int firstSpan )
00456 {
00457     // we need to add a new columnStruct
00458     int oldSize = columns.size();
00459     columns.resize( oldSize + 1 );
00460     int oldSpan = columns[pos].span;
00461 //     qDebug("splitColumn( %d,%d ), oldSize=%d, oldSpan=%d", pos, firstSpan, oldSize, oldSpan );
00462     KHTMLAssert( oldSpan > firstSpan );
00463     columns[pos].span = firstSpan;
00464     memmove( columns.data()+pos+1, columns.data()+pos, (oldSize-pos)*sizeof(ColumnStruct) );
00465     columns[pos+1].span = oldSpan - firstSpan;
00466 
00467     // change width of all rows.
00468     RenderObject *child = firstChild();
00469     while ( child ) {
00470     if ( child->isTableSection() ) {
00471         RenderTableSection *section = static_cast<RenderTableSection *>(child);
00472         int size = section->grid.size();
00473         int row = 0;
00474         if ( section->cCol > pos )
00475         section->cCol++;
00476         while ( row < size ) {
00477         section->grid[row].row->resize( oldSize+1 );
00478         RenderTableSection::Row &r = *section->grid[row].row;
00479         memmove( r.data()+pos+1, r.data()+pos, (oldSize-pos)*sizeof( RenderTableCell * ) );
00480 //      qDebug("moving from %d to %d, num=%d", pos, pos+1, (oldSize-pos-1) );
00481         r[pos+1] = r[pos] ? (RenderTableCell *)-1 : 0;
00482         row++;
00483         }
00484     }
00485     child = child->nextSibling();
00486     }
00487     columnPos.resize( numEffCols()+1 );
00488     setMinMaxKnown( false );
00489     setLayouted( false );
00490 }
00491 
00492 void RenderTable::appendColumn( int span )
00493 {
00494     // easy case.
00495     int pos = columns.size();
00496 //     qDebug("appendColumn( %d ), size=%d", span, pos );
00497     int newSize = pos + 1;
00498     columns.resize( newSize );
00499     columns[pos].span = span;
00500     //qDebug("appending column at %d, span %d", pos,  span );
00501 
00502     // change width of all rows.
00503     RenderObject *child = firstChild();
00504     while ( child ) {
00505     if ( child->isTableSection() ) {
00506         RenderTableSection *section = static_cast<RenderTableSection *>(child);
00507         int size = section->grid.size();
00508         int row = 0;
00509         while ( row < size ) {
00510         section->grid[row].row->resize( newSize );
00511         section->cellAt( row, pos ) = 0;
00512         row++;
00513         }
00514 
00515     }
00516     child = child->nextSibling();
00517     }
00518     columnPos.resize( numEffCols()+1 );
00519     setMinMaxKnown( false );
00520     setLayouted( false );
00521 }
00522 
00523 RenderTableCol *RenderTable::colElement( int col ) {
00524     if ( !has_col_elems )
00525     return 0;
00526     RenderObject *child = firstChild();
00527     int cCol = 0;
00528     while ( child ) {
00529     if ( child->isTableCol() ) {
00530         RenderTableCol *colElem = static_cast<RenderTableCol *>(child);
00531         int span = colElem->span();
00532         if ( !colElem->firstChild() ) {
00533         cCol += span;
00534         if ( cCol > col )
00535             return colElem;
00536         }
00537 
00538         RenderObject *next = child->firstChild();
00539         if ( !next )
00540         next = child->nextSibling();
00541         if ( !next && child->parent()->isTableCol() )
00542         next = child->parent()->nextSibling();
00543         child = next;
00544     } else
00545         break;
00546     }
00547     return 0;
00548 }
00549 
00550 void RenderTable::recalcSections()
00551 {
00552     tCaption = 0;
00553     head = foot = firstBody = 0;
00554     has_col_elems = false;
00555 
00556     RenderObject *child = firstChild();
00557     // We need to get valid pointers to caption, head, foot and firstbody again
00558     while ( child ) {
00559     switch(child->style()->display()) {
00560     case TABLE_CAPTION:
00561         if ( !tCaption) {
00562         tCaption = static_cast<RenderFlow*>(child);
00563                 tCaption->setLayouted(false);
00564             }
00565         break;
00566     case TABLE_COLUMN:
00567     case TABLE_COLUMN_GROUP:
00568         has_col_elems = true;
00569         return;
00570     case TABLE_HEADER_GROUP: {
00571         RenderTableSection *section = static_cast<RenderTableSection *>(child);
00572         if ( !head )
00573         head = section;
00574         if ( section->needCellRecalc )
00575         section->recalcCells();
00576         break;
00577     }
00578     case TABLE_FOOTER_GROUP: {
00579         RenderTableSection *section = static_cast<RenderTableSection *>(child);
00580         if ( !foot )
00581         foot = section;
00582         if ( section->needCellRecalc )
00583         section->recalcCells();
00584         break;
00585     }
00586     case TABLE_ROW_GROUP: {
00587         RenderTableSection *section = static_cast<RenderTableSection *>(child);
00588         if ( !firstBody )
00589         firstBody = section;
00590         if ( section->needCellRecalc )
00591         section->recalcCells();
00592     }
00593     default:
00594         break;
00595     }
00596     child = child->nextSibling();
00597     }
00598     needSectionRecalc = false;
00599     setLayouted( false );
00600 }
00601 
00602 RenderObject* RenderTable::removeChildNode(RenderObject* child)
00603 {
00604     setNeedSectionRecalc();
00605     return RenderContainer::removeChildNode( child );
00606 }
00607 
00608 
00609 #ifndef NDEBUG
00610 void RenderTable::dump(QTextStream *stream, QString ind) const
00611 {
00612     if (tCaption)
00613     *stream << " tCaption";
00614     if (head)
00615     *stream << " head";
00616     if (foot)
00617     *stream << " foot";
00618 
00619     *stream << endl << ind << "cspans:";
00620     for ( unsigned int i = 0; i < columns.size(); i++ )
00621     *stream << " " << columns[i].span;
00622     *stream << endl << ind;
00623 
00624     RenderFlow::dump(stream,ind);
00625 }
00626 #endif
00627 
00628 // --------------------------------------------------------------------------
00629 
00630 RenderTableSection::RenderTableSection(DOM::NodeImpl* node)
00631     : RenderBox(node)
00632 {
00633     // init RenderObject attributes
00634     setInline(false);   // our object is not Inline
00635     cCol = 0;
00636     cRow = -1;
00637     needCellRecalc = false;
00638 }
00639 
00640 RenderTableSection::~RenderTableSection()
00641 {
00642     clearGrid();
00643 }
00644 
00645 void RenderTableSection::detach()
00646 {
00647     // recalc cell info because RenderTable has unguarded pointers
00648     // stored that point to this RenderTableSection.
00649     if (table())
00650         table()->setNeedSectionRecalc();
00651 
00652     RenderBox::detach();
00653 }
00654 
00655 void RenderTableSection::setStyle(RenderStyle* _style)
00656 {
00657     // we don't allow changing this one
00658     if (style())
00659         _style->setDisplay(style()->display());
00660     else if (_style->display() != TABLE_FOOTER_GROUP && _style->display() != TABLE_HEADER_GROUP)
00661         _style->setDisplay(TABLE_ROW_GROUP);
00662 
00663     RenderBox::setStyle(_style);
00664 }
00665 
00666 void RenderTableSection::addChild(RenderObject *child, RenderObject *beforeChild)
00667 {
00668 #ifdef DEBUG_LAYOUT
00669     kdDebug( 6040 ) << renderName() << "(TableSection)::addChild( " << child->renderName()  << ", beforeChild=" <<
00670                        (beforeChild ? beforeChild->renderName() : "0") << " )" << endl;
00671 #endif
00672     RenderObject *row = child;
00673 
00674     if ( !child->isTableRow() ) {
00675 
00676         if( !beforeChild )
00677             beforeChild = lastChild();
00678 
00679         if( beforeChild && beforeChild->isAnonymousBox() )
00680             row = beforeChild;
00681         else {
00682         RenderObject *lastBox = beforeChild;
00683         while ( lastBox && lastBox->parent()->isAnonymousBox() && !lastBox->isTableRow() )
00684         lastBox = lastBox->parent();
00685         if ( lastBox && lastBox->isAnonymousBox() ) {
00686         lastBox->addChild( child, beforeChild );
00687         return;
00688         } else {
00689         //kdDebug( 6040 ) << "creating anonymous table row" << endl;
00690         row = new RenderTableRow(0 /* anonymous table */);
00691         RenderStyle *newStyle = new RenderStyle();
00692         newStyle->inheritFrom(style());
00693         newStyle->setDisplay( TABLE_ROW );
00694         row->setStyle(newStyle);
00695         row->setIsAnonymousBox(true);
00696         addChild(row, beforeChild);
00697         }
00698         }
00699         row->addChild(child);
00700     child->setLayouted( false );
00701     child->setMinMaxKnown( false );
00702         return;
00703     }
00704 
00705     if (beforeChild)
00706     setNeedCellRecalc();
00707 
00708     cRow++;
00709     cCol = 0;
00710 
00711     ensureRows( cRow+1 );
00712 
00713     if (!beforeChild) {
00714         grid[cRow].height = child->style()->height();
00715         if ( grid[cRow].height.type == Relative )
00716             grid[cRow].height = Length();
00717     }
00718 
00719 
00720     RenderContainer::addChild(child,beforeChild);
00721 }
00722 
00723 void RenderTableSection::ensureRows( int numRows )
00724 {
00725     int nRows = grid.size();
00726     int nCols = table()->numEffCols();
00727     if ( numRows > nRows ) {
00728     grid.resize( numRows );
00729     for ( int r = nRows; r < numRows; r++ ) {
00730         grid[r].row = new Row( nCols );
00731         grid[r].row->fill( 0 );
00732         grid[r].baseLine = 0;
00733         grid[r].height = Length();
00734     }
00735     }
00736 
00737 }
00738 
00739 void RenderTableSection::addCell( RenderTableCell *cell )
00740 {
00741     int rSpan = cell->rowSpan();
00742     int cSpan = cell->colSpan();
00743     QMemArray<RenderTable::ColumnStruct> &columns = table()->columns;
00744     int nCols = columns.size();
00745 
00746     // ### mozilla still seems to do the old HTML way, even for strict DTD
00747     // (see the annotation on table cell layouting in the CSS specs and the testcase below:
00748     // <TABLE border>
00749     // <TR><TD>1 <TD rowspan="2">2 <TD>3 <TD>4
00750     // <TR><TD colspan="2">5
00751     // </TABLE>
00752 #if 0
00753     // find empty space for the cell
00754     bool found = false;
00755     while ( !found ) {
00756     found = true;
00757     while ( cCol < nCols && cellAt( cRow, cCol ) )
00758         cCol++;
00759     int pos = cCol;
00760     int span = 0;
00761     while ( pos < nCols && span < cSpan ) {
00762         if ( cellAt( cRow, pos ) ) {
00763         found = false;
00764         cCol = pos;
00765         break;
00766         }
00767         span += columns[pos].span;
00768         pos++;
00769     }
00770     }
00771 #else
00772     while ( cCol < nCols && cellAt( cRow, cCol ) )
00773     cCol++;
00774 #endif
00775 
00776 //       qDebug("adding cell at %d/%d span=(%d/%d)",  cRow, cCol, rSpan, cSpan );
00777 
00778     if ( rSpan == 1 ) {
00779     // we ignore height settings on rowspan cells
00780     Length height = cell->style()->height();
00781     if ( height.value > 0 || (height.type == Relative && height.value >= 0) ) {
00782         Length cRowHeight = grid[cRow].height;
00783         switch( height.type ) {
00784         case Percent:
00785         if ( !(cRowHeight.type == Percent) ||
00786              ( cRowHeight.type == Percent && cRowHeight.value < height.value ) )
00787             grid[cRow].height = height;
00788              break;
00789         case Fixed:
00790         if ( cRowHeight.type < Percent ||
00791              ( cRowHeight.type == Fixed && cRowHeight.value < height.value ) )
00792             grid[cRow].height = height;
00793         break;
00794         case Relative:
00795 #if 0
00796         // we treat this as variable. This is correct according to HTML4, as it only specifies length for the height.
00797         if ( cRowHeight.type == Variable ||
00798              ( cRowHeight.type == Relative && cRowHeight.value < height.value ) )
00799              grid[cRow].height = height;
00800              break;
00801 #endif
00802         default:
00803         break;
00804         }
00805     }
00806     }
00807 
00808     // make sure we have enough rows
00809     ensureRows( cRow + rSpan );
00810 
00811     int col = cCol;
00812     // tell the cell where it is
00813     RenderTableCell *set = cell;
00814     while ( cSpan ) {
00815     int currentSpan;
00816     if ( cCol >= nCols ) {
00817         table()->appendColumn( cSpan );
00818         currentSpan = cSpan;
00819     } else {
00820         if ( cSpan < columns[cCol].span )
00821         table()->splitColumn( cCol, cSpan );
00822         currentSpan = columns[cCol].span;
00823     }
00824     int r = 0;
00825     while ( r < rSpan ) {
00826         if ( !cellAt( cRow + r, cCol ) ) {
00827 //      qDebug("    adding cell at %d, %d",  cRow + r, cCol );
00828         cellAt( cRow + r, cCol ) = set;
00829         }
00830         r++;
00831     }
00832     cCol++;
00833     cSpan -= currentSpan;
00834     set = (RenderTableCell *)-1;
00835     }
00836     if ( cell ) {
00837     cell->setRow( cRow );
00838     cell->setCol( table()->effColToCol( col ) );
00839     }
00840 }
00841 
00842 
00843 
00844 void RenderTableSection::setCellWidths()
00845 {
00846 #ifdef DEBUG_LAYOUT
00847     kdDebug( 6040 ) << renderName() << "(Table, this=0x" << this << ")::setCellWidths()" << endl;
00848 #endif
00849     QMemArray<int> &columnPos = table()->columnPos;
00850 
00851     int rows = grid.size();
00852     for ( int i = 0; i < rows; i++ ) {
00853     Row &row = *grid[i].row;
00854     int cols = row.size();
00855     for ( int j = 0; j < cols; j++ ) {
00856         RenderTableCell *cell = row[j];
00857 //      qDebug("cell[%d,%d] = %p", i, j, cell );
00858         if ( !cell || cell == (RenderTableCell *)-1 )
00859         continue;
00860         int endCol = j;
00861         int cspan = cell->colSpan();
00862         while ( cspan && endCol < cols ) {
00863         cspan -= table()->columns[endCol].span;
00864         endCol++;
00865         }
00866         int w = columnPos[endCol] - columnPos[j] - table()->cellSpacing();
00867 #ifdef DEBUG_LAYOUT
00868         kdDebug( 6040 ) << "setting width of cell " << cell << " " << cell->row() << "/" << cell->col() << " to " << w << " colspan=" << cell->colSpan() << " start=" << j << " end=" << endCol << endl;
00869 #endif
00870         int oldWidth = cell->width();
00871         if ( w != oldWidth ) {
00872         cell->setLayouted(false);
00873         cell->setWidth( w );
00874         }
00875     }
00876     }
00877 }
00878 
00879 
00880 void RenderTableSection::calcRowHeight()
00881 {
00882     int indx;
00883     RenderTableCell *cell;
00884 
00885     int totalRows = grid.size();
00886     int spacing = table()->cellSpacing();
00887 
00888     rowPos.resize( totalRows + 1 );
00889     rowPos[0] =  spacing + borderTop();
00890 
00891     for ( int r = 0; r < totalRows; r++ ) {
00892     rowPos[r+1] = 0;
00893 
00894     int baseline=0;
00895     int bdesc = 0;
00896 //  qDebug("height of row %d is %d/%d", r, grid[r].height.value, grid[r].height.type );
00897     int ch = grid[r].height.minWidth( 0 );
00898     int pos = rowPos[ r+1 ] + ch + table()->cellSpacing();
00899 
00900     if ( pos > rowPos[r+1] )
00901         rowPos[r+1] = pos;
00902 
00903     Row *row = grid[r].row;
00904     int totalCols = row->size();
00905     int totalRows = grid.size();
00906 
00907     for ( int c = 0; c < totalCols; c++ ) {
00908         cell = cellAt(r, c);
00909         if ( !cell || cell == (RenderTableCell *)-1 )
00910         continue;
00911         if ( r < totalRows - 1 && cellAt(r+1, c) == cell )
00912         continue;
00913 
00914         if ( ( indx = r - cell->rowSpan() + 1 ) < 0 )
00915         indx = 0;
00916 
00917         ch = cell->style()->height().width(0);
00918         if ( cell->height() > ch)
00919         ch = cell->height();
00920 
00921         pos = rowPos[ indx ] + ch + table()->cellSpacing();
00922 
00923         if ( pos > rowPos[r+1] )
00924         rowPos[r+1] = pos;
00925 
00926         // find out the baseline
00927         EVerticalAlign va = cell->style()->verticalAlign();
00928         if (va == BASELINE || va == TEXT_BOTTOM || va == TEXT_TOP
00929         || va == SUPER || va == SUB)
00930         {
00931         int b=cell->baselinePosition();
00932 
00933         if (b>baseline)
00934             baseline=b;
00935 
00936         int td = rowPos[ indx ] + ch - b;
00937         if (td>bdesc)
00938             bdesc = td;
00939         }
00940     }
00941 
00942     //do we have baseline aligned elements?
00943     if (baseline) {
00944         // increase rowheight if baseline requires
00945         int bRowPos = baseline + bdesc  + table()->cellSpacing() ; // + 2*padding
00946         if (rowPos[r+1]<bRowPos)
00947         rowPos[r+1]=bRowPos;
00948 
00949         grid[r].baseLine = baseline;
00950     }
00951 
00952     if ( rowPos[r+1] < rowPos[r] )
00953         rowPos[r+1] = rowPos[r];
00954 //      qDebug("rowpos(%d)=%d",  r, rowPos[r] );
00955     }
00956 }
00957 
00958 int RenderTableSection::layoutRows( int toAdd )
00959 {
00960     int rHeight;
00961     int rindx;
00962     int totalRows = grid.size();
00963     int spacing = table()->cellSpacing();
00964 
00965     if (toAdd && totalRows && rowPos[totalRows]) {
00966 
00967     int totalHeight = rowPos[totalRows] + toAdd;
00968 //  qDebug("layoutRows: totalHeight = %d",  totalHeight );
00969 
00970         int dh = totalHeight-rowPos[totalRows];
00971     int totalPercent = 0;
00972     int numVariable = 0;
00973     for ( int r = 0; r < totalRows; r++ ) {
00974         if ( grid[r].height.type == Variable )
00975         numVariable++;
00976         else if ( grid[r].height.type == Percent )
00977         totalPercent += grid[r].height.value;
00978     }
00979     if ( totalPercent ) {
00980 //      qDebug("distributing %d over percent rows totalPercent=%d", dh,  totalPercent );
00981         // try to satisfy percent
00982         int add = 0;
00983         if ( totalPercent > 100 )
00984         totalPercent = 100;
00985         int rh = rowPos[1]-rowPos[0];
00986         for ( int r = 0; r < totalRows; r++ ) {
00987         if ( totalPercent > 0 && grid[r].height.type == Percent ) {
00988             int toAdd = QMIN( dh, (totalHeight * grid[r].height.value / 100)-rh );
00989             add += toAdd;
00990             dh -= toAdd;
00991             totalPercent -= grid[r].height.value;
00992 //          qDebug( "adding %d to row %d", toAdd, r );
00993         }
00994         if ( r < totalRows-1 )
00995             rh = rowPos[r+2] - rowPos[r+1];
00996                 rowPos[r+1] += add;
00997         }
00998     }
00999     if ( numVariable ) {
01000         // distribute over variable cols
01001 //      qDebug("distributing %d over variable rows numVariable=%d", dh,  numVariable );
01002         int add = 0;
01003         for ( int r = 0; r < totalRows; r++ ) {
01004         if ( numVariable > 0 && grid[r].height.type == Variable ) {
01005             int toAdd = dh/numVariable;
01006             add += toAdd;
01007             dh -= toAdd;
01008         }
01009                 rowPos[r+1] += add;
01010         }
01011     }
01012         if (dh>0) {
01013         // if some left overs, distribute equally.
01014             int tot=rowPos[totalRows];
01015             int add=0;
01016             int prev=rowPos[0];
01017             for ( int r = 0; r < totalRows; r++ ) {
01018                 //weight with the original height
01019                 add+=dh*(rowPos[r+1]-prev)/tot;
01020                 prev=rowPos[r+1];
01021                 rowPos[r+1]+=add;
01022             }
01023         }
01024     }
01025 
01026     int leftOffset = borderLeft() + spacing;
01027 
01028     int nEffCols = table()->numEffCols();
01029     for ( int r = 0; r < totalRows; r++ )
01030     {
01031     Row *row = grid[r].row;
01032     int totalCols = row->size();
01033         for ( int c = 0; c < nEffCols; c++ )
01034         {
01035             RenderTableCell *cell = cellAt(r, c);
01036             if (!cell || cell == (RenderTableCell *)-1 )
01037                 continue;
01038             if ( r < totalRows - 1 && cell == cellAt(r+1, c) )
01039         continue;
01040 
01041             if ( ( rindx = r-cell->rowSpan()+1 ) < 0 )
01042                 rindx = 0;
01043 
01044             rHeight = rowPos[r+1] - rowPos[rindx] - spacing;
01045 #ifdef DEBUG_LAYOUT
01046             kdDebug( 6040 ) << "setting position " << r << "/" << c << ": "
01047                 << table()->columnPos[c] /*+ padding */ << "/" << rowPos[rindx] << " height=" << rHeight<< endl;
01048 #endif
01049 
01050             EVerticalAlign va = cell->style()->verticalAlign();
01051             int te=0;
01052             switch (va)
01053             {
01054             case SUB:
01055             case SUPER:
01056             case TEXT_TOP:
01057             case TEXT_BOTTOM:
01058             case BASELINE:
01059         te = getBaseline(r) - cell->baselinePosition() ;
01060                 break;
01061             case TOP:
01062                 te = 0;
01063                 break;
01064             case MIDDLE:
01065                 te = (rHeight - cell->height())/2;
01066                 break;
01067             case BOTTOM:
01068                 te = rHeight - cell->height();
01069                 break;
01070             default:
01071                 break;
01072             }
01073 #ifdef DEBUG_LAYOUT
01074         //            kdDebug( 6040 ) << "CELL " << cell << " te=" << te << ", be=" << rHeight - cell->height() - te << ", rHeight=" << rHeight << ", valign=" << va << endl;
01075 #endif
01076             cell->setCellTopExtra( te );
01077             cell->setCellBottomExtra( rHeight - cell->height() - te);
01078 
01079             if (style()->direction()==RTL) {
01080                 cell->setPos(
01081             table()->columnPos[(int)totalCols] -
01082             table()->columnPos[table()->colToEffCol(cell->col()+cell->colSpan())] +
01083             leftOffset,
01084                     rowPos[rindx] );
01085             } else {
01086                 cell->setPos( table()->columnPos[c] + leftOffset, rowPos[rindx] );
01087         }
01088         }
01089     }
01090 
01091     m_height = rowPos[totalRows];
01092     return m_height;
01093 }
01094 
01095 
01096 void RenderTableSection::paint( QPainter *p, int x, int y, int w, int h,
01097                 int tx, int ty)
01098 {
01099     unsigned int totalRows = grid.size();
01100     unsigned int totalCols = table()->columns.size();
01101 
01102     tx += m_x;
01103     ty += m_y;
01104 
01105     // check which rows and cols are visible and only paint these
01106     // ### fixme: could use a binary search here
01107     unsigned int startrow = 0;
01108     unsigned int endrow = totalRows;
01109     for ( ; startrow < totalRows; startrow++ ) {
01110     if ( ty + rowPos[startrow+1] > y )
01111         break;
01112     }
01113     for ( ; endrow > 0; endrow-- ) {
01114     if ( ty + rowPos[endrow-1] < y + h )
01115         break;
01116     }
01117     unsigned int startcol = 0;
01118     unsigned int endcol = totalCols;
01119     if ( style()->direction() == LTR ) {
01120     for ( ; startcol < totalCols; startcol++ ) {
01121         if ( tx + table()->columnPos[startcol+1] > x )
01122         break;
01123     }
01124     for ( ; endcol > 0; endcol-- ) {
01125         if ( tx + table()->columnPos[endcol-1] < x + w )
01126         break;
01127     }
01128     }
01129     if ( startcol < endcol ) {
01130     // draw the cells
01131     for ( unsigned int r = startrow; r < endrow; r++ ) {
01132         unsigned int c = startcol;
01133         // since a cell can be -1 (indicating a colspan) we might have to search backwards to include it
01134         while ( c && cellAt( r, c ) == (RenderTableCell *)-1 )
01135         c--;
01136         for ( ; c < endcol; c++ ) {
01137         RenderTableCell *cell = cellAt(r, c);
01138         if (!cell || cell == (RenderTableCell *)-1 )
01139             continue;
01140         if ( (r < endrow - 1) && (cellAt(r+1, c) == cell) )
01141             continue;
01142 
01143 #ifdef TABLE_PRINT
01144         kdDebug( 6040 ) << "painting cell " << r << "/" << c << endl;
01145 #endif
01146         cell->paint( p, x, y, w, h, tx, ty);
01147         }
01148     }
01149     }
01150 }
01151 
01152 void RenderTableSection::recalcCells()
01153 {
01154     cCol = 0;
01155     cRow = -1;
01156     clearGrid();
01157     grid.resize( 0 );
01158 
01159     RenderObject *row = firstChild();
01160     while ( row ) {
01161     cRow++;
01162     cCol = 0;
01163     ensureRows( cRow+1 );
01164     RenderObject *cell = row->firstChild();
01165     while ( cell ) {
01166         if ( cell->isTableCell() )
01167         addCell( static_cast<RenderTableCell *>(cell) );
01168         cell = cell->nextSibling();
01169     }
01170     row = row->nextSibling();
01171     }
01172     needCellRecalc = false;
01173     setLayouted( false );
01174 }
01175 
01176 void RenderTableSection::clearGrid()
01177 {
01178     int rows = grid.size();
01179     while ( rows-- ) {
01180     delete grid[rows].row;
01181     }
01182 }
01183 
01184 RenderObject* RenderTableSection::removeChildNode(RenderObject* child)
01185 {
01186     setNeedCellRecalc();
01187     return RenderContainer::removeChildNode( child );
01188 }
01189 
01190 #ifndef NDEBUG
01191 void RenderTableSection::dump(QTextStream *stream, QString ind) const
01192 {
01193     *stream << endl << ind << "grid=(" << grid.size() << "," << table()->numEffCols() << ")" << endl << ind;
01194     for ( unsigned int r = 0; r < grid.size(); r++ ) {
01195     for ( int c = 0; c < table()->numEffCols(); c++ ) {
01196         if ( cellAt( r,  c ) && cellAt( r, c ) != (RenderTableCell *)-1 )
01197         *stream << "(" << cellAt( r, c )->row() << "," << cellAt( r, c )->col() << ","
01198             << cellAt(r, c)->rowSpan() << "," << cellAt(r, c)->colSpan() << ") ";
01199         else
01200         *stream << cellAt( r, c ) << "null cell ";
01201     }
01202     *stream << endl << ind;
01203     }
01204     RenderContainer::dump(stream,ind);
01205 }
01206 #endif
01207 
01208 // -------------------------------------------------------------------------
01209 
01210 RenderTableRow::RenderTableRow(DOM::NodeImpl* node)
01211     : RenderContainer(node)
01212 {
01213     // init RenderObject attributes
01214     setInline(false);   // our object is not Inline
01215 }
01216 
01217 void RenderTableRow::detach()
01218 {
01219     section()->setNeedCellRecalc();
01220 
01221     RenderContainer::detach();
01222 }
01223 
01224 void RenderTableRow::setStyle(RenderStyle* style)
01225 {
01226     style->setDisplay(TABLE_ROW);
01227     RenderContainer::setStyle(style);
01228 }
01229 
01230 void RenderTableRow::addChild(RenderObject *child, RenderObject *beforeChild)
01231 {
01232 #ifdef DEBUG_LAYOUT
01233     kdDebug( 6040 ) << renderName() << "(TableRow)::addChild( " << child->renderName() << " )"  << ", " <<
01234                        (beforeChild ? beforeChild->renderName() : "0") << " )" << endl;
01235 #endif
01236     RenderTableCell *cell;
01237 
01238     if ( !child->isTableCell() ) {
01239     RenderObject *last = beforeChild;
01240         if ( !last )
01241             last = lastChild();
01242         RenderTableCell *cell = 0;
01243         if( last && last->isAnonymousBox() && last->isTableCell() )
01244             cell = static_cast<RenderTableCell *>(last);
01245         else {
01246         kdDebug( 6040 ) << "creating anonymous table cell" << endl;
01247         cell = new RenderTableCell(0 /* anonymous object */);
01248         RenderStyle *newStyle = new RenderStyle();
01249         newStyle->inheritFrom(style());
01250         newStyle->setDisplay( TABLE_CELL );
01251         cell->setStyle(newStyle);
01252         cell->setIsAnonymousBox(true);
01253         addChild(cell, beforeChild);
01254         }
01255         cell->addChild(child);
01256     child->setLayouted( false );
01257     child->setMinMaxKnown( false );
01258         return;
01259     } else
01260         cell = static_cast<RenderTableCell *>(child);
01261 
01262     static_cast<RenderTableSection *>(parent())->addCell( cell );
01263 
01264     RenderContainer::addChild(cell,beforeChild);
01265 
01266     if ( ( beforeChild || nextSibling()) && section() )
01267     section()->setNeedCellRecalc();
01268 }
01269 
01270 RenderObject* RenderTableRow::removeChildNode(RenderObject* child)
01271 {
01272 // RenderTableCell detach should do it
01273 //     if ( section() )
01274 //  section()->setNeedCellRecalc();
01275     return RenderContainer::removeChildNode( child );
01276 }
01277 
01278 #ifndef NDEBUG
01279 void RenderTableRow::dump(QTextStream *stream, QString ind) const
01280 {
01281     RenderContainer::dump(stream,ind);
01282 }
01283 #endif
01284 
01285 void RenderTableRow::layout()
01286 {
01287     KHTMLAssert( !layouted() );
01288     KHTMLAssert( minMaxKnown() );
01289 
01290     RenderObject *child = firstChild();
01291     while( child ) {
01292     if ( child->isTableCell() && !child->layouted() ) {
01293         RenderTableCell *cell = static_cast<RenderTableCell *>(child);
01294         cell->calcVerticalMargins();
01295         cell->layout();
01296         cell->setCellTopExtra(0);
01297         cell->setCellBottomExtra(0);
01298     }
01299     child = child->nextSibling();
01300     }
01301     setLayouted();
01302 }
01303 
01304 // -------------------------------------------------------------------------
01305 
01306 RenderTableCell::RenderTableCell(DOM::NodeImpl* _node)
01307   : RenderFlow(_node)
01308 {
01309   _col = -1;
01310   _row = -1;
01311   updateFromElement();
01312   setSpecialObjects(true);
01313   _topExtra = 0;
01314   _bottomExtra = 0;
01315 }
01316 
01317 void RenderTableCell::detach()
01318 {
01319     if (parent() && section())
01320         section()->setNeedCellRecalc();
01321 
01322     RenderFlow::detach();
01323 }
01324 
01325 void RenderTableCell::updateFromElement()
01326 {
01327   DOM::NodeImpl *node = element();
01328   if ( node && (node->id() == ID_TD || node->id() == ID_TH) ) {
01329       DOM::HTMLTableCellElementImpl *tc = static_cast<DOM::HTMLTableCellElementImpl *>(node);
01330       cSpan = tc->colSpan();
01331       rSpan = tc->rowSpan();
01332       nWrap = tc->noWrap();
01333   } else {
01334       cSpan = rSpan = 1;
01335       nWrap = false;
01336   }
01337 }
01338 
01339 void RenderTableCell::calcMinMaxWidth()
01340 {
01341     KHTMLAssert( !minMaxKnown() );
01342 #ifdef DEBUG_LAYOUT
01343     kdDebug( 6040 ) << renderName() << "(TableCell)::calcMinMaxWidth() known=" << minMaxKnown() << endl;
01344 #endif
01345 
01346     RenderFlow::calcMinMaxWidth();
01347 
01348     setMinMaxKnown();
01349 }
01350 
01351 void RenderTableCell::calcWidth()
01352 {
01353 }
01354 
01355 void RenderTableCell::setWidth( int width )
01356 {
01357     if ( width != m_width ) {
01358     m_width = width;
01359     m_widthChanged = true;
01360     }
01361 }
01362 
01363 void RenderTableCell::close()
01364 {
01365     RenderFlow::close();
01366 
01367 #ifdef DEBUG_LAYOUT
01368     kdDebug( 6040 ) << renderName() << "(RenderTableCell)::close() total height =" << m_height << endl;
01369 #endif
01370 }
01371 
01372 
01373 void RenderTableCell::repaintRectangle(int x, int y, int w, int h, bool f)
01374 {
01375     y += _topExtra;
01376     RenderFlow::repaintRectangle(x, y, w, h, f);
01377 }
01378 
01379 bool RenderTableCell::absolutePosition(int &xPos, int &yPos, bool f)
01380 {
01381     bool ret = RenderFlow::absolutePosition(xPos, yPos, f);
01382     if (ret)
01383       yPos += _topExtra;
01384     return ret;
01385 }
01386 
01387 short RenderTableCell::baselinePosition( bool ) const
01388 {
01389     RenderObject *o = firstChild();
01390     int offset = paddingTop() + borderTop();
01391     if ( !o ) return offset;
01392     while ( o->firstChild() ) {
01393     if ( !o->isInline() )
01394         offset += o->paddingTop() + o->borderTop();
01395     o = o->firstChild();
01396     }
01397     offset += o->baselinePosition( true );
01398     return offset;
01399 }
01400 
01401 
01402 void RenderTableCell::setStyle( RenderStyle *style )
01403 {
01404     style->setDisplay(TABLE_CELL);
01405     RenderFlow::setStyle( style );
01406     setSpecialObjects(true);
01407 }
01408 
01409 #ifdef BOX_DEBUG
01410 #include <qpainter.h>
01411 
01412 static void outlineBox(QPainter *p, int _tx, int _ty, int w, int h)
01413 {
01414     p->setPen(QPen(QColor("yellow"), 3, Qt::DotLine));
01415     p->setBrush( Qt::NoBrush );
01416     p->drawRect(_tx, _ty, w, h );
01417 }
01418 #endif
01419 
01420 void RenderTableCell::paint(QPainter *p, int _x, int _y,
01421                                        int _w, int _h, int _tx, int _ty)
01422 {
01423 
01424 #ifdef TABLE_PRINT
01425     kdDebug( 6040 ) << renderName() << "(RenderTableCell)::paint() w/h = (" << width() << "/" << height() << ")" << " _y/_h=" << _y << "/" << _h << endl;
01426 #endif
01427 
01428     if (!layouted()) return;
01429 
01430     _tx += m_x;
01431     _ty += m_y + _topExtra;
01432 
01433     // check if we need to do anything at all...
01434     if(!overhangingContents() && ((_ty-_topExtra > _y + _h)
01435         || (_ty + m_height+_topExtra+_bottomExtra < _y))) return;
01436 
01437     paintObject(p, _x, _y, _w, _h, _tx, _ty);
01438 
01439 #ifdef BOX_DEBUG
01440     ::outlineBox( p, _tx, _ty - _topExtra, width(), height() + borderTopExtra() + borderBottomExtra());
01441 #endif
01442 }
01443 
01444 
01445 void RenderTableCell::paintBoxDecorations(QPainter *p,int, int _y,
01446                                        int, int _h, int _tx, int _ty)
01447 {
01448     int w = width();
01449     int h = height() + borderTopExtra() + borderBottomExtra();
01450     _ty -= borderTopExtra();
01451 
01452     QColor c = style()->backgroundColor();
01453     if ( !c.isValid() && parent() ) // take from row
01454         c = parent()->style()->backgroundColor();
01455     if ( !c.isValid() && parent() && parent()->parent() ) // take from rowgroup
01456         c = parent()->parent()->style()->backgroundColor();
01457     if ( !c.isValid() ) {
01458     // see if we have a col or colgroup for this
01459     RenderTableCol *col = table()->colElement( _col );
01460     if ( col ) {
01461         c = col->style()->backgroundColor();
01462         if ( !c.isValid() ) {
01463         // try column group
01464         RenderStyle *style = col->parent()->style();
01465         if ( style->display() == TABLE_COLUMN_GROUP )
01466             c = style->backgroundColor();
01467         }
01468     }
01469     }
01470 
01471     // ### get offsets right in case the bgimage is inherited.
01472     CachedImage *bg = style()->backgroundImage();
01473     if ( !bg && parent() )
01474         bg = parent()->style()->backgroundImage();
01475     if ( !bg && parent() && parent()->parent() )
01476         bg = parent()->parent()->style()->backgroundImage();
01477     if ( !bg ) {
01478     // see if we have a col or colgroup for this
01479     RenderTableCol *col = table()->colElement( _col );
01480     if ( col ) {
01481         bg = col->style()->backgroundImage();
01482         if ( !bg ) {
01483         // try column group
01484         RenderStyle *style = col->parent()->style();
01485         if ( style->display() == TABLE_COLUMN_GROUP )
01486             bg = style->backgroundImage();
01487         }
01488     }
01489     }
01490 
01491     int my = QMAX(_ty,_y);
01492     int end = QMIN( _y + _h,  _ty + h );
01493     int mh = end - my;
01494 
01495     if ( bg || c.isValid() )
01496     paintBackground(p, c, bg, my, mh, _tx, _ty, w, h);
01497 
01498     if(style()->hasBorder())
01499         paintBorder(p, _tx, _ty, w, h, style());
01500 }
01501 
01502 
01503 #ifndef NDEBUG
01504 void RenderTableCell::dump(QTextStream *stream, QString ind) const
01505 {
01506     *stream << " row=" << _row;
01507     *stream << " col=" << _col;
01508     *stream << " rSpan=" << rSpan;
01509     *stream << " cSpan=" << cSpan;
01510 //    *stream << " nWrap=" << nWrap;
01511 
01512     RenderFlow::dump(stream,ind);
01513 }
01514 #endif
01515 
01516 // -------------------------------------------------------------------------
01517 
01518 RenderTableCol::RenderTableCol(DOM::NodeImpl* node)
01519     : RenderContainer(node)
01520 {
01521     // init RenderObject attributes
01522     setInline(true);   // our object is not Inline
01523 
01524     _span = 1;
01525     updateFromElement();
01526 }
01527 
01528 void RenderTableCol::updateFromElement()
01529 {
01530   DOM::NodeImpl *node = element();
01531   if ( node && (node->id() == ID_COL || node->id() == ID_COLGROUP) ) {
01532       DOM::HTMLTableColElementImpl *tc = static_cast<DOM::HTMLTableColElementImpl *>(node);
01533       _span = tc->span();
01534   } else
01535       _span = ! ( style() && style()->display() == TABLE_COLUMN_GROUP );
01536 }
01537 
01538 void RenderTableCol::addChild(RenderObject *child, RenderObject *beforeChild)
01539 {
01540 #ifdef DEBUG_LAYOUT
01541     //kdDebug( 6040 ) << renderName() << "(Table)::addChild( " << child->renderName() << " )"  << ", " <<
01542     //                   (beforeChild ? beforeChild->renderName() : 0) << " )" << endl;
01543 #endif
01544 
01545     if (child->style()->display() == TABLE_COLUMN)
01546         // these have to come before the table definition!
01547         RenderContainer::addChild(child,beforeChild);
01548 }
01549 
01550 #ifndef NDEBUG
01551 void RenderTableCol::dump(QTextStream *stream, QString ind) const
01552 {
01553     *stream << " _span=" << _span;
01554     RenderContainer::dump(stream,ind);
01555 }
01556 #endif
01557 
01558 #undef TABLE_DEBUG
01559 #undef DEBUG_LAYOUT
01560 #undef BOX_DEBUG
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.0.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Oct 8 12:22:43 2003 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2001