📄 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.1.1.1 2002/01/16 10:39:56 ymwei Exp $ *///#define TABLE_DEBUG//#define DEBUG_LAYOUT//#define BOX_DEBUG#include <assert.h>#include "render_interface.h"#include "mgcolor.h"#include "mgpen.h"#include "mgbrush.h"#include "mgsize.h"#include "mgrect.h"#include "mgfontmetrics.h"#include "mgpainter.h"#include "mghtml_part.h"#include "dom_string.h"#include "render_table.h"#include "khtmllayout.h"#include "kdebug.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() : RenderBox(){ 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); setParsing(); _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 * )); }}RenderTable::~RenderTable(){ for ( unsigned int r = 0; r < allocRows; r++ ) delete [] cells[r]; delete [] cells;}void RenderTable::setStyle(RenderStyle *style){ RenderBox::setStyle(style); // init RenderObject attributes m_inline = (style->display()==INLINE_TABLE); m_replaced = (style->display()==INLINE_TABLE); spacing = style->borderSpacing(); collapseBorders = style->borderCollapse();}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: { RenderObject::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(m_style); newStyle->setDisplay(TABLE_ROW_GROUP); o->setPart(m_part); o->setStyle(newStyle); o->setIsAnonymousBox(true); addChild(o, beforeChild); } o->addChild(child); return; } RenderObject::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(){ bool recalc = false; while ( col < totalCols && cells[row][col] != 0L ) col++; if (col<=0) return; RenderTableCell* cell = cells[row][col-1]; if (!cell) return; while ( col < totalCols && cells[row][col] == 0L ) { cells[row][col] = cell; col++; recalc = true; } if (recalc) { recalcColInfos(); } }void RenderTable::addCell( RenderTableCell *cell ){ while ( col < totalCols && cells[row][col] != 0L ) col++; setCells( row, col, cell ); setMinMaxKnown(false); setLayouted(false); col++;}int RenderTable::realSpan( RenderTableCell* cell){ unsigned int r = cell->row(); unsigned int c = cell->col(); unsigned int sp = cell->colSpan(); int span=1; if (c+sp==totalCols || cells[r][c+sp]!=cell) span = sp; else { while (c>0 && cells[r][c-1]==cell) c--; while (c<totalCols && cells[r][c+1]==cell) { c++ ; span++; } }// kdDebug(0) << "realspan(" << r << "," << c << ")=" << span << endl; return span;}int RenderTable::realSpan( unsigned int r, unsigned int c){ return realSpan(cells[r][c]);}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(); // The first row sets the number of columns. Do not allow subsequent // rows to change the number of columns.//WABA: Why not? Let's give crappy HTML a chance// if ( row != 0 && endCol > totalCols )// endCol = totalCols; 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)); } // check if adding of cols means that we have to // spread some existing columns to cover the new cols bool recalc = false; for ( unsigned int r=0 ; r < row ; r++) { RenderTableCell* cell = cells[r][totalCols-1]; if (cell && cell->rowSpan()==1) //might need to be more generic { for ( unsigned int c = totalCols; (int)c < newCols; c++ ) { if (cells[r][c]==0L) { cells[r][c] = cell; recalc=true; } } } } totalCols = newCols; if (recalc) { recalcColInfos(); } }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(); 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 = realSpan(cell); 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 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -