webengine/osswebengine/WebCore/rendering/RenderFlow.cpp
changeset 0 dd21522fd290
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webengine/osswebengine/WebCore/rendering/RenderFlow.cpp	Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,872 @@
+/*
+ * 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, RenderStyle* style)
+{
+    RenderFlow* result;
+    if (style->display() == INLINE)
+        result = new (doc->renderArena()) RenderInline(doc);
+    else
+        result = new (doc->renderArena()) RenderBlock(doc);
+    result->setStyle(style);
+    return result;
+}
+
+RenderFlow* RenderFlow::continuationBefore(RenderObject* beforeChild)
+{
+    if (beforeChild && beforeChild->parent() == this)
+        return this;
+
+    RenderFlow* curr = continuation();
+    RenderFlow* nextToLast = this;
+    RenderFlow* last = this;
+    while (curr) {
+        if (beforeChild && beforeChild->parent() == curr) {
+            if (curr->firstChild() == beforeChild)
+                return last;
+            return curr;
+        }
+
+        nextToLast = last;
+        last = curr;
+        curr = curr->continuation();
+    }
+
+    if (!beforeChild && !last->firstChild())
+        return nextToLast;
+    return last;
+}
+
+void RenderFlow::addChildWithContinuation(RenderObject* newChild, RenderObject* beforeChild)
+{
+    RenderFlow* flow = continuationBefore(beforeChild);
+    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();
+        }
+    }
+}
+
+short 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)
+        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()->subtractScrollOffset(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())
+        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())
+        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())
+        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::caretRect(int offset, EAffinity affinity, int* extraWidthToEndOfLine)
+{
+    // Do the normal calculation in most cases.
+    if (firstChild() || style()->display() == INLINE)
+        return RenderContainer::caretRect(offset, affinity, 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;
+            int ignore;
+            absolutePositionForContent(myRight, ignore);
+
+            int containerRight = containingBlock()->xPos() + containingBlockWidth();
+            absolutePositionForContent(containerRight, ignore);
+
+            *extraWidthToEndOfLine = containerRight - myRight;
+        }
+    }
+
+    int absx, absy;
+    absolutePositionForContent(absx, absy);
+    x += absx;
+    int y = absy + 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()) {
+                int x = 0;
+                int y = 0;
+                if (curr->layer()) 
+                    curr->absolutePosition(x, y);
+                else {
+                    x = tx + curr->xPos();
+                    y = ty + curr->yPos();
+                }
+                curr->addFocusRingRects(graphicsContext, x, 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() <= BHIDDEN)
+        return;
+
+    Vector<IntRect*> rects;
+
+    rects.append(new IntRect);
+    for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
+        rects.append(new IntRect(curr->xPos(), curr->yPos(), curr->width(), curr->height()));
+
+    rects.append(new 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));
+    deleteAllValues(rects);
+}
+
+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);
+}
+
+#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