blob: 91250c34afea9d4555a89c6bd72003476093a340 [file] [log] [blame]
darin55ae73e2007-05-11 15:47:28 +00001/*
kociendabb0c24b2001-08-24 14:24:40 +00002 * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
mitz@apple.com86470c82011-01-27 01:39:27 +00003 * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All right reserved.
eric@webkit.orgddbec0aa2010-01-06 01:13:11 +00004 * Copyright (C) 2010 Google Inc. All rights reserved.
kociendabb0c24b2001-08-24 14:24:40 +00005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
ddkilzerc8eccec2007-09-26 02:29:57 +000018 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
kociendabb0c24b2001-08-24 14:24:40 +000020 *
kociendabb0c24b2001-08-24 14:24:40 +000021 */
darinbe4c67d2005-12-19 19:53:12 +000022
mjsb64c50a2005-10-03 21:13:12 +000023#include "config.h"
darin36d11362006-04-11 16:30:21 +000024
mitz@apple.com4c1ff322009-07-13 00:54:12 +000025#include "BidiResolver.h"
mitz@apple.comb2107652010-06-21 16:54:52 +000026#include "Hyphenation.h"
hyatt@apple.com71eeb442010-02-11 20:05:51 +000027#include "InlineIterator.h"
eseidel3a6d1322006-01-09 03:14:50 +000028#include "InlineTextBox.h"
ggarenec11e5b2007-02-25 02:14:54 +000029#include "Logging.h"
darin36d11362006-04-11 16:30:21 +000030#include "RenderArena.h"
hyatt@apple.com4d046b72011-01-31 20:39:09 +000031#include "RenderCombineText.h"
esprehn@chromium.org7745ffb2013-02-19 21:51:19 +000032#include "RenderCounter.h"
hyatt@apple.coma10d30e2011-09-22 22:28:21 +000033#include "RenderFlowThread.h"
hyatt@apple.comc3c7e902009-01-28 21:48:33 +000034#include "RenderInline.h"
eric@webkit.orgb35848a2010-06-10 08:33:22 +000035#include "RenderLayer.h"
mjsd26b2972007-02-13 13:09:04 +000036#include "RenderListMarker.h"
zoltan@webkit.orgb7a73462013-02-22 19:53:35 +000037#include "RenderRegion.h"
mitz@apple.comddb59872011-04-05 05:21:16 +000038#include "RenderRubyRun.h"
hyattd8048342006-05-31 01:48:18 +000039#include "RenderView.h"
hyatt@apple.comcc1737c2010-09-16 20:20:02 +000040#include "Settings.h"
dbates@webkit.orgf6f05a92010-05-17 04:58:25 +000041#include "TrailingFloatsRootInlineBox.h"
hyatt@apple.com4a9c625a2010-11-17 20:55:40 +000042#include "VerticalPositionCache.h"
darin36d11362006-04-11 16:30:21 +000043#include "break_lines.h"
mjsbb863512006-05-09 09:27:55 +000044#include <wtf/AlwaysInline.h>
slewis@apple.coma7615ca2008-07-12 05:51:33 +000045#include <wtf/RefCountedLeakCounter.h>
bolsinga@apple.com97e42c42008-11-15 04:47:20 +000046#include <wtf/StdLibExtras.h>
darin91298e52006-06-12 01:10:17 +000047#include <wtf/Vector.h>
paroga@webkit.org10c9e1b2011-01-29 17:04:51 +000048#include <wtf/unicode/CharacterNames.h>
hyatt8c371e52004-06-16 01:19:26 +000049
commit-queue@webkit.orgb3540512012-08-24 18:48:49 +000050#if ENABLE(CSS_EXCLUSIONS)
commit-queue@webkit.org3a988eb2012-09-26 19:55:35 +000051#include "ExclusionShapeInsideInfo.h"
commit-queue@webkit.orgb3540512012-08-24 18:48:49 +000052#endif
53
zimmermann@webkit.orgb40815c2010-06-18 11:18:44 +000054#if ENABLE(SVG)
zimmermann@webkit.org6e96afd2010-09-10 15:35:50 +000055#include "RenderSVGInlineText.h"
zimmermann@webkit.orgb40815c2010-06-18 11:18:44 +000056#include "SVGRootInlineBox.h"
57#endif
58
darin7bd70952006-04-13 07:07:34 +000059using namespace std;
darinf9e5d6c2007-01-09 14:54:26 +000060using namespace WTF;
61using namespace Unicode;
darin7bd70952006-04-13 07:07:34 +000062
darinb9481ed2006-03-20 02:57:59 +000063namespace WebCore {
mjsfe301d72003-10-02 18:46:18 +000064
hyatt1d5d87b2007-04-24 04:55:54 +000065// We don't let our line box tree for a single line get any deeper than this.
66const unsigned cMaxLineDepth = 200;
eric@webkit.org060caf62011-05-03 22:11:39 +000067
zoltan@webkit.orgb7a73462013-02-22 19:53:35 +000068static LayoutUnit logicalHeightForLine(const RenderBlock* block, bool isFirstLine, LayoutUnit replacedHeight = 0)
69{
70 if (!block->document()->inNoQuirksMode() && replacedHeight)
71 return replacedHeight;
72
73 if (!(block->style(isFirstLine)->lineBoxContain() & LineBoxContainBlock))
74 return 0;
75
76 return max<LayoutUnit>(replacedHeight, block->lineHeight(isFirstLine, block->isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
77}
78
commit-queue@webkit.org3b26f3d2012-09-25 18:22:39 +000079#if ENABLE(CSS_EXCLUSIONS)
betravis@adobe.com1e4305c2013-04-05 17:30:27 +000080ExclusionShapeInsideInfo* RenderBlock::layoutExclusionShapeInsideInfo(ExclusionShapeStatus exclusionShapeStatus) const
commit-queue@webkit.org3b26f3d2012-09-25 18:22:39 +000081{
betravis@adobe.coma53af342013-03-01 21:02:16 +000082 ExclusionShapeInsideInfo* shapeInsideInfo = view()->layoutState()->exclusionShapeInsideInfo();
betravis@adobe.com1e4305c2013-04-05 17:30:27 +000083 if (shapeInsideInfo && shapeInsideInfo->needsRemoval() && exclusionShapeStatus == ShapePresent)
84 shapeInsideInfo = 0;
85
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +000086 if (!shapeInsideInfo && flowThreadContainingBlock()) {
betravis@adobe.coma53af342013-03-01 21:02:16 +000087 LayoutUnit offset = logicalHeight() + logicalHeightForLine(this, false);
88 RenderRegion* region = regionAtBlockOffset(offset);
betravis@adobe.com1e4305c2013-04-05 17:30:27 +000089 if (region)
90 shapeInsideInfo = region->exclusionShapeInsideInfo();
91 return shapeInsideInfo && shapeInsideInfo->needsRemoval() && exclusionShapeStatus == ShapePresent ? 0 : shapeInsideInfo;
zoltan@webkit.orgb7a73462013-02-22 19:53:35 +000092 }
betravis@adobe.com1e4305c2013-04-05 17:30:27 +000093
zoltan@webkit.orgb7a73462013-02-22 19:53:35 +000094 return shapeInsideInfo;
commit-queue@webkit.org3b26f3d2012-09-25 18:22:39 +000095}
96#endif
97
commit-queue@webkit.orgab781b02013-04-03 01:32:24 +000098enum IndentTextOrNot { DoNotIndentText, IndentText };
99
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000100class LineWidth {
101public:
commit-queue@webkit.orgab781b02013-04-03 01:32:24 +0000102 LineWidth(RenderBlock* block, bool isFirstLine, IndentTextOrNot shouldIndentText)
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000103 : m_block(block)
104 , m_uncommittedWidth(0)
105 , m_committedWidth(0)
106 , m_overhangWidth(0)
107 , m_left(0)
108 , m_right(0)
109 , m_availableWidth(0)
commit-queue@webkit.orgb3540512012-08-24 18:48:49 +0000110#if ENABLE(CSS_EXCLUSIONS)
111 , m_segment(0)
112#endif
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000113 , m_isFirstLine(isFirstLine)
commit-queue@webkit.orgab781b02013-04-03 01:32:24 +0000114 , m_shouldIndentText(shouldIndentText)
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000115 {
116 ASSERT(block);
commit-queue@webkit.orgb3540512012-08-24 18:48:49 +0000117#if ENABLE(CSS_EXCLUSIONS)
betravis@adobe.coma53af342013-03-01 21:02:16 +0000118 ExclusionShapeInsideInfo* exclusionShapeInsideInfo = m_block->layoutExclusionShapeInsideInfo();
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +0000119 if (exclusionShapeInsideInfo)
120 m_segment = exclusionShapeInsideInfo->currentSegment();
commit-queue@webkit.orgb3540512012-08-24 18:48:49 +0000121#endif
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000122 updateAvailableWidth();
123 }
eae@chromium.org271b04a2012-09-26 16:25:41 +0000124 bool fitsOnLine() const { return currentWidth() <= m_availableWidth; }
125 bool fitsOnLine(float extra) const { return currentWidth() + extra <= m_availableWidth; }
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000126 float currentWidth() const { return m_committedWidth + m_uncommittedWidth; }
127
128 // FIXME: We should eventually replace these three functions by ones that work on a higher abstraction.
129 float uncommittedWidth() const { return m_uncommittedWidth; }
130 float committedWidth() const { return m_committedWidth; }
131 float availableWidth() const { return m_availableWidth; }
132
robert@webkit.org0903cf52012-12-11 18:14:16 +0000133 void updateAvailableWidth(LayoutUnit minimumHeight = 0);
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000134 void shrinkAvailableWidthForNewFloatIfNeeded(RenderBlock::FloatingObject*);
135 void addUncommittedWidth(float delta) { m_uncommittedWidth += delta; }
136 void commit()
137 {
138 m_committedWidth += m_uncommittedWidth;
139 m_uncommittedWidth = 0;
140 }
141 void applyOverhang(RenderRubyRun*, RenderObject* startRenderer, RenderObject* endRenderer);
142 void fitBelowFloats();
143
commit-queue@webkit.orgab781b02013-04-03 01:32:24 +0000144 bool shouldIndentText() { return m_shouldIndentText == IndentText; }
145
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000146private:
147 void computeAvailableWidthFromLeftAndRight()
148 {
eae@chromium.orgb1054552012-06-05 04:42:55 +0000149 m_availableWidth = max(0.0f, m_right - m_left) + m_overhangWidth;
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000150 }
151
152private:
153 RenderBlock* m_block;
154 float m_uncommittedWidth;
155 float m_committedWidth;
156 float m_overhangWidth; // The amount by which |m_availableWidth| has been inflated to account for possible contraction due to ruby overhang.
eae@chromium.orgb1054552012-06-05 04:42:55 +0000157 float m_left;
158 float m_right;
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000159 float m_availableWidth;
commit-queue@webkit.orgb3540512012-08-24 18:48:49 +0000160#if ENABLE(CSS_EXCLUSIONS)
161 const LineSegment* m_segment;
162#endif
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000163 bool m_isFirstLine;
commit-queue@webkit.orgab781b02013-04-03 01:32:24 +0000164 IndentTextOrNot m_shouldIndentText;
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000165};
166
robert@webkit.org0903cf52012-12-11 18:14:16 +0000167inline void LineWidth::updateAvailableWidth(LayoutUnit replacedHeight)
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000168{
leviw@chromium.org0e230612012-03-01 19:33:44 +0000169 LayoutUnit height = m_block->logicalHeight();
robert@webkit.org0903cf52012-12-11 18:14:16 +0000170 LayoutUnit logicalHeight = logicalHeightForLine(m_block, m_isFirstLine, replacedHeight);
commit-queue@webkit.orgab781b02013-04-03 01:32:24 +0000171 m_left = m_block->logicalLeftOffsetForLine(height, shouldIndentText(), logicalHeight);
172 m_right = m_block->logicalRightOffsetForLine(height, shouldIndentText(), logicalHeight);
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000173
commit-queue@webkit.orgb3540512012-08-24 18:48:49 +0000174#if ENABLE(CSS_EXCLUSIONS)
175 if (m_segment) {
176 m_left = max<float>(m_segment->logicalLeft, m_left);
177 m_right = min<float>(m_segment->logicalRight, m_right);
178 }
179#endif
180
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000181 computeAvailableWidthFromLeftAndRight();
182}
183
184inline void LineWidth::shrinkAvailableWidthForNewFloatIfNeeded(RenderBlock::FloatingObject* newFloat)
185{
leviw@chromium.orgd32486e2012-03-16 10:52:56 +0000186 LayoutUnit height = m_block->logicalHeight();
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000187 if (height < m_block->logicalTopForFloat(newFloat) || height >= m_block->logicalBottomForFloat(newFloat))
188 return;
189
commit-queue@webkit.org31a3bc72013-03-05 18:19:36 +0000190#if ENABLE(CSS_EXCLUSIONS)
191 ExclusionShapeOutsideInfo* shapeOutsideInfo = newFloat->renderer()->exclusionShapeOutsideInfo();
192 if (shapeOutsideInfo)
commit-queue@webkit.org5bbba392013-03-29 21:13:02 +0000193 shapeOutsideInfo->computeSegmentsForLine(m_block->logicalHeight() - m_block->logicalTopForFloat(newFloat) + shapeOutsideInfo->shapeLogicalTop(), logicalHeightForLine(m_block, m_isFirstLine));
commit-queue@webkit.org31a3bc72013-03-05 18:19:36 +0000194#endif
195
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000196 if (newFloat->type() == RenderBlock::FloatingObject::FloatLeft) {
eae@chromium.org5adcf0f2012-10-30 13:36:31 +0000197 float newLeft = m_block->logicalRightForFloat(newFloat);
commit-queue@webkit.org31a3bc72013-03-05 18:19:36 +0000198#if ENABLE(CSS_EXCLUSIONS)
199 if (shapeOutsideInfo)
200 newLeft += shapeOutsideInfo->rightSegmentShapeBoundingBoxDelta();
201#endif
202
commit-queue@webkit.orgab781b02013-04-03 01:32:24 +0000203 if (shouldIndentText() && m_block->style()->isLeftToRightDirection())
robert@webkit.org3bb2d322012-10-21 09:44:21 +0000204 newLeft += floorToInt(m_block->textIndentOffset());
205 m_left = max<float>(m_left, newLeft);
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000206 } else {
eae@chromium.org5adcf0f2012-10-30 13:36:31 +0000207 float newRight = m_block->logicalLeftForFloat(newFloat);
commit-queue@webkit.org31a3bc72013-03-05 18:19:36 +0000208#if ENABLE(CSS_EXCLUSIONS)
209 if (shapeOutsideInfo)
210 newRight += shapeOutsideInfo->leftSegmentShapeBoundingBoxDelta();
211#endif
212
commit-queue@webkit.orgab781b02013-04-03 01:32:24 +0000213 if (shouldIndentText() && !m_block->style()->isLeftToRightDirection())
robert@webkit.org3bb2d322012-10-21 09:44:21 +0000214 newRight -= floorToInt(m_block->textIndentOffset());
215 m_right = min<float>(m_right, newRight);
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000216 }
217
218 computeAvailableWidthFromLeftAndRight();
219}
220
221void LineWidth::applyOverhang(RenderRubyRun* rubyRun, RenderObject* startRenderer, RenderObject* endRenderer)
222{
223 int startOverhang;
224 int endOverhang;
225 rubyRun->getOverhang(m_isFirstLine, startRenderer, endRenderer, startOverhang, endOverhang);
226
227 startOverhang = min<int>(startOverhang, m_committedWidth);
228 m_availableWidth += startOverhang;
229
230 endOverhang = max(min<int>(endOverhang, m_availableWidth - currentWidth()), 0);
231 m_availableWidth += endOverhang;
232 m_overhangWidth += startOverhang + endOverhang;
233}
234
235void LineWidth::fitBelowFloats()
236{
237 ASSERT(!m_committedWidth);
238 ASSERT(!fitsOnLine());
239
leviw@chromium.orgd32486e2012-03-16 10:52:56 +0000240 LayoutUnit floatLogicalBottom;
241 LayoutUnit lastFloatLogicalBottom = m_block->logicalHeight();
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000242 float newLineWidth = m_availableWidth;
243 float newLineLeft = m_left;
244 float newLineRight = m_right;
245 while (true) {
246 floatLogicalBottom = m_block->nextFloatLogicalBottomBelow(lastFloatLogicalBottom);
hyatt@apple.comd4d3bcf2011-10-04 18:17:04 +0000247 if (floatLogicalBottom <= lastFloatLogicalBottom)
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000248 break;
249
commit-queue@webkit.orgab781b02013-04-03 01:32:24 +0000250 newLineLeft = m_block->logicalLeftOffsetForLine(floatLogicalBottom, shouldIndentText());
251 newLineRight = m_block->logicalRightOffsetForLine(floatLogicalBottom, shouldIndentText());
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000252 newLineWidth = max(0.0f, newLineRight - newLineLeft);
253 lastFloatLogicalBottom = floatLogicalBottom;
254 if (newLineWidth >= m_uncommittedWidth)
255 break;
256 }
257
258 if (newLineWidth > m_availableWidth) {
259 m_block->setLogicalHeight(lastFloatLogicalBottom);
260 m_availableWidth = newLineWidth + m_overhangWidth;
261 m_left = newLineLeft;
262 m_right = newLineRight;
263 }
264}
265
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +0000266class LineInfo {
267public:
268 LineInfo()
269 : m_isFirstLine(true)
270 , m_isLastLine(false)
271 , m_isEmpty(true)
272 , m_previousLineBrokeCleanly(true)
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000273 , m_floatPaginationStrut(0)
robert@webkit.org8cbab142011-12-30 20:58:29 +0000274 , m_runsFromLeadingWhitespace(0)
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +0000275 { }
276
277 bool isFirstLine() const { return m_isFirstLine; }
278 bool isLastLine() const { return m_isLastLine; }
279 bool isEmpty() const { return m_isEmpty; }
280 bool previousLineBrokeCleanly() const { return m_previousLineBrokeCleanly; }
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000281 LayoutUnit floatPaginationStrut() const { return m_floatPaginationStrut; }
robert@webkit.org8cbab142011-12-30 20:58:29 +0000282 unsigned runsFromLeadingWhitespace() const { return m_runsFromLeadingWhitespace; }
283 void resetRunsFromLeadingWhitespace() { m_runsFromLeadingWhitespace = 0; }
284 void incrementRunsFromLeadingWhitespace() { m_runsFromLeadingWhitespace++; }
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +0000285
286 void setFirstLine(bool firstLine) { m_isFirstLine = firstLine; }
287 void setLastLine(bool lastLine) { m_isLastLine = lastLine; }
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000288 void setEmpty(bool empty, RenderBlock* block = 0, LineWidth* lineWidth = 0)
289 {
290 if (m_isEmpty == empty)
291 return;
292 m_isEmpty = empty;
293 if (!empty && block && floatPaginationStrut()) {
294 block->setLogicalHeight(block->logicalHeight() + floatPaginationStrut());
295 setFloatPaginationStrut(0);
296 lineWidth->updateAvailableWidth();
297 }
298 }
299
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +0000300 void setPreviousLineBrokeCleanly(bool previousLineBrokeCleanly) { m_previousLineBrokeCleanly = previousLineBrokeCleanly; }
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000301 void setFloatPaginationStrut(LayoutUnit strut) { m_floatPaginationStrut = strut; }
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +0000302
303private:
304 bool m_isFirstLine;
305 bool m_isLastLine;
306 bool m_isEmpty;
307 bool m_previousLineBrokeCleanly;
hyatt@apple.com5950bd42011-09-27 20:39:57 +0000308 LayoutUnit m_floatPaginationStrut;
robert@webkit.org8cbab142011-12-30 20:58:29 +0000309 unsigned m_runsFromLeadingWhitespace;
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +0000310};
hyatt1d5d87b2007-04-24 04:55:54 +0000311
eae@chromium.orgee8613e2011-11-12 01:12:58 +0000312static inline LayoutUnit borderPaddingMarginStart(RenderInline* child)
hyattffe78712003-02-11 01:59:29 +0000313{
hyatt@apple.com0415e5d2010-10-07 17:40:25 +0000314 return child->marginStart() + child->paddingStart() + child->borderStart();
hyattffe78712003-02-11 01:59:29 +0000315}
316
eae@chromium.orgee8613e2011-11-12 01:12:58 +0000317static inline LayoutUnit borderPaddingMarginEnd(RenderInline* child)
rniwa@webkit.org33a346a2011-04-06 17:06:14 +0000318{
319 return child->marginEnd() + child->paddingEnd() + child->borderEnd();
320}
321
robert@webkit.org6dc9a232012-10-08 18:44:03 +0000322static bool shouldAddBorderPaddingMargin(RenderObject* child, bool &checkSide)
323{
324 if (!child || (child->isText() && !toRenderText(child)->textLength()))
325 return true;
326 checkSide = false;
327 return checkSide;
328}
329
eae@chromium.orgee8613e2011-11-12 01:12:58 +0000330static LayoutUnit inlineLogicalWidth(RenderObject* child, bool start = true, bool end = true)
hyattffe78712003-02-11 01:59:29 +0000331{
hyatt1d5d87b2007-04-24 04:55:54 +0000332 unsigned lineDepth = 1;
eae@chromium.orgee8613e2011-11-12 01:12:58 +0000333 LayoutUnit extraWidth = 0;
hyattffe78712003-02-11 01:59:29 +0000334 RenderObject* parent = child->parent();
robert@webkit.orgfc892822013-04-08 18:38:26 +0000335 while (parent->isRenderInline() && lineDepth++ < cMaxLineDepth) {
rniwa@webkit.org63db8cb2011-04-06 21:08:20 +0000336 RenderInline* parentAsRenderInline = toRenderInline(parent);
eae@chromium.org039c76a2013-04-02 23:17:18 +0000337 if (!isEmptyInline(parentAsRenderInline)) {
338 if (start && shouldAddBorderPaddingMargin(child->previousSibling(), start))
339 extraWidth += borderPaddingMarginStart(parentAsRenderInline);
340 if (end && shouldAddBorderPaddingMargin(child->nextSibling(), end))
341 extraWidth += borderPaddingMarginEnd(parentAsRenderInline);
342 if (!start && !end)
343 return extraWidth;
344 }
hyattffe78712003-02-11 01:59:29 +0000345 child = parent;
346 parent = child->parent();
347 }
348 return extraWidth;
349}
350
leviw@chromium.orge7812f32012-02-07 23:46:40 +0000351static void determineDirectionality(TextDirection& dir, InlineIterator iter)
leviw@chromium.org7781b6a2011-06-27 22:01:38 +0000352{
353 while (!iter.atEnd()) {
354 if (iter.atParagraphSeparator())
355 return;
356 if (UChar current = iter.current()) {
357 Direction charDirection = direction(current);
358 if (charDirection == LeftToRight) {
359 dir = LTR;
360 return;
361 }
362 if (charDirection == RightToLeft || charDirection == RightToLeftArabic) {
363 dir = RTL;
364 return;
365 }
366 }
367 iter.increment();
368 }
369}
370
hyatt@apple.comb3466af2009-06-13 06:04:40 +0000371static void checkMidpoints(LineMidpointState& lineMidpointState, InlineIterator& lBreak)
hyattfe99c872003-07-31 22:25:29 +0000372{
373 // Check to see if our last midpoint is a start point beyond the line break. If so,
hyattdca76e92005-11-02 08:52:50 +0000374 // shave it off the list, and shave off a trailing space if the previous end point doesn't
375 // preserve whitespace.
eric@webkit.org8c25a592011-03-29 13:18:11 +0000376 if (lBreak.m_obj && lineMidpointState.numMidpoints && !(lineMidpointState.numMidpoints % 2)) {
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +0000377 InlineIterator* midpoints = lineMidpointState.midpoints.data();
378 InlineIterator& endpoint = midpoints[lineMidpointState.numMidpoints - 2];
379 const InlineIterator& startpoint = midpoints[lineMidpointState.numMidpoints - 1];
mitz@apple.com15035e62008-07-05 20:44:44 +0000380 InlineIterator currpoint = endpoint;
hyattfe99c872003-07-31 22:25:29 +0000381 while (!currpoint.atEnd() && currpoint != startpoint && currpoint != lBreak)
mitz@apple.com1a301772008-03-11 18:30:36 +0000382 currpoint.increment();
hyattfe99c872003-07-31 22:25:29 +0000383 if (currpoint == lBreak) {
384 // We hit the line break before the start point. Shave off the start point.
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +0000385 lineMidpointState.numMidpoints--;
eric@webkit.org8c25a592011-03-29 13:18:11 +0000386 if (endpoint.m_obj->style()->collapseWhiteSpace())
eric@webkit.org86a865a2011-03-29 15:30:41 +0000387 endpoint.m_pos--;
hyattfe99c872003-07-31 22:25:29 +0000388 }
eric@webkit.org060caf62011-05-03 22:11:39 +0000389 }
hyattfe99c872003-07-31 22:25:29 +0000390}
391
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +0000392// Don't call this directly. Use one of the descriptive helper functions below.
393static void deprecatedAddMidpoint(LineMidpointState& lineMidpointState, const InlineIterator& midpoint)
hyatt85586af2003-02-19 23:22:42 +0000394{
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +0000395 if (lineMidpointState.midpoints.size() <= lineMidpointState.numMidpoints)
396 lineMidpointState.midpoints.grow(lineMidpointState.numMidpoints + 10);
hyatt85586af2003-02-19 23:22:42 +0000397
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +0000398 InlineIterator* midpoints = lineMidpointState.midpoints.data();
399 midpoints[lineMidpointState.numMidpoints++] = midpoint;
hyatt85586af2003-02-19 23:22:42 +0000400}
401
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +0000402static inline void startIgnoringSpaces(LineMidpointState& lineMidpointState, const InlineIterator& midpoint)
403{
404 ASSERT(!(lineMidpointState.numMidpoints % 2));
405 deprecatedAddMidpoint(lineMidpointState, midpoint);
406}
407
408static inline void stopIgnoringSpaces(LineMidpointState& lineMidpointState, const InlineIterator& midpoint)
409{
410 ASSERT(lineMidpointState.numMidpoints % 2);
411 deprecatedAddMidpoint(lineMidpointState, midpoint);
412}
413
414// When ignoring spaces, this needs to be called for objects that need line boxes such as RenderInlines or
415// hard line breaks to ensure that they're not ignored.
416static inline void ensureLineBoxInsideIgnoredSpaces(LineMidpointState& lineMidpointState, RenderObject* renderer)
417{
418 InlineIterator midpoint(0, renderer, 0);
419 stopIgnoringSpaces(lineMidpointState, midpoint);
420 startIgnoringSpaces(lineMidpointState, midpoint);
421}
422
423// Adding a pair of midpoints before a character will split it out into a new line box.
424static inline void ensureCharacterGetsLineBox(LineMidpointState& lineMidpointState, InlineIterator& textParagraphSeparator)
425{
426 InlineIterator midpoint(0, textParagraphSeparator.m_obj, textParagraphSeparator.m_pos);
427 startIgnoringSpaces(lineMidpointState, InlineIterator(0, textParagraphSeparator.m_obj, textParagraphSeparator.m_pos - 1));
428 stopIgnoringSpaces(lineMidpointState, InlineIterator(0, textParagraphSeparator.m_obj, textParagraphSeparator.m_pos));
429}
430
eric@webkit.org5bee2942011-04-08 02:12:31 +0000431static inline BidiRun* createRun(int start, int end, RenderObject* obj, InlineBidiResolver& resolver)
432{
433 return new (obj->renderArena()) BidiRun(start, end, obj, resolver.context(), resolver.dir());
434}
435
436void RenderBlock::appendRunsForObject(BidiRunList<BidiRun>& runs, int start, int end, RenderObject* obj, InlineBidiResolver& resolver)
hyatt33f8d492002-11-12 21:44:52 +0000437{
leviw@chromium.orgd8df17d2012-05-24 21:47:47 +0000438 if (start > end || shouldSkipCreatingRunsForObject(obj))
hyatteb003b82002-11-15 22:35:10 +0000439 return;
hyatt85586af2003-02-19 23:22:42 +0000440
hyatt@apple.comb3466af2009-06-13 06:04:40 +0000441 LineMidpointState& lineMidpointState = resolver.midpointState();
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +0000442 bool haveNextMidpoint = (lineMidpointState.currentMidpoint < lineMidpointState.numMidpoints);
mitz@apple.com15035e62008-07-05 20:44:44 +0000443 InlineIterator nextMidpoint;
hyatt85586af2003-02-19 23:22:42 +0000444 if (haveNextMidpoint)
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +0000445 nextMidpoint = lineMidpointState.midpoints[lineMidpointState.currentMidpoint];
446 if (lineMidpointState.betweenMidpoints) {
eric@webkit.org8c25a592011-03-29 13:18:11 +0000447 if (!(haveNextMidpoint && nextMidpoint.m_obj == obj))
hyatt33f8d492002-11-12 21:44:52 +0000448 return;
eric@webkit.org060caf62011-05-03 22:11:39 +0000449 // This is a new start point. Stop ignoring objects and
hyatt33f8d492002-11-12 21:44:52 +0000450 // adjust our start.
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +0000451 lineMidpointState.betweenMidpoints = false;
eric@webkit.org86a865a2011-03-29 15:30:41 +0000452 start = nextMidpoint.m_pos;
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +0000453 lineMidpointState.currentMidpoint++;
hyatt33f8d492002-11-12 21:44:52 +0000454 if (start < end)
eric@webkit.org5bee2942011-04-08 02:12:31 +0000455 return appendRunsForObject(runs, start, end, obj, resolver);
mitz@apple.com15035e62008-07-05 20:44:44 +0000456 } else {
eric@webkit.org8c25a592011-03-29 13:18:11 +0000457 if (!haveNextMidpoint || (obj != nextMidpoint.m_obj)) {
eric@webkit.org5bee2942011-04-08 02:12:31 +0000458 runs.addRun(createRun(start, end, obj, resolver));
hyatt33f8d492002-11-12 21:44:52 +0000459 return;
460 }
mitz@apple.com15035e62008-07-05 20:44:44 +0000461
hyatt78b85132004-03-29 20:07:45 +0000462 // An end midpoint has been encountered within our object. We
hyatt33f8d492002-11-12 21:44:52 +0000463 // need to go ahead and append a run with our endpoint.
eric@webkit.org86a865a2011-03-29 15:30:41 +0000464 if (static_cast<int>(nextMidpoint.m_pos + 1) <= end) {
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +0000465 lineMidpointState.betweenMidpoints = true;
466 lineMidpointState.currentMidpoint++;
eric@webkit.org86a865a2011-03-29 15:30:41 +0000467 if (nextMidpoint.m_pos != UINT_MAX) { // UINT_MAX means stop at the object and don't include any of it.
468 if (static_cast<int>(nextMidpoint.m_pos + 1) > start)
eric@webkit.org5bee2942011-04-08 02:12:31 +0000469 runs.addRun(createRun(start, nextMidpoint.m_pos + 1, obj, resolver));
470 return appendRunsForObject(runs, nextMidpoint.m_pos + 1, end, obj, resolver);
hyattc64f9fc2003-03-14 01:25:59 +0000471 }
mitz@apple.com15035e62008-07-05 20:44:44 +0000472 } else
eric@webkit.org5bee2942011-04-08 02:12:31 +0000473 runs.addRun(createRun(start, end, obj, resolver));
hyatt33f8d492002-11-12 21:44:52 +0000474 }
475}
476
hyatt@apple.comc92b7352009-02-12 01:35:08 +0000477static inline InlineBox* createInlineBoxForRenderer(RenderObject* obj, bool isRootLineBox, bool isOnlyRun = false)
478{
479 if (isRootLineBox)
eric@webkit.org49b9d952009-07-03 01:29:07 +0000480 return toRenderBlock(obj)->createAndAppendRootInlineBox();
eric@webkit.org060caf62011-05-03 22:11:39 +0000481
hyatt@apple.comc92b7352009-02-12 01:35:08 +0000482 if (obj->isText()) {
483 InlineTextBox* textBox = toRenderText(obj)->createInlineTextBox();
484 // We only treat a box as text for a <br> if we are on a line by ourself or in strict mode
485 // (Note the use of strict mode. In "almost strict" mode, we don't treat the box for <br> as text.)
486 if (obj->isBR())
hyatt@apple.comce8ee2a2010-08-27 20:29:34 +0000487 textBox->setIsText(isOnlyRun || obj->document()->inNoQuirksMode());
hyatt@apple.comc92b7352009-02-12 01:35:08 +0000488 return textBox;
489 }
eric@webkit.org060caf62011-05-03 22:11:39 +0000490
hyatt@apple.comc92b7352009-02-12 01:35:08 +0000491 if (obj->isBox())
492 return toRenderBox(obj)->createInlineBox();
eric@webkit.org060caf62011-05-03 22:11:39 +0000493
eric@webkit.org49b9d952009-07-03 01:29:07 +0000494 return toRenderInline(obj)->createAndAppendInlineFlowBox();
hyatt@apple.comc92b7352009-02-12 01:35:08 +0000495}
496
esprehn@chromium.org7745ffb2013-02-19 21:51:19 +0000497// FIXME: Don't let counters mark themselves as needing pref width recalcs during layout
498// so we don't need this hack.
499static inline void updateCounterIfNeeded(RenderText* o)
500{
501 if (!o->preferredLogicalWidthsDirty() || !o->isCounter())
502 return;
503 toRenderCounter(o)->updateCounter();
504}
505
hyatt@apple.comc92b7352009-02-12 01:35:08 +0000506static inline void dirtyLineBoxesForRenderer(RenderObject* o, bool fullLayout)
507{
508 if (o->isText()) {
commit-queue@webkit.orgd639fb72012-09-01 19:46:16 +0000509 RenderText* renderText = toRenderText(o);
esprehn@chromium.org7745ffb2013-02-19 21:51:19 +0000510 updateCounterIfNeeded(renderText);
commit-queue@webkit.orgd639fb72012-09-01 19:46:16 +0000511 renderText->dirtyLineBoxes(fullLayout);
hyatt@apple.comc92b7352009-02-12 01:35:08 +0000512 } else
513 toRenderInline(o)->dirtyLineBoxes(fullLayout);
514}
515
xji@chromium.orgb0ad6eb822011-02-01 20:02:06 +0000516static bool parentIsConstructedOrHaveNext(InlineFlowBox* parentBox)
517{
518 do {
519 if (parentBox->isConstructed() || parentBox->nextOnLine())
520 return true;
521 parentBox = parentBox->parent();
522 } while (parentBox);
523 return false;
524}
525
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +0000526InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj, const LineInfo& lineInfo, InlineBox* childBox, bool startNewSegment)
hyattffe78712003-02-11 01:59:29 +0000527{
528 // See if we have an unconstructed line box for this object that is also
529 // the last item on the line.
hyatt1d5d87b2007-04-24 04:55:54 +0000530 unsigned lineDepth = 1;
hyatt1d5d87b2007-04-24 04:55:54 +0000531 InlineFlowBox* parentBox = 0;
532 InlineFlowBox* result = 0;
hyatt@apple.com7d4066a2011-03-29 17:56:09 +0000533 bool hasDefaultLineBoxContain = style()->lineBoxContain() == RenderStyle::initialLineBoxContain();
hyatt1d5d87b2007-04-24 04:55:54 +0000534 do {
inferno@chromium.org14b04142013-02-04 18:43:03 +0000535 ASSERT_WITH_SECURITY_IMPLICATION(obj->isRenderInline() || obj == this);
eric@webkit.org060caf62011-05-03 22:11:39 +0000536
hyatt@apple.coma61b8a32011-04-06 18:20:52 +0000537 RenderInline* inlineFlow = (obj != this) ? toRenderInline(obj) : 0;
538
hyatt1d5d87b2007-04-24 04:55:54 +0000539 // Get the last box we made for this render object.
hyatt@apple.coma61b8a32011-04-06 18:20:52 +0000540 parentBox = inlineFlow ? inlineFlow->lastLineBox() : toRenderBlock(obj)->lastLineBox();
hyattffe78712003-02-11 01:59:29 +0000541
xji@chromium.orgb0ad6eb822011-02-01 20:02:06 +0000542 // If this box or its ancestor is constructed then it is from a previous line, and we need
543 // to make a new box for our line. If this box or its ancestor is unconstructed but it has
hyatt1d5d87b2007-04-24 04:55:54 +0000544 // something following it on the line, then we know we have to make a new box
545 // as well. In this situation our inline has actually been split in two on
546 // the same line (this can happen with very fancy language mixtures).
547 bool constructedNewBox = false;
hyatt@apple.coma61b8a32011-04-06 18:20:52 +0000548 bool allowedToConstructNewBox = !hasDefaultLineBoxContain || !inlineFlow || inlineFlow->alwaysCreateLineBoxes();
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +0000549 bool mustCreateBoxesToRoot = startNewSegment && !(parentBox && parentBox->isRootInlineBox());
550 bool canUseExistingParentBox = parentBox && !parentIsConstructedOrHaveNext(parentBox) && !mustCreateBoxesToRoot;
hyatt@apple.coma61b8a32011-04-06 18:20:52 +0000551 if (allowedToConstructNewBox && !canUseExistingParentBox) {
hyatt1d5d87b2007-04-24 04:55:54 +0000552 // We need to make a new box for this render object. Once
553 // made, we need to place it at the end of the current line.
hyatt@apple.comc92b7352009-02-12 01:35:08 +0000554 InlineBox* newBox = createInlineBoxForRenderer(obj, obj == this);
inferno@chromium.org14b04142013-02-04 18:43:03 +0000555 ASSERT_WITH_SECURITY_IMPLICATION(newBox->isInlineFlowBox());
jchaffraix@webkit.org8f1781d2011-06-24 21:22:54 +0000556 parentBox = toInlineFlowBox(newBox);
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +0000557 parentBox->setFirstLineStyleBit(lineInfo.isFirstLine());
hyatt@apple.com2a5eb212011-03-22 23:21:54 +0000558 parentBox->setIsHorizontal(isHorizontalWritingMode());
hyatt@apple.com7d4066a2011-03-29 17:56:09 +0000559 if (!hasDefaultLineBoxContain)
560 parentBox->clearDescendantsHaveSameLineHeightAndBaseline();
hyatt1d5d87b2007-04-24 04:55:54 +0000561 constructedNewBox = true;
562 }
mitz@apple.come1364202008-02-28 01:06:41 +0000563
hyatt@apple.coma61b8a32011-04-06 18:20:52 +0000564 if (constructedNewBox || canUseExistingParentBox) {
565 if (!result)
566 result = parentBox;
hyatt1d5d87b2007-04-24 04:55:54 +0000567
hyatt@apple.coma61b8a32011-04-06 18:20:52 +0000568 // If we have hit the block itself, then |box| represents the root
569 // inline box for the line, and it doesn't have to be appended to any parent
570 // inline.
571 if (childBox)
572 parentBox->addToLine(childBox);
mitz@apple.come1364202008-02-28 01:06:41 +0000573
hyatt@apple.coma61b8a32011-04-06 18:20:52 +0000574 if (!constructedNewBox || obj == this)
575 break;
mitz@apple.come1364202008-02-28 01:06:41 +0000576
eric@webkit.org060caf62011-05-03 22:11:39 +0000577 childBox = parentBox;
hyatt@apple.coma61b8a32011-04-06 18:20:52 +0000578 }
mitz@apple.come1364202008-02-28 01:06:41 +0000579
hyatt1d5d87b2007-04-24 04:55:54 +0000580 // If we've exceeded our line depth, then jump straight to the root and skip all the remaining
581 // intermediate inline flows.
582 obj = (++lineDepth >= cMaxLineDepth) ? this : obj->parent();
hyattffe78712003-02-11 01:59:29 +0000583
hyatt1d5d87b2007-04-24 04:55:54 +0000584 } while (true);
585
586 return result;
hyattffe78712003-02-11 01:59:29 +0000587}
588
msaboff@apple.com776c286c72012-10-15 16:56:29 +0000589template <typename CharacterType>
590static inline bool endsWithASCIISpaces(const CharacterType* characters, unsigned pos, unsigned end)
591{
592 while (isASCIISpace(characters[pos])) {
593 pos++;
594 if (pos >= end)
595 return true;
596 }
597 return false;
598}
599
yael.aharon@nokia.com15c605d2011-04-14 05:35:54 +0000600static bool reachedEndOfTextRenderer(const BidiRunList<BidiRun>& bidiRuns)
hyattffe78712003-02-11 01:59:29 +0000601{
yael.aharon@nokia.com15c605d2011-04-14 05:35:54 +0000602 BidiRun* run = bidiRuns.logicallyLastRun();
603 if (!run)
604 return true;
msaboff@apple.com776c286c72012-10-15 16:56:29 +0000605 unsigned pos = run->stop();
yael.aharon@nokia.com15c605d2011-04-14 05:35:54 +0000606 RenderObject* r = run->m_object;
607 if (!r->isText() || r->isBR())
608 return false;
609 RenderText* renderText = toRenderText(r);
msaboff@apple.com776c286c72012-10-15 16:56:29 +0000610 unsigned length = renderText->textLength();
611 if (pos >= length)
yael.aharon@nokia.com15c605d2011-04-14 05:35:54 +0000612 return true;
613
msaboff@apple.com776c286c72012-10-15 16:56:29 +0000614 if (renderText->is8Bit())
615 return endsWithASCIISpaces(renderText->characters8(), pos, length);
616 return endsWithASCIISpaces(renderText->characters16(), pos, length);
yael.aharon@nokia.com15c605d2011-04-14 05:35:54 +0000617}
618
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +0000619RootInlineBox* RenderBlock::constructLine(BidiRunList<BidiRun>& bidiRuns, const LineInfo& lineInfo)
yael.aharon@nokia.com15c605d2011-04-14 05:35:54 +0000620{
621 ASSERT(bidiRuns.firstRun());
hyattffe78712003-02-11 01:59:29 +0000622
inferno@chromium.orge29694f2010-10-07 22:00:02 +0000623 bool rootHasSelectedChildren = false;
hyattffe78712003-02-11 01:59:29 +0000624 InlineFlowBox* parentBox = 0;
robert@webkit.org8cbab142011-12-30 20:58:29 +0000625 int runCount = bidiRuns.runCount() - lineInfo.runsFromLeadingWhitespace();
yael.aharon@nokia.com15c605d2011-04-14 05:35:54 +0000626 for (BidiRun* r = bidiRuns.firstRun(); r; r = r->next()) {
hyattffe78712003-02-11 01:59:29 +0000627 // Create a box for our object.
robert@webkit.org8cbab142011-12-30 20:58:29 +0000628 bool isOnlyRun = (runCount == 1);
629 if (runCount == 2 && !r->m_object->isListMarker())
yael.aharon@nokia.com15c605d2011-04-14 05:35:54 +0000630 isOnlyRun = (!style()->isLeftToRightDirection() ? bidiRuns.lastRun() : bidiRuns.firstRun())->m_object->isListMarker();
mitz@apple.come1364202008-02-28 01:06:41 +0000631
robert@webkit.org56e5a9f2012-02-17 21:10:42 +0000632 if (lineInfo.isEmpty())
633 continue;
634
hyatt@apple.comc92b7352009-02-12 01:35:08 +0000635 InlineBox* box = createInlineBoxForRenderer(r->m_object, false, isOnlyRun);
mitz@apple.com576e84e2008-04-24 19:09:48 +0000636 r->m_box = box;
637
mitz@apple.comaa6ce3d2009-04-10 01:00:20 +0000638 ASSERT(box);
639 if (!box)
640 continue;
hyattffe78712003-02-11 01:59:29 +0000641
inferno@chromium.orge29694f2010-10-07 22:00:02 +0000642 if (!rootHasSelectedChildren && box->renderer()->selectionState() != RenderObject::SelectionNone)
643 rootHasSelectedChildren = true;
644
mitz@apple.comaa6ce3d2009-04-10 01:00:20 +0000645 // If we have no parent box yet, or if the run is not simply a sibling,
646 // then we need to construct inline boxes as necessary to properly enclose the
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +0000647 // run's inline box. Segments can only be siblings at the root level, as
648 // they are positioned separately.
649#if ENABLE(CSS_EXCLUSIONS)
650 bool runStartsSegment = r->m_startsSegment;
651#else
652 bool runStartsSegment = false;
653#endif
654 if (!parentBox || parentBox->renderer() != r->m_object->parent() || runStartsSegment)
mitz@apple.comaa6ce3d2009-04-10 01:00:20 +0000655 // Create new inline boxes all the way back to the appropriate insertion point.
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +0000656 parentBox = createLineBoxes(r->m_object->parent(), lineInfo, box, runStartsSegment);
hyatt@apple.com7d4066a2011-03-29 17:56:09 +0000657 else {
658 // Append the inline box to this line.
659 parentBox->addToLine(box);
660 }
mitz@apple.com576e84e2008-04-24 19:09:48 +0000661
macpherson@chromium.org258babf2011-06-10 06:20:58 +0000662 bool visuallyOrdered = r->m_object->style()->rtlOrdering() == VisualOrder;
xji@chromium.org6b0c0172011-02-14 19:21:12 +0000663 box->setBidiLevel(r->level());
mitz@apple.comaa6ce3d2009-04-10 01:00:20 +0000664
665 if (box->isInlineTextBox()) {
jchaffraix@webkit.org8f1781d2011-06-24 21:22:54 +0000666 InlineTextBox* text = toInlineTextBox(box);
mitz@apple.comaa6ce3d2009-04-10 01:00:20 +0000667 text->setStart(r->m_start);
668 text->setLen(r->m_stop - r->m_start);
rniwa@webkit.org296fcae2012-03-29 09:48:42 +0000669 text->setDirOverride(r->dirOverride(visuallyOrdered));
mitz@apple.comb2107652010-06-21 16:54:52 +0000670 if (r->m_hasHyphen)
671 text->setHasHyphen(true);
hyatt0c3a9862004-02-23 21:26:26 +0000672 }
hyattffe78712003-02-11 01:59:29 +0000673 }
674
675 // We should have a root inline box. It should be unconstructed and
676 // be the last continuation of our line list.
ggarenf9f32ae2007-03-26 20:08:53 +0000677 ASSERT(lastLineBox() && !lastLineBox()->isConstructed());
hyattffe78712003-02-11 01:59:29 +0000678
inferno@chromium.orge29694f2010-10-07 22:00:02 +0000679 // Set the m_selectedChildren flag on the root inline box if one of the leaf inline box
680 // from the bidi runs walk above has a selection state.
681 if (rootHasSelectedChildren)
682 lastLineBox()->root()->setHasSelectedChildren(true);
683
hyattffe78712003-02-11 01:59:29 +0000684 // Set bits on our inline flow boxes that indicate which sides should
685 // paint borders/margins/padding. This knowledge will ultimately be used when
686 // we determine the horizontal positions and widths of all the inline boxes on
687 // the line.
yael.aharon@nokia.com15c605d2011-04-14 05:35:54 +0000688 bool isLogicallyLastRunWrapped = bidiRuns.logicallyLastRun()->m_object && bidiRuns.logicallyLastRun()->m_object->isText() ? !reachedEndOfTextRenderer(bidiRuns) : true;
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +0000689 lastLineBox()->determineSpacingForFlowBoxes(lineInfo.isLastLine(), isLogicallyLastRunWrapped, bidiRuns.logicallyLastRun()->m_object);
hyattffe78712003-02-11 01:59:29 +0000690
691 // Now mark the line boxes as being constructed.
692 lastLineBox()->setConstructed();
693
694 // Return the last line.
hyatt0c3a9862004-02-23 21:26:26 +0000695 return lastRootBox();
hyattffe78712003-02-11 01:59:29 +0000696}
697
mitz@apple.com390fa322011-02-24 23:07:06 +0000698ETextAlign RenderBlock::textAlignmentForLine(bool endsWithSoftBreak) const
699{
700 ETextAlign alignment = style()->textAlign();
701 if (!endsWithSoftBreak && alignment == JUSTIFY)
rniwa@webkit.orgaf7f7a42012-06-15 21:54:44 +0000702 alignment = TASTART;
mitz@apple.com390fa322011-02-24 23:07:06 +0000703
704 return alignment;
705}
706
rniwa@webkit.orgcda6dbd2011-03-28 09:19:50 +0000707static void updateLogicalWidthForLeftAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth)
708{
709 // The direction of the block should determine what happens with wide lines.
710 // In particular with RTL blocks, wide lines should still spill out to the left.
711 if (isLeftToRightDirection) {
712 if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun)
713 trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth));
714 return;
715 }
716
717 if (trailingSpaceRun)
718 trailingSpaceRun->m_box->setLogicalWidth(0);
719 else if (totalLogicalWidth > availableLogicalWidth)
720 logicalLeft -= (totalLogicalWidth - availableLogicalWidth);
721}
722
723static void updateLogicalWidthForRightAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth)
724{
725 // Wide lines spill out of the block based off direction.
726 // So even if text-align is right, if direction is LTR, wide lines should overflow out of the right
727 // side of the block.
728 if (isLeftToRightDirection) {
729 if (trailingSpaceRun) {
730 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
731 trailingSpaceRun->m_box->setLogicalWidth(0);
732 }
733 if (totalLogicalWidth < availableLogicalWidth)
734 logicalLeft += availableLogicalWidth - totalLogicalWidth;
735 return;
736 }
737
738 if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun) {
739 trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth));
740 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
741 } else
742 logicalLeft += availableLogicalWidth - totalLogicalWidth;
743}
744
745static void updateLogicalWidthForCenterAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth)
746{
747 float trailingSpaceWidth = 0;
748 if (trailingSpaceRun) {
749 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
750 trailingSpaceWidth = min(trailingSpaceRun->m_box->logicalWidth(), (availableLogicalWidth - totalLogicalWidth + 1) / 2);
751 trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceWidth));
752 }
753 if (isLeftToRightDirection)
754 logicalLeft += max<float>((availableLogicalWidth - totalLogicalWidth) / 2, 0);
755 else
756 logicalLeft += totalLogicalWidth > availableLogicalWidth ? (availableLogicalWidth - totalLogicalWidth) : (availableLogicalWidth - totalLogicalWidth) / 2 - trailingSpaceWidth;
757}
758
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000759void RenderBlock::setMarginsForRubyRun(BidiRun* run, RenderRubyRun* renderer, RenderObject* previousObject, const LineInfo& lineInfo)
760{
761 int startOverhang;
762 int endOverhang;
763 RenderObject* nextObject = 0;
764 for (BidiRun* runWithNextObject = run->next(); runWithNextObject; runWithNextObject = runWithNextObject->next()) {
simon.fraser@apple.com2f071852012-06-25 00:11:30 +0000765 if (!runWithNextObject->m_object->isOutOfFlowPositioned() && !runWithNextObject->m_box->isLineBreak()) {
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000766 nextObject = runWithNextObject->m_object;
767 break;
768 }
769 }
770 renderer->getOverhang(lineInfo.isFirstLine(), renderer->style()->isLeftToRightDirection() ? previousObject : nextObject, renderer->style()->isLeftToRightDirection() ? nextObject : previousObject, startOverhang, endOverhang);
771 setMarginStartForChild(renderer, -startOverhang);
772 setMarginEndForChild(renderer, -endOverhang);
773}
774
commit-queue@webkit.orge60bb902011-09-08 19:18:43 +0000775static inline float measureHyphenWidth(RenderText* renderer, const Font& font)
776{
777 RenderStyle* style = renderer->style();
778 return font.width(RenderBlock::constructTextRun(renderer, font, style->hyphenString().string(), style));
779}
780
enrica@apple.com885c84d2012-10-10 05:48:51 +0000781class WordMeasurement {
782public:
783 WordMeasurement()
784 : renderer(0)
785 , width(0)
786 , startOffset(0)
787 , endOffset(0)
788 {
789 }
790
791 RenderText* renderer;
792 float width;
793 int startOffset;
794 int endOffset;
795 HashSet<const SimpleFontData*> fallbackFonts;
796};
797
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000798static inline void setLogicalWidthForTextRun(RootInlineBox* lineBox, BidiRun* run, RenderText* renderer, float xPos, const LineInfo& lineInfo,
enrica@apple.com885c84d2012-10-10 05:48:51 +0000799 GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache, WordMeasurements& wordMeasurements)
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000800{
801 HashSet<const SimpleFontData*> fallbackFonts;
802 GlyphOverflow glyphOverflow;
803
enrica@apple.com885c84d2012-10-10 05:48:51 +0000804 const Font& font = renderer->style(lineInfo.isFirstLine())->font();
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000805 // Always compute glyph overflow if the block's line-box-contain value is "glyphs".
806 if (lineBox->fitsToGlyphs()) {
807 // If we don't stick out of the root line's font box, then don't bother computing our glyph overflow. This optimization
808 // will keep us from computing glyph bounds in nearly all cases.
809 bool includeRootLine = lineBox->includesRootLineBoxFontOrLeading();
810 int baselineShift = lineBox->verticalPositionForBox(run->m_box, verticalPositionCache);
enrica@apple.com885c84d2012-10-10 05:48:51 +0000811 int rootDescent = includeRootLine ? font.fontMetrics().descent() : 0;
812 int rootAscent = includeRootLine ? font.fontMetrics().ascent() : 0;
813 int boxAscent = font.fontMetrics().ascent() - baselineShift;
814 int boxDescent = font.fontMetrics().descent() + baselineShift;
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000815 if (boxAscent > rootDescent || boxDescent > rootAscent)
816 glyphOverflow.computeBounds = true;
817 }
818
leviw@chromium.orgd32486e2012-03-16 10:52:56 +0000819 LayoutUnit hyphenWidth = 0;
jchaffraix@webkit.org8f1781d2011-06-24 21:22:54 +0000820 if (toInlineTextBox(run->m_box)->hasHyphen()) {
zimmermann@webkit.org8a7e7ff2011-05-24 15:27:36 +0000821 const Font& font = renderer->style(lineInfo.isFirstLine())->font();
commit-queue@webkit.orge60bb902011-09-08 19:18:43 +0000822 hyphenWidth = measureHyphenWidth(renderer, font);
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000823 }
enrica@apple.com885c84d2012-10-10 05:48:51 +0000824 float measuredWidth = 0;
825
enrica@apple.com885c84d2012-10-10 05:48:51 +0000826 bool kerningIsEnabled = font.typesettingFeatures() & Kerning;
leviw@chromium.orgd70f4cc2013-03-28 21:03:44 +0000827 bool canUseSimpleFontCodePath = renderer->canUseSimpleFontCodePath();
enrica@apple.com885c84d2012-10-10 05:48:51 +0000828
829 // Since we don't cache glyph overflows, we need to re-measure the run if
830 // the style is linebox-contain: glyph.
831
leviw@chromium.orgd70f4cc2013-03-28 21:03:44 +0000832 if (!lineBox->fitsToGlyphs() && canUseSimpleFontCodePath) {
enrica@apple.com885c84d2012-10-10 05:48:51 +0000833 int lastEndOffset = run->m_start;
834 for (size_t i = 0, size = wordMeasurements.size(); i < size && lastEndOffset < run->m_stop; ++i) {
835 const WordMeasurement& wordMeasurement = wordMeasurements[i];
836 if (wordMeasurement.width <=0 || wordMeasurement.startOffset == wordMeasurement.endOffset)
837 continue;
838 if (wordMeasurement.renderer != renderer || wordMeasurement.startOffset != lastEndOffset || wordMeasurement.endOffset > run->m_stop)
839 continue;
840
841 lastEndOffset = wordMeasurement.endOffset;
842 if (kerningIsEnabled && lastEndOffset == run->m_stop) {
dino@apple.com7c50e7c2013-03-18 18:01:05 +0000843 int wordLength = lastEndOffset - wordMeasurement.startOffset;
844 measuredWidth += renderer->width(wordMeasurement.startOffset, wordLength, xPos, lineInfo.isFirstLine());
845 if (i > 0 && wordLength == 1 && renderer->characterAt(wordMeasurement.startOffset) == ' ')
enrica@apple.com885c84d2012-10-10 05:48:51 +0000846 measuredWidth += renderer->style()->wordSpacing();
847 } else
848 measuredWidth += wordMeasurement.width;
849 if (!wordMeasurement.fallbackFonts.isEmpty()) {
850 HashSet<const SimpleFontData*>::const_iterator end = wordMeasurement.fallbackFonts.end();
851 for (HashSet<const SimpleFontData*>::const_iterator it = wordMeasurement.fallbackFonts.begin(); it != end; ++it)
852 fallbackFonts.add(*it);
853 }
854 }
855 if (measuredWidth && lastEndOffset != run->m_stop) {
856 // If we don't have enough cached data, we'll measure the run again.
857 measuredWidth = 0;
858 fallbackFonts.clear();
859 }
860 }
enrica@apple.com885c84d2012-10-10 05:48:51 +0000861
862 if (!measuredWidth)
863 measuredWidth = renderer->width(run->m_start, run->m_stop - run->m_start, xPos, lineInfo.isFirstLine(), &fallbackFonts, &glyphOverflow);
864
865 run->m_box->setLogicalWidth(measuredWidth + hyphenWidth);
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000866 if (!fallbackFonts.isEmpty()) {
867 ASSERT(run->m_box->isText());
caio.oliveira@openbossa.org4c11ee02012-03-29 18:48:23 +0000868 GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.add(toInlineTextBox(run->m_box), make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).iterator;
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000869 ASSERT(it->value.first.isEmpty());
870 copyToVector(fallbackFonts, it->value.first);
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000871 run->m_box->parent()->clearDescendantsHaveSameLineHeightAndBaseline();
872 }
873 if ((glyphOverflow.top || glyphOverflow.bottom || glyphOverflow.left || glyphOverflow.right)) {
874 ASSERT(run->m_box->isText());
caio.oliveira@openbossa.org4c11ee02012-03-29 18:48:23 +0000875 GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.add(toInlineTextBox(run->m_box), make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).iterator;
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000876 it->value.second = glyphOverflow;
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000877 run->m_box->clearKnownToHaveNoOverflow();
878 }
879}
880
881static inline void computeExpansionForJustifiedText(BidiRun* firstRun, BidiRun* trailingSpaceRun, Vector<unsigned, 16>& expansionOpportunities, unsigned expansionOpportunityCount, float& totalLogicalWidth, float availableLogicalWidth)
882{
mitz@apple.comc7a1a512011-05-08 16:27:31 +0000883 if (!expansionOpportunityCount || availableLogicalWidth <= totalLogicalWidth)
884 return;
885
886 size_t i = 0;
887 for (BidiRun* r = firstRun; r; r = r->next()) {
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +0000888#if ENABLE(CSS_EXCLUSIONS)
889 // This method is called once per segment, do not move past the current segment.
890 if (r->m_startsSegment)
891 break;
892#endif
mitz@apple.comc7a1a512011-05-08 16:27:31 +0000893 if (!r->m_box || r == trailingSpaceRun)
894 continue;
895
896 if (r->m_object->isText()) {
897 unsigned opportunitiesInRun = expansionOpportunities[i++];
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000898
mitz@apple.comc7a1a512011-05-08 16:27:31 +0000899 ASSERT(opportunitiesInRun <= expansionOpportunityCount);
900
901 // Only justify text if whitespace is collapsed.
902 if (r->m_object->style()->collapseWhiteSpace()) {
jchaffraix@webkit.org8f1781d2011-06-24 21:22:54 +0000903 InlineTextBox* textBox = toInlineTextBox(r->m_box);
mitz@apple.comc7a1a512011-05-08 16:27:31 +0000904 int expansion = (availableLogicalWidth - totalLogicalWidth) * opportunitiesInRun / expansionOpportunityCount;
905 textBox->setExpansion(expansion);
906 totalLogicalWidth += expansion;
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000907 }
mitz@apple.comc7a1a512011-05-08 16:27:31 +0000908 expansionOpportunityCount -= opportunitiesInRun;
909 if (!expansionOpportunityCount)
910 break;
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000911 }
912 }
913}
914
robert@webkit.orgfc7763c2011-09-03 18:28:57 +0000915void RenderBlock::updateLogicalWidthForAlignment(const ETextAlign& textAlign, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float& availableLogicalWidth, int expansionOpportunityCount)
916{
917 // Armed with the total width of the line (without justification),
918 // we now examine our text-align property in order to determine where to position the
919 // objects horizontally. The total width of the line can be increased if we end up
920 // justifying text.
921 switch (textAlign) {
922 case LEFT:
923 case WEBKIT_LEFT:
924 updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
925 break;
rniwa@webkit.orgaf7f7a42012-06-15 21:54:44 +0000926 case RIGHT:
927 case WEBKIT_RIGHT:
928 updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
929 break;
930 case CENTER:
931 case WEBKIT_CENTER:
932 updateLogicalWidthForCenterAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
933 break;
robert@webkit.orgfc7763c2011-09-03 18:28:57 +0000934 case JUSTIFY:
935 adjustInlineDirectionLineBounds(expansionOpportunityCount, logicalLeft, availableLogicalWidth);
936 if (expansionOpportunityCount) {
937 if (trailingSpaceRun) {
938 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
939 trailingSpaceRun->m_box->setLogicalWidth(0);
940 }
941 break;
942 }
rniwa@webkit.orgaf7f7a42012-06-15 21:54:44 +0000943 // Fall through
robert@webkit.orgfc7763c2011-09-03 18:28:57 +0000944 case TASTART:
945 if (style()->isLeftToRightDirection())
946 updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
947 else
948 updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
949 break;
950 case TAEND:
951 if (style()->isLeftToRightDirection())
952 updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
953 else
954 updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
955 break;
956 }
957}
958
commit-queue@webkit.orgab781b02013-04-03 01:32:24 +0000959static IndentTextOrNot requiresIndent(bool isFirstLine, bool isAfterHardLineBreak, RenderStyle* style)
960{
961 if (isFirstLine)
962 return IndentText;
963#if ENABLE(CSS3_TEXT)
964 if (isAfterHardLineBreak && style->textIndentLine() == TextIndentEachLine)
965 return IndentText;
966#else
967 UNUSED_PARAM(isAfterHardLineBreak);
968 UNUSED_PARAM(style);
969#endif
970 return DoNotIndentText;
971}
972
973static void updateLogicalInlinePositions(RenderBlock* block, float& lineLogicalLeft, float& lineLogicalRight, float& availableLogicalWidth, bool firstLine, IndentTextOrNot shouldIndentText, LayoutUnit boxLogicalHeight)
robert@webkit.org0903cf52012-12-11 18:14:16 +0000974{
975 LayoutUnit lineLogicalHeight = logicalHeightForLine(block, firstLine, boxLogicalHeight);
commit-queue@webkit.orgab781b02013-04-03 01:32:24 +0000976 lineLogicalLeft = block->pixelSnappedLogicalLeftOffsetForLine(block->logicalHeight(), shouldIndentText == IndentText, lineLogicalHeight);
977 lineLogicalRight = block->pixelSnappedLogicalRightOffsetForLine(block->logicalHeight(), shouldIndentText == IndentText, lineLogicalHeight);
robert@webkit.org0903cf52012-12-11 18:14:16 +0000978 availableLogicalWidth = lineLogicalRight - lineLogicalLeft;
979}
980
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +0000981void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, const LineInfo& lineInfo, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd,
enrica@apple.com885c84d2012-10-10 05:48:51 +0000982 GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache, WordMeasurements& wordMeasurements)
hyattffe78712003-02-11 01:59:29 +0000983{
mitz@apple.com390fa322011-02-24 23:07:06 +0000984 ETextAlign textAlign = textAlignmentForLine(!reachedEnd && !lineBox->endsWithBreak());
robert@webkit.org4f76df92012-07-03 17:41:35 +0000985
robert@webkit.org328ecd02012-08-09 21:12:44 +0000986 // CSS 2.1: "'Text-indent' only affects a line if it is the first formatted line of an element. For example, the first line of an anonymous block
987 // box is only affected if it is the first child of its parent element."
commit-queue@webkit.orgab781b02013-04-03 01:32:24 +0000988 // CSS3 "text-indent", "-webkit-each-line" affects the first line of the block container as well as each line after a forced line break,
989 // but does not affect lines after a soft wrap break.
990 bool isFirstLine = lineInfo.isFirstLine() && !(isAnonymousBlock() && parent()->firstChild() != this);
991 bool isAfterHardLineBreak = lineBox->prevRootBox() && lineBox->prevRootBox()->endsWithBreak();
992 IndentTextOrNot shouldIndentText = requiresIndent(isFirstLine, isAfterHardLineBreak, style());
robert@webkit.org0903cf52012-12-11 18:14:16 +0000993 float lineLogicalLeft;
994 float lineLogicalRight;
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +0000995 float availableLogicalWidth;
commit-queue@webkit.orgab781b02013-04-03 01:32:24 +0000996 updateLogicalInlinePositions(this, lineLogicalLeft, lineLogicalRight, availableLogicalWidth, isFirstLine, shouldIndentText, 0);
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +0000997 bool needsWordSpacing;
commit-queue@webkit.orgb3540512012-08-24 18:48:49 +0000998#if ENABLE(CSS_EXCLUSIONS)
betravis@adobe.coma53af342013-03-01 21:02:16 +0000999 ExclusionShapeInsideInfo* exclusionShapeInsideInfo = layoutExclusionShapeInsideInfo();
commit-queue@webkit.org3a988eb2012-09-26 19:55:35 +00001000 if (exclusionShapeInsideInfo && exclusionShapeInsideInfo->hasSegments()) {
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00001001 BidiRun* segmentStart = firstRun;
1002 const SegmentList& segments = exclusionShapeInsideInfo->segments();
1003 float logicalLeft = max<float>(roundToInt(segments[0].logicalLeft), lineLogicalLeft);
1004 float logicalRight = min<float>(floorToInt(segments[0].logicalRight), lineLogicalRight);
1005 float startLogicalLeft = logicalLeft;
1006 float endLogicalRight = logicalLeft;
1007 float minLogicalLeft = logicalLeft;
1008 float maxLogicalRight = logicalLeft;
1009 lineBox->beginPlacingBoxRangesInInlineDirection(logicalLeft);
1010 for (size_t i = 0; i < segments.size(); i++) {
1011 if (i) {
1012 logicalLeft = max<float>(roundToInt(segments[i].logicalLeft), lineLogicalLeft);
1013 logicalRight = min<float>(floorToInt(segments[i].logicalRight), lineLogicalRight);
1014 }
1015 availableLogicalWidth = logicalRight - logicalLeft;
1016 BidiRun* newSegmentStart = computeInlineDirectionPositionsForSegment(lineBox, lineInfo, textAlign, logicalLeft, availableLogicalWidth, segmentStart, trailingSpaceRun, textBoxDataMap, verticalPositionCache, wordMeasurements);
1017 needsWordSpacing = false;
1018 endLogicalRight = lineBox->placeBoxRangeInInlineDirection(segmentStart->m_box, newSegmentStart ? newSegmentStart->m_box : 0, logicalLeft, minLogicalLeft, maxLogicalRight, needsWordSpacing, textBoxDataMap);
1019 if (!newSegmentStart || !newSegmentStart->next())
1020 break;
1021 ASSERT(newSegmentStart->m_startsSegment);
1022 // Discard the empty segment start marker bidi runs
1023 segmentStart = newSegmentStart->next();
1024 }
1025 lineBox->endPlacingBoxRangesInInlineDirection(startLogicalLeft, endLogicalRight, minLogicalLeft, maxLogicalRight);
1026 return;
commit-queue@webkit.orgb3540512012-08-24 18:48:49 +00001027 }
1028#endif
robert@webkit.org0903cf52012-12-11 18:14:16 +00001029
1030 if (firstRun && firstRun->m_object->isReplaced()) {
1031 RenderBox* renderBox = toRenderBox(firstRun->m_object);
commit-queue@webkit.orgab781b02013-04-03 01:32:24 +00001032 updateLogicalInlinePositions(this, lineLogicalLeft, lineLogicalRight, availableLogicalWidth, isFirstLine, shouldIndentText, renderBox->logicalHeight());
robert@webkit.org0903cf52012-12-11 18:14:16 +00001033 }
1034
1035 computeInlineDirectionPositionsForSegment(lineBox, lineInfo, textAlign, lineLogicalLeft, availableLogicalWidth, firstRun, trailingSpaceRun, textBoxDataMap, verticalPositionCache, wordMeasurements);
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00001036 // The widths of all runs are now known. We can now place every inline box (and
1037 // compute accurate widths for the inline flow boxes).
1038 needsWordSpacing = false;
1039 lineBox->placeBoxesInInlineDirection(lineLogicalLeft, needsWordSpacing, textBoxDataMap);
1040}
mitz@apple.com390fa322011-02-24 23:07:06 +00001041
robert@webkit.org0903cf52012-12-11 18:14:16 +00001042BidiRun* RenderBlock::computeInlineDirectionPositionsForSegment(RootInlineBox* lineBox, const LineInfo& lineInfo, ETextAlign textAlign, float& logicalLeft,
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00001043 float& availableLogicalWidth, BidiRun* firstRun, BidiRun* trailingSpaceRun, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache,
1044 WordMeasurements& wordMeasurements)
1045{
darin06dcb9c2005-08-15 04:31:09 +00001046 bool needsWordSpacing = false;
mitz@apple.com390fa322011-02-24 23:07:06 +00001047 float totalLogicalWidth = lineBox->getFlowSpacingLogicalWidth();
mitz@apple.com86470c82011-01-27 01:39:27 +00001048 unsigned expansionOpportunityCount = 0;
1049 bool isAfterExpansion = true;
1050 Vector<unsigned, 16> expansionOpportunities;
mitz@apple.comddb59872011-04-05 05:21:16 +00001051 RenderObject* previousObject = 0;
mitz@apple.com815ef2f2008-02-25 17:11:56 +00001052
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00001053 BidiRun* r = firstRun;
1054 for (; r; r = r->next()) {
1055#if ENABLE(CSS_EXCLUSIONS)
1056 // Once we have reached the start of the next segment, we have finished
1057 // computing the positions for this segment's contents.
1058 if (r->m_startsSegment)
1059 break;
1060#endif
simon.fraser@apple.com2f071852012-06-25 00:11:30 +00001061 if (!r->m_box || r->m_object->isOutOfFlowPositioned() || r->m_box->isLineBreak())
hyatt98ee7e42003-05-14 01:39:15 +00001062 continue; // Positioned objects are only participating to figure out their
1063 // correct static x position. They have no effect on the width.
hyatt0c05e102006-04-14 08:15:00 +00001064 // Similarly, line break boxes have no effect on the width.
mitz@apple.come1364202008-02-28 01:06:41 +00001065 if (r->m_object->isText()) {
darin@apple.com36744d62009-01-25 20:23:04 +00001066 RenderText* rt = toRenderText(r->m_object);
mitz@apple.comc13ea5f2008-04-18 21:18:26 +00001067 if (textAlign == JUSTIFY && r != trailingSpaceRun) {
mitz@apple.com80968932011-03-26 00:46:26 +00001068 if (!isAfterExpansion)
jchaffraix@webkit.org8f1781d2011-06-24 21:22:54 +00001069 toInlineTextBox(r->m_box)->setCanHaveLeadingExpansion(true);
msaboff@apple.com776c286c72012-10-15 16:56:29 +00001070 unsigned opportunitiesInRun;
1071 if (rt->is8Bit())
1072 opportunitiesInRun = Font::expansionOpportunityCount(rt->characters8() + r->m_start, r->m_stop - r->m_start, r->m_box->direction(), isAfterExpansion);
1073 else
1074 opportunitiesInRun = Font::expansionOpportunityCount(rt->characters16() + r->m_start, r->m_stop - r->m_start, r->m_box->direction(), isAfterExpansion);
mitz@apple.com86470c82011-01-27 01:39:27 +00001075 expansionOpportunities.append(opportunitiesInRun);
1076 expansionOpportunityCount += opportunitiesInRun;
mitz@apple.com815ef2f2008-02-25 17:11:56 +00001077 }
1078
mitz@apple.come1364202008-02-28 01:06:41 +00001079 if (int length = rt->textLength()) {
msaboff@apple.com776c286c72012-10-15 16:56:29 +00001080 if (!r->m_start && needsWordSpacing && isSpaceOrNewline(rt->characterAt(r->m_start)))
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +00001081 totalLogicalWidth += rt->style(lineInfo.isFirstLine())->font().wordSpacing();
msaboff@apple.com776c286c72012-10-15 16:56:29 +00001082 needsWordSpacing = !isSpaceOrNewline(rt->characterAt(r->m_stop - 1)) && r->m_stop == length;
darin06dcb9c2005-08-15 04:31:09 +00001083 }
eric@webkit.org060caf62011-05-03 22:11:39 +00001084
enrica@apple.com885c84d2012-10-10 05:48:51 +00001085 setLogicalWidthForTextRun(lineBox, r, rt, totalLogicalWidth, lineInfo, textBoxDataMap, verticalPositionCache, wordMeasurements);
mitz@apple.com86470c82011-01-27 01:39:27 +00001086 } else {
1087 isAfterExpansion = false;
1088 if (!r->m_object->isRenderInline()) {
1089 RenderBox* renderBox = toRenderBox(r->m_object);
leviw@chromium.orgd70a0072011-05-03 23:28:11 +00001090 if (renderBox->isRubyRun())
1091 setMarginsForRubyRun(r, toRenderRubyRun(renderBox), previousObject, lineInfo);
mitz@apple.com86470c82011-01-27 01:39:27 +00001092 r->m_box->setLogicalWidth(logicalWidthForChild(renderBox));
1093 totalLogicalWidth += marginStartForChild(renderBox) + marginEndForChild(renderBox);
1094 }
hyattffe78712003-02-11 01:59:29 +00001095 }
hyatt4b381692003-03-10 21:11:59 +00001096
hyatt@apple.com546a2482010-10-07 21:16:49 +00001097 totalLogicalWidth += r->m_box->logicalWidth();
mitz@apple.comddb59872011-04-05 05:21:16 +00001098 previousObject = r->m_object;
hyattffe78712003-02-11 01:59:29 +00001099 }
1100
mitz@apple.com86470c82011-01-27 01:39:27 +00001101 if (isAfterExpansion && !expansionOpportunities.isEmpty()) {
1102 expansionOpportunities.last()--;
1103 expansionOpportunityCount--;
1104 }
1105
robert@webkit.orgfc7763c2011-09-03 18:28:57 +00001106 updateLogicalWidthForAlignment(textAlign, trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth, expansionOpportunityCount);
hyattffe78712003-02-11 01:59:29 +00001107
leviw@chromium.orgd70a0072011-05-03 23:28:11 +00001108 computeExpansionForJustifiedText(firstRun, trailingSpaceRun, expansionOpportunities, expansionOpportunityCount, totalLogicalWidth, availableLogicalWidth);
mitz@apple.come1364202008-02-28 01:06:41 +00001109
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00001110 return r;
hyattffe78712003-02-11 01:59:29 +00001111}
1112
hyatt@apple.com4a9c625a2010-11-17 20:55:40 +00001113void RenderBlock::computeBlockDirectionPositionsForLine(RootInlineBox* lineBox, BidiRun* firstRun, GlyphOverflowAndFallbackFontsMap& textBoxDataMap,
1114 VerticalPositionCache& verticalPositionCache)
hyattffe78712003-02-11 01:59:29 +00001115{
hyatt@apple.com4a9c625a2010-11-17 20:55:40 +00001116 setLogicalHeight(lineBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache));
hyattffe78712003-02-11 01:59:29 +00001117
1118 // Now make sure we place replaced render objects correctly.
mitz@apple.com887f3592008-02-25 22:03:08 +00001119 for (BidiRun* r = firstRun; r; r = r->next()) {
mitz@apple.comaa6ce3d2009-04-10 01:00:20 +00001120 ASSERT(r->m_box);
mitz@apple.come1364202008-02-28 01:06:41 +00001121 if (!r->m_box)
eseidel789896f2005-11-27 22:52:09 +00001122 continue; // Skip runs with no line boxes.
hyatt0c3a9862004-02-23 21:26:26 +00001123
hyatt98ee7e42003-05-14 01:39:15 +00001124 // Align positioned boxes with the top of the line box. This is
1125 // a reasonable approximation of an appropriate y position.
simon.fraser@apple.com2f071852012-06-25 00:11:30 +00001126 if (r->m_object->isOutOfFlowPositioned())
hyatt@apple.com35d2ad52010-10-20 18:17:36 +00001127 r->m_box->setLogicalTop(logicalHeight());
hyatt98ee7e42003-05-14 01:39:15 +00001128
1129 // Position is used to properly position both replaced elements and
1130 // to update the static normal flow x/y of positioned elements.
hyatt@apple.com6a551ad2009-02-11 22:43:12 +00001131 if (r->m_object->isText())
1132 toRenderText(r->m_object)->positionLineBox(r->m_box);
1133 else if (r->m_object->isBox())
1134 toRenderBox(r->m_object)->positionLineBox(r->m_box);
hyatt98ee7e42003-05-14 01:39:15 +00001135 }
mitz@apple.coma927be62008-03-21 05:30:19 +00001136 // Positioned objects and zero-length text nodes destroy their boxes in
1137 // position(), which unnecessarily dirties the line.
1138 lineBox->markDirty(false);
hyattffe78712003-02-11 01:59:29 +00001139}
kociendabb0c24b2001-08-24 14:24:40 +00001140
mitz@apple.comc13ea5f2008-04-18 21:18:26 +00001141static inline bool isCollapsibleSpace(UChar character, RenderText* renderer)
1142{
1143 if (character == ' ' || character == '\t' || character == softHyphen)
1144 return true;
1145 if (character == '\n')
1146 return !renderer->style()->preserveNewline();
1147 if (character == noBreakSpace)
1148 return renderer->style()->nbspMode() == SPACE;
1149 return false;
1150}
1151
hyatt@apple.com14e332d2011-03-25 21:57:07 +00001152
1153static void setStaticPositions(RenderBlock* block, RenderBox* child)
1154{
1155 // FIXME: The math here is actually not really right. It's a best-guess approximation that
1156 // will work for the common cases
1157 RenderObject* containerBlock = child->container();
eae@chromium.orgee8613e2011-11-12 01:12:58 +00001158 LayoutUnit blockHeight = block->logicalHeight();
hyatt@apple.com14e332d2011-03-25 21:57:07 +00001159 if (containerBlock->isRenderInline()) {
1160 // A relative positioned inline encloses us. In this case, we also have to determine our
1161 // position as though we were an inline. Set |staticInlinePosition| and |staticBlockPosition| on the relative positioned
1162 // inline so that we can obtain the value later.
robert@webkit.org82903f42012-08-28 19:18:40 +00001163 toRenderInline(containerBlock)->layer()->setStaticInlinePosition(block->startAlignedOffsetForLine(blockHeight, false));
hyatt@apple.com14e332d2011-03-25 21:57:07 +00001164 toRenderInline(containerBlock)->layer()->setStaticBlockPosition(blockHeight);
1165 }
robert@webkit.org83f864f2013-01-23 20:15:12 +00001166 block->updateStaticInlinePositionForChild(child, blockHeight);
hyatt@apple.com14e332d2011-03-25 21:57:07 +00001167 child->layer()->setStaticBlockPosition(blockHeight);
1168}
1169
msaboff@apple.com142fc202012-10-18 18:03:14 +00001170template <typename CharacterType>
1171static inline int findFirstTrailingSpace(RenderText* lastText, const CharacterType* characters, int start, int stop)
1172{
1173 int firstSpace = stop;
1174 while (firstSpace > start) {
1175 UChar current = characters[firstSpace - 1];
1176 if (!isCollapsibleSpace(current, lastText))
1177 break;
1178 firstSpace--;
1179 }
1180
1181 return firstSpace;
1182}
1183
eric@webkit.org5bee2942011-04-08 02:12:31 +00001184inline BidiRun* RenderBlock::handleTrailingSpaces(BidiRunList<BidiRun>& bidiRuns, BidiContext* currentContext)
eric@webkit.org0894bb82011-04-03 08:29:40 +00001185{
eric@webkit.org5bee2942011-04-08 02:12:31 +00001186 if (!bidiRuns.runCount()
1187 || !bidiRuns.logicallyLastRun()->m_object->style()->breakOnlyAfterWhiteSpace()
1188 || !bidiRuns.logicallyLastRun()->m_object->style()->autoWrap())
eric@webkit.org0894bb82011-04-03 08:29:40 +00001189 return 0;
1190
eric@webkit.org5bee2942011-04-08 02:12:31 +00001191 BidiRun* trailingSpaceRun = bidiRuns.logicallyLastRun();
eric@webkit.org0894bb82011-04-03 08:29:40 +00001192 RenderObject* lastObject = trailingSpaceRun->m_object;
1193 if (!lastObject->isText())
1194 return 0;
1195
1196 RenderText* lastText = toRenderText(lastObject);
msaboff@apple.com142fc202012-10-18 18:03:14 +00001197 int firstSpace;
1198 if (lastText->is8Bit())
1199 firstSpace = findFirstTrailingSpace(lastText, lastText->characters8(), trailingSpaceRun->start(), trailingSpaceRun->stop());
1200 else
1201 firstSpace = findFirstTrailingSpace(lastText, lastText->characters16(), trailingSpaceRun->start(), trailingSpaceRun->stop());
1202
eric@webkit.org0894bb82011-04-03 08:29:40 +00001203 if (firstSpace == trailingSpaceRun->stop())
1204 return 0;
1205
1206 TextDirection direction = style()->direction();
eric@webkit.org5bee2942011-04-08 02:12:31 +00001207 bool shouldReorder = trailingSpaceRun != (direction == LTR ? bidiRuns.lastRun() : bidiRuns.firstRun());
eric@webkit.org0894bb82011-04-03 08:29:40 +00001208 if (firstSpace != trailingSpaceRun->start()) {
eric@webkit.org5bee2942011-04-08 02:12:31 +00001209 BidiContext* baseContext = currentContext;
eric@webkit.org0894bb82011-04-03 08:29:40 +00001210 while (BidiContext* parent = baseContext->parent())
1211 baseContext = parent;
1212
1213 BidiRun* newTrailingRun = new (renderArena()) BidiRun(firstSpace, trailingSpaceRun->m_stop, trailingSpaceRun->m_object, baseContext, OtherNeutral);
1214 trailingSpaceRun->m_stop = firstSpace;
1215 if (direction == LTR)
eric@webkit.org5bee2942011-04-08 02:12:31 +00001216 bidiRuns.addRun(newTrailingRun);
eric@webkit.org0894bb82011-04-03 08:29:40 +00001217 else
eric@webkit.org5bee2942011-04-08 02:12:31 +00001218 bidiRuns.prependRun(newTrailingRun);
eric@webkit.org0894bb82011-04-03 08:29:40 +00001219 trailingSpaceRun = newTrailingRun;
1220 return trailingSpaceRun;
1221 }
1222 if (!shouldReorder)
1223 return trailingSpaceRun;
1224
1225 if (direction == LTR) {
eric@webkit.org5bee2942011-04-08 02:12:31 +00001226 bidiRuns.moveRunToEnd(trailingSpaceRun);
eric@webkit.org0894bb82011-04-03 08:29:40 +00001227 trailingSpaceRun->m_level = 0;
1228 } else {
eric@webkit.org5bee2942011-04-08 02:12:31 +00001229 bidiRuns.moveRunToBeginning(trailingSpaceRun);
eric@webkit.org0894bb82011-04-03 08:29:40 +00001230 trailingSpaceRun->m_level = 1;
1231 }
1232 return trailingSpaceRun;
1233}
1234
mitz@apple.comd17e8c02011-04-16 21:59:36 +00001235void RenderBlock::appendFloatingObjectToLastLine(FloatingObject* floatingObject)
1236{
mitz@apple.com0c4ce9f2011-05-04 02:20:02 +00001237 ASSERT(!floatingObject->m_originatingLine);
1238 floatingObject->m_originatingLine = lastRootBox();
mitz@apple.comd17e8c02011-04-16 21:59:36 +00001239 lastRootBox()->appendFloat(floatingObject->renderer());
1240}
1241
eric@webkit.orga26de042011-09-08 18:46:01 +00001242// FIXME: This should be a BidiStatus constructor or create method.
rniwa@webkit.orgc275acf2012-03-05 23:09:22 +00001243static inline BidiStatus statusWithDirection(TextDirection textDirection, bool isOverride)
eric@webkit.orga26de042011-09-08 18:46:01 +00001244{
1245 WTF::Unicode::Direction direction = textDirection == LTR ? LeftToRight : RightToLeft;
rniwa@webkit.orgc275acf2012-03-05 23:09:22 +00001246 RefPtr<BidiContext> context = BidiContext::create(textDirection == LTR ? 0 : 1, direction, isOverride, FromStyleOrDOM);
eric@webkit.orga26de042011-09-08 18:46:01 +00001247
1248 // This copies BidiStatus and may churn the ref on BidiContext. I doubt it matters.
1249 return BidiStatus(direction, direction, direction, context.release());
1250}
1251
1252// FIXME: BidiResolver should have this logic.
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00001253static inline void constructBidiRunsForSegment(InlineBidiResolver& topResolver, BidiRunList<BidiRun>& bidiRuns, const InlineIterator& endOfRuns, VisualDirectionOverride override, bool previousLineBrokeCleanly)
eric@webkit.orga26de042011-09-08 18:46:01 +00001254{
1255 // FIXME: We should pass a BidiRunList into createBidiRunsForLine instead
1256 // of the resolver owning the runs.
1257 ASSERT(&topResolver.runs() == &bidiRuns);
commit-queue@webkit.org30cc2912011-12-15 04:19:24 +00001258 RenderObject* currentRoot = topResolver.position().root();
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00001259 topResolver.createBidiRunsForLine(endOfRuns, override, previousLineBrokeCleanly);
eric@webkit.orga26de042011-09-08 18:46:01 +00001260
1261 while (!topResolver.isolatedRuns().isEmpty()) {
1262 // It does not matter which order we resolve the runs as long as we resolve them all.
1263 BidiRun* isolatedRun = topResolver.isolatedRuns().last();
1264 topResolver.isolatedRuns().removeLast();
1265
commit-queue@webkit.org30cc2912011-12-15 04:19:24 +00001266 RenderObject* startObj = isolatedRun->object();
1267
eric@webkit.orga26de042011-09-08 18:46:01 +00001268 // Only inlines make sense with unicode-bidi: isolate (blocks are already isolated).
commit-queue@webkit.org30cc2912011-12-15 04:19:24 +00001269 // FIXME: Because enterIsolate is not passed a RenderObject, we have to crawl up the
1270 // tree to see which parent inline is the isolate. We could change enterIsolate
1271 // to take a RenderObject and do this logic there, but that would be a layering
1272 // violation for BidiResolver (which knows nothing about RenderObject).
leviw@chromium.orge7812f32012-02-07 23:46:40 +00001273 RenderInline* isolatedInline = toRenderInline(containingIsolate(startObj, currentRoot));
eric@webkit.orga26de042011-09-08 18:46:01 +00001274 InlineBidiResolver isolatedResolver;
leviw@chromium.orge7812f32012-02-07 23:46:40 +00001275 EUnicodeBidi unicodeBidi = isolatedInline->style()->unicodeBidi();
1276 TextDirection direction;
1277 if (unicodeBidi == Plaintext)
1278 determineDirectionality(direction, InlineIterator(isolatedInline, isolatedRun->object(), 0));
1279 else {
rniwa@webkit.org4d4bd332012-08-20 21:34:11 +00001280 ASSERT(unicodeBidi == Isolate || unicodeBidi == IsolateOverride);
leviw@chromium.orge7812f32012-02-07 23:46:40 +00001281 direction = isolatedInline->style()->direction();
1282 }
rniwa@webkit.orgc275acf2012-03-05 23:09:22 +00001283 isolatedResolver.setStatus(statusWithDirection(direction, isOverride(unicodeBidi)));
eric@webkit.orga26de042011-09-08 18:46:01 +00001284
1285 // FIXME: The fact that we have to construct an Iterator here
1286 // currently prevents this code from moving into BidiResolver.
leviw@chromium.orge7812f32012-02-07 23:46:40 +00001287 if (!bidiFirstSkippingEmptyInlines(isolatedInline, &isolatedResolver))
rniwa@webkit.org2343fab2011-11-25 20:21:06 +00001288 continue;
leviw@chromium.orge7812f32012-02-07 23:46:40 +00001289
commit-queue@webkit.org30cc2912011-12-15 04:19:24 +00001290 // The starting position is the beginning of the first run within the isolate that was identified
1291 // during the earlier call to createBidiRunsForLine. This can be but is not necessarily the
1292 // first run within the isolate.
leviw@chromium.orge7812f32012-02-07 23:46:40 +00001293 InlineIterator iter = InlineIterator(isolatedInline, startObj, isolatedRun->m_start);
commit-queue@webkit.org30cc2912011-12-15 04:19:24 +00001294 isolatedResolver.setPositionIgnoringNestedIsolates(iter);
eric@webkit.orga26de042011-09-08 18:46:01 +00001295
commit-queue@webkit.org30cc2912011-12-15 04:19:24 +00001296 // We stop at the next end of line; we may re-enter this isolate in the next call to constructBidiRuns().
eric@webkit.orga26de042011-09-08 18:46:01 +00001297 // FIXME: What should end and previousLineBrokeCleanly be?
1298 // rniwa says previousLineBrokeCleanly is just a WinIE hack and could always be false here?
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00001299 isolatedResolver.createBidiRunsForLine(endOfRuns, NoVisualOverride, previousLineBrokeCleanly);
eric@webkit.orga26de042011-09-08 18:46:01 +00001300 // Note that we do not delete the runs from the resolver.
rniwa@webkit.orgd0ad8882012-05-23 07:37:07 +00001301 // We're not guaranteed to get any BidiRuns in the previous step. If we don't, we allow the placeholder
leviw@chromium.orgf0d6f362012-05-23 04:00:47 +00001302 // itself to be turned into an InlineBox. We can't remove it here without potentially losing track of
1303 // the logically last run.
1304 if (isolatedResolver.runs().runCount())
1305 bidiRuns.replaceRunWithRuns(isolatedRun, isolatedResolver.runs());
eric@webkit.orga26de042011-09-08 18:46:01 +00001306
1307 // If we encountered any nested isolate runs, just move them
1308 // to the top resolver's list for later processing.
1309 if (!isolatedResolver.isolatedRuns().isEmpty()) {
1310 topResolver.isolatedRuns().append(isolatedResolver.isolatedRuns());
1311 isolatedResolver.isolatedRuns().clear();
1312 }
1313 }
1314}
1315
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00001316static inline void constructBidiRunsForLine(const RenderBlock* block, InlineBidiResolver& topResolver, BidiRunList<BidiRun>& bidiRuns, const InlineIterator& endOfLine, VisualDirectionOverride override, bool previousLineBrokeCleanly)
1317{
1318#if !ENABLE(CSS_EXCLUSIONS)
1319 UNUSED_PARAM(block);
1320 constructBidiRunsForSegment(topResolver, bidiRuns, endOfLine, override, previousLineBrokeCleanly);
1321#else
betravis@adobe.coma53af342013-03-01 21:02:16 +00001322 ExclusionShapeInsideInfo* exclusionShapeInsideInfo = block->layoutExclusionShapeInsideInfo();
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00001323 if (!exclusionShapeInsideInfo || !exclusionShapeInsideInfo->hasSegments()) {
1324 constructBidiRunsForSegment(topResolver, bidiRuns, endOfLine, override, previousLineBrokeCleanly);
1325 return;
1326 }
1327
1328 const SegmentRangeList& segmentRanges = exclusionShapeInsideInfo->segmentRanges();
1329 ASSERT(segmentRanges.size());
1330
1331 for (size_t i = 0; i < segmentRanges.size(); i++) {
betravis@adobe.com28fba072013-03-12 23:27:35 +00001332 LineSegmentIterator iterator = segmentRanges[i].start;
1333 InlineIterator segmentStart(iterator.root, iterator.object, iterator.offset);
1334 iterator = segmentRanges[i].end;
1335 InlineIterator segmentEnd(iterator.root, iterator.object, iterator.offset);
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00001336 if (i) {
1337 ASSERT(segmentStart.m_obj);
1338 BidiRun* segmentMarker = createRun(segmentStart.m_pos, segmentStart.m_pos, segmentStart.m_obj, topResolver);
1339 segmentMarker->m_startsSegment = true;
1340 bidiRuns.addRun(segmentMarker);
1341 // Do not collapse midpoints between segments
1342 topResolver.midpointState().betweenMidpoints = false;
1343 }
1344 topResolver.setPosition(segmentStart, numberOfIsolateAncestors(segmentStart));
1345 constructBidiRunsForSegment(topResolver, bidiRuns, segmentEnd, override, previousLineBrokeCleanly);
1346 }
1347#endif
1348}
1349
eric@webkit.org45e33a52011-05-04 11:51:09 +00001350// This function constructs line boxes for all of the text runs in the resolver and computes their position.
enrica@apple.com885c84d2012-10-10 05:48:51 +00001351RootInlineBox* RenderBlock::createLineBoxesFromBidiRuns(BidiRunList<BidiRun>& bidiRuns, const InlineIterator& end, LineInfo& lineInfo, VerticalPositionCache& verticalPositionCache, BidiRun* trailingSpaceRun, WordMeasurements& wordMeasurements)
eric@webkit.org45e33a52011-05-04 11:51:09 +00001352{
1353 if (!bidiRuns.runCount())
1354 return 0;
1355
1356 // FIXME: Why is this only done when we had runs?
1357 lineInfo.setLastLine(!end.m_obj);
1358
1359 RootInlineBox* lineBox = constructLine(bidiRuns, lineInfo);
1360 if (!lineBox)
1361 return 0;
1362
1363 lineBox->setEndsWithBreak(lineInfo.previousLineBrokeCleanly());
1364
1365#if ENABLE(SVG)
1366 bool isSVGRootInlineBox = lineBox->isSVGRootInlineBox();
1367#else
1368 bool isSVGRootInlineBox = false;
1369#endif
1370
1371 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
1372
1373 // Now we position all of our text runs horizontally.
1374 if (!isSVGRootInlineBox)
enrica@apple.com885c84d2012-10-10 05:48:51 +00001375 computeInlineDirectionPositionsForLine(lineBox, lineInfo, bidiRuns.firstRun(), trailingSpaceRun, end.atEnd(), textBoxDataMap, verticalPositionCache, wordMeasurements);
eric@webkit.org45e33a52011-05-04 11:51:09 +00001376
1377 // Now position our text runs vertically.
1378 computeBlockDirectionPositionsForLine(lineBox, bidiRuns.firstRun(), textBoxDataMap, verticalPositionCache);
1379
1380#if ENABLE(SVG)
1381 // SVG text layout code computes vertical & horizontal positions on its own.
1382 // Note that we still need to execute computeVerticalPositionsForLine() as
1383 // it calls InlineTextBox::positionLineBox(), which tracks whether the box
1384 // contains reversed text or not. If we wouldn't do that editing and thus
1385 // text selection in RTL boxes would not work as expected.
1386 if (isSVGRootInlineBox) {
1387 ASSERT(isSVGText());
1388 static_cast<SVGRootInlineBox*>(lineBox)->computePerCharacterLayoutInformation();
1389 }
1390#endif
1391
1392 // Compute our overflow now.
1393 lineBox->computeOverflow(lineBox->lineTop(), lineBox->lineBottom(), textBoxDataMap);
1394
1395#if PLATFORM(MAC)
1396 // Highlight acts as an overflow inflation.
1397 if (style()->highlight() != nullAtom)
1398 lineBox->addHighlightOverflow();
1399#endif
1400 return lineBox;
1401}
1402
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001403// Like LayoutState for layout(), LineLayoutState keeps track of global information
1404// during an entire linebox tree layout pass (aka layoutInlineChildren).
1405class LineLayoutState {
1406public:
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00001407 LineLayoutState(bool fullLayout, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom, RenderFlowThread* flowThread)
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001408 : m_lastFloat(0)
1409 , m_endLine(0)
1410 , m_floatIndex(0)
1411 , m_endLineLogicalTop(0)
1412 , m_endLineMatched(false)
1413 , m_checkForFloatsFromLastLine(false)
1414 , m_isFullLayout(fullLayout)
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001415 , m_repaintLogicalTop(repaintLogicalTop)
1416 , m_repaintLogicalBottom(repaintLogicalBottom)
commit-queue@webkit.org49ad4732011-07-15 07:23:01 +00001417 , m_usesRepaintBounds(false)
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00001418 , m_flowThread(flowThread)
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001419 { }
1420
1421 void markForFullLayout() { m_isFullLayout = true; }
1422 bool isFullLayout() const { return m_isFullLayout; }
1423
commit-queue@webkit.org49ad4732011-07-15 07:23:01 +00001424 bool usesRepaintBounds() const { return m_usesRepaintBounds; }
1425
eae@chromium.orgee8613e2011-11-12 01:12:58 +00001426 void setRepaintRange(LayoutUnit logicalHeight)
commit-queue@webkit.org49ad4732011-07-15 07:23:01 +00001427 {
1428 m_usesRepaintBounds = true;
1429 m_repaintLogicalTop = m_repaintLogicalBottom = logicalHeight;
1430 }
1431
eae@chromium.orgee8613e2011-11-12 01:12:58 +00001432 void updateRepaintRangeFromBox(RootInlineBox* box, LayoutUnit paginationDelta = 0)
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001433 {
commit-queue@webkit.org49ad4732011-07-15 07:23:01 +00001434 m_usesRepaintBounds = true;
eae@chromium.org9717cd82012-11-07 18:33:44 +00001435 m_repaintLogicalTop = min(m_repaintLogicalTop, box->logicalTopVisualOverflow() + min<LayoutUnit>(paginationDelta, 0));
1436 m_repaintLogicalBottom = max(m_repaintLogicalBottom, box->logicalBottomVisualOverflow() + max<LayoutUnit>(paginationDelta, 0));
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001437 }
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001438
1439 bool endLineMatched() const { return m_endLineMatched; }
1440 void setEndLineMatched(bool endLineMatched) { m_endLineMatched = endLineMatched; }
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001441
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001442 bool checkForFloatsFromLastLine() const { return m_checkForFloatsFromLastLine; }
1443 void setCheckForFloatsFromLastLine(bool check) { m_checkForFloatsFromLastLine = check; }
1444
1445 LineInfo& lineInfo() { return m_lineInfo; }
1446 const LineInfo& lineInfo() const { return m_lineInfo; }
1447
leviw@chromium.orgd32486e2012-03-16 10:52:56 +00001448 LayoutUnit endLineLogicalTop() const { return m_endLineLogicalTop; }
1449 void setEndLineLogicalTop(LayoutUnit logicalTop) { m_endLineLogicalTop = logicalTop; }
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001450
1451 RootInlineBox* endLine() const { return m_endLine; }
1452 void setEndLine(RootInlineBox* line) { m_endLine = line; }
1453
1454 RenderBlock::FloatingObject* lastFloat() const { return m_lastFloat; }
1455 void setLastFloat(RenderBlock::FloatingObject* lastFloat) { m_lastFloat = lastFloat; }
1456
1457 Vector<RenderBlock::FloatWithRect>& floats() { return m_floats; }
1458
1459 unsigned floatIndex() const { return m_floatIndex; }
1460 void setFloatIndex(unsigned floatIndex) { m_floatIndex = floatIndex; }
1461
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00001462 RenderFlowThread* flowThread() const { return m_flowThread; }
1463 void setFlowThread(RenderFlowThread* thread) { m_flowThread = thread; }
1464
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001465private:
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001466 Vector<RenderBlock::FloatWithRect> m_floats;
1467 RenderBlock::FloatingObject* m_lastFloat;
1468 RootInlineBox* m_endLine;
1469 LineInfo m_lineInfo;
1470 unsigned m_floatIndex;
leviw@chromium.orgd32486e2012-03-16 10:52:56 +00001471 LayoutUnit m_endLineLogicalTop;
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001472 bool m_endLineMatched;
1473 bool m_checkForFloatsFromLastLine;
1474
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001475 bool m_isFullLayout;
1476
1477 // FIXME: Should this be a range object instead of two ints?
eae@chromium.orgee8613e2011-11-12 01:12:58 +00001478 LayoutUnit& m_repaintLogicalTop;
1479 LayoutUnit& m_repaintLogicalBottom;
1480
commit-queue@webkit.org49ad4732011-07-15 07:23:01 +00001481 bool m_usesRepaintBounds;
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00001482
1483 RenderFlowThread* m_flowThread;
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001484};
1485
1486static void deleteLineRange(LineLayoutState& layoutState, RenderArena* arena, RootInlineBox* startLine, RootInlineBox* stopLine = 0)
eric@webkit.org455d90e2011-05-09 22:27:27 +00001487{
1488 RootInlineBox* boxToDelete = startLine;
1489 while (boxToDelete && boxToDelete != stopLine) {
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001490 layoutState.updateRepaintRangeFromBox(boxToDelete);
eric@webkit.orge2532d92011-05-16 23:10:49 +00001491 // Note: deleteLineRange(renderArena(), firstRootBox()) is not identical to deleteLineBoxTree().
1492 // deleteLineBoxTree uses nextLineBox() instead of nextRootBox() when traversing.
eric@webkit.org455d90e2011-05-09 22:27:27 +00001493 RootInlineBox* next = boxToDelete->nextRootBox();
1494 boxToDelete->deleteLine(arena);
1495 boxToDelete = next;
1496 }
1497}
1498
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001499void RenderBlock::layoutRunsAndFloats(LineLayoutState& layoutState, bool hasInlineChild)
eric@webkit.org060caf62011-05-03 22:11:39 +00001500{
1501 // We want to skip ahead to the first dirty line
1502 InlineBidiResolver resolver;
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001503 RootInlineBox* startLine = determineStartPosition(layoutState, resolver);
eric@webkit.org060caf62011-05-03 22:11:39 +00001504
mitz@apple.com10ed3cb2011-09-07 20:59:39 +00001505 unsigned consecutiveHyphenatedLines = 0;
1506 if (startLine) {
1507 for (RootInlineBox* line = startLine->prevRootBox(); line && line->isHyphenated(); line = line->prevRootBox())
1508 consecutiveHyphenatedLines++;
1509 }
1510
eric@webkit.org060caf62011-05-03 22:11:39 +00001511 // FIXME: This would make more sense outside of this function, but since
1512 // determineStartPosition can change the fullLayout flag we have to do this here. Failure to call
1513 // determineStartPosition first will break fast/repaint/line-flow-with-floats-9.html.
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001514 if (layoutState.isFullLayout() && hasInlineChild && !selfNeedsLayout()) {
eric@webkit.org218b4e02012-03-28 19:25:02 +00001515 setNeedsLayout(true, MarkOnlyThis); // Mark as needing a full layout to force us to repaint.
eric@webkit.org060caf62011-05-03 22:11:39 +00001516 RenderView* v = view();
1517 if (v && !v->doingFullRepaint() && hasLayer()) {
1518 // Because we waited until we were already inside layout to discover
1519 // that the block really needed a full layout, we missed our chance to repaint the layer
1520 // before layout started. Luckily the layer has cached the repaint rect for its original
1521 // position and size, and so we can use that to make a repaint happen now.
leviw@chromium.org52066f32012-09-12 19:17:03 +00001522 repaintUsingContainer(containerForRepaint(), pixelSnappedIntRect(layer()->repaintRect()));
eric@webkit.org060caf62011-05-03 22:11:39 +00001523 }
1524 }
1525
mihnea@adobe.com99467792013-03-19 09:09:04 +00001526 if (containsFloats())
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001527 layoutState.setLastFloat(m_floatingObjects->set().last());
eric@webkit.org060caf62011-05-03 22:11:39 +00001528
1529 // We also find the first clean line and extract these lines. We will add them back
1530 // if we determine that we're able to synchronize after handling all our dirty lines.
1531 InlineIterator cleanLineStart;
1532 BidiStatus cleanLineBidiStatus;
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001533 if (!layoutState.isFullLayout() && startLine)
1534 determineEndPosition(layoutState, startLine, cleanLineStart, cleanLineBidiStatus);
eric@webkit.org060caf62011-05-03 22:11:39 +00001535
1536 if (startLine) {
commit-queue@webkit.org49ad4732011-07-15 07:23:01 +00001537 if (!layoutState.usesRepaintBounds())
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001538 layoutState.setRepaintRange(logicalHeight());
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001539 deleteLineRange(layoutState, renderArena(), startLine);
eric@webkit.org060caf62011-05-03 22:11:39 +00001540 }
1541
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001542 if (!layoutState.isFullLayout() && lastRootBox() && lastRootBox()->endsWithBreak()) {
eric@webkit.org060caf62011-05-03 22:11:39 +00001543 // If the last line before the start line ends with a line break that clear floats,
1544 // adjust the height accordingly.
1545 // A line break can be either the first or the last object on a line, depending on its direction.
1546 if (InlineBox* lastLeafChild = lastRootBox()->lastLeafChild()) {
1547 RenderObject* lastObject = lastLeafChild->renderer();
1548 if (!lastObject->isBR())
1549 lastObject = lastRootBox()->firstLeafChild()->renderer();
1550 if (lastObject->isBR()) {
1551 EClear clear = lastObject->style()->clear();
1552 if (clear != CNONE)
1553 newLine(clear);
1554 }
1555 }
1556 }
1557
mitz@apple.com10ed3cb2011-09-07 20:59:39 +00001558 layoutRunsAndFloatsInRange(layoutState, resolver, cleanLineStart, cleanLineBidiStatus, consecutiveHyphenatedLines);
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001559 linkToEndLineIfNeeded(layoutState);
1560 repaintDirtyFloats(layoutState.floats());
1561}
eric@webkit.org060caf62011-05-03 22:11:39 +00001562
mitz@apple.com6a859602012-08-27 15:31:56 +00001563RenderBlock::RenderTextInfo::RenderTextInfo()
1564 : m_text(0)
mitz@apple.comd4c153d2012-09-16 23:36:41 +00001565 , m_font(0)
mitz@apple.com6a859602012-08-27 15:31:56 +00001566{
1567}
1568
1569RenderBlock::RenderTextInfo::~RenderTextInfo()
1570{
1571}
1572
commit-queue@webkit.org4055b2e2012-12-06 19:05:15 +00001573// Before restarting the layout loop with a new logicalHeight, remove all floats that were added and reset the resolver.
1574inline const InlineIterator& RenderBlock::restartLayoutRunsAndFloatsInRange(LayoutUnit oldLogicalHeight, LayoutUnit newLogicalHeight, FloatingObject* lastFloatFromPreviousLine, InlineBidiResolver& resolver, const InlineIterator& oldEnd)
1575{
1576 removeFloatingObjectsBelow(lastFloatFromPreviousLine, oldLogicalHeight);
1577 setLogicalHeight(newLogicalHeight);
1578 resolver.setPositionIgnoringNestedIsolates(oldEnd);
1579 return oldEnd;
1580}
1581
mitz@apple.com10ed3cb2011-09-07 20:59:39 +00001582void RenderBlock::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, InlineBidiResolver& resolver, const InlineIterator& cleanLineStart, const BidiStatus& cleanLineBidiStatus, unsigned consecutiveHyphenatedLines)
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001583{
mihnea@adobe.com3bebbf22012-01-19 09:22:59 +00001584 RenderStyle* styleToUse = style();
eric@webkit.org060caf62011-05-03 22:11:39 +00001585 bool paginated = view()->layoutState() && view()->layoutState()->isPaginated();
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001586 LineMidpointState& lineMidpointState = resolver.midpointState();
1587 InlineIterator end = resolver.position();
1588 bool checkForEndLineMatch = layoutState.endLine();
mitz@apple.com6a859602012-08-27 15:31:56 +00001589 RenderTextInfo renderTextInfo;
eric@webkit.org060caf62011-05-03 22:11:39 +00001590 VerticalPositionCache verticalPositionCache;
1591
leviw@chromium.org1a508692011-05-05 00:01:11 +00001592 LineBreaker lineBreaker(this);
1593
commit-queue@webkit.orgb3540512012-08-24 18:48:49 +00001594#if ENABLE(CSS_EXCLUSIONS)
commit-queue@webkit.org3b26f3d2012-09-25 18:22:39 +00001595 LayoutUnit absoluteLogicalTop;
betravis@adobe.coma53af342013-03-01 21:02:16 +00001596 ExclusionShapeInsideInfo* exclusionShapeInsideInfo = layoutExclusionShapeInsideInfo();
commit-queue@webkit.org3a988eb2012-09-26 19:55:35 +00001597 if (exclusionShapeInsideInfo) {
commit-queue@webkit.orgeb2209e2013-01-28 18:36:28 +00001598 ASSERT(exclusionShapeInsideInfo->owner() == this || allowsExclusionShapeInsideInfoSharing());
commit-queue@webkit.org3a988eb2012-09-26 19:55:35 +00001599 if (exclusionShapeInsideInfo != this->exclusionShapeInsideInfo()) {
commit-queue@webkit.org5fe2dfd2012-10-26 19:57:52 +00001600 // FIXME Bug 100284: If subsequent LayoutStates are pushed, we will have to add
1601 // their offsets from the original shape-inside container.
1602 absoluteLogicalTop = logicalTop();
commit-queue@webkit.org3b26f3d2012-09-25 18:22:39 +00001603 }
1604 // Begin layout at the logical top of our shape inside.
commit-queue@webkit.org3a988eb2012-09-26 19:55:35 +00001605 if (logicalHeight() + absoluteLogicalTop < exclusionShapeInsideInfo->shapeLogicalTop())
1606 setLogicalHeight(exclusionShapeInsideInfo->shapeLogicalTop() - absoluteLogicalTop);
commit-queue@webkit.org3b26f3d2012-09-25 18:22:39 +00001607 }
zoltan@webkit.org59c70cf2013-03-28 21:01:49 +00001608
1609 if (layoutState.flowThread()) {
1610 // In a flow thread we need to update absoluteLogicalTop in every run to match to the current logical top increased by the height of the current line to calculate the right values for the
1611 // actual shape when a line is beginning in a new region which has a shape on it. Usecase: shape-inside is applied not on the first, but on either of the following regions in the region chain.
1612 absoluteLogicalTop = logicalTop() + lineHeight(layoutState.lineInfo().isFirstLine(), isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
1613 }
commit-queue@webkit.orgb3540512012-08-24 18:48:49 +00001614#endif
1615
eric@webkit.org060caf62011-05-03 22:11:39 +00001616 while (!end.atEnd()) {
1617 // FIXME: Is this check necessary before the first iteration or can it be moved to the end?
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001618 if (checkForEndLineMatch) {
1619 layoutState.setEndLineMatched(matchedEndLine(layoutState, resolver, cleanLineStart, cleanLineBidiStatus));
rniwa@webkit.org7daa12d2011-12-02 02:39:14 +00001620 if (layoutState.endLineMatched()) {
1621 resolver.setPosition(InlineIterator(resolver.position().root(), 0, 0), 0);
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001622 break;
rniwa@webkit.org7daa12d2011-12-02 02:39:14 +00001623 }
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001624 }
eric@webkit.org060caf62011-05-03 22:11:39 +00001625
1626 lineMidpointState.reset();
1627
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001628 layoutState.lineInfo().setEmpty(true);
robert@webkit.org8cbab142011-12-30 20:58:29 +00001629 layoutState.lineInfo().resetRunsFromLeadingWhitespace();
eric@webkit.org060caf62011-05-03 22:11:39 +00001630
rniwa@webkit.org53d106b2011-11-30 22:33:20 +00001631 const InlineIterator oldEnd = end;
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001632 bool isNewUBAParagraph = layoutState.lineInfo().previousLineBrokeCleanly();
mihnea@adobe.com99467792013-03-19 09:09:04 +00001633 FloatingObject* lastFloatFromPreviousLine = (containsFloats()) ? m_floatingObjects->set().last() : 0;
commit-queue@webkit.orgb3540512012-08-24 18:48:49 +00001634#if ENABLE(CSS_EXCLUSIONS)
commit-queue@webkit.org2d53dd52012-09-26 03:38:54 +00001635 // FIXME: Bug 95361: It is possible for a line to grow beyond lineHeight, in which
1636 // case these segments may be incorrect.
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00001637 if (layoutState.flowThread())
betravis@adobe.coma53af342013-03-01 21:02:16 +00001638 exclusionShapeInsideInfo = layoutExclusionShapeInsideInfo();
commit-queue@webkit.org3a988eb2012-09-26 19:55:35 +00001639 if (exclusionShapeInsideInfo) {
commit-queue@webkit.org2d53dd52012-09-26 03:38:54 +00001640 LayoutUnit lineTop = logicalHeight() + absoluteLogicalTop;
commit-queue@webkit.org849e71b2012-10-22 20:14:09 +00001641 exclusionShapeInsideInfo->computeSegmentsForLine(lineTop, lineHeight(layoutState.lineInfo().isFirstLine(), isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
commit-queue@webkit.org2d53dd52012-09-26 03:38:54 +00001642 }
commit-queue@webkit.orgb3540512012-08-24 18:48:49 +00001643#endif
enrica@apple.com885c84d2012-10-10 05:48:51 +00001644 WordMeasurements wordMeasurements;
1645 end = lineBreaker.nextLineBreak(resolver, layoutState.lineInfo(), renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
glenn@skynav.com61b1abf2013-04-02 23:28:32 +00001646 renderTextInfo.m_lineBreakIterator.resetPriorContext();
eric@webkit.org060caf62011-05-03 22:11:39 +00001647 if (resolver.position().atEnd()) {
leviw@chromium.orge7812f32012-02-07 23:46:40 +00001648 // FIXME: We shouldn't be creating any runs in nextLineBreak to begin with!
eric@webkit.org060caf62011-05-03 22:11:39 +00001649 // Once BidiRunList is separated from BidiResolver this will not be needed.
1650 resolver.runs().deleteRuns();
1651 resolver.markCurrentRunEmpty(); // FIXME: This can probably be replaced by an ASSERT (or just removed).
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001652 layoutState.setCheckForFloatsFromLastLine(true);
rniwa@webkit.org7daa12d2011-12-02 02:39:14 +00001653 resolver.setPosition(InlineIterator(resolver.position().root(), 0, 0), 0);
eric@webkit.org060caf62011-05-03 22:11:39 +00001654 break;
1655 }
1656 ASSERT(end != resolver.position());
1657
commit-queue@webkit.org4055b2e2012-12-06 19:05:15 +00001658#if ENABLE(CSS_EXCLUSIONS)
1659 if (exclusionShapeInsideInfo && wordMeasurements.size() && exclusionShapeInsideInfo->adjustLogicalLineTop(wordMeasurements[0].width)) {
1660 end = restartLayoutRunsAndFloatsInRange(logicalHeight(), exclusionShapeInsideInfo->logicalLineTop() - absoluteLogicalTop, lastFloatFromPreviousLine, resolver, oldEnd);
1661 continue;
1662 }
1663#endif
1664
eric@webkit.org45e33a52011-05-04 11:51:09 +00001665 // This is a short-cut for empty lines.
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001666 if (layoutState.lineInfo().isEmpty()) {
eric@webkit.org060caf62011-05-03 22:11:39 +00001667 if (lastRootBox())
1668 lastRootBox()->setLineBreakInfo(end.m_obj, end.m_pos, resolver.status());
1669 } else {
mihnea@adobe.com3bebbf22012-01-19 09:22:59 +00001670 VisualDirectionOverride override = (styleToUse->rtlOrdering() == VisualOrder ? (styleToUse->direction() == LTR ? VisualLeftToRightOverride : VisualRightToLeftOverride) : NoVisualOverride);
leviw@chromium.org7781b6a2011-06-27 22:01:38 +00001671
mihnea@adobe.com3bebbf22012-01-19 09:22:59 +00001672 if (isNewUBAParagraph && styleToUse->unicodeBidi() == Plaintext && !resolver.context()->parent()) {
1673 TextDirection direction = styleToUse->direction();
leviw@chromium.orge7812f32012-02-07 23:46:40 +00001674 determineDirectionality(direction, resolver.position());
rniwa@webkit.orgc275acf2012-03-05 23:09:22 +00001675 resolver.setStatus(BidiStatus(direction, isOverride(styleToUse->unicodeBidi())));
leviw@chromium.org7781b6a2011-06-27 22:01:38 +00001676 }
eric@webkit.org060caf62011-05-03 22:11:39 +00001677 // FIXME: This ownership is reversed. We should own the BidiRunList and pass it to createBidiRunsForLine.
1678 BidiRunList<BidiRun>& bidiRuns = resolver.runs();
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00001679 constructBidiRunsForLine(this, resolver, bidiRuns, end, override, layoutState.lineInfo().previousLineBrokeCleanly());
eric@webkit.org060caf62011-05-03 22:11:39 +00001680 ASSERT(resolver.position() == end);
1681
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001682 BidiRun* trailingSpaceRun = !layoutState.lineInfo().previousLineBrokeCleanly() ? handleTrailingSpaces(bidiRuns, resolver.context()) : 0;
eric@webkit.org060caf62011-05-03 22:11:39 +00001683
mitz@apple.com10ed3cb2011-09-07 20:59:39 +00001684 if (bidiRuns.runCount() && lineBreaker.lineWasHyphenated()) {
eric@webkit.org45e33a52011-05-04 11:51:09 +00001685 bidiRuns.logicallyLastRun()->m_hasHyphen = true;
mitz@apple.com10ed3cb2011-09-07 20:59:39 +00001686 consecutiveHyphenatedLines++;
1687 } else
1688 consecutiveHyphenatedLines = 0;
eric@webkit.org45e33a52011-05-04 11:51:09 +00001689
eric@webkit.org060caf62011-05-03 22:11:39 +00001690 // Now that the runs have been ordered, we create the line boxes.
1691 // At the same time we figure out where border/padding/margin should be applied for
1692 // inline flow boxes.
1693
eae@chromium.orgee8613e2011-11-12 01:12:58 +00001694 LayoutUnit oldLogicalHeight = logicalHeight();
enrica@apple.com885c84d2012-10-10 05:48:51 +00001695 RootInlineBox* lineBox = createLineBoxesFromBidiRuns(bidiRuns, end, layoutState.lineInfo(), verticalPositionCache, trailingSpaceRun, wordMeasurements);
eric@webkit.org060caf62011-05-03 22:11:39 +00001696
1697 bidiRuns.deleteRuns();
1698 resolver.markCurrentRunEmpty(); // FIXME: This can probably be replaced by an ASSERT (or just removed).
1699
1700 if (lineBox) {
1701 lineBox->setLineBreakInfo(end.m_obj, end.m_pos, resolver.status());
commit-queue@webkit.org49ad4732011-07-15 07:23:01 +00001702 if (layoutState.usesRepaintBounds())
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001703 layoutState.updateRepaintRangeFromBox(lineBox);
eric@webkit.org060caf62011-05-03 22:11:39 +00001704
1705 if (paginated) {
eae@chromium.orgee8613e2011-11-12 01:12:58 +00001706 LayoutUnit adjustment = 0;
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00001707 adjustLinePositionForPagination(lineBox, adjustment, layoutState.flowThread());
eric@webkit.org060caf62011-05-03 22:11:39 +00001708 if (adjustment) {
eae@chromium.orgee8613e2011-11-12 01:12:58 +00001709 LayoutUnit oldLineWidth = availableLogicalWidthForLine(oldLogicalHeight, layoutState.lineInfo().isFirstLine());
eric@webkit.org060caf62011-05-03 22:11:39 +00001710 lineBox->adjustBlockDirectionPosition(adjustment);
commit-queue@webkit.org49ad4732011-07-15 07:23:01 +00001711 if (layoutState.usesRepaintBounds())
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001712 layoutState.updateRepaintRangeFromBox(lineBox);
eric@webkit.org060caf62011-05-03 22:11:39 +00001713
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001714 if (availableLogicalWidthForLine(oldLogicalHeight + adjustment, layoutState.lineInfo().isFirstLine()) != oldLineWidth) {
eric@webkit.org060caf62011-05-03 22:11:39 +00001715 // We have to delete this line, remove all floats that got added, and let line layout re-run.
1716 lineBox->deleteLine(renderArena());
commit-queue@webkit.org4055b2e2012-12-06 19:05:15 +00001717 end = restartLayoutRunsAndFloatsInRange(oldLogicalHeight, oldLogicalHeight + adjustment, lastFloatFromPreviousLine, resolver, oldEnd);
eric@webkit.org060caf62011-05-03 22:11:39 +00001718 continue;
1719 }
1720
hyatt@apple.com7ce0d422011-08-30 16:57:37 +00001721 setLogicalHeight(lineBox->lineBottomWithLeading());
eric@webkit.org060caf62011-05-03 22:11:39 +00001722 }
commit-queue@webkit.orgbe554b22012-11-26 20:00:49 +00001723
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00001724 if (layoutState.flowThread())
commit-queue@webkit.orgbe554b22012-11-26 20:00:49 +00001725 lineBox->setContainingRegion(regionAtBlockOffset(lineBox->lineTopWithLeading()));
eric@webkit.org060caf62011-05-03 22:11:39 +00001726 }
1727 }
robert@webkit.org402c1512013-02-07 18:48:39 +00001728 }
eric@webkit.org060caf62011-05-03 22:11:39 +00001729
robert@webkit.org402c1512013-02-07 18:48:39 +00001730 for (size_t i = 0; i < lineBreaker.positionedObjects().size(); ++i)
1731 setStaticPositions(this, lineBreaker.positionedObjects()[i]);
eric@webkit.org060caf62011-05-03 22:11:39 +00001732
robert@webkit.org402c1512013-02-07 18:48:39 +00001733 if (!layoutState.lineInfo().isEmpty()) {
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001734 layoutState.lineInfo().setFirstLine(false);
leviw@chromium.org1a508692011-05-05 00:01:11 +00001735 newLine(lineBreaker.clear());
eric@webkit.org060caf62011-05-03 22:11:39 +00001736 }
1737
1738 if (m_floatingObjects && lastRootBox()) {
hyatt@apple.com46c65b32011-08-09 19:13:45 +00001739 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
eric@webkit.org060caf62011-05-03 22:11:39 +00001740 FloatingObjectSetIterator it = floatingObjectSet.begin();
1741 FloatingObjectSetIterator end = floatingObjectSet.end();
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001742 if (layoutState.lastFloat()) {
1743 FloatingObjectSetIterator lastFloatIterator = floatingObjectSet.find(layoutState.lastFloat());
eric@webkit.org060caf62011-05-03 22:11:39 +00001744 ASSERT(lastFloatIterator != end);
1745 ++lastFloatIterator;
1746 it = lastFloatIterator;
1747 }
1748 for (; it != end; ++it) {
1749 FloatingObject* f = *it;
1750 appendFloatingObjectToLastLine(f);
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001751 ASSERT(f->m_renderer == layoutState.floats()[layoutState.floatIndex()].object);
eric@webkit.org060caf62011-05-03 22:11:39 +00001752 // If a float's geometry has changed, give up on syncing with clean lines.
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001753 if (layoutState.floats()[layoutState.floatIndex()].rect != f->frameRect())
eric@webkit.org060caf62011-05-03 22:11:39 +00001754 checkForEndLineMatch = false;
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001755 layoutState.setFloatIndex(layoutState.floatIndex() + 1);
eric@webkit.org060caf62011-05-03 22:11:39 +00001756 }
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001757 layoutState.setLastFloat(!floatingObjectSet.isEmpty() ? floatingObjectSet.last() : 0);
eric@webkit.org060caf62011-05-03 22:11:39 +00001758 }
1759
1760 lineMidpointState.reset();
rniwa@webkit.org53d106b2011-11-30 22:33:20 +00001761 resolver.setPosition(end, numberOfIsolateAncestors(end));
eric@webkit.org060caf62011-05-03 22:11:39 +00001762 }
dino@apple.comfde5fdf2012-12-10 21:22:44 +00001763
1764 if (paginated && !style()->hasAutoWidows()) {
1765 // Check the line boxes to make sure we didn't create unacceptable widows.
1766 // However, we'll prioritize orphans - so nothing we do here should create
1767 // a new orphan.
1768
1769 RootInlineBox* lineBox = lastRootBox();
1770
1771 // Count from the end of the block backwards, to see how many hanging
1772 // lines we have.
1773 RootInlineBox* firstLineInBlock = firstRootBox();
1774 int numLinesHanging = 1;
1775 while (lineBox && lineBox != firstLineInBlock && !lineBox->isFirstAfterPageBreak()) {
1776 ++numLinesHanging;
1777 lineBox = lineBox->prevRootBox();
1778 }
1779
1780 // If there were no breaks in the block, we didn't create any widows.
jchaffraix@webkit.org0f225142013-01-28 22:28:21 +00001781 if (!lineBox || !lineBox->isFirstAfterPageBreak() || lineBox == firstLineInBlock)
dino@apple.comfde5fdf2012-12-10 21:22:44 +00001782 return;
1783
1784 if (numLinesHanging < style()->widows()) {
1785 // We have detected a widow. Now we need to work out how many
1786 // lines there are on the previous page, and how many we need
1787 // to steal.
1788 int numLinesNeeded = style()->widows() - numLinesHanging;
1789 RootInlineBox* currentFirstLineOfNewPage = lineBox;
1790
1791 // Count the number of lines in the previous page.
1792 lineBox = lineBox->prevRootBox();
1793 int numLinesInPreviousPage = 1;
1794 while (lineBox && lineBox != firstLineInBlock && !lineBox->isFirstAfterPageBreak()) {
1795 ++numLinesInPreviousPage;
1796 lineBox = lineBox->prevRootBox();
1797 }
1798
1799 // If there was an explicit value for orphans, respect that. If not, we still
1800 // shouldn't create a situation where we make an orphan bigger than the initial value.
1801 // This means that setting widows implies we also care about orphans, but given
1802 // the specification says the initial orphan value is non-zero, this is ok. The
1803 // author is always free to set orphans explicitly as well.
1804 int orphans = style()->hasAutoOrphans() ? style()->initialOrphans() : style()->orphans();
1805 int numLinesAvailable = numLinesInPreviousPage - orphans;
1806 if (numLinesAvailable <= 0)
1807 return;
1808
1809 int numLinesToTake = min(numLinesAvailable, numLinesNeeded);
1810 // Wind back from our first widowed line.
1811 lineBox = currentFirstLineOfNewPage;
1812 for (int i = 0; i < numLinesToTake; ++i)
1813 lineBox = lineBox->prevRootBox();
1814
1815 // We now want to break at this line. Remember for next layout and trigger relayout.
1816 setBreakAtLineToAvoidWidow(lineBox);
1817 markLinesDirtyInBlockRange(lastRootBox()->lineBottomWithLeading(), lineBox->lineBottomWithLeading(), lineBox);
1818 }
1819 }
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001820}
eric@webkit.org060caf62011-05-03 22:11:39 +00001821
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001822void RenderBlock::linkToEndLineIfNeeded(LineLayoutState& layoutState)
1823{
1824 if (layoutState.endLine()) {
1825 if (layoutState.endLineMatched()) {
1826 bool paginated = view()->layoutState() && view()->layoutState()->isPaginated();
eric@webkit.org060caf62011-05-03 22:11:39 +00001827 // Attach all the remaining lines, and then adjust their y-positions as needed.
eae@chromium.orgee8613e2011-11-12 01:12:58 +00001828 LayoutUnit delta = logicalHeight() - layoutState.endLineLogicalTop();
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001829 for (RootInlineBox* line = layoutState.endLine(); line; line = line->nextRootBox()) {
eric@webkit.org060caf62011-05-03 22:11:39 +00001830 line->attachLine();
1831 if (paginated) {
1832 delta -= line->paginationStrut();
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00001833 adjustLinePositionForPagination(line, delta, layoutState.flowThread());
eric@webkit.org060caf62011-05-03 22:11:39 +00001834 }
1835 if (delta) {
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001836 layoutState.updateRepaintRangeFromBox(line, delta);
eric@webkit.org060caf62011-05-03 22:11:39 +00001837 line->adjustBlockDirectionPosition(delta);
1838 }
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00001839 if (layoutState.flowThread())
commit-queue@webkit.orgbe554b22012-11-26 20:00:49 +00001840 line->setContainingRegion(regionAtBlockOffset(line->lineTopWithLeading()));
eric@webkit.org060caf62011-05-03 22:11:39 +00001841 if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) {
1842 Vector<RenderBox*>::iterator end = cleanLineFloats->end();
1843 for (Vector<RenderBox*>::iterator f = cleanLineFloats->begin(); f != end; ++f) {
mitz@apple.com0c4ce9f2011-05-04 02:20:02 +00001844 FloatingObject* floatingObject = insertFloatingObject(*f);
1845 ASSERT(!floatingObject->m_originatingLine);
1846 floatingObject->m_originatingLine = line;
eric@webkit.org060caf62011-05-03 22:11:39 +00001847 setLogicalHeight(logicalTopForChild(*f) - marginBeforeForChild(*f) + delta);
1848 positionNewFloats();
1849 }
1850 }
1851 }
hyatt@apple.com7ce0d422011-08-30 16:57:37 +00001852 setLogicalHeight(lastRootBox()->lineBottomWithLeading());
eric@webkit.org060caf62011-05-03 22:11:39 +00001853 } else {
1854 // Delete all the remaining lines.
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001855 deleteLineRange(layoutState, renderArena(), layoutState.endLine());
eric@webkit.org060caf62011-05-03 22:11:39 +00001856 }
1857 }
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001858
1859 if (m_floatingObjects && (layoutState.checkForFloatsFromLastLine() || positionNewFloats()) && lastRootBox()) {
eric@webkit.org060caf62011-05-03 22:11:39 +00001860 // In case we have a float on the last line, it might not be positioned up to now.
1861 // This has to be done before adding in the bottom border/padding, or the float will
1862 // include the padding incorrectly. -dwh
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001863 if (layoutState.checkForFloatsFromLastLine()) {
leviw@chromium.orgd32486e2012-03-16 10:52:56 +00001864 LayoutUnit bottomVisualOverflow = lastRootBox()->logicalBottomVisualOverflow();
1865 LayoutUnit bottomLayoutOverflow = lastRootBox()->logicalBottomLayoutOverflow();
eric@webkit.org060caf62011-05-03 22:11:39 +00001866 TrailingFloatsRootInlineBox* trailingFloatsLineBox = new (renderArena()) TrailingFloatsRootInlineBox(this);
1867 m_lineBoxes.appendLineBox(trailingFloatsLineBox);
1868 trailingFloatsLineBox->setConstructed();
1869 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
1870 VerticalPositionCache verticalPositionCache;
leviw@chromium.orgd32486e2012-03-16 10:52:56 +00001871 LayoutUnit blockLogicalHeight = logicalHeight();
hyatt@apple.coma8b5b822011-09-07 18:48:07 +00001872 trailingFloatsLineBox->alignBoxesInBlockDirection(blockLogicalHeight, textBoxDataMap, verticalPositionCache);
1873 trailingFloatsLineBox->setLineTopBottomPositions(blockLogicalHeight, blockLogicalHeight, blockLogicalHeight, blockLogicalHeight);
hyatt@apple.com0c6cd7a2011-09-22 20:50:41 +00001874 trailingFloatsLineBox->setPaginatedLineWidth(availableLogicalWidthForContent(blockLogicalHeight));
leviw@chromium.orgd32486e2012-03-16 10:52:56 +00001875 LayoutRect logicalLayoutOverflow(0, blockLogicalHeight, 1, bottomLayoutOverflow - blockLogicalHeight);
1876 LayoutRect logicalVisualOverflow(0, blockLogicalHeight, 1, bottomVisualOverflow - blockLogicalHeight);
eric@webkit.org060caf62011-05-03 22:11:39 +00001877 trailingFloatsLineBox->setOverflowFromLogicalRects(logicalLayoutOverflow, logicalVisualOverflow, trailingFloatsLineBox->lineTop(), trailingFloatsLineBox->lineBottom());
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00001878 if (layoutState.flowThread())
commit-queue@webkit.orgbe554b22012-11-26 20:00:49 +00001879 trailingFloatsLineBox->setContainingRegion(regionAtBlockOffset(trailingFloatsLineBox->lineTopWithLeading()));
eric@webkit.org060caf62011-05-03 22:11:39 +00001880 }
1881
hyatt@apple.com46c65b32011-08-09 19:13:45 +00001882 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
eric@webkit.org060caf62011-05-03 22:11:39 +00001883 FloatingObjectSetIterator it = floatingObjectSet.begin();
1884 FloatingObjectSetIterator end = floatingObjectSet.end();
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001885 if (layoutState.lastFloat()) {
1886 FloatingObjectSetIterator lastFloatIterator = floatingObjectSet.find(layoutState.lastFloat());
eric@webkit.org060caf62011-05-03 22:11:39 +00001887 ASSERT(lastFloatIterator != end);
1888 ++lastFloatIterator;
1889 it = lastFloatIterator;
1890 }
1891 for (; it != end; ++it)
1892 appendFloatingObjectToLastLine(*it);
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001893 layoutState.setLastFloat(!floatingObjectSet.isEmpty() ? floatingObjectSet.last() : 0);
eric@webkit.org060caf62011-05-03 22:11:39 +00001894 }
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001895}
1896
1897void RenderBlock::repaintDirtyFloats(Vector<FloatWithRect>& floats)
1898{
eric@webkit.org060caf62011-05-03 22:11:39 +00001899 size_t floatCount = floats.size();
1900 // Floats that did not have layout did not repaint when we laid them out. They would have
1901 // painted by now if they had moved, but if they stayed at (0, 0), they still need to be
1902 // painted.
1903 for (size_t i = 0; i < floatCount; ++i) {
1904 if (!floats[i].everHadLayout) {
1905 RenderBox* f = floats[i].object;
1906 if (!f->x() && !f->y() && f->checkForRepaintDuringLayout())
1907 f->repaint();
1908 }
1909 }
1910}
1911
eae@chromium.orgee8613e2011-11-12 01:12:58 +00001912void RenderBlock::layoutInlineChildren(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
jamesr@google.com19548ad2010-04-02 23:21:35 +00001913{
hyatt@apple.com81c1d742010-10-06 21:44:02 +00001914 setLogicalHeight(borderBefore() + paddingBefore());
hyatt@apple.comee7af1d2012-01-17 19:16:24 +00001915
1916 // Lay out our hypothetical grid line as though it occurs at the top of the block.
hyatt@apple.com989d2172012-02-09 01:50:05 +00001917 if (view()->layoutState() && view()->layoutState()->lineGrid() == this)
hyatt@apple.comee7af1d2012-01-17 19:16:24 +00001918 layoutLineGridBox();
mitz@apple.come1364202008-02-28 01:06:41 +00001919
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00001920 RenderFlowThread* flowThread = flowThreadContainingBlock();
1921 bool clearLinesForPagination = firstLineBox() && flowThread && !flowThread->hasRegions();
commit-queue@webkit.org93cdd632012-12-07 00:33:56 +00001922
hyatt0c3a9862004-02-23 21:26:26 +00001923 // Figure out if we should clear out our line boxes.
1924 // FIXME: Handle resize eventually!
commit-queue@webkit.org93cdd632012-12-07 00:33:56 +00001925 bool isFullLayout = !firstLineBox() || selfNeedsLayout() || relayoutChildren || clearLinesForPagination;
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00001926 LineLayoutState layoutState(isFullLayout, repaintLogicalTop, repaintLogicalBottom, flowThread);
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001927
1928 if (isFullLayout)
inferno@chromium.orgf5af4c42012-02-26 18:06:55 +00001929 lineBoxes()->deleteLineBoxes(renderArena());
mitz@apple.come1364202008-02-28 01:06:41 +00001930
commit-queue@webkit.org07797312013-02-22 18:58:19 +00001931 // Text truncation kicks in in two cases:
1932 // 1) If your overflow isn't visible and your text-overflow-mode isn't clip.
1933 // 2) If you're an anonymous block with a block parent that satisfies #1.
hyatted77ad82004-06-15 07:21:23 +00001934 // FIXME: CSS3 says that descendants that are clipped must also know how to truncate. This is insanely
commit-queue@webkit.org07797312013-02-22 18:58:19 +00001935 // difficult to figure out in general (especially in the middle of doing layout), so we only handle the
1936 // simple case of an anonymous block truncating when it's parent is clipped.
1937 bool hasTextOverflow = (style()->textOverflow() && hasOverflowClip())
1938 || (isAnonymousBlock() && parent() && parent()->isRenderBlock() && parent()->style()->textOverflow() && parent()->hasOverflowClip());
mitz@apple.come1364202008-02-28 01:06:41 +00001939
hyatted77ad82004-06-15 07:21:23 +00001940 // Walk all the lines and delete our ellipsis line boxes if they exist.
1941 if (hasTextOverflow)
1942 deleteEllipsisLineBoxes();
1943
hyattffe78712003-02-11 01:59:29 +00001944 if (firstChild()) {
inferno@chromium.org13563122012-08-16 20:50:05 +00001945 // In full layout mode, clear the line boxes of children upfront. Otherwise,
1946 // siblings can run into stale root lineboxes during layout. Then layout
1947 // the replaced elements later. In partial layout mode, line boxes are not
1948 // deleted and only dirtied. In that case, we can layout the replaced
1949 // elements at the same time.
abarth@webkit.org31d23df2010-04-05 21:52:09 +00001950 bool hasInlineChild = false;
inferno@chromium.org13563122012-08-16 20:50:05 +00001951 Vector<RenderBox*> replacedChildren;
eric@webkit.org33510472011-06-04 19:34:29 +00001952 for (InlineWalker walker(this); !walker.atEnd(); walker.advance()) {
1953 RenderObject* o = walker.current();
commit-queue@webkit.orgcf45df92010-09-14 13:25:06 +00001954 if (!hasInlineChild && o->isInline())
1955 hasInlineChild = true;
1956
simon.fraser@apple.com2f071852012-06-25 00:11:30 +00001957 if (o->isReplaced() || o->isFloating() || o->isOutOfFlowPositioned()) {
abarth@webkit.org31d23df2010-04-05 21:52:09 +00001958 RenderBox* box = toRenderBox(o);
eric@webkit.org060caf62011-05-03 22:11:39 +00001959
commit-queue@webkit.orgb6cbe4f2012-02-28 16:01:19 +00001960 if (relayoutChildren || box->hasRelativeDimensions())
eric@webkit.org218b4e02012-03-28 19:25:02 +00001961 o->setChildNeedsLayout(true, MarkOnlyThis);
eric@webkit.org060caf62011-05-03 22:11:39 +00001962
zimmermann@webkit.orgac68af42011-06-15 08:02:37 +00001963 // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
1964 if (relayoutChildren && box->needsPreferredWidthsRecalculation())
eric@webkit.org218b4e02012-03-28 19:25:02 +00001965 o->setPreferredLogicalWidthsDirty(true, MarkOnlyThis);
eric@webkit.org060caf62011-05-03 22:11:39 +00001966
simon.fraser@apple.com2f071852012-06-25 00:11:30 +00001967 if (o->isOutOfFlowPositioned())
abarth@webkit.org31d23df2010-04-05 21:52:09 +00001968 o->containingBlock()->insertPositionedObject(box);
hyatt@apple.comcc1737c2010-09-16 20:20:02 +00001969 else if (o->isFloating())
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001970 layoutState.floats().append(FloatWithRect(box));
inferno@chromium.org13563122012-08-16 20:50:05 +00001971 else if (isFullLayout || o->needsLayout()) {
1972 // Replaced element.
1973 box->dirtyLineBoxes(isFullLayout);
1974 if (isFullLayout)
1975 replacedChildren.append(box);
1976 else
1977 o->layoutIfNeeded();
abarth@webkit.org31d23df2010-04-05 21:52:09 +00001978 }
eric@webkit.org33510472011-06-04 19:34:29 +00001979 } else if (o->isText() || (o->isRenderInline() && !walker.atEndOfInline())) {
hyatt@apple.coma61b8a32011-04-06 18:20:52 +00001980 if (!o->isText())
inferno@chromium.org88a424d2011-08-09 18:18:36 +00001981 toRenderInline(o)->updateAlwaysCreateLineBoxes(layoutState.isFullLayout());
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001982 if (layoutState.isFullLayout() || o->selfNeedsLayout())
1983 dirtyLineBoxesForRenderer(o, layoutState.isFullLayout());
abarth@webkit.org31d23df2010-04-05 21:52:09 +00001984 o->setNeedsLayout(false);
abarth@webkit.org31d23df2010-04-05 21:52:09 +00001985 }
abarth@webkit.org31d23df2010-04-05 21:52:09 +00001986 }
1987
inferno@chromium.orgba2dceb2012-08-21 00:09:47 +00001988 for (size_t i = 0; i < replacedChildren.size(); i++)
1989 replacedChildren[i]->layoutIfNeeded();
inferno@chromium.org13563122012-08-16 20:50:05 +00001990
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001991 layoutRunsAndFloats(layoutState, hasInlineChild);
kociendabb0c24b2001-08-24 14:24:40 +00001992 }
hyatt85586af2003-02-19 23:22:42 +00001993
mitz@apple.com3672d9e2010-12-17 19:31:16 +00001994 // Expand the last line to accommodate Ruby and emphasis marks.
1995 int lastLineAnnotationsAdjustment = 0;
1996 if (lastRootBox()) {
leviw@chromium.orgd32486e2012-03-16 10:52:56 +00001997 LayoutUnit lowestAllowedPosition = max(lastRootBox()->lineBottom(), logicalHeight() + paddingAfter());
mitz@apple.com3672d9e2010-12-17 19:31:16 +00001998 if (!style()->isFlippedLinesWritingMode())
1999 lastLineAnnotationsAdjustment = lastRootBox()->computeUnderAnnotationAdjustment(lowestAllowedPosition);
2000 else
2001 lastLineAnnotationsAdjustment = lastRootBox()->computeOverAnnotationAdjustment(lowestAllowedPosition);
hyatt@apple.com5e48ff52010-11-19 00:43:29 +00002002 }
mitz@apple.com3672d9e2010-12-17 19:31:16 +00002003
hyatta70560a2002-11-20 01:53:20 +00002004 // Now add in the bottom border/padding.
mitz@apple.com3672d9e2010-12-17 19:31:16 +00002005 setLogicalHeight(logicalHeight() + lastLineAnnotationsAdjustment + borderAfter() + paddingAfter() + scrollbarLogicalHeight());
kociendabb0c24b2001-08-24 14:24:40 +00002006
adele7a470a72006-04-20 22:22:14 +00002007 if (!firstLineBox() && hasLineIfEmpty())
hyatt@apple.com2a5eb212011-03-22 23:21:54 +00002008 setLogicalHeight(logicalHeight() + lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
hyatted77ad82004-06-15 07:21:23 +00002009
2010 // See if we have any lines that spill out of our block. If we do, then we will possibly need to
2011 // truncate text.
2012 if (hasTextOverflow)
2013 checkLinesForTextOverflow();
kociendabb0c24b2001-08-24 14:24:40 +00002014}
2015
mitz@apple.comd9ccfeb2011-03-10 01:56:27 +00002016void RenderBlock::checkFloatsInCleanLine(RootInlineBox* line, Vector<FloatWithRect>& floats, size_t& floatIndex, bool& encounteredNewFloat, bool& dirtiedByFloat)
2017{
2018 Vector<RenderBox*>* cleanLineFloats = line->floatsPtr();
2019 if (!cleanLineFloats)
2020 return;
2021
2022 Vector<RenderBox*>::iterator end = cleanLineFloats->end();
2023 for (Vector<RenderBox*>::iterator it = cleanLineFloats->begin(); it != end; ++it) {
2024 RenderBox* floatingBox = *it;
2025 floatingBox->layoutIfNeeded();
tkent@chromium.orgb27646b2012-03-08 03:31:25 +00002026 LayoutSize newSize(floatingBox->width() + floatingBox->marginWidth(), floatingBox->height() + floatingBox->marginHeight());
inferno@chromium.orga227be62013-02-11 08:06:45 +00002027 ASSERT_WITH_SECURITY_IMPLICATION(floatIndex < floats.size());
mitz@apple.comd9ccfeb2011-03-10 01:56:27 +00002028 if (floats[floatIndex].object != floatingBox) {
2029 encounteredNewFloat = true;
2030 return;
2031 }
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00002032
mitz@apple.comd9ccfeb2011-03-10 01:56:27 +00002033 if (floats[floatIndex].rect.size() != newSize) {
eae@chromium.orgee8613e2011-11-12 01:12:58 +00002034 LayoutUnit floatTop = isHorizontalWritingMode() ? floats[floatIndex].rect.y() : floats[floatIndex].rect.x();
2035 LayoutUnit floatHeight = isHorizontalWritingMode() ? max(floats[floatIndex].rect.height(), newSize.height())
mitz@apple.comd9ccfeb2011-03-10 01:56:27 +00002036 : max(floats[floatIndex].rect.width(), newSize.width());
eae@chromium.org9717cd82012-11-07 18:33:44 +00002037 floatHeight = min(floatHeight, LayoutUnit::max() - floatTop);
mitz@apple.comd9ccfeb2011-03-10 01:56:27 +00002038 line->markDirty();
hyatt@apple.com7ce0d422011-08-30 16:57:37 +00002039 markLinesDirtyInBlockRange(line->lineBottomWithLeading(), floatTop + floatHeight, line);
mitz@apple.comd9ccfeb2011-03-10 01:56:27 +00002040 floats[floatIndex].rect.setSize(newSize);
2041 dirtiedByFloat = true;
2042 }
2043 floatIndex++;
2044 }
2045}
2046
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002047RootInlineBox* RenderBlock::determineStartPosition(LineLayoutState& layoutState, InlineBidiResolver& resolver)
hyatt0c3a9862004-02-23 21:26:26 +00002048{
2049 RootInlineBox* curr = 0;
2050 RootInlineBox* last = 0;
mitz@apple.come1364202008-02-28 01:06:41 +00002051
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00002052 // FIXME: This entire float-checking block needs to be broken into a new function.
mitz@apple.com40547b32008-03-18 04:04:34 +00002053 bool dirtiedByFloat = false;
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00002054 if (!layoutState.isFullLayout()) {
hyatt@apple.comcc1737c2010-09-16 20:20:02 +00002055 // Paginate all of the clean lines.
2056 bool paginated = view()->layoutState() && view()->layoutState()->isPaginated();
eae@chromium.orgee8613e2011-11-12 01:12:58 +00002057 LayoutUnit paginationDelta = 0;
mitz@apple.com40547b32008-03-18 04:04:34 +00002058 size_t floatIndex = 0;
2059 for (curr = firstRootBox(); curr && !curr->isDirty(); curr = curr->nextRootBox()) {
hyatt@apple.comcc1737c2010-09-16 20:20:02 +00002060 if (paginated) {
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00002061 if (lineWidthForPaginatedLineChanged(curr, 0, layoutState.flowThread())) {
hyatt@apple.com0c6cd7a2011-09-22 20:50:41 +00002062 curr->markDirty();
2063 break;
2064 }
hyatt@apple.comcc1737c2010-09-16 20:20:02 +00002065 paginationDelta -= curr->paginationStrut();
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00002066 adjustLinePositionForPagination(curr, paginationDelta, layoutState.flowThread());
hyatt@apple.comcc1737c2010-09-16 20:20:02 +00002067 if (paginationDelta) {
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002068 if (containsFloats() || !layoutState.floats().isEmpty()) {
hyatt@apple.comcc1737c2010-09-16 20:20:02 +00002069 // FIXME: Do better eventually. For now if we ever shift because of pagination and floats are present just go to a full layout.
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00002070 layoutState.markForFullLayout();
hyatt@apple.comcc1737c2010-09-16 20:20:02 +00002071 break;
2072 }
eric@webkit.org060caf62011-05-03 22:11:39 +00002073
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00002074 layoutState.updateRepaintRangeFromBox(curr, paginationDelta);
hyatt@apple.com61bbedf2011-01-26 23:10:57 +00002075 curr->adjustBlockDirectionPosition(paginationDelta);
eric@webkit.org060caf62011-05-03 22:11:39 +00002076 }
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00002077 if (layoutState.flowThread())
commit-queue@webkit.orgbe554b22012-11-26 20:00:49 +00002078 curr->setContainingRegion(regionAtBlockOffset(curr->lineTopWithLeading()));
hyatt@apple.comcc1737c2010-09-16 20:20:02 +00002079 }
mitz@apple.comd9ccfeb2011-03-10 01:56:27 +00002080
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00002081 // If a new float has been inserted before this line or before its last known float, just do a full layout.
2082 bool encounteredNewFloat = false;
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002083 checkFloatsInCleanLine(curr, layoutState.floats(), floatIndex, encounteredNewFloat, dirtiedByFloat);
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00002084 if (encounteredNewFloat)
2085 layoutState.markForFullLayout();
2086
2087 if (dirtiedByFloat || layoutState.isFullLayout())
mitz@apple.com40547b32008-03-18 04:04:34 +00002088 break;
2089 }
2090 // Check if a new float has been inserted after the last known float.
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002091 if (!curr && floatIndex < layoutState.floats().size())
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00002092 layoutState.markForFullLayout();
mitz@apple.com40547b32008-03-18 04:04:34 +00002093 }
2094
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00002095 if (layoutState.isFullLayout()) {
eric@webkit.orge2532d92011-05-16 23:10:49 +00002096 // FIXME: This should just call deleteLineBoxTree, but that causes
2097 // crashes for fast/repaint tests.
2098 RenderArena* arena = renderArena();
2099 curr = firstRootBox();
2100 while (curr) {
2101 // Note: This uses nextRootBox() insted of nextLineBox() like deleteLineBoxTree does.
2102 RootInlineBox* next = curr->nextRootBox();
2103 curr->deleteLine(arena);
2104 curr = next;
hyatt0c3a9862004-02-23 21:26:26 +00002105 }
eric@webkit.orge2532d92011-05-16 23:10:49 +00002106 ASSERT(!firstLineBox() && !lastLineBox());
eseidel789896f2005-11-27 22:52:09 +00002107 } else {
hyatt0c3a9862004-02-23 21:26:26 +00002108 if (curr) {
2109 // We have a dirty line.
mjs9f78dd92007-02-12 04:06:07 +00002110 if (RootInlineBox* prevRootBox = curr->prevRootBox()) {
hyatt0c3a9862004-02-23 21:26:26 +00002111 // We have a previous line.
tasak@google.comfcfd96f2012-11-26 07:45:38 +00002112 if (!dirtiedByFloat && (!prevRootBox->endsWithBreak() || !prevRootBox->lineBreakObj() || (prevRootBox->lineBreakObj()->isText() && prevRootBox->lineBreakPos() >= toRenderText(prevRootBox->lineBreakObj())->textLength())))
mjs9f78dd92007-02-12 04:06:07 +00002113 // The previous line didn't break cleanly or broke at a newline
2114 // that has been deleted, so treat it as dirty too.
2115 curr = prevRootBox;
hyatt0c3a9862004-02-23 21:26:26 +00002116 }
eseidel789896f2005-11-27 22:52:09 +00002117 } else {
hyatt0c3a9862004-02-23 21:26:26 +00002118 // No dirty lines were found.
2119 // If the last line didn't break cleanly, treat it as dirty.
2120 if (lastRootBox() && !lastRootBox()->endsWithBreak())
2121 curr = lastRootBox();
2122 }
mitz@apple.come1364202008-02-28 01:06:41 +00002123
hyatt0c3a9862004-02-23 21:26:26 +00002124 // If we have no dirty lines, then last is just the last root box.
2125 last = curr ? curr->prevRootBox() : lastRootBox();
2126 }
mitz@apple.come1364202008-02-28 01:06:41 +00002127
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002128 unsigned numCleanFloats = 0;
2129 if (!layoutState.floats().isEmpty()) {
eae@chromium.orgee8613e2011-11-12 01:12:58 +00002130 LayoutUnit savedLogicalHeight = logicalHeight();
mitz@apple.com40547b32008-03-18 04:04:34 +00002131 // Restore floats from clean lines.
2132 RootInlineBox* line = firstRootBox();
2133 while (line != curr) {
hyatt@apple.comd885df72009-01-22 02:31:52 +00002134 if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) {
2135 Vector<RenderBox*>::iterator end = cleanLineFloats->end();
2136 for (Vector<RenderBox*>::iterator f = cleanLineFloats->begin(); f != end; ++f) {
mitz@apple.com0c4ce9f2011-05-04 02:20:02 +00002137 FloatingObject* floatingObject = insertFloatingObject(*f);
2138 ASSERT(!floatingObject->m_originatingLine);
2139 floatingObject->m_originatingLine = line;
hyatt@apple.com9a2e7d22010-10-06 22:13:31 +00002140 setLogicalHeight(logicalTopForChild(*f) - marginBeforeForChild(*f));
mitz@apple.com40547b32008-03-18 04:04:34 +00002141 positionNewFloats();
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002142 ASSERT(layoutState.floats()[numCleanFloats].object == *f);
mitz@apple.com40547b32008-03-18 04:04:34 +00002143 numCleanFloats++;
2144 }
2145 }
2146 line = line->nextRootBox();
2147 }
hyatt@apple.com9a2e7d22010-10-06 22:13:31 +00002148 setLogicalHeight(savedLogicalHeight);
mitz@apple.com40547b32008-03-18 04:04:34 +00002149 }
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002150 layoutState.setFloatIndex(numCleanFloats);
mitz@apple.com40547b32008-03-18 04:04:34 +00002151
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002152 layoutState.lineInfo().setFirstLine(!last);
2153 layoutState.lineInfo().setPreviousLineBrokeCleanly(!last || last->endsWithBreak());
mitz@apple.com1a301772008-03-11 18:30:36 +00002154
hyatt0c3a9862004-02-23 21:26:26 +00002155 if (last) {
hyatt@apple.com7ce0d422011-08-30 16:57:37 +00002156 setLogicalHeight(last->lineBottomWithLeading());
rniwa@webkit.org53d106b2011-11-30 22:33:20 +00002157 InlineIterator iter = InlineIterator(this, last->lineBreakObj(), last->lineBreakPos());
2158 resolver.setPosition(iter, numberOfIsolateAncestors(iter));
mitz@apple.com15035e62008-07-05 20:44:44 +00002159 resolver.setStatus(last->lineBreakBidiStatus());
darindde01502005-12-18 22:55:35 +00002160 } else {
leviw@chromium.org7781b6a2011-06-27 22:01:38 +00002161 TextDirection direction = style()->direction();
leviw@chromium.orge7812f32012-02-07 23:46:40 +00002162 if (style()->unicodeBidi() == Plaintext)
2163 determineDirectionality(direction, InlineIterator(this, bidiFirstSkippingEmptyInlines(this), 0));
rniwa@webkit.orgc275acf2012-03-05 23:09:22 +00002164 resolver.setStatus(BidiStatus(direction, isOverride(style()->unicodeBidi())));
rniwa@webkit.org53d106b2011-11-30 22:33:20 +00002165 InlineIterator iter = InlineIterator(this, bidiFirstSkippingEmptyInlines(this, &resolver), 0);
2166 resolver.setPosition(iter, numberOfIsolateAncestors(iter));
darindde01502005-12-18 22:55:35 +00002167 }
hyatt0c3a9862004-02-23 21:26:26 +00002168 return curr;
2169}
2170
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002171void RenderBlock::determineEndPosition(LineLayoutState& layoutState, RootInlineBox* startLine, InlineIterator& cleanLineStart, BidiStatus& cleanLineBidiStatus)
hyatt0c3a9862004-02-23 21:26:26 +00002172{
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002173 ASSERT(!layoutState.endLine());
2174 size_t floatIndex = layoutState.floatIndex();
hyatt0c3a9862004-02-23 21:26:26 +00002175 RootInlineBox* last = 0;
mitz@apple.comd9ccfeb2011-03-10 01:56:27 +00002176 for (RootInlineBox* curr = startLine->nextRootBox(); curr; curr = curr->nextRootBox()) {
2177 if (!curr->isDirty()) {
2178 bool encounteredNewFloat = false;
2179 bool dirtiedByFloat = false;
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002180 checkFloatsInCleanLine(curr, layoutState.floats(), floatIndex, encounteredNewFloat, dirtiedByFloat);
mitz@apple.comd9ccfeb2011-03-10 01:56:27 +00002181 if (encounteredNewFloat)
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002182 return;
hyatt04420ca2004-07-16 00:05:42 +00002183 }
mitz@apple.comd9ccfeb2011-03-10 01:56:27 +00002184 if (curr->isDirty())
2185 last = 0;
2186 else if (!last)
2187 last = curr;
hyatt0c3a9862004-02-23 21:26:26 +00002188 }
mitz@apple.come1364202008-02-28 01:06:41 +00002189
hyatt0c3a9862004-02-23 21:26:26 +00002190 if (!last)
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002191 return;
mitz@apple.come1364202008-02-28 01:06:41 +00002192
mitz@apple.comd9ccfeb2011-03-10 01:56:27 +00002193 // At this point, |last| is the first line in a run of clean lines that ends with the last line
2194 // in the block.
2195
eseidel789896f2005-11-27 22:52:09 +00002196 RootInlineBox* prev = last->prevRootBox();
mitz@apple.com15035e62008-07-05 20:44:44 +00002197 cleanLineStart = InlineIterator(this, prev->lineBreakObj(), prev->lineBreakPos());
eseidel789896f2005-11-27 22:52:09 +00002198 cleanLineBidiStatus = prev->lineBreakBidiStatus();
hyatt@apple.com7ce0d422011-08-30 16:57:37 +00002199 layoutState.setEndLineLogicalTop(prev->lineBottomWithLeading());
mitz@apple.come1364202008-02-28 01:06:41 +00002200
hyatt0c3a9862004-02-23 21:26:26 +00002201 for (RootInlineBox* line = last; line; line = line->nextRootBox())
2202 line->extractLine(); // Disconnect all line boxes from their render objects while preserving
2203 // their connections to one another.
mitz@apple.come1364202008-02-28 01:06:41 +00002204
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002205 layoutState.setEndLine(last);
hyatt0c3a9862004-02-23 21:26:26 +00002206}
2207
hyatt@apple.coma10d30e2011-09-22 22:28:21 +00002208bool RenderBlock::checkPaginationAndFloatsAtEndLine(LineLayoutState& layoutState)
2209{
2210 LayoutUnit lineDelta = logicalHeight() - layoutState.endLineLogicalTop();
2211
2212 bool paginated = view()->layoutState() && view()->layoutState()->isPaginated();
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00002213 if (paginated && layoutState.flowThread()) {
hyatt@apple.coma10d30e2011-09-22 22:28:21 +00002214 // Check all lines from here to the end, and see if the hypothetical new position for the lines will result
2215 // in a different available line width.
2216 for (RootInlineBox* lineBox = layoutState.endLine(); lineBox; lineBox = lineBox->nextRootBox()) {
2217 if (paginated) {
2218 // This isn't the real move we're going to do, so don't update the line box's pagination
2219 // strut yet.
2220 LayoutUnit oldPaginationStrut = lineBox->paginationStrut();
2221 lineDelta -= oldPaginationStrut;
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00002222 adjustLinePositionForPagination(lineBox, lineDelta, layoutState.flowThread());
hyatt@apple.coma10d30e2011-09-22 22:28:21 +00002223 lineBox->setPaginationStrut(oldPaginationStrut);
2224 }
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00002225 if (lineWidthForPaginatedLineChanged(lineBox, lineDelta, layoutState.flowThread()))
hyatt@apple.coma10d30e2011-09-22 22:28:21 +00002226 return false;
2227 }
2228 }
2229
2230 if (!lineDelta || !m_floatingObjects)
2231 return true;
2232
2233 // See if any floats end in the range along which we want to shift the lines vertically.
eae@chromium.orgee8613e2011-11-12 01:12:58 +00002234 LayoutUnit logicalTop = min(logicalHeight(), layoutState.endLineLogicalTop());
hyatt@apple.coma10d30e2011-09-22 22:28:21 +00002235
2236 RootInlineBox* lastLine = layoutState.endLine();
2237 while (RootInlineBox* nextLine = lastLine->nextRootBox())
2238 lastLine = nextLine;
2239
leviw@chromium.org3957b452012-05-01 00:06:37 +00002240 LayoutUnit logicalBottom = lastLine->lineBottomWithLeading() + absoluteValue(lineDelta);
hyatt@apple.coma10d30e2011-09-22 22:28:21 +00002241
2242 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2243 FloatingObjectSetIterator end = floatingObjectSet.end();
2244 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
2245 FloatingObject* f = *it;
2246 if (logicalBottomForFloat(f) >= logicalTop && logicalBottomForFloat(f) < logicalBottom)
2247 return false;
2248 }
2249
2250 return true;
2251}
2252
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002253bool RenderBlock::matchedEndLine(LineLayoutState& layoutState, const InlineBidiResolver& resolver, const InlineIterator& endLineStart, const BidiStatus& endLineStatus)
hyatt0c3a9862004-02-23 21:26:26 +00002254{
mitz@apple.com15035e62008-07-05 20:44:44 +00002255 if (resolver.position() == endLineStart) {
2256 if (resolver.status() != endLineStatus)
mitz@apple.com40547b32008-03-18 04:04:34 +00002257 return false;
hyatt@apple.coma10d30e2011-09-22 22:28:21 +00002258 return checkPaginationAndFloatsAtEndLine(layoutState);
mitz@apple.com40547b32008-03-18 04:04:34 +00002259 }
hyatt0c3a9862004-02-23 21:26:26 +00002260
mitz@apple.come1364202008-02-28 01:06:41 +00002261 // The first clean line doesn't match, but we can check a handful of following lines to try
2262 // to match back up.
2263 static int numLines = 8; // The # of lines we're willing to match against.
hyatt@apple.coma10d30e2011-09-22 22:28:21 +00002264 RootInlineBox* originalEndLine = layoutState.endLine();
2265 RootInlineBox* line = originalEndLine;
mitz@apple.come1364202008-02-28 01:06:41 +00002266 for (int i = 0; i < numLines && line; i++, line = line->nextRootBox()) {
eric@webkit.org86a865a2011-03-29 15:30:41 +00002267 if (line->lineBreakObj() == resolver.position().m_obj && line->lineBreakPos() == resolver.position().m_pos) {
mitz@apple.come1364202008-02-28 01:06:41 +00002268 // We have a match.
mitz@apple.com15035e62008-07-05 20:44:44 +00002269 if (line->lineBreakBidiStatus() != resolver.status())
mitz@apple.come1364202008-02-28 01:06:41 +00002270 return false; // ...but the bidi state doesn't match.
hyatt@apple.coma10d30e2011-09-22 22:28:21 +00002271
2272 bool matched = false;
mitz@apple.come1364202008-02-28 01:06:41 +00002273 RootInlineBox* result = line->nextRootBox();
hyatt@apple.com1fb7d582011-09-23 20:25:11 +00002274 layoutState.setEndLine(result);
hyatt@apple.coma10d30e2011-09-22 22:28:21 +00002275 if (result) {
hyatt@apple.com7ce0d422011-08-30 16:57:37 +00002276 layoutState.setEndLineLogicalTop(line->lineBottomWithLeading());
hyatt@apple.coma10d30e2011-09-22 22:28:21 +00002277 matched = checkPaginationAndFloatsAtEndLine(layoutState);
mitz@apple.com40547b32008-03-18 04:04:34 +00002278 }
2279
mitz@apple.come1364202008-02-28 01:06:41 +00002280 // Now delete the lines that we failed to sync.
hyatt@apple.coma10d30e2011-09-22 22:28:21 +00002281 deleteLineRange(layoutState, renderArena(), originalEndLine, result);
2282 return matched;
hyatt0c3a9862004-02-23 21:26:26 +00002283 }
2284 }
mitz@apple.come1364202008-02-28 01:06:41 +00002285
hyatt0c3a9862004-02-23 21:26:26 +00002286 return false;
2287}
2288
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +00002289static inline bool skipNonBreakingSpace(const InlineIterator& it, const LineInfo& lineInfo)
kocienda98440082004-10-14 23:51:47 +00002290{
eric@webkit.org8c25a592011-03-29 13:18:11 +00002291 if (it.m_obj->style()->nbspMode() != SPACE || it.current() != noBreakSpace)
kocienda98440082004-10-14 23:51:47 +00002292 return false;
mitz@apple.come1364202008-02-28 01:06:41 +00002293
hyattdca76e92005-11-02 08:52:50 +00002294 // FIXME: This is bad. It makes nbsp inconsistent with space and won't work correctly
2295 // with m_minWidth/m_maxWidth.
kocienda498d1982004-10-15 21:07:24 +00002296 // Do not skip a non-breaking space if it is the first character
hyattdca76e92005-11-02 08:52:50 +00002297 // on a line after a clean line break (or on the first line, since previousLineBrokeCleanly starts off
2298 // |true|).
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +00002299 if (lineInfo.isEmpty() && lineInfo.previousLineBrokeCleanly())
kocienda498d1982004-10-15 21:07:24 +00002300 return false;
mitz@apple.come1364202008-02-28 01:06:41 +00002301
kocienda498d1982004-10-15 21:07:24 +00002302 return true;
kocienda98440082004-10-14 23:51:47 +00002303}
2304
rniwa@webkit.org40248422011-06-15 00:19:39 +00002305enum WhitespacePosition { LeadingWhitespace, TrailingWhitespace };
2306static inline bool shouldCollapseWhiteSpace(const RenderStyle* style, const LineInfo& lineInfo, WhitespacePosition whitespacePosition)
hyattd9953212005-11-03 21:05:59 +00002307{
rniwa@webkit.org40248422011-06-15 00:19:39 +00002308 // CSS2 16.6.1
2309 // If a space (U+0020) at the beginning of a line has 'white-space' set to 'normal', 'nowrap', or 'pre-line', it is removed.
2310 // If a space (U+0020) at the end of a line has 'white-space' set to 'normal', 'nowrap', or 'pre-line', it is also removed.
2311 // If spaces (U+0020) or tabs (U+0009) at the end of a line have 'white-space' set to 'pre-wrap', UAs may visually collapse them.
2312 return style->collapseWhiteSpace()
2313 || (whitespacePosition == TrailingWhitespace && style->whiteSpace() == PRE_WRAP && (!lineInfo.isEmpty() || !lineInfo.previousLineBrokeCleanly()));
hyattd9953212005-11-03 21:05:59 +00002314}
2315
robert@webkit.org56e5a9f2012-02-17 21:10:42 +00002316static bool requiresLineBoxForContent(RenderInline* flow, const LineInfo& lineInfo)
2317{
2318 RenderObject* parent = flow->parent();
2319 if (flow->document()->inNoQuirksMode()
2320 && (flow->style(lineInfo.isFirstLine())->lineHeight() != parent->style(lineInfo.isFirstLine())->lineHeight()
2321 || flow->style()->verticalAlign() != parent->style()->verticalAlign()
2322 || !parent->style()->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(flow->style()->font().fontMetrics())))
2323 return true;
2324 return false;
2325}
2326
robert@webkit.org2b307a72013-01-24 18:46:11 +00002327static bool alwaysRequiresLineBox(RenderObject* flow)
bdakinf876bee2007-10-30 05:27:09 +00002328{
2329 // FIXME: Right now, we only allow line boxes for inlines that are truly empty.
hyatt@apple.comeb66ef42008-01-18 22:59:29 +00002330 // We need to fix this, though, because at the very least, inlines containing only
eric@webkit.org060caf62011-05-03 22:11:39 +00002331 // ignorable whitespace should should also have line boxes.
robert@webkit.org2b307a72013-01-24 18:46:11 +00002332 return isEmptyInline(flow) && toRenderInline(flow)->hasInlineDirectionBordersPaddingOrMargin();
bdakinf876bee2007-10-30 05:27:09 +00002333}
2334
rniwa@webkit.org40248422011-06-15 00:19:39 +00002335static bool requiresLineBox(const InlineIterator& it, const LineInfo& lineInfo = LineInfo(), WhitespacePosition whitespacePosition = LeadingWhitespace)
bdashccffb432007-07-13 11:51:40 +00002336{
simon.fraser@apple.com2f071852012-06-25 00:11:30 +00002337 if (it.m_obj->isFloatingOrOutOfFlowPositioned())
bdashccffb432007-07-13 11:51:40 +00002338 return false;
bdakinf876bee2007-10-30 05:27:09 +00002339
robert@webkit.org2b307a72013-01-24 18:46:11 +00002340 if (it.m_obj->isRenderInline() && !alwaysRequiresLineBox(it.m_obj) && !requiresLineBoxForContent(toRenderInline(it.m_obj), lineInfo))
bdakinf876bee2007-10-30 05:27:09 +00002341 return false;
2342
rniwa@webkit.org40248422011-06-15 00:19:39 +00002343 if (!shouldCollapseWhiteSpace(it.m_obj->style(), lineInfo, whitespacePosition) || it.m_obj->isBR())
bdashccffb432007-07-13 11:51:40 +00002344 return true;
2345
2346 UChar current = it.current();
robert@webkit.org2b307a72013-01-24 18:46:11 +00002347 bool notJustWhitespace = current != ' ' && current != '\t' && current != softHyphen && (current != '\n' || it.m_obj->preservesNewline()) && !skipNonBreakingSpace(it, lineInfo);
2348 return notJustWhitespace || isEmptyInline(it.m_obj);
bdashccffb432007-07-13 11:51:40 +00002349}
2350
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +00002351bool RenderBlock::generatesLineBoxesForInlineChild(RenderObject* inlineObj)
bdashccffb432007-07-13 11:51:40 +00002352{
2353 ASSERT(inlineObj->parent() == this);
2354
mitz@apple.com15035e62008-07-05 20:44:44 +00002355 InlineIterator it(this, inlineObj, 0);
rniwa@webkit.org40248422011-06-15 00:19:39 +00002356 // FIXME: We should pass correct value for WhitespacePosition.
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +00002357 while (!it.atEnd() && !requiresLineBox(it))
mitz@apple.com1a301772008-03-11 18:30:36 +00002358 it.increment();
bdashccffb432007-07-13 11:51:40 +00002359
2360 return !it.atEnd();
2361}
2362
mitz@apple.combf6e8d32008-07-25 20:21:06 +00002363// FIXME: The entire concept of the skipTrailingWhitespace function is flawed, since we really need to be building
leviw@chromium.org1a508692011-05-05 00:01:11 +00002364// line boxes even for containers that may ultimately collapse away. Otherwise we'll never get positioned
2365// elements quite right. In other words, we need to build this function's work into the normal line
mitz@apple.com1a301772008-03-11 18:30:36 +00002366// object iteration process.
mitz@apple.combf6e8d32008-07-25 20:21:06 +00002367// NB. this function will insert any floating elements that would otherwise
2368// be skipped but it will not position them.
leviw@chromium.org1a508692011-05-05 00:01:11 +00002369void RenderBlock::LineBreaker::skipTrailingWhitespace(InlineIterator& iterator, const LineInfo& lineInfo)
kociendabb0c24b2001-08-24 14:24:40 +00002370{
rniwa@webkit.org40248422011-06-15 00:19:39 +00002371 while (!iterator.atEnd() && !requiresLineBox(iterator, lineInfo, TrailingWhitespace)) {
eric@webkit.org8c25a592011-03-29 13:18:11 +00002372 RenderObject* object = iterator.m_obj;
simon.fraser@apple.com2f071852012-06-25 00:11:30 +00002373 if (object->isOutOfFlowPositioned())
leviw@chromium.org1a508692011-05-05 00:01:11 +00002374 setStaticPositions(m_block, toRenderBox(object));
mitz@apple.comd67fb212011-12-19 02:51:46 +00002375 else if (object->isFloating())
2376 m_block->insertFloatingObject(toRenderBox(object));
mitz@apple.com1a301772008-03-11 18:30:36 +00002377 iterator.increment();
mjs6f821c82002-03-22 00:31:57 +00002378 }
mitz@apple.com1a301772008-03-11 18:30:36 +00002379}
bdashccffb432007-07-13 11:51:40 +00002380
hyatt@apple.com5950bd42011-09-27 20:39:57 +00002381void RenderBlock::LineBreaker::skipLeadingWhitespace(InlineBidiResolver& resolver, LineInfo& lineInfo,
leviw@chromium.org1a508692011-05-05 00:01:11 +00002382 FloatingObject* lastFloatFromPreviousLine, LineWidth& width)
mitz@apple.com1a301772008-03-11 18:30:36 +00002383{
rniwa@webkit.org40248422011-06-15 00:19:39 +00002384 while (!resolver.position().atEnd() && !requiresLineBox(resolver.position(), lineInfo, LeadingWhitespace)) {
eric@webkit.org8c25a592011-03-29 13:18:11 +00002385 RenderObject* object = resolver.position().m_obj;
simon.fraser@apple.com2f071852012-06-25 00:11:30 +00002386 if (object->isOutOfFlowPositioned()) {
leviw@chromium.org1a508692011-05-05 00:01:11 +00002387 setStaticPositions(m_block, toRenderBox(object));
robert@webkit.org8cbab142011-12-30 20:58:29 +00002388 if (object->style()->isOriginalDisplayInlineType()) {
2389 resolver.runs().addRun(createRun(0, 1, object, resolver));
2390 lineInfo.incrementRunsFromLeadingWhitespace();
2391 }
robert@webkit.org8de78c62012-12-07 19:30:51 +00002392 } else if (object->isFloating()) {
2393 // The top margin edge of a self-collapsing block that clears a float intrudes up into it by the height of the margin,
robert@webkit.orgab9ec782013-02-12 21:06:07 +00002394 // so in order to place this first child float at the top content edge of the self-collapsing block add the margin back in before placement.
2395 LayoutUnit marginOffset = (!object->previousSibling() && m_block->isSelfCollapsingBlock() && m_block->style()->clear() && m_block->getClearDelta(m_block, LayoutUnit())) ? m_block->collapsedMarginBeforeForChild(m_block) : LayoutUnit();
robert@webkit.org8de78c62012-12-07 19:30:51 +00002396 LayoutUnit oldLogicalHeight = m_block->logicalHeight();
2397 m_block->setLogicalHeight(oldLogicalHeight + marginOffset);
mitz@apple.comd67fb212011-12-19 02:51:46 +00002398 m_block->positionNewFloatOnLine(m_block->insertFloatingObject(toRenderBox(object)), lastFloatFromPreviousLine, lineInfo, width);
robert@webkit.org8de78c62012-12-07 19:30:51 +00002399 m_block->setLogicalHeight(oldLogicalHeight);
2400 } else if (object->isText() && object->style()->hasTextCombine() && object->isCombineText() && !toRenderCombineText(object)->isCombined()) {
commit-queue@webkit.orgf6c35c02012-01-06 20:30:15 +00002401 toRenderCombineText(object)->combineText();
commit-queue@webkit.org8e277fd2012-01-19 18:05:33 +00002402 if (toRenderCombineText(object)->isCombined())
2403 continue;
commit-queue@webkit.orgf6c35c02012-01-06 20:30:15 +00002404 }
mitz@apple.com15035e62008-07-05 20:44:44 +00002405 resolver.increment();
mitz@apple.com1a301772008-03-11 18:30:36 +00002406 }
mitz@apple.com83d2e872008-10-23 21:56:03 +00002407 resolver.commitExplicitEmbedding();
kociendae40cb942004-10-05 20:05:38 +00002408}
2409
eric@webkit.org060caf62011-05-03 22:11:39 +00002410// This is currently just used for list markers and inline flows that have line boxes. Neither should
2411// have an effect on whitespace at the start of the line.
hyatt@apple.comb3466af2009-06-13 06:04:40 +00002412static bool shouldSkipWhitespaceAfterStartObject(RenderBlock* block, RenderObject* o, LineMidpointState& lineMidpointState)
bdakinf876bee2007-10-30 05:27:09 +00002413{
eric@webkit.orgd4b9d772011-08-22 23:34:31 +00002414 RenderObject* next = bidiNextSkippingEmptyInlines(block, o);
darin@apple.com36744d62009-01-25 20:23:04 +00002415 if (next && !next->isBR() && next->isText() && toRenderText(next)->textLength() > 0) {
2416 RenderText* nextText = toRenderText(next);
msaboff@apple.com776c286c72012-10-15 16:56:29 +00002417 UChar nextChar = nextText->characterAt(0);
bdakinf876bee2007-10-30 05:27:09 +00002418 if (nextText->style()->isCollapsibleWhiteSpace(nextChar)) {
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00002419 startIgnoringSpaces(lineMidpointState, InlineIterator(0, o, 0));
bdakinf876bee2007-10-30 05:27:09 +00002420 return true;
2421 }
2422 }
2423
2424 return false;
2425}
2426
enrica@apple.com885c84d2012-10-10 05:48:51 +00002427static ALWAYS_INLINE float textWidth(RenderText* text, unsigned from, unsigned len, const Font& font, float xPos, bool isFixedPitch, bool collapseWhiteSpace, HashSet<const SimpleFontData*>* fallbackFonts = 0, TextLayout* layout = 0)
mitz@apple.com34106442009-02-01 06:23:39 +00002428{
enrica@apple.com885c84d2012-10-10 05:48:51 +00002429 GlyphOverflow glyphOverflow;
hyatt@apple.com4d046b72011-01-31 20:39:09 +00002430 if (isFixedPitch || (!from && len == text->textLength()) || text->style()->hasTextCombine())
enrica@apple.com885c84d2012-10-10 05:48:51 +00002431 return text->width(from, len, font, xPos, fallbackFonts, &glyphOverflow);
zimmermann@webkit.org544abde2011-06-12 12:40:40 +00002432
mitz@apple.com6a859602012-08-27 15:31:56 +00002433 if (layout)
enrica@apple.com885c84d2012-10-10 05:48:51 +00002434 return Font::width(*layout, from, len, fallbackFonts);
mitz@apple.com6a859602012-08-27 15:31:56 +00002435
msaboff@apple.com776c286c72012-10-15 16:56:29 +00002436 TextRun run = RenderBlock::constructTextRun(text, font, text, from, len, text->style());
zimmermann@webkit.org544abde2011-06-12 12:40:40 +00002437 run.setCharactersLength(text->textLength() - from);
2438 ASSERT(run.charactersLength() >= run.length());
2439
hyatt@apple.comc2fdbe12012-04-12 21:06:50 +00002440 run.setCharacterScanForCodePath(!text->canUseSimpleFontCodePath());
morrita@google.com6e818ec2012-05-11 03:28:46 +00002441 run.setTabSize(!collapseWhiteSpace, text->style()->tabSize());
zimmermann@webkit.org8a7e7ff2011-05-24 15:27:36 +00002442 run.setXPos(xPos);
enrica@apple.com885c84d2012-10-10 05:48:51 +00002443 return font.width(run, fallbackFonts, &glyphOverflow);
mitz@apple.com34106442009-02-01 06:23:39 +00002444}
2445
msaboff@apple.com776c286c72012-10-15 16:56:29 +00002446static void tryHyphenating(RenderText* text, const Font& font, const AtomicString& localeIdentifier, unsigned consecutiveHyphenatedLines, int consecutiveHyphenatedLinesLimit, int minimumPrefixLimit, int minimumSuffixLimit, unsigned lastSpace, unsigned pos, float xPos, int availableWidth, bool isFixedPitch, bool collapseWhiteSpace, int lastSpaceWordSpacing, InlineIterator& lineBreak, int nextBreakable, bool& hyphenated)
mitz@apple.comb2107652010-06-21 16:54:52 +00002447{
mitz@apple.comd56f1082011-03-06 22:44:48 +00002448 // Map 'hyphenate-limit-{before,after}: auto;' to 2.
msaboff@apple.com776c286c72012-10-15 16:56:29 +00002449 unsigned minimumPrefixLength;
2450 unsigned minimumSuffixLength;
mitz@apple.comd56f1082011-03-06 22:44:48 +00002451
msaboff@apple.com776c286c72012-10-15 16:56:29 +00002452 if (minimumPrefixLimit < 0)
2453 minimumPrefixLength = 2;
2454 else
2455 minimumPrefixLength = static_cast<unsigned>(minimumPrefixLimit);
2456
2457 if (minimumSuffixLimit < 0)
mitz@apple.comd56f1082011-03-06 22:44:48 +00002458 minimumSuffixLength = 2;
msaboff@apple.com776c286c72012-10-15 16:56:29 +00002459 else
2460 minimumSuffixLength = static_cast<unsigned>(minimumSuffixLimit);
mitz@apple.comd56f1082011-03-06 22:44:48 +00002461
2462 if (pos - lastSpace <= minimumSuffixLength)
2463 return;
2464
mitz@apple.com10ed3cb2011-09-07 20:59:39 +00002465 if (consecutiveHyphenatedLinesLimit >= 0 && consecutiveHyphenatedLines >= static_cast<unsigned>(consecutiveHyphenatedLinesLimit))
2466 return;
2467
commit-queue@webkit.orge60bb902011-09-08 19:18:43 +00002468 int hyphenWidth = measureHyphenWidth(text, font);
mitz@apple.comb2107652010-06-21 16:54:52 +00002469
hyatt@apple.com0acc9352011-02-17 19:19:07 +00002470 float maxPrefixWidth = availableWidth - xPos - hyphenWidth - lastSpaceWordSpacing;
mitz@apple.com7c67b292010-09-12 23:04:16 +00002471 // If the maximum width available for the prefix before the hyphen is small, then it is very unlikely
2472 // that an hyphenation opportunity exists, so do not bother to look for it.
2473 if (maxPrefixWidth <= font.pixelSize() * 5 / 4)
2474 return;
2475
msaboff@apple.com776c286c72012-10-15 16:56:29 +00002476 TextRun run = RenderBlock::constructTextRun(text, font, text, lastSpace, pos - lastSpace, text->style());
zimmermann@webkit.org544abde2011-06-12 12:40:40 +00002477 run.setCharactersLength(text->textLength() - lastSpace);
2478 ASSERT(run.charactersLength() >= run.length());
2479
morrita@google.com6e818ec2012-05-11 03:28:46 +00002480 run.setTabSize(!collapseWhiteSpace, text->style()->tabSize());
zimmermann@webkit.org8a7e7ff2011-05-24 15:27:36 +00002481 run.setXPos(xPos + lastSpaceWordSpacing);
2482
2483 unsigned prefixLength = font.offsetForPosition(run, maxPrefixWidth, false);
msaboff@apple.com776c286c72012-10-15 16:56:29 +00002484 if (prefixLength < minimumPrefixLength)
mitz@apple.comb2107652010-06-21 16:54:52 +00002485 return;
2486
msaboff@apple.com776c286c72012-10-15 16:56:29 +00002487 prefixLength = lastHyphenLocation(text->characters() + lastSpace, pos - lastSpace, min(prefixLength, pos - lastSpace - minimumSuffixLength) + 1, localeIdentifier);
2488 if (!prefixLength || prefixLength < minimumPrefixLength)
mitz@apple.comb2107652010-06-21 16:54:52 +00002489 return;
2490
mitz@apple.com348878a2011-12-11 19:06:56 +00002491 // When lastSapce is a space, which it always is except sometimes at the beginning of a line or after collapsed
2492 // space, it should not count towards hyphenate-limit-before.
msaboff@apple.com776c286c72012-10-15 16:56:29 +00002493 if (prefixLength == minimumPrefixLength) {
2494 UChar characterAtLastSpace = text->characterAt(lastSpace);
mitz@apple.com348878a2011-12-11 19:06:56 +00002495 if (characterAtLastSpace == ' ' || characterAtLastSpace == '\n' || characterAtLastSpace == '\t' || characterAtLastSpace == noBreakSpace)
2496 return;
2497 }
2498
msaboff@apple.com776c286c72012-10-15 16:56:29 +00002499 ASSERT(pos - lastSpace - prefixLength >= minimumSuffixLength);
mitz@apple.comd56f1082011-03-06 22:44:48 +00002500
mitz@apple.comb2107652010-06-21 16:54:52 +00002501#if !ASSERT_DISABLED
hyatt@apple.com0acc9352011-02-17 19:19:07 +00002502 float prefixWidth = hyphenWidth + textWidth(text, lastSpace, prefixLength, font, xPos, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing;
mitz@apple.comb2107652010-06-21 16:54:52 +00002503 ASSERT(xPos + prefixWidth <= availableWidth);
mitz@apple.com34b43c72010-06-21 17:21:22 +00002504#else
2505 UNUSED_PARAM(isFixedPitch);
mitz@apple.comb2107652010-06-21 16:54:52 +00002506#endif
2507
eric@webkit.orgbd143592011-03-29 17:44:41 +00002508 lineBreak.moveTo(text, lastSpace + prefixLength, nextBreakable);
mitz@apple.comb2107652010-06-21 16:54:52 +00002509 hyphenated = true;
2510}
2511
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002512class TrailingObjects {
2513public:
2514 TrailingObjects();
2515 void setTrailingWhitespace(RenderText*);
2516 void clear();
2517 void appendBoxIfNeeded(RenderBox*);
mitz@apple.come98acc92011-05-22 04:44:27 +00002518
2519 enum CollapseFirstSpaceOrNot { DoNotCollapseFirstSpace, CollapseFirstSpace };
2520
2521 void updateMidpointsForTrailingBoxes(LineMidpointState&, const InlineIterator& lBreak, CollapseFirstSpaceOrNot);
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002522
2523private:
2524 RenderText* m_whitespace;
2525 Vector<RenderBox*, 4> m_boxes;
2526};
2527
2528TrailingObjects::TrailingObjects()
2529 : m_whitespace(0)
2530{
2531}
2532
2533inline void TrailingObjects::setTrailingWhitespace(RenderText* whitespace)
2534{
2535 ASSERT(whitespace);
2536 m_whitespace = whitespace;
2537}
2538
2539inline void TrailingObjects::clear()
2540{
2541 m_whitespace = 0;
2542 m_boxes.clear();
2543}
2544
2545inline void TrailingObjects::appendBoxIfNeeded(RenderBox* box)
2546{
2547 if (m_whitespace)
2548 m_boxes.append(box);
2549}
2550
mitz@apple.come98acc92011-05-22 04:44:27 +00002551void TrailingObjects::updateMidpointsForTrailingBoxes(LineMidpointState& lineMidpointState, const InlineIterator& lBreak, CollapseFirstSpaceOrNot collapseFirstSpace)
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002552{
2553 if (!m_whitespace)
2554 return;
2555
2556 // This object is either going to be part of the last midpoint, or it is going to be the actual endpoint.
2557 // In both cases we just decrease our pos by 1 level to exclude the space, allowing it to - in effect - collapse into the newline.
2558 if (lineMidpointState.numMidpoints % 2) {
2559 // Find the trailing space object's midpoint.
2560 int trailingSpaceMidpoint = lineMidpointState.numMidpoints - 1;
inferno@chromium.org92ca04e2011-08-01 18:03:03 +00002561 for ( ; trailingSpaceMidpoint > 0 && lineMidpointState.midpoints[trailingSpaceMidpoint].m_obj != m_whitespace; --trailingSpaceMidpoint) { }
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002562 ASSERT(trailingSpaceMidpoint >= 0);
mitz@apple.come98acc92011-05-22 04:44:27 +00002563 if (collapseFirstSpace == CollapseFirstSpace)
2564 lineMidpointState.midpoints[trailingSpaceMidpoint].m_pos--;
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002565
eric@webkit.org060caf62011-05-03 22:11:39 +00002566 // Now make sure every single trailingPositionedBox following the trailingSpaceMidpoint properly stops and starts
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002567 // ignoring spaces.
2568 size_t currentMidpoint = trailingSpaceMidpoint + 1;
2569 for (size_t i = 0; i < m_boxes.size(); ++i) {
2570 if (currentMidpoint >= lineMidpointState.numMidpoints) {
2571 // We don't have a midpoint for this box yet.
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00002572 ensureLineBoxInsideIgnoredSpaces(lineMidpointState, m_boxes[i]);
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002573 } else {
2574 ASSERT(lineMidpointState.midpoints[currentMidpoint].m_obj == m_boxes[i]);
2575 ASSERT(lineMidpointState.midpoints[currentMidpoint + 1].m_obj == m_boxes[i]);
2576 }
2577 currentMidpoint += 2;
2578 }
2579 } else if (!lBreak.m_obj) {
2580 ASSERT(m_whitespace->isText());
mitz@apple.come98acc92011-05-22 04:44:27 +00002581 ASSERT(collapseFirstSpace == CollapseFirstSpace);
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002582 // Add a new end midpoint that stops right at the very end.
2583 unsigned length = m_whitespace->textLength();
2584 unsigned pos = length >= 2 ? length - 2 : UINT_MAX;
2585 InlineIterator endMid(0, m_whitespace, pos);
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00002586 startIgnoringSpaces(lineMidpointState, endMid);
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002587 for (size_t i = 0; i < m_boxes.size(); ++i) {
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00002588 ensureLineBoxInsideIgnoredSpaces(lineMidpointState, m_boxes[i]);
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002589 }
2590 }
2591}
2592
leviw@chromium.org1a508692011-05-05 00:01:11 +00002593void RenderBlock::LineBreaker::reset()
kociendae40cb942004-10-05 20:05:38 +00002594{
leviw@chromium.org1a508692011-05-05 00:01:11 +00002595 m_positionedObjects.clear();
2596 m_hyphenated = false;
2597 m_clear = CNONE;
2598}
2599
enrica@apple.com885c84d2012-10-10 05:48:51 +00002600InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, RenderTextInfo& renderTextInfo, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements& wordMeasurements)
leviw@chromium.org1a508692011-05-05 00:01:11 +00002601{
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00002602#if !ENABLE(CSS_EXCLUSIONS)
2603 return nextSegmentBreak(resolver, lineInfo, renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
2604#else
betravis@adobe.coma53af342013-03-01 21:02:16 +00002605 ExclusionShapeInsideInfo* exclusionShapeInsideInfo = m_block->layoutExclusionShapeInsideInfo();
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00002606 if (!exclusionShapeInsideInfo || !exclusionShapeInsideInfo->hasSegments())
2607 return nextSegmentBreak(resolver, lineInfo, renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
2608
2609 InlineIterator end = resolver.position();
2610 InlineIterator oldEnd = end;
2611
2612 const SegmentList& segments = exclusionShapeInsideInfo->segments();
2613 SegmentRangeList& segmentRanges = exclusionShapeInsideInfo->segmentRanges();
2614
hmuller@adobe.com6da71872013-03-18 16:54:04 +00002615 for (unsigned i = 0; i < segments.size() && !end.atEnd(); i++) {
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00002616 InlineIterator segmentStart = resolver.position();
2617 end = nextSegmentBreak(resolver, lineInfo, renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
2618
2619 ASSERT(segmentRanges.size() == i);
hmuller@adobe.com6da71872013-03-18 16:54:04 +00002620 if (resolver.position().atEnd()) {
2621 segmentRanges.append(LineSegmentRange(segmentStart, end));
2622 break;
2623 }
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00002624 if (resolver.position() == end) {
2625 // Nothing fit this segment
2626 segmentRanges.append(LineSegmentRange(segmentStart, segmentStart));
2627 resolver.setPositionIgnoringNestedIsolates(segmentStart);
2628 } else {
2629 // Note that resolver.position is already skipping some of the white space at the beginning of the line,
2630 // so that's why segmentStart might be different than resolver.position().
2631 LineSegmentRange range(resolver.position(), end);
2632 segmentRanges.append(range);
2633 resolver.setPosition(end, numberOfIsolateAncestors(end));
2634
2635 if (lineInfo.previousLineBrokeCleanly()) {
2636 // If we hit a new line break, just stop adding anything to this line.
2637 break;
2638 }
2639 }
2640 }
2641 resolver.setPositionIgnoringNestedIsolates(oldEnd);
2642 return end;
2643#endif
2644}
2645
leviw@chromium.org17fe64d2013-04-02 23:10:49 +00002646static inline bool iteratorIsBeyondEndOfRenderCombineText(const InlineIterator& iter, RenderCombineText* renderer)
2647{
2648 return iter.m_obj == renderer && iter.m_pos >= renderer->textLength();
2649}
2650
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00002651InlineIterator RenderBlock::LineBreaker::nextSegmentBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, RenderTextInfo& renderTextInfo, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements& wordMeasurements)
2652{
leviw@chromium.org1a508692011-05-05 00:01:11 +00002653 reset();
2654
2655 ASSERT(resolver.position().root() == m_block);
mitz@apple.com51017322008-02-26 06:47:43 +00002656
eric@webkit.org86a865a2011-03-29 15:30:41 +00002657 bool appliedStartWidth = resolver.position().m_pos > 0;
yael.aharon@nokia.com1cfbceb2011-06-06 18:32:54 +00002658 bool includeEndWidth = true;
hyatt@apple.comb3466af2009-06-13 06:04:40 +00002659 LineMidpointState& lineMidpointState = resolver.midpointState();
mitz@apple.com1a301772008-03-11 18:30:36 +00002660
commit-queue@webkit.orgab781b02013-04-03 01:32:24 +00002661 LineWidth width(m_block, lineInfo.isFirstLine(), requiresIndent(lineInfo.isFirstLine(), lineInfo.previousLineBrokeCleanly(), m_block->style()));
rniwa@webkit.org7881ad02011-04-07 13:05:35 +00002662
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +00002663 skipLeadingWhitespace(resolver, lineInfo, lastFloatFromPreviousLine, width);
kociendae40cb942004-10-05 20:05:38 +00002664
mitz@apple.com15035e62008-07-05 20:44:44 +00002665 if (resolver.position().atEnd())
2666 return resolver.position();
mjs6f821c82002-03-22 00:31:57 +00002667
hyatt33f8d492002-11-12 21:44:52 +00002668 // This variable is used only if whitespace isn't set to PRE, and it tells us whether
2669 // or not we are currently ignoring whitespace.
2670 bool ignoringSpaces = false;
mitz@apple.com15035e62008-07-05 20:44:44 +00002671 InlineIterator ignoreStart;
eric@webkit.org060caf62011-05-03 22:11:39 +00002672
hyatt33f8d492002-11-12 21:44:52 +00002673 // This variable tracks whether the very last character we saw was a space. We use
2674 // this to detect when we encounter a second space so we know we have to terminate
2675 // a run.
rjwc9c257d2003-01-24 03:46:17 +00002676 bool currentCharacterIsSpace = false;
harrisone343c412005-01-18 01:07:26 +00002677 bool currentCharacterIsWS = false;
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002678 TrailingObjects trailingObjects;
hyatt98b16282004-03-31 18:43:12 +00002679
mitz@apple.com15035e62008-07-05 20:44:44 +00002680 InlineIterator lBreak = resolver.position();
mjs6f821c82002-03-22 00:31:57 +00002681
eric@webkit.orgbd143592011-03-29 17:44:41 +00002682 // FIXME: It is error-prone to split the position object out like this.
2683 // Teach this code to work with objects instead of this split tuple.
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002684 InlineIterator current = resolver.position();
2685 RenderObject* last = current.m_obj;
ddkilzere8759ef2007-03-25 06:28:19 +00002686 bool atStart = true;
kociendabb0c24b2001-08-24 14:24:40 +00002687
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +00002688 bool startingNewParagraph = lineInfo.previousLineBrokeCleanly();
2689 lineInfo.setPreviousLineBrokeCleanly(false);
ddkilzer5d01fa22007-01-29 03:10:37 +00002690
2691 bool autoWrapWasEverTrueOnLine = false;
mitz@apple.com25beac62008-02-24 18:48:27 +00002692 bool floatsFitOnLine = true;
eric@webkit.org060caf62011-05-03 22:11:39 +00002693
hyatt@apple.com69340902008-01-16 21:24:21 +00002694 // Firefox and Opera will allow a table cell to grow to fit an image inside it under
eric@webkit.org060caf62011-05-03 22:11:39 +00002695 // very specific circumstances (in order to match common WinIE renderings).
2696 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
mihnea@adobe.com3bebbf22012-01-19 09:22:59 +00002697 RenderStyle* blockStyle = m_block->style();
2698 bool allowImagesToBreak = !m_block->document()->inQuirksMode() || !m_block->isTableCell() || !blockStyle->logicalWidth().isIntrinsicOrAuto();
hyatt@apple.com69340902008-01-16 21:24:21 +00002699
mihnea@adobe.com3bebbf22012-01-19 09:22:59 +00002700 EWhiteSpace currWS = blockStyle->whiteSpace();
hyattb0d9f602007-01-15 01:28:23 +00002701 EWhiteSpace lastWS = currWS;
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002702 while (current.m_obj) {
mihnea@adobe.com3bebbf22012-01-19 09:22:59 +00002703 RenderStyle* currentStyle = current.m_obj->style();
eric@webkit.orgd4b9d772011-08-22 23:34:31 +00002704 RenderObject* next = bidiNextSkippingEmptyInlines(m_block, current.m_obj);
yael.aharon@nokia.com1cfbceb2011-06-06 18:32:54 +00002705 if (next && next->parent() && !next->parent()->isDescendantOf(current.m_obj->parent()))
2706 includeEndWidth = true;
mitz@apple.comddb59872011-04-05 05:21:16 +00002707
mihnea@adobe.com3bebbf22012-01-19 09:22:59 +00002708 currWS = current.m_obj->isReplaced() ? current.m_obj->parent()->style()->whiteSpace() : currentStyle->whiteSpace();
hyattb0d9f602007-01-15 01:28:23 +00002709 lastWS = last->isReplaced() ? last->parent()->style()->whiteSpace() : last->style()->whiteSpace();
eric@webkit.org060caf62011-05-03 22:11:39 +00002710
hyattb0d9f602007-01-15 01:28:23 +00002711 bool autoWrap = RenderStyle::autoWrap(currWS);
ddkilzer5d01fa22007-01-29 03:10:37 +00002712 autoWrapWasEverTrueOnLine = autoWrapWasEverTrueOnLine || autoWrap;
zimmermannac3781f2007-02-04 01:25:03 +00002713
mjsd2948ef2007-02-26 19:29:04 +00002714#if ENABLE(SVG)
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002715 bool preserveNewline = current.m_obj->isSVGInlineText() ? false : RenderStyle::preserveNewline(currWS);
zimmermannac3781f2007-02-04 01:25:03 +00002716#else
hyattb0d9f602007-01-15 01:28:23 +00002717 bool preserveNewline = RenderStyle::preserveNewline(currWS);
zimmermannac3781f2007-02-04 01:25:03 +00002718#endif
2719
hyattb0d9f602007-01-15 01:28:23 +00002720 bool collapseWhiteSpace = RenderStyle::collapseWhiteSpace(currWS);
eric@webkit.org060caf62011-05-03 22:11:39 +00002721
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002722 if (current.m_obj->isBR()) {
rniwa@webkit.org5eb8d162011-04-13 02:13:33 +00002723 if (width.fitsOnLine()) {
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002724 lBreak.moveToStartOf(current.m_obj);
mitz@apple.com1a301772008-03-11 18:30:36 +00002725 lBreak.increment();
hyatt0c3a9862004-02-23 21:26:26 +00002726
hyatt33f8d492002-11-12 21:44:52 +00002727 // A <br> always breaks a line, so don't let the line be collapsed
2728 // away. Also, the space at the end of a line with a <br> does not
hyatt01eff982003-03-14 20:13:23 +00002729 // get collapsed away. It only does this if the previous line broke
2730 // cleanly. Otherwise the <br> has no effect on whether the line is
2731 // empty or not.
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +00002732 if (startingNewParagraph)
hyatt@apple.com5950bd42011-09-27 20:39:57 +00002733 lineInfo.setEmpty(false, m_block, &width);
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002734 trailingObjects.clear();
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +00002735 lineInfo.setPreviousLineBrokeCleanly(true);
hyatt74eec4d2003-03-23 08:02:47 +00002736
robert@webkit.org3c75e502012-10-21 10:27:50 +00002737 // A <br> with clearance always needs a linebox in case the lines below it get dirtied later and
2738 // need to check for floats to clear - so if we're ignoring spaces, stop ignoring them and add a
2739 // run for this object.
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00002740 if (ignoringSpaces && currentStyle->clear() != CNONE)
2741 ensureLineBoxInsideIgnoredSpaces(lineMidpointState, current.m_obj);
robert@webkit.org3c75e502012-10-21 10:27:50 +00002742
leviw@chromium.org1a508692011-05-05 00:01:11 +00002743 if (!lineInfo.isEmpty())
mihnea@adobe.com3bebbf22012-01-19 09:22:59 +00002744 m_clear = currentStyle->clear();
kociendabb0c24b2001-08-24 14:24:40 +00002745 }
2746 goto end;
2747 }
hyattb0d9f602007-01-15 01:28:23 +00002748
simon.fraser@apple.com2f071852012-06-25 00:11:30 +00002749 if (current.m_obj->isOutOfFlowPositioned()) {
rniwa@webkit.org76aa5222011-05-04 13:03:32 +00002750 // If our original display wasn't an inline type, then we can
2751 // go ahead and determine our static inline position now.
2752 RenderBox* box = toRenderBox(current.m_obj);
2753 bool isInlineType = box->style()->isOriginalDisplayInlineType();
2754 if (!isInlineType)
hyatt@apple.coma5cac3f2011-10-12 18:51:17 +00002755 m_block->setStaticInlinePositionForChild(box, m_block->logicalHeight(), m_block->startOffsetForContent(m_block->logicalHeight()));
rniwa@webkit.org76aa5222011-05-04 13:03:32 +00002756 else {
2757 // If our original display was an INLINE type, then we can go ahead
2758 // and determine our static y position now.
leviw@chromium.org1a508692011-05-05 00:01:11 +00002759 box->layer()->setStaticBlockPosition(m_block->logicalHeight());
hyatt98ee7e42003-05-14 01:39:15 +00002760 }
rniwa@webkit.org76aa5222011-05-04 13:03:32 +00002761
2762 // If we're ignoring spaces, we have to stop and include this object and
2763 // then start ignoring spaces again.
2764 if (isInlineType || current.m_obj->container()->isRenderInline()) {
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00002765 if (ignoringSpaces)
2766 ensureLineBoxInsideIgnoredSpaces(lineMidpointState, current.m_obj);
rniwa@webkit.org76aa5222011-05-04 13:03:32 +00002767 trailingObjects.appendBoxIfNeeded(box);
2768 } else
leviw@chromium.org1a508692011-05-05 00:01:11 +00002769 m_positionedObjects.append(box);
robert@webkit.org0a971dc2013-02-01 18:45:27 +00002770 width.addUncommittedWidth(inlineLogicalWidth(current.m_obj));
glenn@skynav.com1fa656a2013-03-11 03:30:57 +00002771 // Reset prior line break context characters.
glenn@skynav.com61b1abf2013-04-02 23:28:32 +00002772 renderTextInfo.m_lineBreakIterator.resetPriorContext();
mitz@apple.comd67fb212011-12-19 02:51:46 +00002773 } else if (current.m_obj->isFloating()) {
2774 RenderBox* floatBox = toRenderBox(current.m_obj);
2775 FloatingObject* f = m_block->insertFloatingObject(floatBox);
2776 // check if it fits in the current line.
2777 // If it does, position it now, otherwise, position
2778 // it after moving to next line (in newLine() func)
commit-queue@webkit.org31a3bc72013-03-05 18:19:36 +00002779 // FIXME: Bug 110372: Properly position multiple stacked floats with non-rectangular shape outside.
mitz@apple.comd67fb212011-12-19 02:51:46 +00002780 if (floatsFitOnLine && width.fitsOnLine(m_block->logicalWidthForFloat(f))) {
2781 m_block->positionNewFloatOnLine(f, lastFloatFromPreviousLine, lineInfo, width);
2782 if (lBreak.m_obj == current.m_obj) {
2783 ASSERT(!lBreak.m_pos);
2784 lBreak.increment();
2785 }
2786 } else
2787 floatsFitOnLine = false;
glenn@skynav.com1fa656a2013-03-11 03:30:57 +00002788 // Update prior line break context characters, using U+FFFD (OBJECT REPLACEMENT CHARACTER) for floating element.
glenn@skynav.com61b1abf2013-04-02 23:28:32 +00002789 renderTextInfo.m_lineBreakIterator.updatePriorContext(replacementCharacter);
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002790 } else if (current.m_obj->isRenderInline()) {
bdakinf876bee2007-10-30 05:27:09 +00002791 // Right now, we should only encounter empty inlines here.
robert@webkit.org2b307a72013-01-24 18:46:11 +00002792 ASSERT(isEmptyInline(current.m_obj));
eric@webkit.org060caf62011-05-03 22:11:39 +00002793
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002794 RenderInline* flowBox = toRenderInline(current.m_obj);
eric@webkit.org060caf62011-05-03 22:11:39 +00002795
2796 // Now that some inline flows have line boxes, if we are already ignoring spaces, we need
2797 // to make sure that we stop to include this object and then start ignoring spaces again.
2798 // If this object is at the start of the line, we need to behave like list markers and
bdakinf876bee2007-10-30 05:27:09 +00002799 // start ignoring spaces.
robert@webkit.org2b307a72013-01-24 18:46:11 +00002800 bool requiresLineBox = alwaysRequiresLineBox(current.m_obj);
robert@webkit.org56e5a9f2012-02-17 21:10:42 +00002801 if (requiresLineBox || requiresLineBoxForContent(flowBox, lineInfo)) {
2802 // An empty inline that only has line-height, vertical-align or font-metrics will only get a
2803 // line box to affect the height of the line if the rest of the line is not empty.
2804 if (requiresLineBox)
2805 lineInfo.setEmpty(false, m_block, &width);
bdakinf876bee2007-10-30 05:27:09 +00002806 if (ignoringSpaces) {
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002807 trailingObjects.clear();
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00002808 ensureLineBoxInsideIgnoredSpaces(lineMidpointState, current.m_obj);
mihnea@adobe.com3bebbf22012-01-19 09:22:59 +00002809 } else if (blockStyle->collapseWhiteSpace() && resolver.position().m_obj == current.m_obj
leviw@chromium.org1a508692011-05-05 00:01:11 +00002810 && shouldSkipWhitespaceAfterStartObject(m_block, current.m_obj, lineMidpointState)) {
eric@webkit.org060caf62011-05-03 22:11:39 +00002811 // Like with list markers, we start ignoring spaces to make sure that any
bdakinf876bee2007-10-30 05:27:09 +00002812 // additional spaces we see will be discarded.
2813 currentCharacterIsSpace = true;
2814 currentCharacterIsWS = true;
2815 ignoringSpaces = true;
2816 }
2817 }
2818
robert@webkit.org0a971dc2013-02-01 18:45:27 +00002819 width.addUncommittedWidth(inlineLogicalWidth(current.m_obj) + borderPaddingMarginStart(flowBox) + borderPaddingMarginEnd(flowBox));
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002820 } else if (current.m_obj->isReplaced()) {
2821 RenderBox* replacedBox = toRenderBox(current.m_obj);
hyatt@apple.comd885df72009-01-22 02:31:52 +00002822
robert@webkit.org0903cf52012-12-11 18:14:16 +00002823 if (atStart)
2824 width.updateAvailableWidth(replacedBox->logicalHeight());
2825
hyattde396342003-10-29 08:57:20 +00002826 // Break on replaced elements if either has normal white-space.
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002827 if ((autoWrap || RenderStyle::autoWrap(lastWS)) && (!current.m_obj->isImage() || allowImagesToBreak)) {
rniwa@webkit.org58925e82011-04-12 21:32:58 +00002828 width.commit();
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002829 lBreak.moveToStartOf(current.m_obj);
hyatt711fe232002-11-20 21:25:14 +00002830 }
2831
mitz@apple.combfdc9112008-02-21 19:59:40 +00002832 if (ignoringSpaces)
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00002833 stopIgnoringSpaces(lineMidpointState, InlineIterator(0, current.m_obj, 0));
mitz@apple.combfdc9112008-02-21 19:59:40 +00002834
hyatt@apple.com5950bd42011-09-27 20:39:57 +00002835 lineInfo.setEmpty(false, m_block, &width);
hyatt33f8d492002-11-12 21:44:52 +00002836 ignoringSpaces = false;
rjwc9c257d2003-01-24 03:46:17 +00002837 currentCharacterIsSpace = false;
harrisone343c412005-01-18 01:07:26 +00002838 currentCharacterIsWS = false;
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002839 trailingObjects.clear();
hamaji@chromium.org382642b2009-12-01 07:37:14 +00002840
bdakinf876bee2007-10-30 05:27:09 +00002841 // Optimize for a common case. If we can't find whitespace after the list
hyatt@apple.com0415e5d2010-10-07 17:40:25 +00002842 // item, then this is all moot.
eae@chromium.orgee8613e2011-11-12 01:12:58 +00002843 LayoutUnit replacedLogicalWidth = m_block->logicalWidthForChild(replacedBox) + m_block->marginStartForChild(replacedBox) + m_block->marginEndForChild(replacedBox) + inlineLogicalWidth(current.m_obj);
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002844 if (current.m_obj->isListMarker()) {
mihnea@adobe.com3bebbf22012-01-19 09:22:59 +00002845 if (blockStyle->collapseWhiteSpace() && shouldSkipWhitespaceAfterStartObject(m_block, current.m_obj, lineMidpointState)) {
eric@webkit.org060caf62011-05-03 22:11:39 +00002846 // Like with inline flows, we start ignoring spaces to make sure that any
bdakinf876bee2007-10-30 05:27:09 +00002847 // additional spaces we see will be discarded.
2848 currentCharacterIsSpace = true;
2849 currentCharacterIsWS = true;
2850 ignoringSpaces = true;
hyatte85e4a72002-12-08 02:06:16 +00002851 }
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002852 if (toRenderListMarker(current.m_obj)->isInside())
rniwa@webkit.org58925e82011-04-12 21:32:58 +00002853 width.addUncommittedWidth(replacedLogicalWidth);
justing244d3a32006-04-13 01:31:24 +00002854 } else
rniwa@webkit.org58925e82011-04-12 21:32:58 +00002855 width.addUncommittedWidth(replacedLogicalWidth);
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002856 if (current.m_obj->isRubyRun())
2857 width.applyOverhang(toRenderRubyRun(current.m_obj), last, next);
glenn@skynav.com1fa656a2013-03-11 03:30:57 +00002858 // Update prior line break context characters, using U+FFFD (OBJECT REPLACEMENT CHARACTER) for replaced element.
glenn@skynav.com61b1abf2013-04-02 23:28:32 +00002859 renderTextInfo.m_lineBreakIterator.updatePriorContext(replacementCharacter);
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002860 } else if (current.m_obj->isText()) {
2861 if (!current.m_pos)
mitz@apple.com51017322008-02-26 06:47:43 +00002862 appliedStartWidth = false;
2863
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002864 RenderText* t = toRenderText(current.m_obj);
mitz@apple.comfb8da4e2008-02-19 21:13:19 +00002865
zimmermann@webkit.org6e96afd2010-09-10 15:35:50 +00002866#if ENABLE(SVG)
2867 bool isSVGText = t->isSVGInlineText();
2868#endif
2869
leviw@chromium.org17fe64d2013-04-02 23:10:49 +00002870 if (t->style()->hasTextCombine() && current.m_obj->isCombineText() && !toRenderCombineText(current.m_obj)->isCombined()) {
2871 RenderCombineText* combineRenderer = toRenderCombineText(current.m_obj);
2872 combineRenderer->combineText();
2873 // The length of the renderer's text may have changed. Increment stale iterator positions
2874 if (iteratorIsBeyondEndOfRenderCombineText(lBreak, combineRenderer)) {
2875 ASSERT(iteratorIsBeyondEndOfRenderCombineText(resolver.position(), combineRenderer));
2876 lBreak.increment();
2877 resolver.increment();
2878 }
2879 }
kociendabb0c24b2001-08-24 14:24:40 +00002880
commit-queue@webkit.org5047aee2012-08-14 02:52:03 +00002881 RenderStyle* style = t->style(lineInfo.isFirstLine());
mitz@apple.comb2107652010-06-21 16:54:52 +00002882 const Font& f = style->font();
mitz@apple.com34106442009-02-01 06:23:39 +00002883 bool isFixedPitch = f.isFixedPitch();
mitz@apple.com6ae88612011-03-03 23:09:11 +00002884 bool canHyphenate = style->hyphens() == HyphensAuto && WebCore::canHyphenate(style->locale());
weinigf28a1c32007-02-14 14:10:31 +00002885
msaboff@apple.com776c286c72012-10-15 16:56:29 +00002886 unsigned lastSpace = current.m_pos;
mihnea@adobe.com3bebbf22012-01-19 09:22:59 +00002887 float wordSpacing = currentStyle->wordSpacing();
hyatt@apple.com0acc9352011-02-17 19:19:07 +00002888 float lastSpaceWordSpacing = 0;
enrica@apple.com885c84d2012-10-10 05:48:51 +00002889 float wordSpacingForWordMeasurement = 0;
hyattffe78712003-02-11 01:59:29 +00002890
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002891 float wrapW = width.uncommittedWidth() + inlineLogicalWidth(current.m_obj, !appliedStartWidth, true);
hyatt@apple.com0acc9352011-02-17 19:19:07 +00002892 float charWidth = 0;
mihnea@adobe.com3bebbf22012-01-19 09:22:59 +00002893 bool breakNBSP = autoWrap && currentStyle->nbspMode() == SPACE;
weinigf28a1c32007-02-14 14:10:31 +00002894 // Auto-wrapping text should wrap in the middle of a word only if it could not wrap before the word,
2895 // which is only possible if the word is the first thing on the line, that is, if |w| is zero.
mihnea@adobe.com3bebbf22012-01-19 09:22:59 +00002896 bool breakWords = currentStyle->breakWords() && ((autoWrap && !width.committedWidth()) || currWS == PRE);
weinigf28a1c32007-02-14 14:10:31 +00002897 bool midWordBreak = false;
mihnea@adobe.com3bebbf22012-01-19 09:22:59 +00002898 bool breakAll = currentStyle->wordBreak() == BreakAllWordBreak && autoWrap;
hyatt@apple.com0acc9352011-02-17 19:19:07 +00002899 float hyphenWidth = 0;
commit-queue@webkit.org4f54eff2013-03-08 14:32:54 +00002900#if ENABLE(SVG)
2901 if (isSVGText) {
2902 breakWords = false;
2903 breakAll = false;
2904 }
2905#endif
hyattea474f72007-04-20 05:02:19 +00002906
mitz@apple.comfb8da4e2008-02-19 21:13:19 +00002907 if (t->isWordBreak()) {
rniwa@webkit.org58925e82011-04-12 21:32:58 +00002908 width.commit();
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002909 lBreak.moveToStartOf(current.m_obj);
2910 ASSERT(current.m_pos == t->textLength());
mitz@apple.comfb8da4e2008-02-19 21:13:19 +00002911 }
2912
commit-queue@webkit.orgd639fb72012-09-01 19:46:16 +00002913 if (renderTextInfo.m_text != t) {
esprehn@chromium.org7745ffb2013-02-19 21:51:19 +00002914 updateCounterIfNeeded(t);
mitz@apple.com6a859602012-08-27 15:31:56 +00002915 renderTextInfo.m_text = t;
mitz@apple.comd4c153d2012-09-16 23:36:41 +00002916 renderTextInfo.m_font = &f;
mitz@apple.com6a859602012-08-27 15:31:56 +00002917 renderTextInfo.m_layout = f.createLayout(t, width.currentWidth(), collapseWhiteSpace);
glenn@skynav.com61b1abf2013-04-02 23:28:32 +00002918 renderTextInfo.m_lineBreakIterator.resetStringAndReleaseIterator(t->text(), style->locale());
mitz@apple.comd4c153d2012-09-16 23:36:41 +00002919 } else if (renderTextInfo.m_layout && renderTextInfo.m_font != &f) {
2920 renderTextInfo.m_font = &f;
2921 renderTextInfo.m_layout = f.createLayout(t, width.currentWidth(), collapseWhiteSpace);
mitz@apple.com6a859602012-08-27 15:31:56 +00002922 }
mitz@apple.comd4c153d2012-09-16 23:36:41 +00002923
mitz@apple.com6a859602012-08-27 15:31:56 +00002924 TextLayout* textLayout = renderTextInfo.m_layout.get();
2925
mitz@apple.com8520cd82012-09-22 01:00:01 +00002926 // Non-zero only when kerning is enabled and TextLayout isn't used, in which case we measure
2927 // words with their trailing space, then subtract its width.
2928 float wordTrailingSpaceWidth = (f.typesettingFeatures() & Kerning) && !textLayout ? f.width(constructTextRun(t, f, &space, 1, style)) + wordSpacing : 0;
2929
glenn@skynav.com61b1abf2013-04-02 23:28:32 +00002930 UChar lastCharacter = renderTextInfo.m_lineBreakIterator.lastCharacter();
2931 UChar secondToLastCharacter = renderTextInfo.m_lineBreakIterator.secondToLastCharacter();
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002932 for (; current.m_pos < t->textLength(); current.fastIncrementInTextNode()) {
rjwc9c257d2003-01-24 03:46:17 +00002933 bool previousCharacterIsSpace = currentCharacterIsSpace;
harrisone343c412005-01-18 01:07:26 +00002934 bool previousCharacterIsWS = currentCharacterIsWS;
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002935 UChar c = current.current();
hyattb0d9f602007-01-15 01:28:23 +00002936 currentCharacterIsSpace = c == ' ' || c == '\t' || (!preserveNewline && (c == '\n'));
darin47ece0d2005-09-04 07:42:31 +00002937
hyattb0d9f602007-01-15 01:28:23 +00002938 if (!collapseWhiteSpace || !currentCharacterIsSpace)
hyatt@apple.com5950bd42011-09-27 20:39:57 +00002939 lineInfo.setEmpty(false, m_block, &width);
mitz@apple.combe429562008-03-07 01:09:51 +00002940
mitz@apple.com20e34452010-09-28 19:38:15 +00002941 if (c == softHyphen && autoWrap && !hyphenWidth && style->hyphens() != HyphensNone) {
commit-queue@webkit.orge60bb902011-09-08 19:18:43 +00002942 hyphenWidth = measureHyphenWidth(t, f);
rniwa@webkit.org58925e82011-04-12 21:32:58 +00002943 width.addUncommittedWidth(hyphenWidth);
hyatt78b85132004-03-29 20:07:45 +00002944 }
mitz@apple.com20e34452010-09-28 19:38:15 +00002945
hyatt3aff2332003-01-23 01:15:28 +00002946 bool applyWordSpacing = false;
eric@webkit.org060caf62011-05-03 22:11:39 +00002947
darinf9e5d6c2007-01-09 14:54:26 +00002948 currentCharacterIsWS = currentCharacterIsSpace || (breakNBSP && c == noBreakSpace);
harrisone343c412005-01-18 01:07:26 +00002949
weiniged111c12007-07-13 22:45:11 +00002950 if ((breakAll || breakWords) && !midWordBreak) {
2951 wrapW += charWidth;
mitz@apple.com880d8e12011-08-17 20:52:31 +00002952 bool midWordBreakIsBeforeSurrogatePair = U16_IS_LEAD(c) && current.m_pos + 1 < t->textLength() && U16_IS_TRAIL(t->characters()[current.m_pos + 1]);
enrica@apple.com885c84d2012-10-10 05:48:51 +00002953 charWidth = textWidth(t, current.m_pos, midWordBreakIsBeforeSurrogatePair ? 2 : 1, f, width.committedWidth() + wrapW, isFixedPitch, collapseWhiteSpace, 0, textLayout);
rniwa@webkit.org5eb8d162011-04-13 02:13:33 +00002954 midWordBreak = width.committedWidth() + wrapW + charWidth > width.availableWidth();
weinigf28a1c32007-02-14 14:10:31 +00002955 }
darin47ece0d2005-09-04 07:42:31 +00002956
commit-queue@webkit.orga94b1b32013-02-26 18:38:39 +00002957 bool betweenWords = c == '\n' || (currWS != PRE && !atStart && isBreakable(renderTextInfo.m_lineBreakIterator, current.m_pos, current.m_nextBreakablePosition, breakNBSP)
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002958 && (style->hyphens() != HyphensNone || (current.previousInSameNode() != softHyphen)));
mitz@apple.com20e34452010-09-28 19:38:15 +00002959
weiniged111c12007-07-13 22:45:11 +00002960 if (betweenWords || midWordBreak) {
hyatt0c05e102006-04-14 08:15:00 +00002961 bool stoppedIgnoringSpaces = false;
hyatt33f8d492002-11-12 21:44:52 +00002962 if (ignoringSpaces) {
leviw@chromium.orga16671e2013-02-20 23:44:21 +00002963 lastSpaceWordSpacing = 0;
rjwc9c257d2003-01-24 03:46:17 +00002964 if (!currentCharacterIsSpace) {
hyatt33f8d492002-11-12 21:44:52 +00002965 // Stop ignoring spaces and begin at this
2966 // new point.
hyatt48710d62003-08-21 09:17:13 +00002967 ignoringSpaces = false;
enrica@apple.com885c84d2012-10-10 05:48:51 +00002968 wordSpacingForWordMeasurement = 0;
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002969 lastSpace = current.m_pos; // e.g., "Foo goo", don't add in any of the ignored spaces.
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00002970 stopIgnoringSpaces(lineMidpointState, InlineIterator(0, current.m_obj, current.m_pos));
hyatt0c05e102006-04-14 08:15:00 +00002971 stoppedIgnoringSpaces = true;
harrisone343c412005-01-18 01:07:26 +00002972 } else {
hyatt33f8d492002-11-12 21:44:52 +00002973 // Just keep ignoring these spaces.
glenn@skynav.com1fa656a2013-03-11 03:30:57 +00002974 goto nextCharacter;
hyatt33f8d492002-11-12 21:44:52 +00002975 }
2976 }
rjwc9c257d2003-01-24 03:46:17 +00002977
enrica@apple.com885c84d2012-10-10 05:48:51 +00002978 wordMeasurements.grow(wordMeasurements.size() + 1);
2979 WordMeasurement& wordMeasurement = wordMeasurements.last();
2980
2981 wordMeasurement.renderer = t;
2982 wordMeasurement.endOffset = current.m_pos;
2983 wordMeasurement.startOffset = lastSpace;
2984
hyatt@apple.com0acc9352011-02-17 19:19:07 +00002985 float additionalTmpW;
mitz@apple.comdc33a5f62012-11-28 19:43:24 +00002986 if (wordTrailingSpaceWidth && c == ' ')
enrica@apple.com885c84d2012-10-10 05:48:51 +00002987 additionalTmpW = textWidth(t, lastSpace, current.m_pos + 1 - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout) - wordTrailingSpaceWidth;
mitz@apple.comfa13fcc2010-01-07 01:41:32 +00002988 else
enrica@apple.com885c84d2012-10-10 05:48:51 +00002989 additionalTmpW = textWidth(t, lastSpace, current.m_pos - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout);
2990
2991 wordMeasurement.width = additionalTmpW + wordSpacingForWordMeasurement;
2992 additionalTmpW += lastSpaceWordSpacing;
rniwa@webkit.org58925e82011-04-12 21:32:58 +00002993 width.addUncommittedWidth(additionalTmpW);
hyattffe78712003-02-11 01:59:29 +00002994 if (!appliedStartWidth) {
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002995 width.addUncommittedWidth(inlineLogicalWidth(current.m_obj, true, false));
hyattffe78712003-02-11 01:59:29 +00002996 appliedStartWidth = true;
2997 }
eric@webkit.org060caf62011-05-03 22:11:39 +00002998
enrica@apple.com885c84d2012-10-10 05:48:51 +00002999 applyWordSpacing = wordSpacing && currentCharacterIsSpace;
hyatt3aff2332003-01-23 01:15:28 +00003000
rniwa@webkit.org5eb8d162011-04-13 02:13:33 +00003001 if (!width.committedWidth() && autoWrap && !width.fitsOnLine())
rniwa@webkit.org44424752011-04-14 00:58:40 +00003002 width.fitBelowFloats();
mitz@apple.comcfd9b7b2008-02-24 04:00:21 +00003003
hyattb0d9f602007-01-15 01:28:23 +00003004 if (autoWrap || breakWords) {
hyattdca76e92005-11-02 08:52:50 +00003005 // If we break only after white-space, consider the current character
kociendae4134242004-10-25 18:48:44 +00003006 // as candidate width for this line.
ap932806a2006-10-01 09:06:09 +00003007 bool lineWasTooWide = false;
mihnea@adobe.com3bebbf22012-01-19 09:22:59 +00003008 if (width.fitsOnLine() && currentCharacterIsWS && currentStyle->breakOnlyAfterWhiteSpace() && !midWordBreak) {
enrica@apple.com885c84d2012-10-10 05:48:51 +00003009 float charWidth = textWidth(t, current.m_pos, 1, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout) + (applyWordSpacing ? wordSpacing : 0);
ap932806a2006-10-01 09:06:09 +00003010 // Check if line is too big even without the extra space
eric@webkit.org060caf62011-05-03 22:11:39 +00003011 // at the end of the line. If it is not, do nothing.
3012 // If the line needs the extra whitespace to be too long,
3013 // then move the line break to the space and skip all
ap932806a2006-10-01 09:06:09 +00003014 // additional whitespace.
rniwa@webkit.org5eb8d162011-04-13 02:13:33 +00003015 if (!width.fitsOnLine(charWidth)) {
ap932806a2006-10-01 09:06:09 +00003016 lineWasTooWide = true;
rniwa@webkit.org15b91522011-05-04 00:38:05 +00003017 lBreak.moveTo(current.m_obj, current.m_pos, current.m_nextBreakablePosition);
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +00003018 skipTrailingWhitespace(lBreak, lineInfo);
kocienda9dbe9b12004-10-22 20:07:05 +00003019 }
ap932806a2006-10-01 09:06:09 +00003020 }
rniwa@webkit.org5eb8d162011-04-13 02:13:33 +00003021 if (lineWasTooWide || !width.fitsOnLine()) {
3022 if (canHyphenate && !width.fitsOnLine()) {
mihnea@adobe.com3bebbf22012-01-19 09:22:59 +00003023 tryHyphenating(t, f, style->locale(), consecutiveHyphenatedLines, blockStyle->hyphenationLimitLines(), style->hyphenationLimitBefore(), style->hyphenationLimitAfter(), lastSpace, current.m_pos, width.currentWidth() - additionalTmpW, width.availableWidth(), isFixedPitch, collapseWhiteSpace, lastSpaceWordSpacing, lBreak, current.m_nextBreakablePosition, m_hyphenated);
leviw@chromium.org1a508692011-05-05 00:01:11 +00003024 if (m_hyphenated)
mitz@apple.com67ed70a2010-06-22 22:10:10 +00003025 goto end;
3026 }
leviw@chromium.orgcee20512011-04-06 12:12:58 +00003027 if (lBreak.atTextParagraphSeparator()) {
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00003028 if (!stoppedIgnoringSpaces && current.m_pos > 0)
3029 ensureCharacterGetsLineBox(lineMidpointState, current);
mitz@apple.com1a301772008-03-11 18:30:36 +00003030 lBreak.increment();
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +00003031 lineInfo.setPreviousLineBrokeCleanly(true);
enrica@apple.com885c84d2012-10-10 05:48:51 +00003032 wordMeasurement.endOffset = lBreak.m_pos;
adele7fc3e832006-02-17 09:31:35 +00003033 }
msaboff@apple.com776c286c72012-10-15 16:56:29 +00003034 if (lBreak.m_obj && lBreak.m_pos && lBreak.m_obj->isText() && toRenderText(lBreak.m_obj)->textLength() && toRenderText(lBreak.m_obj)->characterAt(lBreak.m_pos - 1) == softHyphen && style->hyphens() != HyphensNone)
leviw@chromium.org1a508692011-05-05 00:01:11 +00003035 m_hyphenated = true;
enrica@apple.com885c84d2012-10-10 05:48:51 +00003036 if (lBreak.m_pos && lBreak.m_pos != (unsigned)wordMeasurement.endOffset && !wordMeasurement.width) {
3037 if (charWidth) {
3038 wordMeasurement.endOffset = lBreak.m_pos;
3039 wordMeasurement.width = charWidth;
3040 }
3041 }
commit-queue@webkit.org63cc2d02013-01-02 22:52:58 +00003042 // Didn't fit. Jump to the end unless there's still an opportunity to collapse whitespace.
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00003043 if (ignoringSpaces || !collapseWhiteSpace || !currentCharacterIsSpace || !previousCharacterIsSpace)
commit-queue@webkit.org63cc2d02013-01-02 22:52:58 +00003044 goto end;
darin54008922006-01-13 16:39:05 +00003045 } else {
weiniged111c12007-07-13 22:45:11 +00003046 if (!betweenWords || (midWordBreak && !autoWrap))
rniwa@webkit.org58925e82011-04-12 21:32:58 +00003047 width.addUncommittedWidth(-additionalTmpW);
mitz@apple.com20e34452010-09-28 19:38:15 +00003048 if (hyphenWidth) {
darin54008922006-01-13 16:39:05 +00003049 // Subtract the width of the soft hyphen out since we fit on a line.
rniwa@webkit.org58925e82011-04-12 21:32:58 +00003050 width.addUncommittedWidth(-hyphenWidth);
mitz@apple.com20e34452010-09-28 19:38:15 +00003051 hyphenWidth = 0;
3052 }
darin54008922006-01-13 16:39:05 +00003053 }
rjwc9c257d2003-01-24 03:46:17 +00003054 }
hyatt33f8d492002-11-12 21:44:52 +00003055
hyattb0d9f602007-01-15 01:28:23 +00003056 if (c == '\n' && preserveNewline) {
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00003057 if (!stoppedIgnoringSpaces && current.m_pos > 0)
3058 ensureCharacterGetsLineBox(lineMidpointState, current);
rniwa@webkit.org15b91522011-05-04 00:38:05 +00003059 lBreak.moveTo(current.m_obj, current.m_pos, current.m_nextBreakablePosition);
mitz@apple.com1a301772008-03-11 18:30:36 +00003060 lBreak.increment();
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +00003061 lineInfo.setPreviousLineBrokeCleanly(true);
hyatt33f8d492002-11-12 21:44:52 +00003062 return lBreak;
3063 }
hyatta9f48e32003-02-03 22:48:01 +00003064
weinigf28a1c32007-02-14 14:10:31 +00003065 if (autoWrap && betweenWords) {
rniwa@webkit.org58925e82011-04-12 21:32:58 +00003066 width.commit();
weiniged111c12007-07-13 22:45:11 +00003067 wrapW = 0;
rniwa@webkit.org15b91522011-05-04 00:38:05 +00003068 lBreak.moveTo(current.m_obj, current.m_pos, current.m_nextBreakablePosition);
weinigf28a1c32007-02-14 14:10:31 +00003069 // Auto-wrapping text should not wrap in the middle of a word once it has had an
3070 // opportunity to break after a word.
3071 breakWords = false;
hyatta9f48e32003-02-03 22:48:01 +00003072 }
eric@webkit.org060caf62011-05-03 22:11:39 +00003073
mitz@apple.com86877722011-08-19 16:29:32 +00003074 if (midWordBreak && !U16_IS_TRAIL(c) && !(category(c) & (Mark_NonSpacing | Mark_Enclosing | Mark_SpacingCombining))) {
darin54008922006-01-13 16:39:05 +00003075 // Remember this as a breakable position in case
3076 // adding the end width forces a break.
rniwa@webkit.org15b91522011-05-04 00:38:05 +00003077 lBreak.moveTo(current.m_obj, current.m_pos, current.m_nextBreakablePosition);
weiniged111c12007-07-13 22:45:11 +00003078 midWordBreak &= (breakWords || breakAll);
3079 }
3080
3081 if (betweenWords) {
darin54008922006-01-13 16:39:05 +00003082 lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
enrica@apple.com885c84d2012-10-10 05:48:51 +00003083 wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurement.width) ? wordSpacing : 0;
rniwa@webkit.org15b91522011-05-04 00:38:05 +00003084 lastSpace = current.m_pos;
darin54008922006-01-13 16:39:05 +00003085 }
eric@webkit.org060caf62011-05-03 22:11:39 +00003086
mihnea@adobe.com3bebbf22012-01-19 09:22:59 +00003087 if (!ignoringSpaces && currentStyle->collapseWhiteSpace()) {
hyatt33f8d492002-11-12 21:44:52 +00003088 // If we encounter a newline, or if we encounter a
3089 // second space, we need to go ahead and break up this
3090 // run and enter a mode where we start collapsing spaces.
hyatt98b16282004-03-31 18:43:12 +00003091 if (currentCharacterIsSpace && previousCharacterIsSpace) {
hyatt33f8d492002-11-12 21:44:52 +00003092 ignoringSpaces = true;
eric@webkit.org060caf62011-05-03 22:11:39 +00003093
hyatt33f8d492002-11-12 21:44:52 +00003094 // We just entered a mode where we are ignoring
3095 // spaces. Create a midpoint to terminate the run
eric@webkit.org060caf62011-05-03 22:11:39 +00003096 // before the second space.
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00003097 startIgnoringSpaces(lineMidpointState, ignoreStart);
mitz@apple.come98acc92011-05-22 04:44:27 +00003098 trailingObjects.updateMidpointsForTrailingBoxes(lineMidpointState, InlineIterator(), TrailingObjects::DoNotCollapseFirstSpace);
hyatt33f8d492002-11-12 21:44:52 +00003099 }
3100 }
eseidel789896f2005-11-27 22:52:09 +00003101 } else if (ignoringSpaces) {
hyatt33f8d492002-11-12 21:44:52 +00003102 // Stop ignoring spaces and begin at this
3103 // new point.
3104 ignoringSpaces = false;
eseideld13fe532005-11-30 02:40:29 +00003105 lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
enrica@apple.com885c84d2012-10-10 05:48:51 +00003106 wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurements.last().width) ? wordSpacing : 0;
rniwa@webkit.org15b91522011-05-04 00:38:05 +00003107 lastSpace = current.m_pos; // e.g., "Foo goo", don't add in any of the ignored spaces.
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00003108 stopIgnoringSpaces(lineMidpointState, InlineIterator(0, current.m_obj, current.m_pos));
hyatt33f8d492002-11-12 21:44:52 +00003109 }
hyatt98b16282004-03-31 18:43:12 +00003110
zimmermann@webkit.orgcea314662011-04-05 16:38:10 +00003111#if ENABLE(SVG)
rniwa@webkit.org15b91522011-05-04 00:38:05 +00003112 if (isSVGText && current.m_pos > 0) {
zimmermann@webkit.orgcea314662011-04-05 16:38:10 +00003113 // Force creation of new InlineBoxes for each absolute positioned character (those that start new text chunks).
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00003114 if (toRenderSVGInlineText(t)->characterStartsNewTextChunk(current.m_pos))
3115 ensureCharacterGetsLineBox(lineMidpointState, current);
zimmermann@webkit.orgcea314662011-04-05 16:38:10 +00003116 }
3117#endif
3118
hyatt98b16282004-03-31 18:43:12 +00003119 if (currentCharacterIsSpace && !previousCharacterIsSpace) {
rniwa@webkit.org15b91522011-05-04 00:38:05 +00003120 ignoreStart.m_obj = current.m_obj;
3121 ignoreStart.m_pos = current.m_pos;
hyatt98b16282004-03-31 18:43:12 +00003122 }
harrisone343c412005-01-18 01:07:26 +00003123
3124 if (!currentCharacterIsWS && previousCharacterIsWS) {
mihnea@adobe.com3bebbf22012-01-19 09:22:59 +00003125 if (autoWrap && currentStyle->breakOnlyAfterWhiteSpace())
rniwa@webkit.org15b91522011-05-04 00:38:05 +00003126 lBreak.moveTo(current.m_obj, current.m_pos, current.m_nextBreakablePosition);
harrisone343c412005-01-18 01:07:26 +00003127 }
eric@webkit.org060caf62011-05-03 22:11:39 +00003128
hyattb0d9f602007-01-15 01:28:23 +00003129 if (collapseWhiteSpace && currentCharacterIsSpace && !ignoringSpaces)
jchaffraix@webkit.org3e44dfa2011-06-20 23:14:23 +00003130 trailingObjects.setTrailingWhitespace(toRenderText(current.m_obj));
mihnea@adobe.com3bebbf22012-01-19 09:22:59 +00003131 else if (!currentStyle->collapseWhiteSpace() || !currentCharacterIsSpace)
rniwa@webkit.org105350c2011-05-03 20:33:25 +00003132 trailingObjects.clear();
3133
ddkilzere8759ef2007-03-25 06:28:19 +00003134 atStart = false;
glenn@skynav.com1fa656a2013-03-11 03:30:57 +00003135 nextCharacter:
glenn@skynav.com61b1abf2013-04-02 23:28:32 +00003136 secondToLastCharacter = lastCharacter;
3137 lastCharacter = c;
hyatt33f8d492002-11-12 21:44:52 +00003138 }
mitz@apple.comfb8da4e2008-02-19 21:13:19 +00003139
glenn@skynav.com61b1abf2013-04-02 23:28:32 +00003140 renderTextInfo.m_lineBreakIterator.setPriorContext(lastCharacter, secondToLastCharacter);
glenn@skynav.com1fa656a2013-03-11 03:30:57 +00003141
enrica@apple.com885c84d2012-10-10 05:48:51 +00003142 wordMeasurements.grow(wordMeasurements.size() + 1);
3143 WordMeasurement& wordMeasurement = wordMeasurements.last();
3144 wordMeasurement.renderer = t;
3145
rniwa@webkit.org15b91522011-05-04 00:38:05 +00003146 // IMPORTANT: current.m_pos is > length here!
enrica@apple.com885c84d2012-10-10 05:48:51 +00003147 float additionalTmpW = ignoringSpaces ? 0 : textWidth(t, lastSpace, current.m_pos - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout);
3148 wordMeasurement.startOffset = lastSpace;
3149 wordMeasurement.endOffset = current.m_pos;
3150 wordMeasurement.width = ignoringSpaces ? 0 : additionalTmpW + wordSpacingForWordMeasurement;
3151 additionalTmpW += lastSpaceWordSpacing;
yael.aharon@nokia.com1cfbceb2011-06-06 18:32:54 +00003152 width.addUncommittedWidth(additionalTmpW + inlineLogicalWidth(current.m_obj, !appliedStartWidth, includeEndWidth));
3153 includeEndWidth = false;
mitz@apple.comb2107652010-06-21 16:54:52 +00003154
rniwa@webkit.org5eb8d162011-04-13 02:13:33 +00003155 if (!width.fitsOnLine()) {
mitz@apple.com96cf46d2011-03-14 01:09:26 +00003156 if (canHyphenate)
mihnea@adobe.com3bebbf22012-01-19 09:22:59 +00003157 tryHyphenating(t, f, style->locale(), consecutiveHyphenatedLines, blockStyle->hyphenationLimitLines(), style->hyphenationLimitBefore(), style->hyphenationLimitAfter(), lastSpace, current.m_pos, width.currentWidth() - additionalTmpW, width.availableWidth(), isFixedPitch, collapseWhiteSpace, lastSpaceWordSpacing, lBreak, current.m_nextBreakablePosition, m_hyphenated);
rniwa@webkit.org58925e82011-04-12 21:32:58 +00003158
leviw@chromium.org1a508692011-05-05 00:01:11 +00003159 if (!m_hyphenated && lBreak.previousInSameNode() == softHyphen && style->hyphens() != HyphensNone)
3160 m_hyphenated = true;
rniwa@webkit.org58925e82011-04-12 21:32:58 +00003161
leviw@chromium.org1a508692011-05-05 00:01:11 +00003162 if (m_hyphenated)
mitz@apple.comb2107652010-06-21 16:54:52 +00003163 goto end;
3164 }
kociendabb0c24b2001-08-24 14:24:40 +00003165 } else
weinigf28a1c32007-02-14 14:10:31 +00003166 ASSERT_NOT_REACHED();
kociendabb0c24b2001-08-24 14:24:40 +00003167
robert@webkit.org744e01c2013-01-02 20:18:15 +00003168 bool checkForBreak = autoWrap;
rniwa@webkit.org5eb8d162011-04-13 02:13:33 +00003169 if (width.committedWidth() && !width.fitsOnLine() && lBreak.m_obj && currWS == NOWRAP)
hyatt74eec4d2003-03-23 08:02:47 +00003170 checkForBreak = true;
commit-queue@webkit.org63cc2d02013-01-02 22:52:58 +00003171 else if (next && current.m_obj->isText() && next->isText() && !next->isBR() && (autoWrap || next->style()->autoWrap())) {
3172 if (autoWrap && currentCharacterIsSpace)
rniwa@webkit.org76aa5222011-05-04 13:03:32 +00003173 checkForBreak = true;
3174 else {
3175 RenderText* nextText = toRenderText(next);
3176 if (nextText->textLength()) {
msaboff@apple.com776c286c72012-10-15 16:56:29 +00003177 UChar c = nextText->characterAt(0);
rniwa@webkit.org76aa5222011-05-04 13:03:32 +00003178 // If the next item on the line is text, and if we did not end with
3179 // a space, then the next text run continues our word (and so it needs to
commit-queue@webkit.org63cc2d02013-01-02 22:52:58 +00003180 // keep adding to the uncommitted width. Just update and continue.
3181 checkForBreak = !currentCharacterIsSpace && (c == ' ' || c == '\t' || (c == '\n' && !next->preservesNewline()));
rniwa@webkit.org76aa5222011-05-04 13:03:32 +00003182 } else if (nextText->isWordBreak())
hyatta9f48e32003-02-03 22:48:01 +00003183 checkForBreak = true;
rniwa@webkit.org5eb8d162011-04-13 02:13:33 +00003184
rniwa@webkit.org76aa5222011-05-04 13:03:32 +00003185 if (!width.fitsOnLine() && !width.committedWidth())
3186 width.fitBelowFloats();
rniwa@webkit.org5eb8d162011-04-13 02:13:33 +00003187
rniwa@webkit.org76aa5222011-05-04 13:03:32 +00003188 bool canPlaceOnLine = width.fitsOnLine() || !autoWrapWasEverTrueOnLine;
3189 if (canPlaceOnLine && checkForBreak) {
3190 width.commit();
3191 lBreak.moveToStartOf(next);
hyatta9f48e32003-02-03 22:48:01 +00003192 }
3193 }
3194 }
3195
rniwa@webkit.org5eb8d162011-04-13 02:13:33 +00003196 if (checkForBreak && !width.fitsOnLine()) {
kociendabb0c24b2001-08-24 14:24:40 +00003197 // if we have floats, try to get below them.
mihnea@adobe.com3bebbf22012-01-19 09:22:59 +00003198 if (currentCharacterIsSpace && !ignoringSpaces && currentStyle->collapseWhiteSpace())
rniwa@webkit.org105350c2011-05-03 20:33:25 +00003199 trailingObjects.clear();
mitz@apple.comcfd9b7b2008-02-24 04:00:21 +00003200
rniwa@webkit.org58925e82011-04-12 21:32:58 +00003201 if (width.committedWidth())
mitz@apple.comcfd9b7b2008-02-24 04:00:21 +00003202 goto end;
3203
rniwa@webkit.org44424752011-04-14 00:58:40 +00003204 width.fitBelowFloats();
hyattf14a4a32002-11-21 22:06:32 +00003205
hyatta14d1742003-01-02 20:25:46 +00003206 // |width| may have been adjusted because we got shoved down past a float (thus
3207 // giving us more room), so we need to retest, and only jump to
3208 // the end label if we still don't fit on the line. -dwh
rniwa@webkit.org5eb8d162011-04-13 02:13:33 +00003209 if (!width.fitsOnLine())
hyatta14d1742003-01-02 20:25:46 +00003210 goto end;
robert@webkit.org744e01c2013-01-02 20:18:15 +00003211 } else if (blockStyle->autoWrap() && !width.fitsOnLine() && !width.committedWidth()) {
3212 // If the container autowraps but the current child does not then we still need to ensure that it
3213 // wraps and moves below any floats.
3214 width.fitBelowFloats();
kociendabb0c24b2001-08-24 14:24:40 +00003215 }
hyatt1d9e29b2003-04-10 01:48:53 +00003216
simon.fraser@apple.com2f071852012-06-25 00:11:30 +00003217 if (!current.m_obj->isFloatingOrOutOfFlowPositioned()) {
rniwa@webkit.org15b91522011-05-04 00:38:05 +00003218 last = current.m_obj;
darin@apple.comb6cb2562009-08-05 21:25:09 +00003219 if (last->isReplaced() && autoWrap && (!last->isImage() || allowImagesToBreak) && (!last->isListMarker() || toRenderListMarker(last)->isInside())) {
rniwa@webkit.org58925e82011-04-12 21:32:58 +00003220 width.commit();
eric@webkit.orgbd143592011-03-29 17:44:41 +00003221 lBreak.moveToStartOf(next);
mitz@apple.com1a301772008-03-11 18:30:36 +00003222 }
hyatt711fe232002-11-20 21:25:14 +00003223 }
3224
hyatta9f48e32003-02-03 22:48:01 +00003225 // Clear out our character space bool, since inline <pre>s don't collapse whitespace
3226 // with adjacent inline normal/nowrap spans.
hyattb0d9f602007-01-15 01:28:23 +00003227 if (!collapseWhiteSpace)
hyatta9f48e32003-02-03 22:48:01 +00003228 currentCharacterIsSpace = false;
eric@webkit.org060caf62011-05-03 22:11:39 +00003229
rniwa@webkit.org15b91522011-05-04 00:38:05 +00003230 current.moveToStartOf(next);
ddkilzere8759ef2007-03-25 06:28:19 +00003231 atStart = false;
kociendabb0c24b2001-08-24 14:24:40 +00003232 }
eric@webkit.org060caf62011-05-03 22:11:39 +00003233
rniwa@webkit.org5eb8d162011-04-13 02:13:33 +00003234 if (width.fitsOnLine() || lastWS == NOWRAP)
eric@webkit.orgbd143592011-03-29 17:44:41 +00003235 lBreak.clear();
kociendabb0c24b2001-08-24 14:24:40 +00003236
3237 end:
eric@webkit.org8c25a592011-03-29 13:18:11 +00003238 if (lBreak == resolver.position() && (!lBreak.m_obj || !lBreak.m_obj->isBR())) {
kociendabb0c24b2001-08-24 14:24:40 +00003239 // we just add as much as possible
commit-queue@webkit.org63cc2d02013-01-02 22:52:58 +00003240 if (blockStyle->whiteSpace() == PRE && !current.m_pos) {
3241 lBreak.moveTo(last, last->isText() ? last->length() : 0);
eric@webkit.org8c25a592011-03-29 13:18:11 +00003242 } else if (lBreak.m_obj) {
yuzo@google.comc25f62f2010-02-09 09:16:36 +00003243 // Don't ever break in the middle of a word if we can help it.
3244 // There's no room at all. We just have to be on this line,
3245 // even though we'll spill out.
rniwa@webkit.org15b91522011-05-04 00:38:05 +00003246 lBreak.moveTo(current.m_obj, current.m_pos);
kociendabb0c24b2001-08-24 14:24:40 +00003247 }
3248 }
3249
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00003250 // FIXME Bug 100049: We do not need to consume input in a multi-segment line
3251 // unless no segment will.
kociendabb0c24b2001-08-24 14:24:40 +00003252 // make sure we consume at least one char/object.
mitz@apple.com15035e62008-07-05 20:44:44 +00003253 if (lBreak == resolver.position())
mitz@apple.com1a301772008-03-11 18:30:36 +00003254 lBreak.increment();
hyatt33f8d492002-11-12 21:44:52 +00003255
hyattfe99c872003-07-31 22:25:29 +00003256 // Sanity check our midpoints.
hyatt@apple.comb3466af2009-06-13 06:04:40 +00003257 checkMidpoints(lineMidpointState, lBreak);
hyatt@apple.com63a8df32011-03-28 19:44:19 +00003258
mitz@apple.come98acc92011-05-22 04:44:27 +00003259 trailingObjects.updateMidpointsForTrailingBoxes(lineMidpointState, lBreak, TrailingObjects::CollapseFirstSpace);
rjwc9c257d2003-01-24 03:46:17 +00003260
mjs54b64002003-04-02 02:59:02 +00003261 // We might have made lBreak an iterator that points past the end
3262 // of the object. Do this adjustment to make it point to the start
3263 // of the next object instead to avoid confusing the rest of the
3264 // code.
eric@webkit.org86a865a2011-03-29 15:30:41 +00003265 if (lBreak.m_pos > 0) {
3266 lBreak.m_pos--;
mitz@apple.com1a301772008-03-11 18:30:36 +00003267 lBreak.increment();
mjs54b64002003-04-02 02:59:02 +00003268 }
3269
kociendabb0c24b2001-08-24 14:24:40 +00003270 return lBreak;
3271}
3272
hyatt@apple.com5dc5a312009-08-18 19:15:19 +00003273void RenderBlock::addOverflowFromInlineChildren()
hyattb4b20872004-10-20 21:34:01 +00003274{
eae@chromium.org9717cd82012-11-07 18:33:44 +00003275 LayoutUnit endPadding = hasOverflowClip() ? paddingEnd() : LayoutUnit();
hyatt@apple.com592848f2010-12-06 20:03:43 +00003276 // FIXME: Need to find another way to do this, since scrollbars could show when we don't want them to.
commit-queue@webkit.org5f402932012-05-11 20:09:13 +00003277 if (hasOverflowClip() && !endPadding && node() && node()->isRootEditableElement() && style()->isLeftToRightDirection())
hyatt@apple.com592848f2010-12-06 20:03:43 +00003278 endPadding = 1;
hyattb4b20872004-10-20 21:34:01 +00003279 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
hyatt@apple.com592848f2010-12-06 20:03:43 +00003280 addLayoutOverflow(curr->paddedLayoutOverflowRect(endPadding));
hyatt@apple.com5dc5a312009-08-18 19:15:19 +00003281 if (!hasOverflowClip())
hyatt@apple.com61f25322011-03-31 20:40:48 +00003282 addVisualOverflow(curr->visualOverflowRect(curr->lineTop(), curr->lineBottom()));
hyattb4b20872004-10-20 21:34:01 +00003283 }
3284}
3285
hyatted77ad82004-06-15 07:21:23 +00003286void RenderBlock::deleteEllipsisLineBoxes()
3287{
benjamin@webkit.orgf68b1be2012-06-23 02:02:28 +00003288 ETextAlign textAlign = style()->textAlign();
3289 bool ltr = style()->isLeftToRightDirection();
3290 bool firstLine = true;
3291 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
3292 if (curr->hasEllipsisBox()) {
3293 curr->clearTruncation();
3294
3295 // Shift the line back where it belongs if we cannot accomodate an ellipsis.
3296 float logicalLeft = pixelSnappedLogicalLeftOffsetForLine(curr->lineTop(), firstLine);
3297 float availableLogicalWidth = logicalRightOffsetForLine(curr->lineTop(), false) - logicalLeft;
3298 float totalLogicalWidth = curr->logicalWidth();
3299 updateLogicalWidthForAlignment(textAlign, 0, logicalLeft, totalLogicalWidth, availableLogicalWidth, 0);
3300
3301 if (ltr)
3302 curr->adjustLogicalPosition((logicalLeft - curr->logicalLeft()), 0);
3303 else
3304 curr->adjustLogicalPosition(-(curr->logicalLeft() - logicalLeft), 0);
3305 }
3306 firstLine = false;
3307 }
hyatted77ad82004-06-15 07:21:23 +00003308}
3309
3310void RenderBlock::checkLinesForTextOverflow()
3311{
3312 // Determine the width of the ellipsis using the current font.
darindbba2bb2007-01-11 12:23:49 +00003313 // FIXME: CSS3 says this is configurable, also need to use 0x002E (FULL STOP) if horizontal ellipsis is "not renderable"
zimmermann@webkit.org8a7e7ff2011-05-24 15:27:36 +00003314 const Font& font = style()->font();
bolsinga@apple.com97e42c42008-11-15 04:47:20 +00003315 DEFINE_STATIC_LOCAL(AtomicString, ellipsisStr, (&horizontalEllipsis, 1));
hyatt3e99d1c2006-02-24 21:13:08 +00003316 const Font& firstLineFont = firstLineStyle()->font();
leviw@chromium.orgd32486e2012-03-16 10:52:56 +00003317 int firstLineEllipsisWidth = firstLineFont.width(constructTextRun(this, firstLineFont, &horizontalEllipsis, 1, firstLineStyle()));
3318 int ellipsisWidth = (font == firstLineFont) ? firstLineEllipsisWidth : font.width(constructTextRun(this, font, &horizontalEllipsis, 1, style()));
hyatted77ad82004-06-15 07:21:23 +00003319
3320 // For LTR text truncation, we want to get the right edge of our padding box, and then we want to see
3321 // if the right edge of a line box exceeds that. For RTL, we use the left edge of the padding box and
3322 // check the left edge of the line box to see if it is less
3323 // Include the scrollbar for overflow blocks, which means we want to use "contentWidth()"
hyatt@apple.comc0fa1632010-09-30 20:01:33 +00003324 bool ltr = style()->isLeftToRightDirection();
benjamin@webkit.orgf68b1be2012-06-23 02:02:28 +00003325 ETextAlign textAlign = style()->textAlign();
3326 bool firstLine = true;
hyatted77ad82004-06-15 07:21:23 +00003327 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
eae@chromium.org275da182012-12-19 23:07:55 +00003328 // FIXME: Use pixelSnappedLogicalRightOffsetForLine instead of snapping it ourselves once the column workaround in said method has been fixed.
3329 // https://bugs.webkit.org/show_bug.cgi?id=105461
3330 int blockRightEdge = snapSizeToPixel(logicalRightOffsetForLine(curr->lineTop(), firstLine), curr->x());
3331 int blockLeftEdge = pixelSnappedLogicalLeftOffsetForLine(curr->lineTop(), firstLine);
eae@chromium.orgc491d962012-12-28 18:32:08 +00003332 int lineBoxEdge = ltr ? snapSizeToPixel(curr->x() + curr->logicalWidth(), curr->x()) : snapSizeToPixel(curr->x(), 0);
dglazkov@chromium.org28434e62009-05-13 22:30:10 +00003333 if ((ltr && lineBoxEdge > blockRightEdge) || (!ltr && lineBoxEdge < blockLeftEdge)) {
hyattf918d2d2004-06-15 07:24:11 +00003334 // This line spills out of our box in the appropriate direction. Now we need to see if the line
hyatted77ad82004-06-15 07:21:23 +00003335 // can be truncated. In order for truncation to be possible, the line must have sufficient space to
3336 // accommodate our truncation string, and no replaced elements (images, tables) can overlap the ellipsis
3337 // space.
benjamin@webkit.orgf68b1be2012-06-23 02:02:28 +00003338
3339 LayoutUnit width = firstLine ? firstLineEllipsisWidth : ellipsisWidth;
eae@chromium.orgee8613e2011-11-12 01:12:58 +00003340 LayoutUnit blockEdge = ltr ? blockRightEdge : blockLeftEdge;
benjamin@webkit.orgf68b1be2012-06-23 02:02:28 +00003341 if (curr->lineCanAccommodateEllipsis(ltr, blockEdge, lineBoxEdge, width)) {
3342 float totalLogicalWidth = curr->placeEllipsis(ellipsisStr, ltr, blockLeftEdge, blockRightEdge, width);
3343
3344 float logicalLeft = 0; // We are only intersted in the delta from the base position.
3345 float truncatedWidth = pixelSnappedLogicalRightOffsetForLine(curr->lineTop(), firstLine);
3346 updateLogicalWidthForAlignment(textAlign, 0, logicalLeft, totalLogicalWidth, truncatedWidth, 0);
3347 if (ltr)
3348 curr->adjustLogicalPosition(logicalLeft, 0);
3349 else
3350 curr->adjustLogicalPosition(-(truncatedWidth - (logicalLeft + totalLogicalWidth)), 0);
3351 }
hyatted77ad82004-06-15 07:21:23 +00003352 }
benjamin@webkit.orgf68b1be2012-06-23 02:02:28 +00003353 firstLine = false;
hyatted77ad82004-06-15 07:21:23 +00003354 }
3355}
3356
hyatt@apple.com5950bd42011-09-27 20:39:57 +00003357bool RenderBlock::positionNewFloatOnLine(FloatingObject* newFloat, FloatingObject* lastFloatFromPreviousLine, LineInfo& lineInfo, LineWidth& width)
rniwa@webkit.org73ce42a2011-04-06 14:10:02 +00003358{
rniwa@webkit.org7881ad02011-04-07 13:05:35 +00003359 if (!positionNewFloats())
3360 return false;
rniwa@webkit.org73ce42a2011-04-06 14:10:02 +00003361
rniwa@webkit.org44424752011-04-14 00:58:40 +00003362 width.shrinkAvailableWidthForNewFloatIfNeeded(newFloat);
rniwa@webkit.org73ce42a2011-04-06 14:10:02 +00003363
hyatt@apple.comdd78df82011-09-27 22:11:41 +00003364 // We only connect floats to lines for pagination purposes if the floats occur at the start of
3365 // the line and the previous line had a hard break (so this line is either the first in the block
3366 // or follows a <br>).
3367 if (!newFloat->m_paginationStrut || !lineInfo.previousLineBrokeCleanly() || !lineInfo.isEmpty())
rniwa@webkit.org7881ad02011-04-07 13:05:35 +00003368 return true;
rniwa@webkit.org73ce42a2011-04-06 14:10:02 +00003369
hyatt@apple.com46c65b32011-08-09 19:13:45 +00003370 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
rniwa@webkit.org73ce42a2011-04-06 14:10:02 +00003371 ASSERT(floatingObjectSet.last() == newFloat);
3372
eae@chromium.orgee8613e2011-11-12 01:12:58 +00003373 LayoutUnit floatLogicalTop = logicalTopForFloat(newFloat);
rniwa@webkit.org73ce42a2011-04-06 14:10:02 +00003374 int paginationStrut = newFloat->m_paginationStrut;
3375
hyatt@apple.com5950bd42011-09-27 20:39:57 +00003376 if (floatLogicalTop - paginationStrut != logicalHeight() + lineInfo.floatPaginationStrut())
rniwa@webkit.org7881ad02011-04-07 13:05:35 +00003377 return true;
rniwa@webkit.org73ce42a2011-04-06 14:10:02 +00003378
3379 FloatingObjectSetIterator it = floatingObjectSet.end();
3380 --it; // Last float is newFloat, skip that one.
3381 FloatingObjectSetIterator begin = floatingObjectSet.begin();
3382 while (it != begin) {
3383 --it;
3384 FloatingObject* f = *it;
3385 if (f == lastFloatFromPreviousLine)
3386 break;
hyatt@apple.com5950bd42011-09-27 20:39:57 +00003387 if (logicalTopForFloat(f) == logicalHeight() + lineInfo.floatPaginationStrut()) {
3388 f->m_paginationStrut += paginationStrut;
rniwa@webkit.org73ce42a2011-04-06 14:10:02 +00003389 RenderBox* o = f->m_renderer;
3390 setLogicalTopForChild(o, logicalTopForChild(o) + marginBeforeForChild(o) + paginationStrut);
3391 if (o->isRenderBlock())
eric@webkit.org218b4e02012-03-28 19:25:02 +00003392 toRenderBlock(o)->setChildNeedsLayout(true, MarkOnlyThis);
rniwa@webkit.org73ce42a2011-04-06 14:10:02 +00003393 o->layoutIfNeeded();
hyatt@apple.com46c65b32011-08-09 19:13:45 +00003394 // Save the old logical top before calling removePlacedObject which will set
3395 // isPlaced to false. Otherwise it will trigger an assert in logicalTopForFloat.
3396 LayoutUnit oldLogicalTop = logicalTopForFloat(f);
3397 m_floatingObjects->removePlacedObject(f);
hyatt@apple.com5950bd42011-09-27 20:39:57 +00003398 setLogicalTopForFloat(f, oldLogicalTop + paginationStrut);
hyatt@apple.com46c65b32011-08-09 19:13:45 +00003399 m_floatingObjects->addPlacedObject(f);
rniwa@webkit.org73ce42a2011-04-06 14:10:02 +00003400 }
3401 }
3402
hyatt@apple.comdd78df82011-09-27 22:11:41 +00003403 // Just update the line info's pagination strut without altering our logical height yet. If the line ends up containing
3404 // no content, then we don't want to improperly grow the height of the block.
3405 lineInfo.setFloatPaginationStrut(lineInfo.floatPaginationStrut() + paginationStrut);
rniwa@webkit.org7881ad02011-04-07 13:05:35 +00003406 return true;
rniwa@webkit.org73ce42a2011-04-06 14:10:02 +00003407}
3408
robert@webkit.org82903f42012-08-28 19:18:40 +00003409LayoutUnit RenderBlock::startAlignedOffsetForLine(LayoutUnit position, bool firstLine)
robert@webkit.orgfc7763c2011-09-03 18:28:57 +00003410{
3411 ETextAlign textAlign = style()->textAlign();
3412
rniwa@webkit.orgaf7f7a42012-06-15 21:54:44 +00003413 if (textAlign == TASTART) // FIXME: Handle TAEND here
robert@webkit.orgfc7763c2011-09-03 18:28:57 +00003414 return startOffsetForLine(position, firstLine);
3415
3416 // updateLogicalWidthForAlignment() handles the direction of the block so no need to consider it here
robert@webkit.org82903f42012-08-28 19:18:40 +00003417 float totalLogicalWidth = 0;
3418 float logicalLeft = logicalLeftOffsetForLine(logicalHeight(), false);
3419 float availableLogicalWidth = logicalRightOffsetForLine(logicalHeight(), false) - logicalLeft;
benjamin@webkit.orgf68b1be2012-06-23 02:02:28 +00003420 updateLogicalWidthForAlignment(textAlign, 0, logicalLeft, totalLogicalWidth, availableLogicalWidth, 0);
robert@webkit.org7861a102011-09-22 17:16:47 +00003421
3422 if (!style()->isLeftToRightDirection())
robert@webkit.org82903f42012-08-28 19:18:40 +00003423 return logicalWidth() - logicalLeft;
robert@webkit.orgfc7763c2011-09-03 18:28:57 +00003424 return logicalLeft;
3425}
3426
hyatt@apple.comee7af1d2012-01-17 19:16:24 +00003427
3428void RenderBlock::layoutLineGridBox()
3429{
3430 if (style()->lineGrid() == RenderStyle::initialLineGrid()) {
3431 setLineGridBox(0);
3432 return;
3433 }
3434
3435 setLineGridBox(0);
3436
3437 RootInlineBox* lineGridBox = new (renderArena()) RootInlineBox(this);
3438 lineGridBox->setHasTextChildren(); // Needed to make the line ascent/descent actually be honored in quirks mode.
3439 lineGridBox->setConstructed();
3440 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
3441 VerticalPositionCache verticalPositionCache;
3442 lineGridBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache);
3443
3444 setLineGridBox(lineGridBox);
3445
3446 // FIXME: If any of the characteristics of the box change compared to the old one, then we need to do a deep dirtying
3447 // (similar to what happens when the page height changes). Ideally, though, we only do this if someone is actually snapping
3448 // to this grid.
3449}
3450
hyattffe78712003-02-11 01:59:29 +00003451}