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 "core/layout/line/LineWidth.h"
33 #include "core/layout/api/LineLayoutRubyRun.h"
34 #include "core/layout/shapes/ShapeOutsideInfo.h"
38 LineWidth::LineWidth(LineLayoutBlockFlow block
, bool isFirstLine
, IndentTextOrNot shouldIndentText
)
40 , m_uncommittedWidth(0)
43 , m_trailingWhitespaceWidth(0)
47 , m_isFirstLine(isFirstLine
)
48 , m_shouldIndentText(shouldIndentText
)
50 updateAvailableWidth();
53 void LineWidth::updateAvailableWidth(LayoutUnit replacedHeight
)
55 LayoutUnit height
= m_block
.logicalHeight();
56 LayoutUnit logicalHeight
= m_block
.minLineHeightForReplacedObject(m_isFirstLine
, replacedHeight
);
57 m_left
= m_block
.logicalLeftOffsetForLine(height
, shouldIndentText(), logicalHeight
).toFloat();
58 m_right
= m_block
.logicalRightOffsetForLine(height
, shouldIndentText(), logicalHeight
).toFloat();
60 computeAvailableWidthFromLeftAndRight();
63 void LineWidth::shrinkAvailableWidthForNewFloatIfNeeded(const FloatingObject
& newFloat
)
65 LayoutUnit height
= m_block
.logicalHeight();
66 if (height
< m_block
.logicalTopForFloat(newFloat
) || height
>= m_block
.logicalBottomForFloat(newFloat
))
69 ShapeOutsideDeltas shapeDeltas
;
70 if (ShapeOutsideInfo
* shapeOutsideInfo
= newFloat
.layoutObject()->shapeOutsideInfo()) {
71 LayoutUnit lineHeight
= m_block
.lineHeight(m_isFirstLine
, m_block
.isHorizontalWritingMode() ? HorizontalLine
: VerticalLine
, PositionOfInteriorLineBoxes
);
72 shapeDeltas
= shapeOutsideInfo
->computeDeltasForContainingBlockLine(m_block
, newFloat
, m_block
.logicalHeight(), lineHeight
);
75 if (newFloat
.type() == FloatingObject::FloatLeft
) {
76 float newLeft
= m_block
.logicalRightForFloat(newFloat
).toFloat();
77 if (shapeDeltas
.isValid()) {
78 if (shapeDeltas
.lineOverlapsShape())
79 newLeft
+= shapeDeltas
.rightMarginBoxDelta();
80 else // Per the CSS Shapes spec, If the line doesn't overlap the shape, then ignore this shape for this line.
83 if (shouldIndentText() && m_block
.style()->isLeftToRightDirection())
84 newLeft
+= floorToInt(m_block
.textIndentOffset());
85 m_left
= std::max
<float>(m_left
, newLeft
);
87 float newRight
= m_block
.logicalLeftForFloat(newFloat
).toFloat();
88 if (shapeDeltas
.isValid()) {
89 if (shapeDeltas
.lineOverlapsShape())
90 newRight
+= shapeDeltas
.leftMarginBoxDelta();
91 else // Per the CSS Shapes spec, If the line doesn't overlap the shape, then ignore this shape for this line.
94 if (shouldIndentText() && !m_block
.style()->isLeftToRightDirection())
95 newRight
-= floorToInt(m_block
.textIndentOffset());
96 m_right
= std::min
<float>(m_right
, newRight
);
99 computeAvailableWidthFromLeftAndRight();
102 void LineWidth::commit()
104 m_committedWidth
+= m_uncommittedWidth
;
105 m_uncommittedWidth
= 0;
108 void LineWidth::applyOverhang(LineLayoutRubyRun rubyRun
, LineLayoutItem startLayoutItem
, LineLayoutItem endLayoutItem
)
112 rubyRun
.getOverhang(m_isFirstLine
, startLayoutItem
, endLayoutItem
, startOverhang
, endOverhang
);
114 startOverhang
= std::min
<int>(startOverhang
, m_committedWidth
);
115 m_availableWidth
+= startOverhang
;
117 endOverhang
= std::max(std::min
<int>(endOverhang
, m_availableWidth
- currentWidth()), 0);
118 m_availableWidth
+= endOverhang
;
119 m_overhangWidth
+= startOverhang
+ endOverhang
;
122 inline static float availableWidthAtOffset(LineLayoutBlockFlow block
, const LayoutUnit
& offset
, bool shouldIndentText
, float& newLineLeft
,
123 float& newLineRight
, const LayoutUnit
& lineHeight
= 0)
125 newLineLeft
= block
.logicalLeftOffsetForLine(offset
, shouldIndentText
, lineHeight
).toFloat();
126 newLineRight
= block
.logicalRightOffsetForLine(offset
, shouldIndentText
, lineHeight
).toFloat();
127 return std::max(0.0f
, newLineRight
- newLineLeft
);
130 void LineWidth::updateLineDimension(LayoutUnit newLineTop
, LayoutUnit newLineWidth
, const float& newLineLeft
, const float& newLineRight
)
132 if (newLineWidth
<= m_availableWidth
)
135 m_block
.setLogicalHeight(newLineTop
);
136 m_availableWidth
= newLineWidth
+ m_overhangWidth
;
137 m_left
= newLineLeft
;
138 m_right
= newLineRight
;
141 void LineWidth::wrapNextToShapeOutside(bool isFirstLine
)
143 LayoutUnit lineHeight
= m_block
.lineHeight(isFirstLine
, m_block
.isHorizontalWritingMode() ? HorizontalLine
: VerticalLine
, PositionOfInteriorLineBoxes
);
144 LayoutUnit lineLogicalTop
= m_block
.logicalHeight();
145 LayoutUnit newLineTop
= lineLogicalTop
;
146 LayoutUnit floatLogicalBottom
= m_block
.nextFloatLogicalBottomBelow(lineLogicalTop
);
149 float newLineLeft
= m_left
;
150 float newLineRight
= m_right
;
152 newLineWidth
= availableWidthAtOffset(m_block
, newLineTop
, shouldIndentText(), newLineLeft
, newLineRight
, lineHeight
);
153 if (newLineWidth
>= m_uncommittedWidth
)
156 if (newLineTop
>= floatLogicalBottom
)
161 updateLineDimension(newLineTop
, newLineWidth
, newLineLeft
, newLineRight
);
164 void LineWidth::fitBelowFloats(bool isFirstLine
)
166 ASSERT(!m_committedWidth
);
167 ASSERT(!fitsOnLine());
168 m_block
.positionNewFloats(this);
170 LayoutUnit floatLogicalBottom
;
171 LayoutUnit lastFloatLogicalBottom
= m_block
.logicalHeight();
172 float newLineWidth
= m_availableWidth
;
173 float newLineLeft
= m_left
;
174 float newLineRight
= m_right
;
176 FloatingObject
* lastFloatFromPreviousLine
= m_block
.lastFloatFromPreviousLine();
177 if (lastFloatFromPreviousLine
&& lastFloatFromPreviousLine
->layoutObject()->shapeOutsideInfo())
178 return wrapNextToShapeOutside(isFirstLine
);
181 floatLogicalBottom
= m_block
.nextFloatLogicalBottomBelow(lastFloatLogicalBottom
, ShapeOutsideFloatShapeOffset
);
182 if (floatLogicalBottom
<= lastFloatLogicalBottom
)
185 newLineWidth
= availableWidthAtOffset(m_block
, floatLogicalBottom
, shouldIndentText(), newLineLeft
, newLineRight
);
186 lastFloatLogicalBottom
= floatLogicalBottom
;
188 if (newLineWidth
>= m_uncommittedWidth
)
191 updateLineDimension(lastFloatLogicalBottom
, newLineWidth
, newLineLeft
, newLineRight
);
194 void LineWidth::computeAvailableWidthFromLeftAndRight()
196 m_availableWidth
= max(0.0f
, m_right
- m_left
) + m_overhangWidth
;