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