Home | History | Annotate | Download | only in rendering
      1 /*
      2  * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
      3  *
      4  * This library is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU Library General Public
      6  * License as published by the Free Software Foundation; either
      7  * version 2 of the License, or (at your option) any later version.
      8  *
      9  * This library is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  * Library General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU Library General Public License
     15  * along with this library; see the file COPYING.LIB.  If not, write to
     16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     17  * Boston, MA 02110-1301, USA.
     18  */
     19 
     20 #include "config.h"
     21 #include "InlineFlowBox.h"
     22 
     23 #include "CachedImage.h"
     24 #include "Document.h"
     25 #include "EllipsisBox.h"
     26 #include "GraphicsContext.h"
     27 #include "InlineTextBox.h"
     28 #include "HitTestResult.h"
     29 #include "RootInlineBox.h"
     30 #include "RenderBlock.h"
     31 #include "RenderInline.h"
     32 #include "RenderLayer.h"
     33 #include "RenderListMarker.h"
     34 #include "RenderTableCell.h"
     35 #include "RootInlineBox.h"
     36 #include "Text.h"
     37 
     38 #include <math.h>
     39 
     40 using namespace std;
     41 
     42 namespace WebCore {
     43 
     44 #ifndef NDEBUG
     45 
     46 InlineFlowBox::~InlineFlowBox()
     47 {
     48     if (!m_hasBadChildList)
     49         for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
     50             child->setHasBadParent();
     51 }
     52 
     53 #endif
     54 
     55 int InlineFlowBox::getFlowSpacingWidth()
     56 {
     57     int totWidth = marginBorderPaddingLeft() + marginBorderPaddingRight();
     58     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
     59         if (curr->isInlineFlowBox())
     60             totWidth += static_cast<InlineFlowBox*>(curr)->getFlowSpacingWidth();
     61     }
     62     return totWidth;
     63 }
     64 
     65 void InlineFlowBox::addToLine(InlineBox* child)
     66 {
     67     ASSERT(!child->parent());
     68     ASSERT(!child->nextOnLine());
     69     ASSERT(!child->prevOnLine());
     70     checkConsistency();
     71 
     72     child->setParent(this);
     73     if (!m_firstChild) {
     74         m_firstChild = child;
     75         m_lastChild = child;
     76     } else {
     77         m_lastChild->setNextOnLine(child);
     78         child->setPrevOnLine(m_lastChild);
     79         m_lastChild = child;
     80     }
     81     child->setFirstLineStyleBit(m_firstLine);
     82     if (child->isText())
     83         m_hasTextChildren = true;
     84 
     85     checkConsistency();
     86 }
     87 
     88 void InlineFlowBox::removeChild(InlineBox* child)
     89 {
     90     checkConsistency();
     91 
     92     if (!m_dirty)
     93         dirtyLineBoxes();
     94 
     95     root()->childRemoved(child);
     96 
     97     if (child == m_firstChild)
     98         m_firstChild = child->nextOnLine();
     99     if (child == m_lastChild)
    100         m_lastChild = child->prevOnLine();
    101     if (child->nextOnLine())
    102         child->nextOnLine()->setPrevOnLine(child->prevOnLine());
    103     if (child->prevOnLine())
    104         child->prevOnLine()->setNextOnLine(child->nextOnLine());
    105 
    106     child->setParent(0);
    107 
    108     checkConsistency();
    109 }
    110 
    111 void InlineFlowBox::deleteLine(RenderArena* arena)
    112 {
    113     InlineBox* child = firstChild();
    114     InlineBox* next = 0;
    115     while (child) {
    116         ASSERT(this == child->parent());
    117         next = child->nextOnLine();
    118 #ifndef NDEBUG
    119         child->setParent(0);
    120 #endif
    121         child->deleteLine(arena);
    122         child = next;
    123     }
    124 #ifndef NDEBUG
    125     m_firstChild = 0;
    126     m_lastChild = 0;
    127 #endif
    128 
    129     removeLineBoxFromRenderObject();
    130     destroy(arena);
    131 }
    132 
    133 void InlineFlowBox::removeLineBoxFromRenderObject()
    134 {
    135     toRenderInline(renderer())->lineBoxes()->removeLineBox(this);
    136 }
    137 
    138 void InlineFlowBox::extractLine()
    139 {
    140     if (!m_extracted)
    141         extractLineBoxFromRenderObject();
    142     for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
    143         child->extractLine();
    144 }
    145 
    146 void InlineFlowBox::extractLineBoxFromRenderObject()
    147 {
    148     toRenderInline(renderer())->lineBoxes()->extractLineBox(this);
    149 }
    150 
    151 void InlineFlowBox::attachLine()
    152 {
    153     if (m_extracted)
    154         attachLineBoxToRenderObject();
    155     for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
    156         child->attachLine();
    157 }
    158 
    159 void InlineFlowBox::attachLineBoxToRenderObject()
    160 {
    161     toRenderInline(renderer())->lineBoxes()->attachLineBox(this);
    162 }
    163 
    164 void InlineFlowBox::adjustPosition(int dx, int dy)
    165 {
    166     InlineRunBox::adjustPosition(dx, dy);
    167     for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
    168         child->adjustPosition(dx, dy);
    169     if (m_overflow)
    170         m_overflow->move(dx, dy);
    171 }
    172 
    173 RenderLineBoxList* InlineFlowBox::rendererLineBoxes() const
    174 {
    175     return toRenderInline(renderer())->lineBoxes();
    176 }
    177 
    178 bool InlineFlowBox::onEndChain(RenderObject* endObject)
    179 {
    180     if (!endObject)
    181         return false;
    182 
    183     if (endObject == renderer())
    184         return true;
    185 
    186     RenderObject* curr = endObject;
    187     RenderObject* parent = curr->parent();
    188     while (parent && !parent->isRenderBlock()) {
    189         if (parent->lastChild() != curr || parent == renderer())
    190             return false;
    191 
    192         curr = parent;
    193         parent = curr->parent();
    194     }
    195 
    196     return true;
    197 }
    198 
    199 void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, RenderObject* endObject)
    200 {
    201     // All boxes start off open.  They will not apply any margins/border/padding on
    202     // any side.
    203     bool includeLeftEdge = false;
    204     bool includeRightEdge = false;
    205 
    206     // The root inline box never has borders/margins/padding.
    207     if (parent()) {
    208         bool ltr = renderer()->style()->direction() == LTR;
    209 
    210         // Check to see if all initial lines are unconstructed.  If so, then
    211         // we know the inline began on this line (unless we are a continuation).
    212         RenderLineBoxList* lineBoxList = rendererLineBoxes();
    213         if (!lineBoxList->firstLineBox()->isConstructed() && !renderer()->isInlineContinuation()) {
    214             if (ltr && lineBoxList->firstLineBox() == this)
    215                 includeLeftEdge = true;
    216             else if (!ltr && lineBoxList->lastLineBox() == this)
    217                 includeRightEdge = true;
    218         }
    219 
    220         // In order to determine if the inline ends on this line, we check three things:
    221         // (1) If we are the last line and we don't have a continuation(), then we can
    222         // close up.
    223         // (2) If the last line box for the flow has an object following it on the line (ltr,
    224         // reverse for rtl), then the inline has closed.
    225         // (3) The line may end on the inline.  If we are the last child (climbing up
    226         // the end object's chain), then we just closed as well.
    227         if (!lineBoxList->lastLineBox()->isConstructed()) {
    228             RenderInline* inlineFlow = toRenderInline(renderer());
    229             if (ltr) {
    230                 if (!nextLineBox() &&
    231                     ((lastLine && !inlineFlow->continuation()) || nextOnLineExists() || onEndChain(endObject)))
    232                     includeRightEdge = true;
    233             } else {
    234                 if ((!prevLineBox() || prevLineBox()->isConstructed()) &&
    235                     ((lastLine && !inlineFlow->continuation()) || prevOnLineExists() || onEndChain(endObject)))
    236                     includeLeftEdge = true;
    237             }
    238         }
    239     }
    240 
    241     setEdges(includeLeftEdge, includeRightEdge);
    242 
    243     // Recur into our children.
    244     for (InlineBox* currChild = firstChild(); currChild; currChild = currChild->nextOnLine()) {
    245         if (currChild->isInlineFlowBox()) {
    246             InlineFlowBox* currFlow = static_cast<InlineFlowBox*>(currChild);
    247             currFlow->determineSpacingForFlowBoxes(lastLine, endObject);
    248         }
    249     }
    250 }
    251 
    252 int InlineFlowBox::placeBoxesHorizontally(int xPos, bool& needsWordSpacing)
    253 {
    254     // Set our x position.
    255     setX(xPos);
    256 
    257     int leftLayoutOverflow = xPos;
    258     int rightLayoutOverflow = xPos;
    259     int leftVisualOverflow = xPos;
    260     int rightVisualOverflow = xPos;
    261 
    262     int boxShadowLeft;
    263     int boxShadowRight;
    264     renderer()->style(m_firstLine)->getBoxShadowHorizontalExtent(boxShadowLeft, boxShadowRight);
    265 
    266     leftVisualOverflow = min(xPos + boxShadowLeft, leftVisualOverflow);
    267 
    268     int startX = xPos;
    269     xPos += borderLeft() + paddingLeft();
    270 
    271     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
    272         if (curr->renderer()->isText()) {
    273             InlineTextBox* text = static_cast<InlineTextBox*>(curr);
    274             RenderText* rt = toRenderText(text->renderer());
    275             if (rt->textLength()) {
    276                 if (needsWordSpacing && isSpaceOrNewline(rt->characters()[text->start()]))
    277                     xPos += rt->style(m_firstLine)->font().wordSpacing();
    278                 needsWordSpacing = !isSpaceOrNewline(rt->characters()[text->end()]);
    279             }
    280             text->setX(xPos);
    281 
    282             int strokeOverflow = static_cast<int>(ceilf(rt->style()->textStrokeWidth() / 2.0f));
    283 
    284             // If letter-spacing is negative, we should factor that into right layout overflow. (Even in RTL, letter-spacing is
    285             // applied to the right, so this is not an issue with left overflow.
    286             int letterSpacing = min(0, (int)rt->style(m_firstLine)->font().letterSpacing());
    287             rightLayoutOverflow = max(xPos + text->width() - letterSpacing, rightLayoutOverflow);
    288 
    289             int leftGlyphOverflow = -strokeOverflow;
    290             int rightGlyphOverflow = strokeOverflow - letterSpacing;
    291 
    292             int childOverflowLeft = leftGlyphOverflow;
    293             int childOverflowRight = rightGlyphOverflow;
    294             for (ShadowData* shadow = rt->style()->textShadow(); shadow; shadow = shadow->next) {
    295                 childOverflowLeft = min(childOverflowLeft, shadow->x - shadow->blur + leftGlyphOverflow);
    296                 childOverflowRight = max(childOverflowRight, shadow->x + shadow->blur + rightGlyphOverflow);
    297             }
    298 
    299             leftVisualOverflow = min(xPos + childOverflowLeft, leftVisualOverflow);
    300             rightVisualOverflow = max(xPos + text->width() + childOverflowRight, rightVisualOverflow);
    301 
    302             xPos += text->width();
    303         } else {
    304             if (curr->renderer()->isPositioned()) {
    305                 if (curr->renderer()->parent()->style()->direction() == LTR)
    306                     curr->setX(xPos);
    307                 else
    308                     // Our offset that we cache needs to be from the edge of the right border box and
    309                     // not the left border box.  We have to subtract |x| from the width of the block
    310                     // (which can be obtained from the root line box).
    311                     curr->setX(root()->block()->width() - xPos);
    312                 continue; // The positioned object has no effect on the width.
    313             }
    314             if (curr->renderer()->isRenderInline()) {
    315                 InlineFlowBox* flow = static_cast<InlineFlowBox*>(curr);
    316                 xPos += flow->marginLeft();
    317                 xPos = flow->placeBoxesHorizontally(xPos, needsWordSpacing);
    318                 xPos += flow->marginRight();
    319                 leftLayoutOverflow = min(leftLayoutOverflow, flow->leftLayoutOverflow());
    320                 rightLayoutOverflow = max(rightLayoutOverflow, flow->rightLayoutOverflow());
    321                 leftVisualOverflow = min(leftVisualOverflow, flow->leftVisualOverflow());
    322                 rightVisualOverflow = max(rightVisualOverflow, flow->rightVisualOverflow());
    323             } else if (!curr->renderer()->isListMarker() || toRenderListMarker(curr->renderer())->isInside()) {
    324                 xPos += curr->boxModelObject()->marginLeft();
    325                 curr->setX(xPos);
    326 
    327                 RenderBox* box = toRenderBox(curr->renderer());
    328                 int childLeftOverflow = box->hasOverflowClip() ? 0 : box->leftLayoutOverflow();
    329                 int childRightOverflow = box->hasOverflowClip() ? curr->width() : box->rightLayoutOverflow();
    330 
    331                 leftLayoutOverflow = min(xPos + childLeftOverflow, leftLayoutOverflow);
    332                 rightLayoutOverflow = max(xPos + childRightOverflow, rightLayoutOverflow);
    333 
    334                 leftVisualOverflow = min(xPos + box->leftVisualOverflow(), leftVisualOverflow);
    335                 rightVisualOverflow = max(xPos + box->rightVisualOverflow(), rightVisualOverflow);
    336 
    337                 xPos += curr->width() + curr->boxModelObject()->marginRight();
    338             }
    339         }
    340     }
    341 
    342     xPos += borderRight() + paddingRight();
    343     setWidth(xPos - startX);
    344     rightVisualOverflow = max(x() + width() + boxShadowRight, rightVisualOverflow);
    345     rightLayoutOverflow = max(x() + width(), rightLayoutOverflow);
    346 
    347     setHorizontalOverflowPositions(leftLayoutOverflow, rightLayoutOverflow, leftVisualOverflow, rightVisualOverflow);
    348     return xPos;
    349 }
    350 
    351 void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent,
    352                                               int maxPositionTop, int maxPositionBottom)
    353 {
    354     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
    355         // The computed lineheight needs to be extended for the
    356         // positioned elements
    357         if (curr->renderer()->isPositioned())
    358             continue; // Positioned placeholders don't affect calculations.
    359         if (curr->y() == PositionTop || curr->y() == PositionBottom) {
    360             int lineHeight = curr->lineHeight(false);
    361             if (curr->y() == PositionTop) {
    362                 if (maxAscent + maxDescent < lineHeight)
    363                     maxDescent = lineHeight - maxAscent;
    364             }
    365             else {
    366                 if (maxAscent + maxDescent < lineHeight)
    367                     maxAscent = lineHeight - maxDescent;
    368             }
    369 
    370             if (maxAscent + maxDescent >= max(maxPositionTop, maxPositionBottom))
    371                 break;
    372         }
    373 
    374         if (curr->isInlineFlowBox())
    375             static_cast<InlineFlowBox*>(curr)->adjustMaxAscentAndDescent(maxAscent, maxDescent, maxPositionTop, maxPositionBottom);
    376     }
    377 }
    378 
    379 static int verticalPositionForBox(InlineBox* curr, bool firstLine)
    380 {
    381     if (curr->renderer()->isText())
    382         return curr->parent()->y();
    383     if (curr->renderer()->isBox())
    384         return toRenderBox(curr->renderer())->verticalPosition(firstLine);
    385     return toRenderInline(curr->renderer())->verticalPositionFromCache(firstLine);
    386 }
    387 
    388 void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositionBottom,
    389                                              int& maxAscent, int& maxDescent, bool strictMode)
    390 {
    391     if (isRootInlineBox()) {
    392         // Examine our root box.
    393         int height = lineHeight(true);
    394         int baseline = baselinePosition(true);
    395         if (hasTextChildren() || strictMode) {
    396             int ascent = baseline;
    397             int descent = height - ascent;
    398             if (maxAscent < ascent)
    399                 maxAscent = ascent;
    400             if (maxDescent < descent)
    401                 maxDescent = descent;
    402         }
    403     }
    404 
    405     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
    406         if (curr->renderer()->isPositioned())
    407             continue; // Positioned placeholders don't affect calculations.
    408 
    409         bool isInlineFlow = curr->isInlineFlowBox();
    410 
    411         int lineHeight;
    412         int baseline;
    413         Vector<const SimpleFontData*> usedFonts;
    414         if (curr->isInlineTextBox())
    415             static_cast<InlineTextBox*>(curr)->takeFallbackFonts(usedFonts);
    416 
    417         if (!usedFonts.isEmpty()) {
    418             usedFonts.append(curr->renderer()->style(m_firstLine)->font().primaryFont());
    419             Length parentLineHeight = curr->renderer()->parent()->style()->lineHeight();
    420             if (parentLineHeight.isNegative()) {
    421                 int baselineToBottom = 0;
    422                 baseline = 0;
    423                 for (size_t i = 0; i < usedFonts.size(); ++i) {
    424                     int halfLeading = (usedFonts[i]->lineSpacing() - usedFonts[i]->ascent() - usedFonts[i]->descent()) / 2;
    425                     baseline = max(baseline, halfLeading + usedFonts[i]->ascent());
    426                     baselineToBottom = max(baselineToBottom, usedFonts[i]->lineSpacing() - usedFonts[i]->ascent() - usedFonts[i]->descent() - halfLeading);
    427                 }
    428                 lineHeight = baseline + baselineToBottom;
    429             } else if (parentLineHeight.isPercent()) {
    430                 lineHeight = parentLineHeight.calcMinValue(curr->renderer()->style()->fontSize());
    431                 baseline = 0;
    432                 for (size_t i = 0; i < usedFonts.size(); ++i) {
    433                     int halfLeading = (lineHeight - usedFonts[i]->ascent() - usedFonts[i]->descent()) / 2;
    434                     baseline = max(baseline, halfLeading + usedFonts[i]->ascent());
    435                 }
    436             } else {
    437                 lineHeight = parentLineHeight.value();
    438                 baseline = 0;
    439                 for (size_t i = 0; i < usedFonts.size(); ++i) {
    440                     int halfLeading = (lineHeight - usedFonts[i]->ascent() - usedFonts[i]->descent()) / 2;
    441                     baseline = max(baseline, halfLeading + usedFonts[i]->ascent());
    442                 }
    443             }
    444         } else {
    445             lineHeight = curr->lineHeight(false);
    446             baseline = curr->baselinePosition(false);
    447         }
    448 
    449         curr->setY(verticalPositionForBox(curr, m_firstLine));
    450         if (curr->y() == PositionTop) {
    451             if (maxPositionTop < lineHeight)
    452                 maxPositionTop = lineHeight;
    453         } else if (curr->y() == PositionBottom) {
    454             if (maxPositionBottom < lineHeight)
    455                 maxPositionBottom = lineHeight;
    456         } else if ((!isInlineFlow || static_cast<InlineFlowBox*>(curr)->hasTextChildren()) || curr->boxModelObject()->hasHorizontalBordersOrPadding() || strictMode) {
    457             int ascent = baseline - curr->y();
    458             int descent = lineHeight - ascent;
    459             if (maxAscent < ascent)
    460                 maxAscent = ascent;
    461             if (maxDescent < descent)
    462                 maxDescent = descent;
    463         }
    464 
    465         if (curr->isInlineFlowBox())
    466             static_cast<InlineFlowBox*>(curr)->computeLogicalBoxHeights(maxPositionTop, maxPositionBottom, maxAscent, maxDescent, strictMode);
    467     }
    468 }
    469 
    470 void InlineFlowBox::placeBoxesVertically(int yPos, int maxHeight, int maxAscent, bool strictMode, int& selectionTop, int& selectionBottom)
    471 {
    472     if (isRootInlineBox())
    473         setY(yPos + maxAscent - baselinePosition(true)); // Place our root box.
    474 
    475     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
    476         if (curr->renderer()->isPositioned())
    477             continue; // Positioned placeholders don't affect calculations.
    478 
    479         // Adjust boxes to use their real box y/height and not the logical height (as dictated by
    480         // line-height).
    481         bool isInlineFlow = curr->isInlineFlowBox();
    482         if (isInlineFlow)
    483             static_cast<InlineFlowBox*>(curr)->placeBoxesVertically(yPos, maxHeight, maxAscent, strictMode, selectionTop, selectionBottom);
    484 
    485         bool childAffectsTopBottomPos = true;
    486         if (curr->y() == PositionTop)
    487             curr->setY(yPos);
    488         else if (curr->y() == PositionBottom)
    489             curr->setY(yPos + maxHeight - curr->lineHeight(false));
    490         else {
    491             if ((isInlineFlow && !static_cast<InlineFlowBox*>(curr)->hasTextChildren()) && !curr->boxModelObject()->hasHorizontalBordersOrPadding() && !strictMode)
    492                 childAffectsTopBottomPos = false;
    493             int posAdjust = maxAscent - curr->baselinePosition(false);
    494             curr->setY(curr->y() + yPos + posAdjust);
    495         }
    496 
    497         int newY = curr->y();
    498         if (curr->isText() || curr->isInlineFlowBox()) {
    499             const Font& font = curr->renderer()->style(m_firstLine)->font();
    500             newY += curr->baselinePosition(false) - font.ascent();
    501             if (curr->isInlineFlowBox())
    502                 newY -= curr->boxModelObject()->borderTop() + curr->boxModelObject()->paddingTop();
    503         } else if (!curr->renderer()->isBR()) {
    504             RenderBox* box = toRenderBox(curr->renderer());
    505             newY += box->marginTop();
    506         }
    507 
    508         curr->setY(newY);
    509 
    510         if (childAffectsTopBottomPos) {
    511             int boxHeight = curr->height();
    512             selectionTop = min(selectionTop, newY);
    513             selectionBottom = max(selectionBottom, newY + boxHeight);
    514         }
    515     }
    516 
    517     if (isRootInlineBox()) {
    518         const Font& font = renderer()->style(m_firstLine)->font();
    519         setY(y() + baselinePosition(true) - font.ascent());
    520         if (hasTextChildren() || strictMode) {
    521             selectionTop = min(selectionTop, y());
    522             selectionBottom = max(selectionBottom, y() + height());
    523         }
    524     }
    525 }
    526 
    527 void InlineFlowBox::computeVerticalOverflow(int lineTop, int lineBottom, bool strictMode)
    528 {
    529     int boxHeight = height();
    530 
    531     // Any spillage outside of the line top and bottom is not considered overflow.  We just ignore this, since it only happens
    532     // from the "your ascent/descent don't affect the line" quirk.
    533     int topOverflow = max(y(), lineTop);
    534     int bottomOverflow = min(y() + boxHeight, lineBottom);
    535 
    536     int topLayoutOverflow = topOverflow;
    537     int bottomLayoutOverflow = bottomOverflow;
    538 
    539     int topVisualOverflow = topOverflow;
    540     int bottomVisualOverflow = bottomOverflow;
    541 
    542     // box-shadow on root line boxes is applying to the block and not to the lines.
    543     if (parent()) {
    544         int boxShadowTop;
    545         int boxShadowBottom;
    546         renderer()->style(m_firstLine)->getBoxShadowVerticalExtent(boxShadowTop, boxShadowBottom);
    547 
    548         topVisualOverflow = min(y() + boxShadowTop, topVisualOverflow);
    549         bottomVisualOverflow = max(y() + boxHeight + boxShadowBottom, bottomVisualOverflow);
    550     }
    551 
    552     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
    553         if (curr->renderer()->isPositioned())
    554             continue; // Positioned placeholders don't affect calculations.
    555 
    556         if (curr->renderer()->isText()) {
    557             InlineTextBox* text = static_cast<InlineTextBox*>(curr);
    558             RenderText* rt = toRenderText(text->renderer());
    559             if (rt->isBR())
    560                 continue;
    561 
    562             int strokeOverflow = static_cast<int>(ceilf(rt->style()->textStrokeWidth() / 2.0f));
    563 
    564             int topGlyphOverflow = -strokeOverflow;
    565             int bottomGlyphOverflow = strokeOverflow;
    566 
    567             int childOverflowTop = topGlyphOverflow;
    568             int childOverflowBottom = bottomGlyphOverflow;
    569             for (ShadowData* shadow = rt->style()->textShadow(); shadow; shadow = shadow->next) {
    570                 childOverflowTop = min(childOverflowTop, shadow->y - shadow->blur + topGlyphOverflow);
    571                 childOverflowBottom = max(childOverflowBottom, shadow->y + shadow->blur + bottomGlyphOverflow);
    572             }
    573 
    574             topVisualOverflow = min(curr->y() + childOverflowTop, topVisualOverflow);
    575             bottomVisualOverflow = max(curr->y() + text->height() + childOverflowBottom, bottomVisualOverflow);
    576         } else  if (curr->renderer()->isRenderInline()) {
    577             InlineFlowBox* flow = static_cast<InlineFlowBox*>(curr);
    578             flow->computeVerticalOverflow(lineTop, lineBottom, strictMode);
    579             topLayoutOverflow = min(topLayoutOverflow, flow->topLayoutOverflow());
    580             bottomLayoutOverflow = max(bottomLayoutOverflow, flow->bottomLayoutOverflow());
    581             topVisualOverflow = min(topVisualOverflow, flow->topVisualOverflow());
    582             bottomVisualOverflow = max(bottomVisualOverflow, flow->bottomVisualOverflow());
    583         } else if (!curr->boxModelObject()->hasSelfPaintingLayer()){
    584             // Only include overflow from replaced inlines if they do not paint themselves.
    585             RenderBox* box = toRenderBox(curr->renderer());
    586             int boxY = curr->y();
    587             int childTopOverflow = box->hasOverflowClip() ? 0 : box->topLayoutOverflow();
    588             int childBottomOverflow = box->hasOverflowClip() ? curr->height() : box->bottomLayoutOverflow();
    589             topLayoutOverflow = min(boxY + childTopOverflow, topLayoutOverflow);
    590             bottomLayoutOverflow = max(boxY + childBottomOverflow, bottomLayoutOverflow);
    591             topVisualOverflow = min(boxY + box->topVisualOverflow(), topVisualOverflow);
    592             bottomVisualOverflow = max(boxY + box->bottomVisualOverflow(), bottomVisualOverflow);
    593         }
    594     }
    595 
    596     setVerticalOverflowPositions(topLayoutOverflow, bottomLayoutOverflow, topVisualOverflow, bottomVisualOverflow, boxHeight);
    597 }
    598 
    599 bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty)
    600 {
    601     IntRect overflowRect(visibleOverflowRect());
    602     overflowRect.move(tx, ty);
    603     if (!overflowRect.contains(x, y))
    604         return false;
    605 
    606     // Check children first.
    607     for (InlineBox* curr = lastChild(); curr; curr = curr->prevOnLine()) {
    608         if ((curr->renderer()->isText() || !curr->boxModelObject()->hasSelfPaintingLayer()) && curr->nodeAtPoint(request, result, x, y, tx, ty)) {
    609             renderer()->updateHitTestResult(result, IntPoint(x - tx, y - ty));
    610             return true;
    611         }
    612     }
    613 
    614     // Now check ourselves.
    615     IntRect rect(tx + m_x, ty + m_y, m_width, height());
    616     if (visibleToHitTesting() && rect.contains(x, y)) {
    617         renderer()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); // Don't add in m_x or m_y here, we want coords in the containing block's space.
    618         return true;
    619     }
    620 
    621     return false;
    622 }
    623 
    624 void InlineFlowBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
    625 {
    626     IntRect overflowRect(visibleOverflowRect());
    627     overflowRect.inflate(renderer()->maximalOutlineSize(paintInfo.phase));
    628     overflowRect.move(tx, ty);
    629 
    630     if (!paintInfo.rect.intersects(overflowRect))
    631         return;
    632 
    633     if (paintInfo.phase != PaintPhaseChildOutlines) {
    634         if (paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) {
    635             // Add ourselves to the paint info struct's list of inlines that need to paint their
    636             // outlines.
    637             if (renderer()->style()->visibility() == VISIBLE && renderer()->hasOutline() && !isRootInlineBox()) {
    638                 RenderInline* inlineFlow = toRenderInline(renderer());
    639 
    640                 RenderBlock* cb = 0;
    641                 bool containingBlockPaintsContinuationOutline = inlineFlow->continuation() || inlineFlow->isInlineContinuation();
    642                 if (containingBlockPaintsContinuationOutline) {
    643                     cb = renderer()->containingBlock()->containingBlock();
    644 
    645                     for (RenderBoxModelObject* box = boxModelObject(); box != cb; box = box->parent()->enclosingBoxModelObject()) {
    646                         if (box->hasSelfPaintingLayer()) {
    647                             containingBlockPaintsContinuationOutline = false;
    648                             break;
    649                         }
    650                     }
    651                 }
    652 
    653                 if (containingBlockPaintsContinuationOutline) {
    654                     // Add ourselves to the containing block of the entire continuation so that it can
    655                     // paint us atomically.
    656                     cb->addContinuationWithOutline(toRenderInline(renderer()->node()->renderer()));
    657                 } else if (!inlineFlow->isInlineContinuation())
    658                     paintInfo.outlineObjects->add(inlineFlow);
    659             }
    660         } else if (paintInfo.phase == PaintPhaseMask) {
    661             paintMask(paintInfo, tx, ty);
    662             return;
    663         } else {
    664             // 1. Paint our background, border and box-shadow.
    665             paintBoxDecorations(paintInfo, tx, ty);
    666 
    667             // 2. Paint our underline and overline.
    668             paintTextDecorations(paintInfo, tx, ty, false);
    669         }
    670     }
    671 
    672     if (paintInfo.phase == PaintPhaseMask)
    673         return;
    674 
    675     PaintPhase paintPhase = paintInfo.phase == PaintPhaseChildOutlines ? PaintPhaseOutline : paintInfo.phase;
    676     RenderObject::PaintInfo childInfo(paintInfo);
    677     childInfo.phase = paintPhase;
    678     childInfo.paintingRoot = renderer()->paintingRootForChildren(paintInfo);
    679 
    680     // 3. Paint our children.
    681     if (paintPhase != PaintPhaseSelfOutline) {
    682         for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
    683             if (curr->renderer()->isText() || !curr->boxModelObject()->hasSelfPaintingLayer())
    684                 curr->paint(childInfo, tx, ty);
    685         }
    686     }
    687 
    688     // 4. Paint our strike-through
    689     if (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)
    690         paintTextDecorations(paintInfo, tx, ty, true);
    691 }
    692 
    693 void InlineFlowBox::paintFillLayers(const RenderObject::PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int _tx, int _ty, int w, int h, CompositeOperator op)
    694 {
    695     if (!fillLayer)
    696         return;
    697     paintFillLayers(paintInfo, c, fillLayer->next(), _tx, _ty, w, h, op);
    698     paintFillLayer(paintInfo, c, fillLayer, _tx, _ty, w, h, op);
    699 }
    700 
    701 void InlineFlowBox::paintFillLayer(const RenderObject::PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int w, int h, CompositeOperator op)
    702 {
    703     StyleImage* img = fillLayer->image();
    704     bool hasFillImage = img && img->canRender(renderer()->style()->effectiveZoom());
    705     if ((!hasFillImage && !renderer()->style()->hasBorderRadius()) || (!prevLineBox() && !nextLineBox()) || !parent())
    706         boxModelObject()->paintFillLayerExtended(paintInfo, c, fillLayer, tx, ty, w, h, this, op);
    707     else {
    708         // We have a fill image that spans multiple lines.
    709         // We need to adjust _tx and _ty by the width of all previous lines.
    710         // Think of background painting on inlines as though you had one long line, a single continuous
    711         // strip.  Even though that strip has been broken up across multiple lines, you still paint it
    712         // as though you had one single line.  This means each line has to pick up the background where
    713         // the previous line left off.
    714         // FIXME: What the heck do we do with RTL here? The math we're using is obviously not right,
    715         // but it isn't even clear how this should work at all.
    716         int xOffsetOnLine = 0;
    717         for (InlineRunBox* curr = prevLineBox(); curr; curr = curr->prevLineBox())
    718             xOffsetOnLine += curr->width();
    719         int startX = tx - xOffsetOnLine;
    720         int totalWidth = xOffsetOnLine;
    721         for (InlineRunBox* curr = this; curr; curr = curr->nextLineBox())
    722             totalWidth += curr->width();
    723         paintInfo.context->save();
    724         paintInfo.context->clip(IntRect(tx, ty, width(), height()));
    725         boxModelObject()->paintFillLayerExtended(paintInfo, c, fillLayer, startX, ty, totalWidth, h, this, op);
    726         paintInfo.context->restore();
    727     }
    728 }
    729 
    730 void InlineFlowBox::paintBoxShadow(GraphicsContext* context, RenderStyle* s, ShadowStyle shadowStyle, int tx, int ty, int w, int h)
    731 {
    732     if ((!prevLineBox() && !nextLineBox()) || !parent())
    733         boxModelObject()->paintBoxShadow(context, tx, ty, w, h, s, shadowStyle);
    734     else {
    735         // FIXME: We can do better here in the multi-line case. We want to push a clip so that the shadow doesn't
    736         // protrude incorrectly at the edges, and we want to possibly include shadows cast from the previous/following lines
    737         boxModelObject()->paintBoxShadow(context, tx, ty, w, h, s, shadowStyle, includeLeftEdge(), includeRightEdge());
    738     }
    739 }
    740 
    741 void InlineFlowBox::paintBoxDecorations(RenderObject::PaintInfo& paintInfo, int tx, int ty)
    742 {
    743     if (!renderer()->shouldPaintWithinRoot(paintInfo) || renderer()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseForeground)
    744         return;
    745 
    746     int x = m_x;
    747     int y = m_y;
    748     int w = width();
    749     int h = height();
    750 
    751     // Constrain our background/border painting to the line top and bottom if necessary.
    752     bool strictMode = renderer()->document()->inStrictMode();
    753     if (!hasTextChildren() && !strictMode) {
    754         RootInlineBox* rootBox = root();
    755         int bottom = min(rootBox->lineBottom(), y + h);
    756         y = max(rootBox->lineTop(), y);
    757         h = bottom - y;
    758     }
    759 
    760     // Move x/y to our coordinates.
    761     tx += x;
    762     ty += y;
    763 
    764     GraphicsContext* context = paintInfo.context;
    765 
    766     // You can use p::first-line to specify a background. If so, the root line boxes for
    767     // a line may actually have to paint a background.
    768     RenderStyle* styleToUse = renderer()->style(m_firstLine);
    769     if ((!parent() && m_firstLine && styleToUse != renderer()->style()) || (parent() && renderer()->hasBoxDecorations())) {
    770         // Shadow comes first and is behind the background and border.
    771         if (styleToUse->boxShadow())
    772             paintBoxShadow(context, styleToUse, Normal, tx, ty, w, h);
    773 
    774         Color c = styleToUse->backgroundColor();
    775         paintFillLayers(paintInfo, c, styleToUse->backgroundLayers(), tx, ty, w, h);
    776 
    777         if (styleToUse->boxShadow())
    778             paintBoxShadow(context, styleToUse, Inset, tx, ty, w, h);
    779 
    780         // :first-line cannot be used to put borders on a line. Always paint borders with our
    781         // non-first-line style.
    782         if (parent() && renderer()->style()->hasBorder()) {
    783             StyleImage* borderImage = renderer()->style()->borderImage().image();
    784             bool hasBorderImage = borderImage && borderImage->canRender(styleToUse->effectiveZoom());
    785             if (hasBorderImage && !borderImage->isLoaded())
    786                 return; // Don't paint anything while we wait for the image to load.
    787 
    788             // The simple case is where we either have no border image or we are the only box for this object.  In those
    789             // cases only a single call to draw is required.
    790             if (!hasBorderImage || (!prevLineBox() && !nextLineBox()))
    791                 boxModelObject()->paintBorder(context, tx, ty, w, h, renderer()->style(), includeLeftEdge(), includeRightEdge());
    792             else {
    793                 // We have a border image that spans multiple lines.
    794                 // We need to adjust _tx and _ty by the width of all previous lines.
    795                 // Think of border image painting on inlines as though you had one long line, a single continuous
    796                 // strip.  Even though that strip has been broken up across multiple lines, you still paint it
    797                 // as though you had one single line.  This means each line has to pick up the image where
    798                 // the previous line left off.
    799                 // FIXME: What the heck do we do with RTL here? The math we're using is obviously not right,
    800                 // but it isn't even clear how this should work at all.
    801                 int xOffsetOnLine = 0;
    802                 for (InlineRunBox* curr = prevLineBox(); curr; curr = curr->prevLineBox())
    803                     xOffsetOnLine += curr->width();
    804                 int startX = tx - xOffsetOnLine;
    805                 int totalWidth = xOffsetOnLine;
    806                 for (InlineRunBox* curr = this; curr; curr = curr->nextLineBox())
    807                     totalWidth += curr->width();
    808                 context->save();
    809                 context->clip(IntRect(tx, ty, w, h));
    810                 boxModelObject()->paintBorder(context, startX, ty, totalWidth, h, renderer()->style());
    811                 context->restore();
    812             }
    813         }
    814     }
    815 }
    816 
    817 void InlineFlowBox::paintMask(RenderObject::PaintInfo& paintInfo, int tx, int ty)
    818 {
    819     if (!renderer()->shouldPaintWithinRoot(paintInfo) || renderer()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
    820         return;
    821 
    822     int x = m_x;
    823     int y = m_y;
    824     int w = width();
    825     int h = height();
    826 
    827     // Constrain our background/border painting to the line top and bottom if necessary.
    828     bool strictMode = renderer()->document()->inStrictMode();
    829     if (!hasTextChildren() && !strictMode) {
    830         RootInlineBox* rootBox = root();
    831         int bottom = min(rootBox->lineBottom(), y + h);
    832         y = max(rootBox->lineTop(), y);
    833         h = bottom - y;
    834     }
    835 
    836     // Move x/y to our coordinates.
    837     tx += x;
    838     ty += y;
    839 
    840     const NinePieceImage& maskNinePieceImage = renderer()->style()->maskBoxImage();
    841     StyleImage* maskBoxImage = renderer()->style()->maskBoxImage().image();
    842 
    843     // Figure out if we need to push a transparency layer to render our mask.
    844     bool pushTransparencyLayer = false;
    845     bool compositedMask = renderer()->hasLayer() && boxModelObject()->layer()->hasCompositedMask();
    846     CompositeOperator compositeOp = CompositeSourceOver;
    847     if (!compositedMask) {
    848         if ((maskBoxImage && renderer()->style()->maskLayers()->hasImage()) || renderer()->style()->maskLayers()->next())
    849             pushTransparencyLayer = true;
    850 
    851         compositeOp = CompositeDestinationIn;
    852         if (pushTransparencyLayer) {
    853             paintInfo.context->setCompositeOperation(CompositeDestinationIn);
    854             paintInfo.context->beginTransparencyLayer(1.0f);
    855             compositeOp = CompositeSourceOver;
    856         }
    857     }
    858 
    859     paintFillLayers(paintInfo, Color(), renderer()->style()->maskLayers(), tx, ty, w, h, compositeOp);
    860 
    861     bool hasBoxImage = maskBoxImage && maskBoxImage->canRender(renderer()->style()->effectiveZoom());
    862     if (!hasBoxImage || !maskBoxImage->isLoaded())
    863         return; // Don't paint anything while we wait for the image to load.
    864 
    865     // The simple case is where we are the only box for this object.  In those
    866     // cases only a single call to draw is required.
    867     if (!prevLineBox() && !nextLineBox()) {
    868         boxModelObject()->paintNinePieceImage(paintInfo.context, tx, ty, w, h, renderer()->style(), maskNinePieceImage, compositeOp);
    869     } else {
    870         // We have a mask image that spans multiple lines.
    871         // We need to adjust _tx and _ty by the width of all previous lines.
    872         int xOffsetOnLine = 0;
    873         for (InlineRunBox* curr = prevLineBox(); curr; curr = curr->prevLineBox())
    874             xOffsetOnLine += curr->width();
    875         int startX = tx - xOffsetOnLine;
    876         int totalWidth = xOffsetOnLine;
    877         for (InlineRunBox* curr = this; curr; curr = curr->nextLineBox())
    878             totalWidth += curr->width();
    879         paintInfo.context->save();
    880         paintInfo.context->clip(IntRect(tx, ty, w, h));
    881         boxModelObject()->paintNinePieceImage(paintInfo.context, startX, ty, totalWidth, h, renderer()->style(), maskNinePieceImage, compositeOp);
    882         paintInfo.context->restore();
    883     }
    884 
    885     if (pushTransparencyLayer)
    886         paintInfo.context->endTransparencyLayer();
    887 }
    888 
    889 static bool shouldDrawTextDecoration(RenderObject* obj)
    890 {
    891     for (RenderObject* curr = obj->firstChild(); curr; curr = curr->nextSibling()) {
    892         if (curr->isRenderInline())
    893             return true;
    894         if (curr->isText() && !curr->isBR()) {
    895             if (!curr->style()->collapseWhiteSpace())
    896                 return true;
    897             Node* currElement = curr->node();
    898             if (!currElement)
    899                 return true;
    900             if (!currElement->isTextNode())
    901                 return true;
    902             if (!static_cast<Text*>(currElement)->containsOnlyWhitespace())
    903                 return true;
    904         }
    905     }
    906     return false;
    907 }
    908 
    909 void InlineFlowBox::paintTextDecorations(RenderObject::PaintInfo& paintInfo, int tx, int ty, bool paintedChildren)
    910 {
    911     // Paint text decorations like underlines/overlines. We only do this if we aren't in quirks mode (i.e., in
    912     // almost-strict mode or strict mode).
    913     if (renderer()->style()->htmlHacks() || !renderer()->shouldPaintWithinRoot(paintInfo) ||
    914         renderer()->style()->visibility() != VISIBLE)
    915         return;
    916 
    917     // We don't want underlines or other decorations when we're trying to draw nothing but the selection as white text.
    918     if (paintInfo.phase == PaintPhaseSelection && paintInfo.forceBlackText)
    919         return;
    920 
    921     GraphicsContext* context = paintInfo.context;
    922     tx += m_x;
    923     ty += m_y;
    924     RenderStyle* styleToUse = renderer()->style(m_firstLine);
    925     int deco = parent() ? styleToUse->textDecoration() : styleToUse->textDecorationsInEffect();
    926     if (deco != TDNONE &&
    927         ((!paintedChildren && ((deco & UNDERLINE) || (deco & OVERLINE))) || (paintedChildren && (deco & LINE_THROUGH))) &&
    928         shouldDrawTextDecoration(renderer())) {
    929         int x = m_x + borderLeft() + paddingLeft();
    930         int w = m_width - (borderLeft() + paddingLeft() + borderRight() + paddingRight());
    931         RootInlineBox* rootLine = root();
    932         if (rootLine->ellipsisBox()) {
    933             int ellipsisX = m_x + rootLine->ellipsisBox()->x();
    934             int ellipsisWidth = rootLine->ellipsisBox()->width();
    935             bool ltr = renderer()->style()->direction() == LTR;
    936             if (rootLine == this) {
    937                 // Trim w and x so that the underline isn't drawn underneath the ellipsis.
    938                 // ltr: is our right edge farther right than the right edge of the ellipsis.
    939                 // rtl: is the left edge of our box farther left than the left edge of the ellipsis.
    940                 bool ltrTruncation = ltr && (x + w >= ellipsisX + ellipsisWidth);
    941                 bool rtlTruncation = !ltr && (x <= ellipsisX + ellipsisWidth);
    942                 if (ltrTruncation)
    943                     w -= (x + w) - (ellipsisX + ellipsisWidth);
    944                 else if (rtlTruncation) {
    945                     int dx = m_x - ((ellipsisX - m_x) + ellipsisWidth);
    946                     tx -= dx;
    947                     w += dx;
    948                 }
    949             } else {
    950                 bool ltrPastEllipsis = ltr && x >= ellipsisX;
    951                 bool rtlPastEllipsis = !ltr && (x + w) <= (ellipsisX + ellipsisWidth);
    952                 if (ltrPastEllipsis || rtlPastEllipsis)
    953                     return;
    954 
    955                 bool ltrTruncation = ltr && x + w >= ellipsisX;
    956                 bool rtlTruncation = !ltr && x <= ellipsisX;
    957                 if (ltrTruncation)
    958                     w -= (x + w - ellipsisX);
    959                 else if (rtlTruncation) {
    960                     int dx = m_x - ((ellipsisX - m_x) + ellipsisWidth);
    961                     tx -= dx;
    962                     w += dx;
    963                 }
    964             }
    965         }
    966 
    967         // We must have child boxes and have decorations defined.
    968         tx += borderLeft() + paddingLeft();
    969 
    970         Color underline, overline, linethrough;
    971         underline = overline = linethrough = styleToUse->color();
    972         if (!parent())
    973             renderer()->getTextDecorationColors(deco, underline, overline, linethrough);
    974 
    975         bool isPrinting = renderer()->document()->printing();
    976         context->setStrokeThickness(1.0f); // FIXME: We should improve this rule and not always just assume 1.
    977 
    978         bool paintUnderline = deco & UNDERLINE && !paintedChildren;
    979         bool paintOverline = deco & OVERLINE && !paintedChildren;
    980         bool paintLineThrough = deco & LINE_THROUGH && paintedChildren;
    981 
    982         bool linesAreOpaque = !isPrinting && (!paintUnderline || underline.alpha() == 255) && (!paintOverline || overline.alpha() == 255) && (!paintLineThrough || linethrough.alpha() == 255);
    983 
    984         int baselinePos = renderer()->style(m_firstLine)->font().ascent();
    985         if (!isRootInlineBox())
    986             baselinePos += borderTop() + paddingTop();
    987 
    988         bool setClip = false;
    989         int extraOffset = 0;
    990         ShadowData* shadow = styleToUse->textShadow();
    991         if (!linesAreOpaque && shadow && shadow->next) {
    992             IntRect clipRect(tx, ty, w, baselinePos + 2);
    993             for (ShadowData* s = shadow; s; s = s->next) {
    994                 IntRect shadowRect(tx, ty, w, baselinePos + 2);
    995                 shadowRect.inflate(s->blur);
    996                 shadowRect.move(s->x, s->y);
    997                 clipRect.unite(shadowRect);
    998                 extraOffset = max(extraOffset, max(0, s->y) + s->blur);
    999             }
   1000             context->save();
   1001             context->clip(clipRect);
   1002             extraOffset += baselinePos + 2;
   1003             ty += extraOffset;
   1004             setClip = true;
   1005         }
   1006 
   1007         ColorSpace colorSpace = renderer()->style()->colorSpace();
   1008         bool setShadow = false;
   1009         do {
   1010             if (shadow) {
   1011                 if (!shadow->next) {
   1012                     // The last set of lines paints normally inside the clip.
   1013                     ty -= extraOffset;
   1014                     extraOffset = 0;
   1015                 }
   1016                 context->setShadow(IntSize(shadow->x, shadow->y - extraOffset), shadow->blur, shadow->color, colorSpace);
   1017                 setShadow = true;
   1018                 shadow = shadow->next;
   1019             }
   1020 
   1021             if (paintUnderline) {
   1022                 context->setStrokeColor(underline, colorSpace);
   1023                 context->setStrokeStyle(SolidStroke);
   1024                 // Leave one pixel of white between the baseline and the underline.
   1025                 context->drawLineForText(IntPoint(tx, ty + baselinePos + 1), w, isPrinting);
   1026             }
   1027             if (paintOverline) {
   1028                 context->setStrokeColor(overline, colorSpace);
   1029                 context->setStrokeStyle(SolidStroke);
   1030                 context->drawLineForText(IntPoint(tx, ty), w, isPrinting);
   1031             }
   1032             if (paintLineThrough) {
   1033                 context->setStrokeColor(linethrough, colorSpace);
   1034                 context->setStrokeStyle(SolidStroke);
   1035                 context->drawLineForText(IntPoint(tx, ty + 2 * baselinePos / 3), w, isPrinting);
   1036             }
   1037         } while (shadow);
   1038 
   1039         if (setClip)
   1040             context->restore();
   1041         else if (setShadow)
   1042             context->clearShadow();
   1043     }
   1044 }
   1045 
   1046 InlineBox* InlineFlowBox::firstLeafChild() const
   1047 {
   1048     InlineBox* leaf = 0;
   1049     for (InlineBox* child = firstChild(); child && !leaf; child = child->nextOnLine())
   1050         leaf = child->isLeaf() ? child : static_cast<InlineFlowBox*>(child)->firstLeafChild();
   1051     return leaf;
   1052 }
   1053 
   1054 InlineBox* InlineFlowBox::lastLeafChild() const
   1055 {
   1056     InlineBox* leaf = 0;
   1057     for (InlineBox* child = lastChild(); child && !leaf; child = child->prevOnLine())
   1058         leaf = child->isLeaf() ? child : static_cast<InlineFlowBox*>(child)->lastLeafChild();
   1059     return leaf;
   1060 }
   1061 
   1062 RenderObject::SelectionState InlineFlowBox::selectionState()
   1063 {
   1064     return RenderObject::SelectionNone;
   1065 }
   1066 
   1067 bool InlineFlowBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth)
   1068 {
   1069     for (InlineBox *box = firstChild(); box; box = box->nextOnLine()) {
   1070         if (!box->canAccommodateEllipsis(ltr, blockEdge, ellipsisWidth))
   1071             return false;
   1072     }
   1073     return true;
   1074 }
   1075 
   1076 int InlineFlowBox::placeEllipsisBox(bool ltr, int blockLeftEdge, int blockRightEdge, int ellipsisWidth, bool& foundBox)
   1077 {
   1078     int result = -1;
   1079     // We iterate over all children, the foundBox variable tells us when we've found the
   1080     // box containing the ellipsis.  All boxes after that one in the flow are hidden.
   1081     // If our flow is ltr then iterate over the boxes from left to right, otherwise iterate
   1082     // from right to left. Varying the order allows us to correctly hide the boxes following the ellipsis.
   1083     InlineBox *box = ltr ? firstChild() : lastChild();
   1084 
   1085     // NOTE: these will cross after foundBox = true.
   1086     int visibleLeftEdge = blockLeftEdge;
   1087     int visibleRightEdge = blockRightEdge;
   1088 
   1089     while (box) {
   1090         int currResult = box->placeEllipsisBox(ltr, visibleLeftEdge, visibleRightEdge, ellipsisWidth, foundBox);
   1091         if (currResult != -1 && result == -1)
   1092             result = currResult;
   1093 
   1094         if (ltr) {
   1095             visibleLeftEdge += box->width();
   1096             box = box->nextOnLine();
   1097         }
   1098         else {
   1099             visibleRightEdge -= box->width();
   1100             box = box->prevOnLine();
   1101         }
   1102     }
   1103     return result;
   1104 }
   1105 
   1106 void InlineFlowBox::clearTruncation()
   1107 {
   1108     for (InlineBox *box = firstChild(); box; box = box->nextOnLine())
   1109         box->clearTruncation();
   1110 }
   1111 
   1112 #ifndef NDEBUG
   1113 
   1114 void InlineFlowBox::checkConsistency() const
   1115 {
   1116 #ifdef CHECK_CONSISTENCY
   1117     ASSERT(!m_hasBadChildList);
   1118     const InlineBox* prev = 0;
   1119     for (const InlineBox* child = m_firstChild; child; child = child->nextOnLine()) {
   1120         ASSERT(child->parent() == this);
   1121         ASSERT(child->prevOnLine() == prev);
   1122         prev = child;
   1123     }
   1124     ASSERT(prev == m_lastChild);
   1125 #endif
   1126 }
   1127 
   1128 #endif
   1129 
   1130 } // namespace WebCore
   1131