OSDN Git Service

Merge WebKit at r71558: Initial merge by git.
[android-x86/external-webkit.git] / WebCore / rendering / RenderInline.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  */
22
23 #include "config.h"
24 #include "RenderInline.h"
25
26 #include "Chrome.h"
27 #include "FloatQuad.h"
28 #include "GraphicsContext.h"
29 #include "HitTestResult.h"
30 #include "Page.h"
31 #include "RenderArena.h"
32 #include "RenderBlock.h"
33 #include "RenderLayer.h"
34 #include "RenderTheme.h"
35 #include "RenderView.h"
36 #include "TransformState.h"
37 #include "VisiblePosition.h"
38
39 #if ENABLE(DASHBOARD_SUPPORT)
40 #include "Frame.h"
41 #endif
42
43 using namespace std;
44
45 namespace WebCore {
46
47 RenderInline::RenderInline(Node* node)
48     : RenderBoxModelObject(node)
49     , m_continuation(0)
50     , m_lineHeight(-1)
51     , m_verticalPosition(PositionUndefined)
52 {
53     setChildrenInline(true);
54 }
55
56 void RenderInline::destroy()
57 {
58     // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
59     // properly dirty line boxes that they are removed from.  Effects that do :before/:after only on hover could crash otherwise.
60     children()->destroyLeftoverChildren();
61
62     // Destroy our continuation before anything other than anonymous children.
63     // The reason we don't destroy it before anonymous children is that they may
64     // have continuations of their own that are anonymous children of our continuation.
65     if (m_continuation) {
66         m_continuation->destroy();
67         m_continuation = 0;
68     }
69     
70     if (!documentBeingDestroyed()) {
71         if (firstLineBox()) {
72             // We can't wait for RenderBoxModelObject::destroy to clear the selection,
73             // because by then we will have nuked the line boxes.
74             // FIXME: The SelectionController should be responsible for this when it
75             // is notified of DOM mutations.
76             if (isSelectionBorder())
77                 view()->clearSelection();
78
79             // If line boxes are contained inside a root, that means we're an inline.
80             // In that case, we need to remove all the line boxes so that the parent
81             // lines aren't pointing to deleted children. If the first line box does
82             // not have a parent that means they are either already disconnected or
83             // root lines that can just be destroyed without disconnecting.
84             if (firstLineBox()->parent()) {
85                 for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox())
86                     box->remove();
87             }
88         } else if (isInline() && parent())
89             parent()->dirtyLinesFromChangedChild(this);
90     }
91
92     m_lineBoxes.deleteLineBoxes(renderArena());
93
94     RenderBoxModelObject::destroy();
95 }
96
97 RenderInline* RenderInline::inlineElementContinuation() const
98 {
99     if (!m_continuation || m_continuation->isInline())
100         return toRenderInline(m_continuation);
101     return toRenderBlock(m_continuation)->inlineElementContinuation();
102 }
103
104 void RenderInline::updateBoxModelInfoFromStyle()
105 {
106     RenderBoxModelObject::updateBoxModelInfoFromStyle();
107
108     setInline(true); // Needed for run-ins, since run-in is considered a block display type.
109
110     // FIXME: Support transforms and reflections on inline flows someday.
111     setHasTransform(false);
112     setHasReflection(false);    
113 }
114
115 void RenderInline::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
116 {
117     RenderBoxModelObject::styleDidChange(diff, oldStyle);
118
119     // Ensure that all of the split inlines pick up the new style. We
120     // only do this if we're an inline, since we don't want to propagate
121     // a block's style to the other inlines.
122     // e.g., <font>foo <h4>goo</h4> moo</font>.  The <font> inlines before
123     // and after the block share the same style, but the block doesn't
124     // need to pass its style on to anyone else.
125     for (RenderInline* currCont = inlineElementContinuation(); currCont; currCont = currCont->inlineElementContinuation()) {
126         RenderBoxModelObject* nextCont = currCont->continuation();
127         currCont->setContinuation(0);
128         currCont->setStyle(style());
129         currCont->setContinuation(nextCont);
130     }
131
132     m_lineHeight = -1;
133
134     // Update pseudos for :before and :after now.
135     if (!isAnonymous() && document()->usesBeforeAfterRules()) {
136         children()->updateBeforeAfterContent(this, BEFORE);
137         children()->updateBeforeAfterContent(this, AFTER);
138     }
139 }
140
141 void RenderInline::addChild(RenderObject* newChild, RenderObject* beforeChild)
142 {
143     if (continuation())
144         return addChildToContinuation(newChild, beforeChild);
145     return addChildIgnoringContinuation(newChild, beforeChild);
146 }
147
148 static RenderBoxModelObject* nextContinuation(RenderObject* renderer)
149 {
150     if (renderer->isInline() && !renderer->isReplaced())
151         return toRenderInline(renderer)->continuation();
152     return toRenderBlock(renderer)->inlineElementContinuation();
153 }
154
155 RenderBoxModelObject* RenderInline::continuationBefore(RenderObject* beforeChild)
156 {
157     if (beforeChild && beforeChild->parent() == this)
158         return this;
159
160     RenderBoxModelObject* curr = nextContinuation(this);
161     RenderBoxModelObject* nextToLast = this;
162     RenderBoxModelObject* last = this;
163     while (curr) {
164         if (beforeChild && beforeChild->parent() == curr) {
165             if (curr->firstChild() == beforeChild)
166                 return last;
167             return curr;
168         }
169
170         nextToLast = last;
171         last = curr;
172         curr = nextContinuation(curr);
173     }
174
175     if (!beforeChild && !last->firstChild())
176         return nextToLast;
177     return last;
178 }
179
180 void RenderInline::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild)
181 {
182     // Make sure we don't append things after :after-generated content if we have it.
183     if (!beforeChild && isAfterContent(lastChild()))
184         beforeChild = lastChild();
185
186     if (!newChild->isInline() && !newChild->isFloatingOrPositioned()) {
187         // We are placing a block inside an inline. We have to perform a split of this
188         // inline into continuations.  This involves creating an anonymous block box to hold
189         // |newChild|.  We then make that block box a continuation of this inline.  We take all of
190         // the children after |beforeChild| and put them in a clone of this object.
191         RefPtr<RenderStyle> newStyle = RenderStyle::create();
192         newStyle->inheritFrom(style());
193         newStyle->setDisplay(BLOCK);
194
195         RenderBlock* newBox = new (renderArena()) RenderBlock(document() /* anonymous box */);
196         newBox->setStyle(newStyle.release());
197         RenderBoxModelObject* oldContinuation = continuation();
198         setContinuation(newBox);
199
200         // Someone may have put a <p> inside a <q>, causing a split.  When this happens, the :after content
201         // has to move into the inline continuation.  Call updateBeforeAfterContent to ensure that our :after
202         // content gets properly destroyed.
203         bool isLastChild = (beforeChild == lastChild());
204         if (document()->usesBeforeAfterRules())
205             children()->updateBeforeAfterContent(this, AFTER);
206         if (isLastChild && beforeChild != lastChild())
207             beforeChild = 0; // We destroyed the last child, so now we need to update our insertion
208                              // point to be 0.  It's just a straight append now.
209
210         splitFlow(beforeChild, newBox, newChild, oldContinuation);
211         return;
212     }
213
214     RenderBoxModelObject::addChild(newChild, beforeChild);
215
216     newChild->setNeedsLayoutAndPrefWidthsRecalc();
217 }
218
219 RenderInline* RenderInline::cloneInline(RenderInline* src)
220 {
221     RenderInline* o = new (src->renderArena()) RenderInline(src->node());
222     o->setStyle(src->style());
223     return o;
224 }
225
226 void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock,
227                                 RenderBlock* middleBlock,
228                                 RenderObject* beforeChild, RenderBoxModelObject* oldCont)
229 {
230     // Create a clone of this inline.
231     RenderInline* clone = cloneInline(this);
232     clone->setContinuation(oldCont);
233
234     // Now take all of the children from beforeChild to the end and remove
235     // them from |this| and place them in the clone.
236     RenderObject* o = beforeChild;
237     while (o) {
238         RenderObject* tmp = o;
239         o = tmp->nextSibling();
240         clone->addChildIgnoringContinuation(children()->removeChildNode(this, tmp), 0);
241         tmp->setNeedsLayoutAndPrefWidthsRecalc();
242     }
243
244     // Hook |clone| up as the continuation of the middle block.
245     middleBlock->setContinuation(clone);
246
247     // We have been reparented and are now under the fromBlock.  We need
248     // to walk up our inline parent chain until we hit the containing block.
249     // Once we hit the containing block we're done.
250     RenderBoxModelObject* curr = toRenderBoxModelObject(parent());
251     RenderBoxModelObject* currChild = this;
252     
253     // FIXME: Because splitting is O(n^2) as tags nest pathologically, we cap the depth at which we're willing to clone.
254     // There will eventually be a better approach to this problem that will let us nest to a much
255     // greater depth (see bugzilla bug 13430) but for now we have a limit.  This *will* result in
256     // incorrect rendering, but the alternative is to hang forever.
257     unsigned splitDepth = 1;
258     const unsigned cMaxSplitDepth = 200; 
259     while (curr && curr != fromBlock) {
260         ASSERT(curr->isRenderInline());
261         if (splitDepth < cMaxSplitDepth) {
262             // Create a new clone.
263             RenderInline* cloneChild = clone;
264             clone = cloneInline(toRenderInline(curr));
265
266             // Insert our child clone as the first child.
267             clone->addChildIgnoringContinuation(cloneChild, 0);
268
269             // Hook the clone up as a continuation of |curr|.
270             RenderInline* inlineCurr = toRenderInline(curr);
271             oldCont = inlineCurr->continuation();
272             inlineCurr->setContinuation(clone);
273             clone->setContinuation(oldCont);
274
275             // Someone may have indirectly caused a <q> to split.  When this happens, the :after content
276             // has to move into the inline continuation.  Call updateBeforeAfterContent to ensure that the inline's :after
277             // content gets properly destroyed.
278             if (document()->usesBeforeAfterRules())
279                 inlineCurr->children()->updateBeforeAfterContent(inlineCurr, AFTER);
280
281             // Now we need to take all of the children starting from the first child
282             // *after* currChild and append them all to the clone.
283             o = currChild->nextSibling();
284             while (o) {
285                 RenderObject* tmp = o;
286                 o = tmp->nextSibling();
287                 clone->addChildIgnoringContinuation(inlineCurr->children()->removeChildNode(curr, tmp), 0);
288                 tmp->setNeedsLayoutAndPrefWidthsRecalc();
289             }
290         }
291         
292         // Keep walking up the chain.
293         currChild = curr;
294         curr = toRenderBoxModelObject(curr->parent());
295         splitDepth++;
296     }
297
298     // Now we are at the block level. We need to put the clone into the toBlock.
299     toBlock->children()->appendChildNode(toBlock, clone);
300
301     // Now take all the children after currChild and remove them from the fromBlock
302     // and put them in the toBlock.
303     o = currChild->nextSibling();
304     while (o) {
305         RenderObject* tmp = o;
306         o = tmp->nextSibling();
307         toBlock->children()->appendChildNode(toBlock, fromBlock->children()->removeChildNode(fromBlock, tmp));
308     }
309 }
310
311 void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
312                              RenderObject* newChild, RenderBoxModelObject* oldCont)
313 {
314     RenderBlock* pre = 0;
315     RenderBlock* block = containingBlock();
316     
317     // Delete our line boxes before we do the inline split into continuations.
318     block->deleteLineBoxTree();
319     
320     bool madeNewBeforeBlock = false;
321     if (block->isAnonymousBlock() && (!block->parent() || !block->parent()->createsAnonymousWrapper())) {
322         // We can reuse this block and make it the preBlock of the next continuation.
323         pre = block;
324         pre->removePositionedObjects(0);
325         block = block->containingBlock();
326     } else {
327         // No anonymous block available for use.  Make one.
328         pre = block->createAnonymousBlock();
329         madeNewBeforeBlock = true;
330     }
331
332     RenderBlock* post = block->createAnonymousBlock();
333
334     RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling();
335     if (madeNewBeforeBlock)
336         block->children()->insertChildNode(block, pre, boxFirst);
337     block->children()->insertChildNode(block, newBlockBox, boxFirst);
338     block->children()->insertChildNode(block, post, boxFirst);
339     block->setChildrenInline(false);
340     
341     if (madeNewBeforeBlock) {
342         RenderObject* o = boxFirst;
343         while (o) {
344             RenderObject* no = o;
345             o = no->nextSibling();
346             pre->children()->appendChildNode(pre, block->children()->removeChildNode(block, no));
347             no->setNeedsLayoutAndPrefWidthsRecalc();
348         }
349     }
350
351     splitInlines(pre, post, newBlockBox, beforeChild, oldCont);
352
353     // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
354     // time in makeChildrenNonInline by just setting this explicitly up front.
355     newBlockBox->setChildrenInline(false);
356
357     // We delayed adding the newChild until now so that the |newBlockBox| would be fully
358     // connected, thus allowing newChild access to a renderArena should it need
359     // to wrap itself in additional boxes (e.g., table construction).
360     newBlockBox->addChild(newChild);
361
362     // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
363     // get deleted properly.  Because objects moves from the pre block into the post block, we want to
364     // make new line boxes instead of leaving the old line boxes around.
365     pre->setNeedsLayoutAndPrefWidthsRecalc();
366     block->setNeedsLayoutAndPrefWidthsRecalc();
367     post->setNeedsLayoutAndPrefWidthsRecalc();
368 }
369
370 void RenderInline::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild)
371 {
372     RenderBoxModelObject* flow = continuationBefore(beforeChild);
373     ASSERT(!beforeChild || beforeChild->parent()->isRenderBlock() || beforeChild->parent()->isRenderInline());
374     RenderBoxModelObject* beforeChildParent = 0;
375     if (beforeChild)
376         beforeChildParent = toRenderBoxModelObject(beforeChild->parent());
377     else {
378         RenderBoxModelObject* cont = nextContinuation(flow);
379         if (cont)
380             beforeChildParent = cont;
381         else
382             beforeChildParent = flow;
383     }
384
385     if (newChild->isFloatingOrPositioned())
386         return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
387
388     // A continuation always consists of two potential candidates: an inline or an anonymous
389     // block box holding block children.
390     bool childInline = newChild->isInline();
391     bool bcpInline = beforeChildParent->isInline();
392     bool flowInline = flow->isInline();
393
394     if (flow == beforeChildParent)
395         return flow->addChildIgnoringContinuation(newChild, beforeChild);
396     else {
397         // The goal here is to match up if we can, so that we can coalesce and create the
398         // minimal # of continuations needed for the inline.
399         if (childInline == bcpInline)
400             return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
401         else if (flowInline == childInline)
402             return flow->addChildIgnoringContinuation(newChild, 0); // Just treat like an append.
403         else
404             return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
405     }
406 }
407
408 void RenderInline::paint(PaintInfo& paintInfo, int tx, int ty)
409 {
410     m_lineBoxes.paint(this, paintInfo, tx, ty);
411 }
412
413 void RenderInline::absoluteRects(Vector<IntRect>& rects, int tx, int ty)
414 {
415     if (InlineFlowBox* curr = firstLineBox()) {
416         for (; curr; curr = curr->nextLineBox())
417             rects.append(IntRect(tx + curr->x(), ty + curr->y(), curr->logicalWidth(), curr->logicalHeight()));
418     } else
419         rects.append(IntRect(tx, ty, 0, 0));
420
421     if (continuation()) {
422         if (continuation()->isBox()) {
423             RenderBox* box = toRenderBox(continuation());
424             continuation()->absoluteRects(rects, 
425                                           tx - containingBlock()->x() + box->x(),
426                                           ty - containingBlock()->y() + box->y());
427         } else
428             continuation()->absoluteRects(rects, tx - containingBlock()->x(), ty - containingBlock()->y());
429     }
430 }
431
432 void RenderInline::absoluteQuads(Vector<FloatQuad>& quads)
433 {
434     if (InlineFlowBox* curr = firstLineBox()) {
435         for (; curr; curr = curr->nextLineBox()) {
436             FloatRect localRect(curr->x(), curr->y(), curr->logicalWidth(), curr->logicalHeight());
437             quads.append(localToAbsoluteQuad(localRect));
438         }
439     } else
440         quads.append(localToAbsoluteQuad(FloatRect()));
441
442     if (continuation())
443         continuation()->absoluteQuads(quads);
444 }
445
446 int RenderInline::offsetLeft() const
447 {
448     int x = RenderBoxModelObject::offsetLeft();
449     if (firstLineBox())
450         x += firstLineBox()->x();
451     return x;
452 }
453
454 int RenderInline::offsetTop() const
455 {
456     int y = RenderBoxModelObject::offsetTop();
457     if (firstLineBox())
458         y += firstLineBox()->y();
459     return y;
460 }
461
462 static int computeMargin(const RenderInline* renderer, const Length& margin)
463 {
464     if (margin.isAuto())
465         return 0;
466     if (margin.isFixed())
467         return margin.value();
468     if (margin.isPercent())
469         return margin.calcMinValue(max(0, renderer->containingBlock()->availableLogicalWidth()));
470     return 0;
471 }
472
473 int RenderInline::marginLeft() const
474 {
475     if (!style()->isHorizontalWritingMode())
476         return 0;
477     return computeMargin(this, style()->marginLeft());
478 }
479
480 int RenderInline::marginRight() const
481 {
482     if (!style()->isHorizontalWritingMode())
483         return 0;
484     return computeMargin(this, style()->marginRight());
485 }
486
487 int RenderInline::marginTop() const
488 {
489     if (style()->isHorizontalWritingMode())
490         return 0;
491     return computeMargin(this, style()->marginTop());
492 }
493
494 int RenderInline::marginBottom() const
495 {
496     if (style()->isHorizontalWritingMode())
497         return 0;
498     return computeMargin(this, style()->marginBottom());
499 }
500
501 int RenderInline::marginStart() const
502 {
503     return computeMargin(this, style()->marginStart());
504 }
505
506 int RenderInline::marginEnd() const
507 {
508     return computeMargin(this, style()->marginEnd());
509 }
510
511 const char* RenderInline::renderName() const
512 {
513     if (isRelPositioned())
514         return "RenderInline (relative positioned)";
515     if (isAnonymous())
516         return "RenderInline (generated)";
517     if (isRunIn())
518         return "RenderInline (run-in)";
519     return "RenderInline";
520 }
521
522 bool RenderInline::nodeAtPoint(const HitTestRequest& request, HitTestResult& result,
523                                 int x, int y, int tx, int ty, HitTestAction hitTestAction)
524 {
525     return m_lineBoxes.hitTest(this, request, result, x, y, tx, ty, hitTestAction);
526 }
527
528 VisiblePosition RenderInline::positionForPoint(const IntPoint& point)
529 {
530     // FIXME: Does not deal with relative positioned inlines (should it?)
531     RenderBlock* cb = containingBlock();
532     if (firstLineBox()) {
533         // This inline actually has a line box.  We must have clicked in the border/padding of one of these boxes.  We
534         // should try to find a result by asking our containing block.
535         return cb->positionForPoint(point);
536     }
537
538     // Translate the coords from the pre-anonymous block to the post-anonymous block.
539     int parentBlockX = cb->x() + point.x();
540     int parentBlockY = cb->y() + point.y();
541     RenderBoxModelObject* c = continuation();
542     while (c) {
543         RenderBox* contBlock = c->isInline() ? c->containingBlock() : toRenderBlock(c);
544         if (c->isInline() || c->firstChild())
545             return c->positionForCoordinates(parentBlockX - contBlock->x(), parentBlockY - contBlock->y());
546         c = toRenderBlock(c)->inlineElementContinuation();
547     }
548     
549     return RenderBoxModelObject::positionForPoint(point);
550 }
551
552 IntRect RenderInline::linesBoundingBox() const
553 {
554     IntRect result;
555     
556     // 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
557     // 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
558     // builds and help us someday figure out why.  We also put in a redundant check of lastLineBox() to avoid the crash for now.
559     ASSERT(!firstLineBox() == !lastLineBox());  // Either both are null or both exist.
560     if (firstLineBox() && lastLineBox()) {
561         // Return the width of the minimal left side and the maximal right side.
562         int logicalLeftSide = 0;
563         int logicalRightSide = 0;
564         for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
565             if (curr == firstLineBox() || curr->logicalLeft() < logicalLeftSide)
566                 logicalLeftSide = curr->logicalLeft();
567             if (curr == firstLineBox() || curr->logicalRight() > logicalRightSide)
568                 logicalRightSide = curr->logicalRight();
569         }
570         
571         bool isHorizontal = style()->isHorizontalWritingMode();
572         
573         int x = isHorizontal ? logicalLeftSide : firstLineBox()->x();
574         int y = isHorizontal ? firstLineBox()->y() : logicalLeftSide;
575         int width = isHorizontal ? logicalRightSide - logicalLeftSide : lastLineBox()->logicalBottom() - x;
576         int height = isHorizontal ? lastLineBox()->logicalBottom() - y : logicalRightSide - logicalLeftSide;
577         result = IntRect(x, y, width, height);
578     }
579
580     return result;
581 }
582
583 IntRect RenderInline::linesVisibleOverflowBoundingBox() const
584 {
585     if (!firstLineBox() || !lastLineBox())
586         return IntRect();
587
588     // Return the width of the minimal left side and the maximal right side.
589     int logicalLeftSide = numeric_limits<int>::max();
590     int logicalRightSide = numeric_limits<int>::min();
591     for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
592         logicalLeftSide = min(logicalLeftSide, curr->logicalLeftVisibleOverflow());
593         logicalRightSide = max(logicalRightSide, curr->logicalRightVisibleOverflow());
594     }
595
596     bool isHorizontal = style()->isHorizontalWritingMode();
597         
598     int x = isHorizontal ? logicalLeftSide : firstLineBox()->leftVisibleOverflow();
599     int y = isHorizontal ? firstLineBox()->topVisibleOverflow() : logicalLeftSide;
600     int width = isHorizontal ? logicalRightSide - logicalLeftSide : lastLineBox()->rightVisibleOverflow() - firstLineBox()->leftVisibleOverflow();
601     int height = isHorizontal ? lastLineBox()->bottomVisibleOverflow() - firstLineBox()->topVisibleOverflow() : logicalRightSide - logicalLeftSide;
602     return IntRect(x, y, width, height);
603 }
604
605 IntRect RenderInline::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
606 {
607     // Only run-ins are allowed in here during layout.
608     ASSERT(!view() || !view()->layoutStateEnabled() || isRunIn());
609
610     if (!firstLineBox() && !continuation())
611         return IntRect();
612
613     // Find our leftmost position.
614     IntRect boundingBox(linesVisibleOverflowBoundingBox());
615     int left = boundingBox.x();
616     int top = boundingBox.y();
617
618     // Now invalidate a rectangle.
619     int ow = style() ? style()->outlineSize() : 0;
620     
621     // We need to add in the relative position offsets of any inlines (including us) up to our
622     // containing block.
623     RenderBlock* cb = containingBlock();
624     for (RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isRenderInline() && inlineFlow != cb; 
625          inlineFlow = inlineFlow->parent()) {
626          if (inlineFlow->style()->position() == RelativePosition && inlineFlow->hasLayer())
627             toRenderInline(inlineFlow)->layer()->relativePositionOffset(left, top);
628     }
629
630     IntRect r(-ow + left, -ow + top, boundingBox.width() + ow * 2, boundingBox.height() + ow * 2);
631     cb->flipForWritingMode(r);
632
633     if (cb->hasColumns())
634         cb->adjustRectForColumns(r);
635
636     if (cb->hasOverflowClip()) {
637         // cb->height() is inaccurate if we're in the middle of a layout of |cb|, so use the
638         // layer's size instead.  Even if the layer's size is wrong, the layer itself will repaint
639         // anyway if its size does change.
640         IntRect repaintRect(r);
641         repaintRect.move(-cb->layer()->scrolledContentOffset()); // For overflow:auto/scroll/hidden.
642
643         IntRect boxRect(0, 0, cb->layer()->width(), cb->layer()->height());
644         r = intersection(repaintRect, boxRect);
645     }
646     
647     // FIXME: need to ensure that we compute the correct repaint rect when the repaint container
648     // is an inline.
649     if (repaintContainer != this)
650         cb->computeRectForRepaint(repaintContainer, r);
651
652     if (ow) {
653         for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
654             if (!curr->isText()) {
655                 IntRect childRect = curr->rectWithOutlineForRepaint(repaintContainer, ow);
656                 r.unite(childRect);
657             }
658         }
659
660         if (continuation() && !continuation()->isInline()) {
661             IntRect contRect = continuation()->rectWithOutlineForRepaint(repaintContainer, ow);
662             r.unite(contRect);
663         }
664     }
665
666     return r;
667 }
668
669 IntRect RenderInline::rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, int outlineWidth)
670 {
671     IntRect r(RenderBoxModelObject::rectWithOutlineForRepaint(repaintContainer, outlineWidth));
672     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
673         if (!curr->isText())
674             r.unite(curr->rectWithOutlineForRepaint(repaintContainer, outlineWidth));
675     }
676     return r;
677 }
678
679 void RenderInline::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& rect, bool fixed)
680 {
681     if (RenderView* v = view()) {
682         // LayoutState is only valid for root-relative repainting
683         if (v->layoutStateEnabled() && !repaintContainer) {
684             LayoutState* layoutState = v->layoutState();
685             if (style()->position() == RelativePosition && layer())
686                 rect.move(layer()->relativePositionOffset());
687             rect.move(layoutState->m_paintOffset);
688             if (layoutState->m_clipped)
689                 rect.intersect(layoutState->m_clipRect);
690             return;
691         }
692     }
693
694     if (repaintContainer == this)
695         return;
696
697     bool containerSkipped;
698     RenderObject* o = container(repaintContainer, &containerSkipped);
699     if (!o)
700         return;
701
702     IntPoint topLeft = rect.location();
703
704     if (o->isBlockFlow() && style()->position() != AbsolutePosition && style()->position() != FixedPosition) {
705         RenderBlock* cb = toRenderBlock(o);
706         if (cb->hasColumns()) {
707             IntRect repaintRect(topLeft, rect.size());
708             cb->adjustRectForColumns(repaintRect);
709             topLeft = repaintRect.location();
710             rect = repaintRect;
711         }
712     }
713
714     if (style()->position() == RelativePosition && layer()) {
715         // Apply the relative position offset when invalidating a rectangle.  The layer
716         // is translated, but the render box isn't, so we need to do this to get the
717         // right dirty rect.  Since this is called from RenderObject::setStyle, the relative position
718         // flag on the RenderObject has been cleared, so use the one on the style().
719         topLeft += layer()->relativePositionOffset();
720     }
721     
722     // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
723     // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
724     if (o->hasOverflowClip()) {
725         RenderBox* containerBox = toRenderBox(o);
726
727         // o->height() is inaccurate if we're in the middle of a layout of |o|, so use the
728         // layer's size instead.  Even if the layer's size is wrong, the layer itself will repaint
729         // anyway if its size does change.
730         topLeft -= containerBox->layer()->scrolledContentOffset(); // For overflow:auto/scroll/hidden.
731
732         IntRect repaintRect(topLeft, rect.size());
733         IntRect boxRect(0, 0, containerBox->layer()->width(), containerBox->layer()->height());
734         rect = intersection(repaintRect, boxRect);
735         if (rect.isEmpty())
736             return;
737     } else
738         rect.setLocation(topLeft);
739
740     if (containerSkipped) {
741         // If the repaintContainer is below o, then we need to map the rect into repaintContainer's coordinates.
742         IntSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
743         rect.move(-containerOffset);
744         return;
745     }
746     
747     o->computeRectForRepaint(repaintContainer, rect, fixed);
748 }
749
750 IntSize RenderInline::offsetFromContainer(RenderObject* container, const IntPoint& point) const
751 {
752     ASSERT(container == this->container());
753
754     IntSize offset;    
755     if (isRelPositioned())
756         offset += relativePositionOffset();
757
758     container->adjustForColumns(offset, point);
759
760     if (container->hasOverflowClip())
761         offset -= toRenderBox(container)->layer()->scrolledContentOffset();
762
763     return offset;
764 }
765
766 void RenderInline::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState) const
767 {
768     if (repaintContainer == this)
769         return;
770
771     if (RenderView *v = view()) {
772         if (v->layoutStateEnabled() && !repaintContainer) {
773             LayoutState* layoutState = v->layoutState();
774             IntSize offset = layoutState->m_paintOffset;
775             if (style()->position() == RelativePosition && layer())
776                 offset += layer()->relativePositionOffset();
777             transformState.move(offset);
778             return;
779         }
780     }
781
782     bool containerSkipped;
783     RenderObject* o = container(repaintContainer, &containerSkipped);
784     if (!o)
785         return;
786
787     IntSize containerOffset = offsetFromContainer(o, roundedIntPoint(transformState.mappedPoint()));
788
789     bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
790     if (useTransforms && shouldUseTransformFromContainer(o)) {
791         TransformationMatrix t;
792         getTransformFromContainer(o, containerOffset, t);
793         transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
794     } else
795         transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
796
797     if (containerSkipped) {
798         // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
799         // to just subtract the delta between the repaintContainer and o.
800         IntSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
801         transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
802         return;
803     }
804
805     o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState);
806 }
807
808 void RenderInline::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState& transformState) const
809 {
810     // We don't expect this function to be called during layout.
811     ASSERT(!view() || !view()->layoutStateEnabled());
812
813     RenderObject* o = container();
814     if (!o)
815         return;
816
817     o->mapAbsoluteToLocalPoint(fixed, useTransforms, transformState);
818
819     IntSize containerOffset = offsetFromContainer(o, IntPoint());
820
821     bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
822     if (useTransforms && shouldUseTransformFromContainer(o)) {
823         TransformationMatrix t;
824         getTransformFromContainer(o, containerOffset, t);
825         transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
826     } else
827         transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
828 }
829
830 void RenderInline::updateDragState(bool dragOn)
831 {
832     RenderBoxModelObject::updateDragState(dragOn);
833     if (continuation())
834         continuation()->updateDragState(dragOn);
835 }
836
837 void RenderInline::childBecameNonInline(RenderObject* child)
838 {
839     // We have to split the parent flow.
840     RenderBlock* newBox = containingBlock()->createAnonymousBlock();
841     RenderBoxModelObject* oldContinuation = continuation();
842     setContinuation(newBox);
843     RenderObject* beforeChild = child->nextSibling();
844     children()->removeChildNode(this, child);
845     splitFlow(beforeChild, newBox, child, oldContinuation);
846 }
847
848 void RenderInline::updateHitTestResult(HitTestResult& result, const IntPoint& point)
849 {
850     if (result.innerNode())
851         return;
852
853     Node* n = node();
854     IntPoint localPoint(point);
855     if (n) {
856         if (isInlineElementContinuation()) {
857             // We're in the continuation of a split inline.  Adjust our local point to be in the coordinate space
858             // of the principal renderer's containing block.  This will end up being the innerNonSharedNode.
859             RenderBlock* firstBlock = n->renderer()->containingBlock();
860             
861             // Get our containing block.
862             RenderBox* block = containingBlock();
863             localPoint.move(block->x() - firstBlock->x(), block->y() - firstBlock->y());
864         }
865
866         result.setInnerNode(n);
867         if (!result.innerNonSharedNode())
868             result.setInnerNonSharedNode(n);
869         result.setLocalPoint(localPoint);
870     }
871 }
872
873 void RenderInline::dirtyLineBoxes(bool fullLayout)
874 {
875     if (fullLayout)
876         m_lineBoxes.deleteLineBoxes(renderArena());
877     else
878         m_lineBoxes.dirtyLineBoxes();
879 }
880
881 InlineFlowBox* RenderInline::createInlineFlowBox() 
882 {
883     return new (renderArena()) InlineFlowBox(this);
884 }
885
886 InlineFlowBox* RenderInline::createAndAppendInlineFlowBox()
887 {
888     InlineFlowBox* flowBox = createInlineFlowBox();
889     m_lineBoxes.appendLineBox(flowBox);
890     return flowBox;
891 }
892
893 int RenderInline::lineHeight(bool firstLine, LineDirectionMode /*direction*/, LinePositionMode /*linePositionMode*/) const
894 {
895     if (firstLine && document()->usesFirstLineRules()) {
896         RenderStyle* s = style(firstLine);
897         if (s != style())
898             return s->computedLineHeight();
899     }
900     
901     if (m_lineHeight == -1)
902         m_lineHeight = style()->computedLineHeight();
903     
904     return m_lineHeight;
905 }
906
907 int RenderInline::baselinePosition(bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
908 {
909     const Font& f = style(firstLine)->font();
910     return f.ascent() + (lineHeight(firstLine, direction, linePositionMode) - f.height()) / 2;
911 }
912
913 int RenderInline::verticalPositionFromCache(bool firstLine) const
914 {
915     if (firstLine) // We're only really a first-line style if the document actually uses first-line rules.
916         firstLine = document()->usesFirstLineRules();
917     int vpos = m_verticalPosition;
918     if (m_verticalPosition == PositionUndefined || firstLine) {
919         vpos = verticalPosition(firstLine);
920         if (!firstLine)
921             m_verticalPosition = vpos;
922     }
923     return vpos;
924 }
925
926 IntSize RenderInline::relativePositionedInlineOffset(const RenderBox* child) const
927 {
928     ASSERT(isRelPositioned());
929     if (!isRelPositioned())
930         return IntSize();
931
932     // When we have an enclosing relpositioned inline, we need to add in the offset of the first line
933     // box from the rest of the content, but only in the cases where we know we're positioned
934     // relative to the inline itself.
935
936     IntSize offset;
937     int sx;
938     int sy;
939     if (firstLineBox()) {
940         sx = firstLineBox()->x();
941         sy = firstLineBox()->y();
942     } else {
943         sx = layer()->staticX();
944         sy = layer()->staticY();
945     }
946
947     if (!child->style()->hasStaticX())
948         offset.setWidth(sx);
949     // This is not terribly intuitive, but we have to match other browsers.  Despite being a block display type inside
950     // an inline, we still keep our x locked to the left of the relative positioned inline.  Arguably the correct
951     // behavior would be to go flush left to the block that contains the inline, but that isn't what other browsers
952     // do.
953     else if (!child->style()->isOriginalDisplayInlineType())
954         // Avoid adding in the left border/padding of the containing block twice.  Subtract it out.
955         offset.setWidth(sx - (child->containingBlock()->borderLeft() + child->containingBlock()->paddingLeft()));
956
957     if (!child->style()->hasStaticY())
958         offset.setHeight(sy);
959
960     return offset;
961 }
962
963 void RenderInline::imageChanged(WrappedImagePtr, const IntRect*)
964 {
965     if (!parent())
966         return;
967         
968     // FIXME: We can do better.
969     repaint();
970 }
971
972 void RenderInline::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty)
973 {
974     for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
975         RootInlineBox* root = curr->root();
976         int top = max(root->lineTop(), curr->y());
977         int bottom = min(root->lineBottom(), curr->y() + curr->logicalHeight());
978         IntRect rect(tx + curr->x(), ty + top, curr->logicalWidth(), bottom - top);
979         if (!rect.isEmpty())
980             rects.append(rect);
981     }
982
983     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
984         if (!curr->isText() && !curr->isListMarker()) {
985             FloatPoint pos(tx, ty);
986             // FIXME: This doesn't work correctly with transforms.
987             if (curr->hasLayer()) 
988                 pos = curr->localToAbsolute();
989             else if (curr->isBox())
990                 pos.move(toRenderBox(curr)->x(), toRenderBox(curr)->y());
991            curr->addFocusRingRects(rects, pos.x(), pos.y());
992         }
993     }
994
995     if (continuation()) {
996         if (continuation()->isInline())
997             continuation()->addFocusRingRects(rects, 
998                                               tx - containingBlock()->x() + continuation()->containingBlock()->x(),
999                                               ty - containingBlock()->y() + continuation()->containingBlock()->y());
1000         else
1001             continuation()->addFocusRingRects(rects, 
1002                                               tx - containingBlock()->x() + toRenderBox(continuation())->x(),
1003                                               ty - containingBlock()->y() + toRenderBox(continuation())->y());
1004     }
1005 }
1006
1007 void RenderInline::paintOutline(GraphicsContext* graphicsContext, int tx, int ty)
1008 {
1009     if (!hasOutline())
1010         return;
1011     
1012     RenderStyle* styleToUse = style();
1013     if (styleToUse->outlineStyleIsAuto() || hasOutlineAnnotation()) {
1014         if (!theme()->supportsFocusRing(styleToUse)) {
1015             // Only paint the focus ring by hand if the theme isn't able to draw the focus ring.
1016             paintFocusRing(graphicsContext, tx, ty, styleToUse);
1017         }
1018     }
1019
1020     if (styleToUse->outlineStyleIsAuto() || styleToUse->outlineStyle() == BNONE)
1021         return;
1022
1023     Vector<IntRect> rects;
1024
1025     rects.append(IntRect());
1026     for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
1027         RootInlineBox* root = curr->root();
1028         int top = max(root->lineTop(), curr->y());
1029         int bottom = min(root->lineBottom(), curr->y() + curr->logicalHeight());
1030         rects.append(IntRect(curr->x(), top, curr->logicalWidth(), bottom - top));
1031     }
1032     rects.append(IntRect());
1033
1034     for (unsigned i = 1; i < rects.size() - 1; i++)
1035         paintOutlineForLine(graphicsContext, tx, ty, rects.at(i - 1), rects.at(i), rects.at(i + 1));
1036 }
1037
1038 void RenderInline::paintOutlineForLine(GraphicsContext* graphicsContext, int tx, int ty,
1039                                        const IntRect& lastline, const IntRect& thisline, const IntRect& nextline)
1040 {
1041     RenderStyle* styleToUse = style();
1042     int ow = styleToUse->outlineWidth();
1043     EBorderStyle os = styleToUse->outlineStyle();
1044     Color oc = styleToUse->visitedDependentColor(CSSPropertyOutlineColor);
1045
1046     int offset = style()->outlineOffset();
1047
1048     int t = ty + thisline.y() - offset;
1049     int l = tx + thisline.x() - offset;
1050     int b = ty + thisline.bottom() + offset;
1051     int r = tx + thisline.right() + offset;
1052     
1053     // left edge
1054     drawLineForBoxSide(graphicsContext,
1055                l - ow,
1056                t - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.right() - 1) <= thisline.x() ? ow : 0),
1057                l,
1058                b + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.right() - 1) <= thisline.x() ? ow : 0),
1059                BSLeft,
1060                oc, os,
1061                (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.right() - 1) <= thisline.x() ? ow : -ow),
1062                (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.right() - 1) <= thisline.x() ? ow : -ow));
1063     
1064     // right edge
1065     drawLineForBoxSide(graphicsContext,
1066                r,
1067                t - (lastline.isEmpty() || lastline.right() < thisline.right() || (thisline.right() - 1) <= lastline.x() ? ow : 0),
1068                r + ow,
1069                b + (nextline.isEmpty() || nextline.right() <= thisline.right() || (thisline.right() - 1) <= nextline.x() ? ow : 0),
1070                BSRight,
1071                oc, os,
1072                (lastline.isEmpty() || lastline.right() < thisline.right() || (thisline.right() - 1) <= lastline.x() ? ow : -ow),
1073                (nextline.isEmpty() || nextline.right() <= thisline.right() || (thisline.right() - 1) <= nextline.x() ? ow : -ow));
1074     // upper edge
1075     if (thisline.x() < lastline.x())
1076         drawLineForBoxSide(graphicsContext,
1077                    l - ow,
1078                    t - ow,
1079                    min(r+ow, (lastline.isEmpty() ? 1000000 : tx + lastline.x())),
1080                    t ,
1081                    BSTop, oc, os,
1082                    ow,
1083                    (!lastline.isEmpty() && tx + lastline.x() + 1 < r + ow) ? -ow : ow);
1084     
1085     if (lastline.right() < thisline.right())
1086         drawLineForBoxSide(graphicsContext,
1087                    max(lastline.isEmpty() ? -1000000 : tx + lastline.right(), l - ow),
1088                    t - ow,
1089                    r + ow,
1090                    t ,
1091                    BSTop, oc, os,
1092                    (!lastline.isEmpty() && l - ow < tx + lastline.right()) ? -ow : ow,
1093                    ow);
1094     
1095     // lower edge
1096     if (thisline.x() < nextline.x())
1097         drawLineForBoxSide(graphicsContext,
1098                    l - ow,
1099                    b,
1100                    min(r + ow, !nextline.isEmpty() ? tx + nextline.x() + 1 : 1000000),
1101                    b + ow,
1102                    BSBottom, oc, os,
1103                    ow,
1104                    (!nextline.isEmpty() && tx + nextline.x() + 1 < r + ow) ? -ow : ow);
1105     
1106     if (nextline.right() < thisline.right())
1107         drawLineForBoxSide(graphicsContext,
1108                    max(!nextline.isEmpty() ? tx + nextline.right() : -1000000, l - ow),
1109                    b,
1110                    r + ow,
1111                    b + ow,
1112                    BSBottom, oc, os,
1113                    (!nextline.isEmpty() && l - ow < tx + nextline.right()) ? -ow : ow,
1114                    ow);
1115 }
1116
1117 #if ENABLE(DASHBOARD_SUPPORT)
1118 void RenderInline::addDashboardRegions(Vector<DashboardRegionValue>& regions)
1119 {
1120     // Convert the style regions to absolute coordinates.
1121     if (style()->visibility() != VISIBLE)
1122         return;
1123
1124     const Vector<StyleDashboardRegion>& styleRegions = style()->dashboardRegions();
1125     unsigned i, count = styleRegions.size();
1126     for (i = 0; i < count; i++) {
1127         StyleDashboardRegion styleRegion = styleRegions[i];
1128
1129         IntRect linesBoundingBox = this->linesBoundingBox();
1130         int w = linesBoundingBox.width();
1131         int h = linesBoundingBox.height();
1132
1133         DashboardRegionValue region;
1134         region.label = styleRegion.label;
1135         region.bounds = IntRect(linesBoundingBox.x() + styleRegion.offset.left().value(),
1136                                 linesBoundingBox.y() + styleRegion.offset.top().value(),
1137                                 w - styleRegion.offset.left().value() - styleRegion.offset.right().value(),
1138                                 h - styleRegion.offset.top().value() - styleRegion.offset.bottom().value());
1139         region.type = styleRegion.type;
1140
1141         RenderObject* container = containingBlock();
1142         if (!container)
1143             container = this;
1144
1145         region.clip = region.bounds;
1146         container->computeAbsoluteRepaintRect(region.clip);
1147         if (region.clip.height() < 0) {
1148             region.clip.setHeight(0);
1149             region.clip.setWidth(0);
1150         }
1151
1152         FloatPoint absPos = container->localToAbsolute();
1153         region.bounds.setX(absPos.x() + region.bounds.x());
1154         region.bounds.setY(absPos.y() + region.bounds.y());
1155
1156         if (frame()) {
1157             float pageScaleFactor = frame()->page()->chrome()->scaleFactor();
1158             if (pageScaleFactor != 1.0f) {
1159                 region.bounds.scale(pageScaleFactor);
1160                 region.clip.scale(pageScaleFactor);
1161             }
1162         }
1163
1164         regions.append(region);
1165     }
1166 }
1167 #endif
1168
1169 } // namespace WebCore