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 = KMIN( short( 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             break;
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.isRelative() )
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.isRelative() && height.value() >= 0) ) {
00782         Length cRowHeight = grid[cRow].height;
00783         switch( height.type() ) {
00784         case Percent:
00785         if ( !cRowHeight.isPercent() ||
00786              (cRowHeight.isPercent() && cRowHeight.value() < height.value() ) )
00787             grid[cRow].height = height;
00788              break;
00789         case Fixed:
00790         if ( cRowHeight.type() < Percent ||
00791              ( cRowHeight.isFixed() && 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.isVariable() )
00975         numVariable++;
00976         else if ( grid[r].height.isPercent() )
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.isPercent() ) {
00988             int toAdd = QMIN( dh, (totalHeight * grid[r].height.value() / 100)-rh );
00989                     // If toAdd is negative, then we don't want to shrink the row (this bug
00990                     // affected Outlook Web Access).
00991                     toAdd = QMAX(0, toAdd);
00992             add += toAdd;
00993             dh -= toAdd;
00994             totalPercent -= grid[r].height.value();
00995 //          qDebug( "adding %d to row %d", toAdd, r );
00996         }
00997         if ( r < totalRows-1 )
00998             rh = rowPos[r+2] - rowPos[r+1];
00999                 rowPos[r+1] += add;
01000         }
01001     }
01002     if ( numVariable ) {
01003         // distribute over variable cols
01004 //      qDebug("distributing %d over variable rows numVariable=%d", dh,  numVariable );
01005         int add = 0;
01006         for ( int r = 0; r < totalRows; r++ ) {
01007         if ( numVariable > 0 && grid[r].height.isVariable() ) {
01008             int toAdd = dh/numVariable;
01009             add += toAdd;
01010             dh -= toAdd;
01011         }
01012                 rowPos[r+1] += add;
01013         }
01014     }
01015         if (dh>0) {
01016         // if some left overs, distribute equally.
01017             int tot=rowPos[totalRows];
01018             int add=0;
01019             int prev=rowPos[0];
01020             for ( int r = 0; r < totalRows; r++ ) {
01021                 //weight with the original height
01022                 add+=dh*(rowPos[r+1]-prev)/tot;
01023                 prev=rowPos[r+1];
01024                 rowPos[r+1]+=add;
01025             }
01026         }
01027     }
01028 
01029     int leftOffset = borderLeft() + spacing;
01030 
01031     int nEffCols = table()->numEffCols();
01032     for ( int r = 0; r < totalRows; r++ )
01033     {
01034     Row *row = grid[r].row;
01035     int totalCols = row->size();
01036         for ( int c = 0; c < nEffCols; c++ )
01037         {
01038             RenderTableCell *cell = cellAt(r, c);
01039             if (!cell || cell == (RenderTableCell *)-1 )
01040                 continue;
01041             if ( r < totalRows - 1 && cell == cellAt(r+1, c) )
01042         continue;
01043 
01044             if ( ( rindx = r-cell->rowSpan()+1 ) < 0 )
01045                 rindx = 0;
01046 
01047             rHeight = rowPos[r+1] - rowPos[rindx] - spacing;
01048 #ifdef DEBUG_LAYOUT
01049             kdDebug( 6040 ) << "setting position " << r << "/" << c << ": "
01050                 << table()->columnPos[c] /*+ padding */ << "/" << rowPos[rindx] << " height=" << rHeight<< endl;
01051 #endif
01052 
01053             EVerticalAlign va = cell->style()->verticalAlign();
01054             int te=0;
01055             switch (va)
01056             {
01057             case SUB:
01058             case SUPER:
01059             case TEXT_TOP:
01060             case TEXT_BOTTOM:
01061             case BASELINE:
01062         te = getBaseline(r) - cell->baselinePosition() ;
01063                 break;
01064             case TOP:
01065                 te = 0;
01066                 break;
01067             case MIDDLE:
01068                 te = (rHeight - cell->height())/2;
01069                 break;
01070             case BOTTOM:
01071                 te = rHeight - cell->height();
01072                 break;
01073             default:
01074                 break;
01075             }
01076 #ifdef DEBUG_LAYOUT
01077         //            kdDebug( 6040 ) << "CELL " << cell << " te=" << te << ", be=" << rHeight - cell->height() - te << ", rHeight=" << rHeight << ", valign=" << va << endl;
01078 #endif
01079             cell->setCellTopExtra( te );
01080             cell->setCellBottomExtra( rHeight - cell->height() - te);
01081 
01082             if (style()->direction()==RTL) {
01083                 cell->setPos(
01084             table()->columnPos[(int)totalCols] -
01085             table()->columnPos[table()->colToEffCol(cell->col()+cell->colSpan())] +
01086             leftOffset,
01087                     rowPos[rindx] );
01088             } else {
01089                 cell->setPos( table()->columnPos[c] + leftOffset, rowPos[rindx] );
01090         }
01091         }
01092     }
01093 
01094     m_height = rowPos[totalRows];
01095     return m_height;
01096 }
01097 
01098 
01099 void RenderTableSection::paint( QPainter *p, int x, int y, int w, int h,
01100                 int tx, int ty)
01101 {
01102     unsigned int totalRows = grid.size();
01103     unsigned int totalCols = table()->columns.size();
01104 
01105     tx += m_x;
01106     ty += m_y;
01107 
01108     // check which rows and cols are visible and only paint these
01109     // ### fixme: could use a binary search here
01110     unsigned int startrow = 0;
01111     unsigned int endrow = totalRows;
01112     for ( ; startrow < totalRows; startrow++ ) {
01113     if ( ty + rowPos[startrow+1] > y )
01114         break;
01115     }
01116     for ( ; endrow > 0; endrow-- ) {
01117     if ( ty + rowPos[endrow-1] < y + h )
01118         break;
01119     }
01120     unsigned int startcol = 0;
01121     unsigned int endcol = totalCols;
01122     if ( style()->direction() == LTR ) {
01123     for ( ; startcol < totalCols; startcol++ ) {
01124         if ( tx + table()->columnPos[startcol+1] > x )
01125         break;
01126     }
01127     for ( ; endcol > 0; endcol-- ) {
01128         if ( tx + table()->columnPos[endcol-1] < x + w )
01129         break;
01130     }
01131     }
01132     if ( startcol < endcol ) {
01133     // draw the cells
01134     for ( unsigned int r = startrow; r < endrow; r++ ) {
01135         unsigned int c = startcol;
01136         // since a cell can be -1 (indicating a colspan) we might have to search backwards to include it
01137         while ( c && cellAt( r, c ) == (RenderTableCell *)-1 )
01138         c--;
01139         for ( ; c < endcol; c++ ) {
01140         RenderTableCell *cell = cellAt(r, c);
01141         if (!cell || cell == (RenderTableCell *)-1 )
01142             continue;
01143         if ( (r < endrow - 1) && (cellAt(r+1, c) == cell) )
01144             continue;
01145 
01146 #ifdef TABLE_PRINT
01147         kdDebug( 6040 ) << "painting cell " << r << "/" << c << endl;
01148 #endif
01149         cell->paint( p, x, y, w, h, tx, ty);
01150         }
01151     }
01152     }
01153 }
01154 
01155 void RenderTableSection::recalcCells()
01156 {
01157     cCol = 0;
01158     cRow = -1;
01159     clearGrid();
01160     grid.resize( 0 );
01161 
01162     RenderObject *row = firstChild();
01163     while ( row ) {
01164     cRow++;
01165     cCol = 0;
01166     ensureRows( cRow+1 );
01167     RenderObject *cell = row->firstChild();
01168     while ( cell ) {
01169         if ( cell->isTableCell() )
01170         addCell( static_cast<RenderTableCell *>(cell) );
01171         cell = cell->nextSibling();
01172     }
01173     row = row->nextSibling();
01174     }
01175     needCellRecalc = false;
01176     setLayouted( false );
01177 }
01178 
01179 void RenderTableSection::clearGrid()
01180 {
01181     int rows = grid.size();
01182     while ( rows-- ) {
01183     delete grid[rows].row;
01184     }
01185 }
01186 
01187 RenderObject* RenderTableSection::removeChildNode(RenderObject* child)
01188 {
01189     setNeedCellRecalc();
01190     return RenderContainer::removeChildNode( child );
01191 }
01192 
01193 #ifndef NDEBUG
01194 void RenderTableSection::dump(QTextStream *stream, QString ind) const
01195 {
01196     *stream << endl << ind << "grid=(" << grid.size() << "," << table()->numEffCols() << ")" << endl << ind;
01197     for ( unsigned int r = 0; r < grid.size(); r++ ) {
01198     for ( int c = 0; c < table()->numEffCols(); c++ ) {
01199         if ( cellAt( r,  c ) && cellAt( r, c ) != (RenderTableCell *)-1 )
01200         *stream << "(" << cellAt( r, c )->row() << "," << cellAt( r, c )->col() << ","
01201             << cellAt(r, c)->rowSpan() << "," << cellAt(r, c)->colSpan() << ") ";
01202         else
01203         *stream << cellAt( r, c ) << "null cell ";
01204     }
01205     *stream << endl << ind;
01206     }
01207     RenderContainer::dump(stream,ind);
01208 }
01209 #endif
01210 
01211 // -------------------------------------------------------------------------
01212 
01213 RenderTableRow::RenderTableRow(DOM::NodeImpl* node)
01214     : RenderContainer(node)
01215 {
01216     // init RenderObject attributes
01217     setInline(false);   // our object is not Inline
01218 }
01219 
01220 void RenderTableRow::detach()
01221 {
01222     section()->setNeedCellRecalc();
01223 
01224     RenderContainer::detach();
01225 }
01226 
01227 void RenderTableRow::setStyle(RenderStyle* style)
01228 {
01229     style->setDisplay(TABLE_ROW);
01230     RenderContainer::setStyle(style);
01231 }
01232 
01233 void RenderTableRow::addChild(RenderObject *child, RenderObject *beforeChild)
01234 {
01235 #ifdef DEBUG_LAYOUT
01236     kdDebug( 6040 ) << renderName() << "(TableRow)::addChild( " << child->renderName() << " )"  << ", " <<
01237                        (beforeChild ? beforeChild->renderName() : "0") << " )" << endl;
01238 #endif
01239     RenderTableCell *cell;
01240 
01241     if ( !child->isTableCell() ) {
01242     RenderObject *last = beforeChild;
01243         if ( !last )
01244             last = lastChild();
01245         RenderTableCell *cell = 0;
01246         if( last && last->isAnonymousBox() && last->isTableCell() )
01247             cell = static_cast<RenderTableCell *>(last);
01248         else {
01249         kdDebug( 6040 ) << "creating anonymous table cell" << endl;
01250         cell = new RenderTableCell(0 /* anonymous object */);
01251         RenderStyle *newStyle = new RenderStyle();
01252         newStyle->inheritFrom(style());
01253         newStyle->setDisplay( TABLE_CELL );
01254         cell->setStyle(newStyle);
01255         cell->setIsAnonymousBox(true);
01256         addChild(cell, beforeChild);
01257         }
01258         cell->addChild(child);
01259     child->setLayouted( false );
01260     child->setMinMaxKnown( false );
01261         return;
01262     } else
01263         cell = static_cast<RenderTableCell *>(child);
01264 
01265     static_cast<RenderTableSection *>(parent())->addCell( cell );
01266 
01267     RenderContainer::addChild(cell,beforeChild);
01268 
01269     if ( ( beforeChild || nextSibling()) && section() )
01270     section()->setNeedCellRecalc();
01271 }
01272 
01273 RenderObject* RenderTableRow::removeChildNode(RenderObject* child)
01274 {
01275 // RenderTableCell detach should do it
01276 //     if ( section() )
01277 //  section()->setNeedCellRecalc();
01278     return RenderContainer::removeChildNode( child );
01279 }
01280 
01281 #ifndef NDEBUG
01282 void RenderTableRow::dump(QTextStream *stream, QString ind) const
01283 {
01284     RenderContainer::dump(stream,ind);
01285 }
01286 #endif
01287 
01288 void RenderTableRow::layout()
01289 {
01290     KHTMLAssert( !layouted() );
01291     KHTMLAssert( minMaxKnown() );
01292 
01293     RenderObject *child = firstChild();
01294     while( child ) {
01295     if ( child->isTableCell() && !child->layouted() ) {
01296         RenderTableCell *cell = static_cast<RenderTableCell *>(child);
01297         cell->calcVerticalMargins();
01298         cell->layout();
01299         cell->setCellTopExtra(0);
01300         cell->setCellBottomExtra(0);
01301     }
01302     child = child->nextSibling();
01303     }
01304     setLayouted();
01305 }
01306 
01307 // -------------------------------------------------------------------------
01308 
01309 RenderTableCell::RenderTableCell(DOM::NodeImpl* _node)
01310   : RenderFlow(_node)
01311 {
01312   _col = -1;
01313   _row = -1;
01314   updateFromElement();
01315   setSpecialObjects(true);
01316   _topExtra = 0;
01317   _bottomExtra = 0;
01318 }
01319 
01320 void RenderTableCell::detach()
01321 {
01322     if (parent() && section())
01323         section()->setNeedCellRecalc();
01324 
01325     RenderFlow::detach();
01326 }
01327 
01328 void RenderTableCell::updateFromElement()
01329 {
01330   DOM::NodeImpl *node = element();
01331   if ( node && (node->id() == ID_TD || node->id() == ID_TH) ) {
01332       DOM::HTMLTableCellElementImpl *tc = static_cast<DOM::HTMLTableCellElementImpl *>(node);
01333       cSpan = tc->colSpan();
01334       rSpan = tc->rowSpan();
01335       nWrap = tc->noWrap();
01336   } else {
01337       cSpan = rSpan = 1;
01338       nWrap = false;
01339   }
01340 }
01341 
01342 void RenderTableCell::calcMinMaxWidth()
01343 {
01344     KHTMLAssert( !minMaxKnown() );
01345 #ifdef DEBUG_LAYOUT
01346     kdDebug( 6040 ) << renderName() << "(TableCell)::calcMinMaxWidth() known=" << minMaxKnown() << endl;
01347 #endif
01348 
01349     RenderFlow::calcMinMaxWidth();
01350 
01351     setMinMaxKnown();
01352 }
01353 
01354 void RenderTableCell::calcWidth()
01355 {
01356 }
01357 
01358 void RenderTableCell::setWidth( int width )
01359 {
01360     if ( width != m_width ) {
01361     m_width = width;
01362     m_widthChanged = true;
01363     }
01364 }
01365 
01366 void RenderTableCell::close()
01367 {
01368     RenderFlow::close();
01369 
01370 #ifdef DEBUG_LAYOUT
01371     kdDebug( 6040 ) << renderName() << "(RenderTableCell)::close() total height =" << m_height << endl;
01372 #endif
01373 }
01374 
01375 
01376 void RenderTableCell::repaintRectangle(int x, int y, int w, int h, bool f)
01377 {
01378     y += _topExtra;
01379     RenderFlow::repaintRectangle(x, y, w, h, f);
01380 }
01381 
01382 bool RenderTableCell::absolutePosition(int &xPos, int &yPos, bool f)
01383 {
01384     bool ret = RenderFlow::absolutePosition(xPos, yPos, f);
01385     if (ret)
01386       yPos += _topExtra;
01387     return ret;
01388 }
01389 
01390 short RenderTableCell::baselinePosition( bool ) const
01391 {
01392     RenderObject *o = firstChild();
01393     int offset = paddingTop() + borderTop();
01394     if ( !o ) return offset;
01395     while ( o->firstChild() ) {
01396     if ( !o->isInline() )
01397         offset += o->paddingTop() + o->borderTop();
01398     o = o->firstChild();
01399     }
01400     offset += o->baselinePosition( true );
01401     return offset;
01402 }
01403 
01404 
01405 void RenderTableCell::setStyle( RenderStyle *style )
01406 {
01407     style->setDisplay(TABLE_CELL);
01408     RenderFlow::setStyle( style );
01409     setSpecialObjects(true);
01410 }
01411 
01412 #ifdef BOX_DEBUG
01413 #include <qpainter.h>
01414 
01415 static void outlineBox(QPainter *p, int _tx, int _ty, int w, int h)
01416 {
01417     p->setPen(QPen(QColor("yellow"), 3, Qt::DotLine));
01418     p->setBrush( Qt::NoBrush );
01419     p->drawRect(_tx, _ty, w, h );
01420 }
01421 #endif
01422 
01423 void RenderTableCell::paint(QPainter *p, int _x, int _y,
01424                                        int _w, int _h, int _tx, int _ty)
01425 {
01426 
01427 #ifdef TABLE_PRINT
01428     kdDebug( 6040 ) << renderName() << "(RenderTableCell)::paint() w/h = (" << width() << "/" << height() << ")" << " _y/_h=" << _y << "/" << _h << endl;
01429 #endif
01430 
01431     if (!layouted()) return;
01432 
01433     _tx += m_x;
01434     _ty += m_y + _topExtra;
01435 
01436     // check if we need to do anything at all...
01437     if(!overhangingContents() && ((_ty-_topExtra > _y + _h)
01438         || (_ty + m_height+_topExtra+_bottomExtra < _y))) return;
01439 
01440     paintObject(p, _x, _y, _w, _h, _tx, _ty);
01441 
01442 #ifdef BOX_DEBUG
01443     ::outlineBox( p, _tx, _ty - _topExtra, width(), height() + borderTopExtra() + borderBottomExtra());
01444 #endif
01445 }
01446 
01447 
01448 void RenderTableCell::paintBoxDecorations(QPainter *p,int, int _y,
01449                                        int, int _h, int _tx, int _ty)
01450 {
01451     int w = width();
01452     int h = height() + borderTopExtra() + borderBottomExtra();
01453     _ty -= borderTopExtra();
01454 
01455     QColor c = style()->backgroundColor();
01456     if ( !c.isValid() && parent() ) // take from row
01457         c = parent()->style()->backgroundColor();
01458     if ( !c.isValid() && parent() && parent()->parent() ) // take from rowgroup
01459         c = parent()->parent()->style()->backgroundColor();
01460     if ( !c.isValid() ) {
01461     // see if we have a col or colgroup for this
01462     RenderTableCol *col = table()->colElement( _col );
01463     if ( col ) {
01464         c = col->style()->backgroundColor();
01465         if ( !c.isValid() ) {
01466         // try column group
01467         RenderStyle *style = col->parent()->style();
01468         if ( style->display() == TABLE_COLUMN_GROUP )
01469             c = style->backgroundColor();
01470         }
01471     }
01472     }
01473 
01474     // ### get offsets right in case the bgimage is inherited.
01475     CachedImage *bg = style()->backgroundImage();
01476     if ( !bg && parent() )
01477         bg = parent()->style()->backgroundImage();
01478     if ( !bg && parent() && parent()->parent() )
01479         bg = parent()->parent()->style()->backgroundImage();
01480     if ( !bg ) {
01481     // see if we have a col or colgroup for this
01482     RenderTableCol *col = table()->colElement( _col );
01483     if ( col ) {
01484         bg = col->style()->backgroundImage();
01485         if ( !bg ) {
01486         // try column group
01487         RenderStyle *style = col->parent()->style();
01488         if ( style->display() == TABLE_COLUMN_GROUP )
01489             bg = style->backgroundImage();
01490         }
01491     }
01492     }
01493 
01494     int my = QMAX(_ty,_y);
01495     int end = QMIN( _y + _h,  _ty + h );
01496     int mh = end - my;
01497 
01498     if ( bg || c.isValid() )
01499     paintBackground(p, c, bg, my, mh, _tx, _ty, w, h);
01500 
01501     if(style()->hasBorder())
01502         paintBorder(p, _tx, _ty, w, h, style());
01503 }
01504 
01505 
01506 #ifndef NDEBUG
01507 void RenderTableCell::dump(QTextStream *stream, QString ind) const
01508 {
01509     *stream << " row=" << _row;
01510     *stream << " col=" << _col;
01511     *stream << " rSpan=" << rSpan;
01512     *stream << " cSpan=" << cSpan;
01513 //    *stream << " nWrap=" << nWrap;
01514 
01515     RenderFlow::dump(stream,ind);
01516 }
01517 #endif
01518 
01519 // -------------------------------------------------------------------------
01520 
01521 RenderTableCol::RenderTableCol(DOM::NodeImpl* node)
01522     : RenderContainer(node)
01523 {
01524     // init RenderObject attributes
01525     setInline(true);   // our object is not Inline
01526 
01527     _span = 1;
01528     updateFromElement();
01529 }
01530 
01531 void RenderTableCol::updateFromElement()
01532 {
01533   DOM::NodeImpl *node = element();
01534   if ( node && (node->id() == ID_COL || node->id() == ID_COLGROUP) ) {
01535       DOM::HTMLTableColElementImpl *tc = static_cast<DOM::HTMLTableColElementImpl *>(node);
01536       _span = tc->span();
01537   } else
01538       _span = ! ( style() && style()->display() == TABLE_COLUMN_GROUP );
01539 }
01540 
01541 void RenderTableCol::addChild(RenderObject *child, RenderObject *beforeChild)
01542 {
01543 #ifdef DEBUG_LAYOUT
01544     //kdDebug( 6040 ) << renderName() << "(Table)::addChild( " << child->renderName() << " )"  << ", " <<
01545     //                   (beforeChild ? beforeChild->renderName() : 0) << " )" << endl;
01546 #endif
01547 
01548     if (child->style()->display() == TABLE_COLUMN)
01549         // these have to come before the table definition!
01550         RenderContainer::addChild(child,beforeChild);
01551 }
01552 
01553 #ifndef NDEBUG
01554 void RenderTableCol::dump(QTextStream *stream, QString ind) const
01555 {
01556     *stream << " _span=" << _span;
01557     RenderContainer::dump(stream,ind);
01558 }
01559 #endif
01560 
01561 #undef TABLE_DEBUG
01562 #undef DEBUG_LAYOUT
01563 #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:40 2005 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001