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/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 
     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_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 
    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     // 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 
    137 static 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 
    147 static 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 
    176 void 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 
    216 void 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 
    249 LayoutRect 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 
    273 void RenderInline::addChild(RenderObject* newChild, RenderObject* beforeChild)
    274 {
    275     if (continuation())
    276         return addChildToContinuation(newChild, beforeChild);
    277     return addChildIgnoringContinuation(newChild, beforeChild);
    278 }
    279 
    280 static RenderBoxModelObject* nextContinuation(RenderObject* renderer)
    281 {
    282     if (renderer->isInline() && !renderer->isReplaced())
    283         return toRenderInline(renderer)->continuation();
    284     return toRenderBlock(renderer)->inlineElementContinuation();
    285 }
    286 
    287 RenderBoxModelObject* 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 
    312 void 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 
    344 RenderInline* RenderInline::clone() const
    345 {
    346     RenderInline* cloneInline = new RenderInline(node());
    347     cloneInline->setStyle(style());
    348     cloneInline->setFlowThreadState(flowThreadState());
    349     return cloneInline;
    350 }
    351 
    352 void 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 
    442 void 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 
    500 void 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 
    537 void RenderInline::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
    538 {
    539     ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this);
    540     m_lineBoxes.paint(this, paintInfo, paintOffset);
    541 }
    542 
    543 template<typename GeneratorContext>
    544 void 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 
    555 template<typename GeneratorContext>
    556 void 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 
    619 namespace {
    620 
    621 class AbsoluteRectsGeneratorContext {
    622 public:
    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     }
    633 private:
    634     Vector<IntRect>& m_rects;
    635     const LayoutPoint& m_accumulatedOffset;
    636 };
    637 
    638 } // unnamed namespace
    639 
    640 void 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 
    655 namespace {
    656 
    657 class AbsoluteQuadsGeneratorContext {
    658 public:
    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     }
    670 private:
    671     Vector<FloatQuad>& m_quads;
    672     RenderGeometryMap m_geometryMap;
    673 };
    674 
    675 } // unnamed namespace
    676 
    677 void 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 
    686 LayoutUnit RenderInline::offsetLeft() const
    687 {
    688     LayoutPoint topLeft;
    689     if (InlineBox* firstBox = firstLineBoxIncludingCulling())
    690         topLeft = flooredLayoutPoint(firstBox->topLeft());
    691     return adjustedPositionRelativeToOffsetParent(topLeft).x();
    692 }
    693 
    694 LayoutUnit RenderInline::offsetTop() const
    695 {
    696     LayoutPoint topLeft;
    697     if (InlineBox* firstBox = firstLineBoxIncludingCulling())
    698         topLeft = flooredLayoutPoint(firstBox->topLeft());
    699     return adjustedPositionRelativeToOffsetParent(topLeft).y();
    700 }
    701 
    702 static 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 
    713 LayoutUnit RenderInline::marginLeft() const
    714 {
    715     return computeMargin(this, style()->marginLeft());
    716 }
    717 
    718 LayoutUnit RenderInline::marginRight() const
    719 {
    720     return computeMargin(this, style()->marginRight());
    721 }
    722 
    723 LayoutUnit RenderInline::marginTop() const
    724 {
    725     return computeMargin(this, style()->marginTop());
    726 }
    727 
    728 LayoutUnit RenderInline::marginBottom() const
    729 {
    730     return computeMargin(this, style()->marginBottom());
    731 }
    732 
    733 LayoutUnit RenderInline::marginStart(const RenderStyle* otherStyle) const
    734 {
    735     return computeMargin(this, style()->marginStartUsing(otherStyle ? otherStyle : style()));
    736 }
    737 
    738 LayoutUnit RenderInline::marginEnd(const RenderStyle* otherStyle) const
    739 {
    740     return computeMargin(this, style()->marginEndUsing(otherStyle ? otherStyle : style()));
    741 }
    742 
    743 LayoutUnit RenderInline::marginBefore(const RenderStyle* otherStyle) const
    744 {
    745     return computeMargin(this, style()->marginBeforeUsing(otherStyle ? otherStyle : style()));
    746 }
    747 
    748 LayoutUnit RenderInline::marginAfter(const RenderStyle* otherStyle) const
    749 {
    750     return computeMargin(this, style()->marginAfterUsing(otherStyle ? otherStyle : style()));
    751 }
    752 
    753 const 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 
    767 bool 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 
    773 namespace {
    774 
    775 class HitTestCulledInlinesGeneratorContext {
    776 public:
    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; }
    784 private:
    785     bool m_intersected;
    786     Region& m_region;
    787     const HitTestLocation& m_location;
    788 };
    789 
    790 } // unnamed namespace
    791 
    792 bool 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 
    814 PositionWithAffinity 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 
    837 namespace {
    838 
    839 class LinesBoundingBoxGeneratorContext {
    840 public:
    841     LinesBoundingBoxGeneratorContext(FloatRect& rect) : m_rect(rect) { }
    842     void operator()(const FloatRect& rect)
    843     {
    844         m_rect.uniteIfNonZero(rect);
    845     }
    846 private:
    847     FloatRect& m_rect;
    848 };
    849 
    850 } // unnamed namespace
    851 
    852 IntRect 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 
    891 InlineBox* 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 
    915 InlineBox* 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 
    939 LayoutRect 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 
    980 LayoutRect 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 
   1009 LayoutRect 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 
   1059 LayoutRect 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 
   1069 void 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 
   1132 LayoutSize 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 
   1154 void 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 
   1204 void RenderInline::updateDragState(bool dragOn)
   1205 {
   1206     RenderBoxModelObject::updateDragState(dragOn);
   1207     if (continuation())
   1208         continuation()->updateDragState(dragOn);
   1209 }
   1210 
   1211 void 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 
   1222 void 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 
   1247 void 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 
   1279 void RenderInline::deleteLineBoxTree()
   1280 {
   1281     m_lineBoxes.deleteLineBoxTree();
   1282 }
   1283 
   1284 InlineFlowBox* RenderInline::createInlineFlowBox()
   1285 {
   1286     return new InlineFlowBox(*this);
   1287 }
   1288 
   1289 InlineFlowBox* RenderInline::createAndAppendInlineFlowBox()
   1290 {
   1291     setAlwaysCreateLineBoxes();
   1292     InlineFlowBox* flowBox = createInlineFlowBox();
   1293     m_lineBoxes.appendLineBox(flowBox);
   1294     return flowBox;
   1295 }
   1296 
   1297 LayoutUnit 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 
   1308 int 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 
   1315 LayoutSize 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 
   1355 void RenderInline::imageChanged(WrappedImagePtr, const IntRect*)
   1356 {
   1357     if (!parent())
   1358         return;
   1359 
   1360     // FIXME: We can do better.
   1361     paintInvalidationForWholeRenderer();
   1362 }
   1363 
   1364 void 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 
   1382 namespace {
   1383 
   1384 class AbsoluteLayoutRectsGeneratorContext {
   1385 public:
   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     }
   1396 private:
   1397     Vector<LayoutRect>& m_rects;
   1398     const LayoutPoint& m_accumulatedOffset;
   1399 };
   1400 
   1401 }
   1402 
   1403 void RenderInline::computeSelfHitTestRects(Vector<LayoutRect>& rects, const LayoutPoint& layerOffset) const
   1404 {
   1405     AbsoluteLayoutRectsGeneratorContext context(rects, layerOffset);
   1406     generateLineBoxRects(context);
   1407 }
   1408 
   1409 void 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 
   1454 void 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 
   1565 void 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