bd8cd6b48ca0a4a12888e04eab1389a18691e1bf
[WebKit-https.git] / WebCore / rendering / RenderInline.cpp
1 /*
2  * This file is part of the render object implementation for KHTML.
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., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  */
24
25 #include "config.h"
26 #include "RenderInline.h"
27
28 #include "FloatQuad.h"
29 #include "GraphicsContext.h"
30 #include "HitTestResult.h"
31 #include "RenderArena.h"
32 #include "RenderBlock.h"
33 #include "RenderView.h"
34 #include "VisiblePosition.h"
35
36 using namespace std;
37
38 namespace WebCore {
39
40 RenderInline::RenderInline(Node* node)
41     : RenderContainer(node)
42     , m_continuation(0)
43     , m_lineHeight(-1)
44 {
45     setChildrenInline(true);
46 }
47
48 RenderInline::~RenderInline()
49 {
50 }
51
52 void RenderInline::destroy()
53 {
54     // Detach our continuation first.
55     if (m_continuation)
56         m_continuation->destroy();
57     m_continuation = 0;
58     
59     // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
60     // properly dirty line boxes that they are removed from.  Effects that do :before/:after only on hover could crash otherwise.
61     children()->destroyLeftoverChildren();
62
63     if (!documentBeingDestroyed()) {
64         if (firstLineBox()) {
65             // We can't wait for RenderContainer::destroy to clear the selection,
66             // because by then we will have nuked the line boxes.
67             // FIXME: The SelectionController should be responsible for this when it
68             // is notified of DOM mutations.
69             if (isSelectionBorder())
70                 view()->clearSelection();
71
72             // If line boxes are contained inside a root, that means we're an inline.
73             // In that case, we need to remove all the line boxes so that the parent
74             // lines aren't pointing to deleted children. If the first line box does
75             // not have a parent that means they are either already disconnected or
76             // root lines that can just be destroyed without disconnecting.
77             if (firstLineBox()->parent()) {
78                 for (InlineRunBox* box = firstLineBox(); box; box = box->nextLineBox())
79                     box->remove();
80             }
81         } else if (isInline() && parent())
82             parent()->dirtyLinesFromChangedChild(this);
83     }
84
85     m_lineBoxes.deleteLineBoxes(renderArena());
86
87     RenderContainer::destroy();
88 }
89
90 RenderInline* RenderInline::inlineContinuation() const
91 {
92     if (!m_continuation || m_continuation->isInline())
93         return toRenderInline(m_continuation);
94     return toRenderBlock(m_continuation)->inlineContinuation();
95 }
96
97 void RenderInline::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
98 {
99     RenderContainer::styleDidChange(diff, oldStyle);
100
101     setInline(true);
102     setHasReflection(false);
103
104     // Ensure that all of the split inlines pick up the new style. We
105     // only do this if we're an inline, since we don't want to propagate
106     // a block's style to the other inlines.
107     // e.g., <font>foo <h4>goo</h4> moo</font>.  The <font> inlines before
108     // and after the block share the same style, but the block doesn't
109     // need to pass its style on to anyone else.
110     for (RenderInline* currCont = inlineContinuation(); currCont; currCont = currCont->inlineContinuation()) {
111         RenderContainer* nextCont = currCont->continuation();
112         currCont->setContinuation(0);
113         currCont->setStyle(style());
114         currCont->setContinuation(nextCont);
115     }
116
117     m_lineHeight = -1;
118
119     // Update pseudos for :before and :after now.
120     if (!isAnonymous() && document()->usesBeforeAfterRules()) {
121         children()->updateBeforeAfterContent(this, RenderStyle::BEFORE);
122         children()->updateBeforeAfterContent(this, RenderStyle::AFTER);
123     }
124 }
125
126 static inline bool isAfterContent(RenderObject* child)
127 {
128     if (!child)
129         return false;
130     if (child->style()->styleType() != RenderStyle::AFTER)
131         return false;
132     // Text nodes don't have their own styles, so ignore the style on a text node.
133     if (child->isText() && !child->isBR())
134         return false;
135     return true;
136 }
137
138 void RenderInline::addChild(RenderObject* newChild, RenderObject* beforeChild)
139 {
140     if (continuation())
141         return addChildToContinuation(newChild, beforeChild);
142     return addChildIgnoringContinuation(newChild, beforeChild);
143 }
144
145 static RenderContainer* nextContinuation(RenderObject* renderer)
146 {
147     if (renderer->isInline() && !renderer->isReplaced())
148         return toRenderInline(renderer)->continuation();
149     return toRenderBlock(renderer)->inlineContinuation();
150 }
151
152 RenderContainer* RenderInline::continuationBefore(RenderObject* beforeChild)
153 {
154     if (beforeChild && beforeChild->parent() == this)
155         return this;
156
157     RenderContainer* curr = nextContinuation(this);
158     RenderContainer* nextToLast = this;
159     RenderContainer* last = this;
160     while (curr) {
161         if (beforeChild && beforeChild->parent() == curr) {
162             if (curr->firstChild() == beforeChild)
163                 return last;
164             return curr;
165         }
166
167         nextToLast = last;
168         last = curr;
169         curr = nextContinuation(curr);
170     }
171
172     if (!beforeChild && !last->firstChild())
173         return nextToLast;
174     return last;
175 }
176
177 void RenderInline::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild)
178 {
179     // Make sure we don't append things after :after-generated content if we have it.
180     if (!beforeChild && isAfterContent(lastChild()))
181         beforeChild = lastChild();
182
183     if (!newChild->isInline() && !newChild->isFloatingOrPositioned()) {
184         // We are placing a block inside an inline. We have to perform a split of this
185         // inline into continuations.  This involves creating an anonymous block box to hold
186         // |newChild|.  We then make that block box a continuation of this inline.  We take all of
187         // the children after |beforeChild| and put them in a clone of this object.
188         RefPtr<RenderStyle> newStyle = RenderStyle::create();
189         newStyle->inheritFrom(style());
190         newStyle->setDisplay(BLOCK);
191
192         RenderBlock* newBox = new (renderArena()) RenderBlock(document() /* anonymous box */);
193         newBox->setStyle(newStyle.release());
194         RenderContainer* oldContinuation = continuation();
195         setContinuation(newBox);
196
197         // Someone may have put a <p> inside a <q>, causing a split.  When this happens, the :after content
198         // has to move into the inline continuation.  Call updateBeforeAfterContent to ensure that our :after
199         // content gets properly destroyed.
200         bool isLastChild = (beforeChild == lastChild());
201         if (document()->usesBeforeAfterRules())
202             children()->updateBeforeAfterContent(this, RenderStyle::AFTER);
203         if (isLastChild && beforeChild != lastChild())
204             beforeChild = 0; // We destroyed the last child, so now we need to update our insertion
205                              // point to be 0.  It's just a straight append now.
206
207         splitFlow(beforeChild, newBox, newChild, oldContinuation);
208         return;
209     }
210
211     RenderContainer::addChild(newChild, beforeChild);
212
213     newChild->setNeedsLayoutAndPrefWidthsRecalc();
214 }
215
216 RenderInline* RenderInline::cloneInline(RenderInline* src)
217 {
218     RenderInline* o = new (src->renderArena()) RenderInline(src->element());
219     o->setStyle(src->style());
220     return o;
221 }
222
223 void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock,
224                                 RenderBlock* middleBlock,
225                                 RenderObject* beforeChild, RenderContainer* oldCont)
226 {
227     // Create a clone of this inline.
228     RenderInline* clone = cloneInline(this);
229     clone->setContinuation(oldCont);
230
231     // Now take all of the children from beforeChild to the end and remove
232     // them from |this| and place them in the clone.
233     RenderObject* o = beforeChild;
234     while (o) {
235         RenderObject* tmp = o;
236         o = tmp->nextSibling();
237         clone->addChildIgnoringContinuation(removeChildNode(tmp), 0);
238         tmp->setNeedsLayoutAndPrefWidthsRecalc();
239     }
240
241     // Hook |clone| up as the continuation of the middle block.
242     middleBlock->setInlineContinuation(clone);
243
244     // We have been reparented and are now under the fromBlock.  We need
245     // to walk up our inline parent chain until we hit the containing block.
246     // Once we hit the containing block we're done.
247     RenderContainer* curr = static_cast<RenderContainer*>(parent());
248     RenderContainer* currChild = this;
249     
250     // FIXME: Because splitting is O(n^2) as tags nest pathologically, we cap the depth at which we're willing to clone.
251     // There will eventually be a better approach to this problem that will let us nest to a much
252     // greater depth (see bugzilla bug 13430) but for now we have a limit.  This *will* result in
253     // incorrect rendering, but the alternative is to hang forever.
254     unsigned splitDepth = 1;
255     const unsigned cMaxSplitDepth = 200; 
256     while (curr && curr != fromBlock) {
257         ASSERT(curr->isRenderInline());
258         if (splitDepth < cMaxSplitDepth) {
259             // Create a new clone.
260             RenderInline* cloneChild = clone;
261             clone = cloneInline(toRenderInline(curr));
262
263             // Insert our child clone as the first child.
264             clone->addChildIgnoringContinuation(cloneChild, 0);
265
266             // Hook the clone up as a continuation of |curr|.
267             RenderInline* inlineCurr = toRenderInline(curr);
268             oldCont = inlineCurr->continuation();
269             inlineCurr->setContinuation(clone);
270             clone->setContinuation(oldCont);
271
272             // Someone may have indirectly caused a <q> to split.  When this happens, the :after content
273             // has to move into the inline continuation.  Call updateBeforeAfterContent to ensure that the inline's :after
274             // content gets properly destroyed.
275             if (document()->usesBeforeAfterRules())
276                 inlineCurr->children()->updateBeforeAfterContent(this, RenderStyle::AFTER);
277
278             // Now we need to take all of the children starting from the first child
279             // *after* currChild and append them all to the clone.
280             o = currChild->nextSibling();
281             while (o) {
282                 RenderObject* tmp = o;
283                 o = tmp->nextSibling();
284                 clone->addChildIgnoringContinuation(curr->removeChildNode(tmp), 0);
285                 tmp->setNeedsLayoutAndPrefWidthsRecalc();
286             }
287         }
288         
289         // Keep walking up the chain.
290         currChild = curr;
291         curr = static_cast<RenderContainer*>(curr->parent());
292         splitDepth++;
293     }
294
295     // Now we are at the block level. We need to put the clone into the toBlock.
296     toBlock->appendChildNode(clone);
297
298     // Now take all the children after currChild and remove them from the fromBlock
299     // and put them in the toBlock.
300     o = currChild->nextSibling();
301     while (o) {
302         RenderObject* tmp = o;
303         o = tmp->nextSibling();
304         toBlock->appendChildNode(fromBlock->removeChildNode(tmp));
305     }
306 }
307
308 void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
309                              RenderObject* newChild, RenderContainer* oldCont)
310 {
311     RenderBlock* pre = 0;
312     RenderBlock* block = containingBlock();
313     
314     // Delete our line boxes before we do the inline split into continuations.
315     block->deleteLineBoxTree();
316     
317     bool madeNewBeforeBlock = false;
318     if (block->isAnonymousBlock() && (!block->parent() || !block->parent()->createsAnonymousWrapper())) {
319         // We can reuse this block and make it the preBlock of the next continuation.
320         pre = block;
321         block = block->containingBlock();
322     } else {
323         // No anonymous block available for use.  Make one.
324         pre = block->createAnonymousBlock();
325         madeNewBeforeBlock = true;
326     }
327
328     RenderBlock* post = block->createAnonymousBlock();
329
330     RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling();
331     if (madeNewBeforeBlock)
332         block->insertChildNode(pre, boxFirst);
333     block->insertChildNode(newBlockBox, boxFirst);
334     block->insertChildNode(post, boxFirst);
335     block->setChildrenInline(false);
336     
337     if (madeNewBeforeBlock) {
338         RenderObject* o = boxFirst;
339         while (o) {
340             RenderObject* no = o;
341             o = no->nextSibling();
342             pre->appendChildNode(block->removeChildNode(no));
343             no->setNeedsLayoutAndPrefWidthsRecalc();
344         }
345     }
346
347     splitInlines(pre, post, newBlockBox, beforeChild, oldCont);
348
349     // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
350     // time in makeChildrenNonInline by just setting this explicitly up front.
351     newBlockBox->setChildrenInline(false);
352
353     // We delayed adding the newChild until now so that the |newBlockBox| would be fully
354     // connected, thus allowing newChild access to a renderArena should it need
355     // to wrap itself in additional boxes (e.g., table construction).
356     newBlockBox->addChild(newChild);
357
358     // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
359     // get deleted properly.  Because objects moves from the pre block into the post block, we want to
360     // make new line boxes instead of leaving the old line boxes around.
361     pre->setNeedsLayoutAndPrefWidthsRecalc();
362     block->setNeedsLayoutAndPrefWidthsRecalc();
363     post->setNeedsLayoutAndPrefWidthsRecalc();
364 }
365
366 void RenderInline::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild)
367 {
368     RenderContainer* flow = continuationBefore(beforeChild);
369     ASSERT(!beforeChild || beforeChild->parent()->isRenderBlock() || beforeChild->parent()->isRenderInline());
370     RenderContainer* beforeChildParent = 0;
371     if (beforeChild)
372         beforeChildParent = static_cast<RenderContainer*>(beforeChild->parent());
373     else {
374         RenderContainer* cont = nextContinuation(flow);
375         if (cont)
376             beforeChildParent = cont;
377         else
378             beforeChildParent = flow;
379     }
380
381     if (newChild->isFloatingOrPositioned())
382         return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
383
384     // A continuation always consists of two potential candidates: an inline or an anonymous
385     // block box holding block children.
386     bool childInline = newChild->isInline();
387     bool bcpInline = beforeChildParent->isInline();
388     bool flowInline = flow->isInline();
389
390     if (flow == beforeChildParent)
391         return flow->addChildIgnoringContinuation(newChild, beforeChild);
392     else {
393         // The goal here is to match up if we can, so that we can coalesce and create the
394         // minimal # of continuations needed for the inline.
395         if (childInline == bcpInline)
396             return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
397         else if (flowInline == childInline)
398             return flow->addChildIgnoringContinuation(newChild, 0); // Just treat like an append.
399         else
400             return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
401     }
402 }
403
404 void RenderInline::paint(PaintInfo& paintInfo, int tx, int ty)
405 {
406     m_lineBoxes.paint(this, paintInfo, tx, ty);
407 }
408
409 void RenderInline::absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool topLevel)
410 {
411     for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
412         rects.append(IntRect(tx + curr->xPos(), ty + curr->yPos(), curr->width(), curr->height()));
413
414     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
415         if (curr->isBox()) {
416             RenderBox* box = toRenderBox(curr);
417             curr->absoluteRects(rects, tx + box->x(), ty + box->y(), false);
418         }
419     }
420
421     if (continuation() && topLevel)
422         continuation()->absoluteRects(rects, 
423                                       tx - containingBlock()->x() + continuation()->x(),
424                                       ty - containingBlock()->y() + continuation()->y(),
425                                       topLevel);
426 }
427
428 void RenderInline::absoluteQuads(Vector<FloatQuad>& quads, bool topLevel)
429 {
430     for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
431         FloatRect localRect(curr->xPos(), curr->yPos(), curr->width(), curr->height());
432         quads.append(localToAbsoluteQuad(localRect));
433     }
434     
435     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
436         if (!curr->isText())
437             curr->absoluteQuads(quads, false);
438     }
439
440     if (continuation() && topLevel)
441         continuation()->absoluteQuads(quads, topLevel);
442 }
443
444 int RenderInline::offsetLeft() const
445 {
446     int x = RenderContainer::offsetLeft();
447     if (firstLineBox())
448         x += firstLineBox()->xPos();
449     return x;
450 }
451
452 int RenderInline::offsetTop() const
453 {
454     int y = RenderContainer::offsetTop();
455     if (firstLineBox())
456         y += firstLineBox()->yPos();
457     return y;
458 }
459
460 const char* RenderInline::renderName() const
461 {
462     if (isRelPositioned())
463         return "RenderInline (relative positioned)";
464     if (isAnonymous())
465         return "RenderInline (generated)";
466     if (isRunIn())
467         return "RenderInline (run-in)";
468     return "RenderInline";
469 }
470
471 bool RenderInline::nodeAtPoint(const HitTestRequest& request, HitTestResult& result,
472                                 int x, int y, int tx, int ty, HitTestAction hitTestAction)
473 {
474     return m_lineBoxes.hitTest(this, request, result, x, y, tx, ty, hitTestAction);
475 }
476
477 VisiblePosition RenderInline::positionForCoordinates(int x, int y)
478 {
479     // Translate the coords from the pre-anonymous block to the post-anonymous block.
480     RenderBlock* cb = containingBlock();
481     int parentBlockX = cb->x() + x;
482     int parentBlockY = cb->y() + y;
483     RenderBox* c = continuation();
484     while (c) {
485         RenderBox* contBlock = c;
486         if (c->isInline() || c->firstChild())
487             return c->positionForCoordinates(parentBlockX - contBlock->x(), parentBlockY - contBlock->y());
488         c = toRenderBlock(c)->inlineContinuation();
489     }
490     
491     return RenderContainer::positionForCoordinates(x, y);
492 }
493
494 IntRect RenderInline::linesBoundingBox() const
495 {
496     IntRect result;
497     
498     // See <rdar://problem/5289721>, for an unknown reason the linked list here is sometimes inconsistent, first is non-zero and last is zero.  We have been
499     // unable to reproduce this at all (and consequently unable to figure ot why this is happening).  The assert will hopefully catch the problem in debug
500     // builds and help us someday figure out why.  We also put in a redundant check of lastLineBox() to avoid the crash for now.
501     ASSERT(!firstLineBox() == !lastLineBox());  // Either both are null or both exist.
502     if (firstLineBox() && lastLineBox()) {
503         // Return the width of the minimal left side and the maximal right side.
504         int leftSide = 0;
505         int rightSide = 0;
506         for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
507             if (curr == firstLineBox() || curr->xPos() < leftSide)
508                 leftSide = curr->xPos();
509             if (curr == firstLineBox() || curr->xPos() + curr->width() > rightSide)
510                 rightSide = curr->xPos() + curr->width();
511         }
512         result.setWidth(rightSide - leftSide);
513         result.setX(leftSide);
514         result.setHeight(lastLineBox()->yPos() + lastLineBox()->height() - firstLineBox()->yPos());
515         result.setY(firstLineBox()->yPos());
516     }
517
518     return result;
519 }
520
521 IntRect RenderInline::clippedOverflowRectForRepaint(RenderBox* repaintContainer)
522 {
523     // Only run-ins are allowed in here during layout.
524     ASSERT(!view() || !view()->layoutStateEnabled() || isRunIn());
525
526     if (!firstLineBox() && !continuation())
527         return IntRect();
528
529     // Find our leftmost position.
530     IntRect boundingBox(linesBoundingBox());
531     int left = boundingBox.x();
532     int top = boundingBox.y();
533
534     // Now invalidate a rectangle.
535     int ow = style() ? style()->outlineSize() : 0;
536     
537     // We need to add in the relative position offsets of any inlines (including us) up to our
538     // containing block.
539     RenderBlock* cb = containingBlock();
540     for (RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isRenderInline() && inlineFlow != cb; 
541          inlineFlow = inlineFlow->parent()) {
542          if (inlineFlow->style()->position() == RelativePosition && inlineFlow->hasLayer())
543             toRenderBox(inlineFlow)->layer()->relativePositionOffset(left, top);
544     }
545
546     IntRect r(-ow + left, -ow + top, boundingBox.width() + ow * 2, boundingBox.height() + ow * 2);
547     if (cb->hasColumns())
548         cb->adjustRectForColumns(r);
549
550     if (cb->hasOverflowClip()) {
551         // cb->height() is inaccurate if we're in the middle of a layout of |cb|, so use the
552         // layer's size instead.  Even if the layer's size is wrong, the layer itself will repaint
553         // anyway if its size does change.
554         int x = r.x();
555         int y = r.y();
556         IntRect boxRect(0, 0, cb->layer()->width(), cb->layer()->height());
557         cb->layer()->subtractScrolledContentOffset(x, y); // For overflow:auto/scroll/hidden.
558         IntRect repaintRect(x, y, r.width(), r.height());
559         r = intersection(repaintRect, boxRect);
560     }
561     ASSERT(repaintContainer != this);
562     cb->computeRectForRepaint(repaintContainer, r);
563
564     if (ow) {
565         for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
566             if (!curr->isText()) {
567                 IntRect childRect = curr->rectWithOutlineForRepaint(repaintContainer, ow);
568                 r.unite(childRect);
569             }
570         }
571
572         if (continuation() && !continuation()->isInline()) {
573             IntRect contRect = continuation()->rectWithOutlineForRepaint(repaintContainer, ow);
574             r.unite(contRect);
575         }
576     }
577
578     return r;
579 }
580
581 IntRect RenderInline::rectWithOutlineForRepaint(RenderBox* repaintContainer, int outlineWidth)
582 {
583     IntRect r(RenderContainer::rectWithOutlineForRepaint(repaintContainer, outlineWidth));
584     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
585         if (!curr->isText())
586             r.unite(curr->rectWithOutlineForRepaint(repaintContainer, outlineWidth));
587     }
588     return r;
589 }
590
591 void RenderInline::updateDragState(bool dragOn)
592 {
593     RenderContainer::updateDragState(dragOn);
594     if (continuation())
595         continuation()->updateDragState(dragOn);
596 }
597
598 void RenderInline::childBecameNonInline(RenderObject* child)
599 {
600     // We have to split the parent flow.
601     RenderBlock* newBox = createAnonymousBlock();
602     RenderContainer* oldContinuation = continuation();
603     setContinuation(newBox);
604     RenderObject* beforeChild = child->nextSibling();
605     removeChildNode(child);
606     splitFlow(beforeChild, newBox, child, oldContinuation);
607 }
608
609 void RenderInline::updateHitTestResult(HitTestResult& result, const IntPoint& point)
610 {
611     if (result.innerNode())
612         return;
613
614     Node* node = element();
615     IntPoint localPoint(point);
616     if (node) {
617         if (isInlineContinuation()) {
618             // We're in the continuation of a split inline.  Adjust our local point to be in the coordinate space
619             // of the principal renderer's containing block.  This will end up being the innerNonSharedNode.
620             RenderBlock* firstBlock = node->renderer()->containingBlock();
621             
622             // Get our containing block.
623             RenderBox* block = this;
624             if (isInline())
625                 block = containingBlock();
626         
627             localPoint.move(block->x() - firstBlock->x(), block->y() - firstBlock->y());
628         }
629
630         result.setInnerNode(node);
631         if (!result.innerNonSharedNode())
632             result.setInnerNonSharedNode(node);
633         result.setLocalPoint(localPoint);
634     }
635 }
636
637 void RenderInline::dirtyLineBoxes(bool fullLayout, bool)
638 {
639     if (fullLayout)
640         m_lineBoxes.deleteLineBoxes(renderArena());
641     else
642         m_lineBoxes.dirtyLineBoxes();
643 }
644
645 InlineBox* RenderInline::createInlineBox(bool, bool, bool)
646 {
647     InlineFlowBox* flowBox = new (renderArena()) InlineFlowBox(this);
648     m_lineBoxes.appendLineBox(flowBox);
649     return flowBox;
650 }
651
652 int RenderInline::lineHeight(bool firstLine, bool /*isRootLineBox*/) const
653 {
654     if (firstLine && document()->usesFirstLineRules()) {
655         RenderStyle* s = style(firstLine);
656         if (s != style())
657             return s->computedLineHeight();
658     }
659     
660     if (m_lineHeight == -1)
661         m_lineHeight = style()->computedLineHeight();
662     
663     return m_lineHeight;
664 }
665
666 IntSize RenderInline::relativePositionedInlineOffset(const RenderObject* child) const
667 {
668     ASSERT(isRelPositioned());
669     if (!isRelPositioned())
670         return IntSize();
671
672     // When we have an enclosing relpositioned inline, we need to add in the offset of the first line
673     // box from the rest of the content, but only in the cases where we know we're positioned
674     // relative to the inline itself.
675
676     IntSize offset;
677     int sx;
678     int sy;
679     if (firstLineBox()) {
680         sx = firstLineBox()->xPos();
681         sy = firstLineBox()->yPos();
682     } else {
683         sx = staticX();
684         sy = staticY();
685     }
686
687     if (!child->hasStaticX())
688         offset.setWidth(sx);
689     // This is not terribly intuitive, but we have to match other browsers.  Despite being a block display type inside
690     // an inline, we still keep our x locked to the left of the relative positioned inline.  Arguably the correct
691     // behavior would be to go flush left to the block that contains the inline, but that isn't what other browsers
692     // do.
693     else if (!child->style()->isOriginalDisplayInlineType())
694         // Avoid adding in the left border/padding of the containing block twice.  Subtract it out.
695         offset.setWidth(sx - (child->containingBlock()->borderLeft() + child->containingBlock()->paddingLeft()));
696
697     if (!child->hasStaticY())
698         offset.setHeight(sy);
699
700     return offset;
701 }
702
703 void RenderInline::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty)
704 {
705     for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
706         graphicsContext->addFocusRingRect(IntRect(tx + curr->xPos(), ty + curr->yPos(), curr->width(), curr->height()));
707
708     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
709         if (!curr->isText() && !curr->isListMarker() && curr->isBox()) {
710             RenderBox* box = toRenderBox(curr);
711             FloatPoint pos;
712             // FIXME: This doesn't work correctly with transforms.
713             if (box->layer()) 
714                 pos = curr->localToAbsolute();
715             else
716                 pos = FloatPoint(tx + box->x(), ty + box->y());
717             box->addFocusRingRects(graphicsContext, pos.x(), pos.y());
718         }
719     }
720
721     if (continuation())
722         continuation()->addFocusRingRects(graphicsContext, 
723                                           tx - containingBlock()->x() + continuation()->x(),
724                                           ty - containingBlock()->y() + continuation()->y());
725 }
726
727 void RenderInline::paintOutline(GraphicsContext* graphicsContext, int tx, int ty)
728 {
729     if (!hasOutline())
730         return;
731     
732     if (style()->outlineStyleIsAuto() || hasOutlineAnnotation()) {
733         int ow = style()->outlineWidth();
734         Color oc = style()->outlineColor();
735         if (!oc.isValid())
736             oc = style()->color();
737
738         graphicsContext->initFocusRing(ow, style()->outlineOffset());
739         addFocusRingRects(graphicsContext, tx, ty);
740         if (style()->outlineStyleIsAuto())
741             graphicsContext->drawFocusRing(oc);
742         else
743             addPDFURLRect(graphicsContext, graphicsContext->focusRingBoundingRect());
744         graphicsContext->clearFocusRing();
745     }
746
747     if (style()->outlineStyleIsAuto() || style()->outlineStyle() == BNONE)
748         return;
749
750     Vector<IntRect> rects;
751
752     rects.append(IntRect());
753     for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
754         rects.append(IntRect(curr->xPos(), curr->yPos(), curr->width(), curr->height()));
755
756     rects.append(IntRect());
757
758     for (unsigned i = 1; i < rects.size() - 1; i++)
759         paintOutlineForLine(graphicsContext, tx, ty, rects.at(i - 1), rects.at(i), rects.at(i + 1));
760 }
761
762 void RenderInline::paintOutlineForLine(GraphicsContext* graphicsContext, int tx, int ty,
763                                        const IntRect& lastline, const IntRect& thisline, const IntRect& nextline)
764 {
765     int ow = style()->outlineWidth();
766     EBorderStyle os = style()->outlineStyle();
767     Color oc = style()->outlineColor();
768     if (!oc.isValid())
769         oc = style()->color();
770
771     int offset = style()->outlineOffset();
772
773     int t = ty + thisline.y() - offset;
774     int l = tx + thisline.x() - offset;
775     int b = ty + thisline.bottom() + offset;
776     int r = tx + thisline.right() + offset;
777     
778     // left edge
779     drawBorder(graphicsContext,
780                l - ow,
781                t - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.right() - 1) <= thisline.x() ? ow : 0),
782                l,
783                b + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.right() - 1) <= thisline.x() ? ow : 0),
784                BSLeft,
785                oc, style()->color(), os,
786                (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.right() - 1) <= thisline.x() ? ow : -ow),
787                (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.right() - 1) <= thisline.x() ? ow : -ow));
788     
789     // right edge
790     drawBorder(graphicsContext,
791                r,
792                t - (lastline.isEmpty() || lastline.right() < thisline.right() || (thisline.right() - 1) <= lastline.x() ? ow : 0),
793                r + ow,
794                b + (nextline.isEmpty() || nextline.right() <= thisline.right() || (thisline.right() - 1) <= nextline.x() ? ow : 0),
795                BSRight,
796                oc, style()->color(), os,
797                (lastline.isEmpty() || lastline.right() < thisline.right() || (thisline.right() - 1) <= lastline.x() ? ow : -ow),
798                (nextline.isEmpty() || nextline.right() <= thisline.right() || (thisline.right() - 1) <= nextline.x() ? ow : -ow));
799     // upper edge
800     if (thisline.x() < lastline.x())
801         drawBorder(graphicsContext,
802                    l - ow,
803                    t - ow,
804                    min(r+ow, (lastline.isEmpty() ? 1000000 : tx + lastline.x())),
805                    t ,
806                    BSTop, oc, style()->color(), os,
807                    ow,
808                    (!lastline.isEmpty() && tx + lastline.x() + 1 < r + ow) ? -ow : ow);
809     
810     if (lastline.right() < thisline.right())
811         drawBorder(graphicsContext,
812                    max(lastline.isEmpty() ? -1000000 : tx + lastline.right(), l - ow),
813                    t - ow,
814                    r + ow,
815                    t ,
816                    BSTop, oc, style()->color(), os,
817                    (!lastline.isEmpty() && l - ow < tx + lastline.right()) ? -ow : ow,
818                    ow);
819     
820     // lower edge
821     if (thisline.x() < nextline.x())
822         drawBorder(graphicsContext,
823                    l - ow,
824                    b,
825                    min(r + ow, !nextline.isEmpty() ? tx + nextline.x() + 1 : 1000000),
826                    b + ow,
827                    BSBottom, oc, style()->color(), os,
828                    ow,
829                    (!nextline.isEmpty() && tx + nextline.x() + 1 < r + ow) ? -ow : ow);
830     
831     if (nextline.right() < thisline.right())
832         drawBorder(graphicsContext,
833                    max(!nextline.isEmpty() ? tx + nextline.right() : -1000000, l - ow),
834                    b,
835                    r + ow,
836                    b + ow,
837                    BSBottom, oc, style()->color(), os,
838                    (!nextline.isEmpty() && l - ow < tx + nextline.right()) ? -ow : ow,
839                    ow);
840 }
841
842 } // namespace WebCore