📄 render_table.cpp
字号:
int dh = toAdd; int totalPercent = 0; int numVariable = 0; for ( int r = 0; r < totalRows; r++ ) { if ( grid[r].height.isVariable() && !emptyRow(r)) numVariable++; else if ( grid[r].height.isPercent() ) totalPercent += grid[r].height.value(); } if ( totalPercent ) {// qDebug("distributing %d over percent rows totalPercent=%d", dh, totalPercent ); // try to satisfy percent int add = 0; if ( totalPercent > 100 ) totalPercent = 100; int rh = rowPos[1]-rowPos[0]; for ( int r = 0; r < totalRows; r++ ) { if ( totalPercent > 0 && grid[r].height.isPercent() ) { int toAdd = kMin( dh, (totalHeight * grid[r].height.value() / 100)-rh ); // If toAdd is negative, then we don't want to shrink the row (this bug // affected Outlook Web Access). toAdd = kMax(0, toAdd); add += toAdd; dh -= toAdd; totalPercent -= grid[r].height.value();// qDebug( "adding %d to row %d", toAdd, r ); } if ( r < totalRows-1 ) rh = rowPos[r+2] - rowPos[r+1]; rowPos[r+1] += add; } } if ( numVariable ) { // distribute over non-empty variable rows// qDebug("distributing %d over variable rows numVariable=%d", dh, numVariable ); int add = 0; int toAdd = dh/numVariable; for ( int r = 0; r < totalRows; r++ ) { if ( grid[r].height.isVariable() && !emptyRow(r)) { add += toAdd; } rowPos[r+1] += add; } dh -= add; } if (dh>0 && rowPos[totalRows]) { // if some left overs, distribute weighted. int tot=rowPos[totalRows]; int add=0; int prev=rowPos[0]; for ( int r = 0; r < totalRows; r++ ) { //weight with the original height add+=dh*(rowPos[r+1]-prev)/tot; prev=rowPos[r+1]; rowPos[r+1]+=add; } dh -= add; } if (dh > totalRows) { // distribute to tables with all empty rows int add=0; int toAdd = dh/totalRows; for ( int r = 0; r < totalRows; r++ ) { add += toAdd; rowPos[r+1] += add; } dh -= add; } // Finally distribute round-off values if (dh > 0) { // There is not enough for every row int add=0; for ( int r = 0; r < totalRows; r++ ) { if (add < dh) add++; rowPos[r+1] += add; } dh -= add; } assert (dh == 0); } int leftOffset = borderLeft() + hspacing; int nEffCols = table()->numEffCols(); for ( int r = 0; r < totalRows; r++ ) { Row *row = grid[r].row; int totalCols = row->size(); for ( int c = 0; c < nEffCols; c++ ) { RenderTableCell *cell = cellAt(r, c); if (!cell || cell == (RenderTableCell *)-1 ) continue; if ( r < totalRows - 1 && cell == cellAt(r+1, c) ) continue; if ( ( rindx = r-cell->rowSpan()+1 ) < 0 ) rindx = 0; rHeight = rowPos[r+1] - rowPos[rindx] - vspacing; // Force percent height children to lay themselves out again. // This will cause, e.g., textareas to grow to // fill the area. FIXME: <div>s and blocks still don't // work right. We'll need to have an efficient way of // invalidating all percent height objects in a render subtree. // For now, we just handle immediate children. -dwh bool flexAllChildren = grid[r].needFlex || (!table()->style()->height().isVariable() && rHeight != cell->height()); cell->setHasFlexedAnonymous(false); if ( flexAllChildren && flexCellChildren(cell) ) { cell->setCellPercentageHeight(kMax(0, rHeight - cell->borderTop() - cell->paddingTop() - cell->borderBottom() - cell->paddingBottom())); cell->layoutIfNeeded(); } {#ifdef DEBUG_LAYOUT kdDebug( 6040 ) << "setting position " << r << "/" << c << ": " << table()->columnPos[c] /*+ padding */ << "/" << rowPos[rindx] << " height=" << rHeight<< endl;#endif EVerticalAlign va = cell->style()->verticalAlign(); int te=0; switch (va) { case SUB: case SUPER: case TEXT_TOP: case TEXT_BOTTOM: case BASELINE: te = getBaseline(r) - cell->baselinePosition() ; break; case TOP: te = 0; break; case MIDDLE: te = (rHeight - cell->height())/2; break; case BOTTOM: te = rHeight - cell->height(); break; default: break; } te = kMax( 0, te );#ifdef DEBUG_LAYOUT // kdDebug( 6040 ) << "CELL " << cell << " te=" << te << ", be=" << rHeight - cell->height() - te << ", rHeight=" << rHeight << ", valign=" << va << endl;#endif cell->setCellTopExtra( te ); cell->setCellBottomExtra( rHeight - cell->height() - te); } if (style()->direction()==RTL) { cell->setPos( table()->columnPos[(int)totalCols] - table()->columnPos[table()->colToEffCol(cell->col()+cell->colSpan())] + leftOffset, rowPos[rindx] ); } else { cell->setPos( table()->columnPos[c] + leftOffset, rowPos[rindx] ); } } } m_height = rowPos[totalRows]; return m_height;}bool RenderTableSection::flexCellChildren(RenderObject* p) const{ if (!p) return false; RenderObject* o = p->firstChild(); bool didFlex = false; while (o) { if (!o->isText() && o->style()->height().isPercent()) { if (o->isWidget()) { // cancel resizes from transitory relayouts static_cast<RenderWidget *>(o)->cancelPendingResize(); } o->setNeedsLayout(true, false); p->setChildNeedsLayout(true, false); didFlex = true; } else if (o->isAnonymousBlock() && flexCellChildren( o )) { p->setChildNeedsLayout(true, false); if (p->isTableCell()) static_cast<RenderTableCell*>(p)->setHasFlexedAnonymous(); didFlex = true; } o = o->nextSibling(); } return didFlex;}inline static RenderTableRow *firstTableRow(RenderObject *row){ while (row && !row->isTableRow()) row = row->nextSibling(); return static_cast<RenderTableRow *>(row);}inline static RenderTableRow *nextTableRow(RenderObject *row){ row = row ? row->nextSibling() : row; while (row && !row->isTableRow()) row = row->nextSibling(); return static_cast<RenderTableRow *>(row);}void RenderTableSection::paint( PaintInfo& pI, int tx, int ty ){ unsigned int totalRows = grid.size(); unsigned int totalCols = table()->columns.size(); tx += m_x; ty += m_y; if (pI.phase == PaintActionOutline) paintOutline(pI.p, tx, ty, width(), height(), style()); CollapsedBorderValue *cbs = table()->currentBorderStyle(); int cbsw2 = cbs ? cbs->width()/2 : 0; int cbsw21 = cbs ? (cbs->width()+1)/2 : 0; RenderTableRow *trow = firstTableRow(firstChild()); int x = pI.r.x(), y = pI.r.y(), w = pI.r.width(), h = pI.r.height(); // check which rows and cols are visible and only paint these // ### fixme: could use a binary search here int os = 2*maximalOutlineSize(pI.phase); unsigned int startrow = 0; unsigned int endrow = totalRows; for ( ; startrow < totalRows; startrow++, trow = nextTableRow(trow) ) { if ( ty + rowPos[startrow+1] + kMax(cbsw21, os) > y - os ) break; } for ( ; endrow > 0; endrow-- ) { if ( ty + rowPos[endrow-1] - kMax(cbsw2, os) < y + h + os ) break; } unsigned int startcol = 0; unsigned int endcol = totalCols; if ( style()->direction() == LTR ) { for ( ; startcol < totalCols; startcol++ ) { if ( tx + table()->columnPos[startcol+1] + kMax(cbsw21, os) > x - os ) break; } for ( ; endcol > 0; endcol-- ) { if ( tx + table()->columnPos[endcol-1] - kMax(cbsw2, os) < x + w + os ) break; } } if ( startcol < endcol ) { // draw the cells for ( unsigned int r = startrow; r < endrow; r++, trow = nextTableRow(trow) ) { // paint the row if (trow) { int height = rowPos[r+1] - rowPos[r] - table()->borderVSpacing(); trow->paintRow(pI, tx, ty + rowPos[r], width(), height); } unsigned int c = startcol; // since a cell can be -1 (indicating a colspan) we might have to search backwards to include it while ( c && cellAt( r, c ) == (RenderTableCell *)-1 ) c--; for ( ; c < endcol; c++ ) { RenderTableCell *cell = cellAt(r, c); if (!cell || cell == (RenderTableCell *)-1 ) continue; if ( (r < endrow - 1) && (cellAt(r+1, c) == cell) ) continue;#ifdef TABLE_PRINT kdDebug( 6040 ) << "painting cell " << r << "/" << c << endl;#endif cell->paint( pI, tx, ty); } } }}void RenderTableSection::recalcCells(){ cCol = 0; cRow = -1; clearGrid(); grid.resize( 0 ); RenderObject *row = firstChild(); while ( row ) { cRow++; cCol = 0; ensureRows( cRow+1 ); RenderObject *cell = row->firstChild(); while ( cell ) { if ( cell->isTableCell() ) addCell( static_cast<RenderTableCell *>(cell) ); cell = cell->nextSibling(); } row = row->nextSibling(); } needCellRecalc = false; setNeedsLayout(true);}void RenderTableSection::clearGrid(){ int rows = grid.size(); while ( rows-- ) { delete grid[rows].row; }}bool RenderTableSection::emptyRow(int rowNum) { Row &r = *grid[rowNum].row; const int s = r.size(); RenderTableCell *cell; for(int i=0; i<s; i++) { cell = r[i]; if (!cell || cell==(RenderTableCell*)-1) continue; return false; } return true;}RenderObject* RenderTableSection::removeChildNode(RenderObject* child){ setNeedCellRecalc(); return RenderContainer::removeChildNode( child );}bool RenderTableSection::canClear(RenderObject */*child*/, PageBreakLevel level){ // We cannot clear rows yet. return parent()->canClear(this, level);}void RenderTableSection::addSpaceAt(int pos, int dy){ const int nEffCols = table()->numEffCols(); const int totalRows = numRows(); for ( int r = 0; r < totalRows; r++ ) { if (rowPos[r] >= pos) { rowPos[r] += dy; Row *row = grid[r].row; int totalCols = row->size(); int rindx; for ( int c = 0; c < nEffCols; c++ ) { RenderTableCell *cell = cellAt(r, c); if (!cell || cell == (RenderTableCell *)-1 ) continue; if ( r < totalRows - 1 && cell == cellAt(r+1, c) ) continue; if ( ( rindx = r-cell->rowSpan()+1 ) < 0 ) rindx = 0; cell->setPos(cell->xPos(), rowPos[r]); } } } if (rowPos[totalRows] >= pos) rowPos[totalRows] += dy; m_height = rowPos[totalRows]; setContainsPageBreak(true);}#ifdef ENABLE_DUMPvoid RenderTableSection::dump(QTextStream &stream, const QString &ind) const{ RenderContainer::dump(stream,ind); stream << " grid=(" << grid.size() << "," << table()->numEffCols() << ")"; for ( unsigned int r = 0; r < grid.size(); r++ ) { for ( int c = 0; c < table()->numEffCols(); c++ ) { if ( cellAt( r, c ) && cellAt( r, c ) != (RenderTableCell *)-1 ) stream << " (" << cellAt( r, c )->row() << "," << cellAt( r, c )->col() << "," << cellAt(r, c)->rowSpan() << "," << cellAt(r, c)->colSpan() << ") "; else stream << " null cell"; } }}#endifstatic RenderTableCell *seekCell(RenderTableSection *section, int row, int col){ if (row < 0 || col < 0 || row >= section->numRows()) return 0; // since a cell can be -1 (indicating a colspan) we might have to search backwards to include it while ( col && section->cellAt( row, col ) == (RenderTableCell *)-1 ) col--; return section->cellAt(row, col);}/** Looks for the first element suitable for text selection, beginning from * the last. * @param base search is restricted within this node. This node must have * a renderer. * @return the element or @p base if no suitable element found. */static NodeImpl *findLastSelectableNode(NodeImpl *base){ NodeImpl *last = base; // Look for last text/cdata node that has a renderer, // or last childless replaced element while ( last && !(last->renderer() && ((last->nodeType() == Node::TEXT_NODE || last->nodeType() == Node::CDATA_SECTION_NODE) || (last->renderer()->isReplaced() && !last->renderer()->lastChild())))) { NodeImpl *next = last->lastChild(); if ( !next ) next = last->previousSibling(); while ( last && last != base && !next ) { last = last->parentNode(); if ( last && last != base ) next = last->previousSibling(); } last = next; } return last ? last : base;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -