📄 inlineflowbox.cpp
字号:
/* * Copyright (C) 2003, 2004, 2005, 2006, 2007 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 "InlineFlowBox.h"#include "CachedImage.h"#include "Document.h"#include "EllipsisBox.h"#include "GraphicsContext.h"#include "InlineTextBox.h"#include "HitTestResult.h"#include "RootInlineBox.h"#include "RenderBlock.h"#include "RenderInline.h"#include "RenderListMarker.h"#include "RenderTableCell.h"#include "RootInlineBox.h"#include "Text.h"#include <math.h>using namespace std;namespace WebCore {#ifndef NDEBUGInlineFlowBox::~InlineFlowBox(){ if (!m_hasBadChildList) for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) child->setHasBadParent();}#endifint InlineFlowBox::height() const{ const Font& font = renderer()->style(m_firstLine)->font(); int result = font.height(); bool strictMode = renderer()->document()->inStrictMode(); RenderBoxModelObject* box = boxModelObject(); result += box->borderTop() + box->paddingTop() + box->borderBottom() + box->paddingBottom(); if (!strictMode && !hasTextChildren() && !box->hasHorizontalBordersOrPadding()) { int bottomOverflow = root()->bottomOverflow(); if (y() + result > bottomOverflow) result = bottomOverflow - y(); } return result;}int InlineFlowBox::getFlowSpacingWidth(){ int totWidth = marginBorderPaddingLeft() + marginBorderPaddingRight(); for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { if (curr->isInlineFlowBox()) totWidth += static_cast<InlineFlowBox*>(curr)->getFlowSpacingWidth(); } return totWidth;}void InlineFlowBox::addToLine(InlineBox* child) { ASSERT(!child->parent()); ASSERT(!child->nextOnLine()); ASSERT(!child->prevOnLine()); checkConsistency(); child->setParent(this); if (!m_firstChild) { m_firstChild = child; m_lastChild = child; } else { m_lastChild->setNextOnLine(child); child->setPrevOnLine(m_lastChild); m_lastChild = child; } child->setFirstLineStyleBit(m_firstLine); if (child->isText()) m_hasTextChildren = true; if (child->renderer()->selectionState() != RenderObject::SelectionNone) root()->setHasSelectedChildren(true); checkConsistency();}void InlineFlowBox::removeChild(InlineBox* child){ checkConsistency(); if (!m_dirty) dirtyLineBoxes(); root()->childRemoved(child); if (child == m_firstChild) m_firstChild = child->nextOnLine(); if (child == m_lastChild) m_lastChild = child->prevOnLine(); if (child->nextOnLine()) child->nextOnLine()->setPrevOnLine(child->prevOnLine()); if (child->prevOnLine()) child->prevOnLine()->setNextOnLine(child->nextOnLine()); child->setParent(0); checkConsistency();}void InlineFlowBox::deleteLine(RenderArena* arena){ InlineBox* child = firstChild(); InlineBox* next = 0; while (child) { ASSERT(this == child->parent()); next = child->nextOnLine();#ifndef NDEBUG child->setParent(0);#endif child->deleteLine(arena); child = next; }#ifndef NDEBUG m_firstChild = 0; m_lastChild = 0;#endif removeLineBoxFromRenderObject(); destroy(arena);}void InlineFlowBox::removeLineBoxFromRenderObject(){ toRenderInline(renderer())->lineBoxes()->removeLineBox(this);}void InlineFlowBox::extractLine(){ if (!m_extracted) extractLineBoxFromRenderObject(); for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) child->extractLine();}void InlineFlowBox::extractLineBoxFromRenderObject(){ toRenderInline(renderer())->lineBoxes()->extractLineBox(this);}void InlineFlowBox::attachLine(){ if (m_extracted) attachLineBoxToRenderObject(); for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) child->attachLine();}void InlineFlowBox::attachLineBoxToRenderObject(){ toRenderInline(renderer())->lineBoxes()->attachLineBox(this);}void InlineFlowBox::adjustPosition(int dx, int dy){ InlineRunBox::adjustPosition(dx, dy); for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) child->adjustPosition(dx, dy);}RenderLineBoxList* InlineFlowBox::rendererLineBoxes() const{ return toRenderInline(renderer())->lineBoxes();}bool InlineFlowBox::onEndChain(RenderObject* endObject){ if (!endObject) return false; if (endObject == renderer()) return true; RenderObject* curr = endObject; RenderObject* parent = curr->parent(); while (parent && !parent->isRenderBlock()) { if (parent->lastChild() != curr || parent == renderer()) 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; // The root inline box never has borders/margins/padding. if (parent()) { bool ltr = renderer()->style()->direction() == LTR; // Check to see if all initial lines are unconstructed. If so, then // we know the inline began on this line (unless we are a continuation). RenderLineBoxList* lineBoxList = rendererLineBoxes(); if (!lineBoxList->firstLineBox()->isConstructed() && !renderer()->isInlineContinuation()) { if (ltr && lineBoxList->firstLineBox() == this) includeLeftEdge = true; else if (!ltr && lineBoxList->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 (!lineBoxList->lastLineBox()->isConstructed()) { RenderInline* inlineFlow = toRenderInline(renderer()); if (ltr) { if (!nextLineBox() && ((lastLine && !inlineFlow->continuation()) || nextOnLineExists() || onEndChain(endObject))) includeRightEdge = true; } else { if ((!prevLineBox() || prevLineBox()->isConstructed()) && ((lastLine && !inlineFlow->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 xPos, int& leftPosition, int& rightPosition, bool& needsWordSpacing){ // Set our x position. setX(xPos); int boxShadowLeft = 0; int boxShadowRight = 0; for (ShadowData* boxShadow = renderer()->style(m_firstLine)->boxShadow(); boxShadow; boxShadow = boxShadow->next) { boxShadowLeft = min(boxShadow->x - boxShadow->blur, boxShadowLeft); boxShadowRight = max(boxShadow->x + boxShadow->blur, boxShadowRight); } leftPosition = min(xPos + boxShadowLeft, leftPosition); int startX = xPos; xPos += borderLeft() + paddingLeft(); for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { if (curr->renderer()->isText()) { InlineTextBox* text = static_cast<InlineTextBox*>(curr); RenderText* rt = toRenderText(text->renderer()); if (rt->textLength()) { if (needsWordSpacing && isSpaceOrNewline(rt->characters()[text->start()])) xPos += rt->style(m_firstLine)->font().wordSpacing(); needsWordSpacing = !isSpaceOrNewline(rt->characters()[text->end()]); } text->setX(xPos); int strokeOverflow = static_cast<int>(ceilf(rt->style()->textStrokeWidth() / 2.0f)); // If letter-spacing is negative, we should factor that into right overflow. (Even in RTL, letter-spacing is // applied to the right, so this is not an issue with left overflow. int letterSpacing = min(0, (int)rt->style(m_firstLine)->font().letterSpacing()); int leftGlyphOverflow = -strokeOverflow; int rightGlyphOverflow = strokeOverflow - letterSpacing; int visualOverflowLeft = leftGlyphOverflow; int visualOverflowRight = rightGlyphOverflow; for (ShadowData* shadow = rt->style()->textShadow(); shadow; shadow = shadow->next) { visualOverflowLeft = min(visualOverflowLeft, shadow->x - shadow->blur + leftGlyphOverflow); visualOverflowRight = max(visualOverflowRight, shadow->x + shadow->blur + rightGlyphOverflow); } leftPosition = min(xPos + visualOverflowLeft, leftPosition); rightPosition = max(xPos + text->width() + visualOverflowRight, rightPosition); m_maxHorizontalVisualOverflow = max(max(visualOverflowRight, -visualOverflowLeft), (int)m_maxHorizontalVisualOverflow); xPos += text->width(); } else { if (curr->renderer()->isPositioned()) { if (curr->renderer()->parent()->style()->direction() == LTR) curr->setX(xPos); 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 from the root line box). curr->setX(root()->block()->width() - xPos); continue; // The positioned object has no effect on the width. } if (curr->renderer()->isRenderInline()) { InlineFlowBox* flow = static_cast<InlineFlowBox*>(curr); xPos += flow->marginLeft(); xPos = flow->placeBoxesHorizontally(xPos, leftPosition, rightPosition, needsWordSpacing); xPos += flow->marginRight(); } else if (!curr->renderer()->isListMarker() || static_cast<RenderListMarker*>(curr->renderer())->isInside()) { xPos += curr->boxModelObject()->marginLeft(); curr->setX(xPos); leftPosition = min(xPos + toRenderBox(curr->renderer())->overflowLeft(false), leftPosition); rightPosition = max(xPos + toRenderBox(curr->renderer())->overflowWidth(false), rightPosition); xPos += curr->width() + curr->boxModelObject()->marginRight(); } } } xPos += borderRight() + paddingRight(); setWidth(xPos - startX); rightPosition = max(x() + width() + boxShadowRight, rightPosition); return xPos;}int InlineFlowBox::verticallyAlignBoxes(int heightOfBlock)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -