📄 render_block.cpp
字号:
/* * This file is part of the render object implementation for KHTML. * * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) * (C) 1999-2003 Antti Koivisto (koivisto@kde.org) * (C) 2002-2003 Dirk Mueller (mueller@kde.org) * (C) 2003 Apple Computer, Inc. * (C) 2004 Germain Garand (germain@ebooksfrance.org) * (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 DEBUG//#define DEBUG_LAYOUT//#define BOX_DEBUG//#define FLOAT_DEBUG//#define PAGE_DEBUG#include <kdebug.h>#include "rendering/render_text.h"#include "rendering/render_table.h"#include "rendering/render_canvas.h"#include "rendering/render_layer.h"#include "rendering/render_block.h"#include "xml/dom_nodeimpl.h"#include "xml/dom_docimpl.h"#include "html/html_formimpl.h"#include "misc/htmltags.h"#include "khtmlview.h"using namespace DOM;namespace khtml {// -------------------------------------------------------------------------------------------------------// 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->isCanvas() && !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().isVariable() && 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(DOM::NodeImpl* node) : RenderFlow(node){ m_childrenInline = true; m_floatingObjects = 0; m_positionedObjects = 0; m_pre = false; m_firstLine = false; m_avoidPageBreak = false; m_clearStatus = CNONE; m_maxTopPosMargin = m_maxTopNegMargin = m_maxBottomPosMargin = m_maxBottomNegMargin = 0; m_topMarginQuirk = m_bottomMarginQuirk = false; m_overflowHeight = 0; m_overflowWidth = 0;}RenderBlock::~RenderBlock(){ delete m_floatingObjects; delete m_positionedObjects;}void RenderBlock::setStyle(RenderStyle* _style){ setReplaced(_style->isDisplayReplacedType()); RenderFlow::setStyle(_style); m_pre = ( _style->whiteSpace() == PRE ); // ### we could save this call when the change only affected // non inherited properties RenderObject *child = firstChild(); while (child != 0) { if (child->isAnonymousBlock()) { RenderStyle* newStyle = new RenderStyle(); newStyle->inheritFrom(style()); newStyle->setDisplay(BLOCK); child->setStyle(newStyle); } child = child->nextSibling(); } // Update pseudos for :before and :after now. updatePseudoChildren(); // handled by close() during parsing if (!document()->parsing()) updateFirstLetter();}void RenderBlock::updateFirstLetter(){ // FIXME: We need to destroy the first-letter object if it is no longer the first child. Need to find // an efficient way to check for that situation though before implementing anything. RenderStyle * pseudoStyle; if ( isTable() || !(pseudoStyle = style()->getPseudoStyle(RenderStyle::FIRST_LETTER)) ) return; // Drill into inlines looking for our first text child. RenderObject* currChild = firstChild(); while (currChild && currChild->needsLayout() && !currChild->isReplaced() && !currChild->isText()) currChild = currChild->firstChild(); if (currChild && currChild->isText() && !currChild->isBR()) { bool update = (currChild->parent()->style()->styleType() == RenderStyle::FIRST_LETTER); RenderObject* firstLetterContainer = update ? currChild->parent()->parent() : currChild->parent(); RenderText* textObj = static_cast<RenderText*>(currChild); // Force inline display (except for floating first-letters) pseudoStyle->setDisplay( pseudoStyle->isFloating() ? BLOCK : INLINE); pseudoStyle->setPosition( STATIC ); // CSS2 says first-letter can't be positioned. if (update) { firstLetterContainer->firstChild()->setStyle( pseudoStyle ); RenderStyle* newStyle = new RenderStyle(); newStyle->inheritFrom( pseudoStyle ); currChild->setStyle( newStyle ); return; } RenderObject* firstLetter = RenderFlow::createFlow(element(), pseudoStyle, renderArena() ); firstLetter->setIsAnonymous( true ); firstLetterContainer->addChild(firstLetter, firstLetterContainer->firstChild()); // The original string is going to be either a generated content string or a DOM node's // string. We want the original string before it got transformed in case first-letter has // no text-transform or a different text-transform applied to it. DOMStringImpl* oldText = textObj->originalString(); if (!oldText) oldText = textObj->string(); if(oldText->l >= 1) { oldText->ref(); unsigned int length = 0; while ( length < oldText->l && ( (oldText->s+length)->isSpace() || (oldText->s+length)->isPunct() ) ) length++; if ( length < oldText->l && !( (oldText->s+length)->isSpace() || (oldText->s+length)->isPunct() )) length++; RenderTextFragment* remainingText = new (renderArena()) RenderTextFragment(textObj->node(), oldText, length, oldText->l-length); remainingText->setIsAnonymous( textObj->isAnonymous() ); remainingText->setStyle(textObj->style()); if (remainingText->element()) remainingText->element()->setRenderer(remainingText); RenderObject* nextObj = textObj->nextSibling(); firstLetterContainer->removeChild(textObj); firstLetterContainer->addChild(remainingText, nextObj); RenderTextFragment* letter = new (renderArena()) RenderTextFragment(remainingText->node(), oldText, 0, length); letter->setIsAnonymous( remainingText->isAnonymous() ); RenderStyle* newStyle = new RenderStyle(); newStyle->inheritFrom(pseudoStyle); letter->setStyle(newStyle); firstLetter->addChild(letter); oldText->deref(); } firstLetter->close(); }}void RenderBlock::addChildToFlow(RenderObject* newChild, RenderObject* beforeChild){ // Make sure we don't append things after :after-generated content if we have it. if ( !beforeChild && lastChild() && lastChild()->style()->styleType() == RenderStyle::AFTER ) beforeChild = lastChild(); bool madeBoxesNonInline = false; // If the requested beforeChild is not one of our children, then this is most likely because // there is an anonymous block box within this object that contains the beforeChild. So // just insert the child into the anonymous block box instead of here. if (beforeChild && beforeChild->parent() != this) { KHTMLAssert(beforeChild->parent()); KHTMLAssert(beforeChild->parent()->isAnonymousBlock()); if (newChild->isInline()) { beforeChild->parent()->addChild(newChild,beforeChild); return; } else if (beforeChild->parent()->firstChild() != beforeChild) return beforeChild->parent()->addChild(newChild, beforeChild); else return addChildToFlow(newChild, beforeChild->parent()); } // prevent elements that haven't received a layout yet from getting painted by pushing // them far above the top of the page if (!newChild->isInline()) newChild->setPos(newChild->xPos(), -500000); if (!newChild->isText() && newChild->style()->position() != STATIC) setOverhangingContents(); // 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 if ( m_childrenInline && !newChild->isInline() && !newChild->isFloatingOrPositioned() ) { // This is a block with inline content. Wrap the inline content in anonymous blocks. makeChildrenNonInline(beforeChild); madeBoxesNonInline = true; if (beforeChild && beforeChild->parent() != this) { beforeChild = beforeChild->parent(); KHTMLAssert(beforeChild->isAnonymousBlock()); KHTMLAssert(beforeChild->parent() == this); } } else if (!m_childrenInline && !newChild->isFloatingOrPositioned()) { // If we're inserting an inline child but all of our children are blocks, then we have to make sure // it is put into an anomyous block box. We try to use an existing anonymous box if possible, otherwise // a new one is created and inserted into our list of children in the appropriate position. if (newChild->isInline()) { if (beforeChild) { if ( beforeChild->previousSibling() && beforeChild->previousSibling()->isAnonymousBlock() ) { beforeChild->previousSibling()->addChild(newChild); return; } } else { if ( m_last && m_last->isAnonymousBlock() ) { m_last->addChild(newChild); return; } } // no suitable existing anonymous box - create a new one RenderBlock* newBox = createAnonymousBlock(); RenderBox::addChild(newBox,beforeChild); newBox->addChild(newChild); newBox->setPos(newBox->xPos(), -500000); return; } else { // We are adding another block child... if the current last child is an anonymous box // then it needs to be closed. // ### get rid of the closing thing altogether this will only work during initial parsing if (lastChild() && lastChild()->isAnonymous()) { lastChild()->close(); } } } RenderBox::addChild(newChild,beforeChild); // ### care about aligned stuff if ( madeBoxesNonInline ) removeLeftoverAnonymousBoxes();}static void getInlineRun(RenderObject* start, RenderObject* stop, RenderObject*& inlineRunStart, RenderObject*& inlineRunEnd)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -