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