6655c4334e46a1e285e71cd62475f09a38593fff
[WebKit-https.git] / Source / WebCore / rendering / RootInlineBox.cpp
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 "RootInlineBox.h"
22
23 #include "BidiResolver.h"
24 #include "Chrome.h"
25 #include "ChromeClient.h"
26 #include "Document.h"
27 #include "EllipsisBox.h"
28 #include "Frame.h"
29 #include "GraphicsContext.h"
30 #include "HitTestResult.h"
31 #include "InlineTextBox.h"
32 #include "Page.h"
33 #include "PaintInfo.h"
34 #include "RenderArena.h"
35 #include "RenderBlock.h"
36 #include "RenderFlowThread.h"
37 #include "RenderView.h"
38 #include "VerticalPositionCache.h"
39 #include <wtf/unicode/Unicode.h>
40
41 using namespace std;
42
43 namespace WebCore {
44     
45 typedef WTF::HashMap<const RootInlineBox*, EllipsisBox*> EllipsisBoxMap;
46 static EllipsisBoxMap* gEllipsisBoxMap = 0;
47
48 RootInlineBox::RootInlineBox(RenderBlock* block)
49     : InlineFlowBox(block)
50     , m_lineBreakPos(0)
51     , m_lineBreakObj(0)
52     , m_lineTop(0)
53     , m_lineBottom(0)
54     , m_lineTopWithLeading(0)
55     , m_lineBottomWithLeading(0)
56 #if ENABLE(CSS3_TEXT)
57     , m_maxLogicalTop(0)
58 #endif // CSS3_TEXT
59 {
60     setIsHorizontal(block->isHorizontalWritingMode());
61 }
62
63
64 void RootInlineBox::destroy(RenderArena* arena)
65 {
66     detachEllipsisBox(arena);
67     InlineFlowBox::destroy(arena);
68 }
69
70 void RootInlineBox::detachEllipsisBox(RenderArena* arena)
71 {
72     if (hasEllipsisBox()) {
73         EllipsisBox* box = gEllipsisBoxMap->take(this);
74         box->setParent(0);
75         box->destroy(arena);
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(renderer()->renderArena());
89         InlineFlowBox::clearTruncation();
90     }
91 }
92
93 bool RootInlineBox::isHyphenated() const
94 {
95     for (InlineBox* box = firstLeafChild(); box; box = box->nextLeafChild()) {
96         if (box->isInlineTextBox()) {
97             if (toInlineTextBox(box)->hasHyphen())
98                 return true;
99         }
100     }
101
102     return false;
103 }
104
105 int RootInlineBox::baselinePosition(FontBaseline baselineType) const
106 {
107     return boxModelObject()->baselinePosition(baselineType, isFirstLineStyle(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
108 }
109
110 LayoutUnit RootInlineBox::lineHeight() const
111 {
112     return boxModelObject()->lineHeight(isFirstLineStyle(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
113 }
114
115 bool RootInlineBox::lineCanAccommodateEllipsis(bool ltr, int blockEdge, int lineBoxEdge, int ellipsisWidth)
116 {
117     // First sanity-check the unoverflowed width of the whole line to see if there is sufficient room.
118     int delta = ltr ? lineBoxEdge - blockEdge : blockEdge - lineBoxEdge;
119     if (logicalWidth() - delta < ellipsisWidth)
120         return false;
121
122     // Next iterate over all the line boxes on the line.  If we find a replaced element that intersects
123     // then we refuse to accommodate the ellipsis.  Otherwise we're ok.
124     return InlineFlowBox::canAccommodateEllipsis(ltr, blockEdge, ellipsisWidth);
125 }
126
127 float RootInlineBox::placeEllipsis(const AtomicString& ellipsisStr,  bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth,
128                                   InlineBox* markupBox)
129 {
130     // Create an ellipsis box.
131     EllipsisBox* ellipsisBox = new (renderer()->renderArena()) EllipsisBox(renderer(), ellipsisStr, this,
132                                                               ellipsisWidth - (markupBox ? markupBox->logicalWidth() : 0), logicalHeight(),
133                                                               y(), !prevRootBox(), isHorizontal(), markupBox);
134     
135     if (!gEllipsisBoxMap)
136         gEllipsisBoxMap = new EllipsisBoxMap();
137     gEllipsisBoxMap->add(this, ellipsisBox);
138     setHasEllipsisBox(true);
139
140     // FIXME: Do we need an RTL version of this?
141     if (ltr && (x() + logicalWidth() + ellipsisWidth) <= blockRightEdge) {
142         ellipsisBox->setX(x() + logicalWidth());
143         return logicalWidth() + ellipsisWidth;
144     }
145
146     // Now attempt to find the nearest glyph horizontally and place just to the right (or left in RTL)
147     // of that glyph.  Mark all of the objects that intersect the ellipsis box as not painting (as being
148     // truncated).
149     bool foundBox = false;
150     float truncatedWidth = 0;
151     float position = placeEllipsisBox(ltr, blockLeftEdge, blockRightEdge, ellipsisWidth, truncatedWidth, foundBox);
152     ellipsisBox->setX(position);
153     return truncatedWidth;
154 }
155
156 float RootInlineBox::placeEllipsisBox(bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, float &truncatedWidth, bool& foundBox)
157 {
158     float result = InlineFlowBox::placeEllipsisBox(ltr, blockLeftEdge, blockRightEdge, ellipsisWidth, truncatedWidth, foundBox);
159     if (result == -1) {
160         result = ltr ? blockRightEdge - ellipsisWidth : blockLeftEdge;
161         truncatedWidth = blockRightEdge - blockLeftEdge;
162     }
163     return result;
164 }
165
166 void RootInlineBox::paintEllipsisBox(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom) const
167 {
168     if (hasEllipsisBox() && paintInfo.shouldPaintWithinRoot(renderer()) && renderer()->style()->visibility() == VISIBLE
169             && paintInfo.phase == PaintPhaseForeground)
170         ellipsisBox()->paint(paintInfo, paintOffset, lineTop, lineBottom);
171 }
172
173 #if PLATFORM(MAC)
174
175 void RootInlineBox::addHighlightOverflow()
176 {
177     Frame* frame = renderer()->frame();
178     if (!frame)
179         return;
180     Page* page = frame->page();
181     if (!page)
182         return;
183
184     // Highlight acts as a selection inflation.
185     FloatRect rootRect(0, selectionTop(), logicalWidth(), selectionHeight());
186     IntRect inflatedRect = enclosingIntRect(page->chrome()->client()->customHighlightRect(renderer()->node(), renderer()->style()->highlight(), rootRect));
187     setOverflowFromLogicalRects(inflatedRect, inflatedRect, lineTop(), lineBottom());
188 }
189
190 void RootInlineBox::paintCustomHighlight(PaintInfo& paintInfo, const LayoutPoint& paintOffset, const AtomicString& highlightType)
191 {
192     if (!paintInfo.shouldPaintWithinRoot(renderer()) || renderer()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseForeground)
193         return;
194
195     Frame* frame = renderer()->frame();
196     if (!frame)
197         return;
198     Page* page = frame->page();
199     if (!page)
200         return;
201
202     // Get the inflated rect so that we can properly hit test.
203     FloatRect rootRect(paintOffset.x() + x(), paintOffset.y() + selectionTop(), logicalWidth(), selectionHeight());
204     FloatRect inflatedRect = page->chrome()->client()->customHighlightRect(renderer()->node(), highlightType, rootRect);
205     if (inflatedRect.intersects(paintInfo.rect))
206         page->chrome()->client()->paintCustomHighlight(renderer()->node(), highlightType, rootRect, rootRect, false, true);
207 }
208
209 #endif
210
211 void RootInlineBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom)
212 {
213     InlineFlowBox::paint(paintInfo, paintOffset, lineTop, lineBottom);
214     paintEllipsisBox(paintInfo, paintOffset, lineTop, lineBottom);
215 #if PLATFORM(MAC)
216     RenderStyle* styleToUse = renderer()->style(isFirstLineStyle());
217     if (styleToUse->highlight() != nullAtom && !paintInfo.context->paintingDisabled())
218         paintCustomHighlight(paintInfo, paintOffset, styleToUse->highlight());
219 #endif
220 }
221
222 bool RootInlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom)
223 {
224     if (hasEllipsisBox() && visibleToHitTesting()) {
225         if (ellipsisBox()->nodeAtPoint(request, result, locationInContainer, accumulatedOffset, lineTop, lineBottom)) {
226             renderer()->updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset));
227             return true;
228         }
229     }
230     return InlineFlowBox::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, lineTop, lineBottom);
231 }
232
233 void RootInlineBox::adjustPosition(float dx, float dy)
234 {
235     InlineFlowBox::adjustPosition(dx, dy);
236     LayoutUnit blockDirectionDelta = isHorizontal() ? dy : dx; // The block direction delta is a LayoutUnit.
237     m_lineTop += blockDirectionDelta;
238     m_lineBottom += blockDirectionDelta;
239     m_lineTopWithLeading += blockDirectionDelta;
240     m_lineBottomWithLeading += blockDirectionDelta;
241     if (hasEllipsisBox())
242         ellipsisBox()->adjustPosition(dx, dy);
243 }
244
245 void RootInlineBox::childRemoved(InlineBox* box)
246 {
247     if (box->renderer() == m_lineBreakObj)
248         setLineBreakInfo(0, 0, BidiStatus());
249
250     for (RootInlineBox* prev = prevRootBox(); prev && prev->lineBreakObj() == box->renderer(); prev = prev->prevRootBox()) {
251         prev->setLineBreakInfo(0, 0, BidiStatus());
252         prev->markDirty();
253     }
254 }
255
256 RenderRegion* RootInlineBox::containingRegion() const
257 {
258     RenderRegion* region = m_fragmentationData ? m_fragmentationData->m_containingRegion : 0;
259
260 #ifndef NDEBUG
261     if (region) {
262         RenderFlowThread* flowThread = block()->flowThreadContainingBlock();
263         const RenderRegionList& regionList = flowThread->renderRegionList();
264         ASSERT(regionList.contains(region));
265     }
266 #endif
267
268     return region;
269 }
270
271 void RootInlineBox::setContainingRegion(RenderRegion* region)
272 {
273     ASSERT(!isDirty());
274     ASSERT(block()->flowThreadContainingBlock());
275     LineFragmentationData* fragmentationData  = ensureLineFragmentationData();
276     fragmentationData->m_containingRegion = region;
277 }
278
279 LayoutUnit RootInlineBox::alignBoxesInBlockDirection(LayoutUnit heightOfBlock, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache)
280 {
281 #if ENABLE(SVG)
282     // SVG will handle vertical alignment on its own.
283     if (isSVGRootInlineBox())
284         return 0;
285
286     // FIXME: figure out how to call computeMaxLogicalTop() when SVG is enabled.
287 #endif
288
289     LayoutUnit maxPositionTop = 0;
290     LayoutUnit maxPositionBottom = 0;
291     int maxAscent = 0;
292     int maxDescent = 0;
293     bool setMaxAscent = false;
294     bool setMaxDescent = false;
295
296     // Figure out if we're in no-quirks mode.
297     bool noQuirksMode = renderer()->document()->inNoQuirksMode();
298
299     m_baselineType = requiresIdeographicBaseline(textBoxDataMap) ? IdeographicBaseline : AlphabeticBaseline;
300
301     computeLogicalBoxHeights(this, maxPositionTop, maxPositionBottom, maxAscent, maxDescent, setMaxAscent, setMaxDescent, noQuirksMode,
302                              textBoxDataMap, baselineType(), verticalPositionCache);
303
304     if (maxAscent + maxDescent < max(maxPositionTop, maxPositionBottom))
305         adjustMaxAscentAndDescent(maxAscent, maxDescent, maxPositionTop, maxPositionBottom);
306
307     LayoutUnit maxHeight = maxAscent + maxDescent;
308     LayoutUnit lineTop = heightOfBlock;
309     LayoutUnit lineBottom = heightOfBlock;
310     LayoutUnit lineTopIncludingMargins = heightOfBlock;
311     LayoutUnit lineBottomIncludingMargins = heightOfBlock;
312     bool setLineTop = false;
313     bool hasAnnotationsBefore = false;
314     bool hasAnnotationsAfter = false;
315     placeBoxesInBlockDirection(heightOfBlock, maxHeight, maxAscent, noQuirksMode, lineTop, lineBottom, setLineTop,
316                                lineTopIncludingMargins, lineBottomIncludingMargins, hasAnnotationsBefore, hasAnnotationsAfter, baselineType());
317     m_hasAnnotationsBefore = hasAnnotationsBefore;
318     m_hasAnnotationsAfter = hasAnnotationsAfter;
319     
320     maxHeight = max<LayoutUnit>(0, maxHeight); // FIXME: Is this really necessary?
321
322     setLineTopBottomPositions(lineTop, lineBottom, heightOfBlock, heightOfBlock + maxHeight);
323     setPaginatedLineWidth(block()->availableLogicalWidthForContent(heightOfBlock));
324
325     LayoutUnit annotationsAdjustment = beforeAnnotationsAdjustment();
326     if (annotationsAdjustment) {
327         // FIXME: Need to handle pagination here. We might have to move to the next page/column as a result of the
328         // ruby expansion.
329         adjustBlockDirectionPosition(annotationsAdjustment);
330         heightOfBlock += annotationsAdjustment;
331     }
332
333     LayoutUnit gridSnapAdjustment = lineSnapAdjustment();
334     if (gridSnapAdjustment) {
335         adjustBlockDirectionPosition(gridSnapAdjustment);
336         heightOfBlock += gridSnapAdjustment;
337     }
338
339 #if ENABLE(CSS3_TEXT)
340     m_maxLogicalTop = 0;
341     computeMaxLogicalTop(m_maxLogicalTop);
342 #endif // CSS3_TEXT
343
344     return heightOfBlock + maxHeight;
345 }
346
347 LayoutUnit RootInlineBox::beforeAnnotationsAdjustment() const
348 {
349     LayoutUnit result = 0;
350
351     if (!renderer()->style()->isFlippedLinesWritingMode()) {
352         // Annotations under the previous line may push us down.
353         if (prevRootBox() && prevRootBox()->hasAnnotationsAfter())
354             result = prevRootBox()->computeUnderAnnotationAdjustment(lineTop());
355
356         if (!hasAnnotationsBefore())
357             return result;
358
359         // Annotations over this line may push us further down.
360         LayoutUnit highestAllowedPosition = prevRootBox() ? min(prevRootBox()->lineBottom(), lineTop()) + result : static_cast<LayoutUnit>(block()->borderBefore());
361         result = computeOverAnnotationAdjustment(highestAllowedPosition);
362     } else {
363         // Annotations under this line may push us up.
364         if (hasAnnotationsBefore())
365             result = computeUnderAnnotationAdjustment(prevRootBox() ? prevRootBox()->lineBottom() : static_cast<LayoutUnit>(block()->borderBefore()));
366
367         if (!prevRootBox() || !prevRootBox()->hasAnnotationsAfter())
368             return result;
369
370         // We have to compute the expansion for annotations over the previous line to see how much we should move.
371         LayoutUnit lowestAllowedPosition = max(prevRootBox()->lineBottom(), lineTop()) - result;
372         result = prevRootBox()->computeOverAnnotationAdjustment(lowestAllowedPosition);
373     }
374
375     return result;
376 }
377
378 LayoutUnit RootInlineBox::lineSnapAdjustment(LayoutUnit delta) const
379 {
380     // If our block doesn't have snapping turned on, do nothing.
381     // FIXME: Implement bounds snapping.
382     if (block()->style()->lineSnap() == LineSnapNone)
383         return 0;
384
385     // Get the current line grid and offset.
386     LayoutState* layoutState = block()->view()->layoutState();
387     RenderBlock* lineGrid = layoutState->lineGrid();
388     LayoutSize lineGridOffset = layoutState->lineGridOffset();
389     if (!lineGrid || lineGrid->style()->writingMode() != block()->style()->writingMode())
390         return 0;
391
392     // Get the hypothetical line box used to establish the grid.
393     RootInlineBox* lineGridBox = lineGrid->lineGridBox();
394     if (!lineGridBox)
395         return 0;
396     
397     LayoutUnit lineGridBlockOffset = lineGrid->isHorizontalWritingMode() ? lineGridOffset.height() : lineGridOffset.width();
398     LayoutUnit blockOffset = block()->isHorizontalWritingMode() ? layoutState->layoutOffset().height() : layoutState->layoutOffset().width();
399
400     // Now determine our position on the grid. Our baseline needs to be adjusted to the nearest baseline multiple
401     // as established by the line box.
402     // FIXME: Need to handle crazy line-box-contain values that cause the root line box to not be considered. I assume
403     // the grid should honor line-box-contain.
404     LayoutUnit gridLineHeight = lineGridBox->lineBottomWithLeading() - lineGridBox->lineTopWithLeading();
405     if (!gridLineHeight)
406         return 0;
407
408     LayoutUnit lineGridFontAscent = lineGrid->style()->fontMetrics().ascent(baselineType());
409     LayoutUnit lineGridFontHeight = lineGridBox->logicalHeight();
410     LayoutUnit firstTextTop = lineGridBlockOffset + lineGridBox->logicalTop();
411     LayoutUnit firstLineTopWithLeading = lineGridBlockOffset + lineGridBox->lineTopWithLeading();
412     LayoutUnit firstBaselinePosition = firstTextTop + lineGridFontAscent;
413
414     LayoutUnit currentTextTop = blockOffset + logicalTop() + delta;
415     LayoutUnit currentFontAscent = block()->style()->fontMetrics().ascent(baselineType());
416     LayoutUnit currentBaselinePosition = currentTextTop + currentFontAscent;
417
418     LayoutUnit lineGridPaginationOrigin = isHorizontal() ? layoutState->lineGridPaginationOrigin().height() : layoutState->lineGridPaginationOrigin().width();
419
420     // If we're paginated, see if we're on a page after the first one. If so, the grid resets on subsequent pages.
421     // FIXME: If the grid is an ancestor of the pagination establisher, then this is incorrect.
422     LayoutUnit pageLogicalTop = 0;
423     if (layoutState->isPaginated() && layoutState->pageLogicalHeight()) {
424         pageLogicalTop = block()->pageLogicalTopForOffset(lineTopWithLeading() + delta);
425         if (pageLogicalTop > firstLineTopWithLeading)
426             firstTextTop = pageLogicalTop + lineGridBox->logicalTop() - lineGrid->borderBefore() - lineGrid->paddingBefore() + lineGridPaginationOrigin;
427     }
428
429     if (block()->style()->lineSnap() == LineSnapContain) {
430         // Compute the desired offset from the text-top of a grid line.
431         // Look at our height (logicalHeight()).
432         // Look at the total available height. It's going to be (textBottom - textTop) + (n-1)*(multiple with leading)
433         // where n is number of grid lines required to enclose us.
434         if (logicalHeight() <= lineGridFontHeight)
435             firstTextTop += (lineGridFontHeight - logicalHeight()) / 2;
436         else {
437             LayoutUnit numberOfLinesWithLeading = ceilf(static_cast<float>(logicalHeight() - lineGridFontHeight) / gridLineHeight);
438             LayoutUnit totalHeight = lineGridFontHeight + numberOfLinesWithLeading * gridLineHeight;
439             firstTextTop += (totalHeight - logicalHeight()) / 2;
440         }
441         firstBaselinePosition = firstTextTop + currentFontAscent;
442     } else
443         firstBaselinePosition = firstTextTop + lineGridFontAscent;
444
445     // If we're above the first line, just push to the first line.
446     if (currentBaselinePosition < firstBaselinePosition)
447         return delta + firstBaselinePosition - currentBaselinePosition;
448
449     // Otherwise we're in the middle of the grid somewhere. Just push to the next line.
450     LayoutUnit baselineOffset = currentBaselinePosition - firstBaselinePosition;
451     LayoutUnit remainder = roundToInt(baselineOffset) % roundToInt(gridLineHeight);
452     LayoutUnit result = delta;
453     if (remainder)
454         result += gridLineHeight - remainder;
455
456     // If we aren't paginated we can return the result.
457     if (!layoutState->isPaginated() || !layoutState->pageLogicalHeight() || result == delta)
458         return result;
459     
460     // We may end up shifted to a new page. We need to do a re-snap when that happens.
461     LayoutUnit newPageLogicalTop = block()->pageLogicalTopForOffset(lineBottomWithLeading() + result);
462     if (newPageLogicalTop == pageLogicalTop)
463         return result;
464     
465     // Put ourselves at the top of the next page to force a snap onto the new grid established by that page.
466     return lineSnapAdjustment(newPageLogicalTop - (blockOffset + lineTopWithLeading()));
467 }
468
469 GapRects RootInlineBox::lineSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock, 
470                                          LayoutUnit selTop, LayoutUnit selHeight, const PaintInfo* paintInfo)
471 {
472     RenderObject::SelectionState lineState = selectionState();
473
474     bool leftGap, rightGap;
475     block()->getSelectionGapInfo(lineState, leftGap, rightGap);
476
477     GapRects result;
478
479     InlineBox* firstBox = firstSelectedBox();
480     InlineBox* lastBox = lastSelectedBox();
481     if (leftGap)
482         result.uniteLeft(block()->logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock,
483                                                           firstBox->parent()->renderer(), firstBox->logicalLeft(), selTop, selHeight, paintInfo));
484     if (rightGap)
485         result.uniteRight(block()->logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock,
486                                                             lastBox->parent()->renderer(), lastBox->logicalRight(), selTop, selHeight, paintInfo));
487
488     // When dealing with bidi text, a non-contiguous selection region is possible.
489     // e.g. The logical text aaaAAAbbb (capitals denote RTL text and non-capitals LTR) is layed out
490     // visually as 3 text runs |aaa|bbb|AAA| if we select 4 characters from the start of the text the
491     // selection will look like (underline denotes selection):
492     // |aaa|bbb|AAA|
493     //  ___       _
494     // We can see that the |bbb| run is not part of the selection while the runs around it are.
495     if (firstBox && firstBox != lastBox) {
496         // Now fill in any gaps on the line that occurred between two selected elements.
497         LayoutUnit lastLogicalLeft = firstBox->logicalRight();
498         bool isPreviousBoxSelected = firstBox->selectionState() != RenderObject::SelectionNone;
499         for (InlineBox* box = firstBox->nextLeafChild(); box; box = box->nextLeafChild()) {
500             if (box->selectionState() != RenderObject::SelectionNone) {
501                 LayoutRect logicalRect(lastLogicalLeft, selTop, box->logicalLeft() - lastLogicalLeft, selHeight);
502                 logicalRect.move(renderer()->isHorizontalWritingMode() ? offsetFromRootBlock : LayoutSize(offsetFromRootBlock.height(), offsetFromRootBlock.width()));
503                 LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
504                 if (isPreviousBoxSelected && gapRect.width() > 0 && gapRect.height() > 0) {
505                     if (paintInfo && box->parent()->renderer()->style()->visibility() == VISIBLE)
506                         paintInfo->context->fillRect(gapRect, box->parent()->renderer()->selectionBackgroundColor(), box->parent()->renderer()->style()->colorSpace());
507                     // VisibleSelection may be non-contiguous, see comment above.
508                     result.uniteCenter(gapRect);
509                 }
510                 lastLogicalLeft = box->logicalRight();
511             }
512             if (box == lastBox)
513                 break;
514             isPreviousBoxSelected = box->selectionState() != RenderObject::SelectionNone;
515         }
516     }
517
518     return result;
519 }
520
521 RenderObject::SelectionState RootInlineBox::selectionState()
522 {
523     // Walk over all of the selected boxes.
524     RenderObject::SelectionState state = RenderObject::SelectionNone;
525     for (InlineBox* box = firstLeafChild(); box; box = box->nextLeafChild()) {
526         RenderObject::SelectionState boxState = box->selectionState();
527         if ((boxState == RenderObject::SelectionStart && state == RenderObject::SelectionEnd) ||
528             (boxState == RenderObject::SelectionEnd && state == RenderObject::SelectionStart))
529             state = RenderObject::SelectionBoth;
530         else if (state == RenderObject::SelectionNone ||
531                  ((boxState == RenderObject::SelectionStart || boxState == RenderObject::SelectionEnd) &&
532                   (state == RenderObject::SelectionNone || state == RenderObject::SelectionInside)))
533             state = boxState;
534         else if (boxState == RenderObject::SelectionNone && state == RenderObject::SelectionStart) {
535             // We are past the end of the selection.
536             state = RenderObject::SelectionBoth;
537         }
538         if (state == RenderObject::SelectionBoth)
539             break;
540     }
541
542     return state;
543 }
544
545 InlineBox* RootInlineBox::firstSelectedBox()
546 {
547     for (InlineBox* box = firstLeafChild(); box; box = box->nextLeafChild()) {
548         if (box->selectionState() != RenderObject::SelectionNone)
549             return box;
550     }
551
552     return 0;
553 }
554
555 InlineBox* RootInlineBox::lastSelectedBox()
556 {
557     for (InlineBox* box = lastLeafChild(); box; box = box->prevLeafChild()) {
558         if (box->selectionState() != RenderObject::SelectionNone)
559             return box;
560     }
561
562     return 0;
563 }
564
565 LayoutUnit RootInlineBox::selectionTop() const
566 {
567     LayoutUnit selectionTop = m_lineTop;
568
569     if (m_hasAnnotationsBefore)
570         selectionTop -= !renderer()->style()->isFlippedLinesWritingMode() ? computeOverAnnotationAdjustment(m_lineTop) : computeUnderAnnotationAdjustment(m_lineTop);
571
572     if (renderer()->style()->isFlippedLinesWritingMode())
573         return selectionTop;
574
575     LayoutUnit prevBottom = prevRootBox() ? prevRootBox()->selectionBottom() : block()->borderBefore() + block()->paddingBefore();
576     if (prevBottom < selectionTop && block()->containsFloats()) {
577         // This line has actually been moved further down, probably from a large line-height, but possibly because the
578         // line was forced to clear floats.  If so, let's check the offsets, and only be willing to use the previous
579         // line's bottom if the offsets are greater on both sides.
580         LayoutUnit prevLeft = block()->logicalLeftOffsetForLine(prevBottom, false);
581         LayoutUnit prevRight = block()->logicalRightOffsetForLine(prevBottom, false);
582         LayoutUnit newLeft = block()->logicalLeftOffsetForLine(selectionTop, false);
583         LayoutUnit newRight = block()->logicalRightOffsetForLine(selectionTop, false);
584         if (prevLeft > newLeft || prevRight < newRight)
585             return selectionTop;
586     }
587
588     return prevBottom;
589 }
590
591 LayoutUnit RootInlineBox::selectionTopAdjustedForPrecedingBlock() const
592 {
593     LayoutUnit top = selectionTop();
594
595     RenderObject::SelectionState blockSelectionState = root()->block()->selectionState();
596     if (blockSelectionState != RenderObject::SelectionInside && blockSelectionState != RenderObject::SelectionEnd)
597         return top;
598
599     LayoutSize offsetToBlockBefore;
600     if (RenderBlock* block = root()->block()->blockBeforeWithinSelectionRoot(offsetToBlockBefore)) {
601         if (RootInlineBox* lastLine = block->lastRootBox()) {
602             RenderObject::SelectionState lastLineSelectionState = lastLine->selectionState();
603             if (lastLineSelectionState != RenderObject::SelectionInside && lastLineSelectionState != RenderObject::SelectionStart)
604                 return top;
605
606             LayoutUnit lastLineSelectionBottom = lastLine->selectionBottom() + offsetToBlockBefore.height();
607             top = max(top, lastLineSelectionBottom);
608         }
609     }
610
611     return top;
612 }
613
614 LayoutUnit RootInlineBox::selectionBottom() const
615 {
616     LayoutUnit selectionBottom = m_lineBottom;
617
618     if (m_hasAnnotationsAfter)
619         selectionBottom += !renderer()->style()->isFlippedLinesWritingMode() ? computeUnderAnnotationAdjustment(m_lineBottom) : computeOverAnnotationAdjustment(m_lineBottom);
620
621     if (!renderer()->style()->isFlippedLinesWritingMode() || !nextRootBox())
622         return selectionBottom;
623
624     LayoutUnit nextTop = nextRootBox()->selectionTop();
625     if (nextTop > selectionBottom && block()->containsFloats()) {
626         // The next line has actually been moved further over, probably from a large line-height, but possibly because the
627         // line was forced to clear floats.  If so, let's check the offsets, and only be willing to use the next
628         // line's top if the offsets are greater on both sides.
629         LayoutUnit nextLeft = block()->logicalLeftOffsetForLine(nextTop, false);
630         LayoutUnit nextRight = block()->logicalRightOffsetForLine(nextTop, false);
631         LayoutUnit newLeft = block()->logicalLeftOffsetForLine(selectionBottom, false);
632         LayoutUnit newRight = block()->logicalRightOffsetForLine(selectionBottom, false);
633         if (nextLeft > newLeft || nextRight < newRight)
634             return selectionBottom;
635     }
636
637     return nextTop;
638 }
639
640 int RootInlineBox::blockDirectionPointInLine() const
641 {
642     return !block()->style()->isFlippedBlocksWritingMode() ? max(lineTop(), selectionTop()) : min(lineBottom(), selectionBottom());
643 }
644
645 RenderBlock* RootInlineBox::block() const
646 {
647     return toRenderBlock(renderer());
648 }
649
650 static bool isEditableLeaf(InlineBox* leaf)
651 {
652     return leaf && leaf->renderer() && leaf->renderer()->node() && leaf->renderer()->node()->rendererIsEditable();
653 }
654
655 InlineBox* RootInlineBox::closestLeafChildForPoint(const IntPoint& pointInContents, bool onlyEditableLeaves)
656 {
657     return closestLeafChildForLogicalLeftPosition(block()->isHorizontalWritingMode() ? pointInContents.x() : pointInContents.y(), onlyEditableLeaves);
658 }
659
660 InlineBox* RootInlineBox::closestLeafChildForLogicalLeftPosition(int leftPosition, bool onlyEditableLeaves)
661 {
662     InlineBox* firstLeaf = firstLeafChild();
663     InlineBox* lastLeaf = lastLeafChild();
664
665     if (firstLeaf != lastLeaf) {
666         if (firstLeaf->isLineBreak())
667             firstLeaf = firstLeaf->nextLeafChildIgnoringLineBreak();
668         else if (lastLeaf->isLineBreak())
669             lastLeaf = lastLeaf->prevLeafChildIgnoringLineBreak();
670     }
671
672     if (firstLeaf == lastLeaf && (!onlyEditableLeaves || isEditableLeaf(firstLeaf)))
673         return firstLeaf;
674
675     // Avoid returning a list marker when possible.
676     if (leftPosition <= firstLeaf->logicalLeft() && !firstLeaf->renderer()->isListMarker() && (!onlyEditableLeaves || isEditableLeaf(firstLeaf)))
677         // The leftPosition coordinate is less or equal to left edge of the firstLeaf.
678         // Return it.
679         return firstLeaf;
680
681     if (leftPosition >= lastLeaf->logicalRight() && !lastLeaf->renderer()->isListMarker() && (!onlyEditableLeaves || isEditableLeaf(lastLeaf)))
682         // The leftPosition coordinate is greater or equal to right edge of the lastLeaf.
683         // Return it.
684         return lastLeaf;
685
686     InlineBox* closestLeaf = 0;
687     for (InlineBox* leaf = firstLeaf; leaf; leaf = leaf->nextLeafChildIgnoringLineBreak()) {
688         if (!leaf->renderer()->isListMarker() && (!onlyEditableLeaves || isEditableLeaf(leaf))) {
689             closestLeaf = leaf;
690             if (leftPosition < leaf->logicalRight())
691                 // The x coordinate is less than the right edge of the box.
692                 // Return it.
693                 return leaf;
694         }
695     }
696
697     return closestLeaf ? closestLeaf : lastLeaf;
698 }
699
700 BidiStatus RootInlineBox::lineBreakBidiStatus() const
701
702     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);
703 }
704
705 void RootInlineBox::setLineBreakInfo(RenderObject* obj, unsigned breakPos, const BidiStatus& status)
706 {
707     m_lineBreakObj = obj;
708     m_lineBreakPos = breakPos;
709     m_lineBreakBidiStatusEor = status.eor;
710     m_lineBreakBidiStatusLastStrong = status.lastStrong;
711     m_lineBreakBidiStatusLast = status.last;
712     m_lineBreakContext = status.context;
713 }
714
715 EllipsisBox* RootInlineBox::ellipsisBox() const
716 {
717     if (!hasEllipsisBox())
718         return 0;
719     return gEllipsisBoxMap->get(this);
720 }
721
722 void RootInlineBox::removeLineBoxFromRenderObject()
723 {
724     block()->lineBoxes()->removeLineBox(this);
725 }
726
727 void RootInlineBox::extractLineBoxFromRenderObject()
728 {
729     block()->lineBoxes()->extractLineBox(this);
730 }
731
732 void RootInlineBox::attachLineBoxToRenderObject()
733 {
734     block()->lineBoxes()->attachLineBox(this);
735 }
736
737 LayoutRect RootInlineBox::paddedLayoutOverflowRect(LayoutUnit endPadding) const
738 {
739     LayoutRect lineLayoutOverflow = layoutOverflowRect(lineTop(), lineBottom());
740     if (!endPadding)
741         return lineLayoutOverflow;
742     
743     // FIXME: Audit whether to use pixel snapped values when not using integers for layout: https://bugs.webkit.org/show_bug.cgi?id=63656
744     if (isHorizontal()) {
745         if (isLeftToRightDirection())
746             lineLayoutOverflow.shiftMaxXEdgeTo(max<LayoutUnit>(lineLayoutOverflow.maxX(), pixelSnappedLogicalRight() + endPadding));
747         else
748             lineLayoutOverflow.shiftXEdgeTo(min<LayoutUnit>(lineLayoutOverflow.x(), pixelSnappedLogicalLeft() - endPadding));
749     } else {
750         if (isLeftToRightDirection())
751             lineLayoutOverflow.shiftMaxYEdgeTo(max<LayoutUnit>(lineLayoutOverflow.maxY(), pixelSnappedLogicalRight() + endPadding));
752         else
753             lineLayoutOverflow.shiftYEdgeTo(min<LayoutUnit>(lineLayoutOverflow.y(), pixelSnappedLogicalLeft() - endPadding));
754     }
755     
756     return lineLayoutOverflow;
757 }
758
759 static void setAscentAndDescent(int& ascent, int& descent, int newAscent, int newDescent, bool& ascentDescentSet)
760 {
761     if (!ascentDescentSet) {
762         ascentDescentSet = true;
763         ascent = newAscent;
764         descent = newDescent;
765     } else {
766         ascent = max(ascent, newAscent);
767         descent = max(descent, newDescent);
768     }
769 }
770
771 void RootInlineBox::ascentAndDescentForBox(InlineBox* box, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, int& ascent, int& descent,
772                                            bool& affectsAscent, bool& affectsDescent) const
773 {
774     bool ascentDescentSet = false;
775
776     // Replaced boxes will return 0 for the line-height if line-box-contain says they are
777     // not to be included.
778     if (box->renderer()->isReplaced()) {
779         if (renderer()->style(isFirstLineStyle())->lineBoxContain() & LineBoxContainReplaced) {
780             ascent = box->baselinePosition(baselineType());
781             descent = box->lineHeight() - ascent;
782             
783             // Replaced elements always affect both the ascent and descent.
784             affectsAscent = true;
785             affectsDescent = true;
786         }
787         return;
788     }
789
790     Vector<const SimpleFontData*>* usedFonts = 0;
791     GlyphOverflow* glyphOverflow = 0;
792     if (box->isText()) {
793         GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.find(toInlineTextBox(box));
794         usedFonts = it == textBoxDataMap.end() ? 0 : &it->value.first;
795         glyphOverflow = it == textBoxDataMap.end() ? 0 : &it->value.second;
796     }
797         
798     bool includeLeading = includeLeadingForBox(box);
799     bool includeFont = includeFontForBox(box);
800     
801     bool setUsedFont = false;
802     bool setUsedFontWithLeading = false;
803
804     if (usedFonts && !usedFonts->isEmpty() && (includeFont || (box->renderer()->style(isFirstLineStyle())->lineHeight().isNegative() && includeLeading))) {
805         usedFonts->append(box->renderer()->style(isFirstLineStyle())->font().primaryFont());
806         for (size_t i = 0; i < usedFonts->size(); ++i) {
807             const FontMetrics& fontMetrics = usedFonts->at(i)->fontMetrics();
808             int usedFontAscent = fontMetrics.ascent(baselineType());
809             int usedFontDescent = fontMetrics.descent(baselineType());
810             int halfLeading = (fontMetrics.lineSpacing() - fontMetrics.height()) / 2;
811             int usedFontAscentAndLeading = usedFontAscent + halfLeading;
812             int usedFontDescentAndLeading = fontMetrics.lineSpacing() - usedFontAscentAndLeading;
813             if (includeFont) {
814                 setAscentAndDescent(ascent, descent, usedFontAscent, usedFontDescent, ascentDescentSet);
815                 setUsedFont = true;
816             }
817             if (includeLeading) {
818                 setAscentAndDescent(ascent, descent, usedFontAscentAndLeading, usedFontDescentAndLeading, ascentDescentSet);
819                 setUsedFontWithLeading = true;
820             }
821             if (!affectsAscent)
822                 affectsAscent = usedFontAscent - box->logicalTop() > 0;
823             if (!affectsDescent)
824                 affectsDescent = usedFontDescent + box->logicalTop() > 0;
825         }
826     }
827
828     // If leading is included for the box, then we compute that box.
829     if (includeLeading && !setUsedFontWithLeading) {
830         int ascentWithLeading = box->baselinePosition(baselineType());
831         int descentWithLeading = box->lineHeight() - ascentWithLeading;
832         setAscentAndDescent(ascent, descent, ascentWithLeading, descentWithLeading, ascentDescentSet);
833         
834         // Examine the font box for inline flows and text boxes to see if any part of it is above the baseline.
835         // If the top of our font box relative to the root box baseline is above the root box baseline, then
836         // we are contributing to the maxAscent value. Descent is similar. If any part of our font box is below
837         // the root box's baseline, then we contribute to the maxDescent value.
838         affectsAscent = ascentWithLeading - box->logicalTop() > 0;
839         affectsDescent = descentWithLeading + box->logicalTop() > 0; 
840     }
841     
842     if (includeFontForBox(box) && !setUsedFont) {
843         int fontAscent = box->renderer()->style(isFirstLineStyle())->fontMetrics().ascent();
844         int fontDescent = box->renderer()->style(isFirstLineStyle())->fontMetrics().descent();
845         setAscentAndDescent(ascent, descent, fontAscent, fontDescent, ascentDescentSet);
846         affectsAscent = fontAscent - box->logicalTop() > 0;
847         affectsDescent = fontDescent + box->logicalTop() > 0; 
848     }
849
850     if (includeGlyphsForBox(box) && glyphOverflow && glyphOverflow->computeBounds) {
851         setAscentAndDescent(ascent, descent, glyphOverflow->top, glyphOverflow->bottom, ascentDescentSet);
852         affectsAscent = glyphOverflow->top - box->logicalTop() > 0;
853         affectsDescent = glyphOverflow->bottom + box->logicalTop() > 0; 
854         glyphOverflow->top = min(glyphOverflow->top, max(0, glyphOverflow->top - box->renderer()->style(isFirstLineStyle())->fontMetrics().ascent()));
855         glyphOverflow->bottom = min(glyphOverflow->bottom, max(0, glyphOverflow->bottom - box->renderer()->style(isFirstLineStyle())->fontMetrics().descent()));
856     }
857
858     if (includeMarginForBox(box)) {
859         LayoutUnit ascentWithMargin = box->renderer()->style(isFirstLineStyle())->fontMetrics().ascent();
860         LayoutUnit descentWithMargin = box->renderer()->style(isFirstLineStyle())->fontMetrics().descent();
861         if (box->parent() && !box->renderer()->isText()) {
862             ascentWithMargin += box->boxModelObject()->borderBefore() + box->boxModelObject()->paddingBefore() + box->boxModelObject()->marginBefore();
863             descentWithMargin += box->boxModelObject()->borderAfter() + box->boxModelObject()->paddingAfter() + box->boxModelObject()->marginAfter();
864         }
865         setAscentAndDescent(ascent, descent, ascentWithMargin, descentWithMargin, ascentDescentSet);
866         
867         // Treat like a replaced element, since we're using the margin box.
868         affectsAscent = true;
869         affectsDescent = true;
870     }
871 }
872
873 LayoutUnit RootInlineBox::verticalPositionForBox(InlineBox* box, VerticalPositionCache& verticalPositionCache)
874 {
875     if (box->renderer()->isText())
876         return box->parent()->logicalTop();
877     
878     RenderBoxModelObject* renderer = box->boxModelObject();
879     ASSERT(renderer->isInline());
880     if (!renderer->isInline())
881         return 0;
882
883     // This method determines the vertical position for inline elements.
884     bool firstLine = isFirstLineStyle();
885     if (firstLine && !renderer->document()->styleSheetCollection()->usesFirstLineRules())
886         firstLine = false;
887
888     // Check the cache.
889     bool isRenderInline = renderer->isRenderInline();
890     if (isRenderInline && !firstLine) {
891         LayoutUnit verticalPosition = verticalPositionCache.get(renderer, baselineType());
892         if (verticalPosition != PositionUndefined)
893             return verticalPosition;
894     }
895
896     LayoutUnit verticalPosition = 0;
897     EVerticalAlign verticalAlign = renderer->style()->verticalAlign();
898     if (verticalAlign == TOP || verticalAlign == BOTTOM)
899         return 0;
900    
901     RenderObject* parent = renderer->parent();
902     if (parent->isRenderInline() && parent->style()->verticalAlign() != TOP && parent->style()->verticalAlign() != BOTTOM)
903         verticalPosition = box->parent()->logicalTop();
904     
905     if (verticalAlign != BASELINE) {
906         const Font& font = parent->style(firstLine)->font();
907         const FontMetrics& fontMetrics = font.fontMetrics();
908         int fontSize = font.pixelSize();
909
910         LineDirectionMode lineDirection = parent->isHorizontalWritingMode() ? HorizontalLine : VerticalLine;
911
912         if (verticalAlign == SUB)
913             verticalPosition += fontSize / 5 + 1;
914         else if (verticalAlign == SUPER)
915             verticalPosition -= fontSize / 3 + 1;
916         else if (verticalAlign == TEXT_TOP)
917             verticalPosition += renderer->baselinePosition(baselineType(), firstLine, lineDirection) - fontMetrics.ascent(baselineType());
918         else if (verticalAlign == MIDDLE)
919             verticalPosition = (verticalPosition - static_cast<LayoutUnit>(fontMetrics.xHeight() / 2) - renderer->lineHeight(firstLine, lineDirection) / 2 + renderer->baselinePosition(baselineType(), firstLine, lineDirection)).round();
920         else if (verticalAlign == TEXT_BOTTOM) {
921             verticalPosition += fontMetrics.descent(baselineType());
922             // lineHeight - baselinePosition is always 0 for replaced elements (except inline blocks), so don't bother wasting time in that case.
923             if (!renderer->isReplaced() || renderer->isInlineBlockOrInlineTable())
924                 verticalPosition -= (renderer->lineHeight(firstLine, lineDirection) - renderer->baselinePosition(baselineType(), firstLine, lineDirection));
925         } else if (verticalAlign == BASELINE_MIDDLE)
926             verticalPosition += -renderer->lineHeight(firstLine, lineDirection) / 2 + renderer->baselinePosition(baselineType(), firstLine, lineDirection);
927         else if (verticalAlign == LENGTH) {
928             LayoutUnit lineHeight;
929             //Per http://www.w3.org/TR/CSS21/visudet.html#propdef-vertical-align: 'Percentages: refer to the 'line-height' of the element itself'.
930             if (renderer->style()->verticalAlignLength().isPercent())
931                 lineHeight = renderer->style()->computedLineHeight();
932             else
933                 lineHeight = renderer->lineHeight(firstLine, lineDirection);
934             verticalPosition -= valueForLength(renderer->style()->verticalAlignLength(), lineHeight, renderer->view());
935         }
936     }
937
938     // Store the cached value.
939     if (isRenderInline && !firstLine)
940         verticalPositionCache.set(renderer, baselineType(), verticalPosition);
941
942     return verticalPosition;
943 }
944
945 bool RootInlineBox::includeLeadingForBox(InlineBox* box) const
946 {
947     if (box->renderer()->isReplaced() || (box->renderer()->isText() && !box->isText()))
948         return false;
949
950     LineBoxContain lineBoxContain = renderer()->style()->lineBoxContain();
951     return (lineBoxContain & LineBoxContainInline) || (box == this && (lineBoxContain & LineBoxContainBlock));
952 }
953
954 bool RootInlineBox::includeFontForBox(InlineBox* box) const
955 {
956     if (box->renderer()->isReplaced() || (box->renderer()->isText() && !box->isText()))
957         return false;
958     
959     if (!box->isText() && box->isInlineFlowBox() && !toInlineFlowBox(box)->hasTextChildren())
960         return false;
961
962     // For now map "glyphs" to "font" in vertical text mode until the bounds returned by glyphs aren't garbage.
963     LineBoxContain lineBoxContain = renderer()->style()->lineBoxContain();
964     return (lineBoxContain & LineBoxContainFont) || (!isHorizontal() && (lineBoxContain & LineBoxContainGlyphs));
965 }
966
967 bool RootInlineBox::includeGlyphsForBox(InlineBox* box) const
968 {
969     if (box->renderer()->isReplaced() || (box->renderer()->isText() && !box->isText()))
970         return false;
971     
972     if (!box->isText() && box->isInlineFlowBox() && !toInlineFlowBox(box)->hasTextChildren())
973         return false;
974
975     // FIXME: We can't fit to glyphs yet for vertical text, since the bounds returned are garbage.
976     LineBoxContain lineBoxContain = renderer()->style()->lineBoxContain();
977     return isHorizontal() && (lineBoxContain & LineBoxContainGlyphs);
978 }
979
980 bool RootInlineBox::includeMarginForBox(InlineBox* box) const
981 {
982     if (box->renderer()->isReplaced() || (box->renderer()->isText() && !box->isText()))
983         return false;
984
985     LineBoxContain lineBoxContain = renderer()->style()->lineBoxContain();
986     return lineBoxContain & LineBoxContainInlineBox;
987 }
988
989
990 bool RootInlineBox::fitsToGlyphs() const
991 {
992     // FIXME: We can't fit to glyphs yet for vertical text, since the bounds returned are garbage.
993     LineBoxContain lineBoxContain = renderer()->style()->lineBoxContain();
994     return isHorizontal() && (lineBoxContain & LineBoxContainGlyphs);
995 }
996
997 bool RootInlineBox::includesRootLineBoxFontOrLeading() const
998 {
999     LineBoxContain lineBoxContain = renderer()->style()->lineBoxContain();
1000     return (lineBoxContain & LineBoxContainBlock) || (lineBoxContain & LineBoxContainInline) || (lineBoxContain & LineBoxContainFont);
1001 }
1002
1003 Node* RootInlineBox::getLogicalStartBoxWithNode(InlineBox*& startBox) const
1004 {
1005     Vector<InlineBox*> leafBoxesInLogicalOrder;
1006     collectLeafBoxesInLogicalOrder(leafBoxesInLogicalOrder);
1007     for (size_t i = 0; i < leafBoxesInLogicalOrder.size(); ++i) {
1008         if (leafBoxesInLogicalOrder[i]->renderer()->node()) {
1009             startBox = leafBoxesInLogicalOrder[i];
1010             return startBox->renderer()->node();
1011         }
1012     }
1013     startBox = 0;
1014     return 0;
1015 }
1016     
1017 Node* RootInlineBox::getLogicalEndBoxWithNode(InlineBox*& endBox) const
1018 {
1019     Vector<InlineBox*> leafBoxesInLogicalOrder;
1020     collectLeafBoxesInLogicalOrder(leafBoxesInLogicalOrder);
1021     for (size_t i = leafBoxesInLogicalOrder.size(); i > 0; --i) { 
1022         if (leafBoxesInLogicalOrder[i - 1]->renderer()->node()) {
1023             endBox = leafBoxesInLogicalOrder[i - 1];
1024             return endBox->renderer()->node();
1025         }
1026     }
1027     endBox = 0;
1028     return 0;
1029 }
1030
1031 #ifndef NDEBUG
1032 const char* RootInlineBox::boxName() const
1033 {
1034     return "RootInlineBox";
1035 }
1036 #endif
1037
1038 } // namespace WebCore