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