Patch written mostly by Ken Kraisler, but also by me.
[WebKit-https.git] / WebCore / rendering / RenderFlow.cpp
1 /**
2  * This file is part of the html renderer for KDE.
3  *
4  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
6  * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23 // -------------------------------------------------------------------------
24
25 #include "config.h"
26 #include "RenderFlow.h"
27
28 #include "Document.h"
29 #include "GraphicsContext.h"
30 #include "InlineTextBox.h"
31 #include "HTMLNames.h"
32 #include "RenderArena.h"
33 #include "RenderView.h"
34 #include "RenderInline.h"
35
36 using namespace std;
37
38 namespace WebCore {
39
40 using namespace HTMLNames;
41
42 RenderFlow* RenderFlow::createAnonymousFlow(Document* doc, RenderStyle* style)
43 {
44     RenderFlow* result;
45     if (style->display() == INLINE)
46         result = new (doc->renderArena()) RenderInline(doc);
47     else
48         result = new (doc->renderArena()) RenderBlock(doc);
49     result->setStyle(style);
50     return result;
51 }
52
53 RenderFlow* RenderFlow::continuationBefore(RenderObject* beforeChild)
54 {
55     if (beforeChild && beforeChild->parent() == this)
56         return this;
57     
58     RenderFlow* curr = continuation();
59     RenderFlow* nextToLast = this;
60     RenderFlow* last = this;
61     while (curr) {
62         if (beforeChild && beforeChild->parent() == curr) {
63             if (curr->firstChild() == beforeChild)
64                 return last;
65             return curr;
66         }
67         
68         nextToLast = last;
69         last = curr;
70         curr = curr->continuation();
71     }
72     
73     if (!beforeChild && !last->firstChild())
74         return nextToLast;
75     return last;
76 }
77
78 void RenderFlow::addChildWithContinuation(RenderObject* newChild, RenderObject* beforeChild)
79 {
80     RenderFlow* flow = continuationBefore(beforeChild);
81     ASSERT(!beforeChild || beforeChild->parent()->isRenderBlock() ||
82                 beforeChild->parent()->isRenderInline());
83     RenderFlow* beforeChildParent = beforeChild ? static_cast<RenderFlow*>(beforeChild->parent()) : 
84                                     (flow->continuation() ? flow->continuation() : flow);
85     
86     if (newChild->isFloatingOrPositioned())
87         return beforeChildParent->addChildToFlow(newChild, beforeChild);
88     
89     // A continuation always consists of two potential candidates: an inline or an anonymous
90     // block box holding block children.
91     bool childInline = newChild->isInline();
92     bool bcpInline = beforeChildParent->isInline();
93     bool flowInline = flow->isInline();
94     
95     if (flow == beforeChildParent)
96         return flow->addChildToFlow(newChild, beforeChild);
97     else {
98         // The goal here is to match up if we can, so that we can coalesce and create the
99         // minimal # of continuations needed for the inline.
100         if (childInline == bcpInline)
101             return beforeChildParent->addChildToFlow(newChild, beforeChild);
102         else if (flowInline == childInline)
103             return flow->addChildToFlow(newChild, 0); // Just treat like an append.
104         else 
105             return beforeChildParent->addChildToFlow(newChild, beforeChild);
106     }
107 }
108
109 void RenderFlow::addChild(RenderObject *newChild, RenderObject *beforeChild)
110 {
111 #ifdef DEBUG_LAYOUT
112     kdDebug( 6040 ) << renderName() << "(RenderFlow)::addChild( " << newChild->renderName() <<
113                        ", " << (beforeChild ? beforeChild->renderName() : "0") << " )" << endl;
114     kdDebug( 6040 ) << "current height = " << m_height << endl;
115 #endif
116
117     if (continuation())
118         return addChildWithContinuation(newChild, beforeChild);
119     return addChildToFlow(newChild, beforeChild);
120 }
121
122 void RenderFlow::extractLineBox(InlineFlowBox* box)
123 {
124     m_lastLineBox = box->prevFlowBox();
125     if (box == m_firstLineBox)
126         m_firstLineBox = 0;
127     if (box->prevLineBox())
128         box->prevLineBox()->setNextLineBox(0);
129     box->setPreviousLineBox(0);
130     for (InlineRunBox* curr = box; curr; curr = curr->nextLineBox())
131         curr->setExtracted();
132 }
133
134 void RenderFlow::attachLineBox(InlineFlowBox* box)
135 {
136     if (m_lastLineBox) {
137         m_lastLineBox->setNextLineBox(box);
138         box->setPreviousLineBox(m_lastLineBox);
139     }
140     else
141         m_firstLineBox = box;
142     InlineFlowBox* last = box;
143     for (InlineFlowBox* curr = box; curr; curr = curr->nextFlowBox()) {
144         curr->setExtracted(false);
145         last = curr;
146     }
147     m_lastLineBox = last;
148 }
149
150 void RenderFlow::removeLineBox(InlineFlowBox* box)
151 {
152     if (box == m_firstLineBox)
153         m_firstLineBox = box->nextFlowBox();
154     if (box == m_lastLineBox)
155         m_lastLineBox = box->prevFlowBox();
156     if (box->nextLineBox())
157         box->nextLineBox()->setPreviousLineBox(box->prevLineBox());
158     if (box->prevLineBox())
159         box->prevLineBox()->setNextLineBox(box->nextLineBox());
160 }
161
162 void RenderFlow::deleteLineBoxes()
163 {
164     if (m_firstLineBox) {
165         RenderArena* arena = renderArena();
166         InlineRunBox *curr=m_firstLineBox, *next=0;
167         while (curr) {
168             next = curr->nextLineBox();
169             curr->destroy(arena);
170             curr = next;
171         }
172         m_firstLineBox = 0;
173         m_lastLineBox = 0;
174     }
175 }
176
177 void RenderFlow::destroy()
178 {
179     // Detach our continuation first.
180     if (m_continuation)
181         m_continuation->destroy();
182     m_continuation = 0;
183     
184     // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
185     // properly dirty line boxes that they are removed from.  Effects that do :before/:after only on hover could crash otherwise.
186     RenderContainer::destroyLeftoverChildren();
187     
188     if (!documentBeingDestroyed()) {
189         if (m_firstLineBox) {
190             // We can't wait for RenderContainer::destroy to clear the selection,
191             // because by then we will have nuked the line boxes.
192             // FIXME: The SelectionController should be responsible for this when it
193             // is notified of DOM mutations.
194             if (isSelectionBorder())
195                 view()->clearSelection();
196
197             // If line boxes are contained inside a root, that means we're an inline.
198             // In that case, we need to remove all the line boxes so that the parent
199             // lines aren't pointing to deleted children. If the first line box does
200             // not have a parent that means they are either already disconnected or
201             // root lines that can just be destroyed without disconnecting.
202             if (m_firstLineBox->parent()) {
203                 for (InlineRunBox* box = m_firstLineBox; box; box = box->nextLineBox())
204                     box->remove();
205             }
206
207             // If we are an anonymous block, then our line boxes might have children
208             // that will outlast this block. In the non-anonymous block case those
209             // children will be destroyed by the time we return from this function.
210             if (isAnonymousBlock()) {
211                 for (InlineFlowBox* box = m_firstLineBox; box; box = box->nextFlowBox()) {
212                     while (InlineBox *childBox = box->firstChild()) {
213                         childBox->remove();
214                     }
215                 }
216             }
217         }
218         else if (isInline() && parent())
219             parent()->dirtyLinesFromChangedChild(this);
220     }
221
222     deleteLineBoxes();
223
224     RenderContainer::destroy();
225 }
226
227 void RenderFlow::dirtyLinesFromChangedChild(RenderObject* child)
228 {
229     if (!parent() || (selfNeedsLayout() && !isInlineFlow()) || isTable())
230         return;
231
232     // For an empty inline, go ahead and propagate the check up to our parent.
233     if (isInline() && !firstLineBox())
234         return parent()->dirtyLinesFromChangedChild(this);
235     
236     // Try to figure out which line box we belong in.  First try to find a previous
237     // line box by examining our siblings.  If we didn't find a line box, then use our 
238     // parent's first line box.
239     RootInlineBox* box = 0;
240     RenderObject* curr = 0;
241     for (curr = child->previousSibling(); curr; curr = curr->previousSibling()) {
242         if (curr->isFloatingOrPositioned())
243             continue;
244         
245         if (curr->isReplaced()) {
246             InlineBox* wrapper = curr->inlineBoxWrapper();
247             if (wrapper)
248                 box = wrapper->root();
249         }
250         else if (curr->isText()) {
251             InlineTextBox* textBox = static_cast<RenderText*>(curr)->lastTextBox();
252             if (textBox)
253                 box = textBox->root();
254         }
255         else if (curr->isInlineFlow()) {
256             InlineRunBox* runBox = static_cast<RenderFlow*>(curr)->lastLineBox();
257             if (runBox)
258                 box = runBox->root();
259         }
260         
261         if (box)
262             break;
263     }
264     if (!box && firstLineBox())
265         box = firstLineBox()->root();
266
267     // If we found a line box, then dirty it.
268     if (box) {
269         RootInlineBox* adjacentBox;
270         box->markDirty();
271         
272         // dirty the adjacent lines that might be affected
273         // NOTE: we dirty the previous line because RootInlineBox objects cache
274         // the address of the first object on the next line after a BR, which we may be
275         // invalidating here.  For more info, see how RenderBlock::layoutInlineChildren
276         // calls setLineBreakInfo with the result of findNextLineBreak.  findNextLineBreak,
277         // despite the name, actually returns the first RenderObject after the BR.
278         // <rdar://problem/3849947> "Typing after pasting line does not appear until after window resize."
279         adjacentBox = box->prevRootBox();
280         if (adjacentBox)
281             adjacentBox->markDirty();
282         if (child->isBR() || (curr && curr->isBR())) {
283             adjacentBox = box->nextRootBox();
284             if (adjacentBox)
285                 adjacentBox->markDirty();
286         }
287     }
288 }
289
290 short RenderFlow::lineHeight(bool firstLine, bool isRootLineBox) const
291 {
292     if (firstLine) {
293         RenderStyle* s = style(firstLine);
294         Length lh = s->lineHeight();
295         if (lh.value() < 0) {
296             if (s == style()) {
297                 if (m_lineHeight == -1)
298                     m_lineHeight = RenderObject::lineHeight(false);
299                 return m_lineHeight;
300             }
301             return s->font().lineSpacing();
302         }
303         if (lh.isPercent())
304             return lh.calcMinValue(s->fontSize());
305         return lh.value();
306     }
307
308     if (m_lineHeight == -1)
309         m_lineHeight = RenderObject::lineHeight(false);
310     return m_lineHeight;
311 }
312
313 void RenderFlow::dirtyLineBoxes(bool fullLayout, bool isRootLineBox)
314 {
315     if (!isRootLineBox && isReplaced())
316         return RenderContainer::dirtyLineBoxes(fullLayout, isRootLineBox);
317     
318     if (fullLayout)
319         deleteLineBoxes();
320     else {
321         for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
322             curr->dirtyLineBoxes();
323     }
324 }
325
326 InlineBox* RenderFlow::createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool isOnlyRun)
327 {
328     if (!isRootLineBox &&
329         (isReplaced() || makePlaceHolderBox))                     // Inline tables and inline blocks
330         return RenderContainer::createInlineBox(false, isRootLineBox);  // (or positioned element placeholders).
331
332     InlineFlowBox* flowBox = 0;
333     if (isInlineFlow())
334         flowBox = new (renderArena()) InlineFlowBox(this);
335     else
336         flowBox = new (renderArena()) RootInlineBox(this);
337     
338     if (!m_firstLineBox)
339         m_firstLineBox = m_lastLineBox = flowBox;
340     else {
341         m_lastLineBox->setNextLineBox(flowBox);
342         flowBox->setPreviousLineBox(m_lastLineBox);
343         m_lastLineBox = flowBox;
344     }
345
346     return flowBox;
347 }
348
349 void RenderFlow::paintLines(PaintInfo& i, int _tx, int _ty)
350 {
351     // Only paint during the foreground/selection phases.
352     if (i.phase != PaintPhaseForeground && i.phase != PaintPhaseSelection && i.phase != PaintPhaseOutline 
353         && i.phase != PaintPhaseSelfOutline && i.phase != PaintPhaseChildOutlines)
354         return;
355     
356     bool inlineFlow = isInlineFlow();
357     if (inlineFlow)
358         ASSERT(m_layer); // The only way a compact/run-in/inline could paint like this is if it has a layer.
359
360     // If we have no lines then we have no work to do.
361     if (!firstLineBox())
362         return;
363
364     // We can check the first box and last box and avoid painting if we don't
365     // intersect.  This is a quick short-circuit that we can take to avoid walking any lines.
366     // FIXME: This check is flawed in the following extremely obscure way:
367     // if some line in the middle has a huge overflow, it might actually extend below the last line.
368     int yPos = firstLineBox()->root()->topOverflow() - maximalOutlineSize(i.phase);
369     int h = maximalOutlineSize(i.phase) + lastLineBox()->root()->bottomOverflow() - yPos;
370     yPos += _ty;
371     if (yPos >= i.r.bottom() || yPos + h <= i.r.y())
372         return;
373
374     PaintInfo info(i);
375     RenderFlowSequencedSet outlineObjects;
376     info.outlineObjects = &outlineObjects;
377     
378     // See if our root lines intersect with the dirty rect.  If so, then we paint
379     // them.  Note that boxes can easily overlap, so we can't make any assumptions
380     // based off positions of our first line box or our last line box.
381     bool isPrinting = document()->printing();
382     for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextFlowBox()) {
383         if (isPrinting) {
384             // FIXME: This is a feeble effort to avoid splitting a line across two pages.
385             // It is utterly inadequate, and this should not be done at paint time at all.
386             // The whole way objects break across pages needs to be redone.
387             RenderView* c = view();
388             // Try to avoid splitting a line vertically, but only if it's less than the height
389             // of the entire page.
390             if (curr->root()->bottomOverflow() - curr->root()->topOverflow() <= c->printRect().height()) {
391                 if (_ty + curr->root()->bottomOverflow() > c->printRect().bottom()) {
392                     if (_ty + curr->root()->topOverflow() < c->truncatedAt())
393                         c->setBestTruncatedAt(_ty + curr->root()->topOverflow(), this);
394                     // If we were able to truncate, don't paint.
395                     if (_ty + curr->root()->topOverflow() >= c->truncatedAt())
396                         break;
397                 }
398             }
399         }
400
401         int top = min(curr->root()->topOverflow(), curr->root()->selectionTop()) - maximalOutlineSize(info.phase);
402         int bottom = curr->root()->bottomOverflow() + maximalOutlineSize(info.phase);
403         h = bottom - top;
404         yPos = _ty + top;
405         if (yPos < info.r.bottom() && yPos + h > info.r.y())
406             curr->paint(info, _tx, _ty);
407     }
408
409     if (info.phase == PaintPhaseOutline || info.phase == PaintPhaseSelfOutline || info.phase == PaintPhaseChildOutlines) {
410         RenderFlowSequencedSet::iterator end = info.outlineObjects->end();
411         for (RenderFlowSequencedSet::iterator it = info.outlineObjects->begin(); it != end; ++it) {
412             RenderFlow* flow = *it;
413             flow->paintOutline(info.p, _tx, _ty);
414         }
415         info.outlineObjects->clear();
416     }
417 }
418
419 bool RenderFlow::hitTestLines(NodeInfo& i, int x, int y, int tx, int ty, HitTestAction hitTestAction)
420 {
421     if (hitTestAction != HitTestForeground)
422         return false;
423
424     bool inlineFlow = isInlineFlow();
425     if (inlineFlow)
426         ASSERT(m_layer); // The only way a compact/run-in/inline could paint like this is if it has a layer.
427
428     // If we have no lines then we have no work to do.
429     if (!firstLineBox())
430         return false;
431
432     // We can check the first box and last box and avoid hit testing if we don't
433     // contain the point.  This is a quick short-circuit that we can take to avoid walking any lines.
434     // FIXME: This check is flawed in the following extremely obscure way:
435     // if some line in the middle has a huge overflow, it might actually extend below the last line.
436     if ((y >= ty + lastLineBox()->root()->bottomOverflow()) || (y < ty + firstLineBox()->root()->topOverflow()))
437         return false;
438
439     // See if our root lines contain the point.  If so, then we hit test
440     // them further.  Note that boxes can easily overlap, so we can't make any assumptions
441     // based off positions of our first line box or our last line box.
442     for (InlineFlowBox* curr = lastLineBox(); curr; curr = curr->prevFlowBox()) {
443         if (y >= ty + curr->root()->topOverflow() && y < ty + curr->root()->bottomOverflow()) {
444             bool inside = curr->nodeAtPoint(i, x, y, tx, ty);
445             if (inside) {
446                 setInnerNode(i);
447                 return true;
448             }
449         }
450     }
451     
452     return false;
453 }
454
455 IntRect RenderFlow::getAbsoluteRepaintRect()
456 {
457     if (isInlineFlow()) {
458         // Find our leftmost position.
459         int left = 0;
460         int top = firstLineBox() ? firstLineBox()->yPos() : 0;
461         for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
462             if (curr == firstLineBox() || curr->xPos() < left)
463                 left = curr->xPos();
464
465         // Now invalidate a rectangle.
466         int ow = style() ? style()->outlineSize() : 0;
467         if (isCompact())
468             left -= m_x;
469         
470         // We need to add in the relative position offsets of any inlines (including us) up to our
471         // containing block.
472         RenderBlock* cb = containingBlock();
473         for (RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isInlineFlow() && inlineFlow != cb; 
474              inlineFlow = inlineFlow->parent()) {
475              if (inlineFlow->style()->position() == RelativePosition && inlineFlow->layer())
476                 inlineFlow->layer()->relativePositionOffset(left, top);
477         }
478
479         IntRect r(-ow+left, -ow+top, width()+ow*2, height()+ow*2);
480         if (cb->hasOverflowClip()) {
481             // cb->height() is inaccurate if we're in the middle of a layout of |cb|, so use the
482             // layer's size instead.  Even if the layer's size is wrong, the layer itself will repaint
483             // anyway if its size does change.
484             int x = r.x();
485             int y = r.y();
486             IntRect boxRect(0, 0, cb->layer()->width(), cb->layer()->height());
487             cb->layer()->subtractScrollOffset(x, y); // For overflow:auto/scroll/hidden.
488             IntRect repaintRect(x, y, r.width(), r.height());
489             r = intersection(repaintRect, boxRect);
490         }
491         cb->computeAbsoluteRepaintRect(r);
492         
493         if (ow) {
494             for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
495                 if (!curr->isText()) {
496                     IntRect childRect = curr->getAbsoluteRepaintRectWithOutline(ow);
497                     r.unite(childRect);
498                 }
499             }
500             
501             if (continuation() && !continuation()->isInline()) {
502                 IntRect contRect = continuation()->getAbsoluteRepaintRectWithOutline(ow);
503                 r.unite(contRect);
504             }
505         }
506         
507         return r;
508     } else
509         return RenderContainer::getAbsoluteRepaintRect();
510 }
511
512 int
513 RenderFlow::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
514 {
515     assert(!isInlineFlow());
516     int bottom = includeSelf && m_width > 0 ? m_height : 0;
517     if (!includeOverflowInterior && hasOverflowClip())
518         return bottom;
519
520     // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids.
521     // For now, we have to descend into all the children, since we may have a huge abs div inside
522     // a tiny rel div buried somewhere deep in our child tree.  In this case we have to get to
523     // the abs div.
524     for (RenderObject *c = firstChild(); c; c = c->nextSibling()) {
525         if (!c->isFloatingOrPositioned() && !c->isText() && !c->isInlineFlow()) {
526             int lp = c->yPos() + c->lowestPosition(false);
527             bottom = max(bottom, lp);
528         }
529     }
530  
531     if (isRelPositioned())
532         bottom += relativePositionOffsetY();         
533     
534     return bottom;
535 }
536
537 int RenderFlow::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
538 {
539     assert(!isInlineFlow());
540     int right = includeSelf && m_height > 0 ? m_width : 0;
541     if (!includeOverflowInterior && hasOverflowClip())
542         return right;
543
544     // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids.
545     // For now, we have to descend into all the children, since we may have a huge abs div inside
546     // a tiny rel div buried somewhere deep in our child tree.  In this case we have to get to
547     // the abs div.
548     for (RenderObject *c = firstChild(); c; c = c->nextSibling()) {
549         if (!c->isFloatingOrPositioned() && !c->isText() && !c->isInlineFlow()) {
550             int rp = c->xPos() + c->rightmostPosition(false);
551             right = max(right, rp);
552         }
553     }
554     
555     if (isRelPositioned())
556         right += relativePositionOffsetX();
557     
558     return right;
559 }
560
561 int RenderFlow::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
562 {
563     assert(!isInlineFlow());
564     int left = includeSelf && m_height > 0 ? 0 : m_width;
565     if (!includeOverflowInterior && hasOverflowClip())
566         return left;
567     
568     // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids.
569     // For now, we have to descend into all the children, since we may have a huge abs div inside
570     // a tiny rel div buried somewhere deep in our child tree.  In this case we have to get to
571     // the abs div.
572     for (RenderObject *c = firstChild(); c; c = c->nextSibling()) {
573         if (!c->isFloatingOrPositioned() && !c->isText() && !c->isInlineFlow()) {
574             int lp = c->xPos() + c->leftmostPosition(false);
575             left = min(left, lp);
576         }
577     }
578     
579     if (isRelPositioned())
580         left += relativePositionOffsetX(); 
581         
582     return left;
583 }
584
585 IntRect RenderFlow::caretRect(int offset, EAffinity affinity, int *extraWidthToEndOfLine)
586 {
587     // Do the normal calculation in most cases.
588     if (firstChild() || style()->display() == INLINE)
589         return RenderContainer::caretRect(offset, affinity, extraWidthToEndOfLine);
590
591     // This is a special case:
592     // The element is not an inline element, and it's empty. So we have to
593     // calculate a fake position to indicate where objects are to be inserted.
594     
595     // FIXME: This does not take into account either :first-line or :first-letter
596     // However, as soon as some content is entered, the line boxes will be
597     // constructed and this kludge is not called any more. So only the caret size
598     // of an empty :first-line'd block is wrong. I think we can live with that.
599     RenderStyle *currentStyle = firstLineStyle();
600     int height = lineHeight(true);
601     const int caretWidth = 1;
602
603     enum CaretAlignment { alignLeft, alignRight, alignCenter };
604
605     CaretAlignment alignment = alignLeft;
606
607     switch (currentStyle->textAlign()) {
608         case TAAUTO:
609         case JUSTIFY:
610             if (currentStyle->direction() == RTL)
611                 alignment = alignRight;
612             break;
613         case LEFT:
614         case KHTML_LEFT:
615             break;
616         case CENTER:
617         case KHTML_CENTER:
618             alignment = alignCenter;
619             break;
620         case RIGHT:
621         case KHTML_RIGHT:
622             alignment = alignRight;
623             break;
624     }
625
626     int x = borderLeft() + paddingLeft();
627     int w = width();
628
629     switch (alignment) {
630         case alignLeft:
631             break;
632         case alignCenter:
633             x = (x + w - (borderRight() + paddingRight())) / 2;
634             break;
635         case alignRight:
636             x = w - (borderRight() + paddingRight());
637             break;
638     }
639
640     if (extraWidthToEndOfLine) {
641         if (isRenderBlock()) {
642             *extraWidthToEndOfLine = w - (x + caretWidth);
643         } else {
644             // FIXME: This code looks wrong.
645             // myRight and containerRight are set up, but then clobbered.
646             // So *extraWidthToEndOfLine will always be 0 here.
647
648             int myRight = x + caretWidth;
649             int ignore;
650             absolutePositionForContent(myRight, ignore);
651             
652             int containerRight = containingBlock()->xPos() + containingBlockWidth();
653             absolutePositionForContent(containerRight, ignore);
654             
655             *extraWidthToEndOfLine = containerRight - myRight;
656         }
657     }
658
659     int absx, absy;
660     absolutePositionForContent(absx, absy);
661     x += absx;
662     int y = absy + paddingTop() + borderTop();
663
664     return IntRect(x, y, caretWidth, height);
665 }
666
667 void RenderFlow::addFocusRingRects(GraphicsContext* p, int _tx, int _ty)
668 {
669     if (isRenderBlock())
670        p->addFocusRingRect(IntRect(_tx, _ty, width(), height()));
671
672     if (!hasOverflowClip()) {
673         for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
674             p->addFocusRingRect(IntRect(_tx + curr->xPos(), _ty + curr->yPos(), curr->width(), curr->height()));
675         
676         for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
677             if (!curr->isText() && !curr->isListMarker())
678                 curr->addFocusRingRects(p, _tx + curr->xPos(), _ty + curr->yPos());
679     }
680         
681     if (continuation())
682         continuation()->addFocusRingRects(p, 
683                                           _tx - containingBlock()->xPos() + continuation()->xPos(),
684                                           _ty - containingBlock()->yPos() + continuation()->yPos());
685 }
686
687 void RenderFlow::paintOutline(GraphicsContext* p, int _tx, int _ty)
688 {
689     if (!hasOutline())
690         return;
691     
692     if (style()->outlineStyleIsAuto() || hasOutlineAnnotation()) {
693         int ow = style()->outlineWidth();
694         Color oc = style()->outlineColor();
695         if (!oc.isValid())
696             oc = style()->color();
697         
698         p->initFocusRing(ow, style()->outlineOffset());
699         addFocusRingRects(p, _tx, _ty);
700         if (style()->outlineStyleIsAuto())
701             p->drawFocusRing(oc);
702         else
703             addPDFURLRect(p, p->focusRingBoundingRect());
704         p->clearFocusRing();
705     }
706
707     if (style()->outlineStyleIsAuto() || style()->outlineStyle() <= BHIDDEN)
708         return;
709
710     DeprecatedPtrList <IntRect> rects;
711     rects.setAutoDelete(true);
712
713     rects.append(new IntRect);
714     for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
715         rects.append(new IntRect(curr->xPos(), curr->yPos(), curr->width(), curr->height()));
716
717     rects.append(new IntRect);
718
719     for (unsigned int i = 1; i < rects.count() - 1; i++)
720         paintOutlineForLine(p, _tx, _ty, *rects.at(i-1), *rects.at(i), *rects.at(i+1));
721 }
722
723 void RenderFlow::paintOutlineForLine(GraphicsContext* p, int tx, int ty, const IntRect &lastline, const IntRect &thisline, const IntRect &nextline)
724 {
725     int ow = style()->outlineWidth();
726     EBorderStyle os = style()->outlineStyle();
727     Color oc = style()->outlineColor();
728     if (!oc.isValid())
729         oc = style()->color();
730     
731     int offset = style()->outlineOffset();
732     
733     int t = ty + thisline.y() - offset;
734     int l = tx + thisline.x() - offset;
735     int b = ty + thisline.bottom() + offset;
736     int r = tx + thisline.right() + offset;
737     
738     // left edge
739     drawBorder(p,
740                l - ow,
741                t - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.right() - 1) <= thisline.x() ? ow : 0),
742                l,
743                b + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.right() - 1) <= thisline.x() ? ow : 0),
744                BSLeft,
745                oc, style()->color(), os,
746                (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.right() - 1) <= thisline.x() ? ow : -ow),
747                (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.right() - 1) <= thisline.x() ? ow : -ow));
748     
749     // right edge
750     drawBorder(p,
751                r,
752                t - (lastline.isEmpty() || lastline.right() < thisline.right() || (thisline.right() - 1) <= lastline.x() ? ow : 0),
753                r + ow,
754                b + (nextline.isEmpty() || nextline.right() <= thisline.right() || (thisline.right() - 1) <= nextline.x() ? ow : 0),
755                BSRight,
756                oc, style()->color(), os,
757                (lastline.isEmpty() || lastline.right() < thisline.right() || (thisline.right() - 1) <= lastline.x() ? ow : -ow),
758                (nextline.isEmpty() || nextline.right() <= thisline.right() || (thisline.right() - 1) <= nextline.x() ? ow : -ow));
759     // upper edge
760     if (thisline.x() < lastline.x())
761         drawBorder(p,
762                    l - ow,
763                    t - ow,
764                    min(r+ow, (lastline.isEmpty() ? 1000000 : tx + lastline.x())),
765                    t ,
766                    BSTop, oc, style()->color(), os,
767                    ow,
768                    (!lastline.isEmpty() && tx + lastline.x() + 1 < r + ow) ? -ow : ow);
769     
770     if (lastline.right() < thisline.right())
771         drawBorder(p,
772                    max(lastline.isEmpty() ? -1000000 : tx + lastline.right(), l - ow),
773                    t - ow,
774                    r + ow,
775                    t ,
776                    BSTop, oc, style()->color(), os,
777                    (!lastline.isEmpty() && l - ow < tx + lastline.right()) ? -ow : ow,
778                    ow);
779     
780     // lower edge
781     if (thisline.x() < nextline.x())
782         drawBorder(p,
783                    l - ow,
784                    b,
785                    min(r + ow, !nextline.isEmpty() ? tx + nextline.x() + 1 : 1000000),
786                    b + ow,
787                    BSBottom, oc, style()->color(), os,
788                    ow,
789                    (!nextline.isEmpty() && tx + nextline.x() + 1 < r + ow) ? -ow : ow);
790     
791     if (nextline.right() < thisline.right())
792         drawBorder(p,
793                    max(!nextline.isEmpty() ? tx + nextline.right() : -1000000, l - ow),
794                    b,
795                    r + ow,
796                    b + ow,
797                    BSBottom, oc, style()->color(), os,
798                    (!nextline.isEmpty() && l - ow < tx + nextline.right()) ? -ow : ow,
799                    ow);
800 }
801
802 }