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