📄 render_flow.cpp
字号:
/** * This file is part of the html renderer for KDE. * * 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. */// -------------------------------------------------------------------------#include <kdebug.h>#include <assert.h>#include <qpainter.h>#include <kglobal.h>#include "rendering/render_flow.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 "html/html_formimpl.h"#include "render_inline.h"#include "render_block.h"#include "render_arena.h"#include "render_line.h"#include "khtmlview.h"#include "htmltags.h"using namespace DOM;using namespace khtml;RenderFlow* RenderFlow::createAnonymousFlow(DOM::DocumentImpl* doc, RenderStyle* style){ RenderFlow* result; if (style->display() == INLINE) result = new (doc->renderArena()) RenderInline(doc); else result = new (doc->renderArena()) RenderBlock(doc); result->setStyle(style); return result;}RenderFlow* RenderFlow::continuationBefore(RenderObject* beforeChild){ if (beforeChild && beforeChild->parent() == this) return this; RenderFlow* curr = continuation(); RenderFlow* nextToLast = this; RenderFlow* last = this; while (curr) { if (beforeChild && beforeChild->parent() == curr) { if (curr->firstChild() == beforeChild) return last; return curr; } nextToLast = last; last = curr; curr = curr->continuation(); } if (!beforeChild && !last->firstChild()) return nextToLast; return last;}void RenderFlow::addChildWithContinuation(RenderObject* newChild, RenderObject* beforeChild){ RenderFlow* flow = continuationBefore(beforeChild); KHTMLAssert(!beforeChild || beforeChild->parent()->isRenderBlock() || beforeChild->parent()->isRenderInline()); RenderFlow* beforeChildParent = beforeChild ? static_cast<RenderFlow*>(beforeChild->parent()) : (flow->continuation() ? flow->continuation() : flow); if (newChild->isFloatingOrPositioned()) return beforeChildParent->addChildToFlow(newChild, beforeChild); // A continuation always consists of two potential candidates: an inline or an anonymous // block box holding block children. bool childInline = newChild->isInline(); bool bcpInline = beforeChildParent->isInline(); bool flowInline = flow->isInline(); if (flow == beforeChildParent) return flow->addChildToFlow(newChild, beforeChild); else { // The goal here is to match up if we can, so that we can coalesce and create the // minimal # of continuations needed for the inline. if (childInline == bcpInline) return beforeChildParent->addChildToFlow(newChild, beforeChild); else if (flowInline == childInline) return flow->addChildToFlow(newChild, 0); // Just treat like an append. else return beforeChildParent->addChildToFlow(newChild, beforeChild); }}void RenderFlow::addChild(RenderObject *newChild, RenderObject *beforeChild){#ifdef DEBUG_LAYOUT kdDebug( 6040 ) << renderName() << "(RenderFlow)::addChild( " << newChild->renderName() << ", " << (beforeChild ? beforeChild->renderName() : "0") << " )" << endl; kdDebug( 6040 ) << "current height = " << m_height << endl;#endif if (continuation()) return addChildWithContinuation(newChild, beforeChild); return addChildToFlow(newChild, beforeChild);}void RenderFlow::extractLineBox(InlineFlowBox* box){ m_lastLineBox = box->prevFlowBox(); if (box == m_firstLineBox) m_firstLineBox = 0; if (box->prevLineBox()) box->prevLineBox()->setNextLineBox(0); box->setPreviousLineBox(0); for (InlineRunBox* curr = box; curr; curr = curr->nextLineBox()) curr->setExtracted();}void RenderFlow::attachLineBox(InlineFlowBox* box){ if (m_lastLineBox) { m_lastLineBox->setNextLineBox(box); box->setPreviousLineBox(m_lastLineBox); } else m_firstLineBox = box; InlineFlowBox* last = box; for (InlineFlowBox* curr = box; curr; curr = curr->nextFlowBox()) { curr->setExtracted(false); last = curr; } m_lastLineBox = last;}void RenderFlow::removeLineBox(InlineFlowBox* box){ if (box == m_firstLineBox) m_firstLineBox = box->nextFlowBox(); if (box == m_lastLineBox) m_lastLineBox = box->prevFlowBox(); if (box->nextLineBox()) box->nextLineBox()->setPreviousLineBox(box->prevLineBox()); if (box->prevLineBox()) box->prevLineBox()->setNextLineBox(box->nextLineBox());}void RenderFlow::deleteLineBoxes(){ if (m_firstLineBox) { RenderArena* arena = renderArena(); InlineRunBox *curr=m_firstLineBox, *next=0; while (curr) { next = curr->nextLineBox(); curr->detach(arena); curr = next; } m_firstLineBox = 0; m_lastLineBox = 0; }}void RenderFlow::detach(){ if (!documentBeingDestroyed() && m_firstLineBox && m_firstLineBox->parent()) { for (InlineRunBox* box = m_firstLineBox; box; box = box->nextLineBox()) box->parent()->removeChild(box); } deleteLineBoxes(); RenderBox::detach();}void RenderFlow::dirtyLinesFromChangedChild(RenderObject* child){ if (!parent() || selfNeedsLayout() || isTable()) return; if (!isInline() && (!child->nextSibling() || !firstLineBox())) { // An append onto the end of a block or we don't have any lines anyway. // In this case we don't have to dirty any specific lines. static_cast<RenderBlock*>(this)->setLinesAppended(); return; } // For an empty inline, go ahead and propagate the check up to our parent. if (isInline() && !firstLineBox()) return parent()->dirtyLinesFromChangedChild(this); // Try to figure out which line box we belong in. First try to find a previous // line box by examining our siblings. If we didn't find a line box, then use our // parent's first line box. RootInlineBox* box = 0; for (RenderObject* curr = child->previousSibling(); curr; curr = curr->previousSibling()) { if (curr->isFloatingOrPositioned()) continue; if (curr->isReplaced()) { InlineBox* wrapper = curr->inlineBoxWrapper(); if (wrapper) box = wrapper->root(); } else if (curr->isText()) { InlineTextBox* textBox = static_cast<RenderText*>(curr)->lastTextBox(); if (textBox) box = textBox->root(); } else if (curr->isInlineFlow()) { InlineRunBox* runBox = static_cast<RenderFlow*>(curr)->lastLineBox(); if (runBox) box = runBox->root(); } if (box) break; } if (!box) box = lastLineBox()->root(); // If we found a line box, then dirty it. if (box) { box->markDirty(); if (child->isBR()) { RootInlineBox* next = box->nextRootBox(); if (next) next->markDirty(); } }}short RenderFlow::lineHeight(bool firstLine, bool isRootLineBox) const{ if (firstLine) { RenderStyle* s = style(firstLine); Length lh = s->lineHeight(); if (lh.value < 0) { if (s == style()) { if (m_lineHeight == -1) m_lineHeight = RenderObject::lineHeight(false); return m_lineHeight; } return s->fontMetrics().lineSpacing(); } if (lh.isPercent())
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -