⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rendertable.cpp

📁 linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自WebKit
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/* * 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, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.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. */#include "config.h"#include "RenderTable.h"#include "AutoTableLayout.h"#include "DeleteButtonController.h"#include "Document.h"#include "FixedTableLayout.h"#include "FrameView.h"#include "HTMLNames.h"#include "RenderLayer.h"#include "RenderTableCell.h"#include "RenderTableCol.h"#include "RenderTableSection.h"#include "RenderView.h"using namespace std;namespace WebCore {using namespace HTMLNames;RenderTable::RenderTable(Node* node)    : RenderBlock(node)    , m_caption(0)    , m_head(0)    , m_foot(0)    , m_firstBody(0)    , m_tableLayout(0)    , m_currentBorder(0)    , m_hasColElements(false)    , m_needsSectionRecalc(0)    , m_hSpacing(0)    , m_vSpacing(0)    , m_borderLeft(0)    , m_borderRight(0){    m_columnPos.fill(0, 2);    m_columns.fill(ColumnStruct(), 1);}RenderTable::~RenderTable(){    delete m_tableLayout;}void RenderTable::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle){    RenderBlock::styleDidChange(diff, oldStyle);    ETableLayout oldTableLayout = oldStyle ? oldStyle->tableLayout() : TAUTO;    // In the collapsed border model, there is no cell spacing.    m_hSpacing = collapseBorders() ? 0 : style()->horizontalBorderSpacing();    m_vSpacing = collapseBorders() ? 0 : style()->verticalBorderSpacing();    m_columnPos[0] = m_hSpacing;    if (!m_tableLayout || style()->tableLayout() != oldTableLayout) {        delete m_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().isAuto())            m_tableLayout = new FixedTableLayout(this);        else            m_tableLayout = new AutoTableLayout(this);    }}static inline void resetSectionPointerIfNotBefore(RenderTableSection*& ptr, RenderObject* before){    if (!before || !ptr)        return;    RenderObject* o = before->previousSibling();    while (o && o != ptr)        o = o->previousSibling();    if (!o)        ptr = 0;}void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild){    // Make sure we don't append things after :after-generated content if we have it.    if (!beforeChild && isAfterContent(lastChild()))        beforeChild = lastChild();    bool wrapInAnonymousSection = !child->isPositioned();    bool isTableElement = node() && node()->hasTagName(tableTag);    if (child->isRenderBlock() && child->style()->display() == TABLE_CAPTION) {        // First caption wins.        if (beforeChild && m_caption) {            RenderObject* o = beforeChild->previousSibling();            while (o && o != m_caption)                o = o->previousSibling();            if (!o)                m_caption = 0;        }        if (!m_caption)            m_caption = toRenderBlock(child);        wrapInAnonymousSection = false;    } else if (child->isTableCol()) {        m_hasColElements = true;        wrapInAnonymousSection = false;    } else if (child->isTableSection()) {        switch (child->style()->display()) {            case TABLE_HEADER_GROUP:                if (child->isTableSection()) {                    resetSectionPointerIfNotBefore(m_head, beforeChild);                    if (!m_head) {                        m_head = static_cast<RenderTableSection*>(child);                    } else {                        resetSectionPointerIfNotBefore(m_firstBody, beforeChild);                        if (!m_firstBody)                             m_firstBody = static_cast<RenderTableSection*>(child);                    }                }                wrapInAnonymousSection = false;                break;            case TABLE_FOOTER_GROUP:                if (child->isTableSection()) {                    resetSectionPointerIfNotBefore(m_foot, beforeChild);                    if (!m_foot) {                        m_foot = static_cast<RenderTableSection*>(child);                        wrapInAnonymousSection = false;                        break;                    }                }                // Fall through.            case TABLE_ROW_GROUP:                if (child->isTableSection()) {                    resetSectionPointerIfNotBefore(m_firstBody, beforeChild);                    if (!m_firstBody)                        m_firstBody = static_cast<RenderTableSection*>(child);                }                wrapInAnonymousSection = false;                break;            default:                ASSERT_NOT_REACHED();        }    } else if (child->isTableCell() || child->isTableRow()) {        wrapInAnonymousSection = true;    } else        // Allow a form to just sit at the top level.        wrapInAnonymousSection = !isTableElement || !child->node() || !(child->node()->hasTagName(formTag) && document()->isHTMLDocument());    if (!wrapInAnonymousSection) {        // If the next renderer is actually wrapped in an anonymous table section, we need to go up and find that.        while (beforeChild && !beforeChild->isTableSection() && !beforeChild->isTableCol() && beforeChild->style()->display() != TABLE_CAPTION)            beforeChild = beforeChild->parent();        RenderBox::addChild(child, beforeChild);        return;    }    if (!beforeChild && lastChild() && lastChild()->isTableSection() && lastChild()->isAnonymous()) {        lastChild()->addChild(child);        return;    }    RenderObject* lastBox = beforeChild;    while (lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableSection() && lastBox->style()->display() != TABLE_CAPTION && lastBox->style()->display() != TABLE_COLUMN_GROUP)        lastBox = lastBox->parent();    if (lastBox && lastBox->isAnonymous() && !isAfterContent(lastBox)) {        lastBox->addChild(child, beforeChild);        return;    }    if (beforeChild && !beforeChild->isTableSection() && beforeChild->style()->display() != TABLE_CAPTION && beforeChild->style()->display() != TABLE_COLUMN_GROUP)        beforeChild = 0;    RenderTableSection* section = new (renderArena()) RenderTableSection(document() /* anonymous */);    RefPtr<RenderStyle> newStyle = RenderStyle::create();    newStyle->inheritFrom(style());    newStyle->setDisplay(TABLE_ROW_GROUP);    section->setStyle(newStyle.release());    addChild(section, beforeChild);    section->addChild(child);}void RenderTable::removeChild(RenderObject* oldChild){    RenderBox::removeChild(oldChild);    setNeedsSectionRecalc();}void RenderTable::calcWidth(){    if (isPositioned())        calcAbsoluteHorizontal();    RenderBlock* cb = containingBlock();    int availableWidth = cb->availableWidth();    LengthType widthType = style()->width().type();    if (widthType > Relative && style()->width().isPositive()) {        // Percent or fixed table        setWidth(style()->width().calcMinValue(availableWidth));        setWidth(max(minPrefWidth(), width()));    } else {        // An auto width table should shrink to fit within the line width if necessary in order to         // avoid overlapping floats.        availableWidth = cb->lineWidth(y(), false);                // Subtract out any fixed margins from our available width for auto width tables.        int marginTotal = 0;        if (!style()->marginLeft().isAuto())            marginTotal += style()->marginLeft().calcValue(availableWidth);        if (!style()->marginRight().isAuto())            marginTotal += style()->marginRight().calcValue(availableWidth);                    // Subtract out our margins to get the available content width.        int availContentWidth = max(0, availableWidth - marginTotal);                // Ensure we aren't bigger than our max width or smaller than our min width.        setWidth(min(availContentWidth, maxPrefWidth()));    }        setWidth(max(width(), minPrefWidth()));    // 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(){    ASSERT(needsLayout());    if (layoutOnlyPositionedObjects())        return;    recalcSectionsIfNeeded();            LayoutRepainter repainter(*this, checkForRepaintDuringLayout());    LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()));    setHeight(0);    m_overflowHeight = 0;    m_overflowTop = 0;    initMaxMarginValues();        int oldWidth = width();    calcWidth();    if (m_caption && width() != oldWidth)        m_caption->setNeedsLayout(true, false);    // FIXME: 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 != width() || columns.size() + 1 != columnPos.size() )    m_tableLayout->layout();    setCellWidths();    // layout child objects    int calculatedHeight = 0;    int oldTableTop = m_caption ? m_caption->height() + m_caption->marginTop() + m_caption->marginBottom() : 0;    bool collapsing = collapseBorders();    for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {        if (child->isTableSection()) {            child->layoutIfNeeded();            RenderTableSection* section = static_cast<RenderTableSection*>(child);            calculatedHeight += section->calcRowHeight();            if (collapsing)                section->recalcOuterBorder();            ASSERT(!section->needsLayout());        }    }    // Only lay out one caption, since it's the only one we're going to end up painting.    if (m_caption)        m_caption->layoutIfNeeded();    m_overflowWidth = width() + (collapsing ? outerBorderRight() - borderRight() : 0);    m_overflowLeft = collapsing ? borderLeft() - outerBorderLeft() : 0;    // If any table section moved vertically, we will just repaint everything from that    // section down (it is quite unlikely that any of the following sections    // did not shift).    bool sectionMoved = false;    int movedSectionTop = 0;    // FIXME: Collapse caption margin.    if (m_caption && m_caption->style()->captionSide() != CAPBOTTOM) {        IntRect captionRect(m_caption->x(), m_caption->y(), m_caption->width(), m_caption->height());        m_caption->setLocation(m_caption->marginLeft(), height());        if (!selfNeedsLayout() && m_caption->checkForRepaintDuringLayout())            m_caption->repaintDuringLayoutIfMoved(captionRect);        setHeight(height() + m_caption->height() + m_caption->marginTop() + m_caption->marginBottom());        m_overflowLeft = min(m_overflowLeft, m_caption->x() + m_caption->overflowLeft(false));        m_overflowWidth = max(m_overflowWidth, m_caption->x() + m_caption->overflowWidth(false));        m_overflowTop = min(m_overflowTop, m_caption->y() + m_caption->overflowTop(false));        m_overflowHeight = max(m_overflowHeight, m_caption->y() + m_caption->overflowHeight(false));        if (height() != oldTableTop) {            sectionMoved = true;            movedSectionTop = min(height(), oldTableTop);        }    }    int bpTop = borderTop() + (collapsing ? 0 : paddingTop());    int bpBottom = borderBottom() + (collapsing ? 0 : paddingBottom());        setHeight(height() + bpTop);    if (!isPositioned())        calcHeight();    Length h = style()->height();    int th = 0;    if (h.isFixed())        // Tables size as though CSS height includes border/padding.        th = h.value() - (bpTop + bpBottom);    else if (h.isPercent())        th = calcPercentageHeight(h);    th = max(0, th);    for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {        if (child->isTableSection())            // FIXME: Distribute extra height between all table body sections instead of giving it all to the first one.            static_cast<RenderTableSection*>(child)->layoutRows(child == m_firstBody ? max(0, th - calculatedHeight) : 0);    }    if (!m_firstBody && th > calculatedHeight && !style()->htmlHacks()) {        // Completely empty tables (with no sections or anything) should at least honor specified height        // in strict mode.        setHeight(height() + th);    }        int bl = borderLeft();    if (!collapsing)        bl += paddingLeft();    // position the table sections    RenderTableSection* section = m_head ? m_head : (m_firstBody ? m_firstBody : m_foot);    while (section) {        if (!sectionMoved && section->y() != height()) {            sectionMoved = true;            movedSectionTop = min(height(), section->y()) + section->overflowTop(false);        }        section->setLocation(bl, height());        setHeight(height() + section->height());        m_overflowLeft = min(m_overflowLeft, section->x() + section->overflowLeft(false));        m_overflowWidth = max(m_overflowWidth, section->x() + section->overflowWidth(false));        m_overflowTop = min(m_overflowTop, section->y() + section->overflowTop(false));        m_overflowHeight = max(m_overflowHeight, section->y() + section->overflowHeight(false));        section = sectionBelow(section);    }    setHeight(height() + bpBottom);    if (m_caption && m_caption->style()->captionSide() == CAPBOTTOM) {        IntRect captionRect(m_caption->x(), m_caption->y(), m_caption->width(), m_caption->height());        m_caption->setLocation(m_caption->marginLeft(), height());        if (!selfNeedsLayout() && m_caption->checkForRepaintDuringLayout())            m_caption->repaintDuringLayoutIfMoved(captionRect);        setHeight(height() + m_caption->height() + m_caption->marginTop() + m_caption->marginBottom());        m_overflowLeft = min(m_overflowLeft, m_caption->x() + m_caption->overflowLeft(false));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -