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