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