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.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:34:43 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001