2 * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the following
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.
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.
31 #include "LineWidth.h"
35 LineWidth::LineWidth(RenderBlock& block, bool isFirstLine, IndentTextOrNot shouldIndentText)
37 , m_uncommittedWidth(0)
40 , m_trailingWhitespaceWidth(0)
41 , m_trailingCollapsedWhitespaceWidth(0)
45 #if ENABLE(CSS_SHAPES)
48 , m_isFirstLine(isFirstLine)
49 , m_shouldIndentText(shouldIndentText)
51 #if ENABLE(CSS_SHAPES)
52 updateCurrentShapeSegment();
54 updateAvailableWidth();
57 bool LineWidth::fitsOnLine(bool ignoringTrailingSpace) const
59 return ignoringTrailingSpace ? fitsOnLineExcludingTrailingCollapsedWhitespace() : fitsOnLineIncludingExtraWidth(0);
62 bool LineWidth::fitsOnLineIncludingExtraWidth(float extra) const
64 return currentWidth() + extra <= m_availableWidth;
67 bool LineWidth::fitsOnLineExcludingTrailingWhitespace(float extra) const
69 return currentWidth() - m_trailingWhitespaceWidth + extra <= m_availableWidth;
72 void LineWidth::updateAvailableWidth(LayoutUnit replacedHeight)
74 LayoutUnit height = m_block.logicalHeight();
75 LayoutUnit logicalHeight = logicalHeightForLine(&m_block, m_isFirstLine, replacedHeight);
76 m_left = m_block.logicalLeftOffsetForLine(height, shouldIndentText(), logicalHeight);
77 m_right = m_block.logicalRightOffsetForLine(height, shouldIndentText(), logicalHeight);
79 #if ENABLE(CSS_SHAPES)
81 m_left = std::max<float>(m_segment->logicalLeft, m_left);
82 m_right = std::min<float>(m_segment->logicalRight, m_right);
86 computeAvailableWidthFromLeftAndRight();
89 void LineWidth::shrinkAvailableWidthForNewFloatIfNeeded(FloatingObject* newFloat)
91 LayoutUnit height = m_block.logicalHeight();
92 if (height < newFloat->logicalTop(m_block.isHorizontalWritingMode()) || height >= newFloat->logicalBottom(m_block.isHorizontalWritingMode()))
95 #if ENABLE(CSS_SHAPES)
96 // When floats with shape outside are stacked, the floats are positioned based on the margin box of the float,
97 // not the shape's contour. Since we computed the width based on the shape contour when we added the float,
98 // when we add a subsequent float on the same line, we need to undo the shape delta in order to position
99 // based on the margin box. In order to do this, we need to walk back through the floating object list to find
100 // the first previous float that is on the same side as our newFloat.
101 ShapeOutsideInfo* previousShapeOutsideInfo = 0;
102 const FloatingObjectSet& floatingObjectSet = m_block.m_floatingObjects->set();
103 FloatingObjectSetIterator it = floatingObjectSet.end();
104 FloatingObjectSetIterator begin = floatingObjectSet.begin();
105 for (--it; it != begin; --it) {
106 FloatingObject* previousFloat = *it;
107 if (previousFloat != newFloat && previousFloat->type() == newFloat->type()) {
108 previousShapeOutsideInfo = previousFloat->renderer()->shapeOutsideInfo();
109 if (previousShapeOutsideInfo)
110 previousShapeOutsideInfo->updateDeltasForContainingBlockLine(&m_block, previousFloat, m_block.logicalHeight(), logicalHeightForLine(&m_block, m_isFirstLine));
115 ShapeOutsideInfo* shapeOutsideInfo = newFloat->renderer()->shapeOutsideInfo();
116 if (shapeOutsideInfo)
117 shapeOutsideInfo->updateDeltasForContainingBlockLine(&m_block, newFloat, m_block.logicalHeight(), logicalHeightForLine(&m_block, m_isFirstLine));
120 if (newFloat->type() == FloatingObject::FloatLeft) {
121 float newLeft = newFloat->logicalRight(m_block.isHorizontalWritingMode());
122 #if ENABLE(CSS_SHAPES)
123 if (previousShapeOutsideInfo)
124 newLeft -= previousShapeOutsideInfo->rightMarginBoxDelta();
125 if (shapeOutsideInfo)
126 newLeft += shapeOutsideInfo->rightMarginBoxDelta();
129 if (shouldIndentText() && m_block.style()->isLeftToRightDirection())
130 newLeft += floorToInt(m_block.textIndentOffset());
131 m_left = std::max<float>(m_left, newLeft);
133 float newRight = newFloat->logicalLeft(m_block.isHorizontalWritingMode());
134 #if ENABLE(CSS_SHAPES)
135 if (previousShapeOutsideInfo)
136 newRight -= previousShapeOutsideInfo->leftMarginBoxDelta();
137 if (shapeOutsideInfo)
138 newRight += shapeOutsideInfo->leftMarginBoxDelta();
141 if (shouldIndentText() && !m_block.style()->isLeftToRightDirection())
142 newRight -= floorToInt(m_block.textIndentOffset());
143 m_right = std::min<float>(m_right, newRight);
146 computeAvailableWidthFromLeftAndRight();
149 void LineWidth::commit()
151 m_committedWidth += m_uncommittedWidth;
152 m_uncommittedWidth = 0;
155 void LineWidth::applyOverhang(RenderRubyRun* rubyRun, RenderObject* startRenderer, RenderObject* endRenderer)
159 rubyRun->getOverhang(m_isFirstLine, startRenderer, endRenderer, startOverhang, endOverhang);
161 startOverhang = std::min<int>(startOverhang, m_committedWidth);
162 m_availableWidth += startOverhang;
164 endOverhang = std::max(std::min<int>(endOverhang, m_availableWidth - currentWidth()), 0);
165 m_availableWidth += endOverhang;
166 m_overhangWidth += startOverhang + endOverhang;
169 void LineWidth::fitBelowFloats()
171 ASSERT(!m_committedWidth);
172 ASSERT(!fitsOnLine());
174 LayoutUnit floatLogicalBottom;
175 LayoutUnit lastFloatLogicalBottom = m_block.logicalHeight();
176 float newLineWidth = m_availableWidth;
177 float newLineLeft = m_left;
178 float newLineRight = m_right;
180 floatLogicalBottom = m_block.nextFloatLogicalBottomBelow(lastFloatLogicalBottom);
181 if (floatLogicalBottom <= lastFloatLogicalBottom)
184 newLineLeft = m_block.logicalLeftOffsetForLine(floatLogicalBottom, shouldIndentText());
185 newLineRight = m_block.logicalRightOffsetForLine(floatLogicalBottom, shouldIndentText());
186 newLineWidth = max(0.0f, newLineRight - newLineLeft);
187 lastFloatLogicalBottom = floatLogicalBottom;
188 if (newLineWidth >= m_uncommittedWidth)
192 if (newLineWidth > m_availableWidth) {
193 m_block.setLogicalHeight(lastFloatLogicalBottom);
194 m_availableWidth = newLineWidth + m_overhangWidth;
195 m_left = newLineLeft;
196 m_right = newLineRight;
200 void LineWidth::setTrailingWhitespaceWidth(float collapsedWhitespace, float borderPaddingMargin)
202 m_trailingCollapsedWhitespaceWidth = collapsedWhitespace;
203 m_trailingWhitespaceWidth = collapsedWhitespace + borderPaddingMargin;
206 #if ENABLE(CSS_SHAPES)
207 void LineWidth::updateCurrentShapeSegment()
209 if (ShapeInsideInfo* shapeInsideInfo = m_block.layoutShapeInsideInfo())
210 m_segment = shapeInsideInfo->currentSegment();
214 void LineWidth::computeAvailableWidthFromLeftAndRight()
216 m_availableWidth = max(0.0f, m_right - m_left) + m_overhangWidth;
219 bool LineWidth::fitsOnLineExcludingTrailingCollapsedWhitespace() const
221 return currentWidth() - m_trailingCollapsedWhitespaceWidth <= m_availableWidth;