blob: cabf01e96db631dd749361f82960031e1c2b8a7e [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.
commit-queue@webkit.org17761402013-04-17 18:48:56 +00005 * Copyright (C) 2013 ChangSeok Oh <shivamidow@gmail.com>
kociendabb0c24b2001-08-24 14:24:40 +00006 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
ddkilzerc8eccec2007-09-26 02:29:57 +000019 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
kociendabb0c24b2001-08-24 14:24:40 +000021 *
kociendabb0c24b2001-08-24 14:24:40 +000022 */
darinbe4c67d2005-12-19 19:53:12 +000023
mjsb64c50a2005-10-03 21:13:12 +000024#include "config.h"
darin36d11362006-04-11 16:30:21 +000025
mitz@apple.com4c1ff322009-07-13 00:54:12 +000026#include "BidiResolver.h"
bjonesbe@adobe.com67478092013-09-09 22:18:17 +000027#include "FloatingObjects.h"
mitz@apple.comb2107652010-06-21 16:54:52 +000028#include "Hyphenation.h"
hyatt@apple.com71eeb442010-02-11 20:05:51 +000029#include "InlineIterator.h"
eseidel3a6d1322006-01-09 03:14:50 +000030#include "InlineTextBox.h"
zoltan@webkit.orgfefa1412013-09-12 16:57:55 +000031#include "LineInfo.h"
zoltan@webkit.org4c74e8d2013-09-13 17:59:12 +000032#include "LineLayoutState.h"
ggarenec11e5b2007-02-25 02:14:54 +000033#include "Logging.h"
darin36d11362006-04-11 16:30:21 +000034#include "RenderArena.h"
hyatt@apple.com4d046b72011-01-31 20:39:09 +000035#include "RenderCombineText.h"
esprehn@chromium.org7745ffb2013-02-19 21:51:19 +000036#include "RenderCounter.h"
hyatt@apple.coma10d30e2011-09-22 22:28:21 +000037#include "RenderFlowThread.h"
hyatt@apple.comc3c7e902009-01-28 21:48:33 +000038#include "RenderInline.h"
eric@webkit.orgb35848a2010-06-10 08:33:22 +000039#include "RenderLayer.h"
antti@apple.com8d8ae712013-09-18 18:04:32 +000040#include "RenderLineBreak.h"
mjsd26b2972007-02-13 13:09:04 +000041#include "RenderListMarker.h"
zoltan@webkit.orgb7a73462013-02-22 19:53:35 +000042#include "RenderRegion.h"
mitz@apple.comddb59872011-04-05 05:21:16 +000043#include "RenderRubyRun.h"
hyattd8048342006-05-31 01:48:18 +000044#include "RenderView.h"
hyatt@apple.comcc1737c2010-09-16 20:20:02 +000045#include "Settings.h"
dbates@webkit.orgf6f05a92010-05-17 04:58:25 +000046#include "TrailingFloatsRootInlineBox.h"
hyatt@apple.com4a9c625a2010-11-17 20:55:40 +000047#include "VerticalPositionCache.h"
darin36d11362006-04-11 16:30:21 +000048#include "break_lines.h"
slewis@apple.coma7615ca2008-07-12 05:51:33 +000049#include <wtf/RefCountedLeakCounter.h>
bolsinga@apple.com97e42c42008-11-15 04:47:20 +000050#include <wtf/StdLibExtras.h>
darin91298e52006-06-12 01:10:17 +000051#include <wtf/Vector.h>
paroga@webkit.org10c9e1b2011-01-29 17:04:51 +000052#include <wtf/unicode/CharacterNames.h>
hyatt8c371e52004-06-16 01:19:26 +000053
betravis@adobe.comed90c982013-06-05 23:05:57 +000054#if ENABLE(CSS_SHAPES)
betravis@adobe.comcf7cba62013-06-10 21:23:45 +000055#include "ShapeInsideInfo.h"
commit-queue@webkit.orgb3540512012-08-24 18:48:49 +000056#endif
57
zimmermann@webkit.orgb40815c2010-06-18 11:18:44 +000058#if ENABLE(SVG)
zimmermann@webkit.org6e96afd2010-09-10 15:35:50 +000059#include "RenderSVGInlineText.h"
zimmermann@webkit.orgb40815c2010-06-18 11:18:44 +000060#include "SVGRootInlineBox.h"
61#endif
62
darin7bd70952006-04-13 07:07:34 +000063using namespace std;
darinf9e5d6c2007-01-09 14:54:26 +000064using namespace WTF;
65using namespace Unicode;
darin7bd70952006-04-13 07:07:34 +000066
darinb9481ed2006-03-20 02:57:59 +000067namespace WebCore {
mjsfe301d72003-10-02 18:46:18 +000068
hyatt1d5d87b2007-04-24 04:55:54 +000069// We don't let our line box tree for a single line get any deeper than this.
70const unsigned cMaxLineDepth = 200;
eric@webkit.org060caf62011-05-03 22:11:39 +000071
zoltan@webkit.org8b422c82013-09-20 21:17:43 +000072struct RenderTextInfo {
73 // Destruction of m_layout requires TextLayout to be a complete type, so the constructor and destructor are made non-inline to avoid compilation errors.
74 RenderTextInfo();
75 ~RenderTextInfo();
76
77 RenderText* m_text;
78 OwnPtr<TextLayout> m_layout;
79 LazyLineBreakIterator m_lineBreakIterator;
80 const Font* m_font;
81};
82
83class LineBreaker {
84public:
85 LineBreaker(RenderBlock* block)
86 : m_block(block)
87 {
88 reset();
89 }
90
91 InlineIterator nextLineBreak(InlineBidiResolver&, LineInfo&, RenderTextInfo&, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements&);
92
93 bool lineWasHyphenated() { return m_hyphenated; }
94 const Vector<RenderBox*>& positionedObjects() { return m_positionedObjects; }
95 EClear clear() { return m_clear; }
96private:
97 void reset();
98
99 InlineIterator nextSegmentBreak(InlineBidiResolver&, LineInfo&, RenderTextInfo&, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements&);
100 void skipTrailingWhitespace(InlineIterator&, const LineInfo&);
101 void skipLeadingWhitespace(InlineBidiResolver&, LineInfo&, FloatingObject* lastFloatFromPreviousLine, LineWidth&);
102
103 RenderBlock* m_block;
104 bool m_hyphenated;
105 EClear m_clear;
106 Vector<RenderBox*> m_positionedObjects;
107};
108
betravis@adobe.comed90c982013-06-05 23:05:57 +0000109#if ENABLE(CSS_SHAPES)
betravis@adobe.comcf7cba62013-06-10 21:23:45 +0000110ShapeInsideInfo* RenderBlock::layoutShapeInsideInfo() const
commit-queue@webkit.org3b26f3d2012-09-25 18:22:39 +0000111{
akling@apple.com691cf5c2013-08-24 16:33:15 +0000112 ShapeInsideInfo* shapeInsideInfo = view().layoutState()->shapeInsideInfo();
betravis@adobe.com1e4305c2013-04-05 17:30:27 +0000113
betravis@adobe.comcf7cba62013-06-10 21:23:45 +0000114 if (!shapeInsideInfo && flowThreadContainingBlock() && allowsShapeInsideInfoSharing()) {
zoltan@webkit.org68678b72013-09-20 20:53:44 +0000115 LayoutUnit lineHeight = this->lineHeight(false, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
zoltan@webkit.orgbd3dabd2013-05-13 19:11:33 +0000116 // regionAtBlockOffset returns regions like an array first={0,N-1}, second={N,M-1}, ...
zoltan@webkit.org68678b72013-09-20 20:53:44 +0000117 LayoutUnit offset = logicalHeight() + lineHeight - LayoutUnit(1);
betravis@adobe.coma53af342013-03-01 21:02:16 +0000118 RenderRegion* region = regionAtBlockOffset(offset);
betravis@adobe.com1e4305c2013-04-05 17:30:27 +0000119 if (region)
betravis@adobe.comcf7cba62013-06-10 21:23:45 +0000120 shapeInsideInfo = region->shapeInsideInfo();
zoltan@webkit.orgb7a73462013-02-22 19:53:35 +0000121 }
betravis@adobe.com1e4305c2013-04-05 17:30:27 +0000122
zoltan@webkit.orgb7a73462013-02-22 19:53:35 +0000123 return shapeInsideInfo;
commit-queue@webkit.org3b26f3d2012-09-25 18:22:39 +0000124}
125#endif
126
antti@apple.com3ab7ef32013-09-29 20:50:01 +0000127static inline LayoutUnit borderPaddingMarginStart(const RenderInline& child)
hyattffe78712003-02-11 01:59:29 +0000128{
antti@apple.com3ab7ef32013-09-29 20:50:01 +0000129 return child.marginStart() + child.paddingStart() + child.borderStart();
hyattffe78712003-02-11 01:59:29 +0000130}
131
antti@apple.com3ab7ef32013-09-29 20:50:01 +0000132static inline LayoutUnit borderPaddingMarginEnd(const RenderInline& child)
rniwa@webkit.org33a346a2011-04-06 17:06:14 +0000133{
antti@apple.com3ab7ef32013-09-29 20:50:01 +0000134 return child.marginEnd() + child.paddingEnd() + child.borderEnd();
rniwa@webkit.org33a346a2011-04-06 17:06:14 +0000135}
136
robert@webkit.orgfea9b8d2013-05-24 16:18:16 +0000137static inline bool shouldAddBorderPaddingMargin(RenderObject* child)
robert@webkit.org6dc9a232012-10-08 18:44:03 +0000138{
robert@webkit.orgfea9b8d2013-05-24 16:18:16 +0000139 // When deciding whether we're at the edge of an inline, adjacent collapsed whitespace is the same as no sibling at all.
140 return !child || (child->isText() && !toRenderText(child)->textLength());
robert@webkit.org6dc9a232012-10-08 18:44:03 +0000141}
142
robert@webkit.orge10af552013-04-15 18:23:37 +0000143static RenderObject* previousInFlowSibling(RenderObject* child)
144{
145 child = child->previousSibling();
146 while (child && child->isOutOfFlowPositioned())
147 child = child->previousSibling();
148 return child;
149}
150
robert@webkit.orgfea9b8d2013-05-24 16:18:16 +0000151static LayoutUnit inlineLogicalWidth(RenderObject* child, bool checkStartEdge = true, bool checkEndEdge = true)
hyattffe78712003-02-11 01:59:29 +0000152{
hyatt1d5d87b2007-04-24 04:55:54 +0000153 unsigned lineDepth = 1;
eae@chromium.orgee8613e2011-11-12 01:12:58 +0000154 LayoutUnit extraWidth = 0;
antti@apple.com3ab7ef32013-09-29 20:50:01 +0000155 RenderElement* parent = child->parent();
robert@webkit.orgfc892822013-04-08 18:38:26 +0000156 while (parent->isRenderInline() && lineDepth++ < cMaxLineDepth) {
antti@apple.com3ab7ef32013-09-29 20:50:01 +0000157 const RenderInline& parentAsRenderInline = toRenderInline(*parent);
eae@chromium.org039c76a2013-04-02 23:17:18 +0000158 if (!isEmptyInline(parentAsRenderInline)) {
robert@webkit.orgfea9b8d2013-05-24 16:18:16 +0000159 checkStartEdge = checkStartEdge && shouldAddBorderPaddingMargin(previousInFlowSibling(child));
160 if (checkStartEdge)
eae@chromium.org039c76a2013-04-02 23:17:18 +0000161 extraWidth += borderPaddingMarginStart(parentAsRenderInline);
robert@webkit.orgfea9b8d2013-05-24 16:18:16 +0000162 checkEndEdge = checkEndEdge && shouldAddBorderPaddingMargin(child->nextSibling());
163 if (checkEndEdge)
eae@chromium.org039c76a2013-04-02 23:17:18 +0000164 extraWidth += borderPaddingMarginEnd(parentAsRenderInline);
robert@webkit.orgfea9b8d2013-05-24 16:18:16 +0000165 if (!checkStartEdge && !checkEndEdge)
eae@chromium.org039c76a2013-04-02 23:17:18 +0000166 return extraWidth;
167 }
hyattffe78712003-02-11 01:59:29 +0000168 child = parent;
169 parent = child->parent();
170 }
171 return extraWidth;
172}
173
leviw@chromium.orge7812f32012-02-07 23:46:40 +0000174static void determineDirectionality(TextDirection& dir, InlineIterator iter)
leviw@chromium.org7781b6a2011-06-27 22:01:38 +0000175{
176 while (!iter.atEnd()) {
177 if (iter.atParagraphSeparator())
178 return;
179 if (UChar current = iter.current()) {
180 Direction charDirection = direction(current);
181 if (charDirection == LeftToRight) {
182 dir = LTR;
183 return;
184 }
185 if (charDirection == RightToLeft || charDirection == RightToLeftArabic) {
186 dir = RTL;
187 return;
188 }
189 }
190 iter.increment();
191 }
192}
193
hyatt@apple.comb3466af2009-06-13 06:04:40 +0000194static void checkMidpoints(LineMidpointState& lineMidpointState, InlineIterator& lBreak)
hyattfe99c872003-07-31 22:25:29 +0000195{
196 // Check to see if our last midpoint is a start point beyond the line break. If so,
hyattdca76e92005-11-02 08:52:50 +0000197 // shave it off the list, and shave off a trailing space if the previous end point doesn't
198 // preserve whitespace.
eric@webkit.org8c25a592011-03-29 13:18:11 +0000199 if (lBreak.m_obj && lineMidpointState.numMidpoints && !(lineMidpointState.numMidpoints % 2)) {
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +0000200 InlineIterator* midpoints = lineMidpointState.midpoints.data();
201 InlineIterator& endpoint = midpoints[lineMidpointState.numMidpoints - 2];
202 const InlineIterator& startpoint = midpoints[lineMidpointState.numMidpoints - 1];
mitz@apple.com15035e62008-07-05 20:44:44 +0000203 InlineIterator currpoint = endpoint;
hyattfe99c872003-07-31 22:25:29 +0000204 while (!currpoint.atEnd() && currpoint != startpoint && currpoint != lBreak)
mitz@apple.com1a301772008-03-11 18:30:36 +0000205 currpoint.increment();
hyattfe99c872003-07-31 22:25:29 +0000206 if (currpoint == lBreak) {
207 // We hit the line break before the start point. Shave off the start point.
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +0000208 lineMidpointState.numMidpoints--;
eric@webkit.org8c25a592011-03-29 13:18:11 +0000209 if (endpoint.m_obj->style()->collapseWhiteSpace())
eric@webkit.org86a865a2011-03-29 15:30:41 +0000210 endpoint.m_pos--;
hyattfe99c872003-07-31 22:25:29 +0000211 }
eric@webkit.org060caf62011-05-03 22:11:39 +0000212 }
hyattfe99c872003-07-31 22:25:29 +0000213}
214
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +0000215// Don't call this directly. Use one of the descriptive helper functions below.
216static void deprecatedAddMidpoint(LineMidpointState& lineMidpointState, const InlineIterator& midpoint)
hyatt85586af2003-02-19 23:22:42 +0000217{
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +0000218 if (lineMidpointState.midpoints.size() <= lineMidpointState.numMidpoints)
219 lineMidpointState.midpoints.grow(lineMidpointState.numMidpoints + 10);
hyatt85586af2003-02-19 23:22:42 +0000220
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +0000221 InlineIterator* midpoints = lineMidpointState.midpoints.data();
222 midpoints[lineMidpointState.numMidpoints++] = midpoint;
hyatt85586af2003-02-19 23:22:42 +0000223}
224
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +0000225static inline void startIgnoringSpaces(LineMidpointState& lineMidpointState, const InlineIterator& midpoint)
226{
227 ASSERT(!(lineMidpointState.numMidpoints % 2));
228 deprecatedAddMidpoint(lineMidpointState, midpoint);
229}
230
231static inline void stopIgnoringSpaces(LineMidpointState& lineMidpointState, const InlineIterator& midpoint)
232{
233 ASSERT(lineMidpointState.numMidpoints % 2);
234 deprecatedAddMidpoint(lineMidpointState, midpoint);
235}
236
237// When ignoring spaces, this needs to be called for objects that need line boxes such as RenderInlines or
238// hard line breaks to ensure that they're not ignored.
239static inline void ensureLineBoxInsideIgnoredSpaces(LineMidpointState& lineMidpointState, RenderObject* renderer)
240{
241 InlineIterator midpoint(0, renderer, 0);
242 stopIgnoringSpaces(lineMidpointState, midpoint);
243 startIgnoringSpaces(lineMidpointState, midpoint);
244}
245
246// Adding a pair of midpoints before a character will split it out into a new line box.
247static inline void ensureCharacterGetsLineBox(LineMidpointState& lineMidpointState, InlineIterator& textParagraphSeparator)
248{
249 InlineIterator midpoint(0, textParagraphSeparator.m_obj, textParagraphSeparator.m_pos);
250 startIgnoringSpaces(lineMidpointState, InlineIterator(0, textParagraphSeparator.m_obj, textParagraphSeparator.m_pos - 1));
251 stopIgnoringSpaces(lineMidpointState, InlineIterator(0, textParagraphSeparator.m_obj, textParagraphSeparator.m_pos));
252}
253
eric@webkit.org5bee2942011-04-08 02:12:31 +0000254static inline BidiRun* createRun(int start, int end, RenderObject* obj, InlineBidiResolver& resolver)
255{
256 return new (obj->renderArena()) BidiRun(start, end, obj, resolver.context(), resolver.dir());
257}
258
259void RenderBlock::appendRunsForObject(BidiRunList<BidiRun>& runs, int start, int end, RenderObject* obj, InlineBidiResolver& resolver)
hyatt33f8d492002-11-12 21:44:52 +0000260{
leviw@chromium.orgd8df17d2012-05-24 21:47:47 +0000261 if (start > end || shouldSkipCreatingRunsForObject(obj))
hyatteb003b82002-11-15 22:35:10 +0000262 return;
hyatt85586af2003-02-19 23:22:42 +0000263
hyatt@apple.comb3466af2009-06-13 06:04:40 +0000264 LineMidpointState& lineMidpointState = resolver.midpointState();
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +0000265 bool haveNextMidpoint = (lineMidpointState.currentMidpoint < lineMidpointState.numMidpoints);
mitz@apple.com15035e62008-07-05 20:44:44 +0000266 InlineIterator nextMidpoint;
hyatt85586af2003-02-19 23:22:42 +0000267 if (haveNextMidpoint)
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +0000268 nextMidpoint = lineMidpointState.midpoints[lineMidpointState.currentMidpoint];
269 if (lineMidpointState.betweenMidpoints) {
eric@webkit.org8c25a592011-03-29 13:18:11 +0000270 if (!(haveNextMidpoint && nextMidpoint.m_obj == obj))
hyatt33f8d492002-11-12 21:44:52 +0000271 return;
eric@webkit.org060caf62011-05-03 22:11:39 +0000272 // This is a new start point. Stop ignoring objects and
hyatt33f8d492002-11-12 21:44:52 +0000273 // adjust our start.
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +0000274 lineMidpointState.betweenMidpoints = false;
eric@webkit.org86a865a2011-03-29 15:30:41 +0000275 start = nextMidpoint.m_pos;
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +0000276 lineMidpointState.currentMidpoint++;
hyatt33f8d492002-11-12 21:44:52 +0000277 if (start < end)
eric@webkit.org5bee2942011-04-08 02:12:31 +0000278 return appendRunsForObject(runs, start, end, obj, resolver);
mitz@apple.com15035e62008-07-05 20:44:44 +0000279 } else {
eric@webkit.org8c25a592011-03-29 13:18:11 +0000280 if (!haveNextMidpoint || (obj != nextMidpoint.m_obj)) {
eric@webkit.org5bee2942011-04-08 02:12:31 +0000281 runs.addRun(createRun(start, end, obj, resolver));
hyatt33f8d492002-11-12 21:44:52 +0000282 return;
283 }
mitz@apple.com15035e62008-07-05 20:44:44 +0000284
hyatt78b85132004-03-29 20:07:45 +0000285 // An end midpoint has been encountered within our object. We
hyatt33f8d492002-11-12 21:44:52 +0000286 // need to go ahead and append a run with our endpoint.
eric@webkit.org86a865a2011-03-29 15:30:41 +0000287 if (static_cast<int>(nextMidpoint.m_pos + 1) <= end) {
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +0000288 lineMidpointState.betweenMidpoints = true;
289 lineMidpointState.currentMidpoint++;
eric@webkit.org86a865a2011-03-29 15:30:41 +0000290 if (nextMidpoint.m_pos != UINT_MAX) { // UINT_MAX means stop at the object and don't include any of it.
291 if (static_cast<int>(nextMidpoint.m_pos + 1) > start)
eric@webkit.org5bee2942011-04-08 02:12:31 +0000292 runs.addRun(createRun(start, nextMidpoint.m_pos + 1, obj, resolver));
293 return appendRunsForObject(runs, nextMidpoint.m_pos + 1, end, obj, resolver);
hyattc64f9fc2003-03-14 01:25:59 +0000294 }
mitz@apple.com15035e62008-07-05 20:44:44 +0000295 } else
eric@webkit.org5bee2942011-04-08 02:12:31 +0000296 runs.addRun(createRun(start, end, obj, resolver));
hyatt33f8d492002-11-12 21:44:52 +0000297 }
298}
299
hyatt@apple.comc92b7352009-02-12 01:35:08 +0000300static inline InlineBox* createInlineBoxForRenderer(RenderObject* obj, bool isRootLineBox, bool isOnlyRun = false)
301{
302 if (isRootLineBox)
eric@webkit.org49b9d952009-07-03 01:29:07 +0000303 return toRenderBlock(obj)->createAndAppendRootInlineBox();
eric@webkit.org060caf62011-05-03 22:11:39 +0000304
antti@apple.com9d8157e2013-09-17 15:13:37 +0000305 if (obj->isText())
306 return toRenderText(obj)->createInlineTextBox();
eric@webkit.org060caf62011-05-03 22:11:39 +0000307
hyatt@apple.comc92b7352009-02-12 01:35:08 +0000308 if (obj->isBox())
309 return toRenderBox(obj)->createInlineBox();
eric@webkit.org060caf62011-05-03 22:11:39 +0000310
antti@apple.com3014ac02013-09-18 14:33:55 +0000311 if (obj->isLineBreak()) {
antti@apple.com8d8ae712013-09-18 18:04:32 +0000312 InlineBox* inlineBox = toRenderLineBreak(obj)->createInlineBox();
antti@apple.com9d8157e2013-09-17 15:13:37 +0000313 // We only treat a box as text for a <br> if we are on a line by ourself or in strict mode
314 // (Note the use of strict mode. In "almost strict" mode, we don't treat the box for <br> as text.)
antti@apple.com3014ac02013-09-18 14:33:55 +0000315 inlineBox->setBehavesLikeText(isOnlyRun || obj->document().inNoQuirksMode() || obj->isLineBreakOpportunity());
antti@apple.com9d8157e2013-09-17 15:13:37 +0000316 return inlineBox;
317 }
318
eric@webkit.org49b9d952009-07-03 01:29:07 +0000319 return toRenderInline(obj)->createAndAppendInlineFlowBox();
hyatt@apple.comc92b7352009-02-12 01:35:08 +0000320}
321
esprehn@chromium.org7745ffb2013-02-19 21:51:19 +0000322// FIXME: Don't let counters mark themselves as needing pref width recalcs during layout
323// so we don't need this hack.
324static inline void updateCounterIfNeeded(RenderText* o)
325{
326 if (!o->preferredLogicalWidthsDirty() || !o->isCounter())
327 return;
328 toRenderCounter(o)->updateCounter();
329}
330
hyatt@apple.comc92b7352009-02-12 01:35:08 +0000331static inline void dirtyLineBoxesForRenderer(RenderObject* o, bool fullLayout)
332{
333 if (o->isText()) {
commit-queue@webkit.orgd639fb72012-09-01 19:46:16 +0000334 RenderText* renderText = toRenderText(o);
esprehn@chromium.org7745ffb2013-02-19 21:51:19 +0000335 updateCounterIfNeeded(renderText);
commit-queue@webkit.orgd639fb72012-09-01 19:46:16 +0000336 renderText->dirtyLineBoxes(fullLayout);
antti@apple.com3014ac02013-09-18 14:33:55 +0000337 } else if (o->isLineBreak())
antti@apple.com8d8ae712013-09-18 18:04:32 +0000338 toRenderLineBreak(o)->dirtyLineBoxes(fullLayout);
antti@apple.com9d8157e2013-09-17 15:13:37 +0000339 else
hyatt@apple.comc92b7352009-02-12 01:35:08 +0000340 toRenderInline(o)->dirtyLineBoxes(fullLayout);
341}
342
xji@chromium.orgb0ad6eb822011-02-01 20:02:06 +0000343static bool parentIsConstructedOrHaveNext(InlineFlowBox* parentBox)
344{
345 do {
346 if (parentBox->isConstructed() || parentBox->nextOnLine())
347 return true;
348 parentBox = parentBox->parent();
349 } while (parentBox);
350 return false;
351}
352
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +0000353InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj, const LineInfo& lineInfo, InlineBox* childBox, bool startNewSegment)
hyattffe78712003-02-11 01:59:29 +0000354{
355 // See if we have an unconstructed line box for this object that is also
356 // the last item on the line.
hyatt1d5d87b2007-04-24 04:55:54 +0000357 unsigned lineDepth = 1;
hyatt1d5d87b2007-04-24 04:55:54 +0000358 InlineFlowBox* parentBox = 0;
359 InlineFlowBox* result = 0;
hyatt@apple.com7d4066a2011-03-29 17:56:09 +0000360 bool hasDefaultLineBoxContain = style()->lineBoxContain() == RenderStyle::initialLineBoxContain();
hyatt1d5d87b2007-04-24 04:55:54 +0000361 do {
inferno@chromium.org14b04142013-02-04 18:43:03 +0000362 ASSERT_WITH_SECURITY_IMPLICATION(obj->isRenderInline() || obj == this);
eric@webkit.org060caf62011-05-03 22:11:39 +0000363
hyatt@apple.coma61b8a32011-04-06 18:20:52 +0000364 RenderInline* inlineFlow = (obj != this) ? toRenderInline(obj) : 0;
365
hyatt1d5d87b2007-04-24 04:55:54 +0000366 // Get the last box we made for this render object.
hyatt@apple.coma61b8a32011-04-06 18:20:52 +0000367 parentBox = inlineFlow ? inlineFlow->lastLineBox() : toRenderBlock(obj)->lastLineBox();
hyattffe78712003-02-11 01:59:29 +0000368
xji@chromium.orgb0ad6eb822011-02-01 20:02:06 +0000369 // If this box or its ancestor is constructed then it is from a previous line, and we need
370 // 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 +0000371 // something following it on the line, then we know we have to make a new box
372 // as well. In this situation our inline has actually been split in two on
373 // the same line (this can happen with very fancy language mixtures).
374 bool constructedNewBox = false;
hyatt@apple.coma61b8a32011-04-06 18:20:52 +0000375 bool allowedToConstructNewBox = !hasDefaultLineBoxContain || !inlineFlow || inlineFlow->alwaysCreateLineBoxes();
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +0000376 bool mustCreateBoxesToRoot = startNewSegment && !(parentBox && parentBox->isRootInlineBox());
377 bool canUseExistingParentBox = parentBox && !parentIsConstructedOrHaveNext(parentBox) && !mustCreateBoxesToRoot;
hyatt@apple.coma61b8a32011-04-06 18:20:52 +0000378 if (allowedToConstructNewBox && !canUseExistingParentBox) {
hyatt1d5d87b2007-04-24 04:55:54 +0000379 // We need to make a new box for this render object. Once
380 // made, we need to place it at the end of the current line.
hyatt@apple.comc92b7352009-02-12 01:35:08 +0000381 InlineBox* newBox = createInlineBoxForRenderer(obj, obj == this);
inferno@chromium.org14b04142013-02-04 18:43:03 +0000382 ASSERT_WITH_SECURITY_IMPLICATION(newBox->isInlineFlowBox());
jchaffraix@webkit.org8f1781d2011-06-24 21:22:54 +0000383 parentBox = toInlineFlowBox(newBox);
antti@apple.comb0608f62013-09-28 18:30:16 +0000384 parentBox->setIsFirstLine(lineInfo.isFirstLine());
hyatt@apple.com2a5eb212011-03-22 23:21:54 +0000385 parentBox->setIsHorizontal(isHorizontalWritingMode());
hyatt@apple.com7d4066a2011-03-29 17:56:09 +0000386 if (!hasDefaultLineBoxContain)
387 parentBox->clearDescendantsHaveSameLineHeightAndBaseline();
hyatt1d5d87b2007-04-24 04:55:54 +0000388 constructedNewBox = true;
389 }
mitz@apple.come1364202008-02-28 01:06:41 +0000390
hyatt@apple.coma61b8a32011-04-06 18:20:52 +0000391 if (constructedNewBox || canUseExistingParentBox) {
392 if (!result)
393 result = parentBox;
hyatt1d5d87b2007-04-24 04:55:54 +0000394
hyatt@apple.coma61b8a32011-04-06 18:20:52 +0000395 // If we have hit the block itself, then |box| represents the root
396 // inline box for the line, and it doesn't have to be appended to any parent
397 // inline.
398 if (childBox)
399 parentBox->addToLine(childBox);
mitz@apple.come1364202008-02-28 01:06:41 +0000400
hyatt@apple.coma61b8a32011-04-06 18:20:52 +0000401 if (!constructedNewBox || obj == this)
402 break;
mitz@apple.come1364202008-02-28 01:06:41 +0000403
eric@webkit.org060caf62011-05-03 22:11:39 +0000404 childBox = parentBox;
hyatt@apple.coma61b8a32011-04-06 18:20:52 +0000405 }
mitz@apple.come1364202008-02-28 01:06:41 +0000406
hyatt1d5d87b2007-04-24 04:55:54 +0000407 // If we've exceeded our line depth, then jump straight to the root and skip all the remaining
408 // intermediate inline flows.
409 obj = (++lineDepth >= cMaxLineDepth) ? this : obj->parent();
hyattffe78712003-02-11 01:59:29 +0000410
hyatt1d5d87b2007-04-24 04:55:54 +0000411 } while (true);
412
413 return result;
hyattffe78712003-02-11 01:59:29 +0000414}
415
msaboff@apple.com776c286c72012-10-15 16:56:29 +0000416template <typename CharacterType>
417static inline bool endsWithASCIISpaces(const CharacterType* characters, unsigned pos, unsigned end)
418{
419 while (isASCIISpace(characters[pos])) {
420 pos++;
421 if (pos >= end)
422 return true;
423 }
424 return false;
425}
426
yael.aharon@nokia.com15c605d2011-04-14 05:35:54 +0000427static bool reachedEndOfTextRenderer(const BidiRunList<BidiRun>& bidiRuns)
hyattffe78712003-02-11 01:59:29 +0000428{
yael.aharon@nokia.com15c605d2011-04-14 05:35:54 +0000429 BidiRun* run = bidiRuns.logicallyLastRun();
430 if (!run)
431 return true;
msaboff@apple.com776c286c72012-10-15 16:56:29 +0000432 unsigned pos = run->stop();
yael.aharon@nokia.com15c605d2011-04-14 05:35:54 +0000433 RenderObject* r = run->m_object;
antti@apple.com9d8157e2013-09-17 15:13:37 +0000434 if (!r->isText())
yael.aharon@nokia.com15c605d2011-04-14 05:35:54 +0000435 return false;
436 RenderText* renderText = toRenderText(r);
msaboff@apple.com776c286c72012-10-15 16:56:29 +0000437 unsigned length = renderText->textLength();
438 if (pos >= length)
yael.aharon@nokia.com15c605d2011-04-14 05:35:54 +0000439 return true;
440
msaboff@apple.com776c286c72012-10-15 16:56:29 +0000441 if (renderText->is8Bit())
442 return endsWithASCIISpaces(renderText->characters8(), pos, length);
443 return endsWithASCIISpaces(renderText->characters16(), pos, length);
yael.aharon@nokia.com15c605d2011-04-14 05:35:54 +0000444}
445
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +0000446RootInlineBox* RenderBlock::constructLine(BidiRunList<BidiRun>& bidiRuns, const LineInfo& lineInfo)
yael.aharon@nokia.com15c605d2011-04-14 05:35:54 +0000447{
448 ASSERT(bidiRuns.firstRun());
hyattffe78712003-02-11 01:59:29 +0000449
inferno@chromium.orge29694f2010-10-07 22:00:02 +0000450 bool rootHasSelectedChildren = false;
hyattffe78712003-02-11 01:59:29 +0000451 InlineFlowBox* parentBox = 0;
robert@webkit.org8cbab142011-12-30 20:58:29 +0000452 int runCount = bidiRuns.runCount() - lineInfo.runsFromLeadingWhitespace();
yael.aharon@nokia.com15c605d2011-04-14 05:35:54 +0000453 for (BidiRun* r = bidiRuns.firstRun(); r; r = r->next()) {
hyattffe78712003-02-11 01:59:29 +0000454 // Create a box for our object.
robert@webkit.org8cbab142011-12-30 20:58:29 +0000455 bool isOnlyRun = (runCount == 1);
456 if (runCount == 2 && !r->m_object->isListMarker())
yael.aharon@nokia.com15c605d2011-04-14 05:35:54 +0000457 isOnlyRun = (!style()->isLeftToRightDirection() ? bidiRuns.lastRun() : bidiRuns.firstRun())->m_object->isListMarker();
mitz@apple.come1364202008-02-28 01:06:41 +0000458
robert@webkit.org56e5a9f2012-02-17 21:10:42 +0000459 if (lineInfo.isEmpty())
460 continue;
461
hyatt@apple.comc92b7352009-02-12 01:35:08 +0000462 InlineBox* box = createInlineBoxForRenderer(r->m_object, false, isOnlyRun);
mitz@apple.com576e84e2008-04-24 19:09:48 +0000463 r->m_box = box;
464
mitz@apple.comaa6ce3d2009-04-10 01:00:20 +0000465 ASSERT(box);
466 if (!box)
467 continue;
hyattffe78712003-02-11 01:59:29 +0000468
akling@apple.com0b8172b72013-08-31 18:34:23 +0000469 if (!rootHasSelectedChildren && box->renderer().selectionState() != RenderObject::SelectionNone)
inferno@chromium.orge29694f2010-10-07 22:00:02 +0000470 rootHasSelectedChildren = true;
471
mitz@apple.comaa6ce3d2009-04-10 01:00:20 +0000472 // If we have no parent box yet, or if the run is not simply a sibling,
473 // then we need to construct inline boxes as necessary to properly enclose the
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +0000474 // run's inline box. Segments can only be siblings at the root level, as
475 // they are positioned separately.
betravis@adobe.comed90c982013-06-05 23:05:57 +0000476#if ENABLE(CSS_SHAPES)
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +0000477 bool runStartsSegment = r->m_startsSegment;
478#else
479 bool runStartsSegment = false;
480#endif
akling@apple.com0b8172b72013-08-31 18:34:23 +0000481 if (!parentBox || &parentBox->renderer() != r->m_object->parent() || runStartsSegment)
mitz@apple.comaa6ce3d2009-04-10 01:00:20 +0000482 // Create new inline boxes all the way back to the appropriate insertion point.
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +0000483 parentBox = createLineBoxes(r->m_object->parent(), lineInfo, box, runStartsSegment);
hyatt@apple.com7d4066a2011-03-29 17:56:09 +0000484 else {
485 // Append the inline box to this line.
486 parentBox->addToLine(box);
487 }
mitz@apple.com576e84e2008-04-24 19:09:48 +0000488
macpherson@chromium.org258babf2011-06-10 06:20:58 +0000489 bool visuallyOrdered = r->m_object->style()->rtlOrdering() == VisualOrder;
xji@chromium.org6b0c0172011-02-14 19:21:12 +0000490 box->setBidiLevel(r->level());
mitz@apple.comaa6ce3d2009-04-10 01:00:20 +0000491
492 if (box->isInlineTextBox()) {
jchaffraix@webkit.org8f1781d2011-06-24 21:22:54 +0000493 InlineTextBox* text = toInlineTextBox(box);
mitz@apple.comaa6ce3d2009-04-10 01:00:20 +0000494 text->setStart(r->m_start);
495 text->setLen(r->m_stop - r->m_start);
rniwa@webkit.org296fcae2012-03-29 09:48:42 +0000496 text->setDirOverride(r->dirOverride(visuallyOrdered));
mitz@apple.comb2107652010-06-21 16:54:52 +0000497 if (r->m_hasHyphen)
498 text->setHasHyphen(true);
hyatt0c3a9862004-02-23 21:26:26 +0000499 }
hyattffe78712003-02-11 01:59:29 +0000500 }
501
502 // We should have a root inline box. It should be unconstructed and
503 // be the last continuation of our line list.
ggarenf9f32ae2007-03-26 20:08:53 +0000504 ASSERT(lastLineBox() && !lastLineBox()->isConstructed());
hyattffe78712003-02-11 01:59:29 +0000505
inferno@chromium.orge29694f2010-10-07 22:00:02 +0000506 // Set the m_selectedChildren flag on the root inline box if one of the leaf inline box
507 // from the bidi runs walk above has a selection state.
508 if (rootHasSelectedChildren)
akling@apple.comdbf70302013-09-09 02:11:06 +0000509 lastLineBox()->root().setHasSelectedChildren(true);
inferno@chromium.orge29694f2010-10-07 22:00:02 +0000510
hyattffe78712003-02-11 01:59:29 +0000511 // Set bits on our inline flow boxes that indicate which sides should
512 // paint borders/margins/padding. This knowledge will ultimately be used when
513 // we determine the horizontal positions and widths of all the inline boxes on
514 // the line.
yael.aharon@nokia.com15c605d2011-04-14 05:35:54 +0000515 bool isLogicallyLastRunWrapped = bidiRuns.logicallyLastRun()->m_object && bidiRuns.logicallyLastRun()->m_object->isText() ? !reachedEndOfTextRenderer(bidiRuns) : true;
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +0000516 lastLineBox()->determineSpacingForFlowBoxes(lineInfo.isLastLine(), isLogicallyLastRunWrapped, bidiRuns.logicallyLastRun()->m_object);
hyattffe78712003-02-11 01:59:29 +0000517
518 // Now mark the line boxes as being constructed.
519 lastLineBox()->setConstructed();
520
521 // Return the last line.
hyatt0c3a9862004-02-23 21:26:26 +0000522 return lastRootBox();
hyattffe78712003-02-11 01:59:29 +0000523}
524
mitz@apple.com390fa322011-02-24 23:07:06 +0000525ETextAlign RenderBlock::textAlignmentForLine(bool endsWithSoftBreak) const
526{
527 ETextAlign alignment = style()->textAlign();
528 if (!endsWithSoftBreak && alignment == JUSTIFY)
rniwa@webkit.orgaf7f7a42012-06-15 21:54:44 +0000529 alignment = TASTART;
mitz@apple.com390fa322011-02-24 23:07:06 +0000530
531 return alignment;
532}
533
rniwa@webkit.orgcda6dbd2011-03-28 09:19:50 +0000534static void updateLogicalWidthForLeftAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth)
535{
536 // The direction of the block should determine what happens with wide lines.
537 // In particular with RTL blocks, wide lines should still spill out to the left.
538 if (isLeftToRightDirection) {
539 if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun)
540 trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth));
541 return;
542 }
543
544 if (trailingSpaceRun)
545 trailingSpaceRun->m_box->setLogicalWidth(0);
546 else if (totalLogicalWidth > availableLogicalWidth)
547 logicalLeft -= (totalLogicalWidth - availableLogicalWidth);
548}
549
550static void updateLogicalWidthForRightAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth)
551{
552 // Wide lines spill out of the block based off direction.
553 // So even if text-align is right, if direction is LTR, wide lines should overflow out of the right
554 // side of the block.
555 if (isLeftToRightDirection) {
556 if (trailingSpaceRun) {
557 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
558 trailingSpaceRun->m_box->setLogicalWidth(0);
559 }
560 if (totalLogicalWidth < availableLogicalWidth)
561 logicalLeft += availableLogicalWidth - totalLogicalWidth;
562 return;
563 }
564
565 if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun) {
566 trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth));
567 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
568 } else
569 logicalLeft += availableLogicalWidth - totalLogicalWidth;
570}
571
572static void updateLogicalWidthForCenterAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth)
573{
574 float trailingSpaceWidth = 0;
575 if (trailingSpaceRun) {
576 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
577 trailingSpaceWidth = min(trailingSpaceRun->m_box->logicalWidth(), (availableLogicalWidth - totalLogicalWidth + 1) / 2);
578 trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceWidth));
579 }
580 if (isLeftToRightDirection)
581 logicalLeft += max<float>((availableLogicalWidth - totalLogicalWidth) / 2, 0);
582 else
583 logicalLeft += totalLogicalWidth > availableLogicalWidth ? (availableLogicalWidth - totalLogicalWidth) : (availableLogicalWidth - totalLogicalWidth) / 2 - trailingSpaceWidth;
584}
585
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000586void RenderBlock::setMarginsForRubyRun(BidiRun* run, RenderRubyRun* renderer, RenderObject* previousObject, const LineInfo& lineInfo)
587{
588 int startOverhang;
589 int endOverhang;
590 RenderObject* nextObject = 0;
591 for (BidiRun* runWithNextObject = run->next(); runWithNextObject; runWithNextObject = runWithNextObject->next()) {
simon.fraser@apple.com2f071852012-06-25 00:11:30 +0000592 if (!runWithNextObject->m_object->isOutOfFlowPositioned() && !runWithNextObject->m_box->isLineBreak()) {
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000593 nextObject = runWithNextObject->m_object;
594 break;
595 }
596 }
597 renderer->getOverhang(lineInfo.isFirstLine(), renderer->style()->isLeftToRightDirection() ? previousObject : nextObject, renderer->style()->isLeftToRightDirection() ? nextObject : previousObject, startOverhang, endOverhang);
598 setMarginStartForChild(renderer, -startOverhang);
599 setMarginEndForChild(renderer, -endOverhang);
600}
601
rniwa@webkit.orgfe811f22013-06-07 17:59:01 +0000602static inline float measureHyphenWidth(RenderText* renderer, const Font& font, HashSet<const SimpleFontData*>* fallbackFonts = 0)
commit-queue@webkit.orge60bb902011-09-08 19:18:43 +0000603{
antti@apple.com78e56772013-09-29 04:34:37 +0000604 const RenderStyle& style = *renderer->style();
605 return font.width(RenderBlock::constructTextRun(renderer, font, style.hyphenString().string(), style), fallbackFonts);
commit-queue@webkit.orge60bb902011-09-08 19:18:43 +0000606}
607
enrica@apple.com885c84d2012-10-10 05:48:51 +0000608class WordMeasurement {
609public:
610 WordMeasurement()
611 : renderer(0)
612 , width(0)
613 , startOffset(0)
614 , endOffset(0)
615 {
616 }
617
618 RenderText* renderer;
619 float width;
620 int startOffset;
621 int endOffset;
622 HashSet<const SimpleFontData*> fallbackFonts;
623};
624
antti@apple.com3ab7ef32013-09-29 20:50:01 +0000625static inline const RenderStyle& lineStyle(const RenderElement& renderer, const LineInfo& lineInfo)
antti@apple.comb0608f62013-09-28 18:30:16 +0000626{
627 return lineInfo.isFirstLine() ? *renderer.firstLineStyle() : *renderer.style();
628}
629
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000630static inline void setLogicalWidthForTextRun(RootInlineBox* lineBox, BidiRun* run, RenderText* renderer, float xPos, const LineInfo& lineInfo,
rniwa@webkit.orgfe811f22013-06-07 17:59:01 +0000631 GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache, WordMeasurements& wordMeasurements)
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000632{
633 HashSet<const SimpleFontData*> fallbackFonts;
634 GlyphOverflow glyphOverflow;
antti@apple.comb0608f62013-09-28 18:30:16 +0000635
636 const Font& font = lineStyle(*renderer->parent(), lineInfo).font();
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000637 // Always compute glyph overflow if the block's line-box-contain value is "glyphs".
638 if (lineBox->fitsToGlyphs()) {
639 // If we don't stick out of the root line's font box, then don't bother computing our glyph overflow. This optimization
640 // will keep us from computing glyph bounds in nearly all cases.
641 bool includeRootLine = lineBox->includesRootLineBoxFontOrLeading();
642 int baselineShift = lineBox->verticalPositionForBox(run->m_box, verticalPositionCache);
enrica@apple.com885c84d2012-10-10 05:48:51 +0000643 int rootDescent = includeRootLine ? font.fontMetrics().descent() : 0;
644 int rootAscent = includeRootLine ? font.fontMetrics().ascent() : 0;
645 int boxAscent = font.fontMetrics().ascent() - baselineShift;
646 int boxDescent = font.fontMetrics().descent() + baselineShift;
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000647 if (boxAscent > rootDescent || boxDescent > rootAscent)
648 glyphOverflow.computeBounds = true;
649 }
650
leviw@chromium.orgd32486e2012-03-16 10:52:56 +0000651 LayoutUnit hyphenWidth = 0;
antti@apple.comb0608f62013-09-28 18:30:16 +0000652 if (toInlineTextBox(run->m_box)->hasHyphen())
rniwa@webkit.orgfe811f22013-06-07 17:59:01 +0000653 hyphenWidth = measureHyphenWidth(renderer, font, &fallbackFonts);
antti@apple.comb0608f62013-09-28 18:30:16 +0000654
enrica@apple.com885c84d2012-10-10 05:48:51 +0000655 float measuredWidth = 0;
656
enrica@apple.com885c84d2012-10-10 05:48:51 +0000657 bool kerningIsEnabled = font.typesettingFeatures() & Kerning;
leviw@chromium.orgd70f4cc2013-03-28 21:03:44 +0000658 bool canUseSimpleFontCodePath = renderer->canUseSimpleFontCodePath();
enrica@apple.com885c84d2012-10-10 05:48:51 +0000659
660 // Since we don't cache glyph overflows, we need to re-measure the run if
661 // the style is linebox-contain: glyph.
662
leviw@chromium.orgd70f4cc2013-03-28 21:03:44 +0000663 if (!lineBox->fitsToGlyphs() && canUseSimpleFontCodePath) {
enrica@apple.com885c84d2012-10-10 05:48:51 +0000664 int lastEndOffset = run->m_start;
665 for (size_t i = 0, size = wordMeasurements.size(); i < size && lastEndOffset < run->m_stop; ++i) {
rniwa@webkit.orgfe811f22013-06-07 17:59:01 +0000666 WordMeasurement& wordMeasurement = wordMeasurements[i];
667 if (wordMeasurement.width <= 0 || wordMeasurement.startOffset == wordMeasurement.endOffset)
enrica@apple.com885c84d2012-10-10 05:48:51 +0000668 continue;
669 if (wordMeasurement.renderer != renderer || wordMeasurement.startOffset != lastEndOffset || wordMeasurement.endOffset > run->m_stop)
670 continue;
671
672 lastEndOffset = wordMeasurement.endOffset;
673 if (kerningIsEnabled && lastEndOffset == run->m_stop) {
dino@apple.com7c50e7c2013-03-18 18:01:05 +0000674 int wordLength = lastEndOffset - wordMeasurement.startOffset;
rniwa@webkit.orgfe811f22013-06-07 17:59:01 +0000675 GlyphOverflow overflow;
676 measuredWidth += renderer->width(wordMeasurement.startOffset, wordLength, xPos + measuredWidth, lineInfo.isFirstLine(),
677 &wordMeasurement.fallbackFonts, &overflow);
dino@apple.comd0b89252013-05-10 18:20:28 +0000678 UChar c = renderer->characterAt(wordMeasurement.startOffset);
679 if (i > 0 && wordLength == 1 && (c == ' ' || c == '\t'))
enrica@apple.com885c84d2012-10-10 05:48:51 +0000680 measuredWidth += renderer->style()->wordSpacing();
681 } else
682 measuredWidth += wordMeasurement.width;
683 if (!wordMeasurement.fallbackFonts.isEmpty()) {
684 HashSet<const SimpleFontData*>::const_iterator end = wordMeasurement.fallbackFonts.end();
685 for (HashSet<const SimpleFontData*>::const_iterator it = wordMeasurement.fallbackFonts.begin(); it != end; ++it)
686 fallbackFonts.add(*it);
687 }
688 }
689 if (measuredWidth && lastEndOffset != run->m_stop) {
690 // If we don't have enough cached data, we'll measure the run again.
691 measuredWidth = 0;
692 fallbackFonts.clear();
693 }
694 }
enrica@apple.com885c84d2012-10-10 05:48:51 +0000695
696 if (!measuredWidth)
697 measuredWidth = renderer->width(run->m_start, run->m_stop - run->m_start, xPos, lineInfo.isFirstLine(), &fallbackFonts, &glyphOverflow);
698
699 run->m_box->setLogicalWidth(measuredWidth + hyphenWidth);
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000700 if (!fallbackFonts.isEmpty()) {
antti@apple.com843ff0c2013-09-18 06:30:30 +0000701 ASSERT(run->m_box->behavesLikeText());
caio.oliveira@openbossa.org4c11ee02012-03-29 18:48:23 +0000702 GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.add(toInlineTextBox(run->m_box), make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).iterator;
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000703 ASSERT(it->value.first.isEmpty());
704 copyToVector(fallbackFonts, it->value.first);
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000705 run->m_box->parent()->clearDescendantsHaveSameLineHeightAndBaseline();
706 }
707 if ((glyphOverflow.top || glyphOverflow.bottom || glyphOverflow.left || glyphOverflow.right)) {
antti@apple.com843ff0c2013-09-18 06:30:30 +0000708 ASSERT(run->m_box->behavesLikeText());
caio.oliveira@openbossa.org4c11ee02012-03-29 18:48:23 +0000709 GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.add(toInlineTextBox(run->m_box), make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).iterator;
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000710 it->value.second = glyphOverflow;
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000711 run->m_box->clearKnownToHaveNoOverflow();
712 }
713}
714
715static inline void computeExpansionForJustifiedText(BidiRun* firstRun, BidiRun* trailingSpaceRun, Vector<unsigned, 16>& expansionOpportunities, unsigned expansionOpportunityCount, float& totalLogicalWidth, float availableLogicalWidth)
716{
mitz@apple.comc7a1a512011-05-08 16:27:31 +0000717 if (!expansionOpportunityCount || availableLogicalWidth <= totalLogicalWidth)
718 return;
719
720 size_t i = 0;
721 for (BidiRun* r = firstRun; r; r = r->next()) {
betravis@adobe.comed90c982013-06-05 23:05:57 +0000722#if ENABLE(CSS_SHAPES)
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +0000723 // This method is called once per segment, do not move past the current segment.
724 if (r->m_startsSegment)
725 break;
726#endif
mitz@apple.comc7a1a512011-05-08 16:27:31 +0000727 if (!r->m_box || r == trailingSpaceRun)
728 continue;
729
730 if (r->m_object->isText()) {
731 unsigned opportunitiesInRun = expansionOpportunities[i++];
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000732
mitz@apple.comc7a1a512011-05-08 16:27:31 +0000733 ASSERT(opportunitiesInRun <= expansionOpportunityCount);
734
735 // Only justify text if whitespace is collapsed.
736 if (r->m_object->style()->collapseWhiteSpace()) {
jchaffraix@webkit.org8f1781d2011-06-24 21:22:54 +0000737 InlineTextBox* textBox = toInlineTextBox(r->m_box);
mitz@apple.comc7a1a512011-05-08 16:27:31 +0000738 int expansion = (availableLogicalWidth - totalLogicalWidth) * opportunitiesInRun / expansionOpportunityCount;
739 textBox->setExpansion(expansion);
740 totalLogicalWidth += expansion;
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000741 }
mitz@apple.comc7a1a512011-05-08 16:27:31 +0000742 expansionOpportunityCount -= opportunitiesInRun;
743 if (!expansionOpportunityCount)
744 break;
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000745 }
746 }
747}
748
robert@webkit.orgfc7763c2011-09-03 18:28:57 +0000749void RenderBlock::updateLogicalWidthForAlignment(const ETextAlign& textAlign, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float& availableLogicalWidth, int expansionOpportunityCount)
750{
751 // Armed with the total width of the line (without justification),
752 // we now examine our text-align property in order to determine where to position the
753 // objects horizontally. The total width of the line can be increased if we end up
754 // justifying text.
755 switch (textAlign) {
756 case LEFT:
757 case WEBKIT_LEFT:
758 updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
759 break;
rniwa@webkit.orgaf7f7a42012-06-15 21:54:44 +0000760 case RIGHT:
761 case WEBKIT_RIGHT:
762 updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
763 break;
764 case CENTER:
765 case WEBKIT_CENTER:
766 updateLogicalWidthForCenterAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
767 break;
robert@webkit.orgfc7763c2011-09-03 18:28:57 +0000768 case JUSTIFY:
769 adjustInlineDirectionLineBounds(expansionOpportunityCount, logicalLeft, availableLogicalWidth);
770 if (expansionOpportunityCount) {
771 if (trailingSpaceRun) {
772 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
773 trailingSpaceRun->m_box->setLogicalWidth(0);
774 }
775 break;
776 }
rniwa@webkit.orgaf7f7a42012-06-15 21:54:44 +0000777 // Fall through
robert@webkit.orgfc7763c2011-09-03 18:28:57 +0000778 case TASTART:
779 if (style()->isLeftToRightDirection())
780 updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
781 else
782 updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
783 break;
784 case TAEND:
785 if (style()->isLeftToRightDirection())
786 updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
787 else
788 updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
789 break;
790 }
791}
792
antti@apple.com78e56772013-09-29 04:34:37 +0000793static IndentTextOrNot requiresIndent(bool isFirstLine, bool isAfterHardLineBreak, const RenderStyle& style)
commit-queue@webkit.orgab781b02013-04-03 01:32:24 +0000794{
commit-queue@webkit.org1eb07872013-04-18 04:25:46 +0000795 IndentTextOrNot shouldIndentText = DoNotIndentText;
commit-queue@webkit.orgab781b02013-04-03 01:32:24 +0000796 if (isFirstLine)
commit-queue@webkit.org1eb07872013-04-18 04:25:46 +0000797 shouldIndentText = IndentText;
commit-queue@webkit.orgab781b02013-04-03 01:32:24 +0000798#if ENABLE(CSS3_TEXT)
zandobersek@gmail.com81787312013-09-29 05:42:35 +0000799 else if (isAfterHardLineBreak && style.textIndentLine() == TextIndentEachLine)
commit-queue@webkit.org1eb07872013-04-18 04:25:46 +0000800 shouldIndentText = IndentText;
801
zandobersek@gmail.com81787312013-09-29 05:42:35 +0000802 if (style.textIndentType() == TextIndentHanging)
commit-queue@webkit.org1eb07872013-04-18 04:25:46 +0000803 shouldIndentText = shouldIndentText == IndentText ? DoNotIndentText : IndentText;
commit-queue@webkit.orgab781b02013-04-03 01:32:24 +0000804#else
805 UNUSED_PARAM(isAfterHardLineBreak);
806 UNUSED_PARAM(style);
807#endif
commit-queue@webkit.org1eb07872013-04-18 04:25:46 +0000808 return shouldIndentText;
commit-queue@webkit.orgab781b02013-04-03 01:32:24 +0000809}
810
811static void updateLogicalInlinePositions(RenderBlock* block, float& lineLogicalLeft, float& lineLogicalRight, float& availableLogicalWidth, bool firstLine, IndentTextOrNot shouldIndentText, LayoutUnit boxLogicalHeight)
robert@webkit.org0903cf52012-12-11 18:14:16 +0000812{
zoltan@webkit.org68678b72013-09-20 20:53:44 +0000813 LayoutUnit lineLogicalHeight = block->minLineHeightForReplacedRenderer(firstLine, boxLogicalHeight);
commit-queue@webkit.orgab781b02013-04-03 01:32:24 +0000814 lineLogicalLeft = block->pixelSnappedLogicalLeftOffsetForLine(block->logicalHeight(), shouldIndentText == IndentText, lineLogicalHeight);
815 lineLogicalRight = block->pixelSnappedLogicalRightOffsetForLine(block->logicalHeight(), shouldIndentText == IndentText, lineLogicalHeight);
robert@webkit.org0903cf52012-12-11 18:14:16 +0000816 availableLogicalWidth = lineLogicalRight - lineLogicalLeft;
817}
818
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +0000819void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, const LineInfo& lineInfo, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd,
enrica@apple.com885c84d2012-10-10 05:48:51 +0000820 GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache, WordMeasurements& wordMeasurements)
hyattffe78712003-02-11 01:59:29 +0000821{
mitz@apple.com390fa322011-02-24 23:07:06 +0000822 ETextAlign textAlign = textAlignmentForLine(!reachedEnd && !lineBox->endsWithBreak());
robert@webkit.org4f76df92012-07-03 17:41:35 +0000823
robert@webkit.org328ecd02012-08-09 21:12:44 +0000824 // 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
825 // box is only affected if it is the first child of its parent element."
commit-queue@webkit.orgab781b02013-04-03 01:32:24 +0000826 // CSS3 "text-indent", "-webkit-each-line" affects the first line of the block container as well as each line after a forced line break,
827 // but does not affect lines after a soft wrap break.
828 bool isFirstLine = lineInfo.isFirstLine() && !(isAnonymousBlock() && parent()->firstChild() != this);
829 bool isAfterHardLineBreak = lineBox->prevRootBox() && lineBox->prevRootBox()->endsWithBreak();
antti@apple.com78e56772013-09-29 04:34:37 +0000830 IndentTextOrNot shouldIndentText = requiresIndent(isFirstLine, isAfterHardLineBreak, *style());
robert@webkit.org0903cf52012-12-11 18:14:16 +0000831 float lineLogicalLeft;
832 float lineLogicalRight;
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +0000833 float availableLogicalWidth;
commit-queue@webkit.orgab781b02013-04-03 01:32:24 +0000834 updateLogicalInlinePositions(this, lineLogicalLeft, lineLogicalRight, availableLogicalWidth, isFirstLine, shouldIndentText, 0);
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +0000835 bool needsWordSpacing;
betravis@adobe.comed90c982013-06-05 23:05:57 +0000836#if ENABLE(CSS_SHAPES)
betravis@adobe.comcf7cba62013-06-10 21:23:45 +0000837 ShapeInsideInfo* shapeInsideInfo = layoutShapeInsideInfo();
838 if (shapeInsideInfo && shapeInsideInfo->hasSegments()) {
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +0000839 BidiRun* segmentStart = firstRun;
betravis@adobe.comcf7cba62013-06-10 21:23:45 +0000840 const SegmentList& segments = shapeInsideInfo->segments();
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +0000841 float logicalLeft = max<float>(roundToInt(segments[0].logicalLeft), lineLogicalLeft);
842 float logicalRight = min<float>(floorToInt(segments[0].logicalRight), lineLogicalRight);
843 float startLogicalLeft = logicalLeft;
844 float endLogicalRight = logicalLeft;
845 float minLogicalLeft = logicalLeft;
846 float maxLogicalRight = logicalLeft;
847 lineBox->beginPlacingBoxRangesInInlineDirection(logicalLeft);
848 for (size_t i = 0; i < segments.size(); i++) {
849 if (i) {
850 logicalLeft = max<float>(roundToInt(segments[i].logicalLeft), lineLogicalLeft);
851 logicalRight = min<float>(floorToInt(segments[i].logicalRight), lineLogicalRight);
852 }
853 availableLogicalWidth = logicalRight - logicalLeft;
854 BidiRun* newSegmentStart = computeInlineDirectionPositionsForSegment(lineBox, lineInfo, textAlign, logicalLeft, availableLogicalWidth, segmentStart, trailingSpaceRun, textBoxDataMap, verticalPositionCache, wordMeasurements);
855 needsWordSpacing = false;
856 endLogicalRight = lineBox->placeBoxRangeInInlineDirection(segmentStart->m_box, newSegmentStart ? newSegmentStart->m_box : 0, logicalLeft, minLogicalLeft, maxLogicalRight, needsWordSpacing, textBoxDataMap);
857 if (!newSegmentStart || !newSegmentStart->next())
858 break;
859 ASSERT(newSegmentStart->m_startsSegment);
860 // Discard the empty segment start marker bidi runs
861 segmentStart = newSegmentStart->next();
862 }
863 lineBox->endPlacingBoxRangesInInlineDirection(startLogicalLeft, endLogicalRight, minLogicalLeft, maxLogicalRight);
864 return;
commit-queue@webkit.orgb3540512012-08-24 18:48:49 +0000865 }
866#endif
robert@webkit.org0903cf52012-12-11 18:14:16 +0000867
868 if (firstRun && firstRun->m_object->isReplaced()) {
869 RenderBox* renderBox = toRenderBox(firstRun->m_object);
commit-queue@webkit.orgab781b02013-04-03 01:32:24 +0000870 updateLogicalInlinePositions(this, lineLogicalLeft, lineLogicalRight, availableLogicalWidth, isFirstLine, shouldIndentText, renderBox->logicalHeight());
robert@webkit.org0903cf52012-12-11 18:14:16 +0000871 }
872
873 computeInlineDirectionPositionsForSegment(lineBox, lineInfo, textAlign, lineLogicalLeft, availableLogicalWidth, firstRun, trailingSpaceRun, textBoxDataMap, verticalPositionCache, wordMeasurements);
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +0000874 // The widths of all runs are now known. We can now place every inline box (and
875 // compute accurate widths for the inline flow boxes).
876 needsWordSpacing = false;
877 lineBox->placeBoxesInInlineDirection(lineLogicalLeft, needsWordSpacing, textBoxDataMap);
878}
mitz@apple.com390fa322011-02-24 23:07:06 +0000879
robert@webkit.org0903cf52012-12-11 18:14:16 +0000880BidiRun* RenderBlock::computeInlineDirectionPositionsForSegment(RootInlineBox* lineBox, const LineInfo& lineInfo, ETextAlign textAlign, float& logicalLeft,
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +0000881 float& availableLogicalWidth, BidiRun* firstRun, BidiRun* trailingSpaceRun, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache,
882 WordMeasurements& wordMeasurements)
883{
darin06dcb9c2005-08-15 04:31:09 +0000884 bool needsWordSpacing = false;
mitz@apple.com390fa322011-02-24 23:07:06 +0000885 float totalLogicalWidth = lineBox->getFlowSpacingLogicalWidth();
mitz@apple.com86470c82011-01-27 01:39:27 +0000886 unsigned expansionOpportunityCount = 0;
887 bool isAfterExpansion = true;
888 Vector<unsigned, 16> expansionOpportunities;
mitz@apple.comddb59872011-04-05 05:21:16 +0000889 RenderObject* previousObject = 0;
mitz@apple.com815ef2f2008-02-25 17:11:56 +0000890
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +0000891 BidiRun* r = firstRun;
892 for (; r; r = r->next()) {
betravis@adobe.comed90c982013-06-05 23:05:57 +0000893#if ENABLE(CSS_SHAPES)
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +0000894 // Once we have reached the start of the next segment, we have finished
895 // computing the positions for this segment's contents.
896 if (r->m_startsSegment)
897 break;
898#endif
simon.fraser@apple.com2f071852012-06-25 00:11:30 +0000899 if (!r->m_box || r->m_object->isOutOfFlowPositioned() || r->m_box->isLineBreak())
hyatt98ee7e42003-05-14 01:39:15 +0000900 continue; // Positioned objects are only participating to figure out their
901 // correct static x position. They have no effect on the width.
hyatt0c05e102006-04-14 08:15:00 +0000902 // Similarly, line break boxes have no effect on the width.
mitz@apple.come1364202008-02-28 01:06:41 +0000903 if (r->m_object->isText()) {
darin@apple.com36744d62009-01-25 20:23:04 +0000904 RenderText* rt = toRenderText(r->m_object);
mitz@apple.comc13ea5f2008-04-18 21:18:26 +0000905 if (textAlign == JUSTIFY && r != trailingSpaceRun) {
mitz@apple.com80968932011-03-26 00:46:26 +0000906 if (!isAfterExpansion)
jchaffraix@webkit.org8f1781d2011-06-24 21:22:54 +0000907 toInlineTextBox(r->m_box)->setCanHaveLeadingExpansion(true);
msaboff@apple.com776c286c72012-10-15 16:56:29 +0000908 unsigned opportunitiesInRun;
909 if (rt->is8Bit())
910 opportunitiesInRun = Font::expansionOpportunityCount(rt->characters8() + r->m_start, r->m_stop - r->m_start, r->m_box->direction(), isAfterExpansion);
911 else
912 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 +0000913 expansionOpportunities.append(opportunitiesInRun);
914 expansionOpportunityCount += opportunitiesInRun;
mitz@apple.com815ef2f2008-02-25 17:11:56 +0000915 }
916
mitz@apple.come1364202008-02-28 01:06:41 +0000917 if (int length = rt->textLength()) {
msaboff@apple.com776c286c72012-10-15 16:56:29 +0000918 if (!r->m_start && needsWordSpacing && isSpaceOrNewline(rt->characterAt(r->m_start)))
antti@apple.comb0608f62013-09-28 18:30:16 +0000919 totalLogicalWidth += lineStyle(*rt->parent(), lineInfo).font().wordSpacing();
msaboff@apple.com776c286c72012-10-15 16:56:29 +0000920 needsWordSpacing = !isSpaceOrNewline(rt->characterAt(r->m_stop - 1)) && r->m_stop == length;
darin06dcb9c2005-08-15 04:31:09 +0000921 }
eric@webkit.org060caf62011-05-03 22:11:39 +0000922
enrica@apple.com885c84d2012-10-10 05:48:51 +0000923 setLogicalWidthForTextRun(lineBox, r, rt, totalLogicalWidth, lineInfo, textBoxDataMap, verticalPositionCache, wordMeasurements);
mitz@apple.com86470c82011-01-27 01:39:27 +0000924 } else {
925 isAfterExpansion = false;
926 if (!r->m_object->isRenderInline()) {
927 RenderBox* renderBox = toRenderBox(r->m_object);
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000928 if (renderBox->isRubyRun())
929 setMarginsForRubyRun(r, toRenderRubyRun(renderBox), previousObject, lineInfo);
mitz@apple.com86470c82011-01-27 01:39:27 +0000930 r->m_box->setLogicalWidth(logicalWidthForChild(renderBox));
931 totalLogicalWidth += marginStartForChild(renderBox) + marginEndForChild(renderBox);
932 }
hyattffe78712003-02-11 01:59:29 +0000933 }
hyatt4b381692003-03-10 21:11:59 +0000934
hyatt@apple.com546a2482010-10-07 21:16:49 +0000935 totalLogicalWidth += r->m_box->logicalWidth();
mitz@apple.comddb59872011-04-05 05:21:16 +0000936 previousObject = r->m_object;
hyattffe78712003-02-11 01:59:29 +0000937 }
938
mitz@apple.com86470c82011-01-27 01:39:27 +0000939 if (isAfterExpansion && !expansionOpportunities.isEmpty()) {
940 expansionOpportunities.last()--;
941 expansionOpportunityCount--;
942 }
943
robert@webkit.orgfc7763c2011-09-03 18:28:57 +0000944 updateLogicalWidthForAlignment(textAlign, trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth, expansionOpportunityCount);
hyattffe78712003-02-11 01:59:29 +0000945
leviw@chromium.orgd70a0072011-05-03 23:28:11 +0000946 computeExpansionForJustifiedText(firstRun, trailingSpaceRun, expansionOpportunities, expansionOpportunityCount, totalLogicalWidth, availableLogicalWidth);
mitz@apple.come1364202008-02-28 01:06:41 +0000947
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +0000948 return r;
hyattffe78712003-02-11 01:59:29 +0000949}
950
hyatt@apple.com4a9c625a2010-11-17 20:55:40 +0000951void RenderBlock::computeBlockDirectionPositionsForLine(RootInlineBox* lineBox, BidiRun* firstRun, GlyphOverflowAndFallbackFontsMap& textBoxDataMap,
952 VerticalPositionCache& verticalPositionCache)
hyattffe78712003-02-11 01:59:29 +0000953{
hyatt@apple.com4a9c625a2010-11-17 20:55:40 +0000954 setLogicalHeight(lineBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache));
hyattffe78712003-02-11 01:59:29 +0000955
956 // Now make sure we place replaced render objects correctly.
mitz@apple.com887f3592008-02-25 22:03:08 +0000957 for (BidiRun* r = firstRun; r; r = r->next()) {
mitz@apple.comaa6ce3d2009-04-10 01:00:20 +0000958 ASSERT(r->m_box);
mitz@apple.come1364202008-02-28 01:06:41 +0000959 if (!r->m_box)
eseidel789896f2005-11-27 22:52:09 +0000960 continue; // Skip runs with no line boxes.
hyatt0c3a9862004-02-23 21:26:26 +0000961
hyatt98ee7e42003-05-14 01:39:15 +0000962 // Align positioned boxes with the top of the line box. This is
963 // a reasonable approximation of an appropriate y position.
simon.fraser@apple.com2f071852012-06-25 00:11:30 +0000964 if (r->m_object->isOutOfFlowPositioned())
hyatt@apple.com35d2ad52010-10-20 18:17:36 +0000965 r->m_box->setLogicalTop(logicalHeight());
hyatt98ee7e42003-05-14 01:39:15 +0000966
967 // Position is used to properly position both replaced elements and
968 // to update the static normal flow x/y of positioned elements.
hyatt@apple.com6a551ad2009-02-11 22:43:12 +0000969 if (r->m_object->isText())
970 toRenderText(r->m_object)->positionLineBox(r->m_box);
971 else if (r->m_object->isBox())
972 toRenderBox(r->m_object)->positionLineBox(r->m_box);
antti@apple.com3014ac02013-09-18 14:33:55 +0000973 else if (r->m_object->isLineBreak())
antti@apple.com8d8ae712013-09-18 18:04:32 +0000974 toRenderLineBreak(r->m_object)->replaceInlineBoxWrapper(r->m_box);
hyatt98ee7e42003-05-14 01:39:15 +0000975 }
mitz@apple.coma927be62008-03-21 05:30:19 +0000976 // Positioned objects and zero-length text nodes destroy their boxes in
977 // position(), which unnecessarily dirties the line.
978 lineBox->markDirty(false);
hyattffe78712003-02-11 01:59:29 +0000979}
kociendabb0c24b2001-08-24 14:24:40 +0000980
mitz@apple.comc13ea5f2008-04-18 21:18:26 +0000981static inline bool isCollapsibleSpace(UChar character, RenderText* renderer)
982{
983 if (character == ' ' || character == '\t' || character == softHyphen)
984 return true;
985 if (character == '\n')
986 return !renderer->style()->preserveNewline();
987 if (character == noBreakSpace)
988 return renderer->style()->nbspMode() == SPACE;
989 return false;
990}
991
hyatt@apple.com14e332d2011-03-25 21:57:07 +0000992
993static void setStaticPositions(RenderBlock* block, RenderBox* child)
994{
995 // FIXME: The math here is actually not really right. It's a best-guess approximation that
996 // will work for the common cases
akling@apple.comc096ce42013-09-23 23:55:20 +0000997 RenderElement* containerBlock = child->container();
eae@chromium.orgee8613e2011-11-12 01:12:58 +0000998 LayoutUnit blockHeight = block->logicalHeight();
hyatt@apple.com14e332d2011-03-25 21:57:07 +0000999 if (containerBlock->isRenderInline()) {
1000 // A relative positioned inline encloses us. In this case, we also have to determine our
1001 // position as though we were an inline. Set |staticInlinePosition| and |staticBlockPosition| on the relative positioned
1002 // inline so that we can obtain the value later.
robert@webkit.org82903f42012-08-28 19:18:40 +00001003 toRenderInline(containerBlock)->layer()->setStaticInlinePosition(block->startAlignedOffsetForLine(blockHeight, false));
hyatt@apple.com14e332d2011-03-25 21:57:07 +00001004 toRenderInline(containerBlock)->layer()->setStaticBlockPosition(blockHeight);
1005 }
robert@webkit.org83f864f2013-01-23 20:15:12 +00001006 block->updateStaticInlinePositionForChild(child, blockHeight);
hyatt@apple.com14e332d2011-03-25 21:57:07 +00001007 child->layer()->setStaticBlockPosition(blockHeight);
1008}
1009
msaboff@apple.com142fc202012-10-18 18:03:14 +00001010template <typename CharacterType>
1011static inline int findFirstTrailingSpace(RenderText* lastText, const CharacterType* characters, int start, int stop)
1012{
1013 int firstSpace = stop;
1014 while (firstSpace > start) {
1015 UChar current = characters[firstSpace - 1];
1016 if (!isCollapsibleSpace(current, lastText))
1017 break;
1018 firstSpace--;
1019 }
1020
1021 return firstSpace;
1022}
1023
eric@webkit.org5bee2942011-04-08 02:12:31 +00001024inline BidiRun* RenderBlock::handleTrailingSpaces(BidiRunList<BidiRun>& bidiRuns, BidiContext* currentContext)
eric@webkit.org0894bb82011-04-03 08:29:40 +00001025{
eric@webkit.org5bee2942011-04-08 02:12:31 +00001026 if (!bidiRuns.runCount()
1027 || !bidiRuns.logicallyLastRun()->m_object->style()->breakOnlyAfterWhiteSpace()
1028 || !bidiRuns.logicallyLastRun()->m_object->style()->autoWrap())
eric@webkit.org0894bb82011-04-03 08:29:40 +00001029 return 0;
1030
eric@webkit.org5bee2942011-04-08 02:12:31 +00001031 BidiRun* trailingSpaceRun = bidiRuns.logicallyLastRun();
eric@webkit.org0894bb82011-04-03 08:29:40 +00001032 RenderObject* lastObject = trailingSpaceRun->m_object;
1033 if (!lastObject->isText())
1034 return 0;
1035
1036 RenderText* lastText = toRenderText(lastObject);
msaboff@apple.com142fc202012-10-18 18:03:14 +00001037 int firstSpace;
1038 if (lastText->is8Bit())
1039 firstSpace = findFirstTrailingSpace(lastText, lastText->characters8(), trailingSpaceRun->start(), trailingSpaceRun->stop());
1040 else
1041 firstSpace = findFirstTrailingSpace(lastText, lastText->characters16(), trailingSpaceRun->start(), trailingSpaceRun->stop());
1042
eric@webkit.org0894bb82011-04-03 08:29:40 +00001043 if (firstSpace == trailingSpaceRun->stop())
1044 return 0;
1045
1046 TextDirection direction = style()->direction();
eric@webkit.org5bee2942011-04-08 02:12:31 +00001047 bool shouldReorder = trailingSpaceRun != (direction == LTR ? bidiRuns.lastRun() : bidiRuns.firstRun());
eric@webkit.org0894bb82011-04-03 08:29:40 +00001048 if (firstSpace != trailingSpaceRun->start()) {
eric@webkit.org5bee2942011-04-08 02:12:31 +00001049 BidiContext* baseContext = currentContext;
eric@webkit.org0894bb82011-04-03 08:29:40 +00001050 while (BidiContext* parent = baseContext->parent())
1051 baseContext = parent;
1052
1053 BidiRun* newTrailingRun = new (renderArena()) BidiRun(firstSpace, trailingSpaceRun->m_stop, trailingSpaceRun->m_object, baseContext, OtherNeutral);
1054 trailingSpaceRun->m_stop = firstSpace;
1055 if (direction == LTR)
eric@webkit.org5bee2942011-04-08 02:12:31 +00001056 bidiRuns.addRun(newTrailingRun);
eric@webkit.org0894bb82011-04-03 08:29:40 +00001057 else
eric@webkit.org5bee2942011-04-08 02:12:31 +00001058 bidiRuns.prependRun(newTrailingRun);
eric@webkit.org0894bb82011-04-03 08:29:40 +00001059 trailingSpaceRun = newTrailingRun;
1060 return trailingSpaceRun;
1061 }
1062 if (!shouldReorder)
1063 return trailingSpaceRun;
1064
1065 if (direction == LTR) {
eric@webkit.org5bee2942011-04-08 02:12:31 +00001066 bidiRuns.moveRunToEnd(trailingSpaceRun);
eric@webkit.org0894bb82011-04-03 08:29:40 +00001067 trailingSpaceRun->m_level = 0;
1068 } else {
eric@webkit.org5bee2942011-04-08 02:12:31 +00001069 bidiRuns.moveRunToBeginning(trailingSpaceRun);
eric@webkit.org0894bb82011-04-03 08:29:40 +00001070 trailingSpaceRun->m_level = 1;
1071 }
1072 return trailingSpaceRun;
1073}
1074
mitz@apple.comd17e8c02011-04-16 21:59:36 +00001075void RenderBlock::appendFloatingObjectToLastLine(FloatingObject* floatingObject)
1076{
bjonesbe@adobe.coma9c66662013-08-14 20:30:14 +00001077 ASSERT(!floatingObject->originatingLine());
1078 floatingObject->setOriginatingLine(lastRootBox());
darin@apple.com7cad7042013-09-24 05:53:55 +00001079 lastRootBox()->appendFloat(&floatingObject->renderer());
mitz@apple.comd17e8c02011-04-16 21:59:36 +00001080}
1081
eric@webkit.orga26de042011-09-08 18:46:01 +00001082// FIXME: This should be a BidiStatus constructor or create method.
rniwa@webkit.orgc275acf2012-03-05 23:09:22 +00001083static inline BidiStatus statusWithDirection(TextDirection textDirection, bool isOverride)
eric@webkit.orga26de042011-09-08 18:46:01 +00001084{
1085 WTF::Unicode::Direction direction = textDirection == LTR ? LeftToRight : RightToLeft;
rniwa@webkit.orgc275acf2012-03-05 23:09:22 +00001086 RefPtr<BidiContext> context = BidiContext::create(textDirection == LTR ? 0 : 1, direction, isOverride, FromStyleOrDOM);
eric@webkit.orga26de042011-09-08 18:46:01 +00001087
1088 // This copies BidiStatus and may churn the ref on BidiContext. I doubt it matters.
1089 return BidiStatus(direction, direction, direction, context.release());
1090}
1091
1092// FIXME: BidiResolver should have this logic.
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00001093static inline void constructBidiRunsForSegment(InlineBidiResolver& topResolver, BidiRunList<BidiRun>& bidiRuns, const InlineIterator& endOfRuns, VisualDirectionOverride override, bool previousLineBrokeCleanly)
eric@webkit.orga26de042011-09-08 18:46:01 +00001094{
1095 // FIXME: We should pass a BidiRunList into createBidiRunsForLine instead
1096 // of the resolver owning the runs.
1097 ASSERT(&topResolver.runs() == &bidiRuns);
betravis@adobe.com9e5e8242013-04-19 23:28:26 +00001098 ASSERT(topResolver.position() != endOfRuns);
commit-queue@webkit.org30cc2912011-12-15 04:19:24 +00001099 RenderObject* currentRoot = topResolver.position().root();
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00001100 topResolver.createBidiRunsForLine(endOfRuns, override, previousLineBrokeCleanly);
eric@webkit.orga26de042011-09-08 18:46:01 +00001101
1102 while (!topResolver.isolatedRuns().isEmpty()) {
1103 // It does not matter which order we resolve the runs as long as we resolve them all.
1104 BidiRun* isolatedRun = topResolver.isolatedRuns().last();
1105 topResolver.isolatedRuns().removeLast();
1106
commit-queue@webkit.org30cc2912011-12-15 04:19:24 +00001107 RenderObject* startObj = isolatedRun->object();
1108
eric@webkit.orga26de042011-09-08 18:46:01 +00001109 // Only inlines make sense with unicode-bidi: isolate (blocks are already isolated).
commit-queue@webkit.org30cc2912011-12-15 04:19:24 +00001110 // FIXME: Because enterIsolate is not passed a RenderObject, we have to crawl up the
1111 // tree to see which parent inline is the isolate. We could change enterIsolate
1112 // to take a RenderObject and do this logic there, but that would be a layering
1113 // violation for BidiResolver (which knows nothing about RenderObject).
leviw@chromium.orge7812f32012-02-07 23:46:40 +00001114 RenderInline* isolatedInline = toRenderInline(containingIsolate(startObj, currentRoot));
eric@webkit.orga26de042011-09-08 18:46:01 +00001115 InlineBidiResolver isolatedResolver;
leviw@chromium.orge7812f32012-02-07 23:46:40 +00001116 EUnicodeBidi unicodeBidi = isolatedInline->style()->unicodeBidi();
1117 TextDirection direction;
1118 if (unicodeBidi == Plaintext)
1119 determineDirectionality(direction, InlineIterator(isolatedInline, isolatedRun->object(), 0));
1120 else {
rniwa@webkit.org4d4bd332012-08-20 21:34:11 +00001121 ASSERT(unicodeBidi == Isolate || unicodeBidi == IsolateOverride);
leviw@chromium.orge7812f32012-02-07 23:46:40 +00001122 direction = isolatedInline->style()->direction();
1123 }
rniwa@webkit.orgc275acf2012-03-05 23:09:22 +00001124 isolatedResolver.setStatus(statusWithDirection(direction, isOverride(unicodeBidi)));
eric@webkit.orga26de042011-09-08 18:46:01 +00001125
1126 // FIXME: The fact that we have to construct an Iterator here
1127 // currently prevents this code from moving into BidiResolver.
leviw@chromium.orge7812f32012-02-07 23:46:40 +00001128 if (!bidiFirstSkippingEmptyInlines(isolatedInline, &isolatedResolver))
rniwa@webkit.org2343fab2011-11-25 20:21:06 +00001129 continue;
leviw@chromium.orge7812f32012-02-07 23:46:40 +00001130
commit-queue@webkit.org30cc2912011-12-15 04:19:24 +00001131 // The starting position is the beginning of the first run within the isolate that was identified
1132 // during the earlier call to createBidiRunsForLine. This can be but is not necessarily the
1133 // first run within the isolate.
leviw@chromium.orge7812f32012-02-07 23:46:40 +00001134 InlineIterator iter = InlineIterator(isolatedInline, startObj, isolatedRun->m_start);
commit-queue@webkit.org30cc2912011-12-15 04:19:24 +00001135 isolatedResolver.setPositionIgnoringNestedIsolates(iter);
eric@webkit.orga26de042011-09-08 18:46:01 +00001136
commit-queue@webkit.org30cc2912011-12-15 04:19:24 +00001137 // 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 +00001138 // FIXME: What should end and previousLineBrokeCleanly be?
1139 // rniwa says previousLineBrokeCleanly is just a WinIE hack and could always be false here?
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00001140 isolatedResolver.createBidiRunsForLine(endOfRuns, NoVisualOverride, previousLineBrokeCleanly);
eric@webkit.orga26de042011-09-08 18:46:01 +00001141 // Note that we do not delete the runs from the resolver.
rniwa@webkit.orgd0ad8882012-05-23 07:37:07 +00001142 // 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 +00001143 // itself to be turned into an InlineBox. We can't remove it here without potentially losing track of
1144 // the logically last run.
1145 if (isolatedResolver.runs().runCount())
1146 bidiRuns.replaceRunWithRuns(isolatedRun, isolatedResolver.runs());
eric@webkit.orga26de042011-09-08 18:46:01 +00001147
1148 // If we encountered any nested isolate runs, just move them
1149 // to the top resolver's list for later processing.
1150 if (!isolatedResolver.isolatedRuns().isEmpty()) {
andersca@apple.com92012992013-05-05 19:03:49 +00001151 topResolver.isolatedRuns().appendVector(isolatedResolver.isolatedRuns());
eric@webkit.orga26de042011-09-08 18:46:01 +00001152 isolatedResolver.isolatedRuns().clear();
commit-queue@webkit.org1968a432013-09-11 19:23:58 +00001153 currentRoot = isolatedInline;
eric@webkit.orga26de042011-09-08 18:46:01 +00001154 }
1155 }
1156}
1157
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00001158static inline void constructBidiRunsForLine(const RenderBlock* block, InlineBidiResolver& topResolver, BidiRunList<BidiRun>& bidiRuns, const InlineIterator& endOfLine, VisualDirectionOverride override, bool previousLineBrokeCleanly)
1159{
betravis@adobe.comed90c982013-06-05 23:05:57 +00001160#if !ENABLE(CSS_SHAPES)
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00001161 UNUSED_PARAM(block);
1162 constructBidiRunsForSegment(topResolver, bidiRuns, endOfLine, override, previousLineBrokeCleanly);
1163#else
betravis@adobe.comcf7cba62013-06-10 21:23:45 +00001164 ShapeInsideInfo* shapeInsideInfo = block->layoutShapeInsideInfo();
1165 if (!shapeInsideInfo || !shapeInsideInfo->hasSegments()) {
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00001166 constructBidiRunsForSegment(topResolver, bidiRuns, endOfLine, override, previousLineBrokeCleanly);
1167 return;
1168 }
1169
betravis@adobe.comcf7cba62013-06-10 21:23:45 +00001170 const SegmentRangeList& segmentRanges = shapeInsideInfo->segmentRanges();
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00001171 ASSERT(segmentRanges.size());
1172
1173 for (size_t i = 0; i < segmentRanges.size(); i++) {
betravis@adobe.com28fba072013-03-12 23:27:35 +00001174 LineSegmentIterator iterator = segmentRanges[i].start;
1175 InlineIterator segmentStart(iterator.root, iterator.object, iterator.offset);
1176 iterator = segmentRanges[i].end;
1177 InlineIterator segmentEnd(iterator.root, iterator.object, iterator.offset);
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00001178 if (i) {
1179 ASSERT(segmentStart.m_obj);
1180 BidiRun* segmentMarker = createRun(segmentStart.m_pos, segmentStart.m_pos, segmentStart.m_obj, topResolver);
1181 segmentMarker->m_startsSegment = true;
1182 bidiRuns.addRun(segmentMarker);
1183 // Do not collapse midpoints between segments
1184 topResolver.midpointState().betweenMidpoints = false;
1185 }
betravis@adobe.com9e5e8242013-04-19 23:28:26 +00001186 if (segmentStart == segmentEnd)
1187 continue;
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00001188 topResolver.setPosition(segmentStart, numberOfIsolateAncestors(segmentStart));
1189 constructBidiRunsForSegment(topResolver, bidiRuns, segmentEnd, override, previousLineBrokeCleanly);
1190 }
1191#endif
1192}
1193
eric@webkit.org45e33a52011-05-04 11:51:09 +00001194// 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 +00001195RootInlineBox* RenderBlock::createLineBoxesFromBidiRuns(BidiRunList<BidiRun>& bidiRuns, const InlineIterator& end, LineInfo& lineInfo, VerticalPositionCache& verticalPositionCache, BidiRun* trailingSpaceRun, WordMeasurements& wordMeasurements)
eric@webkit.org45e33a52011-05-04 11:51:09 +00001196{
1197 if (!bidiRuns.runCount())
1198 return 0;
1199
1200 // FIXME: Why is this only done when we had runs?
1201 lineInfo.setLastLine(!end.m_obj);
1202
1203 RootInlineBox* lineBox = constructLine(bidiRuns, lineInfo);
1204 if (!lineBox)
1205 return 0;
1206
1207 lineBox->setEndsWithBreak(lineInfo.previousLineBrokeCleanly());
1208
1209#if ENABLE(SVG)
1210 bool isSVGRootInlineBox = lineBox->isSVGRootInlineBox();
1211#else
1212 bool isSVGRootInlineBox = false;
1213#endif
1214
1215 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
1216
1217 // Now we position all of our text runs horizontally.
1218 if (!isSVGRootInlineBox)
enrica@apple.com885c84d2012-10-10 05:48:51 +00001219 computeInlineDirectionPositionsForLine(lineBox, lineInfo, bidiRuns.firstRun(), trailingSpaceRun, end.atEnd(), textBoxDataMap, verticalPositionCache, wordMeasurements);
eric@webkit.org45e33a52011-05-04 11:51:09 +00001220
1221 // Now position our text runs vertically.
1222 computeBlockDirectionPositionsForLine(lineBox, bidiRuns.firstRun(), textBoxDataMap, verticalPositionCache);
1223
1224#if ENABLE(SVG)
1225 // SVG text layout code computes vertical & horizontal positions on its own.
1226 // Note that we still need to execute computeVerticalPositionsForLine() as
1227 // it calls InlineTextBox::positionLineBox(), which tracks whether the box
1228 // contains reversed text or not. If we wouldn't do that editing and thus
1229 // text selection in RTL boxes would not work as expected.
1230 if (isSVGRootInlineBox) {
1231 ASSERT(isSVGText());
1232 static_cast<SVGRootInlineBox*>(lineBox)->computePerCharacterLayoutInformation();
1233 }
1234#endif
1235
1236 // Compute our overflow now.
1237 lineBox->computeOverflow(lineBox->lineTop(), lineBox->lineBottom(), textBoxDataMap);
1238
1239#if PLATFORM(MAC)
1240 // Highlight acts as an overflow inflation.
1241 if (style()->highlight() != nullAtom)
1242 lineBox->addHighlightOverflow();
1243#endif
1244 return lineBox;
1245}
1246
akling@apple.com7ce905d2013-09-17 11:05:01 +00001247static void deleteLineRange(LineLayoutState& layoutState, RenderArena& arena, RootInlineBox* startLine, RootInlineBox* stopLine = 0)
eric@webkit.org455d90e2011-05-09 22:27:27 +00001248{
1249 RootInlineBox* boxToDelete = startLine;
1250 while (boxToDelete && boxToDelete != stopLine) {
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001251 layoutState.updateRepaintRangeFromBox(boxToDelete);
eric@webkit.orge2532d92011-05-16 23:10:49 +00001252 // Note: deleteLineRange(renderArena(), firstRootBox()) is not identical to deleteLineBoxTree().
1253 // deleteLineBoxTree uses nextLineBox() instead of nextRootBox() when traversing.
eric@webkit.org455d90e2011-05-09 22:27:27 +00001254 RootInlineBox* next = boxToDelete->nextRootBox();
1255 boxToDelete->deleteLine(arena);
1256 boxToDelete = next;
1257 }
1258}
1259
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001260void RenderBlock::layoutRunsAndFloats(LineLayoutState& layoutState, bool hasInlineChild)
eric@webkit.org060caf62011-05-03 22:11:39 +00001261{
1262 // We want to skip ahead to the first dirty line
1263 InlineBidiResolver resolver;
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001264 RootInlineBox* startLine = determineStartPosition(layoutState, resolver);
eric@webkit.org060caf62011-05-03 22:11:39 +00001265
mitz@apple.com10ed3cb2011-09-07 20:59:39 +00001266 unsigned consecutiveHyphenatedLines = 0;
1267 if (startLine) {
1268 for (RootInlineBox* line = startLine->prevRootBox(); line && line->isHyphenated(); line = line->prevRootBox())
1269 consecutiveHyphenatedLines++;
1270 }
1271
eric@webkit.org060caf62011-05-03 22:11:39 +00001272 // FIXME: This would make more sense outside of this function, but since
1273 // determineStartPosition can change the fullLayout flag we have to do this here. Failure to call
1274 // determineStartPosition first will break fast/repaint/line-flow-with-floats-9.html.
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001275 if (layoutState.isFullLayout() && hasInlineChild && !selfNeedsLayout()) {
antti@apple.comca2a8ff2013-10-04 04:04:35 +00001276 setNeedsLayout(MarkOnlyThis); // Mark as needing a full layout to force us to repaint.
akling@apple.com691cf5c2013-08-24 16:33:15 +00001277 if (!view().doingFullRepaint() && hasLayer()) {
eric@webkit.org060caf62011-05-03 22:11:39 +00001278 // Because we waited until we were already inside layout to discover
1279 // that the block really needed a full layout, we missed our chance to repaint the layer
1280 // before layout started. Luckily the layer has cached the repaint rect for its original
1281 // position and size, and so we can use that to make a repaint happen now.
leviw@chromium.org52066f32012-09-12 19:17:03 +00001282 repaintUsingContainer(containerForRepaint(), pixelSnappedIntRect(layer()->repaintRect()));
eric@webkit.org060caf62011-05-03 22:11:39 +00001283 }
1284 }
1285
mihnea@adobe.com99467792013-03-19 09:09:04 +00001286 if (containsFloats())
darin@apple.com7cad7042013-09-24 05:53:55 +00001287 layoutState.setLastFloat(m_floatingObjects->set().last().get());
eric@webkit.org060caf62011-05-03 22:11:39 +00001288
1289 // We also find the first clean line and extract these lines. We will add them back
1290 // if we determine that we're able to synchronize after handling all our dirty lines.
1291 InlineIterator cleanLineStart;
1292 BidiStatus cleanLineBidiStatus;
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001293 if (!layoutState.isFullLayout() && startLine)
1294 determineEndPosition(layoutState, startLine, cleanLineStart, cleanLineBidiStatus);
eric@webkit.org060caf62011-05-03 22:11:39 +00001295
1296 if (startLine) {
commit-queue@webkit.org49ad4732011-07-15 07:23:01 +00001297 if (!layoutState.usesRepaintBounds())
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001298 layoutState.setRepaintRange(logicalHeight());
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001299 deleteLineRange(layoutState, renderArena(), startLine);
eric@webkit.org060caf62011-05-03 22:11:39 +00001300 }
1301
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001302 if (!layoutState.isFullLayout() && lastRootBox() && lastRootBox()->endsWithBreak()) {
eric@webkit.org060caf62011-05-03 22:11:39 +00001303 // If the last line before the start line ends with a line break that clear floats,
1304 // adjust the height accordingly.
1305 // A line break can be either the first or the last object on a line, depending on its direction.
1306 if (InlineBox* lastLeafChild = lastRootBox()->lastLeafChild()) {
akling@apple.com0b8172b72013-08-31 18:34:23 +00001307 RenderObject* lastObject = &lastLeafChild->renderer();
eric@webkit.org060caf62011-05-03 22:11:39 +00001308 if (!lastObject->isBR())
akling@apple.com0b8172b72013-08-31 18:34:23 +00001309 lastObject = &lastRootBox()->firstLeafChild()->renderer();
eric@webkit.org060caf62011-05-03 22:11:39 +00001310 if (lastObject->isBR()) {
1311 EClear clear = lastObject->style()->clear();
1312 if (clear != CNONE)
1313 newLine(clear);
1314 }
1315 }
1316 }
1317
mitz@apple.com10ed3cb2011-09-07 20:59:39 +00001318 layoutRunsAndFloatsInRange(layoutState, resolver, cleanLineStart, cleanLineBidiStatus, consecutiveHyphenatedLines);
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001319 linkToEndLineIfNeeded(layoutState);
1320 repaintDirtyFloats(layoutState.floats());
1321}
eric@webkit.org060caf62011-05-03 22:11:39 +00001322
zoltan@webkit.org8b422c82013-09-20 21:17:43 +00001323RenderTextInfo::RenderTextInfo()
mitz@apple.com6a859602012-08-27 15:31:56 +00001324 : m_text(0)
mitz@apple.comd4c153d2012-09-16 23:36:41 +00001325 , m_font(0)
mitz@apple.com6a859602012-08-27 15:31:56 +00001326{
1327}
1328
zoltan@webkit.org8b422c82013-09-20 21:17:43 +00001329RenderTextInfo::~RenderTextInfo()
mitz@apple.com6a859602012-08-27 15:31:56 +00001330{
1331}
1332
commit-queue@webkit.org4055b2e2012-12-06 19:05:15 +00001333// Before restarting the layout loop with a new logicalHeight, remove all floats that were added and reset the resolver.
1334inline const InlineIterator& RenderBlock::restartLayoutRunsAndFloatsInRange(LayoutUnit oldLogicalHeight, LayoutUnit newLogicalHeight, FloatingObject* lastFloatFromPreviousLine, InlineBidiResolver& resolver, const InlineIterator& oldEnd)
1335{
1336 removeFloatingObjectsBelow(lastFloatFromPreviousLine, oldLogicalHeight);
1337 setLogicalHeight(newLogicalHeight);
1338 resolver.setPositionIgnoringNestedIsolates(oldEnd);
1339 return oldEnd;
1340}
1341
betravis@adobe.comed90c982013-06-05 23:05:57 +00001342#if ENABLE(CSS_SHAPES)
betravis@adobe.com9e5e8242013-04-19 23:28:26 +00001343static inline float firstPositiveWidth(const WordMeasurements& wordMeasurements)
1344{
1345 for (size_t i = 0; i < wordMeasurements.size(); ++i) {
1346 if (wordMeasurements[i].width > 0)
1347 return wordMeasurements[i].width;
1348 }
1349 return 0;
1350}
1351
betravis@adobe.comcf7cba62013-06-10 21:23:45 +00001352static inline LayoutUnit adjustLogicalLineTop(ShapeInsideInfo* shapeInsideInfo, InlineIterator start, InlineIterator end, const WordMeasurements& wordMeasurements)
betravis@adobe.com9e5e8242013-04-19 23:28:26 +00001353{
betravis@adobe.comcf7cba62013-06-10 21:23:45 +00001354 if (!shapeInsideInfo || end != start)
betravis@adobe.com9e5e8242013-04-19 23:28:26 +00001355 return 0;
1356
1357 float minWidth = firstPositiveWidth(wordMeasurements);
1358 ASSERT(minWidth || wordMeasurements.isEmpty());
betravis@adobe.comcf7cba62013-06-10 21:23:45 +00001359 if (minWidth > 0 && shapeInsideInfo->adjustLogicalLineTop(minWidth))
1360 return shapeInsideInfo->logicalLineTop();
betravis@adobe.com9e5e8242013-04-19 23:28:26 +00001361
betravis@adobe.comcf7cba62013-06-10 21:23:45 +00001362 return shapeInsideInfo->shapeLogicalBottom();
betravis@adobe.com9e5e8242013-04-19 23:28:26 +00001363}
zoltan@webkit.orgbd3dabd2013-05-13 19:11:33 +00001364
zoltan@webkit.org758f6ce2013-06-18 22:31:57 +00001365static inline void pushShapeContentOverflowBelowTheContentBox(RenderBlock* block, ShapeInsideInfo* shapeInsideInfo, LayoutUnit lineTop, LayoutUnit lineHeight)
zoltan@webkit.org3a337ba2013-06-17 20:23:58 +00001366{
zoltan@webkit.org758f6ce2013-06-18 22:31:57 +00001367 ASSERT(shapeInsideInfo);
zoltan@webkit.org3a337ba2013-06-17 20:23:58 +00001368
1369 LayoutUnit logicalLineBottom = lineTop + lineHeight;
zoltan@webkit.orgb20fd7c2013-07-19 17:46:08 +00001370 LayoutUnit shapeLogicalBottom = shapeInsideInfo->shapeLogicalBottom();
zoltan@webkit.org22964092013-09-12 22:55:59 +00001371 LayoutUnit shapeContainingBlockLogicalHeight = shapeInsideInfo->shapeContainingBlockLogicalHeight();
zoltan@webkit.org758f6ce2013-06-18 22:31:57 +00001372
zoltan@webkit.org22964092013-09-12 22:55:59 +00001373 bool isOverflowPositionedAlready = (shapeContainingBlockLogicalHeight - shapeInsideInfo->owner()->borderAndPaddingAfter() + lineHeight) <= lineTop;
zoltan@webkit.org758f6ce2013-06-18 22:31:57 +00001374
zoltan@webkit.orgb20fd7c2013-07-19 17:46:08 +00001375 // If the last line overlaps with the shape, we don't need the segments anymore
1376 if (lineTop < shapeLogicalBottom && shapeLogicalBottom < logicalLineBottom)
1377 shapeInsideInfo->clearSegments();
1378
zoltan@webkit.org22964092013-09-12 22:55:59 +00001379 if (logicalLineBottom <= shapeLogicalBottom || !shapeContainingBlockLogicalHeight || isOverflowPositionedAlready)
zoltan@webkit.org3a337ba2013-06-17 20:23:58 +00001380 return;
1381
zoltan@webkit.org22964092013-09-12 22:55:59 +00001382 LayoutUnit newLogicalHeight = block->logicalHeight() + (shapeContainingBlockLogicalHeight - (lineTop + shapeInsideInfo->owner()->borderAndPaddingAfter()));
zoltan@webkit.org3a337ba2013-06-17 20:23:58 +00001383 block->setLogicalHeight(newLogicalHeight);
zoltan@webkit.org3a337ba2013-06-17 20:23:58 +00001384}
1385
betravis@adobe.com5fd027a2013-09-03 22:14:51 +00001386void RenderBlock::updateShapeAndSegmentsForCurrentLine(ShapeInsideInfo*& shapeInsideInfo, const LayoutSize& logicalOffsetFromShapeContainer, LineLayoutState& layoutState)
zoltan@webkit.orgbd3dabd2013-05-13 19:11:33 +00001387{
zoltan@webkit.org758bf022013-06-13 21:09:43 +00001388 if (layoutState.flowThread())
zoltan@webkit.org758f6ce2013-06-18 22:31:57 +00001389 return updateShapeAndSegmentsForCurrentLineInFlowThread(shapeInsideInfo, layoutState);
zoltan@webkit.org758bf022013-06-13 21:09:43 +00001390
zoltan@webkit.org758f6ce2013-06-18 22:31:57 +00001391 if (!shapeInsideInfo)
zoltan@webkit.orgbd3dabd2013-05-13 19:11:33 +00001392 return;
1393
betravis@adobe.com5fd027a2013-09-03 22:14:51 +00001394 LayoutUnit lineTop = logicalHeight() + logicalOffsetFromShapeContainer.height();
1395 LayoutUnit lineLeft = logicalOffsetFromShapeContainer.width();
zoltan@webkit.org3a337ba2013-06-17 20:23:58 +00001396 LayoutUnit lineHeight = this->lineHeight(layoutState.lineInfo().isFirstLine(), isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
zoltan@webkit.orgbd3dabd2013-05-13 19:11:33 +00001397
zoltan@webkit.org3a337ba2013-06-17 20:23:58 +00001398 // FIXME: Bug 95361: It is possible for a line to grow beyond lineHeight, in which case these segments may be incorrect.
zoltan@webkit.orge1a0c952013-09-18 03:27:35 +00001399 shapeInsideInfo->updateSegmentsForLine(LayoutSize(lineLeft, lineTop), lineHeight);
zoltan@webkit.org3a337ba2013-06-17 20:23:58 +00001400
zoltan@webkit.org758f6ce2013-06-18 22:31:57 +00001401 pushShapeContentOverflowBelowTheContentBox(this, shapeInsideInfo, lineTop, lineHeight);
zoltan@webkit.org758bf022013-06-13 21:09:43 +00001402}
zoltan@webkit.orgd07fc732013-05-20 19:00:22 +00001403
zoltan@webkit.org758f6ce2013-06-18 22:31:57 +00001404void RenderBlock::updateShapeAndSegmentsForCurrentLineInFlowThread(ShapeInsideInfo*& shapeInsideInfo, LineLayoutState& layoutState)
zoltan@webkit.org758bf022013-06-13 21:09:43 +00001405{
1406 ASSERT(layoutState.flowThread());
zoltan@webkit.orgee0f4072013-05-21 21:04:27 +00001407
zoltan@webkit.org758bf022013-06-13 21:09:43 +00001408 LayoutUnit lineHeight = this->lineHeight(layoutState.lineInfo().isFirstLine(), isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
zoltan@webkit.orgee0f4072013-05-21 21:04:27 +00001409
zoltan@webkit.org758bf022013-06-13 21:09:43 +00001410 RenderRegion* currentRegion = regionAtBlockOffset(logicalHeight());
1411 if (!currentRegion)
1412 return;
zoltan@webkit.orgee0f4072013-05-21 21:04:27 +00001413
zoltan@webkit.org758bf022013-06-13 21:09:43 +00001414 shapeInsideInfo = currentRegion->shapeInsideInfo();
zoltan@webkit.orgee0f4072013-05-21 21:04:27 +00001415
zoltan@webkit.org758bf022013-06-13 21:09:43 +00001416 LayoutUnit logicalLineTopInFlowThread = logicalHeight() + offsetFromLogicalTopOfFirstPage();
1417 LayoutUnit logicalLineBottomInFlowThread = logicalLineTopInFlowThread + lineHeight;
1418 LayoutUnit logicalRegionTopInFlowThread = currentRegion->logicalTopForFlowThreadContent();
zoltan@webkit.org8e79cc22013-06-14 00:39:36 +00001419 LayoutUnit logicalRegionBottomInFlowThread = logicalRegionTopInFlowThread + currentRegion->logicalHeight() - currentRegion->borderAndPaddingBefore() - currentRegion->borderAndPaddingAfter();
zoltan@webkit.orgee0f4072013-05-21 21:04:27 +00001420
zoltan@webkit.org758bf022013-06-13 21:09:43 +00001421 // We only want to deal regions with shapes, so we look up for the next region whether it has a shape
1422 if (!shapeInsideInfo && !currentRegion->isLastRegion()) {
1423 LayoutUnit deltaToNextRegion = logicalHeight() + logicalRegionBottomInFlowThread - logicalLineTopInFlowThread;
1424 RenderRegion* lookupForNextRegion = regionAtBlockOffset(logicalHeight() + deltaToNextRegion);
1425 if (!lookupForNextRegion->shapeInsideInfo())
1426 return;
1427 }
1428
1429 LayoutUnit shapeBottomInFlowThread = LayoutUnit::max();
1430 if (shapeInsideInfo)
1431 shapeBottomInFlowThread = shapeInsideInfo->shapeLogicalBottom() + currentRegion->logicalTopForFlowThreadContent();
1432
1433 // If the line is between two shapes/regions we position the line to the top of the next shape/region
1434 RenderRegion* nextRegion = regionAtBlockOffset(logicalHeight() + lineHeight);
1435 if ((currentRegion != nextRegion && (logicalLineBottomInFlowThread > logicalRegionBottomInFlowThread)) || (!currentRegion->isLastRegion() && shapeBottomInFlowThread < logicalLineBottomInFlowThread)) {
1436 LayoutUnit deltaToNextRegion = logicalRegionBottomInFlowThread - logicalLineTopInFlowThread;
1437 nextRegion = regionAtBlockOffset(logicalHeight() + deltaToNextRegion);
1438
1439 ASSERT(currentRegion != nextRegion);
1440
1441 shapeInsideInfo = nextRegion->shapeInsideInfo();
1442 setLogicalHeight(logicalHeight() + deltaToNextRegion);
1443
1444 currentRegion = nextRegion;
1445
1446 logicalLineTopInFlowThread = logicalHeight() + offsetFromLogicalTopOfFirstPage();
1447 logicalLineBottomInFlowThread = logicalLineTopInFlowThread + lineHeight;
1448 logicalRegionTopInFlowThread = currentRegion->logicalTopForFlowThreadContent();
zoltan@webkit.org8e79cc22013-06-14 00:39:36 +00001449 logicalRegionBottomInFlowThread = logicalRegionTopInFlowThread + currentRegion->logicalHeight() - currentRegion->borderAndPaddingBefore() - currentRegion->borderAndPaddingAfter();
zoltan@webkit.org758bf022013-06-13 21:09:43 +00001450 }
1451
1452 if (!shapeInsideInfo)
1453 return;
1454
1455 // We position the first line to the top of the shape in the region or to the previously adjusted position in the shape
1456 if (logicalLineBottomInFlowThread <= (logicalRegionTopInFlowThread + lineHeight) || (logicalLineTopInFlowThread - logicalRegionTopInFlowThread) < (layoutState.adjustedLogicalLineTop() - currentRegion->borderAndPaddingBefore())) {
1457 LayoutUnit shapeTopOffset = layoutState.adjustedLogicalLineTop();
1458 if (!shapeTopOffset)
1459 shapeTopOffset = shapeInsideInfo->shapeLogicalTop();
1460
1461 LayoutUnit shapePositionInFlowThread = currentRegion->logicalTopForFlowThreadContent() + shapeTopOffset;
1462 LayoutUnit shapeTopLineTopDelta = shapePositionInFlowThread - logicalLineTopInFlowThread - currentRegion->borderAndPaddingBefore();
1463
1464 setLogicalHeight(logicalHeight() + shapeTopLineTopDelta);
1465 logicalLineTopInFlowThread += shapeTopLineTopDelta;
1466 layoutState.setAdjustedLogicalLineTop(0);
1467 }
1468
1469 LayoutUnit lineTop = logicalLineTopInFlowThread - currentRegion->logicalTopForFlowThreadContent() + currentRegion->borderAndPaddingBefore();
betravis@adobe.com5fd027a2013-09-03 22:14:51 +00001470
1471 // FIXME: 118571 - Shape inside on a region does not yet take into account its padding for nested flow blocks
zoltan@webkit.orge1a0c952013-09-18 03:27:35 +00001472 shapeInsideInfo->updateSegmentsForLine(LayoutSize(0, lineTop), lineHeight);
zoltan@webkit.org758bf022013-06-13 21:09:43 +00001473
zoltan@webkit.org3a337ba2013-06-17 20:23:58 +00001474 if (currentRegion->isLastRegion())
zoltan@webkit.org758f6ce2013-06-18 22:31:57 +00001475 pushShapeContentOverflowBelowTheContentBox(this, shapeInsideInfo, lineTop, lineHeight);
zoltan@webkit.orgbd3dabd2013-05-13 19:11:33 +00001476}
1477
betravis@adobe.comcf7cba62013-06-10 21:23:45 +00001478bool RenderBlock::adjustLogicalLineTopAndLogicalHeightIfNeeded(ShapeInsideInfo* shapeInsideInfo, LayoutUnit absoluteLogicalTop, LineLayoutState& layoutState, InlineBidiResolver& resolver, FloatingObject* lastFloatFromPreviousLine, InlineIterator& end, WordMeasurements& wordMeasurements)
zoltan@webkit.orgbd3dabd2013-05-13 19:11:33 +00001479{
betravis@adobe.comcf7cba62013-06-10 21:23:45 +00001480 LayoutUnit adjustedLogicalLineTop = adjustLogicalLineTop(shapeInsideInfo, resolver.position(), end, wordMeasurements);
zoltan@webkit.org2b977c02013-10-03 18:24:59 +00001481
1482 if (shapeInsideInfo && !wordMeasurements.size() && containsFloats()) {
1483 lastFloatFromPreviousLine = m_floatingObjects->set().last().get();
1484 LayoutUnit floatLogicalTopOffset = shapeInsideInfo->computeFirstFitPositionForFloat(lastFloatFromPreviousLine->logicalSize(isHorizontalWritingMode()));
1485 if (logicalHeight() < floatLogicalTopOffset)
1486 adjustedLogicalLineTop = floatLogicalTopOffset;
1487 }
1488
zoltan@webkit.orgbd3dabd2013-05-13 19:11:33 +00001489 if (!adjustedLogicalLineTop)
1490 return false;
1491
1492 LayoutUnit newLogicalHeight = adjustedLogicalLineTop - absoluteLogicalTop;
zoltan@webkit.org758bf022013-06-13 21:09:43 +00001493
1494 if (layoutState.flowThread()) {
1495 layoutState.setAdjustedLogicalLineTop(adjustedLogicalLineTop);
zoltan@webkit.orgee0f4072013-05-21 21:04:27 +00001496 newLogicalHeight = logicalHeight();
zoltan@webkit.org758bf022013-06-13 21:09:43 +00001497 }
1498
zoltan@webkit.orgbd3dabd2013-05-13 19:11:33 +00001499 end = restartLayoutRunsAndFloatsInRange(logicalHeight(), newLogicalHeight, lastFloatFromPreviousLine, resolver, end);
1500 return true;
1501}
betravis@adobe.com9e5e8242013-04-19 23:28:26 +00001502#endif
1503
mitz@apple.com10ed3cb2011-09-07 20:59:39 +00001504void RenderBlock::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, InlineBidiResolver& resolver, const InlineIterator& cleanLineStart, const BidiStatus& cleanLineBidiStatus, unsigned consecutiveHyphenatedLines)
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001505{
mihnea@adobe.com3bebbf22012-01-19 09:22:59 +00001506 RenderStyle* styleToUse = style();
akling@apple.com691cf5c2013-08-24 16:33:15 +00001507 bool paginated = view().layoutState() && view().layoutState()->isPaginated();
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001508 LineMidpointState& lineMidpointState = resolver.midpointState();
1509 InlineIterator end = resolver.position();
1510 bool checkForEndLineMatch = layoutState.endLine();
mitz@apple.com6a859602012-08-27 15:31:56 +00001511 RenderTextInfo renderTextInfo;
eric@webkit.org060caf62011-05-03 22:11:39 +00001512 VerticalPositionCache verticalPositionCache;
1513
leviw@chromium.org1a508692011-05-05 00:01:11 +00001514 LineBreaker lineBreaker(this);
1515
betravis@adobe.comed90c982013-06-05 23:05:57 +00001516#if ENABLE(CSS_SHAPES)
betravis@adobe.com5fd027a2013-09-03 22:14:51 +00001517 LayoutSize logicalOffsetFromShapeContainer;
betravis@adobe.comcf7cba62013-06-10 21:23:45 +00001518 ShapeInsideInfo* shapeInsideInfo = layoutShapeInsideInfo();
1519 if (shapeInsideInfo) {
1520 ASSERT(shapeInsideInfo->owner() == this || allowsShapeInsideInfoSharing());
1521 if (shapeInsideInfo != this->shapeInsideInfo()) {
commit-queue@webkit.org5fe2dfd2012-10-26 19:57:52 +00001522 // FIXME Bug 100284: If subsequent LayoutStates are pushed, we will have to add
1523 // their offsets from the original shape-inside container.
betravis@adobe.com5fd027a2013-09-03 22:14:51 +00001524 logicalOffsetFromShapeContainer = logicalOffsetFromShapeAncestorContainer(shapeInsideInfo->owner());
commit-queue@webkit.org3b26f3d2012-09-25 18:22:39 +00001525 }
1526 // Begin layout at the logical top of our shape inside.
betravis@adobe.com5fd027a2013-09-03 22:14:51 +00001527 if (logicalHeight() + logicalOffsetFromShapeContainer.height() < shapeInsideInfo->shapeLogicalTop()) {
1528 LayoutUnit logicalHeight = shapeInsideInfo->shapeLogicalTop() - logicalOffsetFromShapeContainer.height();
zoltan@webkit.orgd07fc732013-05-20 19:00:22 +00001529 if (layoutState.flowThread())
betravis@adobe.comcf7cba62013-06-10 21:23:45 +00001530 logicalHeight -= shapeInsideInfo->owner()->borderAndPaddingBefore();
zoltan@webkit.orgd07fc732013-05-20 19:00:22 +00001531 setLogicalHeight(logicalHeight);
1532 }
commit-queue@webkit.org3b26f3d2012-09-25 18:22:39 +00001533 }
commit-queue@webkit.orgb3540512012-08-24 18:48:49 +00001534#endif
1535
eric@webkit.org060caf62011-05-03 22:11:39 +00001536 while (!end.atEnd()) {
1537 // 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 +00001538 if (checkForEndLineMatch) {
1539 layoutState.setEndLineMatched(matchedEndLine(layoutState, resolver, cleanLineStart, cleanLineBidiStatus));
rniwa@webkit.org7daa12d2011-12-02 02:39:14 +00001540 if (layoutState.endLineMatched()) {
1541 resolver.setPosition(InlineIterator(resolver.position().root(), 0, 0), 0);
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001542 break;
rniwa@webkit.org7daa12d2011-12-02 02:39:14 +00001543 }
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001544 }
eric@webkit.org060caf62011-05-03 22:11:39 +00001545
1546 lineMidpointState.reset();
1547
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001548 layoutState.lineInfo().setEmpty(true);
robert@webkit.org8cbab142011-12-30 20:58:29 +00001549 layoutState.lineInfo().resetRunsFromLeadingWhitespace();
eric@webkit.org060caf62011-05-03 22:11:39 +00001550
rniwa@webkit.org53d106b2011-11-30 22:33:20 +00001551 const InlineIterator oldEnd = end;
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001552 bool isNewUBAParagraph = layoutState.lineInfo().previousLineBrokeCleanly();
darin@apple.com7cad7042013-09-24 05:53:55 +00001553 FloatingObject* lastFloatFromPreviousLine = (containsFloats()) ? m_floatingObjects->set().last().get() : 0;
zoltan@webkit.org3bd77f52013-04-23 18:23:36 +00001554
betravis@adobe.comed90c982013-06-05 23:05:57 +00001555#if ENABLE(CSS_SHAPES)
betravis@adobe.com5fd027a2013-09-03 22:14:51 +00001556 updateShapeAndSegmentsForCurrentLine(shapeInsideInfo, logicalOffsetFromShapeContainer, layoutState);
commit-queue@webkit.orgb3540512012-08-24 18:48:49 +00001557#endif
enrica@apple.com885c84d2012-10-10 05:48:51 +00001558 WordMeasurements wordMeasurements;
1559 end = lineBreaker.nextLineBreak(resolver, layoutState.lineInfo(), renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
glenn@skynav.com61b1abf2013-04-02 23:28:32 +00001560 renderTextInfo.m_lineBreakIterator.resetPriorContext();
eric@webkit.org060caf62011-05-03 22:11:39 +00001561 if (resolver.position().atEnd()) {
leviw@chromium.orge7812f32012-02-07 23:46:40 +00001562 // FIXME: We shouldn't be creating any runs in nextLineBreak to begin with!
eric@webkit.org060caf62011-05-03 22:11:39 +00001563 // Once BidiRunList is separated from BidiResolver this will not be needed.
1564 resolver.runs().deleteRuns();
1565 resolver.markCurrentRunEmpty(); // FIXME: This can probably be replaced by an ASSERT (or just removed).
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001566 layoutState.setCheckForFloatsFromLastLine(true);
rniwa@webkit.org7daa12d2011-12-02 02:39:14 +00001567 resolver.setPosition(InlineIterator(resolver.position().root(), 0, 0), 0);
eric@webkit.org060caf62011-05-03 22:11:39 +00001568 break;
1569 }
eric@webkit.org060caf62011-05-03 22:11:39 +00001570
betravis@adobe.comed90c982013-06-05 23:05:57 +00001571#if ENABLE(CSS_SHAPES)
betravis@adobe.com5fd027a2013-09-03 22:14:51 +00001572 if (adjustLogicalLineTopAndLogicalHeightIfNeeded(shapeInsideInfo, logicalOffsetFromShapeContainer.height(), layoutState, resolver, lastFloatFromPreviousLine, end, wordMeasurements))
commit-queue@webkit.org4055b2e2012-12-06 19:05:15 +00001573 continue;
commit-queue@webkit.org4055b2e2012-12-06 19:05:15 +00001574#endif
betravis@adobe.com9e5e8242013-04-19 23:28:26 +00001575 ASSERT(end != resolver.position());
1576
eric@webkit.org45e33a52011-05-04 11:51:09 +00001577 // This is a short-cut for empty lines.
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001578 if (layoutState.lineInfo().isEmpty()) {
eric@webkit.org060caf62011-05-03 22:11:39 +00001579 if (lastRootBox())
1580 lastRootBox()->setLineBreakInfo(end.m_obj, end.m_pos, resolver.status());
1581 } else {
mihnea@adobe.com3bebbf22012-01-19 09:22:59 +00001582 VisualDirectionOverride override = (styleToUse->rtlOrdering() == VisualOrder ? (styleToUse->direction() == LTR ? VisualLeftToRightOverride : VisualRightToLeftOverride) : NoVisualOverride);
leviw@chromium.org7781b6a2011-06-27 22:01:38 +00001583
mihnea@adobe.com3bebbf22012-01-19 09:22:59 +00001584 if (isNewUBAParagraph && styleToUse->unicodeBidi() == Plaintext && !resolver.context()->parent()) {
1585 TextDirection direction = styleToUse->direction();
leviw@chromium.orge7812f32012-02-07 23:46:40 +00001586 determineDirectionality(direction, resolver.position());
rniwa@webkit.orgc275acf2012-03-05 23:09:22 +00001587 resolver.setStatus(BidiStatus(direction, isOverride(styleToUse->unicodeBidi())));
leviw@chromium.org7781b6a2011-06-27 22:01:38 +00001588 }
eric@webkit.org060caf62011-05-03 22:11:39 +00001589 // FIXME: This ownership is reversed. We should own the BidiRunList and pass it to createBidiRunsForLine.
1590 BidiRunList<BidiRun>& bidiRuns = resolver.runs();
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00001591 constructBidiRunsForLine(this, resolver, bidiRuns, end, override, layoutState.lineInfo().previousLineBrokeCleanly());
eric@webkit.org060caf62011-05-03 22:11:39 +00001592 ASSERT(resolver.position() == end);
1593
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001594 BidiRun* trailingSpaceRun = !layoutState.lineInfo().previousLineBrokeCleanly() ? handleTrailingSpaces(bidiRuns, resolver.context()) : 0;
eric@webkit.org060caf62011-05-03 22:11:39 +00001595
mitz@apple.com10ed3cb2011-09-07 20:59:39 +00001596 if (bidiRuns.runCount() && lineBreaker.lineWasHyphenated()) {
eric@webkit.org45e33a52011-05-04 11:51:09 +00001597 bidiRuns.logicallyLastRun()->m_hasHyphen = true;
mitz@apple.com10ed3cb2011-09-07 20:59:39 +00001598 consecutiveHyphenatedLines++;
1599 } else
1600 consecutiveHyphenatedLines = 0;
eric@webkit.org45e33a52011-05-04 11:51:09 +00001601
eric@webkit.org060caf62011-05-03 22:11:39 +00001602 // Now that the runs have been ordered, we create the line boxes.
1603 // At the same time we figure out where border/padding/margin should be applied for
1604 // inline flow boxes.
1605
eae@chromium.orgee8613e2011-11-12 01:12:58 +00001606 LayoutUnit oldLogicalHeight = logicalHeight();
enrica@apple.com885c84d2012-10-10 05:48:51 +00001607 RootInlineBox* lineBox = createLineBoxesFromBidiRuns(bidiRuns, end, layoutState.lineInfo(), verticalPositionCache, trailingSpaceRun, wordMeasurements);
eric@webkit.org060caf62011-05-03 22:11:39 +00001608
1609 bidiRuns.deleteRuns();
1610 resolver.markCurrentRunEmpty(); // FIXME: This can probably be replaced by an ASSERT (or just removed).
1611
1612 if (lineBox) {
1613 lineBox->setLineBreakInfo(end.m_obj, end.m_pos, resolver.status());
commit-queue@webkit.org49ad4732011-07-15 07:23:01 +00001614 if (layoutState.usesRepaintBounds())
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001615 layoutState.updateRepaintRangeFromBox(lineBox);
eric@webkit.org060caf62011-05-03 22:11:39 +00001616
1617 if (paginated) {
eae@chromium.orgee8613e2011-11-12 01:12:58 +00001618 LayoutUnit adjustment = 0;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001619 // FIXME-BLOCKFLOW: Remove this type conversion once the owning function moves.
1620 toRenderBlockFlow(this)->adjustLinePositionForPagination(lineBox, adjustment, layoutState.flowThread());
eric@webkit.org060caf62011-05-03 22:11:39 +00001621 if (adjustment) {
eae@chromium.orgee8613e2011-11-12 01:12:58 +00001622 LayoutUnit oldLineWidth = availableLogicalWidthForLine(oldLogicalHeight, layoutState.lineInfo().isFirstLine());
eric@webkit.org060caf62011-05-03 22:11:39 +00001623 lineBox->adjustBlockDirectionPosition(adjustment);
commit-queue@webkit.org49ad4732011-07-15 07:23:01 +00001624 if (layoutState.usesRepaintBounds())
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001625 layoutState.updateRepaintRangeFromBox(lineBox);
eric@webkit.org060caf62011-05-03 22:11:39 +00001626
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001627 if (availableLogicalWidthForLine(oldLogicalHeight + adjustment, layoutState.lineInfo().isFirstLine()) != oldLineWidth) {
eric@webkit.org060caf62011-05-03 22:11:39 +00001628 // We have to delete this line, remove all floats that got added, and let line layout re-run.
1629 lineBox->deleteLine(renderArena());
commit-queue@webkit.org4055b2e2012-12-06 19:05:15 +00001630 end = restartLayoutRunsAndFloatsInRange(oldLogicalHeight, oldLogicalHeight + adjustment, lastFloatFromPreviousLine, resolver, oldEnd);
eric@webkit.org060caf62011-05-03 22:11:39 +00001631 continue;
1632 }
1633
hyatt@apple.com7ce0d422011-08-30 16:57:37 +00001634 setLogicalHeight(lineBox->lineBottomWithLeading());
eric@webkit.org060caf62011-05-03 22:11:39 +00001635 }
commit-queue@webkit.orgbe554b22012-11-26 20:00:49 +00001636
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00001637 if (layoutState.flowThread())
commit-queue@webkit.orgbe554b22012-11-26 20:00:49 +00001638 lineBox->setContainingRegion(regionAtBlockOffset(lineBox->lineTopWithLeading()));
eric@webkit.org060caf62011-05-03 22:11:39 +00001639 }
1640 }
robert@webkit.org402c1512013-02-07 18:48:39 +00001641 }
eric@webkit.org060caf62011-05-03 22:11:39 +00001642
robert@webkit.org402c1512013-02-07 18:48:39 +00001643 for (size_t i = 0; i < lineBreaker.positionedObjects().size(); ++i)
1644 setStaticPositions(this, lineBreaker.positionedObjects()[i]);
eric@webkit.org060caf62011-05-03 22:11:39 +00001645
robert@webkit.org402c1512013-02-07 18:48:39 +00001646 if (!layoutState.lineInfo().isEmpty()) {
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001647 layoutState.lineInfo().setFirstLine(false);
leviw@chromium.org1a508692011-05-05 00:01:11 +00001648 newLine(lineBreaker.clear());
eric@webkit.org060caf62011-05-03 22:11:39 +00001649 }
1650
1651 if (m_floatingObjects && lastRootBox()) {
hyatt@apple.com46c65b32011-08-09 19:13:45 +00001652 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
darin@apple.com7cad7042013-09-24 05:53:55 +00001653 auto it = floatingObjectSet.begin();
1654 auto end = floatingObjectSet.end();
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001655 if (layoutState.lastFloat()) {
darin@apple.com7cad7042013-09-24 05:53:55 +00001656 auto lastFloatIterator = floatingObjectSet.find<FloatingObject&, FloatingObjectHashTranslator>(*layoutState.lastFloat());
eric@webkit.org060caf62011-05-03 22:11:39 +00001657 ASSERT(lastFloatIterator != end);
1658 ++lastFloatIterator;
1659 it = lastFloatIterator;
1660 }
1661 for (; it != end; ++it) {
darin@apple.com7cad7042013-09-24 05:53:55 +00001662 FloatingObject* f = it->get();
eric@webkit.org060caf62011-05-03 22:11:39 +00001663 appendFloatingObjectToLastLine(f);
darin@apple.com7cad7042013-09-24 05:53:55 +00001664 ASSERT(&f->renderer() == layoutState.floats()[layoutState.floatIndex()].object);
eric@webkit.org060caf62011-05-03 22:11:39 +00001665 // If a float's geometry has changed, give up on syncing with clean lines.
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001666 if (layoutState.floats()[layoutState.floatIndex()].rect != f->frameRect())
eric@webkit.org060caf62011-05-03 22:11:39 +00001667 checkForEndLineMatch = false;
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001668 layoutState.setFloatIndex(layoutState.floatIndex() + 1);
eric@webkit.org060caf62011-05-03 22:11:39 +00001669 }
darin@apple.com7cad7042013-09-24 05:53:55 +00001670 layoutState.setLastFloat(!floatingObjectSet.isEmpty() ? floatingObjectSet.last().get() : nullptr);
eric@webkit.org060caf62011-05-03 22:11:39 +00001671 }
1672
1673 lineMidpointState.reset();
rniwa@webkit.org53d106b2011-11-30 22:33:20 +00001674 resolver.setPosition(end, numberOfIsolateAncestors(end));
eric@webkit.org060caf62011-05-03 22:11:39 +00001675 }
dino@apple.comfde5fdf2012-12-10 21:22:44 +00001676
abucur@adobe.comfc497132013-10-04 08:49:21 +00001677 // In case we already adjusted the line positions during this layout to avoid widows
1678 // then we need to ignore the possibility of having a new widows situation.
1679 // Otherwise, we risk leaving empty containers which is against the block fragmentation principles.
1680 // FIXME-BLOCKFLOW: Remove this type conversion once the owning function moves.
1681 if (paginated && !style()->hasAutoWidows() && !toRenderBlockFlow(this)->didBreakAtLineToAvoidWidow()) {
dino@apple.comfde5fdf2012-12-10 21:22:44 +00001682 // Check the line boxes to make sure we didn't create unacceptable widows.
1683 // However, we'll prioritize orphans - so nothing we do here should create
1684 // a new orphan.
1685
1686 RootInlineBox* lineBox = lastRootBox();
1687
1688 // Count from the end of the block backwards, to see how many hanging
1689 // lines we have.
1690 RootInlineBox* firstLineInBlock = firstRootBox();
1691 int numLinesHanging = 1;
1692 while (lineBox && lineBox != firstLineInBlock && !lineBox->isFirstAfterPageBreak()) {
1693 ++numLinesHanging;
1694 lineBox = lineBox->prevRootBox();
1695 }
1696
1697 // If there were no breaks in the block, we didn't create any widows.
jchaffraix@webkit.org0f225142013-01-28 22:28:21 +00001698 if (!lineBox || !lineBox->isFirstAfterPageBreak() || lineBox == firstLineInBlock)
dino@apple.comfde5fdf2012-12-10 21:22:44 +00001699 return;
1700
1701 if (numLinesHanging < style()->widows()) {
1702 // We have detected a widow. Now we need to work out how many
1703 // lines there are on the previous page, and how many we need
1704 // to steal.
1705 int numLinesNeeded = style()->widows() - numLinesHanging;
1706 RootInlineBox* currentFirstLineOfNewPage = lineBox;
1707
1708 // Count the number of lines in the previous page.
1709 lineBox = lineBox->prevRootBox();
1710 int numLinesInPreviousPage = 1;
1711 while (lineBox && lineBox != firstLineInBlock && !lineBox->isFirstAfterPageBreak()) {
1712 ++numLinesInPreviousPage;
1713 lineBox = lineBox->prevRootBox();
1714 }
1715
1716 // If there was an explicit value for orphans, respect that. If not, we still
1717 // shouldn't create a situation where we make an orphan bigger than the initial value.
1718 // This means that setting widows implies we also care about orphans, but given
1719 // the specification says the initial orphan value is non-zero, this is ok. The
1720 // author is always free to set orphans explicitly as well.
1721 int orphans = style()->hasAutoOrphans() ? style()->initialOrphans() : style()->orphans();
1722 int numLinesAvailable = numLinesInPreviousPage - orphans;
1723 if (numLinesAvailable <= 0)
1724 return;
1725
1726 int numLinesToTake = min(numLinesAvailable, numLinesNeeded);
1727 // Wind back from our first widowed line.
1728 lineBox = currentFirstLineOfNewPage;
1729 for (int i = 0; i < numLinesToTake; ++i)
1730 lineBox = lineBox->prevRootBox();
1731
1732 // We now want to break at this line. Remember for next layout and trigger relayout.
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001733 // FIXME-BLOCKFLOW: Remove this type conversion once the owning function moves.
1734 toRenderBlockFlow(this)->setBreakAtLineToAvoidWidow(lineCount(lineBox));
dino@apple.comfde5fdf2012-12-10 21:22:44 +00001735 markLinesDirtyInBlockRange(lastRootBox()->lineBottomWithLeading(), lineBox->lineBottomWithLeading(), lineBox);
1736 }
1737 }
abucur@adobe.comfc497132013-10-04 08:49:21 +00001738
1739 // FIXME-BLOCKFLOW: Remove this type conversion once the owning function moves.
1740 toRenderBlockFlow(this)->clearDidBreakAtLineToAvoidWidow();
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001741}
eric@webkit.org060caf62011-05-03 22:11:39 +00001742
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001743void RenderBlock::linkToEndLineIfNeeded(LineLayoutState& layoutState)
1744{
1745 if (layoutState.endLine()) {
1746 if (layoutState.endLineMatched()) {
akling@apple.com691cf5c2013-08-24 16:33:15 +00001747 bool paginated = view().layoutState() && view().layoutState()->isPaginated();
eric@webkit.org060caf62011-05-03 22:11:39 +00001748 // Attach all the remaining lines, and then adjust their y-positions as needed.
eae@chromium.orgee8613e2011-11-12 01:12:58 +00001749 LayoutUnit delta = logicalHeight() - layoutState.endLineLogicalTop();
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001750 for (RootInlineBox* line = layoutState.endLine(); line; line = line->nextRootBox()) {
eric@webkit.org060caf62011-05-03 22:11:39 +00001751 line->attachLine();
1752 if (paginated) {
1753 delta -= line->paginationStrut();
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001754 // FIXME-BLOCKFLOW: Remove this type conversion once the owning function moves.
1755 toRenderBlockFlow(this)->adjustLinePositionForPagination(line, delta, layoutState.flowThread());
eric@webkit.org060caf62011-05-03 22:11:39 +00001756 }
1757 if (delta) {
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001758 layoutState.updateRepaintRangeFromBox(line, delta);
eric@webkit.org060caf62011-05-03 22:11:39 +00001759 line->adjustBlockDirectionPosition(delta);
1760 }
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00001761 if (layoutState.flowThread())
commit-queue@webkit.orgbe554b22012-11-26 20:00:49 +00001762 line->setContainingRegion(regionAtBlockOffset(line->lineTopWithLeading()));
eric@webkit.org060caf62011-05-03 22:11:39 +00001763 if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) {
1764 Vector<RenderBox*>::iterator end = cleanLineFloats->end();
1765 for (Vector<RenderBox*>::iterator f = cleanLineFloats->begin(); f != end; ++f) {
mitz@apple.com0c4ce9f2011-05-04 02:20:02 +00001766 FloatingObject* floatingObject = insertFloatingObject(*f);
bjonesbe@adobe.coma9c66662013-08-14 20:30:14 +00001767 ASSERT(!floatingObject->originatingLine());
1768 floatingObject->setOriginatingLine(line);
eric@webkit.org060caf62011-05-03 22:11:39 +00001769 setLogicalHeight(logicalTopForChild(*f) - marginBeforeForChild(*f) + delta);
1770 positionNewFloats();
1771 }
1772 }
1773 }
hyatt@apple.com7ce0d422011-08-30 16:57:37 +00001774 setLogicalHeight(lastRootBox()->lineBottomWithLeading());
eric@webkit.org060caf62011-05-03 22:11:39 +00001775 } else {
1776 // Delete all the remaining lines.
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001777 deleteLineRange(layoutState, renderArena(), layoutState.endLine());
eric@webkit.org060caf62011-05-03 22:11:39 +00001778 }
1779 }
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001780
1781 if (m_floatingObjects && (layoutState.checkForFloatsFromLastLine() || positionNewFloats()) && lastRootBox()) {
eric@webkit.org060caf62011-05-03 22:11:39 +00001782 // In case we have a float on the last line, it might not be positioned up to now.
1783 // This has to be done before adding in the bottom border/padding, or the float will
1784 // include the padding incorrectly. -dwh
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001785 if (layoutState.checkForFloatsFromLastLine()) {
leviw@chromium.orgd32486e2012-03-16 10:52:56 +00001786 LayoutUnit bottomVisualOverflow = lastRootBox()->logicalBottomVisualOverflow();
1787 LayoutUnit bottomLayoutOverflow = lastRootBox()->logicalBottomLayoutOverflow();
akling@apple.com0b8172b72013-08-31 18:34:23 +00001788 TrailingFloatsRootInlineBox* trailingFloatsLineBox = new (renderArena()) TrailingFloatsRootInlineBox(*this);
eric@webkit.org060caf62011-05-03 22:11:39 +00001789 m_lineBoxes.appendLineBox(trailingFloatsLineBox);
1790 trailingFloatsLineBox->setConstructed();
1791 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
1792 VerticalPositionCache verticalPositionCache;
leviw@chromium.orgd32486e2012-03-16 10:52:56 +00001793 LayoutUnit blockLogicalHeight = logicalHeight();
hyatt@apple.coma8b5b822011-09-07 18:48:07 +00001794 trailingFloatsLineBox->alignBoxesInBlockDirection(blockLogicalHeight, textBoxDataMap, verticalPositionCache);
1795 trailingFloatsLineBox->setLineTopBottomPositions(blockLogicalHeight, blockLogicalHeight, blockLogicalHeight, blockLogicalHeight);
hyatt@apple.com0c6cd7a2011-09-22 20:50:41 +00001796 trailingFloatsLineBox->setPaginatedLineWidth(availableLogicalWidthForContent(blockLogicalHeight));
leviw@chromium.orgd32486e2012-03-16 10:52:56 +00001797 LayoutRect logicalLayoutOverflow(0, blockLogicalHeight, 1, bottomLayoutOverflow - blockLogicalHeight);
1798 LayoutRect logicalVisualOverflow(0, blockLogicalHeight, 1, bottomVisualOverflow - blockLogicalHeight);
eric@webkit.org060caf62011-05-03 22:11:39 +00001799 trailingFloatsLineBox->setOverflowFromLogicalRects(logicalLayoutOverflow, logicalVisualOverflow, trailingFloatsLineBox->lineTop(), trailingFloatsLineBox->lineBottom());
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00001800 if (layoutState.flowThread())
commit-queue@webkit.orgbe554b22012-11-26 20:00:49 +00001801 trailingFloatsLineBox->setContainingRegion(regionAtBlockOffset(trailingFloatsLineBox->lineTopWithLeading()));
eric@webkit.org060caf62011-05-03 22:11:39 +00001802 }
1803
hyatt@apple.com46c65b32011-08-09 19:13:45 +00001804 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
darin@apple.com7cad7042013-09-24 05:53:55 +00001805 auto it = floatingObjectSet.begin();
1806 auto end = floatingObjectSet.end();
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001807 if (layoutState.lastFloat()) {
darin@apple.com7cad7042013-09-24 05:53:55 +00001808 auto lastFloatIterator = floatingObjectSet.find<FloatingObject&, FloatingObjectHashTranslator>(*layoutState.lastFloat());
eric@webkit.org060caf62011-05-03 22:11:39 +00001809 ASSERT(lastFloatIterator != end);
1810 ++lastFloatIterator;
1811 it = lastFloatIterator;
1812 }
1813 for (; it != end; ++it)
darin@apple.com7cad7042013-09-24 05:53:55 +00001814 appendFloatingObjectToLastLine(it->get());
1815 layoutState.setLastFloat(!floatingObjectSet.isEmpty() ? floatingObjectSet.last().get() : nullptr);
eric@webkit.org060caf62011-05-03 22:11:39 +00001816 }
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001817}
1818
1819void RenderBlock::repaintDirtyFloats(Vector<FloatWithRect>& floats)
1820{
eric@webkit.org060caf62011-05-03 22:11:39 +00001821 size_t floatCount = floats.size();
1822 // Floats that did not have layout did not repaint when we laid them out. They would have
1823 // painted by now if they had moved, but if they stayed at (0, 0), they still need to be
1824 // painted.
1825 for (size_t i = 0; i < floatCount; ++i) {
1826 if (!floats[i].everHadLayout) {
1827 RenderBox* f = floats[i].object;
1828 if (!f->x() && !f->y() && f->checkForRepaintDuringLayout())
1829 f->repaint();
1830 }
1831 }
1832}
1833
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +00001834void RenderBlockFlow::layoutInlineChildren(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
jamesr@google.com19548ad2010-04-02 23:21:35 +00001835{
zoltan@webkit.org8e79cc22013-06-14 00:39:36 +00001836 setLogicalHeight(borderAndPaddingBefore());
hyatt@apple.comee7af1d2012-01-17 19:16:24 +00001837
1838 // Lay out our hypothetical grid line as though it occurs at the top of the block.
akling@apple.com691cf5c2013-08-24 16:33:15 +00001839 if (view().layoutState() && view().layoutState()->lineGrid() == this)
hyatt@apple.comee7af1d2012-01-17 19:16:24 +00001840 layoutLineGridBox();
mitz@apple.come1364202008-02-28 01:06:41 +00001841
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00001842 RenderFlowThread* flowThread = flowThreadContainingBlock();
1843 bool clearLinesForPagination = firstLineBox() && flowThread && !flowThread->hasRegions();
commit-queue@webkit.org93cdd632012-12-07 00:33:56 +00001844
hyatt0c3a9862004-02-23 21:26:26 +00001845 // Figure out if we should clear out our line boxes.
1846 // FIXME: Handle resize eventually!
commit-queue@webkit.org93cdd632012-12-07 00:33:56 +00001847 bool isFullLayout = !firstLineBox() || selfNeedsLayout() || relayoutChildren || clearLinesForPagination;
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00001848 LineLayoutState layoutState(isFullLayout, repaintLogicalTop, repaintLogicalBottom, flowThread);
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001849
1850 if (isFullLayout)
akling@apple.com06262e02013-09-08 11:02:24 +00001851 lineBoxes().deleteLineBoxes(renderArena());
mitz@apple.come1364202008-02-28 01:06:41 +00001852
commit-queue@webkit.org07797312013-02-22 18:58:19 +00001853 // Text truncation kicks in in two cases:
1854 // 1) If your overflow isn't visible and your text-overflow-mode isn't clip.
1855 // 2) If you're an anonymous block with a block parent that satisfies #1.
hyatted77ad82004-06-15 07:21:23 +00001856 // 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 +00001857 // difficult to figure out in general (especially in the middle of doing layout), so we only handle the
1858 // simple case of an anonymous block truncating when it's parent is clipped.
1859 bool hasTextOverflow = (style()->textOverflow() && hasOverflowClip())
1860 || (isAnonymousBlock() && parent() && parent()->isRenderBlock() && parent()->style()->textOverflow() && parent()->hasOverflowClip());
mitz@apple.come1364202008-02-28 01:06:41 +00001861
hyatted77ad82004-06-15 07:21:23 +00001862 // Walk all the lines and delete our ellipsis line boxes if they exist.
1863 if (hasTextOverflow)
1864 deleteEllipsisLineBoxes();
1865
hyattffe78712003-02-11 01:59:29 +00001866 if (firstChild()) {
inferno@chromium.org13563122012-08-16 20:50:05 +00001867 // In full layout mode, clear the line boxes of children upfront. Otherwise,
1868 // siblings can run into stale root lineboxes during layout. Then layout
1869 // the replaced elements later. In partial layout mode, line boxes are not
1870 // deleted and only dirtied. In that case, we can layout the replaced
1871 // elements at the same time.
abarth@webkit.org31d23df2010-04-05 21:52:09 +00001872 bool hasInlineChild = false;
inferno@chromium.org13563122012-08-16 20:50:05 +00001873 Vector<RenderBox*> replacedChildren;
eric@webkit.org33510472011-06-04 19:34:29 +00001874 for (InlineWalker walker(this); !walker.atEnd(); walker.advance()) {
1875 RenderObject* o = walker.current();
abucur@adobe.com33159da2013-08-13 07:44:32 +00001876
commit-queue@webkit.orgcf45df92010-09-14 13:25:06 +00001877 if (!hasInlineChild && o->isInline())
1878 hasInlineChild = true;
1879
simon.fraser@apple.com2f071852012-06-25 00:11:30 +00001880 if (o->isReplaced() || o->isFloating() || o->isOutOfFlowPositioned()) {
abarth@webkit.org31d23df2010-04-05 21:52:09 +00001881 RenderBox* box = toRenderBox(o);
eric@webkit.org060caf62011-05-03 22:11:39 +00001882
commit-queue@webkit.orgb6cbe4f2012-02-28 16:01:19 +00001883 if (relayoutChildren || box->hasRelativeDimensions())
antti@apple.comca2a8ff2013-10-04 04:04:35 +00001884 box->setChildNeedsLayout(MarkOnlyThis);
eric@webkit.org060caf62011-05-03 22:11:39 +00001885
zimmermann@webkit.orgac68af42011-06-15 08:02:37 +00001886 // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
1887 if (relayoutChildren && box->needsPreferredWidthsRecalculation())
eric@webkit.org218b4e02012-03-28 19:25:02 +00001888 o->setPreferredLogicalWidthsDirty(true, MarkOnlyThis);
eric@webkit.org060caf62011-05-03 22:11:39 +00001889
simon.fraser@apple.com2f071852012-06-25 00:11:30 +00001890 if (o->isOutOfFlowPositioned())
abarth@webkit.org31d23df2010-04-05 21:52:09 +00001891 o->containingBlock()->insertPositionedObject(box);
hyatt@apple.comcc1737c2010-09-16 20:20:02 +00001892 else if (o->isFloating())
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001893 layoutState.floats().append(FloatWithRect(box));
inferno@chromium.org13563122012-08-16 20:50:05 +00001894 else if (isFullLayout || o->needsLayout()) {
1895 // Replaced element.
1896 box->dirtyLineBoxes(isFullLayout);
1897 if (isFullLayout)
1898 replacedChildren.append(box);
1899 else
1900 o->layoutIfNeeded();
abarth@webkit.org31d23df2010-04-05 21:52:09 +00001901 }
antti@apple.com3014ac02013-09-18 14:33:55 +00001902 } else if (o->isTextOrLineBreak() || (o->isRenderInline() && !walker.atEndOfInline())) {
antti@apple.com9d8157e2013-09-17 15:13:37 +00001903 if (o->isRenderInline())
inferno@chromium.org88a424d2011-08-09 18:18:36 +00001904 toRenderInline(o)->updateAlwaysCreateLineBoxes(layoutState.isFullLayout());
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001905 if (layoutState.isFullLayout() || o->selfNeedsLayout())
1906 dirtyLineBoxesForRenderer(o, layoutState.isFullLayout());
antti@apple.comca2a8ff2013-10-04 04:04:35 +00001907 o->clearNeedsLayout();
abarth@webkit.org31d23df2010-04-05 21:52:09 +00001908 }
abarth@webkit.org31d23df2010-04-05 21:52:09 +00001909 }
1910
inferno@chromium.orgba2dceb2012-08-21 00:09:47 +00001911 for (size_t i = 0; i < replacedChildren.size(); i++)
1912 replacedChildren[i]->layoutIfNeeded();
inferno@chromium.org13563122012-08-16 20:50:05 +00001913
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001914 layoutRunsAndFloats(layoutState, hasInlineChild);
kociendabb0c24b2001-08-24 14:24:40 +00001915 }
hyatt85586af2003-02-19 23:22:42 +00001916
mitz@apple.com3672d9e2010-12-17 19:31:16 +00001917 // Expand the last line to accommodate Ruby and emphasis marks.
1918 int lastLineAnnotationsAdjustment = 0;
1919 if (lastRootBox()) {
leviw@chromium.orgd32486e2012-03-16 10:52:56 +00001920 LayoutUnit lowestAllowedPosition = max(lastRootBox()->lineBottom(), logicalHeight() + paddingAfter());
mitz@apple.com3672d9e2010-12-17 19:31:16 +00001921 if (!style()->isFlippedLinesWritingMode())
1922 lastLineAnnotationsAdjustment = lastRootBox()->computeUnderAnnotationAdjustment(lowestAllowedPosition);
1923 else
1924 lastLineAnnotationsAdjustment = lastRootBox()->computeOverAnnotationAdjustment(lowestAllowedPosition);
hyatt@apple.com5e48ff52010-11-19 00:43:29 +00001925 }
mitz@apple.com3672d9e2010-12-17 19:31:16 +00001926
hyatta70560a2002-11-20 01:53:20 +00001927 // Now add in the bottom border/padding.
zoltan@webkit.org8e79cc22013-06-14 00:39:36 +00001928 setLogicalHeight(logicalHeight() + lastLineAnnotationsAdjustment + borderAndPaddingAfter() + scrollbarLogicalHeight());
kociendabb0c24b2001-08-24 14:24:40 +00001929
adele7a470a72006-04-20 22:22:14 +00001930 if (!firstLineBox() && hasLineIfEmpty())
hyatt@apple.com2a5eb212011-03-22 23:21:54 +00001931 setLogicalHeight(logicalHeight() + lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
hyatted77ad82004-06-15 07:21:23 +00001932
1933 // See if we have any lines that spill out of our block. If we do, then we will possibly need to
1934 // truncate text.
1935 if (hasTextOverflow)
1936 checkLinesForTextOverflow();
kociendabb0c24b2001-08-24 14:24:40 +00001937}
1938
mitz@apple.comd9ccfeb2011-03-10 01:56:27 +00001939void RenderBlock::checkFloatsInCleanLine(RootInlineBox* line, Vector<FloatWithRect>& floats, size_t& floatIndex, bool& encounteredNewFloat, bool& dirtiedByFloat)
1940{
1941 Vector<RenderBox*>* cleanLineFloats = line->floatsPtr();
1942 if (!cleanLineFloats)
1943 return;
1944
1945 Vector<RenderBox*>::iterator end = cleanLineFloats->end();
1946 for (Vector<RenderBox*>::iterator it = cleanLineFloats->begin(); it != end; ++it) {
1947 RenderBox* floatingBox = *it;
1948 floatingBox->layoutIfNeeded();
tkent@chromium.orgb27646b2012-03-08 03:31:25 +00001949 LayoutSize newSize(floatingBox->width() + floatingBox->marginWidth(), floatingBox->height() + floatingBox->marginHeight());
inferno@chromium.orga227be62013-02-11 08:06:45 +00001950 ASSERT_WITH_SECURITY_IMPLICATION(floatIndex < floats.size());
mitz@apple.comd9ccfeb2011-03-10 01:56:27 +00001951 if (floats[floatIndex].object != floatingBox) {
1952 encounteredNewFloat = true;
1953 return;
1954 }
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001955
mitz@apple.comd9ccfeb2011-03-10 01:56:27 +00001956 if (floats[floatIndex].rect.size() != newSize) {
eae@chromium.orgee8613e2011-11-12 01:12:58 +00001957 LayoutUnit floatTop = isHorizontalWritingMode() ? floats[floatIndex].rect.y() : floats[floatIndex].rect.x();
1958 LayoutUnit floatHeight = isHorizontalWritingMode() ? max(floats[floatIndex].rect.height(), newSize.height())
mitz@apple.comd9ccfeb2011-03-10 01:56:27 +00001959 : max(floats[floatIndex].rect.width(), newSize.width());
eae@chromium.org9717cd82012-11-07 18:33:44 +00001960 floatHeight = min(floatHeight, LayoutUnit::max() - floatTop);
mitz@apple.comd9ccfeb2011-03-10 01:56:27 +00001961 line->markDirty();
hyatt@apple.com7ce0d422011-08-30 16:57:37 +00001962 markLinesDirtyInBlockRange(line->lineBottomWithLeading(), floatTop + floatHeight, line);
mitz@apple.comd9ccfeb2011-03-10 01:56:27 +00001963 floats[floatIndex].rect.setSize(newSize);
1964 dirtiedByFloat = true;
1965 }
1966 floatIndex++;
1967 }
1968}
1969
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001970RootInlineBox* RenderBlock::determineStartPosition(LineLayoutState& layoutState, InlineBidiResolver& resolver)
hyatt0c3a9862004-02-23 21:26:26 +00001971{
1972 RootInlineBox* curr = 0;
1973 RootInlineBox* last = 0;
mitz@apple.come1364202008-02-28 01:06:41 +00001974
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001975 // FIXME: This entire float-checking block needs to be broken into a new function.
mitz@apple.com40547b32008-03-18 04:04:34 +00001976 bool dirtiedByFloat = false;
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001977 if (!layoutState.isFullLayout()) {
hyatt@apple.comcc1737c2010-09-16 20:20:02 +00001978 // Paginate all of the clean lines.
akling@apple.com691cf5c2013-08-24 16:33:15 +00001979 bool paginated = view().layoutState() && view().layoutState()->isPaginated();
eae@chromium.orgee8613e2011-11-12 01:12:58 +00001980 LayoutUnit paginationDelta = 0;
mitz@apple.com40547b32008-03-18 04:04:34 +00001981 size_t floatIndex = 0;
1982 for (curr = firstRootBox(); curr && !curr->isDirty(); curr = curr->nextRootBox()) {
hyatt@apple.comcc1737c2010-09-16 20:20:02 +00001983 if (paginated) {
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00001984 if (lineWidthForPaginatedLineChanged(curr, 0, layoutState.flowThread())) {
hyatt@apple.com0c6cd7a2011-09-22 20:50:41 +00001985 curr->markDirty();
1986 break;
1987 }
hyatt@apple.comcc1737c2010-09-16 20:20:02 +00001988 paginationDelta -= curr->paginationStrut();
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001989 // FIXME-BLOCKFLOW: Remove this type conversion once the owning function moves.
1990 toRenderBlockFlow(this)->adjustLinePositionForPagination(curr, paginationDelta, layoutState.flowThread());
hyatt@apple.comcc1737c2010-09-16 20:20:02 +00001991 if (paginationDelta) {
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00001992 if (containsFloats() || !layoutState.floats().isEmpty()) {
hyatt@apple.comcc1737c2010-09-16 20:20:02 +00001993 // 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 +00001994 layoutState.markForFullLayout();
hyatt@apple.comcc1737c2010-09-16 20:20:02 +00001995 break;
1996 }
eric@webkit.org060caf62011-05-03 22:11:39 +00001997
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00001998 layoutState.updateRepaintRangeFromBox(curr, paginationDelta);
hyatt@apple.com61bbedf2011-01-26 23:10:57 +00001999 curr->adjustBlockDirectionPosition(paginationDelta);
eric@webkit.org060caf62011-05-03 22:11:39 +00002000 }
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00002001 if (layoutState.flowThread())
commit-queue@webkit.orgbe554b22012-11-26 20:00:49 +00002002 curr->setContainingRegion(regionAtBlockOffset(curr->lineTopWithLeading()));
hyatt@apple.comcc1737c2010-09-16 20:20:02 +00002003 }
mitz@apple.comd9ccfeb2011-03-10 01:56:27 +00002004
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00002005 // If a new float has been inserted before this line or before its last known float, just do a full layout.
2006 bool encounteredNewFloat = false;
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002007 checkFloatsInCleanLine(curr, layoutState.floats(), floatIndex, encounteredNewFloat, dirtiedByFloat);
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00002008 if (encounteredNewFloat)
2009 layoutState.markForFullLayout();
2010
2011 if (dirtiedByFloat || layoutState.isFullLayout())
mitz@apple.com40547b32008-03-18 04:04:34 +00002012 break;
2013 }
2014 // Check if a new float has been inserted after the last known float.
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002015 if (!curr && floatIndex < layoutState.floats().size())
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00002016 layoutState.markForFullLayout();
mitz@apple.com40547b32008-03-18 04:04:34 +00002017 }
2018
eric@webkit.org59c3c1e2011-05-17 19:45:24 +00002019 if (layoutState.isFullLayout()) {
igor.o@sisa.samsung.comf6a57df2013-04-15 21:25:35 +00002020 m_lineBoxes.deleteLineBoxTree(renderArena());
2021 curr = 0;
2022
eric@webkit.orge2532d92011-05-16 23:10:49 +00002023 ASSERT(!firstLineBox() && !lastLineBox());
eseidel789896f2005-11-27 22:52:09 +00002024 } else {
hyatt0c3a9862004-02-23 21:26:26 +00002025 if (curr) {
2026 // We have a dirty line.
mjs9f78dd92007-02-12 04:06:07 +00002027 if (RootInlineBox* prevRootBox = curr->prevRootBox()) {
hyatt0c3a9862004-02-23 21:26:26 +00002028 // We have a previous line.
tasak@google.comfcfd96f2012-11-26 07:45:38 +00002029 if (!dirtiedByFloat && (!prevRootBox->endsWithBreak() || !prevRootBox->lineBreakObj() || (prevRootBox->lineBreakObj()->isText() && prevRootBox->lineBreakPos() >= toRenderText(prevRootBox->lineBreakObj())->textLength())))
mjs9f78dd92007-02-12 04:06:07 +00002030 // The previous line didn't break cleanly or broke at a newline
2031 // that has been deleted, so treat it as dirty too.
2032 curr = prevRootBox;
hyatt0c3a9862004-02-23 21:26:26 +00002033 }
eseidel789896f2005-11-27 22:52:09 +00002034 } else {
hyatt0c3a9862004-02-23 21:26:26 +00002035 // No dirty lines were found.
2036 // If the last line didn't break cleanly, treat it as dirty.
2037 if (lastRootBox() && !lastRootBox()->endsWithBreak())
2038 curr = lastRootBox();
2039 }
mitz@apple.come1364202008-02-28 01:06:41 +00002040
hyatt0c3a9862004-02-23 21:26:26 +00002041 // If we have no dirty lines, then last is just the last root box.
2042 last = curr ? curr->prevRootBox() : lastRootBox();
2043 }
mitz@apple.come1364202008-02-28 01:06:41 +00002044
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002045 unsigned numCleanFloats = 0;
2046 if (!layoutState.floats().isEmpty()) {
eae@chromium.orgee8613e2011-11-12 01:12:58 +00002047 LayoutUnit savedLogicalHeight = logicalHeight();
mitz@apple.com40547b32008-03-18 04:04:34 +00002048 // Restore floats from clean lines.
2049 RootInlineBox* line = firstRootBox();
2050 while (line != curr) {
hyatt@apple.comd885df72009-01-22 02:31:52 +00002051 if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) {
2052 Vector<RenderBox*>::iterator end = cleanLineFloats->end();
2053 for (Vector<RenderBox*>::iterator f = cleanLineFloats->begin(); f != end; ++f) {
mitz@apple.com0c4ce9f2011-05-04 02:20:02 +00002054 FloatingObject* floatingObject = insertFloatingObject(*f);
bjonesbe@adobe.coma9c66662013-08-14 20:30:14 +00002055 ASSERT(!floatingObject->originatingLine());
2056 floatingObject->setOriginatingLine(line);
hyatt@apple.com9a2e7d22010-10-06 22:13:31 +00002057 setLogicalHeight(logicalTopForChild(*f) - marginBeforeForChild(*f));
mitz@apple.com40547b32008-03-18 04:04:34 +00002058 positionNewFloats();
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002059 ASSERT(layoutState.floats()[numCleanFloats].object == *f);
mitz@apple.com40547b32008-03-18 04:04:34 +00002060 numCleanFloats++;
2061 }
2062 }
2063 line = line->nextRootBox();
2064 }
hyatt@apple.com9a2e7d22010-10-06 22:13:31 +00002065 setLogicalHeight(savedLogicalHeight);
mitz@apple.com40547b32008-03-18 04:04:34 +00002066 }
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002067 layoutState.setFloatIndex(numCleanFloats);
mitz@apple.com40547b32008-03-18 04:04:34 +00002068
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002069 layoutState.lineInfo().setFirstLine(!last);
2070 layoutState.lineInfo().setPreviousLineBrokeCleanly(!last || last->endsWithBreak());
mitz@apple.com1a301772008-03-11 18:30:36 +00002071
hyatt0c3a9862004-02-23 21:26:26 +00002072 if (last) {
hyatt@apple.com7ce0d422011-08-30 16:57:37 +00002073 setLogicalHeight(last->lineBottomWithLeading());
rniwa@webkit.org53d106b2011-11-30 22:33:20 +00002074 InlineIterator iter = InlineIterator(this, last->lineBreakObj(), last->lineBreakPos());
2075 resolver.setPosition(iter, numberOfIsolateAncestors(iter));
mitz@apple.com15035e62008-07-05 20:44:44 +00002076 resolver.setStatus(last->lineBreakBidiStatus());
darindde01502005-12-18 22:55:35 +00002077 } else {
leviw@chromium.org7781b6a2011-06-27 22:01:38 +00002078 TextDirection direction = style()->direction();
leviw@chromium.orge7812f32012-02-07 23:46:40 +00002079 if (style()->unicodeBidi() == Plaintext)
2080 determineDirectionality(direction, InlineIterator(this, bidiFirstSkippingEmptyInlines(this), 0));
rniwa@webkit.orgc275acf2012-03-05 23:09:22 +00002081 resolver.setStatus(BidiStatus(direction, isOverride(style()->unicodeBidi())));
rniwa@webkit.org53d106b2011-11-30 22:33:20 +00002082 InlineIterator iter = InlineIterator(this, bidiFirstSkippingEmptyInlines(this, &resolver), 0);
2083 resolver.setPosition(iter, numberOfIsolateAncestors(iter));
darindde01502005-12-18 22:55:35 +00002084 }
hyatt0c3a9862004-02-23 21:26:26 +00002085 return curr;
2086}
2087
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002088void RenderBlock::determineEndPosition(LineLayoutState& layoutState, RootInlineBox* startLine, InlineIterator& cleanLineStart, BidiStatus& cleanLineBidiStatus)
hyatt0c3a9862004-02-23 21:26:26 +00002089{
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002090 ASSERT(!layoutState.endLine());
2091 size_t floatIndex = layoutState.floatIndex();
hyatt0c3a9862004-02-23 21:26:26 +00002092 RootInlineBox* last = 0;
mitz@apple.comd9ccfeb2011-03-10 01:56:27 +00002093 for (RootInlineBox* curr = startLine->nextRootBox(); curr; curr = curr->nextRootBox()) {
2094 if (!curr->isDirty()) {
2095 bool encounteredNewFloat = false;
2096 bool dirtiedByFloat = false;
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002097 checkFloatsInCleanLine(curr, layoutState.floats(), floatIndex, encounteredNewFloat, dirtiedByFloat);
mitz@apple.comd9ccfeb2011-03-10 01:56:27 +00002098 if (encounteredNewFloat)
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002099 return;
hyatt04420ca2004-07-16 00:05:42 +00002100 }
mitz@apple.comd9ccfeb2011-03-10 01:56:27 +00002101 if (curr->isDirty())
2102 last = 0;
2103 else if (!last)
2104 last = curr;
hyatt0c3a9862004-02-23 21:26:26 +00002105 }
mitz@apple.come1364202008-02-28 01:06:41 +00002106
hyatt0c3a9862004-02-23 21:26:26 +00002107 if (!last)
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002108 return;
mitz@apple.come1364202008-02-28 01:06:41 +00002109
mitz@apple.comd9ccfeb2011-03-10 01:56:27 +00002110 // At this point, |last| is the first line in a run of clean lines that ends with the last line
2111 // in the block.
2112
eseidel789896f2005-11-27 22:52:09 +00002113 RootInlineBox* prev = last->prevRootBox();
mitz@apple.com15035e62008-07-05 20:44:44 +00002114 cleanLineStart = InlineIterator(this, prev->lineBreakObj(), prev->lineBreakPos());
eseidel789896f2005-11-27 22:52:09 +00002115 cleanLineBidiStatus = prev->lineBreakBidiStatus();
hyatt@apple.com7ce0d422011-08-30 16:57:37 +00002116 layoutState.setEndLineLogicalTop(prev->lineBottomWithLeading());
mitz@apple.come1364202008-02-28 01:06:41 +00002117
hyatt0c3a9862004-02-23 21:26:26 +00002118 for (RootInlineBox* line = last; line; line = line->nextRootBox())
2119 line->extractLine(); // Disconnect all line boxes from their render objects while preserving
2120 // their connections to one another.
mitz@apple.come1364202008-02-28 01:06:41 +00002121
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002122 layoutState.setEndLine(last);
hyatt0c3a9862004-02-23 21:26:26 +00002123}
2124
hyatt@apple.coma10d30e2011-09-22 22:28:21 +00002125bool RenderBlock::checkPaginationAndFloatsAtEndLine(LineLayoutState& layoutState)
2126{
2127 LayoutUnit lineDelta = logicalHeight() - layoutState.endLineLogicalTop();
2128
akling@apple.com691cf5c2013-08-24 16:33:15 +00002129 bool paginated = view().layoutState() && view().layoutState()->isPaginated();
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00002130 if (paginated && layoutState.flowThread()) {
hyatt@apple.coma10d30e2011-09-22 22:28:21 +00002131 // Check all lines from here to the end, and see if the hypothetical new position for the lines will result
2132 // in a different available line width.
2133 for (RootInlineBox* lineBox = layoutState.endLine(); lineBox; lineBox = lineBox->nextRootBox()) {
2134 if (paginated) {
2135 // This isn't the real move we're going to do, so don't update the line box's pagination
2136 // strut yet.
2137 LayoutUnit oldPaginationStrut = lineBox->paginationStrut();
2138 lineDelta -= oldPaginationStrut;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00002139 // FIXME-BLOCKFLOW: Remove this type conversion once the owning function moves.
2140 toRenderBlockFlow(this)->adjustLinePositionForPagination(lineBox, lineDelta, layoutState.flowThread());
hyatt@apple.coma10d30e2011-09-22 22:28:21 +00002141 lineBox->setPaginationStrut(oldPaginationStrut);
2142 }
hyatt@apple.comfd6f22e2013-03-01 21:44:06 +00002143 if (lineWidthForPaginatedLineChanged(lineBox, lineDelta, layoutState.flowThread()))
hyatt@apple.coma10d30e2011-09-22 22:28:21 +00002144 return false;
2145 }
2146 }
2147
2148 if (!lineDelta || !m_floatingObjects)
2149 return true;
2150
2151 // 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 +00002152 LayoutUnit logicalTop = min(logicalHeight(), layoutState.endLineLogicalTop());
hyatt@apple.coma10d30e2011-09-22 22:28:21 +00002153
2154 RootInlineBox* lastLine = layoutState.endLine();
2155 while (RootInlineBox* nextLine = lastLine->nextRootBox())
2156 lastLine = nextLine;
2157
leviw@chromium.org3957b452012-05-01 00:06:37 +00002158 LayoutUnit logicalBottom = lastLine->lineBottomWithLeading() + absoluteValue(lineDelta);
hyatt@apple.coma10d30e2011-09-22 22:28:21 +00002159
2160 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
darin@apple.com7cad7042013-09-24 05:53:55 +00002161 auto end = floatingObjectSet.end();
2162 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2163 FloatingObject* f = it->get();
bjonesbe@adobe.com93de7e72013-09-04 18:01:27 +00002164 if (f->logicalBottom(isHorizontalWritingMode()) >= logicalTop && f->logicalBottom(isHorizontalWritingMode()) < logicalBottom)
hyatt@apple.coma10d30e2011-09-22 22:28:21 +00002165 return false;
2166 }
2167
2168 return true;
2169}
2170
commit-queue@webkit.orgc979afb2011-08-02 18:07:32 +00002171bool RenderBlock::matchedEndLine(LineLayoutState& layoutState, const InlineBidiResolver& resolver, const InlineIterator& endLineStart, const BidiStatus& endLineStatus)
hyatt0c3a9862004-02-23 21:26:26 +00002172{
mitz@apple.com15035e62008-07-05 20:44:44 +00002173 if (resolver.position() == endLineStart) {
2174 if (resolver.status() != endLineStatus)
mitz@apple.com40547b32008-03-18 04:04:34 +00002175 return false;
hyatt@apple.coma10d30e2011-09-22 22:28:21 +00002176 return checkPaginationAndFloatsAtEndLine(layoutState);
mitz@apple.com40547b32008-03-18 04:04:34 +00002177 }
hyatt0c3a9862004-02-23 21:26:26 +00002178
mitz@apple.come1364202008-02-28 01:06:41 +00002179 // The first clean line doesn't match, but we can check a handful of following lines to try
2180 // to match back up.
2181 static int numLines = 8; // The # of lines we're willing to match against.
hyatt@apple.coma10d30e2011-09-22 22:28:21 +00002182 RootInlineBox* originalEndLine = layoutState.endLine();
2183 RootInlineBox* line = originalEndLine;
mitz@apple.come1364202008-02-28 01:06:41 +00002184 for (int i = 0; i < numLines && line; i++, line = line->nextRootBox()) {
eric@webkit.org86a865a2011-03-29 15:30:41 +00002185 if (line->lineBreakObj() == resolver.position().m_obj && line->lineBreakPos() == resolver.position().m_pos) {
mitz@apple.come1364202008-02-28 01:06:41 +00002186 // We have a match.
mitz@apple.com15035e62008-07-05 20:44:44 +00002187 if (line->lineBreakBidiStatus() != resolver.status())
mitz@apple.come1364202008-02-28 01:06:41 +00002188 return false; // ...but the bidi state doesn't match.
hyatt@apple.coma10d30e2011-09-22 22:28:21 +00002189
2190 bool matched = false;
mitz@apple.come1364202008-02-28 01:06:41 +00002191 RootInlineBox* result = line->nextRootBox();
hyatt@apple.com1fb7d582011-09-23 20:25:11 +00002192 layoutState.setEndLine(result);
hyatt@apple.coma10d30e2011-09-22 22:28:21 +00002193 if (result) {
hyatt@apple.com7ce0d422011-08-30 16:57:37 +00002194 layoutState.setEndLineLogicalTop(line->lineBottomWithLeading());
hyatt@apple.coma10d30e2011-09-22 22:28:21 +00002195 matched = checkPaginationAndFloatsAtEndLine(layoutState);
mitz@apple.com40547b32008-03-18 04:04:34 +00002196 }
2197
mitz@apple.come1364202008-02-28 01:06:41 +00002198 // Now delete the lines that we failed to sync.
hyatt@apple.coma10d30e2011-09-22 22:28:21 +00002199 deleteLineRange(layoutState, renderArena(), originalEndLine, result);
2200 return matched;
hyatt0c3a9862004-02-23 21:26:26 +00002201 }
2202 }
mitz@apple.come1364202008-02-28 01:06:41 +00002203
hyatt0c3a9862004-02-23 21:26:26 +00002204 return false;
2205}
2206
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +00002207static inline bool skipNonBreakingSpace(const InlineIterator& it, const LineInfo& lineInfo)
kocienda98440082004-10-14 23:51:47 +00002208{
eric@webkit.org8c25a592011-03-29 13:18:11 +00002209 if (it.m_obj->style()->nbspMode() != SPACE || it.current() != noBreakSpace)
kocienda98440082004-10-14 23:51:47 +00002210 return false;
mitz@apple.come1364202008-02-28 01:06:41 +00002211
hyattdca76e92005-11-02 08:52:50 +00002212 // FIXME: This is bad. It makes nbsp inconsistent with space and won't work correctly
2213 // with m_minWidth/m_maxWidth.
kocienda498d1982004-10-15 21:07:24 +00002214 // Do not skip a non-breaking space if it is the first character
hyattdca76e92005-11-02 08:52:50 +00002215 // on a line after a clean line break (or on the first line, since previousLineBrokeCleanly starts off
2216 // |true|).
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +00002217 if (lineInfo.isEmpty() && lineInfo.previousLineBrokeCleanly())
kocienda498d1982004-10-15 21:07:24 +00002218 return false;
mitz@apple.come1364202008-02-28 01:06:41 +00002219
kocienda498d1982004-10-15 21:07:24 +00002220 return true;
kocienda98440082004-10-14 23:51:47 +00002221}
2222
rniwa@webkit.org40248422011-06-15 00:19:39 +00002223enum WhitespacePosition { LeadingWhitespace, TrailingWhitespace };
2224static inline bool shouldCollapseWhiteSpace(const RenderStyle* style, const LineInfo& lineInfo, WhitespacePosition whitespacePosition)
hyattd9953212005-11-03 21:05:59 +00002225{
rniwa@webkit.org40248422011-06-15 00:19:39 +00002226 // CSS2 16.6.1
2227 // If a space (U+0020) at the beginning of a line has 'white-space' set to 'normal', 'nowrap', or 'pre-line', it is removed.
2228 // 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.
2229 // 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.
2230 return style->collapseWhiteSpace()
2231 || (whitespacePosition == TrailingWhitespace && style->whiteSpace() == PRE_WRAP && (!lineInfo.isEmpty() || !lineInfo.previousLineBrokeCleanly()));
hyattd9953212005-11-03 21:05:59 +00002232}
2233
antti@apple.com3ab7ef32013-09-29 20:50:01 +00002234static bool requiresLineBoxForContent(const RenderInline& flow, const LineInfo& lineInfo)
robert@webkit.org56e5a9f2012-02-17 21:10:42 +00002235{
antti@apple.com3ab7ef32013-09-29 20:50:01 +00002236 RenderElement* parent = flow.parent();
2237 if (flow.document().inNoQuirksMode()) {
2238 const RenderStyle& flowStyle = lineStyle(flow, lineInfo);
antti@apple.comb0608f62013-09-28 18:30:16 +00002239 const RenderStyle& parentStyle = lineStyle(*parent, lineInfo);
2240 if (flowStyle.lineHeight() != parentStyle.lineHeight()
2241 || flowStyle.verticalAlign() != parentStyle.verticalAlign()
2242 || !parentStyle.font().fontMetrics().hasIdenticalAscentDescentAndLineGap(flowStyle.font().fontMetrics()))
robert@webkit.org56e5a9f2012-02-17 21:10:42 +00002243 return true;
antti@apple.comb0608f62013-09-28 18:30:16 +00002244 }
robert@webkit.org56e5a9f2012-02-17 21:10:42 +00002245 return false;
2246}
2247
antti@apple.com3ab7ef32013-09-29 20:50:01 +00002248static bool hasInlineDirectionBordersPaddingOrMargin(const RenderInline& flow)
robert@webkit.org19a94342013-04-10 18:56:36 +00002249{
2250 // Where an empty inline is split across anonymous blocks we should only give lineboxes to the 'sides' of the
2251 // inline that have borders, padding or margin.
antti@apple.com3ab7ef32013-09-29 20:50:01 +00002252 bool shouldApplyStartBorderPaddingOrMargin = !flow.parent()->isAnonymousBlock() || !flow.isInlineElementContinuation();
2253 if (shouldApplyStartBorderPaddingOrMargin && (flow.borderStart() || flow.marginStart() || flow.paddingStart()))
robert@webkit.org19a94342013-04-10 18:56:36 +00002254 return true;
2255
antti@apple.com3ab7ef32013-09-29 20:50:01 +00002256 bool shouldApplyEndBorderPaddingOrMargin = !flow.parent()->isAnonymousBlock() || flow.isInlineElementContinuation() || !flow.inlineElementContinuation();
2257 return shouldApplyEndBorderPaddingOrMargin && (flow.borderEnd() || flow.marginEnd() || flow.paddingEnd());
robert@webkit.org19a94342013-04-10 18:56:36 +00002258}
2259
antti@apple.com3ab7ef32013-09-29 20:50:01 +00002260static bool alwaysRequiresLineBox(const RenderInline& flow)
bdakinf876bee2007-10-30 05:27:09 +00002261{
2262 // FIXME: Right now, we only allow line boxes for inlines that are truly empty.
hyatt@apple.comeb66ef42008-01-18 22:59:29 +00002263 // We need to fix this, though, because at the very least, inlines containing only
eric@webkit.org060caf62011-05-03 22:11:39 +00002264 // ignorable whitespace should should also have line boxes.
antti@apple.com3ab7ef32013-09-29 20:50:01 +00002265 return isEmptyInline(flow) && hasInlineDirectionBordersPaddingOrMargin(flow);
bdakinf876bee2007-10-30 05:27:09 +00002266}
2267
rniwa@webkit.org40248422011-06-15 00:19:39 +00002268static bool requiresLineBox(const InlineIterator& it, const LineInfo& lineInfo = LineInfo(), WhitespacePosition whitespacePosition = LeadingWhitespace)
bdashccffb432007-07-13 11:51:40 +00002269{
simon.fraser@apple.com2f071852012-06-25 00:11:30 +00002270 if (it.m_obj->isFloatingOrOutOfFlowPositioned())
bdashccffb432007-07-13 11:51:40 +00002271 return false;
bdakinf876bee2007-10-30 05:27:09 +00002272
antti@apple.com9d8157e2013-09-17 15:13:37 +00002273 if (it.m_obj->isBR())
2274 return true;
2275
antti@apple.com3ab7ef32013-09-29 20:50:01 +00002276 bool rendererIsEmptyInline = false;
2277 if (it.m_obj->isRenderInline()) {
2278 const RenderInline& inlineRenderer = toRenderInline(*it.m_obj);
2279 if (!alwaysRequiresLineBox(inlineRenderer) && !requiresLineBoxForContent(inlineRenderer, lineInfo))
2280 return false;
2281 rendererIsEmptyInline = isEmptyInline(inlineRenderer);
2282 }
bdakinf876bee2007-10-30 05:27:09 +00002283
antti@apple.com9d8157e2013-09-17 15:13:37 +00002284 if (!shouldCollapseWhiteSpace(it.m_obj->style(), lineInfo, whitespacePosition))
bdashccffb432007-07-13 11:51:40 +00002285 return true;
2286
2287 UChar current = it.current();
robert@webkit.org2b307a72013-01-24 18:46:11 +00002288 bool notJustWhitespace = current != ' ' && current != '\t' && current != softHyphen && (current != '\n' || it.m_obj->preservesNewline()) && !skipNonBreakingSpace(it, lineInfo);
antti@apple.com3ab7ef32013-09-29 20:50:01 +00002289 return notJustWhitespace || rendererIsEmptyInline;
bdashccffb432007-07-13 11:51:40 +00002290}
2291
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +00002292bool RenderBlock::generatesLineBoxesForInlineChild(RenderObject* inlineObj)
bdashccffb432007-07-13 11:51:40 +00002293{
2294 ASSERT(inlineObj->parent() == this);
2295
mitz@apple.com15035e62008-07-05 20:44:44 +00002296 InlineIterator it(this, inlineObj, 0);
rniwa@webkit.org40248422011-06-15 00:19:39 +00002297 // FIXME: We should pass correct value for WhitespacePosition.
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +00002298 while (!it.atEnd() && !requiresLineBox(it))
mitz@apple.com1a301772008-03-11 18:30:36 +00002299 it.increment();
bdashccffb432007-07-13 11:51:40 +00002300
2301 return !it.atEnd();
2302}
2303
mitz@apple.combf6e8d32008-07-25 20:21:06 +00002304// 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 +00002305// line boxes even for containers that may ultimately collapse away. Otherwise we'll never get positioned
2306// 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 +00002307// object iteration process.
mitz@apple.combf6e8d32008-07-25 20:21:06 +00002308// NB. this function will insert any floating elements that would otherwise
2309// be skipped but it will not position them.
zoltan@webkit.org8b422c82013-09-20 21:17:43 +00002310void LineBreaker::skipTrailingWhitespace(InlineIterator& iterator, const LineInfo& lineInfo)
kociendabb0c24b2001-08-24 14:24:40 +00002311{
rniwa@webkit.org40248422011-06-15 00:19:39 +00002312 while (!iterator.atEnd() && !requiresLineBox(iterator, lineInfo, TrailingWhitespace)) {
eric@webkit.org8c25a592011-03-29 13:18:11 +00002313 RenderObject* object = iterator.m_obj;
simon.fraser@apple.com2f071852012-06-25 00:11:30 +00002314 if (object->isOutOfFlowPositioned())
leviw@chromium.org1a508692011-05-05 00:01:11 +00002315 setStaticPositions(m_block, toRenderBox(object));
mitz@apple.comd67fb212011-12-19 02:51:46 +00002316 else if (object->isFloating())
2317 m_block->insertFloatingObject(toRenderBox(object));
mitz@apple.com1a301772008-03-11 18:30:36 +00002318 iterator.increment();
mjs6f821c82002-03-22 00:31:57 +00002319 }
mitz@apple.com1a301772008-03-11 18:30:36 +00002320}
bdashccffb432007-07-13 11:51:40 +00002321
zoltan@webkit.org8b422c82013-09-20 21:17:43 +00002322void LineBreaker::skipLeadingWhitespace(InlineBidiResolver& resolver, LineInfo& lineInfo,
leviw@chromium.org1a508692011-05-05 00:01:11 +00002323 FloatingObject* lastFloatFromPreviousLine, LineWidth& width)
mitz@apple.com1a301772008-03-11 18:30:36 +00002324{
rniwa@webkit.org40248422011-06-15 00:19:39 +00002325 while (!resolver.position().atEnd() && !requiresLineBox(resolver.position(), lineInfo, LeadingWhitespace)) {
eric@webkit.org8c25a592011-03-29 13:18:11 +00002326 RenderObject* object = resolver.position().m_obj;
simon.fraser@apple.com2f071852012-06-25 00:11:30 +00002327 if (object->isOutOfFlowPositioned()) {
leviw@chromium.org1a508692011-05-05 00:01:11 +00002328 setStaticPositions(m_block, toRenderBox(object));
robert@webkit.org8cbab142011-12-30 20:58:29 +00002329 if (object->style()->isOriginalDisplayInlineType()) {
2330 resolver.runs().addRun(createRun(0, 1, object, resolver));
2331 lineInfo.incrementRunsFromLeadingWhitespace();
2332 }
robert@webkit.org8de78c62012-12-07 19:30:51 +00002333 } else if (object->isFloating()) {
2334 // 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 +00002335 // 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.
timothy_horton@apple.comeefba762013-08-21 19:50:36 +00002336 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 +00002337 LayoutUnit oldLogicalHeight = m_block->logicalHeight();
2338 m_block->setLogicalHeight(oldLogicalHeight + marginOffset);
mitz@apple.comd67fb212011-12-19 02:51:46 +00002339 m_block->positionNewFloatOnLine(m_block->insertFloatingObject(toRenderBox(object)), lastFloatFromPreviousLine, lineInfo, width);
robert@webkit.org8de78c62012-12-07 19:30:51 +00002340 m_block->setLogicalHeight(oldLogicalHeight);
akling@apple.com4c166d62013-09-01 05:29:00 +00002341 } else if (object->isText() && object->style()->hasTextCombine() && object->isCombineText() && !toRenderCombineText(*object).isCombined()) {
2342 toRenderCombineText(*object).combineText();
2343 if (toRenderCombineText(*object).isCombined())
commit-queue@webkit.org8e277fd2012-01-19 18:05:33 +00002344 continue;
commit-queue@webkit.orgf6c35c02012-01-06 20:30:15 +00002345 }
mitz@apple.com15035e62008-07-05 20:44:44 +00002346 resolver.increment();
mitz@apple.com1a301772008-03-11 18:30:36 +00002347 }
mitz@apple.com83d2e872008-10-23 21:56:03 +00002348 resolver.commitExplicitEmbedding();
kociendae40cb942004-10-05 20:05:38 +00002349}
2350
eric@webkit.org060caf62011-05-03 22:11:39 +00002351// This is currently just used for list markers and inline flows that have line boxes. Neither should
2352// have an effect on whitespace at the start of the line.
hyatt@apple.comb3466af2009-06-13 06:04:40 +00002353static bool shouldSkipWhitespaceAfterStartObject(RenderBlock* block, RenderObject* o, LineMidpointState& lineMidpointState)
bdakinf876bee2007-10-30 05:27:09 +00002354{
eric@webkit.orgd4b9d772011-08-22 23:34:31 +00002355 RenderObject* next = bidiNextSkippingEmptyInlines(block, o);
robert@webkit.orgdc6fd182013-04-11 19:17:12 +00002356 while (next && next->isFloatingOrOutOfFlowPositioned())
2357 next = bidiNextSkippingEmptyInlines(block, next);
2358
antti@apple.com9d8157e2013-09-17 15:13:37 +00002359 if (next && next->isText() && toRenderText(next)->textLength() > 0) {
darin@apple.com36744d62009-01-25 20:23:04 +00002360 RenderText* nextText = toRenderText(next);
msaboff@apple.com776c286c72012-10-15 16:56:29 +00002361 UChar nextChar = nextText->characterAt(0);
bdakinf876bee2007-10-30 05:27:09 +00002362 if (nextText->style()->isCollapsibleWhiteSpace(nextChar)) {
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00002363 startIgnoringSpaces(lineMidpointState, InlineIterator(0, o, 0));
bdakinf876bee2007-10-30 05:27:09 +00002364 return true;
2365 }
2366 }
2367
2368 return false;
2369}
2370
rniwa@webkit.orgfe811f22013-06-07 17:59:01 +00002371static ALWAYS_INLINE float textWidth(RenderText* text, unsigned from, unsigned len, const Font& font, float xPos, bool isFixedPitch, bool collapseWhiteSpace, HashSet<const SimpleFontData*>& fallbackFonts, TextLayout* layout = 0)
mitz@apple.com34106442009-02-01 06:23:39 +00002372{
antti@apple.com78e56772013-09-29 04:34:37 +00002373 const RenderStyle& style = *text->style();
2374
enrica@apple.com885c84d2012-10-10 05:48:51 +00002375 GlyphOverflow glyphOverflow;
antti@apple.com78e56772013-09-29 04:34:37 +00002376 if (isFixedPitch || (!from && len == text->textLength()) || style.hasTextCombine())
rniwa@webkit.orgfe811f22013-06-07 17:59:01 +00002377 return text->width(from, len, font, xPos, &fallbackFonts, &glyphOverflow);
zimmermann@webkit.org544abde2011-06-12 12:40:40 +00002378
mitz@apple.com6a859602012-08-27 15:31:56 +00002379 if (layout)
rniwa@webkit.orgfe811f22013-06-07 17:59:01 +00002380 return Font::width(*layout, from, len, &fallbackFonts);
mitz@apple.com6a859602012-08-27 15:31:56 +00002381
antti@apple.com78e56772013-09-29 04:34:37 +00002382 TextRun run = RenderBlock::constructTextRun(text, font, text, from, len, style);
zimmermann@webkit.org544abde2011-06-12 12:40:40 +00002383 run.setCharactersLength(text->textLength() - from);
2384 ASSERT(run.charactersLength() >= run.length());
2385
hyatt@apple.comc2fdbe12012-04-12 21:06:50 +00002386 run.setCharacterScanForCodePath(!text->canUseSimpleFontCodePath());
morrita@google.com6e818ec2012-05-11 03:28:46 +00002387 run.setTabSize(!collapseWhiteSpace, text->style()->tabSize());
zimmermann@webkit.org8a7e7ff2011-05-24 15:27:36 +00002388 run.setXPos(xPos);
rniwa@webkit.orgfe811f22013-06-07 17:59:01 +00002389 return font.width(run, &fallbackFonts, &glyphOverflow);
mitz@apple.com34106442009-02-01 06:23:39 +00002390}
2391
msaboff@apple.com776c286c72012-10-15 16:56:29 +00002392static 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 +00002393{
mitz@apple.comd56f1082011-03-06 22:44:48 +00002394 // Map 'hyphenate-limit-{before,after}: auto;' to 2.
msaboff@apple.com776c286c72012-10-15 16:56:29 +00002395 unsigned minimumPrefixLength;
2396 unsigned minimumSuffixLength;
mitz@apple.comd56f1082011-03-06 22:44:48 +00002397
msaboff@apple.com776c286c72012-10-15 16:56:29 +00002398 if (minimumPrefixLimit < 0)
2399 minimumPrefixLength = 2;
2400 else
2401 minimumPrefixLength = static_cast<unsigned>(minimumPrefixLimit);
2402
2403 if (minimumSuffixLimit < 0)
mitz@apple.comd56f1082011-03-06 22:44:48 +00002404 minimumSuffixLength = 2;
msaboff@apple.com776c286c72012-10-15 16:56:29 +00002405 else
2406 minimumSuffixLength = static_cast<unsigned>(minimumSuffixLimit);
mitz@apple.comd56f1082011-03-06 22:44:48 +00002407
2408 if (pos - lastSpace <= minimumSuffixLength)
2409 return;
2410
mitz@apple.com10ed3cb2011-09-07 20:59:39 +00002411 if (consecutiveHyphenatedLinesLimit >= 0 && consecutiveHyphenatedLines >= static_cast<unsigned>(consecutiveHyphenatedLinesLimit))
2412 return;
2413
commit-queue@webkit.orge60bb902011-09-08 19:18:43 +00002414 int hyphenWidth = measureHyphenWidth(text, font);
mitz@apple.comb2107652010-06-21 16:54:52 +00002415
hyatt@apple.com0acc9352011-02-17 19:19:07 +00002416 float maxPrefixWidth = availableWidth - xPos - hyphenWidth - lastSpaceWordSpacing;
mitz@apple.com7c67b292010-09-12 23:04:16 +00002417 // If the maximum width available for the prefix before the hyphen is small, then it is very unlikely
2418 // that an hyphenation opportunity exists, so do not bother to look for it.
2419 if (maxPrefixWidth <= font.pixelSize() * 5 / 4)
2420 return;
2421
antti@apple.com78e56772013-09-29 04:34:37 +00002422 const RenderStyle& style = *text->style();
2423 TextRun run = RenderBlock::constructTextRun(text, font, text, lastSpace, pos - lastSpace, style);
zimmermann@webkit.org544abde2011-06-12 12:40:40 +00002424 run.setCharactersLength(text->textLength() - lastSpace);
2425 ASSERT(run.charactersLength() >= run.length());
2426
antti@apple.com78e56772013-09-29 04:34:37 +00002427 run.setTabSize(!collapseWhiteSpace, style.tabSize());
zimmermann@webkit.org8a7e7ff2011-05-24 15:27:36 +00002428 run.setXPos(xPos + lastSpaceWordSpacing);
2429
2430 unsigned prefixLength = font.offsetForPosition(run, maxPrefixWidth, false);
msaboff@apple.com776c286c72012-10-15 16:56:29 +00002431 if (prefixLength < minimumPrefixLength)
mitz@apple.comb2107652010-06-21 16:54:52 +00002432 return;
2433
msaboff@apple.com776c286c72012-10-15 16:56:29 +00002434 prefixLength = lastHyphenLocation(text->characters() + lastSpace, pos - lastSpace, min(prefixLength, pos - lastSpace - minimumSuffixLength) + 1, localeIdentifier);
2435 if (!prefixLength || prefixLength < minimumPrefixLength)
mitz@apple.comb2107652010-06-21 16:54:52 +00002436 return;
2437
mitz@apple.com348878a2011-12-11 19:06:56 +00002438 // When lastSapce is a space, which it always is except sometimes at the beginning of a line or after collapsed
2439 // space, it should not count towards hyphenate-limit-before.
msaboff@apple.com776c286c72012-10-15 16:56:29 +00002440 if (prefixLength == minimumPrefixLength) {
2441 UChar characterAtLastSpace = text->characterAt(lastSpace);
mitz@apple.com348878a2011-12-11 19:06:56 +00002442 if (characterAtLastSpace == ' ' || characterAtLastSpace == '\n' || characterAtLastSpace == '\t' || characterAtLastSpace == noBreakSpace)
2443 return;
2444 }
2445
msaboff@apple.com776c286c72012-10-15 16:56:29 +00002446 ASSERT(pos - lastSpace - prefixLength >= minimumSuffixLength);
mitz@apple.comd56f1082011-03-06 22:44:48 +00002447
mitz@apple.comb2107652010-06-21 16:54:52 +00002448#if !ASSERT_DISABLED
rniwa@webkit.orgfe811f22013-06-07 17:59:01 +00002449 HashSet<const SimpleFontData*> fallbackFonts;
2450 float prefixWidth = hyphenWidth + textWidth(text, lastSpace, prefixLength, font, xPos, isFixedPitch, collapseWhiteSpace, fallbackFonts) + lastSpaceWordSpacing;
mitz@apple.comb2107652010-06-21 16:54:52 +00002451 ASSERT(xPos + prefixWidth <= availableWidth);
mitz@apple.com34b43c72010-06-21 17:21:22 +00002452#else
2453 UNUSED_PARAM(isFixedPitch);
mitz@apple.comb2107652010-06-21 16:54:52 +00002454#endif
2455
eric@webkit.orgbd143592011-03-29 17:44:41 +00002456 lineBreak.moveTo(text, lastSpace + prefixLength, nextBreakable);
mitz@apple.comb2107652010-06-21 16:54:52 +00002457 hyphenated = true;
2458}
2459
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002460class TrailingObjects {
2461public:
2462 TrailingObjects();
2463 void setTrailingWhitespace(RenderText*);
2464 void clear();
commit-queue@webkit.org6af48872013-04-09 16:46:49 +00002465 void appendBoxIfNeeded(RenderBoxModelObject*);
mitz@apple.come98acc92011-05-22 04:44:27 +00002466
2467 enum CollapseFirstSpaceOrNot { DoNotCollapseFirstSpace, CollapseFirstSpace };
2468
2469 void updateMidpointsForTrailingBoxes(LineMidpointState&, const InlineIterator& lBreak, CollapseFirstSpaceOrNot);
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002470
2471private:
2472 RenderText* m_whitespace;
commit-queue@webkit.org6af48872013-04-09 16:46:49 +00002473 Vector<RenderBoxModelObject*, 4> m_boxes;
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002474};
2475
2476TrailingObjects::TrailingObjects()
2477 : m_whitespace(0)
2478{
2479}
2480
2481inline void TrailingObjects::setTrailingWhitespace(RenderText* whitespace)
2482{
2483 ASSERT(whitespace);
2484 m_whitespace = whitespace;
2485}
2486
2487inline void TrailingObjects::clear()
2488{
2489 m_whitespace = 0;
ggaren@apple.com98109ff2013-07-19 17:43:07 +00002490 m_boxes.shrink(0); // Use shrink(0) instead of clear() to retain our capacity.
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002491}
2492
commit-queue@webkit.org6af48872013-04-09 16:46:49 +00002493inline void TrailingObjects::appendBoxIfNeeded(RenderBoxModelObject* box)
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002494{
2495 if (m_whitespace)
2496 m_boxes.append(box);
2497}
2498
mitz@apple.come98acc92011-05-22 04:44:27 +00002499void TrailingObjects::updateMidpointsForTrailingBoxes(LineMidpointState& lineMidpointState, const InlineIterator& lBreak, CollapseFirstSpaceOrNot collapseFirstSpace)
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002500{
2501 if (!m_whitespace)
2502 return;
2503
2504 // This object is either going to be part of the last midpoint, or it is going to be the actual endpoint.
2505 // In both cases we just decrease our pos by 1 level to exclude the space, allowing it to - in effect - collapse into the newline.
2506 if (lineMidpointState.numMidpoints % 2) {
2507 // Find the trailing space object's midpoint.
2508 int trailingSpaceMidpoint = lineMidpointState.numMidpoints - 1;
inferno@chromium.org92ca04e2011-08-01 18:03:03 +00002509 for ( ; trailingSpaceMidpoint > 0 && lineMidpointState.midpoints[trailingSpaceMidpoint].m_obj != m_whitespace; --trailingSpaceMidpoint) { }
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002510 ASSERT(trailingSpaceMidpoint >= 0);
mitz@apple.come98acc92011-05-22 04:44:27 +00002511 if (collapseFirstSpace == CollapseFirstSpace)
2512 lineMidpointState.midpoints[trailingSpaceMidpoint].m_pos--;
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002513
eric@webkit.org060caf62011-05-03 22:11:39 +00002514 // Now make sure every single trailingPositionedBox following the trailingSpaceMidpoint properly stops and starts
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002515 // ignoring spaces.
2516 size_t currentMidpoint = trailingSpaceMidpoint + 1;
2517 for (size_t i = 0; i < m_boxes.size(); ++i) {
2518 if (currentMidpoint >= lineMidpointState.numMidpoints) {
2519 // We don't have a midpoint for this box yet.
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00002520 ensureLineBoxInsideIgnoredSpaces(lineMidpointState, m_boxes[i]);
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002521 } else {
2522 ASSERT(lineMidpointState.midpoints[currentMidpoint].m_obj == m_boxes[i]);
2523 ASSERT(lineMidpointState.midpoints[currentMidpoint + 1].m_obj == m_boxes[i]);
2524 }
2525 currentMidpoint += 2;
2526 }
2527 } else if (!lBreak.m_obj) {
2528 ASSERT(m_whitespace->isText());
mitz@apple.come98acc92011-05-22 04:44:27 +00002529 ASSERT(collapseFirstSpace == CollapseFirstSpace);
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002530 // Add a new end midpoint that stops right at the very end.
2531 unsigned length = m_whitespace->textLength();
2532 unsigned pos = length >= 2 ? length - 2 : UINT_MAX;
2533 InlineIterator endMid(0, m_whitespace, pos);
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00002534 startIgnoringSpaces(lineMidpointState, endMid);
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002535 for (size_t i = 0; i < m_boxes.size(); ++i) {
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00002536 ensureLineBoxInsideIgnoredSpaces(lineMidpointState, m_boxes[i]);
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002537 }
2538 }
2539}
2540
zoltan@webkit.org8b422c82013-09-20 21:17:43 +00002541void LineBreaker::reset()
kociendae40cb942004-10-05 20:05:38 +00002542{
leviw@chromium.org1a508692011-05-05 00:01:11 +00002543 m_positionedObjects.clear();
2544 m_hyphenated = false;
2545 m_clear = CNONE;
2546}
2547
zoltan@webkit.org8b422c82013-09-20 21:17:43 +00002548InlineIterator LineBreaker::nextLineBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, RenderTextInfo& renderTextInfo, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements& wordMeasurements)
leviw@chromium.org1a508692011-05-05 00:01:11 +00002549{
betravis@adobe.comed90c982013-06-05 23:05:57 +00002550#if !ENABLE(CSS_SHAPES)
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00002551 return nextSegmentBreak(resolver, lineInfo, renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
2552#else
betravis@adobe.comcf7cba62013-06-10 21:23:45 +00002553 ShapeInsideInfo* shapeInsideInfo = m_block->layoutShapeInsideInfo();
zoltan@webkit.org3bd77f52013-04-23 18:23:36 +00002554
betravis@adobe.comcf7cba62013-06-10 21:23:45 +00002555 if (!shapeInsideInfo || !shapeInsideInfo->lineOverlapsShapeBounds())
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00002556 return nextSegmentBreak(resolver, lineInfo, renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
2557
2558 InlineIterator end = resolver.position();
2559 InlineIterator oldEnd = end;
2560
betravis@adobe.comcf7cba62013-06-10 21:23:45 +00002561 if (!shapeInsideInfo->hasSegments()) {
betravis@adobe.com9e5e8242013-04-19 23:28:26 +00002562 end = nextSegmentBreak(resolver, lineInfo, renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
2563 resolver.setPositionIgnoringNestedIsolates(oldEnd);
2564 return oldEnd;
2565 }
2566
betravis@adobe.comcf7cba62013-06-10 21:23:45 +00002567 const SegmentList& segments = shapeInsideInfo->segments();
2568 SegmentRangeList& segmentRanges = shapeInsideInfo->segmentRanges();
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00002569
hmuller@adobe.com6da71872013-03-18 16:54:04 +00002570 for (unsigned i = 0; i < segments.size() && !end.atEnd(); i++) {
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00002571 InlineIterator segmentStart = resolver.position();
2572 end = nextSegmentBreak(resolver, lineInfo, renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
2573
2574 ASSERT(segmentRanges.size() == i);
hmuller@adobe.com6da71872013-03-18 16:54:04 +00002575 if (resolver.position().atEnd()) {
2576 segmentRanges.append(LineSegmentRange(segmentStart, end));
2577 break;
2578 }
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00002579 if (resolver.position() == end) {
2580 // Nothing fit this segment
betravis@adobe.com9e5e8242013-04-19 23:28:26 +00002581 end = segmentStart;
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00002582 segmentRanges.append(LineSegmentRange(segmentStart, segmentStart));
2583 resolver.setPositionIgnoringNestedIsolates(segmentStart);
2584 } else {
2585 // Note that resolver.position is already skipping some of the white space at the beginning of the line,
2586 // so that's why segmentStart might be different than resolver.position().
2587 LineSegmentRange range(resolver.position(), end);
2588 segmentRanges.append(range);
2589 resolver.setPosition(end, numberOfIsolateAncestors(end));
2590
2591 if (lineInfo.previousLineBrokeCleanly()) {
2592 // If we hit a new line break, just stop adding anything to this line.
2593 break;
2594 }
2595 }
2596 }
2597 resolver.setPositionIgnoringNestedIsolates(oldEnd);
2598 return end;
2599#endif
2600}
2601
akling@apple.com4c166d62013-09-01 05:29:00 +00002602static inline bool iteratorIsBeyondEndOfRenderCombineText(const InlineIterator& iter, RenderCombineText& renderer)
leviw@chromium.org17fe64d2013-04-02 23:10:49 +00002603{
akling@apple.com4c166d62013-09-01 05:29:00 +00002604 return iter.m_obj == &renderer && iter.m_pos >= renderer.textLength();
leviw@chromium.org17fe64d2013-04-02 23:10:49 +00002605}
2606
robert@webkit.org1f811532013-06-24 20:09:20 +00002607static inline void commitLineBreakAtCurrentWidth(LineWidth& width, InlineIterator& lBreak, RenderObject* object, unsigned offset = 0, int nextBreak = -1)
2608{
2609 width.commit();
2610 lBreak.moveTo(object, offset, nextBreak);
2611}
2612
robert@webkit.org6ce4b392013-07-02 19:30:32 +00002613static bool textBeginsWithBreakablePosition(RenderObject* next)
2614{
2615 ASSERT(next->isText());
2616 RenderText* nextText = toRenderText(next);
robert@webkit.org6ce4b392013-07-02 19:30:32 +00002617 if (!nextText->textLength())
2618 return false;
2619 UChar c = nextText->characterAt(0);
2620 return c == ' ' || c == '\t' || (c == '\n' && !nextText->preservesNewline());
2621}
2622
2623static bool canBreakAtThisPosition(bool autoWrap, LineWidth& width, InlineIterator& lBreak, RenderObject* next, const InlineIterator& current, EWhiteSpace currWS, bool currentCharacterIsSpace, bool autoWrapWasEverTrueOnLine)
2624{
2625 // If we are no-wrap and have found a line-breaking opportunity already then we should take it.
2626 if (width.committedWidth() && !width.fitsOnLine(currentCharacterIsSpace) && currWS == NOWRAP)
2627 return true;
2628
2629 // Avoid breaking before empty inlines.
antti@apple.com3ab7ef32013-09-29 20:50:01 +00002630 if (next && next->isRenderInline() && isEmptyInline(toRenderInline(*next)))
robert@webkit.org6ce4b392013-07-02 19:30:32 +00002631 return false;
2632
2633 // Return early if we autowrap and the current character is a space as we will always want to break at such a position.
2634 if (autoWrap && currentCharacterIsSpace)
2635 return true;
2636
antti@apple.com3014ac02013-09-18 14:33:55 +00002637 if (next && next->isLineBreakOpportunity())
2638 return autoWrap;
2639
antti@apple.com3ab7ef32013-09-29 20:50:01 +00002640 bool nextIsAutoWrappingText = (next && next->isText() && (autoWrap || next->style()->autoWrap()));
2641 if (!nextIsAutoWrappingText)
2642 return autoWrap;
2643 bool currentIsTextOrEmptyInline = current.m_obj->isText() || (current.m_obj->isRenderInline() && isEmptyInline(toRenderInline(*current.m_obj)));
2644 if (!currentIsTextOrEmptyInline)
robert@webkit.org6ce4b392013-07-02 19:30:32 +00002645 return autoWrap;
2646
2647 bool canBreakHere = !currentCharacterIsSpace && textBeginsWithBreakablePosition(next);
2648
2649 // See if attempting to fit below floats creates more available width on the line.
2650 if (!width.fitsOnLine() && !width.committedWidth())
2651 width.fitBelowFloats();
2652
2653 bool canPlaceOnLine = width.fitsOnLine() || !autoWrapWasEverTrueOnLine;
2654
zalan@apple.com576a5fb2013-07-23 19:47:34 +00002655 if (canPlaceOnLine && canBreakHere)
robert@webkit.org6ce4b392013-07-02 19:30:32 +00002656 commitLineBreakAtCurrentWidth(width, lBreak, next);
2657
2658 return canBreakHere;
2659}
2660
zoltan@webkit.orge1a0c952013-09-18 03:27:35 +00002661#if ENABLE(CSS_SHAPES)
2662static void updateSegmentsForShapes(RenderBlock* block, const FloatingObject* lastFloatFromPreviousLine, const WordMeasurements& wordMeasurements, LineWidth& width, bool isFirstLine)
2663{
2664 ASSERT(lastFloatFromPreviousLine);
2665
2666 ShapeInsideInfo* shapeInsideInfo = block->layoutShapeInsideInfo();
zoltan@webkit.org2b977c02013-10-03 18:24:59 +00002667 if (!lastFloatFromPreviousLine->isPlaced() || !shapeInsideInfo)
zoltan@webkit.orge1a0c952013-09-18 03:27:35 +00002668 return;
2669
zoltan@webkit.org3b30db72013-09-24 22:24:39 +00002670 bool isHorizontalWritingMode = block->isHorizontalWritingMode();
zoltan@webkit.org2b977c02013-10-03 18:24:59 +00002671 LayoutUnit logicalOffsetFromShapeContainer = block->logicalOffsetFromShapeAncestorContainer(shapeInsideInfo->owner()).height();
zoltan@webkit.orge1a0c952013-09-18 03:27:35 +00002672
zoltan@webkit.org2b977c02013-10-03 18:24:59 +00002673 LayoutUnit lineLogicalTop = block->logicalHeight() + logicalOffsetFromShapeContainer;
zoltan@webkit.org3b30db72013-09-24 22:24:39 +00002674 LayoutUnit lineLogicalHeight = block->lineHeight(isFirstLine, isHorizontalWritingMode ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
2675 LayoutUnit lineLogicalBottom = lineLogicalTop + lineLogicalHeight;
zoltan@webkit.orge1a0c952013-09-18 03:27:35 +00002676
zoltan@webkit.org3b30db72013-09-24 22:24:39 +00002677 LayoutUnit floatLogicalTop = lastFloatFromPreviousLine->logicalTop(isHorizontalWritingMode);
2678 LayoutUnit floatLogicalBottom = lastFloatFromPreviousLine->logicalBottom(isHorizontalWritingMode);
2679
2680 bool lineOverlapsWithFloat = (floatLogicalTop < lineLogicalBottom) && (lineLogicalTop < floatLogicalBottom);
2681 if (!lineOverlapsWithFloat)
2682 return;
2683
2684 float minSegmentWidth = firstPositiveWidth(wordMeasurements);
2685
2686 LayoutUnit floatLogicalWidth = lastFloatFromPreviousLine->logicalWidth(isHorizontalWritingMode);
2687 LayoutUnit availableLogicalWidth = block->logicalWidth() - lastFloatFromPreviousLine->logicalRight(isHorizontalWritingMode);
2688 if (availableLogicalWidth < minSegmentWidth)
2689 block->setLogicalHeight(floatLogicalBottom);
2690
2691 if (block->logicalHeight() < floatLogicalTop) {
2692 shapeInsideInfo->adjustLogicalLineTop(minSegmentWidth + floatLogicalWidth);
zoltan@webkit.org2b977c02013-10-03 18:24:59 +00002693 block->setLogicalHeight(shapeInsideInfo->logicalLineTop() - logicalOffsetFromShapeContainer);
zoltan@webkit.orge1a0c952013-09-18 03:27:35 +00002694 }
2695
zoltan@webkit.org2b977c02013-10-03 18:24:59 +00002696 lineLogicalTop = block->logicalHeight() + logicalOffsetFromShapeContainer;
2697
2698 shapeInsideInfo->updateSegmentsForLine(lineLogicalTop, lineLogicalHeight);
zoltan@webkit.orge1a0c952013-09-18 03:27:35 +00002699 width.updateCurrentShapeSegment();
2700 width.updateAvailableWidth();
2701}
2702#endif
2703
zoltan@webkit.org8b422c82013-09-20 21:17:43 +00002704InlineIterator LineBreaker::nextSegmentBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, RenderTextInfo& renderTextInfo, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements& wordMeasurements)
commit-queue@webkit.orgccad9242012-12-05 20:17:30 +00002705{
leviw@chromium.org1a508692011-05-05 00:01:11 +00002706 reset();
2707
2708 ASSERT(resolver.position().root() == m_block);
mitz@apple.com51017322008-02-26 06:47:43 +00002709
eric@webkit.org86a865a2011-03-29 15:30:41 +00002710 bool appliedStartWidth = resolver.position().m_pos > 0;
yael.aharon@nokia.com1cfbceb2011-06-06 18:32:54 +00002711 bool includeEndWidth = true;
hyatt@apple.comb3466af2009-06-13 06:04:40 +00002712 LineMidpointState& lineMidpointState = resolver.midpointState();
mitz@apple.com1a301772008-03-11 18:30:36 +00002713
antti@apple.com78e56772013-09-29 04:34:37 +00002714 LineWidth width(*m_block, lineInfo.isFirstLine(), requiresIndent(lineInfo.isFirstLine(), lineInfo.previousLineBrokeCleanly(), *m_block->style()));
rniwa@webkit.org7881ad02011-04-07 13:05:35 +00002715
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +00002716 skipLeadingWhitespace(resolver, lineInfo, lastFloatFromPreviousLine, width);
kociendae40cb942004-10-05 20:05:38 +00002717
mitz@apple.com15035e62008-07-05 20:44:44 +00002718 if (resolver.position().atEnd())
2719 return resolver.position();
mjs6f821c82002-03-22 00:31:57 +00002720
hyatt33f8d492002-11-12 21:44:52 +00002721 // This variable is used only if whitespace isn't set to PRE, and it tells us whether
2722 // or not we are currently ignoring whitespace.
2723 bool ignoringSpaces = false;
mitz@apple.com15035e62008-07-05 20:44:44 +00002724 InlineIterator ignoreStart;
eric@webkit.org060caf62011-05-03 22:11:39 +00002725
hyatt33f8d492002-11-12 21:44:52 +00002726 // This variable tracks whether the very last character we saw was a space. We use
2727 // this to detect when we encounter a second space so we know we have to terminate
2728 // a run.
rjwc9c257d2003-01-24 03:46:17 +00002729 bool currentCharacterIsSpace = false;
harrisone343c412005-01-18 01:07:26 +00002730 bool currentCharacterIsWS = false;
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002731 TrailingObjects trailingObjects;
hyatt98b16282004-03-31 18:43:12 +00002732
mitz@apple.com15035e62008-07-05 20:44:44 +00002733 InlineIterator lBreak = resolver.position();
mjs6f821c82002-03-22 00:31:57 +00002734
eric@webkit.orgbd143592011-03-29 17:44:41 +00002735 // FIXME: It is error-prone to split the position object out like this.
2736 // Teach this code to work with objects instead of this split tuple.
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002737 InlineIterator current = resolver.position();
2738 RenderObject* last = current.m_obj;
ddkilzere8759ef2007-03-25 06:28:19 +00002739 bool atStart = true;
kociendabb0c24b2001-08-24 14:24:40 +00002740
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +00002741 bool startingNewParagraph = lineInfo.previousLineBrokeCleanly();
2742 lineInfo.setPreviousLineBrokeCleanly(false);
ddkilzer5d01fa22007-01-29 03:10:37 +00002743
2744 bool autoWrapWasEverTrueOnLine = false;
mitz@apple.com25beac62008-02-24 18:48:27 +00002745 bool floatsFitOnLine = true;
eric@webkit.org060caf62011-05-03 22:11:39 +00002746
hyatt@apple.com69340902008-01-16 21:24:21 +00002747 // 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 +00002748 // very specific circumstances (in order to match common WinIE renderings).
2749 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
antti@apple.com78e56772013-09-29 04:34:37 +00002750 const RenderStyle& blockStyle = *m_block->style();
2751 bool allowImagesToBreak = !m_block->document().inQuirksMode() || !m_block->isTableCell() || !blockStyle.logicalWidth().isIntrinsicOrAuto();
hyatt@apple.com69340902008-01-16 21:24:21 +00002752
antti@apple.com78e56772013-09-29 04:34:37 +00002753 EWhiteSpace currWS = blockStyle.whiteSpace();
hyattb0d9f602007-01-15 01:28:23 +00002754 EWhiteSpace lastWS = currWS;
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002755 while (current.m_obj) {
antti@apple.com78e56772013-09-29 04:34:37 +00002756 const RenderStyle& currentStyle = *current.m_obj->style();
eric@webkit.orgd4b9d772011-08-22 23:34:31 +00002757 RenderObject* next = bidiNextSkippingEmptyInlines(m_block, current.m_obj);
yael.aharon@nokia.com1cfbceb2011-06-06 18:32:54 +00002758 if (next && next->parent() && !next->parent()->isDescendantOf(current.m_obj->parent()))
2759 includeEndWidth = true;
mitz@apple.comddb59872011-04-05 05:21:16 +00002760
antti@apple.com78e56772013-09-29 04:34:37 +00002761 currWS = current.m_obj->isReplaced() ? current.m_obj->parent()->style()->whiteSpace() : currentStyle.whiteSpace();
hyattb0d9f602007-01-15 01:28:23 +00002762 lastWS = last->isReplaced() ? last->parent()->style()->whiteSpace() : last->style()->whiteSpace();
eric@webkit.org060caf62011-05-03 22:11:39 +00002763
hyattb0d9f602007-01-15 01:28:23 +00002764 bool autoWrap = RenderStyle::autoWrap(currWS);
ddkilzer5d01fa22007-01-29 03:10:37 +00002765 autoWrapWasEverTrueOnLine = autoWrapWasEverTrueOnLine || autoWrap;
zimmermannac3781f2007-02-04 01:25:03 +00002766
mjsd2948ef2007-02-26 19:29:04 +00002767#if ENABLE(SVG)
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002768 bool preserveNewline = current.m_obj->isSVGInlineText() ? false : RenderStyle::preserveNewline(currWS);
zimmermannac3781f2007-02-04 01:25:03 +00002769#else
hyattb0d9f602007-01-15 01:28:23 +00002770 bool preserveNewline = RenderStyle::preserveNewline(currWS);
zimmermannac3781f2007-02-04 01:25:03 +00002771#endif
2772
hyattb0d9f602007-01-15 01:28:23 +00002773 bool collapseWhiteSpace = RenderStyle::collapseWhiteSpace(currWS);
eric@webkit.org060caf62011-05-03 22:11:39 +00002774
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002775 if (current.m_obj->isBR()) {
rniwa@webkit.org5eb8d162011-04-13 02:13:33 +00002776 if (width.fitsOnLine()) {
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002777 lBreak.moveToStartOf(current.m_obj);
mitz@apple.com1a301772008-03-11 18:30:36 +00002778 lBreak.increment();
hyatt0c3a9862004-02-23 21:26:26 +00002779
hyatt33f8d492002-11-12 21:44:52 +00002780 // A <br> always breaks a line, so don't let the line be collapsed
2781 // away. Also, the space at the end of a line with a <br> does not
hyatt01eff982003-03-14 20:13:23 +00002782 // get collapsed away. It only does this if the previous line broke
2783 // cleanly. Otherwise the <br> has no effect on whether the line is
2784 // empty or not.
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +00002785 if (startingNewParagraph)
hyatt@apple.com5950bd42011-09-27 20:39:57 +00002786 lineInfo.setEmpty(false, m_block, &width);
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002787 trailingObjects.clear();
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +00002788 lineInfo.setPreviousLineBrokeCleanly(true);
hyatt74eec4d2003-03-23 08:02:47 +00002789
robert@webkit.org3c75e502012-10-21 10:27:50 +00002790 // A <br> with clearance always needs a linebox in case the lines below it get dirtied later and
2791 // need to check for floats to clear - so if we're ignoring spaces, stop ignoring them and add a
2792 // run for this object.
antti@apple.com78e56772013-09-29 04:34:37 +00002793 if (ignoringSpaces && currentStyle.clear() != CNONE)
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00002794 ensureLineBoxInsideIgnoredSpaces(lineMidpointState, current.m_obj);
robert@webkit.org2cb02642013-09-18 17:58:25 +00002795 // If we were preceded by collapsing space and are in a right-aligned container we need to ensure the space gets
2796 // collapsed away so that it doesn't push the text out from the container's right-hand edge.
2797 // FIXME: Do this regardless of the container's alignment - will require rebaselining a lot of test results.
antti@apple.com78e56772013-09-29 04:34:37 +00002798 else if (ignoringSpaces && (blockStyle.textAlign() == RIGHT || blockStyle.textAlign() == WEBKIT_RIGHT))
robert@webkit.org2cb02642013-09-18 17:58:25 +00002799 stopIgnoringSpaces(lineMidpointState, InlineIterator(0, current.m_obj, current.m_pos));
robert@webkit.org3c75e502012-10-21 10:27:50 +00002800
leviw@chromium.org1a508692011-05-05 00:01:11 +00002801 if (!lineInfo.isEmpty())
antti@apple.com78e56772013-09-29 04:34:37 +00002802 m_clear = currentStyle.clear();
kociendabb0c24b2001-08-24 14:24:40 +00002803 }
2804 goto end;
2805 }
hyattb0d9f602007-01-15 01:28:23 +00002806
simon.fraser@apple.com2f071852012-06-25 00:11:30 +00002807 if (current.m_obj->isOutOfFlowPositioned()) {
rniwa@webkit.org76aa5222011-05-04 13:03:32 +00002808 // If our original display wasn't an inline type, then we can
2809 // go ahead and determine our static inline position now.
2810 RenderBox* box = toRenderBox(current.m_obj);
2811 bool isInlineType = box->style()->isOriginalDisplayInlineType();
2812 if (!isInlineType)
hyatt@apple.coma5cac3f2011-10-12 18:51:17 +00002813 m_block->setStaticInlinePositionForChild(box, m_block->logicalHeight(), m_block->startOffsetForContent(m_block->logicalHeight()));
rniwa@webkit.org76aa5222011-05-04 13:03:32 +00002814 else {
2815 // If our original display was an INLINE type, then we can go ahead
2816 // and determine our static y position now.
leviw@chromium.org1a508692011-05-05 00:01:11 +00002817 box->layer()->setStaticBlockPosition(m_block->logicalHeight());
hyatt98ee7e42003-05-14 01:39:15 +00002818 }
rniwa@webkit.org76aa5222011-05-04 13:03:32 +00002819
2820 // If we're ignoring spaces, we have to stop and include this object and
2821 // then start ignoring spaces again.
2822 if (isInlineType || current.m_obj->container()->isRenderInline()) {
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00002823 if (ignoringSpaces)
2824 ensureLineBoxInsideIgnoredSpaces(lineMidpointState, current.m_obj);
rniwa@webkit.org76aa5222011-05-04 13:03:32 +00002825 trailingObjects.appendBoxIfNeeded(box);
2826 } else
leviw@chromium.org1a508692011-05-05 00:01:11 +00002827 m_positionedObjects.append(box);
zalan@apple.com6833dd92013-09-27 12:47:52 +00002828 width.addUncommittedWidth(inlineLogicalWidth(current.m_obj), *current.m_obj);
glenn@skynav.com1fa656a2013-03-11 03:30:57 +00002829 // Reset prior line break context characters.
glenn@skynav.com61b1abf2013-04-02 23:28:32 +00002830 renderTextInfo.m_lineBreakIterator.resetPriorContext();
mitz@apple.comd67fb212011-12-19 02:51:46 +00002831 } else if (current.m_obj->isFloating()) {
2832 RenderBox* floatBox = toRenderBox(current.m_obj);
2833 FloatingObject* f = m_block->insertFloatingObject(floatBox);
2834 // check if it fits in the current line.
2835 // If it does, position it now, otherwise, position
2836 // it after moving to next line (in newLine() func)
commit-queue@webkit.org31a3bc72013-03-05 18:19:36 +00002837 // FIXME: Bug 110372: Properly position multiple stacked floats with non-rectangular shape outside.
bjonesbe@adobe.com93de7e72013-09-04 18:01:27 +00002838 if (floatsFitOnLine && width.fitsOnLineExcludingTrailingWhitespace(f->logicalWidth(m_block->isHorizontalWritingMode()))) {
mitz@apple.comd67fb212011-12-19 02:51:46 +00002839 m_block->positionNewFloatOnLine(f, lastFloatFromPreviousLine, lineInfo, width);
2840 if (lBreak.m_obj == current.m_obj) {
2841 ASSERT(!lBreak.m_pos);
2842 lBreak.increment();
2843 }
2844 } else
2845 floatsFitOnLine = false;
glenn@skynav.com1fa656a2013-03-11 03:30:57 +00002846 // Update prior line break context characters, using U+FFFD (OBJECT REPLACEMENT CHARACTER) for floating element.
glenn@skynav.com61b1abf2013-04-02 23:28:32 +00002847 renderTextInfo.m_lineBreakIterator.updatePriorContext(replacementCharacter);
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002848 } else if (current.m_obj->isRenderInline()) {
antti@apple.com3ab7ef32013-09-29 20:50:01 +00002849 RenderInline& flowBox = toRenderInline(*current.m_obj);
bdakinf876bee2007-10-30 05:27:09 +00002850 // Right now, we should only encounter empty inlines here.
antti@apple.com3ab7ef32013-09-29 20:50:01 +00002851 ASSERT(isEmptyInline(flowBox));
eric@webkit.org060caf62011-05-03 22:11:39 +00002852 // Now that some inline flows have line boxes, if we are already ignoring spaces, we need
2853 // to make sure that we stop to include this object and then start ignoring spaces again.
2854 // If this object is at the start of the line, we need to behave like list markers and
bdakinf876bee2007-10-30 05:27:09 +00002855 // start ignoring spaces.
antti@apple.com3ab7ef32013-09-29 20:50:01 +00002856 bool requiresLineBox = alwaysRequiresLineBox(flowBox);
robert@webkit.org56e5a9f2012-02-17 21:10:42 +00002857 if (requiresLineBox || requiresLineBoxForContent(flowBox, lineInfo)) {
2858 // An empty inline that only has line-height, vertical-align or font-metrics will only get a
2859 // line box to affect the height of the line if the rest of the line is not empty.
2860 if (requiresLineBox)
2861 lineInfo.setEmpty(false, m_block, &width);
bdakinf876bee2007-10-30 05:27:09 +00002862 if (ignoringSpaces) {
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002863 trailingObjects.clear();
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00002864 ensureLineBoxInsideIgnoredSpaces(lineMidpointState, current.m_obj);
antti@apple.com78e56772013-09-29 04:34:37 +00002865 } else if (blockStyle.collapseWhiteSpace() && resolver.position().m_obj == current.m_obj
leviw@chromium.org1a508692011-05-05 00:01:11 +00002866 && shouldSkipWhitespaceAfterStartObject(m_block, current.m_obj, lineMidpointState)) {
eric@webkit.org060caf62011-05-03 22:11:39 +00002867 // Like with list markers, we start ignoring spaces to make sure that any
bdakinf876bee2007-10-30 05:27:09 +00002868 // additional spaces we see will be discarded.
2869 currentCharacterIsSpace = true;
2870 currentCharacterIsWS = true;
2871 ignoringSpaces = true;
commit-queue@webkit.org6af48872013-04-09 16:46:49 +00002872 } else {
antti@apple.com3ab7ef32013-09-29 20:50:01 +00002873 trailingObjects.appendBoxIfNeeded(&flowBox);
bdakinf876bee2007-10-30 05:27:09 +00002874 }
2875 }
2876
zalan@apple.com6833dd92013-09-27 12:47:52 +00002877 width.addUncommittedWidth(inlineLogicalWidth(current.m_obj) + borderPaddingMarginStart(flowBox) + borderPaddingMarginEnd(flowBox), *current.m_obj);
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002878 } else if (current.m_obj->isReplaced()) {
2879 RenderBox* replacedBox = toRenderBox(current.m_obj);
hyatt@apple.comd885df72009-01-22 02:31:52 +00002880
robert@webkit.org0903cf52012-12-11 18:14:16 +00002881 if (atStart)
2882 width.updateAvailableWidth(replacedBox->logicalHeight());
2883
hyattde396342003-10-29 08:57:20 +00002884 // Break on replaced elements if either has normal white-space.
robert@webkit.org1f811532013-06-24 20:09:20 +00002885 if ((autoWrap || RenderStyle::autoWrap(lastWS)) && (!current.m_obj->isImage() || allowImagesToBreak))
2886 commitLineBreakAtCurrentWidth(width, lBreak, current.m_obj);
hyatt711fe232002-11-20 21:25:14 +00002887
mitz@apple.combfdc9112008-02-21 19:59:40 +00002888 if (ignoringSpaces)
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00002889 stopIgnoringSpaces(lineMidpointState, InlineIterator(0, current.m_obj, 0));
mitz@apple.combfdc9112008-02-21 19:59:40 +00002890
hyatt@apple.com5950bd42011-09-27 20:39:57 +00002891 lineInfo.setEmpty(false, m_block, &width);
hyatt33f8d492002-11-12 21:44:52 +00002892 ignoringSpaces = false;
rjwc9c257d2003-01-24 03:46:17 +00002893 currentCharacterIsSpace = false;
harrisone343c412005-01-18 01:07:26 +00002894 currentCharacterIsWS = false;
rniwa@webkit.org105350c2011-05-03 20:33:25 +00002895 trailingObjects.clear();
hamaji@chromium.org382642b2009-12-01 07:37:14 +00002896
bdakinf876bee2007-10-30 05:27:09 +00002897 // Optimize for a common case. If we can't find whitespace after the list
hyatt@apple.com0415e5d2010-10-07 17:40:25 +00002898 // item, then this is all moot.
eae@chromium.orgee8613e2011-11-12 01:12:58 +00002899 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 +00002900 if (current.m_obj->isListMarker()) {
antti@apple.com78e56772013-09-29 04:34:37 +00002901 if (blockStyle.collapseWhiteSpace() && shouldSkipWhitespaceAfterStartObject(m_block, current.m_obj, lineMidpointState)) {
eric@webkit.org060caf62011-05-03 22:11:39 +00002902 // Like with inline flows, we start ignoring spaces to make sure that any
bdakinf876bee2007-10-30 05:27:09 +00002903 // additional spaces we see will be discarded.
2904 currentCharacterIsSpace = true;
2905 currentCharacterIsWS = true;
2906 ignoringSpaces = true;
hyatte85e4a72002-12-08 02:06:16 +00002907 }
akling@apple.com4c166d62013-09-01 05:29:00 +00002908 if (toRenderListMarker(*current.m_obj).isInside())
zalan@apple.com6833dd92013-09-27 12:47:52 +00002909 width.addUncommittedWidth(replacedLogicalWidth, *current.m_obj);
justing244d3a32006-04-13 01:31:24 +00002910 } else
zalan@apple.com6833dd92013-09-27 12:47:52 +00002911 width.addUncommittedWidth(replacedLogicalWidth, *current.m_obj);
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002912 if (current.m_obj->isRubyRun())
2913 width.applyOverhang(toRenderRubyRun(current.m_obj), last, next);
glenn@skynav.com1fa656a2013-03-11 03:30:57 +00002914 // Update prior line break context characters, using U+FFFD (OBJECT REPLACEMENT CHARACTER) for replaced element.
glenn@skynav.com61b1abf2013-04-02 23:28:32 +00002915 renderTextInfo.m_lineBreakIterator.updatePriorContext(replacementCharacter);
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002916 } else if (current.m_obj->isText()) {
2917 if (!current.m_pos)
mitz@apple.com51017322008-02-26 06:47:43 +00002918 appliedStartWidth = false;
2919
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002920 RenderText* t = toRenderText(current.m_obj);
mitz@apple.comfb8da4e2008-02-19 21:13:19 +00002921
zimmermann@webkit.org6e96afd2010-09-10 15:35:50 +00002922#if ENABLE(SVG)
2923 bool isSVGText = t->isSVGInlineText();
2924#endif
2925
robert@webkit.orgc5223452013-06-12 19:20:33 +00002926 // If we have left a no-wrap inline and entered an autowrap inline while ignoring spaces
2927 // then we need to mark the start of the autowrap inline as a potential linebreak now.
robert@webkit.org1f811532013-06-24 20:09:20 +00002928 if (autoWrap && !RenderStyle::autoWrap(lastWS) && ignoringSpaces)
2929 commitLineBreakAtCurrentWidth(width, lBreak, current.m_obj);
robert@webkit.orgc5223452013-06-12 19:20:33 +00002930
akling@apple.com4c166d62013-09-01 05:29:00 +00002931 if (t->style()->hasTextCombine() && current.m_obj->isCombineText() && !toRenderCombineText(*current.m_obj).isCombined()) {
2932 RenderCombineText& combineRenderer = toRenderCombineText(*current.m_obj);
2933 combineRenderer.combineText();
leviw@chromium.org17fe64d2013-04-02 23:10:49 +00002934 // The length of the renderer's text may have changed. Increment stale iterator positions
2935 if (iteratorIsBeyondEndOfRenderCombineText(lBreak, combineRenderer)) {
2936 ASSERT(iteratorIsBeyondEndOfRenderCombineText(resolver.position(), combineRenderer));
2937 lBreak.increment();
2938 resolver.increment();
2939 }
2940 }
kociendabb0c24b2001-08-24 14:24:40 +00002941
antti@apple.com78e56772013-09-29 04:34:37 +00002942 const RenderStyle& style = lineStyle(*t->parent(), lineInfo);
antti@apple.comb0608f62013-09-28 18:30:16 +00002943 const Font& f = style.font();
mitz@apple.com34106442009-02-01 06:23:39 +00002944 bool isFixedPitch = f.isFixedPitch();
antti@apple.comb0608f62013-09-28 18:30:16 +00002945 bool canHyphenate = style.hyphens() == HyphensAuto && WebCore::canHyphenate(style.locale());
weinigf28a1c32007-02-14 14:10:31 +00002946
msaboff@apple.com776c286c72012-10-15 16:56:29 +00002947 unsigned lastSpace = current.m_pos;
antti@apple.com78e56772013-09-29 04:34:37 +00002948 float wordSpacing = currentStyle.wordSpacing();
hyatt@apple.com0acc9352011-02-17 19:19:07 +00002949 float lastSpaceWordSpacing = 0;
enrica@apple.com885c84d2012-10-10 05:48:51 +00002950 float wordSpacingForWordMeasurement = 0;
hyattffe78712003-02-11 01:59:29 +00002951
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002952 float wrapW = width.uncommittedWidth() + inlineLogicalWidth(current.m_obj, !appliedStartWidth, true);
hyatt@apple.com0acc9352011-02-17 19:19:07 +00002953 float charWidth = 0;
antti@apple.com78e56772013-09-29 04:34:37 +00002954 bool breakNBSP = autoWrap && currentStyle.nbspMode() == SPACE;
weinigf28a1c32007-02-14 14:10:31 +00002955 // Auto-wrapping text should wrap in the middle of a word only if it could not wrap before the word,
2956 // which is only possible if the word is the first thing on the line, that is, if |w| is zero.
antti@apple.com78e56772013-09-29 04:34:37 +00002957 bool breakWords = currentStyle.breakWords() && ((autoWrap && !width.committedWidth()) || currWS == PRE);
weinigf28a1c32007-02-14 14:10:31 +00002958 bool midWordBreak = false;
antti@apple.com78e56772013-09-29 04:34:37 +00002959 bool breakAll = currentStyle.wordBreak() == BreakAllWordBreak && autoWrap;
hyatt@apple.com0acc9352011-02-17 19:19:07 +00002960 float hyphenWidth = 0;
commit-queue@webkit.org4f54eff2013-03-08 14:32:54 +00002961#if ENABLE(SVG)
2962 if (isSVGText) {
2963 breakWords = false;
2964 breakAll = false;
2965 }
2966#endif
hyattea474f72007-04-20 05:02:19 +00002967
commit-queue@webkit.orgd639fb72012-09-01 19:46:16 +00002968 if (renderTextInfo.m_text != t) {
esprehn@chromium.org7745ffb2013-02-19 21:51:19 +00002969 updateCounterIfNeeded(t);
mitz@apple.com6a859602012-08-27 15:31:56 +00002970 renderTextInfo.m_text = t;
mitz@apple.comd4c153d2012-09-16 23:36:41 +00002971 renderTextInfo.m_font = &f;
mitz@apple.com6a859602012-08-27 15:31:56 +00002972 renderTextInfo.m_layout = f.createLayout(t, width.currentWidth(), collapseWhiteSpace);
antti@apple.comb0608f62013-09-28 18:30:16 +00002973 renderTextInfo.m_lineBreakIterator.resetStringAndReleaseIterator(t->text(), style.locale());
mitz@apple.comd4c153d2012-09-16 23:36:41 +00002974 } else if (renderTextInfo.m_layout && renderTextInfo.m_font != &f) {
2975 renderTextInfo.m_font = &f;
2976 renderTextInfo.m_layout = f.createLayout(t, width.currentWidth(), collapseWhiteSpace);
mitz@apple.com6a859602012-08-27 15:31:56 +00002977 }
mitz@apple.comd4c153d2012-09-16 23:36:41 +00002978
mitz@apple.com6a859602012-08-27 15:31:56 +00002979 TextLayout* textLayout = renderTextInfo.m_layout.get();
2980
mitz@apple.com8520cd82012-09-22 01:00:01 +00002981 // Non-zero only when kerning is enabled and TextLayout isn't used, in which case we measure
2982 // words with their trailing space, then subtract its width.
rniwa@webkit.orgfe811f22013-06-07 17:59:01 +00002983 HashSet<const SimpleFontData*> fallbackFonts;
antti@apple.com78e56772013-09-29 04:34:37 +00002984 float wordTrailingSpaceWidth = (f.typesettingFeatures() & Kerning) && !textLayout ? f.width(RenderBlock::constructTextRun(t, f, &space, 1, style), &fallbackFonts) + wordSpacing : 0;
mitz@apple.com8520cd82012-09-22 01:00:01 +00002985
glenn@skynav.com61b1abf2013-04-02 23:28:32 +00002986 UChar lastCharacter = renderTextInfo.m_lineBreakIterator.lastCharacter();
2987 UChar secondToLastCharacter = renderTextInfo.m_lineBreakIterator.secondToLastCharacter();
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002988 for (; current.m_pos < t->textLength(); current.fastIncrementInTextNode()) {
rjwc9c257d2003-01-24 03:46:17 +00002989 bool previousCharacterIsSpace = currentCharacterIsSpace;
harrisone343c412005-01-18 01:07:26 +00002990 bool previousCharacterIsWS = currentCharacterIsWS;
rniwa@webkit.org15b91522011-05-04 00:38:05 +00002991 UChar c = current.current();
hyattb0d9f602007-01-15 01:28:23 +00002992 currentCharacterIsSpace = c == ' ' || c == '\t' || (!preserveNewline && (c == '\n'));
darin47ece0d2005-09-04 07:42:31 +00002993
hyattb0d9f602007-01-15 01:28:23 +00002994 if (!collapseWhiteSpace || !currentCharacterIsSpace)
hyatt@apple.com5950bd42011-09-27 20:39:57 +00002995 lineInfo.setEmpty(false, m_block, &width);
mitz@apple.combe429562008-03-07 01:09:51 +00002996
antti@apple.comb0608f62013-09-28 18:30:16 +00002997 if (c == softHyphen && autoWrap && !hyphenWidth && style.hyphens() != HyphensNone) {
rniwa@webkit.orgfe811f22013-06-07 17:59:01 +00002998 hyphenWidth = measureHyphenWidth(t, f, &fallbackFonts);
zalan@apple.com6833dd92013-09-27 12:47:52 +00002999 width.addUncommittedWidth(hyphenWidth, *current.m_obj);
hyatt78b85132004-03-29 20:07:45 +00003000 }
mitz@apple.com20e34452010-09-28 19:38:15 +00003001
hyatt3aff2332003-01-23 01:15:28 +00003002 bool applyWordSpacing = false;
eric@webkit.org060caf62011-05-03 22:11:39 +00003003
darinf9e5d6c2007-01-09 14:54:26 +00003004 currentCharacterIsWS = currentCharacterIsSpace || (breakNBSP && c == noBreakSpace);
harrisone343c412005-01-18 01:07:26 +00003005
weiniged111c12007-07-13 22:45:11 +00003006 if ((breakAll || breakWords) && !midWordBreak) {
3007 wrapW += charWidth;
mitz@apple.com880d8e12011-08-17 20:52:31 +00003008 bool midWordBreakIsBeforeSurrogatePair = U16_IS_LEAD(c) && current.m_pos + 1 < t->textLength() && U16_IS_TRAIL(t->characters()[current.m_pos + 1]);
rniwa@webkit.orgfe811f22013-06-07 17:59:01 +00003009 charWidth = textWidth(t, current.m_pos, midWordBreakIsBeforeSurrogatePair ? 2 : 1, f, width.committedWidth() + wrapW, isFixedPitch, collapseWhiteSpace, fallbackFonts, textLayout);
rniwa@webkit.org5eb8d162011-04-13 02:13:33 +00003010 midWordBreak = width.committedWidth() + wrapW + charWidth > width.availableWidth();
weinigf28a1c32007-02-14 14:10:31 +00003011 }
darin47ece0d2005-09-04 07:42:31 +00003012
commit-queue@webkit.orga94b1b32013-02-26 18:38:39 +00003013 bool betweenWords = c == '\n' || (currWS != PRE && !atStart && isBreakable(renderTextInfo.m_lineBreakIterator, current.m_pos, current.m_nextBreakablePosition, breakNBSP)
antti@apple.comb0608f62013-09-28 18:30:16 +00003014 && (style.hyphens() != HyphensNone || (current.previousInSameNode() != softHyphen)));
mitz@apple.com20e34452010-09-28 19:38:15 +00003015
weiniged111c12007-07-13 22:45:11 +00003016 if (betweenWords || midWordBreak) {
hyatt0c05e102006-04-14 08:15:00 +00003017 bool stoppedIgnoringSpaces = false;
hyatt33f8d492002-11-12 21:44:52 +00003018 if (ignoringSpaces) {
leviw@chromium.orga16671e2013-02-20 23:44:21 +00003019 lastSpaceWordSpacing = 0;
rjwc9c257d2003-01-24 03:46:17 +00003020 if (!currentCharacterIsSpace) {
hyatt33f8d492002-11-12 21:44:52 +00003021 // Stop ignoring spaces and begin at this
3022 // new point.
hyatt48710d62003-08-21 09:17:13 +00003023 ignoringSpaces = false;
enrica@apple.com885c84d2012-10-10 05:48:51 +00003024 wordSpacingForWordMeasurement = 0;
rniwa@webkit.org15b91522011-05-04 00:38:05 +00003025 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 +00003026 stopIgnoringSpaces(lineMidpointState, InlineIterator(0, current.m_obj, current.m_pos));
hyatt0c05e102006-04-14 08:15:00 +00003027 stoppedIgnoringSpaces = true;
harrisone343c412005-01-18 01:07:26 +00003028 } else {
hyatt33f8d492002-11-12 21:44:52 +00003029 // Just keep ignoring these spaces.
glenn@skynav.com1fa656a2013-03-11 03:30:57 +00003030 goto nextCharacter;
hyatt33f8d492002-11-12 21:44:52 +00003031 }
3032 }
rjwc9c257d2003-01-24 03:46:17 +00003033
enrica@apple.com885c84d2012-10-10 05:48:51 +00003034 wordMeasurements.grow(wordMeasurements.size() + 1);
3035 WordMeasurement& wordMeasurement = wordMeasurements.last();
3036
3037 wordMeasurement.renderer = t;
3038 wordMeasurement.endOffset = current.m_pos;
3039 wordMeasurement.startOffset = lastSpace;
zoltan@webkit.orge1a0c952013-09-18 03:27:35 +00003040
commit-queue@webkit.org17761402013-04-17 18:48:56 +00003041 float additionalTempWidth;
mitz@apple.comdc33a5f62012-11-28 19:43:24 +00003042 if (wordTrailingSpaceWidth && c == ' ')
rniwa@webkit.orgfe811f22013-06-07 17:59:01 +00003043 additionalTempWidth = 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 +00003044 else
rniwa@webkit.orgfe811f22013-06-07 17:59:01 +00003045 additionalTempWidth = textWidth(t, lastSpace, current.m_pos - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, wordMeasurement.fallbackFonts, textLayout);
3046
3047 if (wordMeasurement.fallbackFonts.isEmpty() && !fallbackFonts.isEmpty())
3048 wordMeasurement.fallbackFonts.swap(fallbackFonts);
3049 fallbackFonts.clear();
enrica@apple.com885c84d2012-10-10 05:48:51 +00003050
commit-queue@webkit.org17761402013-04-17 18:48:56 +00003051 wordMeasurement.width = additionalTempWidth + wordSpacingForWordMeasurement;
3052 additionalTempWidth += lastSpaceWordSpacing;
zalan@apple.com6833dd92013-09-27 12:47:52 +00003053 width.addUncommittedWidth(additionalTempWidth, *current.m_obj);
commit-queue@webkit.org17761402013-04-17 18:48:56 +00003054
3055 if (collapseWhiteSpace && previousCharacterIsSpace && currentCharacterIsSpace && additionalTempWidth)
3056 width.setTrailingWhitespaceWidth(additionalTempWidth);
3057
hyattffe78712003-02-11 01:59:29 +00003058 if (!appliedStartWidth) {
zalan@apple.com6833dd92013-09-27 12:47:52 +00003059 width.addUncommittedWidth(inlineLogicalWidth(current.m_obj, true, false), *current.m_obj);
hyattffe78712003-02-11 01:59:29 +00003060 appliedStartWidth = true;
3061 }
eric@webkit.org060caf62011-05-03 22:11:39 +00003062
zoltan@webkit.orge1a0c952013-09-18 03:27:35 +00003063#if ENABLE(CSS_SHAPES)
3064 if (lastFloatFromPreviousLine)
3065 updateSegmentsForShapes(m_block, lastFloatFromPreviousLine, wordMeasurements, width, lineInfo.isFirstLine());
3066#endif
enrica@apple.com885c84d2012-10-10 05:48:51 +00003067 applyWordSpacing = wordSpacing && currentCharacterIsSpace;
hyatt3aff2332003-01-23 01:15:28 +00003068
rniwa@webkit.org5eb8d162011-04-13 02:13:33 +00003069 if (!width.committedWidth() && autoWrap && !width.fitsOnLine())
rniwa@webkit.org44424752011-04-14 00:58:40 +00003070 width.fitBelowFloats();
mitz@apple.comcfd9b7b2008-02-24 04:00:21 +00003071
hyattb0d9f602007-01-15 01:28:23 +00003072 if (autoWrap || breakWords) {
hyattdca76e92005-11-02 08:52:50 +00003073 // If we break only after white-space, consider the current character
kociendae4134242004-10-25 18:48:44 +00003074 // as candidate width for this line.
ap932806a2006-10-01 09:06:09 +00003075 bool lineWasTooWide = false;
antti@apple.com78e56772013-09-29 04:34:37 +00003076 if (width.fitsOnLine() && currentCharacterIsWS && currentStyle.breakOnlyAfterWhiteSpace() && !midWordBreak) {
rniwa@webkit.orgfe811f22013-06-07 17:59:01 +00003077 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 +00003078 // Check if line is too big even without the extra space
eric@webkit.org060caf62011-05-03 22:11:39 +00003079 // at the end of the line. If it is not, do nothing.
3080 // If the line needs the extra whitespace to be too long,
3081 // then move the line break to the space and skip all
ap932806a2006-10-01 09:06:09 +00003082 // additional whitespace.
robert@webkit.org7a80c022013-06-21 21:04:21 +00003083 if (!width.fitsOnLineIncludingExtraWidth(charWidth)) {
ap932806a2006-10-01 09:06:09 +00003084 lineWasTooWide = true;
rniwa@webkit.org15b91522011-05-04 00:38:05 +00003085 lBreak.moveTo(current.m_obj, current.m_pos, current.m_nextBreakablePosition);
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +00003086 skipTrailingWhitespace(lBreak, lineInfo);
kocienda9dbe9b12004-10-22 20:07:05 +00003087 }
ap932806a2006-10-01 09:06:09 +00003088 }
rniwa@webkit.org5eb8d162011-04-13 02:13:33 +00003089 if (lineWasTooWide || !width.fitsOnLine()) {
3090 if (canHyphenate && !width.fitsOnLine()) {
antti@apple.com78e56772013-09-29 04:34:37 +00003091 tryHyphenating(t, f, style.locale(), consecutiveHyphenatedLines, blockStyle.hyphenationLimitLines(), style.hyphenationLimitBefore(), style.hyphenationLimitAfter(), lastSpace, current.m_pos, width.currentWidth() - additionalTempWidth, width.availableWidth(), isFixedPitch, collapseWhiteSpace, lastSpaceWordSpacing, lBreak, current.m_nextBreakablePosition, m_hyphenated);
leviw@chromium.org1a508692011-05-05 00:01:11 +00003092 if (m_hyphenated)
mitz@apple.com67ed70a2010-06-22 22:10:10 +00003093 goto end;
3094 }
leviw@chromium.orgcee20512011-04-06 12:12:58 +00003095 if (lBreak.atTextParagraphSeparator()) {
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00003096 if (!stoppedIgnoringSpaces && current.m_pos > 0)
3097 ensureCharacterGetsLineBox(lineMidpointState, current);
mitz@apple.com1a301772008-03-11 18:30:36 +00003098 lBreak.increment();
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +00003099 lineInfo.setPreviousLineBrokeCleanly(true);
enrica@apple.com885c84d2012-10-10 05:48:51 +00003100 wordMeasurement.endOffset = lBreak.m_pos;
adele7fc3e832006-02-17 09:31:35 +00003101 }
antti@apple.comb0608f62013-09-28 18:30:16 +00003102 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 +00003103 m_hyphenated = true;
enrica@apple.com885c84d2012-10-10 05:48:51 +00003104 if (lBreak.m_pos && lBreak.m_pos != (unsigned)wordMeasurement.endOffset && !wordMeasurement.width) {
3105 if (charWidth) {
3106 wordMeasurement.endOffset = lBreak.m_pos;
3107 wordMeasurement.width = charWidth;
3108 }
3109 }
commit-queue@webkit.org63cc2d02013-01-02 22:52:58 +00003110 // Didn't fit. Jump to the end unless there's still an opportunity to collapse whitespace.
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00003111 if (ignoringSpaces || !collapseWhiteSpace || !currentCharacterIsSpace || !previousCharacterIsSpace)
commit-queue@webkit.org63cc2d02013-01-02 22:52:58 +00003112 goto end;
darin54008922006-01-13 16:39:05 +00003113 } else {
weiniged111c12007-07-13 22:45:11 +00003114 if (!betweenWords || (midWordBreak && !autoWrap))
zalan@apple.com6833dd92013-09-27 12:47:52 +00003115 width.addUncommittedWidth(-additionalTempWidth, *current.m_obj);
mitz@apple.com20e34452010-09-28 19:38:15 +00003116 if (hyphenWidth) {
darin54008922006-01-13 16:39:05 +00003117 // Subtract the width of the soft hyphen out since we fit on a line.
zalan@apple.com6833dd92013-09-27 12:47:52 +00003118 width.addUncommittedWidth(-hyphenWidth, *current.m_obj);
mitz@apple.com20e34452010-09-28 19:38:15 +00003119 hyphenWidth = 0;
3120 }
darin54008922006-01-13 16:39:05 +00003121 }
rjwc9c257d2003-01-24 03:46:17 +00003122 }
hyatt33f8d492002-11-12 21:44:52 +00003123
hyattb0d9f602007-01-15 01:28:23 +00003124 if (c == '\n' && preserveNewline) {
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00003125 if (!stoppedIgnoringSpaces && current.m_pos > 0)
3126 ensureCharacterGetsLineBox(lineMidpointState, current);
rniwa@webkit.org15b91522011-05-04 00:38:05 +00003127 lBreak.moveTo(current.m_obj, current.m_pos, current.m_nextBreakablePosition);
mitz@apple.com1a301772008-03-11 18:30:36 +00003128 lBreak.increment();
leviw@chromium.orgf009c8e2011-05-03 20:49:15 +00003129 lineInfo.setPreviousLineBrokeCleanly(true);
hyatt33f8d492002-11-12 21:44:52 +00003130 return lBreak;
3131 }
hyatta9f48e32003-02-03 22:48:01 +00003132
weinigf28a1c32007-02-14 14:10:31 +00003133 if (autoWrap && betweenWords) {
weiniged111c12007-07-13 22:45:11 +00003134 wrapW = 0;
robert@webkit.org1f811532013-06-24 20:09:20 +00003135 commitLineBreakAtCurrentWidth(width, lBreak, current.m_obj, current.m_pos, current.m_nextBreakablePosition);
weinigf28a1c32007-02-14 14:10:31 +00003136 // Auto-wrapping text should not wrap in the middle of a word once it has had an
3137 // opportunity to break after a word.
3138 breakWords = false;
hyatta9f48e32003-02-03 22:48:01 +00003139 }
eric@webkit.org060caf62011-05-03 22:11:39 +00003140
mitz@apple.com86877722011-08-19 16:29:32 +00003141 if (midWordBreak && !U16_IS_TRAIL(c) && !(category(c) & (Mark_NonSpacing | Mark_Enclosing | Mark_SpacingCombining))) {
darin54008922006-01-13 16:39:05 +00003142 // Remember this as a breakable position in case
3143 // adding the end width forces a break.
rniwa@webkit.org15b91522011-05-04 00:38:05 +00003144 lBreak.moveTo(current.m_obj, current.m_pos, current.m_nextBreakablePosition);
weiniged111c12007-07-13 22:45:11 +00003145 midWordBreak &= (breakWords || breakAll);
3146 }
3147
3148 if (betweenWords) {
darin54008922006-01-13 16:39:05 +00003149 lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
enrica@apple.com885c84d2012-10-10 05:48:51 +00003150 wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurement.width) ? wordSpacing : 0;
rniwa@webkit.org15b91522011-05-04 00:38:05 +00003151 lastSpace = current.m_pos;
darin54008922006-01-13 16:39:05 +00003152 }
eric@webkit.org060caf62011-05-03 22:11:39 +00003153
antti@apple.com78e56772013-09-29 04:34:37 +00003154 if (!ignoringSpaces && currentStyle.collapseWhiteSpace()) {
hyatt33f8d492002-11-12 21:44:52 +00003155 // If we encounter a newline, or if we encounter a
3156 // second space, we need to go ahead and break up this
3157 // run and enter a mode where we start collapsing spaces.
hyatt98b16282004-03-31 18:43:12 +00003158 if (currentCharacterIsSpace && previousCharacterIsSpace) {
hyatt33f8d492002-11-12 21:44:52 +00003159 ignoringSpaces = true;
eric@webkit.org060caf62011-05-03 22:11:39 +00003160
hyatt33f8d492002-11-12 21:44:52 +00003161 // We just entered a mode where we are ignoring
3162 // spaces. Create a midpoint to terminate the run
eric@webkit.org060caf62011-05-03 22:11:39 +00003163 // before the second space.
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00003164 startIgnoringSpaces(lineMidpointState, ignoreStart);
mitz@apple.come98acc92011-05-22 04:44:27 +00003165 trailingObjects.updateMidpointsForTrailingBoxes(lineMidpointState, InlineIterator(), TrailingObjects::DoNotCollapseFirstSpace);
hyatt33f8d492002-11-12 21:44:52 +00003166 }
3167 }
eseidel789896f2005-11-27 22:52:09 +00003168 } else if (ignoringSpaces) {
hyatt33f8d492002-11-12 21:44:52 +00003169 // Stop ignoring spaces and begin at this
3170 // new point.
3171 ignoringSpaces = false;
eseideld13fe532005-11-30 02:40:29 +00003172 lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
enrica@apple.com885c84d2012-10-10 05:48:51 +00003173 wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurements.last().width) ? wordSpacing : 0;
rniwa@webkit.org15b91522011-05-04 00:38:05 +00003174 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 +00003175 stopIgnoringSpaces(lineMidpointState, InlineIterator(0, current.m_obj, current.m_pos));
hyatt33f8d492002-11-12 21:44:52 +00003176 }
hyatt98b16282004-03-31 18:43:12 +00003177
zimmermann@webkit.orgcea314662011-04-05 16:38:10 +00003178#if ENABLE(SVG)
rniwa@webkit.org15b91522011-05-04 00:38:05 +00003179 if (isSVGText && current.m_pos > 0) {
zimmermann@webkit.orgcea314662011-04-05 16:38:10 +00003180 // Force creation of new InlineBoxes for each absolute positioned character (those that start new text chunks).
leviw@chromium.org0e7d89e2013-02-23 00:00:27 +00003181 if (toRenderSVGInlineText(t)->characterStartsNewTextChunk(current.m_pos))
3182 ensureCharacterGetsLineBox(lineMidpointState, current);
zimmermann@webkit.orgcea314662011-04-05 16:38:10 +00003183 }
3184#endif
3185
hyatt98b16282004-03-31 18:43:12 +00003186 if (currentCharacterIsSpace && !previousCharacterIsSpace) {
rniwa@webkit.org15b91522011-05-04 00:38:05 +00003187 ignoreStart.m_obj = current.m_obj;
3188 ignoreStart.m_pos = current.m_pos;
robert@webkit.org2cb02642013-09-18 17:58:25 +00003189 // Spaces after right-aligned text and before a line-break get collapsed away completely so that the trailing
3190 // space doesn't seem to push the text out from the right-hand edge.
3191 // FIXME: Do this regardless of the container's alignment - will require rebaselining a lot of test results.
antti@apple.com78e56772013-09-29 04:34:37 +00003192 if (next && next->isBR() && (blockStyle.textAlign() == RIGHT || blockStyle.textAlign() == WEBKIT_RIGHT)) {
robert@webkit.org2cb02642013-09-18 17:58:25 +00003193 ignoreStart.m_pos--;
3194 // If there's just a single trailing space start ignoring it now so it collapses away.
3195 if (current.m_pos == t->textLength() - 1)
3196 startIgnoringSpaces(lineMidpointState, ignoreStart);
3197 }
hyatt98b16282004-03-31 18:43:12 +00003198 }
harrisone343c412005-01-18 01:07:26 +00003199
3200 if (!currentCharacterIsWS && previousCharacterIsWS) {
antti@apple.com78e56772013-09-29 04:34:37 +00003201 if (autoWrap && currentStyle.breakOnlyAfterWhiteSpace())
rniwa@webkit.org15b91522011-05-04 00:38:05 +00003202 lBreak.moveTo(current.m_obj, current.m_pos, current.m_nextBreakablePosition);
harrisone343c412005-01-18 01:07:26 +00003203 }
eric@webkit.org060caf62011-05-03 22:11:39 +00003204
hyattb0d9f602007-01-15 01:28:23 +00003205 if (collapseWhiteSpace && currentCharacterIsSpace && !ignoringSpaces)
jchaffraix@webkit.org3e44dfa2011-06-20 23:14:23 +00003206 trailingObjects.setTrailingWhitespace(toRenderText(current.m_obj));
antti@apple.com78e56772013-09-29 04:34:37 +00003207 else if (!currentStyle.collapseWhiteSpace() || !currentCharacterIsSpace)
rniwa@webkit.org105350c2011-05-03 20:33:25 +00003208 trailingObjects.clear();
3209
ddkilzere8759ef2007-03-25 06:28:19 +00003210 atStart = false;
glenn@skynav.com1fa656a2013-03-11 03:30:57 +00003211 nextCharacter:
glenn@skynav.com61b1abf2013-04-02 23:28:32 +00003212 secondToLastCharacter = lastCharacter;
3213 lastCharacter = c;
hyatt33f8d492002-11-12 21:44:52 +00003214 }
mitz@apple.comfb8da4e2008-02-19 21:13:19 +00003215
glenn@skynav.com61b1abf2013-04-02 23:28:32 +00003216 renderTextInfo.m_lineBreakIterator.setPriorContext(lastCharacter, secondToLastCharacter);
glenn@skynav.com1fa656a2013-03-11 03:30:57 +00003217
enrica@apple.com885c84d2012-10-10 05:48:51 +00003218 wordMeasurements.grow(wordMeasurements.size() + 1);
3219 WordMeasurement& wordMeasurement = wordMeasurements.last();
3220 wordMeasurement.renderer = t;
3221
rniwa@webkit.org15b91522011-05-04 00:38:05 +00003222 // IMPORTANT: current.m_pos is > length here!
rniwa@webkit.orgfe811f22013-06-07 17:59:01 +00003223 float additionalTempWidth = ignoringSpaces ? 0 : textWidth(t, lastSpace, current.m_pos - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, wordMeasurement.fallbackFonts, textLayout);
enrica@apple.com885c84d2012-10-10 05:48:51 +00003224 wordMeasurement.startOffset = lastSpace;
3225 wordMeasurement.endOffset = current.m_pos;
commit-queue@webkit.org17761402013-04-17 18:48:56 +00003226 wordMeasurement.width = ignoringSpaces ? 0 : additionalTempWidth + wordSpacingForWordMeasurement;
3227 additionalTempWidth += lastSpaceWordSpacing;
3228
3229 float inlineLogicalTempWidth = inlineLogicalWidth(current.m_obj, !appliedStartWidth, includeEndWidth);
zalan@apple.com6833dd92013-09-27 12:47:52 +00003230 width.addUncommittedWidth(additionalTempWidth + inlineLogicalTempWidth, *current.m_obj);
commit-queue@webkit.org17761402013-04-17 18:48:56 +00003231
rniwa@webkit.orgfe811f22013-06-07 17:59:01 +00003232 if (wordMeasurement.fallbackFonts.isEmpty() && !fallbackFonts.isEmpty())
3233 wordMeasurement.fallbackFonts.swap(fallbackFonts);
3234 fallbackFonts.clear();
3235
commit-queue@webkit.org17761402013-04-17 18:48:56 +00003236 if (collapseWhiteSpace && currentCharacterIsSpace && additionalTempWidth)
robert@webkit.orgc5223452013-06-12 19:20:33 +00003237 width.setTrailingWhitespaceWidth(additionalTempWidth, inlineLogicalTempWidth);
commit-queue@webkit.org17761402013-04-17 18:48:56 +00003238
yael.aharon@nokia.com1cfbceb2011-06-06 18:32:54 +00003239 includeEndWidth = false;
mitz@apple.comb2107652010-06-21 16:54:52 +00003240
rniwa@webkit.org5eb8d162011-04-13 02:13:33 +00003241 if (!width.fitsOnLine()) {
mitz@apple.com96cf46d2011-03-14 01:09:26 +00003242 if (canHyphenate)
antti@apple.com78e56772013-09-29 04:34:37 +00003243 tryHyphenating(t, f, style.locale(), consecutiveHyphenatedLines, blockStyle.hyphenationLimitLines(), style.hyphenationLimitBefore(), style.hyphenationLimitAfter(), lastSpace, current.m_pos, width.currentWidth() - additionalTempWidth, width.availableWidth(), isFixedPitch, collapseWhiteSpace, lastSpaceWordSpacing, lBreak, current.m_nextBreakablePosition, m_hyphenated);
rniwa@webkit.org58925e82011-04-12 21:32:58 +00003244
antti@apple.comb0608f62013-09-28 18:30:16 +00003245 if (!m_hyphenated && lBreak.previousInSameNode() == softHyphen && style.hyphens() != HyphensNone)
leviw@chromium.org1a508692011-05-05 00:01:11 +00003246 m_hyphenated = true;
rniwa@webkit.org58925e82011-04-12 21:32:58 +00003247
leviw@chromium.org1a508692011-05-05 00:01:11 +00003248 if (m_hyphenated)
mitz@apple.comb2107652010-06-21 16:54:52 +00003249 goto end;
3250 }
antti@apple.com3014ac02013-09-18 14:33:55 +00003251 } else if (current.m_obj->isLineBreakOpportunity())
3252 commitLineBreakAtCurrentWidth(width, lBreak, current.m_obj);
3253 else
weinigf28a1c32007-02-14 14:10:31 +00003254 ASSERT_NOT_REACHED();
kociendabb0c24b2001-08-24 14:24:40 +00003255
robert@webkit.org6ce4b392013-07-02 19:30:32 +00003256 bool canBreakHere = canBreakAtThisPosition(autoWrap, width, lBreak, next, current, currWS, currentCharacterIsSpace, autoWrapWasEverTrueOnLine);
3257 if (canBreakHere && !width.fitsOnLine(ignoringSpaces)) {
kociendabb0c24b2001-08-24 14:24:40 +00003258 // if we have floats, try to get below them.
antti@apple.com78e56772013-09-29 04:34:37 +00003259 if (currentCharacterIsSpace && !ignoringSpaces && currentStyle.collapseWhiteSpace())
rniwa@webkit.org105350c2011-05-03 20:33:25 +00003260 trailingObjects.clear();
mitz@apple.comcfd9b7b2008-02-24 04:00:21 +00003261
rniwa@webkit.org58925e82011-04-12 21:32:58 +00003262 if (width.committedWidth())
mitz@apple.comcfd9b7b2008-02-24 04:00:21 +00003263 goto end;
3264
rniwa@webkit.org44424752011-04-14 00:58:40 +00003265 width.fitBelowFloats();
hyattf14a4a32002-11-21 22:06:32 +00003266
hyatta14d1742003-01-02 20:25:46 +00003267 // |width| may have been adjusted because we got shoved down past a float (thus
3268 // giving us more room), so we need to retest, and only jump to
3269 // the end label if we still don't fit on the line. -dwh
robert@webkit.org7a80c022013-06-21 21:04:21 +00003270 if (!width.fitsOnLine(ignoringSpaces))
hyatta14d1742003-01-02 20:25:46 +00003271 goto end;
antti@apple.com78e56772013-09-29 04:34:37 +00003272 } else if (blockStyle.autoWrap() && !width.fitsOnLine() && !width.committedWidth()) {
robert@webkit.org744e01c2013-01-02 20:18:15 +00003273 // If the container autowraps but the current child does not then we still need to ensure that it
3274 // wraps and moves below any floats.
3275 width.fitBelowFloats();
kociendabb0c24b2001-08-24 14:24:40 +00003276 }
hyatt1d9e29b2003-04-10 01:48:53 +00003277
simon.fraser@apple.com2f071852012-06-25 00:11:30 +00003278 if (!current.m_obj->isFloatingOrOutOfFlowPositioned()) {
rniwa@webkit.org15b91522011-05-04 00:38:05 +00003279 last = current.m_obj;
akling@apple.com4c166d62013-09-01 05:29:00 +00003280 if (last->isReplaced() && autoWrap && (!last->isImage() || allowImagesToBreak) && (!last->isListMarker() || toRenderListMarker(*last).isInside()))
robert@webkit.org1f811532013-06-24 20:09:20 +00003281 commitLineBreakAtCurrentWidth(width, lBreak, next);
hyatt711fe232002-11-20 21:25:14 +00003282 }
3283
hyatta9f48e32003-02-03 22:48:01 +00003284 // Clear out our character space bool, since inline <pre>s don't collapse whitespace
3285 // with adjacent inline normal/nowrap spans.
hyattb0d9f602007-01-15 01:28:23 +00003286 if (!collapseWhiteSpace)
hyatta9f48e32003-02-03 22:48:01 +00003287 currentCharacterIsSpace = false;
eric@webkit.org060caf62011-05-03 22:11:39 +00003288
rniwa@webkit.org15b91522011-05-04 00:38:05 +00003289 current.moveToStartOf(next);
ddkilzere8759ef2007-03-25 06:28:19 +00003290 atStart = false;
kociendabb0c24b2001-08-24 14:24:40 +00003291 }
eric@webkit.org060caf62011-05-03 22:11:39 +00003292
robert@webkit.org7a80c022013-06-21 21:04:21 +00003293 if (width.fitsOnLine(true) || lastWS == NOWRAP)
eric@webkit.orgbd143592011-03-29 17:44:41 +00003294 lBreak.clear();
kociendabb0c24b2001-08-24 14:24:40 +00003295
3296 end:
betravis@adobe.comed90c982013-06-05 23:05:57 +00003297#if ENABLE(CSS_SHAPES)
betravis@adobe.comcf7cba62013-06-10 21:23:45 +00003298 ShapeInsideInfo* shapeInfo = m_block->layoutShapeInsideInfo();
betravis@adobe.com9e5e8242013-04-19 23:28:26 +00003299 bool segmentAllowsOverflow = !shapeInfo || !shapeInfo->hasSegments();
3300#else
3301 bool segmentAllowsOverflow = true;
3302#endif
3303
akling@apple.comf294cf02013-07-17 18:46:39 +00003304 if (segmentAllowsOverflow) {
3305 if (lBreak == resolver.position()) {
3306 if (!lBreak.m_obj || !lBreak.m_obj->isBR()) {
3307 // we just add as much as possible
antti@apple.com78e56772013-09-29 04:34:37 +00003308 if (blockStyle.whiteSpace() == PRE && !current.m_pos) {
akling@apple.comf294cf02013-07-17 18:46:39 +00003309 lBreak.moveTo(last, last->isText() ? last->length() : 0);
3310 } else if (lBreak.m_obj) {
3311 // Don't ever break in the middle of a word if we can help it.
3312 // There's no room at all. We just have to be on this line,
3313 // even though we'll spill out.
3314 lBreak.moveTo(current.m_obj, current.m_pos);
3315 }
3316 }
3317 // make sure we consume at least one char/object.
3318 if (lBreak == resolver.position())
3319 lBreak.increment();
zalan@apple.com6833dd92013-09-27 12:47:52 +00003320 } else if (!current.m_pos && !width.committedWidth() && current.m_obj && width.uncommittedWidthForObject(*current.m_obj) == width.uncommittedWidth()) {
akling@apple.comf294cf02013-07-17 18:46:39 +00003321 // Do not push the current object to the next line, when this line has some content, but it is still considered empty.
3322 // Empty inline elements like <span></span> can produce such lines and now we just ignore these break opportunities
3323 // at the start of a line, if no width has been committed yet.
3324 // Behave as if it was actually empty and consume at least one object.
3325 lBreak.increment();
kociendabb0c24b2001-08-24 14:24:40 +00003326 }
3327 }
3328
hyattfe99c872003-07-31 22:25:29 +00003329 // Sanity check our midpoints.
hyatt@apple.comb3466af2009-06-13 06:04:40 +00003330 checkMidpoints(lineMidpointState, lBreak);
hyatt@apple.com63a8df32011-03-28 19:44:19 +00003331
mitz@apple.come98acc92011-05-22 04:44:27 +00003332 trailingObjects.updateMidpointsForTrailingBoxes(lineMidpointState, lBreak, TrailingObjects::CollapseFirstSpace);
rjwc9c257d2003-01-24 03:46:17 +00003333
mjs54b64002003-04-02 02:59:02 +00003334 // We might have made lBreak an iterator that points past the end
3335 // of the object. Do this adjustment to make it point to the start
3336 // of the next object instead to avoid confusing the rest of the
3337 // code.
eric@webkit.org86a865a2011-03-29 15:30:41 +00003338 if (lBreak.m_pos > 0) {
3339 lBreak.m_pos--;
mitz@apple.com1a301772008-03-11 18:30:36 +00003340 lBreak.increment();
mjs54b64002003-04-02 02:59:02 +00003341 }
3342
kociendabb0c24b2001-08-24 14:24:40 +00003343 return lBreak;
3344}
3345
hyatt@apple.com5dc5a312009-08-18 19:15:19 +00003346void RenderBlock::addOverflowFromInlineChildren()
hyattb4b20872004-10-20 21:34:01 +00003347{
eae@chromium.org9717cd82012-11-07 18:33:44 +00003348 LayoutUnit endPadding = hasOverflowClip() ? paddingEnd() : LayoutUnit();
hyatt@apple.com592848f2010-12-06 20:03:43 +00003349 // FIXME: Need to find another way to do this, since scrollbars could show when we don't want them to.
antti@apple.com8f335082013-09-09 19:54:33 +00003350 if (hasOverflowClip() && !endPadding && element() && element()->isRootEditableElement() && style()->isLeftToRightDirection())
hyatt@apple.com592848f2010-12-06 20:03:43 +00003351 endPadding = 1;
hyattb4b20872004-10-20 21:34:01 +00003352 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
hyatt@apple.com592848f2010-12-06 20:03:43 +00003353 addLayoutOverflow(curr->paddedLayoutOverflowRect(endPadding));
abucur@adobe.com6585d012013-09-04 08:26:41 +00003354 RenderRegion* region = curr->containingRegion();
3355 if (region)
3356 region->addLayoutOverflowForBox(this, curr->paddedLayoutOverflowRect(endPadding));
3357 if (!hasOverflowClip()) {
hyatt@apple.com61f25322011-03-31 20:40:48 +00003358 addVisualOverflow(curr->visualOverflowRect(curr->lineTop(), curr->lineBottom()));
abucur@adobe.com6585d012013-09-04 08:26:41 +00003359 if (region)
3360 region->addVisualOverflowForBox(this, curr->visualOverflowRect(curr->lineTop(), curr->lineBottom()));
3361 }
hyattb4b20872004-10-20 21:34:01 +00003362 }
3363}
3364
hyatted77ad82004-06-15 07:21:23 +00003365void RenderBlock::deleteEllipsisLineBoxes()
3366{
benjamin@webkit.orgf68b1be2012-06-23 02:02:28 +00003367 ETextAlign textAlign = style()->textAlign();
3368 bool ltr = style()->isLeftToRightDirection();
3369 bool firstLine = true;
3370 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
3371 if (curr->hasEllipsisBox()) {
3372 curr->clearTruncation();
3373
3374 // Shift the line back where it belongs if we cannot accomodate an ellipsis.
3375 float logicalLeft = pixelSnappedLogicalLeftOffsetForLine(curr->lineTop(), firstLine);
3376 float availableLogicalWidth = logicalRightOffsetForLine(curr->lineTop(), false) - logicalLeft;
3377 float totalLogicalWidth = curr->logicalWidth();
3378 updateLogicalWidthForAlignment(textAlign, 0, logicalLeft, totalLogicalWidth, availableLogicalWidth, 0);
3379
3380 if (ltr)
3381 curr->adjustLogicalPosition((logicalLeft - curr->logicalLeft()), 0);
3382 else
3383 curr->adjustLogicalPosition(-(curr->logicalLeft() - logicalLeft), 0);
3384 }
3385 firstLine = false;
3386 }
hyatted77ad82004-06-15 07:21:23 +00003387}
3388
3389void RenderBlock::checkLinesForTextOverflow()
3390{
3391 // Determine the width of the ellipsis using the current font.
darindbba2bb2007-01-11 12:23:49 +00003392 // 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 +00003393 const Font& font = style()->font();
bolsinga@apple.com97e42c42008-11-15 04:47:20 +00003394 DEFINE_STATIC_LOCAL(AtomicString, ellipsisStr, (&horizontalEllipsis, 1));
hyatt3e99d1c2006-02-24 21:13:08 +00003395 const Font& firstLineFont = firstLineStyle()->font();
antti@apple.com78e56772013-09-29 04:34:37 +00003396 int firstLineEllipsisWidth = firstLineFont.width(constructTextRun(this, firstLineFont, &horizontalEllipsis, 1, *firstLineStyle()));
3397 int ellipsisWidth = (font == firstLineFont) ? firstLineEllipsisWidth : font.width(constructTextRun(this, font, &horizontalEllipsis, 1, *style()));
hyatted77ad82004-06-15 07:21:23 +00003398
3399 // For LTR text truncation, we want to get the right edge of our padding box, and then we want to see
3400 // if the right edge of a line box exceeds that. For RTL, we use the left edge of the padding box and
3401 // check the left edge of the line box to see if it is less
3402 // Include the scrollbar for overflow blocks, which means we want to use "contentWidth()"
hyatt@apple.comc0fa1632010-09-30 20:01:33 +00003403 bool ltr = style()->isLeftToRightDirection();
benjamin@webkit.orgf68b1be2012-06-23 02:02:28 +00003404 ETextAlign textAlign = style()->textAlign();
3405 bool firstLine = true;
hyatted77ad82004-06-15 07:21:23 +00003406 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
eae@chromium.org275da182012-12-19 23:07:55 +00003407 // FIXME: Use pixelSnappedLogicalRightOffsetForLine instead of snapping it ourselves once the column workaround in said method has been fixed.
3408 // https://bugs.webkit.org/show_bug.cgi?id=105461
commit-queue@webkit.orgbbac21e2013-06-21 15:45:21 +00003409 int blockRightEdge = snapSizeToPixel(logicalRightOffsetForLine(curr->lineTop(), firstLine), curr->x());
3410 int blockLeftEdge = pixelSnappedLogicalLeftOffsetForLine(curr->lineTop(), firstLine);
eae@chromium.orgc491d962012-12-28 18:32:08 +00003411 int lineBoxEdge = ltr ? snapSizeToPixel(curr->x() + curr->logicalWidth(), curr->x()) : snapSizeToPixel(curr->x(), 0);
dglazkov@chromium.org28434e62009-05-13 22:30:10 +00003412 if ((ltr && lineBoxEdge > blockRightEdge) || (!ltr && lineBoxEdge < blockLeftEdge)) {
hyattf918d2d2004-06-15 07:24:11 +00003413 // 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 +00003414 // can be truncated. In order for truncation to be possible, the line must have sufficient space to
3415 // accommodate our truncation string, and no replaced elements (images, tables) can overlap the ellipsis
3416 // space.
benjamin@webkit.orgf68b1be2012-06-23 02:02:28 +00003417
3418 LayoutUnit width = firstLine ? firstLineEllipsisWidth : ellipsisWidth;
eae@chromium.orgee8613e2011-11-12 01:12:58 +00003419 LayoutUnit blockEdge = ltr ? blockRightEdge : blockLeftEdge;
benjamin@webkit.orgf68b1be2012-06-23 02:02:28 +00003420 if (curr->lineCanAccommodateEllipsis(ltr, blockEdge, lineBoxEdge, width)) {
3421 float totalLogicalWidth = curr->placeEllipsis(ellipsisStr, ltr, blockLeftEdge, blockRightEdge, width);
3422
akling@apple.comf294cf02013-07-17 18:46:39 +00003423 float logicalLeft = 0; // We are only interested in the delta from the base position.
commit-queue@webkit.orgbbac21e2013-06-21 15:45:21 +00003424 float truncatedWidth = pixelSnappedLogicalRightOffsetForLine(curr->lineTop(), firstLine);
benjamin@webkit.orgf68b1be2012-06-23 02:02:28 +00003425 updateLogicalWidthForAlignment(textAlign, 0, logicalLeft, totalLogicalWidth, truncatedWidth, 0);
3426 if (ltr)
3427 curr->adjustLogicalPosition(logicalLeft, 0);
3428 else
3429 curr->adjustLogicalPosition(-(truncatedWidth - (logicalLeft + totalLogicalWidth)), 0);
3430 }
hyatted77ad82004-06-15 07:21:23 +00003431 }
benjamin@webkit.orgf68b1be2012-06-23 02:02:28 +00003432 firstLine = false;
hyatted77ad82004-06-15 07:21:23 +00003433 }
3434}
3435
hyatt@apple.com5950bd42011-09-27 20:39:57 +00003436bool RenderBlock::positionNewFloatOnLine(FloatingObject* newFloat, FloatingObject* lastFloatFromPreviousLine, LineInfo& lineInfo, LineWidth& width)
rniwa@webkit.org73ce42a2011-04-06 14:10:02 +00003437{
rniwa@webkit.org7881ad02011-04-07 13:05:35 +00003438 if (!positionNewFloats())
3439 return false;
rniwa@webkit.org73ce42a2011-04-06 14:10:02 +00003440
rniwa@webkit.org44424752011-04-14 00:58:40 +00003441 width.shrinkAvailableWidthForNewFloatIfNeeded(newFloat);
rniwa@webkit.org73ce42a2011-04-06 14:10:02 +00003442
hyatt@apple.comdd78df82011-09-27 22:11:41 +00003443 // We only connect floats to lines for pagination purposes if the floats occur at the start of
3444 // the line and the previous line had a hard break (so this line is either the first in the block
3445 // or follows a <br>).
bjonesbe@adobe.coma9c66662013-08-14 20:30:14 +00003446 if (!newFloat->paginationStrut() || !lineInfo.previousLineBrokeCleanly() || !lineInfo.isEmpty())
rniwa@webkit.org7881ad02011-04-07 13:05:35 +00003447 return true;
rniwa@webkit.org73ce42a2011-04-06 14:10:02 +00003448
hyatt@apple.com46c65b32011-08-09 19:13:45 +00003449 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
darin@apple.com7cad7042013-09-24 05:53:55 +00003450 ASSERT(floatingObjectSet.last().get() == newFloat);
rniwa@webkit.org73ce42a2011-04-06 14:10:02 +00003451
bjonesbe@adobe.com93de7e72013-09-04 18:01:27 +00003452 LayoutUnit floatLogicalTop = newFloat->logicalTop(isHorizontalWritingMode());
bjonesbe@adobe.coma9c66662013-08-14 20:30:14 +00003453 int paginationStrut = newFloat->paginationStrut();
rniwa@webkit.org73ce42a2011-04-06 14:10:02 +00003454
hyatt@apple.com5950bd42011-09-27 20:39:57 +00003455 if (floatLogicalTop - paginationStrut != logicalHeight() + lineInfo.floatPaginationStrut())
rniwa@webkit.org7881ad02011-04-07 13:05:35 +00003456 return true;
rniwa@webkit.org73ce42a2011-04-06 14:10:02 +00003457
darin@apple.com7cad7042013-09-24 05:53:55 +00003458 auto it = floatingObjectSet.end();
rniwa@webkit.org73ce42a2011-04-06 14:10:02 +00003459 --it; // Last float is newFloat, skip that one.
darin@apple.com7cad7042013-09-24 05:53:55 +00003460 auto begin = floatingObjectSet.begin();
rniwa@webkit.org73ce42a2011-04-06 14:10:02 +00003461 while (it != begin) {
3462 --it;
darin@apple.com7cad7042013-09-24 05:53:55 +00003463 FloatingObject* f = it->get();
rniwa@webkit.org73ce42a2011-04-06 14:10:02 +00003464 if (f == lastFloatFromPreviousLine)
3465 break;
bjonesbe@adobe.com93de7e72013-09-04 18:01:27 +00003466 if (f->logicalTop(isHorizontalWritingMode()) == logicalHeight() + lineInfo.floatPaginationStrut()) {
bjonesbe@adobe.coma9c66662013-08-14 20:30:14 +00003467 f->setPaginationStrut(paginationStrut + f->paginationStrut());
darin@apple.com7cad7042013-09-24 05:53:55 +00003468 RenderBox* o = &f->renderer();
rniwa@webkit.org73ce42a2011-04-06 14:10:02 +00003469 setLogicalTopForChild(o, logicalTopForChild(o) + marginBeforeForChild(o) + paginationStrut);
3470 if (o->isRenderBlock())
antti@apple.comca2a8ff2013-10-04 04:04:35 +00003471 toRenderBlock(o)->setChildNeedsLayout(MarkOnlyThis);
rniwa@webkit.org73ce42a2011-04-06 14:10:02 +00003472 o->layoutIfNeeded();
hyatt@apple.com46c65b32011-08-09 19:13:45 +00003473 // Save the old logical top before calling removePlacedObject which will set
3474 // isPlaced to false. Otherwise it will trigger an assert in logicalTopForFloat.
bjonesbe@adobe.com93de7e72013-09-04 18:01:27 +00003475 LayoutUnit oldLogicalTop = f->logicalTop(isHorizontalWritingMode());
hyatt@apple.com46c65b32011-08-09 19:13:45 +00003476 m_floatingObjects->removePlacedObject(f);
bjonesbe@adobe.com93de7e72013-09-04 18:01:27 +00003477 f->setLogicalTop(oldLogicalTop + paginationStrut, isHorizontalWritingMode());
hyatt@apple.com46c65b32011-08-09 19:13:45 +00003478 m_floatingObjects->addPlacedObject(f);
rniwa@webkit.org73ce42a2011-04-06 14:10:02 +00003479 }
3480 }
3481
hyatt@apple.comdd78df82011-09-27 22:11:41 +00003482 // Just update the line info's pagination strut without altering our logical height yet. If the line ends up containing
3483 // no content, then we don't want to improperly grow the height of the block.
3484 lineInfo.setFloatPaginationStrut(lineInfo.floatPaginationStrut() + paginationStrut);
rniwa@webkit.org7881ad02011-04-07 13:05:35 +00003485 return true;
rniwa@webkit.org73ce42a2011-04-06 14:10:02 +00003486}
3487
robert@webkit.org82903f42012-08-28 19:18:40 +00003488LayoutUnit RenderBlock::startAlignedOffsetForLine(LayoutUnit position, bool firstLine)
robert@webkit.orgfc7763c2011-09-03 18:28:57 +00003489{
3490 ETextAlign textAlign = style()->textAlign();
3491
rniwa@webkit.orgaf7f7a42012-06-15 21:54:44 +00003492 if (textAlign == TASTART) // FIXME: Handle TAEND here
robert@webkit.orgfc7763c2011-09-03 18:28:57 +00003493 return startOffsetForLine(position, firstLine);
3494
3495 // updateLogicalWidthForAlignment() handles the direction of the block so no need to consider it here
robert@webkit.org82903f42012-08-28 19:18:40 +00003496 float totalLogicalWidth = 0;
3497 float logicalLeft = logicalLeftOffsetForLine(logicalHeight(), false);
3498 float availableLogicalWidth = logicalRightOffsetForLine(logicalHeight(), false) - logicalLeft;
benjamin@webkit.orgf68b1be2012-06-23 02:02:28 +00003499 updateLogicalWidthForAlignment(textAlign, 0, logicalLeft, totalLogicalWidth, availableLogicalWidth, 0);
robert@webkit.org7861a102011-09-22 17:16:47 +00003500
3501 if (!style()->isLeftToRightDirection())
robert@webkit.org82903f42012-08-28 19:18:40 +00003502 return logicalWidth() - logicalLeft;
robert@webkit.orgfc7763c2011-09-03 18:28:57 +00003503 return logicalLeft;
3504}
3505
hyattffe78712003-02-11 01:59:29 +00003506}