📄 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-2003 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2003 Apple Computer, Inc. * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) * * 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., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. *///#define TABLE_DEBUG//#define TABLE_PRINT//#define DEBUG_LAYOUT//#define BOX_DEBUG#include "rendering/render_table.h"#include "rendering/render_replaced.h"#include "rendering/render_canvas.h"#include "rendering/table_layout.h"#include "html/html_tableimpl.h"#include "misc/htmltags.h"#include "misc/htmlattrs.h"#include "rendering/render_line.h"#include "xml/dom_docimpl.h"#include <kglobal.h>#include <qapplication.h>#include <qstyle.h>#include <kdebug.h>#include <assert.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 = 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; if ( _style->display() == INLINE ) _style->setDisplay( INLINE_TABLE ); if ( _style->display() != INLINE_TABLE ) _style->setDisplay(TABLE); RenderBlock::setStyle(_style); // init RenderObject attributes setInline(style()->display()==INLINE_TABLE && !isPositioned()); setReplaced(style()->display()==INLINE_TABLE); // In the collapsed border model, there is no cell spacing. hspacing = collapseBorders() ? 0 : style()->borderHorizontalSpacing(); vspacing = collapseBorders() ? 0 : style()->borderVerticalSpacing(); 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); }}short RenderTable::lineHeight(bool b) const{ // Inline tables are replaced elements. Otherwise, just pass off to // the base class. if (isReplaced()) return height()+marginTop()+marginBottom(); return RenderBlock::lineHeight(b);}short RenderTable::baselinePosition(bool b) const{ // Inline tables are replaced elements. Otherwise, just pass off to // the base class. if (isReplaced()) return height()+marginTop()+marginBottom(); return RenderBlock::baselinePosition(b);}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 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(); // Subtract minimum margins availableWidth -= style()->marginLeft().minWidth(cb->contentWidth()); availableWidth -= style()->marginRight().minWidth(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 { m_width = KMIN(short( availableWidth ), short(m_maxWidth)); } // restrict width to what we really have // EXCEPT percent tables, which are still calculated as above availableWidth = cb->lineWidth( m_y ); if ( widthType != Percent ) m_width = KMIN( short( availableWidth ), m_width ); 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; } if (markedForRepaint()) { repaintDuringLayout(); setMarkedForRepaint(false); } m_height = 0; initMaxMarginValues(); //int oldWidth = m_width; calcWidth(); m_overflowWidth = m_width; // the optimization 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; 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()) th += calcPercentageHeight(h); // 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 ); } else if (!style()->htmlHacks()) { // Completely empty tables (with no sections or anything) should at least honor specified height // in strict mode. m_height += th; } } 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(); } if (canvas()->pagedMode()) { RenderObject *child = firstChild(); // relayout taking real position into account while( child ) { if ( !(child->element() && child->element()->id() == ID_FORM) ) { child->setNeedsLayout(true); child->layout(); if (child->containsPageBreak()) setContainsPageBreak(true); if (child->needsPageClear()) setNeedsPageClear(true); } child = child->nextSibling(); } } //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 ); m_overflowHeight = m_height; 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& pI, int _tx, int _ty){ if(needsLayout()) return; _tx += xPos(); _ty += yPos();#ifdef TABLE_PRINT kdDebug( 6040 ) << "RenderTable::paint() w/h = (" << width() << "/" << height() << ")" << endl;#endif if (!overhangingContents() && !isRelPositioned() && !isPositioned()) { int os = 2*maximalOutlineSize(pI.phase); if((_ty > pI.r.y() + pI.r.height() + os) || (_ty + height() < pI.r.y() - os)) return; if((_tx > pI.r.x() + pI.r.width() + os) || (_tx + width() < pI.r.x() - os)) return; }#ifdef TABLE_PRINT kdDebug( 6040 ) << "RenderTable::paint(2) " << _tx << "/" << _ty << " (" << _y << "/" << _h << ")" << endl;#endif if (pI.phase == PaintActionOutline) paintOutline(pI.p, _tx, _ty, width(), height(), style()); if(( pI.phase == PaintActionElementBackground || pI.phase == PaintActionChildBackground )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -