📄 render_line.cpp
字号:
/*** This file is part of the html renderer for KDE. * * 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., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, 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_inline.h"#include "rendering/render_block.h"#include "rendering/render_arena.h"#include "rendering/render_line.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;using namespace khtml;#ifndef NDEBUGstatic bool inInlineBoxDetach;#endifvoid InlineBox::detach(RenderArena* renderArena){ if (m_parent) m_parent->removeFromLine(this);#ifndef NDEBUG inInlineBoxDetach = true;#endif delete this;#ifndef NDEBUG inInlineBoxDetach = false;#endif // Recover the size left there for us by operator delete and free the memory. renderArena->free(*(size_t *)this, this);}void* InlineBox::operator new(size_t sz, RenderArena* renderArena) throw(){ return renderArena->allocate(sz);}void InlineBox::operator delete(void* ptr, size_t sz){ assert(inInlineBoxDetach); // Stash size where detach can find it. *(size_t *)ptr = sz;}RootInlineBox* InlineBox::root(){ if (m_parent) return m_parent->root(); return static_cast<RootInlineBox*>(this);}InlineFlowBox::~InlineFlowBox(){ /* If we're destroyed, set the children free, and break their links */ while (m_firstChild) removeFromLine(m_firstChild);}void InlineFlowBox::removeFromLine(InlineBox *child){ if (child == m_firstChild) { m_firstChild = child->nextOnLine(); } if (child == m_lastChild) { m_lastChild = child->prevOnLine(); } if (child->nextOnLine()) { child->nextOnLine()->m_prev = child->prevOnLine(); } if (child->prevOnLine()) { child->prevOnLine()->m_next = child->nextOnLine(); } child->setParent(0);}int InlineFlowBox::marginLeft() const{ if (!includeLeftEdge()) return 0; RenderStyle* cstyle = object()->style(); Length margin = cstyle->marginLeft(); if (!margin.isVariable()) return (margin.isFixed() ? margin.value() : object()->marginLeft()); return 0;}int InlineFlowBox::marginRight() const{ if (!includeRightEdge()) return 0; RenderStyle* cstyle = object()->style(); Length margin = cstyle->marginRight(); if (!margin.isVariable()) return (margin.isFixed() ? margin.value() : object()->marginRight()); return 0;}int InlineFlowBox::marginBorderPaddingLeft() const{ return marginLeft() + borderLeft() + paddingLeft();}int InlineFlowBox::marginBorderPaddingRight() const{ return marginRight() + borderRight() + paddingRight();}int InlineFlowBox::getFlowSpacingWidth() const{ int totWidth = marginBorderPaddingLeft() + marginBorderPaddingRight(); for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { if (curr->isInlineFlowBox()) totWidth += static_cast<InlineFlowBox*>(curr)->getFlowSpacingWidth(); } return totWidth;}bool InlineFlowBox::nextOnLineExists(){ if (!parent()) return false; if (nextOnLine()) return true; return parent()->nextOnLineExists();}bool InlineFlowBox::prevOnLineExists(){ if (!parent()) return false; if (prevOnLine()) return true; return parent()->prevOnLineExists();}bool InlineFlowBox::onEndChain(RenderObject* endObject){ if (!endObject) return false; if (endObject == object()) return true; RenderObject* curr = endObject; RenderObject* parent = curr->parent(); while (parent && !parent->isRenderBlock()) { if (parent->lastChild() != curr) return false; curr = parent; parent = curr->parent(); } return true;}void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, RenderObject* endObject){ // All boxes start off open. They will not apply any margins/border/padding on // any side. bool includeLeftEdge = false; bool includeRightEdge = false; RenderFlow* flow = static_cast<RenderFlow*>(object()); if (!flow->firstChild()) includeLeftEdge = includeRightEdge = true; // Empty inlines never split across lines. else if (parent()) { // The root inline box never has borders/margins/padding. bool ltr = flow->style()->direction() == LTR; // Check to see if all initial lines are unconstructed. If so, then // we know the inline began on this line. if (!flow->firstLineBox()->isConstructed()) { if (ltr && flow->firstLineBox() == this) includeLeftEdge = true; else if (!ltr && flow->lastLineBox() == this) includeRightEdge = true; } // In order to determine if the inline ends on this line, we check three things: // (1) If we are the last line and we don't have a continuation(), then we can // close up. // (2) If the last line box for the flow has an object following it on the line (ltr, // reverse for rtl), then the inline has closed. // (3) The line may end on the inline. If we are the last child (climbing up // the end object's chain), then we just closed as well. if (!flow->lastLineBox()->isConstructed()) { if (ltr) { if (!nextLineBox() && ((lastLine && !object()->continuation()) || nextOnLineExists() || onEndChain(endObject))) includeRightEdge = true; } else { if ((!prevLineBox() || !prevLineBox()->isConstructed()) && ((lastLine && !object()->continuation()) || prevOnLineExists() || onEndChain(endObject))) includeLeftEdge = true; } } } setEdges(includeLeftEdge, includeRightEdge); // Recur into our children. for (InlineBox* currChild = firstChild(); currChild; currChild = currChild->nextOnLine()) { if (currChild->isInlineFlowBox()) { InlineFlowBox* currFlow = static_cast<InlineFlowBox*>(currChild); currFlow->determineSpacingForFlowBoxes(lastLine, endObject); } }}int InlineFlowBox::placeBoxesHorizontally(int x){ // Set our x position. setXPos(x); int startX = x; x += borderLeft() + paddingLeft(); for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { if (curr->object()->isText()) { InlineTextBox* text = static_cast<InlineTextBox*>(curr); text->setXPos(x); x += curr->width(); } else { if (curr->object()->isPositioned()) { if (curr->object()->parent()->style()->direction() == LTR) curr->setXPos(x); else { // Our offset that we cache needs to be from the edge of the right border box and // not the left border box. We have to subtract |x| from the width of the block // (which can be obtained by walking up to the root line box). InlineBox* root = this; while (!root->isRootInlineBox()) root = root->parent(); curr->setXPos(root->object()->width()-x); } continue; // The positioned object has no effect on the width. } if (curr->object()->isInlineFlow()) { InlineFlowBox* flow = static_cast<InlineFlowBox*>(curr); x += flow->marginLeft(); x = flow->placeBoxesHorizontally(x); x += flow->marginRight(); } else { x += curr->object()->marginLeft(); curr->setXPos(x); x += curr->width() + curr->object()->marginRight(); } } } x += borderRight() + paddingRight(); setWidth(x-startX); return x;}void InlineFlowBox::verticallyAlignBoxes(int& heightOfBlock){ int maxPositionTop = 0; int maxPositionBottom = 0; int maxAscent = 0; int maxDescent = 0; // Figure out if we're in strict mode. RenderObject* curr = object(); while (curr && !curr->element()) curr = curr->container(); bool strictMode = (curr && curr->element()->getDocument()->inStrictMode()); computeLogicalBoxHeights(maxPositionTop, maxPositionBottom, maxAscent, maxDescent, strictMode); if (maxAscent + maxDescent < kMax(maxPositionTop, maxPositionBottom)) adjustMaxAscentAndDescent(maxAscent, maxDescent, maxPositionTop, maxPositionBottom); int maxHeight = maxAscent + maxDescent; int topPosition = heightOfBlock; int bottomPosition = heightOfBlock; placeBoxesVertically(heightOfBlock, maxHeight, maxAscent, strictMode, topPosition, bottomPosition); setOverflowPositions(topPosition, bottomPosition); // Shrink boxes with no text children in quirks and almost strict mode. if (!strictMode)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -