diff options
Diffstat (limited to 'src/3rdparty/webkit/WebCore/rendering/RenderFlow.cpp')
-rw-r--r-- | src/3rdparty/webkit/WebCore/rendering/RenderFlow.cpp | 883 |
1 files changed, 0 insertions, 883 deletions
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderFlow.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderFlow.cpp deleted file mode 100644 index 86a92f3..0000000 --- a/src/3rdparty/webkit/WebCore/rendering/RenderFlow.cpp +++ /dev/null @@ -1,883 +0,0 @@ -/* - * Copyright (C) 1999 Lars Knoll (knoll@kde.org) - * (C) 1999 Antti Koivisto (koivisto@kde.org) - * 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 "RenderFlow.h" - -#include "Document.h" -#include "GraphicsContext.h" -#include "HTMLNames.h" -#include "InlineTextBox.h" -#include "RenderArena.h" -#include "RenderInline.h" -#include "RenderLayer.h" -#include "RenderView.h" - -using namespace std; - -namespace WebCore { - -using namespace HTMLNames; - -#ifndef NDEBUG - -RenderFlow::~RenderFlow() -{ - ASSERT(!m_firstLineBox); - ASSERT(!m_lastLineBox); -} - -#endif - -RenderFlow* RenderFlow::createAnonymousFlow(Document* doc, PassRefPtr<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) -{ - if (beforeChild && (beforeChild->parent()->isTableRow() || beforeChild->parent()->isTableSection() || beforeChild->parent()->isTable())) { - RenderObject* anonymousTablePart = beforeChild->parent(); - ASSERT(anonymousTablePart->isAnonymous()); - while (!anonymousTablePart->isTable()) { - anonymousTablePart = anonymousTablePart->parent(); - ASSERT(anonymousTablePart->isAnonymous()); - } - return anonymousTablePart->addChild(newChild, beforeChild); - } - - RenderFlow* flow = continuationBefore(beforeChild); - ASSERT(!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) -{ - if (continuation()) - return addChildWithContinuation(newChild, beforeChild); - return addChildToFlow(newChild, beforeChild); -} - -void RenderFlow::extractLineBox(InlineFlowBox* box) -{ - checkConsistency(); - - 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(); - - checkConsistency(); -} - -void RenderFlow::attachLineBox(InlineFlowBox* box) -{ - checkConsistency(); - - 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; - - checkConsistency(); -} - -void RenderFlow::removeLineBox(InlineFlowBox* box) -{ - checkConsistency(); - - 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()); - - checkConsistency(); -} - -void RenderFlow::deleteLineBoxes() -{ - if (m_firstLineBox) { - RenderArena* arena = renderArena(); - InlineRunBox* next; - for (InlineRunBox* curr = m_firstLineBox; curr; curr = next) { - next = curr->nextLineBox(); - curr->destroy(arena); - } - m_firstLineBox = 0; - m_lastLineBox = 0; - } -} - -void RenderFlow::destroy() -{ - // Detach our continuation first. - if (m_continuation) - m_continuation->destroy(); - m_continuation = 0; - - // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will - // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise. - RenderContainer::destroyLeftoverChildren(); - - if (!documentBeingDestroyed()) { - if (m_firstLineBox) { - // We can't wait for RenderContainer::destroy to clear the selection, - // because by then we will have nuked the line boxes. - // FIXME: The SelectionController should be responsible for this when it - // is notified of DOM mutations. - if (isSelectionBorder()) - view()->clearSelection(); - - // If line boxes are contained inside a root, that means we're an inline. - // In that case, we need to remove all the line boxes so that the parent - // lines aren't pointing to deleted children. If the first line box does - // not have a parent that means they are either already disconnected or - // root lines that can just be destroyed without disconnecting. - if (m_firstLineBox->parent()) { - for (InlineRunBox* box = m_firstLineBox; box; box = box->nextLineBox()) - box->remove(); - } - - // If we are an anonymous block, then our line boxes might have children - // that will outlast this block. In the non-anonymous block case those - // children will be destroyed by the time we return from this function. - if (isAnonymousBlock()) { - for (InlineFlowBox* box = m_firstLineBox; box; box = box->nextFlowBox()) { - while (InlineBox* childBox = box->firstChild()) - childBox->remove(); - } - } - } else if (isInline() && parent()) - parent()->dirtyLinesFromChangedChild(this); - } - - deleteLineBoxes(); - - RenderContainer::destroy(); -} - -void RenderFlow::dirtyLinesFromChangedChild(RenderObject* child) -{ - if (!parent() || (selfNeedsLayout() && !isInlineFlow()) || isTable()) - return; - - // If we have no first line box, then just bail early. - if (!firstLineBox()) { - // For an empty inline, go ahead and propagate the check up to our parent, unless the parent - // is already dirty. - if (isInline() && !parent()->selfNeedsLayout()) - parent()->dirtyLinesFromChangedChild(this); - return; - } - - // 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; - RenderObject* curr = 0; - for (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 = firstLineBox()->root(); - - // If we found a line box, then dirty it. - if (box) { - RootInlineBox* adjacentBox; - box->markDirty(); - - // dirty the adjacent lines that might be affected - // NOTE: we dirty the previous line because RootInlineBox objects cache - // the address of the first object on the next line after a BR, which we may be - // invalidating here. For more info, see how RenderBlock::layoutInlineChildren - // calls setLineBreakInfo with the result of findNextLineBreak. findNextLineBreak, - // despite the name, actually returns the first RenderObject after the BR. - // <rdar://problem/3849947> "Typing after pasting line does not appear until after window resize." - adjacentBox = box->prevRootBox(); - if (adjacentBox) - adjacentBox->markDirty(); - if (child->isBR() || (curr && curr->isBR())) { - adjacentBox = box->nextRootBox(); - if (adjacentBox) - adjacentBox->markDirty(); - } - } -} - -int RenderFlow::lineHeight(bool firstLine, bool /*isRootLineBox*/) const -{ - if (firstLine) { - RenderStyle* s = style(firstLine); - Length lh = s->lineHeight(); - if (lh.isNegative()) { - if (s == style()) { - if (m_lineHeight == -1) - m_lineHeight = RenderObject::lineHeight(false); - return m_lineHeight; - } - return s->font().lineSpacing(); - } - if (lh.isPercent()) - return lh.calcMinValue(s->fontSize()); - return lh.value(); - } - - if (m_lineHeight == -1) - m_lineHeight = RenderObject::lineHeight(false); - return m_lineHeight; -} - -void RenderFlow::dirtyLineBoxes(bool fullLayout, bool isRootLineBox) -{ - if (!isRootLineBox && isReplaced()) - return RenderContainer::dirtyLineBoxes(fullLayout, isRootLineBox); - - if (fullLayout) - deleteLineBoxes(); - else { - for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) - curr->dirtyLineBoxes(); - } -} - -InlineBox* RenderFlow::createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool /*isOnlyRun*/) -{ - checkConsistency(); - - if (!isRootLineBox && - (isReplaced() || makePlaceHolderBox)) // Inline tables and inline blocks - return RenderContainer::createInlineBox(false, isRootLineBox); // (or positioned element placeholders). - - InlineFlowBox* flowBox = 0; - if (isInlineFlow()) - flowBox = new (renderArena()) InlineFlowBox(this); - else - flowBox = new (renderArena()) RootInlineBox(this); - - if (!m_firstLineBox) - m_firstLineBox = m_lastLineBox = flowBox; - else { - m_lastLineBox->setNextLineBox(flowBox); - flowBox->setPreviousLineBox(m_lastLineBox); - m_lastLineBox = flowBox; - } - - checkConsistency(); - - return flowBox; -} - -void RenderFlow::paintLines(PaintInfo& paintInfo, int tx, int ty) -{ - // Only paint during the foreground/selection phases. - if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseOutline - && paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseChildOutlines && paintInfo.phase != PaintPhaseTextClip - && paintInfo.phase != PaintPhaseMask) - return; - - bool inlineFlow = isInlineFlow(); - if (inlineFlow) - ASSERT(m_layer); // The only way a compact/run-in/inline could paint like this is if it has a layer. - - // If we have no lines then we have no work to do. - if (!firstLineBox()) - return; - - // We can check the first box and last box and avoid painting if we don't - // intersect. This is a quick short-circuit that we can take to avoid walking any lines. - // FIXME: This check is flawed in the following extremely obscure way: - // if some line in the middle has a huge overflow, it might actually extend below the last line. - int yPos = firstLineBox()->root()->topOverflow() - maximalOutlineSize(paintInfo.phase); - int h = maximalOutlineSize(paintInfo.phase) + lastLineBox()->root()->bottomOverflow() - yPos; - yPos += ty; - if (yPos >= paintInfo.rect.bottom() || yPos + h <= paintInfo.rect.y()) - return; - - PaintInfo info(paintInfo); - RenderFlowSequencedSet outlineObjects; - info.outlineObjects = &outlineObjects; - - // See if our root lines intersect with the dirty rect. If so, then we paint - // them. Note that boxes can easily overlap, so we can't make any assumptions - // based off positions of our first line box or our last line box. - RenderView* v = view(); - bool usePrintRect = !v->printRect().isEmpty(); - for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextFlowBox()) { - if (usePrintRect) { - // FIXME: This is a feeble effort to avoid splitting a line across two pages. - // It is utterly inadequate, and this should not be done at paint time at all. - // The whole way objects break across pages needs to be redone. - // Try to avoid splitting a line vertically, but only if it's less than the height - // of the entire page. - if (curr->root()->bottomOverflow() - curr->root()->topOverflow() <= v->printRect().height()) { - if (ty + curr->root()->bottomOverflow() > v->printRect().bottom()) { - if (ty + curr->root()->topOverflow() < v->truncatedAt()) - v->setBestTruncatedAt(ty + curr->root()->topOverflow(), this); - // If we were able to truncate, don't paint. - if (ty + curr->root()->topOverflow() >= v->truncatedAt()) - break; - } - } - } - - int top = min(curr->root()->topOverflow(), curr->root()->selectionTop()) - maximalOutlineSize(info.phase); - int bottom = curr->root()->bottomOverflow() + maximalOutlineSize(info.phase); - h = bottom - top; - yPos = ty + top; - if (yPos < info.rect.bottom() && yPos + h > info.rect.y()) - curr->paint(info, tx, ty); - } - - if (info.phase == PaintPhaseOutline || info.phase == PaintPhaseSelfOutline || info.phase == PaintPhaseChildOutlines) { - RenderFlowSequencedSet::iterator end = info.outlineObjects->end(); - for (RenderFlowSequencedSet::iterator it = info.outlineObjects->begin(); it != end; ++it) { - RenderFlow* flow = *it; - flow->paintOutline(info.context, tx, ty); - } - info.outlineObjects->clear(); - } -} - -bool RenderFlow::hitTestLines(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction) -{ - if (hitTestAction != HitTestForeground) - return false; - - bool inlineFlow = isInlineFlow(); - if (inlineFlow) - ASSERT(m_layer); // The only way a compact/run-in/inline could paint like this is if it has a layer. - - // If we have no lines then we have no work to do. - if (!firstLineBox()) - return false; - - // We can check the first box and last box and avoid hit testing if we don't - // contain the point. This is a quick short-circuit that we can take to avoid walking any lines. - // FIXME: This check is flawed in the following extremely obscure way: - // if some line in the middle has a huge overflow, it might actually extend below the last line. - if ((y >= ty + lastLineBox()->root()->bottomOverflow()) || (y < ty + firstLineBox()->root()->topOverflow())) - return false; - - // See if our root lines contain the point. If so, then we hit test - // them further. Note that boxes can easily overlap, so we can't make any assumptions - // based off positions of our first line box or our last line box. - for (InlineFlowBox* curr = lastLineBox(); curr; curr = curr->prevFlowBox()) { - if (y >= ty + curr->root()->topOverflow() && y < ty + curr->root()->bottomOverflow()) { - bool inside = curr->nodeAtPoint(request, result, x, y, tx, ty); - if (inside) { - updateHitTestResult(result, IntPoint(x - tx, y - ty)); - return true; - } - } - } - - return false; -} - -IntRect RenderFlow::absoluteClippedOverflowRect() -{ - if (isInlineFlow()) { - // Only compacts and run-ins are allowed in here during layout. - ASSERT(!view() || !view()->layoutState() || isCompact() || isRunIn()); - - if (!firstLineBox() && !continuation()) - return IntRect(); - - // Find our leftmost position. - int left = 0; - int top = firstLineBox() ? firstLineBox()->yPos() : 0; - for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) { - if (curr == firstLineBox() || curr->xPos() < left) - left = curr->xPos(); - } - - // Now invalidate a rectangle. - int ow = style() ? style()->outlineSize() : 0; - if (isCompact()) - left -= m_x; - - // We need to add in the relative position offsets of any inlines (including us) up to our - // containing block. - RenderBlock* cb = containingBlock(); - for (RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isInlineFlow() && inlineFlow != cb; - inlineFlow = inlineFlow->parent()) { - if (inlineFlow->style()->position() == RelativePosition && inlineFlow->hasLayer()) - inlineFlow->layer()->relativePositionOffset(left, top); - } - - IntRect r(-ow + left, -ow + top, width() + ow * 2, height() + ow * 2); - if (cb->hasColumns()) - cb->adjustRectForColumns(r); - - if (cb->hasOverflowClip()) { - // cb->height() is inaccurate if we're in the middle of a layout of |cb|, so use the - // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint - // anyway if its size does change. - int x = r.x(); - int y = r.y(); - IntRect boxRect(0, 0, cb->layer()->width(), cb->layer()->height()); - cb->layer()->subtractScrolledContentOffset(x, y); // For overflow:auto/scroll/hidden. - IntRect repaintRect(x, y, r.width(), r.height()); - r = intersection(repaintRect, boxRect); - } - cb->computeAbsoluteRepaintRect(r); - - if (ow) { - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { - if (!curr->isText()) { - IntRect childRect = curr->getAbsoluteRepaintRectWithOutline(ow); - r.unite(childRect); - } - } - - if (continuation() && !continuation()->isInline()) { - IntRect contRect = continuation()->getAbsoluteRepaintRectWithOutline(ow); - r.unite(contRect); - } - } - - return r; - } - - return RenderContainer::absoluteClippedOverflowRect(); -} - -int RenderFlow::lowestPosition(bool includeOverflowInterior, bool includeSelf) const -{ - ASSERT(!isInlineFlow()); - if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) - return includeSelf && m_width > 0 ? overflowHeight(false) : 0; - - int bottom = includeSelf && m_width > 0 ? m_height : 0; - if (!hasColumns()) { - // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. - // For now, we have to descend into all the children, since we may have a huge abs div inside - // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to - // the abs div. - for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { - if (!c->isFloatingOrPositioned() && !c->isText() && !c->isInlineFlow()) - bottom = max(bottom, c->yPos() + c->lowestPosition(false)); - } - } - - if (includeSelf && isRelPositioned()) - bottom += relativePositionOffsetY(); - - return bottom; -} - -int RenderFlow::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const -{ - ASSERT(!isInlineFlow()); - if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) - return includeSelf && m_height > 0 ? overflowWidth(false) : 0; - - int right = includeSelf && m_height > 0 ? m_width : 0; - if (!hasColumns()) { - // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. - // For now, we have to descend into all the children, since we may have a huge abs div inside - // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to - // the abs div. - for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { - if (!c->isFloatingOrPositioned() && !c->isText() && !c->isInlineFlow()) - right = max(right, c->xPos() + c->rightmostPosition(false)); - } - } - - if (includeSelf && isRelPositioned()) - right += relativePositionOffsetX(); - - return right; -} - -int RenderFlow::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const -{ - ASSERT(!isInlineFlow()); - if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) - return includeSelf && m_height > 0 ? overflowLeft(false) : m_width; - - int left = includeSelf && m_height > 0 ? 0 : m_width; - if (!hasColumns()) { - // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. - // For now, we have to descend into all the children, since we may have a huge abs div inside - // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to - // the abs div. - for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { - if (!c->isFloatingOrPositioned() && !c->isText() && !c->isInlineFlow()) - left = min(left, c->xPos() + c->leftmostPosition(false)); - } - } - - if (includeSelf && isRelPositioned()) - left += relativePositionOffsetX(); - - return left; -} - -IntRect RenderFlow::localCaretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine) -{ - // Do the normal calculation in most cases. - if (firstChild() || style()->display() == INLINE) - return RenderContainer::localCaretRect(inlineBox, caretOffset, extraWidthToEndOfLine); - - // This is a special case: - // The element is not an inline element, and it's empty. So we have to - // calculate a fake position to indicate where objects are to be inserted. - - // FIXME: This does not take into account either :first-line or :first-letter - // However, as soon as some content is entered, the line boxes will be - // constructed and this kludge is not called any more. So only the caret size - // of an empty :first-line'd block is wrong. I think we can live with that. - RenderStyle* currentStyle = firstLineStyle(); - int height = lineHeight(true); - const int caretWidth = 1; - - enum CaretAlignment { alignLeft, alignRight, alignCenter }; - - CaretAlignment alignment = alignLeft; - - switch (currentStyle->textAlign()) { - case TAAUTO: - case JUSTIFY: - if (currentStyle->direction() == RTL) - alignment = alignRight; - break; - case LEFT: - case WEBKIT_LEFT: - break; - case CENTER: - case WEBKIT_CENTER: - alignment = alignCenter; - break; - case RIGHT: - case WEBKIT_RIGHT: - alignment = alignRight; - break; - } - - int x = borderLeft() + paddingLeft(); - int w = width(); - - switch (alignment) { - case alignLeft: - break; - case alignCenter: - x = (x + w - (borderRight() + paddingRight())) / 2; - break; - case alignRight: - x = w - (borderRight() + paddingRight()); - break; - } - - if (extraWidthToEndOfLine) { - if (isRenderBlock()) { - *extraWidthToEndOfLine = w - (x + caretWidth); - } else { - // FIXME: This code looks wrong. - // myRight and containerRight are set up, but then clobbered. - // So *extraWidthToEndOfLine will always be 0 here. - - int myRight = x + caretWidth; - // FIXME: why call localToAbsoluteForContent() twice here, too? - FloatPoint absRightPoint = localToAbsoluteForContent(FloatPoint(myRight, 0)); - - int containerRight = containingBlock()->xPos() + containingBlockWidth(); - FloatPoint absContainerPoint = localToAbsoluteForContent(FloatPoint(containerRight, 0)); - - *extraWidthToEndOfLine = absContainerPoint.x() - absRightPoint.x(); - } - } - - int y = paddingTop() + borderTop(); - - return IntRect(x, y, caretWidth, height); -} - -void RenderFlow::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty) -{ - if (isRenderBlock()) { - // Continuations should include their margins in the outline rect. - if (continuation()) { - bool nextInlineHasLineBox = continuation()->firstLineBox(); - bool prevInlineHasLineBox = static_cast<RenderFlow*>(continuation()->element()->renderer())->firstLineBox(); - int topMargin = prevInlineHasLineBox ? collapsedMarginTop() : 0; - int bottomMargin = nextInlineHasLineBox ? collapsedMarginBottom() : 0; - graphicsContext->addFocusRingRect(IntRect(tx, ty - topMargin, - width(), height() + topMargin + bottomMargin)); - } else - graphicsContext->addFocusRingRect(IntRect(tx, ty, width(), height())); - } - - if (!hasOverflowClip() && !hasControlClip()) { - for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) - graphicsContext->addFocusRingRect(IntRect(tx + curr->xPos(), ty + curr->yPos(), curr->width(), curr->height())); - - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) - if (!curr->isText() && !curr->isListMarker()) { - FloatPoint pos; - // FIXME: This doesn't work correctly with transforms. - if (curr->layer()) - pos = curr->localToAbsolute(); - else - pos = FloatPoint(tx + curr->xPos(), ty + curr->yPos()); - curr->addFocusRingRects(graphicsContext, pos.x(), pos.y()); - } - } - - if (continuation()) { - if (isInline()) - continuation()->addFocusRingRects(graphicsContext, - tx - containingBlock()->xPos() + continuation()->xPos(), - ty - containingBlock()->yPos() + continuation()->yPos()); - else - continuation()->addFocusRingRects(graphicsContext, - tx - xPos() + continuation()->containingBlock()->xPos(), - ty - yPos() + continuation()->containingBlock()->yPos()); - } -} - -void RenderFlow::paintOutline(GraphicsContext* graphicsContext, int tx, int ty) -{ - if (!hasOutline()) - return; - - if (style()->outlineStyleIsAuto() || hasOutlineAnnotation()) { - int ow = style()->outlineWidth(); - Color oc = style()->outlineColor(); - if (!oc.isValid()) - oc = style()->color(); - - graphicsContext->initFocusRing(ow, style()->outlineOffset()); - addFocusRingRects(graphicsContext, tx, ty); - if (style()->outlineStyleIsAuto()) - graphicsContext->drawFocusRing(oc); - else - addPDFURLRect(graphicsContext, graphicsContext->focusRingBoundingRect()); - graphicsContext->clearFocusRing(); - } - - if (style()->outlineStyleIsAuto() || style()->outlineStyle() == BNONE) - return; - - Vector<IntRect> rects; - - rects.append(IntRect()); - for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) - rects.append(IntRect(curr->xPos(), curr->yPos(), curr->width(), curr->height())); - - rects.append(IntRect()); - - for (unsigned i = 1; i < rects.size() - 1; i++) - paintOutlineForLine(graphicsContext, tx, ty, rects.at(i - 1), rects.at(i), rects.at(i + 1)); -} - -void RenderFlow::paintOutlineForLine(GraphicsContext* graphicsContext, int tx, int ty, - const IntRect& lastline, const IntRect& thisline, const IntRect& nextline) -{ - int ow = style()->outlineWidth(); - EBorderStyle os = style()->outlineStyle(); - Color oc = style()->outlineColor(); - if (!oc.isValid()) - oc = style()->color(); - - int offset = style()->outlineOffset(); - - int t = ty + thisline.y() - offset; - int l = tx + thisline.x() - offset; - int b = ty + thisline.bottom() + offset; - int r = tx + thisline.right() + offset; - - // left edge - drawBorder(graphicsContext, - l - ow, - t - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.right() - 1) <= thisline.x() ? ow : 0), - l, - b + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.right() - 1) <= thisline.x() ? ow : 0), - BSLeft, - oc, style()->color(), os, - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.right() - 1) <= thisline.x() ? ow : -ow), - (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.right() - 1) <= thisline.x() ? ow : -ow)); - - // right edge - drawBorder(graphicsContext, - r, - t - (lastline.isEmpty() || lastline.right() < thisline.right() || (thisline.right() - 1) <= lastline.x() ? ow : 0), - r + ow, - b + (nextline.isEmpty() || nextline.right() <= thisline.right() || (thisline.right() - 1) <= nextline.x() ? ow : 0), - BSRight, - oc, style()->color(), os, - (lastline.isEmpty() || lastline.right() < thisline.right() || (thisline.right() - 1) <= lastline.x() ? ow : -ow), - (nextline.isEmpty() || nextline.right() <= thisline.right() || (thisline.right() - 1) <= nextline.x() ? ow : -ow)); - // upper edge - if (thisline.x() < lastline.x()) - drawBorder(graphicsContext, - l - ow, - t - ow, - min(r+ow, (lastline.isEmpty() ? 1000000 : tx + lastline.x())), - t , - BSTop, oc, style()->color(), os, - ow, - (!lastline.isEmpty() && tx + lastline.x() + 1 < r + ow) ? -ow : ow); - - if (lastline.right() < thisline.right()) - drawBorder(graphicsContext, - max(lastline.isEmpty() ? -1000000 : tx + lastline.right(), l - ow), - t - ow, - r + ow, - t , - BSTop, oc, style()->color(), os, - (!lastline.isEmpty() && l - ow < tx + lastline.right()) ? -ow : ow, - ow); - - // lower edge - if (thisline.x() < nextline.x()) - drawBorder(graphicsContext, - l - ow, - b, - min(r + ow, !nextline.isEmpty() ? tx + nextline.x() + 1 : 1000000), - b + ow, - BSBottom, oc, style()->color(), os, - ow, - (!nextline.isEmpty() && tx + nextline.x() + 1 < r + ow) ? -ow : ow); - - if (nextline.right() < thisline.right()) - drawBorder(graphicsContext, - max(!nextline.isEmpty() ? tx + nextline.right() : -1000000, l - ow), - b, - r + ow, - b + ow, - BSBottom, oc, style()->color(), os, - (!nextline.isEmpty() && l - ow < tx + nextline.right()) ? -ow : ow, - ow); -} - -void RenderFlow::calcMargins(int containerWidth) -{ - m_marginLeft = style()->marginLeft().calcMinValue(containerWidth); - m_marginRight = style()->marginRight().calcMinValue(containerWidth); -} - -#ifndef NDEBUG - -void RenderFlow::checkConsistency() const -{ -#ifdef CHECK_CONSISTENCY - const InlineFlowBox* prev = 0; - for (const InlineFlowBox* child = m_firstLineBox; child != 0; child = child->nextFlowBox()) { - ASSERT(child->object() == this); - ASSERT(child->prevFlowBox() == prev); - prev = child; - } - ASSERT(prev == m_lastLineBox); -#endif -} - -#endif - -} // namespace WebCore |