render_table.cpp Source File (khtml Library)

| # khtml Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# 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

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