• 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 "CSSPropertyNames.h"
25 #include "Document.h"
26 #include "EllipsisBox.h"
27 #include "GraphicsContext.h"
28 #include "InlineTextBox.h"
29 #include "HitTestResult.h"
30 #include "RootInlineBox.h"
31 #include "RenderBlock.h"
32 #include "RenderInline.h"
33 #include "RenderLayer.h"
34 #include "RenderListMarker.h"
35 #include "RenderRubyBase.h"
36 #include "RenderRubyRun.h"
37 #include "RenderRubyText.h"
38 #include "RenderTableCell.h"
39 #include "RootInlineBox.h"
40 #include "Text.h"
41 
42 #include <math.h>
43 
44 using namespace std;
45 
46 namespace WebCore {
47 
48 #ifndef NDEBUG
49 
~InlineFlowBox()50 InlineFlowBox::~InlineFlowBox()
51 {
52     if (!m_hasBadChildList)
53         for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
54             child->setHasBadParent();
55 }
56 
57 #endif
58 
getFlowSpacingLogicalWidth()59 int InlineFlowBox::getFlowSpacingLogicalWidth()
60 {
61     int totWidth = marginBorderPaddingLogicalLeft() + marginBorderPaddingLogicalRight();
62     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
63         if (curr->isInlineFlowBox())
64             totWidth += static_cast<InlineFlowBox*>(curr)->getFlowSpacingLogicalWidth();
65     }
66     return totWidth;
67 }
68 
roundedFrameRect() const69 IntRect InlineFlowBox::roundedFrameRect() const
70 {
71     // Begin by snapping the x and y coordinates to the nearest pixel.
72     int snappedX = lroundf(x());
73     int snappedY = lroundf(y());
74 
75     int snappedMaxX = lroundf(x() + width());
76     int snappedMaxY = lroundf(y() + height());
77 
78     return IntRect(snappedX, snappedY, snappedMaxX - snappedX, snappedMaxY - snappedY);
79 }
80 
addToLine(InlineBox * child)81 void InlineFlowBox::addToLine(InlineBox* child)
82 {
83     ASSERT(!child->parent());
84     ASSERT(!child->nextOnLine());
85     ASSERT(!child->prevOnLine());
86     checkConsistency();
87 
88     child->setParent(this);
89     if (!m_firstChild) {
90         m_firstChild = child;
91         m_lastChild = child;
92     } else {
93         m_lastChild->setNextOnLine(child);
94         child->setPrevOnLine(m_lastChild);
95         m_lastChild = child;
96     }
97     child->setFirstLineStyleBit(m_firstLine);
98     child->setIsHorizontal(isHorizontal());
99     if (child->isText()) {
100         if (child->renderer()->parent() == renderer())
101             m_hasTextChildren = true;
102         m_hasTextDescendants = true;
103     } else if (child->isInlineFlowBox()) {
104         if (static_cast<InlineFlowBox*>(child)->hasTextDescendants())
105             m_hasTextDescendants = true;
106     }
107 
108     if (descendantsHaveSameLineHeightAndBaseline() && !child->renderer()->isPositioned()) {
109         RenderStyle* parentStyle = renderer()->style(m_firstLine);
110         RenderStyle* childStyle = child->renderer()->style(m_firstLine);
111         bool shouldClearDescendantsHaveSameLineHeightAndBaseline = false;
112         if (child->renderer()->isReplaced())
113             shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
114         else if (child->isText()) {
115             if (child->renderer()->isBR() || child->renderer()->parent() != renderer()) {
116                 if (!parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle->font().fontMetrics())
117                     || parentStyle->lineHeight() != childStyle->lineHeight()
118                     || (parentStyle->verticalAlign() != BASELINE && !isRootInlineBox()) || childStyle->verticalAlign() != BASELINE)
119                     shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
120             }
121             if (childStyle->hasTextCombine() || childStyle->textEmphasisMark() != TextEmphasisMarkNone)
122                 shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
123         } else {
124             if (child->renderer()->isBR()) {
125                 // FIXME: This is dumb. We only turn off because current layout test results expect the <br> to be 0-height on the baseline.
126                 // Other than making a zillion tests have to regenerate results, there's no reason to ditch the optimization here.
127                 shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
128             } else {
129                 ASSERT(isInlineFlowBox());
130                 InlineFlowBox* childFlowBox = static_cast<InlineFlowBox*>(child);
131                 // Check the child's bit, and then also check for differences in font, line-height, vertical-align
132                 if (!childFlowBox->descendantsHaveSameLineHeightAndBaseline()
133                     || !parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle->font().fontMetrics())
134                     || parentStyle->lineHeight() != childStyle->lineHeight()
135                     || (parentStyle->verticalAlign() != BASELINE && !isRootInlineBox()) || childStyle->verticalAlign() != BASELINE
136                     || childStyle->hasBorder() || childStyle->hasPadding() || childStyle->hasTextCombine())
137                     shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
138             }
139         }
140 
141         if (shouldClearDescendantsHaveSameLineHeightAndBaseline)
142             clearDescendantsHaveSameLineHeightAndBaseline();
143     }
144 
145     if (!child->renderer()->isPositioned()) {
146         if (child->isText()) {
147             RenderStyle* childStyle = child->renderer()->style(m_firstLine);
148             if (childStyle->letterSpacing() < 0 || childStyle->textShadow() || childStyle->textEmphasisMark() != TextEmphasisMarkNone || childStyle->textStrokeWidth())
149                 child->clearKnownToHaveNoOverflow();
150         } else if (child->renderer()->isReplaced()) {
151             RenderBox* box = toRenderBox(child->renderer());
152             if (box->hasRenderOverflow() || box->hasSelfPaintingLayer())
153                 child->clearKnownToHaveNoOverflow();
154         } else if (!child->renderer()->isBR() && (child->renderer()->style(m_firstLine)->boxShadow() || child->boxModelObject()->hasSelfPaintingLayer()
155                    || (child->renderer()->isListMarker() && !toRenderListMarker(child->renderer())->isInside())))
156             child->clearKnownToHaveNoOverflow();
157 
158         if (knownToHaveNoOverflow() && child->isInlineFlowBox() && !static_cast<InlineFlowBox*>(child)->knownToHaveNoOverflow())
159             clearKnownToHaveNoOverflow();
160     }
161 
162     checkConsistency();
163 }
164 
removeChild(InlineBox * child)165 void InlineFlowBox::removeChild(InlineBox* child)
166 {
167     checkConsistency();
168 
169     if (!m_dirty)
170         dirtyLineBoxes();
171 
172     root()->childRemoved(child);
173 
174     if (child == m_firstChild)
175         m_firstChild = child->nextOnLine();
176     if (child == m_lastChild)
177         m_lastChild = child->prevOnLine();
178     if (child->nextOnLine())
179         child->nextOnLine()->setPrevOnLine(child->prevOnLine());
180     if (child->prevOnLine())
181         child->prevOnLine()->setNextOnLine(child->nextOnLine());
182 
183     child->setParent(0);
184 
185     checkConsistency();
186 }
187 
deleteLine(RenderArena * arena)188 void InlineFlowBox::deleteLine(RenderArena* arena)
189 {
190     InlineBox* child = firstChild();
191     InlineBox* next = 0;
192     while (child) {
193         ASSERT(this == child->parent());
194         next = child->nextOnLine();
195 #ifndef NDEBUG
196         child->setParent(0);
197 #endif
198         child->deleteLine(arena);
199         child = next;
200     }
201 #ifndef NDEBUG
202     m_firstChild = 0;
203     m_lastChild = 0;
204 #endif
205 
206     removeLineBoxFromRenderObject();
207     destroy(arena);
208 }
209 
removeLineBoxFromRenderObject()210 void InlineFlowBox::removeLineBoxFromRenderObject()
211 {
212     toRenderInline(renderer())->lineBoxes()->removeLineBox(this);
213 }
214 
extractLine()215 void InlineFlowBox::extractLine()
216 {
217     if (!m_extracted)
218         extractLineBoxFromRenderObject();
219     for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
220         child->extractLine();
221 }
222 
extractLineBoxFromRenderObject()223 void InlineFlowBox::extractLineBoxFromRenderObject()
224 {
225     toRenderInline(renderer())->lineBoxes()->extractLineBox(this);
226 }
227 
attachLine()228 void InlineFlowBox::attachLine()
229 {
230     if (m_extracted)
231         attachLineBoxToRenderObject();
232     for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
233         child->attachLine();
234 }
235 
attachLineBoxToRenderObject()236 void InlineFlowBox::attachLineBoxToRenderObject()
237 {
238     toRenderInline(renderer())->lineBoxes()->attachLineBox(this);
239 }
240 
adjustPosition(float dx,float dy)241 void InlineFlowBox::adjustPosition(float dx, float dy)
242 {
243     InlineBox::adjustPosition(dx, dy);
244     for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
245         child->adjustPosition(dx, dy);
246     if (m_overflow)
247         m_overflow->move(dx, dy); // FIXME: Rounding error here since overflow was pixel snapped, but nobody other than list markers passes non-integral values here.
248 }
249 
rendererLineBoxes() const250 RenderLineBoxList* InlineFlowBox::rendererLineBoxes() const
251 {
252     return toRenderInline(renderer())->lineBoxes();
253 }
254 
isLastChildForRenderer(RenderObject * ancestor,RenderObject * child)255 static inline bool isLastChildForRenderer(RenderObject* ancestor, RenderObject* child)
256 {
257     if (!child)
258         return false;
259 
260     if (child == ancestor)
261         return true;
262 
263     RenderObject* curr = child;
264     RenderObject* parent = curr->parent();
265     while (parent && (!parent->isRenderBlock() || parent->isInline())) {
266         if (parent->lastChild() != curr)
267             return false;
268         if (parent == ancestor)
269             return true;
270 
271         curr = parent;
272         parent = curr->parent();
273     }
274 
275     return true;
276 }
277 
isAnsectorAndWithinBlock(RenderObject * ancestor,RenderObject * child)278 static bool isAnsectorAndWithinBlock(RenderObject* ancestor, RenderObject* child)
279 {
280     RenderObject* object = child;
281     while (object && (!object->isRenderBlock() || object->isInline())) {
282         if (object == ancestor)
283             return true;
284         object = object->parent();
285     }
286     return false;
287 }
288 
determineSpacingForFlowBoxes(bool lastLine,bool isLogicallyLastRunWrapped,RenderObject * logicallyLastRunRenderer)289 void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, bool isLogicallyLastRunWrapped, RenderObject* logicallyLastRunRenderer)
290 {
291     // All boxes start off open.  They will not apply any margins/border/padding on
292     // any side.
293     bool includeLeftEdge = false;
294     bool includeRightEdge = false;
295 
296     // The root inline box never has borders/margins/padding.
297     if (parent()) {
298         bool ltr = renderer()->style()->isLeftToRightDirection();
299 
300         // Check to see if all initial lines are unconstructed.  If so, then
301         // we know the inline began on this line (unless we are a continuation).
302         RenderLineBoxList* lineBoxList = rendererLineBoxes();
303         if (!lineBoxList->firstLineBox()->isConstructed() && !renderer()->isInlineElementContinuation()) {
304             if (ltr && lineBoxList->firstLineBox() == this)
305                 includeLeftEdge = true;
306             else if (!ltr && lineBoxList->lastLineBox() == this)
307                 includeRightEdge = true;
308         }
309 
310         if (!lineBoxList->lastLineBox()->isConstructed()) {
311             RenderInline* inlineFlow = toRenderInline(renderer());
312             bool isLastObjectOnLine = !isAnsectorAndWithinBlock(renderer(), logicallyLastRunRenderer) || (isLastChildForRenderer(renderer(), logicallyLastRunRenderer) && !isLogicallyLastRunWrapped);
313 
314             // We include the border under these conditions:
315             // (1) The next line was not created, or it is constructed. We check the previous line for rtl.
316             // (2) The logicallyLastRun is not a descendant of this renderer.
317             // (3) The logicallyLastRun is a descendant of this renderer, but it is the last child of this renderer and it does not wrap to the next line.
318 
319             if (ltr) {
320                 if (!nextLineBox()
321                     && ((lastLine || isLastObjectOnLine) && !inlineFlow->continuation()))
322                     includeRightEdge = true;
323             } else {
324                 if ((!prevLineBox() || prevLineBox()->isConstructed())
325                     && ((lastLine || isLastObjectOnLine) && !inlineFlow->continuation()))
326                     includeLeftEdge = true;
327             }
328         }
329     }
330 
331     setEdges(includeLeftEdge, includeRightEdge);
332 
333     // Recur into our children.
334     for (InlineBox* currChild = firstChild(); currChild; currChild = currChild->nextOnLine()) {
335         if (currChild->isInlineFlowBox()) {
336             InlineFlowBox* currFlow = static_cast<InlineFlowBox*>(currChild);
337             currFlow->determineSpacingForFlowBoxes(lastLine, isLogicallyLastRunWrapped, logicallyLastRunRenderer);
338         }
339     }
340 }
341 
placeBoxesInInlineDirection(float logicalLeft,bool & needsWordSpacing,GlyphOverflowAndFallbackFontsMap & textBoxDataMap)342 float InlineFlowBox::placeBoxesInInlineDirection(float logicalLeft, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap& textBoxDataMap)
343 {
344     // Set our x position.
345     setLogicalLeft(logicalLeft);
346 
347     float startLogicalLeft = logicalLeft;
348     logicalLeft += borderLogicalLeft() + paddingLogicalLeft();
349 
350     float minLogicalLeft = startLogicalLeft;
351     float maxLogicalRight = logicalLeft;
352 
353     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
354         if (curr->renderer()->isText()) {
355             InlineTextBox* text = static_cast<InlineTextBox*>(curr);
356             RenderText* rt = toRenderText(text->renderer());
357             if (rt->textLength()) {
358                 if (needsWordSpacing && isSpaceOrNewline(rt->characters()[text->start()]))
359                     logicalLeft += rt->style(m_firstLine)->font().wordSpacing();
360                 needsWordSpacing = !isSpaceOrNewline(rt->characters()[text->end()]);
361             }
362             text->setLogicalLeft(logicalLeft);
363             if (knownToHaveNoOverflow())
364                 minLogicalLeft = min(logicalLeft, minLogicalLeft);
365             logicalLeft += text->logicalWidth();
366             if (knownToHaveNoOverflow())
367                 maxLogicalRight = max(logicalLeft, maxLogicalRight);
368         } else {
369             if (curr->renderer()->isPositioned()) {
370                 if (curr->renderer()->parent()->style()->isLeftToRightDirection())
371                     curr->setLogicalLeft(logicalLeft);
372                 else
373                     // Our offset that we cache needs to be from the edge of the right border box and
374                     // not the left border box.  We have to subtract |x| from the width of the block
375                     // (which can be obtained from the root line box).
376                     curr->setLogicalLeft(root()->block()->logicalWidth() - logicalLeft);
377                 continue; // The positioned object has no effect on the width.
378             }
379             if (curr->renderer()->isRenderInline()) {
380                 InlineFlowBox* flow = static_cast<InlineFlowBox*>(curr);
381                 logicalLeft += flow->marginLogicalLeft();
382                 if (knownToHaveNoOverflow())
383                     minLogicalLeft = min(logicalLeft, minLogicalLeft);
384                 logicalLeft = flow->placeBoxesInInlineDirection(logicalLeft, needsWordSpacing, textBoxDataMap);
385                 if (knownToHaveNoOverflow())
386                     maxLogicalRight = max(logicalLeft, maxLogicalRight);
387                 logicalLeft += flow->marginLogicalRight();
388             } else if (!curr->renderer()->isListMarker() || toRenderListMarker(curr->renderer())->isInside()) {
389                 // The box can have a different writing-mode than the overall line, so this is a bit complicated.
390                 // Just get all the physical margin and overflow values by hand based off |isVertical|.
391                 int logicalLeftMargin = isHorizontal() ? curr->boxModelObject()->marginLeft() : curr->boxModelObject()->marginTop();
392                 int logicalRightMargin = isHorizontal() ? curr->boxModelObject()->marginRight() : curr->boxModelObject()->marginBottom();
393 
394                 logicalLeft += logicalLeftMargin;
395                 curr->setLogicalLeft(logicalLeft);
396                 if (knownToHaveNoOverflow())
397                     minLogicalLeft = min(logicalLeft, minLogicalLeft);
398                 logicalLeft += curr->logicalWidth();
399                 if (knownToHaveNoOverflow())
400                     maxLogicalRight = max(logicalLeft, maxLogicalRight);
401                 logicalLeft += logicalRightMargin;
402             }
403         }
404     }
405 
406     logicalLeft += borderLogicalRight() + paddingLogicalRight();
407     setLogicalWidth(logicalLeft - startLogicalLeft);
408     if (knownToHaveNoOverflow() && (minLogicalLeft < startLogicalLeft || maxLogicalRight > logicalLeft))
409         clearKnownToHaveNoOverflow();
410     return logicalLeft;
411 }
412 
requiresIdeographicBaseline(const GlyphOverflowAndFallbackFontsMap & textBoxDataMap) const413 bool InlineFlowBox::requiresIdeographicBaseline(const GlyphOverflowAndFallbackFontsMap& textBoxDataMap) const
414 {
415     if (isHorizontal())
416         return false;
417 
418     if (renderer()->style(m_firstLine)->fontDescription().textOrientation() == TextOrientationUpright
419         || renderer()->style(m_firstLine)->font().primaryFont()->hasVerticalGlyphs())
420         return true;
421 
422     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
423         if (curr->renderer()->isPositioned())
424             continue; // Positioned placeholders don't affect calculations.
425 
426         if (curr->isInlineFlowBox()) {
427             if (static_cast<InlineFlowBox*>(curr)->requiresIdeographicBaseline(textBoxDataMap))
428                 return true;
429         } else {
430             if (curr->renderer()->style(m_firstLine)->font().primaryFont()->hasVerticalGlyphs())
431                 return true;
432 
433             const Vector<const SimpleFontData*>* usedFonts = 0;
434             if (curr->isInlineTextBox()) {
435                 GlyphOverflowAndFallbackFontsMap::const_iterator it = textBoxDataMap.find(static_cast<InlineTextBox*>(curr));
436                 usedFonts = it == textBoxDataMap.end() ? 0 : &it->second.first;
437             }
438 
439             if (usedFonts) {
440                 for (size_t i = 0; i < usedFonts->size(); ++i) {
441                     if (usedFonts->at(i)->hasVerticalGlyphs())
442                         return true;
443                 }
444             }
445         }
446     }
447 
448     return false;
449 }
450 
adjustMaxAscentAndDescent(int & maxAscent,int & maxDescent,int maxPositionTop,int maxPositionBottom)451 void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, int maxPositionTop, int maxPositionBottom)
452 {
453     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
454         // The computed lineheight needs to be extended for the
455         // positioned elements
456         if (curr->renderer()->isPositioned())
457             continue; // Positioned placeholders don't affect calculations.
458         if (curr->verticalAlign() == TOP || curr->verticalAlign() == BOTTOM) {
459             int lineHeight = curr->lineHeight();
460             if (curr->verticalAlign() == TOP) {
461                 if (maxAscent + maxDescent < lineHeight)
462                     maxDescent = lineHeight - maxAscent;
463             }
464             else {
465                 if (maxAscent + maxDescent < lineHeight)
466                     maxAscent = lineHeight - maxDescent;
467             }
468 
469             if (maxAscent + maxDescent >= max(maxPositionTop, maxPositionBottom))
470                 break;
471         }
472 
473         if (curr->isInlineFlowBox())
474             static_cast<InlineFlowBox*>(curr)->adjustMaxAscentAndDescent(maxAscent, maxDescent, maxPositionTop, maxPositionBottom);
475     }
476 }
477 
computeLogicalBoxHeights(RootInlineBox * rootBox,int & maxPositionTop,int & maxPositionBottom,int & maxAscent,int & maxDescent,bool & setMaxAscent,bool & setMaxDescent,bool strictMode,GlyphOverflowAndFallbackFontsMap & textBoxDataMap,FontBaseline baselineType,VerticalPositionCache & verticalPositionCache)478 void InlineFlowBox::computeLogicalBoxHeights(RootInlineBox* rootBox, int& maxPositionTop, int& maxPositionBottom,
479                                              int& maxAscent, int& maxDescent, bool& setMaxAscent, bool& setMaxDescent,
480                                              bool strictMode, GlyphOverflowAndFallbackFontsMap& textBoxDataMap,
481                                              FontBaseline baselineType, VerticalPositionCache& verticalPositionCache)
482 {
483     // The primary purpose of this function is to compute the maximal ascent and descent values for
484     // a line. These values are computed based off the block's line-box-contain property, which indicates
485     // what parts of descendant boxes have to fit within the line.
486     //
487     // The maxAscent value represents the distance of the highest point of any box (typically including line-height) from
488     // the root box's baseline. The maxDescent value represents the distance of the lowest point of any box
489     // (also typically including line-height) from the root box baseline. These values can be negative.
490     //
491     // A secondary purpose of this function is to store the offset of every box's baseline from the root box's
492     // baseline. This information is cached in the logicalTop() of every box. We're effectively just using
493     // the logicalTop() as scratch space.
494     //
495     // Because a box can be positioned such that it ends up fully above or fully below the
496     // root line box, we only consider it to affect the maxAscent and maxDescent values if some
497     // part of the box (EXCLUDING leading) is above (for ascent) or below (for descent) the root box's baseline.
498     bool affectsAscent = false;
499     bool affectsDescent = false;
500     bool checkChildren = !descendantsHaveSameLineHeightAndBaseline();
501 
502     if (isRootInlineBox()) {
503         // Examine our root box.
504         int ascent = 0;
505         int descent = 0;
506         rootBox->ascentAndDescentForBox(rootBox, textBoxDataMap, ascent, descent, affectsAscent, affectsDescent);
507         if (strictMode || hasTextChildren() || (!checkChildren && hasTextDescendants())) {
508             if (maxAscent < ascent || !setMaxAscent) {
509                 maxAscent = ascent;
510                 setMaxAscent = true;
511             }
512             if (maxDescent < descent || !setMaxDescent) {
513                 maxDescent = descent;
514                 setMaxDescent = true;
515             }
516         }
517     }
518 
519     if (!checkChildren)
520         return;
521 
522     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
523         if (curr->renderer()->isPositioned())
524             continue; // Positioned placeholders don't affect calculations.
525 
526         InlineFlowBox* inlineFlowBox = curr->isInlineFlowBox() ? static_cast<InlineFlowBox*>(curr) : 0;
527 
528         bool affectsAscent = false;
529         bool affectsDescent = false;
530 
531         // The verticalPositionForBox function returns the distance between the child box's baseline
532         // and the root box's baseline.  The value is negative if the child box's baseline is above the
533         // root box's baseline, and it is positive if the child box's baseline is below the root box's baseline.
534         curr->setLogicalTop(rootBox->verticalPositionForBox(curr, verticalPositionCache));
535 
536         int ascent = 0;
537         int descent = 0;
538         rootBox->ascentAndDescentForBox(curr, textBoxDataMap, ascent, descent, affectsAscent, affectsDescent);
539 
540         int boxHeight = ascent + descent;
541         if (curr->verticalAlign() == TOP) {
542             if (maxPositionTop < boxHeight)
543                 maxPositionTop = boxHeight;
544         } else if (curr->verticalAlign() == BOTTOM) {
545             if (maxPositionBottom < boxHeight)
546                 maxPositionBottom = boxHeight;
547         } else if (!inlineFlowBox || strictMode || inlineFlowBox->hasTextChildren() || (inlineFlowBox->descendantsHaveSameLineHeightAndBaseline() && inlineFlowBox->hasTextDescendants())
548                    || inlineFlowBox->boxModelObject()->hasInlineDirectionBordersOrPadding()) {
549             // Note that these values can be negative.  Even though we only affect the maxAscent and maxDescent values
550             // if our box (excluding line-height) was above (for ascent) or below (for descent) the root baseline, once you factor in line-height
551             // the final box can end up being fully above or fully below the root box's baseline!  This is ok, but what it
552             // means is that ascent and descent (including leading), can end up being negative.  The setMaxAscent and
553             // setMaxDescent booleans are used to ensure that we're willing to initially set maxAscent/Descent to negative
554             // values.
555             ascent -= curr->logicalTop();
556             descent += curr->logicalTop();
557             if (affectsAscent && (maxAscent < ascent || !setMaxAscent)) {
558                 maxAscent = ascent;
559                 setMaxAscent = true;
560             }
561 
562             if (affectsDescent && (maxDescent < descent || !setMaxDescent)) {
563                 maxDescent = descent;
564                 setMaxDescent = true;
565             }
566         }
567 
568         if (inlineFlowBox)
569             inlineFlowBox->computeLogicalBoxHeights(rootBox, maxPositionTop, maxPositionBottom, maxAscent, maxDescent,
570                                                     setMaxAscent, setMaxDescent, strictMode, textBoxDataMap,
571                                                     baselineType, verticalPositionCache);
572     }
573 }
574 
placeBoxesInBlockDirection(int top,int maxHeight,int maxAscent,bool strictMode,int & lineTop,int & lineBottom,bool & setLineTop,int & lineTopIncludingMargins,int & lineBottomIncludingMargins,bool & hasAnnotationsBefore,bool & hasAnnotationsAfter,FontBaseline baselineType)575 void InlineFlowBox::placeBoxesInBlockDirection(int top, int maxHeight, int maxAscent, bool strictMode, int& lineTop, int& lineBottom, bool& setLineTop,
576                                                int& lineTopIncludingMargins, int& lineBottomIncludingMargins, bool& hasAnnotationsBefore, bool& hasAnnotationsAfter, FontBaseline baselineType)
577 {
578     bool isRootBox = isRootInlineBox();
579     if (isRootBox) {
580         const FontMetrics& fontMetrics = renderer()->style(m_firstLine)->fontMetrics();
581         setLogicalTop(top + maxAscent - fontMetrics.ascent(baselineType));
582     }
583 
584     int adjustmentForChildrenWithSameLineHeightAndBaseline = 0;
585     if (descendantsHaveSameLineHeightAndBaseline()) {
586         adjustmentForChildrenWithSameLineHeightAndBaseline = logicalTop();
587         if (parent())
588             adjustmentForChildrenWithSameLineHeightAndBaseline += (boxModelObject()->borderBefore() + boxModelObject()->paddingBefore());
589     }
590 
591     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
592         if (curr->renderer()->isPositioned())
593             continue; // Positioned placeholders don't affect calculations.
594 
595         if (descendantsHaveSameLineHeightAndBaseline()) {
596             curr->adjustBlockDirectionPosition(adjustmentForChildrenWithSameLineHeightAndBaseline);
597             continue;
598         }
599 
600         InlineFlowBox* inlineFlowBox = curr->isInlineFlowBox() ? static_cast<InlineFlowBox*>(curr) : 0;
601         bool childAffectsTopBottomPos = true;
602         if (curr->verticalAlign() == TOP)
603             curr->setLogicalTop(top);
604         else if (curr->verticalAlign() == BOTTOM)
605             curr->setLogicalTop(top + maxHeight - curr->lineHeight());
606         else {
607             if (!strictMode && inlineFlowBox && !inlineFlowBox->hasTextChildren() && !curr->boxModelObject()->hasInlineDirectionBordersOrPadding()
608                 && !(inlineFlowBox->descendantsHaveSameLineHeightAndBaseline() && inlineFlowBox->hasTextDescendants()))
609                 childAffectsTopBottomPos = false;
610             int posAdjust = maxAscent - curr->baselinePosition(baselineType);
611             curr->setLogicalTop(curr->logicalTop() + top + posAdjust);
612         }
613 
614         int newLogicalTop = curr->logicalTop();
615         int newLogicalTopIncludingMargins = newLogicalTop;
616         int boxHeight = curr->logicalHeight();
617         int boxHeightIncludingMargins = boxHeight;
618 
619         if (curr->isText() || curr->isInlineFlowBox()) {
620             const FontMetrics& fontMetrics = curr->renderer()->style(m_firstLine)->fontMetrics();
621             newLogicalTop += curr->baselinePosition(baselineType) - fontMetrics.ascent(baselineType);
622             if (curr->isInlineFlowBox()) {
623                 RenderBoxModelObject* boxObject = toRenderBoxModelObject(curr->renderer());
624                 newLogicalTop -= boxObject->style(m_firstLine)->isHorizontalWritingMode() ? boxObject->borderTop() + boxObject->paddingTop() :
625                                  boxObject->borderRight() + boxObject->paddingRight();
626             }
627             newLogicalTopIncludingMargins = newLogicalTop;
628         } else if (!curr->renderer()->isBR()) {
629             RenderBox* box = toRenderBox(curr->renderer());
630             newLogicalTopIncludingMargins = newLogicalTop;
631             int overSideMargin = curr->isHorizontal() ? box->marginTop() : box->marginRight();
632             int underSideMargin = curr->isHorizontal() ? box->marginBottom() : box->marginLeft();
633             newLogicalTop += overSideMargin;
634             boxHeightIncludingMargins += overSideMargin + underSideMargin;
635         }
636 
637         curr->setLogicalTop(newLogicalTop);
638 
639         if (childAffectsTopBottomPos) {
640             if (curr->renderer()->isRubyRun()) {
641                 // Treat the leading on the first and last lines of ruby runs as not being part of the overall lineTop/lineBottom.
642                 // Really this is a workaround hack for the fact that ruby should have been done as line layout and not done using
643                 // inline-block.
644                 if (!renderer()->style()->isFlippedLinesWritingMode())
645                     hasAnnotationsBefore = true;
646                 else
647                     hasAnnotationsAfter = true;
648 
649                 RenderRubyRun* rubyRun = static_cast<RenderRubyRun*>(curr->renderer());
650                 if (RenderRubyBase* rubyBase = rubyRun->rubyBase()) {
651                     int bottomRubyBaseLeading = (curr->logicalHeight() - rubyBase->logicalBottom()) + rubyBase->logicalHeight() - (rubyBase->lastRootBox() ? rubyBase->lastRootBox()->lineBottom() : 0);
652                     int topRubyBaseLeading = rubyBase->logicalTop() + (rubyBase->firstRootBox() ? rubyBase->firstRootBox()->lineTop() : 0);
653                     newLogicalTop += !renderer()->style()->isFlippedLinesWritingMode() ? topRubyBaseLeading : bottomRubyBaseLeading;
654                     boxHeight -= (topRubyBaseLeading + bottomRubyBaseLeading);
655                 }
656             }
657             if (curr->isInlineTextBox()) {
658                 TextEmphasisPosition emphasisMarkPosition;
659                 if (static_cast<InlineTextBox*>(curr)->getEmphasisMarkPosition(curr->renderer()->style(m_firstLine), emphasisMarkPosition)) {
660                     bool emphasisMarkIsOver = emphasisMarkPosition == TextEmphasisPositionOver;
661                     if (emphasisMarkIsOver != curr->renderer()->style(m_firstLine)->isFlippedLinesWritingMode())
662                         hasAnnotationsBefore = true;
663                     else
664                         hasAnnotationsAfter = true;
665                 }
666             }
667 
668             if (!setLineTop) {
669                 setLineTop = true;
670                 lineTop = newLogicalTop;
671                 lineTopIncludingMargins = min(lineTop, newLogicalTopIncludingMargins);
672             } else {
673                 lineTop = min(lineTop, newLogicalTop);
674                 lineTopIncludingMargins = min(lineTop, min(lineTopIncludingMargins, newLogicalTopIncludingMargins));
675             }
676             lineBottom = max(lineBottom, newLogicalTop + boxHeight);
677             lineBottomIncludingMargins = max(lineBottom, max(lineBottomIncludingMargins, newLogicalTopIncludingMargins + boxHeightIncludingMargins));
678         }
679 
680         // Adjust boxes to use their real box y/height and not the logical height (as dictated by
681         // line-height).
682         if (inlineFlowBox)
683             inlineFlowBox->placeBoxesInBlockDirection(top, maxHeight, maxAscent, strictMode, lineTop, lineBottom, setLineTop,
684                                                       lineTopIncludingMargins, lineBottomIncludingMargins, hasAnnotationsBefore, hasAnnotationsAfter, baselineType);
685     }
686 
687     if (isRootBox) {
688         if (strictMode || hasTextChildren() || (descendantsHaveSameLineHeightAndBaseline() && hasTextDescendants())) {
689             if (!setLineTop) {
690                 setLineTop = true;
691                 lineTop = logicalTop();
692                 lineTopIncludingMargins = lineTop;
693             } else {
694                 lineTop = min(lineTop, logicalTop());
695                 lineTopIncludingMargins = min(lineTop, lineTopIncludingMargins);
696             }
697             lineBottom = max(lineBottom, logicalTop() + logicalHeight());
698             lineBottomIncludingMargins = max(lineBottom, lineBottomIncludingMargins);
699         }
700 
701         if (renderer()->style()->isFlippedLinesWritingMode())
702             flipLinesInBlockDirection(lineTopIncludingMargins, lineBottomIncludingMargins);
703     }
704 }
705 
flipLinesInBlockDirection(int lineTop,int lineBottom)706 void InlineFlowBox::flipLinesInBlockDirection(int lineTop, int lineBottom)
707 {
708     // Flip the box on the line such that the top is now relative to the lineBottom instead of the lineTop.
709     setLogicalTop(lineBottom - (logicalTop() - lineTop) - logicalHeight());
710 
711     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
712         if (curr->renderer()->isPositioned())
713             continue; // Positioned placeholders aren't affected here.
714 
715         if (curr->isInlineFlowBox())
716             static_cast<InlineFlowBox*>(curr)->flipLinesInBlockDirection(lineTop, lineBottom);
717         else
718             curr->setLogicalTop(lineBottom - (curr->logicalTop() - lineTop) - curr->logicalHeight());
719     }
720 }
721 
addBoxShadowVisualOverflow(IntRect & logicalVisualOverflow)722 inline void InlineFlowBox::addBoxShadowVisualOverflow(IntRect& logicalVisualOverflow)
723 {
724     if (!parent())
725         return; // Box-shadow doesn't apply to root line boxes.
726 
727     int boxShadowLogicalTop;
728     int boxShadowLogicalBottom;
729     renderer()->style(m_firstLine)->getBoxShadowBlockDirectionExtent(boxShadowLogicalTop, boxShadowLogicalBottom);
730 
731     int logicalTopVisualOverflow = min(logicalTop() + boxShadowLogicalTop, logicalVisualOverflow.y());
732     int logicalBottomVisualOverflow = max(logicalBottom() + boxShadowLogicalBottom, logicalVisualOverflow.maxY());
733 
734     int boxShadowLogicalLeft;
735     int boxShadowLogicalRight;
736     renderer()->style(m_firstLine)->getBoxShadowInlineDirectionExtent(boxShadowLogicalLeft, boxShadowLogicalRight);
737 
738     int logicalLeftVisualOverflow = min(pixelSnappedLogicalLeft() + boxShadowLogicalLeft, logicalVisualOverflow.x());
739     int logicalRightVisualOverflow = max(pixelSnappedLogicalRight() + boxShadowLogicalRight, logicalVisualOverflow.maxX());
740 
741     logicalVisualOverflow = IntRect(logicalLeftVisualOverflow, logicalTopVisualOverflow,
742                                     logicalRightVisualOverflow - logicalLeftVisualOverflow, logicalBottomVisualOverflow - logicalTopVisualOverflow);
743 }
744 
addTextBoxVisualOverflow(InlineTextBox * textBox,GlyphOverflowAndFallbackFontsMap & textBoxDataMap,IntRect & logicalVisualOverflow)745 inline void InlineFlowBox::addTextBoxVisualOverflow(InlineTextBox* textBox, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, IntRect& logicalVisualOverflow)
746 {
747     if (textBox->knownToHaveNoOverflow())
748         return;
749 
750     RenderStyle* style = textBox->renderer()->style(m_firstLine);
751 
752     GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.find(textBox);
753     GlyphOverflow* glyphOverflow = it == textBoxDataMap.end() ? 0 : &it->second.second;
754     bool isFlippedLine = style->isFlippedLinesWritingMode();
755 
756     int topGlyphEdge = glyphOverflow ? (isFlippedLine ? glyphOverflow->bottom : glyphOverflow->top) : 0;
757     int bottomGlyphEdge = glyphOverflow ? (isFlippedLine ? glyphOverflow->top : glyphOverflow->bottom) : 0;
758     int leftGlyphEdge = glyphOverflow ? glyphOverflow->left : 0;
759     int rightGlyphEdge = glyphOverflow ? glyphOverflow->right : 0;
760 
761     int strokeOverflow = static_cast<int>(ceilf(style->textStrokeWidth() / 2.0f));
762     int topGlyphOverflow = -strokeOverflow - topGlyphEdge;
763     int bottomGlyphOverflow = strokeOverflow + bottomGlyphEdge;
764     int leftGlyphOverflow = -strokeOverflow - leftGlyphEdge;
765     int rightGlyphOverflow = strokeOverflow + rightGlyphEdge;
766 
767     TextEmphasisPosition emphasisMarkPosition;
768     if (style->textEmphasisMark() != TextEmphasisMarkNone && textBox->getEmphasisMarkPosition(style, emphasisMarkPosition)) {
769         int emphasisMarkHeight = style->font().emphasisMarkHeight(style->textEmphasisMarkString());
770         if ((emphasisMarkPosition == TextEmphasisPositionOver) == (!style->isFlippedLinesWritingMode()))
771             topGlyphOverflow = min(topGlyphOverflow, -emphasisMarkHeight);
772         else
773             bottomGlyphOverflow = max(bottomGlyphOverflow, emphasisMarkHeight);
774     }
775 
776     // If letter-spacing is negative, we should factor that into right layout overflow. (Even in RTL, letter-spacing is
777     // applied to the right, so this is not an issue with left overflow.
778     rightGlyphOverflow -= min(0, (int)style->font().letterSpacing());
779 
780     int textShadowLogicalTop;
781     int textShadowLogicalBottom;
782     style->getTextShadowBlockDirectionExtent(textShadowLogicalTop, textShadowLogicalBottom);
783 
784     int childOverflowLogicalTop = min(textShadowLogicalTop + topGlyphOverflow, topGlyphOverflow);
785     int childOverflowLogicalBottom = max(textShadowLogicalBottom + bottomGlyphOverflow, bottomGlyphOverflow);
786 
787     int textShadowLogicalLeft;
788     int textShadowLogicalRight;
789     style->getTextShadowInlineDirectionExtent(textShadowLogicalLeft, textShadowLogicalRight);
790 
791     int childOverflowLogicalLeft = min(textShadowLogicalLeft + leftGlyphOverflow, leftGlyphOverflow);
792     int childOverflowLogicalRight = max(textShadowLogicalRight + rightGlyphOverflow, rightGlyphOverflow);
793 
794     int logicalTopVisualOverflow = min(textBox->logicalTop() + childOverflowLogicalTop, logicalVisualOverflow.y());
795     int logicalBottomVisualOverflow = max(textBox->logicalBottom() + childOverflowLogicalBottom, logicalVisualOverflow.maxY());
796     int logicalLeftVisualOverflow = min(textBox->pixelSnappedLogicalLeft() + childOverflowLogicalLeft, logicalVisualOverflow.x());
797     int logicalRightVisualOverflow = max(textBox->pixelSnappedLogicalRight() + childOverflowLogicalRight, logicalVisualOverflow.maxX());
798 
799     logicalVisualOverflow = IntRect(logicalLeftVisualOverflow, logicalTopVisualOverflow,
800                                     logicalRightVisualOverflow - logicalLeftVisualOverflow, logicalBottomVisualOverflow - logicalTopVisualOverflow);
801 
802     textBox->setLogicalOverflowRect(logicalVisualOverflow);
803 }
804 
addReplacedChildOverflow(const InlineBox * inlineBox,IntRect & logicalLayoutOverflow,IntRect & logicalVisualOverflow)805 inline void InlineFlowBox::addReplacedChildOverflow(const InlineBox* inlineBox, IntRect& logicalLayoutOverflow, IntRect& logicalVisualOverflow)
806 {
807     RenderBox* box = toRenderBox(inlineBox->renderer());
808 
809     // Visual overflow only propagates if the box doesn't have a self-painting layer.  This rectangle does not include
810     // transforms or relative positioning (since those objects always have self-painting layers), but it does need to be adjusted
811     // for writing-mode differences.
812     if (!box->hasSelfPaintingLayer()) {
813         IntRect childLogicalVisualOverflow = box->logicalVisualOverflowRectForPropagation(renderer()->style());
814         childLogicalVisualOverflow.move(inlineBox->logicalLeft(), inlineBox->logicalTop());
815         logicalVisualOverflow.unite(childLogicalVisualOverflow);
816     }
817 
818     // Layout overflow internal to the child box only propagates if the child box doesn't have overflow clip set.
819     // Otherwise the child border box propagates as layout overflow.  This rectangle must include transforms and relative positioning
820     // and be adjusted for writing-mode differences.
821     IntRect childLogicalLayoutOverflow = box->logicalLayoutOverflowRectForPropagation(renderer()->style());
822     childLogicalLayoutOverflow.move(inlineBox->logicalLeft(), inlineBox->logicalTop());
823     logicalLayoutOverflow.unite(childLogicalLayoutOverflow);
824 }
825 
computeOverflow(int lineTop,int lineBottom,GlyphOverflowAndFallbackFontsMap & textBoxDataMap)826 void InlineFlowBox::computeOverflow(int lineTop, int lineBottom, GlyphOverflowAndFallbackFontsMap& textBoxDataMap)
827 {
828     // If we know we have no overflow, we can just bail.
829     if (knownToHaveNoOverflow())
830         return;
831 
832     // Visual overflow just includes overflow for stuff we need to repaint ourselves.  Self-painting layers are ignored.
833     // Layout overflow is used to determine scrolling extent, so it still includes child layers and also factors in
834     // transforms, relative positioning, etc.
835     IntRect logicalLayoutOverflow(enclosingIntRect(logicalFrameRectIncludingLineHeight(lineTop, lineBottom)));
836     IntRect logicalVisualOverflow(logicalLayoutOverflow);
837 
838     // box-shadow on root line boxes is applying to the block and not to the lines.
839     addBoxShadowVisualOverflow(logicalVisualOverflow);
840 
841     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
842         if (curr->renderer()->isPositioned())
843             continue; // Positioned placeholders don't affect calculations.
844 
845         if (curr->renderer()->isText()) {
846             InlineTextBox* text = static_cast<InlineTextBox*>(curr);
847             RenderText* rt = toRenderText(text->renderer());
848             if (rt->isBR())
849                 continue;
850             IntRect textBoxOverflow(enclosingIntRect(text->logicalFrameRect()));
851             addTextBoxVisualOverflow(text, textBoxDataMap, textBoxOverflow);
852             logicalVisualOverflow.unite(textBoxOverflow);
853         } else  if (curr->renderer()->isRenderInline()) {
854             InlineFlowBox* flow = static_cast<InlineFlowBox*>(curr);
855             flow->computeOverflow(lineTop, lineBottom, textBoxDataMap);
856             if (!flow->boxModelObject()->hasSelfPaintingLayer())
857                 logicalVisualOverflow.unite(flow->logicalVisualOverflowRect(lineTop, lineBottom));
858             IntRect childLayoutOverflow = flow->logicalLayoutOverflowRect(lineTop, lineBottom);
859             childLayoutOverflow.move(flow->boxModelObject()->relativePositionLogicalOffset());
860             logicalLayoutOverflow.unite(childLayoutOverflow);
861         } else
862             addReplacedChildOverflow(curr, logicalLayoutOverflow, logicalVisualOverflow);
863     }
864 
865     setOverflowFromLogicalRects(logicalLayoutOverflow, logicalVisualOverflow, lineTop, lineBottom);
866 }
867 
setLayoutOverflow(const IntRect & rect,int lineTop,int lineBottom)868 void InlineFlowBox::setLayoutOverflow(const IntRect& rect, int lineTop, int lineBottom)
869 {
870     IntRect frameBox = enclosingIntRect(frameRectIncludingLineHeight(lineTop, lineBottom));
871     if (frameBox.contains(rect) || rect.isEmpty())
872         return;
873 
874     if (!m_overflow)
875         m_overflow.set(new RenderOverflow(frameBox, frameBox));
876 
877     m_overflow->setLayoutOverflow(rect);
878 }
879 
setVisualOverflow(const IntRect & rect,int lineTop,int lineBottom)880 void InlineFlowBox::setVisualOverflow(const IntRect& rect, int lineTop, int lineBottom)
881 {
882     IntRect frameBox = enclosingIntRect(frameRectIncludingLineHeight(lineTop, lineBottom));
883     if (frameBox.contains(rect) || rect.isEmpty())
884         return;
885 
886     if (!m_overflow)
887         m_overflow.set(new RenderOverflow(frameBox, frameBox));
888 
889     m_overflow->setVisualOverflow(rect);
890 }
891 
setOverflowFromLogicalRects(const IntRect & logicalLayoutOverflow,const IntRect & logicalVisualOverflow,int lineTop,int lineBottom)892 void InlineFlowBox::setOverflowFromLogicalRects(const IntRect& logicalLayoutOverflow, const IntRect& logicalVisualOverflow, int lineTop, int lineBottom)
893 {
894     IntRect layoutOverflow(isHorizontal() ? logicalLayoutOverflow : logicalLayoutOverflow.transposedRect());
895     setLayoutOverflow(layoutOverflow, lineTop, lineBottom);
896 
897     IntRect visualOverflow(isHorizontal() ? logicalVisualOverflow : logicalVisualOverflow.transposedRect());
898     setVisualOverflow(visualOverflow, lineTop, lineBottom);
899 }
900 
nodeAtPoint(const HitTestRequest & request,HitTestResult & result,int x,int y,int tx,int ty,int lineTop,int lineBottom)901 bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, int lineTop, int lineBottom)
902 {
903     IntRect overflowRect(visualOverflowRect(lineTop, lineBottom));
904     flipForWritingMode(overflowRect);
905     overflowRect.move(tx, ty);
906     if (!overflowRect.intersects(result.rectForPoint(x, y)))
907         return false;
908 
909     // Check children first.
910     for (InlineBox* curr = lastChild(); curr; curr = curr->prevOnLine()) {
911         if ((curr->renderer()->isText() || !curr->boxModelObject()->hasSelfPaintingLayer()) && curr->nodeAtPoint(request, result, x, y, tx, ty, lineTop, lineBottom)) {
912             renderer()->updateHitTestResult(result, IntPoint(x - tx, y - ty));
913             return true;
914         }
915     }
916 
917     // Now check ourselves. Pixel snap hit testing.
918     IntRect frameRect = roundedFrameRect();
919     int minX = frameRect.x();
920     int minY = frameRect.y();
921     int width = frameRect.width();
922     int height = frameRect.height();
923 
924     // Constrain our hit testing to the line top and bottom if necessary.
925     bool noQuirksMode = renderer()->document()->inNoQuirksMode();
926     if (!noQuirksMode && !hasTextChildren() && !(descendantsHaveSameLineHeightAndBaseline() && hasTextDescendants())) {
927         RootInlineBox* rootBox = root();
928         int& top = isHorizontal() ? minY : minX;
929         int& logicalHeight = isHorizontal() ? height : width;
930         int bottom = min(rootBox->lineBottom(), top + logicalHeight);
931         top = max(rootBox->lineTop(), top);
932         logicalHeight = bottom - top;
933     }
934 
935     // Move x/y to our coordinates.
936     IntRect rect(minX, minY, width, height);
937     flipForWritingMode(rect);
938     rect.move(tx, ty);
939 
940     if (visibleToHitTesting() && rect.intersects(result.rectForPoint(x, y))) {
941         renderer()->updateHitTestResult(result, flipForWritingMode(IntPoint(x - tx, y - ty))); // Don't add in m_x or m_y here, we want coords in the containing block's space.
942         if (!result.addNodeToRectBasedTestResult(renderer()->node(), x, y, rect))
943             return true;
944     }
945 
946     return false;
947 }
948 
paint(PaintInfo & paintInfo,int tx,int ty,int lineTop,int lineBottom)949 void InlineFlowBox::paint(PaintInfo& paintInfo, int tx, int ty, int lineTop, int lineBottom)
950 {
951     IntRect overflowRect(visualOverflowRect(lineTop, lineBottom));
952     overflowRect.inflate(renderer()->maximalOutlineSize(paintInfo.phase));
953     flipForWritingMode(overflowRect);
954     overflowRect.move(tx, ty);
955 
956     if (!paintInfo.rect.intersects(overflowRect))
957         return;
958 
959     if (paintInfo.phase != PaintPhaseChildOutlines) {
960         if (paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) {
961             // Add ourselves to the paint info struct's list of inlines that need to paint their
962             // outlines.
963             if (renderer()->style()->visibility() == VISIBLE && renderer()->hasOutline() && !isRootInlineBox()) {
964                 RenderInline* inlineFlow = toRenderInline(renderer());
965 
966                 RenderBlock* cb = 0;
967                 bool containingBlockPaintsContinuationOutline = inlineFlow->continuation() || inlineFlow->isInlineElementContinuation();
968                 if (containingBlockPaintsContinuationOutline) {
969                     // FIXME: See https://bugs.webkit.org/show_bug.cgi?id=54690. We currently don't reconnect inline continuations
970                     // after a child removal. As a result, those merged inlines do not get seperated and hence not get enclosed by
971                     // anonymous blocks. In this case, it is better to bail out and paint it ourself.
972                     RenderBlock* enclosingAnonymousBlock = renderer()->containingBlock();
973                     if (!enclosingAnonymousBlock->isAnonymousBlock())
974                         containingBlockPaintsContinuationOutline = false;
975                     else {
976                         cb = enclosingAnonymousBlock->containingBlock();
977                         for (RenderBoxModelObject* box = boxModelObject(); box != cb; box = box->parent()->enclosingBoxModelObject()) {
978                             if (box->hasSelfPaintingLayer()) {
979                                 containingBlockPaintsContinuationOutline = false;
980                                 break;
981                             }
982                         }
983                     }
984                 }
985 
986                 if (containingBlockPaintsContinuationOutline) {
987                     // Add ourselves to the containing block of the entire continuation so that it can
988                     // paint us atomically.
989                     cb->addContinuationWithOutline(toRenderInline(renderer()->node()->renderer()));
990                 } else if (!inlineFlow->isInlineElementContinuation())
991                     paintInfo.outlineObjects->add(inlineFlow);
992             }
993         } else if (paintInfo.phase == PaintPhaseMask) {
994             paintMask(paintInfo, tx, ty);
995             return;
996         } else {
997             // Paint our background, border and box-shadow.
998             paintBoxDecorations(paintInfo, tx, ty);
999         }
1000     }
1001 
1002     if (paintInfo.phase == PaintPhaseMask)
1003         return;
1004 
1005     PaintPhase paintPhase = paintInfo.phase == PaintPhaseChildOutlines ? PaintPhaseOutline : paintInfo.phase;
1006     PaintInfo childInfo(paintInfo);
1007     childInfo.phase = paintPhase;
1008     childInfo.updatePaintingRootForChildren(renderer());
1009 
1010     // Paint our children.
1011     if (paintPhase != PaintPhaseSelfOutline) {
1012         for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
1013             if (curr->renderer()->isText() || !curr->boxModelObject()->hasSelfPaintingLayer())
1014                 curr->paint(childInfo, tx, ty, lineTop, lineBottom);
1015         }
1016     }
1017 }
1018 
paintFillLayers(const PaintInfo & paintInfo,const Color & c,const FillLayer * fillLayer,int _tx,int _ty,int w,int h,CompositeOperator op)1019 void InlineFlowBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int _tx, int _ty, int w, int h, CompositeOperator op)
1020 {
1021     if (!fillLayer)
1022         return;
1023     paintFillLayers(paintInfo, c, fillLayer->next(), _tx, _ty, w, h, op);
1024     paintFillLayer(paintInfo, c, fillLayer, _tx, _ty, w, h, op);
1025 }
1026 
paintFillLayer(const PaintInfo & paintInfo,const Color & c,const FillLayer * fillLayer,int tx,int ty,int w,int h,CompositeOperator op)1027 void InlineFlowBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int tx, int ty, int w, int h, CompositeOperator op)
1028 {
1029     StyleImage* img = fillLayer->image();
1030     bool hasFillImage = img && img->canRender(renderer()->style()->effectiveZoom());
1031     if ((!hasFillImage && !renderer()->style()->hasBorderRadius()) || (!prevLineBox() && !nextLineBox()) || !parent())
1032         boxModelObject()->paintFillLayerExtended(paintInfo, c, fillLayer, tx, ty, w, h, this, w, h, op);
1033     else {
1034         // We have a fill image that spans multiple lines.
1035         // We need to adjust tx and ty by the width of all previous lines.
1036         // Think of background painting on inlines as though you had one long line, a single continuous
1037         // strip.  Even though that strip has been broken up across multiple lines, you still paint it
1038         // as though you had one single line.  This means each line has to pick up the background where
1039         // the previous line left off.
1040         int logicalOffsetOnLine = 0;
1041         int totalLogicalWidth;
1042         if (renderer()->style()->direction() == LTR) {
1043             for (InlineFlowBox* curr = prevLineBox(); curr; curr = curr->prevLineBox())
1044                 logicalOffsetOnLine += curr->logicalWidth();
1045             totalLogicalWidth = logicalOffsetOnLine;
1046             for (InlineFlowBox* curr = this; curr; curr = curr->nextLineBox())
1047                 totalLogicalWidth += curr->logicalWidth();
1048         } else {
1049             for (InlineFlowBox* curr = nextLineBox(); curr; curr = curr->nextLineBox())
1050                 logicalOffsetOnLine += curr->logicalWidth();
1051             totalLogicalWidth = logicalOffsetOnLine;
1052             for (InlineFlowBox* curr = this; curr; curr = curr->prevLineBox())
1053                 totalLogicalWidth += curr->logicalWidth();
1054         }
1055         int stripX = tx - (isHorizontal() ? logicalOffsetOnLine : 0);
1056         int stripY = ty - (isHorizontal() ? 0 : logicalOffsetOnLine);
1057         int stripWidth = isHorizontal() ? totalLogicalWidth : width();
1058         int stripHeight = isHorizontal() ? height() : totalLogicalWidth;
1059         paintInfo.context->save();
1060         paintInfo.context->clip(IntRect(tx, ty, width(), height()));
1061         boxModelObject()->paintFillLayerExtended(paintInfo, c, fillLayer, stripX, stripY, stripWidth, stripHeight, this, w, h, op);
1062         paintInfo.context->restore();
1063     }
1064 }
1065 
paintBoxShadow(GraphicsContext * context,RenderStyle * s,ShadowStyle shadowStyle,int tx,int ty,int w,int h)1066 void InlineFlowBox::paintBoxShadow(GraphicsContext* context, RenderStyle* s, ShadowStyle shadowStyle, int tx, int ty, int w, int h)
1067 {
1068     if ((!prevLineBox() && !nextLineBox()) || !parent())
1069         boxModelObject()->paintBoxShadow(context, tx, ty, w, h, s, shadowStyle);
1070     else {
1071         // FIXME: We can do better here in the multi-line case. We want to push a clip so that the shadow doesn't
1072         // protrude incorrectly at the edges, and we want to possibly include shadows cast from the previous/following lines
1073         boxModelObject()->paintBoxShadow(context, tx, ty, w, h, s, shadowStyle, includeLogicalLeftEdge(), includeLogicalRightEdge());
1074     }
1075 }
1076 
paintBoxDecorations(PaintInfo & paintInfo,int tx,int ty)1077 void InlineFlowBox::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
1078 {
1079     if (!paintInfo.shouldPaintWithinRoot(renderer()) || renderer()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseForeground)
1080         return;
1081 
1082     // Pixel snap background/border painting.
1083     IntRect frameRect = roundedFrameRect();
1084     int x = frameRect.x();
1085     int y = frameRect.y();
1086     int w = frameRect.width();
1087     int h = frameRect.height();
1088 
1089     // Constrain our background/border painting to the line top and bottom if necessary.
1090     bool noQuirksMode = renderer()->document()->inNoQuirksMode();
1091     if (!noQuirksMode && !hasTextChildren() && !(descendantsHaveSameLineHeightAndBaseline() && hasTextDescendants())) {
1092         RootInlineBox* rootBox = root();
1093         int& top = isHorizontal() ? y : x;
1094         int& logicalHeight = isHorizontal() ? h : w;
1095         int bottom = min(rootBox->lineBottom(), top + logicalHeight);
1096         top = max(rootBox->lineTop(), top);
1097         logicalHeight = bottom - top;
1098     }
1099 
1100     // Move x/y to our coordinates.
1101     IntRect localRect(x, y, w, h);
1102     flipForWritingMode(localRect);
1103     tx += localRect.x();
1104     ty += localRect.y();
1105 
1106     GraphicsContext* context = paintInfo.context;
1107 
1108     // You can use p::first-line to specify a background. If so, the root line boxes for
1109     // a line may actually have to paint a background.
1110     RenderStyle* styleToUse = renderer()->style(m_firstLine);
1111     if ((!parent() && m_firstLine && styleToUse != renderer()->style()) || (parent() && renderer()->hasBoxDecorations())) {
1112         // Shadow comes first and is behind the background and border.
1113         paintBoxShadow(context, styleToUse, Normal, tx, ty, w, h);
1114 
1115         Color c = styleToUse->visitedDependentColor(CSSPropertyBackgroundColor);
1116         paintFillLayers(paintInfo, c, styleToUse->backgroundLayers(), tx, ty, w, h);
1117         paintBoxShadow(context, styleToUse, Inset, tx, ty, w, h);
1118 
1119         // :first-line cannot be used to put borders on a line. Always paint borders with our
1120         // non-first-line style.
1121         if (parent() && renderer()->style()->hasBorder()) {
1122             StyleImage* borderImage = renderer()->style()->borderImage().image();
1123             bool hasBorderImage = borderImage && borderImage->canRender(styleToUse->effectiveZoom());
1124             if (hasBorderImage && !borderImage->isLoaded())
1125                 return; // Don't paint anything while we wait for the image to load.
1126 
1127             // The simple case is where we either have no border image or we are the only box for this object.  In those
1128             // cases only a single call to draw is required.
1129             if (!hasBorderImage || (!prevLineBox() && !nextLineBox()))
1130                 boxModelObject()->paintBorder(context, tx, ty, w, h, renderer()->style(), includeLogicalLeftEdge(), includeLogicalRightEdge());
1131             else {
1132                 // We have a border image that spans multiple lines.
1133                 // We need to adjust tx and ty by the width of all previous lines.
1134                 // Think of border image painting on inlines as though you had one long line, a single continuous
1135                 // strip.  Even though that strip has been broken up across multiple lines, you still paint it
1136                 // as though you had one single line.  This means each line has to pick up the image where
1137                 // the previous line left off.
1138                 // FIXME: What the heck do we do with RTL here? The math we're using is obviously not right,
1139                 // but it isn't even clear how this should work at all.
1140                 int logicalOffsetOnLine = 0;
1141                 for (InlineFlowBox* curr = prevLineBox(); curr; curr = curr->prevLineBox())
1142                     logicalOffsetOnLine += curr->logicalWidth();
1143                 int totalLogicalWidth = logicalOffsetOnLine;
1144                 for (InlineFlowBox* curr = this; curr; curr = curr->nextLineBox())
1145                     totalLogicalWidth += curr->logicalWidth();
1146                 int stripX = tx - (isHorizontal() ? logicalOffsetOnLine : 0);
1147                 int stripY = ty - (isHorizontal() ? 0 : logicalOffsetOnLine);
1148                 int stripWidth = isHorizontal() ? totalLogicalWidth : w;
1149                 int stripHeight = isHorizontal() ? h : totalLogicalWidth;
1150                 context->save();
1151                 context->clip(IntRect(tx, ty, w, h));
1152                 boxModelObject()->paintBorder(context, stripX, stripY, stripWidth, stripHeight, renderer()->style());
1153                 context->restore();
1154             }
1155         }
1156     }
1157 }
1158 
paintMask(PaintInfo & paintInfo,int tx,int ty)1159 void InlineFlowBox::paintMask(PaintInfo& paintInfo, int tx, int ty)
1160 {
1161     if (!paintInfo.shouldPaintWithinRoot(renderer()) || renderer()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
1162         return;
1163 
1164     // Pixel snap mask painting.
1165     IntRect frameRect = roundedFrameRect();
1166     int x = frameRect.x();
1167     int y = frameRect.y();
1168     int w = frameRect.width();
1169     int h = frameRect.height();
1170 
1171     // Constrain our background/border painting to the line top and bottom if necessary.
1172     bool noQuirksMode = renderer()->document()->inNoQuirksMode();
1173     if (!noQuirksMode && !hasTextChildren() && !(descendantsHaveSameLineHeightAndBaseline() && hasTextDescendants())) {
1174         RootInlineBox* rootBox = root();
1175         int& top = isHorizontal() ? y : x;
1176         int& logicalHeight = isHorizontal() ? h : w;
1177         int bottom = min(rootBox->lineBottom(), top + logicalHeight);
1178         top = max(rootBox->lineTop(), top);
1179         logicalHeight = bottom - top;
1180     }
1181 
1182     // Move x/y to our coordinates.
1183     IntRect localRect(x, y, w, h);
1184     flipForWritingMode(localRect);
1185     tx += localRect.x();
1186     ty += localRect.y();
1187 
1188     const NinePieceImage& maskNinePieceImage = renderer()->style()->maskBoxImage();
1189     StyleImage* maskBoxImage = renderer()->style()->maskBoxImage().image();
1190 
1191     // Figure out if we need to push a transparency layer to render our mask.
1192     bool pushTransparencyLayer = false;
1193     bool compositedMask = renderer()->hasLayer() && boxModelObject()->layer()->hasCompositedMask();
1194     CompositeOperator compositeOp = CompositeSourceOver;
1195     if (!compositedMask) {
1196         if ((maskBoxImage && renderer()->style()->maskLayers()->hasImage()) || renderer()->style()->maskLayers()->next())
1197             pushTransparencyLayer = true;
1198 
1199         compositeOp = CompositeDestinationIn;
1200         if (pushTransparencyLayer) {
1201             paintInfo.context->setCompositeOperation(CompositeDestinationIn);
1202             paintInfo.context->beginTransparencyLayer(1.0f);
1203             compositeOp = CompositeSourceOver;
1204         }
1205     }
1206 
1207     paintFillLayers(paintInfo, Color(), renderer()->style()->maskLayers(), tx, ty, w, h, compositeOp);
1208 
1209     bool hasBoxImage = maskBoxImage && maskBoxImage->canRender(renderer()->style()->effectiveZoom());
1210     if (!hasBoxImage || !maskBoxImage->isLoaded())
1211         return; // Don't paint anything while we wait for the image to load.
1212 
1213     // The simple case is where we are the only box for this object.  In those
1214     // cases only a single call to draw is required.
1215     if (!prevLineBox() && !nextLineBox()) {
1216         boxModelObject()->paintNinePieceImage(paintInfo.context, tx, ty, w, h, renderer()->style(), maskNinePieceImage, compositeOp);
1217     } else {
1218         // We have a mask image that spans multiple lines.
1219         // We need to adjust _tx and _ty by the width of all previous lines.
1220         int logicalOffsetOnLine = 0;
1221         for (InlineFlowBox* curr = prevLineBox(); curr; curr = curr->prevLineBox())
1222             logicalOffsetOnLine += curr->logicalWidth();
1223         int totalLogicalWidth = logicalOffsetOnLine;
1224         for (InlineFlowBox* curr = this; curr; curr = curr->nextLineBox())
1225             totalLogicalWidth += curr->logicalWidth();
1226         int stripX = tx - (isHorizontal() ? logicalOffsetOnLine : 0);
1227         int stripY = ty - (isHorizontal() ? 0 : logicalOffsetOnLine);
1228         int stripWidth = isHorizontal() ? totalLogicalWidth : w;
1229         int stripHeight = isHorizontal() ? h : totalLogicalWidth;
1230         paintInfo.context->save();
1231         paintInfo.context->clip(IntRect(tx, ty, w, h));
1232         boxModelObject()->paintNinePieceImage(paintInfo.context, stripX, stripY, stripWidth, stripHeight, renderer()->style(), maskNinePieceImage, compositeOp);
1233         paintInfo.context->restore();
1234     }
1235 
1236     if (pushTransparencyLayer)
1237         paintInfo.context->endTransparencyLayer();
1238 }
1239 
firstLeafChild() const1240 InlineBox* InlineFlowBox::firstLeafChild() const
1241 {
1242     InlineBox* leaf = 0;
1243     for (InlineBox* child = firstChild(); child && !leaf; child = child->nextOnLine())
1244         leaf = child->isLeaf() ? child : static_cast<InlineFlowBox*>(child)->firstLeafChild();
1245     return leaf;
1246 }
1247 
lastLeafChild() const1248 InlineBox* InlineFlowBox::lastLeafChild() const
1249 {
1250     InlineBox* leaf = 0;
1251     for (InlineBox* child = lastChild(); child && !leaf; child = child->prevOnLine())
1252         leaf = child->isLeaf() ? child : static_cast<InlineFlowBox*>(child)->lastLeafChild();
1253     return leaf;
1254 }
1255 
selectionState()1256 RenderObject::SelectionState InlineFlowBox::selectionState()
1257 {
1258     return RenderObject::SelectionNone;
1259 }
1260 
canAccommodateEllipsis(bool ltr,int blockEdge,int ellipsisWidth)1261 bool InlineFlowBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth)
1262 {
1263     for (InlineBox *box = firstChild(); box; box = box->nextOnLine()) {
1264         if (!box->canAccommodateEllipsis(ltr, blockEdge, ellipsisWidth))
1265             return false;
1266     }
1267     return true;
1268 }
1269 
placeEllipsisBox(bool ltr,float blockLeftEdge,float blockRightEdge,float ellipsisWidth,bool & foundBox)1270 float InlineFlowBox::placeEllipsisBox(bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, bool& foundBox)
1271 {
1272     float result = -1;
1273     // We iterate over all children, the foundBox variable tells us when we've found the
1274     // box containing the ellipsis.  All boxes after that one in the flow are hidden.
1275     // If our flow is ltr then iterate over the boxes from left to right, otherwise iterate
1276     // from right to left. Varying the order allows us to correctly hide the boxes following the ellipsis.
1277     InlineBox* box = ltr ? firstChild() : lastChild();
1278 
1279     // NOTE: these will cross after foundBox = true.
1280     int visibleLeftEdge = blockLeftEdge;
1281     int visibleRightEdge = blockRightEdge;
1282 
1283     while (box) {
1284         int currResult = box->placeEllipsisBox(ltr, visibleLeftEdge, visibleRightEdge, ellipsisWidth, foundBox);
1285         if (currResult != -1 && result == -1)
1286             result = currResult;
1287 
1288         if (ltr) {
1289             visibleLeftEdge += box->logicalWidth();
1290             box = box->nextOnLine();
1291         }
1292         else {
1293             visibleRightEdge -= box->logicalWidth();
1294             box = box->prevOnLine();
1295         }
1296     }
1297     return result;
1298 }
1299 
clearTruncation()1300 void InlineFlowBox::clearTruncation()
1301 {
1302     for (InlineBox *box = firstChild(); box; box = box->nextOnLine())
1303         box->clearTruncation();
1304 }
1305 
computeOverAnnotationAdjustment(int allowedPosition) const1306 int InlineFlowBox::computeOverAnnotationAdjustment(int allowedPosition) const
1307 {
1308     int result = 0;
1309     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
1310         if (curr->renderer()->isPositioned())
1311             continue; // Positioned placeholders don't affect calculations.
1312 
1313         if (curr->isInlineFlowBox())
1314             result = max(result, static_cast<InlineFlowBox*>(curr)->computeOverAnnotationAdjustment(allowedPosition));
1315 
1316         if (curr->renderer()->isReplaced() && curr->renderer()->isRubyRun()) {
1317             RenderRubyRun* rubyRun = static_cast<RenderRubyRun*>(curr->renderer());
1318             RenderRubyText* rubyText = rubyRun->rubyText();
1319             if (!rubyText)
1320                 continue;
1321 
1322             if (!rubyRun->style()->isFlippedLinesWritingMode()) {
1323                 int topOfFirstRubyTextLine = rubyText->logicalTop() + (rubyText->firstRootBox() ? rubyText->firstRootBox()->lineTop() : 0);
1324                 if (topOfFirstRubyTextLine >= 0)
1325                     continue;
1326                 topOfFirstRubyTextLine += curr->logicalTop();
1327                 result = max(result, allowedPosition - topOfFirstRubyTextLine);
1328             } else {
1329                 int bottomOfLastRubyTextLine = rubyText->logicalTop() + (rubyText->lastRootBox() ? rubyText->lastRootBox()->lineBottom() : rubyText->logicalHeight());
1330                 if (bottomOfLastRubyTextLine <= curr->logicalHeight())
1331                     continue;
1332                 bottomOfLastRubyTextLine += curr->logicalTop();
1333                 result = max(result, bottomOfLastRubyTextLine - allowedPosition);
1334             }
1335         }
1336 
1337         if (curr->isInlineTextBox()) {
1338             RenderStyle* style = curr->renderer()->style(m_firstLine);
1339             TextEmphasisPosition emphasisMarkPosition;
1340             if (style->textEmphasisMark() != TextEmphasisMarkNone && static_cast<InlineTextBox*>(curr)->getEmphasisMarkPosition(style, emphasisMarkPosition) && emphasisMarkPosition == TextEmphasisPositionOver) {
1341                 if (!style->isFlippedLinesWritingMode()) {
1342                     int topOfEmphasisMark = curr->logicalTop() - style->font().emphasisMarkHeight(style->textEmphasisMarkString());
1343                     result = max(result, allowedPosition - topOfEmphasisMark);
1344                 } else {
1345                     int bottomOfEmphasisMark = curr->logicalBottom() + style->font().emphasisMarkHeight(style->textEmphasisMarkString());
1346                     result = max(result, bottomOfEmphasisMark - allowedPosition);
1347                 }
1348             }
1349         }
1350     }
1351     return result;
1352 }
1353 
computeUnderAnnotationAdjustment(int allowedPosition) const1354 int InlineFlowBox::computeUnderAnnotationAdjustment(int allowedPosition) const
1355 {
1356     int result = 0;
1357     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
1358         if (curr->renderer()->isPositioned())
1359             continue; // Positioned placeholders don't affect calculations.
1360 
1361         if (curr->isInlineFlowBox())
1362             result = max(result, static_cast<InlineFlowBox*>(curr)->computeUnderAnnotationAdjustment(allowedPosition));
1363 
1364         if (curr->isInlineTextBox()) {
1365             RenderStyle* style = curr->renderer()->style(m_firstLine);
1366             if (style->textEmphasisMark() != TextEmphasisMarkNone && style->textEmphasisPosition() == TextEmphasisPositionUnder) {
1367                 if (!style->isFlippedLinesWritingMode()) {
1368                     int bottomOfEmphasisMark = curr->logicalBottom() + style->font().emphasisMarkHeight(style->textEmphasisMarkString());
1369                     result = max(result, bottomOfEmphasisMark - allowedPosition);
1370                 } else {
1371                     int topOfEmphasisMark = curr->logicalTop() - style->font().emphasisMarkHeight(style->textEmphasisMarkString());
1372                     result = max(result, allowedPosition - topOfEmphasisMark);
1373                 }
1374             }
1375         }
1376     }
1377     return result;
1378 }
1379 
collectLeafBoxesInLogicalOrder(Vector<InlineBox * > & leafBoxesInLogicalOrder,CustomInlineBoxRangeReverse customReverseImplementation,void * userData) const1380 void InlineFlowBox::collectLeafBoxesInLogicalOrder(Vector<InlineBox*>& leafBoxesInLogicalOrder, CustomInlineBoxRangeReverse customReverseImplementation, void* userData) const
1381 {
1382     InlineBox* leaf = firstLeafChild();
1383 
1384     // FIXME: The reordering code is a copy of parts from BidiResolver::createBidiRunsForLine, operating directly on InlineBoxes, instead of BidiRuns.
1385     // Investigate on how this code could possibly be shared.
1386     unsigned char minLevel = 128;
1387     unsigned char maxLevel = 0;
1388 
1389     // First find highest and lowest levels, and initialize leafBoxesInLogicalOrder with the leaf boxes in visual order.
1390     for (; leaf; leaf = leaf->nextLeafChild()) {
1391         minLevel = min(minLevel, leaf->bidiLevel());
1392         maxLevel = max(maxLevel, leaf->bidiLevel());
1393         leafBoxesInLogicalOrder.append(leaf);
1394     }
1395 
1396     if (renderer()->style()->visuallyOrdered())
1397         return;
1398 
1399     // Reverse of reordering of the line (L2 according to Bidi spec):
1400     // L2. From the highest level found in the text to the lowest odd level on each line,
1401     // reverse any contiguous sequence of characters that are at that level or higher.
1402 
1403     // Reversing the reordering of the line is only done up to the lowest odd level.
1404     if (!(minLevel % 2))
1405         ++minLevel;
1406 
1407     Vector<InlineBox*>::iterator end = leafBoxesInLogicalOrder.end();
1408     while (minLevel <= maxLevel) {
1409         Vector<InlineBox*>::iterator it = leafBoxesInLogicalOrder.begin();
1410         while (it != end) {
1411             while (it != end) {
1412                 if ((*it)->bidiLevel() >= minLevel)
1413                     break;
1414                 ++it;
1415             }
1416             Vector<InlineBox*>::iterator first = it;
1417             while (it != end) {
1418                 if ((*it)->bidiLevel() < minLevel)
1419                     break;
1420                 ++it;
1421             }
1422             Vector<InlineBox*>::iterator last = it;
1423             if (customReverseImplementation) {
1424                 ASSERT(userData);
1425                 (*customReverseImplementation)(userData, first, last);
1426             } else
1427                 std::reverse(first, last);
1428         }
1429         ++minLevel;
1430     }
1431 }
1432 
1433 #ifndef NDEBUG
1434 
checkConsistency() const1435 void InlineFlowBox::checkConsistency() const
1436 {
1437 #ifdef CHECK_CONSISTENCY
1438     ASSERT(!m_hasBadChildList);
1439     const InlineBox* prev = 0;
1440     for (const InlineBox* child = m_firstChild; child; child = child->nextOnLine()) {
1441         ASSERT(child->parent() == this);
1442         ASSERT(child->prevOnLine() == prev);
1443         prev = child;
1444     }
1445     ASSERT(prev == m_lastChild);
1446 #endif
1447 }
1448 
1449 #endif
1450 
1451 } // namespace WebCore
1452