📄 render_block.cpp
字号:
/* * This file is part of the render object implementation for KHTML. * * Copyright (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 DEBUG//#define DEBUG_LAYOUT//#define BOX_DEBUG//#define FLOAT_DEBUG#include <kdebug.h>#include "rendering/render_text.h"#include "rendering/render_table.h"#include "rendering/render_canvas.h"#include "xml/dom_nodeimpl.h"#include "xml/dom_docimpl.h"#include "xml/dom_position.h"#include "xml/dom_selection.h"#include "html/html_formimpl.h"#include "render_block.h"#include "khtmlview.h"#include "khtml_part.h"#include "htmltags.h"using namespace DOM;namespace khtml {RenderBlock::RenderBlock(DOM::NodeImpl* node):RenderFlow(node){ m_childrenInline = true; m_floatingObjects = 0; m_positionedObjects = 0; m_pre = false; m_firstLine = false; m_linesAppended = false; m_hasMarkupTruncation = 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 = false; if (_style->whiteSpace() == PRE) m_pre = true; // ### 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 (renderArena()) RenderStyle(); newStyle->inheritFrom(style()); newStyle->setDisplay(BLOCK); child->setStyle(newStyle); } child = child->nextSibling(); } m_lineHeight = -1; // Update pseudos for :before and :after now. updatePseudoChild(RenderStyle::BEFORE, firstChild()); updatePseudoChild(RenderStyle::AFTER, lastChild());}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); // 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; } } RenderBox::addChild(newChild,beforeChild); // ### care about aligned stuff if ( madeBoxesNonInline ) removeLeftoverAnonymousBoxes();}static void getInlineRun(RenderObject* start, RenderObject* stop, RenderObject*& inlineRunStart, RenderObject*& inlineRunEnd){ // Beginning at |start| we find the largest contiguous run of inlines that // we can. We denote the run with start and end points, |inlineRunStart| // and |inlineRunEnd|. Note that these two values may be the same if // we encounter only one inline. // // We skip any non-inlines we encounter as long as we haven't found any // inlines yet. // // |stop| indicates a non-inclusive stop point. Regardless of whether |stop| // is inline or not, we will not include it. It's as though we encountered // a non-inline. inlineRunStart = inlineRunEnd = 0; // Start by skipping as many non-inlines as we can. RenderObject * curr = start; while (curr && !(curr->isInline() || curr->isFloatingOrPositioned())) curr = curr->nextSibling(); if (!curr) return; // No more inline children to be found. inlineRunStart = inlineRunEnd = curr; bool sawInline = curr->isInline(); curr = curr->nextSibling(); while (curr && (curr->isInline() || curr->isFloatingOrPositioned()) && (curr != stop)) { inlineRunEnd = curr; if (curr->isInline()) sawInline = true; curr = curr->nextSibling(); } // Need to really see an inline in order to do any work. if (!sawInline) inlineRunStart = inlineRunEnd = 0;}void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint){ // makeChildrenNonInline takes a block whose children are *all* inline and it // makes sure that inline children are coalesced under anonymous // blocks. If |insertionPoint| is defined, then it represents the insertion point for // the new block child that is causing us to have to wrap all the inlines. This // means that we cannot coalesce inlines before |insertionPoint| with inlines following // |insertionPoint|, because the new child is going to be inserted in between the inlines, // splitting them. KHTMLAssert(isInlineBlockOrInlineTable() || !isInline()); KHTMLAssert(!insertionPoint || insertionPoint->parent() == this); m_childrenInline = false; RenderObject *child = firstChild(); while (child) { RenderObject *inlineRunStart, *inlineRunEnd; getInlineRun(child, insertionPoint, inlineRunStart, inlineRunEnd); if (!inlineRunStart) break; child = inlineRunEnd->nextSibling(); RenderBlock* box = createAnonymousBlock(); insertChildNode(box, inlineRunStart); RenderObject* o = inlineRunStart; while(o != inlineRunEnd) { RenderObject* no = o; o = no->nextSibling(); box->appendChildNode(removeChildNode(no)); } box->appendChildNode(removeChildNode(inlineRunEnd)); box->close(); box->setPos(box->xPos(), -500000); }}void RenderBlock::removeChildrenFromLineBoxes(){ // In the case where we do a collapse/merge from the destruction // of a block in between two anonymous blocks with inlines (see removeChild in render_block.cpp), // we have line boxes that need to have their parents nulled. KHTMLAssert(!documentBeingDestroyed()); for (InlineFlowBox* box = m_firstLineBox; box; box = box->nextFlowBox()) for (InlineBox* child = box->firstChild(); child; child = child->nextOnLine()) child->remove();}void RenderBlock::removeChild(RenderObject *oldChild){ // If this child is a block, and if our previous and next siblings are // both anonymous blocks with inline content, then we can go ahead and // fold the inline content back together. RenderObject* prev = oldChild->previousSibling(); RenderObject* next = oldChild->nextSibling(); bool mergedBlocks = false; if (!documentBeingDestroyed() && !isInline() && !oldChild->isInline() && !oldChild->continuation() && prev && prev->isAnonymousBlock() && prev->childrenInline() && next && next->isAnonymousBlock() && next->childrenInline()) { // Clean up the line box children inside |next|. static_cast<RenderBlock*>(next)->removeChildrenFromLineBoxes(); // Take all the children out of the |next| block and put them in // the |prev| block. RenderObject* o = next->firstChild(); while (o) { RenderObject* no = o; o = no->nextSibling(); prev->appendChildNode(next->removeChildNode(no)); no->setNeedsLayoutAndMinMaxRecalc(); } prev->setNeedsLayoutAndMinMaxRecalc(); // Nuke the now-empty block. next->detach(); mergedBlocks = true; } RenderFlow::removeChild(oldChild); if (mergedBlocks && prev && !prev->previousSibling() && !prev->nextSibling()) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -