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