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