📄 renderblock.cpp
字号:
/* * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2007 David Smith (catfish.man@gmail.com) * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. * * 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 "RenderBlock.h"#include "Document.h"#include "Element.h"#include "FloatQuad.h"#include "Frame.h"#include "FrameView.h"#include "GraphicsContext.h"#include "HTMLNames.h"#include "HitTestResult.h"#include "InlineTextBox.h"#include "RenderImage.h"#include "RenderInline.h"#include "RenderMarquee.h"#include "RenderReplica.h"#include "RenderTableCell.h"#include "RenderTextFragment.h"#include "RenderTheme.h"#include "RenderView.h"#include "SelectionController.h"#include <wtf/StdLibExtras.h>using namespace std;using namespace WTF;using namespace Unicode;namespace WebCore {// Number of pixels to allow as a fudge factor when clicking above or below a line.// clicking up to verticalLineClickFudgeFactor pixels above a line will correspond to the closest point on the line. const int verticalLineClickFudgeFactor= 3;using namespace HTMLNames;static void moveChild(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* from, RenderObjectChildList* fromChildList, RenderObject* child){ ASSERT(from == child->parent()); toChildList->appendChildNode(to, fromChildList->removeChildNode(from, child, false), false);}struct ColumnInfo { ColumnInfo() : m_desiredColumnWidth(0) , m_desiredColumnCount(1) { } int m_desiredColumnWidth; unsigned m_desiredColumnCount; Vector<IntRect> m_columnRects;};typedef WTF::HashMap<const RenderBox*, ColumnInfo*> ColumnInfoMap;static ColumnInfoMap* gColumnInfoMap = 0;typedef WTF::HashMap<const RenderBlock*, HashSet<RenderBox*>*> PercentHeightDescendantsMap;static PercentHeightDescendantsMap* gPercentHeightDescendantsMap = 0;typedef WTF::HashMap<const RenderBox*, HashSet<RenderBlock*>*> PercentHeightContainerMap;static PercentHeightContainerMap* gPercentHeightContainerMap = 0; typedef WTF::HashMap<RenderBlock*, ListHashSet<RenderInline*>*> ContinuationOutlineTableMap;// Our MarginInfo state used when laying out block children.RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, int top, int bottom){ // Whether or not we can collapse our own margins with our children. We don't do this // if we had any border/padding (obviously), if we're the root or HTML elements, or if // we're positioned, floating, a table cell. m_canCollapseWithChildren = !block->isRenderView() && !block->isRoot() && !block->isPositioned() && !block->isFloating() && !block->isTableCell() && !block->hasOverflowClip() && !block->isInlineBlockOrInlineTable(); m_canCollapseTopWithChildren = m_canCollapseWithChildren && (top == 0) && block->style()->marginTopCollapse() != MSEPARATE; // If any height other than auto is specified in CSS, then we don't collapse our bottom // margins with our children's margins. To do otherwise would be to risk odd visual // effects when the children overflow out of the parent block and yet still collapse // with it. We also don't collapse if we have any bottom border/padding. m_canCollapseBottomWithChildren = m_canCollapseWithChildren && (bottom == 0) && (block->style()->height().isAuto() && block->style()->height().value() == 0) && block->style()->marginBottomCollapse() != MSEPARATE; m_quirkContainer = block->isTableCell() || block->isBody() || block->style()->marginTopCollapse() == MDISCARD || block->style()->marginBottomCollapse() == MDISCARD; m_atTopOfBlock = true; m_atBottomOfBlock = false; m_posMargin = m_canCollapseTopWithChildren ? block->maxTopMargin(true) : 0; m_negMargin = m_canCollapseTopWithChildren ? block->maxTopMargin(false) : 0; m_selfCollapsingBlockClearedFloat = false; m_topQuirk = m_bottomQuirk = m_determinedTopQuirk = false;}// -------------------------------------------------------------------------------------------------------RenderBlock::RenderBlock(Node* node) : RenderBox(node) , m_floatingObjects(0) , m_positionedObjects(0) , m_inlineContinuation(0) , m_maxMargin(0) , m_overflowHeight(0) , m_overflowWidth(0) , m_overflowLeft(0) , m_overflowTop(0) , m_lineHeight(-1){ setChildrenInline(true);}RenderBlock::~RenderBlock(){ delete m_floatingObjects; delete m_positionedObjects; delete m_maxMargin; if (hasColumns()) delete gColumnInfoMap->take(this); if (gPercentHeightDescendantsMap) { if (HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->take(this)) { HashSet<RenderBox*>::iterator end = descendantSet->end(); for (HashSet<RenderBox*>::iterator descendant = descendantSet->begin(); descendant != end; ++descendant) { HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->get(*descendant); ASSERT(containerSet); if (!containerSet) continue; ASSERT(containerSet->contains(this)); containerSet->remove(this); if (containerSet->isEmpty()) { gPercentHeightContainerMap->remove(*descendant); delete containerSet; } } delete descendantSet; } }}void RenderBlock::destroy(){ // Detach our continuation first. if (m_inlineContinuation) m_inlineContinuation->destroy(); m_inlineContinuation = 0; // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise. children()->destroyLeftoverChildren(); if (!documentBeingDestroyed()) { if (firstLineBox()) { // We can't wait for RenderBox::destroy to clear the selection, // because by then we will have nuked the line boxes. // FIXME: The SelectionController should be responsible for this when it // is notified of DOM mutations. if (isSelectionBorder()) view()->clearSelection(); // If we are an anonymous block, then our line boxes might have children // that will outlast this block. In the non-anonymous block case those // children will be destroyed by the time we return from this function. if (isAnonymousBlock()) { for (InlineFlowBox* box = firstLineBox(); box; box = box->nextFlowBox()) { while (InlineBox* childBox = box->firstChild()) childBox->remove(); } } } else if (isInline() && parent()) parent()->dirtyLinesFromChangedChild(this); } m_lineBoxes.deleteLineBoxes(renderArena()); RenderBox::destroy();}void RenderBlock::styleWillChange(StyleDifference diff, const RenderStyle* newStyle){ setReplaced(newStyle->isDisplayReplacedType()); if (style() && parent() && diff == StyleDifferenceLayout && style()->position() != newStyle->position()) { if (newStyle->position() == StaticPosition) // Clear our positioned objects list. Our absolutely positioned descendants will be // inserted into our containing block's positioned objects list during layout. removePositionedObjects(0); else if (style()->position() == StaticPosition) { // Remove our absolutely positioned descendants from their current containing block. // They will be inserted into our positioned objects list during layout. RenderObject* cb = parent(); while (cb && (cb->style()->position() == StaticPosition || (cb->isInline() && !cb->isReplaced())) && !cb->isRenderView()) { if (cb->style()->position() == RelativePosition && cb->isInline() && !cb->isReplaced()) { cb = cb->containingBlock(); break; } cb = cb->parent(); } if (cb->isRenderBlock()) toRenderBlock(cb)->removePositionedObjects(this); } } RenderBox::styleWillChange(diff, newStyle);}void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle){ RenderBox::styleDidChange(diff, oldStyle); // FIXME: We could save this call when the change only affected non-inherited properties for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { if (child->isAnonymousBlock()) { RefPtr<RenderStyle> newStyle = RenderStyle::create(); newStyle->inheritFrom(style()); newStyle->setDisplay(BLOCK); child->setStyle(newStyle.release()); } } m_lineHeight = -1; // Update pseudos for :before and :after now. if (!isAnonymous() && document()->usesBeforeAfterRules() && canHaveChildren()) { updateBeforeAfterContent(BEFORE); updateBeforeAfterContent(AFTER); } updateFirstLetter();}void RenderBlock::updateBeforeAfterContent(PseudoId pseudoId){ // If this is an anonymous wrapper, then the parent applies its own pseudo-element style to it. if (parent() && parent()->createsAnonymousWrapper()) return; return children()->updateBeforeAfterContent(this, pseudoId);} void RenderBlock::addChild(RenderObject* newChild, RenderObject* beforeChild){ // Make sure we don't append things after :after-generated content if we have it. if (!beforeChild && isAfterContent(lastChild())) beforeChild = lastChild(); bool madeBoxesNonInline = false; // If the requested beforeChild is not one of our children, then this is because // there is an anonymous container within this object that contains the beforeChild. if (beforeChild && beforeChild->parent() != this) { RenderObject* anonymousChild = beforeChild->parent(); ASSERT(anonymousChild); while (anonymousChild->parent() != this) anonymousChild = anonymousChild->parent(); ASSERT(anonymousChild->isAnonymous()); if (anonymousChild->isAnonymousBlock()) { // Insert the child into the anonymous block box instead of here. if (newChild->isInline() || beforeChild->parent()->firstChild() != beforeChild) beforeChild->parent()->addChild(newChild, beforeChild); else addChild(newChild, beforeChild->parent()); return; } ASSERT(anonymousChild->isTable()); if (newChild->isTableCol() && newChild->style()->display() == TABLE_COLUMN_GROUP || newChild->isRenderBlock() && newChild->style()->display() == TABLE_CAPTION || newChild->isTableSection() || newChild->isTableRow() || newChild->isTableCell()) { // Insert into the anonymous table. anonymousChild->addChild(newChild, beforeChild); return; } // Go on to insert before the anonymous table. beforeChild = anonymousChild; } // A block has to either have all of its children inline, or all of its children as blocks. // So, if our children are currently inline and a block child has to be inserted, we move all our // inline children into anonymous block boxes.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -