WebCore/rendering/RenderInline.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
       
     3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
       
     4  * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
       
     5  *
       
     6  * This library is free software; you can redistribute it and/or
       
     7  * modify it under the terms of the GNU Library General Public
       
     8  * License as published by the Free Software Foundation; either
       
     9  * version 2 of the License, or (at your option) any later version.
       
    10  *
       
    11  * This library is distributed in the hope that it will be useful,
       
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    14  * Library General Public License for more details.
       
    15  *
       
    16  * You should have received a copy of the GNU Library General Public License
       
    17  * along with this library; see the file COPYING.LIB.  If not, write to
       
    18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
       
    19  * Boston, MA 02110-1301, USA.
       
    20  *
       
    21  */
       
    22 
       
    23 #include "config.h"
       
    24 #include "RenderInline.h"
       
    25 
       
    26 #include "Chrome.h"
       
    27 #include "FloatQuad.h"
       
    28 #include "GraphicsContext.h"
       
    29 #include "HitTestResult.h"
       
    30 #include "Page.h"
       
    31 #include "RenderArena.h"
       
    32 #include "RenderBlock.h"
       
    33 #include "RenderLayer.h"
       
    34 #include "RenderView.h"
       
    35 #include "TransformState.h"
       
    36 #include "VisiblePosition.h"
       
    37 
       
    38 #if ENABLE(DASHBOARD_SUPPORT)
       
    39 #include "Frame.h"
       
    40 #endif
       
    41 
       
    42 using namespace std;
       
    43 
       
    44 namespace WebCore {
       
    45 
       
    46 RenderInline::RenderInline(Node* node)
       
    47     : RenderBoxModelObject(node)
       
    48     , m_continuation(0)
       
    49     , m_lineHeight(-1)
       
    50     , m_verticalPosition(PositionUndefined)
       
    51 {
       
    52     setChildrenInline(true);
       
    53 }
       
    54 
       
    55 void RenderInline::destroy()
       
    56 {
       
    57     // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
       
    58     // properly dirty line boxes that they are removed from.  Effects that do :before/:after only on hover could crash otherwise.
       
    59     children()->destroyLeftoverChildren();
       
    60 
       
    61     // Destroy our continuation before anything other than anonymous children.
       
    62     // The reason we don't destroy it before anonymous children is that they may
       
    63     // have continuations of their own that are anonymous children of our continuation.
       
    64     if (m_continuation) {
       
    65         m_continuation->destroy();
       
    66         m_continuation = 0;
       
    67     }
       
    68     
       
    69     if (!documentBeingDestroyed()) {
       
    70         if (firstLineBox()) {
       
    71             // We can't wait for RenderBoxModelObject::destroy to clear the selection,
       
    72             // because by then we will have nuked the line boxes.
       
    73             // FIXME: The SelectionController should be responsible for this when it
       
    74             // is notified of DOM mutations.
       
    75             if (isSelectionBorder())
       
    76                 view()->clearSelection();
       
    77 
       
    78             // If line boxes are contained inside a root, that means we're an inline.
       
    79             // In that case, we need to remove all the line boxes so that the parent
       
    80             // lines aren't pointing to deleted children. If the first line box does
       
    81             // not have a parent that means they are either already disconnected or
       
    82             // root lines that can just be destroyed without disconnecting.
       
    83             if (firstLineBox()->parent()) {
       
    84                 for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox())
       
    85                     box->remove();
       
    86             }
       
    87         } else if (isInline() && parent())
       
    88             parent()->dirtyLinesFromChangedChild(this);
       
    89     }
       
    90 
       
    91     m_lineBoxes.deleteLineBoxes(renderArena());
       
    92 
       
    93     RenderBoxModelObject::destroy();
       
    94 }
       
    95 
       
    96 RenderInline* RenderInline::inlineElementContinuation() const
       
    97 {
       
    98     if (!m_continuation || m_continuation->isInline())
       
    99         return toRenderInline(m_continuation);
       
   100     return toRenderBlock(m_continuation)->inlineElementContinuation();
       
   101 }
       
   102 
       
   103 void RenderInline::updateBoxModelInfoFromStyle()
       
   104 {
       
   105     RenderBoxModelObject::updateBoxModelInfoFromStyle();
       
   106 
       
   107     setInline(true); // Needed for run-ins, since run-in is considered a block display type.
       
   108 
       
   109     // FIXME: Support transforms and reflections on inline flows someday.
       
   110     setHasTransform(false);
       
   111     setHasReflection(false);    
       
   112 }
       
   113 
       
   114 void RenderInline::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
       
   115 {
       
   116     RenderBoxModelObject::styleDidChange(diff, oldStyle);
       
   117 
       
   118     // Ensure that all of the split inlines pick up the new style. We
       
   119     // only do this if we're an inline, since we don't want to propagate
       
   120     // a block's style to the other inlines.
       
   121     // e.g., <font>foo <h4>goo</h4> moo</font>.  The <font> inlines before
       
   122     // and after the block share the same style, but the block doesn't
       
   123     // need to pass its style on to anyone else.
       
   124     for (RenderInline* currCont = inlineElementContinuation(); currCont; currCont = currCont->inlineElementContinuation()) {
       
   125         RenderBoxModelObject* nextCont = currCont->continuation();
       
   126         currCont->setContinuation(0);
       
   127         currCont->setStyle(style());
       
   128         currCont->setContinuation(nextCont);
       
   129     }
       
   130 
       
   131     m_lineHeight = -1;
       
   132 
       
   133     // Update pseudos for :before and :after now.
       
   134     if (!isAnonymous() && document()->usesBeforeAfterRules()) {
       
   135         children()->updateBeforeAfterContent(this, BEFORE);
       
   136         children()->updateBeforeAfterContent(this, AFTER);
       
   137     }
       
   138 }
       
   139 
       
   140 void RenderInline::addChild(RenderObject* newChild, RenderObject* beforeChild)
       
   141 {
       
   142     if (continuation())
       
   143         return addChildToContinuation(newChild, beforeChild);
       
   144     return addChildIgnoringContinuation(newChild, beforeChild);
       
   145 }
       
   146 
       
   147 static RenderBoxModelObject* nextContinuation(RenderObject* renderer)
       
   148 {
       
   149     if (renderer->isInline() && !renderer->isReplaced())
       
   150         return toRenderInline(renderer)->continuation();
       
   151     return toRenderBlock(renderer)->inlineElementContinuation();
       
   152 }
       
   153 
       
   154 RenderBoxModelObject* RenderInline::continuationBefore(RenderObject* beforeChild)
       
   155 {
       
   156     if (beforeChild && beforeChild->parent() == this)
       
   157         return this;
       
   158 
       
   159     RenderBoxModelObject* curr = nextContinuation(this);
       
   160     RenderBoxModelObject* nextToLast = this;
       
   161     RenderBoxModelObject* last = this;
       
   162     while (curr) {
       
   163         if (beforeChild && beforeChild->parent() == curr) {
       
   164             if (curr->firstChild() == beforeChild)
       
   165                 return last;
       
   166             return curr;
       
   167         }
       
   168 
       
   169         nextToLast = last;
       
   170         last = curr;
       
   171         curr = nextContinuation(curr);
       
   172     }
       
   173 
       
   174     if (!beforeChild && !last->firstChild())
       
   175         return nextToLast;
       
   176     return last;
       
   177 }
       
   178 
       
   179 void RenderInline::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild)
       
   180 {
       
   181     // Make sure we don't append things after :after-generated content if we have it.
       
   182     if (!beforeChild && isAfterContent(lastChild()))
       
   183         beforeChild = lastChild();
       
   184 
       
   185     if (!newChild->isInline() && !newChild->isFloatingOrPositioned()) {
       
   186         // We are placing a block inside an inline. We have to perform a split of this
       
   187         // inline into continuations.  This involves creating an anonymous block box to hold
       
   188         // |newChild|.  We then make that block box a continuation of this inline.  We take all of
       
   189         // the children after |beforeChild| and put them in a clone of this object.
       
   190         RefPtr<RenderStyle> newStyle = RenderStyle::create();
       
   191         newStyle->inheritFrom(style());
       
   192         newStyle->setDisplay(BLOCK);
       
   193 
       
   194         RenderBlock* newBox = new (renderArena()) RenderBlock(document() /* anonymous box */);
       
   195         newBox->setStyle(newStyle.release());
       
   196         RenderBoxModelObject* oldContinuation = continuation();
       
   197         setContinuation(newBox);
       
   198 
       
   199         // Someone may have put a <p> inside a <q>, causing a split.  When this happens, the :after content
       
   200         // has to move into the inline continuation.  Call updateBeforeAfterContent to ensure that our :after
       
   201         // content gets properly destroyed.
       
   202         bool isLastChild = (beforeChild == lastChild());
       
   203         if (document()->usesBeforeAfterRules())
       
   204             children()->updateBeforeAfterContent(this, AFTER);
       
   205         if (isLastChild && beforeChild != lastChild())
       
   206             beforeChild = 0; // We destroyed the last child, so now we need to update our insertion
       
   207                              // point to be 0.  It's just a straight append now.
       
   208 
       
   209         splitFlow(beforeChild, newBox, newChild, oldContinuation);
       
   210         return;
       
   211     }
       
   212 
       
   213     RenderBoxModelObject::addChild(newChild, beforeChild);
       
   214 
       
   215     newChild->setNeedsLayoutAndPrefWidthsRecalc();
       
   216 }
       
   217 
       
   218 RenderInline* RenderInline::cloneInline(RenderInline* src)
       
   219 {
       
   220     RenderInline* o = new (src->renderArena()) RenderInline(src->node());
       
   221     o->setStyle(src->style());
       
   222     return o;
       
   223 }
       
   224 
       
   225 void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock,
       
   226                                 RenderBlock* middleBlock,
       
   227                                 RenderObject* beforeChild, RenderBoxModelObject* oldCont)
       
   228 {
       
   229     // Create a clone of this inline.
       
   230     RenderInline* clone = cloneInline(this);
       
   231     clone->setContinuation(oldCont);
       
   232 
       
   233     // Now take all of the children from beforeChild to the end and remove
       
   234     // them from |this| and place them in the clone.
       
   235     RenderObject* o = beforeChild;
       
   236     while (o) {
       
   237         RenderObject* tmp = o;
       
   238         o = tmp->nextSibling();
       
   239         clone->addChildIgnoringContinuation(children()->removeChildNode(this, tmp), 0);
       
   240         tmp->setNeedsLayoutAndPrefWidthsRecalc();
       
   241     }
       
   242 
       
   243     // Hook |clone| up as the continuation of the middle block.
       
   244     middleBlock->setContinuation(clone);
       
   245 
       
   246     // We have been reparented and are now under the fromBlock.  We need
       
   247     // to walk up our inline parent chain until we hit the containing block.
       
   248     // Once we hit the containing block we're done.
       
   249     RenderBoxModelObject* curr = toRenderBoxModelObject(parent());
       
   250     RenderBoxModelObject* currChild = this;
       
   251     
       
   252     // FIXME: Because splitting is O(n^2) as tags nest pathologically, we cap the depth at which we're willing to clone.
       
   253     // There will eventually be a better approach to this problem that will let us nest to a much
       
   254     // greater depth (see bugzilla bug 13430) but for now we have a limit.  This *will* result in
       
   255     // incorrect rendering, but the alternative is to hang forever.
       
   256     unsigned splitDepth = 1;
       
   257     const unsigned cMaxSplitDepth = 200; 
       
   258     while (curr && curr != fromBlock) {
       
   259         ASSERT(curr->isRenderInline());
       
   260         if (splitDepth < cMaxSplitDepth) {
       
   261             // Create a new clone.
       
   262             RenderInline* cloneChild = clone;
       
   263             clone = cloneInline(toRenderInline(curr));
       
   264 
       
   265             // Insert our child clone as the first child.
       
   266             clone->addChildIgnoringContinuation(cloneChild, 0);
       
   267 
       
   268             // Hook the clone up as a continuation of |curr|.
       
   269             RenderInline* inlineCurr = toRenderInline(curr);
       
   270             oldCont = inlineCurr->continuation();
       
   271             inlineCurr->setContinuation(clone);
       
   272             clone->setContinuation(oldCont);
       
   273 
       
   274             // Someone may have indirectly caused a <q> to split.  When this happens, the :after content
       
   275             // has to move into the inline continuation.  Call updateBeforeAfterContent to ensure that the inline's :after
       
   276             // content gets properly destroyed.
       
   277             if (document()->usesBeforeAfterRules())
       
   278                 inlineCurr->children()->updateBeforeAfterContent(inlineCurr, AFTER);
       
   279 
       
   280             // Now we need to take all of the children starting from the first child
       
   281             // *after* currChild and append them all to the clone.
       
   282             o = currChild->nextSibling();
       
   283             while (o) {
       
   284                 RenderObject* tmp = o;
       
   285                 o = tmp->nextSibling();
       
   286                 clone->addChildIgnoringContinuation(inlineCurr->children()->removeChildNode(curr, tmp), 0);
       
   287                 tmp->setNeedsLayoutAndPrefWidthsRecalc();
       
   288             }
       
   289         }
       
   290         
       
   291         // Keep walking up the chain.
       
   292         currChild = curr;
       
   293         curr = toRenderBoxModelObject(curr->parent());
       
   294         splitDepth++;
       
   295     }
       
   296 
       
   297     // Now we are at the block level. We need to put the clone into the toBlock.
       
   298     toBlock->children()->appendChildNode(toBlock, clone);
       
   299 
       
   300     // Now take all the children after currChild and remove them from the fromBlock
       
   301     // and put them in the toBlock.
       
   302     o = currChild->nextSibling();
       
   303     while (o) {
       
   304         RenderObject* tmp = o;
       
   305         o = tmp->nextSibling();
       
   306         toBlock->children()->appendChildNode(toBlock, fromBlock->children()->removeChildNode(fromBlock, tmp));
       
   307     }
       
   308 }
       
   309 
       
   310 void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
       
   311                              RenderObject* newChild, RenderBoxModelObject* oldCont)
       
   312 {
       
   313     RenderBlock* pre = 0;
       
   314     RenderBlock* block = containingBlock();
       
   315     
       
   316     // Delete our line boxes before we do the inline split into continuations.
       
   317     block->deleteLineBoxTree();
       
   318     
       
   319     bool madeNewBeforeBlock = false;
       
   320     if (block->isAnonymousBlock() && (!block->parent() || !block->parent()->createsAnonymousWrapper())) {
       
   321         // We can reuse this block and make it the preBlock of the next continuation.
       
   322         pre = block;
       
   323         pre->removePositionedObjects(0);
       
   324         block = block->containingBlock();
       
   325     } else {
       
   326         // No anonymous block available for use.  Make one.
       
   327         pre = block->createAnonymousBlock();
       
   328         madeNewBeforeBlock = true;
       
   329     }
       
   330 
       
   331     RenderBlock* post = block->createAnonymousBlock();
       
   332 
       
   333     RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling();
       
   334     if (madeNewBeforeBlock)
       
   335         block->children()->insertChildNode(block, pre, boxFirst);
       
   336     block->children()->insertChildNode(block, newBlockBox, boxFirst);
       
   337     block->children()->insertChildNode(block, post, boxFirst);
       
   338     block->setChildrenInline(false);
       
   339     
       
   340     if (madeNewBeforeBlock) {
       
   341         RenderObject* o = boxFirst;
       
   342         while (o) {
       
   343             RenderObject* no = o;
       
   344             o = no->nextSibling();
       
   345             pre->children()->appendChildNode(pre, block->children()->removeChildNode(block, no));
       
   346             no->setNeedsLayoutAndPrefWidthsRecalc();
       
   347         }
       
   348     }
       
   349 
       
   350     splitInlines(pre, post, newBlockBox, beforeChild, oldCont);
       
   351 
       
   352     // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
       
   353     // time in makeChildrenNonInline by just setting this explicitly up front.
       
   354     newBlockBox->setChildrenInline(false);
       
   355 
       
   356     // We delayed adding the newChild until now so that the |newBlockBox| would be fully
       
   357     // connected, thus allowing newChild access to a renderArena should it need
       
   358     // to wrap itself in additional boxes (e.g., table construction).
       
   359     newBlockBox->addChild(newChild);
       
   360 
       
   361     // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
       
   362     // get deleted properly.  Because objects moves from the pre block into the post block, we want to
       
   363     // make new line boxes instead of leaving the old line boxes around.
       
   364     pre->setNeedsLayoutAndPrefWidthsRecalc();
       
   365     block->setNeedsLayoutAndPrefWidthsRecalc();
       
   366     post->setNeedsLayoutAndPrefWidthsRecalc();
       
   367 }
       
   368 
       
   369 void RenderInline::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild)
       
   370 {
       
   371     RenderBoxModelObject* flow = continuationBefore(beforeChild);
       
   372     ASSERT(!beforeChild || beforeChild->parent()->isRenderBlock() || beforeChild->parent()->isRenderInline());
       
   373     RenderBoxModelObject* beforeChildParent = 0;
       
   374     if (beforeChild)
       
   375         beforeChildParent = toRenderBoxModelObject(beforeChild->parent());
       
   376     else {
       
   377         RenderBoxModelObject* cont = nextContinuation(flow);
       
   378         if (cont)
       
   379             beforeChildParent = cont;
       
   380         else
       
   381             beforeChildParent = flow;
       
   382     }
       
   383 
       
   384     if (newChild->isFloatingOrPositioned())
       
   385         return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
       
   386 
       
   387     // A continuation always consists of two potential candidates: an inline or an anonymous
       
   388     // block box holding block children.
       
   389     bool childInline = newChild->isInline();
       
   390     bool bcpInline = beforeChildParent->isInline();
       
   391     bool flowInline = flow->isInline();
       
   392 
       
   393     if (flow == beforeChildParent)
       
   394         return flow->addChildIgnoringContinuation(newChild, beforeChild);
       
   395     else {
       
   396         // The goal here is to match up if we can, so that we can coalesce and create the
       
   397         // minimal # of continuations needed for the inline.
       
   398         if (childInline == bcpInline)
       
   399             return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
       
   400         else if (flowInline == childInline)
       
   401             return flow->addChildIgnoringContinuation(newChild, 0); // Just treat like an append.
       
   402         else
       
   403             return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
       
   404     }
       
   405 }
       
   406 
       
   407 void RenderInline::paint(PaintInfo& paintInfo, int tx, int ty)
       
   408 {
       
   409     m_lineBoxes.paint(this, paintInfo, tx, ty);
       
   410 }
       
   411 
       
   412 void RenderInline::absoluteRects(Vector<IntRect>& rects, int tx, int ty)
       
   413 {
       
   414     if (InlineFlowBox* curr = firstLineBox()) {
       
   415         for (; curr; curr = curr->nextLineBox())
       
   416             rects.append(IntRect(tx + curr->x(), ty + curr->y(), curr->width(), curr->height()));
       
   417     } else
       
   418         rects.append(IntRect(tx, ty, 0, 0));
       
   419 
       
   420     if (continuation()) {
       
   421         if (continuation()->isBox()) {
       
   422             RenderBox* box = toRenderBox(continuation());
       
   423             continuation()->absoluteRects(rects, 
       
   424                                           tx - containingBlock()->x() + box->x(),
       
   425                                           ty - containingBlock()->y() + box->y());
       
   426         } else
       
   427             continuation()->absoluteRects(rects, tx - containingBlock()->x(), ty - containingBlock()->y());
       
   428     }
       
   429 }
       
   430 
       
   431 void RenderInline::absoluteQuads(Vector<FloatQuad>& quads)
       
   432 {
       
   433     if (InlineFlowBox* curr = firstLineBox()) {
       
   434         for (; curr; curr = curr->nextLineBox()) {
       
   435             FloatRect localRect(curr->x(), curr->y(), curr->width(), curr->height());
       
   436             quads.append(localToAbsoluteQuad(localRect));
       
   437         }
       
   438     } else
       
   439         quads.append(localToAbsoluteQuad(FloatRect()));
       
   440 
       
   441     if (continuation())
       
   442         continuation()->absoluteQuads(quads);
       
   443 }
       
   444 
       
   445 int RenderInline::offsetLeft() const
       
   446 {
       
   447     int x = RenderBoxModelObject::offsetLeft();
       
   448     if (firstLineBox())
       
   449         x += firstLineBox()->x();
       
   450     return x;
       
   451 }
       
   452 
       
   453 int RenderInline::offsetTop() const
       
   454 {
       
   455     int y = RenderBoxModelObject::offsetTop();
       
   456     if (firstLineBox())
       
   457         y += firstLineBox()->y();
       
   458     return y;
       
   459 }
       
   460 
       
   461 int RenderInline::marginLeft() const
       
   462 {
       
   463     Length margin = style()->marginLeft();
       
   464     if (margin.isAuto())
       
   465         return 0;
       
   466     if (margin.isFixed())
       
   467         return margin.value();
       
   468     if (margin.isPercent())
       
   469         return margin.calcMinValue(max(0, containingBlock()->availableWidth()));
       
   470     return 0;
       
   471 }
       
   472 
       
   473 int RenderInline::marginRight() const
       
   474 {
       
   475     Length margin = style()->marginRight();
       
   476     if (margin.isAuto())
       
   477         return 0;
       
   478     if (margin.isFixed())
       
   479         return margin.value();
       
   480     if (margin.isPercent())
       
   481         return margin.calcMinValue(max(0, containingBlock()->availableWidth()));
       
   482     return 0;
       
   483 }
       
   484 
       
   485 const char* RenderInline::renderName() const
       
   486 {
       
   487     if (isRelPositioned())
       
   488         return "RenderInline (relative positioned)";
       
   489     if (isAnonymous())
       
   490         return "RenderInline (generated)";
       
   491     if (isRunIn())
       
   492         return "RenderInline (run-in)";
       
   493     return "RenderInline";
       
   494 }
       
   495 
       
   496 bool RenderInline::nodeAtPoint(const HitTestRequest& request, HitTestResult& result,
       
   497                                 int x, int y, int tx, int ty, HitTestAction hitTestAction)
       
   498 {
       
   499     return m_lineBoxes.hitTest(this, request, result, x, y, tx, ty, hitTestAction);
       
   500 }
       
   501 
       
   502 VisiblePosition RenderInline::positionForPoint(const IntPoint& point)
       
   503 {
       
   504     // FIXME: Does not deal with relative positioned inlines (should it?)
       
   505     RenderBlock* cb = containingBlock();
       
   506     if (firstLineBox()) {
       
   507         // This inline actually has a line box.  We must have clicked in the border/padding of one of these boxes.  We
       
   508         // should try to find a result by asking our containing block.
       
   509         return cb->positionForPoint(point);
       
   510     }
       
   511 
       
   512     // Translate the coords from the pre-anonymous block to the post-anonymous block.
       
   513     int parentBlockX = cb->x() + point.x();
       
   514     int parentBlockY = cb->y() + point.y();
       
   515     RenderBoxModelObject* c = continuation();
       
   516     while (c) {
       
   517         RenderBox* contBlock = c->isInline() ? c->containingBlock() : toRenderBlock(c);
       
   518         if (c->isInline() || c->firstChild())
       
   519             return c->positionForCoordinates(parentBlockX - contBlock->x(), parentBlockY - contBlock->y());
       
   520         c = toRenderBlock(c)->inlineElementContinuation();
       
   521     }
       
   522     
       
   523     return RenderBoxModelObject::positionForPoint(point);
       
   524 }
       
   525 
       
   526 IntRect RenderInline::linesBoundingBox() const
       
   527 {
       
   528     IntRect result;
       
   529     
       
   530     // 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
       
   531     // 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
       
   532     // builds and help us someday figure out why.  We also put in a redundant check of lastLineBox() to avoid the crash for now.
       
   533     ASSERT(!firstLineBox() == !lastLineBox());  // Either both are null or both exist.
       
   534     if (firstLineBox() && lastLineBox()) {
       
   535         // Return the width of the minimal left side and the maximal right side.
       
   536         int leftSide = 0;
       
   537         int rightSide = 0;
       
   538         for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
       
   539             if (curr == firstLineBox() || curr->x() < leftSide)
       
   540                 leftSide = curr->x();
       
   541             if (curr == firstLineBox() || curr->x() + curr->width() > rightSide)
       
   542                 rightSide = curr->x() + curr->width();
       
   543         }
       
   544         result.setWidth(rightSide - leftSide);
       
   545         result.setX(leftSide);
       
   546         result.setHeight(lastLineBox()->y() + lastLineBox()->height() - firstLineBox()->y());
       
   547         result.setY(firstLineBox()->y());
       
   548     }
       
   549 
       
   550     return result;
       
   551 }
       
   552 
       
   553 IntRect RenderInline::linesVisibleOverflowBoundingBox() const
       
   554 {
       
   555     if (!firstLineBox() || !lastLineBox())
       
   556         return IntRect();
       
   557 
       
   558     // Return the width of the minimal left side and the maximal right side.
       
   559     int leftSide = numeric_limits<int>::max();
       
   560     int rightSide = numeric_limits<int>::min();
       
   561     for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
       
   562         leftSide = min(leftSide, curr->leftVisibleOverflow());
       
   563         rightSide = max(rightSide, curr->rightVisibleOverflow());
       
   564     }
       
   565 
       
   566     return IntRect(leftSide, firstLineBox()->topVisibleOverflow(), rightSide - leftSide,
       
   567         lastLineBox()->bottomVisibleOverflow() - firstLineBox()->topVisibleOverflow());
       
   568 }
       
   569 
       
   570 IntRect RenderInline::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
       
   571 {
       
   572     // Only run-ins are allowed in here during layout.
       
   573     ASSERT(!view() || !view()->layoutStateEnabled() || isRunIn());
       
   574 
       
   575     if (!firstLineBox() && !continuation())
       
   576         return IntRect();
       
   577 
       
   578     // Find our leftmost position.
       
   579     IntRect boundingBox(linesVisibleOverflowBoundingBox());
       
   580     int left = boundingBox.x();
       
   581     int top = boundingBox.y();
       
   582 
       
   583     // Now invalidate a rectangle.
       
   584     int ow = style() ? style()->outlineSize() : 0;
       
   585     
       
   586     // We need to add in the relative position offsets of any inlines (including us) up to our
       
   587     // containing block.
       
   588     RenderBlock* cb = containingBlock();
       
   589     for (RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isRenderInline() && inlineFlow != cb; 
       
   590          inlineFlow = inlineFlow->parent()) {
       
   591          if (inlineFlow->style()->position() == RelativePosition && inlineFlow->hasLayer())
       
   592             toRenderInline(inlineFlow)->layer()->relativePositionOffset(left, top);
       
   593     }
       
   594 
       
   595     IntRect r(-ow + left, -ow + top, boundingBox.width() + ow * 2, boundingBox.height() + ow * 2);
       
   596     if (cb->hasColumns())
       
   597         cb->adjustRectForColumns(r);
       
   598 
       
   599     if (cb->hasOverflowClip()) {
       
   600         // cb->height() is inaccurate if we're in the middle of a layout of |cb|, so use the
       
   601         // layer's size instead.  Even if the layer's size is wrong, the layer itself will repaint
       
   602         // anyway if its size does change.
       
   603         IntRect repaintRect(r);
       
   604         repaintRect.move(-cb->layer()->scrolledContentOffset()); // For overflow:auto/scroll/hidden.
       
   605 
       
   606         IntRect boxRect(0, 0, cb->layer()->width(), cb->layer()->height());
       
   607         r = intersection(repaintRect, boxRect);
       
   608     }
       
   609     
       
   610     // FIXME: need to ensure that we compute the correct repaint rect when the repaint container
       
   611     // is an inline.
       
   612     if (repaintContainer != this)
       
   613         cb->computeRectForRepaint(repaintContainer, r);
       
   614 
       
   615     if (ow) {
       
   616         for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
       
   617             if (!curr->isText()) {
       
   618                 IntRect childRect = curr->rectWithOutlineForRepaint(repaintContainer, ow);
       
   619                 r.unite(childRect);
       
   620             }
       
   621         }
       
   622 
       
   623         if (continuation() && !continuation()->isInline()) {
       
   624             IntRect contRect = continuation()->rectWithOutlineForRepaint(repaintContainer, ow);
       
   625             r.unite(contRect);
       
   626         }
       
   627     }
       
   628 
       
   629     return r;
       
   630 }
       
   631 
       
   632 IntRect RenderInline::rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, int outlineWidth)
       
   633 {
       
   634     IntRect r(RenderBoxModelObject::rectWithOutlineForRepaint(repaintContainer, outlineWidth));
       
   635     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
       
   636         if (!curr->isText())
       
   637             r.unite(curr->rectWithOutlineForRepaint(repaintContainer, outlineWidth));
       
   638     }
       
   639     return r;
       
   640 }
       
   641 
       
   642 void RenderInline::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& rect, bool fixed)
       
   643 {
       
   644     if (RenderView* v = view()) {
       
   645         // LayoutState is only valid for root-relative repainting
       
   646         if (v->layoutStateEnabled() && !repaintContainer) {
       
   647             LayoutState* layoutState = v->layoutState();
       
   648             if (style()->position() == RelativePosition && layer())
       
   649                 rect.move(layer()->relativePositionOffset());
       
   650             rect.move(layoutState->m_offset);
       
   651             if (layoutState->m_clipped)
       
   652                 rect.intersect(layoutState->m_clipRect);
       
   653             return;
       
   654         }
       
   655     }
       
   656 
       
   657     if (repaintContainer == this)
       
   658         return;
       
   659 
       
   660     bool containerSkipped;
       
   661     RenderObject* o = container(repaintContainer, &containerSkipped);
       
   662     if (!o)
       
   663         return;
       
   664 
       
   665     IntPoint topLeft = rect.location();
       
   666 
       
   667     if (o->isBlockFlow() && style()->position() != AbsolutePosition && style()->position() != FixedPosition) {
       
   668         RenderBlock* cb = toRenderBlock(o);
       
   669         if (cb->hasColumns()) {
       
   670             IntRect repaintRect(topLeft, rect.size());
       
   671             cb->adjustRectForColumns(repaintRect);
       
   672             topLeft = repaintRect.location();
       
   673             rect = repaintRect;
       
   674         }
       
   675     }
       
   676 
       
   677     if (style()->position() == RelativePosition && layer()) {
       
   678         // Apply the relative position offset when invalidating a rectangle.  The layer
       
   679         // is translated, but the render box isn't, so we need to do this to get the
       
   680         // right dirty rect.  Since this is called from RenderObject::setStyle, the relative position
       
   681         // flag on the RenderObject has been cleared, so use the one on the style().
       
   682         topLeft += layer()->relativePositionOffset();
       
   683     }
       
   684     
       
   685     // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
       
   686     // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
       
   687     if (o->hasOverflowClip()) {
       
   688         RenderBox* containerBox = toRenderBox(o);
       
   689 
       
   690         // o->height() is inaccurate if we're in the middle of a layout of |o|, so use the
       
   691         // layer's size instead.  Even if the layer's size is wrong, the layer itself will repaint
       
   692         // anyway if its size does change.
       
   693         topLeft -= containerBox->layer()->scrolledContentOffset(); // For overflow:auto/scroll/hidden.
       
   694 
       
   695         IntRect repaintRect(topLeft, rect.size());
       
   696         IntRect boxRect(0, 0, containerBox->layer()->width(), containerBox->layer()->height());
       
   697         rect = intersection(repaintRect, boxRect);
       
   698         if (rect.isEmpty())
       
   699             return;
       
   700     } else
       
   701         rect.setLocation(topLeft);
       
   702 
       
   703     if (containerSkipped) {
       
   704         // If the repaintContainer is below o, then we need to map the rect into repaintContainer's coordinates.
       
   705         IntSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
       
   706         rect.move(-containerOffset);
       
   707         return;
       
   708     }
       
   709     
       
   710     o->computeRectForRepaint(repaintContainer, rect, fixed);
       
   711 }
       
   712 
       
   713 IntSize RenderInline::offsetFromContainer(RenderObject* container, const IntPoint& point) const
       
   714 {
       
   715     ASSERT(container == this->container());
       
   716 
       
   717     IntSize offset;    
       
   718     if (isRelPositioned())
       
   719         offset += relativePositionOffset();
       
   720 
       
   721     container->adjustForColumns(offset, point);
       
   722 
       
   723     if (container->hasOverflowClip())
       
   724         offset -= toRenderBox(container)->layer()->scrolledContentOffset();
       
   725 
       
   726     return offset;
       
   727 }
       
   728 
       
   729 void RenderInline::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState) const
       
   730 {
       
   731     if (repaintContainer == this)
       
   732         return;
       
   733 
       
   734     if (RenderView *v = view()) {
       
   735         if (v->layoutStateEnabled() && !repaintContainer) {
       
   736             LayoutState* layoutState = v->layoutState();
       
   737             IntSize offset = layoutState->m_offset;
       
   738             if (style()->position() == RelativePosition && layer())
       
   739                 offset += layer()->relativePositionOffset();
       
   740             transformState.move(offset);
       
   741             return;
       
   742         }
       
   743     }
       
   744 
       
   745     bool containerSkipped;
       
   746     RenderObject* o = container(repaintContainer, &containerSkipped);
       
   747     if (!o)
       
   748         return;
       
   749 
       
   750     IntSize containerOffset = offsetFromContainer(o, roundedIntPoint(transformState.mappedPoint()));
       
   751 
       
   752     bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
       
   753     if (useTransforms && shouldUseTransformFromContainer(o)) {
       
   754         TransformationMatrix t;
       
   755         getTransformFromContainer(o, containerOffset, t);
       
   756         transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
       
   757     } else
       
   758         transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
       
   759 
       
   760     if (containerSkipped) {
       
   761         // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
       
   762         // to just subtract the delta between the repaintContainer and o.
       
   763         IntSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
       
   764         transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
       
   765         return;
       
   766     }
       
   767 
       
   768     o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState);
       
   769 }
       
   770 
       
   771 void RenderInline::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState& transformState) const
       
   772 {
       
   773     // We don't expect this function to be called during layout.
       
   774     ASSERT(!view() || !view()->layoutStateEnabled());
       
   775 
       
   776     RenderObject* o = container();
       
   777     if (!o)
       
   778         return;
       
   779 
       
   780     o->mapAbsoluteToLocalPoint(fixed, useTransforms, transformState);
       
   781 
       
   782     IntSize containerOffset = offsetFromContainer(o, IntPoint());
       
   783 
       
   784     bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
       
   785     if (useTransforms && shouldUseTransformFromContainer(o)) {
       
   786         TransformationMatrix t;
       
   787         getTransformFromContainer(o, containerOffset, t);
       
   788         transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
       
   789     } else
       
   790         transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
       
   791 }
       
   792 
       
   793 void RenderInline::updateDragState(bool dragOn)
       
   794 {
       
   795     RenderBoxModelObject::updateDragState(dragOn);
       
   796     if (continuation())
       
   797         continuation()->updateDragState(dragOn);
       
   798 }
       
   799 
       
   800 void RenderInline::childBecameNonInline(RenderObject* child)
       
   801 {
       
   802     // We have to split the parent flow.
       
   803     RenderBlock* newBox = containingBlock()->createAnonymousBlock();
       
   804     RenderBoxModelObject* oldContinuation = continuation();
       
   805     setContinuation(newBox);
       
   806     RenderObject* beforeChild = child->nextSibling();
       
   807     children()->removeChildNode(this, child);
       
   808     splitFlow(beforeChild, newBox, child, oldContinuation);
       
   809 }
       
   810 
       
   811 void RenderInline::updateHitTestResult(HitTestResult& result, const IntPoint& point)
       
   812 {
       
   813     if (result.innerNode())
       
   814         return;
       
   815 
       
   816     Node* n = node();
       
   817     IntPoint localPoint(point);
       
   818     if (n) {
       
   819         if (isInlineElementContinuation()) {
       
   820             // We're in the continuation of a split inline.  Adjust our local point to be in the coordinate space
       
   821             // of the principal renderer's containing block.  This will end up being the innerNonSharedNode.
       
   822             RenderBlock* firstBlock = n->renderer()->containingBlock();
       
   823             
       
   824             // Get our containing block.
       
   825             RenderBox* block = containingBlock();
       
   826             localPoint.move(block->x() - firstBlock->x(), block->y() - firstBlock->y());
       
   827         }
       
   828 
       
   829         result.setInnerNode(n);
       
   830         if (!result.innerNonSharedNode())
       
   831             result.setInnerNonSharedNode(n);
       
   832         result.setLocalPoint(localPoint);
       
   833     }
       
   834 }
       
   835 
       
   836 void RenderInline::dirtyLineBoxes(bool fullLayout)
       
   837 {
       
   838     if (fullLayout)
       
   839         m_lineBoxes.deleteLineBoxes(renderArena());
       
   840     else
       
   841         m_lineBoxes.dirtyLineBoxes();
       
   842 }
       
   843 
       
   844 InlineFlowBox* RenderInline::createInlineFlowBox() 
       
   845 {
       
   846     return new (renderArena()) InlineFlowBox(this);
       
   847 }
       
   848 
       
   849 InlineFlowBox* RenderInline::createAndAppendInlineFlowBox()
       
   850 {
       
   851     InlineFlowBox* flowBox = createInlineFlowBox();
       
   852     m_lineBoxes.appendLineBox(flowBox);
       
   853     return flowBox;
       
   854 }
       
   855 
       
   856 int RenderInline::lineHeight(bool firstLine, bool /*isRootLineBox*/) const
       
   857 {
       
   858     if (firstLine && document()->usesFirstLineRules()) {
       
   859         RenderStyle* s = style(firstLine);
       
   860         if (s != style())
       
   861             return s->computedLineHeight();
       
   862     }
       
   863     
       
   864     if (m_lineHeight == -1)
       
   865         m_lineHeight = style()->computedLineHeight();
       
   866     
       
   867     return m_lineHeight;
       
   868 }
       
   869 
       
   870 int RenderInline::verticalPositionFromCache(bool firstLine) const
       
   871 {
       
   872     if (firstLine) // We're only really a first-line style if the document actually uses first-line rules.
       
   873         firstLine = document()->usesFirstLineRules();
       
   874     int vpos = m_verticalPosition;
       
   875     if (m_verticalPosition == PositionUndefined || firstLine) {
       
   876         vpos = verticalPosition(firstLine);
       
   877         if (!firstLine)
       
   878             m_verticalPosition = vpos;
       
   879     }
       
   880     return vpos;
       
   881 }
       
   882 
       
   883 IntSize RenderInline::relativePositionedInlineOffset(const RenderBox* child) const
       
   884 {
       
   885     ASSERT(isRelPositioned());
       
   886     if (!isRelPositioned())
       
   887         return IntSize();
       
   888 
       
   889     // When we have an enclosing relpositioned inline, we need to add in the offset of the first line
       
   890     // box from the rest of the content, but only in the cases where we know we're positioned
       
   891     // relative to the inline itself.
       
   892 
       
   893     IntSize offset;
       
   894     int sx;
       
   895     int sy;
       
   896     if (firstLineBox()) {
       
   897         sx = firstLineBox()->x();
       
   898         sy = firstLineBox()->y();
       
   899     } else {
       
   900         sx = layer()->staticX();
       
   901         sy = layer()->staticY();
       
   902     }
       
   903 
       
   904     if (!child->style()->hasStaticX())
       
   905         offset.setWidth(sx);
       
   906     // This is not terribly intuitive, but we have to match other browsers.  Despite being a block display type inside
       
   907     // an inline, we still keep our x locked to the left of the relative positioned inline.  Arguably the correct
       
   908     // behavior would be to go flush left to the block that contains the inline, but that isn't what other browsers
       
   909     // do.
       
   910     else if (!child->style()->isOriginalDisplayInlineType())
       
   911         // Avoid adding in the left border/padding of the containing block twice.  Subtract it out.
       
   912         offset.setWidth(sx - (child->containingBlock()->borderLeft() + child->containingBlock()->paddingLeft()));
       
   913 
       
   914     if (!child->style()->hasStaticY())
       
   915         offset.setHeight(sy);
       
   916 
       
   917     return offset;
       
   918 }
       
   919 
       
   920 void RenderInline::imageChanged(WrappedImagePtr, const IntRect*)
       
   921 {
       
   922     if (!parent())
       
   923         return;
       
   924         
       
   925     // FIXME: We can do better.
       
   926     repaint();
       
   927 }
       
   928 
       
   929 void RenderInline::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty)
       
   930 {
       
   931     for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
       
   932         RootInlineBox* root = curr->root();
       
   933         int top = max(root->lineTop(), curr->y());
       
   934         int bottom = min(root->lineBottom(), curr->y() + curr->height());
       
   935         IntRect rect(tx + curr->x(), ty + top, curr->width(), bottom - top);
       
   936         if (!rect.isEmpty())
       
   937             rects.append(rect);
       
   938     }
       
   939 
       
   940     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
       
   941         if (!curr->isText() && !curr->isListMarker()) {
       
   942             FloatPoint pos(tx, ty);
       
   943             // FIXME: This doesn't work correctly with transforms.
       
   944             if (curr->hasLayer()) 
       
   945                 pos = curr->localToAbsolute();
       
   946             else if (curr->isBox())
       
   947                 pos.move(toRenderBox(curr)->x(), toRenderBox(curr)->y());
       
   948            curr->addFocusRingRects(rects, pos.x(), pos.y());
       
   949         }
       
   950     }
       
   951 
       
   952     if (continuation()) {
       
   953         if (continuation()->isInline())
       
   954             continuation()->addFocusRingRects(rects, 
       
   955                                               tx - containingBlock()->x() + continuation()->containingBlock()->x(),
       
   956                                               ty - containingBlock()->y() + continuation()->containingBlock()->y());
       
   957         else
       
   958             continuation()->addFocusRingRects(rects, 
       
   959                                               tx - containingBlock()->x() + toRenderBox(continuation())->x(),
       
   960                                               ty - containingBlock()->y() + toRenderBox(continuation())->y());
       
   961     }
       
   962 }
       
   963 
       
   964 void RenderInline::paintOutline(GraphicsContext* graphicsContext, int tx, int ty)
       
   965 {
       
   966     if (!hasOutline())
       
   967         return;
       
   968     
       
   969     RenderStyle* styleToUse = style();
       
   970     if (styleToUse->outlineStyleIsAuto() || hasOutlineAnnotation()) {
       
   971         int ow = styleToUse->outlineWidth();
       
   972         Color oc = styleToUse->visitedDependentColor(CSSPropertyOutlineColor);
       
   973 
       
   974         Vector<IntRect> focusRingRects;
       
   975         addFocusRingRects(focusRingRects, tx, ty);
       
   976         if (styleToUse->outlineStyleIsAuto())
       
   977             graphicsContext->drawFocusRing(focusRingRects, ow, styleToUse->outlineOffset(), oc);
       
   978         else
       
   979             addPDFURLRect(graphicsContext, unionRect(focusRingRects));
       
   980     }
       
   981 
       
   982     if (styleToUse->outlineStyleIsAuto() || styleToUse->outlineStyle() == BNONE)
       
   983         return;
       
   984 
       
   985     Vector<IntRect> rects;
       
   986 
       
   987     rects.append(IntRect());
       
   988     for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
       
   989         RootInlineBox* root = curr->root();
       
   990         int top = max(root->lineTop(), curr->y());
       
   991         int bottom = min(root->lineBottom(), curr->y() + curr->height());
       
   992         rects.append(IntRect(curr->x(), top, curr->width(), bottom - top));
       
   993     }
       
   994     rects.append(IntRect());
       
   995 
       
   996     for (unsigned i = 1; i < rects.size() - 1; i++)
       
   997         paintOutlineForLine(graphicsContext, tx, ty, rects.at(i - 1), rects.at(i), rects.at(i + 1));
       
   998 }
       
   999 
       
  1000 void RenderInline::paintOutlineForLine(GraphicsContext* graphicsContext, int tx, int ty,
       
  1001                                        const IntRect& lastline, const IntRect& thisline, const IntRect& nextline)
       
  1002 {
       
  1003     RenderStyle* styleToUse = style();
       
  1004     int ow = styleToUse->outlineWidth();
       
  1005     EBorderStyle os = styleToUse->outlineStyle();
       
  1006     Color oc = styleToUse->visitedDependentColor(CSSPropertyOutlineColor);
       
  1007 
       
  1008     int offset = style()->outlineOffset();
       
  1009 
       
  1010     int t = ty + thisline.y() - offset;
       
  1011     int l = tx + thisline.x() - offset;
       
  1012     int b = ty + thisline.bottom() + offset;
       
  1013     int r = tx + thisline.right() + offset;
       
  1014     
       
  1015     // left edge
       
  1016     drawLineForBoxSide(graphicsContext,
       
  1017                l - ow,
       
  1018                t - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.right() - 1) <= thisline.x() ? ow : 0),
       
  1019                l,
       
  1020                b + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.right() - 1) <= thisline.x() ? ow : 0),
       
  1021                BSLeft,
       
  1022                oc, os,
       
  1023                (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.right() - 1) <= thisline.x() ? ow : -ow),
       
  1024                (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.right() - 1) <= thisline.x() ? ow : -ow));
       
  1025     
       
  1026     // right edge
       
  1027     drawLineForBoxSide(graphicsContext,
       
  1028                r,
       
  1029                t - (lastline.isEmpty() || lastline.right() < thisline.right() || (thisline.right() - 1) <= lastline.x() ? ow : 0),
       
  1030                r + ow,
       
  1031                b + (nextline.isEmpty() || nextline.right() <= thisline.right() || (thisline.right() - 1) <= nextline.x() ? ow : 0),
       
  1032                BSRight,
       
  1033                oc, os,
       
  1034                (lastline.isEmpty() || lastline.right() < thisline.right() || (thisline.right() - 1) <= lastline.x() ? ow : -ow),
       
  1035                (nextline.isEmpty() || nextline.right() <= thisline.right() || (thisline.right() - 1) <= nextline.x() ? ow : -ow));
       
  1036     // upper edge
       
  1037     if (thisline.x() < lastline.x())
       
  1038         drawLineForBoxSide(graphicsContext,
       
  1039                    l - ow,
       
  1040                    t - ow,
       
  1041                    min(r+ow, (lastline.isEmpty() ? 1000000 : tx + lastline.x())),
       
  1042                    t ,
       
  1043                    BSTop, oc, os,
       
  1044                    ow,
       
  1045                    (!lastline.isEmpty() && tx + lastline.x() + 1 < r + ow) ? -ow : ow);
       
  1046     
       
  1047     if (lastline.right() < thisline.right())
       
  1048         drawLineForBoxSide(graphicsContext,
       
  1049                    max(lastline.isEmpty() ? -1000000 : tx + lastline.right(), l - ow),
       
  1050                    t - ow,
       
  1051                    r + ow,
       
  1052                    t ,
       
  1053                    BSTop, oc, os,
       
  1054                    (!lastline.isEmpty() && l - ow < tx + lastline.right()) ? -ow : ow,
       
  1055                    ow);
       
  1056     
       
  1057     // lower edge
       
  1058     if (thisline.x() < nextline.x())
       
  1059         drawLineForBoxSide(graphicsContext,
       
  1060                    l - ow,
       
  1061                    b,
       
  1062                    min(r + ow, !nextline.isEmpty() ? tx + nextline.x() + 1 : 1000000),
       
  1063                    b + ow,
       
  1064                    BSBottom, oc, os,
       
  1065                    ow,
       
  1066                    (!nextline.isEmpty() && tx + nextline.x() + 1 < r + ow) ? -ow : ow);
       
  1067     
       
  1068     if (nextline.right() < thisline.right())
       
  1069         drawLineForBoxSide(graphicsContext,
       
  1070                    max(!nextline.isEmpty() ? tx + nextline.right() : -1000000, l - ow),
       
  1071                    b,
       
  1072                    r + ow,
       
  1073                    b + ow,
       
  1074                    BSBottom, oc, os,
       
  1075                    (!nextline.isEmpty() && l - ow < tx + nextline.right()) ? -ow : ow,
       
  1076                    ow);
       
  1077 }
       
  1078 
       
  1079 #if ENABLE(DASHBOARD_SUPPORT)
       
  1080 void RenderInline::addDashboardRegions(Vector<DashboardRegionValue>& regions)
       
  1081 {
       
  1082     // Convert the style regions to absolute coordinates.
       
  1083     if (style()->visibility() != VISIBLE)
       
  1084         return;
       
  1085 
       
  1086     const Vector<StyleDashboardRegion>& styleRegions = style()->dashboardRegions();
       
  1087     unsigned i, count = styleRegions.size();
       
  1088     for (i = 0; i < count; i++) {
       
  1089         StyleDashboardRegion styleRegion = styleRegions[i];
       
  1090 
       
  1091         IntRect linesBoundingBox = this->linesBoundingBox();
       
  1092         int w = linesBoundingBox.width();
       
  1093         int h = linesBoundingBox.height();
       
  1094 
       
  1095         DashboardRegionValue region;
       
  1096         region.label = styleRegion.label;
       
  1097         region.bounds = IntRect(linesBoundingBox.x() + styleRegion.offset.left().value(),
       
  1098                                 linesBoundingBox.y() + styleRegion.offset.top().value(),
       
  1099                                 w - styleRegion.offset.left().value() - styleRegion.offset.right().value(),
       
  1100                                 h - styleRegion.offset.top().value() - styleRegion.offset.bottom().value());
       
  1101         region.type = styleRegion.type;
       
  1102 
       
  1103         RenderObject* container = containingBlock();
       
  1104         if (!container)
       
  1105             container = this;
       
  1106 
       
  1107         region.clip = region.bounds;
       
  1108         container->computeAbsoluteRepaintRect(region.clip);
       
  1109         if (region.clip.height() < 0) {
       
  1110             region.clip.setHeight(0);
       
  1111             region.clip.setWidth(0);
       
  1112         }
       
  1113 
       
  1114         FloatPoint absPos = container->localToAbsolute();
       
  1115         region.bounds.setX(absPos.x() + region.bounds.x());
       
  1116         region.bounds.setY(absPos.y() + region.bounds.y());
       
  1117 
       
  1118         if (frame()) {
       
  1119             float pageScaleFactor = frame()->page()->chrome()->scaleFactor();
       
  1120             if (pageScaleFactor != 1.0f) {
       
  1121                 region.bounds.scale(pageScaleFactor);
       
  1122                 region.clip.scale(pageScaleFactor);
       
  1123             }
       
  1124         }
       
  1125 
       
  1126         regions.append(region);
       
  1127     }
       
  1128 }
       
  1129 #endif
       
  1130 
       
  1131 } // namespace WebCore