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