blob: 9909d98c98e959b595c83d52520b4062df2416c6 [file] [log] [blame]
darin55ae73e2007-05-11 15:47:28 +00001/*
kociendabb0c24b2001-08-24 14:24:40 +00002 * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
mitz@apple.com86470c82011-01-27 01:39:27 +00003 * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All right reserved.
eric@webkit.orgddbec0aa2010-01-06 01:13:11 +00004 * Copyright (C) 2010 Google Inc. All rights reserved.
kociendabb0c24b2001-08-24 14:24:40 +00005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
ddkilzerc8eccec2007-09-26 02:29:57 +000018 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
kociendabb0c24b2001-08-24 14:24:40 +000020 *
kociendabb0c24b2001-08-24 14:24:40 +000021 */
darinbe4c67d2005-12-19 19:53:12 +000022
mjsb64c50a2005-10-03 21:13:12 +000023#include "config.h"
darin36d11362006-04-11 16:30:21 +000024
mitz@apple.com4c1ff322009-07-13 00:54:12 +000025#include "BidiResolver.h"
mitz@apple.comb2107652010-06-21 16:54:52 +000026#include "Hyphenation.h"
hyatt@apple.com71eeb442010-02-11 20:05:51 +000027#include "InlineIterator.h"
eseidel3a6d1322006-01-09 03:14:50 +000028#include "InlineTextBox.h"
ggarenec11e5b2007-02-25 02:14:54 +000029#include "Logging.h"
darin36d11362006-04-11 16:30:21 +000030#include "RenderArena.h"
hyatt@apple.com4d046b72011-01-31 20:39:09 +000031#include "RenderCombineText.h"
hyatt@apple.comc3c7e902009-01-28 21:48:33 +000032#include "RenderInline.h"
eric@webkit.orgb35848a2010-06-10 08:33:22 +000033#include "RenderLayer.h"
mjsd26b2972007-02-13 13:09:04 +000034#include "RenderListMarker.h"
hyattd8048342006-05-31 01:48:18 +000035#include "RenderView.h"
hyatt@apple.comcc1737c2010-09-16 20:20:02 +000036#include "Settings.h"
tonyg@chromium.org9c384212011-01-19 23:13:26 +000037#include "TextRun.h"
dbates@webkit.orgf6f05a92010-05-17 04:58:25 +000038#include "TrailingFloatsRootInlineBox.h"
hyatt@apple.com4a9c625a2010-11-17 20:55:40 +000039#include "VerticalPositionCache.h"
darin36d11362006-04-11 16:30:21 +000040#include "break_lines.h"
mjsbb863512006-05-09 09:27:55 +000041#include <wtf/AlwaysInline.h>
slewis@apple.coma7615ca2008-07-12 05:51:33 +000042#include <wtf/RefCountedLeakCounter.h>
bolsinga@apple.com97e42c42008-11-15 04:47:20 +000043#include <wtf/StdLibExtras.h>
darin91298e52006-06-12 01:10:17 +000044#include <wtf/Vector.h>
paroga@webkit.org10c9e1b2011-01-29 17:04:51 +000045#include <wtf/unicode/CharacterNames.h>
hyatt8c371e52004-06-16 01:19:26 +000046
zimmermann@webkit.orgb40815c2010-06-18 11:18:44 +000047#if ENABLE(SVG)
zimmermann@webkit.org6e96afd2010-09-10 15:35:50 +000048#include "RenderSVGInlineText.h"
zimmermann@webkit.orgb40815c2010-06-18 11:18:44 +000049#include "SVGRootInlineBox.h"
50#endif
51
darin7bd70952006-04-13 07:07:34 +000052using namespace std;
darinf9e5d6c2007-01-09 14:54:26 +000053using namespace WTF;
54using namespace Unicode;
darin7bd70952006-04-13 07:07:34 +000055
darinb9481ed2006-03-20 02:57:59 +000056namespace WebCore {
mjsfe301d72003-10-02 18:46:18 +000057
hyatt1d5d87b2007-04-24 04:55:54 +000058// We don't let our line box tree for a single line get any deeper than this.
59const unsigned cMaxLineDepth = 200;
60
hyatt@apple.com0d4818f2009-02-08 05:39:22 +000061static int getBorderPaddingMargin(RenderBoxModelObject* child, bool endOfInline)
hyattffe78712003-02-11 01:59:29 +000062{
hyatt@apple.com0415e5d2010-10-07 17:40:25 +000063 if (endOfInline)
64 return child->marginEnd() + child->paddingEnd() + child->borderEnd();
65 return child->marginStart() + child->paddingStart() + child->borderStart();
hyattffe78712003-02-11 01:59:29 +000066}
67
hyatt@apple.com0415e5d2010-10-07 17:40:25 +000068static int inlineLogicalWidth(RenderObject* child, bool start = true, bool end = true)
hyattffe78712003-02-11 01:59:29 +000069{
hyatt1d5d87b2007-04-24 04:55:54 +000070 unsigned lineDepth = 1;
hyattffe78712003-02-11 01:59:29 +000071 int extraWidth = 0;
72 RenderObject* parent = child->parent();
hyatt@apple.com0d4818f2009-02-08 05:39:22 +000073 while (parent->isInline() && !parent->isInlineBlockOrInlineTable() && lineDepth++ < cMaxLineDepth) {
hyatt@apple.com40232f82009-02-04 04:26:08 +000074 if (start && !child->previousSibling())
hyatt@apple.com0d4818f2009-02-08 05:39:22 +000075 extraWidth += getBorderPaddingMargin(toRenderBoxModelObject(parent), false);
hyatt@apple.com40232f82009-02-04 04:26:08 +000076 if (end && !child->nextSibling())
hyatt@apple.com0d4818f2009-02-08 05:39:22 +000077 extraWidth += getBorderPaddingMargin(toRenderBoxModelObject(parent), true);
hyattffe78712003-02-11 01:59:29 +000078 child = parent;
79 parent = child->parent();
80 }
81 return extraWidth;
82}
83
hyatt@apple.comb3466af2009-06-13 06:04:40 +000084static void checkMidpoints(LineMidpointState& lineMidpointState, InlineIterator& lBreak)
hyattfe99c872003-07-31 22:25:29 +000085{
86 // Check to see if our last midpoint is a start point beyond the line break. If so,
hyattdca76e92005-11-02 08:52:50 +000087 // shave it off the list, and shave off a trailing space if the previous end point doesn't
88 // preserve whitespace.
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +000089 if (lBreak.obj && lineMidpointState.numMidpoints && !(lineMidpointState.numMidpoints % 2)) {
90 InlineIterator* midpoints = lineMidpointState.midpoints.data();
91 InlineIterator& endpoint = midpoints[lineMidpointState.numMidpoints - 2];
92 const InlineIterator& startpoint = midpoints[lineMidpointState.numMidpoints - 1];
mitz@apple.com15035e62008-07-05 20:44:44 +000093 InlineIterator currpoint = endpoint;
hyattfe99c872003-07-31 22:25:29 +000094 while (!currpoint.atEnd() && currpoint != startpoint && currpoint != lBreak)
mitz@apple.com1a301772008-03-11 18:30:36 +000095 currpoint.increment();
hyattfe99c872003-07-31 22:25:29 +000096 if (currpoint == lBreak) {
97 // We hit the line break before the start point. Shave off the start point.
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +000098 lineMidpointState.numMidpoints--;
mitz@apple.com20e34452010-09-28 19:38:15 +000099 if (endpoint.obj->style()->collapseWhiteSpace())
hyattfe99c872003-07-31 22:25:29 +0000100 endpoint.pos--;
101 }
102 }
103}
104
hyatt@apple.comb3466af2009-06-13 06:04:40 +0000105static void addMidpoint(LineMidpointState& lineMidpointState, const InlineIterator& midpoint)
hyatt85586af2003-02-19 23:22:42 +0000106{
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +0000107 if (lineMidpointState.midpoints.size() <= lineMidpointState.numMidpoints)
108 lineMidpointState.midpoints.grow(lineMidpointState.numMidpoints + 10);
hyatt85586af2003-02-19 23:22:42 +0000109
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +0000110 InlineIterator* midpoints = lineMidpointState.midpoints.data();
111 midpoints[lineMidpointState.numMidpoints++] = midpoint;
hyatt85586af2003-02-19 23:22:42 +0000112}
113
hyatt@apple.com71eeb442010-02-11 20:05:51 +0000114void RenderBlock::appendRunsForObject(int start, int end, RenderObject* obj, InlineBidiResolver& resolver)
hyatt33f8d492002-11-12 21:44:52 +0000115{
hyatt98ee7e42003-05-14 01:39:15 +0000116 if (start > end || obj->isFloating() ||
hyatt@apple.com0de4d642009-02-05 22:26:53 +0000117 (obj->isPositioned() && !obj->style()->hasStaticX() && !obj->style()->hasStaticY() && !obj->container()->isRenderInline()))
hyatteb003b82002-11-15 22:35:10 +0000118 return;
hyatt85586af2003-02-19 23:22:42 +0000119
hyatt@apple.comb3466af2009-06-13 06:04:40 +0000120 LineMidpointState& lineMidpointState = resolver.midpointState();
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +0000121 bool haveNextMidpoint = (lineMidpointState.currentMidpoint < lineMidpointState.numMidpoints);
mitz@apple.com15035e62008-07-05 20:44:44 +0000122 InlineIterator nextMidpoint;
hyatt85586af2003-02-19 23:22:42 +0000123 if (haveNextMidpoint)
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +0000124 nextMidpoint = lineMidpointState.midpoints[lineMidpointState.currentMidpoint];
125 if (lineMidpointState.betweenMidpoints) {
hyatt85586af2003-02-19 23:22:42 +0000126 if (!(haveNextMidpoint && nextMidpoint.obj == obj))
hyatt33f8d492002-11-12 21:44:52 +0000127 return;
128 // This is a new start point. Stop ignoring objects and
129 // adjust our start.
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +0000130 lineMidpointState.betweenMidpoints = false;
hyatt85586af2003-02-19 23:22:42 +0000131 start = nextMidpoint.pos;
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +0000132 lineMidpointState.currentMidpoint++;
hyatt33f8d492002-11-12 21:44:52 +0000133 if (start < end)
mitz@apple.com15035e62008-07-05 20:44:44 +0000134 return appendRunsForObject(start, end, obj, resolver);
135 } else {
mitz@apple.com5c2e0e02008-03-13 00:25:55 +0000136 if (!haveNextMidpoint || (obj != nextMidpoint.obj)) {
mitz@apple.com15035e62008-07-05 20:44:44 +0000137 resolver.addRun(new (obj->renderArena()) BidiRun(start, end, obj, resolver.context(), resolver.dir()));
hyatt33f8d492002-11-12 21:44:52 +0000138 return;
139 }
mitz@apple.com15035e62008-07-05 20:44:44 +0000140
hyatt78b85132004-03-29 20:07:45 +0000141 // An end midpoint has been encountered within our object. We
hyatt33f8d492002-11-12 21:44:52 +0000142 // need to go ahead and append a run with our endpoint.
mitz@apple.com15035e62008-07-05 20:44:44 +0000143 if (static_cast<int>(nextMidpoint.pos + 1) <= end) {
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +0000144 lineMidpointState.betweenMidpoints = true;
145 lineMidpointState.currentMidpoint++;
hyattc64f9fc2003-03-14 01:25:59 +0000146 if (nextMidpoint.pos != UINT_MAX) { // UINT_MAX means stop at the object and don't include any of it.
mitz@apple.com15035e62008-07-05 20:44:44 +0000147 if (static_cast<int>(nextMidpoint.pos + 1) > start)
148 resolver.addRun(new (obj->renderArena())
149 BidiRun(start, nextMidpoint.pos + 1, obj, resolver.context(), resolver.dir()));
150 return appendRunsForObject(nextMidpoint.pos + 1, end, obj, resolver);
hyattc64f9fc2003-03-14 01:25:59 +0000151 }
mitz@apple.com15035e62008-07-05 20:44:44 +0000152 } else
153 resolver.addRun(new (obj->renderArena()) BidiRun(start, end, obj, resolver.context(), resolver.dir()));
hyatt33f8d492002-11-12 21:44:52 +0000154 }
155}
156
hyatt@apple.comc92b7352009-02-12 01:35:08 +0000157static inline InlineBox* createInlineBoxForRenderer(RenderObject* obj, bool isRootLineBox, bool isOnlyRun = false)
158{
159 if (isRootLineBox)
eric@webkit.org49b9d952009-07-03 01:29:07 +0000160 return toRenderBlock(obj)->createAndAppendRootInlineBox();
hyatt@apple.comc92b7352009-02-12 01:35:08 +0000161
162 if (obj->isText()) {
163 InlineTextBox* textBox = toRenderText(obj)->createInlineTextBox();
164 // We only treat a box as text for a <br> if we are on a line by ourself or in strict mode
165 // (Note the use of strict mode. In "almost strict" mode, we don't treat the box for <br> as text.)
166 if (obj->isBR())
hyatt@apple.comce8ee2a2010-08-27 20:29:34 +0000167 textBox->setIsText(isOnlyRun || obj->document()->inNoQuirksMode());
hyatt@apple.comc92b7352009-02-12 01:35:08 +0000168 return textBox;
169 }
170
171 if (obj->isBox())
172 return toRenderBox(obj)->createInlineBox();
173
eric@webkit.org49b9d952009-07-03 01:29:07 +0000174 return toRenderInline(obj)->createAndAppendInlineFlowBox();
hyatt@apple.comc92b7352009-02-12 01:35:08 +0000175}
176
177static inline void dirtyLineBoxesForRenderer(RenderObject* o, bool fullLayout)
178{
179 if (o->isText()) {
hyatt@apple.com75dad742010-09-24 18:07:44 +0000180 if (o->preferredLogicalWidthsDirty() && o->isCounter())
181 toRenderText(o)->computePreferredLogicalWidths(0); // FIXME: Counters depend on this hack. No clue why. Should be investigated and removed.
hyatt@apple.comc92b7352009-02-12 01:35:08 +0000182 toRenderText(o)->dirtyLineBoxes(fullLayout);
183 } else
184 toRenderInline(o)->dirtyLineBoxes(fullLayout);
185}
186
xji@chromium.orgb0ad6eb822011-02-01 20:02:06 +0000187static bool parentIsConstructedOrHaveNext(InlineFlowBox* parentBox)
188{
189 do {
190 if (parentBox->isConstructed() || parentBox->nextOnLine())
191 return true;
192 parentBox = parentBox->parent();
193 } while (parentBox);
194 return false;
195}
196
hyatt@apple.comcd6f8952009-01-28 17:30:26 +0000197InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj, bool firstLine)
hyattffe78712003-02-11 01:59:29 +0000198{
199 // See if we have an unconstructed line box for this object that is also
200 // the last item on the line.
hyatt1d5d87b2007-04-24 04:55:54 +0000201 unsigned lineDepth = 1;
202 InlineFlowBox* childBox = 0;
203 InlineFlowBox* parentBox = 0;
204 InlineFlowBox* result = 0;
205 do {
hyatt@apple.com415d8de2009-01-26 22:29:19 +0000206 ASSERT(obj->isRenderInline() || obj == this);
hyatt@apple.com76dbdb52009-01-29 22:49:13 +0000207
hyatt1d5d87b2007-04-24 04:55:54 +0000208 // Get the last box we made for this render object.
weinig@apple.com7c50a3b2009-01-30 19:55:45 +0000209 parentBox = obj->isRenderInline() ? toRenderInline(obj)->lastLineBox() : toRenderBlock(obj)->lastLineBox();
hyattffe78712003-02-11 01:59:29 +0000210
xji@chromium.orgb0ad6eb822011-02-01 20:02:06 +0000211 // If this box or its ancestor is constructed then it is from a previous line, and we need
212 // 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 +0000213 // something following it on the line, then we know we have to make a new box
214 // as well. In this situation our inline has actually been split in two on
215 // the same line (this can happen with very fancy language mixtures).
216 bool constructedNewBox = false;
xji@chromium.orgb0ad6eb822011-02-01 20:02:06 +0000217 if (!parentBox || parentIsConstructedOrHaveNext(parentBox)) {
hyatt1d5d87b2007-04-24 04:55:54 +0000218 // We need to make a new box for this render object. Once
219 // made, we need to place it at the end of the current line.
hyatt@apple.comc92b7352009-02-12 01:35:08 +0000220 InlineBox* newBox = createInlineBoxForRenderer(obj, obj == this);
hyatt1d5d87b2007-04-24 04:55:54 +0000221 ASSERT(newBox->isInlineFlowBox());
222 parentBox = static_cast<InlineFlowBox*>(newBox);
hyatt@apple.comcd6f8952009-01-28 17:30:26 +0000223 parentBox->setFirstLineStyleBit(firstLine);
hyatt@apple.com6bd34682010-11-01 21:13:55 +0000224 parentBox->setIsHorizontal(style()->isHorizontalWritingMode());
hyatt1d5d87b2007-04-24 04:55:54 +0000225 constructedNewBox = true;
226 }
mitz@apple.come1364202008-02-28 01:06:41 +0000227
hyatt1d5d87b2007-04-24 04:55:54 +0000228 if (!result)
229 result = parentBox;
230
231 // If we have hit the block itself, then |box| represents the root
hyattffe78712003-02-11 01:59:29 +0000232 // inline box for the line, and it doesn't have to be appended to any parent
233 // inline.
hyatt1d5d87b2007-04-24 04:55:54 +0000234 if (childBox)
235 parentBox->addToLine(childBox);
mitz@apple.come1364202008-02-28 01:06:41 +0000236
hyatt1d5d87b2007-04-24 04:55:54 +0000237 if (!constructedNewBox || obj == this)
238 break;
mitz@apple.come1364202008-02-28 01:06:41 +0000239
hyatt1d5d87b2007-04-24 04:55:54 +0000240 childBox = parentBox;
mitz@apple.come1364202008-02-28 01:06:41 +0000241
hyatt1d5d87b2007-04-24 04:55:54 +0000242 // If we've exceeded our line depth, then jump straight to the root and skip all the remaining
243 // intermediate inline flows.
244 obj = (++lineDepth >= cMaxLineDepth) ? this : obj->parent();
hyattffe78712003-02-11 01:59:29 +0000245
hyatt1d5d87b2007-04-24 04:55:54 +0000246 } while (true);
247
248 return result;
hyattffe78712003-02-11 01:59:29 +0000249}
250
hyatt@apple.comcd6f8952009-01-28 17:30:26 +0000251RootInlineBox* RenderBlock::constructLine(unsigned runCount, BidiRun* firstRun, BidiRun* lastRun, bool firstLine, bool lastLine, RenderObject* endObject)
hyattffe78712003-02-11 01:59:29 +0000252{
mitz@apple.com887f3592008-02-25 22:03:08 +0000253 ASSERT(firstRun);
hyattffe78712003-02-11 01:59:29 +0000254
inferno@chromium.orge29694f2010-10-07 22:00:02 +0000255 bool rootHasSelectedChildren = false;
hyattffe78712003-02-11 01:59:29 +0000256 InlineFlowBox* parentBox = 0;
mitz@apple.com887f3592008-02-25 22:03:08 +0000257 for (BidiRun* r = firstRun; r; r = r->next()) {
hyattffe78712003-02-11 01:59:29 +0000258 // Create a box for our object.
mitz@apple.com887f3592008-02-25 22:03:08 +0000259 bool isOnlyRun = (runCount == 1);
mitz@apple.come1364202008-02-28 01:06:41 +0000260 if (runCount == 2 && !r->m_object->isListMarker())
hyatt@apple.comc0fa1632010-09-30 20:01:33 +0000261 isOnlyRun = (!style()->isLeftToRightDirection() ? lastRun : firstRun)->m_object->isListMarker();
mitz@apple.come1364202008-02-28 01:06:41 +0000262
hyatt@apple.comc92b7352009-02-12 01:35:08 +0000263 InlineBox* box = createInlineBoxForRenderer(r->m_object, false, isOnlyRun);
mitz@apple.com576e84e2008-04-24 19:09:48 +0000264 r->m_box = box;
265
mitz@apple.comaa6ce3d2009-04-10 01:00:20 +0000266 ASSERT(box);
267 if (!box)
268 continue;
hyattffe78712003-02-11 01:59:29 +0000269
inferno@chromium.orge29694f2010-10-07 22:00:02 +0000270 if (!rootHasSelectedChildren && box->renderer()->selectionState() != RenderObject::SelectionNone)
271 rootHasSelectedChildren = true;
272
mitz@apple.comaa6ce3d2009-04-10 01:00:20 +0000273 // If we have no parent box yet, or if the run is not simply a sibling,
274 // then we need to construct inline boxes as necessary to properly enclose the
275 // run's inline box.
276 if (!parentBox || parentBox->renderer() != r->m_object->parent())
277 // Create new inline boxes all the way back to the appropriate insertion point.
278 parentBox = createLineBoxes(r->m_object->parent(), firstLine);
mitz@apple.com576e84e2008-04-24 19:09:48 +0000279
mitz@apple.comaa6ce3d2009-04-10 01:00:20 +0000280 // Append the inline box to this line.
281 parentBox->addToLine(box);
mitz@apple.com576e84e2008-04-24 19:09:48 +0000282
mitz@apple.comaa6ce3d2009-04-10 01:00:20 +0000283 bool visuallyOrdered = r->m_object->style()->visuallyOrdered();
284 box->setBidiLevel(visuallyOrdered ? 0 : r->level());
285
286 if (box->isInlineTextBox()) {
287 InlineTextBox* text = static_cast<InlineTextBox*>(box);
288 text->setStart(r->m_start);
289 text->setLen(r->m_stop - r->m_start);
290 text->m_dirOverride = r->dirOverride(visuallyOrdered);
mitz@apple.comb2107652010-06-21 16:54:52 +0000291 if (r->m_hasHyphen)
292 text->setHasHyphen(true);
hyatt0c3a9862004-02-23 21:26:26 +0000293 }
hyattffe78712003-02-11 01:59:29 +0000294 }
295
296 // We should have a root inline box. It should be unconstructed and
297 // be the last continuation of our line list.
ggarenf9f32ae2007-03-26 20:08:53 +0000298 ASSERT(lastLineBox() && !lastLineBox()->isConstructed());
hyattffe78712003-02-11 01:59:29 +0000299
inferno@chromium.orge29694f2010-10-07 22:00:02 +0000300 // Set the m_selectedChildren flag on the root inline box if one of the leaf inline box
301 // from the bidi runs walk above has a selection state.
302 if (rootHasSelectedChildren)
303 lastLineBox()->root()->setHasSelectedChildren(true);
304
hyattffe78712003-02-11 01:59:29 +0000305 // Set bits on our inline flow boxes that indicate which sides should
306 // paint borders/margins/padding. This knowledge will ultimately be used when
307 // we determine the horizontal positions and widths of all the inline boxes on
308 // the line.
hyattffe78712003-02-11 01:59:29 +0000309 lastLineBox()->determineSpacingForFlowBoxes(lastLine, endObject);
310
311 // Now mark the line boxes as being constructed.
312 lastLineBox()->setConstructed();
313
314 // Return the last line.
hyatt0c3a9862004-02-23 21:26:26 +0000315 return lastRootBox();
hyattffe78712003-02-11 01:59:29 +0000316}
317
hyatt@apple.com44e83c02010-09-23 22:21:30 +0000318void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, bool firstLine, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd, GlyphOverflowAndFallbackFontsMap& textBoxDataMap)
hyattffe78712003-02-11 01:59:29 +0000319{
hyatt@apple.com546a2482010-10-07 21:16:49 +0000320 // First determine our total logical width.
321 int availableLogicalWidth = availableLogicalWidthForLine(logicalHeight(), firstLine);
322 int totalLogicalWidth = lineBox->getFlowSpacingLogicalWidth();
darin06dcb9c2005-08-15 04:31:09 +0000323 bool needsWordSpacing = false;
mitz@apple.com86470c82011-01-27 01:39:27 +0000324 unsigned expansionOpportunityCount = 0;
325 bool isAfterExpansion = true;
326 Vector<unsigned, 16> expansionOpportunities;
mitz@apple.com815ef2f2008-02-25 17:11:56 +0000327 ETextAlign textAlign = style()->textAlign();
328
mitz@apple.come1364202008-02-28 01:06:41 +0000329 for (BidiRun* r = firstRun; r; r = r->next()) {
330 if (!r->m_box || r->m_object->isPositioned() || r->m_box->isLineBreak())
hyatt98ee7e42003-05-14 01:39:15 +0000331 continue; // Positioned objects are only participating to figure out their
332 // correct static x position. They have no effect on the width.
hyatt0c05e102006-04-14 08:15:00 +0000333 // Similarly, line break boxes have no effect on the width.
mitz@apple.come1364202008-02-28 01:06:41 +0000334 if (r->m_object->isText()) {
darin@apple.com36744d62009-01-25 20:23:04 +0000335 RenderText* rt = toRenderText(r->m_object);
mitz@apple.com815ef2f2008-02-25 17:11:56 +0000336
mitz@apple.comc13ea5f2008-04-18 21:18:26 +0000337 if (textAlign == JUSTIFY && r != trailingSpaceRun) {
mitz@apple.com1b0578d2011-01-27 08:23:31 +0000338 unsigned opportunitiesInRun = Font::expansionOpportunityCount(rt->characters() + r->m_start, r->m_stop - r->m_start, r->m_box->direction(), isAfterExpansion);
mitz@apple.com86470c82011-01-27 01:39:27 +0000339 expansionOpportunities.append(opportunitiesInRun);
340 expansionOpportunityCount += opportunitiesInRun;
mitz@apple.com815ef2f2008-02-25 17:11:56 +0000341 }
342
mitz@apple.come1364202008-02-28 01:06:41 +0000343 if (int length = rt->textLength()) {
hyatt@apple.comd0301a52009-01-26 21:50:57 +0000344 if (!r->m_start && needsWordSpacing && isSpaceOrNewline(rt->characters()[r->m_start]))
hyatt@apple.com546a2482010-10-07 21:16:49 +0000345 totalLogicalWidth += rt->style(firstLine)->font().wordSpacing();
mitz@apple.come1364202008-02-28 01:06:41 +0000346 needsWordSpacing = !isSpaceOrNewline(rt->characters()[r->m_stop - 1]) && r->m_stop == length;
darin06dcb9c2005-08-15 04:31:09 +0000347 }
mitz@apple.comaa6ce3d2009-04-10 01:00:20 +0000348 HashSet<const SimpleFontData*> fallbackFonts;
enrica@apple.comb9050ed2010-04-07 17:01:52 +0000349 GlyphOverflow glyphOverflow;
mitz@apple.comb2107652010-06-21 16:54:52 +0000350 int hyphenWidth = 0;
351 if (static_cast<InlineTextBox*>(r->m_box)->hasHyphen()) {
352 const AtomicString& hyphenString = rt->style()->hyphenString();
353 hyphenWidth = rt->style(firstLine)->font().width(TextRun(hyphenString.characters(), hyphenString.length()));
354 }
hyatt@apple.com546a2482010-10-07 21:16:49 +0000355 r->m_box->setLogicalWidth(rt->width(r->m_start, r->m_stop - r->m_start, totalLogicalWidth, firstLine, &fallbackFonts, &glyphOverflow) + hyphenWidth);
zimmermann@webkit.orgb40815c2010-06-18 11:18:44 +0000356 if (!fallbackFonts.isEmpty()) {
mitz@apple.comaa6ce3d2009-04-10 01:00:20 +0000357 ASSERT(r->m_box->isText());
mitz@apple.com0cc7bed2010-05-17 01:43:49 +0000358 GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.add(static_cast<InlineTextBox*>(r->m_box), make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).first;
359 ASSERT(it->second.first.isEmpty());
360 copyToVector(fallbackFonts, it->second.first);
mitz@apple.comaa6ce3d2009-04-10 01:00:20 +0000361 }
zimmermann@webkit.orgb40815c2010-06-18 11:18:44 +0000362 if ((glyphOverflow.top || glyphOverflow.bottom || glyphOverflow.left || glyphOverflow.right)) {
enrica@apple.comb9050ed2010-04-07 17:01:52 +0000363 ASSERT(r->m_box->isText());
mitz@apple.com0cc7bed2010-05-17 01:43:49 +0000364 GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.add(static_cast<InlineTextBox*>(r->m_box), make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).first;
365 it->second.second = glyphOverflow;
enrica@apple.comb9050ed2010-04-07 17:01:52 +0000366 }
mitz@apple.com86470c82011-01-27 01:39:27 +0000367 } else {
368 isAfterExpansion = false;
369 if (!r->m_object->isRenderInline()) {
370 RenderBox* renderBox = toRenderBox(r->m_object);
371 renderBox->computeLogicalWidth();
372 r->m_box->setLogicalWidth(logicalWidthForChild(renderBox));
373 totalLogicalWidth += marginStartForChild(renderBox) + marginEndForChild(renderBox);
374 }
hyattffe78712003-02-11 01:59:29 +0000375 }
hyatt4b381692003-03-10 21:11:59 +0000376
hyatt@apple.com546a2482010-10-07 21:16:49 +0000377 totalLogicalWidth += r->m_box->logicalWidth();
hyattffe78712003-02-11 01:59:29 +0000378 }
379
mitz@apple.com86470c82011-01-27 01:39:27 +0000380 if (isAfterExpansion && !expansionOpportunities.isEmpty()) {
381 expansionOpportunities.last()--;
382 expansionOpportunityCount--;
383 }
384
hyattffe78712003-02-11 01:59:29 +0000385 // Armed with the total width of the line (without justification),
386 // we now examine our text-align property in order to determine where to position the
387 // objects horizontally. The total width of the line can be increased if we end up
388 // justifying text.
hyatt@apple.com546a2482010-10-07 21:16:49 +0000389 int logicalLeft = logicalLeftOffsetForLine(logicalHeight(), firstLine);
ddkilzer@apple.comdfdc3fd2009-07-08 13:55:55 +0000390 switch (textAlign) {
hyattffe78712003-02-11 01:59:29 +0000391 case LEFT:
ddkilzer95d2be02007-04-14 01:26:07 +0000392 case WEBKIT_LEFT:
hyatt959a54e2004-09-27 17:52:18 +0000393 // The direction of the block should determine what happens with wide lines. In
394 // particular with RTL blocks, wide lines should still spill out to the left.
hyatt@apple.comc0fa1632010-09-30 20:01:33 +0000395 if (style()->isLeftToRightDirection()) {
hyatt@apple.com546a2482010-10-07 21:16:49 +0000396 if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun)
397 trailingSpaceRun->m_box->setLogicalWidth(max(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth));
mitz@apple.comc13ea5f2008-04-18 21:18:26 +0000398 } else {
399 if (trailingSpaceRun)
hyatt@apple.comc01df9e2010-09-23 19:17:33 +0000400 trailingSpaceRun->m_box->setLogicalWidth(0);
hyatt@apple.com546a2482010-10-07 21:16:49 +0000401 else if (totalLogicalWidth > availableLogicalWidth)
402 logicalLeft -= (totalLogicalWidth - availableLogicalWidth);
mitz@apple.comc13ea5f2008-04-18 21:18:26 +0000403 }
hyattffe78712003-02-11 01:59:29 +0000404 break;
405 case JUSTIFY:
mitz@apple.com86470c82011-01-27 01:39:27 +0000406 if (expansionOpportunityCount && !reachedEnd && !lineBox->endsWithBreak()) {
mitz@apple.comc13ea5f2008-04-18 21:18:26 +0000407 if (trailingSpaceRun) {
hyatt@apple.com546a2482010-10-07 21:16:49 +0000408 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
hyatt@apple.comc01df9e2010-09-23 19:17:33 +0000409 trailingSpaceRun->m_box->setLogicalWidth(0);
mitz@apple.comc13ea5f2008-04-18 21:18:26 +0000410 }
hyattffe78712003-02-11 01:59:29 +0000411 break;
mitz@apple.comc13ea5f2008-04-18 21:18:26 +0000412 }
hyattffe78712003-02-11 01:59:29 +0000413 // fall through
414 case TAAUTO:
mitz@apple.com86470c82011-01-27 01:39:27 +0000415 expansionOpportunityCount = 0;
hyattffe78712003-02-11 01:59:29 +0000416 // for right to left fall through to right aligned
hyatt@apple.comc0fa1632010-09-30 20:01:33 +0000417 if (style()->isLeftToRightDirection()) {
hyatt@apple.com546a2482010-10-07 21:16:49 +0000418 if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun)
419 trailingSpaceRun->m_box->setLogicalWidth(max(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth));
hyattffe78712003-02-11 01:59:29 +0000420 break;
mitz@apple.comc13ea5f2008-04-18 21:18:26 +0000421 }
hyattffe78712003-02-11 01:59:29 +0000422 case RIGHT:
ddkilzer95d2be02007-04-14 01:26:07 +0000423 case WEBKIT_RIGHT:
hyatt959a54e2004-09-27 17:52:18 +0000424 // Wide lines spill out of the block based off direction.
425 // So even if text-align is right, if direction is LTR, wide lines should overflow out of the right
426 // side of the block.
hyatt@apple.comc0fa1632010-09-30 20:01:33 +0000427 if (style()->isLeftToRightDirection()) {
mitz@apple.comc13ea5f2008-04-18 21:18:26 +0000428 if (trailingSpaceRun) {
hyatt@apple.com546a2482010-10-07 21:16:49 +0000429 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
hyatt@apple.comc01df9e2010-09-23 19:17:33 +0000430 trailingSpaceRun->m_box->setLogicalWidth(0);
mitz@apple.comc13ea5f2008-04-18 21:18:26 +0000431 }
hyatt@apple.com546a2482010-10-07 21:16:49 +0000432 if (totalLogicalWidth < availableLogicalWidth)
433 logicalLeft += availableLogicalWidth - totalLogicalWidth;
mitz@apple.comc13ea5f2008-04-18 21:18:26 +0000434 } else {
hyatt@apple.com546a2482010-10-07 21:16:49 +0000435 if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun) {
436 trailingSpaceRun->m_box->setLogicalWidth(max(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth));
437 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
mitz@apple.comc13ea5f2008-04-18 21:18:26 +0000438 } else
hyatt@apple.com546a2482010-10-07 21:16:49 +0000439 logicalLeft += availableLogicalWidth - totalLogicalWidth;
mitz@apple.comc13ea5f2008-04-18 21:18:26 +0000440 }
hyattffe78712003-02-11 01:59:29 +0000441 break;
442 case CENTER:
ddkilzer95d2be02007-04-14 01:26:07 +0000443 case WEBKIT_CENTER:
mitz@apple.comc13ea5f2008-04-18 21:18:26 +0000444 int trailingSpaceWidth = 0;
445 if (trailingSpaceRun) {
hyatt@apple.com546a2482010-10-07 21:16:49 +0000446 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
447 trailingSpaceWidth = min(trailingSpaceRun->m_box->logicalWidth(), (availableLogicalWidth - totalLogicalWidth + 1) / 2);
hyatt@apple.comc01df9e2010-09-23 19:17:33 +0000448 trailingSpaceRun->m_box->setLogicalWidth(max(0, trailingSpaceWidth));
mitz@apple.comc13ea5f2008-04-18 21:18:26 +0000449 }
hyatt@apple.comc0fa1632010-09-30 20:01:33 +0000450 if (style()->isLeftToRightDirection())
hyatt@apple.com546a2482010-10-07 21:16:49 +0000451 logicalLeft += max((availableLogicalWidth - totalLogicalWidth) / 2, 0);
mitz@apple.com37717da2008-02-28 02:23:22 +0000452 else
hyatt@apple.com546a2482010-10-07 21:16:49 +0000453 logicalLeft += totalLogicalWidth > availableLogicalWidth ? (availableLogicalWidth - totalLogicalWidth) : (availableLogicalWidth - totalLogicalWidth) / 2 - trailingSpaceWidth;
hyattffe78712003-02-11 01:59:29 +0000454 break;
455 }
456
mitz@apple.com86470c82011-01-27 01:39:27 +0000457 if (expansionOpportunityCount) {
458 size_t i = 0;
mitz@apple.come1364202008-02-28 01:06:41 +0000459 for (BidiRun* r = firstRun; r; r = r->next()) {
mitz@apple.comc13ea5f2008-04-18 21:18:26 +0000460 if (!r->m_box || r == trailingSpaceRun)
mitz@apple.com815ef2f2008-02-25 17:11:56 +0000461 continue;
hyatt0c3a9862004-02-23 21:26:26 +0000462
hyatt@apple.comd0301a52009-01-26 21:50:57 +0000463 if (r->m_object->isText()) {
mitz@apple.com86470c82011-01-27 01:39:27 +0000464 unsigned opportunitiesInRun = expansionOpportunities[i++];
hyatt870bdda2003-05-21 23:37:33 +0000465
mitz@apple.com86470c82011-01-27 01:39:27 +0000466 ASSERT(opportunitiesInRun <= expansionOpportunityCount);
hyatt870bdda2003-05-21 23:37:33 +0000467
hyattdca76e92005-11-02 08:52:50 +0000468 // Only justify text if whitespace is collapsed.
mitz@apple.come1364202008-02-28 01:06:41 +0000469 if (r->m_object->style()->collapseWhiteSpace()) {
mitz@apple.com86470c82011-01-27 01:39:27 +0000470 InlineTextBox* textBox = static_cast<InlineTextBox*>(r->m_box);
471 int expansion = (availableLogicalWidth - totalLogicalWidth) * opportunitiesInRun / expansionOpportunityCount;
472 textBox->setExpansion(expansion);
473 totalLogicalWidth += expansion;
hyatt870bdda2003-05-21 23:37:33 +0000474 }
mitz@apple.com86470c82011-01-27 01:39:27 +0000475 expansionOpportunityCount -= opportunitiesInRun;
476 if (!expansionOpportunityCount)
mitz@apple.come1364202008-02-28 01:06:41 +0000477 break;
hyattacbb0d42003-04-25 01:32:49 +0000478 }
hyattffe78712003-02-11 01:59:29 +0000479 }
hyattffe78712003-02-11 01:59:29 +0000480 }
mitz@apple.come1364202008-02-28 01:06:41 +0000481
hyattffe78712003-02-11 01:59:29 +0000482 // The widths of all runs are now known. We can now place every inline box (and
483 // compute accurate widths for the inline flow boxes).
darin06dcb9c2005-08-15 04:31:09 +0000484 needsWordSpacing = false;
hyatt@apple.com546a2482010-10-07 21:16:49 +0000485 lineBox->placeBoxesInInlineDirection(logicalLeft, needsWordSpacing, textBoxDataMap);
hyattffe78712003-02-11 01:59:29 +0000486}
487
hyatt@apple.com4a9c625a2010-11-17 20:55:40 +0000488void RenderBlock::computeBlockDirectionPositionsForLine(RootInlineBox* lineBox, BidiRun* firstRun, GlyphOverflowAndFallbackFontsMap& textBoxDataMap,
489 VerticalPositionCache& verticalPositionCache)
hyattffe78712003-02-11 01:59:29 +0000490{
hyatt@apple.com4a9c625a2010-11-17 20:55:40 +0000491 setLogicalHeight(lineBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache));
hyatt@apple.com35d2ad52010-10-20 18:17:36 +0000492 lineBox->setBlockLogicalHeight(logicalHeight());
hyattffe78712003-02-11 01:59:29 +0000493
494 // Now make sure we place replaced render objects correctly.
mitz@apple.com887f3592008-02-25 22:03:08 +0000495 for (BidiRun* r = firstRun; r; r = r->next()) {
mitz@apple.comaa6ce3d2009-04-10 01:00:20 +0000496 ASSERT(r->m_box);
mitz@apple.come1364202008-02-28 01:06:41 +0000497 if (!r->m_box)
eseidel789896f2005-11-27 22:52:09 +0000498 continue; // Skip runs with no line boxes.
hyatt0c3a9862004-02-23 21:26:26 +0000499
hyatt98ee7e42003-05-14 01:39:15 +0000500 // Align positioned boxes with the top of the line box. This is
501 // a reasonable approximation of an appropriate y position.
mitz@apple.come1364202008-02-28 01:06:41 +0000502 if (r->m_object->isPositioned())
hyatt@apple.com35d2ad52010-10-20 18:17:36 +0000503 r->m_box->setLogicalTop(logicalHeight());
hyatt98ee7e42003-05-14 01:39:15 +0000504
505 // Position is used to properly position both replaced elements and
506 // to update the static normal flow x/y of positioned elements.
hyatt@apple.com6a551ad2009-02-11 22:43:12 +0000507 if (r->m_object->isText())
508 toRenderText(r->m_object)->positionLineBox(r->m_box);
509 else if (r->m_object->isBox())
510 toRenderBox(r->m_object)->positionLineBox(r->m_box);
hyatt98ee7e42003-05-14 01:39:15 +0000511 }
mitz@apple.coma927be62008-03-21 05:30:19 +0000512 // Positioned objects and zero-length text nodes destroy their boxes in
513 // position(), which unnecessarily dirties the line.
514 lineBox->markDirty(false);
hyattffe78712003-02-11 01:59:29 +0000515}
kociendabb0c24b2001-08-24 14:24:40 +0000516
mitz@apple.comc13ea5f2008-04-18 21:18:26 +0000517static inline bool isCollapsibleSpace(UChar character, RenderText* renderer)
518{
519 if (character == ' ' || character == '\t' || character == softHyphen)
520 return true;
521 if (character == '\n')
522 return !renderer->style()->preserveNewline();
523 if (character == noBreakSpace)
524 return renderer->style()->nbspMode() == SPACE;
525 return false;
526}
527
hyatt@apple.com81c1d742010-10-06 21:44:02 +0000528void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogicalTop, int& repaintLogicalBottom)
jamesr@google.com19548ad2010-04-02 23:21:35 +0000529{
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000530 bool useRepaintBounds = false;
531
hyatt@apple.com5dc5a312009-08-18 19:15:19 +0000532 m_overflow.clear();
hyatt7b41b9d2007-05-30 05:32:40 +0000533
hyatt@apple.com81c1d742010-10-06 21:44:02 +0000534 setLogicalHeight(borderBefore() + paddingBefore());
mitz@apple.come1364202008-02-28 01:06:41 +0000535
hyatt0c3a9862004-02-23 21:26:26 +0000536 // Figure out if we should clear out our line boxes.
537 // FIXME: Handle resize eventually!
eric@webkit.orgc0249422010-01-06 00:07:56 +0000538 bool fullLayout = !firstLineBox() || selfNeedsLayout() || relayoutChildren;
hyatt0c3a9862004-02-23 21:26:26 +0000539 if (fullLayout)
hyatt@apple.comb83de652009-01-28 20:48:04 +0000540 lineBoxes()->deleteLineBoxes(renderArena());
mitz@apple.come1364202008-02-28 01:06:41 +0000541
hyatted77ad82004-06-15 07:21:23 +0000542 // Text truncation only kicks in if your overflow isn't visible and your text-overflow-mode isn't
543 // clip.
544 // FIXME: CSS3 says that descendants that are clipped must also know how to truncate. This is insanely
545 // difficult to figure out (especially in the middle of doing layout), and is really an esoteric pile of nonsense
546 // anyway, so we won't worry about following the draft here.
547 bool hasTextOverflow = style()->textOverflow() && hasOverflowClip();
mitz@apple.come1364202008-02-28 01:06:41 +0000548
hyatted77ad82004-06-15 07:21:23 +0000549 // Walk all the lines and delete our ellipsis line boxes if they exist.
550 if (hasTextOverflow)
551 deleteEllipsisLineBoxes();
552
hyattffe78712003-02-11 01:59:29 +0000553 if (firstChild()) {
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000554 // layout replaced elements
555 bool endOfInline = false;
556 RenderObject* o = bidiFirst(this, 0, false);
mitz@apple.com40547b32008-03-18 04:04:34 +0000557 Vector<FloatWithRect> floats;
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000558 bool hasInlineChild = false;
559 while (o) {
commit-queue@webkit.orgcf45df92010-09-14 13:25:06 +0000560 if (!hasInlineChild && o->isInline())
561 hasInlineChild = true;
562
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000563 if (o->isReplaced() || o->isFloating() || o->isPositioned()) {
564 RenderBox* box = toRenderBox(o);
565
566 if (relayoutChildren || o->style()->width().isPercent() || o->style()->height().isPercent())
567 o->setChildNeedsLayout(true, false);
568
569 // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths.
hyatt@apple.com81c1d742010-10-06 21:44:02 +0000570 if (relayoutChildren && (o->style()->paddingStart().isPercent() || o->style()->paddingEnd().isPercent()))
hyatt@apple.com75dad742010-09-24 18:07:44 +0000571 o->setPreferredLogicalWidthsDirty(true, false);
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000572
573 if (o->isPositioned())
574 o->containingBlock()->insertPositionedObject(box);
hyatt@apple.comcc1737c2010-09-16 20:20:02 +0000575 else if (o->isFloating())
576 floats.append(FloatWithRect(box));
577 else if (fullLayout || o->needsLayout()) {
578 // Replaced elements
579 toRenderBox(o)->dirtyLineBoxes(fullLayout);
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000580 o->layoutIfNeeded();
581 }
582 } else if (o->isText() || (o->isRenderInline() && !endOfInline)) {
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000583 if (fullLayout || o->selfNeedsLayout())
584 dirtyLineBoxesForRenderer(o, fullLayout);
585 o->setNeedsLayout(false);
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000586 }
587 o = bidiNext(this, o, 0, false, &endOfInline);
588 }
589
590 // We want to skip ahead to the first dirty line
591 InlineBidiResolver resolver;
592 unsigned floatIndex;
593 bool firstLine = true;
594 bool previousLineBrokeCleanly = true;
hyatt@apple.comcc1737c2010-09-16 20:20:02 +0000595 RootInlineBox* startLine = determineStartPosition(firstLine, fullLayout, previousLineBrokeCleanly, resolver, floats, floatIndex,
hyatt@apple.com81c1d742010-10-06 21:44:02 +0000596 useRepaintBounds, repaintLogicalTop, repaintLogicalBottom);
mitz@apple.come1364202008-02-28 01:06:41 +0000597
eric@webkit.orgddbec0aa2010-01-06 01:13:11 +0000598 if (fullLayout && hasInlineChild && !selfNeedsLayout()) {
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000599 setNeedsLayout(true, false); // Mark ourselves as needing a full layout. This way we'll repaint like
600 // we're supposed to.
simon.fraser@apple.com6528b502009-01-12 21:42:25 +0000601 RenderView* v = view();
hyatt@apple.com0de4d642009-02-05 22:26:53 +0000602 if (v && !v->doingFullRepaint() && hasLayer()) {
hyatt837eb362004-05-21 22:17:10 +0000603 // Because we waited until we were already inside layout to discover
604 // that the block really needed a full layout, we missed our chance to repaint the layer
605 // before layout started. Luckily the layer has cached the repaint rect for its original
606 // position and size, and so we can use that to make a repaint happen now.
hyatt@apple.com0de4d642009-02-05 22:26:53 +0000607 repaintUsingContainer(containerForRepaint(), layer()->repaintRect());
hyatt837eb362004-05-21 22:17:10 +0000608 }
609 }
hyatt0c3a9862004-02-23 21:26:26 +0000610
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000611 FloatingObject* lastFloat = m_floatingObjects ? m_floatingObjects->last() : 0;
612
613 LineMidpointState& lineMidpointState = resolver.midpointState();
614
615 // We also find the first clean line and extract these lines. We will add them back
616 // if we determine that we're able to synchronize after handling all our dirty lines.
617 InlineIterator cleanLineStart;
618 BidiStatus cleanLineBidiStatus;
hyatt@apple.com81c1d742010-10-06 21:44:02 +0000619 int endLineLogicalTop = 0;
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000620 RootInlineBox* endLine = (fullLayout || !startLine) ?
hyatt@apple.com81c1d742010-10-06 21:44:02 +0000621 0 : determineEndPosition(startLine, cleanLineStart, cleanLineBidiStatus, endLineLogicalTop);
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000622
623 if (startLine) {
hyatt@apple.comcc1737c2010-09-16 20:20:02 +0000624 if (!useRepaintBounds) {
625 useRepaintBounds = true;
hyatt@apple.com81c1d742010-10-06 21:44:02 +0000626 repaintLogicalTop = logicalHeight();
627 repaintLogicalBottom = logicalHeight();
hyatt@apple.comcc1737c2010-09-16 20:20:02 +0000628 }
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000629 RenderArena* arena = renderArena();
630 RootInlineBox* box = startLine;
631 while (box) {
hyatt@apple.com592848f2010-12-06 20:03:43 +0000632 repaintLogicalTop = min(repaintLogicalTop, beforeSideVisualOverflowForLine(box));
633 repaintLogicalBottom = max(repaintLogicalBottom, afterSideVisualOverflowForLine(box));
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000634 RootInlineBox* next = box->nextRootBox();
635 box->deleteLine(arena);
636 box = next;
637 }
638 }
639
640 InlineIterator end = resolver.position();
641
642 if (!fullLayout && lastRootBox() && lastRootBox()->endsWithBreak()) {
643 // If the last line before the start line ends with a line break that clear floats,
644 // adjust the height accordingly.
645 // A line break can be either the first or the last object on a line, depending on its direction.
646 if (InlineBox* lastLeafChild = lastRootBox()->lastLeafChild()) {
647 RenderObject* lastObject = lastLeafChild->renderer();
648 if (!lastObject->isBR())
649 lastObject = lastRootBox()->firstLeafChild()->renderer();
650 if (lastObject->isBR()) {
651 EClear clear = lastObject->style()->clear();
652 if (clear != CNONE)
653 newLine(clear);
654 }
655 }
656 }
657
658 bool endLineMatched = false;
659 bool checkForEndLineMatch = endLine;
660 bool checkForFloatsFromLastLine = false;
661
662 bool isLineEmpty = true;
hyatt@apple.comcc1737c2010-09-16 20:20:02 +0000663 bool paginated = view()->layoutState() && view()->layoutState()->isPaginated();
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000664
hyatt@apple.com4a9c625a2010-11-17 20:55:40 +0000665 VerticalPositionCache verticalPositionCache;
666
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000667 while (!end.atEnd()) {
668 // FIXME: Is this check necessary before the first iteration or can it be moved to the end?
hyatt@apple.com81c1d742010-10-06 21:44:02 +0000669 if (checkForEndLineMatch && (endLineMatched = matchedEndLine(resolver, cleanLineStart, cleanLineBidiStatus, endLine, endLineLogicalTop, repaintLogicalBottom, repaintLogicalTop)))
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000670 break;
671
672 lineMidpointState.reset();
673
674 isLineEmpty = true;
675
676 EClear clear = CNONE;
mitz@apple.comb2107652010-06-21 16:54:52 +0000677 bool hyphenated;
hyatt@apple.comcc1737c2010-09-16 20:20:02 +0000678
679 InlineIterator oldEnd = end;
680 FloatingObject* lastFloatFromPreviousLine = m_floatingObjects ? m_floatingObjects->last() : 0;
681 end = findNextLineBreak(resolver, firstLine, isLineEmpty, previousLineBrokeCleanly, hyphenated, &clear, lastFloatFromPreviousLine);
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000682 if (resolver.position().atEnd()) {
683 resolver.deleteRuns();
684 checkForFloatsFromLastLine = true;
685 break;
686 }
687 ASSERT(end != resolver.position());
688
689 if (!isLineEmpty) {
mitz@apple.com62d5bbd2010-06-25 18:07:01 +0000690 resolver.createBidiRunsForLine(end, style()->visuallyOrdered(), previousLineBrokeCleanly);
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000691 ASSERT(resolver.position() == end);
692
693 BidiRun* trailingSpaceRun = 0;
694 if (!previousLineBrokeCleanly && resolver.runCount() && resolver.logicallyLastRun()->m_object->style()->breakOnlyAfterWhiteSpace()
695 && resolver.logicallyLastRun()->m_object->style()->autoWrap()) {
696 trailingSpaceRun = resolver.logicallyLastRun();
697 RenderObject* lastObject = trailingSpaceRun->m_object;
698 if (lastObject->isText()) {
699 RenderText* lastText = toRenderText(lastObject);
700 const UChar* characters = lastText->characters();
701 int firstSpace = trailingSpaceRun->stop();
702 while (firstSpace > trailingSpaceRun->start()) {
703 UChar current = characters[firstSpace - 1];
704 if (!isCollapsibleSpace(current, lastText))
705 break;
706 firstSpace--;
707 }
708 if (firstSpace == trailingSpaceRun->stop())
709 trailingSpaceRun = 0;
710 else {
711 TextDirection direction = style()->direction();
712 bool shouldReorder = trailingSpaceRun != (direction == LTR ? resolver.lastRun() : resolver.firstRun());
713 if (firstSpace != trailingSpaceRun->start()) {
714 BidiContext* baseContext = resolver.context();
715 while (BidiContext* parent = baseContext->parent())
716 baseContext = parent;
717
718 BidiRun* newTrailingRun = new (renderArena()) BidiRun(firstSpace, trailingSpaceRun->m_stop, trailingSpaceRun->m_object, baseContext, OtherNeutral);
719 trailingSpaceRun->m_stop = firstSpace;
720 if (direction == LTR)
721 resolver.addRun(newTrailingRun);
722 else
723 resolver.prependRun(newTrailingRun);
724 trailingSpaceRun = newTrailingRun;
725 shouldReorder = false;
726 }
727 if (shouldReorder) {
728 if (direction == LTR) {
729 resolver.moveRunToEnd(trailingSpaceRun);
730 trailingSpaceRun->m_level = 0;
731 } else {
732 resolver.moveRunToBeginning(trailingSpaceRun);
733 trailingSpaceRun->m_level = 1;
734 }
735 }
736 }
737 } else
738 trailingSpaceRun = 0;
739 }
740
741 // Now that the runs have been ordered, we create the line boxes.
742 // At the same time we figure out where border/padding/margin should be applied for
743 // inline flow boxes.
744
745 RootInlineBox* lineBox = 0;
hyatt@apple.com81c1d742010-10-06 21:44:02 +0000746 int oldLogicalHeight = logicalHeight();
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000747 if (resolver.runCount()) {
mitz@apple.comb2107652010-06-21 16:54:52 +0000748 if (hyphenated)
749 resolver.logicallyLastRun()->m_hasHyphen = true;
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000750 lineBox = constructLine(resolver.runCount(), resolver.firstRun(), resolver.lastRun(), firstLine, !end.obj, end.obj && !end.pos ? end.obj : 0);
751 if (lineBox) {
752 lineBox->setEndsWithBreak(previousLineBrokeCleanly);
753
zimmermann@webkit.orgb40815c2010-06-18 11:18:44 +0000754#if ENABLE(SVG)
755 bool isSVGRootInlineBox = lineBox->isSVGRootInlineBox();
756#else
757 bool isSVGRootInlineBox = false;
758#endif
759
mitz@apple.com0cc7bed2010-05-17 01:43:49 +0000760 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
zimmermann@webkit.orgb40815c2010-06-18 11:18:44 +0000761
762 // Now we position all of our text runs horizontally.
763 if (!isSVGRootInlineBox)
hyatt@apple.com44e83c02010-09-23 22:21:30 +0000764 computeInlineDirectionPositionsForLine(lineBox, firstLine, resolver.firstRun(), trailingSpaceRun, end.atEnd(), textBoxDataMap);
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000765
766 // Now position our text runs vertically.
hyatt@apple.com4a9c625a2010-11-17 20:55:40 +0000767 computeBlockDirectionPositionsForLine(lineBox, resolver.firstRun(), textBoxDataMap, verticalPositionCache);
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000768
769#if ENABLE(SVG)
zimmermann@webkit.orgb40815c2010-06-18 11:18:44 +0000770 // SVG text layout code computes vertical & horizontal positions on its own.
771 // Note that we still need to execute computeVerticalPositionsForLine() as
772 // it calls InlineTextBox::positionLineBox(), which tracks whether the box
773 // contains reversed text or not. If we wouldn't do that editing and thus
774 // text selection in RTL boxes would not work as expected.
775 if (isSVGRootInlineBox) {
776 ASSERT(isSVGText());
777 static_cast<SVGRootInlineBox*>(lineBox)->computePerCharacterLayoutInformation();
778 }
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000779#endif
780
hyatt@apple.com592848f2010-12-06 20:03:43 +0000781 // Compute our overflow now.
782 lineBox->computeOverflow(lineBox->lineTop(), lineBox->lineBottom(), document()->inNoQuirksMode(), textBoxDataMap);
783
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000784#if PLATFORM(MAC)
785 // Highlight acts as an overflow inflation.
786 if (style()->highlight() != nullAtom)
787 lineBox->addHighlightOverflow();
788#endif
789 }
790 }
791
792 resolver.deleteRuns();
793
794 if (lineBox) {
795 lineBox->setLineBreakInfo(end.obj, end.pos, resolver.status());
796 if (useRepaintBounds) {
hyatt@apple.com592848f2010-12-06 20:03:43 +0000797 repaintLogicalTop = min(repaintLogicalTop, beforeSideVisualOverflowForLine(lineBox));
798 repaintLogicalBottom = max(repaintLogicalBottom, afterSideVisualOverflowForLine(lineBox));
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000799 }
hyatt@apple.comcc1737c2010-09-16 20:20:02 +0000800
801 if (paginated) {
802 int adjustment = 0;
803 adjustLinePositionForPagination(lineBox, adjustment);
804 if (adjustment) {
hyatt@apple.com81c1d742010-10-06 21:44:02 +0000805 int oldLineWidth = availableLogicalWidthForLine(oldLogicalHeight, firstLine);
hyatt@apple.com61bbedf2011-01-26 23:10:57 +0000806 lineBox->adjustBlockDirectionPosition(adjustment);
hyatt@apple.comcc1737c2010-09-16 20:20:02 +0000807 if (useRepaintBounds) // This can only be a positive adjustment, so no need to update repaintTop.
hyatt@apple.com592848f2010-12-06 20:03:43 +0000808 repaintLogicalBottom = max(repaintLogicalBottom, afterSideVisualOverflowForLine(lineBox));
hyatt@apple.comcc1737c2010-09-16 20:20:02 +0000809
hyatt@apple.com81c1d742010-10-06 21:44:02 +0000810 if (availableLogicalWidthForLine(oldLogicalHeight + adjustment, firstLine) != oldLineWidth) {
hyatt@apple.comcc1737c2010-09-16 20:20:02 +0000811 // We have to delete this line, remove all floats that got added, and let line layout re-run.
812 lineBox->deleteLine(renderArena());
hyatt@apple.com81c1d742010-10-06 21:44:02 +0000813 removeFloatingObjectsBelow(lastFloatFromPreviousLine, oldLogicalHeight);
814 setLogicalHeight(oldLogicalHeight + adjustment);
hyatt@apple.comcc1737c2010-09-16 20:20:02 +0000815 resolver.setPosition(oldEnd);
816 end = oldEnd;
817 continue;
818 }
819
hyatt@apple.coma956e332010-10-06 20:35:21 +0000820 setLogicalHeight(lineBox->blockLogicalHeight());
hyatt@apple.comcc1737c2010-09-16 20:20:02 +0000821 }
822 }
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000823 }
824
825 firstLine = false;
826 newLine(clear);
827 }
828
829 if (m_floatingObjects && lastRootBox()) {
830 if (lastFloat) {
831 for (FloatingObject* f = m_floatingObjects->last(); f != lastFloat; f = m_floatingObjects->prev()) {
832 }
833 m_floatingObjects->next();
834 } else
835 m_floatingObjects->first();
836 for (FloatingObject* f = m_floatingObjects->current(); f; f = m_floatingObjects->next()) {
837 lastRootBox()->floats().append(f->m_renderer);
838 ASSERT(f->m_renderer == floats[floatIndex].object);
839 // If a float's geometry has changed, give up on syncing with clean lines.
hyatt@apple.comf382f2e2010-10-01 21:25:39 +0000840 if (floats[floatIndex].rect != f->frameRect())
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000841 checkForEndLineMatch = false;
842 floatIndex++;
843 }
844 lastFloat = m_floatingObjects->last();
845 }
846
847 lineMidpointState.reset();
848 resolver.setPosition(end);
849 }
850
851 if (endLine) {
852 if (endLineMatched) {
853 // Attach all the remaining lines, and then adjust their y-positions as needed.
hyatt@apple.com81c1d742010-10-06 21:44:02 +0000854 int delta = logicalHeight() - endLineLogicalTop;
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000855 for (RootInlineBox* line = endLine; line; line = line->nextRootBox()) {
856 line->attachLine();
hyatt@apple.comcc1737c2010-09-16 20:20:02 +0000857 if (paginated) {
858 delta -= line->paginationStrut();
859 adjustLinePositionForPagination(line, delta);
860 }
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000861 if (delta) {
hyatt@apple.com592848f2010-12-06 20:03:43 +0000862 repaintLogicalTop = min(repaintLogicalTop, beforeSideVisualOverflowForLine(line) + min(delta, 0));
863 repaintLogicalBottom = max(repaintLogicalBottom, afterSideVisualOverflowForLine(line) + max(delta, 0));
hyatt@apple.com61bbedf2011-01-26 23:10:57 +0000864 line->adjustBlockDirectionPosition(delta);
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000865 }
866 if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) {
867 Vector<RenderBox*>::iterator end = cleanLineFloats->end();
868 for (Vector<RenderBox*>::iterator f = cleanLineFloats->begin(); f != end; ++f) {
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000869 insertFloatingObject(*f);
hyatt@apple.com81c1d742010-10-06 21:44:02 +0000870 setLogicalHeight(logicalTopForChild(*f) - marginBeforeForChild(*f) + delta);
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000871 positionNewFloats();
872 }
873 }
874 }
hyatt@apple.coma956e332010-10-06 20:35:21 +0000875 setLogicalHeight(lastRootBox()->blockLogicalHeight());
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000876 } else {
877 // Delete all the remaining lines.
878 RootInlineBox* line = endLine;
879 RenderArena* arena = renderArena();
880 while (line) {
hyatt@apple.com592848f2010-12-06 20:03:43 +0000881 repaintLogicalTop = min(repaintLogicalTop, beforeSideVisualOverflowForLine(line));
882 repaintLogicalBottom = max(repaintLogicalBottom, afterSideVisualOverflowForLine(line));
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000883 RootInlineBox* next = line->nextRootBox();
884 line->deleteLine(arena);
885 line = next;
886 }
887 }
888 }
889 if (m_floatingObjects && (checkForFloatsFromLastLine || positionNewFloats()) && lastRootBox()) {
890 // In case we have a float on the last line, it might not be positioned up to now.
891 // This has to be done before adding in the bottom border/padding, or the float will
892 // include the padding incorrectly. -dwh
893 if (checkForFloatsFromLastLine) {
hyatt@apple.com592848f2010-12-06 20:03:43 +0000894 int bottomVisualOverflow = afterSideVisualOverflowForLine(lastRootBox());
hyatt@apple.com81c1d742010-10-06 21:44:02 +0000895 int bottomLayoutOverflow = afterSideLayoutOverflowForLine(lastRootBox());
dbates@webkit.orgf6f05a92010-05-17 04:58:25 +0000896 TrailingFloatsRootInlineBox* trailingFloatsLineBox = new (renderArena()) TrailingFloatsRootInlineBox(this);
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000897 m_lineBoxes.appendLineBox(trailingFloatsLineBox);
898 trailingFloatsLineBox->setConstructed();
mitz@apple.com0cc7bed2010-05-17 01:43:49 +0000899 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
hyatt@apple.com4a9c625a2010-11-17 20:55:40 +0000900 VerticalPositionCache verticalPositionCache;
901 trailingFloatsLineBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache);
hyatt@apple.com592848f2010-12-06 20:03:43 +0000902 IntRect logicalLayoutOverflow(0, logicalHeight(), 1, bottomLayoutOverflow);
903 IntRect logicalVisualOverflow(0, logicalHeight(), 1, bottomVisualOverflow);
904 trailingFloatsLineBox->setOverflowFromLogicalRects(logicalLayoutOverflow, logicalVisualOverflow);
hyatt@apple.com81c1d742010-10-06 21:44:02 +0000905 trailingFloatsLineBox->setBlockLogicalHeight(logicalHeight());
abarth@webkit.org31d23df2010-04-05 21:52:09 +0000906 }
907 if (lastFloat) {
908 for (FloatingObject* f = m_floatingObjects->last(); f != lastFloat; f = m_floatingObjects->prev()) {
909 }
910 m_floatingObjects->next();
911 } else
912 m_floatingObjects->first();
913 for (FloatingObject* f = m_floatingObjects->current(); f; f = m_floatingObjects->next())
914 lastRootBox()->floats().append(f->m_renderer);
915 lastFloat = m_floatingObjects->last();
916 }
917 size_t floatCount = floats.size();
918 // Floats that did not have layout did not repaint when we laid them out. They would have
919 // painted by now if they had moved, but if they stayed at (0, 0), they still need to be
920 // painted.
921 for (size_t i = 0; i < floatCount; ++i) {
922 if (!floats[i].everHadLayout) {
923 RenderBox* f = floats[i].object;
924 if (!f->x() && !f->y() && f->checkForRepaintDuringLayout())
925 f->repaint();
926 }
927 }
kociendabb0c24b2001-08-24 14:24:40 +0000928 }
hyatt85586af2003-02-19 23:22:42 +0000929
mitz@apple.com3672d9e2010-12-17 19:31:16 +0000930 // Expand the last line to accommodate Ruby and emphasis marks.
931 int lastLineAnnotationsAdjustment = 0;
932 if (lastRootBox()) {
hyatt@apple.com5e48ff52010-11-19 00:43:29 +0000933 int lowestAllowedPosition = max(lastRootBox()->lineBottom(), logicalHeight() + paddingAfter());
mitz@apple.com3672d9e2010-12-17 19:31:16 +0000934 if (!style()->isFlippedLinesWritingMode())
935 lastLineAnnotationsAdjustment = lastRootBox()->computeUnderAnnotationAdjustment(lowestAllowedPosition);
936 else
937 lastLineAnnotationsAdjustment = lastRootBox()->computeOverAnnotationAdjustment(lowestAllowedPosition);
hyatt@apple.com5e48ff52010-11-19 00:43:29 +0000938 }
mitz@apple.com3672d9e2010-12-17 19:31:16 +0000939
hyatta70560a2002-11-20 01:53:20 +0000940 // Now add in the bottom border/padding.
mitz@apple.com3672d9e2010-12-17 19:31:16 +0000941 setLogicalHeight(logicalHeight() + lastLineAnnotationsAdjustment + borderAfter() + paddingAfter() + scrollbarLogicalHeight());
kociendabb0c24b2001-08-24 14:24:40 +0000942
adele7a470a72006-04-20 22:22:14 +0000943 if (!firstLineBox() && hasLineIfEmpty())
hyatt@apple.comddd8c302010-10-19 18:38:14 +0000944 setLogicalHeight(logicalHeight() + lineHeight(true, style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
hyatted77ad82004-06-15 07:21:23 +0000945
946 // See if we have any lines that spill out of our block. If we do, then we will possibly need to
947 // truncate text.
948 if (hasTextOverflow)
949 checkLinesForTextOverflow();
kociendabb0c24b2001-08-24 14:24:40 +0000950}
951
hyatt@apple.comb3466af2009-06-13 06:04:40 +0000952RootInlineBox* RenderBlock::determineStartPosition(bool& firstLine, bool& fullLayout, bool& previousLineBrokeCleanly,
hyatt@apple.comcc1737c2010-09-16 20:20:02 +0000953 InlineBidiResolver& resolver, Vector<FloatWithRect>& floats, unsigned& numCleanFloats,
hyatt@apple.com9a2e7d22010-10-06 22:13:31 +0000954 bool& useRepaintBounds, int& repaintLogicalTop, int& repaintLogicalBottom)
hyatt0c3a9862004-02-23 21:26:26 +0000955{
956 RootInlineBox* curr = 0;
957 RootInlineBox* last = 0;
mitz@apple.come1364202008-02-28 01:06:41 +0000958
mitz@apple.com40547b32008-03-18 04:04:34 +0000959 bool dirtiedByFloat = false;
960 if (!fullLayout) {
hyatt@apple.comcc1737c2010-09-16 20:20:02 +0000961 // Paginate all of the clean lines.
962 bool paginated = view()->layoutState() && view()->layoutState()->isPaginated();
963 int paginationDelta = 0;
mitz@apple.com40547b32008-03-18 04:04:34 +0000964 size_t floatIndex = 0;
965 for (curr = firstRootBox(); curr && !curr->isDirty(); curr = curr->nextRootBox()) {
hyatt@apple.comcc1737c2010-09-16 20:20:02 +0000966 if (paginated) {
967 paginationDelta -= curr->paginationStrut();
968 adjustLinePositionForPagination(curr, paginationDelta);
969 if (paginationDelta) {
970 if (containsFloats() || !floats.isEmpty()) {
971 // FIXME: Do better eventually. For now if we ever shift because of pagination and floats are present just go to a full layout.
972 fullLayout = true;
973 break;
974 }
975
976 if (!useRepaintBounds)
977 useRepaintBounds = true;
978
hyatt@apple.com592848f2010-12-06 20:03:43 +0000979 repaintLogicalTop = min(repaintLogicalTop, beforeSideVisualOverflowForLine(curr) + min(paginationDelta, 0));
980 repaintLogicalBottom = max(repaintLogicalBottom, afterSideVisualOverflowForLine(curr) + max(paginationDelta, 0));
hyatt@apple.com61bbedf2011-01-26 23:10:57 +0000981 curr->adjustBlockDirectionPosition(paginationDelta);
hyatt@apple.comcc1737c2010-09-16 20:20:02 +0000982 }
983 }
984
hyatt@apple.comd885df72009-01-22 02:31:52 +0000985 if (Vector<RenderBox*>* cleanLineFloats = curr->floatsPtr()) {
986 Vector<RenderBox*>::iterator end = cleanLineFloats->end();
987 for (Vector<RenderBox*>::iterator o = cleanLineFloats->begin(); o != end; ++o) {
988 RenderBox* f = *o;
hyatt@apple.comcc1737c2010-09-16 20:20:02 +0000989 f->layoutIfNeeded();
990 IntSize newSize(f->width() + f->marginLeft() + f->marginRight(), f->height() + f->marginTop() + f->marginBottom());
mitz@apple.com40547b32008-03-18 04:04:34 +0000991 ASSERT(floatIndex < floats.size());
992 if (floats[floatIndex].object != f) {
993 // A new float has been inserted before this line or before its last known float.
994 // Just do a full layout.
995 fullLayout = true;
996 break;
997 }
998 if (floats[floatIndex].rect.size() != newSize) {
hyatt@apple.com9a2e7d22010-10-06 22:13:31 +0000999 int floatTop = style()->isHorizontalWritingMode() ? floats[floatIndex].rect.y() : floats[floatIndex].rect.x();
1000 int floatHeight = style()->isHorizontalWritingMode() ? max(floats[floatIndex].rect.height(), newSize.height())
1001 : max(floats[floatIndex].rect.width(), newSize.width());
mitz@apple.com40547b32008-03-18 04:04:34 +00001002 curr->markDirty();
hyatt@apple.com9a2e7d22010-10-06 22:13:31 +00001003 markLinesDirtyInBlockRange(curr->blockLogicalHeight(), floatTop + floatHeight, curr);
mitz@apple.com40547b32008-03-18 04:04:34 +00001004 floats[floatIndex].rect.setSize(newSize);
1005 dirtiedByFloat = true;
1006 }
1007 floatIndex++;
1008 }
1009 }
1010 if (dirtiedByFloat || fullLayout)
1011 break;
1012 }
1013 // Check if a new float has been inserted after the last known float.
1014 if (!curr && floatIndex < floats.size())
1015 fullLayout = true;
1016 }
1017
hyatt0c3a9862004-02-23 21:26:26 +00001018 if (fullLayout) {
1019 // Nuke all our lines.
1020 if (firstRootBox()) {
1021 RenderArena* arena = renderArena();
1022 curr = firstRootBox();
1023 while (curr) {
1024 RootInlineBox* next = curr->nextRootBox();
1025 curr->deleteLine(arena);
1026 curr = next;
1027 }
darinec375482007-01-06 01:36:24 +00001028 ASSERT(!firstLineBox() && !lastLineBox());
hyatt0c3a9862004-02-23 21:26:26 +00001029 }
eseidel789896f2005-11-27 22:52:09 +00001030 } else {
hyatt0c3a9862004-02-23 21:26:26 +00001031 if (curr) {
1032 // We have a dirty line.
mjs9f78dd92007-02-12 04:06:07 +00001033 if (RootInlineBox* prevRootBox = curr->prevRootBox()) {
hyatt0c3a9862004-02-23 21:26:26 +00001034 // We have a previous line.
staikos@webkit.org19d8c5f2009-03-26 14:24:15 +00001035 if (!dirtiedByFloat && (!prevRootBox->endsWithBreak() || (prevRootBox->lineBreakObj()->isText() && prevRootBox->lineBreakPos() >= toRenderText(prevRootBox->lineBreakObj())->textLength())))
mjs9f78dd92007-02-12 04:06:07 +00001036 // The previous line didn't break cleanly or broke at a newline
1037 // that has been deleted, so treat it as dirty too.
1038 curr = prevRootBox;
hyatt0c3a9862004-02-23 21:26:26 +00001039 }
eseidel789896f2005-11-27 22:52:09 +00001040 } else {
hyatt0c3a9862004-02-23 21:26:26 +00001041 // No dirty lines were found.
1042 // If the last line didn't break cleanly, treat it as dirty.
1043 if (lastRootBox() && !lastRootBox()->endsWithBreak())
1044 curr = lastRootBox();
1045 }
mitz@apple.come1364202008-02-28 01:06:41 +00001046
hyatt0c3a9862004-02-23 21:26:26 +00001047 // If we have no dirty lines, then last is just the last root box.
1048 last = curr ? curr->prevRootBox() : lastRootBox();
1049 }
mitz@apple.come1364202008-02-28 01:06:41 +00001050
mitz@apple.com40547b32008-03-18 04:04:34 +00001051 numCleanFloats = 0;
1052 if (!floats.isEmpty()) {
hyatt@apple.com9a2e7d22010-10-06 22:13:31 +00001053 int savedLogicalHeight = logicalHeight();
mitz@apple.com40547b32008-03-18 04:04:34 +00001054 // Restore floats from clean lines.
1055 RootInlineBox* line = firstRootBox();
1056 while (line != curr) {
hyatt@apple.comd885df72009-01-22 02:31:52 +00001057 if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) {
1058 Vector<RenderBox*>::iterator end = cleanLineFloats->end();
1059 for (Vector<RenderBox*>::iterator f = cleanLineFloats->begin(); f != end; ++f) {
mitz@apple.com40547b32008-03-18 04:04:34 +00001060 insertFloatingObject(*f);
hyatt@apple.com9a2e7d22010-10-06 22:13:31 +00001061 setLogicalHeight(logicalTopForChild(*f) - marginBeforeForChild(*f));
mitz@apple.com40547b32008-03-18 04:04:34 +00001062 positionNewFloats();
1063 ASSERT(floats[numCleanFloats].object == *f);
1064 numCleanFloats++;
1065 }
1066 }
1067 line = line->nextRootBox();
1068 }
hyatt@apple.com9a2e7d22010-10-06 22:13:31 +00001069 setLogicalHeight(savedLogicalHeight);
mitz@apple.com40547b32008-03-18 04:04:34 +00001070 }
1071
hyatt@apple.comcd6f8952009-01-28 17:30:26 +00001072 firstLine = !last;
hyatt0c3a9862004-02-23 21:26:26 +00001073 previousLineBrokeCleanly = !last || last->endsWithBreak();
mitz@apple.com1a301772008-03-11 18:30:36 +00001074
1075 RenderObject* startObj;
1076 int pos = 0;
hyatt0c3a9862004-02-23 21:26:26 +00001077 if (last) {
hyatt@apple.coma956e332010-10-06 20:35:21 +00001078 setLogicalHeight(last->blockLogicalHeight());
hyatt0c3a9862004-02-23 21:26:26 +00001079 startObj = last->lineBreakObj();
1080 pos = last->lineBreakPos();
mitz@apple.com15035e62008-07-05 20:44:44 +00001081 resolver.setStatus(last->lineBreakBidiStatus());
darindde01502005-12-18 22:55:35 +00001082 } else {
hyatt@apple.comc0fa1632010-09-30 20:01:33 +00001083 bool ltr = style()->isLeftToRightDirection()
mitz@apple.com1a301772008-03-11 18:30:36 +00001084 #if ENABLE(SVG)
1085 || (style()->unicodeBidi() == UBNormal && isSVGText())
1086 #endif
1087 ;
mitz@apple.com40547b32008-03-18 04:04:34 +00001088
mitz@apple.com45d9e102009-04-27 16:24:55 +00001089 Direction direction = ltr ? LeftToRight : RightToLeft;
1090 resolver.setLastStrongDir(direction);
1091 resolver.setLastDir(direction);
1092 resolver.setEorDir(direction);
1093 resolver.setContext(BidiContext::create(ltr ? 0 : 1, direction, style()->unicodeBidi() == Override));
mitz@apple.com1a301772008-03-11 18:30:36 +00001094
mitz@apple.com15035e62008-07-05 20:44:44 +00001095 startObj = bidiFirst(this, &resolver);
darindde01502005-12-18 22:55:35 +00001096 }
mitz@apple.come1364202008-02-28 01:06:41 +00001097
mitz@apple.com15035e62008-07-05 20:44:44 +00001098 resolver.setPosition(InlineIterator(this, startObj, pos));
mitz@apple.come1364202008-02-28 01:06:41 +00001099
hyatt0c3a9862004-02-23 21:26:26 +00001100 return curr;
1101}
1102
hyatt@apple.com9a2e7d22010-10-06 22:13:31 +00001103RootInlineBox* RenderBlock::determineEndPosition(RootInlineBox* startLine, InlineIterator& cleanLineStart, BidiStatus& cleanLineBidiStatus, int& logicalTop)
hyatt0c3a9862004-02-23 21:26:26 +00001104{
1105 RootInlineBox* last = 0;
hyatta6960b12004-12-07 02:09:10 +00001106 if (!startLine)
hyatt0c3a9862004-02-23 21:26:26 +00001107 last = 0;
1108 else {
hyatt04420ca2004-07-16 00:05:42 +00001109 for (RootInlineBox* curr = startLine->nextRootBox(); curr; curr = curr->nextRootBox()) {
1110 if (curr->isDirty())
1111 last = 0;
1112 else if (!last)
1113 last = curr;
1114 }
hyatt0c3a9862004-02-23 21:26:26 +00001115 }
mitz@apple.come1364202008-02-28 01:06:41 +00001116
hyatt0c3a9862004-02-23 21:26:26 +00001117 if (!last)
1118 return 0;
mitz@apple.come1364202008-02-28 01:06:41 +00001119
eseidel789896f2005-11-27 22:52:09 +00001120 RootInlineBox* prev = last->prevRootBox();
mitz@apple.com15035e62008-07-05 20:44:44 +00001121 cleanLineStart = InlineIterator(this, prev->lineBreakObj(), prev->lineBreakPos());
eseidel789896f2005-11-27 22:52:09 +00001122 cleanLineBidiStatus = prev->lineBreakBidiStatus();
hyatt@apple.com9a2e7d22010-10-06 22:13:31 +00001123 logicalTop = prev->blockLogicalHeight();
mitz@apple.come1364202008-02-28 01:06:41 +00001124
hyatt0c3a9862004-02-23 21:26:26 +00001125 for (RootInlineBox* line = last; line; line = line->nextRootBox())
1126 line->extractLine(); // Disconnect all line boxes from their render objects while preserving
1127 // their connections to one another.
mitz@apple.come1364202008-02-28 01:06:41 +00001128
hyatt0c3a9862004-02-23 21:26:26 +00001129 return last;
1130}
1131
hyatt@apple.com9a2e7d22010-10-06 22:13:31 +00001132bool RenderBlock::matchedEndLine(const InlineBidiResolver& resolver, const InlineIterator& endLineStart, const BidiStatus& endLineStatus, RootInlineBox*& endLine,
1133 int& endLogicalTop, int& repaintLogicalBottom, int& repaintLogicalTop)
hyatt0c3a9862004-02-23 21:26:26 +00001134{
mitz@apple.com15035e62008-07-05 20:44:44 +00001135 if (resolver.position() == endLineStart) {
1136 if (resolver.status() != endLineStatus)
mitz@apple.com40547b32008-03-18 04:04:34 +00001137 return false;
1138
hyatt@apple.com9a2e7d22010-10-06 22:13:31 +00001139 int delta = logicalHeight() - endLogicalTop;
mitz@apple.com40547b32008-03-18 04:04:34 +00001140 if (!delta || !m_floatingObjects)
1141 return true;
1142
1143 // See if any floats end in the range along which we want to shift the lines vertically.
hyatt@apple.com9a2e7d22010-10-06 22:13:31 +00001144 int logicalTop = min(logicalHeight(), endLogicalTop);
mitz@apple.com40547b32008-03-18 04:04:34 +00001145
1146 RootInlineBox* lastLine = endLine;
1147 while (RootInlineBox* nextLine = lastLine->nextRootBox())
1148 lastLine = nextLine;
1149
hyatt@apple.com9a2e7d22010-10-06 22:13:31 +00001150 int logicalBottom = lastLine->blockLogicalHeight() + abs(delta);
mitz@apple.com40547b32008-03-18 04:04:34 +00001151
1152 for (FloatingObject* f = m_floatingObjects->first(); f; f = m_floatingObjects->next()) {
hyatt@apple.com9a2e7d22010-10-06 22:13:31 +00001153 if (logicalBottomForFloat(f) >= logicalTop && logicalBottomForFloat(f) < logicalBottom)
mitz@apple.com40547b32008-03-18 04:04:34 +00001154 return false;
1155 }
1156
1157 return true;
1158 }
hyatt0c3a9862004-02-23 21:26:26 +00001159
mitz@apple.come1364202008-02-28 01:06:41 +00001160 // The first clean line doesn't match, but we can check a handful of following lines to try
1161 // to match back up.
1162 static int numLines = 8; // The # of lines we're willing to match against.
1163 RootInlineBox* line = endLine;
1164 for (int i = 0; i < numLines && line; i++, line = line->nextRootBox()) {
mitz@apple.com15035e62008-07-05 20:44:44 +00001165 if (line->lineBreakObj() == resolver.position().obj && line->lineBreakPos() == resolver.position().pos) {
mitz@apple.come1364202008-02-28 01:06:41 +00001166 // We have a match.
mitz@apple.com15035e62008-07-05 20:44:44 +00001167 if (line->lineBreakBidiStatus() != resolver.status())
mitz@apple.come1364202008-02-28 01:06:41 +00001168 return false; // ...but the bidi state doesn't match.
1169 RootInlineBox* result = line->nextRootBox();
1170
hyatt@apple.com9a2e7d22010-10-06 22:13:31 +00001171 // Set our logical top to be the block height of endLine.
mitz@apple.come1364202008-02-28 01:06:41 +00001172 if (result)
hyatt@apple.com9a2e7d22010-10-06 22:13:31 +00001173 endLogicalTop = line->blockLogicalHeight();
mitz@apple.come1364202008-02-28 01:06:41 +00001174
hyatt@apple.com9a2e7d22010-10-06 22:13:31 +00001175 int delta = logicalHeight() - endLogicalTop;
mitz@apple.com40547b32008-03-18 04:04:34 +00001176 if (delta && m_floatingObjects) {
1177 // See if any floats end in the range along which we want to shift the lines vertically.
hyatt@apple.com9a2e7d22010-10-06 22:13:31 +00001178 int logicalTop = min(logicalHeight(), endLogicalTop);
mitz@apple.com40547b32008-03-18 04:04:34 +00001179
1180 RootInlineBox* lastLine = endLine;
1181 while (RootInlineBox* nextLine = lastLine->nextRootBox())
1182 lastLine = nextLine;
1183
hyatt@apple.com9a2e7d22010-10-06 22:13:31 +00001184 int logicalBottom = lastLine->blockLogicalHeight() + abs(delta);
mitz@apple.com40547b32008-03-18 04:04:34 +00001185
1186 for (FloatingObject* f = m_floatingObjects->first(); f; f = m_floatingObjects->next()) {
hyatt@apple.com9a2e7d22010-10-06 22:13:31 +00001187 if (logicalBottomForFloat(f) >= logicalTop && logicalBottomForFloat(f) < logicalBottom)
mitz@apple.com40547b32008-03-18 04:04:34 +00001188 return false;
1189 }
1190 }
1191
mitz@apple.come1364202008-02-28 01:06:41 +00001192 // Now delete the lines that we failed to sync.
1193 RootInlineBox* boxToDelete = endLine;
1194 RenderArena* arena = renderArena();
1195 while (boxToDelete && boxToDelete != result) {
hyatt@apple.com592848f2010-12-06 20:03:43 +00001196 repaintLogicalTop = min(repaintLogicalTop, beforeSideVisualOverflowForLine(boxToDelete));
1197 repaintLogicalBottom = max(repaintLogicalBottom, afterSideVisualOverflowForLine(boxToDelete));
mitz@apple.come1364202008-02-28 01:06:41 +00001198 RootInlineBox* next = boxToDelete->nextRootBox();
1199 boxToDelete->deleteLine(arena);
1200 boxToDelete = next;
hyatt0c3a9862004-02-23 21:26:26 +00001201 }
mitz@apple.come1364202008-02-28 01:06:41 +00001202
1203 endLine = result;
1204 return result;
hyatt0c3a9862004-02-23 21:26:26 +00001205 }
1206 }
mitz@apple.come1364202008-02-28 01:06:41 +00001207
hyatt0c3a9862004-02-23 21:26:26 +00001208 return false;
1209}
1210
hyatt@apple.comb3466af2009-06-13 06:04:40 +00001211static inline bool skipNonBreakingSpace(const InlineIterator& it, bool isLineEmpty, bool previousLineBrokeCleanly)
kocienda98440082004-10-14 23:51:47 +00001212{
darinf9e5d6c2007-01-09 14:54:26 +00001213 if (it.obj->style()->nbspMode() != SPACE || it.current() != noBreakSpace)
kocienda98440082004-10-14 23:51:47 +00001214 return false;
mitz@apple.come1364202008-02-28 01:06:41 +00001215
hyattdca76e92005-11-02 08:52:50 +00001216 // FIXME: This is bad. It makes nbsp inconsistent with space and won't work correctly
1217 // with m_minWidth/m_maxWidth.
kocienda498d1982004-10-15 21:07:24 +00001218 // Do not skip a non-breaking space if it is the first character
hyattdca76e92005-11-02 08:52:50 +00001219 // on a line after a clean line break (or on the first line, since previousLineBrokeCleanly starts off
1220 // |true|).
1221 if (isLineEmpty && previousLineBrokeCleanly)
kocienda498d1982004-10-15 21:07:24 +00001222 return false;
mitz@apple.come1364202008-02-28 01:06:41 +00001223
kocienda498d1982004-10-15 21:07:24 +00001224 return true;
kocienda98440082004-10-14 23:51:47 +00001225}
1226
hyatt@apple.comb3466af2009-06-13 06:04:40 +00001227static inline bool shouldCollapseWhiteSpace(const RenderStyle* style, bool isLineEmpty, bool previousLineBrokeCleanly)
hyattd9953212005-11-03 21:05:59 +00001228{
1229 return style->collapseWhiteSpace() || (style->whiteSpace() == PRE_WRAP && (!isLineEmpty || !previousLineBrokeCleanly));
1230}
1231
zimmermannac3781f2007-02-04 01:25:03 +00001232static inline bool shouldPreserveNewline(RenderObject* object)
1233{
mjsd2948ef2007-02-26 19:29:04 +00001234#if ENABLE(SVG)
zimmermann@webkit.orge943aaa2010-06-25 10:03:33 +00001235 if (object->isSVGInlineText())
zimmermannac3781f2007-02-04 01:25:03 +00001236 return false;
1237#endif
1238
1239 return object->style()->preserveNewline();
1240}
1241
hyatt@apple.com0d4818f2009-02-08 05:39:22 +00001242static bool inlineFlowRequiresLineBox(RenderInline* flow)
bdakinf876bee2007-10-30 05:27:09 +00001243{
1244 // FIXME: Right now, we only allow line boxes for inlines that are truly empty.
hyatt@apple.comeb66ef42008-01-18 22:59:29 +00001245 // We need to fix this, though, because at the very least, inlines containing only
1246 // ignorable whitespace should should also have line boxes.
hyatt@apple.com0415e5d2010-10-07 17:40:25 +00001247 return !flow->firstChild() && flow->hasInlineDirectionBordersPaddingOrMargin();
bdakinf876bee2007-10-30 05:27:09 +00001248}
1249
hyatt@apple.com71eeb442010-02-11 20:05:51 +00001250bool RenderBlock::requiresLineBox(const InlineIterator& it, bool isLineEmpty, bool previousLineBrokeCleanly)
bdashccffb432007-07-13 11:51:40 +00001251{
bdakinf876bee2007-10-30 05:27:09 +00001252 if (it.obj->isFloatingOrPositioned())
bdashccffb432007-07-13 11:51:40 +00001253 return false;
bdakinf876bee2007-10-30 05:27:09 +00001254
hyatt@apple.com0d4818f2009-02-08 05:39:22 +00001255 if (it.obj->isRenderInline() && !inlineFlowRequiresLineBox(toRenderInline(it.obj)))
bdakinf876bee2007-10-30 05:27:09 +00001256 return false;
1257
hyatt@apple.comb3466af2009-06-13 06:04:40 +00001258 if (!shouldCollapseWhiteSpace(it.obj->style(), isLineEmpty, previousLineBrokeCleanly) || it.obj->isBR())
bdashccffb432007-07-13 11:51:40 +00001259 return true;
1260
1261 UChar current = it.current();
hyatt@apple.comb3466af2009-06-13 06:04:40 +00001262 return current != ' ' && current != '\t' && current != softHyphen && (current != '\n' || shouldPreserveNewline(it.obj))
1263 && !skipNonBreakingSpace(it, isLineEmpty, previousLineBrokeCleanly);
bdashccffb432007-07-13 11:51:40 +00001264}
1265
hyatt@apple.comb3466af2009-06-13 06:04:40 +00001266bool RenderBlock::generatesLineBoxesForInlineChild(RenderObject* inlineObj, bool isLineEmpty, bool previousLineBrokeCleanly)
bdashccffb432007-07-13 11:51:40 +00001267{
1268 ASSERT(inlineObj->parent() == this);
1269
mitz@apple.com15035e62008-07-05 20:44:44 +00001270 InlineIterator it(this, inlineObj, 0);
hyatt@apple.comb3466af2009-06-13 06:04:40 +00001271 while (!it.atEnd() && !requiresLineBox(it, isLineEmpty, previousLineBrokeCleanly))
mitz@apple.com1a301772008-03-11 18:30:36 +00001272 it.increment();
bdashccffb432007-07-13 11:51:40 +00001273
1274 return !it.atEnd();
1275}
1276
mitz@apple.combf6e8d32008-07-25 20:21:06 +00001277// FIXME: The entire concept of the skipTrailingWhitespace function is flawed, since we really need to be building
mitz@apple.com1a301772008-03-11 18:30:36 +00001278// line boxes even for containers that may ultimately collapse away. Otherwise we'll never get positioned
1279// elements quite right. In other words, we need to build this function's work into the normal line
1280// object iteration process.
mitz@apple.combf6e8d32008-07-25 20:21:06 +00001281// NB. this function will insert any floating elements that would otherwise
1282// be skipped but it will not position them.
hyatt@apple.comb3466af2009-06-13 06:04:40 +00001283void RenderBlock::skipTrailingWhitespace(InlineIterator& iterator, bool isLineEmpty, bool previousLineBrokeCleanly)
kociendabb0c24b2001-08-24 14:24:40 +00001284{
hyatt@apple.comb3466af2009-06-13 06:04:40 +00001285 while (!iterator.atEnd() && !requiresLineBox(iterator, isLineEmpty, previousLineBrokeCleanly)) {
mitz@apple.com1a301772008-03-11 18:30:36 +00001286 RenderObject* object = iterator.obj;
1287 if (object->isFloating()) {
hyatt@apple.comd885df72009-01-22 02:31:52 +00001288 insertFloatingObject(toRenderBox(object));
mitz@apple.com1a301772008-03-11 18:30:36 +00001289 } else if (object->isPositioned()) {
mitz@apple.come1364202008-02-28 01:06:41 +00001290 // FIXME: The math here is actually not really right. It's a best-guess approximation that
1291 // will work for the common cases
mitz@apple.com1a301772008-03-11 18:30:36 +00001292 RenderObject* c = object->container();
hyatt@apple.com415d8de2009-01-26 22:29:19 +00001293 if (c->isRenderInline()) {
mitz@apple.come1364202008-02-28 01:06:41 +00001294 // A relative positioned inline encloses us. In this case, we also have to determine our
1295 // position as though we were an inline. Set |staticX| and |staticY| on the relative positioned
1296 // inline so that we can obtain the value later.
hyatt@apple.comc0fa1632010-09-30 20:01:33 +00001297 toRenderInline(c)->layer()->setStaticX(style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(height(), false) : logicalRightOffsetForLine(height(), false));
hyatt@apple.com0de4d642009-02-05 22:26:53 +00001298 toRenderInline(c)->layer()->setStaticY(height());
hyatt33f8d492002-11-12 21:44:52 +00001299 }
mitz@apple.com1a301772008-03-11 18:30:36 +00001300
hyatt@apple.com0de4d642009-02-05 22:26:53 +00001301 RenderBox* box = toRenderBox(object);
1302 if (box->style()->hasStaticX()) {
1303 if (box->style()->isOriginalDisplayInlineType())
hyatt@apple.comc0fa1632010-09-30 20:01:33 +00001304 box->layer()->setStaticX(style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(height(), false) : width() - logicalRightOffsetForLine(height(), false));
mitz@apple.come1364202008-02-28 01:06:41 +00001305 else
hyatt@apple.comc0fa1632010-09-30 20:01:33 +00001306 box->layer()->setStaticX(style()->isLeftToRightDirection() ? borderLeft() + paddingLeft() : borderRight() + paddingRight());
hyatt98ee7e42003-05-14 01:39:15 +00001307 }
mitz@apple.com1a301772008-03-11 18:30:36 +00001308
hyatt@apple.com0de4d642009-02-05 22:26:53 +00001309 if (box->style()->hasStaticY())
1310 box->layer()->setStaticY(height());
hyatt33f8d492002-11-12 21:44:52 +00001311 }
mitz@apple.com1a301772008-03-11 18:30:36 +00001312 iterator.increment();
mjs6f821c82002-03-22 00:31:57 +00001313 }
mitz@apple.com1a301772008-03-11 18:30:36 +00001314}
bdashccffb432007-07-13 11:51:40 +00001315
hyatt@apple.comcc1737c2010-09-16 20:20:02 +00001316int RenderBlock::skipLeadingWhitespace(InlineBidiResolver& resolver, bool firstLine, bool isLineEmpty, bool previousLineBrokeCleanly,
1317 FloatingObject* lastFloatFromPreviousLine)
mitz@apple.com1a301772008-03-11 18:30:36 +00001318{
hyatt@apple.com0415e5d2010-10-07 17:40:25 +00001319 int availableWidth = availableLogicalWidthForLine(logicalHeight(), firstLine);
hyatt@apple.comb3466af2009-06-13 06:04:40 +00001320 while (!resolver.position().atEnd() && !requiresLineBox(resolver.position(), isLineEmpty, previousLineBrokeCleanly)) {
mitz@apple.com15035e62008-07-05 20:44:44 +00001321 RenderObject* object = resolver.position().obj;
mitz@apple.com1a301772008-03-11 18:30:36 +00001322 if (object->isFloating()) {
hyatt@apple.comcc1737c2010-09-16 20:20:02 +00001323 positionNewFloatOnLine(insertFloatingObject(toRenderBox(object)), lastFloatFromPreviousLine);
hyatt@apple.com0415e5d2010-10-07 17:40:25 +00001324 availableWidth = availableLogicalWidthForLine(logicalHeight(), firstLine);
mitz@apple.com1a301772008-03-11 18:30:36 +00001325 } else if (object->isPositioned()) {
1326 // FIXME: The math here is actually not really right. It's a best-guess approximation that
1327 // will work for the common cases
1328 RenderObject* c = object->container();
hyatt@apple.com415d8de2009-01-26 22:29:19 +00001329 if (c->isRenderInline()) {
mitz@apple.com1a301772008-03-11 18:30:36 +00001330 // A relative positioned inline encloses us. In this case, we also have to determine our
1331 // position as though we were an inline. Set |staticX| and |staticY| on the relative positioned
1332 // inline so that we can obtain the value later.
hyatt@apple.comc0fa1632010-09-30 20:01:33 +00001333 toRenderInline(c)->layer()->setStaticX(style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(height(), firstLine) : logicalRightOffsetForLine(height(), firstLine));
hyatt@apple.com0de4d642009-02-05 22:26:53 +00001334 toRenderInline(c)->layer()->setStaticY(height());
mitz@apple.com1a301772008-03-11 18:30:36 +00001335 }
1336
hyatt@apple.com0de4d642009-02-05 22:26:53 +00001337 RenderBox* box = toRenderBox(object);
1338 if (box->style()->hasStaticX()) {
bfulgham@webkit.orga519d8a2009-02-08 02:10:55 +00001339 if (box->style()->isOriginalDisplayInlineType())
hyatt@apple.comc0fa1632010-09-30 20:01:33 +00001340 box->layer()->setStaticX(style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(height(), firstLine) : width() - logicalRightOffsetForLine(height(), firstLine));
mitz@apple.com1a301772008-03-11 18:30:36 +00001341 else
hyatt@apple.comc0fa1632010-09-30 20:01:33 +00001342 box->layer()->setStaticX(style()->isLeftToRightDirection() ? borderLeft() + paddingLeft() : borderRight() + paddingRight());
mitz@apple.com1a301772008-03-11 18:30:36 +00001343 }
1344
hyatt@apple.com0de4d642009-02-05 22:26:53 +00001345 if (box->style()->hasStaticY())
1346 box->layer()->setStaticY(height());
mitz@apple.com1a301772008-03-11 18:30:36 +00001347 }
mitz@apple.com15035e62008-07-05 20:44:44 +00001348 resolver.increment();
mitz@apple.com1a301772008-03-11 18:30:36 +00001349 }
mitz@apple.com83d2e872008-10-23 21:56:03 +00001350 resolver.commitExplicitEmbedding();
mitz@apple.com1a301772008-03-11 18:30:36 +00001351 return availableWidth;
kociendae40cb942004-10-05 20:05:38 +00001352}
1353
bdakinf876bee2007-10-30 05:27:09 +00001354// This is currently just used for list markers and inline flows that have line boxes. Neither should
1355// have an effect on whitespace at the start of the line.
hyatt@apple.comb3466af2009-06-13 06:04:40 +00001356static bool shouldSkipWhitespaceAfterStartObject(RenderBlock* block, RenderObject* o, LineMidpointState& lineMidpointState)
bdakinf876bee2007-10-30 05:27:09 +00001357{
mitz@apple.com1a301772008-03-11 18:30:36 +00001358 RenderObject* next = bidiNext(block, o);
darin@apple.com36744d62009-01-25 20:23:04 +00001359 if (next && !next->isBR() && next->isText() && toRenderText(next)->textLength() > 0) {
1360 RenderText* nextText = toRenderText(next);
bdakinf876bee2007-10-30 05:27:09 +00001361 UChar nextChar = nextText->characters()[0];
1362 if (nextText->style()->isCollapsibleWhiteSpace(nextChar)) {
hyatt@apple.comb3466af2009-06-13 06:04:40 +00001363 addMidpoint(lineMidpointState, InlineIterator(0, o, 0));
bdakinf876bee2007-10-30 05:27:09 +00001364 return true;
1365 }
1366 }
1367
1368 return false;
1369}
1370
hyatt@apple.comcd6f8952009-01-28 17:30:26 +00001371void RenderBlock::fitBelowFloats(int widthToFit, bool firstLine, int& availableWidth)
mitz@apple.comcfd9b7b2008-02-24 04:00:21 +00001372{
1373 ASSERT(widthToFit > availableWidth);
1374
hyatt@apple.com2d76a3b2010-10-02 00:13:00 +00001375 int floatLogicalBottom;
hyatt@apple.com0415e5d2010-10-07 17:40:25 +00001376 int lastFloatLogicalBottom = logicalHeight();
mitz@apple.comcfd9b7b2008-02-24 04:00:21 +00001377 int newLineWidth = availableWidth;
1378 while (true) {
hyatt@apple.com2d76a3b2010-10-02 00:13:00 +00001379 floatLogicalBottom = nextFloatLogicalBottomBelow(lastFloatLogicalBottom);
1380 if (!floatLogicalBottom)
mitz@apple.comcfd9b7b2008-02-24 04:00:21 +00001381 break;
1382
hyatt@apple.com2d76a3b2010-10-02 00:13:00 +00001383 newLineWidth = availableLogicalWidthForLine(floatLogicalBottom, firstLine);
1384 lastFloatLogicalBottom = floatLogicalBottom;
mitz@apple.comcfd9b7b2008-02-24 04:00:21 +00001385 if (newLineWidth >= widthToFit)
1386 break;
1387 }
1388
1389 if (newLineWidth > availableWidth) {
hyatt@apple.com2d76a3b2010-10-02 00:13:00 +00001390 setLogicalHeight(lastFloatLogicalBottom);
mitz@apple.comcfd9b7b2008-02-24 04:00:21 +00001391 availableWidth = newLineWidth;
1392 }
1393}
1394
mitz@apple.com34106442009-02-01 06:23:39 +00001395static inline unsigned textWidth(RenderText* text, unsigned from, unsigned len, const Font& font, int xPos, bool isFixedPitch, bool collapseWhiteSpace)
1396{
hyatt@apple.com4d046b72011-01-31 20:39:09 +00001397 if (isFixedPitch || (!from && len == text->textLength()) || text->style()->hasTextCombine())
mitz@apple.com34106442009-02-01 06:23:39 +00001398 return text->width(from, len, font, xPos);
1399 return font.width(TextRun(text->characters() + from, len, !collapseWhiteSpace, xPos));
1400}
1401
mitz@apple.com73eb8c92010-08-04 21:22:24 +00001402static void tryHyphenating(RenderText* text, const Font& font, const AtomicString& localeIdentifier, int lastSpace, int pos, int xPos, int availableWidth, bool isFixedPitch, bool collapseWhiteSpace, int lastSpaceWordSpacing, InlineIterator& lineBreak, int nextBreakable, bool& hyphenated)
mitz@apple.comb2107652010-06-21 16:54:52 +00001403{
1404 const AtomicString& hyphenString = text->style()->hyphenString();
1405 int hyphenWidth = font.width(TextRun(hyphenString.characters(), hyphenString.length()));
1406
mitz@apple.com7c67b292010-09-12 23:04:16 +00001407 int maxPrefixWidth = availableWidth - xPos - hyphenWidth - lastSpaceWordSpacing;
1408 // If the maximum width available for the prefix before the hyphen is small, then it is very unlikely
1409 // that an hyphenation opportunity exists, so do not bother to look for it.
1410 if (maxPrefixWidth <= font.pixelSize() * 5 / 4)
1411 return;
1412
1413 unsigned prefixLength = font.offsetForPosition(TextRun(text->characters() + lastSpace, pos - lastSpace, !collapseWhiteSpace, xPos + lastSpaceWordSpacing), maxPrefixWidth, false);
mitz@apple.comb2107652010-06-21 16:54:52 +00001414 if (!prefixLength)
1415 return;
1416
mitz@apple.com2ef44912010-08-07 21:41:06 +00001417 prefixLength = lastHyphenLocation(text->characters() + lastSpace, pos - lastSpace, prefixLength + 1, localeIdentifier);
1418 if (!prefixLength)
mitz@apple.comb2107652010-06-21 16:54:52 +00001419 return;
1420
1421#if !ASSERT_DISABLED
1422 int prefixWidth = hyphenWidth + textWidth(text, lastSpace, prefixLength, font, xPos, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing;
1423 ASSERT(xPos + prefixWidth <= availableWidth);
mitz@apple.com34b43c72010-06-21 17:21:22 +00001424#else
1425 UNUSED_PARAM(isFixedPitch);
mitz@apple.comb2107652010-06-21 16:54:52 +00001426#endif
1427
1428 lineBreak.obj = text;
1429 lineBreak.pos = lastSpace + prefixLength;
1430 lineBreak.nextBreakablePosition = nextBreakable;
1431 hyphenated = true;
1432}
1433
hyatt@apple.comb3466af2009-06-13 06:04:40 +00001434InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool firstLine, bool& isLineEmpty, bool& previousLineBrokeCleanly,
hyatt@apple.comcc1737c2010-09-16 20:20:02 +00001435 bool& hyphenated, EClear* clear, FloatingObject* lastFloatFromPreviousLine)
kociendae40cb942004-10-05 20:05:38 +00001436{
mitz@apple.com15035e62008-07-05 20:44:44 +00001437 ASSERT(resolver.position().block == this);
mitz@apple.com51017322008-02-26 06:47:43 +00001438
mitz@apple.com15035e62008-07-05 20:44:44 +00001439 bool appliedStartWidth = resolver.position().pos > 0;
hyatt@apple.comb3466af2009-06-13 06:04:40 +00001440 LineMidpointState& lineMidpointState = resolver.midpointState();
1441
hyatt@apple.comcc1737c2010-09-16 20:20:02 +00001442 int width = skipLeadingWhitespace(resolver, firstLine, isLineEmpty, previousLineBrokeCleanly, lastFloatFromPreviousLine);
mitz@apple.com1a301772008-03-11 18:30:36 +00001443
kociendae40cb942004-10-05 20:05:38 +00001444 int w = 0;
1445 int tmpW = 0;
kociendae40cb942004-10-05 20:05:38 +00001446
mitz@apple.com15035e62008-07-05 20:44:44 +00001447 if (resolver.position().atEnd())
1448 return resolver.position();
mjs6f821c82002-03-22 00:31:57 +00001449
hyatt33f8d492002-11-12 21:44:52 +00001450 // This variable is used only if whitespace isn't set to PRE, and it tells us whether
1451 // or not we are currently ignoring whitespace.
1452 bool ignoringSpaces = false;
mitz@apple.com15035e62008-07-05 20:44:44 +00001453 InlineIterator ignoreStart;
hyatt33f8d492002-11-12 21:44:52 +00001454
1455 // This variable tracks whether the very last character we saw was a space. We use
1456 // this to detect when we encounter a second space so we know we have to terminate
1457 // a run.
rjwc9c257d2003-01-24 03:46:17 +00001458 bool currentCharacterIsSpace = false;
harrisone343c412005-01-18 01:07:26 +00001459 bool currentCharacterIsWS = false;
hyatt33f8d492002-11-12 21:44:52 +00001460 RenderObject* trailingSpaceObject = 0;
hyatt98b16282004-03-31 18:43:12 +00001461
mitz@apple.com15035e62008-07-05 20:44:44 +00001462 InlineIterator lBreak = resolver.position();
mjs6f821c82002-03-22 00:31:57 +00001463
mitz@apple.com15035e62008-07-05 20:44:44 +00001464 RenderObject *o = resolver.position().obj;
kociendabb0c24b2001-08-24 14:24:40 +00001465 RenderObject *last = o;
mitz@apple.com15035e62008-07-05 20:44:44 +00001466 unsigned pos = resolver.position().pos;
mitz@apple.comd17dc392008-09-15 18:48:20 +00001467 int nextBreakable = resolver.position().nextBreakablePosition;
ddkilzere8759ef2007-03-25 06:28:19 +00001468 bool atStart = true;
kociendabb0c24b2001-08-24 14:24:40 +00001469
hyatt0c3a9862004-02-23 21:26:26 +00001470 bool prevLineBrokeCleanly = previousLineBrokeCleanly;
1471 previousLineBrokeCleanly = false;
ddkilzer5d01fa22007-01-29 03:10:37 +00001472
mitz@apple.comb2107652010-06-21 16:54:52 +00001473 hyphenated = false;
1474
ddkilzer5d01fa22007-01-29 03:10:37 +00001475 bool autoWrapWasEverTrueOnLine = false;
mitz@apple.com25beac62008-02-24 18:48:27 +00001476 bool floatsFitOnLine = true;
hyatt01eff982003-03-14 20:13:23 +00001477
hyatt@apple.com69340902008-01-16 21:24:21 +00001478 // Firefox and Opera will allow a table cell to grow to fit an image inside it under
mitz@apple.com25beac62008-02-24 18:48:27 +00001479 // very specific circumstances (in order to match common WinIE renderings).
hyatt@apple.com69340902008-01-16 21:24:21 +00001480 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
hyatt@apple.com0415e5d2010-10-07 17:40:25 +00001481 bool allowImagesToBreak = !document()->inQuirksMode() || !isTableCell() || !style()->logicalWidth().isIntrinsicOrAuto();
hyatt@apple.com69340902008-01-16 21:24:21 +00001482
hyattb0d9f602007-01-15 01:28:23 +00001483 EWhiteSpace currWS = style()->whiteSpace();
1484 EWhiteSpace lastWS = currWS;
hyatt275d0702005-11-03 23:53:57 +00001485 while (o) {
hyattb0d9f602007-01-15 01:28:23 +00001486 currWS = o->isReplaced() ? o->parent()->style()->whiteSpace() : o->style()->whiteSpace();
1487 lastWS = last->isReplaced() ? last->parent()->style()->whiteSpace() : last->style()->whiteSpace();
1488
1489 bool autoWrap = RenderStyle::autoWrap(currWS);
ddkilzer5d01fa22007-01-29 03:10:37 +00001490 autoWrapWasEverTrueOnLine = autoWrapWasEverTrueOnLine || autoWrap;
zimmermannac3781f2007-02-04 01:25:03 +00001491
mjsd2948ef2007-02-26 19:29:04 +00001492#if ENABLE(SVG)
zimmermann@webkit.orge943aaa2010-06-25 10:03:33 +00001493 bool preserveNewline = o->isSVGInlineText() ? false : RenderStyle::preserveNewline(currWS);
zimmermannac3781f2007-02-04 01:25:03 +00001494#else
hyattb0d9f602007-01-15 01:28:23 +00001495 bool preserveNewline = RenderStyle::preserveNewline(currWS);
zimmermannac3781f2007-02-04 01:25:03 +00001496#endif
1497
hyattb0d9f602007-01-15 01:28:23 +00001498 bool collapseWhiteSpace = RenderStyle::collapseWhiteSpace(currWS);
1499
hyatt275d0702005-11-03 23:53:57 +00001500 if (o->isBR()) {
hyatt0c3a9862004-02-23 21:26:26 +00001501 if (w + tmpW <= width) {
kociendabb0c24b2001-08-24 14:24:40 +00001502 lBreak.obj = o;
1503 lBreak.pos = 0;
mitz@apple.comd17dc392008-09-15 18:48:20 +00001504 lBreak.nextBreakablePosition = -1;
mitz@apple.com1a301772008-03-11 18:30:36 +00001505 lBreak.increment();
hyatt0c3a9862004-02-23 21:26:26 +00001506
hyatt33f8d492002-11-12 21:44:52 +00001507 // A <br> always breaks a line, so don't let the line be collapsed
1508 // away. Also, the space at the end of a line with a <br> does not
hyatt01eff982003-03-14 20:13:23 +00001509 // get collapsed away. It only does this if the previous line broke
1510 // cleanly. Otherwise the <br> has no effect on whether the line is
1511 // empty or not.
1512 if (prevLineBrokeCleanly)
1513 isLineEmpty = false;
hyatt33f8d492002-11-12 21:44:52 +00001514 trailingSpaceObject = 0;
hyatt0c3a9862004-02-23 21:26:26 +00001515 previousLineBrokeCleanly = true;
hyatt74eec4d2003-03-23 08:02:47 +00001516
mitz@apple.com71e30842008-03-18 16:13:31 +00001517 if (!isLineEmpty && clear)
1518 *clear = o->style()->clear();
kociendabb0c24b2001-08-24 14:24:40 +00001519 }
1520 goto end;
1521 }
hyattb0d9f602007-01-15 01:28:23 +00001522
hyatt275d0702005-11-03 23:53:57 +00001523 if (o->isFloatingOrPositioned()) {
kociendabb0c24b2001-08-24 14:24:40 +00001524 // add to special objects...
hyatt275d0702005-11-03 23:53:57 +00001525 if (o->isFloating()) {
hyatt@apple.comd885df72009-01-22 02:31:52 +00001526 RenderBox* floatBox = toRenderBox(o);
hyatt@apple.comcc1737c2010-09-16 20:20:02 +00001527 FloatingObject* f = insertFloatingObject(floatBox);
hyatt33f8d492002-11-12 21:44:52 +00001528 // check if it fits in the current line.
1529 // If it does, position it now, otherwise, position
1530 // it after moving to next line (in newLine() func)
hyatt@apple.com0415e5d2010-10-07 17:40:25 +00001531 if (floatsFitOnLine && logicalWidthForFloat(f) + w + tmpW <= width) {
hyatt@apple.comcc1737c2010-09-16 20:20:02 +00001532 positionNewFloatOnLine(f, lastFloatFromPreviousLine);
hyatt@apple.com0415e5d2010-10-07 17:40:25 +00001533 width = availableLogicalWidthForLine(logicalHeight(), firstLine);
mitz@apple.com25beac62008-02-24 18:48:27 +00001534 } else
1535 floatsFitOnLine = false;
hyatt275d0702005-11-03 23:53:57 +00001536 } else if (o->isPositioned()) {
hyatt851816b2003-07-08 07:54:17 +00001537 // If our original display wasn't an inline type, then we can
hyatt98ee7e42003-05-14 01:39:15 +00001538 // go ahead and determine our static x position now.
hyatt@apple.com0de4d642009-02-05 22:26:53 +00001539 RenderBox* box = toRenderBox(o);
1540 bool isInlineType = box->style()->isOriginalDisplayInlineType();
1541 bool needToSetStaticX = box->style()->hasStaticX();
1542 if (box->style()->hasStaticX() && !isInlineType) {
hyatt@apple.comc0fa1632010-09-30 20:01:33 +00001543 box->layer()->setStaticX(o->parent()->style()->isLeftToRightDirection() ?
hyattb0d9f602007-01-15 01:28:23 +00001544 borderLeft() + paddingLeft() :
1545 borderRight() + paddingRight());
hyatt98ee7e42003-05-14 01:39:15 +00001546 needToSetStaticX = false;
1547 }
1548
1549 // If our original display was an INLINE type, then we can go ahead
1550 // and determine our static y position now.
hyatt@apple.com0de4d642009-02-05 22:26:53 +00001551 bool needToSetStaticY = box->style()->hasStaticY();
1552 if (box->style()->hasStaticY() && isInlineType) {
1553 box->layer()->setStaticY(height());
hyatt98ee7e42003-05-14 01:39:15 +00001554 needToSetStaticY = false;
1555 }
1556
hyatt853cd7d2004-11-05 02:59:48 +00001557 bool needToCreateLineBox = needToSetStaticX || needToSetStaticY;
1558 RenderObject* c = o->container();
hyatt@apple.com415d8de2009-01-26 22:29:19 +00001559 if (c->isRenderInline() && (!needToSetStaticX || !needToSetStaticY))
hyatt853cd7d2004-11-05 02:59:48 +00001560 needToCreateLineBox = true;
1561
hyatt98ee7e42003-05-14 01:39:15 +00001562 // If we're ignoring spaces, we have to stop and include this object and
1563 // then start ignoring spaces again.
hyatt853cd7d2004-11-05 02:59:48 +00001564 if (needToCreateLineBox) {
hyattbc7f07f2003-05-27 20:04:26 +00001565 trailingSpaceObject = 0;
hyatt98b16282004-03-31 18:43:12 +00001566 ignoreStart.obj = o;
1567 ignoreStart.pos = 0;
hyattbc7f07f2003-05-27 20:04:26 +00001568 if (ignoringSpaces) {
hyatt@apple.comb3466af2009-06-13 06:04:40 +00001569 addMidpoint(lineMidpointState, ignoreStart); // Stop ignoring spaces.
1570 addMidpoint(lineMidpointState, ignoreStart); // Start ignoring again.
hyattbc7f07f2003-05-27 20:04:26 +00001571 }
hyatt98b16282004-03-31 18:43:12 +00001572
hyatt851816b2003-07-08 07:54:17 +00001573 }
hyatt98ee7e42003-05-14 01:39:15 +00001574 }
hyatt@apple.com415d8de2009-01-26 22:29:19 +00001575 } else if (o->isRenderInline()) {
bdakinf876bee2007-10-30 05:27:09 +00001576 // Right now, we should only encounter empty inlines here.
ggarenf9f32ae2007-03-26 20:08:53 +00001577 ASSERT(!o->firstChild());
bdakinf876bee2007-10-30 05:27:09 +00001578
hyatt@apple.com0d4818f2009-02-08 05:39:22 +00001579 RenderInline* flowBox = toRenderInline(o);
hyatt@apple.com774bbed2009-01-23 05:13:22 +00001580
bdakinf876bee2007-10-30 05:27:09 +00001581 // Now that some inline flows have line boxes, if we are already ignoring spaces, we need
1582 // to make sure that we stop to include this object and then start ignoring spaces again.
1583 // If this object is at the start of the line, we need to behave like list markers and
1584 // start ignoring spaces.
hyatt@apple.com774bbed2009-01-23 05:13:22 +00001585 if (inlineFlowRequiresLineBox(flowBox)) {
hyatt@apple.comeb66ef42008-01-18 22:59:29 +00001586 isLineEmpty = false;
bdakinf876bee2007-10-30 05:27:09 +00001587 if (ignoringSpaces) {
1588 trailingSpaceObject = 0;
hyatt@apple.comb3466af2009-06-13 06:04:40 +00001589 addMidpoint(lineMidpointState, InlineIterator(0, o, 0)); // Stop ignoring spaces.
1590 addMidpoint(lineMidpointState, InlineIterator(0, o, 0)); // Start ignoring again.
mitz@apple.com15035e62008-07-05 20:44:44 +00001591 } else if (style()->collapseWhiteSpace() && resolver.position().obj == o
hyatt@apple.comb3466af2009-06-13 06:04:40 +00001592 && shouldSkipWhitespaceAfterStartObject(this, o, lineMidpointState)) {
bdakinf876bee2007-10-30 05:27:09 +00001593 // Like with list markers, we start ignoring spaces to make sure that any
1594 // additional spaces we see will be discarded.
1595 currentCharacterIsSpace = true;
1596 currentCharacterIsWS = true;
1597 ignoringSpaces = true;
1598 }
1599 }
1600
hyatt@apple.com0415e5d2010-10-07 17:40:25 +00001601 tmpW += flowBox->marginStart() + flowBox->borderStart() + flowBox->paddingStart() +
1602 flowBox->marginEnd() + flowBox->borderEnd() + flowBox->paddingEnd();
hyatt275d0702005-11-03 23:53:57 +00001603 } else if (o->isReplaced()) {
hyatt@apple.comd885df72009-01-22 02:31:52 +00001604 RenderBox* replacedBox = toRenderBox(o);
1605
hyattde396342003-10-29 08:57:20 +00001606 // Break on replaced elements if either has normal white-space.
hyatt@apple.com69340902008-01-16 21:24:21 +00001607 if ((autoWrap || RenderStyle::autoWrap(lastWS)) && (!o->isImage() || allowImagesToBreak)) {
hyatt711fe232002-11-20 21:25:14 +00001608 w += tmpW;
1609 tmpW = 0;
hyattf14a4a32002-11-21 22:06:32 +00001610 lBreak.obj = o;
1611 lBreak.pos = 0;
mitz@apple.comd17dc392008-09-15 18:48:20 +00001612 lBreak.nextBreakablePosition = -1;
hyatt711fe232002-11-20 21:25:14 +00001613 }
1614
mitz@apple.combfdc9112008-02-21 19:59:40 +00001615 if (ignoringSpaces)
hyatt@apple.comb3466af2009-06-13 06:04:40 +00001616 addMidpoint(lineMidpointState, InlineIterator(0, o, 0));
mitz@apple.combfdc9112008-02-21 19:59:40 +00001617
hyatt33f8d492002-11-12 21:44:52 +00001618 isLineEmpty = false;
1619 ignoringSpaces = false;
rjwc9c257d2003-01-24 03:46:17 +00001620 currentCharacterIsSpace = false;
harrisone343c412005-01-18 01:07:26 +00001621 currentCharacterIsWS = false;
hyatt33f8d492002-11-12 21:44:52 +00001622 trailingSpaceObject = 0;
hamaji@chromium.org382642b2009-12-01 07:37:14 +00001623
bdakinf876bee2007-10-30 05:27:09 +00001624 // Optimize for a common case. If we can't find whitespace after the list
hyatt@apple.com0415e5d2010-10-07 17:40:25 +00001625 // item, then this is all moot.
1626 int replacedLogicalWidth = logicalWidthForChild(replacedBox) + marginStartForChild(replacedBox) + marginEndForChild(replacedBox) + inlineLogicalWidth(o);
hamaji@chromium.org382642b2009-12-01 07:37:14 +00001627 if (o->isListMarker()) {
hyatt@apple.comb3466af2009-06-13 06:04:40 +00001628 if (style()->collapseWhiteSpace() && shouldSkipWhitespaceAfterStartObject(this, o, lineMidpointState)) {
bdakinf876bee2007-10-30 05:27:09 +00001629 // Like with inline flows, we start ignoring spaces to make sure that any
1630 // additional spaces we see will be discarded.
1631 currentCharacterIsSpace = true;
1632 currentCharacterIsWS = true;
1633 ignoringSpaces = true;
hyatte85e4a72002-12-08 02:06:16 +00001634 }
hamaji@chromium.org382642b2009-12-01 07:37:14 +00001635 if (toRenderListMarker(o)->isInside())
hyatt@apple.com0415e5d2010-10-07 17:40:25 +00001636 tmpW += replacedLogicalWidth;
justing244d3a32006-04-13 01:31:24 +00001637 } else
hyatt@apple.com0415e5d2010-10-07 17:40:25 +00001638 tmpW += replacedLogicalWidth;
eseidel789896f2005-11-27 22:52:09 +00001639 } else if (o->isText()) {
mitz@apple.com51017322008-02-26 06:47:43 +00001640 if (!pos)
1641 appliedStartWidth = false;
1642
darin@apple.com36744d62009-01-25 20:23:04 +00001643 RenderText* t = toRenderText(o);
mitz@apple.comfb8da4e2008-02-19 21:13:19 +00001644
zimmermann@webkit.org6e96afd2010-09-10 15:35:50 +00001645#if ENABLE(SVG)
1646 bool isSVGText = t->isSVGInlineText();
1647#endif
1648
hyatt@apple.com4d046b72011-01-31 20:39:09 +00001649 RenderStyle* style = t->style(firstLine);
1650 if (style->hasTextCombine())
1651 toRenderCombineText(o)->combineText();
1652
darin42563ac52007-01-22 17:28:57 +00001653 int strlen = t->textLength();
hyatt33f8d492002-11-12 21:44:52 +00001654 int len = strlen - pos;
darin42563ac52007-01-22 17:28:57 +00001655 const UChar* str = t->characters();
kociendabb0c24b2001-08-24 14:24:40 +00001656
mitz@apple.comb2107652010-06-21 16:54:52 +00001657 const Font& f = style->font();
mitz@apple.com34106442009-02-01 06:23:39 +00001658 bool isFixedPitch = f.isFixedPitch();
mitz@apple.com73eb8c92010-08-04 21:22:24 +00001659 bool canHyphenate = style->hyphens() == HyphensAuto && WebCore::canHyphenate(style->hyphenationLocale());
weinigf28a1c32007-02-14 14:10:31 +00001660
hyatt33f8d492002-11-12 21:44:52 +00001661 int lastSpace = pos;
hyatt3aff2332003-01-23 01:15:28 +00001662 int wordSpacing = o->style()->wordSpacing();
eseideld13fe532005-11-30 02:40:29 +00001663 int lastSpaceWordSpacing = 0;
hyattffe78712003-02-11 01:59:29 +00001664
mitz@apple.comfa13fcc2010-01-07 01:41:32 +00001665 // Non-zero only when kerning is enabled, in which case we measure words with their trailing
1666 // space, then subtract its width.
mitz@apple.com6ff116d2010-07-06 00:11:08 +00001667 int wordTrailingSpaceWidth = f.typesettingFeatures() & Kerning ? f.width(TextRun(&space, 1)) + wordSpacing : 0;
mitz@apple.comfa13fcc2010-01-07 01:41:32 +00001668
hyatt@apple.com0415e5d2010-10-07 17:40:25 +00001669 int wrapW = tmpW + inlineLogicalWidth(o, !appliedStartWidth, true);
weiniged111c12007-07-13 22:45:11 +00001670 int charWidth = 0;
weinigf28a1c32007-02-14 14:10:31 +00001671 bool breakNBSP = autoWrap && o->style()->nbspMode() == SPACE;
1672 // Auto-wrapping text should wrap in the middle of a word only if it could not wrap before the word,
1673 // which is only possible if the word is the first thing on the line, that is, if |w| is zero.
hyattea474f72007-04-20 05:02:19 +00001674 bool breakWords = o->style()->breakWords() && ((autoWrap && !w) || currWS == PRE);
weinigf28a1c32007-02-14 14:10:31 +00001675 bool midWordBreak = false;
hyattea474f72007-04-20 05:02:19 +00001676 bool breakAll = o->style()->wordBreak() == BreakAllWordBreak && autoWrap;
mitz@apple.com20e34452010-09-28 19:38:15 +00001677 int hyphenWidth = 0;
hyattea474f72007-04-20 05:02:19 +00001678
mitz@apple.comfb8da4e2008-02-19 21:13:19 +00001679 if (t->isWordBreak()) {
1680 w += tmpW;
1681 tmpW = 0;
1682 lBreak.obj = o;
1683 lBreak.pos = 0;
mitz@apple.comd17dc392008-09-15 18:48:20 +00001684 lBreak.nextBreakablePosition = -1;
mitz@apple.comfb8da4e2008-02-19 21:13:19 +00001685 ASSERT(!len);
1686 }
1687
hyatt275d0702005-11-03 23:53:57 +00001688 while (len) {
rjwc9c257d2003-01-24 03:46:17 +00001689 bool previousCharacterIsSpace = currentCharacterIsSpace;
harrisone343c412005-01-18 01:07:26 +00001690 bool previousCharacterIsWS = currentCharacterIsWS;
darin7ab31092006-05-10 04:59:57 +00001691 UChar c = str[pos];
hyattb0d9f602007-01-15 01:28:23 +00001692 currentCharacterIsSpace = c == ' ' || c == '\t' || (!preserveNewline && (c == '\n'));
darin47ece0d2005-09-04 07:42:31 +00001693
hyattb0d9f602007-01-15 01:28:23 +00001694 if (!collapseWhiteSpace || !currentCharacterIsSpace)
hyatt33f8d492002-11-12 21:44:52 +00001695 isLineEmpty = false;
mitz@apple.combe429562008-03-07 01:09:51 +00001696
mitz@apple.com20e34452010-09-28 19:38:15 +00001697 if (c == softHyphen && autoWrap && !hyphenWidth && style->hyphens() != HyphensNone) {
1698 const AtomicString& hyphenString = style->hyphenString();
1699 hyphenWidth = f.width(TextRun(hyphenString.characters(), hyphenString.length()));
1700 tmpW += hyphenWidth;
hyatt78b85132004-03-29 20:07:45 +00001701 }
mitz@apple.com20e34452010-09-28 19:38:15 +00001702
zimmermann@webkit.org6e96afd2010-09-10 15:35:50 +00001703#if ENABLE(SVG)
1704 if (isSVGText) {
1705 RenderSVGInlineText* svgInlineText = static_cast<RenderSVGInlineText*>(t);
1706 if (pos > 0) {
1707 if (svgInlineText->characterStartsNewTextChunk(pos)) {
1708 addMidpoint(lineMidpointState, InlineIterator(0, o, pos - 1));
1709 addMidpoint(lineMidpointState, InlineIterator(0, o, pos));
1710 }
1711 }
1712 }
1713#endif
1714
hyatt3aff2332003-01-23 01:15:28 +00001715 bool applyWordSpacing = false;
hyattdca76e92005-11-02 08:52:50 +00001716
darinf9e5d6c2007-01-09 14:54:26 +00001717 currentCharacterIsWS = currentCharacterIsSpace || (breakNBSP && c == noBreakSpace);
harrisone343c412005-01-18 01:07:26 +00001718
weiniged111c12007-07-13 22:45:11 +00001719 if ((breakAll || breakWords) && !midWordBreak) {
1720 wrapW += charWidth;
mitz@apple.com34106442009-02-01 06:23:39 +00001721 charWidth = textWidth(t, pos, 1, f, w + wrapW, isFixedPitch, collapseWhiteSpace);
weiniged111c12007-07-13 22:45:11 +00001722 midWordBreak = w + wrapW + charWidth > width;
weinigf28a1c32007-02-14 14:10:31 +00001723 }
darin47ece0d2005-09-04 07:42:31 +00001724
mitz@apple.com20e34452010-09-28 19:38:15 +00001725 bool betweenWords = c == '\n' || (currWS != PRE && !atStart && isBreakable(str, pos, strlen, nextBreakable, breakNBSP) && (style->hyphens() != HyphensNone || (pos && str[pos - 1] != softHyphen)));
1726
weiniged111c12007-07-13 22:45:11 +00001727 if (betweenWords || midWordBreak) {
hyatt0c05e102006-04-14 08:15:00 +00001728 bool stoppedIgnoringSpaces = false;
hyatt33f8d492002-11-12 21:44:52 +00001729 if (ignoringSpaces) {
rjwc9c257d2003-01-24 03:46:17 +00001730 if (!currentCharacterIsSpace) {
hyatt33f8d492002-11-12 21:44:52 +00001731 // Stop ignoring spaces and begin at this
1732 // new point.
hyatt48710d62003-08-21 09:17:13 +00001733 ignoringSpaces = false;
eseideld13fe532005-11-30 02:40:29 +00001734 lastSpaceWordSpacing = 0;
hyatt48710d62003-08-21 09:17:13 +00001735 lastSpace = pos; // e.g., "Foo goo", don't add in any of the ignored spaces.
hyatt@apple.comb3466af2009-06-13 06:04:40 +00001736 addMidpoint(lineMidpointState, InlineIterator(0, o, pos));
hyatt0c05e102006-04-14 08:15:00 +00001737 stoppedIgnoringSpaces = true;
harrisone343c412005-01-18 01:07:26 +00001738 } else {
hyatt33f8d492002-11-12 21:44:52 +00001739 // Just keep ignoring these spaces.
1740 pos++;
1741 len--;
1742 continue;
1743 }
1744 }
rjwc9c257d2003-01-24 03:46:17 +00001745
mitz@apple.comfa13fcc2010-01-07 01:41:32 +00001746 int additionalTmpW;
1747 if (wordTrailingSpaceWidth && currentCharacterIsSpace)
1748 additionalTmpW = textWidth(t, lastSpace, pos + 1 - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) - wordTrailingSpaceWidth + lastSpaceWordSpacing;
1749 else
1750 additionalTmpW = textWidth(t, lastSpace, pos - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing;
darin54008922006-01-13 16:39:05 +00001751 tmpW += additionalTmpW;
hyattffe78712003-02-11 01:59:29 +00001752 if (!appliedStartWidth) {
hyatt@apple.com0415e5d2010-10-07 17:40:25 +00001753 tmpW += inlineLogicalWidth(o, true, false);
hyattffe78712003-02-11 01:59:29 +00001754 appliedStartWidth = true;
1755 }
1756
eseideld13fe532005-11-30 02:40:29 +00001757 applyWordSpacing = wordSpacing && currentCharacterIsSpace && !previousCharacterIsSpace;
hyatt3aff2332003-01-23 01:15:28 +00001758
mitz@apple.comcfd9b7b2008-02-24 04:00:21 +00001759 if (!w && autoWrap && tmpW > width)
hyatt@apple.comcd6f8952009-01-28 17:30:26 +00001760 fitBelowFloats(tmpW, firstLine, width);
mitz@apple.comcfd9b7b2008-02-24 04:00:21 +00001761
hyattb0d9f602007-01-15 01:28:23 +00001762 if (autoWrap || breakWords) {
hyattdca76e92005-11-02 08:52:50 +00001763 // If we break only after white-space, consider the current character
kociendae4134242004-10-25 18:48:44 +00001764 // as candidate width for this line.
ap932806a2006-10-01 09:06:09 +00001765 bool lineWasTooWide = false;
1766 if (w + tmpW <= width && currentCharacterIsWS && o->style()->breakOnlyAfterWhiteSpace() && !midWordBreak) {
mitz@apple.com34106442009-02-01 06:23:39 +00001767 int charWidth = textWidth(t, pos, 1, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + (applyWordSpacing ? wordSpacing : 0);
ap932806a2006-10-01 09:06:09 +00001768 // Check if line is too big even without the extra space
1769 // at the end of the line. If it is not, do nothing.
1770 // If the line needs the extra whitespace to be too long,
1771 // then move the line break to the space and skip all
1772 // additional whitespace.
1773 if (w + tmpW + charWidth > width) {
1774 lineWasTooWide = true;
1775 lBreak.obj = o;
1776 lBreak.pos = pos;
mitz@apple.comd17dc392008-09-15 18:48:20 +00001777 lBreak.nextBreakablePosition = nextBreakable;
hyatt@apple.comb3466af2009-06-13 06:04:40 +00001778 skipTrailingWhitespace(lBreak, isLineEmpty, previousLineBrokeCleanly);
kocienda9dbe9b12004-10-22 20:07:05 +00001779 }
ap932806a2006-10-01 09:06:09 +00001780 }
1781 if (lineWasTooWide || w + tmpW > width) {
mitz@apple.com67ed70a2010-06-22 22:10:10 +00001782 if (canHyphenate && w + tmpW > width) {
mitz@apple.com73eb8c92010-08-04 21:22:24 +00001783 tryHyphenating(t, f, style->hyphenationLocale(), lastSpace, pos, w + tmpW - additionalTmpW, width, isFixedPitch, collapseWhiteSpace, lastSpaceWordSpacing, lBreak, nextBreakable, hyphenated);
mitz@apple.com67ed70a2010-06-22 22:10:10 +00001784 if (hyphenated)
1785 goto end;
1786 }
eric@webkit.org1cb44402009-12-29 06:25:16 +00001787 if (lBreak.obj && shouldPreserveNewline(lBreak.obj) && lBreak.obj->isText() && toRenderText(lBreak.obj)->textLength() && !toRenderText(lBreak.obj)->isWordBreak() && toRenderText(lBreak.obj)->characters()[lBreak.pos] == '\n') {
hyatt0c05e102006-04-14 08:15:00 +00001788 if (!stoppedIgnoringSpaces && pos > 0) {
1789 // We need to stop right before the newline and then start up again.
hyatt@apple.comb3466af2009-06-13 06:04:40 +00001790 addMidpoint(lineMidpointState, InlineIterator(0, o, pos - 1)); // Stop
1791 addMidpoint(lineMidpointState, InlineIterator(0, o, pos)); // Start
hyatt0c05e102006-04-14 08:15:00 +00001792 }
mitz@apple.com1a301772008-03-11 18:30:36 +00001793 lBreak.increment();
adele7fc3e832006-02-17 09:31:35 +00001794 previousLineBrokeCleanly = true;
adele7fc3e832006-02-17 09:31:35 +00001795 }
mitz@apple.com20e34452010-09-28 19:38:15 +00001796 if (lBreak.obj && lBreak.pos && lBreak.obj->isText() && toRenderText(lBreak.obj)->textLength() && toRenderText(lBreak.obj)->characters()[lBreak.pos - 1] == softHyphen && style->hyphens() != HyphensNone)
1797 hyphenated = true;
hyatt78b85132004-03-29 20:07:45 +00001798 goto end; // Didn't fit. Jump to the end.
darin54008922006-01-13 16:39:05 +00001799 } else {
weiniged111c12007-07-13 22:45:11 +00001800 if (!betweenWords || (midWordBreak && !autoWrap))
darin54008922006-01-13 16:39:05 +00001801 tmpW -= additionalTmpW;
mitz@apple.com20e34452010-09-28 19:38:15 +00001802 if (hyphenWidth) {
darin54008922006-01-13 16:39:05 +00001803 // Subtract the width of the soft hyphen out since we fit on a line.
mitz@apple.com20e34452010-09-28 19:38:15 +00001804 tmpW -= hyphenWidth;
1805 hyphenWidth = 0;
1806 }
darin54008922006-01-13 16:39:05 +00001807 }
rjwc9c257d2003-01-24 03:46:17 +00001808 }
hyatt33f8d492002-11-12 21:44:52 +00001809
hyattb0d9f602007-01-15 01:28:23 +00001810 if (c == '\n' && preserveNewline) {
hyatt0c05e102006-04-14 08:15:00 +00001811 if (!stoppedIgnoringSpaces && pos > 0) {
1812 // We need to stop right before the newline and then start up again.
hyatt@apple.comb3466af2009-06-13 06:04:40 +00001813 addMidpoint(lineMidpointState, InlineIterator(0, o, pos - 1)); // Stop
1814 addMidpoint(lineMidpointState, InlineIterator(0, o, pos)); // Start
hyatt0c05e102006-04-14 08:15:00 +00001815 }
hyatta9f48e32003-02-03 22:48:01 +00001816 lBreak.obj = o;
1817 lBreak.pos = pos;
mitz@apple.comd17dc392008-09-15 18:48:20 +00001818 lBreak.nextBreakablePosition = nextBreakable;
mitz@apple.com1a301772008-03-11 18:30:36 +00001819 lBreak.increment();
adele7fc3e832006-02-17 09:31:35 +00001820 previousLineBrokeCleanly = true;
hyatt33f8d492002-11-12 21:44:52 +00001821 return lBreak;
1822 }
hyatta9f48e32003-02-03 22:48:01 +00001823
weinigf28a1c32007-02-14 14:10:31 +00001824 if (autoWrap && betweenWords) {
hyatta9f48e32003-02-03 22:48:01 +00001825 w += tmpW;
weiniged111c12007-07-13 22:45:11 +00001826 wrapW = 0;
hyatta9f48e32003-02-03 22:48:01 +00001827 tmpW = 0;
1828 lBreak.obj = o;
1829 lBreak.pos = pos;
mitz@apple.comd17dc392008-09-15 18:48:20 +00001830 lBreak.nextBreakablePosition = nextBreakable;
weinigf28a1c32007-02-14 14:10:31 +00001831 // Auto-wrapping text should not wrap in the middle of a word once it has had an
1832 // opportunity to break after a word.
1833 breakWords = false;
hyatta9f48e32003-02-03 22:48:01 +00001834 }
hyatt33f8d492002-11-12 21:44:52 +00001835
darin54008922006-01-13 16:39:05 +00001836 if (midWordBreak) {
1837 // Remember this as a breakable position in case
1838 // adding the end width forces a break.
1839 lBreak.obj = o;
1840 lBreak.pos = pos;
mitz@apple.comd17dc392008-09-15 18:48:20 +00001841 lBreak.nextBreakablePosition = nextBreakable;
weiniged111c12007-07-13 22:45:11 +00001842 midWordBreak &= (breakWords || breakAll);
1843 }
1844
1845 if (betweenWords) {
darin54008922006-01-13 16:39:05 +00001846 lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
1847 lastSpace = pos;
1848 }
hyatt33f8d492002-11-12 21:44:52 +00001849
hyattdca76e92005-11-02 08:52:50 +00001850 if (!ignoringSpaces && o->style()->collapseWhiteSpace()) {
hyatt33f8d492002-11-12 21:44:52 +00001851 // If we encounter a newline, or if we encounter a
1852 // second space, we need to go ahead and break up this
1853 // run and enter a mode where we start collapsing spaces.
hyatt98b16282004-03-31 18:43:12 +00001854 if (currentCharacterIsSpace && previousCharacterIsSpace) {
hyatt33f8d492002-11-12 21:44:52 +00001855 ignoringSpaces = true;
hyatt98b16282004-03-31 18:43:12 +00001856
hyatt33f8d492002-11-12 21:44:52 +00001857 // We just entered a mode where we are ignoring
1858 // spaces. Create a midpoint to terminate the run
1859 // before the second space.
hyatt@apple.comb3466af2009-06-13 06:04:40 +00001860 addMidpoint(lineMidpointState, ignoreStart);
hyatt33f8d492002-11-12 21:44:52 +00001861 }
1862 }
eseidel789896f2005-11-27 22:52:09 +00001863 } else if (ignoringSpaces) {
hyatt33f8d492002-11-12 21:44:52 +00001864 // Stop ignoring spaces and begin at this
1865 // new point.
1866 ignoringSpaces = false;
eseideld13fe532005-11-30 02:40:29 +00001867 lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
hyatt33f8d492002-11-12 21:44:52 +00001868 lastSpace = pos; // e.g., "Foo goo", don't add in any of the ignored spaces.
hyatt@apple.comb3466af2009-06-13 06:04:40 +00001869 addMidpoint(lineMidpointState, InlineIterator(0, o, pos));
hyatt33f8d492002-11-12 21:44:52 +00001870 }
hyatt98b16282004-03-31 18:43:12 +00001871
1872 if (currentCharacterIsSpace && !previousCharacterIsSpace) {
1873 ignoreStart.obj = o;
1874 ignoreStart.pos = pos;
1875 }
harrisone343c412005-01-18 01:07:26 +00001876
1877 if (!currentCharacterIsWS && previousCharacterIsWS) {
hyattb0d9f602007-01-15 01:28:23 +00001878 if (autoWrap && o->style()->breakOnlyAfterWhiteSpace()) {
harrisone343c412005-01-18 01:07:26 +00001879 lBreak.obj = o;
1880 lBreak.pos = pos;
mitz@apple.comd17dc392008-09-15 18:48:20 +00001881 lBreak.nextBreakablePosition = nextBreakable;
harrisone343c412005-01-18 01:07:26 +00001882 }
1883 }
hyatt33f8d492002-11-12 21:44:52 +00001884
hyattb0d9f602007-01-15 01:28:23 +00001885 if (collapseWhiteSpace && currentCharacterIsSpace && !ignoringSpaces)
hyatt33f8d492002-11-12 21:44:52 +00001886 trailingSpaceObject = o;
hyattdca76e92005-11-02 08:52:50 +00001887 else if (!o->style()->collapseWhiteSpace() || !currentCharacterIsSpace)
hyatt33f8d492002-11-12 21:44:52 +00001888 trailingSpaceObject = 0;
1889
1890 pos++;
1891 len--;
ddkilzere8759ef2007-03-25 06:28:19 +00001892 atStart = false;
hyatt33f8d492002-11-12 21:44:52 +00001893 }
mitz@apple.comfb8da4e2008-02-19 21:13:19 +00001894
kociendabb0c24b2001-08-24 14:24:40 +00001895 // IMPORTANT: pos is > length here!
mitz@apple.comb2107652010-06-21 16:54:52 +00001896 int additionalTmpW = ignoringSpaces ? 0 : textWidth(t, lastSpace, pos - lastSpace, f, w + tmpW, isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing;
1897 tmpW += additionalTmpW;
hyatt@apple.com0415e5d2010-10-07 17:40:25 +00001898 tmpW += inlineLogicalWidth(o, !appliedStartWidth, true);
mitz@apple.comb2107652010-06-21 16:54:52 +00001899
1900 if (canHyphenate && w + tmpW > width) {
mitz@apple.com73eb8c92010-08-04 21:22:24 +00001901 tryHyphenating(t, f, style->hyphenationLocale(), lastSpace, pos, w + tmpW - additionalTmpW, width, isFixedPitch, collapseWhiteSpace, lastSpaceWordSpacing, lBreak, nextBreakable, hyphenated);
mitz@apple.comb2107652010-06-21 16:54:52 +00001902 if (hyphenated)
1903 goto end;
1904 }
kociendabb0c24b2001-08-24 14:24:40 +00001905 } else
weinigf28a1c32007-02-14 14:10:31 +00001906 ASSERT_NOT_REACHED();
kociendabb0c24b2001-08-24 14:24:40 +00001907
mitz@apple.com1a301772008-03-11 18:30:36 +00001908 RenderObject* next = bidiNext(this, o);
hyattdca76e92005-11-02 08:52:50 +00001909 bool checkForBreak = autoWrap;
hyattb0d9f602007-01-15 01:28:23 +00001910 if (w && w + tmpW > width && lBreak.obj && currWS == NOWRAP)
hyatt74eec4d2003-03-23 08:02:47 +00001911 checkForBreak = true;
1912 else if (next && o->isText() && next->isText() && !next->isBR()) {
hyattdca76e92005-11-02 08:52:50 +00001913 if (autoWrap || (next->style()->autoWrap())) {
hyatta9f48e32003-02-03 22:48:01 +00001914 if (currentCharacterIsSpace)
1915 checkForBreak = true;
1916 else {
harrison07b5e582005-08-15 23:31:16 +00001917 checkForBreak = false;
darin@apple.com36744d62009-01-25 20:23:04 +00001918 RenderText* nextText = toRenderText(next);
mitz@apple.comfb8da4e2008-02-19 21:13:19 +00001919 if (nextText->textLength()) {
darin42563ac52007-01-22 17:28:57 +00001920 UChar c = nextText->characters()[0];
zimmermannac3781f2007-02-04 01:25:03 +00001921 if (c == ' ' || c == '\t' || (c == '\n' && !shouldPreserveNewline(next)))
eseideld13fe532005-11-30 02:40:29 +00001922 // If the next item on the line is text, and if we did not end with
1923 // a space, then the next text run continues our word (and so it needs to
1924 // keep adding to |tmpW|. Just update and continue.
1925 checkForBreak = true;
mitz@apple.comfb8da4e2008-02-19 21:13:19 +00001926 } else if (nextText->isWordBreak())
1927 checkForBreak = true;
mitz@apple.comcfd9b7b2008-02-24 04:00:21 +00001928 bool willFitOnLine = w + tmpW <= width;
1929 if (!willFitOnLine && !w) {
hyatt@apple.comcd6f8952009-01-28 17:30:26 +00001930 fitBelowFloats(tmpW, firstLine, width);
mitz@apple.comcfd9b7b2008-02-24 04:00:21 +00001931 willFitOnLine = tmpW <= width;
1932 }
ddkilzere8759ef2007-03-25 06:28:19 +00001933 bool canPlaceOnLine = willFitOnLine || !autoWrapWasEverTrueOnLine;
hyatta9f48e32003-02-03 22:48:01 +00001934 if (canPlaceOnLine && checkForBreak) {
1935 w += tmpW;
1936 tmpW = 0;
1937 lBreak.obj = next;
1938 lBreak.pos = 0;
mitz@apple.comd17dc392008-09-15 18:48:20 +00001939 lBreak.nextBreakablePosition = -1;
hyatta9f48e32003-02-03 22:48:01 +00001940 }
1941 }
1942 }
1943 }
1944
darin54008922006-01-13 16:39:05 +00001945 if (checkForBreak && (w + tmpW > width)) {
kociendabb0c24b2001-08-24 14:24:40 +00001946 // if we have floats, try to get below them.
hyattdca76e92005-11-02 08:52:50 +00001947 if (currentCharacterIsSpace && !ignoringSpaces && o->style()->collapseWhiteSpace())
hyatt33f8d492002-11-12 21:44:52 +00001948 trailingSpaceObject = 0;
mitz@apple.comcfd9b7b2008-02-24 04:00:21 +00001949
1950 if (w)
1951 goto end;
1952
hyatt@apple.comcd6f8952009-01-28 17:30:26 +00001953 fitBelowFloats(tmpW, firstLine, width);
hyattf14a4a32002-11-21 22:06:32 +00001954
hyatta14d1742003-01-02 20:25:46 +00001955 // |width| may have been adjusted because we got shoved down past a float (thus
1956 // giving us more room), so we need to retest, and only jump to
1957 // the end label if we still don't fit on the line. -dwh
darin54008922006-01-13 16:39:05 +00001958 if (w + tmpW > width)
hyatta14d1742003-01-02 20:25:46 +00001959 goto end;
kociendabb0c24b2001-08-24 14:24:40 +00001960 }
hyatt1d9e29b2003-04-10 01:48:53 +00001961
mitz@apple.com1a301772008-03-11 18:30:36 +00001962 if (!o->isFloatingOrPositioned()) {
1963 last = o;
darin@apple.comb6cb2562009-08-05 21:25:09 +00001964 if (last->isReplaced() && autoWrap && (!last->isImage() || allowImagesToBreak) && (!last->isListMarker() || toRenderListMarker(last)->isInside())) {
mitz@apple.com1a301772008-03-11 18:30:36 +00001965 w += tmpW;
1966 tmpW = 0;
1967 lBreak.obj = next;
1968 lBreak.pos = 0;
mitz@apple.comd17dc392008-09-15 18:48:20 +00001969 lBreak.nextBreakablePosition = -1;
mitz@apple.com1a301772008-03-11 18:30:36 +00001970 }
hyatt711fe232002-11-20 21:25:14 +00001971 }
1972
mitz@apple.com1a301772008-03-11 18:30:36 +00001973 o = next;
mitz@apple.comd17dc392008-09-15 18:48:20 +00001974 nextBreakable = -1;
mitz@apple.com1a301772008-03-11 18:30:36 +00001975
hyatta9f48e32003-02-03 22:48:01 +00001976 // Clear out our character space bool, since inline <pre>s don't collapse whitespace
1977 // with adjacent inline normal/nowrap spans.
hyattb0d9f602007-01-15 01:28:23 +00001978 if (!collapseWhiteSpace)
hyatta9f48e32003-02-03 22:48:01 +00001979 currentCharacterIsSpace = false;
1980
kociendabb0c24b2001-08-24 14:24:40 +00001981 pos = 0;
ddkilzere8759ef2007-03-25 06:28:19 +00001982 atStart = false;
kociendabb0c24b2001-08-24 14:24:40 +00001983 }
1984
hyattb0d9f602007-01-15 01:28:23 +00001985
1986 if (w + tmpW <= width || lastWS == NOWRAP) {
kociendabb0c24b2001-08-24 14:24:40 +00001987 lBreak.obj = 0;
1988 lBreak.pos = 0;
mitz@apple.comd17dc392008-09-15 18:48:20 +00001989 lBreak.nextBreakablePosition = -1;
kociendabb0c24b2001-08-24 14:24:40 +00001990 }
1991
1992 end:
eric@webkit.orgee76f4f2009-03-25 22:14:46 +00001993 if (lBreak == resolver.position() && (!lBreak.obj || !lBreak.obj->isBR())) {
kociendabb0c24b2001-08-24 14:24:40 +00001994 // we just add as much as possible
weinig98726da2007-03-15 01:22:19 +00001995 if (style()->whiteSpace() == PRE) {
hyattdca76e92005-11-02 08:52:50 +00001996 // FIXME: Don't really understand this case.
hyatt275d0702005-11-03 23:53:57 +00001997 if (pos != 0) {
kociendabb0c24b2001-08-24 14:24:40 +00001998 lBreak.obj = o;
1999 lBreak.pos = pos - 1;
2000 } else {
2001 lBreak.obj = last;
hyattc3731d42002-12-12 06:20:22 +00002002 lBreak.pos = last->isText() ? last->length() : 0;
mitz@apple.comd17dc392008-09-15 18:48:20 +00002003 lBreak.nextBreakablePosition = -1;
kociendabb0c24b2001-08-24 14:24:40 +00002004 }
hyatt275d0702005-11-03 23:53:57 +00002005 } else if (lBreak.obj) {
yuzo@google.comc25f62f2010-02-09 09:16:36 +00002006 // Don't ever break in the middle of a word if we can help it.
2007 // There's no room at all. We just have to be on this line,
2008 // even though we'll spill out.
2009 lBreak.obj = o;
2010 lBreak.pos = pos;
2011 lBreak.nextBreakablePosition = -1;
kociendabb0c24b2001-08-24 14:24:40 +00002012 }
2013 }
2014
2015 // make sure we consume at least one char/object.
mitz@apple.com15035e62008-07-05 20:44:44 +00002016 if (lBreak == resolver.position())
mitz@apple.com1a301772008-03-11 18:30:36 +00002017 lBreak.increment();
hyatt33f8d492002-11-12 21:44:52 +00002018
hyattfe99c872003-07-31 22:25:29 +00002019 // Sanity check our midpoints.
hyatt@apple.comb3466af2009-06-13 06:04:40 +00002020 checkMidpoints(lineMidpointState, lBreak);
hyattfe99c872003-07-31 22:25:29 +00002021
hyatt33f8d492002-11-12 21:44:52 +00002022 if (trailingSpaceObject) {
2023 // This object is either going to be part of the last midpoint, or it is going
2024 // to be the actual endpoint. In both cases we just decrease our pos by 1 level to
2025 // exclude the space, allowing it to - in effect - collapse into the newline.
hyatt@apple.com1a5ffd82009-06-13 17:20:30 +00002026 if (lineMidpointState.numMidpoints % 2) {
2027 InlineIterator* midpoints = lineMidpointState.midpoints.data();
2028 midpoints[lineMidpointState.numMidpoints - 1].pos--;
hyatt33f8d492002-11-12 21:44:52 +00002029 }
2030 //else if (lBreak.pos > 0)
2031 // lBreak.pos--;
2032 else if (lBreak.obj == 0 && trailingSpaceObject->isText()) {
hyattd20075d2002-11-16 02:23:32 +00002033 // Add a new end midpoint that stops right at the very end.
darin@apple.com36744d62009-01-25 20:23:04 +00002034 RenderText* text = toRenderText(trailingSpaceObject);
darin42563ac52007-01-22 17:28:57 +00002035 unsigned length = text->textLength();
2036 unsigned pos = length >= 2 ? length - 2 : UINT_MAX;
mitz@apple.com15035e62008-07-05 20:44:44 +00002037 InlineIterator endMid(0, trailingSpaceObject, pos);
hyatt@apple.comb3466af2009-06-13 06:04:40 +00002038 addMidpoint(lineMidpointState, endMid);
hyatt33f8d492002-11-12 21:44:52 +00002039 }
2040 }
rjwc9c257d2003-01-24 03:46:17 +00002041
mjs54b64002003-04-02 02:59:02 +00002042 // We might have made lBreak an iterator that points past the end
2043 // of the object. Do this adjustment to make it point to the start
2044 // of the next object instead to avoid confusing the rest of the
2045 // code.
2046 if (lBreak.pos > 0) {
darin54008922006-01-13 16:39:05 +00002047 lBreak.pos--;
mitz@apple.com1a301772008-03-11 18:30:36 +00002048 lBreak.increment();
mjs54b64002003-04-02 02:59:02 +00002049 }
2050
kociendabb0c24b2001-08-24 14:24:40 +00002051 return lBreak;
2052}
2053
hyatt@apple.com5dc5a312009-08-18 19:15:19 +00002054void RenderBlock::addOverflowFromInlineChildren()
hyattb4b20872004-10-20 21:34:01 +00002055{
hyatt@apple.com592848f2010-12-06 20:03:43 +00002056 int endPadding = hasOverflowClip() ? paddingEnd() : 0;
2057 // FIXME: Need to find another way to do this, since scrollbars could show when we don't want them to.
2058 if (hasOverflowClip() && !endPadding && node() && node()->isContentEditable() && node() == node()->rootEditableElement() && style()->isLeftToRightDirection())
2059 endPadding = 1;
hyattb4b20872004-10-20 21:34:01 +00002060 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
hyatt@apple.com592848f2010-12-06 20:03:43 +00002061 addLayoutOverflow(curr->paddedLayoutOverflowRect(endPadding));
hyatt@apple.com5dc5a312009-08-18 19:15:19 +00002062 if (!hasOverflowClip())
2063 addVisualOverflow(curr->visualOverflowRect());
hyattb4b20872004-10-20 21:34:01 +00002064 }
2065}
2066
hyatt@apple.com592848f2010-12-06 20:03:43 +00002067int RenderBlock::beforeSideVisualOverflowForLine(RootInlineBox* line) const
hyatt@apple.com81c1d742010-10-06 21:44:02 +00002068{
hyatt@apple.com7a97d272010-11-11 22:17:38 +00002069 // Overflow is in the block's coordinate space, which means it isn't purely physical. For flipped blocks (rl and bt),
2070 // we continue to use top and left overflow even though physically it's bottom and right.
2071 if (style()->isHorizontalWritingMode())
hyatt@apple.com592848f2010-12-06 20:03:43 +00002072 return line->topVisualOverflow();
2073 return line->leftVisualOverflow();
hyatt@apple.com81c1d742010-10-06 21:44:02 +00002074}
2075
hyatt@apple.com592848f2010-12-06 20:03:43 +00002076int RenderBlock::afterSideVisualOverflowForLine(RootInlineBox* line) const
hyatt@apple.com81c1d742010-10-06 21:44:02 +00002077{
hyatt@apple.com7a97d272010-11-11 22:17:38 +00002078 // Overflow is in the block's coordinate space, which means it isn't purely physical. For flipped blocks (rl and bt),
2079 // we continue to use bottom and right overflow even though physically it's top and left.
2080 if (style()->isHorizontalWritingMode())
hyatt@apple.com592848f2010-12-06 20:03:43 +00002081 return line->bottomVisualOverflow();
2082 return line->rightVisualOverflow();
hyatt@apple.com81c1d742010-10-06 21:44:02 +00002083}
2084
2085int RenderBlock::beforeSideLayoutOverflowForLine(RootInlineBox* line) const
2086{
hyatt@apple.com7a97d272010-11-11 22:17:38 +00002087 // Overflow is in the block's coordinate space, which means it isn't purely physical. For flipped blocks (rl and bt),
2088 // we continue to use top and left overflow even though physically it's bottom and right.
2089 if (style()->isHorizontalWritingMode())
hyatt@apple.com81c1d742010-10-06 21:44:02 +00002090 return line->topLayoutOverflow();
hyatt@apple.com7a97d272010-11-11 22:17:38 +00002091 return line->leftLayoutOverflow();
hyatt@apple.com81c1d742010-10-06 21:44:02 +00002092}
2093
2094int RenderBlock::afterSideLayoutOverflowForLine(RootInlineBox* line) const
2095{
hyatt@apple.com7a97d272010-11-11 22:17:38 +00002096 // Overflow is in the block's coordinate space, which means it isn't purely physical. For flipped blocks (rl and bt),
2097 // we continue to use bottom and right overflow even though physically it's top and left.
2098 if (style()->isHorizontalWritingMode())
hyatt@apple.com81c1d742010-10-06 21:44:02 +00002099 return line->bottomLayoutOverflow();
hyatt@apple.com7a97d272010-11-11 22:17:38 +00002100 return line->rightLayoutOverflow();
hyatt@apple.com81c1d742010-10-06 21:44:02 +00002101}
2102
hyatted77ad82004-06-15 07:21:23 +00002103void RenderBlock::deleteEllipsisLineBoxes()
2104{
hyatted77ad82004-06-15 07:21:23 +00002105 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox())
hyattda77c4b2004-06-17 18:09:49 +00002106 curr->clearTruncation();
hyatted77ad82004-06-15 07:21:23 +00002107}
2108
2109void RenderBlock::checkLinesForTextOverflow()
2110{
2111 // Determine the width of the ellipsis using the current font.
darindbba2bb2007-01-11 12:23:49 +00002112 // FIXME: CSS3 says this is configurable, also need to use 0x002E (FULL STOP) if horizontal ellipsis is "not renderable"
2113 TextRun ellipsisRun(&horizontalEllipsis, 1);
bolsinga@apple.com97e42c42008-11-15 04:47:20 +00002114 DEFINE_STATIC_LOCAL(AtomicString, ellipsisStr, (&horizontalEllipsis, 1));
hyatt3e99d1c2006-02-24 21:13:08 +00002115 const Font& firstLineFont = firstLineStyle()->font();
2116 const Font& font = style()->font();
hyatt43d6c792006-05-11 10:19:34 +00002117 int firstLineEllipsisWidth = firstLineFont.width(ellipsisRun);
2118 int ellipsisWidth = (font == firstLineFont) ? firstLineEllipsisWidth : font.width(ellipsisRun);
hyatted77ad82004-06-15 07:21:23 +00002119
2120 // For LTR text truncation, we want to get the right edge of our padding box, and then we want to see
2121 // if the right edge of a line box exceeds that. For RTL, we use the left edge of the padding box and
2122 // check the left edge of the line box to see if it is less
2123 // Include the scrollbar for overflow blocks, which means we want to use "contentWidth()"
hyatt@apple.comc0fa1632010-09-30 20:01:33 +00002124 bool ltr = style()->isLeftToRightDirection();
hyatted77ad82004-06-15 07:21:23 +00002125 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
hyatt@apple.com230b2802010-09-24 19:14:27 +00002126 int blockRightEdge = logicalRightOffsetForLine(curr->y(), curr == firstRootBox());
2127 int blockLeftEdge = logicalLeftOffsetForLine(curr->y(), curr == firstRootBox());
hyatt@apple.comc01df9e2010-09-23 19:17:33 +00002128 int lineBoxEdge = ltr ? curr->x() + curr->logicalWidth() : curr->x();
dglazkov@chromium.org28434e62009-05-13 22:30:10 +00002129 if ((ltr && lineBoxEdge > blockRightEdge) || (!ltr && lineBoxEdge < blockLeftEdge)) {
hyattf918d2d2004-06-15 07:24:11 +00002130 // 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 +00002131 // can be truncated. In order for truncation to be possible, the line must have sufficient space to
2132 // accommodate our truncation string, and no replaced elements (images, tables) can overlap the ellipsis
2133 // space.
2134 int width = curr == firstRootBox() ? firstLineEllipsisWidth : ellipsisWidth;
dglazkov@chromium.org28434e62009-05-13 22:30:10 +00002135 int blockEdge = ltr ? blockRightEdge : blockLeftEdge;
hyatt1a8d2512004-06-17 01:38:30 +00002136 if (curr->canAccommodateEllipsis(ltr, blockEdge, lineBoxEdge, width))
dglazkov@chromium.org28434e62009-05-13 22:30:10 +00002137 curr->placeEllipsis(ellipsisStr, ltr, blockLeftEdge, blockRightEdge, width);
hyatted77ad82004-06-15 07:21:23 +00002138 }
2139 }
2140}
2141
hyattffe78712003-02-11 01:59:29 +00002142}