📄 render_table.cpp
字号:
/** * This file is part of the DOM implementation for KDE. * * Copyright (C) 1997 Martin Jones (mjones@kde.org) * (C) 1997 Torben Weis (weis@kde.org) * (C) 1998 Waldo Bastian (bastian@kde.org) * (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * $Id: render_table.cpp,v 1.133 2001/07/30 19:45:49 koivisto Exp $ *///#define TABLE_DEBUG//#define TABLE_PRINT//#define DEBUG_LAYOUT//#define BOX_DEBUG#include "render_table.h"#include <qlist.h>#include <qstack.h>#include <qbrush.h>#include <qpainter.h>#include <qpalette.h>#include <qdrawutil.h>#include <kglobal.h>#include "dom_string.h"#include "misc/helper.h"#include "misc/khtmllayout.h"#include <kdebug.h>#include <assert.h>using namespace khtml;template class QArray<LengthType>;#define FOR_EACH_CELL(r,c,cell) \ for ( unsigned int r = 0; r < totalRows; r++ ) \ { \ for ( unsigned int c = 0; c < totalCols; c++ ) \ { \ RenderTableCell *cell = cells[r][c]; \ if (!cell) \ continue; \ if ( (c < totalCols - 1) && (cell == cells[r][c+1]) ) \ continue; \ if ( (r < totalRows - 1) && (cells[r+1][c] == cell) ) \ continue;#define END_FOR_EACH } }RenderTable::RenderTable() : RenderFlow(){ tCaption = 0; _oldColElem = 0; head = 0; foot = 0; firstBody = 0; incremental = false; m_maxWidth = 0; rules = None; frame = Void; row = 0; col = 0; maxColSpan = 0; totalColInfos = 0; colInfos.setAutoDelete(true); _currentCol=0; _lastParentWidth = 0; columnPos.resize( 2 ); colMaxWidth.resize( 1 ); colMinWidth.resize( 1 ); colValue.resize(1); colType.resize(1); actColWidth.resize(1); columnPos.fill( 0 ); colMaxWidth.fill( 0 ); colMinWidth.fill( 0 ); colValue.fill(0); colType.fill(Variable); actColWidth.fill(0); columnPos[0] = spacing; totalCols = 0; // this should be expanded to the maximum number of cols // by the first row parsed totalRows = 1; allocRows = 5; // allocate five rows initially cells = new RenderTableCell ** [allocRows]; for ( unsigned int r = 0; r < allocRows; r++ ) { cells[r] = new RenderTableCell * [totalCols]; memset( cells[r], 0, totalCols * sizeof( RenderTableCell * )); } needsCellsRecalc = false;}RenderTable::~RenderTable(){ for ( unsigned int r = 0; r < allocRows; r++ ) delete [] cells[r]; delete [] cells;}void RenderTable::setStyle(RenderStyle *_style){ RenderFlow::setStyle(_style); // init RenderObject attributes setInline(style()->display()==INLINE_TABLE); setReplaced(style()->display()==INLINE_TABLE); spacing = style()->borderSpacing(); collapseBorders = style()->borderCollapse();}void RenderTable::position(int x, int y, int, int, int, bool, bool){ //for inline tables only m_x = x + marginLeft(); m_y = y + marginTop();}inline voidRenderTable::ColInfo::update(){ if (minCell) min = minCell->minWidth(); if (maxCell) max = maxCell->maxWidth();}void RenderTable::addChild(RenderObject *child, RenderObject *beforeChild){#ifdef DEBUG_LAYOUT kdDebug( 6040 ) << renderName() << "(Table)::addChild( " << child->renderName() << ", " << (beforeChild ? beforeChild->renderName() : 0) << " )" << endl;#endif RenderObject *o = child; switch(child->style()->display()) { case TABLE_CAPTION: tCaption = static_cast<RenderTableCaption *>(child); break; case TABLE_COLUMN: case TABLE_COLUMN_GROUP: { RenderContainer::addChild(child,beforeChild); RenderTableCol* colel = static_cast<RenderTableCol *>(child); if (_oldColElem && _oldColElem->style()->display() == TABLE_COLUMN_GROUP) _currentCol = _oldColElem->lastCol(); _oldColElem = colel; colel->setStartCol(_currentCol); if (child->style()->display() == TABLE_COLUMN) _currentCol++; else _currentCol+=colel->span(); addColInfo(colel); incremental = true; colel->setTable(this); } return; case TABLE_HEADER_GROUP: if(incremental && !columnPos[totalCols]);// calcColWidth();// setTHead(static_cast<RenderTableSection *>(child)); break; case TABLE_FOOTER_GROUP: if(incremental && !columnPos[totalCols]);// calcColWidth();// setTFoot(static_cast<RenderTableSection *>(child)); break; case TABLE_ROW_GROUP: if(incremental && !columnPos[totalCols]);// calcColWidth(); if(!firstBody) firstBody = static_cast<RenderTableSection *>(child); break; default: if ( !beforeChild ) beforeChild = lastChild(); if ( beforeChild && beforeChild->isAnonymousBox() ) o = beforeChild; else {// kdDebug( 6040 ) << "creating anonymous table section" << endl; o = new RenderTableSection(); RenderStyle *newStyle = new RenderStyle(); newStyle->inheritFrom(style()); newStyle->setDisplay(TABLE_ROW_GROUP); o->setStyle(newStyle); o->setIsAnonymousBox(true); addChild(o, beforeChild); } o->addChild(child); return; } RenderContainer::addChild(child,beforeChild); child->setTable(this);}void RenderTable::startRow(){ while ( col < totalCols && cells[row][col] != 0 ) col++; if ( col ) row++; col = 0; if(row > totalRows) totalRows = row;}void RenderTable::closeRow(){ while ( col < totalCols && cells[row][col] != 0L ) col++; if (col<=0) return; RenderTableCell* cell = cells[row][col-1]; if (!cell) return;}void RenderTable::addCell( RenderTableCell *cell ){ while ( col < totalCols && cells[row][col] != 0L ) col++; setCells( row, col, cell ); setMinMaxKnown(false); setLayouted(false); col++;}void RenderTable::setCells( unsigned int r, unsigned int c, RenderTableCell *cell ){#ifdef TABLE_DEBUG kdDebug( 6040 ) << "span = " << cell->rowSpan() << "d/" << cell->colSpan() << "d" << endl;#endif cell->setRow(r); cell->setCol(c); unsigned int endRow = r + cell->rowSpan(); unsigned int endCol = c + cell->colSpan(); if ( endCol > totalCols ) addColumns( endCol - totalCols ); if ( endRow >= allocRows ) addRows( endRow - allocRows + 10 ); if ( endRow > totalRows ) totalRows = endRow; for ( ; r < endRow; r++ ) { for ( unsigned int tc = c; tc < endCol; tc++ ) { cells[r][tc] = cell; } }}void RenderTable::addRows( int num ){ RenderTableCell ***newRows = new RenderTableCell ** [allocRows + num]; memcpy( newRows, cells, allocRows * sizeof(RenderTableCell **) ); delete [] cells; cells = newRows; for ( unsigned int r = allocRows; r < allocRows + num; r++ ) { cells[r] = new RenderTableCell * [totalCols]; memset( cells[r], 0, totalCols * sizeof( RenderTableCell * )); } allocRows += num;}void RenderTable::addColumns( int num ){#ifdef TABLE_DEBUG kdDebug( 6040 ) << "addColumns() totalCols=" << totalCols << " new=" << num << endl;#endif RenderTableCell **newCells; int newCols = totalCols + num; // resize the col structs to the number of columns columnPos.resize(newCols+1); memset( columnPos.data() + totalCols + 1, 0, num*sizeof(int)); colMaxWidth.resize(newCols); memset( colMaxWidth.data() + totalCols , 0, num*sizeof(int)); colMinWidth.resize(newCols); memset( colMinWidth.data() + totalCols , 0, num*sizeof(int)); colValue.resize(newCols); memset( colValue.data() + totalCols , 0, num*sizeof(int)); colType.resize(newCols); memset( colType.data() + totalCols , 0, num*sizeof(LengthType)); actColWidth.resize(newCols); memset( actColWidth.data() + totalCols , 0, num*sizeof(LengthType)); for ( unsigned int r = 0; r < allocRows; r++ ) { newCells = new RenderTableCell * [newCols]; memcpy( newCells, cells[r], totalCols * sizeof( RenderTableCell * ) ); memset( newCells + totalCols, 0, num * sizeof( RenderTableCell * ) ); delete [] cells[r]; cells[r] = newCells; } int mSpan = newCols; colInfos.resize(mSpan); for ( unsigned int c =0 ; c < totalCols; c++ ) { colInfos[c]->resize(newCols); } for ( unsigned int c = totalCols; (int)c < newCols; c++ ) { colInfos.insert(c, new ColInfoLine(newCols-c+1)); } totalCols = newCols;}void RenderTable::recalcColInfos(){// kdDebug(0) << "RenderTable::recalcColInfos()" << endl; for (int s=0 ; s<maxColSpan; s++) { for (unsigned int c=0 ; c<totalCols; c++) if (c<colInfos[s]->size()) colInfos[s]->remove(c); } maxColSpan = 0; FOR_EACH_CELL(r,c,cell) addColInfo(cell); END_FOR_EACH}void RenderTable::addColInfo(RenderTableCol *colel){ int _startCol = colel->col(); int span = colel->span(); int _minSize=0; int _maxSize=0; Length _width = colel->width(); if (_width.type==Fixed) _maxSize=_width.value; for (int n=0; n<span; ++n) {#ifdef TABLE_DEBUG kdDebug( 6040 ) << "COL" << endl; kdDebug( 6040 ) << " startCol=" << _startCol << " span=" << span << endl; kdDebug( 6040 ) << " min=" << _minSize << " max=" << _maxSize << " val=" << _width.value << endl;#endif addColInfo(_startCol+n, 1 , _minSize, _maxSize, _width ,0); }}void RenderTable::addColInfo(RenderTableCell *cell){ int _startCol = cell->col(); int _colSpan = cell->colSpan(); int _minSize = cell->minWidth(); int _maxSize = cell->maxWidth(); if (collapseBorders) { int bw = cell->borderLeft() + cell->borderRight(); _minSize -= bw; _maxSize -= bw; } Length _width = cell->style()->width(); addColInfo(_startCol, _colSpan, _minSize, _maxSize, _width ,cell);}void RenderTable::addColInfo(int _startCol, int _colSpan, int _minSize, int _maxSize, Length _width, RenderTableCell* _cell){#ifdef TABLE_DEBUG kdDebug( 6040 ) << "addColInfo():" << endl; kdDebug( 6040 ) << " startCol=" << _startCol << " span=" << _colSpan << endl; kdDebug( 6040 ) << " min=" << _minSize << " max=" << _maxSize << endl; kdDebug( 6040 ) << " totalCols=" << totalCols << endl;#endif // Netscape ignores width values of "0" or "0%" if ( style()->htmlHacks() && _width.value == 0 && (_width.type == Percent || _width.type == Fixed) ) _width = Length(); if (_startCol + _colSpan > (int) totalCols) addColumns(totalCols - _startCol + _colSpan); ColInfo* col = colInfos[_colSpan-1]->at(_startCol); if (!col) { col = new ColInfo; col->span = _colSpan; col->start = _startCol; col->minCell = _cell; col->maxCell = _cell; if (_colSpan>maxColSpan) maxColSpan=_colSpan; colInfos[_colSpan-1]->insert(_startCol,col); } if (_minSize > col->min) { col->min = _minSize; col->minCell = _cell; } if (_maxSize > col->max) { col->max = _maxSize; col->maxCell = _cell; } // Fixed width is treated as variable if (_width.type == col->type) col->value = _width.value > col->value ? _width.value : col->value; if ( (_width.type > col->type && (_width.type!=Fixed || col->type<=Variable)) || ( col->type == Fixed && _width.type!=Variable) ) { col->type = _width.type; col->value = _width.value; } setMinMaxKnown(false);#ifdef TABLE_DEBUG kdDebug( 6040 ) << " end: min=" << colMinWidth[_startCol] << " max=" << colMaxWidth[_startCol] << " act=" << actColWidth[_startCol] << endl;#endif}void RenderTable::spreadSpanMinMax(int col, int span, int distmin, int distmax, LengthType type){#ifdef TABLE_DEBUG kdDebug( 6040 ) << "RenderTable::spreadSpanMinMax() " << type << " " << distmin << " " << distmax << endl;#endif if (distmin<1) distmin=0; if (distmax<1) distmax=0; if (distmin<1 && distmax<1) return; bool hasUsableCols=false; int tmax=distmax; int tmin=distmin; int c; for (c=col; c < col+span ; ++c) { if (colType[c]<=type || (type == Variable && distmax==0)) { hasUsableCols=true; break; } } if (hasUsableCols) { // spread span maxWidth LengthType tt = Undefined; bool out=false; while (tt<=type && !out && tmax) { tmax = distributeMaxWidth(tmax,type,tt,col,span); switch (tt) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -