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