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