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