Home | History | Annotate | Download | only in rendering
      1 /*
      2  * Copyright (C) 2003, 2006, 2008 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/RootInlineBox.h"
     22 
     23 #include "core/dom/Document.h"
     24 #include "core/dom/StyleEngine.h"
     25 #include "core/rendering/EllipsisBox.h"
     26 #include "core/rendering/HitTestResult.h"
     27 #include "core/rendering/InlineTextBox.h"
     28 #include "core/rendering/PaintInfo.h"
     29 #include "core/rendering/RenderBlockFlow.h"
     30 #include "core/rendering/RenderFlowThread.h"
     31 #include "core/rendering/RenderInline.h"
     32 #include "core/rendering/RenderView.h"
     33 #include "core/rendering/VerticalPositionCache.h"
     34 #include "platform/text/BidiResolver.h"
     35 #include "wtf/unicode/Unicode.h"
     36 
     37 namespace blink {
     38 
     39 struct SameSizeAsRootInlineBox : public InlineFlowBox {
     40     unsigned unsignedVariable;
     41     void* pointers[4];
     42     LayoutUnit layoutVariables[5];
     43 };
     44 
     45 COMPILE_ASSERT(sizeof(RootInlineBox) == sizeof(SameSizeAsRootInlineBox), RootInlineBox_should_stay_small);
     46 
     47 typedef WTF::HashMap<const RootInlineBox*, EllipsisBox*> EllipsisBoxMap;
     48 static EllipsisBoxMap* gEllipsisBoxMap = 0;
     49 
     50 RootInlineBox::RootInlineBox(RenderBlockFlow& block)
     51     : InlineFlowBox(block)
     52     , m_lineBreakPos(0)
     53     , m_lineBreakObj(0)
     54     , m_lineTop(0)
     55     , m_lineBottom(0)
     56     , m_lineTopWithLeading(0)
     57     , m_lineBottomWithLeading(0)
     58     , m_selectionBottom(0)
     59 {
     60     setIsHorizontal(block.isHorizontalWritingMode());
     61 }
     62 
     63 
     64 void RootInlineBox::destroy()
     65 {
     66     detachEllipsisBox();
     67     InlineFlowBox::destroy();
     68 }
     69 
     70 void RootInlineBox::detachEllipsisBox()
     71 {
     72     if (hasEllipsisBox()) {
     73         EllipsisBox* box = gEllipsisBoxMap->take(this);
     74         box->setParent(0);
     75         box->destroy();
     76         setHasEllipsisBox(false);
     77     }
     78 }
     79 
     80 RenderLineBoxList* RootInlineBox::rendererLineBoxes() const
     81 {
     82     return block().lineBoxes();
     83 }
     84 
     85 void RootInlineBox::clearTruncation()
     86 {
     87     if (hasEllipsisBox()) {
     88         detachEllipsisBox();
     89         InlineFlowBox::clearTruncation();
     90     }
     91 }
     92 
     93 int RootInlineBox::baselinePosition(FontBaseline baselineType) const
     94 {
     95     return boxModelObject()->baselinePosition(baselineType, isFirstLineStyle(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
     96 }
     97 
     98 LayoutUnit RootInlineBox::lineHeight() const
     99 {
    100     return boxModelObject()->lineHeight(isFirstLineStyle(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
    101 }
    102 
    103 bool RootInlineBox::lineCanAccommodateEllipsis(bool ltr, int blockEdge, int lineBoxEdge, int ellipsisWidth)
    104 {
    105     // First sanity-check the unoverflowed width of the whole line to see if there is sufficient room.
    106     int delta = ltr ? lineBoxEdge - blockEdge : blockEdge - lineBoxEdge;
    107     if (logicalWidth() - delta < ellipsisWidth)
    108         return false;
    109 
    110     // Next iterate over all the line boxes on the line.  If we find a replaced element that intersects
    111     // then we refuse to accommodate the ellipsis.  Otherwise we're ok.
    112     return InlineFlowBox::canAccommodateEllipsis(ltr, blockEdge, ellipsisWidth);
    113 }
    114 
    115 float RootInlineBox::placeEllipsis(const AtomicString& ellipsisStr,  bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth,
    116                                   InlineBox* markupBox)
    117 {
    118     // Create an ellipsis box.
    119     EllipsisBox* ellipsisBox = new EllipsisBox(renderer(), ellipsisStr, this,
    120         ellipsisWidth - (markupBox ? markupBox->logicalWidth() : 0), logicalHeight(),
    121         x(), y(), !prevRootBox(), isHorizontal(), markupBox);
    122 
    123     if (!gEllipsisBoxMap)
    124         gEllipsisBoxMap = new EllipsisBoxMap();
    125     gEllipsisBoxMap->add(this, ellipsisBox);
    126     setHasEllipsisBox(true);
    127 
    128     // FIXME: Do we need an RTL version of this?
    129     if (ltr && (logicalLeft() + logicalWidth() + ellipsisWidth) <= blockRightEdge) {
    130         ellipsisBox->setLogicalLeft(logicalLeft() + logicalWidth());
    131         return logicalWidth() + ellipsisWidth;
    132     }
    133 
    134     // Now attempt to find the nearest glyph horizontally and place just to the right (or left in RTL)
    135     // of that glyph.  Mark all of the objects that intersect the ellipsis box as not painting (as being
    136     // truncated).
    137     bool foundBox = false;
    138     float truncatedWidth = 0;
    139     float position = placeEllipsisBox(ltr, blockLeftEdge, blockRightEdge, ellipsisWidth, truncatedWidth, foundBox);
    140     ellipsisBox->setLogicalLeft(position);
    141     return truncatedWidth;
    142 }
    143 
    144 float RootInlineBox::placeEllipsisBox(bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, float &truncatedWidth, bool& foundBox)
    145 {
    146     float result = InlineFlowBox::placeEllipsisBox(ltr, blockLeftEdge, blockRightEdge, ellipsisWidth, truncatedWidth, foundBox);
    147     if (result == -1) {
    148         result = ltr ? blockRightEdge - ellipsisWidth : blockLeftEdge;
    149         truncatedWidth = blockRightEdge - blockLeftEdge;
    150     }
    151     return result;
    152 }
    153 
    154 void RootInlineBox::paintEllipsisBox(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom) const
    155 {
    156     if (hasEllipsisBox() && paintInfo.shouldPaintWithinRoot(&renderer()) && renderer().style()->visibility() == VISIBLE
    157             && paintInfo.phase == PaintPhaseForeground)
    158         ellipsisBox()->paint(paintInfo, paintOffset, lineTop, lineBottom);
    159 }
    160 
    161 void RootInlineBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom)
    162 {
    163     InlineFlowBox::paint(paintInfo, paintOffset, lineTop, lineBottom);
    164     paintEllipsisBox(paintInfo, paintOffset, lineTop, lineBottom);
    165 }
    166 
    167 bool RootInlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom)
    168 {
    169     if (hasEllipsisBox() && visibleToHitTestRequest(request)) {
    170         if (ellipsisBox()->nodeAtPoint(request, result, locationInContainer, accumulatedOffset, lineTop, lineBottom)) {
    171             renderer().updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset));
    172             return true;
    173         }
    174     }
    175     return InlineFlowBox::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, lineTop, lineBottom);
    176 }
    177 
    178 void RootInlineBox::adjustPosition(float dx, float dy)
    179 {
    180     InlineFlowBox::adjustPosition(dx, dy);
    181     LayoutUnit blockDirectionDelta = isHorizontal() ? dy : dx; // The block direction delta is a LayoutUnit.
    182     m_lineTop += blockDirectionDelta;
    183     m_lineBottom += blockDirectionDelta;
    184     m_lineTopWithLeading += blockDirectionDelta;
    185     m_lineBottomWithLeading += blockDirectionDelta;
    186     m_selectionBottom += blockDirectionDelta;
    187     if (hasEllipsisBox())
    188         ellipsisBox()->adjustPosition(dx, dy);
    189 }
    190 
    191 void RootInlineBox::childRemoved(InlineBox* box)
    192 {
    193     if (&box->renderer() == m_lineBreakObj)
    194         setLineBreakInfo(0, 0, BidiStatus());
    195 
    196     for (RootInlineBox* prev = prevRootBox(); prev && prev->lineBreakObj() == &box->renderer(); prev = prev->prevRootBox()) {
    197         prev->setLineBreakInfo(0, 0, BidiStatus());
    198         prev->markDirty();
    199     }
    200 }
    201 
    202 LayoutUnit RootInlineBox::alignBoxesInBlockDirection(LayoutUnit heightOfBlock, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache)
    203 {
    204     // SVG will handle vertical alignment on its own.
    205     if (isSVGRootInlineBox())
    206         return 0;
    207 
    208     LayoutUnit maxPositionTop = 0;
    209     LayoutUnit maxPositionBottom = 0;
    210     int maxAscent = 0;
    211     int maxDescent = 0;
    212     bool setMaxAscent = false;
    213     bool setMaxDescent = false;
    214 
    215     // Figure out if we're in no-quirks mode.
    216     bool noQuirksMode = renderer().document().inNoQuirksMode();
    217 
    218     m_baselineType = requiresIdeographicBaseline(textBoxDataMap) ? IdeographicBaseline : AlphabeticBaseline;
    219 
    220     computeLogicalBoxHeights(this, maxPositionTop, maxPositionBottom, maxAscent, maxDescent, setMaxAscent, setMaxDescent, noQuirksMode,
    221                              textBoxDataMap, baselineType(), verticalPositionCache);
    222 
    223     if (maxAscent + maxDescent < std::max(maxPositionTop, maxPositionBottom))
    224         adjustMaxAscentAndDescent(maxAscent, maxDescent, maxPositionTop, maxPositionBottom);
    225 
    226     LayoutUnit maxHeight = maxAscent + maxDescent;
    227     LayoutUnit lineTop = heightOfBlock;
    228     LayoutUnit lineBottom = heightOfBlock;
    229     LayoutUnit lineTopIncludingMargins = heightOfBlock;
    230     LayoutUnit lineBottomIncludingMargins = heightOfBlock;
    231     LayoutUnit selectionBottom = heightOfBlock;
    232     bool setLineTop = false;
    233     bool hasAnnotationsBefore = false;
    234     bool hasAnnotationsAfter = false;
    235     placeBoxesInBlockDirection(heightOfBlock, maxHeight, maxAscent, noQuirksMode, lineTop, lineBottom, selectionBottom, setLineTop,
    236                                lineTopIncludingMargins, lineBottomIncludingMargins, hasAnnotationsBefore, hasAnnotationsAfter, baselineType());
    237     m_hasAnnotationsBefore = hasAnnotationsBefore;
    238     m_hasAnnotationsAfter = hasAnnotationsAfter;
    239 
    240     maxHeight = std::max<LayoutUnit>(0, maxHeight); // FIXME: Is this really necessary?
    241 
    242     setLineTopBottomPositions(lineTop, lineBottom, heightOfBlock, heightOfBlock + maxHeight, selectionBottom);
    243     if (block().view()->layoutState()->isPaginated())
    244         setPaginatedLineWidth(block().availableLogicalWidthForContent());
    245 
    246     LayoutUnit annotationsAdjustment = beforeAnnotationsAdjustment();
    247     if (annotationsAdjustment) {
    248         // FIXME: Need to handle pagination here. We might have to move to the next page/column as a result of the
    249         // ruby expansion.
    250         adjustBlockDirectionPosition(annotationsAdjustment.toFloat());
    251         heightOfBlock += annotationsAdjustment;
    252     }
    253 
    254     return heightOfBlock + maxHeight;
    255 }
    256 
    257 float RootInlineBox::maxLogicalTop() const
    258 {
    259     float maxLogicalTop = 0;
    260     computeMaxLogicalTop(maxLogicalTop);
    261     return maxLogicalTop;
    262 }
    263 
    264 LayoutUnit RootInlineBox::beforeAnnotationsAdjustment() const
    265 {
    266     LayoutUnit result = 0;
    267 
    268     if (!renderer().style()->isFlippedLinesWritingMode()) {
    269         // Annotations under the previous line may push us down.
    270         if (prevRootBox() && prevRootBox()->hasAnnotationsAfter())
    271             result = prevRootBox()->computeUnderAnnotationAdjustment(lineTop());
    272 
    273         if (!hasAnnotationsBefore())
    274             return result;
    275 
    276         // Annotations over this line may push us further down.
    277         LayoutUnit highestAllowedPosition = prevRootBox() ? std::min(prevRootBox()->lineBottom(), lineTop()) + result : static_cast<LayoutUnit>(block().borderBefore());
    278         result = computeOverAnnotationAdjustment(highestAllowedPosition);
    279     } else {
    280         // Annotations under this line may push us up.
    281         if (hasAnnotationsBefore())
    282             result = computeUnderAnnotationAdjustment(prevRootBox() ? prevRootBox()->lineBottom() : static_cast<LayoutUnit>(block().borderBefore()));
    283 
    284         if (!prevRootBox() || !prevRootBox()->hasAnnotationsAfter())
    285             return result;
    286 
    287         // We have to compute the expansion for annotations over the previous line to see how much we should move.
    288         LayoutUnit lowestAllowedPosition = std::max(prevRootBox()->lineBottom(), lineTop()) - result;
    289         result = prevRootBox()->computeOverAnnotationAdjustment(lowestAllowedPosition);
    290     }
    291 
    292     return result;
    293 }
    294 
    295 GapRects RootInlineBox::lineSelectionGap(const RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
    296                                          LayoutUnit selTop, LayoutUnit selHeight, const PaintInfo* paintInfo) const
    297 {
    298     RenderObject::SelectionState lineState = selectionState();
    299 
    300     bool leftGap, rightGap;
    301     block().getSelectionGapInfo(lineState, leftGap, rightGap);
    302 
    303     GapRects result;
    304 
    305     InlineBox* firstBox = firstSelectedBox();
    306     InlineBox* lastBox = lastSelectedBox();
    307     if (leftGap) {
    308         result.uniteLeft(block().logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock,
    309             &firstBox->parent()->renderer(), firstBox->logicalLeft(), selTop, selHeight, paintInfo));
    310     }
    311     if (rightGap) {
    312         result.uniteRight(block().logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock,
    313             &lastBox->parent()->renderer(), lastBox->logicalRight(), selTop, selHeight, paintInfo));
    314     }
    315 
    316     // When dealing with bidi text, a non-contiguous selection region is possible.
    317     // e.g. The logical text aaaAAAbbb (capitals denote RTL text and non-capitals LTR) is layed out
    318     // visually as 3 text runs |aaa|bbb|AAA| if we select 4 characters from the start of the text the
    319     // selection will look like (underline denotes selection):
    320     // |aaa|bbb|AAA|
    321     //  ___       _
    322     // We can see that the |bbb| run is not part of the selection while the runs around it are.
    323     if (firstBox && firstBox != lastBox) {
    324         // Now fill in any gaps on the line that occurred between two selected elements.
    325         LayoutUnit lastLogicalLeft = firstBox->logicalRight();
    326         bool isPreviousBoxSelected = firstBox->selectionState() != RenderObject::SelectionNone;
    327         for (InlineBox* box = firstBox->nextLeafChild(); box; box = box->nextLeafChild()) {
    328             if (box->selectionState() != RenderObject::SelectionNone) {
    329                 LayoutRect logicalRect(lastLogicalLeft, selTop, box->logicalLeft() - lastLogicalLeft, selHeight);
    330                 logicalRect.move(renderer().isHorizontalWritingMode() ? offsetFromRootBlock : LayoutSize(offsetFromRootBlock.height(), offsetFromRootBlock.width()));
    331                 LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
    332                 if (isPreviousBoxSelected && gapRect.width() > 0 && gapRect.height() > 0) {
    333                     if (paintInfo && box->parent()->renderer().style()->visibility() == VISIBLE)
    334                         paintInfo->context->fillRect(gapRect, box->parent()->renderer().selectionBackgroundColor());
    335                     // VisibleSelection may be non-contiguous, see comment above.
    336                     result.uniteCenter(gapRect);
    337                 }
    338                 lastLogicalLeft = box->logicalRight();
    339             }
    340             if (box == lastBox)
    341                 break;
    342             isPreviousBoxSelected = box->selectionState() != RenderObject::SelectionNone;
    343         }
    344     }
    345 
    346     return result;
    347 }
    348 
    349 RenderObject::SelectionState RootInlineBox::selectionState() const
    350 {
    351     // Walk over all of the selected boxes.
    352     RenderObject::SelectionState state = RenderObject::SelectionNone;
    353     for (InlineBox* box = firstLeafChild(); box; box = box->nextLeafChild()) {
    354         RenderObject::SelectionState boxState = box->selectionState();
    355         if ((boxState == RenderObject::SelectionStart && state == RenderObject::SelectionEnd) ||
    356             (boxState == RenderObject::SelectionEnd && state == RenderObject::SelectionStart))
    357             state = RenderObject::SelectionBoth;
    358         else if (state == RenderObject::SelectionNone ||
    359                  ((boxState == RenderObject::SelectionStart || boxState == RenderObject::SelectionEnd) &&
    360                   (state == RenderObject::SelectionNone || state == RenderObject::SelectionInside)))
    361             state = boxState;
    362         else if (boxState == RenderObject::SelectionNone && state == RenderObject::SelectionStart) {
    363             // We are past the end of the selection.
    364             state = RenderObject::SelectionBoth;
    365         }
    366         if (state == RenderObject::SelectionBoth)
    367             break;
    368     }
    369 
    370     return state;
    371 }
    372 
    373 InlineBox* RootInlineBox::firstSelectedBox() const
    374 {
    375     for (InlineBox* box = firstLeafChild(); box; box = box->nextLeafChild()) {
    376         if (box->selectionState() != RenderObject::SelectionNone)
    377             return box;
    378     }
    379 
    380     return 0;
    381 }
    382 
    383 InlineBox* RootInlineBox::lastSelectedBox() const
    384 {
    385     for (InlineBox* box = lastLeafChild(); box; box = box->prevLeafChild()) {
    386         if (box->selectionState() != RenderObject::SelectionNone)
    387             return box;
    388     }
    389 
    390     return 0;
    391 }
    392 
    393 LayoutUnit RootInlineBox::selectionTop() const
    394 {
    395     LayoutUnit selectionTop = m_lineTop;
    396 
    397     if (m_hasAnnotationsBefore)
    398         selectionTop -= !renderer().style()->isFlippedLinesWritingMode() ? computeOverAnnotationAdjustment(m_lineTop) : computeUnderAnnotationAdjustment(m_lineTop);
    399 
    400     if (renderer().style()->isFlippedLinesWritingMode() || !prevRootBox())
    401         return selectionTop;
    402 
    403     LayoutUnit prevBottom = prevRootBox()->selectionBottom();
    404     if (prevBottom < selectionTop && block().containsFloats()) {
    405         // This line has actually been moved further down, probably from a large line-height, but possibly because the
    406         // line was forced to clear floats.  If so, let's check the offsets, and only be willing to use the previous
    407         // line's bottom if the offsets are greater on both sides.
    408         LayoutUnit prevLeft = block().logicalLeftOffsetForLine(prevBottom, false);
    409         LayoutUnit prevRight = block().logicalRightOffsetForLine(prevBottom, false);
    410         LayoutUnit newLeft = block().logicalLeftOffsetForLine(selectionTop, false);
    411         LayoutUnit newRight = block().logicalRightOffsetForLine(selectionTop, false);
    412         if (prevLeft > newLeft || prevRight < newRight)
    413             return selectionTop;
    414     }
    415 
    416     return prevBottom;
    417 }
    418 
    419 LayoutUnit RootInlineBox::selectionTopAdjustedForPrecedingBlock() const
    420 {
    421     LayoutUnit top = selectionTop();
    422 
    423     RenderObject::SelectionState blockSelectionState = root().block().selectionState();
    424     if (blockSelectionState != RenderObject::SelectionInside && blockSelectionState != RenderObject::SelectionEnd)
    425         return top;
    426 
    427     LayoutSize offsetToBlockBefore;
    428     if (RenderBlock* block = root().block().blockBeforeWithinSelectionRoot(offsetToBlockBefore)) {
    429         if (block->isRenderBlockFlow()) {
    430             if (RootInlineBox* lastLine = toRenderBlockFlow(block)->lastRootBox()) {
    431                 RenderObject::SelectionState lastLineSelectionState = lastLine->selectionState();
    432                 if (lastLineSelectionState != RenderObject::SelectionInside && lastLineSelectionState != RenderObject::SelectionStart)
    433                     return top;
    434 
    435                 LayoutUnit lastLineSelectionBottom = lastLine->selectionBottom() + offsetToBlockBefore.height();
    436                 top = std::max(top, lastLineSelectionBottom);
    437             }
    438         }
    439     }
    440 
    441     return top;
    442 }
    443 
    444 LayoutUnit RootInlineBox::selectionBottom() const
    445 {
    446     LayoutUnit selectionBottom = m_selectionBottom;
    447 
    448     if (m_hasAnnotationsAfter)
    449         selectionBottom += !renderer().style()->isFlippedLinesWritingMode() ? computeUnderAnnotationAdjustment(m_lineBottom) : computeOverAnnotationAdjustment(m_lineBottom);
    450 
    451     if (!renderer().style()->isFlippedLinesWritingMode() || !nextRootBox())
    452         return selectionBottom;
    453 
    454     LayoutUnit nextTop = nextRootBox()->selectionTop();
    455     if (nextTop > selectionBottom && block().containsFloats()) {
    456         // The next line has actually been moved further over, probably from a large line-height, but possibly because the
    457         // line was forced to clear floats.  If so, let's check the offsets, and only be willing to use the next
    458         // line's top if the offsets are greater on both sides.
    459         LayoutUnit nextLeft = block().logicalLeftOffsetForLine(nextTop, false);
    460         LayoutUnit nextRight = block().logicalRightOffsetForLine(nextTop, false);
    461         LayoutUnit newLeft = block().logicalLeftOffsetForLine(selectionBottom, false);
    462         LayoutUnit newRight = block().logicalRightOffsetForLine(selectionBottom, false);
    463         if (nextLeft > newLeft || nextRight < newRight)
    464             return selectionBottom;
    465     }
    466 
    467     return nextTop;
    468 }
    469 
    470 int RootInlineBox::blockDirectionPointInLine() const
    471 {
    472     return !block().style()->isFlippedBlocksWritingMode() ? std::max(lineTop(), selectionTop()) : std::min(lineBottom(), selectionBottom());
    473 }
    474 
    475 RenderBlockFlow& RootInlineBox::block() const
    476 {
    477     return toRenderBlockFlow(renderer());
    478 }
    479 
    480 static bool isEditableLeaf(InlineBox* leaf)
    481 {
    482     return leaf && leaf->renderer().node() && leaf->renderer().node()->hasEditableStyle();
    483 }
    484 
    485 InlineBox* RootInlineBox::closestLeafChildForPoint(const IntPoint& pointInContents, bool onlyEditableLeaves)
    486 {
    487     return closestLeafChildForLogicalLeftPosition(block().isHorizontalWritingMode() ? pointInContents.x() : pointInContents.y(), onlyEditableLeaves);
    488 }
    489 
    490 InlineBox* RootInlineBox::closestLeafChildForLogicalLeftPosition(int leftPosition, bool onlyEditableLeaves)
    491 {
    492     InlineBox* firstLeaf = firstLeafChild();
    493     InlineBox* lastLeaf = lastLeafChild();
    494 
    495     if (firstLeaf != lastLeaf) {
    496         if (firstLeaf->isLineBreak())
    497             firstLeaf = firstLeaf->nextLeafChildIgnoringLineBreak();
    498         else if (lastLeaf->isLineBreak())
    499             lastLeaf = lastLeaf->prevLeafChildIgnoringLineBreak();
    500     }
    501 
    502     if (firstLeaf == lastLeaf && (!onlyEditableLeaves || isEditableLeaf(firstLeaf)))
    503         return firstLeaf;
    504 
    505     // Avoid returning a list marker when possible.
    506     if (leftPosition <= firstLeaf->logicalLeft() && !firstLeaf->renderer().isListMarker() && (!onlyEditableLeaves || isEditableLeaf(firstLeaf)))
    507         // The leftPosition coordinate is less or equal to left edge of the firstLeaf.
    508         // Return it.
    509         return firstLeaf;
    510 
    511     if (leftPosition >= lastLeaf->logicalRight() && !lastLeaf->renderer().isListMarker() && (!onlyEditableLeaves || isEditableLeaf(lastLeaf)))
    512         // The leftPosition coordinate is greater or equal to right edge of the lastLeaf.
    513         // Return it.
    514         return lastLeaf;
    515 
    516     InlineBox* closestLeaf = 0;
    517     for (InlineBox* leaf = firstLeaf; leaf; leaf = leaf->nextLeafChildIgnoringLineBreak()) {
    518         if (!leaf->renderer().isListMarker() && (!onlyEditableLeaves || isEditableLeaf(leaf))) {
    519             closestLeaf = leaf;
    520             if (leftPosition < leaf->logicalRight())
    521                 // The x coordinate is less than the right edge of the box.
    522                 // Return it.
    523                 return leaf;
    524         }
    525     }
    526 
    527     return closestLeaf ? closestLeaf : lastLeaf;
    528 }
    529 
    530 BidiStatus RootInlineBox::lineBreakBidiStatus() const
    531 {
    532     return BidiStatus(static_cast<WTF::Unicode::Direction>(m_lineBreakBidiStatusEor), static_cast<WTF::Unicode::Direction>(m_lineBreakBidiStatusLastStrong), static_cast<WTF::Unicode::Direction>(m_lineBreakBidiStatusLast), m_lineBreakContext);
    533 }
    534 
    535 void RootInlineBox::setLineBreakInfo(RenderObject* obj, unsigned breakPos, const BidiStatus& status)
    536 {
    537     // When setting lineBreakObj, the RenderObject must not be a RenderInline
    538     // with no line boxes, otherwise all sorts of invariants are broken later.
    539     // This has security implications because if the RenderObject does not
    540     // point to at least one line box, then that RenderInline can be deleted
    541     // later without resetting the lineBreakObj, leading to use-after-free.
    542     ASSERT_WITH_SECURITY_IMPLICATION(!obj || obj->isText() || !(obj->isRenderInline() && obj->isBox() && !toRenderBox(obj)->inlineBoxWrapper()));
    543 
    544     m_lineBreakObj = obj;
    545     m_lineBreakPos = breakPos;
    546     m_lineBreakBidiStatusEor = status.eor;
    547     m_lineBreakBidiStatusLastStrong = status.lastStrong;
    548     m_lineBreakBidiStatusLast = status.last;
    549     m_lineBreakContext = status.context;
    550 }
    551 
    552 EllipsisBox* RootInlineBox::ellipsisBox() const
    553 {
    554     if (!hasEllipsisBox())
    555         return 0;
    556     return gEllipsisBoxMap->get(this);
    557 }
    558 
    559 void RootInlineBox::removeLineBoxFromRenderObject()
    560 {
    561     block().lineBoxes()->removeLineBox(this);
    562 }
    563 
    564 void RootInlineBox::extractLineBoxFromRenderObject()
    565 {
    566     block().lineBoxes()->extractLineBox(this);
    567 }
    568 
    569 void RootInlineBox::attachLineBoxToRenderObject()
    570 {
    571     block().lineBoxes()->attachLineBox(this);
    572 }
    573 
    574 LayoutRect RootInlineBox::paddedLayoutOverflowRect(LayoutUnit endPadding) const
    575 {
    576     LayoutRect lineLayoutOverflow = layoutOverflowRect(lineTop(), lineBottom());
    577     if (!endPadding)
    578         return lineLayoutOverflow;
    579 
    580     if (isHorizontal()) {
    581         if (isLeftToRightDirection())
    582             lineLayoutOverflow.shiftMaxXEdgeTo(std::max<LayoutUnit>(lineLayoutOverflow.maxX(), logicalRight() + endPadding));
    583         else
    584             lineLayoutOverflow.shiftXEdgeTo(std::min<LayoutUnit>(lineLayoutOverflow.x(), logicalLeft() - endPadding));
    585     } else {
    586         if (isLeftToRightDirection())
    587             lineLayoutOverflow.shiftMaxYEdgeTo(std::max<LayoutUnit>(lineLayoutOverflow.maxY(), logicalRight() + endPadding));
    588         else
    589             lineLayoutOverflow.shiftYEdgeTo(std::min<LayoutUnit>(lineLayoutOverflow.y(), logicalLeft() - endPadding));
    590     }
    591 
    592     return lineLayoutOverflow;
    593 }
    594 
    595 static void setAscentAndDescent(int& ascent, int& descent, int newAscent, int newDescent, bool& ascentDescentSet)
    596 {
    597     if (!ascentDescentSet) {
    598         ascentDescentSet = true;
    599         ascent = newAscent;
    600         descent = newDescent;
    601     } else {
    602         ascent = std::max(ascent, newAscent);
    603         descent = std::max(descent, newDescent);
    604     }
    605 }
    606 
    607 void RootInlineBox::ascentAndDescentForBox(InlineBox* box, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, int& ascent, int& descent,
    608                                            bool& affectsAscent, bool& affectsDescent) const
    609 {
    610     bool ascentDescentSet = false;
    611 
    612     // Replaced boxes will return 0 for the line-height if line-box-contain says they are
    613     // not to be included.
    614     if (box->renderer().isReplaced()) {
    615         if (renderer().style(isFirstLineStyle())->lineBoxContain() & LineBoxContainReplaced) {
    616             ascent = box->baselinePosition(baselineType());
    617             descent = box->lineHeight() - ascent;
    618 
    619             // Replaced elements always affect both the ascent and descent.
    620             affectsAscent = true;
    621             affectsDescent = true;
    622         }
    623         return;
    624     }
    625 
    626     Vector<const SimpleFontData*>* usedFonts = 0;
    627     GlyphOverflow* glyphOverflow = 0;
    628     if (box->isText()) {
    629         GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.find(toInlineTextBox(box));
    630         usedFonts = it == textBoxDataMap.end() ? 0 : &it->value.first;
    631         glyphOverflow = it == textBoxDataMap.end() ? 0 : &it->value.second;
    632     }
    633 
    634     bool includeLeading = includeLeadingForBox(box);
    635     bool includeFont = includeFontForBox(box);
    636 
    637     bool setUsedFont = false;
    638     bool setUsedFontWithLeading = false;
    639 
    640     if (usedFonts && !usedFonts->isEmpty() && (includeFont || (box->renderer().style(isFirstLineStyle())->lineHeight().isNegative() && includeLeading))) {
    641         usedFonts->append(box->renderer().style(isFirstLineStyle())->font().primaryFont());
    642         for (size_t i = 0; i < usedFonts->size(); ++i) {
    643             const FontMetrics& fontMetrics = usedFonts->at(i)->fontMetrics();
    644             int usedFontAscent = fontMetrics.ascent(baselineType());
    645             int usedFontDescent = fontMetrics.descent(baselineType());
    646             int halfLeading = (fontMetrics.lineSpacing() - fontMetrics.height()) / 2;
    647             int usedFontAscentAndLeading = usedFontAscent + halfLeading;
    648             int usedFontDescentAndLeading = fontMetrics.lineSpacing() - usedFontAscentAndLeading;
    649             if (includeFont) {
    650                 setAscentAndDescent(ascent, descent, usedFontAscent, usedFontDescent, ascentDescentSet);
    651                 setUsedFont = true;
    652             }
    653             if (includeLeading) {
    654                 setAscentAndDescent(ascent, descent, usedFontAscentAndLeading, usedFontDescentAndLeading, ascentDescentSet);
    655                 setUsedFontWithLeading = true;
    656             }
    657             if (!affectsAscent)
    658                 affectsAscent = usedFontAscent - box->logicalTop() > 0;
    659             if (!affectsDescent)
    660                 affectsDescent = usedFontDescent + box->logicalTop() > 0;
    661         }
    662     }
    663 
    664     // If leading is included for the box, then we compute that box.
    665     if (includeLeading && !setUsedFontWithLeading) {
    666         int ascentWithLeading = box->baselinePosition(baselineType());
    667         int descentWithLeading = box->lineHeight() - ascentWithLeading;
    668         setAscentAndDescent(ascent, descent, ascentWithLeading, descentWithLeading, ascentDescentSet);
    669 
    670         // Examine the font box for inline flows and text boxes to see if any part of it is above the baseline.
    671         // If the top of our font box relative to the root box baseline is above the root box baseline, then
    672         // we are contributing to the maxAscent value. Descent is similar. If any part of our font box is below
    673         // the root box's baseline, then we contribute to the maxDescent value.
    674         affectsAscent = ascentWithLeading - box->logicalTop() > 0;
    675         affectsDescent = descentWithLeading + box->logicalTop() > 0;
    676     }
    677 
    678     if (includeFontForBox(box) && !setUsedFont) {
    679         int fontAscent = box->renderer().style(isFirstLineStyle())->fontMetrics().ascent(baselineType());
    680         int fontDescent = box->renderer().style(isFirstLineStyle())->fontMetrics().descent(baselineType());
    681         setAscentAndDescent(ascent, descent, fontAscent, fontDescent, ascentDescentSet);
    682         affectsAscent = fontAscent - box->logicalTop() > 0;
    683         affectsDescent = fontDescent + box->logicalTop() > 0;
    684     }
    685 
    686     if (includeGlyphsForBox(box) && glyphOverflow && glyphOverflow->computeBounds) {
    687         setAscentAndDescent(ascent, descent, glyphOverflow->top, glyphOverflow->bottom, ascentDescentSet);
    688         affectsAscent = glyphOverflow->top - box->logicalTop() > 0;
    689         affectsDescent = glyphOverflow->bottom + box->logicalTop() > 0;
    690         glyphOverflow->top = std::min(glyphOverflow->top, std::max(0, glyphOverflow->top - box->renderer().style(isFirstLineStyle())->fontMetrics().ascent(baselineType())));
    691         glyphOverflow->bottom = std::min(glyphOverflow->bottom, std::max(0, glyphOverflow->bottom - box->renderer().style(isFirstLineStyle())->fontMetrics().descent(baselineType())));
    692     }
    693 
    694     if (includeMarginForBox(box)) {
    695         LayoutUnit ascentWithMargin = box->renderer().style(isFirstLineStyle())->fontMetrics().ascent(baselineType());
    696         LayoutUnit descentWithMargin = box->renderer().style(isFirstLineStyle())->fontMetrics().descent(baselineType());
    697         if (box->parent() && !box->renderer().isText()) {
    698             ascentWithMargin += box->boxModelObject()->borderBefore() + box->boxModelObject()->paddingBefore() + box->boxModelObject()->marginBefore();
    699             descentWithMargin += box->boxModelObject()->borderAfter() + box->boxModelObject()->paddingAfter() + box->boxModelObject()->marginAfter();
    700         }
    701         setAscentAndDescent(ascent, descent, ascentWithMargin, descentWithMargin, ascentDescentSet);
    702 
    703         // Treat like a replaced element, since we're using the margin box.
    704         affectsAscent = true;
    705         affectsDescent = true;
    706     }
    707 }
    708 
    709 LayoutUnit RootInlineBox::verticalPositionForBox(InlineBox* box, VerticalPositionCache& verticalPositionCache)
    710 {
    711     if (box->renderer().isText())
    712         return box->parent()->logicalTop();
    713 
    714     RenderBoxModelObject* renderer = box->boxModelObject();
    715     ASSERT(renderer->isInline());
    716     if (!renderer->isInline())
    717         return 0;
    718 
    719     // This method determines the vertical position for inline elements.
    720     bool firstLine = isFirstLineStyle();
    721     if (firstLine && !renderer->document().styleEngine()->usesFirstLineRules())
    722         firstLine = false;
    723 
    724     // Check the cache.
    725     bool isRenderInline = renderer->isRenderInline();
    726     if (isRenderInline && !firstLine) {
    727         LayoutUnit verticalPosition = verticalPositionCache.get(renderer, baselineType());
    728         if (verticalPosition != PositionUndefined)
    729             return verticalPosition;
    730     }
    731 
    732     LayoutUnit verticalPosition = 0;
    733     EVerticalAlign verticalAlign = renderer->style()->verticalAlign();
    734     if (verticalAlign == TOP || verticalAlign == BOTTOM)
    735         return 0;
    736 
    737     RenderObject* parent = renderer->parent();
    738     if (parent->isRenderInline() && parent->style()->verticalAlign() != TOP && parent->style()->verticalAlign() != BOTTOM)
    739         verticalPosition = box->parent()->logicalTop();
    740 
    741     if (verticalAlign != BASELINE) {
    742         const Font& font = parent->style(firstLine)->font();
    743         const FontMetrics& fontMetrics = font.fontMetrics();
    744         int fontSize = font.fontDescription().computedPixelSize();
    745 
    746         LineDirectionMode lineDirection = parent->isHorizontalWritingMode() ? HorizontalLine : VerticalLine;
    747 
    748         if (verticalAlign == SUB)
    749             verticalPosition += fontSize / 5 + 1;
    750         else if (verticalAlign == SUPER)
    751             verticalPosition -= fontSize / 3 + 1;
    752         else if (verticalAlign == TEXT_TOP)
    753             verticalPosition += renderer->baselinePosition(baselineType(), firstLine, lineDirection) - fontMetrics.ascent(baselineType());
    754         else if (verticalAlign == MIDDLE)
    755             verticalPosition = (verticalPosition - static_cast<LayoutUnit>(fontMetrics.xHeight() / 2) - renderer->lineHeight(firstLine, lineDirection) / 2 + renderer->baselinePosition(baselineType(), firstLine, lineDirection)).round();
    756         else if (verticalAlign == TEXT_BOTTOM) {
    757             verticalPosition += fontMetrics.descent(baselineType());
    758             // lineHeight - baselinePosition is always 0 for replaced elements (except inline blocks), so don't bother wasting time in that case.
    759             if (!renderer->isReplaced() || renderer->isInlineBlockOrInlineTable())
    760                 verticalPosition -= (renderer->lineHeight(firstLine, lineDirection) - renderer->baselinePosition(baselineType(), firstLine, lineDirection));
    761         } else if (verticalAlign == BASELINE_MIDDLE)
    762             verticalPosition += -renderer->lineHeight(firstLine, lineDirection) / 2 + renderer->baselinePosition(baselineType(), firstLine, lineDirection);
    763         else if (verticalAlign == LENGTH) {
    764             LayoutUnit lineHeight;
    765             //Per http://www.w3.org/TR/CSS21/visudet.html#propdef-vertical-align: 'Percentages: refer to the 'line-height' of the element itself'.
    766             if (renderer->style()->verticalAlignLength().isPercent())
    767                 lineHeight = renderer->style()->computedLineHeight();
    768             else
    769                 lineHeight = renderer->lineHeight(firstLine, lineDirection);
    770             verticalPosition -= valueForLength(renderer->style()->verticalAlignLength(), lineHeight);
    771         }
    772     }
    773 
    774     // Store the cached value.
    775     if (isRenderInline && !firstLine)
    776         verticalPositionCache.set(renderer, baselineType(), verticalPosition);
    777 
    778     return verticalPosition;
    779 }
    780 
    781 bool RootInlineBox::includeLeadingForBox(InlineBox* box) const
    782 {
    783     if (box->renderer().isReplaced() || (box->renderer().isText() && !box->isText()))
    784         return false;
    785 
    786     LineBoxContain lineBoxContain = renderer().style()->lineBoxContain();
    787     return (lineBoxContain & LineBoxContainInline) || (box == this && (lineBoxContain & LineBoxContainBlock));
    788 }
    789 
    790 bool RootInlineBox::includeFontForBox(InlineBox* box) const
    791 {
    792     if (box->renderer().isReplaced() || (box->renderer().isText() && !box->isText()))
    793         return false;
    794 
    795     if (!box->isText() && box->isInlineFlowBox() && !toInlineFlowBox(box)->hasTextChildren())
    796         return false;
    797 
    798     // For now map "glyphs" to "font" in vertical text mode until the bounds returned by glyphs aren't garbage.
    799     LineBoxContain lineBoxContain = renderer().style()->lineBoxContain();
    800     return (lineBoxContain & LineBoxContainFont) || (!isHorizontal() && (lineBoxContain & LineBoxContainGlyphs));
    801 }
    802 
    803 bool RootInlineBox::includeGlyphsForBox(InlineBox* box) const
    804 {
    805     if (box->renderer().isReplaced() || (box->renderer().isText() && !box->isText()))
    806         return false;
    807 
    808     if (!box->isText() && box->isInlineFlowBox() && !toInlineFlowBox(box)->hasTextChildren())
    809         return false;
    810 
    811     // FIXME: We can't fit to glyphs yet for vertical text, since the bounds returned are garbage.
    812     LineBoxContain lineBoxContain = renderer().style()->lineBoxContain();
    813     return isHorizontal() && (lineBoxContain & LineBoxContainGlyphs);
    814 }
    815 
    816 bool RootInlineBox::includeMarginForBox(InlineBox* box) const
    817 {
    818     if (box->renderer().isReplaced() || (box->renderer().isText() && !box->isText()))
    819         return false;
    820 
    821     LineBoxContain lineBoxContain = renderer().style()->lineBoxContain();
    822     return lineBoxContain & LineBoxContainInlineBox;
    823 }
    824 
    825 
    826 bool RootInlineBox::fitsToGlyphs() const
    827 {
    828     // FIXME: We can't fit to glyphs yet for vertical text, since the bounds returned are garbage.
    829     LineBoxContain lineBoxContain = renderer().style()->lineBoxContain();
    830     return isHorizontal() && (lineBoxContain & LineBoxContainGlyphs);
    831 }
    832 
    833 bool RootInlineBox::includesRootLineBoxFontOrLeading() const
    834 {
    835     LineBoxContain lineBoxContain = renderer().style()->lineBoxContain();
    836     return (lineBoxContain & LineBoxContainBlock) || (lineBoxContain & LineBoxContainInline) || (lineBoxContain & LineBoxContainFont);
    837 }
    838 
    839 Node* RootInlineBox::getLogicalStartBoxWithNode(InlineBox*& startBox) const
    840 {
    841     Vector<InlineBox*> leafBoxesInLogicalOrder;
    842     collectLeafBoxesInLogicalOrder(leafBoxesInLogicalOrder);
    843     for (size_t i = 0; i < leafBoxesInLogicalOrder.size(); ++i) {
    844         if (leafBoxesInLogicalOrder[i]->renderer().node()) {
    845             startBox = leafBoxesInLogicalOrder[i];
    846             return startBox->renderer().node();
    847         }
    848     }
    849     startBox = 0;
    850     return 0;
    851 }
    852 
    853 Node* RootInlineBox::getLogicalEndBoxWithNode(InlineBox*& endBox) const
    854 {
    855     Vector<InlineBox*> leafBoxesInLogicalOrder;
    856     collectLeafBoxesInLogicalOrder(leafBoxesInLogicalOrder);
    857     for (size_t i = leafBoxesInLogicalOrder.size(); i > 0; --i) {
    858         if (leafBoxesInLogicalOrder[i - 1]->renderer().node()) {
    859             endBox = leafBoxesInLogicalOrder[i - 1];
    860             return endBox->renderer().node();
    861         }
    862     }
    863     endBox = 0;
    864     return 0;
    865 }
    866 
    867 #ifndef NDEBUG
    868 const char* RootInlineBox::boxName() const
    869 {
    870     return "RootInlineBox";
    871 }
    872 #endif
    873 
    874 } // namespace blink
    875