5e8565cf79124c2ab87a54cab745631112146247
[WebKit-https.git] / Source / 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 "InlineTextBox.h"
31 #include "Page.h"
32 #include "RenderArena.h"
33 #include "RenderBlock.h"
34 #include "RenderLayer.h"
35 #include "RenderTheme.h"
36 #include "RenderView.h"
37 #include "TransformState.h"
38 #include "VisiblePosition.h"
39
40 #if ENABLE(DASHBOARD_SUPPORT)
41 #include "Frame.h"
42 #endif
43
44 using namespace std;
45
46 namespace WebCore {
47
48 RenderInline::RenderInline(Node* node)
49     : RenderBoxModelObject(node)
50     , m_alwaysCreateLineBoxes(false)
51 {
52     setChildrenInline(true);
53 }
54
55 void RenderInline::willBeDestroyed()
56 {
57 #if !ASSERT_DISABLED
58     // Make sure we do not retain "this" in the continuation outline table map of our containing blocks.
59     if (parent() && style()->visibility() == VISIBLE && hasOutline()) {
60         bool containingBlockPaintsContinuationOutline = continuation() || isInlineElementContinuation();
61         if (containingBlockPaintsContinuationOutline) {
62             if (RenderBlock* cb = containingBlock()) {
63                 if (RenderBlock* cbCb = cb->containingBlock())
64                     ASSERT(!cbCb->paintsContinuationOutline(this));
65             }
66         }
67     }
68 #endif
69
70     // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
71     // properly dirty line boxes that they are removed from.  Effects that do :before/:after only on hover could crash otherwise.
72     children()->destroyLeftoverChildren();
73
74     // Destroy our continuation before anything other than anonymous children.
75     // The reason we don't destroy it before anonymous children is that they may
76     // have continuations of their own that are anonymous children of our continuation.
77     RenderBoxModelObject* continuation = this->continuation();
78     if (continuation) {
79         continuation->destroy();
80         setContinuation(0);
81     }
82     
83     if (!documentBeingDestroyed()) {
84         if (firstLineBox()) {
85             // We can't wait for RenderBoxModelObject::destroy to clear the selection,
86             // because by then we will have nuked the line boxes.
87             // FIXME: The FrameSelection should be responsible for this when it
88             // is notified of DOM mutations.
89             if (isSelectionBorder())
90                 view()->clearSelection();
91
92             // If line boxes are contained inside a root, that means we're an inline.
93             // In that case, we need to remove all the line boxes so that the parent
94             // lines aren't pointing to deleted children. If the first line box does
95             // not have a parent that means they are either already disconnected or
96             // root lines that can just be destroyed without disconnecting.
97             if (firstLineBox()->parent()) {
98                 for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox())
99                     box->remove();
100             }
101         } else if (parent()) 
102             parent()->dirtyLinesFromChangedChild(this);
103     }
104
105     m_lineBoxes.deleteLineBoxes(renderArena());
106
107     RenderBoxModelObject::willBeDestroyed();
108 }
109
110 RenderInline* RenderInline::inlineElementContinuation() const
111 {
112     RenderBoxModelObject* continuation = this->continuation();
113     if (!continuation || continuation->isInline())
114         return toRenderInline(continuation);
115     return toRenderBlock(continuation)->inlineElementContinuation();
116 }
117
118 void RenderInline::updateBoxModelInfoFromStyle()
119 {
120     RenderBoxModelObject::updateBoxModelInfoFromStyle();
121
122     setInline(true); // Needed for run-ins, since run-in is considered a block display type.
123
124     // FIXME: Support transforms and reflections on inline flows someday.
125     setHasTransform(false);
126     setHasReflection(false);    
127 }
128
129 static bool hasRelPositionedInlineAncestor(RenderObject* p)
130 {
131     while (p && p->isRenderInline()) {
132         if (p->isRelPositioned())
133             return true;
134         p = p->parent();
135     }
136     return false;
137 }
138
139 static void updateStyleOfAnonymousBlockContinuations(RenderObject* block, const RenderStyle* newStyle, const RenderStyle* oldStyle)
140 {
141     for (;block && block->isAnonymousBlock(); block = block->nextSibling()) {
142         if (!toRenderBlock(block)->isAnonymousBlockContinuation() || block->style()->position() == newStyle->position())
143             continue;
144         // If we are no longer relatively positioned but our descendant block(s) still have a relatively positioned ancestor then 
145         // their containing anonymous block should keep its relative positioning. 
146         RenderInline* cont = toRenderBlock(block)->inlineElementContinuation();
147         if (oldStyle->position() == RelativePosition && hasRelPositionedInlineAncestor(cont))
148             continue;
149         RefPtr<RenderStyle> blockStyle = RenderStyle::createAnonymousStyle(block->style());
150         blockStyle->setPosition(newStyle->position());
151         blockStyle->setDisplay(BLOCK);
152         block->setStyle(blockStyle);
153     }
154 }
155
156 void RenderInline::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
157 {
158     RenderBoxModelObject::styleDidChange(diff, oldStyle);
159
160     // Ensure that all of the split inlines pick up the new style. We
161     // only do this if we're an inline, since we don't want to propagate
162     // a block's style to the other inlines.
163     // e.g., <font>foo <h4>goo</h4> moo</font>.  The <font> inlines before
164     // and after the block share the same style, but the block doesn't
165     // need to pass its style on to anyone else.
166     RenderStyle* newStyle = style();
167     RenderInline* continuation = inlineElementContinuation();
168     for (RenderInline* currCont = continuation; currCont; currCont = currCont->inlineElementContinuation()) {
169         RenderBoxModelObject* nextCont = currCont->continuation();
170         currCont->setContinuation(0);
171         currCont->setStyle(newStyle);
172         currCont->setContinuation(nextCont);
173     }
174
175     // If an inline's relative positioning has changed then any descendant blocks will need to change their relative positioning accordingly.
176     // Do this by updating the position of the descendant blocks' containing anonymous blocks - there may be more than one.
177     if (continuation && oldStyle && newStyle->position() != oldStyle->position() 
178         && (newStyle->position() == RelativePosition || (oldStyle->position() == RelativePosition))) {
179         // If any descendant blocks exist then they will be in the next anonymous block and its siblings.
180         RenderObject* block = containingBlock()->nextSibling();
181         ASSERT(block && block->isAnonymousBlock());
182         updateStyleOfAnonymousBlockContinuations(block, newStyle, oldStyle);
183     }
184
185     if (!m_alwaysCreateLineBoxes) {
186         bool alwaysCreateLineBoxes = hasSelfPaintingLayer() || hasBoxDecorations() || newStyle->hasPadding() || newStyle->hasMargin() || hasOutline();
187         if (oldStyle && alwaysCreateLineBoxes) {
188             dirtyLineBoxes(false);
189             setNeedsLayout(true);
190         }
191         m_alwaysCreateLineBoxes = alwaysCreateLineBoxes;
192     }
193
194     // Update pseudos for :before and :after now.
195     if (!isAnonymous() && document()->usesBeforeAfterRules()) {
196         children()->updateBeforeAfterContent(this, BEFORE);
197         children()->updateBeforeAfterContent(this, AFTER);
198     }
199 }
200
201 void RenderInline::updateAlwaysCreateLineBoxes(bool fullLayout)
202 {
203     // Once we have been tainted once, just assume it will happen again. This way effects like hover highlighting that change the
204     // background color will only cause a layout on the first rollover.
205     if (m_alwaysCreateLineBoxes)
206         return;
207
208     RenderStyle* parentStyle = parent()->style();
209     RenderInline* parentRenderInline = parent()->isRenderInline() ? toRenderInline(parent()) : 0;
210     bool checkFonts = document()->inNoQuirksMode();
211     bool alwaysCreateLineBoxes = (parentRenderInline && parentRenderInline->alwaysCreateLineBoxes())
212         || (parentRenderInline && parentStyle->verticalAlign() != BASELINE)
213         || style()->verticalAlign() != BASELINE
214         || style()->textEmphasisMark() != TextEmphasisMarkNone
215         || (checkFonts && (!parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(style()->font().fontMetrics())
216         || parentStyle->lineHeight() != style()->lineHeight()));
217
218     if (!alwaysCreateLineBoxes && checkFonts && document()->usesFirstLineRules()) {
219         // Have to check the first line style as well.
220         parentStyle = parent()->style(true);
221         RenderStyle* childStyle = style(true);
222         alwaysCreateLineBoxes = !parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle->font().fontMetrics())
223         || childStyle->verticalAlign() != BASELINE
224         || parentStyle->lineHeight() != childStyle->lineHeight();
225     }
226
227     if (alwaysCreateLineBoxes) {
228         if (!fullLayout)
229             dirtyLineBoxes(false);
230         m_alwaysCreateLineBoxes = true;
231     }
232 }
233
234 void RenderInline::addChild(RenderObject* newChild, RenderObject* beforeChild)
235 {
236     if (continuation())
237         return addChildToContinuation(newChild, beforeChild);
238     return addChildIgnoringContinuation(newChild, beforeChild);
239 }
240
241 static RenderBoxModelObject* nextContinuation(RenderObject* renderer)
242 {
243     if (renderer->isInline() && !renderer->isReplaced())
244         return toRenderInline(renderer)->continuation();
245     return toRenderBlock(renderer)->inlineElementContinuation();
246 }
247
248 RenderBoxModelObject* RenderInline::continuationBefore(RenderObject* beforeChild)
249 {
250     if (beforeChild && beforeChild->parent() == this)
251         return this;
252
253     RenderBoxModelObject* curr = nextContinuation(this);
254     RenderBoxModelObject* nextToLast = this;
255     RenderBoxModelObject* last = this;
256     while (curr) {
257         if (beforeChild && beforeChild->parent() == curr) {
258             if (curr->firstChild() == beforeChild)
259                 return last;
260             return curr;
261         }
262
263         nextToLast = last;
264         last = curr;
265         curr = nextContinuation(curr);
266     }
267
268     if (!beforeChild && !last->firstChild())
269         return nextToLast;
270     return last;
271 }
272
273 void RenderInline::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild)
274 {
275     // Make sure we don't append things after :after-generated content if we have it.
276     if (!beforeChild && isAfterContent(lastChild()))
277         beforeChild = lastChild();
278
279     if (!newChild->isInline() && !newChild->isFloatingOrPositioned()) {
280         // We are placing a block inside an inline. We have to perform a split of this
281         // inline into continuations.  This involves creating an anonymous block box to hold
282         // |newChild|.  We then make that block box a continuation of this inline.  We take all of
283         // the children after |beforeChild| and put them in a clone of this object.
284         RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style());
285         newStyle->setDisplay(BLOCK);
286         
287         // If inside an inline affected by relative positioning the block needs to be affected by it too.
288         // Giving the block a layer like this allows it to collect the x/y offsets from inline parents later.
289         if (hasRelPositionedInlineAncestor(this))
290             newStyle->setPosition(RelativePosition);
291
292         RenderBlock* newBox = new (renderArena()) RenderBlock(document() /* anonymous box */);
293         newBox->setStyle(newStyle.release());
294         RenderBoxModelObject* oldContinuation = continuation();
295         setContinuation(newBox);
296
297         // Someone may have put a <p> inside a <q>, causing a split.  When this happens, the :after content
298         // has to move into the inline continuation.  Call updateBeforeAfterContent to ensure that our :after
299         // content gets properly destroyed.
300         bool isLastChild = (beforeChild == lastChild());
301         if (document()->usesBeforeAfterRules())
302             children()->updateBeforeAfterContent(this, AFTER);
303         if (isLastChild && beforeChild != lastChild())
304             beforeChild = 0; // We destroyed the last child, so now we need to update our insertion
305                              // point to be 0.  It's just a straight append now.
306
307         splitFlow(beforeChild, newBox, newChild, oldContinuation);
308         return;
309     }
310
311     RenderBoxModelObject::addChild(newChild, beforeChild);
312
313     newChild->setNeedsLayoutAndPrefWidthsRecalc();
314 }
315
316 RenderInline* RenderInline::cloneInline(RenderInline* src)
317 {
318     RenderInline* o = new (src->renderArena()) RenderInline(src->node());
319     o->setStyle(src->style());
320     return o;
321 }
322
323 void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock,
324                                 RenderBlock* middleBlock,
325                                 RenderObject* beforeChild, RenderBoxModelObject* oldCont)
326 {
327     // Create a clone of this inline.
328     RenderInline* clone = cloneInline(this);
329     clone->setContinuation(oldCont);
330
331     // Now take all of the children from beforeChild to the end and remove
332     // them from |this| and place them in the clone.
333     RenderObject* o = beforeChild;
334     while (o) {
335         RenderObject* tmp = o;
336         o = tmp->nextSibling();
337         clone->addChildIgnoringContinuation(children()->removeChildNode(this, tmp), 0);
338         tmp->setNeedsLayoutAndPrefWidthsRecalc();
339     }
340
341     // Hook |clone| up as the continuation of the middle block.
342     middleBlock->setContinuation(clone);
343
344     // We have been reparented and are now under the fromBlock.  We need
345     // to walk up our inline parent chain until we hit the containing block.
346     // Once we hit the containing block we're done.
347     RenderBoxModelObject* curr = toRenderBoxModelObject(parent());
348     RenderBoxModelObject* currChild = this;
349     
350     // FIXME: Because splitting is O(n^2) as tags nest pathologically, we cap the depth at which we're willing to clone.
351     // There will eventually be a better approach to this problem that will let us nest to a much
352     // greater depth (see bugzilla bug 13430) but for now we have a limit.  This *will* result in
353     // incorrect rendering, but the alternative is to hang forever.
354     unsigned splitDepth = 1;
355     const unsigned cMaxSplitDepth = 200; 
356     while (curr && curr != fromBlock) {
357         ASSERT(curr->isRenderInline());
358         if (splitDepth < cMaxSplitDepth) {
359             // Create a new clone.
360             RenderInline* cloneChild = clone;
361             clone = cloneInline(toRenderInline(curr));
362
363             // Insert our child clone as the first child.
364             clone->addChildIgnoringContinuation(cloneChild, 0);
365
366             // Hook the clone up as a continuation of |curr|.
367             RenderInline* inlineCurr = toRenderInline(curr);
368             oldCont = inlineCurr->continuation();
369             inlineCurr->setContinuation(clone);
370             clone->setContinuation(oldCont);
371
372             // Someone may have indirectly caused a <q> to split.  When this happens, the :after content
373             // has to move into the inline continuation.  Call updateBeforeAfterContent to ensure that the inline's :after
374             // content gets properly destroyed.
375             if (document()->usesBeforeAfterRules())
376                 inlineCurr->children()->updateBeforeAfterContent(inlineCurr, AFTER);
377
378             // Now we need to take all of the children starting from the first child
379             // *after* currChild and append them all to the clone.
380             o = currChild->nextSibling();
381             while (o) {
382                 RenderObject* tmp = o;
383                 o = tmp->nextSibling();
384                 clone->addChildIgnoringContinuation(inlineCurr->children()->removeChildNode(curr, tmp), 0);
385                 tmp->setNeedsLayoutAndPrefWidthsRecalc();
386             }
387         }
388         
389         // Keep walking up the chain.
390         currChild = curr;
391         curr = toRenderBoxModelObject(curr->parent());
392         splitDepth++;
393     }
394
395     // Now we are at the block level. We need to put the clone into the toBlock.
396     toBlock->children()->appendChildNode(toBlock, clone);
397
398     // Now take all the children after currChild and remove them from the fromBlock
399     // and put them in the toBlock.
400     o = currChild->nextSibling();
401     while (o) {
402         RenderObject* tmp = o;
403         o = tmp->nextSibling();
404         toBlock->children()->appendChildNode(toBlock, fromBlock->children()->removeChildNode(fromBlock, tmp));
405     }
406 }
407
408 void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
409                              RenderObject* newChild, RenderBoxModelObject* oldCont)
410 {
411     RenderBlock* pre = 0;
412     RenderBlock* block = containingBlock();
413     
414     // Delete our line boxes before we do the inline split into continuations.
415     block->deleteLineBoxTree();
416     
417     bool madeNewBeforeBlock = false;
418     if (block->isAnonymousBlock() && (!block->parent() || !block->parent()->createsAnonymousWrapper())) {
419         // We can reuse this block and make it the preBlock of the next continuation.
420         pre = block;
421         pre->removePositionedObjects(0);
422         block = block->containingBlock();
423     } else {
424         // No anonymous block available for use.  Make one.
425         pre = block->createAnonymousBlock();
426         madeNewBeforeBlock = true;
427     }
428
429     RenderBlock* post = toRenderBlock(pre->createAnonymousBoxWithSameTypeAs(block));
430
431     RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling();
432     if (madeNewBeforeBlock)
433         block->children()->insertChildNode(block, pre, boxFirst);
434     block->children()->insertChildNode(block, newBlockBox, boxFirst);
435     block->children()->insertChildNode(block, post, boxFirst);
436     block->setChildrenInline(false);
437     
438     if (madeNewBeforeBlock) {
439         RenderObject* o = boxFirst;
440         while (o) {
441             RenderObject* no = o;
442             o = no->nextSibling();
443             pre->children()->appendChildNode(pre, block->children()->removeChildNode(block, no));
444             no->setNeedsLayoutAndPrefWidthsRecalc();
445         }
446     }
447
448     splitInlines(pre, post, newBlockBox, beforeChild, oldCont);
449
450     // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
451     // time in makeChildrenNonInline by just setting this explicitly up front.
452     newBlockBox->setChildrenInline(false);
453
454     // We delayed adding the newChild until now so that the |newBlockBox| would be fully
455     // connected, thus allowing newChild access to a renderArena should it need
456     // to wrap itself in additional boxes (e.g., table construction).
457     newBlockBox->addChild(newChild);
458
459     // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
460     // get deleted properly.  Because objects moves from the pre block into the post block, we want to
461     // make new line boxes instead of leaving the old line boxes around.
462     pre->setNeedsLayoutAndPrefWidthsRecalc();
463     block->setNeedsLayoutAndPrefWidthsRecalc();
464     post->setNeedsLayoutAndPrefWidthsRecalc();
465 }
466
467 void RenderInline::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild)
468 {
469     RenderBoxModelObject* flow = continuationBefore(beforeChild);
470     ASSERT(!beforeChild || beforeChild->parent()->isRenderBlock() || beforeChild->parent()->isRenderInline());
471     RenderBoxModelObject* beforeChildParent = 0;
472     if (beforeChild)
473         beforeChildParent = toRenderBoxModelObject(beforeChild->parent());
474     else {
475         RenderBoxModelObject* cont = nextContinuation(flow);
476         if (cont)
477             beforeChildParent = cont;
478         else
479             beforeChildParent = flow;
480     }
481
482     if (newChild->isFloatingOrPositioned())
483         return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
484
485     // A continuation always consists of two potential candidates: an inline or an anonymous
486     // block box holding block children.
487     bool childInline = newChild->isInline();
488     bool bcpInline = beforeChildParent->isInline();
489     bool flowInline = flow->isInline();
490
491     if (flow == beforeChildParent)
492         return flow->addChildIgnoringContinuation(newChild, beforeChild);
493     else {
494         // The goal here is to match up if we can, so that we can coalesce and create the
495         // minimal # of continuations needed for the inline.
496         if (childInline == bcpInline)
497             return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
498         else if (flowInline == childInline)
499             return flow->addChildIgnoringContinuation(newChild, 0); // Just treat like an append.
500         else
501             return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
502     }
503 }
504
505 void RenderInline::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
506 {
507     m_lineBoxes.paint(this, paintInfo, paintOffset);
508 }
509
510 void RenderInline::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
511 {
512     if (!alwaysCreateLineBoxes())
513         culledInlineAbsoluteRects(this, rects, toLayoutSize(accumulatedOffset));
514     else if (InlineFlowBox* curr = firstLineBox()) {
515         for (; curr; curr = curr->nextLineBox())
516             rects.append(enclosingIntRect(FloatRect(accumulatedOffset + curr->topLeft(), curr->size())));
517     } else
518         rects.append(IntRect(roundedIntPoint(accumulatedOffset), IntSize()));
519
520     if (continuation()) {
521         if (continuation()->isBox()) {
522             RenderBox* box = toRenderBox(continuation());
523             continuation()->absoluteRects(rects, toLayoutPoint(accumulatedOffset - containingBlock()->location() + box->size()));
524         } else
525             continuation()->absoluteRects(rects, toLayoutPoint(accumulatedOffset - containingBlock()->location()));
526     }
527 }
528
529 void RenderInline::culledInlineAbsoluteRects(const RenderInline* container, Vector<IntRect>& rects, const LayoutSize& offset) const
530 {
531     if (!culledInlineFirstLineBox()) {
532         rects.append(IntRect(offset.width(), offset.height(), 0, 0));
533         return;
534     }
535
536     bool isHorizontal = style()->isHorizontalWritingMode();
537     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
538         if (curr->isFloatingOrPositioned())
539             continue;
540             
541         // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
542         // direction (aligned to the root box's baseline).
543         if (curr->isBox()) {
544             RenderBox* currBox = toRenderBox(curr);
545             if (currBox->inlineBoxWrapper()) {
546                 RootInlineBox* rootBox = currBox->inlineBoxWrapper()->root();
547                 int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
548                 int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
549                 FloatRect result;
550                 if (isHorizontal)
551                     result = FloatRect(offset.width() + currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), offset.height() + logicalTop, currBox->width() + currBox->marginWidth(), logicalHeight);
552                 else
553                     result = FloatRect(offset.width() + logicalTop, offset.height() + currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, currBox->height() + currBox->marginHeight());
554                 rects.append(enclosingIntRect(result));
555             }
556         } else if (curr->isRenderInline()) {
557             // If the child doesn't need line boxes either, then we can recur.
558             RenderInline* currInline = toRenderInline(curr);
559             if (!currInline->alwaysCreateLineBoxes())
560                 currInline->culledInlineAbsoluteRects(container, rects, offset);
561             else {
562                 for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) {
563                     RootInlineBox* rootBox = childLine->root();
564                     int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
565                     int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
566                     FloatRect result;
567                     if (isHorizontal)
568                         result = FloatRect(offset.width() + childLine->x() - childLine->marginLogicalLeft(),
569                             offset.height() + logicalTop,
570                             childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(),
571                             logicalHeight);
572                     else
573                         result = FloatRect(offset.width() + logicalTop,
574                             offset.height() + childLine->y() - childLine->marginLogicalLeft(),
575                             logicalHeight,
576                             childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight());
577                     rects.append(enclosingIntRect(result));
578                 }
579             }
580         } else if (curr->isText()) {
581             RenderText* currText = toRenderText(curr);
582             for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) {
583                 RootInlineBox* rootBox = childText->root();
584                 int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
585                 int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
586                 FloatRect result;
587                 if (isHorizontal)
588                     result = FloatRect(offset.width() + childText->x(), offset.height() + logicalTop, childText->logicalWidth(), logicalHeight);
589                 else
590                     result = FloatRect(offset.width() + logicalTop, offset.height() + childText->y(), logicalHeight, childText->logicalWidth());
591                 rects.append(enclosingIntRect(result));
592             }
593         }
594     }
595 }
596
597 void RenderInline::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
598 {
599     if (!alwaysCreateLineBoxes())
600         culledInlineAbsoluteQuads(this, quads);
601     else if (InlineFlowBox* curr = firstLineBox()) {
602         for (; curr; curr = curr->nextLineBox()) {
603             FloatRect localRect(curr->x(), curr->y(), curr->width(), curr->height());
604             quads.append(localToAbsoluteQuad(localRect, false, wasFixed));
605         }
606     } else
607         quads.append(localToAbsoluteQuad(FloatRect(), false, wasFixed));
608
609     if (continuation())
610         continuation()->absoluteQuads(quads, wasFixed);
611 }
612
613 void RenderInline::culledInlineAbsoluteQuads(const RenderInline* container, Vector<FloatQuad>& quads) const
614 {
615     if (!culledInlineFirstLineBox()) {
616         quads.append(localToAbsoluteQuad(FloatRect()));
617         return;
618     }
619
620     bool isHorizontal = style()->isHorizontalWritingMode();
621     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
622         if (curr->isFloatingOrPositioned())
623             continue;
624             
625         // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
626         // direction (aligned to the root box's baseline).
627         if (curr->isBox()) {
628             RenderBox* currBox = toRenderBox(curr);
629             if (currBox->inlineBoxWrapper()) {
630                 RootInlineBox* rootBox = currBox->inlineBoxWrapper()->root();
631                 int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
632                 int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
633                 FloatRect result;
634                 if (isHorizontal)
635                     result = FloatRect(currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), logicalTop, currBox->width() + currBox->marginWidth(), logicalHeight);
636                 else
637                     result = FloatRect(logicalTop, currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, currBox->height() + currBox->marginHeight());
638                 quads.append(localToAbsoluteQuad(result));
639             }
640         } else if (curr->isRenderInline()) {
641             // If the child doesn't need line boxes either, then we can recur.
642             RenderInline* currInline = toRenderInline(curr);
643             if (!currInline->alwaysCreateLineBoxes())
644                 currInline->culledInlineAbsoluteQuads(container, quads);
645             else {
646                 for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) {
647                     RootInlineBox* rootBox = childLine->root();
648                     int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
649                     int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
650                     FloatRect result;
651                     if (isHorizontal)
652                         result = FloatRect(childLine->x() - childLine->marginLogicalLeft(),
653                             logicalTop,
654                             childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(),
655                             logicalHeight);
656                     else
657                         result = FloatRect(logicalTop,
658                             childLine->y() - childLine->marginLogicalLeft(),
659                             logicalHeight,
660                             childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight());
661                     quads.append(localToAbsoluteQuad(result));
662                 }
663             }
664         } else if (curr->isText()) {
665             RenderText* currText = toRenderText(curr);
666             for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) {
667                 RootInlineBox* rootBox = childText->root();
668                 int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
669                 int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
670                 FloatRect result;
671                 if (isHorizontal)
672                     result = FloatRect(childText->x(), logicalTop, childText->logicalWidth(), logicalHeight);
673                 else
674                     result = FloatRect(logicalTop, childText->y(), logicalHeight, childText->logicalWidth());
675                 quads.append(localToAbsoluteQuad(result));
676             }
677         }
678     }
679 }
680
681 LayoutUnit RenderInline::offsetLeft() const
682 {
683     LayoutUnit x = RenderBoxModelObject::offsetLeft();
684     if (InlineBox* firstBox = firstLineBoxIncludingCulling())
685         x += firstBox->x();
686     return x;
687 }
688
689 LayoutUnit RenderInline::offsetTop() const
690 {
691     LayoutUnit y = RenderBoxModelObject::offsetTop();
692     if (InlineBox* firstBox = firstLineBoxIncludingCulling())
693         y += firstBox->y();
694     return y;
695 }
696
697 static LayoutUnit computeMargin(const RenderInline* renderer, const Length& margin)
698 {
699     if (margin.isAuto())
700         return 0;
701     if (margin.isFixed())
702         return margin.value();
703     if (margin.isPercent())
704         return minimumValueForLength(margin, max<LayoutUnit>(0, renderer->containingBlock()->availableLogicalWidth()));
705     if (margin.isViewportPercentage())
706         return valueForLength(margin, 0, renderer->view());
707     return 0;
708 }
709
710 LayoutUnit RenderInline::marginLeft() const
711 {
712     return computeMargin(this, style()->marginLeft());
713 }
714
715 LayoutUnit RenderInline::marginRight() const
716 {
717     return computeMargin(this, style()->marginRight());
718 }
719
720 LayoutUnit RenderInline::marginTop() const
721 {
722     return computeMargin(this, style()->marginTop());
723 }
724
725 LayoutUnit RenderInline::marginBottom() const
726 {
727     return computeMargin(this, style()->marginBottom());
728 }
729
730 LayoutUnit RenderInline::marginStart() const
731 {
732     return computeMargin(this, style()->marginStart());
733 }
734
735 LayoutUnit RenderInline::marginEnd() const
736 {
737     return computeMargin(this, style()->marginEnd());
738 }
739
740 LayoutUnit RenderInline::marginBefore() const
741 {
742     return computeMargin(this, style()->marginBefore());
743 }
744
745 LayoutUnit RenderInline::marginAfter() const
746 {
747     return computeMargin(this, style()->marginAfter());
748 }
749
750 const char* RenderInline::renderName() const
751 {
752     if (isRelPositioned())
753         return "RenderInline (relative positioned)";
754     if (isAnonymous())
755         return "RenderInline (generated)";
756     if (isRunIn())
757         return "RenderInline (run-in)";
758     return "RenderInline";
759 }
760
761 bool RenderInline::nodeAtPoint(const HitTestRequest& request, HitTestResult& result,
762                                 const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
763 {
764     return m_lineBoxes.hitTest(this, request, result, pointInContainer, accumulatedOffset, hitTestAction);
765 }
766
767 VisiblePosition RenderInline::positionForPoint(const LayoutPoint& point)
768 {
769     // FIXME: Does not deal with relative positioned inlines (should it?)
770     RenderBlock* cb = containingBlock();
771     if (firstLineBox()) {
772         // This inline actually has a line box.  We must have clicked in the border/padding of one of these boxes.  We
773         // should try to find a result by asking our containing block.
774         return cb->positionForPoint(point);
775     }
776
777     // Translate the coords from the pre-anonymous block to the post-anonymous block.
778     LayoutPoint parentBlockPoint = cb->location() + point;  
779     RenderBoxModelObject* c = continuation();
780     while (c) {
781         RenderBox* contBlock = c->isInline() ? c->containingBlock() : toRenderBlock(c);
782         if (c->isInline() || c->firstChild())
783             return c->positionForPoint(parentBlockPoint - contBlock->locationOffset());
784         c = toRenderBlock(c)->inlineElementContinuation();
785     }
786     
787     return RenderBoxModelObject::positionForPoint(point);
788 }
789
790 IntRect RenderInline::linesBoundingBox() const
791 {
792     if (!alwaysCreateLineBoxes()) {
793         ASSERT(!firstLineBox());
794         return enclosingIntRect(culledInlineBoundingBox(this));
795     }
796
797     IntRect result;
798     
799     // 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
800     // 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
801     // builds and help us someday figure out why.  We also put in a redundant check of lastLineBox() to avoid the crash for now.
802     ASSERT(!firstLineBox() == !lastLineBox());  // Either both are null or both exist.
803     if (firstLineBox() && lastLineBox()) {
804         // Return the width of the minimal left side and the maximal right side.
805         float logicalLeftSide = 0;
806         float logicalRightSide = 0;
807         for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
808             if (curr == firstLineBox() || curr->logicalLeft() < logicalLeftSide)
809                 logicalLeftSide = curr->logicalLeft();
810             if (curr == firstLineBox() || curr->logicalRight() > logicalRightSide)
811                 logicalRightSide = curr->logicalRight();
812         }
813         
814         bool isHorizontal = style()->isHorizontalWritingMode();
815         
816         float x = isHorizontal ? logicalLeftSide : firstLineBox()->x();
817         float y = isHorizontal ? firstLineBox()->y() : logicalLeftSide;
818         float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastLineBox()->logicalBottom() - x;
819         float height = isHorizontal ? lastLineBox()->logicalBottom() - y : logicalRightSide - logicalLeftSide;
820         result = enclosingIntRect(FloatRect(x, y, width, height));
821     }
822
823     return result;
824 }
825
826 FloatRect RenderInline::culledInlineBoundingBox(const RenderInline* container) const
827 {
828     FloatRect result;
829     bool isHorizontal = style()->isHorizontalWritingMode();
830     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
831         if (curr->isFloatingOrPositioned())
832             continue;
833             
834         // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
835         // direction (aligned to the root box's baseline).
836         if (curr->isBox()) {
837             RenderBox* currBox = toRenderBox(curr);
838             if (currBox->inlineBoxWrapper()) {
839                 RootInlineBox* rootBox = currBox->inlineBoxWrapper()->root();
840                 int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
841                 int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
842                 if (isHorizontal)
843                     result.uniteIfNonZero(FloatRect(currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), logicalTop, currBox->width() + currBox->marginWidth(), logicalHeight));
844                 else
845                     result.uniteIfNonZero(FloatRect(logicalTop, currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, currBox->height() + currBox->marginHeight()));
846             }
847         } else if (curr->isRenderInline()) {
848             // If the child doesn't need line boxes either, then we can recur.
849             RenderInline* currInline = toRenderInline(curr);
850             if (!currInline->alwaysCreateLineBoxes())
851                 result.uniteIfNonZero(currInline->culledInlineBoundingBox(container));
852             else {
853                 for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) {
854                     RootInlineBox* rootBox = childLine->root();
855                     int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
856                     int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
857                     if (isHorizontal)
858                         result.uniteIfNonZero(FloatRect(childLine->x() - childLine->marginLogicalLeft(),
859                             logicalTop,
860                             childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(),
861                             logicalHeight));
862                     else
863                         result.uniteIfNonZero(FloatRect(logicalTop,
864                             childLine->y() - childLine->marginLogicalLeft(),
865                             logicalHeight,
866                             childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight()));
867                                      
868                 }
869             }
870         } else if (curr->isText()) {
871             RenderText* currText = toRenderText(curr);
872             for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) {
873                 RootInlineBox* rootBox = childText->root();
874                 int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
875                 int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
876                 if (isHorizontal)
877                     result.uniteIfNonZero(FloatRect(childText->x(), logicalTop, childText->logicalWidth(), logicalHeight));
878                 else
879                     result.uniteIfNonZero(FloatRect(logicalTop, childText->y(), logicalHeight, childText->logicalWidth()));
880             }
881         }
882     }
883     return enclosingLayoutRect(result);
884 }
885
886 InlineBox* RenderInline::culledInlineFirstLineBox() const
887 {
888     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
889         if (curr->isFloatingOrPositioned())
890             continue;
891             
892         // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
893         // direction (aligned to the root box's baseline).
894         if (curr->isBox())
895             return toRenderBox(curr)->inlineBoxWrapper();
896         if (curr->isRenderInline()) {
897             RenderInline* currInline = toRenderInline(curr);
898             InlineBox* result = currInline->firstLineBoxIncludingCulling();
899             if (result)
900                 return result;
901         } else if (curr->isText()) {
902             RenderText* currText = toRenderText(curr);
903             if (currText->firstTextBox())
904                 return currText->firstTextBox();
905         }
906     }
907     return 0;
908 }
909
910 InlineBox* RenderInline::culledInlineLastLineBox() const
911 {
912     for (RenderObject* curr = lastChild(); curr; curr = curr->previousSibling()) {
913         if (curr->isFloatingOrPositioned())
914             continue;
915             
916         // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
917         // direction (aligned to the root box's baseline).
918         if (curr->isBox())
919             return toRenderBox(curr)->inlineBoxWrapper();
920         if (curr->isRenderInline()) {
921             RenderInline* currInline = toRenderInline(curr);
922             InlineBox* result = currInline->lastLineBoxIncludingCulling();
923             if (result)
924                 return result;
925         } else if (curr->isText()) {
926             RenderText* currText = toRenderText(curr);
927             if (currText->lastTextBox())
928                 return currText->lastTextBox();
929         }
930     }
931     return 0;
932 }
933
934 LayoutRect RenderInline::culledInlineVisualOverflowBoundingBox() const
935 {
936     LayoutRect result(culledInlineBoundingBox(this));
937     bool isHorizontal = style()->isHorizontalWritingMode();
938     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
939         if (curr->isFloatingOrPositioned())
940             continue;
941             
942         // For overflow we just have to propagate by hand and recompute it all.
943         if (curr->isBox()) {
944             RenderBox* currBox = toRenderBox(curr);
945             if (!currBox->hasSelfPaintingLayer() && currBox->inlineBoxWrapper()) {
946                 LayoutRect logicalRect = currBox->logicalVisualOverflowRectForPropagation(style());
947                 if (isHorizontal) {
948                     logicalRect.moveBy(currBox->location());
949                     result.uniteIfNonZero(logicalRect);
950                 } else {
951                     logicalRect.moveBy(currBox->location());
952                     result.uniteIfNonZero(logicalRect.transposedRect());
953                 }
954             }
955         } else if (curr->isRenderInline()) {
956             // If the child doesn't need line boxes either, then we can recur.
957             RenderInline* currInline = toRenderInline(curr);
958             if (!currInline->alwaysCreateLineBoxes())
959                 result.uniteIfNonZero(currInline->culledInlineVisualOverflowBoundingBox());
960             else if (!currInline->hasSelfPaintingLayer())
961                 result.uniteIfNonZero(currInline->linesVisualOverflowBoundingBox());
962         } else if (curr->isText()) {
963             // FIXME; Overflow from text boxes is lost. We will need to cache this information in
964             // InlineTextBoxes.
965             RenderText* currText = toRenderText(curr);
966             result.uniteIfNonZero(currText->linesVisualOverflowBoundingBox());
967         }
968     }
969     return result;
970 }
971
972 LayoutRect RenderInline::linesVisualOverflowBoundingBox() const
973 {
974     if (!alwaysCreateLineBoxes())
975         return culledInlineVisualOverflowBoundingBox();
976
977     if (!firstLineBox() || !lastLineBox())
978         return LayoutRect();
979
980     // Return the width of the minimal left side and the maximal right side.
981     LayoutUnit logicalLeftSide = MAX_LAYOUT_UNIT;
982     LayoutUnit logicalRightSide = MIN_LAYOUT_UNIT;
983     for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
984         logicalLeftSide = min(logicalLeftSide, curr->logicalLeftVisualOverflow());
985         logicalRightSide = max(logicalRightSide, curr->logicalRightVisualOverflow());
986     }
987
988     RootInlineBox* firstRootBox = firstLineBox()->root();
989     RootInlineBox* lastRootBox = lastLineBox()->root();
990     
991     LayoutUnit logicalTop = firstLineBox()->logicalTopVisualOverflow(firstRootBox->lineTop());
992     LayoutUnit logicalWidth = logicalRightSide - logicalLeftSide;
993     LayoutUnit logicalHeight = lastLineBox()->logicalBottomVisualOverflow(lastRootBox->lineBottom()) - logicalTop;
994     
995     LayoutRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight);
996     if (!style()->isHorizontalWritingMode())
997         rect = rect.transposedRect();
998     return rect;
999 }
1000
1001 LayoutRect RenderInline::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) const
1002 {
1003     // Only run-ins are allowed in here during layout.
1004     ASSERT(!view() || !view()->layoutStateEnabled() || isRunIn());
1005
1006     if (!firstLineBoxIncludingCulling() && !continuation())
1007         return LayoutRect();
1008
1009     // Find our leftmost position.
1010     LayoutRect boundingBox(linesVisualOverflowBoundingBox());
1011     LayoutUnit left = boundingBox.x();
1012     LayoutUnit top = boundingBox.y();
1013
1014     // Now invalidate a rectangle.
1015     LayoutUnit ow = style() ? style()->outlineSize() : 0;
1016
1017     bool hitRepaintContainer = false;
1018
1019     // We need to add in the relative position offsets of any inlines (including us) up to our
1020     // containing block.
1021     RenderBlock* cb = containingBlock();
1022     for (const RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isRenderInline() && inlineFlow != cb;
1023          inlineFlow = inlineFlow->parent()) {
1024          if (inlineFlow == repaintContainer) {
1025             hitRepaintContainer = true;
1026             break;
1027         }
1028         if (inlineFlow->style()->position() == RelativePosition && inlineFlow->hasLayer())
1029             toRenderInline(inlineFlow)->layer()->relativePositionOffset(left, top);
1030     }
1031
1032     LayoutRect r(-ow + left, -ow + top, boundingBox.width() + ow * 2, boundingBox.height() + ow * 2);
1033
1034     if (hitRepaintContainer || !cb)
1035         return r;
1036
1037     if (cb->hasColumns())
1038         cb->adjustRectForColumns(r);
1039
1040     if (cb->hasOverflowClip()) {
1041         // cb->height() is inaccurate if we're in the middle of a layout of |cb|, so use the
1042         // layer's size instead.  Even if the layer's size is wrong, the layer itself will repaint
1043         // anyway if its size does change.
1044         LayoutRect repaintRect(r);
1045         repaintRect.move(-cb->scrolledContentOffset()); // For overflow:auto/scroll/hidden.
1046
1047         LayoutRect boxRect(LayoutPoint(), cb->cachedSizeForOverflowClip());
1048         r = intersection(repaintRect, boxRect);
1049     }
1050
1051     cb->computeRectForRepaint(repaintContainer, r);
1052
1053     if (ow) {
1054         for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
1055             if (!curr->isText()) {
1056                 LayoutRect childRect = curr->rectWithOutlineForRepaint(repaintContainer, ow);
1057                 r.unite(childRect);
1058             }
1059         }
1060
1061         if (continuation() && !continuation()->isInline() && continuation()->parent()) {
1062             LayoutRect contRect = continuation()->rectWithOutlineForRepaint(repaintContainer, ow);
1063             r.unite(contRect);
1064         }
1065     }
1066
1067     return r;
1068 }
1069
1070 LayoutRect RenderInline::rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, LayoutUnit outlineWidth) const
1071 {
1072     LayoutRect r(RenderBoxModelObject::rectWithOutlineForRepaint(repaintContainer, outlineWidth));
1073     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
1074         if (!curr->isText())
1075             r.unite(curr->rectWithOutlineForRepaint(repaintContainer, outlineWidth));
1076     }
1077     return r;
1078 }
1079
1080 void RenderInline::computeRectForRepaint(RenderBoxModelObject* repaintContainer, LayoutRect& rect, bool fixed) const
1081 {
1082     if (RenderView* v = view()) {
1083         // LayoutState is only valid for root-relative repainting
1084         if (v->layoutStateEnabled() && !repaintContainer) {
1085             LayoutState* layoutState = v->layoutState();
1086             if (style()->position() == RelativePosition && layer())
1087                 rect.move(layer()->relativePositionOffset());
1088             rect.move(layoutState->m_paintOffset);
1089             if (layoutState->m_clipped)
1090                 rect.intersect(layoutState->m_clipRect);
1091             return;
1092         }
1093     }
1094
1095     if (repaintContainer == this)
1096         return;
1097
1098     bool containerSkipped;
1099     RenderObject* o = container(repaintContainer, &containerSkipped);
1100     if (!o)
1101         return;
1102
1103     LayoutPoint topLeft = rect.location();
1104
1105     if (o->isBlockFlow() && !style()->isPositioned()) {
1106         RenderBlock* cb = toRenderBlock(o);
1107         if (cb->hasColumns()) {
1108             LayoutRect repaintRect(topLeft, rect.size());
1109             cb->adjustRectForColumns(repaintRect);
1110             topLeft = repaintRect.location();
1111             rect = repaintRect;
1112         }
1113     }
1114
1115     if (style()->position() == RelativePosition && layer()) {
1116         // Apply the relative position offset when invalidating a rectangle.  The layer
1117         // is translated, but the render box isn't, so we need to do this to get the
1118         // right dirty rect.  Since this is called from RenderObject::setStyle, the relative position
1119         // flag on the RenderObject has been cleared, so use the one on the style().
1120         topLeft += layer()->relativePositionOffset();
1121     }
1122     
1123     // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
1124     // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
1125     if (o->hasOverflowClip()) {
1126         RenderBox* containerBox = toRenderBox(o);
1127
1128         // o->height() is inaccurate if we're in the middle of a layout of |o|, so use the
1129         // layer's size instead.  Even if the layer's size is wrong, the layer itself will repaint
1130         // anyway if its size does change.
1131         topLeft -= containerBox->scrolledContentOffset(); // For overflow:auto/scroll/hidden.
1132
1133         LayoutRect repaintRect(topLeft, rect.size());
1134         LayoutRect boxRect(LayoutPoint(), containerBox->cachedSizeForOverflowClip());
1135         rect = intersection(repaintRect, boxRect);
1136         if (rect.isEmpty())
1137             return;
1138     } else
1139         rect.setLocation(topLeft);
1140
1141     if (containerSkipped) {
1142         // If the repaintContainer is below o, then we need to map the rect into repaintContainer's coordinates.
1143         LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
1144         rect.move(-containerOffset);
1145         return;
1146     }
1147     
1148     o->computeRectForRepaint(repaintContainer, rect, fixed);
1149 }
1150
1151 LayoutSize RenderInline::offsetFromContainer(RenderObject* container, const LayoutPoint& point) const
1152 {
1153     ASSERT(container == this->container());
1154     
1155     LayoutSize offset;    
1156     if (isRelPositioned())
1157         offset += relativePositionOffset();
1158
1159     container->adjustForColumns(offset, point);
1160
1161     if (container->hasOverflowClip())
1162         offset -= toRenderBox(container)->scrolledContentOffset();
1163
1164     return offset;
1165 }
1166
1167 void RenderInline::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState, bool* wasFixed) const
1168 {
1169     if (repaintContainer == this)
1170         return;
1171
1172     if (RenderView *v = view()) {
1173         if (v->layoutStateEnabled() && !repaintContainer) {
1174             LayoutState* layoutState = v->layoutState();
1175             LayoutSize offset = layoutState->m_paintOffset;
1176             if (style()->position() == RelativePosition && layer())
1177                 offset += layer()->relativePositionOffset();
1178             transformState.move(offset);
1179             return;
1180         }
1181     }
1182
1183     bool containerSkipped;
1184     RenderObject* o = container(repaintContainer, &containerSkipped);
1185     if (!o)
1186         return;
1187
1188     IntPoint centerPoint = roundedIntPoint(transformState.mappedPoint());
1189     if (o->isBox() && o->style()->isFlippedBlocksWritingMode())
1190         transformState.move(toRenderBox(o)->flipForWritingModeIncludingColumns(roundedIntPoint(transformState.mappedPoint())) - centerPoint);
1191
1192     LayoutSize containerOffset = offsetFromContainer(o, roundedLayoutPoint(transformState.mappedPoint()));
1193
1194     bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
1195     if (useTransforms && shouldUseTransformFromContainer(o)) {
1196         TransformationMatrix t;
1197         getTransformFromContainer(o, containerOffset, t);
1198         transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1199     } else
1200         transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1201
1202     if (containerSkipped) {
1203         // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
1204         // to just subtract the delta between the repaintContainer and o.
1205         LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
1206         transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1207         return;
1208     }
1209
1210     o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState, wasFixed);
1211 }
1212
1213 void RenderInline::updateDragState(bool dragOn)
1214 {
1215     RenderBoxModelObject::updateDragState(dragOn);
1216     if (continuation())
1217         continuation()->updateDragState(dragOn);
1218 }
1219
1220 void RenderInline::childBecameNonInline(RenderObject* child)
1221 {
1222     // We have to split the parent flow.
1223     RenderBlock* newBox = containingBlock()->createAnonymousBlock();
1224     RenderBoxModelObject* oldContinuation = continuation();
1225     setContinuation(newBox);
1226     RenderObject* beforeChild = child->nextSibling();
1227     children()->removeChildNode(this, child);
1228     splitFlow(beforeChild, newBox, child, oldContinuation);
1229 }
1230
1231 void RenderInline::updateHitTestResult(HitTestResult& result, const LayoutPoint& point)
1232 {
1233     if (result.innerNode())
1234         return;
1235
1236     Node* n = node();
1237     LayoutPoint localPoint(point);
1238     if (n) {
1239         if (isInlineElementContinuation()) {
1240             // We're in the continuation of a split inline.  Adjust our local point to be in the coordinate space
1241             // of the principal renderer's containing block.  This will end up being the innerNonSharedNode.
1242             RenderBlock* firstBlock = n->renderer()->containingBlock();
1243             
1244             // Get our containing block.
1245             RenderBox* block = containingBlock();
1246             localPoint.move(block->x() - firstBlock->x(), block->y() - firstBlock->y());
1247         }
1248
1249         result.setInnerNode(n);
1250         if (!result.innerNonSharedNode())
1251             result.setInnerNonSharedNode(n);
1252         result.setLocalPoint(localPoint);
1253     }
1254 }
1255
1256 void RenderInline::dirtyLineBoxes(bool fullLayout)
1257 {
1258     if (fullLayout) {
1259         m_lineBoxes.deleteLineBoxes(renderArena());
1260         return;
1261     }
1262
1263     if (!alwaysCreateLineBoxes()) {
1264         // We have to grovel into our children in order to dirty the appropriate lines.
1265         for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
1266             if (curr->isFloatingOrPositioned())
1267                 continue;
1268             if (curr->isBox() && !curr->needsLayout()) {
1269                 RenderBox* currBox = toRenderBox(curr);
1270                 if (currBox->inlineBoxWrapper())
1271                     currBox->inlineBoxWrapper()->root()->markDirty();
1272             } else if (!curr->selfNeedsLayout()) {
1273                 if (curr->isRenderInline()) {
1274                     RenderInline* currInline = toRenderInline(curr);
1275                     for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox())
1276                         childLine->root()->markDirty();
1277                 } else if (curr->isText()) {
1278                     RenderText* currText = toRenderText(curr);
1279                     for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox())
1280                         childText->root()->markDirty();
1281                 }
1282             }
1283         }
1284     } else
1285         m_lineBoxes.dirtyLineBoxes();
1286 }
1287
1288 InlineFlowBox* RenderInline::createInlineFlowBox() 
1289 {
1290     return new (renderArena()) InlineFlowBox(this);
1291 }
1292
1293 InlineFlowBox* RenderInline::createAndAppendInlineFlowBox()
1294 {
1295     setAlwaysCreateLineBoxes();
1296     InlineFlowBox* flowBox = createInlineFlowBox();
1297     m_lineBoxes.appendLineBox(flowBox);
1298     return flowBox;
1299 }
1300
1301 LayoutUnit RenderInline::lineHeight(bool firstLine, LineDirectionMode /*direction*/, LinePositionMode /*linePositionMode*/) const
1302 {
1303     if (firstLine && document()->usesFirstLineRules()) {
1304         RenderStyle* s = style(firstLine);
1305         if (s != style())
1306             return s->computedLineHeight(view());
1307     }
1308
1309     return style()->computedLineHeight(view());
1310 }
1311
1312 LayoutUnit RenderInline::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
1313 {
1314     const FontMetrics& fontMetrics = style(firstLine)->fontMetrics();
1315     return fontMetrics.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - fontMetrics.height()) / 2;
1316 }
1317
1318 LayoutSize RenderInline::relativePositionedInlineOffset(const RenderBox* child) const
1319 {
1320     // FIXME: This function isn't right with mixed writing modes.
1321
1322     ASSERT(isRelPositioned());
1323     if (!isRelPositioned())
1324         return LayoutSize();
1325
1326     // When we have an enclosing relpositioned inline, we need to add in the offset of the first line
1327     // box from the rest of the content, but only in the cases where we know we're positioned
1328     // relative to the inline itself.
1329
1330     LayoutSize logicalOffset;
1331     LayoutUnit inlinePosition;
1332     LayoutUnit blockPosition;
1333     if (firstLineBox()) {
1334         inlinePosition = roundedLayoutUnit(firstLineBox()->logicalLeft());
1335         blockPosition = firstLineBox()->logicalTop();
1336     } else {
1337         inlinePosition = layer()->staticInlinePosition();
1338         blockPosition = layer()->staticBlockPosition();
1339     }
1340
1341     if (!child->style()->hasStaticInlinePosition(style()->isHorizontalWritingMode()))
1342         logicalOffset.setWidth(inlinePosition);
1343
1344     // This is not terribly intuitive, but we have to match other browsers.  Despite being a block display type inside
1345     // an inline, we still keep our x locked to the left of the relative positioned inline.  Arguably the correct
1346     // behavior would be to go flush left to the block that contains the inline, but that isn't what other browsers
1347     // do.
1348     else if (!child->style()->isOriginalDisplayInlineType())
1349         // Avoid adding in the left border/padding of the containing block twice.  Subtract it out.
1350         logicalOffset.setWidth(inlinePosition - child->containingBlock()->borderAndPaddingLogicalLeft());
1351
1352     if (!child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
1353         logicalOffset.setHeight(blockPosition);
1354
1355     return style()->isHorizontalWritingMode() ? logicalOffset : logicalOffset.transposedSize();
1356 }
1357
1358 void RenderInline::imageChanged(WrappedImagePtr, const IntRect*)
1359 {
1360     if (!parent())
1361         return;
1362         
1363     // FIXME: We can do better.
1364     repaint();
1365 }
1366
1367 void RenderInline::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset)
1368 {
1369     if (!alwaysCreateLineBoxes())
1370         culledInlineAbsoluteRects(this, rects, toLayoutSize(additionalOffset));
1371     else {
1372         for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
1373             rects.append(enclosingIntRect(FloatRect(additionalOffset.x() + curr->x(), additionalOffset.y() + curr->y(), curr->width(), curr->height())));
1374     }
1375
1376     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
1377         if (!curr->isText() && !curr->isListMarker()) {
1378             FloatPoint pos(additionalOffset);
1379             // FIXME: This doesn't work correctly with transforms.
1380             if (curr->hasLayer()) 
1381                 pos = curr->localToAbsolute();
1382             else if (curr->isBox())
1383                 pos.move(toRenderBox(curr)->x(), toRenderBox(curr)->y());
1384             curr->addFocusRingRects(rects, flooredIntPoint(pos));
1385         }
1386     }
1387
1388     if (continuation()) {
1389         if (continuation()->isInline())
1390             continuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + continuation()->containingBlock()->location() - containingBlock()->location()));
1391         else
1392             continuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + toRenderBox(continuation())->location() - containingBlock()->location()));
1393     }
1394 }
1395
1396 void RenderInline::paintOutline(GraphicsContext* graphicsContext, const LayoutPoint& paintOffset)
1397 {
1398     if (!hasOutline())
1399         return;
1400     
1401     RenderStyle* styleToUse = style();
1402     if (styleToUse->outlineStyleIsAuto() || hasOutlineAnnotation()) {
1403         if (!theme()->supportsFocusRing(styleToUse)) {
1404             // Only paint the focus ring by hand if the theme isn't able to draw the focus ring.
1405             paintFocusRing(graphicsContext, paintOffset, styleToUse);
1406         }
1407     }
1408
1409     if (graphicsContext->paintingDisabled())
1410         return;
1411
1412     if (styleToUse->outlineStyleIsAuto() || styleToUse->outlineStyle() == BNONE)
1413         return;
1414
1415     Vector<LayoutRect> rects;
1416
1417     rects.append(LayoutRect());
1418     for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
1419         RootInlineBox* root = curr->root();
1420         LayoutUnit top = max<LayoutUnit>(root->lineTop(), curr->logicalTop());
1421         LayoutUnit bottom = min<LayoutUnit>(root->lineBottom(), curr->logicalBottom());
1422         rects.append(LayoutRect(curr->x(), top, curr->logicalWidth(), bottom - top));
1423     }
1424     rects.append(LayoutRect());
1425
1426     Color outlineColor = styleToUse->visitedDependentColor(CSSPropertyOutlineColor);
1427     bool useTransparencyLayer = outlineColor.hasAlpha();
1428     if (useTransparencyLayer) {
1429         graphicsContext->beginTransparencyLayer(static_cast<float>(outlineColor.alpha()) / 255);
1430         outlineColor = Color(outlineColor.red(), outlineColor.green(), outlineColor.blue());
1431     }
1432
1433     for (unsigned i = 1; i < rects.size() - 1; i++)
1434         paintOutlineForLine(graphicsContext, paintOffset, rects.at(i - 1), rects.at(i), rects.at(i + 1), outlineColor);
1435
1436     if (useTransparencyLayer)
1437         graphicsContext->endTransparencyLayer();
1438 }
1439
1440 void RenderInline::paintOutlineForLine(GraphicsContext* graphicsContext, const LayoutPoint& paintOffset,
1441                                        const LayoutRect& lastline, const LayoutRect& thisline, const LayoutRect& nextline,
1442                                        const Color outlineColor)
1443 {
1444     RenderStyle* styleToUse = style();
1445     int outlineWidth = styleToUse->outlineWidth();
1446     EBorderStyle outlineStyle = styleToUse->outlineStyle();
1447
1448     bool antialias = shouldAntialiasLines(graphicsContext);
1449
1450     int offset = style()->outlineOffset();
1451
1452     LayoutRect box(LayoutPoint(paintOffset.x() + thisline.x() - offset, paintOffset.y() + thisline.y() - offset),
1453         LayoutSize(thisline.width() + offset, thisline.height() + offset));
1454
1455     IntRect pixelSnappedBox = pixelSnappedIntRect(box);
1456     IntRect pixelSnappedLastLine = pixelSnappedIntRect(paintOffset.x() + lastline.x(), 0, lastline.width(), 0);
1457     IntRect pixelSnappedNextLine = pixelSnappedIntRect(paintOffset.x() + nextline.x(), 0, nextline.width(), 0);
1458     
1459     // left edge
1460     drawLineForBoxSide(graphicsContext,
1461         pixelSnappedBox.x() - outlineWidth,
1462         pixelSnappedBox.y() - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : 0),
1463         pixelSnappedBox.x(),
1464         pixelSnappedBox.maxY() + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : 0),
1465         BSLeft,
1466         outlineColor, outlineStyle,
1467         (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth),
1468         (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth),
1469         antialias);
1470     
1471     // right edge
1472     drawLineForBoxSide(graphicsContext,
1473         pixelSnappedBox.maxX(),
1474         pixelSnappedBox.y() - (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : 0),
1475         pixelSnappedBox.maxX() + outlineWidth,
1476         pixelSnappedBox.maxY() + (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : 0),
1477         BSRight,
1478         outlineColor, outlineStyle,
1479         (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : -outlineWidth),
1480         (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : -outlineWidth),
1481         antialias);
1482     // upper edge
1483     if (thisline.x() < lastline.x())
1484         drawLineForBoxSide(graphicsContext,
1485             pixelSnappedBox.x() - outlineWidth,
1486             pixelSnappedBox.y() - outlineWidth,
1487             min(pixelSnappedBox.maxX() + outlineWidth, (lastline.isEmpty() ? 1000000 : pixelSnappedLastLine.x())),
1488             pixelSnappedBox.y(),
1489             BSTop, outlineColor, outlineStyle,
1490             outlineWidth,
1491             (!lastline.isEmpty() && paintOffset.x() + lastline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth,
1492             antialias);
1493     
1494     if (lastline.maxX() < thisline.maxX())
1495         drawLineForBoxSide(graphicsContext,
1496             max(lastline.isEmpty() ? -1000000 : pixelSnappedLastLine.maxX(), pixelSnappedBox.x() - outlineWidth),
1497             pixelSnappedBox.y() - outlineWidth,
1498             pixelSnappedBox.maxX() + outlineWidth,
1499             pixelSnappedBox.y(),
1500             BSTop, outlineColor, outlineStyle,
1501             (!lastline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + lastline.maxX()) ? -outlineWidth : outlineWidth,
1502             outlineWidth, antialias);
1503
1504     if (thisline.x() == thisline.maxX())
1505           drawLineForBoxSide(graphicsContext,
1506             pixelSnappedBox.x() - outlineWidth,
1507             pixelSnappedBox.y() - outlineWidth,
1508             pixelSnappedBox.maxX() + outlineWidth,
1509             pixelSnappedBox.y(),
1510             BSTop, outlineColor, outlineStyle,
1511             outlineWidth,
1512             outlineWidth,
1513             antialias);
1514
1515     // lower edge
1516     if (thisline.x() < nextline.x())
1517         drawLineForBoxSide(graphicsContext,
1518             pixelSnappedBox.x() - outlineWidth,
1519             pixelSnappedBox.maxY(),
1520             min(pixelSnappedBox.maxX() + outlineWidth, !nextline.isEmpty() ? pixelSnappedNextLine.x() + 1 : 1000000),
1521             pixelSnappedBox.maxY() + outlineWidth,
1522             BSBottom, outlineColor, outlineStyle,
1523             outlineWidth,
1524             (!nextline.isEmpty() && paintOffset.x() + nextline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth,
1525             antialias);
1526     
1527     if (nextline.maxX() < thisline.maxX())
1528         drawLineForBoxSide(graphicsContext,
1529             max(!nextline.isEmpty() ? pixelSnappedNextLine.maxX() : -1000000, pixelSnappedBox.x() - outlineWidth),
1530             pixelSnappedBox.maxY(),
1531             pixelSnappedBox.maxX() + outlineWidth,
1532             pixelSnappedBox.maxY() + outlineWidth,
1533             BSBottom, outlineColor, outlineStyle,
1534             (!nextline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + nextline.maxX()) ? -outlineWidth : outlineWidth,
1535             outlineWidth, antialias);
1536
1537     if (thisline.x() == thisline.maxX())
1538           drawLineForBoxSide(graphicsContext,
1539             pixelSnappedBox.x() - outlineWidth,
1540             pixelSnappedBox.maxY(),
1541             pixelSnappedBox.maxX() + outlineWidth,
1542             pixelSnappedBox.maxY() + outlineWidth,
1543             BSBottom, outlineColor, outlineStyle,
1544             outlineWidth,
1545             outlineWidth,
1546             antialias);
1547 }
1548
1549 #if ENABLE(DASHBOARD_SUPPORT)
1550 void RenderInline::addDashboardRegions(Vector<DashboardRegionValue>& regions)
1551 {
1552     // Convert the style regions to absolute coordinates.
1553     if (style()->visibility() != VISIBLE)
1554         return;
1555
1556     const Vector<StyleDashboardRegion>& styleRegions = style()->dashboardRegions();
1557     unsigned i, count = styleRegions.size();
1558     for (i = 0; i < count; i++) {
1559         StyleDashboardRegion styleRegion = styleRegions[i];
1560
1561         LayoutRect linesBoundingBox = this->linesBoundingBox();
1562         LayoutUnit w = linesBoundingBox.width();
1563         LayoutUnit h = linesBoundingBox.height();
1564
1565         DashboardRegionValue region;
1566         region.label = styleRegion.label;
1567         region.bounds = LayoutRect(linesBoundingBox.x() + styleRegion.offset.left().value(),
1568                                 linesBoundingBox.y() + styleRegion.offset.top().value(),
1569                                 w - styleRegion.offset.left().value() - styleRegion.offset.right().value(),
1570                                 h - styleRegion.offset.top().value() - styleRegion.offset.bottom().value());
1571         region.type = styleRegion.type;
1572
1573         RenderObject* container = containingBlock();
1574         if (!container)
1575             container = this;
1576
1577         region.clip = region.bounds;
1578         container->computeAbsoluteRepaintRect(region.clip);
1579         if (region.clip.height() < 0) {
1580             region.clip.setHeight(0);
1581             region.clip.setWidth(0);
1582         }
1583
1584         FloatPoint absPos = container->localToAbsolute();
1585         region.bounds.setX(absPos.x() + region.bounds.x());
1586         region.bounds.setY(absPos.y() + region.bounds.y());
1587
1588         regions.append(region);
1589     }
1590 }
1591 #endif
1592
1593 } // namespace WebCore