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 "core/rendering/InlineFlowBox.h"
     22 
     23 #include "core/CSSPropertyNames.h"
     24 #include "core/dom/Document.h"
     25 #include "core/paint/BoxPainter.h"
     26 #include "core/paint/InlineFlowBoxPainter.h"
     27 #include "core/rendering/HitTestResult.h"
     28 #include "core/rendering/InlineTextBox.h"
     29 #include "core/rendering/RenderBlock.h"
     30 #include "core/rendering/RenderInline.h"
     31 #include "core/rendering/RenderLayer.h"
     32 #include "core/rendering/RenderListMarker.h"
     33 #include "core/rendering/RenderObjectInlines.h"
     34 #include "core/rendering/RenderRubyBase.h"
     35 #include "core/rendering/RenderRubyRun.h"
     36 #include "core/rendering/RenderRubyText.h"
     37 #include "core/rendering/RenderView.h"
     38 #include "core/rendering/RootInlineBox.h"
     39 #include "platform/fonts/Font.h"
     40 #include "platform/graphics/GraphicsContextStateSaver.h"
     41 
     42 #include <math.h>
     43 
     44 namespace blink {
     45 
     46 struct SameSizeAsInlineFlowBox : public InlineBox {
     47     void* pointers[5];
     48     uint32_t bitfields : 23;
     49 };
     50 
     51 COMPILE_ASSERT(sizeof(InlineFlowBox) == sizeof(SameSizeAsInlineFlowBox), InlineFlowBox_should_stay_small);
     52 
     53 #if ENABLE(ASSERT)
     54 
     55 InlineFlowBox::~InlineFlowBox()
     56 {
     57     if (!m_hasBadChildList)
     58         for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
     59             child->setHasBadParent();
     60 }
     61 
     62 #endif
     63 
     64 LayoutUnit InlineFlowBox::getFlowSpacingLogicalWidth()
     65 {
     66     LayoutUnit totWidth = marginBorderPaddingLogicalLeft() + marginBorderPaddingLogicalRight();
     67     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
     68         if (curr->isInlineFlowBox())
     69             totWidth += toInlineFlowBox(curr)->getFlowSpacingLogicalWidth();
     70     }
     71     return totWidth;
     72 }
     73 
     74 IntRect InlineFlowBox::roundedFrameRect() const
     75 {
     76     // Begin by snapping the x and y coordinates to the nearest pixel.
     77     int snappedX = lroundf(x());
     78     int snappedY = lroundf(y());
     79 
     80     int snappedMaxX = lroundf(x() + width());
     81     int snappedMaxY = lroundf(y() + height());
     82 
     83     return IntRect(snappedX, snappedY, snappedMaxX - snappedX, snappedMaxY - snappedY);
     84 }
     85 
     86 static void setHasTextDescendantsOnAncestors(InlineFlowBox* box)
     87 {
     88     while (box && !box->hasTextDescendants()) {
     89         box->setHasTextDescendants();
     90         box = box->parent();
     91     }
     92 }
     93 
     94 void InlineFlowBox::addToLine(InlineBox* child)
     95 {
     96     ASSERT(!child->parent());
     97     ASSERT(!child->nextOnLine());
     98     ASSERT(!child->prevOnLine());
     99     checkConsistency();
    100 
    101     child->setParent(this);
    102     if (!m_firstChild) {
    103         m_firstChild = child;
    104         m_lastChild = child;
    105     } else {
    106         m_lastChild->setNextOnLine(child);
    107         child->setPrevOnLine(m_lastChild);
    108         m_lastChild = child;
    109     }
    110     child->setFirstLineStyleBit(isFirstLineStyle());
    111     child->setIsHorizontal(isHorizontal());
    112     if (child->isText()) {
    113         if (child->renderer().parent() == renderer())
    114             m_hasTextChildren = true;
    115         setHasTextDescendantsOnAncestors(this);
    116     } else if (child->isInlineFlowBox()) {
    117         if (toInlineFlowBox(child)->hasTextDescendants())
    118             setHasTextDescendantsOnAncestors(this);
    119     }
    120 
    121     if (descendantsHaveSameLineHeightAndBaseline() && !child->renderer().isOutOfFlowPositioned()) {
    122         RenderStyle* parentStyle = renderer().style(isFirstLineStyle());
    123         RenderStyle* childStyle = child->renderer().style(isFirstLineStyle());
    124         bool shouldClearDescendantsHaveSameLineHeightAndBaseline = false;
    125         if (child->renderer().isReplaced())
    126             shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
    127         else if (child->isText()) {
    128             if (child->renderer().isBR() || child->renderer().parent() != renderer()) {
    129                 if (!parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle->font().fontMetrics())
    130                     || parentStyle->lineHeight() != childStyle->lineHeight()
    131                     || (parentStyle->verticalAlign() != BASELINE && !isRootInlineBox()) || childStyle->verticalAlign() != BASELINE)
    132                     shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
    133             }
    134             if (childStyle->hasTextCombine() || childStyle->textEmphasisMark() != TextEmphasisMarkNone)
    135                 shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
    136         } else {
    137             if (child->renderer().isBR()) {
    138                 // FIXME: This is dumb. We only turn off because current layout test results expect the <br> to be 0-height on the baseline.
    139                 // Other than making a zillion tests have to regenerate results, there's no reason to ditch the optimization here.
    140                 shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
    141             } else {
    142                 ASSERT(isInlineFlowBox());
    143                 InlineFlowBox* childFlowBox = toInlineFlowBox(child);
    144                 // Check the child's bit, and then also check for differences in font, line-height, vertical-align
    145                 if (!childFlowBox->descendantsHaveSameLineHeightAndBaseline()
    146                     || !parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle->font().fontMetrics())
    147                     || parentStyle->lineHeight() != childStyle->lineHeight()
    148                     || (parentStyle->verticalAlign() != BASELINE && !isRootInlineBox()) || childStyle->verticalAlign() != BASELINE
    149                     || childStyle->hasBorder() || childStyle->hasPadding() || childStyle->hasTextCombine())
    150                     shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
    151             }
    152         }
    153 
    154         if (shouldClearDescendantsHaveSameLineHeightAndBaseline)
    155             clearDescendantsHaveSameLineHeightAndBaseline();
    156     }
    157 
    158     if (!child->renderer().isOutOfFlowPositioned()) {
    159         if (child->isText()) {
    160             RenderStyle* childStyle = child->renderer().style(isFirstLineStyle());
    161             if (childStyle->letterSpacing() < 0 || childStyle->textShadow() || childStyle->textEmphasisMark() != TextEmphasisMarkNone || childStyle->textStrokeWidth())
    162                 child->clearKnownToHaveNoOverflow();
    163         } else if (child->renderer().isReplaced()) {
    164             RenderBox& box = toRenderBox(child->renderer());
    165             if (box.hasRenderOverflow() || box.hasSelfPaintingLayer())
    166                 child->clearKnownToHaveNoOverflow();
    167         } else if (!child->renderer().isBR() && (child->renderer().style(isFirstLineStyle())->boxShadow() || child->boxModelObject()->hasSelfPaintingLayer()
    168             || (child->renderer().isListMarker() && !toRenderListMarker(child->renderer()).isInside())
    169             || child->renderer().style(isFirstLineStyle())->hasBorderImageOutsets()
    170             || child->renderer().style(isFirstLineStyle())->hasOutline())) {
    171             child->clearKnownToHaveNoOverflow();
    172         }
    173 
    174         if (knownToHaveNoOverflow() && child->isInlineFlowBox() && !toInlineFlowBox(child)->knownToHaveNoOverflow())
    175             clearKnownToHaveNoOverflow();
    176     }
    177 
    178     checkConsistency();
    179 }
    180 
    181 void InlineFlowBox::removeChild(InlineBox* child, MarkLineBoxes markDirty)
    182 {
    183     checkConsistency();
    184 
    185     if (markDirty == MarkLineBoxesDirty && !isDirty())
    186         dirtyLineBoxes();
    187 
    188     root().childRemoved(child);
    189 
    190     if (child == m_firstChild)
    191         m_firstChild = child->nextOnLine();
    192     if (child == m_lastChild)
    193         m_lastChild = child->prevOnLine();
    194     if (child->nextOnLine())
    195         child->nextOnLine()->setPrevOnLine(child->prevOnLine());
    196     if (child->prevOnLine())
    197         child->prevOnLine()->setNextOnLine(child->nextOnLine());
    198 
    199     child->setParent(0);
    200 
    201     checkConsistency();
    202 }
    203 
    204 void InlineFlowBox::deleteLine()
    205 {
    206     InlineBox* child = firstChild();
    207     InlineBox* next = 0;
    208     while (child) {
    209         ASSERT(this == child->parent());
    210         next = child->nextOnLine();
    211 #if ENABLE(ASSERT)
    212         child->setParent(0);
    213 #endif
    214         child->deleteLine();
    215         child = next;
    216     }
    217 #if ENABLE(ASSERT)
    218     m_firstChild = 0;
    219     m_lastChild = 0;
    220 #endif
    221 
    222     removeLineBoxFromRenderObject();
    223     destroy();
    224 }
    225 
    226 void InlineFlowBox::removeLineBoxFromRenderObject()
    227 {
    228     rendererLineBoxes()->removeLineBox(this);
    229 }
    230 
    231 void InlineFlowBox::extractLine()
    232 {
    233     if (!extracted())
    234         extractLineBoxFromRenderObject();
    235     for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
    236         child->extractLine();
    237 }
    238 
    239 void InlineFlowBox::extractLineBoxFromRenderObject()
    240 {
    241     rendererLineBoxes()->extractLineBox(this);
    242 }
    243 
    244 void InlineFlowBox::attachLine()
    245 {
    246     if (extracted())
    247         attachLineBoxToRenderObject();
    248     for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
    249         child->attachLine();
    250 }
    251 
    252 void InlineFlowBox::attachLineBoxToRenderObject()
    253 {
    254     rendererLineBoxes()->attachLineBox(this);
    255 }
    256 
    257 void InlineFlowBox::adjustPosition(float dx, float dy)
    258 {
    259     InlineBox::adjustPosition(dx, dy);
    260     for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
    261         child->adjustPosition(dx, dy);
    262     if (m_overflow)
    263         m_overflow->move(dx, dy); // FIXME: Rounding error here since overflow was pixel snapped, but nobody other than list markers passes non-integral values here.
    264 }
    265 
    266 RenderLineBoxList* InlineFlowBox::rendererLineBoxes() const
    267 {
    268     return toRenderInline(renderer()).lineBoxes();
    269 }
    270 
    271 static inline bool isLastChildForRenderer(RenderObject* ancestor, RenderObject* child)
    272 {
    273     if (!child)
    274         return false;
    275 
    276     if (child == ancestor)
    277         return true;
    278 
    279     RenderObject* curr = child;
    280     RenderObject* parent = curr->parent();
    281     while (parent && (!parent->isRenderBlock() || parent->isInline())) {
    282         if (parent->slowLastChild() != curr)
    283             return false;
    284         if (parent == ancestor)
    285             return true;
    286 
    287         curr = parent;
    288         parent = curr->parent();
    289     }
    290 
    291     return true;
    292 }
    293 
    294 static bool isAnsectorAndWithinBlock(RenderObject* ancestor, RenderObject* child)
    295 {
    296     RenderObject* object = child;
    297     while (object && (!object->isRenderBlock() || object->isInline())) {
    298         if (object == ancestor)
    299             return true;
    300         object = object->parent();
    301     }
    302     return false;
    303 }
    304 
    305 void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, bool isLogicallyLastRunWrapped, RenderObject* logicallyLastRunRenderer)
    306 {
    307     // All boxes start off open.  They will not apply any margins/border/padding on
    308     // any side.
    309     bool includeLeftEdge = false;
    310     bool includeRightEdge = false;
    311 
    312     // The root inline box never has borders/margins/padding.
    313     if (parent()) {
    314         bool ltr = renderer().style()->isLeftToRightDirection();
    315 
    316         // Check to see if all initial lines are unconstructed.  If so, then
    317         // we know the inline began on this line (unless we are a continuation).
    318         RenderLineBoxList* lineBoxList = rendererLineBoxes();
    319         if (!lineBoxList->firstLineBox()->isConstructed() && !renderer().isInlineElementContinuation()) {
    320             if (renderer().style()->boxDecorationBreak() == DCLONE)
    321                 includeLeftEdge = includeRightEdge = true;
    322             else if (ltr && lineBoxList->firstLineBox() == this)
    323                 includeLeftEdge = true;
    324             else if (!ltr && lineBoxList->lastLineBox() == this)
    325                 includeRightEdge = true;
    326         }
    327 
    328         if (!lineBoxList->lastLineBox()->isConstructed()) {
    329             RenderInline& inlineFlow = toRenderInline(renderer());
    330             bool isLastObjectOnLine = !isAnsectorAndWithinBlock(&renderer(), logicallyLastRunRenderer) || (isLastChildForRenderer(&renderer(), logicallyLastRunRenderer) && !isLogicallyLastRunWrapped);
    331 
    332             // We include the border under these conditions:
    333             // (1) The next line was not created, or it is constructed. We check the previous line for rtl.
    334             // (2) The logicallyLastRun is not a descendant of this renderer.
    335             // (3) The logicallyLastRun is a descendant of this renderer, but it is the last child of this renderer and it does not wrap to the next line.
    336             // (4) The decoration break is set to clone therefore there will be borders on every sides.
    337             if (renderer().style()->boxDecorationBreak() == DCLONE)
    338                 includeLeftEdge = includeRightEdge = true;
    339             else if (ltr) {
    340                 if (!nextLineBox()
    341                     && ((lastLine || isLastObjectOnLine) && !inlineFlow.continuation()))
    342                     includeRightEdge = true;
    343             } else {
    344                 if ((!prevLineBox() || prevLineBox()->isConstructed())
    345                     && ((lastLine || isLastObjectOnLine) && !inlineFlow.continuation()))
    346                     includeLeftEdge = true;
    347             }
    348         }
    349     }
    350 
    351     setEdges(includeLeftEdge, includeRightEdge);
    352 
    353     // Recur into our children.
    354     for (InlineBox* currChild = firstChild(); currChild; currChild = currChild->nextOnLine()) {
    355         if (currChild->isInlineFlowBox()) {
    356             InlineFlowBox* currFlow = toInlineFlowBox(currChild);
    357             currFlow->determineSpacingForFlowBoxes(lastLine, isLogicallyLastRunWrapped, logicallyLastRunRenderer);
    358         }
    359     }
    360 }
    361 
    362 float InlineFlowBox::placeBoxesInInlineDirection(float logicalLeft, bool& needsWordSpacing)
    363 {
    364     // Set our x position.
    365     beginPlacingBoxRangesInInlineDirection(logicalLeft);
    366 
    367     float startLogicalLeft = logicalLeft;
    368     logicalLeft += borderLogicalLeft() + paddingLogicalLeft();
    369 
    370     float minLogicalLeft = startLogicalLeft;
    371     float maxLogicalRight = logicalLeft;
    372 
    373     placeBoxRangeInInlineDirection(firstChild(), 0, logicalLeft, minLogicalLeft, maxLogicalRight, needsWordSpacing);
    374 
    375     logicalLeft += borderLogicalRight() + paddingLogicalRight();
    376     endPlacingBoxRangesInInlineDirection(startLogicalLeft, logicalLeft, minLogicalLeft, maxLogicalRight);
    377     return logicalLeft;
    378 }
    379 
    380 float InlineFlowBox::placeBoxRangeInInlineDirection(InlineBox* firstChild, InlineBox* lastChild,
    381     float& logicalLeft, float& minLogicalLeft, float& maxLogicalRight, bool& needsWordSpacing)
    382 {
    383     for (InlineBox* curr = firstChild; curr && curr != lastChild; curr = curr->nextOnLine()) {
    384         if (curr->renderer().isText()) {
    385             InlineTextBox* text = toInlineTextBox(curr);
    386             RenderText& rt = text->renderer();
    387             float space = 0;
    388             if (rt.textLength()) {
    389                 if (needsWordSpacing && isSpaceOrNewline(rt.characterAt(text->start())))
    390                     space = rt.style(isFirstLineStyle())->font().fontDescription().wordSpacing();
    391                 needsWordSpacing = !isSpaceOrNewline(rt.characterAt(text->end()));
    392             }
    393             if (isLeftToRightDirection()) {
    394                 logicalLeft += space;
    395                 text->setLogicalLeft(logicalLeft);
    396             } else {
    397                 text->setLogicalLeft(logicalLeft);
    398                 logicalLeft += space;
    399             }
    400             if (knownToHaveNoOverflow())
    401                 minLogicalLeft = std::min(logicalLeft, minLogicalLeft);
    402             logicalLeft += text->logicalWidth();
    403             if (knownToHaveNoOverflow())
    404                 maxLogicalRight = std::max(logicalLeft, maxLogicalRight);
    405         } else {
    406             if (curr->renderer().isOutOfFlowPositioned()) {
    407                 if (curr->renderer().parent()->style()->isLeftToRightDirection()) {
    408                     curr->setLogicalLeft(logicalLeft);
    409                 } else {
    410                     // Our offset that we cache needs to be from the edge of the right border box and
    411                     // not the left border box.  We have to subtract |x| from the width of the block
    412                     // (which can be obtained from the root line box).
    413                     curr->setLogicalLeft(root().block().logicalWidth() - logicalLeft);
    414                 }
    415                 continue; // The positioned object has no effect on the width.
    416             }
    417             if (curr->renderer().isRenderInline()) {
    418                 InlineFlowBox* flow = toInlineFlowBox(curr);
    419                 logicalLeft += flow->marginLogicalLeft();
    420                 if (knownToHaveNoOverflow())
    421                     minLogicalLeft = std::min(logicalLeft, minLogicalLeft);
    422                 logicalLeft = flow->placeBoxesInInlineDirection(logicalLeft, needsWordSpacing);
    423                 if (knownToHaveNoOverflow())
    424                     maxLogicalRight = std::max(logicalLeft, maxLogicalRight);
    425                 logicalLeft += flow->marginLogicalRight();
    426             } else if (!curr->renderer().isListMarker() || toRenderListMarker(curr->renderer()).isInside()) {
    427                 // The box can have a different writing-mode than the overall line, so this is a bit complicated.
    428                 // Just get all the physical margin and overflow values by hand based off |isVertical|.
    429                 LayoutUnit logicalLeftMargin = isHorizontal() ? curr->boxModelObject()->marginLeft() : curr->boxModelObject()->marginTop();
    430                 LayoutUnit logicalRightMargin = isHorizontal() ? curr->boxModelObject()->marginRight() : curr->boxModelObject()->marginBottom();
    431 
    432                 logicalLeft += logicalLeftMargin;
    433                 curr->setLogicalLeft(logicalLeft);
    434                 if (knownToHaveNoOverflow())
    435                     minLogicalLeft = std::min(logicalLeft, minLogicalLeft);
    436                 logicalLeft += curr->logicalWidth();
    437                 if (knownToHaveNoOverflow())
    438                     maxLogicalRight = std::max(logicalLeft, maxLogicalRight);
    439                 logicalLeft += logicalRightMargin;
    440                 // If we encounter any space after this inline block then ensure it is treated as the space between two words.
    441                 needsWordSpacing = true;
    442             }
    443         }
    444     }
    445     return logicalLeft;
    446 }
    447 
    448 bool InlineFlowBox::requiresIdeographicBaseline(const GlyphOverflowAndFallbackFontsMap& textBoxDataMap) const
    449 {
    450     if (isHorizontal())
    451         return false;
    452 
    453     if (renderer().style(isFirstLineStyle())->fontDescription().nonCJKGlyphOrientation() == NonCJKGlyphOrientationUpright
    454         || renderer().style(isFirstLineStyle())->font().primaryFont()->hasVerticalGlyphs())
    455         return true;
    456 
    457     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
    458         if (curr->renderer().isOutOfFlowPositioned())
    459             continue; // Positioned placeholders don't affect calculations.
    460 
    461         if (curr->isInlineFlowBox()) {
    462             if (toInlineFlowBox(curr)->requiresIdeographicBaseline(textBoxDataMap))
    463                 return true;
    464         } else {
    465             if (curr->renderer().style(isFirstLineStyle())->font().primaryFont()->hasVerticalGlyphs())
    466                 return true;
    467 
    468             const Vector<const SimpleFontData*>* usedFonts = 0;
    469             if (curr->isInlineTextBox()) {
    470                 GlyphOverflowAndFallbackFontsMap::const_iterator it = textBoxDataMap.find(toInlineTextBox(curr));
    471                 usedFonts = it == textBoxDataMap.end() ? 0 : &it->value.first;
    472             }
    473 
    474             if (usedFonts) {
    475                 for (size_t i = 0; i < usedFonts->size(); ++i) {
    476                     if (usedFonts->at(i)->hasVerticalGlyphs())
    477                         return true;
    478                 }
    479             }
    480         }
    481     }
    482 
    483     return false;
    484 }
    485 
    486 void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, int maxPositionTop, int maxPositionBottom)
    487 {
    488     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
    489         // The computed lineheight needs to be extended for the
    490         // positioned elements
    491         if (curr->renderer().isOutOfFlowPositioned())
    492             continue; // Positioned placeholders don't affect calculations.
    493         if (curr->verticalAlign() == TOP || curr->verticalAlign() == BOTTOM) {
    494             int lineHeight = curr->lineHeight();
    495             if (curr->verticalAlign() == TOP) {
    496                 if (maxAscent + maxDescent < lineHeight)
    497                     maxDescent = lineHeight - maxAscent;
    498             }
    499             else {
    500                 if (maxAscent + maxDescent < lineHeight)
    501                     maxAscent = lineHeight - maxDescent;
    502             }
    503 
    504             if (maxAscent + maxDescent >= std::max(maxPositionTop, maxPositionBottom))
    505                 break;
    506         }
    507 
    508         if (curr->isInlineFlowBox())
    509             toInlineFlowBox(curr)->adjustMaxAscentAndDescent(maxAscent, maxDescent, maxPositionTop, maxPositionBottom);
    510     }
    511 }
    512 
    513 void InlineFlowBox::computeLogicalBoxHeights(RootInlineBox* rootBox, LayoutUnit& maxPositionTop, LayoutUnit& maxPositionBottom,
    514                                              int& maxAscent, int& maxDescent, bool& setMaxAscent, bool& setMaxDescent,
    515                                              bool strictMode, GlyphOverflowAndFallbackFontsMap& textBoxDataMap,
    516                                              FontBaseline baselineType, VerticalPositionCache& verticalPositionCache)
    517 {
    518     // The primary purpose of this function is to compute the maximal ascent and descent values for
    519     // a line. These values are computed based off the block's line-box-contain property, which indicates
    520     // what parts of descendant boxes have to fit within the line.
    521     //
    522     // The maxAscent value represents the distance of the highest point of any box (typically including line-height) from
    523     // the root box's baseline. The maxDescent value represents the distance of the lowest point of any box
    524     // (also typically including line-height) from the root box baseline. These values can be negative.
    525     //
    526     // A secondary purpose of this function is to store the offset of every box's baseline from the root box's
    527     // baseline. This information is cached in the logicalTop() of every box. We're effectively just using
    528     // the logicalTop() as scratch space.
    529     //
    530     // Because a box can be positioned such that it ends up fully above or fully below the
    531     // root line box, we only consider it to affect the maxAscent and maxDescent values if some
    532     // part of the box (EXCLUDING leading) is above (for ascent) or below (for descent) the root box's baseline.
    533     bool affectsAscent = false;
    534     bool affectsDescent = false;
    535     bool checkChildren = !descendantsHaveSameLineHeightAndBaseline();
    536 
    537     if (isRootInlineBox()) {
    538         // Examine our root box.
    539         int ascent = 0;
    540         int descent = 0;
    541         rootBox->ascentAndDescentForBox(rootBox, textBoxDataMap, ascent, descent, affectsAscent, affectsDescent);
    542         if (strictMode || hasTextChildren() || (!checkChildren && hasTextDescendants())) {
    543             if (maxAscent < ascent || !setMaxAscent) {
    544                 maxAscent = ascent;
    545                 setMaxAscent = true;
    546             }
    547             if (maxDescent < descent || !setMaxDescent) {
    548                 maxDescent = descent;
    549                 setMaxDescent = true;
    550             }
    551         }
    552     }
    553 
    554     if (!checkChildren)
    555         return;
    556 
    557     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
    558         if (curr->renderer().isOutOfFlowPositioned())
    559             continue; // Positioned placeholders don't affect calculations.
    560 
    561         InlineFlowBox* inlineFlowBox = curr->isInlineFlowBox() ? toInlineFlowBox(curr) : 0;
    562 
    563         bool affectsAscent = false;
    564         bool affectsDescent = false;
    565 
    566         // The verticalPositionForBox function returns the distance between the child box's baseline
    567         // and the root box's baseline.  The value is negative if the child box's baseline is above the
    568         // root box's baseline, and it is positive if the child box's baseline is below the root box's baseline.
    569         curr->setLogicalTop(rootBox->verticalPositionForBox(curr, verticalPositionCache).toFloat());
    570 
    571         int ascent = 0;
    572         int descent = 0;
    573         rootBox->ascentAndDescentForBox(curr, textBoxDataMap, ascent, descent, affectsAscent, affectsDescent);
    574 
    575         LayoutUnit boxHeight = ascent + descent;
    576         if (curr->verticalAlign() == TOP) {
    577             if (maxPositionTop < boxHeight)
    578                 maxPositionTop = boxHeight;
    579         } else if (curr->verticalAlign() == BOTTOM) {
    580             if (maxPositionBottom < boxHeight)
    581                 maxPositionBottom = boxHeight;
    582         } else if (!inlineFlowBox || strictMode || inlineFlowBox->hasTextChildren() || (inlineFlowBox->descendantsHaveSameLineHeightAndBaseline() && inlineFlowBox->hasTextDescendants())
    583                    || inlineFlowBox->boxModelObject()->hasInlineDirectionBordersOrPadding()) {
    584             // Note that these values can be negative.  Even though we only affect the maxAscent and maxDescent values
    585             // if our box (excluding line-height) was above (for ascent) or below (for descent) the root baseline, once you factor in line-height
    586             // the final box can end up being fully above or fully below the root box's baseline!  This is ok, but what it
    587             // means is that ascent and descent (including leading), can end up being negative.  The setMaxAscent and
    588             // setMaxDescent booleans are used to ensure that we're willing to initially set maxAscent/Descent to negative
    589             // values.
    590             ascent -= curr->logicalTop();
    591             descent += curr->logicalTop();
    592             if (affectsAscent && (maxAscent < ascent || !setMaxAscent)) {
    593                 maxAscent = ascent;
    594                 setMaxAscent = true;
    595             }
    596 
    597             if (affectsDescent && (maxDescent < descent || !setMaxDescent)) {
    598                 maxDescent = descent;
    599                 setMaxDescent = true;
    600             }
    601         }
    602 
    603         if (inlineFlowBox)
    604             inlineFlowBox->computeLogicalBoxHeights(rootBox, maxPositionTop, maxPositionBottom, maxAscent, maxDescent,
    605                                                     setMaxAscent, setMaxDescent, strictMode, textBoxDataMap,
    606                                                     baselineType, verticalPositionCache);
    607     }
    608 }
    609 
    610 void InlineFlowBox::placeBoxesInBlockDirection(LayoutUnit top, LayoutUnit maxHeight, int maxAscent, bool strictMode, LayoutUnit& lineTop, LayoutUnit& lineBottom, LayoutUnit& selectionBottom, bool& setLineTop,
    611                                                LayoutUnit& lineTopIncludingMargins, LayoutUnit& lineBottomIncludingMargins, bool& hasAnnotationsBefore, bool& hasAnnotationsAfter, FontBaseline baselineType)
    612 {
    613     bool isRootBox = isRootInlineBox();
    614     if (isRootBox) {
    615         const FontMetrics& fontMetrics = renderer().style(isFirstLineStyle())->fontMetrics();
    616         // RootInlineBoxes are always placed on at pixel boundaries in their logical y direction. Not doing
    617         // so results in incorrect rendering of text decorations, most notably underlines.
    618         setLogicalTop(roundToInt(top + maxAscent - fontMetrics.ascent(baselineType)));
    619     }
    620 
    621     LayoutUnit adjustmentForChildrenWithSameLineHeightAndBaseline = 0;
    622     if (descendantsHaveSameLineHeightAndBaseline()) {
    623         adjustmentForChildrenWithSameLineHeightAndBaseline = logicalTop();
    624         if (parent())
    625             adjustmentForChildrenWithSameLineHeightAndBaseline += (boxModelObject()->borderBefore() + boxModelObject()->paddingBefore());
    626     }
    627 
    628     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
    629         if (curr->renderer().isOutOfFlowPositioned())
    630             continue; // Positioned placeholders don't affect calculations.
    631 
    632         if (descendantsHaveSameLineHeightAndBaseline()) {
    633             curr->adjustBlockDirectionPosition(adjustmentForChildrenWithSameLineHeightAndBaseline.toFloat());
    634             continue;
    635         }
    636 
    637         InlineFlowBox* inlineFlowBox = curr->isInlineFlowBox() ? toInlineFlowBox(curr) : 0;
    638         bool childAffectsTopBottomPos = true;
    639         if (curr->verticalAlign() == TOP)
    640             curr->setLogicalTop(top.toFloat());
    641         else if (curr->verticalAlign() == BOTTOM)
    642             curr->setLogicalTop((top + maxHeight - curr->lineHeight()).toFloat());
    643         else {
    644             if (!strictMode && inlineFlowBox && !inlineFlowBox->hasTextChildren() && !curr->boxModelObject()->hasInlineDirectionBordersOrPadding()
    645                 && !(inlineFlowBox->descendantsHaveSameLineHeightAndBaseline() && inlineFlowBox->hasTextDescendants()))
    646                 childAffectsTopBottomPos = false;
    647             LayoutUnit posAdjust = maxAscent - curr->baselinePosition(baselineType);
    648             curr->setLogicalTop(curr->logicalTop() + top + posAdjust);
    649         }
    650 
    651         LayoutUnit newLogicalTop = curr->logicalTop();
    652         LayoutUnit newLogicalTopIncludingMargins = newLogicalTop;
    653         LayoutUnit boxHeight = curr->logicalHeight();
    654         LayoutUnit boxHeightIncludingMargins = boxHeight;
    655         LayoutUnit borderPaddingHeight = 0;
    656         if (curr->isText() || curr->isInlineFlowBox()) {
    657             const FontMetrics& fontMetrics = curr->renderer().style(isFirstLineStyle())->fontMetrics();
    658             newLogicalTop += curr->baselinePosition(baselineType) - fontMetrics.ascent(baselineType);
    659             if (curr->isInlineFlowBox()) {
    660                 RenderBoxModelObject& boxObject = toRenderBoxModelObject(curr->renderer());
    661                 newLogicalTop -= boxObject.style(isFirstLineStyle())->isHorizontalWritingMode() ? boxObject.borderTop() + boxObject.paddingTop() :
    662                     boxObject.borderRight() + boxObject.paddingRight();
    663                 borderPaddingHeight = boxObject.borderAndPaddingLogicalHeight();
    664             }
    665             newLogicalTopIncludingMargins = newLogicalTop;
    666         } else if (!curr->renderer().isBR()) {
    667             RenderBox& box = toRenderBox(curr->renderer());
    668             newLogicalTopIncludingMargins = newLogicalTop;
    669             LayoutUnit overSideMargin = curr->isHorizontal() ? box.marginTop() : box.marginRight();
    670             LayoutUnit underSideMargin = curr->isHorizontal() ? box.marginBottom() : box.marginLeft();
    671             newLogicalTop += overSideMargin;
    672             boxHeightIncludingMargins += overSideMargin + underSideMargin;
    673         }
    674 
    675         curr->setLogicalTop(newLogicalTop.toFloat());
    676 
    677         if (childAffectsTopBottomPos) {
    678             if (curr->renderer().isRubyRun()) {
    679                 // Treat the leading on the first and last lines of ruby runs as not being part of the overall lineTop/lineBottom.
    680                 // Really this is a workaround hack for the fact that ruby should have been done as line layout and not done using
    681                 // inline-block.
    682                 if (renderer().style()->isFlippedLinesWritingMode() == (curr->renderer().style()->rubyPosition() == RubyPositionAfter))
    683                     hasAnnotationsBefore = true;
    684                 else
    685                     hasAnnotationsAfter = true;
    686 
    687                 RenderRubyRun& rubyRun = toRenderRubyRun(curr->renderer());
    688                 if (RenderRubyBase* rubyBase = rubyRun.rubyBase()) {
    689                     LayoutUnit bottomRubyBaseLeading = (curr->logicalHeight() - rubyBase->logicalBottom()) + rubyBase->logicalHeight() - (rubyBase->lastRootBox() ? rubyBase->lastRootBox()->lineBottom() : LayoutUnit());
    690                     LayoutUnit topRubyBaseLeading = rubyBase->logicalTop() + (rubyBase->firstRootBox() ? rubyBase->firstRootBox()->lineTop() : LayoutUnit());
    691                     newLogicalTop += !renderer().style()->isFlippedLinesWritingMode() ? topRubyBaseLeading : bottomRubyBaseLeading;
    692                     boxHeight -= (topRubyBaseLeading + bottomRubyBaseLeading);
    693                 }
    694             }
    695             if (curr->isInlineTextBox()) {
    696                 TextEmphasisPosition emphasisMarkPosition;
    697                 if (toInlineTextBox(curr)->getEmphasisMarkPosition(curr->renderer().style(isFirstLineStyle()), emphasisMarkPosition)) {
    698                     bool emphasisMarkIsOver = emphasisMarkPosition == TextEmphasisPositionOver;
    699                     if (emphasisMarkIsOver != curr->renderer().style(isFirstLineStyle())->isFlippedLinesWritingMode())
    700                         hasAnnotationsBefore = true;
    701                     else
    702                         hasAnnotationsAfter = true;
    703                 }
    704             }
    705 
    706             if (!setLineTop) {
    707                 setLineTop = true;
    708                 lineTop = newLogicalTop;
    709                 lineTopIncludingMargins = std::min(lineTop, newLogicalTopIncludingMargins);
    710             } else {
    711                 lineTop = std::min(lineTop, newLogicalTop);
    712                 lineTopIncludingMargins = std::min(lineTop, std::min(lineTopIncludingMargins, newLogicalTopIncludingMargins));
    713             }
    714             selectionBottom = std::max(selectionBottom, newLogicalTop + boxHeight - borderPaddingHeight);
    715             lineBottom = std::max(lineBottom, newLogicalTop + boxHeight);
    716             lineBottomIncludingMargins = std::max(lineBottom, std::max(lineBottomIncludingMargins, newLogicalTopIncludingMargins + boxHeightIncludingMargins));
    717         }
    718 
    719         // Adjust boxes to use their real box y/height and not the logical height (as dictated by
    720         // line-height).
    721         if (inlineFlowBox)
    722             inlineFlowBox->placeBoxesInBlockDirection(top, maxHeight, maxAscent, strictMode, lineTop, lineBottom, selectionBottom, setLineTop,
    723                                                       lineTopIncludingMargins, lineBottomIncludingMargins, hasAnnotationsBefore, hasAnnotationsAfter, baselineType);
    724     }
    725 
    726     if (isRootBox) {
    727         if (strictMode || hasTextChildren() || (descendantsHaveSameLineHeightAndBaseline() && hasTextDescendants())) {
    728             if (!setLineTop) {
    729                 setLineTop = true;
    730                 lineTop = pixelSnappedLogicalTop();
    731                 lineTopIncludingMargins = lineTop;
    732             } else {
    733                 lineTop = std::min<LayoutUnit>(lineTop, pixelSnappedLogicalTop());
    734                 lineTopIncludingMargins = std::min(lineTop, lineTopIncludingMargins);
    735             }
    736             selectionBottom = std::max<LayoutUnit>(selectionBottom, pixelSnappedLogicalBottom());
    737             lineBottom = std::max<LayoutUnit>(lineBottom, pixelSnappedLogicalBottom());
    738             lineBottomIncludingMargins = std::max(lineBottom, lineBottomIncludingMargins);
    739         }
    740 
    741         if (renderer().style()->isFlippedLinesWritingMode())
    742             flipLinesInBlockDirection(lineTopIncludingMargins, lineBottomIncludingMargins);
    743     }
    744 }
    745 
    746 void InlineFlowBox::computeMaxLogicalTop(float& maxLogicalTop) const
    747 {
    748     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
    749         if (curr->renderer().isOutOfFlowPositioned())
    750             continue; // Positioned placeholders don't affect calculations.
    751 
    752         if (descendantsHaveSameLineHeightAndBaseline())
    753             continue;
    754 
    755         maxLogicalTop = std::max<float>(maxLogicalTop, curr->y());
    756         float localMaxLogicalTop = 0;
    757         if (curr->isInlineFlowBox())
    758             toInlineFlowBox(curr)->computeMaxLogicalTop(localMaxLogicalTop);
    759         maxLogicalTop = std::max<float>(maxLogicalTop, localMaxLogicalTop);
    760     }
    761 }
    762 
    763 void InlineFlowBox::flipLinesInBlockDirection(LayoutUnit lineTop, LayoutUnit lineBottom)
    764 {
    765     // Flip the box on the line such that the top is now relative to the lineBottom instead of the lineTop.
    766     setLogicalTop(lineBottom - (logicalTop() - lineTop) - logicalHeight());
    767 
    768     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
    769         if (curr->renderer().isOutOfFlowPositioned())
    770             continue; // Positioned placeholders aren't affected here.
    771 
    772         if (curr->isInlineFlowBox())
    773             toInlineFlowBox(curr)->flipLinesInBlockDirection(lineTop, lineBottom);
    774         else
    775             curr->setLogicalTop(lineBottom - (curr->logicalTop() - lineTop) - curr->logicalHeight());
    776     }
    777 }
    778 
    779 inline void InlineFlowBox::addBoxShadowVisualOverflow(LayoutRect& logicalVisualOverflow)
    780 {
    781     // box-shadow on root line boxes is applying to the block and not to the lines.
    782     if (!parent())
    783         return;
    784 
    785     RenderStyle* style = renderer().style(isFirstLineStyle());
    786     if (!style->boxShadow())
    787         return;
    788 
    789     LayoutUnit boxShadowLogicalTop;
    790     LayoutUnit boxShadowLogicalBottom;
    791     style->getBoxShadowBlockDirectionExtent(boxShadowLogicalTop, boxShadowLogicalBottom);
    792 
    793     // Similar to how glyph overflow works, if our lines are flipped, then it's actually the opposite shadow that applies, since
    794     // the line is "upside down" in terms of block coordinates.
    795     LayoutUnit shadowLogicalTop = style->isFlippedLinesWritingMode() ? -boxShadowLogicalBottom : boxShadowLogicalTop;
    796     LayoutUnit shadowLogicalBottom = style->isFlippedLinesWritingMode() ? -boxShadowLogicalTop : boxShadowLogicalBottom;
    797 
    798     LayoutUnit logicalTopVisualOverflow = std::min(pixelSnappedLogicalTop() + shadowLogicalTop, logicalVisualOverflow.y());
    799     LayoutUnit logicalBottomVisualOverflow = std::max(pixelSnappedLogicalBottom() + shadowLogicalBottom, logicalVisualOverflow.maxY());
    800 
    801     LayoutUnit boxShadowLogicalLeft;
    802     LayoutUnit boxShadowLogicalRight;
    803     style->getBoxShadowInlineDirectionExtent(boxShadowLogicalLeft, boxShadowLogicalRight);
    804 
    805     LayoutUnit logicalLeftVisualOverflow = std::min(pixelSnappedLogicalLeft() + boxShadowLogicalLeft, logicalVisualOverflow.x());
    806     LayoutUnit logicalRightVisualOverflow = std::max(pixelSnappedLogicalRight() + boxShadowLogicalRight, logicalVisualOverflow.maxX());
    807 
    808     logicalVisualOverflow = LayoutRect(logicalLeftVisualOverflow, logicalTopVisualOverflow,
    809                                        logicalRightVisualOverflow - logicalLeftVisualOverflow, logicalBottomVisualOverflow - logicalTopVisualOverflow);
    810 }
    811 
    812 inline void InlineFlowBox::addBorderOutsetVisualOverflow(LayoutRect& logicalVisualOverflow)
    813 {
    814     // border-image-outset on root line boxes is applying to the block and not to the lines.
    815     if (!parent())
    816         return;
    817 
    818     RenderStyle* style = renderer().style(isFirstLineStyle());
    819     if (!style->hasBorderImageOutsets())
    820         return;
    821 
    822     LayoutBoxExtent borderOutsets = style->borderImageOutsets();
    823 
    824     LayoutUnit borderOutsetLogicalTop = borderOutsets.logicalTop(style->writingMode());
    825     LayoutUnit borderOutsetLogicalBottom = borderOutsets.logicalBottom(style->writingMode());
    826     LayoutUnit borderOutsetLogicalLeft = borderOutsets.logicalLeft(style->writingMode());
    827     LayoutUnit borderOutsetLogicalRight = borderOutsets.logicalRight(style->writingMode());
    828 
    829     // Similar to how glyph overflow works, if our lines are flipped, then it's actually the opposite border that applies, since
    830     // the line is "upside down" in terms of block coordinates. vertical-rl and horizontal-bt are the flipped line modes.
    831     LayoutUnit outsetLogicalTop = style->isFlippedLinesWritingMode() ? borderOutsetLogicalBottom : borderOutsetLogicalTop;
    832     LayoutUnit outsetLogicalBottom = style->isFlippedLinesWritingMode() ? borderOutsetLogicalTop : borderOutsetLogicalBottom;
    833 
    834     LayoutUnit logicalTopVisualOverflow = std::min(pixelSnappedLogicalTop() - outsetLogicalTop, logicalVisualOverflow.y());
    835     LayoutUnit logicalBottomVisualOverflow = std::max(pixelSnappedLogicalBottom() + outsetLogicalBottom, logicalVisualOverflow.maxY());
    836 
    837     LayoutUnit outsetLogicalLeft = includeLogicalLeftEdge() ? borderOutsetLogicalLeft : LayoutUnit();
    838     LayoutUnit outsetLogicalRight = includeLogicalRightEdge() ? borderOutsetLogicalRight : LayoutUnit();
    839 
    840     LayoutUnit logicalLeftVisualOverflow = std::min(pixelSnappedLogicalLeft() - outsetLogicalLeft, logicalVisualOverflow.x());
    841     LayoutUnit logicalRightVisualOverflow = std::max(pixelSnappedLogicalRight() + outsetLogicalRight, logicalVisualOverflow.maxX());
    842 
    843     logicalVisualOverflow = LayoutRect(logicalLeftVisualOverflow, logicalTopVisualOverflow,
    844                                        logicalRightVisualOverflow - logicalLeftVisualOverflow, logicalBottomVisualOverflow - logicalTopVisualOverflow);
    845 }
    846 
    847 inline void InlineFlowBox::addOutlineVisualOverflow(LayoutRect& logicalVisualOverflow)
    848 {
    849     // Outline on root line boxes is applied to the block and not to the lines.
    850     if (!parent())
    851         return;
    852 
    853     RenderStyle* style = renderer().style(isFirstLineStyle());
    854     if (!style->hasOutline())
    855         return;
    856 
    857     logicalVisualOverflow.inflate(style->outlineSize());
    858 }
    859 
    860 inline void InlineFlowBox::addTextBoxVisualOverflow(InlineTextBox* textBox, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, LayoutRect& logicalVisualOverflow)
    861 {
    862     if (textBox->knownToHaveNoOverflow())
    863         return;
    864 
    865     RenderStyle* style = textBox->renderer().style(isFirstLineStyle());
    866 
    867     GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.find(textBox);
    868     GlyphOverflow* glyphOverflow = it == textBoxDataMap.end() ? 0 : &it->value.second;
    869     bool isFlippedLine = style->isFlippedLinesWritingMode();
    870 
    871     int topGlyphEdge = glyphOverflow ? (isFlippedLine ? glyphOverflow->bottom : glyphOverflow->top) : 0;
    872     int bottomGlyphEdge = glyphOverflow ? (isFlippedLine ? glyphOverflow->top : glyphOverflow->bottom) : 0;
    873     int leftGlyphEdge = glyphOverflow ? glyphOverflow->left : 0;
    874     int rightGlyphEdge = glyphOverflow ? glyphOverflow->right : 0;
    875 
    876     int strokeOverflow = static_cast<int>(ceilf(style->textStrokeWidth() / 2.0f));
    877     int topGlyphOverflow = -strokeOverflow - topGlyphEdge;
    878     int bottomGlyphOverflow = strokeOverflow + bottomGlyphEdge;
    879     int leftGlyphOverflow = -strokeOverflow - leftGlyphEdge;
    880     int rightGlyphOverflow = strokeOverflow + rightGlyphEdge;
    881 
    882     TextEmphasisPosition emphasisMarkPosition;
    883     if (style->textEmphasisMark() != TextEmphasisMarkNone && textBox->getEmphasisMarkPosition(style, emphasisMarkPosition)) {
    884         int emphasisMarkHeight = style->font().emphasisMarkHeight(style->textEmphasisMarkString());
    885         if ((emphasisMarkPosition == TextEmphasisPositionOver) == (!style->isFlippedLinesWritingMode()))
    886             topGlyphOverflow = std::min(topGlyphOverflow, -emphasisMarkHeight);
    887         else
    888             bottomGlyphOverflow = std::max(bottomGlyphOverflow, emphasisMarkHeight);
    889     }
    890 
    891     // If letter-spacing is negative, we should factor that into right layout overflow. (Even in RTL, letter-spacing is
    892     // applied to the right, so this is not an issue with left overflow.
    893     rightGlyphOverflow -= std::min(0, (int)style->font().fontDescription().letterSpacing());
    894 
    895     LayoutUnit textShadowLogicalTop;
    896     LayoutUnit textShadowLogicalBottom;
    897     style->getTextShadowBlockDirectionExtent(textShadowLogicalTop, textShadowLogicalBottom);
    898 
    899     LayoutUnit childOverflowLogicalTop = std::min<LayoutUnit>(textShadowLogicalTop + topGlyphOverflow, topGlyphOverflow);
    900     LayoutUnit childOverflowLogicalBottom = std::max<LayoutUnit>(textShadowLogicalBottom + bottomGlyphOverflow, bottomGlyphOverflow);
    901 
    902     LayoutUnit textShadowLogicalLeft;
    903     LayoutUnit textShadowLogicalRight;
    904     style->getTextShadowInlineDirectionExtent(textShadowLogicalLeft, textShadowLogicalRight);
    905 
    906     LayoutUnit childOverflowLogicalLeft = std::min<LayoutUnit>(textShadowLogicalLeft + leftGlyphOverflow, leftGlyphOverflow);
    907     LayoutUnit childOverflowLogicalRight = std::max<LayoutUnit>(textShadowLogicalRight + rightGlyphOverflow, rightGlyphOverflow);
    908 
    909     LayoutUnit logicalTopVisualOverflow = std::min(textBox->pixelSnappedLogicalTop() + childOverflowLogicalTop, logicalVisualOverflow.y());
    910     LayoutUnit logicalBottomVisualOverflow = std::max(textBox->pixelSnappedLogicalBottom() + childOverflowLogicalBottom, logicalVisualOverflow.maxY());
    911     LayoutUnit logicalLeftVisualOverflow = std::min(textBox->pixelSnappedLogicalLeft() + childOverflowLogicalLeft, logicalVisualOverflow.x());
    912     LayoutUnit logicalRightVisualOverflow = std::max(textBox->pixelSnappedLogicalRight() + childOverflowLogicalRight, logicalVisualOverflow.maxX());
    913 
    914     logicalVisualOverflow = LayoutRect(logicalLeftVisualOverflow, logicalTopVisualOverflow,
    915                                        logicalRightVisualOverflow - logicalLeftVisualOverflow, logicalBottomVisualOverflow - logicalTopVisualOverflow);
    916 
    917     textBox->setLogicalOverflowRect(logicalVisualOverflow);
    918 }
    919 
    920 inline void InlineFlowBox::addReplacedChildOverflow(const InlineBox* inlineBox, LayoutRect& logicalLayoutOverflow, LayoutRect& logicalVisualOverflow)
    921 {
    922     RenderBox& box = toRenderBox(inlineBox->renderer());
    923 
    924     // Visual overflow only propagates if the box doesn't have a self-painting layer.  This rectangle does not include
    925     // transforms or relative positioning (since those objects always have self-painting layers), but it does need to be adjusted
    926     // for writing-mode differences.
    927     if (!box.hasSelfPaintingLayer()) {
    928         LayoutRect childLogicalVisualOverflow = box.logicalVisualOverflowRectForPropagation(renderer().style());
    929         childLogicalVisualOverflow.move(inlineBox->logicalLeft(), inlineBox->logicalTop());
    930         logicalVisualOverflow.unite(childLogicalVisualOverflow);
    931     }
    932 
    933     // Layout overflow internal to the child box only propagates if the child box doesn't have overflow clip set.
    934     // Otherwise the child border box propagates as layout overflow.  This rectangle must include transforms and relative positioning
    935     // and be adjusted for writing-mode differences.
    936     LayoutRect childLogicalLayoutOverflow = box.logicalLayoutOverflowRectForPropagation(renderer().style());
    937     childLogicalLayoutOverflow.move(inlineBox->logicalLeft(), inlineBox->logicalTop());
    938     logicalLayoutOverflow.unite(childLogicalLayoutOverflow);
    939 }
    940 
    941 void InlineFlowBox::computeOverflow(LayoutUnit lineTop, LayoutUnit lineBottom, GlyphOverflowAndFallbackFontsMap& textBoxDataMap)
    942 {
    943     // If we know we have no overflow, we can just bail.
    944     if (knownToHaveNoOverflow()) {
    945         ASSERT(!m_overflow);
    946         return;
    947     }
    948 
    949     if (m_overflow)
    950         m_overflow.clear();
    951 
    952     // Visual overflow just includes overflow for stuff we need to issues paint invalidations for ourselves. Self-painting layers are ignored.
    953     // Layout overflow is used to determine scrolling extent, so it still includes child layers and also factors in
    954     // transforms, relative positioning, etc.
    955     LayoutRect logicalLayoutOverflow(enclosingLayoutRect(logicalFrameRectIncludingLineHeight(lineTop, lineBottom)));
    956     LayoutRect logicalVisualOverflow(logicalLayoutOverflow);
    957 
    958     addBoxShadowVisualOverflow(logicalVisualOverflow);
    959     addBorderOutsetVisualOverflow(logicalVisualOverflow);
    960     addOutlineVisualOverflow(logicalVisualOverflow);
    961 
    962     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
    963         if (curr->renderer().isOutOfFlowPositioned())
    964             continue; // Positioned placeholders don't affect calculations.
    965 
    966         if (curr->renderer().isText()) {
    967             InlineTextBox* text = toInlineTextBox(curr);
    968             RenderText& rt = text->renderer();
    969             if (rt.isBR())
    970                 continue;
    971             LayoutRect textBoxOverflow(enclosingLayoutRect(text->logicalFrameRect()));
    972             addTextBoxVisualOverflow(text, textBoxDataMap, textBoxOverflow);
    973             logicalVisualOverflow.unite(textBoxOverflow);
    974         } else if (curr->renderer().isRenderInline()) {
    975             InlineFlowBox* flow = toInlineFlowBox(curr);
    976             flow->computeOverflow(lineTop, lineBottom, textBoxDataMap);
    977             if (!flow->boxModelObject()->hasSelfPaintingLayer())
    978                 logicalVisualOverflow.unite(flow->logicalVisualOverflowRect(lineTop, lineBottom));
    979             LayoutRect childLayoutOverflow = flow->logicalLayoutOverflowRect(lineTop, lineBottom);
    980             childLayoutOverflow.move(flow->boxModelObject()->relativePositionLogicalOffset());
    981             logicalLayoutOverflow.unite(childLayoutOverflow);
    982         } else {
    983             addReplacedChildOverflow(curr, logicalLayoutOverflow, logicalVisualOverflow);
    984         }
    985     }
    986 
    987     setOverflowFromLogicalRects(logicalLayoutOverflow, logicalVisualOverflow, lineTop, lineBottom);
    988 }
    989 
    990 void InlineFlowBox::setLayoutOverflow(const LayoutRect& rect, const LayoutRect& frameBox)
    991 {
    992     if (frameBox.contains(rect) || rect.isEmpty())
    993         return;
    994 
    995     if (!m_overflow)
    996         m_overflow = adoptPtr(new RenderOverflow(frameBox, frameBox));
    997 
    998     m_overflow->setLayoutOverflow(rect);
    999 }
   1000 
   1001 void InlineFlowBox::setVisualOverflow(const LayoutRect& rect, const LayoutRect& frameBox)
   1002 {
   1003     if (frameBox.contains(rect) || rect.isEmpty())
   1004         return;
   1005 
   1006     if (!m_overflow)
   1007         m_overflow = adoptPtr(new RenderOverflow(frameBox, frameBox));
   1008 
   1009     m_overflow->setVisualOverflow(rect);
   1010 }
   1011 
   1012 void InlineFlowBox::setOverflowFromLogicalRects(const LayoutRect& logicalLayoutOverflow, const LayoutRect& logicalVisualOverflow, LayoutUnit lineTop, LayoutUnit lineBottom)
   1013 {
   1014     LayoutRect frameBox = enclosingLayoutRect(frameRectIncludingLineHeight(lineTop, lineBottom));
   1015 
   1016     LayoutRect layoutOverflow(isHorizontal() ? logicalLayoutOverflow : logicalLayoutOverflow.transposedRect());
   1017     setLayoutOverflow(layoutOverflow, frameBox);
   1018 
   1019     LayoutRect visualOverflow(isHorizontal() ? logicalVisualOverflow : logicalVisualOverflow.transposedRect());
   1020     setVisualOverflow(visualOverflow, frameBox);
   1021 }
   1022 
   1023 bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom)
   1024 {
   1025     LayoutRect overflowRect(visualOverflowRect(lineTop, lineBottom));
   1026     flipForWritingMode(overflowRect);
   1027     overflowRect.moveBy(accumulatedOffset);
   1028     if (!locationInContainer.intersects(overflowRect))
   1029         return false;
   1030 
   1031     // Check children first.
   1032     // We need to account for culled inline parents of the hit-tested nodes, so that they may also get included in area-based hit-tests.
   1033     RenderObject* culledParent = 0;
   1034     for (InlineBox* curr = lastChild(); curr; curr = curr->prevOnLine()) {
   1035         if (curr->renderer().isText() || !curr->boxModelObject()->hasSelfPaintingLayer()) {
   1036             RenderObject* newParent = 0;
   1037             // Culled parents are only relevant for area-based hit-tests, so ignore it in point-based ones.
   1038             if (locationInContainer.isRectBasedTest()) {
   1039                 newParent = curr->renderer().parent();
   1040                 if (newParent == renderer())
   1041                     newParent = 0;
   1042             }
   1043             // Check the culled parent after all its children have been checked, to do this we wait until
   1044             // we are about to test an element with a different parent.
   1045             if (newParent != culledParent) {
   1046                 if (!newParent || !newParent->isDescendantOf(culledParent)) {
   1047                     while (culledParent && culledParent != renderer() && culledParent != newParent) {
   1048                         if (culledParent->isRenderInline() && toRenderInline(culledParent)->hitTestCulledInline(request, result, locationInContainer, accumulatedOffset))
   1049                             return true;
   1050                         culledParent = culledParent->parent();
   1051                     }
   1052                 }
   1053                 culledParent = newParent;
   1054             }
   1055             if (curr->nodeAtPoint(request, result, locationInContainer, accumulatedOffset, lineTop, lineBottom)) {
   1056                 renderer().updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset));
   1057                 return true;
   1058             }
   1059         }
   1060     }
   1061     // Check any culled ancestor of the final children tested.
   1062     while (culledParent && culledParent != renderer()) {
   1063         if (culledParent->isRenderInline() && toRenderInline(culledParent)->hitTestCulledInline(request, result, locationInContainer, accumulatedOffset))
   1064             return true;
   1065         culledParent = culledParent->parent();
   1066     }
   1067 
   1068     // Now check ourselves. Pixel snap hit testing.
   1069     LayoutRect frameRect = roundedFrameRect();
   1070     LayoutUnit minX = frameRect.x();
   1071     LayoutUnit minY = frameRect.y();
   1072     LayoutUnit width = frameRect.width();
   1073     LayoutUnit height = frameRect.height();
   1074 
   1075     // Constrain our hit testing to the line top and bottom if necessary.
   1076     bool noQuirksMode = renderer().document().inNoQuirksMode();
   1077     if (!noQuirksMode && !hasTextChildren() && !(descendantsHaveSameLineHeightAndBaseline() && hasTextDescendants())) {
   1078         RootInlineBox& rootBox = root();
   1079         LayoutUnit& top = isHorizontal() ? minY : minX;
   1080         LayoutUnit& logicalHeight = isHorizontal() ? height : width;
   1081         LayoutUnit bottom = std::min(rootBox.lineBottom(), top + logicalHeight);
   1082         top = std::max(rootBox.lineTop(), top);
   1083         logicalHeight = bottom - top;
   1084     }
   1085 
   1086     // Move x/y to our coordinates.
   1087     LayoutRect rect(minX, minY, width, height);
   1088     flipForWritingMode(rect);
   1089     rect.moveBy(accumulatedOffset);
   1090 
   1091     if (visibleToHitTestRequest(request) && locationInContainer.intersects(rect)) {
   1092         renderer().updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(accumulatedOffset))); // Don't add in m_x or m_y here, we want coords in the containing block's space.
   1093         if (!result.addNodeToRectBasedTestResult(renderer().node(), request, locationInContainer, rect))
   1094             return true;
   1095     }
   1096 
   1097     return false;
   1098 }
   1099 
   1100 void InlineFlowBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom)
   1101 {
   1102     InlineFlowBoxPainter(*this).paint(paintInfo, paintOffset, lineTop, lineBottom);
   1103 }
   1104 
   1105 bool InlineFlowBox::boxShadowCanBeAppliedToBackground(const FillLayer& lastBackgroundLayer) const
   1106 {
   1107     // The checks here match how paintFillLayer() decides whether to clip (if it does, the shadow
   1108     // would be clipped out, so it has to be drawn separately).
   1109     StyleImage* image = lastBackgroundLayer.image();
   1110     bool hasFillImage = image && image->canRender(renderer(), renderer().style()->effectiveZoom());
   1111     return (!hasFillImage && !renderer().style()->hasBorderRadius()) || (!prevLineBox() && !nextLineBox()) || !parent();
   1112 }
   1113 
   1114 void InlineFlowBox::constrainToLineTopAndBottomIfNeeded(LayoutRect& rect) const
   1115 {
   1116     bool noQuirksMode = renderer().document().inNoQuirksMode();
   1117     if (!noQuirksMode && !hasTextChildren() && !(descendantsHaveSameLineHeightAndBaseline() && hasTextDescendants())) {
   1118         const RootInlineBox& rootBox = root();
   1119         LayoutUnit logicalTop = isHorizontal() ? rect.y() : rect.x();
   1120         LayoutUnit logicalHeight = isHorizontal() ? rect.height() : rect.width();
   1121         LayoutUnit bottom = std::min(rootBox.lineBottom(), logicalTop + logicalHeight);
   1122         logicalTop = std::max(rootBox.lineTop(), logicalTop);
   1123         logicalHeight = bottom - logicalTop;
   1124         if (isHorizontal()) {
   1125             rect.setY(logicalTop);
   1126             rect.setHeight(logicalHeight);
   1127         } else {
   1128             rect.setX(logicalTop);
   1129             rect.setWidth(logicalHeight);
   1130         }
   1131     }
   1132 }
   1133 
   1134 InlineBox* InlineFlowBox::firstLeafChild() const
   1135 {
   1136     InlineBox* leaf = 0;
   1137     for (InlineBox* child = firstChild(); child && !leaf; child = child->nextOnLine())
   1138         leaf = child->isLeaf() ? child : toInlineFlowBox(child)->firstLeafChild();
   1139     return leaf;
   1140 }
   1141 
   1142 InlineBox* InlineFlowBox::lastLeafChild() const
   1143 {
   1144     InlineBox* leaf = 0;
   1145     for (InlineBox* child = lastChild(); child && !leaf; child = child->prevOnLine())
   1146         leaf = child->isLeaf() ? child : toInlineFlowBox(child)->lastLeafChild();
   1147     return leaf;
   1148 }
   1149 
   1150 RenderObject::SelectionState InlineFlowBox::selectionState() const
   1151 {
   1152     return RenderObject::SelectionNone;
   1153 }
   1154 
   1155 bool InlineFlowBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) const
   1156 {
   1157     for (InlineBox *box = firstChild(); box; box = box->nextOnLine()) {
   1158         if (!box->canAccommodateEllipsis(ltr, blockEdge, ellipsisWidth))
   1159             return false;
   1160     }
   1161     return true;
   1162 }
   1163 
   1164 float InlineFlowBox::placeEllipsisBox(bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, float &truncatedWidth, bool& foundBox)
   1165 {
   1166     float result = -1;
   1167     // We iterate over all children, the foundBox variable tells us when we've found the
   1168     // box containing the ellipsis.  All boxes after that one in the flow are hidden.
   1169     // If our flow is ltr then iterate over the boxes from left to right, otherwise iterate
   1170     // from right to left. Varying the order allows us to correctly hide the boxes following the ellipsis.
   1171     InlineBox* box = ltr ? firstChild() : lastChild();
   1172 
   1173     // NOTE: these will cross after foundBox = true.
   1174     int visibleLeftEdge = blockLeftEdge;
   1175     int visibleRightEdge = blockRightEdge;
   1176 
   1177     while (box) {
   1178         int currResult = box->placeEllipsisBox(ltr, visibleLeftEdge, visibleRightEdge, ellipsisWidth, truncatedWidth, foundBox);
   1179         if (currResult != -1 && result == -1)
   1180             result = currResult;
   1181 
   1182         if (ltr) {
   1183             visibleLeftEdge += box->logicalWidth();
   1184             box = box->nextOnLine();
   1185         }
   1186         else {
   1187             visibleRightEdge -= box->logicalWidth();
   1188             box = box->prevOnLine();
   1189         }
   1190     }
   1191     return result;
   1192 }
   1193 
   1194 void InlineFlowBox::clearTruncation()
   1195 {
   1196     for (InlineBox *box = firstChild(); box; box = box->nextOnLine())
   1197         box->clearTruncation();
   1198 }
   1199 
   1200 LayoutUnit InlineFlowBox::computeOverAnnotationAdjustment(LayoutUnit allowedPosition) const
   1201 {
   1202     LayoutUnit result = 0;
   1203     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
   1204         if (curr->renderer().isOutOfFlowPositioned())
   1205             continue; // Positioned placeholders don't affect calculations.
   1206 
   1207         if (curr->isInlineFlowBox())
   1208             result = std::max(result, toInlineFlowBox(curr)->computeOverAnnotationAdjustment(allowedPosition));
   1209 
   1210         if (curr->renderer().isReplaced() && curr->renderer().isRubyRun() && curr->renderer().style()->rubyPosition() == RubyPositionBefore) {
   1211             RenderRubyRun& rubyRun = toRenderRubyRun(curr->renderer());
   1212             RenderRubyText* rubyText = rubyRun.rubyText();
   1213             if (!rubyText)
   1214                 continue;
   1215 
   1216             if (!rubyRun.style()->isFlippedLinesWritingMode()) {
   1217                 LayoutUnit topOfFirstRubyTextLine = rubyText->logicalTop() + (rubyText->firstRootBox() ? rubyText->firstRootBox()->lineTop() : LayoutUnit());
   1218                 if (topOfFirstRubyTextLine >= 0)
   1219                     continue;
   1220                 topOfFirstRubyTextLine += curr->logicalTop();
   1221                 result = std::max(result, allowedPosition - topOfFirstRubyTextLine);
   1222             } else {
   1223                 LayoutUnit bottomOfLastRubyTextLine = rubyText->logicalTop() + (rubyText->lastRootBox() ? rubyText->lastRootBox()->lineBottom() : rubyText->logicalHeight());
   1224                 if (bottomOfLastRubyTextLine <= curr->logicalHeight())
   1225                     continue;
   1226                 bottomOfLastRubyTextLine += curr->logicalTop();
   1227                 result = std::max(result, bottomOfLastRubyTextLine - allowedPosition);
   1228             }
   1229         }
   1230 
   1231         if (curr->isInlineTextBox()) {
   1232             RenderStyle* style = curr->renderer().style(isFirstLineStyle());
   1233             TextEmphasisPosition emphasisMarkPosition;
   1234             if (style->textEmphasisMark() != TextEmphasisMarkNone && toInlineTextBox(curr)->getEmphasisMarkPosition(style, emphasisMarkPosition) && emphasisMarkPosition == TextEmphasisPositionOver) {
   1235                 if (!style->isFlippedLinesWritingMode()) {
   1236                     int topOfEmphasisMark = curr->logicalTop() - style->font().emphasisMarkHeight(style->textEmphasisMarkString());
   1237                     result = std::max(result, allowedPosition - topOfEmphasisMark);
   1238                 } else {
   1239                     int bottomOfEmphasisMark = curr->logicalBottom() + style->font().emphasisMarkHeight(style->textEmphasisMarkString());
   1240                     result = std::max(result, bottomOfEmphasisMark - allowedPosition);
   1241                 }
   1242             }
   1243         }
   1244     }
   1245     return result;
   1246 }
   1247 
   1248 LayoutUnit InlineFlowBox::computeUnderAnnotationAdjustment(LayoutUnit allowedPosition) const
   1249 {
   1250     LayoutUnit result = 0;
   1251     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
   1252         if (curr->renderer().isOutOfFlowPositioned())
   1253             continue; // Positioned placeholders don't affect calculations.
   1254 
   1255         if (curr->isInlineFlowBox())
   1256             result = std::max(result, toInlineFlowBox(curr)->computeUnderAnnotationAdjustment(allowedPosition));
   1257 
   1258         if (curr->renderer().isReplaced() && curr->renderer().isRubyRun() && curr->renderer().style()->rubyPosition() == RubyPositionAfter) {
   1259             RenderRubyRun& rubyRun = toRenderRubyRun(curr->renderer());
   1260             RenderRubyText* rubyText = rubyRun.rubyText();
   1261             if (!rubyText)
   1262                 continue;
   1263 
   1264             if (rubyRun.style()->isFlippedLinesWritingMode()) {
   1265                 LayoutUnit topOfFirstRubyTextLine = rubyText->logicalTop() + (rubyText->firstRootBox() ? rubyText->firstRootBox()->lineTop() : LayoutUnit());
   1266                 if (topOfFirstRubyTextLine >= 0)
   1267                     continue;
   1268                 topOfFirstRubyTextLine += curr->logicalTop();
   1269                 result = std::max(result, allowedPosition - topOfFirstRubyTextLine);
   1270             } else {
   1271                 LayoutUnit bottomOfLastRubyTextLine = rubyText->logicalTop() + (rubyText->lastRootBox() ? rubyText->lastRootBox()->lineBottom() : rubyText->logicalHeight());
   1272                 if (bottomOfLastRubyTextLine <= curr->logicalHeight())
   1273                     continue;
   1274                 bottomOfLastRubyTextLine += curr->logicalTop();
   1275                 result = std::max(result, bottomOfLastRubyTextLine - allowedPosition);
   1276             }
   1277         }
   1278 
   1279         if (curr->isInlineTextBox()) {
   1280             RenderStyle* style = curr->renderer().style(isFirstLineStyle());
   1281             if (style->textEmphasisMark() != TextEmphasisMarkNone && style->textEmphasisPosition() == TextEmphasisPositionUnder) {
   1282                 if (!style->isFlippedLinesWritingMode()) {
   1283                     LayoutUnit bottomOfEmphasisMark = curr->logicalBottom() + style->font().emphasisMarkHeight(style->textEmphasisMarkString());
   1284                     result = std::max(result, bottomOfEmphasisMark - allowedPosition);
   1285                 } else {
   1286                     LayoutUnit topOfEmphasisMark = curr->logicalTop() - style->font().emphasisMarkHeight(style->textEmphasisMarkString());
   1287                     result = std::max(result, allowedPosition - topOfEmphasisMark);
   1288                 }
   1289             }
   1290         }
   1291     }
   1292     return result;
   1293 }
   1294 
   1295 void InlineFlowBox::collectLeafBoxesInLogicalOrder(Vector<InlineBox*>& leafBoxesInLogicalOrder, CustomInlineBoxRangeReverse customReverseImplementation, void* userData) const
   1296 {
   1297     InlineBox* leaf = firstLeafChild();
   1298 
   1299     // FIXME: The reordering code is a copy of parts from BidiResolver::createBidiRunsForLine, operating directly on InlineBoxes, instead of BidiRuns.
   1300     // Investigate on how this code could possibly be shared.
   1301     unsigned char minLevel = 128;
   1302     unsigned char maxLevel = 0;
   1303 
   1304     // First find highest and lowest levels, and initialize leafBoxesInLogicalOrder with the leaf boxes in visual order.
   1305     for (; leaf; leaf = leaf->nextLeafChild()) {
   1306         minLevel = std::min(minLevel, leaf->bidiLevel());
   1307         maxLevel = std::max(maxLevel, leaf->bidiLevel());
   1308         leafBoxesInLogicalOrder.append(leaf);
   1309     }
   1310 
   1311     if (renderer().style()->rtlOrdering() == VisualOrder)
   1312         return;
   1313 
   1314     // Reverse of reordering of the line (L2 according to Bidi spec):
   1315     // L2. From the highest level found in the text to the lowest odd level on each line,
   1316     // reverse any contiguous sequence of characters that are at that level or higher.
   1317 
   1318     // Reversing the reordering of the line is only done up to the lowest odd level.
   1319     if (!(minLevel % 2))
   1320         ++minLevel;
   1321 
   1322     Vector<InlineBox*>::iterator end = leafBoxesInLogicalOrder.end();
   1323     while (minLevel <= maxLevel) {
   1324         Vector<InlineBox*>::iterator it = leafBoxesInLogicalOrder.begin();
   1325         while (it != end) {
   1326             while (it != end) {
   1327                 if ((*it)->bidiLevel() >= minLevel)
   1328                     break;
   1329                 ++it;
   1330             }
   1331             Vector<InlineBox*>::iterator first = it;
   1332             while (it != end) {
   1333                 if ((*it)->bidiLevel() < minLevel)
   1334                     break;
   1335                 ++it;
   1336             }
   1337             Vector<InlineBox*>::iterator last = it;
   1338             if (customReverseImplementation) {
   1339                 ASSERT(userData);
   1340                 (*customReverseImplementation)(userData, first, last);
   1341             } else
   1342                 std::reverse(first, last);
   1343         }
   1344         ++minLevel;
   1345     }
   1346 }
   1347 
   1348 #ifndef NDEBUG
   1349 
   1350 const char* InlineFlowBox::boxName() const
   1351 {
   1352     return "InlineFlowBox";
   1353 }
   1354 
   1355 void InlineFlowBox::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const RenderObject* obj, int depth) const
   1356 {
   1357     InlineBox::showLineTreeAndMark(markedBox1, markedLabel1, markedBox2, markedLabel2, obj, depth);
   1358     for (const InlineBox* box = firstChild(); box; box = box->nextOnLine())
   1359         box->showLineTreeAndMark(markedBox1, markedLabel1, markedBox2, markedLabel2, obj, depth + 1);
   1360 }
   1361 
   1362 #endif
   1363 
   1364 #if ENABLE(ASSERT)
   1365 void InlineFlowBox::checkConsistency() const
   1366 {
   1367 #ifdef CHECK_CONSISTENCY
   1368     ASSERT(!m_hasBadChildList);
   1369     const InlineBox* prev = 0;
   1370     for (const InlineBox* child = m_firstChild; child; child = child->nextOnLine()) {
   1371         ASSERT(child->parent() == this);
   1372         ASSERT(child->prevOnLine() == prev);
   1373         prev = child;
   1374     }
   1375     ASSERT(prev == m_lastChild);
   1376 #endif
   1377 }
   1378 
   1379 #endif
   1380 
   1381 } // namespace blink
   1382