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 "core/rendering/RenderInline.h"
25
26#include "core/dom/Fullscreen.h"
27#include "core/dom/StyleEngine.h"
28#include "core/page/Chrome.h"
29#include "core/page/Page.h"
30#include "core/paint/BoxPainter.h"
31#include "core/paint/InlinePainter.h"
32#include "core/paint/ObjectPainter.h"
33#include "core/rendering/GraphicsContextAnnotator.h"
34#include "core/rendering/HitTestResult.h"
35#include "core/rendering/InlineTextBox.h"
36#include "core/rendering/RenderBlock.h"
37#include "core/rendering/RenderFlowThread.h"
38#include "core/rendering/RenderFullScreen.h"
39#include "core/rendering/RenderGeometryMap.h"
40#include "core/rendering/RenderLayer.h"
41#include "core/rendering/RenderTheme.h"
42#include "core/rendering/RenderView.h"
43#include "core/rendering/style/StyleInheritedData.h"
44#include "platform/geometry/FloatQuad.h"
45#include "platform/geometry/TransformState.h"
46#include "platform/graphics/GraphicsContext.h"
47
48namespace blink {
49
50struct SameSizeAsRenderInline : public RenderBoxModelObject {
51    virtual ~SameSizeAsRenderInline() { }
52    RenderObjectChildList m_children;
53    RenderLineBoxList m_lineBoxes;
54};
55
56COMPILE_ASSERT(sizeof(RenderInline) == sizeof(SameSizeAsRenderInline), RenderInline_should_stay_small);
57
58RenderInline::RenderInline(Element* element)
59    : RenderBoxModelObject(element)
60{
61    setChildrenInline(true);
62}
63
64void RenderInline::trace(Visitor* visitor)
65{
66    visitor->trace(m_children);
67    RenderBoxModelObject::trace(visitor);
68}
69
70RenderInline* RenderInline::createAnonymous(Document* document)
71{
72    RenderInline* renderer = new RenderInline(0);
73    renderer->setDocumentForAnonymous(document);
74    return renderer;
75}
76
77void RenderInline::willBeDestroyed()
78{
79#if ENABLE(ASSERT)
80    // Make sure we do not retain "this" in the continuation outline table map of our containing blocks.
81    if (parent() && style()->visibility() == VISIBLE && style()->hasOutline()) {
82        bool containingBlockPaintsContinuationOutline = continuation() || isInlineElementContinuation();
83        if (containingBlockPaintsContinuationOutline) {
84            if (RenderBlock* cb = containingBlock()) {
85                if (RenderBlock* cbCb = cb->containingBlock())
86                    ASSERT(!cbCb->paintsContinuationOutline(this));
87            }
88        }
89    }
90#endif
91
92    // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
93    // properly dirty line boxes that they are removed from.  Effects that do :before/:after only on hover could crash otherwise.
94    children()->destroyLeftoverChildren();
95
96    // Destroy our continuation before anything other than anonymous children.
97    // The reason we don't destroy it before anonymous children is that they may
98    // have continuations of their own that are anonymous children of our continuation.
99    RenderBoxModelObject* continuation = this->continuation();
100    if (continuation) {
101        continuation->destroy();
102        setContinuation(0);
103    }
104
105    if (!documentBeingDestroyed()) {
106        if (firstLineBox()) {
107            // We can't wait for RenderBoxModelObject::destroy to clear the selection,
108            // because by then we will have nuked the line boxes.
109            // FIXME: The FrameSelection should be responsible for this when it
110            // is notified of DOM mutations.
111            if (isSelectionBorder())
112                view()->clearSelection();
113
114            // If line boxes are contained inside a root, that means we're an inline.
115            // In that case, we need to remove all the line boxes so that the parent
116            // lines aren't pointing to deleted children. If the first line box does
117            // not have a parent that means they are either already disconnected or
118            // root lines that can just be destroyed without disconnecting.
119            if (firstLineBox()->parent()) {
120                for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox())
121                    box->remove();
122            }
123        } else if (parent())
124            parent()->dirtyLinesFromChangedChild(this);
125    }
126
127    m_lineBoxes.deleteLineBoxes();
128
129    RenderBoxModelObject::willBeDestroyed();
130}
131
132RenderInline* RenderInline::inlineElementContinuation() const
133{
134    RenderBoxModelObject* continuation = this->continuation();
135    if (!continuation || continuation->isInline())
136        return toRenderInline(continuation);
137    return toRenderBlock(continuation)->inlineElementContinuation();
138}
139
140void RenderInline::updateFromStyle()
141{
142    RenderBoxModelObject::updateFromStyle();
143
144    // FIXME: Is this still needed. Was needed for run-ins, since run-in is considered a block display type.
145    setInline(true);
146
147    // FIXME: Support transforms and reflections on inline flows someday.
148    setHasTransform(false);
149    setHasReflection(false);
150}
151
152static RenderObject* inFlowPositionedInlineAncestor(RenderObject* p)
153{
154    while (p && p->isRenderInline()) {
155        if (p->isRelPositioned())
156            return p;
157        p = p->parent();
158    }
159    return 0;
160}
161
162static void updateStyleOfAnonymousBlockContinuations(RenderObject* block, const RenderStyle* newStyle, const RenderStyle* oldStyle)
163{
164    for (;block && block->isAnonymousBlock(); block = block->nextSibling()) {
165        if (!toRenderBlock(block)->isAnonymousBlockContinuation())
166            continue;
167
168        RefPtr<RenderStyle> newBlockStyle;
169
170        if (!block->style()->isOutlineEquivalent(newStyle)) {
171            newBlockStyle = RenderStyle::clone(block->style());
172            newBlockStyle->setOutlineFromStyle(*newStyle);
173        }
174
175        if (block->style()->position() != newStyle->position()) {
176            // If we are no longer in-flow positioned but our descendant block(s) still have an in-flow positioned ancestor then
177            // their containing anonymous block should keep its in-flow positioning.
178            if (oldStyle->hasInFlowPosition()
179                && inFlowPositionedInlineAncestor(toRenderBlock(block)->inlineElementContinuation()))
180                continue;
181            if (!newBlockStyle)
182                newBlockStyle = RenderStyle::clone(block->style());
183            newBlockStyle->setPosition(newStyle->position());
184        }
185
186        if (newBlockStyle)
187            block->setStyle(newBlockStyle);
188    }
189}
190
191void RenderInline::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
192{
193    RenderBoxModelObject::styleDidChange(diff, oldStyle);
194
195    // Ensure that all of the split inlines pick up the new style. We
196    // only do this if we're an inline, since we don't want to propagate
197    // a block's style to the other inlines.
198    // e.g., <font>foo <h4>goo</h4> moo</font>.  The <font> inlines before
199    // and after the block share the same style, but the block doesn't
200    // need to pass its style on to anyone else.
201    RenderStyle* newStyle = style();
202    RenderInline* continuation = inlineElementContinuation();
203    for (RenderInline* currCont = continuation; currCont; currCont = currCont->inlineElementContinuation()) {
204        RenderBoxModelObject* nextCont = currCont->continuation();
205        currCont->setContinuation(0);
206        currCont->setStyle(newStyle);
207        currCont->setContinuation(nextCont);
208    }
209
210    // If an inline's outline or in-flow positioning has changed then any descendant blocks will need to change their styles accordingly.
211    // Do this by updating the styles of the descendant blocks' containing anonymous blocks - there may be more than one.
212    if (continuation && oldStyle
213        && (!newStyle->isOutlineEquivalent(oldStyle)
214            || (newStyle->position() != oldStyle->position() && (newStyle->hasInFlowPosition() || oldStyle->hasInFlowPosition())))) {
215        // If any descendant blocks exist then they will be in the next anonymous block and its siblings.
216        RenderObject* block = containingBlock()->nextSibling();
217        if (block && block->isAnonymousBlock())
218            updateStyleOfAnonymousBlockContinuations(block, newStyle, oldStyle);
219    }
220
221    if (!alwaysCreateLineBoxes()) {
222        bool alwaysCreateLineBoxesNew = hasSelfPaintingLayer() || hasBoxDecorationBackground() || newStyle->hasPadding() || newStyle->hasMargin() || newStyle->hasOutline();
223        if (oldStyle && alwaysCreateLineBoxesNew) {
224            dirtyLineBoxes(false);
225            setNeedsLayoutAndFullPaintInvalidation();
226        }
227        setAlwaysCreateLineBoxes(alwaysCreateLineBoxesNew);
228    }
229}
230
231void RenderInline::updateAlwaysCreateLineBoxes(bool fullLayout)
232{
233    // Once we have been tainted once, just assume it will happen again. This way effects like hover highlighting that change the
234    // background color will only cause a layout on the first rollover.
235    if (alwaysCreateLineBoxes())
236        return;
237
238    RenderStyle* parentStyle = parent()->style();
239    RenderInline* parentRenderInline = parent()->isRenderInline() ? toRenderInline(parent()) : 0;
240    bool checkFonts = document().inNoQuirksMode();
241    bool alwaysCreateLineBoxesNew = (parentRenderInline && parentRenderInline->alwaysCreateLineBoxes())
242        || (parentRenderInline && parentStyle->verticalAlign() != BASELINE)
243        || style()->verticalAlign() != BASELINE
244        || style()->textEmphasisMark() != TextEmphasisMarkNone
245        || (checkFonts && (!parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(style()->font().fontMetrics())
246        || parentStyle->lineHeight() != style()->lineHeight()));
247
248    if (!alwaysCreateLineBoxesNew && checkFonts && document().styleEngine()->usesFirstLineRules()) {
249        // Have to check the first line style as well.
250        parentStyle = parent()->style(true);
251        RenderStyle* childStyle = style(true);
252        alwaysCreateLineBoxesNew = !parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle->font().fontMetrics())
253        || childStyle->verticalAlign() != BASELINE
254        || parentStyle->lineHeight() != childStyle->lineHeight();
255    }
256
257    if (alwaysCreateLineBoxesNew) {
258        if (!fullLayout)
259            dirtyLineBoxes(false);
260        setAlwaysCreateLineBoxes();
261    }
262}
263
264LayoutRect RenderInline::localCaretRect(InlineBox* inlineBox, int, LayoutUnit* extraWidthToEndOfLine)
265{
266    if (firstChild()) {
267        // This condition is possible if the RenderInline is at an editing boundary,
268        // i.e. the VisiblePosition is:
269        //   <RenderInline editingBoundary=true>|<RenderText> </RenderText></RenderInline>
270        // FIXME: need to figure out how to make this return a valid rect, note that
271        // there are no line boxes created in the above case.
272        return LayoutRect();
273    }
274
275    ASSERT_UNUSED(inlineBox, !inlineBox);
276
277    if (extraWidthToEndOfLine)
278        *extraWidthToEndOfLine = 0;
279
280    LayoutRect caretRect = localCaretRectForEmptyElement(borderAndPaddingWidth(), 0);
281
282    if (InlineBox* firstBox = firstLineBox())
283        caretRect.moveBy(roundedLayoutPoint(firstBox->topLeft()));
284
285    return caretRect;
286}
287
288void RenderInline::addChild(RenderObject* newChild, RenderObject* beforeChild)
289{
290    if (continuation())
291        return addChildToContinuation(newChild, beforeChild);
292    return addChildIgnoringContinuation(newChild, beforeChild);
293}
294
295static RenderBoxModelObject* nextContinuation(RenderObject* renderer)
296{
297    if (renderer->isInline() && !renderer->isReplaced())
298        return toRenderInline(renderer)->continuation();
299    return toRenderBlock(renderer)->inlineElementContinuation();
300}
301
302RenderBoxModelObject* RenderInline::continuationBefore(RenderObject* beforeChild)
303{
304    if (beforeChild && beforeChild->parent() == this)
305        return this;
306
307    RenderBoxModelObject* curr = nextContinuation(this);
308    RenderBoxModelObject* nextToLast = this;
309    RenderBoxModelObject* last = this;
310    while (curr) {
311        if (beforeChild && beforeChild->parent() == curr) {
312            if (curr->slowFirstChild() == beforeChild)
313                return last;
314            return curr;
315        }
316
317        nextToLast = last;
318        last = curr;
319        curr = nextContinuation(curr);
320    }
321
322    if (!beforeChild && !last->slowFirstChild())
323        return nextToLast;
324    return last;
325}
326
327void RenderInline::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild)
328{
329    // Make sure we don't append things after :after-generated content if we have it.
330    if (!beforeChild && isAfterContent(lastChild()))
331        beforeChild = lastChild();
332
333    if (!newChild->isInline() && !newChild->isFloatingOrOutOfFlowPositioned()) {
334        // We are placing a block inside an inline. We have to perform a split of this
335        // inline into continuations.  This involves creating an anonymous block box to hold
336        // |newChild|.  We then make that block box a continuation of this inline.  We take all of
337        // the children after |beforeChild| and put them in a clone of this object.
338        RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK);
339
340        // If inside an inline affected by in-flow positioning the block needs to be affected by it too.
341        // Giving the block a layer like this allows it to collect the x/y offsets from inline parents later.
342        if (RenderObject* positionedAncestor = inFlowPositionedInlineAncestor(this))
343            newStyle->setPosition(positionedAncestor->style()->position());
344
345        // Push outline style to the block continuation.
346        if (!newStyle->isOutlineEquivalent(style()))
347            newStyle->setOutlineFromStyle(*style());
348
349        RenderBlockFlow* newBox = RenderBlockFlow::createAnonymous(&document());
350        newBox->setStyle(newStyle.release());
351        RenderBoxModelObject* oldContinuation = continuation();
352        setContinuation(newBox);
353
354        splitFlow(beforeChild, newBox, newChild, oldContinuation);
355        return;
356    }
357
358    RenderBoxModelObject::addChild(newChild, beforeChild);
359
360    newChild->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
361}
362
363RenderInline* RenderInline::clone() const
364{
365    RenderInline* cloneInline = new RenderInline(node());
366    cloneInline->setStyle(style());
367    cloneInline->setFlowThreadState(flowThreadState());
368    return cloneInline;
369}
370
371void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock,
372                                RenderBlock* middleBlock,
373                                RenderObject* beforeChild, RenderBoxModelObject* oldCont)
374{
375    // Create a clone of this inline.
376    RenderInline* cloneInline = clone();
377    cloneInline->setContinuation(oldCont);
378
379    // If we're splitting the inline containing the fullscreened element,
380    // |beforeChild| may be the renderer for the fullscreened element. However,
381    // that renderer is wrapped in a RenderFullScreen, so |this| is not its
382    // parent. Since the splitting logic expects |this| to be the parent, set
383    // |beforeChild| to be the RenderFullScreen.
384    if (Fullscreen* fullscreen = Fullscreen::fromIfExists(document())) {
385        const Element* fullScreenElement = fullscreen->webkitCurrentFullScreenElement();
386        if (fullScreenElement && beforeChild && beforeChild->node() == fullScreenElement)
387            beforeChild = fullscreen->fullScreenRenderer();
388    }
389
390    // Now take all of the children from beforeChild to the end and remove
391    // them from |this| and place them in the clone.
392    RenderObject* o = beforeChild;
393    while (o) {
394        RenderObject* tmp = o;
395        o = tmp->nextSibling();
396        cloneInline->addChildIgnoringContinuation(children()->removeChildNode(this, tmp), 0);
397        tmp->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
398    }
399
400    // Hook |clone| up as the continuation of the middle block.
401    middleBlock->setContinuation(cloneInline);
402
403    // We have been reparented and are now under the fromBlock.  We need
404    // to walk up our inline parent chain until we hit the containing block.
405    // Once we hit the containing block we're done.
406    RenderBoxModelObject* curr = toRenderBoxModelObject(parent());
407    RenderBoxModelObject* currChild = this;
408
409    // FIXME: Because splitting is O(n^2) as tags nest pathologically, we cap the depth at which we're willing to clone.
410    // There will eventually be a better approach to this problem that will let us nest to a much
411    // greater depth (see bugzilla bug 13430) but for now we have a limit.  This *will* result in
412    // incorrect rendering, but the alternative is to hang forever.
413    unsigned splitDepth = 1;
414    const unsigned cMaxSplitDepth = 200;
415    while (curr && curr != fromBlock) {
416        ASSERT(curr->isRenderInline());
417        if (splitDepth < cMaxSplitDepth) {
418            // Create a new clone.
419            RenderInline* cloneChild = cloneInline;
420            cloneInline = toRenderInline(curr)->clone();
421
422            // Insert our child clone as the first child.
423            cloneInline->addChildIgnoringContinuation(cloneChild, 0);
424
425            // Hook the clone up as a continuation of |curr|.
426            RenderInline* inlineCurr = toRenderInline(curr);
427            oldCont = inlineCurr->continuation();
428            inlineCurr->setContinuation(cloneInline);
429            cloneInline->setContinuation(oldCont);
430
431            // Now we need to take all of the children starting from the first child
432            // *after* currChild and append them all to the clone.
433            o = currChild->nextSibling();
434            while (o) {
435                RenderObject* tmp = o;
436                o = tmp->nextSibling();
437                cloneInline->addChildIgnoringContinuation(inlineCurr->children()->removeChildNode(curr, tmp), 0);
438                tmp->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
439            }
440        }
441
442        // Keep walking up the chain.
443        currChild = curr;
444        curr = toRenderBoxModelObject(curr->parent());
445        splitDepth++;
446    }
447
448    // Now we are at the block level. We need to put the clone into the toBlock.
449    toBlock->children()->appendChildNode(toBlock, cloneInline);
450
451    // Now take all the children after currChild and remove them from the fromBlock
452    // and put them in the toBlock.
453    o = currChild->nextSibling();
454    while (o) {
455        RenderObject* tmp = o;
456        o = tmp->nextSibling();
457        toBlock->children()->appendChildNode(toBlock, fromBlock->children()->removeChildNode(fromBlock, tmp));
458    }
459}
460
461void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
462                             RenderObject* newChild, RenderBoxModelObject* oldCont)
463{
464    RenderBlock* pre = 0;
465    RenderBlock* block = containingBlock();
466
467    // Delete our line boxes before we do the inline split into continuations.
468    block->deleteLineBoxTree();
469
470    bool madeNewBeforeBlock = false;
471    if (block->isAnonymousBlock() && (!block->parent() || !block->parent()->createsAnonymousWrapper())) {
472        // We can reuse this block and make it the preBlock of the next continuation.
473        pre = block;
474        pre->removePositionedObjects(0);
475        if (pre->isRenderBlockFlow())
476            toRenderBlockFlow(pre)->removeFloatingObjects();
477        block = block->containingBlock();
478    } else {
479        // No anonymous block available for use.  Make one.
480        pre = block->createAnonymousBlock();
481        madeNewBeforeBlock = true;
482    }
483
484    RenderBlock* post = toRenderBlock(pre->createAnonymousBoxWithSameTypeAs(block));
485
486    RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling();
487    if (madeNewBeforeBlock)
488        block->children()->insertChildNode(block, pre, boxFirst);
489    block->children()->insertChildNode(block, newBlockBox, boxFirst);
490    block->children()->insertChildNode(block, post, boxFirst);
491    block->setChildrenInline(false);
492
493    if (madeNewBeforeBlock) {
494        RenderObject* o = boxFirst;
495        while (o) {
496            RenderObject* no = o;
497            o = no->nextSibling();
498            pre->children()->appendChildNode(pre, block->children()->removeChildNode(block, no));
499            no->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
500        }
501    }
502
503    splitInlines(pre, post, newBlockBox, beforeChild, oldCont);
504
505    // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
506    // time in makeChildrenNonInline by just setting this explicitly up front.
507    newBlockBox->setChildrenInline(false);
508
509    newBlockBox->addChild(newChild);
510
511    // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
512    // get deleted properly.  Because objects moves from the pre block into the post block, we want to
513    // make new line boxes instead of leaving the old line boxes around.
514    pre->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
515    block->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
516    post->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
517}
518
519void RenderInline::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild)
520{
521    RenderBoxModelObject* flow = continuationBefore(beforeChild);
522    ASSERT(!beforeChild || beforeChild->parent()->isRenderBlock() || beforeChild->parent()->isRenderInline());
523    RenderBoxModelObject* beforeChildParent = 0;
524    if (beforeChild)
525        beforeChildParent = toRenderBoxModelObject(beforeChild->parent());
526    else {
527        RenderBoxModelObject* cont = nextContinuation(flow);
528        if (cont)
529            beforeChildParent = cont;
530        else
531            beforeChildParent = flow;
532    }
533
534    if (newChild->isFloatingOrOutOfFlowPositioned())
535        return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
536
537    // A continuation always consists of two potential candidates: an inline or an anonymous
538    // block box holding block children.
539    bool childInline = newChild->isInline();
540    bool bcpInline = beforeChildParent->isInline();
541    bool flowInline = flow->isInline();
542
543    if (flow == beforeChildParent)
544        return flow->addChildIgnoringContinuation(newChild, beforeChild);
545    else {
546        // The goal here is to match up if we can, so that we can coalesce and create the
547        // minimal # of continuations needed for the inline.
548        if (childInline == bcpInline || (beforeChild && beforeChild->isInline()))
549            return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
550        if (flowInline == childInline)
551            return flow->addChildIgnoringContinuation(newChild, 0); // Just treat like an append.
552        return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
553    }
554}
555
556void RenderInline::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
557{
558    InlinePainter(*this).paint(paintInfo, paintOffset);
559}
560
561template<typename GeneratorContext>
562void RenderInline::generateLineBoxRects(GeneratorContext& yield) const
563{
564    if (!alwaysCreateLineBoxes())
565        generateCulledLineBoxRects(yield, this);
566    else if (InlineFlowBox* curr = firstLineBox()) {
567        for (; curr; curr = curr->nextLineBox())
568            yield(FloatRect(curr->topLeft(), curr->size()));
569    } else
570        yield(FloatRect());
571}
572
573template<typename GeneratorContext>
574void RenderInline::generateCulledLineBoxRects(GeneratorContext& yield, const RenderInline* container) const
575{
576    if (!culledInlineFirstLineBox()) {
577        yield(FloatRect());
578        return;
579    }
580
581    bool isHorizontal = style()->isHorizontalWritingMode();
582
583    for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
584        if (curr->isFloatingOrOutOfFlowPositioned())
585            continue;
586
587        // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
588        // direction (aligned to the root box's baseline).
589        if (curr->isBox()) {
590            RenderBox* currBox = toRenderBox(curr);
591            if (currBox->inlineBoxWrapper()) {
592                RootInlineBox& rootBox = currBox->inlineBoxWrapper()->root();
593                int logicalTop = rootBox.logicalTop() + (rootBox.renderer().style(rootBox.isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox.isFirstLineStyle())->font().fontMetrics().ascent());
594                int logicalHeight = container->style(rootBox.isFirstLineStyle())->font().fontMetrics().height();
595                if (isHorizontal)
596                    yield(FloatRect(currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), logicalTop, (currBox->width() + currBox->marginWidth()).toFloat(), logicalHeight));
597                else
598                    yield(FloatRect(logicalTop, currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, (currBox->height() + currBox->marginHeight()).toFloat()));
599            }
600        } else if (curr->isRenderInline()) {
601            // If the child doesn't need line boxes either, then we can recur.
602            RenderInline* currInline = toRenderInline(curr);
603            if (!currInline->alwaysCreateLineBoxes())
604                currInline->generateCulledLineBoxRects(yield, container);
605            else {
606                for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) {
607                    RootInlineBox& rootBox = childLine->root();
608                    int logicalTop = rootBox.logicalTop() + (rootBox.renderer().style(rootBox.isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox.isFirstLineStyle())->font().fontMetrics().ascent());
609                    int logicalHeight = container->style(rootBox.isFirstLineStyle())->font().fontMetrics().height();
610                    if (isHorizontal)
611                        yield(FloatRect(childLine->x() - childLine->marginLogicalLeft(),
612                            logicalTop,
613                            childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(),
614                            logicalHeight));
615                    else
616                        yield(FloatRect(logicalTop,
617                            childLine->y() - childLine->marginLogicalLeft(),
618                            logicalHeight,
619                            childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight()));
620                }
621            }
622        } else if (curr->isText()) {
623            RenderText* currText = toRenderText(curr);
624            for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) {
625                RootInlineBox& rootBox = childText->root();
626                int logicalTop = rootBox.logicalTop() + (rootBox.renderer().style(rootBox.isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox.isFirstLineStyle())->font().fontMetrics().ascent());
627                int logicalHeight = container->style(rootBox.isFirstLineStyle())->font().fontMetrics().height();
628                if (isHorizontal)
629                    yield(FloatRect(childText->x(), logicalTop, childText->logicalWidth(), logicalHeight));
630                else
631                    yield(FloatRect(logicalTop, childText->y(), logicalHeight, childText->logicalWidth()));
632            }
633        }
634    }
635}
636
637namespace {
638
639class AbsoluteRectsGeneratorContext {
640public:
641    AbsoluteRectsGeneratorContext(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset)
642        : m_rects(rects)
643        , m_accumulatedOffset(accumulatedOffset) { }
644
645    void operator()(const FloatRect& rect)
646    {
647        IntRect intRect = enclosingIntRect(rect);
648        intRect.move(m_accumulatedOffset.x(), m_accumulatedOffset.y());
649        m_rects.append(intRect);
650    }
651private:
652    Vector<IntRect>& m_rects;
653    const LayoutPoint& m_accumulatedOffset;
654};
655
656} // unnamed namespace
657
658void RenderInline::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
659{
660    AbsoluteRectsGeneratorContext context(rects, accumulatedOffset);
661    generateLineBoxRects(context);
662
663    if (continuation()) {
664        if (continuation()->isBox()) {
665            RenderBox* box = toRenderBox(continuation());
666            continuation()->absoluteRects(rects, toLayoutPoint(accumulatedOffset - containingBlock()->location() + box->locationOffset()));
667        } else
668            continuation()->absoluteRects(rects, toLayoutPoint(accumulatedOffset - containingBlock()->location()));
669    }
670}
671
672
673namespace {
674
675class AbsoluteQuadsGeneratorContext {
676public:
677    AbsoluteQuadsGeneratorContext(const RenderInline* renderer, Vector<FloatQuad>& quads)
678        : m_quads(quads)
679        , m_geometryMap()
680    {
681        m_geometryMap.pushMappingsToAncestor(renderer, 0);
682    }
683
684    void operator()(const FloatRect& rect)
685    {
686        m_quads.append(m_geometryMap.absoluteRect(rect));
687    }
688private:
689    Vector<FloatQuad>& m_quads;
690    RenderGeometryMap m_geometryMap;
691};
692
693} // unnamed namespace
694
695void RenderInline::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
696{
697    AbsoluteQuadsGeneratorContext context(this, quads);
698    generateLineBoxRects(context);
699
700    if (continuation())
701        continuation()->absoluteQuads(quads, wasFixed);
702}
703
704LayoutUnit RenderInline::offsetLeft() const
705{
706    LayoutPoint topLeft;
707    if (InlineBox* firstBox = firstLineBoxIncludingCulling())
708        topLeft = flooredLayoutPoint(firstBox->topLeft());
709    return adjustedPositionRelativeToOffsetParent(topLeft).x();
710}
711
712LayoutUnit RenderInline::offsetTop() const
713{
714    LayoutPoint topLeft;
715    if (InlineBox* firstBox = firstLineBoxIncludingCulling())
716        topLeft = flooredLayoutPoint(firstBox->topLeft());
717    return adjustedPositionRelativeToOffsetParent(topLeft).y();
718}
719
720static LayoutUnit computeMargin(const RenderInline* renderer, const Length& margin)
721{
722    if (margin.isAuto())
723        return 0;
724    if (margin.isFixed())
725        return margin.value();
726    if (margin.isPercent())
727        return minimumValueForLength(margin, std::max<LayoutUnit>(0, renderer->containingBlock()->availableLogicalWidth()));
728    return 0;
729}
730
731LayoutUnit RenderInline::marginLeft() const
732{
733    return computeMargin(this, style()->marginLeft());
734}
735
736LayoutUnit RenderInline::marginRight() const
737{
738    return computeMargin(this, style()->marginRight());
739}
740
741LayoutUnit RenderInline::marginTop() const
742{
743    return computeMargin(this, style()->marginTop());
744}
745
746LayoutUnit RenderInline::marginBottom() const
747{
748    return computeMargin(this, style()->marginBottom());
749}
750
751LayoutUnit RenderInline::marginStart(const RenderStyle* otherStyle) const
752{
753    return computeMargin(this, style()->marginStartUsing(otherStyle ? otherStyle : style()));
754}
755
756LayoutUnit RenderInline::marginEnd(const RenderStyle* otherStyle) const
757{
758    return computeMargin(this, style()->marginEndUsing(otherStyle ? otherStyle : style()));
759}
760
761LayoutUnit RenderInline::marginBefore(const RenderStyle* otherStyle) const
762{
763    return computeMargin(this, style()->marginBeforeUsing(otherStyle ? otherStyle : style()));
764}
765
766LayoutUnit RenderInline::marginAfter(const RenderStyle* otherStyle) const
767{
768    return computeMargin(this, style()->marginAfterUsing(otherStyle ? otherStyle : style()));
769}
770
771const char* RenderInline::renderName() const
772{
773    if (isRelPositioned())
774        return "RenderInline (relative positioned)";
775    // FIXME: Cleanup isPseudoElement duplication with other renderName methods.
776    // crbug.com/415653
777    if (isPseudoElement()) {
778        if (style()->styleType() == BEFORE)
779            return "RenderInline (pseudo:before)";
780        if (style()->styleType() == AFTER)
781            return "RenderInline (pseudo:after)";
782        if (style()->styleType() == BACKDROP)
783            return "RenderInline (pseudo:backdrop)";
784        ASSERT_NOT_REACHED();
785    }
786    if (isAnonymous())
787        return "RenderInline (generated)";
788    return "RenderInline";
789}
790
791bool RenderInline::nodeAtPoint(const HitTestRequest& request, HitTestResult& result,
792                                const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
793{
794    return m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction);
795}
796
797namespace {
798
799class HitTestCulledInlinesGeneratorContext {
800public:
801    HitTestCulledInlinesGeneratorContext(Region& region, const HitTestLocation& location) : m_intersected(false), m_region(region), m_location(location) { }
802    void operator()(const FloatRect& rect)
803    {
804        m_intersected = m_intersected || m_location.intersects(rect);
805        m_region.unite(enclosingIntRect(rect));
806    }
807    bool intersected() const { return m_intersected; }
808private:
809    bool m_intersected;
810    Region& m_region;
811    const HitTestLocation& m_location;
812};
813
814} // unnamed namespace
815
816bool RenderInline::hitTestCulledInline(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset)
817{
818    ASSERT(result.isRectBasedTest() && !alwaysCreateLineBoxes());
819    if (!visibleToHitTestRequest(request))
820        return false;
821
822    HitTestLocation tmpLocation(locationInContainer, -toLayoutSize(accumulatedOffset));
823
824    Region regionResult;
825    HitTestCulledInlinesGeneratorContext context(regionResult, tmpLocation);
826    generateCulledLineBoxRects(context, this);
827
828    if (context.intersected()) {
829        updateHitTestResult(result, tmpLocation.point());
830        // We can not use addNodeToRectBasedTestResult to determine if we fully enclose the hit-test area
831        // because it can only handle rectangular targets.
832        result.addNodeToRectBasedTestResult(node(), request, locationInContainer);
833        return regionResult.contains(tmpLocation.boundingBox());
834    }
835    return false;
836}
837
838PositionWithAffinity RenderInline::positionForPoint(const LayoutPoint& point)
839{
840    // FIXME: Does not deal with relative positioned inlines (should it?)
841    RenderBlock* cb = containingBlock();
842    if (firstLineBox()) {
843        // This inline actually has a line box.  We must have clicked in the border/padding of one of these boxes.  We
844        // should try to find a result by asking our containing block.
845        return cb->positionForPoint(point);
846    }
847
848    // Translate the coords from the pre-anonymous block to the post-anonymous block.
849    LayoutPoint parentBlockPoint = cb->location() + point;
850    RenderBoxModelObject* c = continuation();
851    while (c) {
852        RenderBox* contBlock = c->isInline() ? c->containingBlock() : toRenderBlock(c);
853        if (c->isInline() || c->slowFirstChild())
854            return c->positionForPoint(parentBlockPoint - contBlock->locationOffset());
855        c = toRenderBlock(c)->inlineElementContinuation();
856    }
857
858    return RenderBoxModelObject::positionForPoint(point);
859}
860
861namespace {
862
863class LinesBoundingBoxGeneratorContext {
864public:
865    LinesBoundingBoxGeneratorContext(FloatRect& rect) : m_rect(rect) { }
866    void operator()(const FloatRect& rect)
867    {
868        m_rect.uniteIfNonZero(rect);
869    }
870private:
871    FloatRect& m_rect;
872};
873
874} // unnamed namespace
875
876IntRect RenderInline::linesBoundingBox() const
877{
878    if (!alwaysCreateLineBoxes()) {
879        ASSERT(!firstLineBox());
880        FloatRect floatResult;
881        LinesBoundingBoxGeneratorContext context(floatResult);
882        generateCulledLineBoxRects(context, this);
883        return enclosingIntRect(floatResult);
884    }
885
886    IntRect result;
887
888    // 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
889    // 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
890    // builds and help us someday figure out why.  We also put in a redundant check of lastLineBox() to avoid the crash for now.
891    ASSERT(!firstLineBox() == !lastLineBox());  // Either both are null or both exist.
892    if (firstLineBox() && lastLineBox()) {
893        // Return the width of the minimal left side and the maximal right side.
894        float logicalLeftSide = 0;
895        float logicalRightSide = 0;
896        for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
897            if (curr == firstLineBox() || curr->logicalLeft() < logicalLeftSide)
898                logicalLeftSide = curr->logicalLeft();
899            if (curr == firstLineBox() || curr->logicalRight() > logicalRightSide)
900                logicalRightSide = curr->logicalRight();
901        }
902
903        bool isHorizontal = style()->isHorizontalWritingMode();
904
905        float x = isHorizontal ? logicalLeftSide : firstLineBox()->x();
906        float y = isHorizontal ? firstLineBox()->y() : logicalLeftSide;
907        float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastLineBox()->logicalBottom() - x;
908        float height = isHorizontal ? lastLineBox()->logicalBottom() - y : logicalRightSide - logicalLeftSide;
909        result = enclosingIntRect(FloatRect(x, y, width, height));
910    }
911
912    return result;
913}
914
915InlineBox* RenderInline::culledInlineFirstLineBox() const
916{
917    for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
918        if (curr->isFloatingOrOutOfFlowPositioned())
919            continue;
920
921        // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
922        // direction (aligned to the root box's baseline).
923        if (curr->isBox())
924            return toRenderBox(curr)->inlineBoxWrapper();
925        if (curr->isRenderInline()) {
926            RenderInline* currInline = toRenderInline(curr);
927            InlineBox* result = currInline->firstLineBoxIncludingCulling();
928            if (result)
929                return result;
930        } else if (curr->isText()) {
931            RenderText* currText = toRenderText(curr);
932            if (currText->firstTextBox())
933                return currText->firstTextBox();
934        }
935    }
936    return 0;
937}
938
939InlineBox* RenderInline::culledInlineLastLineBox() const
940{
941    for (RenderObject* curr = lastChild(); curr; curr = curr->previousSibling()) {
942        if (curr->isFloatingOrOutOfFlowPositioned())
943            continue;
944
945        // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
946        // direction (aligned to the root box's baseline).
947        if (curr->isBox())
948            return toRenderBox(curr)->inlineBoxWrapper();
949        if (curr->isRenderInline()) {
950            RenderInline* currInline = toRenderInline(curr);
951            InlineBox* result = currInline->lastLineBoxIncludingCulling();
952            if (result)
953                return result;
954        } else if (curr->isText()) {
955            RenderText* currText = toRenderText(curr);
956            if (currText->lastTextBox())
957                return currText->lastTextBox();
958        }
959    }
960    return 0;
961}
962
963LayoutRect RenderInline::culledInlineVisualOverflowBoundingBox() const
964{
965    FloatRect floatResult;
966    LinesBoundingBoxGeneratorContext context(floatResult);
967    generateCulledLineBoxRects(context, this);
968    LayoutRect result(enclosingLayoutRect(floatResult));
969    bool isHorizontal = style()->isHorizontalWritingMode();
970    for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
971        if (curr->isFloatingOrOutOfFlowPositioned())
972            continue;
973
974        // For overflow we just have to propagate by hand and recompute it all.
975        if (curr->isBox()) {
976            RenderBox* currBox = toRenderBox(curr);
977            if (!currBox->hasSelfPaintingLayer() && currBox->inlineBoxWrapper()) {
978                LayoutRect logicalRect = currBox->logicalVisualOverflowRectForPropagation(style());
979                if (isHorizontal) {
980                    logicalRect.moveBy(currBox->location());
981                    result.uniteIfNonZero(logicalRect);
982                } else {
983                    logicalRect.moveBy(currBox->location());
984                    result.uniteIfNonZero(logicalRect.transposedRect());
985                }
986            }
987        } else if (curr->isRenderInline()) {
988            // If the child doesn't need line boxes either, then we can recur.
989            RenderInline* currInline = toRenderInline(curr);
990            if (!currInline->alwaysCreateLineBoxes())
991                result.uniteIfNonZero(currInline->culledInlineVisualOverflowBoundingBox());
992            else if (!currInline->hasSelfPaintingLayer())
993                result.uniteIfNonZero(currInline->linesVisualOverflowBoundingBox());
994        } else if (curr->isText()) {
995            // FIXME; Overflow from text boxes is lost. We will need to cache this information in
996            // InlineTextBoxes.
997            RenderText* currText = toRenderText(curr);
998            result.uniteIfNonZero(currText->linesVisualOverflowBoundingBox());
999        }
1000    }
1001    return result;
1002}
1003
1004LayoutRect RenderInline::linesVisualOverflowBoundingBox() const
1005{
1006    if (!alwaysCreateLineBoxes())
1007        return culledInlineVisualOverflowBoundingBox();
1008
1009    if (!firstLineBox() || !lastLineBox())
1010        return LayoutRect();
1011
1012    // Return the width of the minimal left side and the maximal right side.
1013    LayoutUnit logicalLeftSide = LayoutUnit::max();
1014    LayoutUnit logicalRightSide = LayoutUnit::min();
1015    for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
1016        logicalLeftSide = std::min(logicalLeftSide, curr->logicalLeftVisualOverflow());
1017        logicalRightSide = std::max(logicalRightSide, curr->logicalRightVisualOverflow());
1018    }
1019
1020    RootInlineBox& firstRootBox = firstLineBox()->root();
1021    RootInlineBox& lastRootBox = lastLineBox()->root();
1022
1023    LayoutUnit logicalTop = firstLineBox()->logicalTopVisualOverflow(firstRootBox.lineTop());
1024    LayoutUnit logicalWidth = logicalRightSide - logicalLeftSide;
1025    LayoutUnit logicalHeight = lastLineBox()->logicalBottomVisualOverflow(lastRootBox.lineBottom()) - logicalTop;
1026
1027    LayoutRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight);
1028    if (!style()->isHorizontalWritingMode())
1029        rect = rect.transposedRect();
1030    return rect;
1031}
1032
1033LayoutRect RenderInline::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, const PaintInvalidationState* paintInvalidationState) const
1034{
1035    if ((!firstLineBoxIncludingCulling() && !continuation()) || style()->visibility() != VISIBLE)
1036        return LayoutRect();
1037
1038    LayoutRect paintInvalidationRect(linesVisualOverflowBoundingBox());
1039
1040    LayoutUnit outlineSize = style()->outlineSize();
1041    paintInvalidationRect.inflate(outlineSize);
1042
1043    mapRectToPaintInvalidationBacking(paintInvalidationContainer, paintInvalidationRect, paintInvalidationState);
1044
1045    if (outlineSize) {
1046        for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
1047            if (!curr->isText())
1048                paintInvalidationRect.unite(curr->rectWithOutlineForPaintInvalidation(paintInvalidationContainer, outlineSize));
1049        }
1050
1051        if (continuation() && !continuation()->isInline() && continuation()->parent())
1052            paintInvalidationRect.unite(continuation()->rectWithOutlineForPaintInvalidation(paintInvalidationContainer, outlineSize));
1053    }
1054
1055    return paintInvalidationRect;
1056}
1057
1058LayoutRect RenderInline::rectWithOutlineForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, LayoutUnit outlineWidth, const PaintInvalidationState* paintInvalidationState) const
1059{
1060    LayoutRect r(RenderBoxModelObject::rectWithOutlineForPaintInvalidation(paintInvalidationContainer, outlineWidth, paintInvalidationState));
1061    for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
1062        if (!curr->isText())
1063            r.unite(curr->rectWithOutlineForPaintInvalidation(paintInvalidationContainer, outlineWidth, paintInvalidationState));
1064    }
1065    return r;
1066}
1067
1068void RenderInline::mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect, const PaintInvalidationState* paintInvalidationState) const
1069{
1070    if (paintInvalidationState && paintInvalidationState->canMapToContainer(paintInvalidationContainer)) {
1071        if (style()->hasInFlowPosition() && layer())
1072            rect.move(layer()->offsetForInFlowPosition());
1073        rect.move(paintInvalidationState->paintOffset());
1074        if (paintInvalidationState->isClipped())
1075            rect.intersect(paintInvalidationState->clipRect());
1076        return;
1077    }
1078
1079    if (paintInvalidationContainer == this)
1080        return;
1081
1082    bool containerSkipped;
1083    RenderObject* o = container(paintInvalidationContainer, &containerSkipped);
1084    if (!o)
1085        return;
1086
1087    LayoutPoint topLeft = rect.location();
1088
1089    if (o->isRenderBlockFlow() && !style()->hasOutOfFlowPosition()) {
1090        RenderBlock* cb = toRenderBlock(o);
1091        if (cb->hasColumns()) {
1092            LayoutRect paintInvalidationRect(topLeft, rect.size());
1093            cb->adjustRectForColumns(paintInvalidationRect);
1094            topLeft = paintInvalidationRect.location();
1095            rect = paintInvalidationRect;
1096        }
1097    }
1098
1099    if (style()->hasInFlowPosition() && layer()) {
1100        // Apply the in-flow position offset when invalidating a rectangle. The layer
1101        // is translated, but the render box isn't, so we need to do this to get the
1102        // right dirty rect. Since this is called from RenderObject::setStyle, the relative position
1103        // flag on the RenderObject has been cleared, so use the one on the style().
1104        topLeft += layer()->offsetForInFlowPosition();
1105    }
1106
1107    // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
1108    // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
1109    rect.setLocation(topLeft);
1110    if (o->hasOverflowClip()) {
1111        RenderBox* containerBox = toRenderBox(o);
1112        containerBox->applyCachedClipAndScrollOffsetForPaintInvalidation(rect);
1113        if (rect.isEmpty())
1114            return;
1115    }
1116
1117    if (containerSkipped) {
1118        // If the paintInvalidationContainer is below o, then we need to map the rect into paintInvalidationContainer's coordinates.
1119        LayoutSize containerOffset = paintInvalidationContainer->offsetFromAncestorContainer(o);
1120        rect.move(-containerOffset);
1121        return;
1122    }
1123
1124    o->mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, paintInvalidationState);
1125}
1126
1127LayoutSize RenderInline::offsetFromContainer(const RenderObject* container, const LayoutPoint& point, bool* offsetDependsOnPoint) const
1128{
1129    ASSERT(container == this->container());
1130
1131    LayoutSize offset;
1132    if (isRelPositioned())
1133        offset += offsetForInFlowPosition();
1134
1135    offset += container->columnOffset(point);
1136
1137    if (container->hasOverflowClip())
1138        offset -= toRenderBox(container)->scrolledContentOffset();
1139
1140    if (offsetDependsOnPoint) {
1141        *offsetDependsOnPoint = container->hasColumns()
1142            || (container->isBox() && container->style()->isFlippedBlocksWritingMode())
1143            || container->isRenderFlowThread();
1144    }
1145
1146    return offset;
1147}
1148
1149void RenderInline::mapLocalToContainer(const RenderLayerModelObject* paintInvalidationContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const
1150{
1151    if (paintInvalidationContainer == this)
1152        return;
1153
1154    if (paintInvalidationState && paintInvalidationState->canMapToContainer(paintInvalidationContainer)) {
1155        LayoutSize offset = paintInvalidationState->paintOffset();
1156        if (style()->hasInFlowPosition() && layer())
1157            offset += layer()->offsetForInFlowPosition();
1158        transformState.move(offset);
1159        return;
1160    }
1161
1162    bool containerSkipped;
1163    RenderObject* o = container(paintInvalidationContainer, &containerSkipped);
1164    if (!o)
1165        return;
1166
1167    if (mode & ApplyContainerFlip && o->isBox()) {
1168        if (o->style()->isFlippedBlocksWritingMode()) {
1169            IntPoint centerPoint = roundedIntPoint(transformState.mappedPoint());
1170            transformState.move(toRenderBox(o)->flipForWritingModeIncludingColumns(centerPoint) - centerPoint);
1171        }
1172        mode &= ~ApplyContainerFlip;
1173    }
1174
1175    LayoutSize containerOffset = offsetFromContainer(o, roundedLayoutPoint(transformState.mappedPoint()));
1176
1177    bool preserve3D = mode & UseTransforms && (o->style()->preserves3D() || style()->preserves3D());
1178    if (mode & UseTransforms && shouldUseTransformFromContainer(o)) {
1179        TransformationMatrix t;
1180        getTransformFromContainer(o, containerOffset, t);
1181        transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1182    } else
1183        transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1184
1185    if (containerSkipped) {
1186        // There can't be a transform between paintInvalidationContainer and o, because transforms create containers, so it should be safe
1187        // to just subtract the delta between the paintInvalidationContainer and o.
1188        LayoutSize containerOffset = paintInvalidationContainer->offsetFromAncestorContainer(o);
1189        transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1190        return;
1191    }
1192
1193    o->mapLocalToContainer(paintInvalidationContainer, transformState, mode, wasFixed, paintInvalidationState);
1194}
1195
1196void RenderInline::updateDragState(bool dragOn)
1197{
1198    RenderBoxModelObject::updateDragState(dragOn);
1199    if (continuation())
1200        continuation()->updateDragState(dragOn);
1201}
1202
1203void RenderInline::childBecameNonInline(RenderObject* child)
1204{
1205    // We have to split the parent flow.
1206    RenderBlock* newBox = containingBlock()->createAnonymousBlock();
1207    RenderBoxModelObject* oldContinuation = continuation();
1208    setContinuation(newBox);
1209    RenderObject* beforeChild = child->nextSibling();
1210    children()->removeChildNode(this, child);
1211    splitFlow(beforeChild, newBox, child, oldContinuation);
1212}
1213
1214void RenderInline::updateHitTestResult(HitTestResult& result, const LayoutPoint& point)
1215{
1216    if (result.innerNode())
1217        return;
1218
1219    Node* n = node();
1220    LayoutPoint localPoint(point);
1221    if (n) {
1222        if (isInlineElementContinuation()) {
1223            // We're in the continuation of a split inline.  Adjust our local point to be in the coordinate space
1224            // of the principal renderer's containing block.  This will end up being the innerNonSharedNode.
1225            RenderBlock* firstBlock = n->renderer()->containingBlock();
1226
1227            // Get our containing block.
1228            RenderBox* block = containingBlock();
1229            localPoint.moveBy(block->location() - firstBlock->locationOffset());
1230        }
1231
1232        result.setInnerNode(n);
1233        if (!result.innerNonSharedNode())
1234            result.setInnerNonSharedNode(n);
1235        result.setLocalPoint(localPoint);
1236    }
1237}
1238
1239void RenderInline::dirtyLineBoxes(bool fullLayout)
1240{
1241    if (fullLayout) {
1242        m_lineBoxes.deleteLineBoxes();
1243        return;
1244    }
1245
1246    if (!alwaysCreateLineBoxes()) {
1247        // We have to grovel into our children in order to dirty the appropriate lines.
1248        for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
1249            if (curr->isFloatingOrOutOfFlowPositioned())
1250                continue;
1251            if (curr->isBox() && !curr->needsLayout()) {
1252                RenderBox* currBox = toRenderBox(curr);
1253                if (currBox->inlineBoxWrapper())
1254                    currBox->inlineBoxWrapper()->root().markDirty();
1255            } else if (!curr->selfNeedsLayout()) {
1256                if (curr->isRenderInline()) {
1257                    RenderInline* currInline = toRenderInline(curr);
1258                    for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox())
1259                        childLine->root().markDirty();
1260                } else if (curr->isText()) {
1261                    RenderText* currText = toRenderText(curr);
1262                    for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox())
1263                        childText->root().markDirty();
1264                }
1265            }
1266        }
1267    } else
1268        m_lineBoxes.dirtyLineBoxes();
1269}
1270
1271void RenderInline::deleteLineBoxTree()
1272{
1273    m_lineBoxes.deleteLineBoxTree();
1274}
1275
1276InlineFlowBox* RenderInline::createInlineFlowBox()
1277{
1278    return new InlineFlowBox(*this);
1279}
1280
1281InlineFlowBox* RenderInline::createAndAppendInlineFlowBox()
1282{
1283    setAlwaysCreateLineBoxes();
1284    InlineFlowBox* flowBox = createInlineFlowBox();
1285    m_lineBoxes.appendLineBox(flowBox);
1286    return flowBox;
1287}
1288
1289LayoutUnit RenderInline::lineHeight(bool firstLine, LineDirectionMode /*direction*/, LinePositionMode /*linePositionMode*/) const
1290{
1291    if (firstLine && document().styleEngine()->usesFirstLineRules()) {
1292        RenderStyle* s = style(firstLine);
1293        if (s != style())
1294            return s->computedLineHeight();
1295    }
1296
1297    return style()->computedLineHeight();
1298}
1299
1300int RenderInline::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
1301{
1302    ASSERT(linePositionMode == PositionOnContainingLine);
1303    const FontMetrics& fontMetrics = style(firstLine)->fontMetrics();
1304    return fontMetrics.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - fontMetrics.height()) / 2;
1305}
1306
1307LayoutSize RenderInline::offsetForInFlowPositionedInline(const RenderBox& child) const
1308{
1309    // FIXME: This function isn't right with mixed writing modes.
1310
1311    ASSERT(isRelPositioned());
1312    if (!isRelPositioned())
1313        return LayoutSize();
1314
1315    // When we have an enclosing relpositioned inline, we need to add in the offset of the first line
1316    // box from the rest of the content, but only in the cases where we know we're positioned
1317    // relative to the inline itself.
1318
1319    LayoutSize logicalOffset;
1320    LayoutUnit inlinePosition;
1321    LayoutUnit blockPosition;
1322    if (firstLineBox()) {
1323        inlinePosition = LayoutUnit::fromFloatRound(firstLineBox()->logicalLeft());
1324        blockPosition = firstLineBox()->logicalTop();
1325    } else {
1326        inlinePosition = layer()->staticInlinePosition();
1327        blockPosition = layer()->staticBlockPosition();
1328    }
1329
1330    // Per http://www.w3.org/TR/CSS2/visudet.html#abs-non-replaced-width an absolute positioned box
1331    // with a static position should locate itself as though it is a normal flow box in relation to
1332    // its containing block. If this relative-positioned inline has a negative offset we need to
1333    // compensate for it so that we align the positioned object with the edge of its containing block.
1334    if (child.style()->hasStaticInlinePosition(style()->isHorizontalWritingMode()))
1335        logicalOffset.setWidth(std::max(LayoutUnit(), -offsetForInFlowPosition().width()));
1336    else
1337        logicalOffset.setWidth(inlinePosition);
1338
1339    if (!child.style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
1340        logicalOffset.setHeight(blockPosition);
1341
1342    return style()->isHorizontalWritingMode() ? logicalOffset : logicalOffset.transposedSize();
1343}
1344
1345void RenderInline::imageChanged(WrappedImagePtr, const IntRect*)
1346{
1347    if (!parent())
1348        return;
1349
1350    // FIXME: We can do better.
1351    setShouldDoFullPaintInvalidation(true);
1352}
1353
1354namespace {
1355
1356class AbsoluteLayoutRectsGeneratorContext {
1357public:
1358    AbsoluteLayoutRectsGeneratorContext(Vector<LayoutRect>& rects, const LayoutPoint& accumulatedOffset)
1359        : m_rects(rects)
1360        , m_accumulatedOffset(accumulatedOffset) { }
1361
1362    void operator()(const FloatRect& rect)
1363    {
1364        LayoutRect layoutRect(rect);
1365        layoutRect.move(m_accumulatedOffset.x(), m_accumulatedOffset.y());
1366        m_rects.append(layoutRect);
1367    }
1368private:
1369    Vector<LayoutRect>& m_rects;
1370    const LayoutPoint& m_accumulatedOffset;
1371};
1372
1373class AbsoluteLayoutRectsIgnoringEmptyRectsGeneratorContext : public AbsoluteLayoutRectsGeneratorContext {
1374public:
1375    AbsoluteLayoutRectsIgnoringEmptyRectsGeneratorContext(Vector<LayoutRect>& rects, const LayoutPoint& accumulatedOffset)
1376        : AbsoluteLayoutRectsGeneratorContext(rects, accumulatedOffset) { }
1377
1378    void operator()(const FloatRect& rect)
1379    {
1380        if (!rect.isEmpty())
1381            AbsoluteLayoutRectsGeneratorContext::operator()(rect);
1382    }
1383};
1384
1385} // unnamed namespace
1386
1387void RenderInline::addFocusRingRects(Vector<LayoutRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer) const
1388{
1389    AbsoluteLayoutRectsIgnoringEmptyRectsGeneratorContext context(rects, additionalOffset);
1390    generateLineBoxRects(context);
1391
1392    addChildFocusRingRects(rects, additionalOffset, paintContainer);
1393
1394    if (continuation()) {
1395        // If the continuation doesn't paint into the same container, let its paint invalidation container handle it.
1396        if (paintContainer != continuation()->containerForPaintInvalidation())
1397            return;
1398        if (continuation()->isInline())
1399            continuation()->addFocusRingRects(rects, additionalOffset + (continuation()->containingBlock()->location() - containingBlock()->location()), paintContainer);
1400        else
1401            continuation()->addFocusRingRects(rects, additionalOffset + (toRenderBox(continuation())->location() - containingBlock()->location()), paintContainer);
1402    }
1403}
1404
1405void RenderInline::computeSelfHitTestRects(Vector<LayoutRect>& rects, const LayoutPoint& layerOffset) const
1406{
1407    AbsoluteLayoutRectsGeneratorContext context(rects, layerOffset);
1408    generateLineBoxRects(context);
1409}
1410
1411void RenderInline::addAnnotatedRegions(Vector<AnnotatedRegionValue>& regions)
1412{
1413    // Convert the style regions to absolute coordinates.
1414    if (style()->visibility() != VISIBLE)
1415        return;
1416
1417    if (style()->getDraggableRegionMode() == DraggableRegionNone)
1418        return;
1419
1420    AnnotatedRegionValue region;
1421    region.draggable = style()->getDraggableRegionMode() == DraggableRegionDrag;
1422    region.bounds = linesBoundingBox();
1423
1424    RenderObject* container = containingBlock();
1425    if (!container)
1426        container = this;
1427
1428    FloatPoint absPos = container->localToAbsolute();
1429    region.bounds.setX(absPos.x() + region.bounds.x());
1430    region.bounds.setY(absPos.y() + region.bounds.y());
1431
1432    regions.append(region);
1433}
1434
1435} // namespace blink
1436