webengine/osswebengine/WebCore/rendering/InlineFlowBox.cpp
changeset 0 dd21522fd290
equal deleted inserted replaced
-1:000000000000 0:dd21522fd290
       
     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 
       
    39 using namespace std;
       
    40 
       
    41 namespace WebCore {
       
    42 
       
    43 #ifndef NDEBUG
       
    44 
       
    45 InlineFlowBox::~InlineFlowBox()
       
    46 {
       
    47     if (!m_hasBadChildList)
       
    48         for (InlineBox* child = firstChild(); child; child = child->nextOnLine())
       
    49             child->setHasBadParent();
       
    50 }
       
    51 
       
    52 #endif
       
    53 
       
    54 RenderFlow* InlineFlowBox::flowObject()
       
    55 {
       
    56     return static_cast<RenderFlow*>(m_object);
       
    57 }
       
    58 
       
    59 int 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 
       
    72 int 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 
       
    85 int InlineFlowBox::marginBorderPaddingLeft()
       
    86 {
       
    87     return marginLeft() + borderLeft() + paddingLeft();
       
    88 }
       
    89 
       
    90 int InlineFlowBox::marginBorderPaddingRight()
       
    91 {
       
    92     return marginRight() + borderRight() + paddingRight();
       
    93 }
       
    94 
       
    95 int 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 
       
   105 void 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 
       
   130 void 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 
       
   153 void 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 
       
   175 void 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 
       
   183 void 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 
       
   191 void 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 
       
   198 bool 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 
       
   219 void 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 
       
   273 int 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     if (ShadowData* boxShadow = object()->style(m_firstLine)->boxShadow()) {
       
   281         boxShadowLeft = min(boxShadow->x - boxShadow->blur, 0);
       
   282         boxShadowRight = max(boxShadow->x + boxShadow->blur, 0);
       
   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 && DeprecatedChar(rt->characters()[text->start()]).isSpace())
       
   295                     x += rt->style(m_firstLine)->font().wordSpacing();
       
   296                 needsWordSpacing = !DeprecatedChar(rt->characters()[text->end()]).isSpace();
       
   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 
       
   358 void 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 
       
   394 void 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 
       
   421 void 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() || 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 
       
   473 void 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() && !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             if (ShadowData* boxShadow = curr->object()->style(m_firstLine)->boxShadow()) {
       
   515                 overflowTop = min(overflowTop, boxShadow->y - boxShadow->blur);
       
   516                 overflowBottom = max(overflowBottom, boxShadow->y + boxShadow->blur);
       
   517             }
       
   518 
       
   519             if (curr->isInlineFlowBox()) {
       
   520                 newHeight += curr->object()->borderTop() + curr->object()->paddingTop() +
       
   521                             curr->object()->borderBottom() + curr->object()->paddingBottom();
       
   522                 newY -= curr->object()->borderTop() + curr->object()->paddingTop();
       
   523                 newBaseline += curr->object()->borderTop() + curr->object()->paddingTop();
       
   524             }
       
   525         } else if (!curr->object()->isBR()) {
       
   526             newY += curr->object()->marginTop();
       
   527             newHeight = curr->height() - (curr->object()->marginTop() + curr->object()->marginBottom());
       
   528             overflowTop = curr->object()->overflowTop(false);
       
   529             overflowBottom = curr->object()->overflowHeight(false) - newHeight;
       
   530         }
       
   531 
       
   532         curr->setYPos(newY);
       
   533         curr->setHeight(newHeight);
       
   534         curr->setBaseline(newBaseline);
       
   535 
       
   536         if (childAffectsTopBottomPos) {
       
   537             selectionTop = min(selectionTop, newY);
       
   538             selectionBottom = max(selectionBottom, newY + newHeight);
       
   539             topPosition = min(topPosition, newY + overflowTop);
       
   540             bottomPosition = max(bottomPosition, newY + newHeight + overflowBottom);
       
   541         }
       
   542     }
       
   543 
       
   544     if (isRootInlineBox()) {
       
   545         const Font& font = object()->style(m_firstLine)->font();
       
   546         setHeight(font.ascent() + font.descent());
       
   547         setYPos(yPos() + baseline() - font.ascent());
       
   548         setBaseline(font.ascent());
       
   549         if (hasTextChildren() || strictMode) {
       
   550             selectionTop = min(selectionTop, yPos());
       
   551             selectionBottom = max(selectionBottom, yPos() + height());
       
   552         }
       
   553     }
       
   554 }
       
   555 
       
   556 void InlineFlowBox::shrinkBoxesWithNoTextChildren(int topPos, int bottomPos)
       
   557 {
       
   558     // First shrink our kids.
       
   559     for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
       
   560         if (curr->object()->isPositioned())
       
   561             continue; // Positioned placeholders don't affect calculations.
       
   562         
       
   563         if (curr->isInlineFlowBox())
       
   564             static_cast<InlineFlowBox*>(curr)->shrinkBoxesWithNoTextChildren(topPos, bottomPos);
       
   565     }
       
   566 
       
   567     // See if we have text children. If not, then we need to shrink ourselves to fit on the line.
       
   568     if (!hasTextChildren()) {
       
   569         if (yPos() < topPos)
       
   570             setYPos(topPos);
       
   571         if (yPos() + height() > bottomPos)
       
   572             setHeight(bottomPos - yPos());
       
   573         if (baseline() > height())
       
   574             setBaseline(height());
       
   575     }
       
   576 }
       
   577 
       
   578 bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty)
       
   579 {
       
   580     // Check children first.
       
   581     for (InlineBox* curr = lastChild(); curr; curr = curr->prevOnLine()) {
       
   582         if (!curr->object()->hasLayer() && curr->nodeAtPoint(request, result, x, y, tx, ty)) {
       
   583             object()->updateHitTestResult(result, IntPoint(x - tx, y - ty));
       
   584             return true;
       
   585         }
       
   586     }
       
   587 
       
   588     // Now check ourselves.
       
   589     IntRect rect(tx + m_x, ty + m_y, m_width, m_height);
       
   590     if (object()->style()->visibility() == VISIBLE && rect.contains(x, y)) {
       
   591         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.
       
   592         return true;
       
   593     }
       
   594     
       
   595     return false;
       
   596 }
       
   597 
       
   598 void InlineFlowBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
       
   599 {
       
   600     int xPos = tx + m_x - object()->maximalOutlineSize(paintInfo.phase);
       
   601     int w = width() + 2 * object()->maximalOutlineSize(paintInfo.phase);
       
   602     if (ShadowData* boxShadow = object()->style(m_firstLine)->boxShadow()) {
       
   603         int shadowLeft = min(boxShadow->x - boxShadow->blur, 0);
       
   604         xPos += shadowLeft;
       
   605         w += -shadowLeft + max(boxShadow->x + boxShadow->blur, 0);
       
   606     }
       
   607     bool intersectsDamageRect = xPos < paintInfo.rect.right() && xPos + w > paintInfo.rect.x();
       
   608 
       
   609     if (intersectsDamageRect && paintInfo.phase != PaintPhaseChildOutlines) {
       
   610         if (paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) {
       
   611             // Add ourselves to the paint info struct's list of inlines that need to paint their
       
   612             // outlines.
       
   613             if (object()->style()->visibility() == VISIBLE && object()->hasOutline() && !isRootInlineBox()) {
       
   614                 if ((object()->continuation() || object()->isInlineContinuation()) && !object()->hasLayer()) {
       
   615                     // Add ourselves to the containing block of the entire continuation so that it can
       
   616                     // paint us atomically.
       
   617                     RenderBlock* block = object()->containingBlock()->containingBlock();
       
   618                     block->addContinuationWithOutline(static_cast<RenderFlow*>(object()->element()->renderer()));
       
   619                 } else if (!object()->isInlineContinuation())
       
   620                     paintInfo.outlineObjects->add(flowObject());
       
   621             }
       
   622         } else {
       
   623             // 1. Paint our background, border and box-shadow.
       
   624             paintBoxDecorations(paintInfo, tx, ty);
       
   625 
       
   626             // 2. Paint our underline and overline.
       
   627             paintTextDecorations(paintInfo, tx, ty, false);
       
   628         }
       
   629     }
       
   630 
       
   631     PaintPhase paintPhase = paintInfo.phase == PaintPhaseChildOutlines ? PaintPhaseOutline : paintInfo.phase;
       
   632     RenderObject::PaintInfo childInfo(paintInfo);
       
   633     childInfo.phase = paintPhase;
       
   634     childInfo.paintingRoot = object()->paintingRootForChildren(paintInfo);
       
   635     
       
   636     // 3. Paint our children.
       
   637     if (paintPhase != PaintPhaseSelfOutline) {
       
   638         for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
       
   639             if (!curr->object()->hasLayer())
       
   640                 curr->paint(childInfo, tx, ty);
       
   641         }
       
   642     }
       
   643 
       
   644     // 4. Paint our strike-through
       
   645     if (intersectsDamageRect && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection))
       
   646         paintTextDecorations(paintInfo, tx, ty, true);
       
   647 }
       
   648 
       
   649 void InlineFlowBox::paintBackgrounds(GraphicsContext* p, const Color& c, const BackgroundLayer* bgLayer,
       
   650                                      int my, int mh, int _tx, int _ty, int w, int h)
       
   651 {
       
   652     if (!bgLayer)
       
   653         return;
       
   654     paintBackgrounds(p, c, bgLayer->next(), my, mh, _tx, _ty, w, h);
       
   655     paintBackground(p, c, bgLayer, my, mh, _tx, _ty, w, h);
       
   656 }
       
   657 
       
   658 void InlineFlowBox::paintBackground(GraphicsContext* context, const Color& c, const BackgroundLayer* bgLayer,
       
   659                                     int my, int mh, int tx, int ty, int w, int h)
       
   660 {
       
   661     CachedImage* bg = bgLayer->backgroundImage();
       
   662     bool hasBackgroundImage = bg && bg->canRender();
       
   663     if ((!hasBackgroundImage && !object()->style()->hasBorderRadius()) || (!prevLineBox() && !nextLineBox()) || !parent())
       
   664         object()->paintBackgroundExtended(context, c, bgLayer, my, mh, tx, ty, w, h);
       
   665     else {
       
   666         // We have a background image that spans multiple lines.
       
   667         // We need to adjust _tx and _ty by the width of all previous lines.
       
   668         // Think of background painting on inlines as though you had one long line, a single continuous
       
   669         // strip.  Even though that strip has been broken up across multiple lines, you still paint it
       
   670         // as though you had one single line.  This means each line has to pick up the background where
       
   671         // the previous line left off.
       
   672         // FIXME: What the heck do we do with RTL here? The math we're using is obviously not right,
       
   673         // but it isn't even clear how this should work at all.
       
   674         int xOffsetOnLine = 0;
       
   675         for (InlineRunBox* curr = prevLineBox(); curr; curr = curr->prevLineBox())
       
   676             xOffsetOnLine += curr->width();
       
   677         int startX = tx - xOffsetOnLine;
       
   678         int totalWidth = xOffsetOnLine;
       
   679         for (InlineRunBox* curr = this; curr; curr = curr->nextLineBox())
       
   680             totalWidth += curr->width();
       
   681         context->save();
       
   682         context->clip(IntRect(tx, ty, width(), height()));
       
   683         object()->paintBackgroundExtended(context, c, bgLayer, my, mh, startX, ty,
       
   684                                           totalWidth, h, includeLeftEdge(), includeRightEdge());
       
   685         context->restore();
       
   686     }
       
   687 }
       
   688 
       
   689 void InlineFlowBox::paintBoxShadow(GraphicsContext* context, RenderStyle* s, int tx, int ty, int w, int h)
       
   690 {
       
   691     if ((!prevLineBox() && !nextLineBox()) || !parent())
       
   692         object()->paintBoxShadow(context, tx, ty, w, h, s);
       
   693     else {
       
   694         // FIXME: We can do better here in the multi-line case. We want to push a clip so that the shadow doesn't
       
   695         // protrude incorrectly at the edges, and we want to possibly include shadows cast from the previous/following lines
       
   696         object()->paintBoxShadow(context, tx, ty, w, h, s, includeLeftEdge(), includeRightEdge());
       
   697     }
       
   698 }
       
   699 
       
   700 void InlineFlowBox::paintBoxDecorations(RenderObject::PaintInfo& paintInfo, int tx, int ty)
       
   701 {
       
   702     if (!object()->shouldPaintWithinRoot(paintInfo) || object()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseForeground)
       
   703         return;
       
   704 
       
   705     // Move x/y to our coordinates.
       
   706     tx += m_x;
       
   707     ty += m_y;
       
   708     
       
   709     int w = width();
       
   710     int h = height();
       
   711 
       
   712     int my = max(ty, paintInfo.rect.y());
       
   713     int mh;
       
   714     if (ty < paintInfo.rect.y())
       
   715         mh = max(0, h - (paintInfo.rect.y() - ty));
       
   716     else
       
   717         mh = min(paintInfo.rect.height(), h);
       
   718 
       
   719     GraphicsContext* context = paintInfo.context;
       
   720     
       
   721     // You can use p::first-line to specify a background. If so, the root line boxes for
       
   722     // a line may actually have to paint a background.
       
   723     RenderStyle* styleToUse = object()->style(m_firstLine);
       
   724     if ((!parent() && m_firstLine && styleToUse != object()->style()) || (parent() && object()->hasBoxDecorations())) {
       
   725         // Shadow comes first and is behind the background and border.
       
   726         if (styleToUse->boxShadow())
       
   727             paintBoxShadow(context, styleToUse, tx, ty, w, h);
       
   728 
       
   729         Color c = styleToUse->backgroundColor();
       
   730         paintBackgrounds(context, c, styleToUse->backgroundLayers(), my, mh, tx, ty, w, h);
       
   731 
       
   732         // :first-line cannot be used to put borders on a line. Always paint borders with our
       
   733         // non-first-line style.
       
   734         if (parent() && object()->style()->hasBorder()) {
       
   735             CachedImage* borderImage = object()->style()->borderImage().image();
       
   736             bool hasBorderImage = borderImage && borderImage->canRender();
       
   737             if (hasBorderImage && !borderImage->isLoaded())
       
   738                 return; // Don't paint anything while we wait for the image to load.
       
   739 
       
   740             // The simple case is where we either have no border image or we are the only box for this object.  In those
       
   741             // cases only a single call to draw is required.
       
   742             if (!hasBorderImage || (!prevLineBox() && !nextLineBox()))
       
   743                 object()->paintBorder(context, tx, ty, w, h, object()->style(), includeLeftEdge(), includeRightEdge());
       
   744             else {
       
   745                 // We have a border image that spans multiple lines.
       
   746                 // We need to adjust _tx and _ty by the width of all previous lines.
       
   747                 // Think of border image painting on inlines as though you had one long line, a single continuous
       
   748                 // strip.  Even though that strip has been broken up across multiple lines, you still paint it
       
   749                 // as though you had one single line.  This means each line has to pick up the image where
       
   750                 // the previous line left off.
       
   751                 // FIXME: What the heck do we do with RTL here? The math we're using is obviously not right,
       
   752                 // but it isn't even clear how this should work at all.
       
   753                 int xOffsetOnLine = 0;
       
   754                 for (InlineRunBox* curr = prevLineBox(); curr; curr = curr->prevLineBox())
       
   755                     xOffsetOnLine += curr->width();
       
   756                 int startX = tx - xOffsetOnLine;
       
   757                 int totalWidth = xOffsetOnLine;
       
   758                 for (InlineRunBox* curr = this; curr; curr = curr->nextLineBox())
       
   759                     totalWidth += curr->width();
       
   760                 context->save();
       
   761                 context->clip(IntRect(tx, ty, width(), height()));
       
   762                 object()->paintBorder(context, startX, ty, totalWidth, h, object()->style());
       
   763                 context->restore();
       
   764             }
       
   765         }
       
   766     }
       
   767 }
       
   768 
       
   769 static bool shouldDrawTextDecoration(RenderObject* obj)
       
   770 {
       
   771     for (RenderObject* curr = obj->firstChild(); curr; curr = curr->nextSibling()) {
       
   772         if (curr->isInlineFlow())
       
   773             return true;
       
   774         if (curr->isText() && !curr->isBR()) {
       
   775             if (!curr->style()->collapseWhiteSpace())
       
   776                 return true;
       
   777             Node* currElement = curr->element();
       
   778             if (!currElement)
       
   779                 return true;
       
   780             if (!currElement->isTextNode())
       
   781                 return true;
       
   782             if (!static_cast<Text*>(currElement)->containsOnlyWhitespace())
       
   783                 return true;
       
   784         }
       
   785     }
       
   786     return false;
       
   787 }
       
   788 
       
   789 void InlineFlowBox::paintTextDecorations(RenderObject::PaintInfo& paintInfo, int tx, int ty, bool paintedChildren)
       
   790 {
       
   791     // Paint text decorations like underlines/overlines. We only do this if we aren't in quirks mode (i.e., in
       
   792     // almost-strict mode or strict mode).
       
   793     if (object()->style()->htmlHacks() || !object()->shouldPaintWithinRoot(paintInfo) ||
       
   794         object()->style()->visibility() != VISIBLE)
       
   795         return;
       
   796     
       
   797     // We don't want underlines or other decorations when we're trying to draw nothing but the selection as white text.
       
   798     if (paintInfo.phase == PaintPhaseSelection && paintInfo.forceBlackText)
       
   799         return;
       
   800 
       
   801     GraphicsContext* context = paintInfo.context;
       
   802     tx += m_x;
       
   803     ty += m_y;
       
   804     RenderStyle* styleToUse = object()->style(m_firstLine);
       
   805     int deco = parent() ? styleToUse->textDecoration() : styleToUse->textDecorationsInEffect();
       
   806     if (deco != TDNONE && 
       
   807         ((!paintedChildren && ((deco & UNDERLINE) || (deco & OVERLINE))) || (paintedChildren && (deco & LINE_THROUGH))) &&
       
   808         shouldDrawTextDecoration(object())) {
       
   809         int x = m_x + borderLeft() + paddingLeft();
       
   810         int w = m_width - (borderLeft() + paddingLeft() + borderRight() + paddingRight());
       
   811         RootInlineBox* rootLine = root();
       
   812         if (rootLine->ellipsisBox()) {
       
   813             int ellipsisX = rootLine->ellipsisBox()->xPos();
       
   814             int ellipsisWidth = rootLine->ellipsisBox()->width();
       
   815             
       
   816             // FIXME: Will need to work with RTL
       
   817             if (rootLine == this) {
       
   818                 if (x + w >= ellipsisX + ellipsisWidth)
       
   819                     w -= (x + w - ellipsisX - ellipsisWidth);
       
   820             } else {
       
   821                 if (x >= ellipsisX)
       
   822                     return;
       
   823                 if (x + w >= ellipsisX)
       
   824                     w -= (x + w - ellipsisX);
       
   825             }
       
   826         }
       
   827 
       
   828         // Set up the appropriate text-shadow effect for the decoration.
       
   829         // FIXME: Support multiple shadow effects.  Need more from the CG API before we can do this.
       
   830         bool setShadow = false;
       
   831         if (styleToUse->textShadow()) {
       
   832             context->setShadow(IntSize(styleToUse->textShadow()->x, styleToUse->textShadow()->y),
       
   833                                styleToUse->textShadow()->blur, styleToUse->textShadow()->color);
       
   834             setShadow = true;
       
   835         }
       
   836 
       
   837         // We must have child boxes and have decorations defined.
       
   838         tx += borderLeft() + paddingLeft();
       
   839 
       
   840         Color underline, overline, linethrough;
       
   841         underline = overline = linethrough = styleToUse->color();
       
   842         if (!parent())
       
   843             object()->getTextDecorationColors(deco, underline, overline, linethrough);
       
   844 
       
   845         if (styleToUse->font() != context->font())
       
   846             context->setFont(styleToUse->font());
       
   847 
       
   848         bool isPrinting = object()->document()->printing();
       
   849         context->setStrokeThickness(1.0f); // FIXME: We should improve this rule and not always just assume 1.
       
   850         if (deco & UNDERLINE && !paintedChildren) {
       
   851             context->setStrokeColor(underline);
       
   852             // Leave one pixel of white between the baseline and the underline.
       
   853             context->drawLineForText(IntPoint(tx, ty + m_baseline + 1), w, isPrinting);
       
   854         }
       
   855         if (deco & OVERLINE && !paintedChildren) {
       
   856             context->setStrokeColor(overline);
       
   857             context->drawLineForText(IntPoint(tx, ty), w, isPrinting);
       
   858         }
       
   859         if (deco & LINE_THROUGH && paintedChildren) {
       
   860             context->setStrokeColor(linethrough);
       
   861             context->drawLineForText(IntPoint(tx, ty + 2 * m_baseline / 3), w, isPrinting);
       
   862         }
       
   863 
       
   864         if (setShadow)
       
   865             context->clearShadow();
       
   866     }
       
   867 }
       
   868 
       
   869 InlineBox* InlineFlowBox::firstLeafChild()
       
   870 {
       
   871     return firstLeafChildAfterBox();
       
   872 }
       
   873 
       
   874 InlineBox* InlineFlowBox::lastLeafChild()
       
   875 {
       
   876     return lastLeafChildBeforeBox();
       
   877 }
       
   878 
       
   879 InlineBox* InlineFlowBox::firstLeafChildAfterBox(InlineBox* start)
       
   880 {
       
   881     InlineBox* leaf = 0;
       
   882     for (InlineBox* box = start ? start->nextOnLine() : firstChild(); box && !leaf; box = box->nextOnLine())
       
   883         leaf = box->firstLeafChild();
       
   884     if (start && !leaf && parent())
       
   885         return parent()->firstLeafChildAfterBox(this);
       
   886     return leaf;
       
   887 }
       
   888 
       
   889 InlineBox* InlineFlowBox::lastLeafChildBeforeBox(InlineBox* start)
       
   890 {
       
   891     InlineBox* leaf = 0;
       
   892     for (InlineBox* box = start ? start->prevOnLine() : lastChild(); box && !leaf; box = box->prevOnLine())
       
   893         leaf = box->lastLeafChild();
       
   894     if (start && !leaf && parent())
       
   895         return parent()->lastLeafChildBeforeBox(this);
       
   896     return leaf;
       
   897 }
       
   898 
       
   899 RenderObject::SelectionState InlineFlowBox::selectionState()
       
   900 {
       
   901     return RenderObject::SelectionNone;
       
   902 }
       
   903 
       
   904 bool InlineFlowBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth)
       
   905 {
       
   906     for (InlineBox *box = firstChild(); box; box = box->nextOnLine()) {
       
   907         if (!box->canAccommodateEllipsis(ltr, blockEdge, ellipsisWidth))
       
   908             return false;
       
   909     }
       
   910     return true;
       
   911 }
       
   912 
       
   913 int InlineFlowBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox)
       
   914 {
       
   915     int result = -1;
       
   916     for (InlineBox *box = firstChild(); box; box = box->nextOnLine()) {
       
   917         int currResult = box->placeEllipsisBox(ltr, blockEdge, ellipsisWidth, foundBox);
       
   918         if (currResult != -1 && result == -1)
       
   919             result = currResult;
       
   920     }
       
   921     return result;
       
   922 }
       
   923 
       
   924 void InlineFlowBox::clearTruncation()
       
   925 {
       
   926     for (InlineBox *box = firstChild(); box; box = box->nextOnLine())
       
   927         box->clearTruncation();
       
   928 }
       
   929 
       
   930 #ifndef NDEBUG
       
   931 
       
   932 void InlineFlowBox::checkConsistency() const
       
   933 {
       
   934 #ifdef CHECK_CONSISTENCY
       
   935     ASSERT(!m_hasBadChildList);
       
   936     const InlineBox* prev = 0;
       
   937     for (const InlineBox* child = m_firstChild; child; child = child->nextOnLine()) {
       
   938         ASSERT(child->parent() == this);
       
   939         ASSERT(child->prevOnLine() == prev);
       
   940         prev = child;
       
   941     }
       
   942     ASSERT(prev == m_lastChild);
       
   943 #endif
       
   944 }
       
   945 
       
   946 #endif
       
   947 
       
   948 } // namespace WebCore