📄 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) * Copyright (C) 2003 Apple Computer, Inc. * * 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. *///#define TABLE_DEBUG//#define TABLE_PRINT//#define DEBUG_LAYOUT//#define BOX_DEBUG#include "rendering/render_table.h"#include "rendering/table_layout.h"#include "html/html_tableimpl.h"#include "misc/htmltags.h"#include "misc/htmlattrs.h"#include "xml/dom_docimpl.h"#include <kglobal.h>#include <qapplication.h>#include <qstyle.h>#include <kdebug.h>#include <assert.h>#include "khtmlview.h"using namespace khtml;using namespace DOM;RenderTable::RenderTable(DOM::NodeImpl* node) : RenderBlock(node){ tCaption = 0; head = foot = firstBody = 0; tableLayout = 0; m_currentBorder = 0; rules = None; frame = Void; has_col_elems = false; hspacing = 0; vspacing = 0; padding = 0; needSectionRecalc = false; padding = 0; columnPos.resize( 2 ); columnPos.fill( 0 ); columns.resize( 1 ); columns.fill( ColumnStruct() ); columnPos[0] = 0;}RenderTable::~RenderTable(){ delete tableLayout;}void RenderTable::setStyle(RenderStyle *_style){ ETableLayout oldTableLayout = style() ? style()->tableLayout() : TAUTO; RenderBlock::setStyle(_style); // In the collapsed border model, there is no cell spacing. hspacing = collapseBorders() ? 0 : style()->horizontalBorderSpacing(); vspacing = collapseBorders() ? 0 : style()->verticalBorderSpacing(); columnPos[0] = hspacing; if ( !tableLayout || style()->tableLayout() != oldTableLayout ) { delete tableLayout; // According to the CSS2 spec, you only use fixed table layout if an // explicit width is specified on the table. Auto width implies auto table layout. if (style()->tableLayout() == TFIXED && !style()->width().isVariable()) { tableLayout = new FixedTableLayout(this);#ifdef DEBUG_LAYOUT kdDebug( 6040 ) << "using fixed table layout" << endl;#endif } else tableLayout = new AutoTableLayout(this); }}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; if (child->element() && child->element()->id() == ID_FORM) { RenderContainer::addChild(child,beforeChild); return; } switch(child->style()->display()) { case TABLE_CAPTION: tCaption = static_cast<RenderBlock *>(child); break; case TABLE_COLUMN: case TABLE_COLUMN_GROUP: has_col_elems = true; break; case TABLE_HEADER_GROUP: if ( !head ) head = static_cast<RenderTableSection *>(child); else if ( !firstBody ) firstBody = static_cast<RenderTableSection *>(child); break; case TABLE_FOOTER_GROUP: if ( !foot ) { foot = static_cast<RenderTableSection *>(child); break; } // fall through case TABLE_ROW_GROUP: if(!firstBody) firstBody = static_cast<RenderTableSection *>(child); break; default: if ( !beforeChild && lastChild() && lastChild()->isTableSection() && lastChild()->isAnonymous() ) { o = lastChild(); } else { RenderObject *lastBox = beforeChild; while ( lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableSection() && lastBox->style()->display() != TABLE_CAPTION ) lastBox = lastBox->parent(); if ( lastBox && lastBox->isAnonymous() ) { lastBox->addChild( child, beforeChild ); return; } else { if ( beforeChild && !beforeChild->isTableSection() ) beforeChild = 0; //kdDebug( 6040 ) << this <<" creating anonymous table section beforeChild="<< beforeChild << endl; o = new (renderArena()) RenderTableSection(document() /* anonymous */); RenderStyle *newStyle = new (renderArena()) RenderStyle(); newStyle->inheritFrom(style()); newStyle->setDisplay(TABLE_ROW_GROUP); o->setStyle(newStyle); addChild(o, beforeChild); } } o->addChild(child); child->setNeedsLayoutAndMinMaxRecalc(); return; } RenderContainer::addChild(child,beforeChild);}void RenderTable::calcWidth(){ if ( isPositioned() ) { calcAbsoluteHorizontal(); } RenderBlock *cb = containingBlock(); int availableWidth = cb->contentWidth(); LengthType widthType = style()->width().type; if (widthType > Relative && style()->width().value > 0) { // Percent or fixed table m_width = style()->width().minWidth( availableWidth ); if(m_minWidth > m_width) m_width = m_minWidth; } else { // An auto width table should shrink to fit within the line width if necessary in order to // avoid overlapping floats. availableWidth = cb->lineWidth( m_y ); // Subtract out any fixed margins from our available width for auto width tables. int marginTotal = 0; if (style()->marginLeft().type != Variable) marginTotal += style()->marginLeft().width(availableWidth); if (style()->marginRight().type != Variable) marginTotal += style()->marginRight().width(availableWidth); // Subtract out our margins to get the available content width. int availContentWidth = kMax(0, availableWidth - marginTotal); // Ensure we aren't bigger than our max width or smaller than our min width. m_width = kMin(availContentWidth, m_maxWidth); } m_width = kMax(m_width, m_minWidth); // Finally, with our true width determined, compute our margins for real. m_marginRight = 0; m_marginLeft = 0; calcHorizontalMargins(style()->marginLeft(),style()->marginRight(),availableWidth);}void RenderTable::layout(){ KHTMLAssert( needsLayout() ); KHTMLAssert( minMaxKnown() ); KHTMLAssert( !needSectionRecalc ); if (posChildNeedsLayout() && !normalChildNeedsLayout() && !selfNeedsLayout()) { // All we have to is lay out our positioned objects. layoutPositionedObjects(true); setNeedsLayout(false); return; } QRect oldBounds, oldFullBounds; bool checkForRepaint = checkForRepaintDuringLayout(); if (checkForRepaint) getAbsoluteRepaintRectIncludingFloats(oldBounds, oldFullBounds); //kdDebug( 6040 ) << renderName() << "(Table)"<< this << " ::layout0() width=" << width() << ", needsLayout=" << needsLayout() << endl; m_height = 0; initMaxMarginValues(); //int oldWidth = m_width; calcWidth(); // the optimisation below doesn't work since the internal table // layout could have changed. we need to add a flag to the table // layout that tells us if something has changed in the min max // calculations to do it correctly.// if ( oldWidth != m_width || columns.size() + 1 != columnPos.size() ) tableLayout->layout();#ifdef DEBUG_LAYOUT kdDebug( 6040 ) << renderName() << "(Table)::layout1() width=" << width() << ", marginLeft=" << marginLeft() << " marginRight=" << marginRight() << endl;#endif setCellWidths(); // layout child objects int calculatedHeight = 0; RenderObject *child = firstChild(); while( child ) { if ( child->needsLayout() && !(child->element() && child->element()->id() == ID_FORM)) child->layout(); if ( child->isTableSection() ) { static_cast<RenderTableSection *>(child)->calcRowHeight(); calculatedHeight += static_cast<RenderTableSection *>(child)->layoutRows( 0 ); } child = child->nextSibling(); } // ### collapse caption margin if(tCaption && tCaption->style()->captionSide() != CAPBOTTOM) { tCaption->setPos(tCaption->marginLeft(), m_height); m_height += tCaption->height() + tCaption->marginTop() + tCaption->marginBottom(); } int bpTop = borderTop() + (collapseBorders() ? 0 : paddingTop()); int bpBottom = borderBottom() + (collapseBorders() ? 0 : paddingBottom()); m_height += bpTop; int oldHeight = m_height; calcHeight(); int newHeight = m_height; m_height = oldHeight; // html tables with percent height are relative to view Length h = style()->height(); int th = -(bpTop + bpBottom); // Tables size as though CSS height includes border/padding. if (isPositioned()) th = newHeight; // FIXME: Leave this alone for now but investigate later. else if (h.isFixed()) th += h.value; else if (h.isPercent()) { RenderObject* c = containingBlock(); for ( ; !c->isCanvas() && !c->isBody() && !c->isTableCell() && !c->isPositioned() && !c->isFloating(); c = c->containingBlock()) { Length ch = c->style()->height(); if (ch.isFixed()) { th += h.width(ch.value); break; } } if (c->isTableCell()) { RenderTableCell* cell = static_cast<RenderTableCell*>(c); int cellHeight = cell->getCellPercentageHeight(); if (cellHeight) th += h.width(cellHeight); } else { Length ch = c->style()->height(); if (ch.isFixed()) th += h.width(ch.value); else // FIXME: Investigate this. Seems wrong to always expand to fill the viewRect. // We need to substract out the margins of this block. -dwh th += h.width(viewRect().height() - c->marginBottom() - c->marginTop()); } } th = kMax(0, th); // layout rows if ( th > calculatedHeight ) { // we have to redistribute that height to get the constraint correctly // just force the first body to the height needed // ### FIXME This should take height constraints on all table sections into account and distribute // accordingly. For now this should be good enough if (firstBody) { firstBody->calcRowHeight(); firstBody->layoutRows( th - calculatedHeight ); } } int bl = borderLeft(); if (!collapseBorders()) bl += paddingLeft(); // position the table sections if ( head ) { head->setPos(bl, m_height); m_height += head->height(); } RenderObject *body = firstBody; while ( body ) { if ( body != head && body != foot && body->isTableSection() ) { body->setPos(bl, m_height); m_height += body->height(); } body = body->nextSibling(); } if ( foot ) { foot->setPos(bl, m_height); m_height += foot->height(); } m_height += bpBottom; if(tCaption && tCaption->style()->captionSide()==CAPBOTTOM) { tCaption->setPos(tCaption->marginLeft(), m_height); m_height += tCaption->height() + tCaption->marginTop() + tCaption->marginBottom(); } //kdDebug(0) << "table height: " << m_height << endl; // table can be containing block of positioned elements. // ### only pass true if width or height changed. layoutPositionedObjects( true ); // Repaint with our new bounds if they are different from our old bounds. if (checkForRepaint) repaintAfterLayoutIfNeeded(oldBounds, oldFullBounds); setNeedsLayout(false);}void RenderTable::setCellWidths(){#ifdef DEBUG_LAYOUT kdDebug( 6040 ) << renderName() << "(Table, this=0x" << this << ")::setCellWidths()" << endl;#endif RenderObject *child = firstChild(); while( child ) { if ( child->isTableSection() ) static_cast<RenderTableSection *>(child)->setCellWidths(); child = child->nextSibling(); }}void RenderTable::paint(PaintInfo& i, int _tx, int _ty){ if (needsLayout()) return; _tx += xPos(); _ty += yPos(); PaintAction paintAction = i.phase; #ifdef TABLE_PRINT kdDebug( 6040 ) << "RenderTable::paint() w/h = (" << width() << "/" << height() << ")" << endl;#endif if (!isRelPositioned() && !isPositioned()) { int os = 2*maximalOutlineSize(paintAction); if ((_ty >= i.r.y() + i.r.height() + os) || (_ty + height() <= i.r.y() - os)) return; if ((_tx >= i.r.x() + i.r.width() + os) || (_tx + width() <= i.r.x() - os)) return; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -