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