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