From 24214e380e80cf1bca313cb33f3b4b37c2aaf096 Mon Sep 17 00:00:00 2001 From: ap Date: Sat, 13 May 2006 15:28:30 +0000 Subject: [PATCH] Re-applied the fix for bug 8835 (REGRESSION: Line moves but selection highlight stays behind) to a correct file; removed the stale one. * rendering/RootInlineBox.cpp: (WebCore::RootInlineBox::adjustPosition): Adjust m_selectionTop and m_selectionBottom. * rendering/render_line.cpp: Removed. git-svn-id: https://svn.webkit.org/repository/webkit/trunk@14354 268f45cc-cd09-0410-ab3c-d52691b4dbfc --- WebCore/rendering/RootInlineBox.cpp | 2 + WebCore/rendering/render_line.cpp | 1391 --------------------------- 2 files changed, 2 insertions(+), 1391 deletions(-) delete mode 100644 WebCore/rendering/render_line.cpp diff --git a/WebCore/rendering/RootInlineBox.cpp b/WebCore/rendering/RootInlineBox.cpp index 9fabb3708176..d81066a36171 100644 --- a/WebCore/rendering/RootInlineBox.cpp +++ b/WebCore/rendering/RootInlineBox.cpp @@ -121,6 +121,8 @@ void RootInlineBox::adjustPosition(int dx, int dy) m_topOverflow += dy; m_bottomOverflow += dy; m_blockHeight += dy; + m_selectionTop += dy; + m_selectionBottom += dy; } void RootInlineBox::childRemoved(InlineBox* box) diff --git a/WebCore/rendering/render_line.cpp b/WebCore/rendering/render_line.cpp deleted file mode 100644 index b5582139f34e..000000000000 --- a/WebCore/rendering/render_line.cpp +++ /dev/null @@ -1,1391 +0,0 @@ -/** -* This file is part of the html renderer for KDE. - * - * Copyright (C) 2003, 2006 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 "config.h" -#include "render_line.h" - -#include "CachedImage.h" -#include "Document.h" -#include "GraphicsContext.h" -#include "InlineTextBox.h" -#include "RenderBlock.h" -#include "RenderTableCell.h" -#include "RenderArena.h" -#include "RenderInline.h" -#include "render_list.h" -#include - -using namespace std; - -namespace WebCore { - -#ifndef NDEBUG -static bool inInlineBoxDetach; -#endif - -class EllipsisBox : public InlineBox -{ -public: - EllipsisBox(RenderObject* obj, const WebCore::AtomicString& ellipsisStr, InlineFlowBox* p, - int w, int y, int h, int b, bool firstLine, InlineBox* markupBox) - :InlineBox(obj), m_str(ellipsisStr) { - m_parent = p; - m_width = w; - m_y = y; - m_height = h; - m_baseline = b; - m_firstLine = firstLine; - m_constructed = true; - m_markupBox = markupBox; - } - - virtual void paint(RenderObject::PaintInfo& i, int _tx, int _ty); - virtual bool nodeAtPoint(RenderObject::NodeInfo& info, int _x, int _y, int _tx, int _ty); - -private: - WebCore::AtomicString m_str; - InlineBox* m_markupBox; -}; - -void InlineBox::remove() -{ - if (parent()) - parent()->removeChild(this); -} - -void InlineBox::destroy(RenderArena* renderArena) -{ -#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 destroy can find it. - *(size_t *)ptr = sz; -} - -#ifndef NDEBUG -void InlineBox::showTreeForThis() const -{ - if (m_object) - m_object->showTreeForThis(); -} -#endif - -int InlineBox::caretMinOffset() const -{ - return 0; -} - -int InlineBox::caretMaxOffset() const -{ - return 1; -} - -unsigned InlineBox::caretMaxRenderedOffset() const -{ - return 1; -} - -void InlineBox::dirtyLineBoxes() -{ - markDirty(); - for (InlineFlowBox* curr = parent(); curr && !curr->isDirty(); curr = curr->parent()) - curr->markDirty(); -} - -void InlineBox::deleteLine(RenderArena* arena) -{ - if (!m_extracted) - m_object->setInlineBoxWrapper(0); - destroy(arena); -} - -void InlineBox::extractLine() -{ - m_extracted = true; - m_object->setInlineBoxWrapper(0); -} - -void InlineBox::attachLine() -{ - m_extracted = false; - m_object->setInlineBoxWrapper(this); -} - -void InlineBox::adjustPosition(int dx, int dy) -{ - m_x += dx; - m_y += dy; - if (m_object->isReplaced() || m_object->isBR()) - m_object->setPos(m_object->xPos() + dx, m_object->yPos() + dy); -} - -void InlineBox::paint(RenderObject::PaintInfo& i, int tx, int ty) -{ - if (!object()->shouldPaintWithinRoot(i) || (i.phase != PaintPhaseForeground && i.phase != PaintPhaseSelection)) - return; - - // Paint all phases of replaced elements atomically, as though the replaced element established its - // own stacking context. (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1 - // specification.) - bool paintSelectionOnly = i.phase == PaintPhaseSelection; - RenderObject::PaintInfo info(i); - info.phase = paintSelectionOnly ? i.phase : PaintPhaseBlockBackground; - object()->paint(info, tx, ty); - if (!paintSelectionOnly) { - info.phase = PaintPhaseChildBlockBackgrounds; - object()->paint(info, tx, ty); - info.phase = PaintPhaseFloat; - object()->paint(info, tx, ty); - info.phase = PaintPhaseForeground; - object()->paint(info, tx, ty); - info.phase = PaintPhaseOutline; - object()->paint(info, tx, ty); - } -} - -bool InlineBox::nodeAtPoint(RenderObject::NodeInfo& i, int x, int y, int tx, int ty) -{ - // Hit test all phases of replaced elements atomically, as though the replaced element established its - // own stacking context. (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1 - // specification.) - return object()->hitTest(i, x, y, tx, ty); -} - -RootInlineBox* InlineBox::root() -{ - if (m_parent) - return m_parent->root(); - return static_cast(this); -} - -bool InlineBox::nextOnLineExists() const -{ - if (!parent()) - return false; - - if (nextOnLine()) - return true; - - return parent()->nextOnLineExists(); -} - -bool InlineBox::prevOnLineExists() const -{ - if (!parent()) - return false; - - if (prevOnLine()) - return true; - - return parent()->prevOnLineExists(); -} - -InlineBox* InlineBox::firstLeafChild() -{ - return this; -} - -InlineBox* InlineBox::lastLeafChild() -{ - return this; -} - -InlineBox* InlineBox::nextLeafChild() -{ - return parent() ? parent()->firstLeafChildAfterBox(this) : 0; -} - -InlineBox* InlineBox::prevLeafChild() -{ - return parent() ? parent()->lastLeafChildBeforeBox(this) : 0; -} - -RenderObject::SelectionState InlineBox::selectionState() -{ - return object()->selectionState(); -} - -bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) -{ - // Non-replaced elements can always accommodate an ellipsis. - if (!m_object || !m_object->isReplaced()) - return true; - - IntRect boxRect(m_x, 0, m_width, 10); - IntRect ellipsisRect(ltr ? blockEdge - ellipsisWidth : blockEdge, 0, ellipsisWidth, 10); - return !(boxRect.intersects(ellipsisRect)); -} - -int InlineBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool&) -{ - // Use -1 to mean "we didn't set the position." - return -1; -} - -RenderFlow* InlineFlowBox::flowObject() -{ - return static_cast(m_object); -} - -int InlineFlowBox::marginLeft() -{ - if (!includeLeftEdge()) - return 0; - - Length margin = object()->style()->marginLeft(); - if (margin.isAuto()) - return 0; - if (margin.isFixed()) - return margin.value(); - return object()->marginLeft(); -} - -int InlineFlowBox::marginRight() -{ - if (!includeRightEdge()) - return 0; - - Length margin = object()->style()->marginRight(); - if (margin.isAuto()) - return 0; - if (margin.isFixed()) - return margin.value(); - return object()->marginRight(); -} - -int InlineFlowBox::marginBorderPaddingLeft() -{ - return marginLeft() + borderLeft() + paddingLeft(); -} - -int InlineFlowBox::marginBorderPaddingRight() -{ - return marginRight() + borderRight() + paddingRight(); -} - -int InlineFlowBox::getFlowSpacingWidth() -{ - int totWidth = marginBorderPaddingLeft() + marginBorderPaddingRight(); - for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->isInlineFlowBox()) - totWidth += static_cast(curr)->getFlowSpacingWidth(); - } - return totWidth; -} - -void InlineFlowBox::addToLine(InlineBox* child) { - if (!m_firstChild) - m_firstChild = m_lastChild = child; - else { - m_lastChild->m_next = child; - child->m_prev = m_lastChild; - m_lastChild = child; - } - child->setFirstLineStyleBit(m_firstLine); - child->setParent(this); - if (child->isText()) - m_hasTextChildren = true; - if (child->object()->selectionState() != RenderObject::SelectionNone) - root()->setHasSelectedChildren(true); -} - -void InlineFlowBox::removeChild(InlineBox* child) -{ - 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); -} - -void InlineFlowBox::deleteLine(RenderArena* arena) -{ - InlineBox* child = m_firstChild; - InlineBox* next = 0; - while (child) { - next = child->nextOnLine(); - child->deleteLine(arena); - child = next; - } - - static_cast(m_object)->removeLineBox(this); - destroy(arena); -} - -void InlineFlowBox::extractLine() -{ - if (!m_extracted) - static_cast(m_object)->extractLineBox(this); - for (InlineBox* child = m_firstChild; child; child = child->nextOnLine()) - child->extractLine(); -} - -void InlineFlowBox::attachLine() -{ - if (m_extracted) - static_cast(m_object)->attachLineBox(this); - for (InlineBox* child = m_firstChild; child; child = child->nextOnLine()) - child->attachLine(); -} - -void InlineFlowBox::adjustPosition(int dx, int dy) -{ - InlineRunBox::adjustPosition(dx, dy); - for (InlineBox* child = m_firstChild; child; child = child->nextOnLine()) - child->adjustPosition(dx, dy); -} - -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 || parent == object()) - 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(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(currChild); - currFlow->determineSpacingForFlowBoxes(lastLine, endObject); - } - } -} - -int InlineFlowBox::placeBoxesHorizontally(int x, int& leftPosition, int& rightPosition, bool & needsWordSpacing) -{ - // Set our x position. - setXPos(x); - leftPosition = min(x, leftPosition); - - int startX = x; - x += borderLeft() + paddingLeft(); - - for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->object()->isText()) { - InlineTextBox *text = static_cast(curr); - RenderText *rt = static_cast(text->object()); - if (rt->length()) { - if (needsWordSpacing && QChar(rt->text()[text->start()]).isSpace()) - x += rt->font(m_firstLine)->wordSpacing(); - needsWordSpacing = !QChar(rt->text()[text->end()]).isSpace(); - } - text->setXPos(x); - int shadowLeft = 0; - int shadowRight = 0; - for (ShadowData* shadow = rt->style()->textShadow(); shadow; shadow = shadow->next) { - shadowLeft = min(shadowLeft, shadow->x - shadow->blur); - shadowRight = max(shadowRight, shadow->x + shadow->blur); - } - leftPosition = min(x + shadowLeft, leftPosition); - rightPosition = max(x + text->width() + shadowRight, rightPosition); - m_maxHorizontalShadow = max(max(shadowRight, -shadowLeft), m_maxHorizontalShadow); - x += text->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 from the root line box). - curr->setXPos(root()->object()->width()-x); - continue; // The positioned object has no effect on the width. - } - if (curr->object()->isInlineFlow()) { - InlineFlowBox* flow = static_cast(curr); - if (curr->object()->isCompact()) { - int ignoredX = x; - flow->placeBoxesHorizontally(ignoredX, leftPosition, rightPosition, needsWordSpacing); - } else { - x += flow->marginLeft(); - x = flow->placeBoxesHorizontally(x, leftPosition, rightPosition, needsWordSpacing); - x += flow->marginRight(); - } - } else if (!curr->object()->isCompact() && (!curr->object()->isListMarker() || static_cast(curr->object())->isInside())) { - x += curr->object()->marginLeft(); - curr->setXPos(x); - leftPosition = min(x, leftPosition); - rightPosition = max(x + curr->width(), rightPosition); - x += curr->width() + curr->object()->marginRight(); - } - } - } - - x += borderRight() + paddingRight(); - setWidth(x-startX); - rightPosition = max(xPos() + width(), rightPosition); - - 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. Note that we can't simply use !style()->htmlHacks(), - // because that would match almost strict mode as well. - RenderObject* curr = object(); - while (curr && !curr->element()) - curr = curr->container(); - bool strictMode = (curr && curr->document()->inStrictMode()); - - computeLogicalBoxHeights(maxPositionTop, maxPositionBottom, maxAscent, maxDescent, strictMode); - - if (maxAscent + maxDescent < max(maxPositionTop, maxPositionBottom)) - adjustMaxAscentAndDescent(maxAscent, maxDescent, maxPositionTop, maxPositionBottom); - - int maxHeight = maxAscent + maxDescent; - int topPosition = heightOfBlock; - int bottomPosition = heightOfBlock; - int selectionTop = heightOfBlock; - int selectionBottom = heightOfBlock; - placeBoxesVertically(heightOfBlock, maxHeight, maxAscent, strictMode, topPosition, bottomPosition, selectionTop, selectionBottom); - - setVerticalOverflowPositions(topPosition, bottomPosition); - setVerticalSelectionPositions(selectionTop, selectionBottom); - - // Shrink boxes with no text children in quirks and almost strict mode. - if (!strictMode) - shrinkBoxesWithNoTextChildren(topPosition, bottomPosition); - - heightOfBlock += maxHeight; -} - -void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, - int maxPositionTop, int maxPositionBottom) -{ - for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - // The computed lineheight needs to be extended for the - // positioned elements - if (curr->object()->isPositioned()) - continue; // Positioned placeholders don't affect calculations. - if (curr->yPos() == PositionTop || curr->yPos() == PositionBottom) { - if (curr->yPos() == PositionTop) { - if (maxAscent + maxDescent < curr->height()) - maxDescent = curr->height() - maxAscent; - } - else { - if (maxAscent + maxDescent < curr->height()) - maxAscent = curr->height() - maxDescent; - } - - if (maxAscent + maxDescent >= max(maxPositionTop, maxPositionBottom)) - break; - } - - if (curr->isInlineFlowBox()) - static_cast(curr)->adjustMaxAscentAndDescent(maxAscent, maxDescent, maxPositionTop, maxPositionBottom); - } -} - -void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositionBottom, - int& maxAscent, int& maxDescent, bool strictMode) -{ - if (isRootInlineBox()) { - // Examine our root box. - setHeight(object()->lineHeight(m_firstLine, true)); - bool isTableCell = object()->isTableCell(); - if (isTableCell) { - RenderTableCell* tableCell = static_cast(object()); - setBaseline(tableCell->RenderBlock::baselinePosition(m_firstLine, true)); - } - else - setBaseline(object()->baselinePosition(m_firstLine, true)); - if (hasTextChildren() || strictMode) { - int ascent = baseline(); - int descent = height() - ascent; - if (maxAscent < ascent) - maxAscent = ascent; - if (maxDescent < descent) - maxDescent = descent; - } - } - - for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->object()->isPositioned()) - continue; // Positioned placeholders don't affect calculations. - - curr->setHeight(curr->object()->lineHeight(m_firstLine)); - curr->setBaseline(curr->object()->baselinePosition(m_firstLine)); - curr->setYPos(curr->object()->verticalPositionHint(m_firstLine)); - if (curr->yPos() == PositionTop) { - if (maxPositionTop < curr->height()) - maxPositionTop = curr->height(); - } - else if (curr->yPos() == PositionBottom) { - if (maxPositionBottom < curr->height()) - maxPositionBottom = curr->height(); - } - else if (curr->hasTextChildren() || strictMode) { - int ascent = curr->baseline() - curr->yPos(); - int descent = curr->height() - ascent; - if (maxAscent < ascent) - maxAscent = ascent; - if (maxDescent < descent) - maxDescent = descent; - } - - if (curr->isInlineFlowBox()) - static_cast(curr)->computeLogicalBoxHeights(maxPositionTop, maxPositionBottom, maxAscent, maxDescent, strictMode); - } -} - -void InlineFlowBox::placeBoxesVertically(int y, int maxHeight, int maxAscent, bool strictMode, - int& topPosition, int& bottomPosition, int& selectionTop, int& selectionBottom) -{ - if (isRootInlineBox()) - setYPos(y + maxAscent - baseline());// Place our root box. - - for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->object()->isPositioned()) - continue; // Positioned placeholders don't affect calculations. - - // Adjust boxes to use their real box y/height and not the logical height (as dictated by - // line-height). - if (curr->isInlineFlowBox()) - static_cast(curr)->placeBoxesVertically(y, maxHeight, maxAscent, strictMode, topPosition, bottomPosition, selectionTop, selectionBottom); - - bool childAffectsTopBottomPos = true; - if (curr->yPos() == PositionTop) - curr->setYPos(y); - else if (curr->yPos() == PositionBottom) - curr->setYPos(y + maxHeight - curr->height()); - else { - if (!curr->hasTextChildren() && !strictMode) - childAffectsTopBottomPos = false; - curr->setYPos(curr->yPos() + y + maxAscent - curr->baseline()); - } - - int newY = curr->yPos(); - int newHeight = curr->height(); - int newBaseline = curr->baseline(); - int overflowTop = 0; - int overflowBottom = 0; - if (curr->isText() || curr->isInlineFlowBox()) { - const Font& font = curr->object()->font(m_firstLine); - newBaseline = font.ascent(); - newY += curr->baseline() - newBaseline; - newHeight = newBaseline + font.descent(); - for (ShadowData* shadow = curr->object()->style()->textShadow(); shadow; shadow = shadow->next) { - overflowTop = min(overflowTop, shadow->y - shadow->blur); - overflowBottom = max(overflowBottom, shadow->y + shadow->blur); - } - if (curr->isInlineFlowBox()) { - newHeight += curr->object()->borderTop() + curr->object()->paddingTop() + - curr->object()->borderBottom() + curr->object()->paddingBottom(); - newY -= curr->object()->borderTop() + curr->object()->paddingTop(); - newBaseline += curr->object()->borderTop() + curr->object()->paddingTop(); - } - } - else if (!curr->object()->isBR()) { - newY += curr->object()->marginTop(); - newHeight = curr->height() - (curr->object()->marginTop() + curr->object()->marginBottom()); - overflowTop = curr->object()->overflowTop(false); - overflowBottom = curr->object()->overflowHeight(false) - newHeight; - } - - curr->setYPos(newY); - curr->setHeight(newHeight); - curr->setBaseline(newBaseline); - - if (childAffectsTopBottomPos) { - selectionTop = min(selectionTop, newY); - selectionBottom = max(selectionBottom, newY + newHeight); - topPosition = min(topPosition, newY + overflowTop); - bottomPosition = max(bottomPosition, newY + newHeight + overflowBottom); - } - } - - if (isRootInlineBox()) { - const Font& font = object()->font(m_firstLine); - setHeight(font.ascent() + font.descent()); - setYPos(yPos() + baseline() - font.ascent()); - setBaseline(font.ascent()); - if (hasTextChildren() || strictMode) { - selectionTop = min(selectionTop, yPos()); - selectionBottom = max(selectionBottom, yPos() + height()); - } - } -} - -void InlineFlowBox::shrinkBoxesWithNoTextChildren(int topPos, int bottomPos) -{ - // First shrink our kids. - for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->object()->isPositioned()) - continue; // Positioned placeholders don't affect calculations. - - if (curr->isInlineFlowBox()) - static_cast(curr)->shrinkBoxesWithNoTextChildren(topPos, bottomPos); - } - - // See if we have text children. If not, then we need to shrink ourselves to fit on the line. - if (!hasTextChildren()) { - if (yPos() < topPos) - setYPos(topPos); - if (yPos() + height() > bottomPos) - setHeight(bottomPos - yPos()); - if (baseline() > height()) - setBaseline(height()); - } -} - -bool InlineFlowBox::nodeAtPoint(RenderObject::NodeInfo& i, int x, int y, int tx, int ty) -{ - // Check children first. - for (InlineBox* curr = lastChild(); curr; curr = curr->prevOnLine()) { - if (!curr->object()->layer() && curr->nodeAtPoint(i, x, y, tx, ty)) { - object()->setInnerNode(i); - return true; - } - } - - // Now check ourselves. - IntRect rect(tx + m_x, ty + m_y, m_width, m_height); - if (object()->style()->visibility() == VISIBLE && rect.contains(x, y)) { - object()->setInnerNode(i); - return true; - } - - return false; -} - -void InlineFlowBox::paint(RenderObject::PaintInfo& i, int tx, int ty) -{ - int xPos = tx + m_x - object()->maximalOutlineSize(i.phase); - int w = width() + 2 * object()->maximalOutlineSize(i.phase); - bool intersectsDamageRect = xPos < i.r.right() && xPos + w > i.r.x(); - - if (intersectsDamageRect && i.phase != PaintPhaseChildOutlines) { - if (i.phase == PaintPhaseOutline || i.phase == PaintPhaseSelfOutline) { - // Add ourselves to the paint info struct's list of inlines that need to paint their - // outlines. - if (object()->style()->visibility() == VISIBLE && object()->style()->outlineWidth() > 0 && - !object()->isInlineContinuation() && !isRootInlineBox()) { - i.outlineObjects->add(flowObject()); - } - } - else { - // 1. Paint our background and border. - paintBackgroundAndBorder(i, tx, ty); - - // 2. Paint our underline and overline. - paintDecorations(i, tx, ty, false); - } - } - - PaintPhase paintPhase = i.phase == PaintPhaseChildOutlines ? PaintPhaseOutline : i.phase; - RenderObject::PaintInfo childInfo(i); - childInfo.phase = paintPhase; - - // 3. Paint our children. - if (paintPhase != PaintPhaseSelfOutline) { - for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (!curr->object()->layer()) - curr->paint(childInfo, tx, ty); - } - } - - // 4. Paint our strike-through - if (intersectsDamageRect && (i.phase == PaintPhaseForeground || i.phase == PaintPhaseSelection)) - paintDecorations(i, tx, ty, true); -} - -void InlineFlowBox::paintBackgrounds(GraphicsContext* p, const Color& c, const BackgroundLayer* bgLayer, - int my, int mh, int _tx, int _ty, int w, int h) -{ - if (!bgLayer) - return; - paintBackgrounds(p, c, bgLayer->next(), my, mh, _tx, _ty, w, h); - paintBackground(p, c, bgLayer, my, mh, _tx, _ty, w, h); -} - -void InlineFlowBox::paintBackground(GraphicsContext* p, const Color& c, const BackgroundLayer* bgLayer, - int my, int mh, int _tx, int _ty, int w, int h) -{ - CachedImage* bg = bgLayer->backgroundImage(); - bool hasBackgroundImage = bg && bg->canRender(); - if (!hasBackgroundImage || (!prevLineBox() && !nextLineBox()) || !parent()) - object()->paintBackgroundExtended(p, c, bgLayer, my, mh, _tx, _ty, w, h, - borderLeft(), borderRight(), paddingLeft(), paddingRight()); - else { - // We have a background image that spans multiple lines. - // We need to adjust _tx and _ty by the width of all previous lines. - // Think of background painting on inlines as though you had one long line, a single continuous - // strip. Even though that strip has been broken up across multiple lines, you still paint it - // as though you had one single line. This means each line has to pick up the background where - // the previous line left off. - // FIXME: What the heck do we do with RTL here? The math we're using is obviously not right, - // but it isn't even clear how this should work at all. - int xOffsetOnLine = 0; - for (InlineRunBox* curr = prevLineBox(); curr; curr = curr->prevLineBox()) - xOffsetOnLine += curr->width(); - int startX = _tx - xOffsetOnLine; - int totalWidth = xOffsetOnLine; - for (InlineRunBox* curr = this; curr; curr = curr->nextLineBox()) - totalWidth += curr->width(); - p->save(); - p->addClip(IntRect(_tx, _ty, width(), height())); - object()->paintBackgroundExtended(p, c, bgLayer, my, mh, startX, _ty, - totalWidth, h, borderLeft(), borderRight(), paddingLeft(), paddingRight()); - p->restore(); - } -} - -void InlineFlowBox::paintBackgroundAndBorder(RenderObject::PaintInfo& i, int _tx, int _ty) -{ - if (!object()->shouldPaintWithinRoot(i) || object()->style()->visibility() != VISIBLE || - i.phase != PaintPhaseForeground) - return; - - // Move x/y to our coordinates. - _tx += m_x; - _ty += m_y; - - int w = width(); - int h = height(); - - int my = max(_ty, i.r.y()); - int mh; - if (_ty < i.r.y()) - mh = max(0, h - (i.r.y() - _ty)); - else - mh = min(i.r.height(), h); - - GraphicsContext* p = i.p; - - // You can use p::first-line to specify a background. If so, the root line boxes for - // a line may actually have to paint a background. - RenderStyle* styleToUse = object()->style(m_firstLine); - if ((!parent() && m_firstLine && styleToUse != object()->style()) || - (parent() && object()->shouldPaintBackgroundOrBorder())) { - Color c = styleToUse->backgroundColor(); - paintBackgrounds(p, c, styleToUse->backgroundLayers(), my, mh, _tx, _ty, w, h); - - // :first-line cannot be used to put borders on a line. Always paint borders with our - // non-first-line style. - if (parent() && object()->style()->hasBorder()) { - CachedImage* borderImage = object()->style()->borderImage().image(); - bool hasBorderImage = borderImage && borderImage->canRender(); - if (hasBorderImage && !borderImage->isLoaded()) - return; // Don't paint anything while we wait for the image to load. - - // The simple case is where we either have no border image or we are the only box for this object. In those - // cases only a single call to draw is required. - if (!hasBorderImage || (!prevLineBox() && !nextLineBox())) - object()->paintBorder(p, _tx, _ty, w, h, object()->style(), includeLeftEdge(), includeRightEdge()); - else { - // We have a border image that spans multiple lines. - // We need to adjust _tx and _ty by the width of all previous lines. - // Think of border image painting on inlines as though you had one long line, a single continuous - // strip. Even though that strip has been broken up across multiple lines, you still paint it - // as though you had one single line. This means each line has to pick up the image where - // the previous line left off. - // FIXME: What the heck do we do with RTL here? The math we're using is obviously not right, - // but it isn't even clear how this should work at all. - int xOffsetOnLine = 0; - for (InlineRunBox* curr = prevLineBox(); curr; curr = curr->prevLineBox()) - xOffsetOnLine += curr->width(); - int startX = _tx - xOffsetOnLine; - int totalWidth = xOffsetOnLine; - for (InlineRunBox* curr = this; curr; curr = curr->nextLineBox()) - totalWidth += curr->width(); - p->save(); - p->addClip(IntRect(_tx, _ty, width(), height())); - object()->paintBorder(p, startX, _ty, totalWidth, h, object()->style()); - p->restore(); - } - } - } -} - -static bool shouldDrawDecoration(RenderObject* obj) -{ - for (RenderObject* curr = obj->firstChild(); curr; curr = curr->nextSibling()) { - if (curr->isInlineFlow()) - return true; - if (curr->isText() && !curr->isBR()) { - if (!curr->style()->collapseWhiteSpace()) - return true; - Node* currElement = curr->element(); - if (!currElement) - return true; - if (!currElement->isTextNode()) - return true; - if (!static_cast(currElement)->containsOnlyWhitespace()) - return true; - } - } - return false; -} - -void InlineFlowBox::paintDecorations(RenderObject::PaintInfo& i, int _tx, int _ty, bool paintedChildren) -{ - // Paint text decorations like underlines/overlines. We only do this if we aren't in quirks mode (i.e., in - // almost-strict mode or strict mode). - if (object()->style()->htmlHacks() || !object()->shouldPaintWithinRoot(i) || - object()->style()->visibility() != VISIBLE) - return; - - GraphicsContext* p = i.p; - _tx += m_x; - _ty += m_y; - RenderStyle* styleToUse = object()->style(m_firstLine); - int deco = parent() ? styleToUse->textDecoration() : styleToUse->textDecorationsInEffect(); - if (deco != TDNONE && - ((!paintedChildren && ((deco & UNDERLINE) || (deco & OVERLINE))) || (paintedChildren && (deco & LINE_THROUGH))) && - shouldDrawDecoration(object())) { - int x = m_x + borderLeft() + paddingLeft(); - int w = m_width - (borderLeft() + paddingLeft() + borderRight() + paddingRight()); - RootInlineBox* rootLine = root(); - if (rootLine->ellipsisBox()) { - int ellipsisX = rootLine->ellipsisBox()->xPos(); - int ellipsisWidth = rootLine->ellipsisBox()->width(); - - // FIXME: Will need to work with RTL - if (rootLine == this) { - if (x + w >= ellipsisX + ellipsisWidth) - w -= (x + w - ellipsisX - ellipsisWidth); - } - else { - if (x >= ellipsisX) - return; - if (x + w >= ellipsisX) - w -= (x + w - ellipsisX); - } - } - - // Set up the appropriate text-shadow effect for the decoration. - // FIXME: Support multiple shadow effects. Need more from the CG API before we can do this. - bool setShadow = false; - if (styleToUse->textShadow()) { - p->setShadow(IntSize(styleToUse->textShadow()->x, styleToUse->textShadow()->y), - styleToUse->textShadow()->blur, styleToUse->textShadow()->color); - setShadow = true; - } - - // We must have child boxes and have decorations defined. - _tx += borderLeft() + paddingLeft(); - - Color underline, overline, linethrough; - underline = overline = linethrough = styleToUse->color(); - if (!parent()) - object()->getTextDecorationColors(deco, underline, overline, linethrough); - - if (styleToUse->font() != p->font()) - p->setFont(styleToUse->font()); - - bool isPrinting = object()->document()->printing(); - if (deco & UNDERLINE && !paintedChildren) { - p->setPen(underline); - p->drawLineForText(IntPoint(_tx, _ty), m_baseline, w, isPrinting); - } - if (deco & OVERLINE && !paintedChildren) { - p->setPen(overline); - p->drawLineForText(IntPoint(_tx, _ty), 0, w, isPrinting); - } - if (deco & LINE_THROUGH && paintedChildren) { - p->setPen(linethrough); - p->drawLineForText(IntPoint(_tx, _ty), 2*m_baseline/3, w, isPrinting); - } - - if (setShadow) - p->clearShadow(); - } -} - -InlineBox* InlineFlowBox::firstLeafChild() -{ - return firstLeafChildAfterBox(); -} - -InlineBox* InlineFlowBox::lastLeafChild() -{ - return lastLeafChildBeforeBox(); -} - -InlineBox* InlineFlowBox::firstLeafChildAfterBox(InlineBox* start) -{ - InlineBox* leaf = 0; - for (InlineBox* box = start ? start->nextOnLine() : firstChild(); box && !leaf; box = box->nextOnLine()) - leaf = box->firstLeafChild(); - if (start && !leaf && parent()) - return parent()->firstLeafChildAfterBox(this); - return leaf; -} - -InlineBox* InlineFlowBox::lastLeafChildBeforeBox(InlineBox* start) -{ - InlineBox* leaf = 0; - for (InlineBox* box = start ? start->prevOnLine() : lastChild(); box && !leaf; box = box->prevOnLine()) - leaf = box->lastLeafChild(); - if (start && !leaf && parent()) - return parent()->lastLeafChildBeforeBox(this); - return leaf; -} - -RenderObject::SelectionState InlineFlowBox::selectionState() -{ - return RenderObject::SelectionNone; -} - -bool InlineFlowBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) -{ - for (InlineBox *box = firstChild(); box; box = box->nextOnLine()) { - if (!box->canAccommodateEllipsis(ltr, blockEdge, ellipsisWidth)) - return false; - } - return true; -} - -int InlineFlowBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox) -{ - int result = -1; - for (InlineBox *box = firstChild(); box; box = box->nextOnLine()) { - int currResult = box->placeEllipsisBox(ltr, blockEdge, ellipsisWidth, foundBox); - if (currResult != -1 && result == -1) - result = currResult; - } - return result; -} - -void InlineFlowBox::clearTruncation() -{ - for (InlineBox *box = firstChild(); box; box = box->nextOnLine()) - box->clearTruncation(); -} - -void EllipsisBox::paint(RenderObject::PaintInfo& i, int _tx, int _ty) -{ - GraphicsContext* p = i.p; - RenderStyle* _style = m_firstLine ? m_object->firstLineStyle() : m_object->style(); - if (_style->font() != p->font()) - p->setFont(_style->font()); - - Color textColor = _style->color(); - if (textColor != p->pen().color()) - p->setPen(textColor); - bool setShadow = false; - if (_style->textShadow()) { - p->setShadow(IntSize(_style->textShadow()->x, _style->textShadow()->y), - _style->textShadow()->blur, _style->textShadow()->color); - setShadow = true; - } - - const String& str = m_str; - p->drawText(TextRun(str.impl()), IntPoint(m_x + _tx, m_y + _ty + m_baseline), TextStyle(0, 0, 0, false, _style->visuallyOrdered())); - - if (setShadow) - p->clearShadow(); - - if (m_markupBox) { - // Paint the markup box - _tx += m_x + m_width - m_markupBox->xPos(); - _ty += m_y + m_baseline - (m_markupBox->yPos() + m_markupBox->baseline()); - m_markupBox->paint(i, _tx, _ty); - } -} - -bool EllipsisBox::nodeAtPoint(RenderObject::NodeInfo& info, int x, int y, int tx, int ty) -{ - tx += m_x; - ty += m_y; - - // Hit test the markup box. - if (m_markupBox) { - int mtx = tx + m_width - m_markupBox->xPos(); - int mty = ty + m_baseline - (m_markupBox->yPos() + m_markupBox->baseline()); - if (m_markupBox->nodeAtPoint(info, x, y, mtx, mty)) { - object()->setInnerNode(info); - return true; - } - } - - if (object()->style()->visibility() == VISIBLE && IntRect(tx, ty, m_width, m_height).contains(x, y)) { - object()->setInnerNode(info); - return true; - } - - return false; -} - -void RootInlineBox::destroy(RenderArena* arena) -{ - detachEllipsisBox(arena); - InlineFlowBox::destroy(arena); -} - -void RootInlineBox::detachEllipsisBox(RenderArena* arena) -{ - if (m_ellipsisBox) { - m_ellipsisBox->destroy(arena); - m_ellipsisBox = 0; - } -} - -void RootInlineBox::clearTruncation() -{ - if (m_ellipsisBox) { - detachEllipsisBox(m_object->renderArena()); - InlineFlowBox::clearTruncation(); - } -} - -bool RootInlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int lineBoxEdge, int ellipsisWidth) -{ - // First sanity-check the unoverflowed width of the whole line to see if there is sufficient room. - int delta = ltr ? lineBoxEdge - blockEdge : blockEdge - lineBoxEdge; - if (width() - delta < ellipsisWidth) - return false; - - // Next iterate over all the line boxes on the line. If we find a replaced element that intersects - // then we refuse to accommodate the ellipsis. Otherwise we're ok. - return InlineFlowBox::canAccommodateEllipsis(ltr, blockEdge, ellipsisWidth); -} - -void RootInlineBox::placeEllipsis(const AtomicString& ellipsisStr, bool ltr, int blockEdge, int ellipsisWidth, - InlineBox* markupBox) -{ - // Create an ellipsis box. - m_ellipsisBox = new (m_object->renderArena()) EllipsisBox(m_object, ellipsisStr, this, - ellipsisWidth - (markupBox ? markupBox->width() : 0), - yPos(), height(), baseline(), !prevRootBox(), - markupBox); - - if (ltr && (xPos() + width() + ellipsisWidth) <= blockEdge) { - m_ellipsisBox->m_x = xPos() + width(); - return; - } - - // Now attempt to find the nearest glyph horizontally and place just to the right (or left in RTL) - // of that glyph. Mark all of the objects that intersect the ellipsis box as not painting (as being - // truncated). - bool foundBox = false; - m_ellipsisBox->m_x = placeEllipsisBox(ltr, blockEdge, ellipsisWidth, foundBox); -} - -int RootInlineBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox) -{ - int result = InlineFlowBox::placeEllipsisBox(ltr, blockEdge, ellipsisWidth, foundBox); - if (result == -1) - result = ltr ? blockEdge - ellipsisWidth : blockEdge; - return result; -} - -void RootInlineBox::paintEllipsisBox(RenderObject::PaintInfo& i, int _tx, int _ty) const -{ - if (m_ellipsisBox && object()->shouldPaintWithinRoot(i) && object()->style()->visibility() == VISIBLE && - i.phase == PaintPhaseForeground) - m_ellipsisBox->paint(i, _tx, _ty); -} - -void RootInlineBox::paint(RenderObject::PaintInfo& i, int tx, int ty) -{ - InlineFlowBox::paint(i, tx, ty); - paintEllipsisBox(i, tx, ty); -} - -bool RootInlineBox::nodeAtPoint(RenderObject::NodeInfo& i, int x, int y, int tx, int ty) -{ - if (m_ellipsisBox && object()->style()->visibility() == VISIBLE) { - if (m_ellipsisBox->nodeAtPoint(i, x, y, tx, ty)) { - object()->setInnerNode(i); - return true; - } - } - return InlineFlowBox::nodeAtPoint(i, x, y, tx, ty); -} - -void RootInlineBox::adjustPosition(int dx, int dy) -{ - InlineFlowBox::adjustPosition(dx, dy); - m_topOverflow += dy; - m_bottomOverflow += dy; - m_blockHeight += dy; - m_selectionTop += dy; - m_selectionBottom += dy; -} - -void RootInlineBox::childRemoved(InlineBox* box) -{ - if (box->object() == m_lineBreakObj) - setLineBreakInfo(0, 0, 0, 0); - - RootInlineBox* prev = prevRootBox(); - if (prev && prev->lineBreakObj() == box->object()) { - prev->setLineBreakInfo(0, 0, 0, 0); - prev->markDirty(); - } -} - -GapRects RootInlineBox::fillLineSelectionGap(int selTop, int selHeight, RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty, - const RenderObject::PaintInfo* i) -{ - GapRects result; - RenderObject::SelectionState lineState = selectionState(); - - bool leftGap, rightGap; - block()->getHorizontalSelectionGapInfo(lineState, leftGap, rightGap); - - InlineBox* firstBox = firstSelectedBox(); - InlineBox* lastBox = lastSelectedBox(); - if (leftGap) - result.uniteLeft(block()->fillLeftSelectionGap(firstBox->parent()->object(), - firstBox->xPos(), selTop, selHeight, - rootBlock, blockX, blockY, tx, ty, i)); - if (rightGap) - result.uniteRight(block()->fillRightSelectionGap(lastBox->parent()->object(), - lastBox->xPos() + lastBox->width(), selTop, selHeight, - rootBlock, blockX, blockY, tx, ty, i)); - - if (firstBox && firstBox != lastBox) { - // Now fill in any gaps on the line that occurred between two selected elements. - int lastX = firstBox->xPos() + firstBox->width(); - for (InlineBox* box = firstBox->nextLeafChild(); box; box = box->nextLeafChild()) { - if (box->selectionState() != RenderObject::SelectionNone) { - result.uniteCenter(block()->fillHorizontalSelectionGap(box->parent()->object(), - lastX + tx, selTop + ty, - box->xPos() - lastX, selHeight, i)); - lastX = box->xPos() + box->width(); - } - if (box == lastBox) - break; - } - } - - return result; -} - -void RootInlineBox::setHasSelectedChildren(bool b) -{ - if (m_hasSelectedChildren == b) - return; - m_hasSelectedChildren = b; -} - -RenderObject::SelectionState RootInlineBox::selectionState() -{ - // Walk over all of the selected boxes. - RenderObject::SelectionState state = RenderObject::SelectionNone; - for (InlineBox* box = firstLeafChild(); box; box = box->nextLeafChild()) { - RenderObject::SelectionState boxState = box->selectionState(); - if ((boxState == RenderObject::SelectionStart && state == RenderObject::SelectionEnd) || - (boxState == RenderObject::SelectionEnd && state == RenderObject::SelectionStart)) - state = RenderObject::SelectionBoth; - else if (state == RenderObject::SelectionNone || - ((boxState == RenderObject::SelectionStart || boxState == RenderObject::SelectionEnd) && - (state == RenderObject::SelectionNone || state == RenderObject::SelectionInside))) - state = boxState; - if (state == RenderObject::SelectionBoth) - break; - } - - return state; -} - -InlineBox* RootInlineBox::firstSelectedBox() -{ - for (InlineBox* box = firstLeafChild(); box; box = box->nextLeafChild()) - if (box->selectionState() != RenderObject::SelectionNone) - return box; - return 0; -} - -InlineBox* RootInlineBox::lastSelectedBox() -{ - for (InlineBox* box = lastLeafChild(); box; box = box->prevLeafChild()) - if (box->selectionState() != RenderObject::SelectionNone) - return box; - return 0; -} - -int RootInlineBox::selectionTop() -{ - if (!prevRootBox()) - return m_selectionTop; - - int prevBottom = prevRootBox()->selectionBottom(); - if (prevBottom < m_selectionTop && block()->containsFloats()) { - // This line has actually been moved further down, probably from a large line-height, but possibly because the - // line was forced to clear floats. If so, let's check the offsets, and only be willing to use the previous - // line's bottom overflow if the offsets are greater on both sides. - int prevLeft = block()->leftOffset(prevBottom); - int prevRight = block()->rightOffset(prevBottom); - int newLeft = block()->leftOffset(m_selectionTop); - int newRight = block()->rightOffset(m_selectionTop); - if (prevLeft > newLeft || prevRight < newRight) - return m_selectionTop; - } - - return prevBottom; -} - -RenderBlock* RootInlineBox::block() const -{ - return static_cast(m_object); -} - -InlineBox* RootInlineBox::closestLeafChildForXPos(int _x, int _tx) -{ - InlineBox *firstLeaf = firstLeafChildAfterBox(); - InlineBox *lastLeaf = lastLeafChildBeforeBox(); - if (firstLeaf == lastLeaf) - return firstLeaf; - - // Avoid returning a list marker when possible. - if (_x <= _tx + firstLeaf->m_x && !firstLeaf->object()->isListMarker()) - // The x coordinate is less or equal to left edge of the firstLeaf. - // Return it. - return firstLeaf; - - if (_x >= _tx + lastLeaf->m_x + lastLeaf->m_width && !lastLeaf->object()->isListMarker()) - // The x coordinate is greater or equal to right edge of the lastLeaf. - // Return it. - return lastLeaf; - - for (InlineBox *leaf = firstLeaf; leaf && leaf != lastLeaf; leaf = leaf->nextLeafChild()) { - if (!leaf->object()->isListMarker()) { - int leafX = _tx + leaf->m_x; - if (_x < leafX + leaf->m_width) - // The x coordinate is less than the right edge of the box. - // Return it. - return leaf; - } - } - - return lastLeaf; -} - -void RootInlineBox::setLineBreakInfo(RenderObject* obj, unsigned breakPos, BidiStatus* status, BidiContext* context) -{ - m_lineBreakObj = obj; - m_lineBreakPos = breakPos; - m_lineBreakContext = context; - if (status) - m_lineBreakBidiStatus = *status; -} - -} - -#ifndef NDEBUG - -void showTree(const WebCore::InlineBox* b) -{ - if (b) - b->showTreeForThis(); -} - -#endif -- 2.36.0