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