Home | History | Annotate | Download | only in rendering
      1 /*
      2  * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *
      8  * 1. Redistributions of source code must retain the above
      9  *    copyright notice, this list of conditions and the following
     10  *    disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above
     12  *    copyright notice, this list of conditions and the following
     13  *    disclaimer in the documentation and/or other materials
     14  *    provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     19  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     20  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     21  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     25  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
     27  * OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 #include "config.h"
     31 #include "core/rendering/LineWidth.h"
     32 
     33 #include "core/rendering/RenderBlock.h"
     34 #include "core/rendering/RenderRubyRun.h"
     35 
     36 namespace WebCore {
     37 
     38 LineWidth::LineWidth(RenderBlockFlow& block, bool isFirstLine, IndentTextOrNot shouldIndentText)
     39     : m_block(block)
     40     , m_uncommittedWidth(0)
     41     , m_committedWidth(0)
     42     , m_overhangWidth(0)
     43     , m_left(0)
     44     , m_right(0)
     45     , m_availableWidth(0)
     46     , m_segment(0)
     47     , m_isFirstLine(isFirstLine)
     48     , m_shouldIndentText(shouldIndentText)
     49 {
     50     updateCurrentShapeSegment();
     51     updateAvailableWidth();
     52 }
     53 
     54 void LineWidth::updateAvailableWidth(LayoutUnit replacedHeight)
     55 {
     56     LayoutUnit height = m_block.logicalHeight();
     57     LayoutUnit logicalHeight = m_block.minLineHeightForReplacedRenderer(m_isFirstLine, replacedHeight);
     58     m_left = m_block.logicalLeftOffsetForLine(height, shouldIndentText(), logicalHeight);
     59     m_right = m_block.logicalRightOffsetForLine(height, shouldIndentText(), logicalHeight);
     60 
     61     if (m_segment) {
     62         m_left = std::max<float>(m_segment->logicalLeft, m_left);
     63         m_right = std::min<float>(m_segment->logicalRight, m_right);
     64     }
     65 
     66     computeAvailableWidthFromLeftAndRight();
     67 }
     68 
     69 void LineWidth::shrinkAvailableWidthForNewFloatIfNeeded(FloatingObject* newFloat)
     70 {
     71     LayoutUnit height = m_block.logicalHeight();
     72     if (height < m_block.logicalTopForFloat(newFloat) || height >= m_block.logicalBottomForFloat(newFloat))
     73         return;
     74 
     75     // When floats with shape outside are stacked, the floats are positioned based on the margin box of the float,
     76     // not the shape's contour. Since we computed the width based on the shape contour when we added the float,
     77     // when we add a subsequent float on the same line, we need to undo the shape delta in order to position
     78     // based on the margin box. In order to do this, we need to walk back through the floating object list to find
     79     // the first previous float that is on the same side as our newFloat.
     80     ShapeOutsideInfo* previousShapeOutsideInfo = 0;
     81     const FloatingObjectSet& floatingObjectSet = m_block.m_floatingObjects->set();
     82     FloatingObjectSetIterator it = floatingObjectSet.end();
     83     FloatingObjectSetIterator begin = floatingObjectSet.begin();
     84     LayoutUnit lineHeight = m_block.lineHeight(m_isFirstLine, m_block.isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
     85     for (--it; it != begin; --it) {
     86         FloatingObject* previousFloat = *it;
     87         if (previousFloat != newFloat && previousFloat->type() == newFloat->type()) {
     88             previousShapeOutsideInfo = previousFloat->renderer()->shapeOutsideInfo();
     89             if (previousShapeOutsideInfo)
     90                 previousShapeOutsideInfo->updateDeltasForContainingBlockLine(&m_block, previousFloat, m_block.logicalHeight(), lineHeight);
     91             break;
     92         }
     93     }
     94 
     95     ShapeOutsideInfo* shapeOutsideInfo = newFloat->renderer()->shapeOutsideInfo();
     96     if (shapeOutsideInfo)
     97         shapeOutsideInfo->updateDeltasForContainingBlockLine(&m_block, newFloat, m_block.logicalHeight(), lineHeight);
     98 
     99     if (newFloat->type() == FloatingObject::FloatLeft) {
    100         float newLeft = m_block.logicalRightForFloat(newFloat);
    101         if (previousShapeOutsideInfo)
    102             newLeft -= previousShapeOutsideInfo->rightMarginBoxDelta();
    103         if (shapeOutsideInfo)
    104             newLeft += shapeOutsideInfo->rightMarginBoxDelta();
    105 
    106         if (shouldIndentText() && m_block.style()->isLeftToRightDirection())
    107             newLeft += floorToInt(m_block.textIndentOffset());
    108         m_left = std::max<float>(m_left, newLeft);
    109     } else {
    110         float newRight = m_block.logicalLeftForFloat(newFloat);
    111         if (previousShapeOutsideInfo)
    112             newRight -= previousShapeOutsideInfo->leftMarginBoxDelta();
    113         if (shapeOutsideInfo)
    114             newRight += shapeOutsideInfo->leftMarginBoxDelta();
    115 
    116         if (shouldIndentText() && !m_block.style()->isLeftToRightDirection())
    117             newRight -= floorToInt(m_block.textIndentOffset());
    118         m_right = std::min<float>(m_right, newRight);
    119     }
    120 
    121     computeAvailableWidthFromLeftAndRight();
    122 }
    123 
    124 void LineWidth::commit()
    125 {
    126     m_committedWidth += m_uncommittedWidth;
    127     m_uncommittedWidth = 0;
    128 }
    129 
    130 void LineWidth::applyOverhang(RenderRubyRun* rubyRun, RenderObject* startRenderer, RenderObject* endRenderer)
    131 {
    132     int startOverhang;
    133     int endOverhang;
    134     rubyRun->getOverhang(m_isFirstLine, startRenderer, endRenderer, startOverhang, endOverhang);
    135 
    136     startOverhang = std::min<int>(startOverhang, m_committedWidth);
    137     m_availableWidth += startOverhang;
    138 
    139     endOverhang = std::max(std::min<int>(endOverhang, m_availableWidth - currentWidth()), 0);
    140     m_availableWidth += endOverhang;
    141     m_overhangWidth += startOverhang + endOverhang;
    142 }
    143 
    144 void LineWidth::fitBelowFloats()
    145 {
    146     ASSERT(!m_committedWidth);
    147     ASSERT(!fitsOnLine());
    148 
    149     LayoutUnit floatLogicalBottom;
    150     LayoutUnit lastFloatLogicalBottom = m_block.logicalHeight();
    151     float newLineWidth = m_availableWidth;
    152     float newLineLeft = m_left;
    153     float newLineRight = m_right;
    154     while (true) {
    155         floatLogicalBottom = m_block.nextFloatLogicalBottomBelow(lastFloatLogicalBottom, ShapeOutsideFloatShapeOffset);
    156         if (floatLogicalBottom <= lastFloatLogicalBottom)
    157             break;
    158 
    159         newLineLeft = m_block.logicalLeftOffsetForLine(floatLogicalBottom, shouldIndentText());
    160         newLineRight = m_block.logicalRightOffsetForLine(floatLogicalBottom, shouldIndentText());
    161         newLineWidth = max(0.0f, newLineRight - newLineLeft);
    162         lastFloatLogicalBottom = floatLogicalBottom;
    163 
    164         // FIXME: This code should be refactored to incorporate with the code above.
    165         ShapeInsideInfo* shapeInsideInfo = m_block.layoutShapeInsideInfo();
    166         if (shapeInsideInfo) {
    167             LayoutUnit logicalOffsetFromShapeContainer = m_block.logicalOffsetFromShapeAncestorContainer(shapeInsideInfo->owner()).height();
    168             LayoutUnit lineHeight = m_block.lineHeight(false, m_block.isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
    169             shapeInsideInfo->updateSegmentsForLine(lastFloatLogicalBottom + logicalOffsetFromShapeContainer, lineHeight);
    170             updateCurrentShapeSegment();
    171             updateAvailableWidth();
    172         }
    173 
    174         if (newLineWidth >= m_uncommittedWidth)
    175             break;
    176     }
    177 
    178     if (newLineWidth > m_availableWidth) {
    179         m_block.setLogicalHeight(lastFloatLogicalBottom);
    180         m_availableWidth = newLineWidth + m_overhangWidth;
    181         m_left = newLineLeft;
    182         m_right = newLineRight;
    183     }
    184 }
    185 
    186 void LineWidth::updateCurrentShapeSegment()
    187 {
    188     if (ShapeInsideInfo* shapeInsideInfo = m_block.layoutShapeInsideInfo())
    189         m_segment = shapeInsideInfo->currentSegment();
    190 }
    191 
    192 void LineWidth::computeAvailableWidthFromLeftAndRight()
    193 {
    194     m_availableWidth = max(0.0f, m_right - m_left) + m_overhangWidth;
    195 }
    196 
    197 }
    198