Implement rendering support for the color-filter CSS property
[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::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
259 {
260     m_lineBoxes.paint(this, paintInfo, paintOffset);
261 }
262
263 template<typename GeneratorContext>
264 void RenderInline::generateLineBoxRects(GeneratorContext& context) const
265 {
266     if (!alwaysCreateLineBoxes())
267         generateCulledLineBoxRects(context, this);
268     else if (InlineFlowBox* curr = firstLineBox()) {
269         for (; curr; curr = curr->nextLineBox())
270             context.addRect(FloatRect(curr->topLeft(), curr->size()));
271     } else
272         context.addRect(FloatRect());
273 }
274
275 template<typename GeneratorContext>
276 void RenderInline::generateCulledLineBoxRects(GeneratorContext& context, const RenderInline* container) const
277 {
278     if (!culledInlineFirstLineBox()) {
279         context.addRect(FloatRect());
280         return;
281     }
282
283     bool isHorizontal = style().isHorizontalWritingMode();
284
285     for (auto& current : childrenOfType<RenderObject>(*this)) {
286         if (current.isFloatingOrOutOfFlowPositioned())
287             continue;
288
289         // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
290         // direction (aligned to the root box's baseline).
291         if (is<RenderBox>(current)) {
292             auto& renderBox = downcast<RenderBox>(current);
293             if (renderBox.inlineBoxWrapper()) {
294                 const RootInlineBox& rootBox = renderBox.inlineBoxWrapper()->root();
295                 const RenderStyle& containerStyle = rootBox.isFirstLine() ? container->firstLineStyle() : container->style();
296                 int logicalTop = rootBox.logicalTop() + (rootBox.lineStyle().fontCascade().fontMetrics().ascent() - containerStyle.fontCascade().fontMetrics().ascent());
297                 int logicalHeight = containerStyle.fontCascade().fontMetrics().height();
298                 if (isHorizontal)
299                     context.addRect(FloatRect(renderBox.inlineBoxWrapper()->x() - renderBox.marginLeft(), logicalTop, renderBox.width() + renderBox.horizontalMarginExtent(), logicalHeight));
300                 else
301                     context.addRect(FloatRect(logicalTop, renderBox.inlineBoxWrapper()->y() - renderBox.marginTop(), logicalHeight, renderBox.height() + renderBox.verticalMarginExtent()));
302             }
303         } else if (is<RenderInline>(current)) {
304             // If the child doesn't need line boxes either, then we can recur.
305             auto& renderInline = downcast<RenderInline>(current);
306             if (!renderInline.alwaysCreateLineBoxes())
307                 renderInline.generateCulledLineBoxRects(context, container);
308             else {
309                 for (InlineFlowBox* childLine = renderInline.firstLineBox(); childLine; childLine = childLine->nextLineBox()) {
310                     const RootInlineBox& rootBox = childLine->root();
311                     const RenderStyle& containerStyle = rootBox.isFirstLine() ? container->firstLineStyle() : container->style();
312                     int logicalTop = rootBox.logicalTop() + (rootBox.lineStyle().fontCascade().fontMetrics().ascent() - containerStyle.fontCascade().fontMetrics().ascent());
313                     int logicalHeight = containerStyle.fontMetrics().height();
314                     if (isHorizontal) {
315                         context.addRect(FloatRect(childLine->x() - childLine->marginLogicalLeft(),
316                             logicalTop,
317                             childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(),
318                             logicalHeight));
319                     } else {
320                         context.addRect(FloatRect(logicalTop,
321                             childLine->y() - childLine->marginLogicalLeft(),
322                             logicalHeight,
323                             childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight()));
324                     }
325                 }
326             }
327         } else if (is<RenderText>(current)) {
328             auto& currText = downcast<RenderText>(current);
329             for (InlineTextBox* childText = currText.firstTextBox(); childText; childText = childText->nextTextBox()) {
330                 const RootInlineBox& rootBox = childText->root();
331                 const RenderStyle& containerStyle = rootBox.isFirstLine() ? container->firstLineStyle() : container->style();
332                 int logicalTop = rootBox.logicalTop() + (rootBox.lineStyle().fontCascade().fontMetrics().ascent() - containerStyle.fontCascade().fontMetrics().ascent());
333                 int logicalHeight = containerStyle.fontCascade().fontMetrics().height();
334                 if (isHorizontal)
335                     context.addRect(FloatRect(childText->x(), logicalTop, childText->logicalWidth(), logicalHeight));
336                 else
337                     context.addRect(FloatRect(logicalTop, childText->y(), logicalHeight, childText->logicalWidth()));
338             }
339         } else if (is<RenderLineBreak>(current)) {
340             if (auto* inlineBox = downcast<RenderLineBreak>(current).inlineBoxWrapper()) {
341                 // FIXME: This could use a helper to share these with text path.
342                 const RootInlineBox& rootBox = inlineBox->root();
343                 const RenderStyle& containerStyle = rootBox.isFirstLine() ? container->firstLineStyle() : container->style();
344                 int logicalTop = rootBox.logicalTop() + (rootBox.lineStyle().fontCascade().fontMetrics().ascent() - containerStyle.fontCascade().fontMetrics().ascent());
345                 int logicalHeight = containerStyle.fontMetrics().height();
346                 if (isHorizontal)
347                     context.addRect(FloatRect(inlineBox->x(), logicalTop, inlineBox->logicalWidth(), logicalHeight));
348                 else
349                     context.addRect(FloatRect(logicalTop, inlineBox->y(), logicalHeight, inlineBox->logicalWidth()));
350             }
351         }
352     }
353 }
354
355 namespace {
356
357 class AbsoluteRectsGeneratorContext {
358 public:
359     AbsoluteRectsGeneratorContext(Vector<LayoutRect>& rects, const LayoutPoint& accumulatedOffset)
360         : m_rects(rects)
361         , m_accumulatedOffset(accumulatedOffset) { }
362
363     void addRect(const FloatRect& rect)
364     {
365         LayoutRect adjustedRect = LayoutRect(rect);
366         adjustedRect.moveBy(m_accumulatedOffset);
367         m_rects.append(adjustedRect);
368     }
369 private:
370     Vector<LayoutRect>& m_rects;
371     const LayoutPoint& m_accumulatedOffset;
372 };
373
374 } // unnamed namespace
375
376 void RenderInline::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
377 {
378     Vector<LayoutRect> lineboxRects;
379     AbsoluteRectsGeneratorContext context(lineboxRects, accumulatedOffset);
380     generateLineBoxRects(context);
381     for (const auto& rect : lineboxRects)
382         rects.append(snappedIntRect(rect));
383
384     if (RenderBoxModelObject* continuation = this->continuation()) {
385         if (is<RenderBox>(*continuation)) {
386             auto& box = downcast<RenderBox>(*continuation);
387             continuation->absoluteRects(rects, toLayoutPoint(accumulatedOffset - containingBlock()->location() + box.locationOffset()));
388         } else
389             continuation->absoluteRects(rects, toLayoutPoint(accumulatedOffset - containingBlock()->location()));
390     }
391 }
392
393
394 namespace {
395
396 class AbsoluteQuadsGeneratorContext {
397 public:
398     AbsoluteQuadsGeneratorContext(const RenderInline* renderer, Vector<FloatQuad>& quads)
399         : m_quads(quads)
400         , m_geometryMap()
401     {
402         m_geometryMap.pushMappingsToAncestor(renderer, nullptr);
403     }
404
405     void addRect(const FloatRect& rect)
406     {
407         m_quads.append(m_geometryMap.absoluteRect(rect));
408     }
409 private:
410     Vector<FloatQuad>& m_quads;
411     RenderGeometryMap m_geometryMap;
412 };
413
414 } // unnamed namespace
415
416 void RenderInline::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
417 {
418     AbsoluteQuadsGeneratorContext context(this, quads);
419     generateLineBoxRects(context);
420
421     if (RenderBoxModelObject* continuation = this->continuation())
422         continuation->absoluteQuads(quads, wasFixed);
423 }
424
425 #if PLATFORM(IOS)
426 void RenderInline::absoluteQuadsForSelection(Vector<FloatQuad>& quads) const
427 {
428     AbsoluteQuadsGeneratorContext context(this, quads);
429     generateLineBoxRects(context);
430 }
431 #endif
432
433 LayoutUnit RenderInline::offsetLeft() const
434 {
435     LayoutPoint topLeft;
436     if (InlineBox* firstBox = firstLineBoxIncludingCulling())
437         topLeft = flooredLayoutPoint(firstBox->topLeft());
438     return adjustedPositionRelativeToOffsetParent(topLeft).x();
439 }
440
441 LayoutUnit RenderInline::offsetTop() const
442 {
443     LayoutPoint topLeft;
444     if (InlineBox* firstBox = firstLineBoxIncludingCulling())
445         topLeft = flooredLayoutPoint(firstBox->topLeft());
446     return adjustedPositionRelativeToOffsetParent(topLeft).y();
447 }
448
449 static LayoutUnit computeMargin(const RenderInline* renderer, const Length& margin)
450 {
451     if (margin.isAuto())
452         return 0;
453     if (margin.isFixed())
454         return margin.value();
455     if (margin.isPercentOrCalculated())
456         return minimumValueForLength(margin, std::max<LayoutUnit>(0, renderer->containingBlock()->availableLogicalWidth()));
457     return 0;
458 }
459
460 LayoutUnit RenderInline::marginLeft() const
461 {
462     return computeMargin(this, style().marginLeft());
463 }
464
465 LayoutUnit RenderInline::marginRight() const
466 {
467     return computeMargin(this, style().marginRight());
468 }
469
470 LayoutUnit RenderInline::marginTop() const
471 {
472     return computeMargin(this, style().marginTop());
473 }
474
475 LayoutUnit RenderInline::marginBottom() const
476 {
477     return computeMargin(this, style().marginBottom());
478 }
479
480 LayoutUnit RenderInline::marginStart(const RenderStyle* otherStyle) const
481 {
482     return computeMargin(this, style().marginStartUsing(otherStyle ? otherStyle : &style()));
483 }
484
485 LayoutUnit RenderInline::marginEnd(const RenderStyle* otherStyle) const
486 {
487     return computeMargin(this, style().marginEndUsing(otherStyle ? otherStyle : &style()));
488 }
489
490 LayoutUnit RenderInline::marginBefore(const RenderStyle* otherStyle) const
491 {
492     return computeMargin(this, style().marginBeforeUsing(otherStyle ? otherStyle : &style()));
493 }
494
495 LayoutUnit RenderInline::marginAfter(const RenderStyle* otherStyle) const
496 {
497     return computeMargin(this, style().marginAfterUsing(otherStyle ? otherStyle : &style()));
498 }
499
500 const char* RenderInline::renderName() const
501 {
502     if (isRelativelyPositioned())
503         return "RenderInline (relative positioned)";
504     if (isStickilyPositioned())
505         return "RenderInline (sticky positioned)";
506     // FIXME: Temporary hack while the new generated content system is being implemented.
507     if (isPseudoElement())
508         return "RenderInline (generated)";
509     if (isAnonymous())
510         return "RenderInline (generated)";
511     return "RenderInline";
512 }
513
514 bool RenderInline::nodeAtPoint(const HitTestRequest& request, HitTestResult& result,
515                                 const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
516 {
517     return m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction);
518 }
519
520 namespace {
521
522 class HitTestCulledInlinesGeneratorContext {
523 public:
524     HitTestCulledInlinesGeneratorContext(Region& region, const HitTestLocation& location)
525         : m_intersected(false)
526         , m_region(region)
527         , m_location(location)
528     { }
529
530     void addRect(const FloatRect& rect)
531     {
532         m_intersected = m_intersected || m_location.intersects(rect);
533         m_region.unite(enclosingIntRect(rect));
534     }
535
536     bool intersected() const { return m_intersected; }
537
538 private:
539     bool m_intersected;
540     Region& m_region;
541     const HitTestLocation& m_location;
542 };
543
544 } // unnamed namespace
545
546 bool RenderInline::hitTestCulledInline(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset)
547 {
548     ASSERT(result.isRectBasedTest() && !alwaysCreateLineBoxes());
549     if (!visibleToHitTesting())
550         return false;
551
552     HitTestLocation tmpLocation(locationInContainer, -toLayoutSize(accumulatedOffset));
553
554     Region regionResult;
555     HitTestCulledInlinesGeneratorContext context(regionResult, tmpLocation);
556     generateCulledLineBoxRects(context, this);
557
558     if (context.intersected()) {
559         updateHitTestResult(result, tmpLocation.point());
560         // We cannot use addNodeToListBasedTestResult to determine if we fully enclose the hit-test area
561         // because it can only handle rectangular targets.
562         result.addNodeToListBasedTestResult(element(), request, locationInContainer);
563         return regionResult.contains(tmpLocation.boundingBox());
564     }
565     return false;
566 }
567
568 VisiblePosition RenderInline::positionForPoint(const LayoutPoint& point, const RenderFragmentContainer* fragment)
569 {
570     // FIXME: Does not deal with relative or sticky positioned inlines (should it?)
571     RenderBlock& containingBlock = *this->containingBlock();
572     if (firstLineBox()) {
573         // This inline actually has a line box.  We must have clicked in the border/padding of one of these boxes.  We
574         // should try to find a result by asking our containing block.
575         return containingBlock.positionForPoint(point, fragment);
576     }
577
578     // Translate the coords from the pre-anonymous block to the post-anonymous block.
579     LayoutPoint parentBlockPoint = containingBlock.location() + point;
580     RenderBoxModelObject* continuation = this->continuation();
581     while (continuation) {
582         RenderBlock* currentBlock = continuation->isInline() ? continuation->containingBlock() : downcast<RenderBlock>(continuation);
583         if (continuation->isInline() || continuation->firstChild())
584             return continuation->positionForPoint(parentBlockPoint - currentBlock->locationOffset(), fragment);
585         continuation = continuation->inlineContinuation();
586     }
587     
588     return RenderBoxModelObject::positionForPoint(point, fragment);
589 }
590
591 namespace {
592
593 class LinesBoundingBoxGeneratorContext {
594 public:
595     LinesBoundingBoxGeneratorContext(FloatRect& rect) : m_rect(rect) { }
596
597     void addRect(const FloatRect& rect)
598     {
599         m_rect.uniteIfNonZero(rect);
600     }
601 private:
602     FloatRect& m_rect;
603 };
604
605 } // unnamed namespace
606
607 IntRect RenderInline::linesBoundingBox() const
608 {
609     if (!alwaysCreateLineBoxes()) {
610         ASSERT(!firstLineBox());
611         FloatRect floatResult;
612         LinesBoundingBoxGeneratorContext context(floatResult);
613         generateCulledLineBoxRects(context, this);
614         return enclosingIntRect(floatResult);
615     }
616
617     IntRect result;
618     
619     // 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
620     // 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
621     // builds and help us someday figure out why.  We also put in a redundant check of lastLineBox() to avoid the crash for now.
622     ASSERT(!firstLineBox() == !lastLineBox());  // Either both are null or both exist.
623     if (firstLineBox() && lastLineBox()) {
624         // Return the width of the minimal left side and the maximal right side.
625         float logicalLeftSide = 0;
626         float logicalRightSide = 0;
627         for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
628             if (curr == firstLineBox() || curr->logicalLeft() < logicalLeftSide)
629                 logicalLeftSide = curr->logicalLeft();
630             if (curr == firstLineBox() || curr->logicalRight() > logicalRightSide)
631                 logicalRightSide = curr->logicalRight();
632         }
633         
634         bool isHorizontal = style().isHorizontalWritingMode();
635         
636         float x = isHorizontal ? logicalLeftSide : firstLineBox()->x();
637         float y = isHorizontal ? firstLineBox()->y() : logicalLeftSide;
638         float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastLineBox()->logicalBottom() - x;
639         float height = isHorizontal ? lastLineBox()->logicalBottom() - y : logicalRightSide - logicalLeftSide;
640         result = enclosingIntRect(FloatRect(x, y, width, height));
641     }
642
643     return result;
644 }
645
646 InlineBox* RenderInline::culledInlineFirstLineBox() const
647 {
648     for (auto& current : childrenOfType<RenderObject>(*this)) {
649         if (current.isFloatingOrOutOfFlowPositioned())
650             continue;
651
652         // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
653         // direction (aligned to the root box's baseline).
654         if (is<RenderBox>(current)) {
655             auto& renderBox = downcast<RenderBox>(current);
656             if (renderBox.inlineBoxWrapper())
657                 return renderBox.inlineBoxWrapper();
658         } else if (is<RenderLineBreak>(current)) {
659             auto& renderBR = downcast<RenderLineBreak>(current);
660             if (renderBR.inlineBoxWrapper())
661                 return renderBR.inlineBoxWrapper();
662         } else if (is<RenderInline>(current)) {
663             auto& renderInline = downcast<RenderInline>(current);
664             if (InlineBox* result = renderInline.firstLineBoxIncludingCulling())
665                 return result;
666         } else if (is<RenderText>(current)) {
667             auto& renderText = downcast<RenderText>(current);
668             if (renderText.firstTextBox())
669                 return renderText.firstTextBox();
670         }
671     }
672     return nullptr;
673 }
674
675 InlineBox* RenderInline::culledInlineLastLineBox() const
676 {
677     for (RenderObject* current = lastChild(); current; current = current->previousSibling()) {
678         if (current->isFloatingOrOutOfFlowPositioned())
679             continue;
680             
681         // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
682         // direction (aligned to the root box's baseline).
683         if (is<RenderBox>(*current)) {
684             const auto& renderBox = downcast<RenderBox>(*current);
685             if (renderBox.inlineBoxWrapper())
686                 return renderBox.inlineBoxWrapper();
687         } else if (is<RenderLineBreak>(*current)) {
688             RenderLineBreak& renderBR = downcast<RenderLineBreak>(*current);
689             if (renderBR.inlineBoxWrapper())
690                 return renderBR.inlineBoxWrapper();
691         } else if (is<RenderInline>(*current)) {
692             RenderInline& renderInline = downcast<RenderInline>(*current);
693             if (InlineBox* result = renderInline.lastLineBoxIncludingCulling())
694                 return result;
695         } else if (is<RenderText>(*current)) {
696             RenderText& renderText = downcast<RenderText>(*current);
697             if (renderText.lastTextBox())
698                 return renderText.lastTextBox();
699         }
700     }
701     return nullptr;
702 }
703
704 LayoutRect RenderInline::culledInlineVisualOverflowBoundingBox() const
705 {
706     FloatRect floatResult;
707     LinesBoundingBoxGeneratorContext context(floatResult);
708     generateCulledLineBoxRects(context, this);
709     LayoutRect result(enclosingLayoutRect(floatResult));
710     bool isHorizontal = style().isHorizontalWritingMode();
711     for (auto& current : childrenOfType<RenderObject>(*this)) {
712         if (current.isFloatingOrOutOfFlowPositioned())
713             continue;
714
715         // For overflow we just have to propagate by hand and recompute it all.
716         if (is<RenderBox>(current)) {
717             auto& renderBox = downcast<RenderBox>(current);
718             if (!renderBox.hasSelfPaintingLayer() && renderBox.inlineBoxWrapper()) {
719                 LayoutRect logicalRect = renderBox.logicalVisualOverflowRectForPropagation(&style());
720                 if (isHorizontal) {
721                     logicalRect.moveBy(renderBox.location());
722                     result.uniteIfNonZero(logicalRect);
723                 } else {
724                     logicalRect.moveBy(renderBox.location());
725                     result.uniteIfNonZero(logicalRect.transposedRect());
726                 }
727             }
728         } else if (is<RenderInline>(current)) {
729             // If the child doesn't need line boxes either, then we can recur.
730             auto& renderInline = downcast<RenderInline>(current);
731             if (!renderInline.alwaysCreateLineBoxes())
732                 result.uniteIfNonZero(renderInline.culledInlineVisualOverflowBoundingBox());
733             else if (!renderInline.hasSelfPaintingLayer())
734                 result.uniteIfNonZero(renderInline.linesVisualOverflowBoundingBox());
735         } else if (is<RenderText>(current)) {
736             // FIXME; Overflow from text boxes is lost. We will need to cache this information in
737             // InlineTextBoxes.
738             auto& renderText = downcast<RenderText>(current);
739             result.uniteIfNonZero(renderText.linesVisualOverflowBoundingBox());
740         }
741     }
742     return result;
743 }
744
745 LayoutRect RenderInline::linesVisualOverflowBoundingBox() const
746 {
747     if (!alwaysCreateLineBoxes())
748         return culledInlineVisualOverflowBoundingBox();
749
750     if (!firstLineBox() || !lastLineBox())
751         return LayoutRect();
752
753     // Return the width of the minimal left side and the maximal right side.
754     LayoutUnit logicalLeftSide = LayoutUnit::max();
755     LayoutUnit logicalRightSide = LayoutUnit::min();
756     for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
757         logicalLeftSide = std::min(logicalLeftSide, curr->logicalLeftVisualOverflow());
758         logicalRightSide = std::max(logicalRightSide, curr->logicalRightVisualOverflow());
759     }
760
761     const RootInlineBox& firstRootBox = firstLineBox()->root();
762     const RootInlineBox& lastRootBox = lastLineBox()->root();
763     
764     LayoutUnit logicalTop = firstLineBox()->logicalTopVisualOverflow(firstRootBox.lineTop());
765     LayoutUnit logicalWidth = logicalRightSide - logicalLeftSide;
766     LayoutUnit logicalHeight = lastLineBox()->logicalBottomVisualOverflow(lastRootBox.lineBottom()) - logicalTop;
767     
768     LayoutRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight);
769     if (!style().isHorizontalWritingMode())
770         rect = rect.transposedRect();
771     return rect;
772 }
773
774 LayoutRect RenderInline::linesVisualOverflowBoundingBoxInFragment(const RenderFragmentContainer* fragment) const
775 {
776     ASSERT(alwaysCreateLineBoxes());
777     ASSERT(fragment);
778
779     if (!firstLineBox() || !lastLineBox())
780         return LayoutRect();
781
782     // Return the width of the minimal left side and the maximal right side.
783     LayoutUnit logicalLeftSide = LayoutUnit::max();
784     LayoutUnit logicalRightSide = LayoutUnit::min();
785     LayoutUnit logicalTop;
786     LayoutUnit logicalHeight;
787     InlineFlowBox* lastInlineInFragment = 0;
788     for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
789         const RootInlineBox& root = curr->root();
790         if (root.containingFragment() != fragment) {
791             if (lastInlineInFragment)
792                 break;
793             continue;
794         }
795
796         if (!lastInlineInFragment)
797             logicalTop = curr->logicalTopVisualOverflow(root.lineTop());
798
799         lastInlineInFragment = curr;
800
801         logicalLeftSide = std::min(logicalLeftSide, curr->logicalLeftVisualOverflow());
802         logicalRightSide = std::max(logicalRightSide, curr->logicalRightVisualOverflow());
803     }
804
805     if (!lastInlineInFragment)
806         return LayoutRect();
807
808     logicalHeight = lastInlineInFragment->logicalBottomVisualOverflow(lastInlineInFragment->root().lineBottom()) - logicalTop;
809     
810     LayoutUnit logicalWidth = logicalRightSide - logicalLeftSide;
811     
812     LayoutRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight);
813     if (!style().isHorizontalWritingMode())
814         rect = rect.transposedRect();
815     return rect;
816 }
817
818 LayoutRect RenderInline::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const
819 {
820     // Only first-letter renderers are allowed in here during layout. They mutate the tree triggering repaints.
821     ASSERT(!view().frameView().layoutContext().isPaintOffsetCacheEnabled() || style().styleType() == FIRST_LETTER || hasSelfPaintingLayer());
822
823     if (!firstLineBoxIncludingCulling() && !continuation())
824         return LayoutRect();
825
826     LayoutRect repaintRect(linesVisualOverflowBoundingBox());
827     bool hitRepaintContainer = false;
828
829     // We need to add in the in-flow position offsets of any inlines (including us) up to our
830     // containing block.
831     RenderBlock* containingBlock = this->containingBlock();
832     for (const RenderElement* inlineFlow = this; is<RenderInline>(inlineFlow) && inlineFlow != containingBlock;
833          inlineFlow = inlineFlow->parent()) {
834          if (inlineFlow == repaintContainer) {
835             hitRepaintContainer = true;
836             break;
837         }
838         if (inlineFlow->style().hasInFlowPosition() && inlineFlow->hasLayer())
839             repaintRect.move(downcast<RenderInline>(*inlineFlow).layer()->offsetForInFlowPosition());
840     }
841
842     LayoutUnit outlineSize = style().outlineSize();
843     repaintRect.inflate(outlineSize);
844
845     if (hitRepaintContainer || !containingBlock)
846         return repaintRect;
847
848     if (containingBlock->hasOverflowClip() && containingBlock->shouldApplyClipAndScrollPositionForRepaint(repaintContainer))
849         containingBlock->applyCachedClipAndScrollPositionForRepaint(repaintRect);
850
851     repaintRect = containingBlock->computeRectForRepaint(repaintRect, repaintContainer);
852
853     if (outlineSize) {
854         for (auto& child : childrenOfType<RenderElement>(*this))
855             repaintRect.unite(child.rectWithOutlineForRepaint(repaintContainer, outlineSize));
856
857         if (RenderBoxModelObject* continuation = this->continuation()) {
858             if (!continuation->isInline() && continuation->parent())
859                 repaintRect.unite(continuation->rectWithOutlineForRepaint(repaintContainer, outlineSize));
860         }
861     }
862
863     return repaintRect;
864 }
865
866 LayoutRect RenderInline::rectWithOutlineForRepaint(const RenderLayerModelObject* repaintContainer, LayoutUnit outlineWidth) const
867 {
868     LayoutRect r(RenderBoxModelObject::rectWithOutlineForRepaint(repaintContainer, outlineWidth));
869     for (auto& child : childrenOfType<RenderElement>(*this))
870         r.unite(child.rectWithOutlineForRepaint(repaintContainer, outlineWidth));
871     return r;
872 }
873
874 LayoutRect RenderInline::computeRectForRepaint(const LayoutRect& rect, const RenderLayerModelObject* repaintContainer, RepaintContext context) const
875 {
876     // Repaint offset cache is only valid for root-relative repainting
877     LayoutRect adjustedRect = rect;
878     if (view().frameView().layoutContext().isPaintOffsetCacheEnabled() && !repaintContainer) {
879         auto* layoutState = view().frameView().layoutContext().layoutState();
880         if (style().hasInFlowPosition() && layer())
881             adjustedRect.move(layer()->offsetForInFlowPosition());
882         adjustedRect.move(layoutState->paintOffset());
883         if (layoutState->isClipped())
884             adjustedRect.intersect(layoutState->clipRect());
885         return adjustedRect;
886     }
887
888     if (repaintContainer == this)
889         return adjustedRect;
890
891     bool containerSkipped;
892     RenderElement* container = this->container(repaintContainer, containerSkipped);
893     if (!container)
894         return adjustedRect;
895
896     LayoutPoint topLeft = adjustedRect.location();
897
898     if (style().hasInFlowPosition() && layer()) {
899         // Apply the in-flow position offset when invalidating a rectangle. The layer
900         // is translated, but the render box isn't, so we need to do this to get the
901         // right dirty rect. Since this is called from RenderObject::setStyle, the relative or sticky position
902         // flag on the RenderObject has been cleared, so use the one on the style().
903         topLeft += layer()->offsetForInFlowPosition();
904     }
905     
906     // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
907     // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
908     adjustedRect.setLocation(topLeft);
909     if (container->hasOverflowClip()) {
910         downcast<RenderBox>(*container).applyCachedClipAndScrollPositionForRepaint(adjustedRect);
911         if (adjustedRect.isEmpty())
912             return adjustedRect;
913     }
914
915     if (containerSkipped) {
916         // If the repaintContainer is below o, then we need to map the rect into repaintContainer's coordinates.
917         LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(*container);
918         adjustedRect.move(-containerOffset);
919         return adjustedRect;
920     }
921     return container->computeRectForRepaint(adjustedRect, repaintContainer, context);
922 }
923
924 LayoutSize RenderInline::offsetFromContainer(RenderElement& container, const LayoutPoint&, bool* offsetDependsOnPoint) const
925 {
926     ASSERT(&container == this->container());
927     
928     LayoutSize offset;    
929     if (isInFlowPositioned())
930         offset += offsetForInFlowPosition();
931
932     if (is<RenderBox>(container))
933         offset -= toLayoutSize(downcast<RenderBox>(container).scrollPosition());
934
935     if (offsetDependsOnPoint)
936         *offsetDependsOnPoint = (is<RenderBox>(container) && container.style().isFlippedBlocksWritingMode()) || is<RenderFragmentedFlow>(container);
937
938     return offset;
939 }
940
941 void RenderInline::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const
942 {
943     if (repaintContainer == this)
944         return;
945
946     if (view().frameView().layoutContext().isPaintOffsetCacheEnabled() && !repaintContainer) {
947         auto* layoutState = view().frameView().layoutContext().layoutState();
948         LayoutSize offset = layoutState->paintOffset();
949         if (style().hasInFlowPosition() && layer())
950             offset += layer()->offsetForInFlowPosition();
951         transformState.move(offset);
952         return;
953     }
954
955     bool containerSkipped;
956     RenderElement* container = this->container(repaintContainer, containerSkipped);
957     if (!container)
958         return;
959
960     if (mode & ApplyContainerFlip && is<RenderBox>(*container)) {
961         if (container->style().isFlippedBlocksWritingMode()) {
962             LayoutPoint centerPoint(transformState.mappedPoint());
963             transformState.move(downcast<RenderBox>(*container).flipForWritingMode(centerPoint) - centerPoint);
964         }
965         mode &= ~ApplyContainerFlip;
966     }
967
968     LayoutSize containerOffset = offsetFromContainer(*container, LayoutPoint(transformState.mappedPoint()));
969
970     bool preserve3D = mode & UseTransforms && (container->style().preserves3D() || style().preserves3D());
971     if (mode & UseTransforms && shouldUseTransformFromContainer(container)) {
972         TransformationMatrix t;
973         getTransformFromContainer(container, containerOffset, t);
974         transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
975     } else
976         transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
977
978     if (containerSkipped) {
979         // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
980         // to just subtract the delta between the repaintContainer and o.
981         LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(*container);
982         transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
983         return;
984     }
985
986     container->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed);
987 }
988
989 const RenderObject* RenderInline::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const
990 {
991     ASSERT(ancestorToStopAt != this);
992
993     bool ancestorSkipped;
994     RenderElement* container = this->container(ancestorToStopAt, ancestorSkipped);
995     if (!container)
996         return nullptr;
997
998     LayoutSize adjustmentForSkippedAncestor;
999     if (ancestorSkipped) {
1000         // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
1001         // to just subtract the delta between the ancestor and o.
1002         adjustmentForSkippedAncestor = -ancestorToStopAt->offsetFromAncestorContainer(*container);
1003     }
1004
1005     bool offsetDependsOnPoint = false;
1006     LayoutSize containerOffset = offsetFromContainer(*container, LayoutPoint(), &offsetDependsOnPoint);
1007
1008     bool preserve3D = container->style().preserves3D() || style().preserves3D();
1009     if (shouldUseTransformFromContainer(container)) {
1010         TransformationMatrix t;
1011         getTransformFromContainer(container, containerOffset, t);
1012         t.translateRight(adjustmentForSkippedAncestor.width(), adjustmentForSkippedAncestor.height()); // FIXME: right?
1013         geometryMap.push(this, t, preserve3D, offsetDependsOnPoint);
1014     } else {
1015         containerOffset += adjustmentForSkippedAncestor;
1016         geometryMap.push(this, containerOffset, preserve3D, offsetDependsOnPoint);
1017     }
1018     
1019     return ancestorSkipped ? ancestorToStopAt : container;
1020 }
1021
1022 void RenderInline::updateDragState(bool dragOn)
1023 {
1024     RenderBoxModelObject::updateDragState(dragOn);
1025     if (RenderBoxModelObject* continuation = this->continuation())
1026         continuation->updateDragState(dragOn);
1027 }
1028
1029 void RenderInline::updateHitTestResult(HitTestResult& result, const LayoutPoint& point)
1030 {
1031     if (result.innerNode())
1032         return;
1033
1034     LayoutPoint localPoint(point);
1035     if (Element* element = this->element()) {
1036         if (isContinuation()) {
1037             // We're in the continuation of a split inline.  Adjust our local point to be in the coordinate space
1038             // of the principal renderer's containing block.  This will end up being the innerNonSharedNode.
1039             RenderBlock* firstBlock = element->renderer()->containingBlock();
1040             
1041             // Get our containing block.
1042             RenderBox* block = containingBlock();
1043             localPoint.moveBy(block->location() - firstBlock->locationOffset());
1044         }
1045
1046         result.setInnerNode(element);
1047         if (!result.innerNonSharedNode())
1048             result.setInnerNonSharedNode(element);
1049         result.setLocalPoint(localPoint);
1050     }
1051 }
1052
1053 void RenderInline::dirtyLineBoxes(bool fullLayout)
1054 {
1055     if (fullLayout) {
1056         m_lineBoxes.deleteLineBoxes();
1057         return;
1058     }
1059
1060     if (!alwaysCreateLineBoxes()) {
1061         // We have to grovel into our children in order to dirty the appropriate lines.
1062         for (auto& current : childrenOfType<RenderObject>(*this)) {
1063             if (current.isFloatingOrOutOfFlowPositioned())
1064                 continue;
1065             if (is<RenderBox>(current) && !current.needsLayout()) {
1066                 auto& renderBox = downcast<RenderBox>(current);
1067                 if (renderBox.inlineBoxWrapper())
1068                     renderBox.inlineBoxWrapper()->root().markDirty();
1069             } else if (!current.selfNeedsLayout()) {
1070                 if (is<RenderInline>(current)) {
1071                     auto& renderInline = downcast<RenderInline>(current);
1072                     for (InlineFlowBox* childLine = renderInline.firstLineBox(); childLine; childLine = childLine->nextLineBox())
1073                         childLine->root().markDirty();
1074                 } else if (is<RenderText>(current)) {
1075                     auto& renderText = downcast<RenderText>(current);
1076                     for (InlineTextBox* childText = renderText.firstTextBox(); childText; childText = childText->nextTextBox())
1077                         childText->root().markDirty();
1078                 } else if (is<RenderLineBreak>(current)) {
1079                     auto& renderBR = downcast<RenderLineBreak>(current);
1080                     if (renderBR.inlineBoxWrapper())
1081                         renderBR.inlineBoxWrapper()->root().markDirty();
1082                 }
1083             }
1084         }
1085     } else
1086         m_lineBoxes.dirtyLineBoxes();
1087 }
1088
1089 void RenderInline::deleteLines()
1090 {
1091     m_lineBoxes.deleteLineBoxTree();
1092 }
1093
1094 std::unique_ptr<InlineFlowBox> RenderInline::createInlineFlowBox()
1095 {
1096     return std::make_unique<InlineFlowBox>(*this);
1097 }
1098
1099 InlineFlowBox* RenderInline::createAndAppendInlineFlowBox()
1100 {
1101     setAlwaysCreateLineBoxes();
1102     auto newFlowBox = createInlineFlowBox();
1103     auto flowBox = newFlowBox.get();
1104     m_lineBoxes.appendLineBox(WTFMove(newFlowBox));
1105     return flowBox;
1106 }
1107
1108 LayoutUnit RenderInline::lineHeight(bool firstLine, LineDirectionMode /*direction*/, LinePositionMode /*linePositionMode*/) const
1109 {
1110     if (firstLine && view().usesFirstLineRules()) {
1111         const RenderStyle& firstLineStyle = this->firstLineStyle();
1112         if (&firstLineStyle != &style())
1113             return firstLineStyle.computedLineHeight();
1114     }
1115
1116     return style().computedLineHeight();
1117 }
1118
1119 int RenderInline::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
1120 {
1121     const RenderStyle& style = firstLine ? firstLineStyle() : this->style();
1122     const FontMetrics& fontMetrics = style.fontMetrics();
1123     return fontMetrics.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - fontMetrics.height()) / 2;
1124 }
1125
1126 LayoutSize RenderInline::offsetForInFlowPositionedInline(const RenderBox* child) const
1127 {
1128     // FIXME: This function isn't right with mixed writing modes.
1129
1130     ASSERT(isInFlowPositioned());
1131     if (!isInFlowPositioned())
1132         return LayoutSize();
1133
1134     // When we have an enclosing relpositioned inline, we need to add in the offset of the first line
1135     // box from the rest of the content, but only in the cases where we know we're positioned
1136     // relative to the inline itself.
1137
1138     LayoutSize logicalOffset;
1139     LayoutUnit inlinePosition;
1140     LayoutUnit blockPosition;
1141     if (firstLineBox()) {
1142         inlinePosition = LayoutUnit::fromFloatRound(firstLineBox()->logicalLeft());
1143         blockPosition = firstLineBox()->logicalTop();
1144     } else {
1145         inlinePosition = layer()->staticInlinePosition();
1146         blockPosition = layer()->staticBlockPosition();
1147     }
1148
1149     if (!child->style().hasStaticInlinePosition(style().isHorizontalWritingMode()))
1150         logicalOffset.setWidth(inlinePosition);
1151
1152     // This is not terribly intuitive, but we have to match other browsers.  Despite being a block display type inside
1153     // an inline, we still keep our x locked to the left of the relative positioned inline.  Arguably the correct
1154     // behavior would be to go flush left to the block that contains the inline, but that isn't what other browsers
1155     // do.
1156     else if (!child->style().isOriginalDisplayInlineType())
1157         // Avoid adding in the left border/padding of the containing block twice.  Subtract it out.
1158         logicalOffset.setWidth(inlinePosition - child->containingBlock()->borderAndPaddingLogicalLeft());
1159
1160     if (!child->style().hasStaticBlockPosition(style().isHorizontalWritingMode()))
1161         logicalOffset.setHeight(blockPosition);
1162
1163     return style().isHorizontalWritingMode() ? logicalOffset : logicalOffset.transposedSize();
1164 }
1165
1166 void RenderInline::imageChanged(WrappedImagePtr, const IntRect*)
1167 {
1168     if (!parent())
1169         return;
1170         
1171     // FIXME: We can do better.
1172     repaint();
1173 }
1174
1175 void RenderInline::addFocusRingRects(Vector<LayoutRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer)
1176 {
1177     AbsoluteRectsGeneratorContext context(rects, additionalOffset);
1178     generateLineBoxRects(context);
1179
1180     for (auto& child : childrenOfType<RenderElement>(*this)) {
1181         if (is<RenderListMarker>(child))
1182             continue;
1183         FloatPoint pos(additionalOffset);
1184         // FIXME: This doesn't work correctly with transforms.
1185         if (child.hasLayer())
1186             pos = child.localToContainerPoint(FloatPoint(), paintContainer);
1187         else if (is<RenderBox>(child))
1188             pos.move(downcast<RenderBox>(child).locationOffset());
1189         child.addFocusRingRects(rects, flooredIntPoint(pos), paintContainer);
1190     }
1191
1192     if (RenderBoxModelObject* continuation = this->continuation()) {
1193         if (continuation->isInline())
1194             continuation->addFocusRingRects(rects, flooredLayoutPoint(LayoutPoint(additionalOffset + continuation->containingBlock()->location() - containingBlock()->location())), paintContainer);
1195         else
1196             continuation->addFocusRingRects(rects, flooredLayoutPoint(LayoutPoint(additionalOffset + downcast<RenderBox>(*continuation).location() - containingBlock()->location())), paintContainer);
1197     }
1198 }
1199
1200 void RenderInline::paintOutline(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1201 {
1202     if (!hasOutline())
1203         return;
1204
1205     auto& styleToUse = style();
1206     // Only paint the focus ring by hand if the theme isn't able to draw it.
1207     if (styleToUse.outlineStyleIsAuto() && !theme().supportsFocusRing(styleToUse)) {
1208         Vector<LayoutRect> focusRingRects;
1209         addFocusRingRects(focusRingRects, paintOffset, paintInfo.paintContainer);
1210         paintFocusRing(paintInfo, styleToUse, focusRingRects);
1211     }
1212
1213     if (hasOutlineAnnotation() && !styleToUse.outlineStyleIsAuto() && !theme().supportsFocusRing(styleToUse))
1214         addPDFURLRect(paintInfo, paintOffset);
1215
1216     GraphicsContext& graphicsContext = paintInfo.context();
1217     if (graphicsContext.paintingDisabled())
1218         return;
1219
1220     if (styleToUse.outlineStyleIsAuto() || !styleToUse.hasOutline())
1221         return;
1222
1223     Vector<LayoutRect> rects;
1224     rects.append(LayoutRect());
1225     for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
1226         const RootInlineBox& rootBox = curr->root();
1227         LayoutUnit top = std::max<LayoutUnit>(rootBox.lineTop(), curr->logicalTop());
1228         LayoutUnit bottom = std::min<LayoutUnit>(rootBox.lineBottom(), curr->logicalBottom());
1229         rects.append(LayoutRect(curr->x(), top, curr->logicalWidth(), bottom - top));
1230     }
1231     rects.append(LayoutRect());
1232
1233     Color outlineColor = styleToUse.visitedDependentColorWithColorFilter(CSSPropertyOutlineColor);
1234     bool useTransparencyLayer = !outlineColor.isOpaque();
1235     if (useTransparencyLayer) {
1236         graphicsContext.beginTransparencyLayer(outlineColor.alphaAsFloat());
1237         outlineColor = outlineColor.opaqueColor();
1238     }
1239
1240     for (unsigned i = 1; i < rects.size() - 1; i++)
1241         paintOutlineForLine(graphicsContext, paintOffset, rects.at(i - 1), rects.at(i), rects.at(i + 1), outlineColor);
1242
1243     if (useTransparencyLayer)
1244         graphicsContext.endTransparencyLayer();
1245 }
1246
1247 void RenderInline::paintOutlineForLine(GraphicsContext& graphicsContext, const LayoutPoint& paintOffset,
1248     const LayoutRect& previousLine, const LayoutRect& thisLine, const LayoutRect& nextLine, const Color& outlineColor)
1249 {
1250     const auto& styleToUse = style();
1251     float outlineOffset = styleToUse.outlineOffset();
1252     LayoutRect outlineBoxRect = thisLine;
1253     outlineBoxRect.inflate(outlineOffset);
1254     outlineBoxRect.moveBy(paintOffset);
1255     if (outlineBoxRect.isEmpty())
1256         return;
1257
1258     float outlineWidth = styleToUse.outlineWidth();
1259     EBorderStyle outlineStyle = styleToUse.outlineStyle();
1260     bool antialias = shouldAntialiasLines(graphicsContext);
1261
1262     auto adjustedPreviousLine = previousLine;
1263     adjustedPreviousLine.moveBy(paintOffset);
1264     auto adjustedNextLine = nextLine;
1265     adjustedNextLine.moveBy(paintOffset);
1266     
1267     float adjacentWidth1 = 0;
1268     float adjacentWidth2 = 0;
1269     // left edge
1270     auto topLeft = outlineBoxRect.minXMinYCorner();
1271     if (previousLine.isEmpty() || thisLine.x() < previousLine.x() || (previousLine.maxX()) <= thisLine.x()) {
1272         topLeft.move(-outlineWidth, -outlineWidth);
1273         adjacentWidth1 = outlineWidth;
1274     } else {
1275         topLeft.move(-outlineWidth, 2 * outlineOffset);
1276         adjacentWidth1 = -outlineWidth;
1277     }
1278     auto bottomRight = outlineBoxRect.minXMaxYCorner();
1279     if (nextLine.isEmpty() || thisLine.x() <= nextLine.x() || (nextLine.maxX()) <= thisLine.x()) {
1280         bottomRight.move(0, outlineWidth);
1281         adjacentWidth2 = outlineWidth;
1282     } else {
1283         bottomRight.move(0, -2 * outlineOffset);
1284         adjacentWidth2 = -outlineWidth;
1285     }
1286     drawLineForBoxSide(graphicsContext, FloatRect(topLeft, bottomRight), BSLeft, outlineColor, outlineStyle, adjacentWidth1, adjacentWidth2, antialias);
1287     
1288     // right edge
1289     topLeft = outlineBoxRect.maxXMinYCorner();
1290     if (previousLine.isEmpty() || previousLine.maxX() < thisLine.maxX() || thisLine.maxX() <= previousLine.x()) {
1291         topLeft.move(0, -outlineWidth);
1292         adjacentWidth1 = outlineWidth;
1293     } else {
1294         topLeft.move(0, 2 * outlineOffset);
1295         adjacentWidth1 = -outlineWidth;
1296     }
1297     bottomRight = outlineBoxRect.maxXMaxYCorner();
1298     if (nextLine.isEmpty() || nextLine.maxX() <= thisLine.maxX() || thisLine.maxX() <= nextLine.x()) {
1299         bottomRight.move(outlineWidth, outlineWidth);
1300         adjacentWidth2 = outlineWidth;
1301     } else {
1302         bottomRight.move(outlineWidth, -2 * outlineOffset);
1303         adjacentWidth2 = -outlineWidth;
1304     }
1305     drawLineForBoxSide(graphicsContext, FloatRect(topLeft, bottomRight), BSRight, outlineColor, outlineStyle, adjacentWidth1, adjacentWidth2, antialias);
1306
1307     // upper edge
1308     if (thisLine.x() < previousLine.x()) {
1309         topLeft = outlineBoxRect.minXMinYCorner();
1310         topLeft.move(-outlineWidth, -outlineWidth);
1311         adjacentWidth1 = outlineWidth;
1312         bottomRight = outlineBoxRect.maxXMinYCorner();
1313         bottomRight.move(outlineWidth, 0);
1314         if (!previousLine.isEmpty() && adjustedPreviousLine.x() < bottomRight.x()) {
1315             bottomRight.setX(adjustedPreviousLine.x() - outlineOffset);
1316             adjacentWidth2 = -outlineWidth;
1317         } else
1318             adjacentWidth2 = outlineWidth;
1319         drawLineForBoxSide(graphicsContext, FloatRect(topLeft, bottomRight), BSTop, outlineColor, outlineStyle, adjacentWidth1, adjacentWidth2, antialias);
1320     }
1321     
1322     if (previousLine.maxX() < thisLine.maxX()) {
1323         topLeft = outlineBoxRect.minXMinYCorner();
1324         topLeft.move(-outlineWidth, -outlineWidth);
1325         if (!previousLine.isEmpty() && adjustedPreviousLine.maxX() > topLeft.x()) {
1326             topLeft.setX(adjustedPreviousLine.maxX() + outlineOffset);
1327             adjacentWidth1 = -outlineWidth;
1328         } else
1329             adjacentWidth1 = outlineWidth;
1330         bottomRight = outlineBoxRect.maxXMinYCorner();
1331         bottomRight.move(outlineWidth, 0);
1332         adjacentWidth2 = outlineWidth;
1333         drawLineForBoxSide(graphicsContext, FloatRect(topLeft, bottomRight), BSTop, outlineColor, outlineStyle, adjacentWidth1, adjacentWidth2, antialias);
1334     }
1335
1336     if (thisLine.x() == thisLine.maxX()) {
1337         topLeft = outlineBoxRect.minXMinYCorner();
1338         topLeft.move(-outlineWidth, -outlineWidth);
1339         adjacentWidth1 = outlineWidth;
1340         bottomRight = outlineBoxRect.maxXMinYCorner();
1341         bottomRight.move(outlineWidth, 0);
1342         adjacentWidth2 = outlineWidth;
1343         drawLineForBoxSide(graphicsContext, FloatRect(topLeft, bottomRight), BSTop, outlineColor, outlineStyle, adjacentWidth1, adjacentWidth2, antialias);
1344     }
1345
1346     // lower edge
1347     if (thisLine.x() < nextLine.x()) {
1348         topLeft = outlineBoxRect.minXMaxYCorner();
1349         topLeft.move(-outlineWidth, 0);
1350         adjacentWidth1 = outlineWidth;
1351         bottomRight = outlineBoxRect.maxXMaxYCorner();
1352         bottomRight.move(outlineWidth, outlineWidth);
1353         if (!nextLine.isEmpty() && (adjustedNextLine.x() < bottomRight.x())) {
1354             bottomRight.setX(adjustedNextLine.x() - outlineOffset);
1355             adjacentWidth2 = -outlineWidth;
1356         } else
1357             adjacentWidth2 = outlineWidth;
1358         drawLineForBoxSide(graphicsContext, FloatRect(topLeft, bottomRight), BSBottom, outlineColor, outlineStyle, adjacentWidth1, adjacentWidth2, antialias);
1359     }
1360     
1361     if (nextLine.maxX() < thisLine.maxX()) {
1362         topLeft = outlineBoxRect.minXMaxYCorner();
1363         topLeft.move(-outlineWidth, 0);
1364         if (!nextLine.isEmpty() && adjustedNextLine.maxX() > topLeft.x()) {
1365             topLeft.setX(adjustedNextLine.maxX() + outlineOffset);
1366             adjacentWidth1 = -outlineWidth;
1367         } else
1368             adjacentWidth1 = outlineWidth;
1369         bottomRight = outlineBoxRect.maxXMaxYCorner();
1370         bottomRight.move(outlineWidth, outlineWidth);
1371         adjacentWidth2 = outlineWidth;
1372         drawLineForBoxSide(graphicsContext, FloatRect(topLeft, bottomRight), BSBottom, outlineColor, outlineStyle, adjacentWidth1, adjacentWidth2, antialias);
1373     }
1374
1375     if (thisLine.x() == thisLine.maxX()) {
1376         topLeft = outlineBoxRect.minXMaxYCorner();
1377         topLeft.move(-outlineWidth, 0);
1378         adjacentWidth1 = outlineWidth;
1379         bottomRight = outlineBoxRect.maxXMaxYCorner();
1380         bottomRight.move(outlineWidth, outlineWidth);
1381         adjacentWidth2 = outlineWidth;
1382         drawLineForBoxSide(graphicsContext, FloatRect(topLeft, bottomRight), BSBottom, outlineColor, outlineStyle, adjacentWidth1, adjacentWidth2, antialias);
1383     }
1384 }
1385
1386 #if ENABLE(DASHBOARD_SUPPORT)
1387 void RenderInline::addAnnotatedRegions(Vector<AnnotatedRegionValue>& regions)
1388 {
1389     // Convert the style regions to absolute coordinates.
1390     if (style().visibility() != VISIBLE)
1391         return;
1392
1393     const Vector<StyleDashboardRegion>& styleRegions = style().dashboardRegions();
1394     unsigned i, count = styleRegions.size();
1395     for (i = 0; i < count; i++) {
1396         StyleDashboardRegion styleRegion = styleRegions[i];
1397
1398         LayoutRect linesBoundingBox = this->linesBoundingBox();
1399         LayoutUnit w = linesBoundingBox.width();
1400         LayoutUnit h = linesBoundingBox.height();
1401
1402         AnnotatedRegionValue region;
1403         region.label = styleRegion.label;
1404         region.bounds = LayoutRect(linesBoundingBox.x() + styleRegion.offset.left().value(),
1405                                 linesBoundingBox.y() + styleRegion.offset.top().value(),
1406                                 w - styleRegion.offset.left().value() - styleRegion.offset.right().value(),
1407                                 h - styleRegion.offset.top().value() - styleRegion.offset.bottom().value());
1408         region.type = styleRegion.type;
1409
1410         RenderObject* container = containingBlock();
1411         if (!container)
1412             container = this;
1413
1414         region.clip = container->computeAbsoluteRepaintRect(region.bounds);
1415         if (region.clip.height() < 0) {
1416             region.clip.setHeight(0);
1417             region.clip.setWidth(0);
1418         }
1419
1420         FloatPoint absPos = container->localToAbsolute();
1421         region.bounds.setX(absPos.x() + region.bounds.x());
1422         region.bounds.setY(absPos.y() + region.bounds.y());
1423
1424         regions.append(region);
1425     }
1426 }
1427 #endif
1428
1429 } // namespace WebCore