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