blob: de1a862f877641cd9c4d40f10bf82b4c59a2b40e [file] [log] [blame]
kociendabb0c24b2001-08-24 14:24:40 +00001/**
2 * This file is part of the html renderer for KDE.
3 *
4 * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
darin7ab31092006-05-10 04:59:57 +00005 * Copyright (C) 2004, 2006 Apple Computer, Inc.
kociendabb0c24b2001-08-24 14:24:40 +00006 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
21 *
kociendabb0c24b2001-08-24 14:24:40 +000022 */
darinbe4c67d2005-12-19 19:53:12 +000023
mjsb64c50a2005-10-03 21:13:12 +000024#include "config.h"
kociendabb0c24b2001-08-24 14:24:40 +000025#include "bidi.h"
darin36d11362006-04-11 16:30:21 +000026
darinf9e5d6c2007-01-09 14:54:26 +000027#include "CharacterNames.h"
darinb9481ed2006-03-20 02:57:59 +000028#include "Document.h"
eseidel40eb1b92006-03-25 22:20:36 +000029#include "Element.h"
mjsd4145d12006-01-11 09:36:47 +000030#include "FrameView.h"
eseidel3a6d1322006-01-09 03:14:50 +000031#include "InlineTextBox.h"
ggarenec11e5b2007-02-25 02:14:54 +000032#include "Logging.h"
darin36d11362006-04-11 16:30:21 +000033#include "RenderArena.h"
darinec375482007-01-06 01:36:24 +000034#include "RenderLayer.h"
mjsd26b2972007-02-13 13:09:04 +000035#include "RenderListMarker.h"
hyattd8048342006-05-31 01:48:18 +000036#include "RenderView.h"
darin36d11362006-04-11 16:30:21 +000037#include "break_lines.h"
mjsbb863512006-05-09 09:27:55 +000038#include <wtf/AlwaysInline.h>
darin91298e52006-06-12 01:10:17 +000039#include <wtf/Vector.h>
hyatt8c371e52004-06-16 01:19:26 +000040
darin7bd70952006-04-13 07:07:34 +000041using namespace std;
darinf9e5d6c2007-01-09 14:54:26 +000042using namespace WTF;
43using namespace Unicode;
darin7bd70952006-04-13 07:07:34 +000044
darinb9481ed2006-03-20 02:57:59 +000045namespace WebCore {
mjsfe301d72003-10-02 18:46:18 +000046
hyatt275d0702005-11-03 23:53:57 +000047// an iterator which traverses all the objects within a block
darin7ab31092006-05-10 04:59:57 +000048struct BidiIterator {
hyatt275d0702005-11-03 23:53:57 +000049 BidiIterator() : block(0), obj(0), pos(0) {}
50 BidiIterator(RenderBlock* b, RenderObject* o, unsigned int p)
darin7ab31092006-05-10 04:59:57 +000051 : block(b), obj(o), pos(p) {}
hyattffe78712003-02-11 01:59:29 +000052
hyatt275d0702005-11-03 23:53:57 +000053 void increment(BidiState& state);
mjsfe301d72003-10-02 18:46:18 +000054 bool atEnd() const;
55
darin7ab31092006-05-10 04:59:57 +000056 UChar current() const;
darinf9e5d6c2007-01-09 14:54:26 +000057 Direction direction() const;
hyatt275d0702005-11-03 23:53:57 +000058
59 RenderBlock* block;
60 RenderObject* obj;
mjsfe301d72003-10-02 18:46:18 +000061 unsigned int pos;
62};
63
mjsfe301d72003-10-02 18:46:18 +000064struct BidiState {
darinf9e5d6c2007-01-09 14:54:26 +000065 BidiState() : context(0), dir(OtherNeutral), adjustEmbedding(false), reachedEndOfLine(false) {}
mjsfe301d72003-10-02 18:46:18 +000066
67 BidiIterator sor;
68 BidiIterator eor;
69 BidiIterator last;
70 BidiIterator current;
mjsbb3d15c2005-12-01 10:32:32 +000071 RefPtr<BidiContext> context;
mjsfe301d72003-10-02 18:46:18 +000072 BidiStatus status;
darinf9e5d6c2007-01-09 14:54:26 +000073 Direction dir;
hyatt275d0702005-11-03 23:53:57 +000074 bool adjustEmbedding;
eseidel789896f2005-11-27 22:52:09 +000075 BidiIterator endOfLine;
76 bool reachedEndOfLine;
darine4fa9e22005-12-16 18:18:50 +000077 BidiIterator lastBeforeET;
mjsfe301d72003-10-02 18:46:18 +000078};
hyatt2f1e7102003-02-20 01:27:03 +000079
eseidel789896f2005-11-27 22:52:09 +000080inline bool operator==(const BidiStatus& status1, const BidiStatus& status2)
81{
82 return status1.eor == status2.eor && status1.last == status2.last && status1.lastStrong == status2.lastStrong;
83}
84
85inline bool operator!=(const BidiStatus& status1, const BidiStatus& status2)
86{
87 return !(status1 == status2);
88}
89
hyatt2f1e7102003-02-20 01:27:03 +000090// Used to track a list of chained bidi runs.
mjsfe301d72003-10-02 18:46:18 +000091static BidiRun* sFirstBidiRun;
92static BidiRun* sLastBidiRun;
ddkilzerfe115062006-07-14 04:42:01 +000093static BidiRun* sLogicallyLastBidiRun;
mjsfe301d72003-10-02 18:46:18 +000094static int sBidiRunCount;
95static BidiRun* sCompactFirstBidiRun;
96static BidiRun* sCompactLastBidiRun;
97static int sCompactBidiRunCount;
98static bool sBuildingCompactRuns;
hyatt85586af2003-02-19 23:22:42 +000099
100// Midpoint globals. The goal is not to do any allocation when dealing with
101// these midpoints, so we just keep an array around and never clear it. We track
102// the number of items and position using the two other variables.
darin91298e52006-06-12 01:10:17 +0000103static Vector<BidiIterator>* smidpoints;
darinb9481ed2006-03-20 02:57:59 +0000104static unsigned sNumMidpoints;
105static unsigned sCurrMidpoint;
mjsfe301d72003-10-02 18:46:18 +0000106static bool betweenMidpoints;
hyatt85586af2003-02-19 23:22:42 +0000107
hyatt33f8d492002-11-12 21:44:52 +0000108static bool isLineEmpty = true;
hyatt0c3a9862004-02-23 21:26:26 +0000109static bool previousLineBrokeCleanly = true;
mjs6f821c82002-03-22 00:31:57 +0000110static bool emptyRun = true;
darinb70665a2002-04-15 23:43:21 +0000111static int numSpaces;
mjs6f821c82002-03-22 00:31:57 +0000112
darinf9e5d6c2007-01-09 14:54:26 +0000113static void embed(Direction, BidiState&);
darin7ab31092006-05-10 04:59:57 +0000114static void appendRun(BidiState&);
ggarenec11e5b2007-02-25 02:14:54 +0000115static void deleteBidiRuns(RenderArena*);
mjs6f821c82002-03-22 00:31:57 +0000116
adele68afa0b2007-02-05 23:25:44 +0000117void RenderBlock::bidiReorderCharacters(Document* document, RenderStyle* style, CharacterBuffer& characterBuffer)
118{
119 unsigned bufferLength = characterBuffer.size();
120 // Create a local copy of the buffer.
121 String string(characterBuffer.data(), bufferLength);
122
123 // Create anonymous RenderBlock
124 RenderStyle* blockStyle = new (document->renderArena()) RenderStyle();
125 blockStyle->inheritFrom(style);
126 blockStyle->setDisplay(BLOCK);
127 blockStyle->setWhiteSpace(PRE);
128 RenderBlock* block = new (document->renderArena()) RenderBlock(document);
129 block->setStyle(blockStyle);
130
131 // Create RenderText
132 RenderText* text = new (document->renderArena()) RenderText(document, string.impl());
133 text->setStyle(blockStyle);
134 block->addChild(text);
135
136 // Call bidiReorderLine
137 BidiState bidi;
adelefcfff3d2007-02-06 02:12:26 +0000138 PassRefPtr<BidiContext> startEmbed;
adele68afa0b2007-02-05 23:25:44 +0000139 if (style->direction() == LTR) {
140 startEmbed = new BidiContext(0, LeftToRight, NULL, style->unicodeBidi() == Override);
141 bidi.status.eor = LeftToRight;
142 } else {
143 startEmbed = new BidiContext(1, RightToLeft, NULL, style->unicodeBidi() == Override);
144 bidi.status.eor = RightToLeft;
145 }
146 bidi.status.lastStrong = startEmbed->dir();
147 bidi.status.last = startEmbed->dir();
148 bidi.status.eor = startEmbed->dir();
149 bidi.context = startEmbed;
150 bidi.dir = OtherNeutral;
151 betweenMidpoints = false;
152
153 block->bidiReorderLine(BidiIterator(block, text, 0), BidiIterator(block, text, bufferLength), bidi);
154
155 // Fill the characterBuffer.
156 int index = 0;
157 BidiRun* r = sFirstBidiRun;
158 while (r) {
159 bool reversed = r->reversed(style->visuallyOrdered());
160 // If there's only one run, and it doesn't need to be reversed, return early
161 if (sBidiRunCount == 1 && !reversed)
162 break;
163 for (int i = r->start; i < r->stop; ++i) {
164 if (reversed)
165 characterBuffer[index] = string[r->stop + r->start - i - 1];
166 else
167 characterBuffer[index] = string[i];
168 ++index;
169 }
170 r = r->nextRun;
171 }
172
ggarenec11e5b2007-02-25 02:14:54 +0000173 // Tear down temporary RenderBlock, RenderText, and BidiRuns
adele68afa0b2007-02-05 23:25:44 +0000174 block->removeChild(text);
175 text->destroy();
176 block->destroy();
ggarenec11e5b2007-02-25 02:14:54 +0000177 deleteBidiRuns(document->renderArena());
adele68afa0b2007-02-05 23:25:44 +0000178}
179
hyattffe78712003-02-11 01:59:29 +0000180static int getBPMWidth(int childValue, Length cssUnit)
181{
hyatt275d0702005-11-03 23:53:57 +0000182 if (!cssUnit.isIntrinsicOrAuto())
darin947a31b2006-02-24 03:08:41 +0000183 return (cssUnit.isFixed() ? cssUnit.value() : childValue);
hyattffe78712003-02-11 01:59:29 +0000184 return 0;
185}
186
187static int getBorderPaddingMargin(RenderObject* child, bool endOfInline)
188{
189 RenderStyle* cstyle = child->style();
190 int result = 0;
191 bool leftSide = (cstyle->direction() == LTR) ? !endOfInline : endOfInline;
192 result += getBPMWidth((leftSide ? child->marginLeft() : child->marginRight()),
193 (leftSide ? cstyle->marginLeft() :
194 cstyle->marginRight()));
195 result += getBPMWidth((leftSide ? child->paddingLeft() : child->paddingRight()),
196 (leftSide ? cstyle->paddingLeft() :
197 cstyle->paddingRight()));
198 result += leftSide ? child->borderLeft() : child->borderRight();
199 return result;
200}
201
202static int inlineWidth(RenderObject* child, bool start = true, bool end = true)
203{
204 int extraWidth = 0;
205 RenderObject* parent = child->parent();
hyatt450813d2003-07-25 20:22:34 +0000206 while (parent->isInline() && !parent->isInlineBlockOrInlineTable()) {
hyattffe78712003-02-11 01:59:29 +0000207 if (start && parent->firstChild() == child)
208 extraWidth += getBorderPaddingMargin(parent, false);
209 if (end && parent->lastChild() == child)
210 extraWidth += getBorderPaddingMargin(parent, true);
211 child = parent;
212 parent = child->parent();
213 }
214 return extraWidth;
215}
216
darin35355e52002-12-20 09:19:00 +0000217#ifndef NDEBUG
ggarenec11e5b2007-02-25 02:14:54 +0000218WTFLogChannel LogWebCoreBidiRunLeaks = { 0x00000000, "", WTFLogChannelOn };
219
220struct BidiRunCounter {
221 static int count;
222 ~BidiRunCounter()
223 {
224 if (count)
225 LOG(WebCoreBidiRunLeaks, "LEAK: %d BidiRun\n", count);
226 }
227};
228int BidiRunCounter::count = 0;
229static BidiRunCounter bidiRunCounter;
230
harrison0012ced2005-10-06 18:37:42 +0000231static bool inBidiRunDestroy;
hyattffe78712003-02-11 01:59:29 +0000232#endif
233
harrisone8363b42005-10-06 00:54:06 +0000234void BidiRun::destroy(RenderArena* renderArena)
hyattffe78712003-02-11 01:59:29 +0000235{
236#ifndef NDEBUG
harrison0012ced2005-10-06 18:37:42 +0000237 inBidiRunDestroy = true;
hyattffe78712003-02-11 01:59:29 +0000238#endif
239 delete this;
240#ifndef NDEBUG
harrison0012ced2005-10-06 18:37:42 +0000241 inBidiRunDestroy = false;
hyattffe78712003-02-11 01:59:29 +0000242#endif
243
244 // Recover the size left there for us by operator delete and free the memory.
245 renderArena->free(*(size_t *)this, this);
246}
247
248void* BidiRun::operator new(size_t sz, RenderArena* renderArena) throw()
249{
ggarenec11e5b2007-02-25 02:14:54 +0000250#ifndef NDEBUG
251 ++BidiRunCounter::count;
252#endif
hyattffe78712003-02-11 01:59:29 +0000253 return renderArena->allocate(sz);
254}
255
256void BidiRun::operator delete(void* ptr, size_t sz)
257{
ggarenec11e5b2007-02-25 02:14:54 +0000258#ifndef NDEBUG
259 --BidiRunCounter::count;
260#endif
harrison0012ced2005-10-06 18:37:42 +0000261 assert(inBidiRunDestroy);
hyattffe78712003-02-11 01:59:29 +0000262
harrisone8363b42005-10-06 00:54:06 +0000263 // Stash size where destroy() can find it.
hyattffe78712003-02-11 01:59:29 +0000264 *(size_t*)ptr = sz;
265}
266
267static void deleteBidiRuns(RenderArena* arena)
268{
darinef0c09f2005-10-09 01:46:17 +0000269 emptyRun = true;
hyatt2f1e7102003-02-20 01:27:03 +0000270 if (!sFirstBidiRun)
hyattffe78712003-02-11 01:59:29 +0000271 return;
272
hyatt2f1e7102003-02-20 01:27:03 +0000273 BidiRun* curr = sFirstBidiRun;
274 while (curr) {
275 BidiRun* s = curr->nextRun;
harrisone8363b42005-10-06 00:54:06 +0000276 curr->destroy(arena);
hyatt2f1e7102003-02-20 01:27:03 +0000277 curr = s;
hyattffe78712003-02-11 01:59:29 +0000278 }
hyatt2f1e7102003-02-20 01:27:03 +0000279
280 sFirstBidiRun = 0;
281 sLastBidiRun = 0;
282 sBidiRunCount = 0;
hyattffe78712003-02-11 01:59:29 +0000283}
284
kociendabb0c24b2001-08-24 14:24:40 +0000285// ---------------------------------------------------------------------
286
287/* a small helper class used internally to resolve Bidi embedding levels.
288 Each line of text caches the embedding level at the start of the line for faster
289 relayouting
290*/
darinf9e5d6c2007-01-09 14:54:26 +0000291BidiContext::BidiContext(unsigned char l, Direction e, BidiContext *p, bool o)
mjs08191d52006-03-06 02:53:41 +0000292 : level(l), override(o), m_dir(e)
kociendabb0c24b2001-08-24 14:24:40 +0000293{
294 parent = p;
weinigda22cda2006-12-27 21:19:02 +0000295 if (p)
kociendabb0c24b2001-08-24 14:24:40 +0000296 p->ref();
kociendabb0c24b2001-08-24 14:24:40 +0000297 count = 0;
298}
299
300BidiContext::~BidiContext()
301{
hyatt275d0702005-11-03 23:53:57 +0000302 if (parent)
303 parent->deref();
kociendabb0c24b2001-08-24 14:24:40 +0000304}
305
306void BidiContext::ref() const
307{
308 count++;
309}
310
311void BidiContext::deref() const
312{
313 count--;
hyatt275d0702005-11-03 23:53:57 +0000314 if (count <= 0)
315 delete this;
kociendabb0c24b2001-08-24 14:24:40 +0000316}
317
eseidel789896f2005-11-27 22:52:09 +0000318bool operator==(const BidiContext& c1, const BidiContext& c2)
319{
320 if (&c1 == &c2)
321 return true;
weinigda22cda2006-12-27 21:19:02 +0000322 if (c1.level != c2.level || c1.override != c2.override || c1.dir() != c2.dir())
eseidel789896f2005-11-27 22:52:09 +0000323 return false;
eseidel6465a0f2006-01-10 13:35:45 +0000324 if (!c1.parent)
325 return !c2.parent;
326 return c2.parent && *c1.parent == *c2.parent;
eseidel789896f2005-11-27 22:52:09 +0000327}
328
329inline bool operator!=(const BidiContext& c1, const BidiContext& c2)
330{
331 return !(c1 == c2);
332}
333
kociendabb0c24b2001-08-24 14:24:40 +0000334// ---------------------------------------------------------------------
335
hyatt275d0702005-11-03 23:53:57 +0000336inline bool operator==(const BidiIterator& it1, const BidiIterator& it2)
darinb70665a2002-04-15 23:43:21 +0000337{
hyatt275d0702005-11-03 23:53:57 +0000338 if (it1.pos != it2.pos)
339 return false;
340 if (it1.obj != it2.obj)
341 return false;
darinb70665a2002-04-15 23:43:21 +0000342 return true;
343}
344
hyatt275d0702005-11-03 23:53:57 +0000345inline bool operator!=(const BidiIterator& it1, const BidiIterator& it2)
darinb70665a2002-04-15 23:43:21 +0000346{
hyatt275d0702005-11-03 23:53:57 +0000347 if (it1.pos != it2.pos)
348 return true;
349 if (it1.obj != it2.obj)
350 return true;
darinb70665a2002-04-15 23:43:21 +0000351 return false;
352}
353
hyatt275d0702005-11-03 23:53:57 +0000354static inline RenderObject* bidiNext(RenderBlock* block, RenderObject* current, BidiState& bidi,
hyattffe78712003-02-11 01:59:29 +0000355 bool skipInlines = true, bool* endOfInline = 0)
mjs6f821c82002-03-22 00:31:57 +0000356{
hyatt275d0702005-11-03 23:53:57 +0000357 RenderObject* next = 0;
hyattffe78712003-02-11 01:59:29 +0000358 bool oldEndOfInline = endOfInline ? *endOfInline : false;
359 if (endOfInline)
360 *endOfInline = false;
361
hyatt275d0702005-11-03 23:53:57 +0000362 while (current) {
sullivanabd4d032007-02-09 22:51:41 +0000363 next = 0;
hyattffe78712003-02-11 01:59:29 +0000364 if (!oldEndOfInline && !current->isFloating() && !current->isReplaced() && !current->isPositioned()) {
365 next = current->firstChild();
darindde01502005-12-18 22:55:35 +0000366 if (next && bidi.adjustEmbedding && next->isInlineFlow()) {
hyattffe78712003-02-11 01:59:29 +0000367 EUnicodeBidi ub = next->style()->unicodeBidi();
hyatt275d0702005-11-03 23:53:57 +0000368 if (ub != UBNormal) {
darin9d0a6282006-03-01 07:49:33 +0000369 TextDirection dir = next->style()->direction();
darinf9e5d6c2007-01-09 14:54:26 +0000370 Direction d = (ub == Embed
371 ? (dir == RTL ? RightToLeftEmbedding : LeftToRightEmbedding)
372 : (dir == RTL ? RightToLeftOverride : LeftToRightOverride));
hyatt275d0702005-11-03 23:53:57 +0000373 embed(d, bidi);
hyattffe78712003-02-11 01:59:29 +0000374 }
375 }
376 }
hyatt275d0702005-11-03 23:53:57 +0000377
hyattffe78712003-02-11 01:59:29 +0000378 if (!next) {
hyatt275d0702005-11-03 23:53:57 +0000379 if (!skipInlines && !oldEndOfInline && current->isInlineFlow()) {
hyattffe78712003-02-11 01:59:29 +0000380 next = current;
381 if (endOfInline)
382 *endOfInline = true;
383 break;
384 }
mjs6f821c82002-03-22 00:31:57 +0000385
hyatt275d0702005-11-03 23:53:57 +0000386 while (current && current != block) {
darindde01502005-12-18 22:55:35 +0000387 if (bidi.adjustEmbedding && current->isInlineFlow() && current->style()->unicodeBidi() != UBNormal)
darinf9e5d6c2007-01-09 14:54:26 +0000388 embed(PopDirectionalFormat, bidi);
hyatt275d0702005-11-03 23:53:57 +0000389
darindde01502005-12-18 22:55:35 +0000390 next = current->nextSibling();
391 if (next) {
392 if (bidi.adjustEmbedding && next->isInlineFlow()) {
393 EUnicodeBidi ub = next->style()->unicodeBidi();
394 if (ub != UBNormal) {
darin9d0a6282006-03-01 07:49:33 +0000395 TextDirection dir = next->style()->direction();
darinf9e5d6c2007-01-09 14:54:26 +0000396 Direction d = (ub == Embed
397 ? (dir == RTL ? RightToLeftEmbedding: LeftToRightEmbedding)
398 : (dir == RTL ? RightToLeftOverride : LeftToRightOverride));
darindde01502005-12-18 22:55:35 +0000399 embed(d, bidi);
400 }
401 }
402 break;
403 }
404
hyattffe78712003-02-11 01:59:29 +0000405 current = current->parent();
hyatt275d0702005-11-03 23:53:57 +0000406 if (!skipInlines && current && current != block && current->isInlineFlow()) {
hyattffe78712003-02-11 01:59:29 +0000407 next = current;
408 if (endOfInline)
409 *endOfInline = true;
410 break;
411 }
412 }
413 }
mjs6f821c82002-03-22 00:31:57 +0000414
hyatt275d0702005-11-03 23:53:57 +0000415 if (!next)
416 break;
hyattffe78712003-02-11 01:59:29 +0000417
418 if (next->isText() || next->isBR() || next->isFloating() || next->isReplaced() || next->isPositioned()
419 || ((!skipInlines || !next->firstChild()) // Always return EMPTY inlines.
420 && next->isInlineFlow()))
mjs6f821c82002-03-22 00:31:57 +0000421 break;
422 current = next;
423 }
424 return next;
425}
426
hyatt275d0702005-11-03 23:53:57 +0000427static RenderObject* bidiFirst(RenderBlock* block, BidiState& bidi, bool skipInlines = true )
mjs6f821c82002-03-22 00:31:57 +0000428{
hyatt275d0702005-11-03 23:53:57 +0000429 if (!block->firstChild())
430 return 0;
431
432 RenderObject* o = block->firstChild();
hyattffe78712003-02-11 01:59:29 +0000433 if (o->isInlineFlow()) {
darindde01502005-12-18 22:55:35 +0000434 if (bidi.adjustEmbedding) {
435 EUnicodeBidi ub = o->style()->unicodeBidi();
436 if (ub != UBNormal) {
darin9d0a6282006-03-01 07:49:33 +0000437 TextDirection dir = o->style()->direction();
darinf9e5d6c2007-01-09 14:54:26 +0000438 Direction d = (ub == Embed
439 ? (dir == RTL ? RightToLeftEmbedding : LeftToRightEmbedding)
440 : (dir == RTL ? RightToLeftOverride : LeftToRightOverride));
darindde01502005-12-18 22:55:35 +0000441 embed(d, bidi);
442 }
443 }
hyattffe78712003-02-11 01:59:29 +0000444 if (skipInlines && o->firstChild())
hyatt275d0702005-11-03 23:53:57 +0000445 o = bidiNext(block, o, bidi, skipInlines);
hyattffe78712003-02-11 01:59:29 +0000446 else
447 return o; // Never skip empty inlines.
448 }
hyattc5334f12003-08-08 22:26:08 +0000449
450 if (o && !o->isText() && !o->isBR() && !o->isReplaced() && !o->isFloating() && !o->isPositioned())
hyatt275d0702005-11-03 23:53:57 +0000451 o = bidiNext(block, o, bidi, skipInlines);
mjs6f821c82002-03-22 00:31:57 +0000452 return o;
453}
454
hyatt275d0702005-11-03 23:53:57 +0000455inline void BidiIterator::increment(BidiState& bidi)
kociendabb0c24b2001-08-24 14:24:40 +0000456{
hyatt275d0702005-11-03 23:53:57 +0000457 if (!obj)
458 return;
459 if (obj->isText()) {
kociendabb0c24b2001-08-24 14:24:40 +0000460 pos++;
darin42563ac52007-01-22 17:28:57 +0000461 if (pos >= static_cast<RenderText *>(obj)->textLength()) {
hyatt275d0702005-11-03 23:53:57 +0000462 obj = bidiNext(block, obj, bidi);
kociendabb0c24b2001-08-24 14:24:40 +0000463 pos = 0;
464 }
465 } else {
hyatt275d0702005-11-03 23:53:57 +0000466 obj = bidiNext(block, obj, bidi);
kociendabb0c24b2001-08-24 14:24:40 +0000467 pos = 0;
468 }
469}
470
mjs6f821c82002-03-22 00:31:57 +0000471inline bool BidiIterator::atEnd() const
kociendabb0c24b2001-08-24 14:24:40 +0000472{
hyatt275d0702005-11-03 23:53:57 +0000473 return !obj;
kociendabb0c24b2001-08-24 14:24:40 +0000474}
475
darin7ab31092006-05-10 04:59:57 +0000476UChar BidiIterator::current() const
kociendabb0c24b2001-08-24 14:24:40 +0000477{
hyatt30586b42003-12-02 23:19:11 +0000478 if (!obj || !obj->isText())
darin7ab31092006-05-10 04:59:57 +0000479 return 0;
hyatt30586b42003-12-02 23:19:11 +0000480
481 RenderText* text = static_cast<RenderText*>(obj);
darin42563ac52007-01-22 17:28:57 +0000482 if (!text->characters())
darin7ab31092006-05-10 04:59:57 +0000483 return 0;
hyatt30586b42003-12-02 23:19:11 +0000484
darin42563ac52007-01-22 17:28:57 +0000485 return text->characters()[pos];
kociendabb0c24b2001-08-24 14:24:40 +0000486}
487
darinf9e5d6c2007-01-09 14:54:26 +0000488ALWAYS_INLINE Direction BidiIterator::direction() const
kociendabb0c24b2001-08-24 14:24:40 +0000489{
hyatt5c18e1a2004-09-28 18:32:47 +0000490 if (!obj)
darinf9e5d6c2007-01-09 14:54:26 +0000491 return OtherNeutral;
hyatt5c18e1a2004-09-28 18:32:47 +0000492 if (obj->isListMarker())
darinf9e5d6c2007-01-09 14:54:26 +0000493 return obj->style()->direction() == LTR ? LeftToRight : RightToLeft;
hyatt5c18e1a2004-09-28 18:32:47 +0000494 if (!obj->isText())
darinf9e5d6c2007-01-09 14:54:26 +0000495 return OtherNeutral;
darin7ab31092006-05-10 04:59:57 +0000496 RenderText* renderTxt = static_cast<RenderText*>(obj);
darin42563ac52007-01-22 17:28:57 +0000497 if (pos >= renderTxt->textLength())
darinf9e5d6c2007-01-09 14:54:26 +0000498 return OtherNeutral;
darin42563ac52007-01-22 17:28:57 +0000499 return Unicode::direction(renderTxt->characters()[pos]);
kociendabb0c24b2001-08-24 14:24:40 +0000500}
501
kociendabb0c24b2001-08-24 14:24:40 +0000502// -------------------------------------------------------------------------------------------------
503
hyatt2f1e7102003-02-20 01:27:03 +0000504static void addRun(BidiRun* bidiRun)
505{
506 if (!sFirstBidiRun)
507 sFirstBidiRun = sLastBidiRun = bidiRun;
508 else {
509 sLastBidiRun->nextRun = bidiRun;
510 sLastBidiRun = bidiRun;
511 }
512 sBidiRunCount++;
hyatt4b381692003-03-10 21:11:59 +0000513 bidiRun->compact = sBuildingCompactRuns;
hyattfe99c872003-07-31 22:25:29 +0000514
515 // Compute the number of spaces in this run,
516 if (bidiRun->obj && bidiRun->obj->isText()) {
517 RenderText* text = static_cast<RenderText*>(bidiRun->obj);
darin42563ac52007-01-22 17:28:57 +0000518 if (text->characters()) {
hyattefebbdd2003-12-02 22:25:31 +0000519 for (int i = bidiRun->start; i < bidiRun->stop; i++) {
darin42563ac52007-01-22 17:28:57 +0000520 UChar c = text->characters()[i];
harrison208ea792005-07-29 23:42:59 +0000521 if (c == ' ' || c == '\n' || c == '\t')
hyattefebbdd2003-12-02 22:25:31 +0000522 numSpaces++;
523 }
darina3c48282003-10-07 15:49:30 +0000524 }
hyattfe99c872003-07-31 22:25:29 +0000525 }
hyatt2f1e7102003-02-20 01:27:03 +0000526}
527
528static void reverseRuns(int start, int end)
529{
530 if (start >= end)
531 return;
532
533 assert(start >= 0 && end < sBidiRunCount);
534
535 // Get the item before the start of the runs to reverse and put it in
536 // |beforeStart|. |curr| should point to the first run to reverse.
537 BidiRun* curr = sFirstBidiRun;
538 BidiRun* beforeStart = 0;
539 int i = 0;
540 while (i < start) {
541 i++;
542 beforeStart = curr;
543 curr = curr->nextRun;
544 }
545
hyatt793fbbc2003-02-26 02:38:01 +0000546 BidiRun* startRun = curr;
hyatt2f1e7102003-02-20 01:27:03 +0000547 while (i < end) {
hyatt793fbbc2003-02-26 02:38:01 +0000548 i++;
549 curr = curr->nextRun;
550 }
551 BidiRun* endRun = curr;
552 BidiRun* afterEnd = curr->nextRun;
553
554 i = start;
555 curr = startRun;
556 BidiRun* newNext = afterEnd;
557 while (i <= end) {
hyatt2f1e7102003-02-20 01:27:03 +0000558 // Do the reversal.
559 BidiRun* next = curr->nextRun;
hyatt793fbbc2003-02-26 02:38:01 +0000560 curr->nextRun = newNext;
561 newNext = curr;
hyatt2f1e7102003-02-20 01:27:03 +0000562 curr = next;
563 i++;
564 }
565
hyatt2f1e7102003-02-20 01:27:03 +0000566 // Now hook up beforeStart and afterEnd to the newStart and newEnd.
567 if (beforeStart)
hyatt793fbbc2003-02-26 02:38:01 +0000568 beforeStart->nextRun = endRun;
hyatt2f1e7102003-02-20 01:27:03 +0000569 else
hyatt793fbbc2003-02-26 02:38:01 +0000570 sFirstBidiRun = endRun;
hyatt2f1e7102003-02-20 01:27:03 +0000571
hyatt793fbbc2003-02-26 02:38:01 +0000572 startRun->nextRun = afterEnd;
hyatt2f1e7102003-02-20 01:27:03 +0000573 if (!afterEnd)
hyatt793fbbc2003-02-26 02:38:01 +0000574 sLastBidiRun = startRun;
hyatt2f1e7102003-02-20 01:27:03 +0000575}
576
darinb9481ed2006-03-20 02:57:59 +0000577static void chopMidpointsAt(RenderObject* obj, unsigned pos)
hyatt78b85132004-03-29 20:07:45 +0000578{
hyatt275d0702005-11-03 23:53:57 +0000579 if (!sNumMidpoints)
580 return;
hyatt78b85132004-03-29 20:07:45 +0000581 BidiIterator* midpoints = smidpoints->data();
darinb9481ed2006-03-20 02:57:59 +0000582 for (unsigned i = 0; i < sNumMidpoints; i++) {
hyatt78b85132004-03-29 20:07:45 +0000583 const BidiIterator& point = midpoints[i];
584 if (point.obj == obj && point.pos == pos) {
585 sNumMidpoints = i;
586 break;
587 }
588 }
589}
590
hyatt275d0702005-11-03 23:53:57 +0000591static void checkMidpoints(BidiIterator& lBreak, BidiState& bidi)
hyattfe99c872003-07-31 22:25:29 +0000592{
593 // Check to see if our last midpoint is a start point beyond the line break. If so,
hyattdca76e92005-11-02 08:52:50 +0000594 // shave it off the list, and shave off a trailing space if the previous end point doesn't
595 // preserve whitespace.
hyattfe99c872003-07-31 22:25:29 +0000596 if (lBreak.obj && sNumMidpoints && sNumMidpoints%2 == 0) {
597 BidiIterator* midpoints = smidpoints->data();
598 BidiIterator& endpoint = midpoints[sNumMidpoints-2];
599 const BidiIterator& startpoint = midpoints[sNumMidpoints-1];
600 BidiIterator currpoint = endpoint;
601 while (!currpoint.atEnd() && currpoint != startpoint && currpoint != lBreak)
hyatt275d0702005-11-03 23:53:57 +0000602 currpoint.increment(bidi);
hyattfe99c872003-07-31 22:25:29 +0000603 if (currpoint == lBreak) {
604 // We hit the line break before the start point. Shave off the start point.
605 sNumMidpoints--;
hyattdca76e92005-11-02 08:52:50 +0000606 if (endpoint.obj->style()->collapseWhiteSpace()) {
hyattee1bcae2004-03-29 21:36:04 +0000607 if (endpoint.obj->isText()) {
harrisona4d6cdc2006-10-02 15:32:17 +0000608 // Don't shave a character off the endpoint if it was from a soft hyphen.
hyattee1bcae2004-03-29 21:36:04 +0000609 RenderText* textObj = static_cast<RenderText*>(endpoint.obj);
darin42563ac52007-01-22 17:28:57 +0000610 if (endpoint.pos + 1 < textObj->textLength()) {
611 if (textObj->characters()[endpoint.pos+1] == softHyphen)
bdakin9151ba52005-10-24 22:51:06 +0000612 return;
613 } else if (startpoint.obj->isText()) {
614 RenderText *startText = static_cast<RenderText*>(startpoint.obj);
darin42563ac52007-01-22 17:28:57 +0000615 if (startText->textLength() && startText->characters()[0] == softHyphen)
bdakin9151ba52005-10-24 22:51:06 +0000616 return;
617 }
hyattee1bcae2004-03-29 21:36:04 +0000618 }
hyattfe99c872003-07-31 22:25:29 +0000619 endpoint.pos--;
hyattee1bcae2004-03-29 21:36:04 +0000620 }
hyattfe99c872003-07-31 22:25:29 +0000621 }
622 }
623}
624
hyatt85586af2003-02-19 23:22:42 +0000625static void addMidpoint(const BidiIterator& midpoint)
626{
627 if (!smidpoints)
628 return;
629
630 if (smidpoints->size() <= sNumMidpoints)
darin91298e52006-06-12 01:10:17 +0000631 smidpoints->resize(sNumMidpoints + 10);
hyatt85586af2003-02-19 23:22:42 +0000632
633 BidiIterator* midpoints = smidpoints->data();
634 midpoints[sNumMidpoints++] = midpoint;
635}
636
mjsfe301d72003-10-02 18:46:18 +0000637static void appendRunsForObject(int start, int end, RenderObject* obj, BidiState &bidi)
hyatt33f8d492002-11-12 21:44:52 +0000638{
hyatt98ee7e42003-05-14 01:39:15 +0000639 if (start > end || obj->isFloating() ||
hyatt853cd7d2004-11-05 02:59:48 +0000640 (obj->isPositioned() && !obj->hasStaticX() && !obj->hasStaticY() && !obj->container()->isInlineFlow()))
hyatteb003b82002-11-15 22:35:10 +0000641 return;
hyatt85586af2003-02-19 23:22:42 +0000642
643 bool haveNextMidpoint = (smidpoints && sCurrMidpoint < sNumMidpoints);
mjsfe301d72003-10-02 18:46:18 +0000644 BidiIterator nextMidpoint;
hyatt85586af2003-02-19 23:22:42 +0000645 if (haveNextMidpoint)
646 nextMidpoint = smidpoints->at(sCurrMidpoint);
hyatt33f8d492002-11-12 21:44:52 +0000647 if (betweenMidpoints) {
hyatt85586af2003-02-19 23:22:42 +0000648 if (!(haveNextMidpoint && nextMidpoint.obj == obj))
hyatt33f8d492002-11-12 21:44:52 +0000649 return;
650 // This is a new start point. Stop ignoring objects and
651 // adjust our start.
652 betweenMidpoints = false;
hyatt85586af2003-02-19 23:22:42 +0000653 start = nextMidpoint.pos;
654 sCurrMidpoint++;
hyatt33f8d492002-11-12 21:44:52 +0000655 if (start < end)
mjsfe301d72003-10-02 18:46:18 +0000656 return appendRunsForObject(start, end, obj, bidi);
hyatt33f8d492002-11-12 21:44:52 +0000657 }
658 else {
hyatt85586af2003-02-19 23:22:42 +0000659 if (!smidpoints || !haveNextMidpoint || (obj != nextMidpoint.obj)) {
eseidel789896f2005-11-27 22:52:09 +0000660 addRun(new (obj->renderArena()) BidiRun(start, end, obj, bidi.context.get(), bidi.dir));
hyatt33f8d492002-11-12 21:44:52 +0000661 return;
662 }
663
hyatt78b85132004-03-29 20:07:45 +0000664 // An end midpoint has been encountered within our object. We
hyatt33f8d492002-11-12 21:44:52 +0000665 // need to go ahead and append a run with our endpoint.
hyatt85586af2003-02-19 23:22:42 +0000666 if (int(nextMidpoint.pos+1) <= end) {
hyatt26179432002-11-17 01:57:27 +0000667 betweenMidpoints = true;
hyatt85586af2003-02-19 23:22:42 +0000668 sCurrMidpoint++;
hyattc64f9fc2003-03-14 01:25:59 +0000669 if (nextMidpoint.pos != UINT_MAX) { // UINT_MAX means stop at the object and don't include any of it.
darinef0c09f2005-10-09 01:46:17 +0000670 if (int(nextMidpoint.pos+1) > start)
671 addRun(new (obj->renderArena())
eseidel789896f2005-11-27 22:52:09 +0000672 BidiRun(start, nextMidpoint.pos+1, obj, bidi.context.get(), bidi.dir));
mjsfe301d72003-10-02 18:46:18 +0000673 return appendRunsForObject(nextMidpoint.pos+1, end, obj, bidi);
hyattc64f9fc2003-03-14 01:25:59 +0000674 }
hyatt26179432002-11-17 01:57:27 +0000675 }
676 else
eseidel789896f2005-11-27 22:52:09 +0000677 addRun(new (obj->renderArena()) BidiRun(start, end, obj, bidi.context.get(), bidi.dir));
hyatt33f8d492002-11-12 21:44:52 +0000678 }
679}
680
hyatt275d0702005-11-03 23:53:57 +0000681static void appendRun(BidiState &bidi)
kociendabb0c24b2001-08-24 14:24:40 +0000682{
ggarenef026b22005-07-06 00:21:53 +0000683 if (emptyRun || !bidi.eor.obj)
684 return;
weinigf18aae32006-08-03 21:55:57 +0000685#if defined(BIDI_DEBUG) && BIDI_DEBUG > 1
kociendabb0c24b2001-08-24 14:24:40 +0000686 kdDebug(6041) << "appendRun: dir="<<(int)dir<<endl;
687#endif
darinf028f812002-06-10 20:08:04 +0000688
hyatt275d0702005-11-03 23:53:57 +0000689 bool b = bidi.adjustEmbedding;
690 bidi.adjustEmbedding = false;
kociendabb0c24b2001-08-24 14:24:40 +0000691
mjsfe301d72003-10-02 18:46:18 +0000692 int start = bidi.sor.pos;
693 RenderObject *obj = bidi.sor.obj;
eseidel789896f2005-11-27 22:52:09 +0000694 while (obj && obj != bidi.eor.obj && obj != bidi.endOfLine.obj) {
mjsfe301d72003-10-02 18:46:18 +0000695 appendRunsForObject(start, obj->length(), obj, bidi);
kociendabb0c24b2001-08-24 14:24:40 +0000696 start = 0;
hyatt275d0702005-11-03 23:53:57 +0000697 obj = bidiNext(bidi.sor.block, obj, bidi);
kociendabb0c24b2001-08-24 14:24:40 +0000698 }
justing5b0e0422005-08-01 03:20:49 +0000699 if (obj) {
eseidel789896f2005-11-27 22:52:09 +0000700 unsigned pos = obj == bidi.eor.obj ? bidi.eor.pos : UINT_MAX;
701 if (obj == bidi.endOfLine.obj && bidi.endOfLine.pos <= pos) {
702 bidi.reachedEndOfLine = true;
703 pos = bidi.endOfLine.pos;
704 }
justing5b0e0422005-08-01 03:20:49 +0000705 // It's OK to add runs for zero-length RenderObjects, just don't make the run larger than it should be
eseidel789896f2005-11-27 22:52:09 +0000706 int end = obj->length() ? pos+1 : 0;
justing5b0e0422005-08-01 03:20:49 +0000707 appendRunsForObject(start, end, obj, bidi);
708 }
hyatt33f8d492002-11-12 21:44:52 +0000709
hyatt275d0702005-11-03 23:53:57 +0000710 bidi.eor.increment(bidi);
mjsfe301d72003-10-02 18:46:18 +0000711 bidi.sor = bidi.eor;
darinf9e5d6c2007-01-09 14:54:26 +0000712 bidi.dir = OtherNeutral;
713 bidi.status.eor = OtherNeutral;
hyatt275d0702005-11-03 23:53:57 +0000714 bidi.adjustEmbedding = b;
mjs6f821c82002-03-22 00:31:57 +0000715}
716
darinf9e5d6c2007-01-09 14:54:26 +0000717static void embed(Direction d, BidiState& bidi)
mjs6f821c82002-03-22 00:31:57 +0000718{
hyatt275d0702005-11-03 23:53:57 +0000719 bool b = bidi.adjustEmbedding;
720 bidi.adjustEmbedding = false;
darinf9e5d6c2007-01-09 14:54:26 +0000721 if (d == PopDirectionalFormat) {
darin54008922006-01-13 16:39:05 +0000722 BidiContext *c = bidi.context->parent;
723 if (c) {
724 if (!emptyRun && bidi.eor != bidi.last) {
darinf9e5d6c2007-01-09 14:54:26 +0000725 assert(bidi.status.eor != OtherNeutral);
hyatt275d0702005-11-03 23:53:57 +0000726 // bidi.sor ... bidi.eor ... bidi.last eor; need to append the bidi.sor-bidi.eor run or extend it through bidi.last
darinf9e5d6c2007-01-09 14:54:26 +0000727 assert(bidi.status.last == EuropeanNumberSeparator
728 || bidi.status.last == EuropeanNumberTerminator
729 || bidi.status.last == CommonNumberSeparator
730 || bidi.status.last == BoundaryNeutral
731 || bidi.status.last == BlockSeparator
732 || bidi.status.last == SegmentSeparator
733 || bidi.status.last == WhiteSpaceNeutral
734 || bidi.status.last == OtherNeutral);
735 if (bidi.dir == OtherNeutral)
mjs08191d52006-03-06 02:53:41 +0000736 bidi.dir = bidi.context->dir();
darinf9e5d6c2007-01-09 14:54:26 +0000737 if (bidi.context->dir() == LeftToRight) {
hyatt275d0702005-11-03 23:53:57 +0000738 // bidi.sor ... bidi.eor ... bidi.last L
darinf9e5d6c2007-01-09 14:54:26 +0000739 if (bidi.status.eor == EuropeanNumber) {
740 if (bidi.status.lastStrong != LeftToRight) {
741 bidi.dir = EuropeanNumber;
hyatt275d0702005-11-03 23:53:57 +0000742 appendRun(bidi);
743 }
darinf9e5d6c2007-01-09 14:54:26 +0000744 } else if (bidi.status.eor == ArabicNumber) {
745 bidi.dir = ArabicNumber;
darinef0c09f2005-10-09 01:46:17 +0000746 appendRun(bidi);
darinf9e5d6c2007-01-09 14:54:26 +0000747 } else if (bidi.status.eor != LeftToRight)
hyatt275d0702005-11-03 23:53:57 +0000748 appendRun(bidi);
darinf9e5d6c2007-01-09 14:54:26 +0000749 } else if (bidi.status.eor != RightToLeft && bidi.status.eor != RightToLeftArabic)
darinef0c09f2005-10-09 01:46:17 +0000750 appendRun(bidi);
hyatt275d0702005-11-03 23:53:57 +0000751 bidi.eor = bidi.last;
752 }
darin54008922006-01-13 16:39:05 +0000753 appendRun(bidi);
754 emptyRun = true;
hyatt275d0702005-11-03 23:53:57 +0000755 // sor for the new run is determined by the higher level (rule X10)
mjs08191d52006-03-06 02:53:41 +0000756 bidi.status.last = bidi.context->dir();
757 bidi.status.lastStrong = bidi.context->dir();
darin54008922006-01-13 16:39:05 +0000758 bidi.context = c;
mjs08191d52006-03-06 02:53:41 +0000759 bidi.status.eor = bidi.context->dir();
hyatt275d0702005-11-03 23:53:57 +0000760 bidi.eor.obj = 0;
761 }
mjs6f821c82002-03-22 00:31:57 +0000762 } else {
darinf9e5d6c2007-01-09 14:54:26 +0000763 Direction runDir;
764 if (d == RightToLeftEmbedding || d == RightToLeftOverride)
765 runDir = RightToLeft;
darin54008922006-01-13 16:39:05 +0000766 else
darinf9e5d6c2007-01-09 14:54:26 +0000767 runDir = LeftToRight;
768 bool override = d == LeftToRightOverride || d == RightToLeftOverride;
mjs6f821c82002-03-22 00:31:57 +0000769
darin54008922006-01-13 16:39:05 +0000770 unsigned char level = bidi.context->level;
darinf9e5d6c2007-01-09 14:54:26 +0000771 if (runDir == RightToLeft) {
darin54008922006-01-13 16:39:05 +0000772 if (level%2) // we have an odd level
773 level += 2;
774 else
775 level++;
776 } else {
777 if (level%2) // we have an odd level
778 level++;
779 else
780 level += 2;
781 }
mjs6f821c82002-03-22 00:31:57 +0000782
darin54008922006-01-13 16:39:05 +0000783 if (level < 61) {
784 if (!emptyRun && bidi.eor != bidi.last) {
darinf9e5d6c2007-01-09 14:54:26 +0000785 assert(bidi.status.eor != OtherNeutral);
hyatt275d0702005-11-03 23:53:57 +0000786 // bidi.sor ... bidi.eor ... bidi.last eor; need to append the bidi.sor-bidi.eor run or extend it through bidi.last
darinf9e5d6c2007-01-09 14:54:26 +0000787 assert(bidi.status.last == EuropeanNumberSeparator
788 || bidi.status.last == EuropeanNumberTerminator
789 || bidi.status.last == CommonNumberSeparator
790 || bidi.status.last == BoundaryNeutral
791 || bidi.status.last == BlockSeparator
792 || bidi.status.last == SegmentSeparator
793 || bidi.status.last == WhiteSpaceNeutral
794 || bidi.status.last == OtherNeutral);
795 if (bidi.dir == OtherNeutral)
hyatt275d0702005-11-03 23:53:57 +0000796 bidi.dir = runDir;
darinf9e5d6c2007-01-09 14:54:26 +0000797 if (runDir == LeftToRight) {
hyatt275d0702005-11-03 23:53:57 +0000798 // bidi.sor ... bidi.eor ... bidi.last L
darinf9e5d6c2007-01-09 14:54:26 +0000799 if (bidi.status.eor == EuropeanNumber) {
800 if (bidi.status.lastStrong != LeftToRight) {
801 bidi.dir = EuropeanNumber;
hyatt275d0702005-11-03 23:53:57 +0000802 appendRun(bidi);
darinf9e5d6c2007-01-09 14:54:26 +0000803 if (bidi.context->dir() != LeftToRight)
804 bidi.dir = RightToLeft;
hyatt275d0702005-11-03 23:53:57 +0000805 }
darinf9e5d6c2007-01-09 14:54:26 +0000806 } else if (bidi.status.eor == ArabicNumber) {
807 bidi.dir = ArabicNumber;
darinef0c09f2005-10-09 01:46:17 +0000808 appendRun(bidi);
darinf9e5d6c2007-01-09 14:54:26 +0000809 if (bidi.context->dir() != LeftToRight) {
hyatt275d0702005-11-03 23:53:57 +0000810 bidi.eor = bidi.last;
darinf9e5d6c2007-01-09 14:54:26 +0000811 bidi.dir = RightToLeft;
hyatt275d0702005-11-03 23:53:57 +0000812 appendRun(bidi);
813 }
darinf9e5d6c2007-01-09 14:54:26 +0000814 } else if (bidi.status.eor != LeftToRight) {
815 if (bidi.context->dir() == LeftToRight || bidi.status.lastStrong == LeftToRight)
hyatt275d0702005-11-03 23:53:57 +0000816 appendRun(bidi);
817 else
darinf9e5d6c2007-01-09 14:54:26 +0000818 bidi.dir = RightToLeft;
darinef0c09f2005-10-09 01:46:17 +0000819 }
darinf9e5d6c2007-01-09 14:54:26 +0000820 } else if (bidi.status.eor != RightToLeft && bidi.status.eor != RightToLeftArabic) {
hyatt275d0702005-11-03 23:53:57 +0000821 // bidi.sor ... bidi.eor ... bidi.last R; bidi.eor=L/EN/AN; EN,AN behave like R (rule N1)
darinf9e5d6c2007-01-09 14:54:26 +0000822 if (bidi.context->dir() == RightToLeft || bidi.status.lastStrong == RightToLeft || bidi.status.lastStrong == RightToLeftArabic)
darinef0c09f2005-10-09 01:46:17 +0000823 appendRun(bidi);
824 else
darinf9e5d6c2007-01-09 14:54:26 +0000825 bidi.dir = LeftToRight;
darinef0c09f2005-10-09 01:46:17 +0000826 }
hyatt275d0702005-11-03 23:53:57 +0000827 bidi.eor = bidi.last;
hyatt2f1e7102003-02-20 01:27:03 +0000828 }
hyatt275d0702005-11-03 23:53:57 +0000829 appendRun(bidi);
830 emptyRun = true;
eseidel789896f2005-11-27 22:52:09 +0000831 bidi.context = new BidiContext(level, runDir, bidi.context.get(), override);
hyatt275d0702005-11-03 23:53:57 +0000832 bidi.status.last = runDir;
833 bidi.status.lastStrong = runDir;
834 bidi.status.eor = runDir;
835 bidi.eor.obj = 0;
darinef0c09f2005-10-09 01:46:17 +0000836 }
mjs6f821c82002-03-22 00:31:57 +0000837 }
hyatt275d0702005-11-03 23:53:57 +0000838 bidi.adjustEmbedding = b;
kociendabb0c24b2001-08-24 14:24:40 +0000839}
840
hyattffe78712003-02-11 01:59:29 +0000841InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj)
842{
843 // See if we have an unconstructed line box for this object that is also
844 // the last item on the line.
darinb53ebdc2006-07-09 15:10:21 +0000845 ASSERT(obj->isInlineFlow() || obj == this);
hyattffe78712003-02-11 01:59:29 +0000846 RenderFlow* flow = static_cast<RenderFlow*>(obj);
847
848 // Get the last box we made for this render object.
849 InlineFlowBox* box = flow->lastLineBox();
850
851 // If this box is constructed then it is from a previous line, and we need
852 // to make a new box for our line. If this box is unconstructed but it has
853 // something following it on the line, then we know we have to make a new box
854 // as well. In this situation our inline has actually been split in two on
855 // the same line (this can happen with very fancy language mixtures).
856 if (!box || box->isConstructed() || box->nextOnLine()) {
857 // We need to make a new box for this render object. Once
858 // made, we need to place it at the end of the current line.
hyatt450813d2003-07-25 20:22:34 +0000859 InlineBox* newBox = obj->createInlineBox(false, obj == this);
darinb53ebdc2006-07-09 15:10:21 +0000860 ASSERT(newBox->isInlineFlowBox());
hyattffe78712003-02-11 01:59:29 +0000861 box = static_cast<InlineFlowBox*>(newBox);
862 box->setFirstLineStyleBit(m_firstLine);
863
864 // We have a new box. Append it to the inline box we get by constructing our
865 // parent. If we have hit the block itself, then |box| represents the root
866 // inline box for the line, and it doesn't have to be appended to any parent
867 // inline.
868 if (obj != this) {
869 InlineFlowBox* parentBox = createLineBoxes(obj->parent());
870 parentBox->addToLine(box);
871 }
872 }
873
874 return box;
875}
876
hyatt275d0702005-11-03 23:53:57 +0000877RootInlineBox* RenderBlock::constructLine(const BidiIterator& start, const BidiIterator& end)
hyattffe78712003-02-11 01:59:29 +0000878{
hyatt2f1e7102003-02-20 01:27:03 +0000879 if (!sFirstBidiRun)
hyattffe78712003-02-11 01:59:29 +0000880 return 0; // We had no runs. Don't make a root inline box at all. The line is empty.
881
882 InlineFlowBox* parentBox = 0;
hyatt2f1e7102003-02-20 01:27:03 +0000883 for (BidiRun* r = sFirstBidiRun; r; r = r->nextRun) {
hyattffe78712003-02-11 01:59:29 +0000884 // Create a box for our object.
harrison8d773e72006-01-29 15:06:17 +0000885 bool isOnlyRun = (sBidiRunCount == 1);
886 if (sBidiRunCount == 2 && !r->obj->isListMarker())
887 isOnlyRun = ((style()->direction() == RTL) ? sLastBidiRun : sFirstBidiRun)->obj->isListMarker();
888 r->box = r->obj->createInlineBox(r->obj->isPositioned(), false, isOnlyRun);
hyatt0c3a9862004-02-23 21:26:26 +0000889 if (r->box) {
890 // If we have no parent box yet, or if the run is not simply a sibling,
891 // then we need to construct inline boxes as necessary to properly enclose the
892 // run's inline box.
hyatt275d0702005-11-03 23:53:57 +0000893 if (!parentBox || parentBox->object() != r->obj->parent())
hyatt0c3a9862004-02-23 21:26:26 +0000894 // Create new inline boxes all the way back to the appropriate insertion point.
895 parentBox = createLineBoxes(r->obj->parent());
hyattffe78712003-02-11 01:59:29 +0000896
hyatt0c3a9862004-02-23 21:26:26 +0000897 // Append the inline box to this line.
898 parentBox->addToLine(r->box);
darin06dcb9c2005-08-15 04:31:09 +0000899
900 if (r->box->isInlineTextBox()) {
901 InlineTextBox *text = static_cast<InlineTextBox*>(r->box);
902 text->setStart(r->start);
adele80407612006-07-28 05:13:24 +0000903 text->setLen(r->stop - r->start);
904 bool visuallyOrdered = r->obj->style()->visuallyOrdered();
adele68afa0b2007-02-05 23:25:44 +0000905 text->m_reversed = r->reversed(visuallyOrdered);
906 text->m_dirOverride = r->dirOverride(visuallyOrdered);
darin06dcb9c2005-08-15 04:31:09 +0000907 }
hyatt0c3a9862004-02-23 21:26:26 +0000908 }
hyattffe78712003-02-11 01:59:29 +0000909 }
910
911 // We should have a root inline box. It should be unconstructed and
912 // be the last continuation of our line list.
hyatt275d0702005-11-03 23:53:57 +0000913 assert(lastLineBox() && !lastLineBox()->isConstructed());
hyattffe78712003-02-11 01:59:29 +0000914
915 // Set bits on our inline flow boxes that indicate which sides should
916 // paint borders/margins/padding. This knowledge will ultimately be used when
917 // we determine the horizontal positions and widths of all the inline boxes on
918 // the line.
919 RenderObject* endObject = 0;
920 bool lastLine = !end.obj;
921 if (end.obj && end.pos == 0)
922 endObject = end.obj;
923 lastLineBox()->determineSpacingForFlowBoxes(lastLine, endObject);
924
925 // Now mark the line boxes as being constructed.
926 lastLineBox()->setConstructed();
927
928 // Return the last line.
hyatt0c3a9862004-02-23 21:26:26 +0000929 return lastRootBox();
hyattffe78712003-02-11 01:59:29 +0000930}
931
harrison208ea792005-07-29 23:42:59 +0000932// usage: tw - (xpos % tw);
933int RenderBlock::tabWidth(bool isWhitespacePre)
934{
935 if (!isWhitespacePre)
936 return 0;
937
adele1a307da2006-06-01 06:30:08 +0000938 if (m_tabWidth == -1) {
darin7ab31092006-05-10 04:59:57 +0000939 const UChar spaceChar = ' ';
hyatt3e99d1c2006-02-24 21:13:08 +0000940 const Font& font = style()->font();
hyatt43d6c792006-05-11 10:19:34 +0000941 int spaceWidth = font.width(TextRun(&spaceChar, 1));
harrison208ea792005-07-29 23:42:59 +0000942 m_tabWidth = spaceWidth * 8;
harrison208ea792005-07-29 23:42:59 +0000943 }
944
945 return m_tabWidth;
946}
947
hyatt275d0702005-11-03 23:53:57 +0000948void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, BidiState& bidi)
hyattffe78712003-02-11 01:59:29 +0000949{
950 // First determine our total width.
kociendae40cb942004-10-05 20:05:38 +0000951 int availableWidth = lineWidth(m_height);
hyattffe78712003-02-11 01:59:29 +0000952 int totWidth = lineBox->getFlowSpacingWidth();
hyatt2f1e7102003-02-20 01:27:03 +0000953 BidiRun* r = 0;
darin06dcb9c2005-08-15 04:31:09 +0000954 bool needsWordSpacing = false;
hyatt2f1e7102003-02-20 01:27:03 +0000955 for (r = sFirstBidiRun; r; r = r->nextRun) {
hyatt0c05e102006-04-14 08:15:00 +0000956 if (!r->box || r->obj->isPositioned() || r->box->isLineBreak())
hyatt98ee7e42003-05-14 01:39:15 +0000957 continue; // Positioned objects are only participating to figure out their
958 // correct static x position. They have no effect on the width.
hyatt0c05e102006-04-14 08:15:00 +0000959 // Similarly, line break boxes have no effect on the width.
kociendae40cb942004-10-05 20:05:38 +0000960 if (r->obj->isText()) {
ddkilzerfe115062006-07-14 04:42:01 +0000961 RenderText* rt = static_cast<RenderText*>(r->obj);
darin06dcb9c2005-08-15 04:31:09 +0000962 int textWidth = rt->width(r->start, r->stop-r->start, totWidth, m_firstLine);
963 int effectiveWidth = textWidth;
darin42563ac52007-01-22 17:28:57 +0000964 int rtLength = rt->textLength();
darin06dcb9c2005-08-15 04:31:09 +0000965 if (rtLength != 0) {
darin42563ac52007-01-22 17:28:57 +0000966 if (r->start == 0 && needsWordSpacing && DeprecatedChar(rt->characters()[r->start]).isSpace())
967 effectiveWidth += rt->style(m_firstLine)->font().wordSpacing();
968 needsWordSpacing = !DeprecatedChar(rt->characters()[r->stop-1]).isSpace() && r->stop == rtLength;
darin06dcb9c2005-08-15 04:31:09 +0000969 }
kociendaee701982004-10-05 23:06:58 +0000970 r->box->setWidth(textWidth);
darin06dcb9c2005-08-15 04:31:09 +0000971 } else if (!r->obj->isInlineFlow()) {
hyattffe78712003-02-11 01:59:29 +0000972 r->obj->calcWidth();
973 r->box->setWidth(r->obj->width());
hyatt4b381692003-03-10 21:11:59 +0000974 if (!r->compact)
darin06dcb9c2005-08-15 04:31:09 +0000975 totWidth += r->obj->marginLeft() + r->obj->marginRight();
hyattffe78712003-02-11 01:59:29 +0000976 }
hyatt4b381692003-03-10 21:11:59 +0000977
978 // Compacts don't contribute to the width of the line, since they are placed in the margin.
979 if (!r->compact)
980 totWidth += r->box->width();
hyattffe78712003-02-11 01:59:29 +0000981 }
982
ddkilzerfe115062006-07-14 04:42:01 +0000983 if (totWidth > availableWidth && sLogicallyLastBidiRun->obj->style(m_firstLine)->autoWrap() &&
984 sLogicallyLastBidiRun->obj->style(m_firstLine)->breakOnlyAfterWhiteSpace() &&
985 !sLogicallyLastBidiRun->compact) {
986 sLogicallyLastBidiRun->box->setWidth(sLogicallyLastBidiRun->box->width() - totWidth + availableWidth);
987 totWidth = availableWidth;
988 }
989
hyattffe78712003-02-11 01:59:29 +0000990 // Armed with the total width of the line (without justification),
991 // we now examine our text-align property in order to determine where to position the
992 // objects horizontally. The total width of the line can be increased if we end up
993 // justifying text.
994 int x = leftOffset(m_height);
hyattffe78712003-02-11 01:59:29 +0000995 switch(style()->textAlign()) {
996 case LEFT:
hyatt47c1d4d2003-07-24 22:07:45 +0000997 case KHTML_LEFT:
hyatt959a54e2004-09-27 17:52:18 +0000998 // The direction of the block should determine what happens with wide lines. In
999 // particular with RTL blocks, wide lines should still spill out to the left.
1000 if (style()->direction() == RTL && totWidth > availableWidth)
1001 x -= (totWidth - availableWidth);
hyattffe78712003-02-11 01:59:29 +00001002 numSpaces = 0;
1003 break;
1004 case JUSTIFY:
hyatt0c3a9862004-02-23 21:26:26 +00001005 if (numSpaces != 0 && !bidi.current.atEnd() && !lineBox->endsWithBreak())
hyattffe78712003-02-11 01:59:29 +00001006 break;
1007 // fall through
1008 case TAAUTO:
1009 numSpaces = 0;
1010 // for right to left fall through to right aligned
weinigda22cda2006-12-27 21:19:02 +00001011 if (style()->direction() == LTR)
hyattffe78712003-02-11 01:59:29 +00001012 break;
1013 case RIGHT:
hyatt47c1d4d2003-07-24 22:07:45 +00001014 case KHTML_RIGHT:
hyatt959a54e2004-09-27 17:52:18 +00001015 // Wide lines spill out of the block based off direction.
1016 // So even if text-align is right, if direction is LTR, wide lines should overflow out of the right
1017 // side of the block.
1018 if (style()->direction() == RTL || totWidth < availableWidth)
1019 x += availableWidth - totWidth;
hyattffe78712003-02-11 01:59:29 +00001020 numSpaces = 0;
1021 break;
1022 case CENTER:
hyatt47c1d4d2003-07-24 22:07:45 +00001023 case KHTML_CENTER:
hyattffe78712003-02-11 01:59:29 +00001024 int xd = (availableWidth - totWidth)/2;
eseidel789896f2005-11-27 22:52:09 +00001025 x += xd > 0 ? xd : 0;
hyattffe78712003-02-11 01:59:29 +00001026 numSpaces = 0;
1027 break;
1028 }
1029
hyattacbb0d42003-04-25 01:32:49 +00001030 if (numSpaces > 0) {
1031 for (r = sFirstBidiRun; r; r = r->nextRun) {
hyatt0c3a9862004-02-23 21:26:26 +00001032 if (!r->box) continue;
1033
hyattacbb0d42003-04-25 01:32:49 +00001034 int spaceAdd = 0;
1035 if (numSpaces > 0 && r->obj->isText() && !r->compact) {
1036 // get the number of spaces in the run
1037 int spaces = 0;
darina3c48282003-10-07 15:49:30 +00001038 for ( int i = r->start; i < r->stop; i++ ) {
darin42563ac52007-01-22 17:28:57 +00001039 UChar c = static_cast<RenderText*>(r->obj)->characters()[i];
harrison208ea792005-07-29 23:42:59 +00001040 if (c == ' ' || c == '\n' || c == '\t')
hyattacbb0d42003-04-25 01:32:49 +00001041 spaces++;
darina3c48282003-10-07 15:49:30 +00001042 }
hyatt870bdda2003-05-21 23:37:33 +00001043
darinb53ebdc2006-07-09 15:10:21 +00001044 ASSERT(spaces <= numSpaces);
hyatt870bdda2003-05-21 23:37:33 +00001045
hyattdca76e92005-11-02 08:52:50 +00001046 // Only justify text if whitespace is collapsed.
1047 if (r->obj->style()->collapseWhiteSpace()) {
hyatt870bdda2003-05-21 23:37:33 +00001048 spaceAdd = (availableWidth - totWidth)*spaces/numSpaces;
kocienda01bcc352003-09-25 16:51:11 +00001049 static_cast<InlineTextBox*>(r->box)->setSpaceAdd(spaceAdd);
hyatt870bdda2003-05-21 23:37:33 +00001050 totWidth += spaceAdd;
1051 }
hyattacbb0d42003-04-25 01:32:49 +00001052 numSpaces -= spaces;
hyattacbb0d42003-04-25 01:32:49 +00001053 }
hyattffe78712003-02-11 01:59:29 +00001054 }
hyattffe78712003-02-11 01:59:29 +00001055 }
hyattacbb0d42003-04-25 01:32:49 +00001056
hyattffe78712003-02-11 01:59:29 +00001057 // The widths of all runs are now known. We can now place every inline box (and
1058 // compute accurate widths for the inline flow boxes).
hyatt1f14a612004-12-07 00:34:02 +00001059 int leftPosition = x;
1060 int rightPosition = x;
darin06dcb9c2005-08-15 04:31:09 +00001061 needsWordSpacing = false;
1062 lineBox->placeBoxesHorizontally(x, leftPosition, rightPosition, needsWordSpacing);
hyatt1f14a612004-12-07 00:34:02 +00001063 lineBox->setHorizontalOverflowPositions(leftPosition, rightPosition);
hyattffe78712003-02-11 01:59:29 +00001064}
1065
hyatt0c3a9862004-02-23 21:26:26 +00001066void RenderBlock::computeVerticalPositionsForLine(RootInlineBox* lineBox)
hyattffe78712003-02-11 01:59:29 +00001067{
1068 lineBox->verticallyAlignBoxes(m_height);
hyatt0c3a9862004-02-23 21:26:26 +00001069 lineBox->setBlockHeight(m_height);
hyattffe78712003-02-11 01:59:29 +00001070
hyatt35a85e52003-02-14 19:43:07 +00001071 // See if the line spilled out. If so set overflow height accordingly.
1072 int bottomOfLine = lineBox->bottomOverflow();
1073 if (bottomOfLine > m_height && bottomOfLine > m_overflowHeight)
1074 m_overflowHeight = bottomOfLine;
1075
hyattffe78712003-02-11 01:59:29 +00001076 // Now make sure we place replaced render objects correctly.
hyatt98ee7e42003-05-14 01:39:15 +00001077 for (BidiRun* r = sFirstBidiRun; r; r = r->nextRun) {
eseidel789896f2005-11-27 22:52:09 +00001078 if (!r->box)
1079 continue; // Skip runs with no line boxes.
hyatt0c3a9862004-02-23 21:26:26 +00001080
hyatt98ee7e42003-05-14 01:39:15 +00001081 // Align positioned boxes with the top of the line box. This is
1082 // a reasonable approximation of an appropriate y position.
1083 if (r->obj->isPositioned())
1084 r->box->setYPos(m_height);
1085
1086 // Position is used to properly position both replaced elements and
1087 // to update the static normal flow x/y of positioned elements.
adele80407612006-07-28 05:13:24 +00001088 r->obj->position(r->box);
hyatt98ee7e42003-05-14 01:39:15 +00001089 }
hyattffe78712003-02-11 01:59:29 +00001090}
kociendabb0c24b2001-08-24 14:24:40 +00001091
1092// collects one line of the paragraph and transforms it to visual order
hyatt275d0702005-11-03 23:53:57 +00001093void RenderBlock::bidiReorderLine(const BidiIterator& start, const BidiIterator& end, BidiState& bidi)
kociendabb0c24b2001-08-24 14:24:40 +00001094{
hyatt275d0702005-11-03 23:53:57 +00001095 if (start == end) {
1096 if (start.current() == '\n')
1097 m_height += lineHeight(m_firstLine, true);
hyatt33f8d492002-11-12 21:44:52 +00001098 return;
darinb70665a2002-04-15 23:43:21 +00001099 }
hyattffe78712003-02-11 01:59:29 +00001100
hyatt2f1e7102003-02-20 01:27:03 +00001101 sFirstBidiRun = 0;
1102 sLastBidiRun = 0;
1103 sBidiRunCount = 0;
rjw834c8062005-02-25 23:41:39 +00001104
darinf9e5d6c2007-01-09 14:54:26 +00001105 assert(bidi.dir == OtherNeutral);
eseidel789896f2005-11-27 22:52:09 +00001106
mjs6f821c82002-03-22 00:31:57 +00001107 emptyRun = true;
eseidel789896f2005-11-27 22:52:09 +00001108
ggarenef026b22005-07-06 00:21:53 +00001109 bidi.eor.obj = 0;
darinf028f812002-06-10 20:08:04 +00001110
darinb70665a2002-04-15 23:43:21 +00001111 numSpaces = 0;
kociendabb0c24b2001-08-24 14:24:40 +00001112
mjsfe301d72003-10-02 18:46:18 +00001113 bidi.current = start;
1114 bidi.last = bidi.current;
eseidel789896f2005-11-27 22:52:09 +00001115 bool pastEnd = false;
eseidel789896f2005-11-27 22:52:09 +00001116 BidiState stateAtEnd;
rjw834c8062005-02-25 23:41:39 +00001117
hyatt275d0702005-11-03 23:53:57 +00001118 while (true) {
darinf9e5d6c2007-01-09 14:54:26 +00001119 Direction dirCurrent;
adele7fc3e832006-02-17 09:31:35 +00001120 if (pastEnd && (previousLineBrokeCleanly || bidi.current.atEnd())) {
eseidel789896f2005-11-27 22:52:09 +00001121 BidiContext *c = bidi.context.get();
1122 while (c->parent)
1123 c = c->parent;
mjs08191d52006-03-06 02:53:41 +00001124 dirCurrent = c->dir();
adele7fc3e832006-02-17 09:31:35 +00001125 if (previousLineBrokeCleanly) {
eseidel789896f2005-11-27 22:52:09 +00001126 // A deviation from the Unicode Bidi Algorithm in order to match
1127 // Mac OS X text and WinIE: a hard line break resets bidi state.
1128 stateAtEnd.context = c;
1129 stateAtEnd.status.eor = dirCurrent;
1130 stateAtEnd.status.last = dirCurrent;
1131 stateAtEnd.status.lastStrong = dirCurrent;
1132 }
darinb70665a2002-04-15 23:43:21 +00001133 } else {
mjsfe301d72003-10-02 18:46:18 +00001134 dirCurrent = bidi.current.direction();
darin7ab31092006-05-10 04:59:57 +00001135 if (bidi.context->override
darinf9e5d6c2007-01-09 14:54:26 +00001136 && dirCurrent != RightToLeftEmbedding
1137 && dirCurrent != LeftToRightEmbedding
1138 && dirCurrent != RightToLeftOverride
1139 && dirCurrent != LeftToRightOverride
1140 && dirCurrent != PopDirectionalFormat)
mjs08191d52006-03-06 02:53:41 +00001141 dirCurrent = bidi.context->dir();
darinf9e5d6c2007-01-09 14:54:26 +00001142 else if (dirCurrent == NonSpacingMark)
darinef0c09f2005-10-09 01:46:17 +00001143 dirCurrent = bidi.status.last;
hyatt33f8d492002-11-12 21:44:52 +00001144 }
darinf028f812002-06-10 20:08:04 +00001145
darinf9e5d6c2007-01-09 14:54:26 +00001146 assert(bidi.status.eor != OtherNeutral);
hyatt275d0702005-11-03 23:53:57 +00001147 switch (dirCurrent) {
kociendabb0c24b2001-08-24 14:24:40 +00001148
hyatt275d0702005-11-03 23:53:57 +00001149 // embedding and overrides (X1-X9 in the Bidi specs)
darinf9e5d6c2007-01-09 14:54:26 +00001150 case RightToLeftEmbedding:
1151 case LeftToRightEmbedding:
1152 case RightToLeftOverride:
1153 case LeftToRightOverride:
1154 case PopDirectionalFormat:
hyatt275d0702005-11-03 23:53:57 +00001155 embed(dirCurrent, bidi);
hyatt33f8d492002-11-12 21:44:52 +00001156 break;
kociendabb0c24b2001-08-24 14:24:40 +00001157
1158 // strong types
darinf9e5d6c2007-01-09 14:54:26 +00001159 case LeftToRight:
hyatt275d0702005-11-03 23:53:57 +00001160 switch(bidi.status.last) {
darinf9e5d6c2007-01-09 14:54:26 +00001161 case RightToLeft:
1162 case RightToLeftArabic:
1163 case EuropeanNumber:
1164 case ArabicNumber:
1165 if (bidi.status.last != EuropeanNumber || bidi.status.lastStrong != LeftToRight)
hyatt275d0702005-11-03 23:53:57 +00001166 appendRun(bidi);
eseidel789896f2005-11-27 22:52:09 +00001167 break;
darinf9e5d6c2007-01-09 14:54:26 +00001168 case LeftToRight:
kociendabb0c24b2001-08-24 14:24:40 +00001169 break;
darinf9e5d6c2007-01-09 14:54:26 +00001170 case EuropeanNumberSeparator:
1171 case EuropeanNumberTerminator:
1172 case CommonNumberSeparator:
1173 case BoundaryNeutral:
1174 case BlockSeparator:
1175 case SegmentSeparator:
1176 case WhiteSpaceNeutral:
1177 case OtherNeutral:
1178 if (bidi.status.eor == EuropeanNumber) {
1179 if (bidi.status.lastStrong != LeftToRight) {
ggarenef026b22005-07-06 00:21:53 +00001180 // the numbers need to be on a higher embedding level, so let's close that run
darinf9e5d6c2007-01-09 14:54:26 +00001181 bidi.dir = EuropeanNumber;
ggarenef026b22005-07-06 00:21:53 +00001182 appendRun(bidi);
darinf9e5d6c2007-01-09 14:54:26 +00001183 if (bidi.context->dir() != LeftToRight) {
ggarenef026b22005-07-06 00:21:53 +00001184 // the neutrals take the embedding direction, which is R
1185 bidi.eor = bidi.last;
darinf9e5d6c2007-01-09 14:54:26 +00001186 bidi.dir = RightToLeft;
ggarenef026b22005-07-06 00:21:53 +00001187 appendRun(bidi);
1188 }
1189 }
darinf9e5d6c2007-01-09 14:54:26 +00001190 } else if (bidi.status.eor == ArabicNumber) {
ggarenef026b22005-07-06 00:21:53 +00001191 // Arabic numbers are always on a higher embedding level, so let's close that run
darinf9e5d6c2007-01-09 14:54:26 +00001192 bidi.dir = ArabicNumber;
ggarenef026b22005-07-06 00:21:53 +00001193 appendRun(bidi);
darinf9e5d6c2007-01-09 14:54:26 +00001194 if (bidi.context->dir() != LeftToRight) {
ggarenef026b22005-07-06 00:21:53 +00001195 // the neutrals take the embedding direction, which is R
1196 bidi.eor = bidi.last;
darinf9e5d6c2007-01-09 14:54:26 +00001197 bidi.dir = RightToLeft;
ggarenef026b22005-07-06 00:21:53 +00001198 appendRun(bidi);
1199 }
darinf9e5d6c2007-01-09 14:54:26 +00001200 } else if(bidi.status.eor != LeftToRight) {
eseidel789896f2005-11-27 22:52:09 +00001201 //last stuff takes embedding dir
darinf9e5d6c2007-01-09 14:54:26 +00001202 if (bidi.context->dir() != LeftToRight && bidi.status.lastStrong != LeftToRight) {
darin6f05b4c2005-05-27 01:17:32 +00001203 bidi.eor = bidi.last;
darinf9e5d6c2007-01-09 14:54:26 +00001204 bidi.dir = RightToLeft;
kociendabb0c24b2001-08-24 14:24:40 +00001205 }
eseidel789896f2005-11-27 22:52:09 +00001206 appendRun(bidi);
kociendabb0c24b2001-08-24 14:24:40 +00001207 }
1208 default:
1209 break;
eseidel789896f2005-11-27 22:52:09 +00001210 }
1211 bidi.eor = bidi.current;
darinf9e5d6c2007-01-09 14:54:26 +00001212 bidi.status.eor = LeftToRight;
1213 bidi.status.lastStrong = LeftToRight;
1214 bidi.dir = LeftToRight;
kociendabb0c24b2001-08-24 14:24:40 +00001215 break;
darinf9e5d6c2007-01-09 14:54:26 +00001216 case RightToLeftArabic:
1217 case RightToLeft:
eseidel789896f2005-11-27 22:52:09 +00001218 switch (bidi.status.last) {
darinf9e5d6c2007-01-09 14:54:26 +00001219 case LeftToRight:
1220 case EuropeanNumber:
1221 case ArabicNumber:
darinef0c09f2005-10-09 01:46:17 +00001222 appendRun(bidi);
darinf9e5d6c2007-01-09 14:54:26 +00001223 case RightToLeft:
1224 case RightToLeftArabic:
kociendabb0c24b2001-08-24 14:24:40 +00001225 break;
darinf9e5d6c2007-01-09 14:54:26 +00001226 case EuropeanNumberSeparator:
1227 case EuropeanNumberTerminator:
1228 case CommonNumberSeparator:
1229 case BoundaryNeutral:
1230 case BlockSeparator:
1231 case SegmentSeparator:
1232 case WhiteSpaceNeutral:
1233 case OtherNeutral:
1234 if (bidi.status.eor != RightToLeft && bidi.status.eor != RightToLeftArabic) {
kociendabb0c24b2001-08-24 14:24:40 +00001235 //last stuff takes embedding dir
darinf9e5d6c2007-01-09 14:54:26 +00001236 if (bidi.context->dir() != RightToLeft && bidi.status.lastStrong != RightToLeft
1237 && bidi.status.lastStrong != RightToLeftArabic) {
mjsfe301d72003-10-02 18:46:18 +00001238 bidi.eor = bidi.last;
darinf9e5d6c2007-01-09 14:54:26 +00001239 bidi.dir = LeftToRight;
kociendabb0c24b2001-08-24 14:24:40 +00001240 }
eseidel789896f2005-11-27 22:52:09 +00001241 appendRun(bidi);
1242 }
kociendabb0c24b2001-08-24 14:24:40 +00001243 default:
1244 break;
eseidel789896f2005-11-27 22:52:09 +00001245 }
1246 bidi.eor = bidi.current;
darinf9e5d6c2007-01-09 14:54:26 +00001247 bidi.status.eor = RightToLeft;
mjsfe301d72003-10-02 18:46:18 +00001248 bidi.status.lastStrong = dirCurrent;
darinf9e5d6c2007-01-09 14:54:26 +00001249 bidi.dir = RightToLeft;
kociendabb0c24b2001-08-24 14:24:40 +00001250 break;
1251
1252 // weak types:
1253
darinf9e5d6c2007-01-09 14:54:26 +00001254 case EuropeanNumber:
1255 if (bidi.status.lastStrong != RightToLeftArabic) {
kociendabb0c24b2001-08-24 14:24:40 +00001256 // if last strong was AL change EN to AN
hyatt275d0702005-11-03 23:53:57 +00001257 switch (bidi.status.last) {
darinf9e5d6c2007-01-09 14:54:26 +00001258 case EuropeanNumber:
1259 case LeftToRight:
kociendabb0c24b2001-08-24 14:24:40 +00001260 break;
darinf9e5d6c2007-01-09 14:54:26 +00001261 case RightToLeft:
1262 case RightToLeftArabic:
1263 case ArabicNumber:
darinef0c09f2005-10-09 01:46:17 +00001264 bidi.eor = bidi.last;
hyatt275d0702005-11-03 23:53:57 +00001265 appendRun(bidi);
darinf9e5d6c2007-01-09 14:54:26 +00001266 bidi.dir = EuropeanNumber;
darinef0c09f2005-10-09 01:46:17 +00001267 break;
darinf9e5d6c2007-01-09 14:54:26 +00001268 case EuropeanNumberSeparator:
1269 case CommonNumberSeparator:
1270 if (bidi.status.eor == EuropeanNumber)
eseidel789896f2005-11-27 22:52:09 +00001271 break;
darinf9e5d6c2007-01-09 14:54:26 +00001272 case EuropeanNumberTerminator:
1273 case BoundaryNeutral:
1274 case BlockSeparator:
1275 case SegmentSeparator:
1276 case WhiteSpaceNeutral:
1277 case OtherNeutral:
1278 if (bidi.status.eor == RightToLeft) {
kociendabb0c24b2001-08-24 14:24:40 +00001279 // neutrals go to R
darinf9e5d6c2007-01-09 14:54:26 +00001280 bidi.eor = bidi.status.last == EuropeanNumberTerminator ? bidi.lastBeforeET : bidi.last;
hyatt275d0702005-11-03 23:53:57 +00001281 appendRun(bidi);
darinf9e5d6c2007-01-09 14:54:26 +00001282 bidi.dir = EuropeanNumber;
1283 } else if (bidi.status.eor != LeftToRight &&
1284 (bidi.status.eor != EuropeanNumber || bidi.status.lastStrong != LeftToRight) &&
1285 bidi.dir != LeftToRight) {
kociendabb0c24b2001-08-24 14:24:40 +00001286 // numbers on both sides, neutrals get right to left direction
eseidel789896f2005-11-27 22:52:09 +00001287 appendRun(bidi);
darinf9e5d6c2007-01-09 14:54:26 +00001288 bidi.eor = bidi.status.last == EuropeanNumberTerminator ? bidi.lastBeforeET : bidi.last;
1289 bidi.dir = RightToLeft;
eseidel789896f2005-11-27 22:52:09 +00001290 appendRun(bidi);
darinf9e5d6c2007-01-09 14:54:26 +00001291 bidi.dir = EuropeanNumber;
kociendabb0c24b2001-08-24 14:24:40 +00001292 }
1293 default:
1294 break;
eseidel789896f2005-11-27 22:52:09 +00001295 }
1296 bidi.eor = bidi.current;
darinf9e5d6c2007-01-09 14:54:26 +00001297 bidi.status.eor = EuropeanNumber;
1298 if (bidi.dir == OtherNeutral)
1299 bidi.dir = LeftToRight;
kociendabb0c24b2001-08-24 14:24:40 +00001300 break;
1301 }
darinf9e5d6c2007-01-09 14:54:26 +00001302 case ArabicNumber:
1303 dirCurrent = ArabicNumber;
eseidel789896f2005-11-27 22:52:09 +00001304 switch (bidi.status.last) {
darinf9e5d6c2007-01-09 14:54:26 +00001305 case LeftToRight:
1306 if (bidi.context->dir() == LeftToRight)
mjs89ab8912005-11-28 04:37:33 +00001307 appendRun(bidi);
1308 break;
darinf9e5d6c2007-01-09 14:54:26 +00001309 case ArabicNumber:
eseidel789896f2005-11-27 22:52:09 +00001310 break;
darinf9e5d6c2007-01-09 14:54:26 +00001311 case RightToLeft:
1312 case RightToLeftArabic:
1313 case EuropeanNumber:
darinef0c09f2005-10-09 01:46:17 +00001314 bidi.eor = bidi.last;
hyatt275d0702005-11-03 23:53:57 +00001315 appendRun(bidi);
kociendabb0c24b2001-08-24 14:24:40 +00001316 break;
darinf9e5d6c2007-01-09 14:54:26 +00001317 case CommonNumberSeparator:
1318 if (bidi.status.eor == ArabicNumber)
eseidel789896f2005-11-27 22:52:09 +00001319 break;
darinf9e5d6c2007-01-09 14:54:26 +00001320 case EuropeanNumberSeparator:
1321 case EuropeanNumberTerminator:
1322 case BoundaryNeutral:
1323 case BlockSeparator:
1324 case SegmentSeparator:
1325 case WhiteSpaceNeutral:
1326 case OtherNeutral:
1327 if (bidi.status.eor != RightToLeft && bidi.status.eor != RightToLeftArabic) {
ggarenef026b22005-07-06 00:21:53 +00001328 // run of L before neutrals, neutrals take embedding dir (N2)
darinf9e5d6c2007-01-09 14:54:26 +00001329 if (bidi.context->dir() == RightToLeft || bidi.status.lastStrong == RightToLeft
1330 || bidi.status.lastStrong == RightToLeftArabic) {
ggarenef026b22005-07-06 00:21:53 +00001331 // the embedding direction is R
1332 // close the L run
hyatt275d0702005-11-03 23:53:57 +00001333 appendRun(bidi);
ggarenef026b22005-07-06 00:21:53 +00001334 // neutrals become an R run
darinf9e5d6c2007-01-09 14:54:26 +00001335 bidi.dir = RightToLeft;
kociendabb0c24b2001-08-24 14:24:40 +00001336 } else {
ggarenef026b22005-07-06 00:21:53 +00001337 // the embedding direction is L
1338 // append neutrals to the L run and close it
darinf9e5d6c2007-01-09 14:54:26 +00001339 bidi.dir = LeftToRight;
kociendabb0c24b2001-08-24 14:24:40 +00001340 }
1341 }
eseidel789896f2005-11-27 22:52:09 +00001342 bidi.eor = bidi.last;
1343 appendRun(bidi);
kociendabb0c24b2001-08-24 14:24:40 +00001344 default:
1345 break;
hyatt275d0702005-11-03 23:53:57 +00001346 }
eseidel789896f2005-11-27 22:52:09 +00001347 bidi.eor = bidi.current;
darinf9e5d6c2007-01-09 14:54:26 +00001348 bidi.status.eor = ArabicNumber;
1349 if (bidi.dir == OtherNeutral)
1350 bidi.dir = ArabicNumber;
kociendabb0c24b2001-08-24 14:24:40 +00001351 break;
darinf9e5d6c2007-01-09 14:54:26 +00001352 case EuropeanNumberSeparator:
1353 case CommonNumberSeparator:
kociendabb0c24b2001-08-24 14:24:40 +00001354 break;
darinf9e5d6c2007-01-09 14:54:26 +00001355 case EuropeanNumberTerminator:
1356 if (bidi.status.last == EuropeanNumber) {
1357 dirCurrent = EuropeanNumber;
hyatt275d0702005-11-03 23:53:57 +00001358 bidi.eor = bidi.current;
1359 bidi.status.eor = dirCurrent;
darinf9e5d6c2007-01-09 14:54:26 +00001360 } else if (bidi.status.last != EuropeanNumberTerminator)
darine4fa9e22005-12-16 18:18:50 +00001361 bidi.lastBeforeET = emptyRun ? bidi.eor : bidi.last;
kociendabb0c24b2001-08-24 14:24:40 +00001362 break;
1363
1364 // boundary neutrals should be ignored
darinf9e5d6c2007-01-09 14:54:26 +00001365 case BoundaryNeutral:
darinef0c09f2005-10-09 01:46:17 +00001366 if (bidi.eor == bidi.last)
1367 bidi.eor = bidi.current;
kociendabb0c24b2001-08-24 14:24:40 +00001368 break;
1369 // neutrals
darinf9e5d6c2007-01-09 14:54:26 +00001370 case BlockSeparator:
kociendabb0c24b2001-08-24 14:24:40 +00001371 // ### what do we do with newline and paragraph seperators that come to here?
1372 break;
darinf9e5d6c2007-01-09 14:54:26 +00001373 case SegmentSeparator:
kociendabb0c24b2001-08-24 14:24:40 +00001374 // ### implement rule L1
1375 break;
darinf9e5d6c2007-01-09 14:54:26 +00001376 case WhiteSpaceNeutral:
hyattfe99c872003-07-31 22:25:29 +00001377 break;
darinf9e5d6c2007-01-09 14:54:26 +00001378 case OtherNeutral:
kociendabb0c24b2001-08-24 14:24:40 +00001379 break;
1380 default:
1381 break;
1382 }
1383
eseidel789896f2005-11-27 22:52:09 +00001384 if (pastEnd) {
1385 if (bidi.eor == bidi.current) {
1386 if (!bidi.reachedEndOfLine) {
1387 bidi.eor = bidi.endOfLine;
1388 switch (bidi.status.eor) {
darinf9e5d6c2007-01-09 14:54:26 +00001389 case LeftToRight:
1390 case RightToLeft:
1391 case ArabicNumber:
eseidel789896f2005-11-27 22:52:09 +00001392 bidi.dir = bidi.status.eor;
1393 break;
darinf9e5d6c2007-01-09 14:54:26 +00001394 case EuropeanNumber:
1395 bidi.dir = bidi.status.lastStrong == LeftToRight ? LeftToRight : EuropeanNumber;
eseidel789896f2005-11-27 22:52:09 +00001396 break;
1397 default:
1398 assert(false);
1399 }
1400 appendRun(bidi);
1401 }
1402 bidi = stateAtEnd;
darinf9e5d6c2007-01-09 14:54:26 +00001403 bidi.dir = OtherNeutral;
eseidel789896f2005-11-27 22:52:09 +00001404 break;
1405 }
1406 }
kociendabb0c24b2001-08-24 14:24:40 +00001407
1408 // set status.last as needed.
hyatt275d0702005-11-03 23:53:57 +00001409 switch (dirCurrent) {
darinf9e5d6c2007-01-09 14:54:26 +00001410 case EuropeanNumberTerminator:
1411 if (bidi.status.last != EuropeanNumber)
1412 bidi.status.last = EuropeanNumberTerminator;
ggarenef026b22005-07-06 00:21:53 +00001413 break;
darinf9e5d6c2007-01-09 14:54:26 +00001414 case EuropeanNumberSeparator:
1415 case CommonNumberSeparator:
1416 case SegmentSeparator:
1417 case WhiteSpaceNeutral:
1418 case OtherNeutral:
hyatt275d0702005-11-03 23:53:57 +00001419 switch(bidi.status.last) {
darinf9e5d6c2007-01-09 14:54:26 +00001420 case LeftToRight:
1421 case RightToLeft:
1422 case RightToLeftArabic:
1423 case EuropeanNumber:
1424 case ArabicNumber:
mjsfe301d72003-10-02 18:46:18 +00001425 bidi.status.last = dirCurrent;
kociendabb0c24b2001-08-24 14:24:40 +00001426 break;
1427 default:
darinf9e5d6c2007-01-09 14:54:26 +00001428 bidi.status.last = OtherNeutral;
kociendabb0c24b2001-08-24 14:24:40 +00001429 }
1430 break;
darinf9e5d6c2007-01-09 14:54:26 +00001431 case NonSpacingMark:
1432 case BoundaryNeutral:
1433 case RightToLeftEmbedding:
1434 case LeftToRightEmbedding:
1435 case RightToLeftOverride:
1436 case LeftToRightOverride:
1437 case PopDirectionalFormat:
kociendabb0c24b2001-08-24 14:24:40 +00001438 // ignore these
1439 break;
darinf9e5d6c2007-01-09 14:54:26 +00001440 case EuropeanNumber:
rjw2028aa42003-01-14 21:14:16 +00001441 // fall through
kociendabb0c24b2001-08-24 14:24:40 +00001442 default:
mjsfe301d72003-10-02 18:46:18 +00001443 bidi.status.last = dirCurrent;
hyatt275d0702005-11-03 23:53:57 +00001444 }
kociendabb0c24b2001-08-24 14:24:40 +00001445
mjsfe301d72003-10-02 18:46:18 +00001446 bidi.last = bidi.current;
mjs6f821c82002-03-22 00:31:57 +00001447
darinf9e5d6c2007-01-09 14:54:26 +00001448 if (emptyRun && !(dirCurrent == RightToLeftEmbedding
1449 || dirCurrent == LeftToRightEmbedding
1450 || dirCurrent == RightToLeftOverride
1451 || dirCurrent == LeftToRightOverride
1452 || dirCurrent == PopDirectionalFormat)) {
darin54008922006-01-13 16:39:05 +00001453 bidi.sor = bidi.current;
1454 emptyRun = false;
1455 }
darinb70665a2002-04-15 23:43:21 +00001456
darin54008922006-01-13 16:39:05 +00001457 // this causes the operator ++ to open and close embedding levels as needed
1458 // for the CSS unicode-bidi property
1459 bidi.adjustEmbedding = true;
hyatt275d0702005-11-03 23:53:57 +00001460 bidi.current.increment(bidi);
darin54008922006-01-13 16:39:05 +00001461 bidi.adjustEmbedding = false;
darinf9e5d6c2007-01-09 14:54:26 +00001462 if (emptyRun && (dirCurrent == RightToLeftEmbedding
1463 || dirCurrent == LeftToRightEmbedding
1464 || dirCurrent == RightToLeftOverride
1465 || dirCurrent == LeftToRightOverride
1466 || dirCurrent == PopDirectionalFormat)) {
darinef0c09f2005-10-09 01:46:17 +00001467 // exclude the embedding char itself from the new run so that ATSUI will never see it
1468 bidi.eor.obj = 0;
1469 bidi.last = bidi.current;
1470 bidi.sor = bidi.current;
1471 }
darinb70665a2002-04-15 23:43:21 +00001472
eseidel789896f2005-11-27 22:52:09 +00001473 if (!pastEnd && (bidi.current == end || bidi.current.atEnd())) {
1474 if (emptyRun)
1475 break;
1476 stateAtEnd = bidi;
1477 bidi.endOfLine = bidi.last;
1478 pastEnd = true;
eseidel789896f2005-11-27 22:52:09 +00001479 }
mjs6f821c82002-03-22 00:31:57 +00001480 }
kociendabb0c24b2001-08-24 14:24:40 +00001481
ddkilzerfe115062006-07-14 04:42:01 +00001482 sLogicallyLastBidiRun = sLastBidiRun;
1483
kociendabb0c24b2001-08-24 14:24:40 +00001484 // reorder line according to run structure...
kociendabb0c24b2001-08-24 14:24:40 +00001485 // do not reverse for visually ordered web sites
hyatt275d0702005-11-03 23:53:57 +00001486 if (!style()->visuallyOrdered()) {
eseidel789896f2005-11-27 22:52:09 +00001487
1488 // first find highest and lowest levels
darin479ef852006-01-30 06:06:32 +00001489 unsigned char levelLow = 128;
1490 unsigned char levelHigh = 0;
eseidel789896f2005-11-27 22:52:09 +00001491 BidiRun* r = sFirstBidiRun;
1492 while (r) {
1493 if (r->level > levelHigh)
1494 levelHigh = r->level;
1495 if (r->level < levelLow)
1496 levelLow = r->level;
1497 r = r->nextRun;
1498 }
1499
1500 // implements reordering of the line (L2 according to Bidi spec):
1501 // L2. From the highest level found in the text to the lowest odd level on each line,
1502 // reverse any contiguous sequence of characters that are at that level or higher.
1503
1504 // reversing is only done up to the lowest odd level
1505 if (!(levelLow%2))
1506 levelLow++;
1507
1508 int count = sBidiRunCount - 1;
1509
hyatt275d0702005-11-03 23:53:57 +00001510 while (levelHigh >= levelLow) {
kociendabb0c24b2001-08-24 14:24:40 +00001511 int i = 0;
hyatt2f1e7102003-02-20 01:27:03 +00001512 BidiRun* currRun = sFirstBidiRun;
hyatt275d0702005-11-03 23:53:57 +00001513 while (i < count) {
1514 while (i < count && currRun && currRun->level < levelHigh) {
kociendabb0c24b2001-08-24 14:24:40 +00001515 i++;
hyatt2f1e7102003-02-20 01:27:03 +00001516 currRun = currRun->nextRun;
kociendabb0c24b2001-08-24 14:24:40 +00001517 }
hyatt2f1e7102003-02-20 01:27:03 +00001518 int start = i;
hyatt275d0702005-11-03 23:53:57 +00001519 while (i <= count && currRun && currRun->level >= levelHigh) {
hyatt2f1e7102003-02-20 01:27:03 +00001520 i++;
1521 currRun = currRun->nextRun;
1522 }
1523 int end = i-1;
1524 reverseRuns(start, end);
kociendabb0c24b2001-08-24 14:24:40 +00001525 }
1526 levelHigh--;
1527 }
1528 }
eseidel789896f2005-11-27 22:52:09 +00001529 bidi.endOfLine.obj = 0;
hyatt4b381692003-03-10 21:11:59 +00001530}
kociendabb0c24b2001-08-24 14:24:40 +00001531
hyatt275d0702005-11-03 23:53:57 +00001532static void buildCompactRuns(RenderObject* compactObj, BidiState& bidi)
hyatt4b381692003-03-10 21:11:59 +00001533{
1534 sBuildingCompactRuns = true;
1535 if (!compactObj->isRenderBlock()) {
1536 // Just append a run for our object.
1537 isLineEmpty = false;
eseidel789896f2005-11-27 22:52:09 +00001538 addRun(new (compactObj->renderArena()) BidiRun(0, compactObj->length(), compactObj, bidi.context.get(), bidi.dir));
hyatt4b381692003-03-10 21:11:59 +00001539 }
1540 else {
1541 // Format the compact like it is its own single line. We build up all the runs for
1542 // the little compact and then reorder them for bidi.
1543 RenderBlock* compactBlock = static_cast<RenderBlock*>(compactObj);
hyatt275d0702005-11-03 23:53:57 +00001544 bidi.adjustEmbedding = true;
1545 BidiIterator start(compactBlock, bidiFirst(compactBlock, bidi), 0);
1546 bidi.adjustEmbedding = false;
darin8341f372003-04-29 18:30:31 +00001547 BidiIterator end = start;
hyattffe78712003-02-11 01:59:29 +00001548
hyatt4b381692003-03-10 21:11:59 +00001549 betweenMidpoints = false;
1550 isLineEmpty = true;
hyatt0c3a9862004-02-23 21:26:26 +00001551 previousLineBrokeCleanly = true;
hyatt01eff982003-03-14 20:13:23 +00001552
mjsfe301d72003-10-02 18:46:18 +00001553 end = compactBlock->findNextLineBreak(start, bidi);
hyatt4b381692003-03-10 21:11:59 +00001554 if (!isLineEmpty)
mjsfe301d72003-10-02 18:46:18 +00001555 compactBlock->bidiReorderLine(start, end, bidi);
hyatt4b381692003-03-10 21:11:59 +00001556 }
hyatt275d0702005-11-03 23:53:57 +00001557
hyatt4b381692003-03-10 21:11:59 +00001558 sCompactFirstBidiRun = sFirstBidiRun;
1559 sCompactLastBidiRun = sLastBidiRun;
1560 sCompactBidiRunCount = sBidiRunCount;
1561
1562 sNumMidpoints = 0;
1563 sCurrMidpoint = 0;
1564 betweenMidpoints = false;
1565 sBuildingCompactRuns = false;
kociendabb0c24b2001-08-24 14:24:40 +00001566}
1567
hyatt673184e2006-01-14 22:07:08 +00001568IntRect RenderBlock::layoutInlineChildren(bool relayoutChildren)
kociendabb0c24b2001-08-24 14:24:40 +00001569{
mjsfe301d72003-10-02 18:46:18 +00001570 BidiState bidi;
1571
hyatt0c3a9862004-02-23 21:26:26 +00001572 bool useRepaintRect = false;
ap9059f6f2006-07-24 16:55:02 +00001573 int repaintTop = 0;
1574 int repaintBottom = 0;
hyatt0c3a9862004-02-23 21:26:26 +00001575
hyatta70560a2002-11-20 01:53:20 +00001576 m_overflowHeight = 0;
1577
kociendabb0c24b2001-08-24 14:24:40 +00001578 invalidateVerticalPositions();
hyattdd7dfe92003-11-16 20:48:12 +00001579
1580 m_height = borderTop() + paddingTop();
hyattf9f247b2007-01-12 22:53:40 +00001581 int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
hyattdd7dfe92003-11-16 20:48:12 +00001582
hyatt0c3a9862004-02-23 21:26:26 +00001583 // Figure out if we should clear out our line boxes.
1584 // FIXME: Handle resize eventually!
1585 // FIXME: Do something better when floats are present.
hyatt452d3112006-07-11 01:22:07 +00001586 bool fullLayout = !firstLineBox() || !firstChild() || selfNeedsLayout() || relayoutChildren || containsFloats();
hyatt0c3a9862004-02-23 21:26:26 +00001587 if (fullLayout)
1588 deleteLineBoxes();
hyatted77ad82004-06-15 07:21:23 +00001589
1590 // Text truncation only kicks in if your overflow isn't visible and your text-overflow-mode isn't
1591 // clip.
1592 // FIXME: CSS3 says that descendants that are clipped must also know how to truncate. This is insanely
1593 // difficult to figure out (especially in the middle of doing layout), and is really an esoteric pile of nonsense
1594 // anyway, so we won't worry about following the draft here.
1595 bool hasTextOverflow = style()->textOverflow() && hasOverflowClip();
hyatt33f8d492002-11-12 21:44:52 +00001596
hyatted77ad82004-06-15 07:21:23 +00001597 // Walk all the lines and delete our ellipsis line boxes if they exist.
1598 if (hasTextOverflow)
1599 deleteEllipsisLineBoxes();
1600
hyattffe78712003-02-11 01:59:29 +00001601 if (firstChild()) {
kociendabb0c24b2001-08-24 14:24:40 +00001602 // layout replaced elements
hyattffe78712003-02-11 01:59:29 +00001603 bool endOfInline = false;
hyatt275d0702005-11-03 23:53:57 +00001604 RenderObject *o = bidiFirst(this, bidi, false);
hyatt0c3a9862004-02-23 21:26:26 +00001605 bool hasFloat = false;
1606 while (o) {
1607 if (o->isReplaced() || o->isFloating() || o->isPositioned()) {
hyatt89377f12002-12-13 21:24:40 +00001608 if (relayoutChildren || o->style()->width().isPercent() || o->style()->height().isPercent())
hyattadbb2ef2003-11-18 09:21:44 +00001609 o->setChildNeedsLayout(true, false);
hyatt3ac01352003-03-22 01:37:33 +00001610 if (o->isPositioned())
1611 o->containingBlock()->insertPositionedObject(o);
hyatt0c3a9862004-02-23 21:26:26 +00001612 else {
1613 if (o->isFloating())
1614 hasFloat = true;
1615 else if (fullLayout || o->needsLayout()) // Replaced elements
1616 o->dirtyLineBoxes(fullLayout);
hyatt390427a2003-05-03 18:33:42 +00001617 o->layoutIfNeeded();
hyatt0c3a9862004-02-23 21:26:26 +00001618 }
kociendabb0c24b2001-08-24 14:24:40 +00001619 }
hyatt0c3a9862004-02-23 21:26:26 +00001620 else if (o->isText() || (o->isInlineFlow() && !endOfInline)) {
1621 if (fullLayout || o->selfNeedsLayout())
1622 o->dirtyLineBoxes(fullLayout);
hyattf4fe67f2003-10-07 04:43:23 +00001623 o->setNeedsLayout(false);
hyattf4fe67f2003-10-07 04:43:23 +00001624 }
hyatt275d0702005-11-03 23:53:57 +00001625 o = bidiNext(this, o, bidi, false, &endOfInline);
kociendabb0c24b2001-08-24 14:24:40 +00001626 }
1627
hyatt0c3a9862004-02-23 21:26:26 +00001628 if (hasFloat)
1629 fullLayout = true; // FIXME: Will need to find a way to optimize floats some day.
1630
hyatt837eb362004-05-21 22:17:10 +00001631 if (fullLayout && !selfNeedsLayout()) {
hyatt0c3a9862004-02-23 21:26:26 +00001632 setNeedsLayout(true, false); // Mark ourselves as needing a full layout. This way we'll repaint like
1633 // we're supposed to.
hyatt837eb362004-05-21 22:17:10 +00001634 if (!document()->view()->needsFullRepaint() && m_layer) {
1635 // Because we waited until we were already inside layout to discover
1636 // that the block really needed a full layout, we missed our chance to repaint the layer
1637 // before layout started. Luckily the layer has cached the repaint rect for its original
1638 // position and size, and so we can use that to make a repaint happen now.
hyattd8048342006-05-31 01:48:18 +00001639 RenderView* c = view();
sfalken6f98c4d2007-01-11 01:39:58 +00001640 if (c && !c->printing())
hyatt837eb362004-05-21 22:17:10 +00001641 c->repaintViewRectangle(m_layer->repaintRect());
1642 }
1643 }
hyatt0c3a9862004-02-23 21:26:26 +00001644
kociendabb0c24b2001-08-24 14:24:40 +00001645 BidiContext *startEmbed;
hyatt275d0702005-11-03 23:53:57 +00001646 if (style()->direction() == LTR) {
darinf9e5d6c2007-01-09 14:54:26 +00001647 startEmbed = new BidiContext(0, LeftToRight, NULL, style()->unicodeBidi() == Override);
1648 bidi.status.eor = LeftToRight;
kociendabb0c24b2001-08-24 14:24:40 +00001649 } else {
darinf9e5d6c2007-01-09 14:54:26 +00001650 startEmbed = new BidiContext(1, RightToLeft, NULL, style()->unicodeBidi() == Override);
1651 bidi.status.eor = RightToLeft;
kociendabb0c24b2001-08-24 14:24:40 +00001652 }
kociendabb0c24b2001-08-24 14:24:40 +00001653
mjs08191d52006-03-06 02:53:41 +00001654 bidi.status.lastStrong = startEmbed->dir();
1655 bidi.status.last = startEmbed->dir();
1656 bidi.status.eor = startEmbed->dir();
mjsfe301d72003-10-02 18:46:18 +00001657 bidi.context = startEmbed;
darinf9e5d6c2007-01-09 14:54:26 +00001658 bidi.dir = OtherNeutral;
hyatt33f8d492002-11-12 21:44:52 +00001659
hyatt85586af2003-02-19 23:22:42 +00001660 if (!smidpoints)
darin91298e52006-06-12 01:10:17 +00001661 smidpoints = new Vector<BidiIterator>();
hyatt0c3a9862004-02-23 21:26:26 +00001662
hyatt85586af2003-02-19 23:22:42 +00001663 sNumMidpoints = 0;
1664 sCurrMidpoint = 0;
hyatt4b381692003-03-10 21:11:59 +00001665 sCompactFirstBidiRun = sCompactLastBidiRun = 0;
1666 sCompactBidiRunCount = 0;
hyatt01eff982003-03-14 20:13:23 +00001667
hyatt0c3a9862004-02-23 21:26:26 +00001668 // We want to skip ahead to the first dirty line
1669 BidiIterator start;
1670 RootInlineBox* startLine = determineStartPosition(fullLayout, start, bidi);
1671
1672 // We also find the first clean line and extract these lines. We will add them back
1673 // if we determine that we're able to synchronize after handling all our dirty lines.
1674 BidiIterator cleanLineStart;
eseidel789896f2005-11-27 22:52:09 +00001675 BidiStatus cleanLineBidiStatus;
1676 BidiContext* cleanLineBidiContext;
hyatt0c3a9862004-02-23 21:26:26 +00001677 int endLineYPos;
1678 RootInlineBox* endLine = (fullLayout || !startLine) ?
eseidel789896f2005-11-27 22:52:09 +00001679 0 : determineEndPosition(startLine, cleanLineStart, cleanLineBidiStatus, cleanLineBidiContext, endLineYPos);
1680 if (endLine && cleanLineBidiContext)
1681 cleanLineBidiContext->ref();
hyatt0c3a9862004-02-23 21:26:26 +00001682 if (startLine) {
1683 useRepaintRect = true;
ap9059f6f2006-07-24 16:55:02 +00001684 repaintTop = m_height;
1685 repaintBottom = m_height;
hyatt0c3a9862004-02-23 21:26:26 +00001686 RenderArena* arena = renderArena();
1687 RootInlineBox* box = startLine;
1688 while (box) {
ap9059f6f2006-07-24 16:55:02 +00001689 repaintTop = min(repaintTop, box->topOverflow());
1690 repaintBottom = max(repaintBottom, box->bottomOverflow());
hyatt0c3a9862004-02-23 21:26:26 +00001691 RootInlineBox* next = box->nextRootBox();
1692 box->deleteLine(arena);
1693 box = next;
1694 }
1695 startLine = 0;
1696 }
1697
1698 BidiIterator end = start;
1699
1700 bool endLineMatched = false;
1701 while (!end.atEnd()) {
kociendabb0c24b2001-08-24 14:24:40 +00001702 start = end;
ap9059f6f2006-07-24 16:55:02 +00001703 if (endLine && (endLineMatched = matchedEndLine(start, bidi.status, bidi.context.get(), cleanLineStart, cleanLineBidiStatus, cleanLineBidiContext, endLine, endLineYPos, repaintBottom, repaintTop)))
hyatt0c3a9862004-02-23 21:26:26 +00001704 break;
1705
hyatt33f8d492002-11-12 21:44:52 +00001706 betweenMidpoints = false;
1707 isLineEmpty = true;
hyatt75c30b62004-07-16 20:15:34 +00001708 if (m_firstLine && firstChild() && firstChild()->isCompact() && firstChild()->isRenderBlock()) {
mjsfe301d72003-10-02 18:46:18 +00001709 buildCompactRuns(firstChild(), bidi);
hyatt4b381692003-03-10 21:11:59 +00001710 start.obj = firstChild()->nextSibling();
1711 end = start;
1712 }
mjsfe301d72003-10-02 18:46:18 +00001713 end = findNextLineBreak(start, bidi);
ggarenec11e5b2007-02-25 02:14:54 +00001714 if (start.atEnd()) {
1715 deleteBidiRuns(renderArena());
eseidel789896f2005-11-27 22:52:09 +00001716 break;
ggarenec11e5b2007-02-25 02:14:54 +00001717 }
hyatt33f8d492002-11-12 21:44:52 +00001718 if (!isLineEmpty) {
mjsfe301d72003-10-02 18:46:18 +00001719 bidiReorderLine(start, end, bidi);
hyatt4b381692003-03-10 21:11:59 +00001720
1721 // Now that the runs have been ordered, we create the line boxes.
1722 // At the same time we figure out where border/padding/margin should be applied for
1723 // inline flow boxes.
1724 if (sCompactFirstBidiRun) {
1725 // We have a compact line sharing this line. Link the compact runs
1726 // to our runs to create a single line of runs.
1727 sCompactLastBidiRun->nextRun = sFirstBidiRun;
1728 sFirstBidiRun = sCompactFirstBidiRun;
1729 sBidiRunCount += sCompactBidiRunCount;
1730 }
hyatt4b381692003-03-10 21:11:59 +00001731
hyatt0c3a9862004-02-23 21:26:26 +00001732 RootInlineBox* lineBox = 0;
hyattdfb09052003-03-11 02:58:59 +00001733 if (sBidiRunCount) {
hyatt0c3a9862004-02-23 21:26:26 +00001734 lineBox = constructLine(start, end);
hyattdfb09052003-03-11 02:58:59 +00001735 if (lineBox) {
hyatt0c3a9862004-02-23 21:26:26 +00001736 lineBox->setEndsWithBreak(previousLineBrokeCleanly);
1737
hyattdfb09052003-03-11 02:58:59 +00001738 // Now we position all of our text runs horizontally.
mjsfe301d72003-10-02 18:46:18 +00001739 computeHorizontalPositionsForLine(lineBox, bidi);
hyattdfb09052003-03-11 02:58:59 +00001740
1741 // Now position our text runs vertically.
1742 computeVerticalPositionsForLine(lineBox);
hyattbddcc612006-07-24 23:16:15 +00001743
1744#if PLATFORM(MAC)
1745 // Highlight acts as an overflow inflation.
1746 if (style()->highlight() != nullAtom)
1747 lineBox->addHighlightOverflow();
1748#endif
hyattdfb09052003-03-11 02:58:59 +00001749 }
1750 }
ggarenec11e5b2007-02-25 02:14:54 +00001751
1752 deleteBidiRuns(renderArena());
hyatt4b381692003-03-10 21:11:59 +00001753
hyatt0c05e102006-04-14 08:15:00 +00001754 if (end == start) {
hyatt275d0702005-11-03 23:53:57 +00001755 bidi.adjustEmbedding = true;
mjsfe301d72003-10-02 18:46:18 +00001756 end.increment(bidi);
hyatt275d0702005-11-03 23:53:57 +00001757 bidi.adjustEmbedding = false;
hyatt33f8d492002-11-12 21:44:52 +00001758 }
hyatt35a85e52003-02-14 19:43:07 +00001759
ap9059f6f2006-07-24 16:55:02 +00001760 if (lineBox) {
eseidel789896f2005-11-27 22:52:09 +00001761 lineBox->setLineBreakInfo(end.obj, end.pos, &bidi.status, bidi.context.get());
ap9059f6f2006-07-24 16:55:02 +00001762 if (useRepaintRect) {
1763 repaintTop = min(repaintTop, lineBox->topOverflow());
1764 repaintBottom = max(repaintBottom, lineBox->bottomOverflow());
1765 }
1766 }
hyatt0c3a9862004-02-23 21:26:26 +00001767
hyatt35a85e52003-02-14 19:43:07 +00001768 m_firstLine = false;
hyatt33f8d492002-11-12 21:44:52 +00001769 newLine();
darinb70665a2002-04-15 23:43:21 +00001770 }
hyatt74eec4d2003-03-23 08:02:47 +00001771
hyatt85586af2003-02-19 23:22:42 +00001772 sNumMidpoints = 0;
1773 sCurrMidpoint = 0;
hyatt4b381692003-03-10 21:11:59 +00001774 sCompactFirstBidiRun = sCompactLastBidiRun = 0;
1775 sCompactBidiRunCount = 0;
kociendabb0c24b2001-08-24 14:24:40 +00001776 }
hyatt0c3a9862004-02-23 21:26:26 +00001777
1778 if (endLine) {
1779 if (endLineMatched) {
1780 // Attach all the remaining lines, and then adjust their y-positions as needed.
1781 for (RootInlineBox* line = endLine; line; line = line->nextRootBox())
1782 line->attachLine();
1783
1784 // Now apply the offset to each line if needed.
1785 int delta = m_height - endLineYPos;
harrison208ea792005-07-29 23:42:59 +00001786 if (delta) {
ap9059f6f2006-07-24 16:55:02 +00001787 for (RootInlineBox* line = endLine; line; line = line->nextRootBox()) {
1788 repaintTop = min(repaintTop, line->topOverflow() + (delta < 0 ? delta : 0));
1789 repaintBottom = max(repaintBottom, line->bottomOverflow() + (delta > 0 ? delta : 0));
hyattda77c4b2004-06-17 18:09:49 +00001790 line->adjustPosition(0, delta);
ap9059f6f2006-07-24 16:55:02 +00001791 }
harrison208ea792005-07-29 23:42:59 +00001792 }
hyatt0c3a9862004-02-23 21:26:26 +00001793 m_height = lastRootBox()->blockHeight();
ap9059f6f2006-07-24 16:55:02 +00001794 } else {
hyatt0c3a9862004-02-23 21:26:26 +00001795 // Delete all the remaining lines.
hyatt0c3a9862004-02-23 21:26:26 +00001796 InlineRunBox* line = endLine;
1797 RenderArena* arena = renderArena();
1798 while (line) {
ap9059f6f2006-07-24 16:55:02 +00001799 repaintTop = min(repaintTop, line->topOverflow());
1800 repaintBottom = max(repaintBottom, line->bottomOverflow());
hyatt0c3a9862004-02-23 21:26:26 +00001801 InlineRunBox* next = line->nextLineBox();
hyatt0c3a9862004-02-23 21:26:26 +00001802 line->deleteLine(arena);
1803 line = next;
1804 }
1805 }
eseidel789896f2005-11-27 22:52:09 +00001806 if (cleanLineBidiContext)
1807 cleanLineBidiContext->deref();
hyatt0c3a9862004-02-23 21:26:26 +00001808 }
kociendabb0c24b2001-08-24 14:24:40 +00001809 }
hyatt85586af2003-02-19 23:22:42 +00001810
1811 sNumMidpoints = 0;
1812 sCurrMidpoint = 0;
hyatta70560a2002-11-20 01:53:20 +00001813
hyattefa00882003-03-22 23:27:03 +00001814 // in case we have a float on the last line, it might not be positioned up to now.
1815 // This has to be done before adding in the bottom border/padding, or the float will
1816 // include the padding incorrectly. -dwh
1817 positionNewFloats();
1818
hyatta70560a2002-11-20 01:53:20 +00001819 // Now add in the bottom border/padding.
kociendabb0c24b2001-08-24 14:24:40 +00001820 m_height += toAdd;
1821
hyatta70560a2002-11-20 01:53:20 +00001822 // Always make sure this is at least our height.
darin7bd70952006-04-13 07:07:34 +00001823 m_overflowHeight = max(m_height, m_overflowHeight);
hyatta70560a2002-11-20 01:53:20 +00001824
hyattb4b20872004-10-20 21:34:01 +00001825 // See if any lines spill out of the block. If so, we need to update our overflow width.
1826 checkLinesForOverflow();
1827
ap9059f6f2006-07-24 16:55:02 +00001828 IntRect repaintRect(0, 0, 0, 0);
hyatt0c3a9862004-02-23 21:26:26 +00001829 if (useRepaintRect) {
eseidelcf075d02006-03-26 22:58:26 +00001830 repaintRect.setX(m_overflowLeft);
ap9059f6f2006-07-24 16:55:02 +00001831 repaintRect.setWidth(m_overflowWidth - m_overflowLeft);
1832 repaintRect.setY(repaintTop);
1833 repaintRect.setHeight(repaintBottom - repaintTop);
hyatt0c3a9862004-02-23 21:26:26 +00001834 }
hyatta6960b12004-12-07 02:09:10 +00001835
adele7a470a72006-04-20 22:22:14 +00001836 if (!firstLineBox() && hasLineIfEmpty())
adele05abee32006-08-25 23:44:05 +00001837 m_height += lineHeight(true, true);
hyatted77ad82004-06-15 07:21:23 +00001838
1839 // See if we have any lines that spill out of our block. If we do, then we will possibly need to
1840 // truncate text.
1841 if (hasTextOverflow)
1842 checkLinesForTextOverflow();
1843
hyatt0c3a9862004-02-23 21:26:26 +00001844 return repaintRect;
1845
weinigf18aae32006-08-03 21:55:57 +00001846#if defined(BIDI_DEBUG) && BIDI_DEBUG > 1
darinb70665a2002-04-15 23:43:21 +00001847 kdDebug(6041) << " ------- bidi end " << this << " -------" << endl;
darinf028f812002-06-10 20:08:04 +00001848#endif
kociendabb0c24b2001-08-24 14:24:40 +00001849}
1850
hyatt0c3a9862004-02-23 21:26:26 +00001851RootInlineBox* RenderBlock::determineStartPosition(bool fullLayout, BidiIterator& start, BidiState& bidi)
1852{
1853 RootInlineBox* curr = 0;
1854 RootInlineBox* last = 0;
1855 RenderObject* startObj = 0;
1856 int pos = 0;
1857
1858 if (fullLayout) {
1859 // Nuke all our lines.
1860 if (firstRootBox()) {
1861 RenderArena* arena = renderArena();
1862 curr = firstRootBox();
1863 while (curr) {
1864 RootInlineBox* next = curr->nextRootBox();
1865 curr->deleteLine(arena);
1866 curr = next;
1867 }
darinec375482007-01-06 01:36:24 +00001868 ASSERT(!firstLineBox() && !lastLineBox());
hyatt0c3a9862004-02-23 21:26:26 +00001869 }
eseidel789896f2005-11-27 22:52:09 +00001870 } else {
hyatt0c3a9862004-02-23 21:26:26 +00001871 for (curr = firstRootBox(); curr && !curr->isDirty(); curr = curr->nextRootBox());
1872 if (curr) {
1873 // We have a dirty line.
mjs9f78dd92007-02-12 04:06:07 +00001874 if (RootInlineBox* prevRootBox = curr->prevRootBox()) {
hyatt0c3a9862004-02-23 21:26:26 +00001875 // We have a previous line.
mjs9f78dd92007-02-12 04:06:07 +00001876 if (!prevRootBox->endsWithBreak() || prevRootBox->lineBreakObj()->isText() && prevRootBox->lineBreakPos() >= static_cast<RenderText*>(prevRootBox->lineBreakObj())->textLength())
1877 // The previous line didn't break cleanly or broke at a newline
1878 // that has been deleted, so treat it as dirty too.
1879 curr = prevRootBox;
hyatt0c3a9862004-02-23 21:26:26 +00001880 }
eseidel789896f2005-11-27 22:52:09 +00001881 } else {
hyatt0c3a9862004-02-23 21:26:26 +00001882 // No dirty lines were found.
1883 // If the last line didn't break cleanly, treat it as dirty.
1884 if (lastRootBox() && !lastRootBox()->endsWithBreak())
1885 curr = lastRootBox();
1886 }
1887
1888 // If we have no dirty lines, then last is just the last root box.
1889 last = curr ? curr->prevRootBox() : lastRootBox();
1890 }
1891
1892 m_firstLine = !last;
1893 previousLineBrokeCleanly = !last || last->endsWithBreak();
1894 if (last) {
1895 m_height = last->blockHeight();
hyatt0c3a9862004-02-23 21:26:26 +00001896 startObj = last->lineBreakObj();
1897 pos = last->lineBreakPos();
eseidel789896f2005-11-27 22:52:09 +00001898 bidi.status = last->lineBreakBidiStatus();
1899 bidi.context = last->lineBreakBidiContext();
darindde01502005-12-18 22:55:35 +00001900 } else {
1901 bidi.adjustEmbedding = true;
hyatt275d0702005-11-03 23:53:57 +00001902 startObj = bidiFirst(this, bidi, 0);
darindde01502005-12-18 22:55:35 +00001903 bidi.adjustEmbedding = false;
1904 }
hyatt0c3a9862004-02-23 21:26:26 +00001905
hyatt0c3a9862004-02-23 21:26:26 +00001906 start = BidiIterator(this, startObj, pos);
hyatt0c3a9862004-02-23 21:26:26 +00001907
1908 return curr;
1909}
1910
1911RootInlineBox* RenderBlock::determineEndPosition(RootInlineBox* startLine, BidiIterator& cleanLineStart,
eseidel789896f2005-11-27 22:52:09 +00001912 BidiStatus& cleanLineBidiStatus, BidiContext*& cleanLineBidiContext,
hyatt0c3a9862004-02-23 21:26:26 +00001913 int& yPos)
1914{
1915 RootInlineBox* last = 0;
hyatta6960b12004-12-07 02:09:10 +00001916 if (!startLine)
hyatt0c3a9862004-02-23 21:26:26 +00001917 last = 0;
1918 else {
hyatt04420ca2004-07-16 00:05:42 +00001919 for (RootInlineBox* curr = startLine->nextRootBox(); curr; curr = curr->nextRootBox()) {
1920 if (curr->isDirty())
1921 last = 0;
1922 else if (!last)
1923 last = curr;
1924 }
hyatt0c3a9862004-02-23 21:26:26 +00001925 }
1926
1927 if (!last)
1928 return 0;
1929
eseidel789896f2005-11-27 22:52:09 +00001930 RootInlineBox* prev = last->prevRootBox();
1931 cleanLineStart = BidiIterator(this, prev->lineBreakObj(), prev->lineBreakPos());
1932 cleanLineBidiStatus = prev->lineBreakBidiStatus();
1933 cleanLineBidiContext = prev->lineBreakBidiContext();
ap9059f6f2006-07-24 16:55:02 +00001934 yPos = prev->blockHeight();
hyatt0c3a9862004-02-23 21:26:26 +00001935
1936 for (RootInlineBox* line = last; line; line = line->nextRootBox())
1937 line->extractLine(); // Disconnect all line boxes from their render objects while preserving
1938 // their connections to one another.
1939
1940 return last;
1941}
1942
eseidel789896f2005-11-27 22:52:09 +00001943bool RenderBlock::matchedEndLine(const BidiIterator& start, const BidiStatus& status, BidiContext* context,
ap9059f6f2006-07-24 16:55:02 +00001944 const BidiIterator& endLineStart, const BidiStatus& endLineStatus, BidiContext* endLineContext,
1945 RootInlineBox*& endLine, int& endYPos, int& repaintBottom, int& repaintTop)
hyatt0c3a9862004-02-23 21:26:26 +00001946{
hyatt40731602005-04-18 18:12:42 +00001947 if (start == endLineStart)
eseidel789896f2005-11-27 22:52:09 +00001948 return status == endLineStatus && *context == *endLineContext;
hyatt40731602005-04-18 18:12:42 +00001949 else {
hyatt0c3a9862004-02-23 21:26:26 +00001950 // The first clean line doesn't match, but we can check a handful of following lines to try
1951 // to match back up.
1952 static int numLines = 8; // The # of lines we're willing to match against.
1953 RootInlineBox* line = endLine;
1954 for (int i = 0; i < numLines && line; i++, line = line->nextRootBox()) {
1955 if (line->lineBreakObj() == start.obj && line->lineBreakPos() == start.pos) {
1956 // We have a match.
eseidel789896f2005-11-27 22:52:09 +00001957 if (line->lineBreakBidiStatus() != status || *line->lineBreakBidiContext() != *context)
1958 return false; // ...but the bidi state doesn't match.
hyatt0c3a9862004-02-23 21:26:26 +00001959 RootInlineBox* result = line->nextRootBox();
1960
1961 // Set our yPos to be the block height of endLine.
1962 if (result)
1963 endYPos = line->blockHeight();
1964
1965 // Now delete the lines that we failed to sync.
1966 RootInlineBox* boxToDelete = endLine;
1967 RenderArena* arena = renderArena();
1968 while (boxToDelete && boxToDelete != result) {
ap9059f6f2006-07-24 16:55:02 +00001969 repaintTop = min(repaintTop, boxToDelete->topOverflow());
1970 repaintBottom = max(repaintBottom, boxToDelete->bottomOverflow());
hyatt0c3a9862004-02-23 21:26:26 +00001971 RootInlineBox* next = boxToDelete->nextRootBox();
1972 boxToDelete->deleteLine(arena);
1973 boxToDelete = next;
1974 }
1975
1976 endLine = result;
1977 return result;
1978 }
1979 }
1980 }
1981 return false;
1982}
1983
hyattd9953212005-11-03 21:05:59 +00001984static inline bool skipNonBreakingSpace(BidiIterator &it)
kocienda98440082004-10-14 23:51:47 +00001985{
darinf9e5d6c2007-01-09 14:54:26 +00001986 if (it.obj->style()->nbspMode() != SPACE || it.current() != noBreakSpace)
kocienda98440082004-10-14 23:51:47 +00001987 return false;
1988
hyattdca76e92005-11-02 08:52:50 +00001989 // FIXME: This is bad. It makes nbsp inconsistent with space and won't work correctly
1990 // with m_minWidth/m_maxWidth.
kocienda498d1982004-10-15 21:07:24 +00001991 // Do not skip a non-breaking space if it is the first character
hyattdca76e92005-11-02 08:52:50 +00001992 // on a line after a clean line break (or on the first line, since previousLineBrokeCleanly starts off
1993 // |true|).
1994 if (isLineEmpty && previousLineBrokeCleanly)
kocienda498d1982004-10-15 21:07:24 +00001995 return false;
1996
1997 return true;
kocienda98440082004-10-14 23:51:47 +00001998}
1999
hyattd9953212005-11-03 21:05:59 +00002000static inline bool shouldCollapseWhiteSpace(const RenderStyle* style)
2001{
2002 return style->collapseWhiteSpace() || (style->whiteSpace() == PRE_WRAP && (!isLineEmpty || !previousLineBrokeCleanly));
2003}
2004
zimmermannac3781f2007-02-04 01:25:03 +00002005static inline bool shouldPreserveNewline(RenderObject* object)
2006{
2007#ifdef SVG_SUPPORT
2008 if (object->isSVGText())
2009 return false;
2010#endif
2011
2012 return object->style()->preserveNewline();
2013}
2014
kociendae40cb942004-10-05 20:05:38 +00002015int RenderBlock::skipWhitespace(BidiIterator &it, BidiState &bidi)
kociendabb0c24b2001-08-24 14:24:40 +00002016{
hyatt853cd7d2004-11-05 02:59:48 +00002017 // FIXME: The entire concept of the skipWhitespace function is flawed, since we really need to be building
2018 // line boxes even for containers that may ultimately collapse away. Otherwise we'll never get positioned
2019 // elements quite right. In other words, we need to build this function's work into the normal line
2020 // object iteration process.
2021 int w = lineWidth(m_height);
hyatt81b29762007-02-20 01:41:26 +00002022 while (!it.atEnd() && (it.obj->isFloatingOrPositioned() || it.obj->isInlineFlow() ||
2023 (shouldCollapseWhiteSpace(it.obj->style()) && !it.obj->isBR() &&
2024 (it.current() == ' ' || it.current() == '\t' || (!shouldPreserveNewline(it.obj) && it.current() == '\n') ||
2025 it.current() == softHyphen || skipNonBreakingSpace(it))))) {
kociendae40cb942004-10-05 20:05:38 +00002026 if (it.obj->isFloatingOrPositioned()) {
2027 RenderObject *o = it.obj;
hyatt3b5905b2003-02-01 01:13:30 +00002028 // add to special objects...
hyatt98ee7e42003-05-14 01:39:15 +00002029 if (o->isFloating()) {
hyatt3ac01352003-03-22 01:37:33 +00002030 insertFloatingObject(o);
hyatt38e32632003-07-31 00:46:03 +00002031 positionNewFloats();
hyatt853cd7d2004-11-05 02:59:48 +00002032 w = lineWidth(m_height);
hyatt33f8d492002-11-12 21:44:52 +00002033 }
hyatt98ee7e42003-05-14 01:39:15 +00002034 else if (o->isPositioned()) {
hyatt853cd7d2004-11-05 02:59:48 +00002035 // FIXME: The math here is actually not really right. It's a best-guess approximation that
2036 // will work for the common cases
2037 RenderObject* c = o->container();
2038 if (c->isInlineFlow()) {
2039 // A relative positioned inline encloses us. In this case, we also have to determine our
2040 // position as though we were an inline. Set |staticX| and |staticY| on the relative positioned
2041 // inline so that we can obtain the value later.
2042 c->setStaticX(style()->direction() == LTR ?
2043 leftOffset(m_height) : rightOffset(m_height));
2044 c->setStaticY(m_height);
2045 }
2046
2047 if (o->hasStaticX()) {
2048 bool wasInline = o->style()->isOriginalDisplayInlineType();
2049 if (wasInline)
2050 o->setStaticX(style()->direction() == LTR ?
2051 leftOffset(m_height) :
2052 width() - rightOffset(m_height));
2053 else
2054 o->setStaticX(style()->direction() == LTR ?
2055 borderLeft() + paddingLeft() :
2056 borderRight() + paddingRight());
2057 }
hyatt98ee7e42003-05-14 01:39:15 +00002058 if (o->hasStaticY())
2059 o->setStaticY(m_height);
2060 }
hyatt33f8d492002-11-12 21:44:52 +00002061 }
hyatt4b381692003-03-10 21:11:59 +00002062
hyatt275d0702005-11-03 23:53:57 +00002063 bidi.adjustEmbedding = true;
kociendae40cb942004-10-05 20:05:38 +00002064 it.increment(bidi);
hyatt275d0702005-11-03 23:53:57 +00002065 bidi.adjustEmbedding = false;
mjs6f821c82002-03-22 00:31:57 +00002066 }
hyatt853cd7d2004-11-05 02:59:48 +00002067 return w;
kociendae40cb942004-10-05 20:05:38 +00002068}
2069
2070BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi)
2071{
thatcher459b94a2005-10-13 22:07:51 +00002072 // eliminate spaces at beginning of line
2073 int width = skipWhitespace(start, bidi);
kociendae40cb942004-10-05 20:05:38 +00002074 int w = 0;
2075 int tmpW = 0;
kociendae40cb942004-10-05 20:05:38 +00002076
hyatt853cd7d2004-11-05 02:59:48 +00002077 if (start.atEnd())
darinb70665a2002-04-15 23:43:21 +00002078 return start;
mjs6f821c82002-03-22 00:31:57 +00002079
hyatt33f8d492002-11-12 21:44:52 +00002080 // This variable is used only if whitespace isn't set to PRE, and it tells us whether
2081 // or not we are currently ignoring whitespace.
2082 bool ignoringSpaces = false;
hyatt98b16282004-03-31 18:43:12 +00002083 BidiIterator ignoreStart;
hyatt33f8d492002-11-12 21:44:52 +00002084
2085 // This variable tracks whether the very last character we saw was a space. We use
2086 // this to detect when we encounter a second space so we know we have to terminate
2087 // a run.
rjwc9c257d2003-01-24 03:46:17 +00002088 bool currentCharacterIsSpace = false;
harrisone343c412005-01-18 01:07:26 +00002089 bool currentCharacterIsWS = false;
hyatt33f8d492002-11-12 21:44:52 +00002090 RenderObject* trailingSpaceObject = 0;
hyatt98b16282004-03-31 18:43:12 +00002091
mjs6f821c82002-03-22 00:31:57 +00002092 BidiIterator lBreak = start;
2093
kociendabb0c24b2001-08-24 14:24:40 +00002094 RenderObject *o = start.obj;
2095 RenderObject *last = o;
bdakin9151ba52005-10-24 22:51:06 +00002096 RenderObject *previous = o;
kociendabb0c24b2001-08-24 14:24:40 +00002097 int pos = start.pos;
2098
hyatt0c3a9862004-02-23 21:26:26 +00002099 bool prevLineBrokeCleanly = previousLineBrokeCleanly;
2100 previousLineBrokeCleanly = false;
ddkilzer5d01fa22007-01-29 03:10:37 +00002101
2102 bool autoWrapWasEverTrueOnLine = false;
hyatt01eff982003-03-14 20:13:23 +00002103
hyattb0d9f602007-01-15 01:28:23 +00002104 EWhiteSpace currWS = style()->whiteSpace();
2105 EWhiteSpace lastWS = currWS;
hyatt275d0702005-11-03 23:53:57 +00002106 while (o) {
hyattb0d9f602007-01-15 01:28:23 +00002107 currWS = o->isReplaced() ? o->parent()->style()->whiteSpace() : o->style()->whiteSpace();
2108 lastWS = last->isReplaced() ? last->parent()->style()->whiteSpace() : last->style()->whiteSpace();
2109
2110 bool autoWrap = RenderStyle::autoWrap(currWS);
ddkilzer5d01fa22007-01-29 03:10:37 +00002111 autoWrapWasEverTrueOnLine = autoWrapWasEverTrueOnLine || autoWrap;
zimmermannac3781f2007-02-04 01:25:03 +00002112
2113#ifdef SVG_SUPPORT
2114 bool preserveNewline = o->isSVGText() ? false : RenderStyle::preserveNewline(currWS);
2115#else
hyattb0d9f602007-01-15 01:28:23 +00002116 bool preserveNewline = RenderStyle::preserveNewline(currWS);
zimmermannac3781f2007-02-04 01:25:03 +00002117#endif
2118
hyattb0d9f602007-01-15 01:28:23 +00002119 bool collapseWhiteSpace = RenderStyle::collapseWhiteSpace(currWS);
2120
hyatt275d0702005-11-03 23:53:57 +00002121 if (o->isBR()) {
hyatt0c3a9862004-02-23 21:26:26 +00002122 if (w + tmpW <= width) {
kociendabb0c24b2001-08-24 14:24:40 +00002123 lBreak.obj = o;
2124 lBreak.pos = 0;
hyatt0c3a9862004-02-23 21:26:26 +00002125 lBreak.increment(bidi);
2126
hyatt33f8d492002-11-12 21:44:52 +00002127 // A <br> always breaks a line, so don't let the line be collapsed
2128 // away. Also, the space at the end of a line with a <br> does not
hyatt01eff982003-03-14 20:13:23 +00002129 // get collapsed away. It only does this if the previous line broke
2130 // cleanly. Otherwise the <br> has no effect on whether the line is
2131 // empty or not.
2132 if (prevLineBrokeCleanly)
2133 isLineEmpty = false;
hyatt33f8d492002-11-12 21:44:52 +00002134 trailingSpaceObject = 0;
hyatt0c3a9862004-02-23 21:26:26 +00002135 previousLineBrokeCleanly = true;
hyatt74eec4d2003-03-23 08:02:47 +00002136
2137 if (!isLineEmpty) {
2138 // only check the clear status for non-empty lines.
2139 EClear clear = o->style()->clear();
eseidel789896f2005-11-27 22:52:09 +00002140 if (clear != CNONE)
hyatt74eec4d2003-03-23 08:02:47 +00002141 m_clearStatus = (EClear) (m_clearStatus | clear);
kociendabb0c24b2001-08-24 14:24:40 +00002142 }
2143 }
2144 goto end;
2145 }
hyattb0d9f602007-01-15 01:28:23 +00002146
hyatt275d0702005-11-03 23:53:57 +00002147 if (o->isFloatingOrPositioned()) {
kociendabb0c24b2001-08-24 14:24:40 +00002148 // add to special objects...
hyatt275d0702005-11-03 23:53:57 +00002149 if (o->isFloating()) {
hyatt3ac01352003-03-22 01:37:33 +00002150 insertFloatingObject(o);
hyatt33f8d492002-11-12 21:44:52 +00002151 // check if it fits in the current line.
2152 // If it does, position it now, otherwise, position
2153 // it after moving to next line (in newLine() func)
hyattb0d9f602007-01-15 01:28:23 +00002154 if (o->width() + o->marginLeft() + o->marginRight() + w + tmpW <= width) {
hyatt33f8d492002-11-12 21:44:52 +00002155 positionNewFloats();
2156 width = lineWidth(m_height);
2157 }
hyatt275d0702005-11-03 23:53:57 +00002158 } else if (o->isPositioned()) {
hyatt851816b2003-07-08 07:54:17 +00002159 // If our original display wasn't an inline type, then we can
hyatt98ee7e42003-05-14 01:39:15 +00002160 // go ahead and determine our static x position now.
hyatt851816b2003-07-08 07:54:17 +00002161 bool isInlineType = o->style()->isOriginalDisplayInlineType();
hyatt98ee7e42003-05-14 01:39:15 +00002162 bool needToSetStaticX = o->hasStaticX();
2163 if (o->hasStaticX() && !isInlineType) {
2164 o->setStaticX(o->parent()->style()->direction() == LTR ?
hyattb0d9f602007-01-15 01:28:23 +00002165 borderLeft() + paddingLeft() :
2166 borderRight() + paddingRight());
hyatt98ee7e42003-05-14 01:39:15 +00002167 needToSetStaticX = false;
2168 }
2169
2170 // If our original display was an INLINE type, then we can go ahead
2171 // and determine our static y position now.
2172 bool needToSetStaticY = o->hasStaticY();
2173 if (o->hasStaticY() && isInlineType) {
2174 o->setStaticY(m_height);
2175 needToSetStaticY = false;
2176 }
2177
hyatt853cd7d2004-11-05 02:59:48 +00002178 bool needToCreateLineBox = needToSetStaticX || needToSetStaticY;
2179 RenderObject* c = o->container();
2180 if (c->isInlineFlow() && (!needToSetStaticX || !needToSetStaticY))
2181 needToCreateLineBox = true;
2182
hyatt98ee7e42003-05-14 01:39:15 +00002183 // If we're ignoring spaces, we have to stop and include this object and
2184 // then start ignoring spaces again.
hyatt853cd7d2004-11-05 02:59:48 +00002185 if (needToCreateLineBox) {
hyattbc7f07f2003-05-27 20:04:26 +00002186 trailingSpaceObject = 0;
hyatt98b16282004-03-31 18:43:12 +00002187 ignoreStart.obj = o;
2188 ignoreStart.pos = 0;
hyattbc7f07f2003-05-27 20:04:26 +00002189 if (ignoringSpaces) {
hyatt98b16282004-03-31 18:43:12 +00002190 addMidpoint(ignoreStart); // Stop ignoring spaces.
2191 addMidpoint(ignoreStart); // Start ignoring again.
hyattbc7f07f2003-05-27 20:04:26 +00002192 }
hyatt98b16282004-03-31 18:43:12 +00002193
hyatt851816b2003-07-08 07:54:17 +00002194 }
hyatt98ee7e42003-05-14 01:39:15 +00002195 }
hyattffe78712003-02-11 01:59:29 +00002196 } else if (o->isInlineFlow()) {
2197 // Only empty inlines matter. We treat those similarly to replaced elements.
hyatt275d0702005-11-03 23:53:57 +00002198 assert(!o->firstChild());
hyattb0d9f602007-01-15 01:28:23 +00002199 tmpW += o->marginLeft() + o->borderLeft() + o->paddingLeft() +
2200 o->marginRight() + o->borderRight() + o->paddingRight();
hyatt275d0702005-11-03 23:53:57 +00002201 } else if (o->isReplaced()) {
hyattde396342003-10-29 08:57:20 +00002202 // Break on replaced elements if either has normal white-space.
hyattb0d9f602007-01-15 01:28:23 +00002203 if (autoWrap || RenderStyle::autoWrap(lastWS)) {
hyatt711fe232002-11-20 21:25:14 +00002204 w += tmpW;
2205 tmpW = 0;
hyattf14a4a32002-11-21 22:06:32 +00002206 lBreak.obj = o;
2207 lBreak.pos = 0;
hyatt711fe232002-11-20 21:25:14 +00002208 }
2209
hyatt33f8d492002-11-12 21:44:52 +00002210 if (ignoringSpaces) {
mjsfe301d72003-10-02 18:46:18 +00002211 BidiIterator startMid( 0, o, 0 );
hyatt85586af2003-02-19 23:22:42 +00002212 addMidpoint(startMid);
hyatt33f8d492002-11-12 21:44:52 +00002213 }
2214 isLineEmpty = false;
2215 ignoringSpaces = false;
rjwc9c257d2003-01-24 03:46:17 +00002216 currentCharacterIsSpace = false;
harrisone343c412005-01-18 01:07:26 +00002217 currentCharacterIsWS = false;
hyatt33f8d492002-11-12 21:44:52 +00002218 trailingSpaceObject = 0;
hyatte85e4a72002-12-08 02:06:16 +00002219
mjsd26b2972007-02-13 13:09:04 +00002220 if (o->isListMarker() && !static_cast<RenderListMarker*>(o)->isInside()) {
hyatte85e4a72002-12-08 02:06:16 +00002221 // The marker must not have an effect on whitespace at the start
2222 // of the line. We start ignoring spaces to make sure that any additional
2223 // spaces we see will be discarded.
2224 //
2225 // Optimize for a common case. If we can't find whitespace after the list
2226 // item, then this is all moot. -dwh
hyatt275d0702005-11-03 23:53:57 +00002227 RenderObject* next = bidiNext(start.block, o, bidi);
darin42563ac52007-01-22 17:28:57 +00002228 if (style()->collapseWhiteSpace() && next && !next->isBR() && next->isText() && static_cast<RenderText*>(next)->textLength() > 0) {
harrison208ea792005-07-29 23:42:59 +00002229 RenderText *nextText = static_cast<RenderText*>(next);
darin42563ac52007-01-22 17:28:57 +00002230 UChar nextChar = nextText->characters()[0];
hyattdca76e92005-11-02 08:52:50 +00002231 if (nextText->style()->isCollapsibleWhiteSpace(nextChar)) {
harrisone343c412005-01-18 01:07:26 +00002232 currentCharacterIsSpace = true;
2233 currentCharacterIsWS = true;
2234 ignoringSpaces = true;
2235 BidiIterator endMid( 0, o, 0 );
2236 addMidpoint(endMid);
2237 }
hyatte85e4a72002-12-08 02:06:16 +00002238 }
justing244d3a32006-04-13 01:31:24 +00002239 } else
hyattb0d9f602007-01-15 01:28:23 +00002240 tmpW += o->width() + o->marginLeft() + o->marginRight() + inlineWidth(o);
eseidel789896f2005-11-27 22:52:09 +00002241 } else if (o->isText()) {
weinigf28a1c32007-02-14 14:10:31 +00002242 RenderText* t = static_cast<RenderText*>(o);
darin42563ac52007-01-22 17:28:57 +00002243 int strlen = t->textLength();
hyatt33f8d492002-11-12 21:44:52 +00002244 int len = strlen - pos;
darin42563ac52007-01-22 17:28:57 +00002245 const UChar* str = t->characters();
kociendabb0c24b2001-08-24 14:24:40 +00002246
darin42563ac52007-01-22 17:28:57 +00002247 const Font& f = t->style(m_firstLine)->font();
weinigf28a1c32007-02-14 14:10:31 +00002248
hyatt33f8d492002-11-12 21:44:52 +00002249 int lastSpace = pos;
hyatt3aff2332003-01-23 01:15:28 +00002250 int wordSpacing = o->style()->wordSpacing();
eseideld13fe532005-11-30 02:40:29 +00002251 int lastSpaceWordSpacing = 0;
hyattffe78712003-02-11 01:59:29 +00002252
2253 bool appliedStartWidth = pos > 0; // If the span originated on a previous line,
2254 // then assume the start width has been applied.
darin54008922006-01-13 16:39:05 +00002255 int wrapW = tmpW + inlineWidth(o, !appliedStartWidth, true);
darin47ece0d2005-09-04 07:42:31 +00002256 int nextBreakable = -1;
weinigf28a1c32007-02-14 14:10:31 +00002257 bool breakNBSP = autoWrap && o->style()->nbspMode() == SPACE;
2258 // Auto-wrapping text should wrap in the middle of a word only if it could not wrap before the word,
2259 // which is only possible if the word is the first thing on the line, that is, if |w| is zero.
2260 bool breakWords = o->style()->wordWrap() == BREAK_WORD && ((autoWrap && !w) || currWS == PRE);
2261 bool midWordBreak = false;
hyattb0d9f602007-01-15 01:28:23 +00002262
hyatt275d0702005-11-03 23:53:57 +00002263 while (len) {
rjwc9c257d2003-01-24 03:46:17 +00002264 bool previousCharacterIsSpace = currentCharacterIsSpace;
harrisone343c412005-01-18 01:07:26 +00002265 bool previousCharacterIsWS = currentCharacterIsWS;
darin7ab31092006-05-10 04:59:57 +00002266 UChar c = str[pos];
hyattb0d9f602007-01-15 01:28:23 +00002267 currentCharacterIsSpace = c == ' ' || c == '\t' || (!preserveNewline && (c == '\n'));
darin47ece0d2005-09-04 07:42:31 +00002268
hyattb0d9f602007-01-15 01:28:23 +00002269 if (!collapseWhiteSpace || !currentCharacterIsSpace)
hyatt33f8d492002-11-12 21:44:52 +00002270 isLineEmpty = false;
hyatt3aff2332003-01-23 01:15:28 +00002271
hyatt78b85132004-03-29 20:07:45 +00002272 // Check for soft hyphens. Go ahead and ignore them.
darin42563ac52007-01-22 17:28:57 +00002273 if (c == softHyphen) {
hyatt78b85132004-03-29 20:07:45 +00002274 if (!ignoringSpaces) {
2275 // Ignore soft hyphens
bdakin9151ba52005-10-24 22:51:06 +00002276 BidiIterator endMid;
2277 if (pos > 0)
weinigf28a1c32007-02-14 14:10:31 +00002278 endMid = BidiIterator(0, o, pos - 1);
bdakin9151ba52005-10-24 22:51:06 +00002279 else
weinigf28a1c32007-02-14 14:10:31 +00002280 endMid = BidiIterator(0, previous, previous->isText() ? static_cast<RenderText*>(previous)->textLength() - 1 : 0);
bdakin9151ba52005-10-24 22:51:06 +00002281 // Two consecutive soft hyphens. Avoid overlapping midpoints.
2282 if (sNumMidpoints && smidpoints->at(sNumMidpoints - 1).obj == endMid.obj && smidpoints->at(sNumMidpoints - 1).pos > endMid.pos)
2283 sNumMidpoints--;
2284 else
2285 addMidpoint(endMid);
hyatt78b85132004-03-29 20:07:45 +00002286
2287 // Add the width up to but not including the hyphen.
weinigf28a1c32007-02-14 14:10:31 +00002288 tmpW += t->width(lastSpace, pos - lastSpace, f, w + tmpW) + lastSpaceWordSpacing;
hyatt78b85132004-03-29 20:07:45 +00002289
hyattdca76e92005-11-02 08:52:50 +00002290 // For wrapping text only, include the hyphen. We need to ensure it will fit
hyatt78b85132004-03-29 20:07:45 +00002291 // on the line if it shows when we break.
hyattb0d9f602007-01-15 01:28:23 +00002292 if (autoWrap)
weinigf28a1c32007-02-14 14:10:31 +00002293 tmpW += t->width(pos, 1, f, w + tmpW);
hyatt78b85132004-03-29 20:07:45 +00002294
weinigf28a1c32007-02-14 14:10:31 +00002295 BidiIterator startMid(0, o, pos + 1);
hyatt78b85132004-03-29 20:07:45 +00002296 addMidpoint(startMid);
2297 }
2298
2299 pos++;
2300 len--;
eseideld13fe532005-11-30 02:40:29 +00002301 lastSpaceWordSpacing = 0;
hyatt78b85132004-03-29 20:07:45 +00002302 lastSpace = pos; // Cheesy hack to prevent adding in widths of the run twice.
2303 continue;
2304 }
2305
hyatt3aff2332003-01-23 01:15:28 +00002306 bool applyWordSpacing = false;
hyattdca76e92005-11-02 08:52:50 +00002307
darinf9e5d6c2007-01-09 14:54:26 +00002308 currentCharacterIsWS = currentCharacterIsSpace || (breakNBSP && c == noBreakSpace);
harrisone343c412005-01-18 01:07:26 +00002309
weinigf28a1c32007-02-14 14:10:31 +00002310 if (breakWords && !midWordBreak) {
harrison208ea792005-07-29 23:42:59 +00002311 wrapW += t->width(pos, 1, f, w+wrapW);
weinigf28a1c32007-02-14 14:10:31 +00002312 midWordBreak = w + wrapW > width;
2313 }
darin47ece0d2005-09-04 07:42:31 +00002314
weinigf28a1c32007-02-14 14:10:31 +00002315 bool betweenWords = c == '\n' || (currWS != PRE && isBreakable(str, pos, strlen, nextBreakable, breakNBSP));
2316
2317 if (betweenWords || midWordBreak) {
hyatt0c05e102006-04-14 08:15:00 +00002318 bool stoppedIgnoringSpaces = false;
hyatt33f8d492002-11-12 21:44:52 +00002319 if (ignoringSpaces) {
rjwc9c257d2003-01-24 03:46:17 +00002320 if (!currentCharacterIsSpace) {
hyatt33f8d492002-11-12 21:44:52 +00002321 // Stop ignoring spaces and begin at this
2322 // new point.
hyatt48710d62003-08-21 09:17:13 +00002323 ignoringSpaces = false;
eseideld13fe532005-11-30 02:40:29 +00002324 lastSpaceWordSpacing = 0;
hyatt48710d62003-08-21 09:17:13 +00002325 lastSpace = pos; // e.g., "Foo goo", don't add in any of the ignored spaces.
weinigf28a1c32007-02-14 14:10:31 +00002326 BidiIterator startMid(0, o, pos);
hyatt85586af2003-02-19 23:22:42 +00002327 addMidpoint(startMid);
hyatt0c05e102006-04-14 08:15:00 +00002328 stoppedIgnoringSpaces = true;
harrisone343c412005-01-18 01:07:26 +00002329 } else {
hyatt33f8d492002-11-12 21:44:52 +00002330 // Just keep ignoring these spaces.
2331 pos++;
2332 len--;
2333 continue;
2334 }
2335 }
rjwc9c257d2003-01-24 03:46:17 +00002336
darin54008922006-01-13 16:39:05 +00002337 int additionalTmpW = t->width(lastSpace, pos - lastSpace, f, w+tmpW) + lastSpaceWordSpacing;
2338 tmpW += additionalTmpW;
hyattffe78712003-02-11 01:59:29 +00002339 if (!appliedStartWidth) {
2340 tmpW += inlineWidth(o, true, false);
2341 appliedStartWidth = true;
2342 }
2343
eseideld13fe532005-11-30 02:40:29 +00002344 applyWordSpacing = wordSpacing && currentCharacterIsSpace && !previousCharacterIsSpace;
hyatt3aff2332003-01-23 01:15:28 +00002345
weinigf28a1c32007-02-14 14:10:31 +00002346 if (autoWrap && w + tmpW > width && !w) {
hyatte2b14092003-01-23 23:33:39 +00002347 int fb = nearestFloatBottom(m_height);
hyatt33f8d492002-11-12 21:44:52 +00002348 int newLineWidth = lineWidth(fb);
hyatt2df52192003-03-28 22:05:02 +00002349 // See if |tmpW| will fit on the new line. As long as it does not,
2350 // keep adjusting our float bottom until we find some room.
2351 int lastFloatBottom = m_height;
2352 while (lastFloatBottom < fb && tmpW > newLineWidth) {
2353 lastFloatBottom = fb;
2354 fb = nearestFloatBottom(fb);
2355 newLineWidth = lineWidth(fb);
2356 }
2357
hyatt275d0702005-11-03 23:53:57 +00002358 if (!w && m_height < fb && width < newLineWidth) {
hyatt33f8d492002-11-12 21:44:52 +00002359 m_height = fb;
2360 width = newLineWidth;
hyatt33f8d492002-11-12 21:44:52 +00002361 }
2362 }
2363
hyattb0d9f602007-01-15 01:28:23 +00002364 if (autoWrap || breakWords) {
hyattdca76e92005-11-02 08:52:50 +00002365 // If we break only after white-space, consider the current character
kociendae4134242004-10-25 18:48:44 +00002366 // as candidate width for this line.
ap932806a2006-10-01 09:06:09 +00002367 bool lineWasTooWide = false;
2368 if (w + tmpW <= width && currentCharacterIsWS && o->style()->breakOnlyAfterWhiteSpace() && !midWordBreak) {
2369 int charWidth = t->width(pos, 1, f, w + tmpW) + (applyWordSpacing ? wordSpacing : 0);
2370 // Check if line is too big even without the extra space
2371 // at the end of the line. If it is not, do nothing.
2372 // If the line needs the extra whitespace to be too long,
2373 // then move the line break to the space and skip all
2374 // additional whitespace.
2375 if (w + tmpW + charWidth > width) {
2376 lineWasTooWide = true;
2377 lBreak.obj = o;
2378 lBreak.pos = pos;
2379 if (pos > 0) {
2380 // Separate the trailing space into its own box, which we will
2381 // resize to fit on the line in computeHorizontalPositionsForLine().
2382 BidiIterator midpoint(0, o, pos);
2383 addMidpoint(BidiIterator(0, o, pos-1)); // Stop
2384 addMidpoint(BidiIterator(0, o, pos)); // Start
kociendae4134242004-10-25 18:48:44 +00002385 }
ap932806a2006-10-01 09:06:09 +00002386 skipWhitespace(lBreak, bidi);
kocienda9dbe9b12004-10-22 20:07:05 +00002387 }
ap932806a2006-10-01 09:06:09 +00002388 }
2389 if (lineWasTooWide || w + tmpW > width) {
zimmermannac3781f2007-02-04 01:25:03 +00002390 if (lBreak.obj && shouldPreserveNewline(lBreak.obj) && lBreak.obj->isText() && static_cast<RenderText*>(lBreak.obj)->characters()[lBreak.pos] == '\n') {
hyatt0c05e102006-04-14 08:15:00 +00002391 if (!stoppedIgnoringSpaces && pos > 0) {
2392 // We need to stop right before the newline and then start up again.
2393 BidiIterator midpoint(0, o, pos);
2394 addMidpoint(BidiIterator(0, o, pos-1)); // Stop
2395 addMidpoint(BidiIterator(0, o, pos)); // Start
2396 }
2397 lBreak.increment(bidi);
adele7fc3e832006-02-17 09:31:35 +00002398 previousLineBrokeCleanly = true;
adele7fc3e832006-02-17 09:31:35 +00002399 }
hyatt78b85132004-03-29 20:07:45 +00002400 goto end; // Didn't fit. Jump to the end.
darin54008922006-01-13 16:39:05 +00002401 } else {
2402 if (midWordBreak)
2403 tmpW -= additionalTmpW;
darin42563ac52007-01-22 17:28:57 +00002404 if (pos > 0 && str[pos-1] == softHyphen)
darin54008922006-01-13 16:39:05 +00002405 // Subtract the width of the soft hyphen out since we fit on a line.
2406 tmpW -= t->width(pos-1, 1, f, w+tmpW);
2407 }
rjwc9c257d2003-01-24 03:46:17 +00002408 }
hyatt33f8d492002-11-12 21:44:52 +00002409
hyattb0d9f602007-01-15 01:28:23 +00002410 if (c == '\n' && preserveNewline) {
hyatt0c05e102006-04-14 08:15:00 +00002411 if (!stoppedIgnoringSpaces && pos > 0) {
2412 // We need to stop right before the newline and then start up again.
2413 BidiIterator midpoint(0, o, pos);
2414 addMidpoint(BidiIterator(0, o, pos-1)); // Stop
2415 addMidpoint(BidiIterator(0, o, pos)); // Start
2416 }
hyatta9f48e32003-02-03 22:48:01 +00002417 lBreak.obj = o;
2418 lBreak.pos = pos;
hyatt0c05e102006-04-14 08:15:00 +00002419 lBreak.increment(bidi);
adele7fc3e832006-02-17 09:31:35 +00002420 previousLineBrokeCleanly = true;
hyatt33f8d492002-11-12 21:44:52 +00002421 return lBreak;
2422 }
hyatta9f48e32003-02-03 22:48:01 +00002423
weinigf28a1c32007-02-14 14:10:31 +00002424 if (autoWrap && betweenWords) {
hyatta9f48e32003-02-03 22:48:01 +00002425 w += tmpW;
2426 tmpW = 0;
2427 lBreak.obj = o;
2428 lBreak.pos = pos;
weinigf28a1c32007-02-14 14:10:31 +00002429 // Auto-wrapping text should not wrap in the middle of a word once it has had an
2430 // opportunity to break after a word.
2431 breakWords = false;
hyatta9f48e32003-02-03 22:48:01 +00002432 }
hyatt33f8d492002-11-12 21:44:52 +00002433
darin54008922006-01-13 16:39:05 +00002434 if (midWordBreak) {
2435 // Remember this as a breakable position in case
2436 // adding the end width forces a break.
2437 lBreak.obj = o;
2438 lBreak.pos = pos;
weinigf28a1c32007-02-14 14:10:31 +00002439 midWordBreak &= breakWords;
darin54008922006-01-13 16:39:05 +00002440 } else {
2441 lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
2442 lastSpace = pos;
2443 }
hyatt33f8d492002-11-12 21:44:52 +00002444
hyattdca76e92005-11-02 08:52:50 +00002445 if (!ignoringSpaces && o->style()->collapseWhiteSpace()) {
hyatt33f8d492002-11-12 21:44:52 +00002446 // If we encounter a newline, or if we encounter a
2447 // second space, we need to go ahead and break up this
2448 // run and enter a mode where we start collapsing spaces.
hyatt98b16282004-03-31 18:43:12 +00002449 if (currentCharacterIsSpace && previousCharacterIsSpace) {
hyatt33f8d492002-11-12 21:44:52 +00002450 ignoringSpaces = true;
hyatt98b16282004-03-31 18:43:12 +00002451
hyatt33f8d492002-11-12 21:44:52 +00002452 // We just entered a mode where we are ignoring
2453 // spaces. Create a midpoint to terminate the run
2454 // before the second space.
hyatt98b16282004-03-31 18:43:12 +00002455 addMidpoint(ignoreStart);
hyatt33f8d492002-11-12 21:44:52 +00002456 }
2457 }
eseidel789896f2005-11-27 22:52:09 +00002458 } else if (ignoringSpaces) {
hyatt33f8d492002-11-12 21:44:52 +00002459 // Stop ignoring spaces and begin at this
2460 // new point.
2461 ignoringSpaces = false;
eseideld13fe532005-11-30 02:40:29 +00002462 lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
hyatt33f8d492002-11-12 21:44:52 +00002463 lastSpace = pos; // e.g., "Foo goo", don't add in any of the ignored spaces.
eseidel789896f2005-11-27 22:52:09 +00002464 BidiIterator startMid(0, o, pos);
hyatt85586af2003-02-19 23:22:42 +00002465 addMidpoint(startMid);
hyatt33f8d492002-11-12 21:44:52 +00002466 }
hyatt98b16282004-03-31 18:43:12 +00002467
2468 if (currentCharacterIsSpace && !previousCharacterIsSpace) {
2469 ignoreStart.obj = o;
2470 ignoreStart.pos = pos;
2471 }
harrisone343c412005-01-18 01:07:26 +00002472
2473 if (!currentCharacterIsWS && previousCharacterIsWS) {
hyattb0d9f602007-01-15 01:28:23 +00002474 if (autoWrap && o->style()->breakOnlyAfterWhiteSpace()) {
harrisone343c412005-01-18 01:07:26 +00002475 lBreak.obj = o;
2476 lBreak.pos = pos;
2477 }
2478 }
hyatt33f8d492002-11-12 21:44:52 +00002479
hyattb0d9f602007-01-15 01:28:23 +00002480 if (collapseWhiteSpace && currentCharacterIsSpace && !ignoringSpaces)
hyatt33f8d492002-11-12 21:44:52 +00002481 trailingSpaceObject = o;
hyattdca76e92005-11-02 08:52:50 +00002482 else if (!o->style()->collapseWhiteSpace() || !currentCharacterIsSpace)
hyatt33f8d492002-11-12 21:44:52 +00002483 trailingSpaceObject = 0;
2484
2485 pos++;
2486 len--;
2487 }
2488
kociendabb0c24b2001-08-24 14:24:40 +00002489 // IMPORTANT: pos is > length here!
hyatt33f8d492002-11-12 21:44:52 +00002490 if (!ignoringSpaces)
eseideld13fe532005-11-30 02:40:29 +00002491 tmpW += t->width(lastSpace, pos - lastSpace, f, w+tmpW) + lastSpaceWordSpacing;
weinigf28a1c32007-02-14 14:10:31 +00002492 tmpW += inlineWidth(o, !appliedStartWidth, true);
kociendabb0c24b2001-08-24 14:24:40 +00002493 } else
weinigf28a1c32007-02-14 14:10:31 +00002494 ASSERT_NOT_REACHED();
kociendabb0c24b2001-08-24 14:24:40 +00002495
hyatt275d0702005-11-03 23:53:57 +00002496 RenderObject* next = bidiNext(start.block, o, bidi);
hyattdca76e92005-11-02 08:52:50 +00002497 bool checkForBreak = autoWrap;
hyattb0d9f602007-01-15 01:28:23 +00002498 if (w && w + tmpW > width && lBreak.obj && currWS == NOWRAP)
hyatt74eec4d2003-03-23 08:02:47 +00002499 checkForBreak = true;
2500 else if (next && o->isText() && next->isText() && !next->isBR()) {
hyattdca76e92005-11-02 08:52:50 +00002501 if (autoWrap || (next->style()->autoWrap())) {
hyatta9f48e32003-02-03 22:48:01 +00002502 if (currentCharacterIsSpace)
2503 checkForBreak = true;
2504 else {
harrison07b5e582005-08-15 23:31:16 +00002505 checkForBreak = false;
hyatta9f48e32003-02-03 22:48:01 +00002506 RenderText* nextText = static_cast<RenderText*>(next);
darin42563ac52007-01-22 17:28:57 +00002507 if (nextText->textLength() != 0) {
2508 UChar c = nextText->characters()[0];
zimmermannac3781f2007-02-04 01:25:03 +00002509 if (c == ' ' || c == '\t' || (c == '\n' && !shouldPreserveNewline(next)))
eseideld13fe532005-11-30 02:40:29 +00002510 // If the next item on the line is text, and if we did not end with
2511 // a space, then the next text run continues our word (and so it needs to
2512 // keep adding to |tmpW|. Just update and continue.
2513 checkForBreak = true;
harrison07b5e582005-08-15 23:31:16 +00002514 }
ddkilzer5d01fa22007-01-29 03:10:37 +00002515 bool willFitOnLine = (w + tmpW <= width);
ddkilzere7605022007-01-31 12:51:30 +00002516 bool canPlaceOnLine = willFitOnLine || !willFitOnLine && !autoWrapWasEverTrueOnLine;
hyatta9f48e32003-02-03 22:48:01 +00002517 if (canPlaceOnLine && checkForBreak) {
2518 w += tmpW;
2519 tmpW = 0;
2520 lBreak.obj = next;
2521 lBreak.pos = 0;
2522 }
2523 }
2524 }
2525 }
2526
darin54008922006-01-13 16:39:05 +00002527 if (checkForBreak && (w + tmpW > width)) {
kociendabb0c24b2001-08-24 14:24:40 +00002528 // if we have floats, try to get below them.
hyattdca76e92005-11-02 08:52:50 +00002529 if (currentCharacterIsSpace && !ignoringSpaces && o->style()->collapseWhiteSpace())
hyatt33f8d492002-11-12 21:44:52 +00002530 trailingSpaceObject = 0;
hyatta14d1742003-01-02 20:25:46 +00002531
hyatte2b14092003-01-23 23:33:39 +00002532 int fb = nearestFloatBottom(m_height);
hyatt33f8d492002-11-12 21:44:52 +00002533 int newLineWidth = lineWidth(fb);
hyatt2df52192003-03-28 22:05:02 +00002534 // See if |tmpW| will fit on the new line. As long as it does not,
2535 // keep adjusting our float bottom until we find some room.
2536 int lastFloatBottom = m_height;
2537 while (lastFloatBottom < fb && tmpW > newLineWidth) {
2538 lastFloatBottom = fb;
2539 fb = nearestFloatBottom(fb);
2540 newLineWidth = lineWidth(fb);
2541 }
hyatt275d0702005-11-03 23:53:57 +00002542 if (!w && m_height < fb && width < newLineWidth) {
kociendabb0c24b2001-08-24 14:24:40 +00002543 m_height = fb;
darinb70665a2002-04-15 23:43:21 +00002544 width = newLineWidth;
kociendabb0c24b2001-08-24 14:24:40 +00002545 }
hyattf14a4a32002-11-21 22:06:32 +00002546
hyatta14d1742003-01-02 20:25:46 +00002547 // |width| may have been adjusted because we got shoved down past a float (thus
2548 // giving us more room), so we need to retest, and only jump to
2549 // the end label if we still don't fit on the line. -dwh
darin54008922006-01-13 16:39:05 +00002550 if (w + tmpW > width)
hyatta14d1742003-01-02 20:25:46 +00002551 goto end;
kociendabb0c24b2001-08-24 14:24:40 +00002552 }
hyatt1d9e29b2003-04-10 01:48:53 +00002553
hyattf14a4a32002-11-21 22:06:32 +00002554 last = o;
bdakin9151ba52005-10-24 22:51:06 +00002555 if (!o->isFloating() && (!o->isPositioned() || o->hasStaticX() || o->hasStaticY() || !o->container()->isInlineFlow()))
2556 previous = o;
hyatta9f48e32003-02-03 22:48:01 +00002557 o = next;
hyattf14a4a32002-11-21 22:06:32 +00002558
hyattb0d9f602007-01-15 01:28:23 +00002559 if (!last->isFloatingOrPositioned() && last->isReplaced() && autoWrap &&
mjsd26b2972007-02-13 13:09:04 +00002560 (!last->isListMarker() || static_cast<RenderListMarker*>(last)->isInside())) {
hyatt711fe232002-11-20 21:25:14 +00002561 w += tmpW;
2562 tmpW = 0;
2563 lBreak.obj = o;
2564 lBreak.pos = 0;
2565 }
2566
hyatta9f48e32003-02-03 22:48:01 +00002567 // Clear out our character space bool, since inline <pre>s don't collapse whitespace
2568 // with adjacent inline normal/nowrap spans.
hyattb0d9f602007-01-15 01:28:23 +00002569 if (!collapseWhiteSpace)
hyatta9f48e32003-02-03 22:48:01 +00002570 currentCharacterIsSpace = false;
2571
kociendabb0c24b2001-08-24 14:24:40 +00002572 pos = 0;
2573 }
2574
hyattb0d9f602007-01-15 01:28:23 +00002575
2576 if (w + tmpW <= width || lastWS == NOWRAP) {
kociendabb0c24b2001-08-24 14:24:40 +00002577 lBreak.obj = 0;
2578 lBreak.pos = 0;
2579 }
2580
2581 end:
rjwc9c257d2003-01-24 03:46:17 +00002582
hyatt275d0702005-11-03 23:53:57 +00002583 if (lBreak == start && !lBreak.obj->isBR()) {
kociendabb0c24b2001-08-24 14:24:40 +00002584 // we just add as much as possible
zimmermannac3781f2007-02-04 01:25:03 +00002585 if (shouldPreserveNewline(this)) {
hyattdca76e92005-11-02 08:52:50 +00002586 // FIXME: Don't really understand this case.
hyatt275d0702005-11-03 23:53:57 +00002587 if (pos != 0) {
kociendabb0c24b2001-08-24 14:24:40 +00002588 lBreak.obj = o;
2589 lBreak.pos = pos - 1;
2590 } else {
2591 lBreak.obj = last;
hyattc3731d42002-12-12 06:20:22 +00002592 lBreak.pos = last->isText() ? last->length() : 0;
kociendabb0c24b2001-08-24 14:24:40 +00002593 }
hyatt275d0702005-11-03 23:53:57 +00002594 } else if (lBreak.obj) {
2595 if (last != o && !last->isListMarker()) {
bdakina964eb32005-10-24 17:47:26 +00002596 // better to break between object boundaries than in the middle of a word (except for list markers)
hyatt33f8d492002-11-12 21:44:52 +00002597 lBreak.obj = o;
2598 lBreak.pos = 0;
2599 } else {
hyattdda1d1b2002-12-13 09:44:17 +00002600 // Don't ever break in the middle of a word if we can help it.
2601 // There's no room at all. We just have to be on this line,
2602 // even though we'll spill out.
2603 lBreak.obj = o;
2604 lBreak.pos = pos;
hyatt33f8d492002-11-12 21:44:52 +00002605 }
kociendabb0c24b2001-08-24 14:24:40 +00002606 }
2607 }
2608
2609 // make sure we consume at least one char/object.
hyatt275d0702005-11-03 23:53:57 +00002610 if (lBreak == start)
mjsfe301d72003-10-02 18:46:18 +00002611 lBreak.increment(bidi);
hyatt33f8d492002-11-12 21:44:52 +00002612
hyattfe99c872003-07-31 22:25:29 +00002613 // Sanity check our midpoints.
mjsfe301d72003-10-02 18:46:18 +00002614 checkMidpoints(lBreak, bidi);
hyattfe99c872003-07-31 22:25:29 +00002615
hyatt33f8d492002-11-12 21:44:52 +00002616 if (trailingSpaceObject) {
2617 // This object is either going to be part of the last midpoint, or it is going
2618 // to be the actual endpoint. In both cases we just decrease our pos by 1 level to
2619 // exclude the space, allowing it to - in effect - collapse into the newline.
hyatt85586af2003-02-19 23:22:42 +00002620 if (sNumMidpoints%2==1) {
2621 BidiIterator* midpoints = smidpoints->data();
2622 midpoints[sNumMidpoints-1].pos--;
hyatt33f8d492002-11-12 21:44:52 +00002623 }
2624 //else if (lBreak.pos > 0)
2625 // lBreak.pos--;
2626 else if (lBreak.obj == 0 && trailingSpaceObject->isText()) {
hyattd20075d2002-11-16 02:23:32 +00002627 // Add a new end midpoint that stops right at the very end.
hyattd20075d2002-11-16 02:23:32 +00002628 RenderText* text = static_cast<RenderText *>(trailingSpaceObject);
darin42563ac52007-01-22 17:28:57 +00002629 unsigned length = text->textLength();
2630 unsigned pos = length >= 2 ? length - 2 : UINT_MAX;
eseidel789896f2005-11-27 22:52:09 +00002631 BidiIterator endMid(0, trailingSpaceObject, pos);
hyatt85586af2003-02-19 23:22:42 +00002632 addMidpoint(endMid);
hyatt33f8d492002-11-12 21:44:52 +00002633 }
2634 }
rjwc9c257d2003-01-24 03:46:17 +00002635
mjs54b64002003-04-02 02:59:02 +00002636 // We might have made lBreak an iterator that points past the end
2637 // of the object. Do this adjustment to make it point to the start
2638 // of the next object instead to avoid confusing the rest of the
2639 // code.
2640 if (lBreak.pos > 0) {
darin54008922006-01-13 16:39:05 +00002641 lBreak.pos--;
2642 lBreak.increment(bidi);
mjs54b64002003-04-02 02:59:02 +00002643 }
2644
hyatt78b85132004-03-29 20:07:45 +00002645 if (lBreak.obj && lBreak.pos >= 2 && lBreak.obj->isText()) {
2646 // For soft hyphens on line breaks, we have to chop out the midpoints that made us
2647 // ignore the hyphen so that it will render at the end of the line.
darin42563ac52007-01-22 17:28:57 +00002648 UChar c = static_cast<RenderText*>(lBreak.obj)->characters()[lBreak.pos-1];
2649 if (c == softHyphen)
hyatt78b85132004-03-29 20:07:45 +00002650 chopMidpointsAt(lBreak.obj, lBreak.pos-2);
2651 }
2652
kociendabb0c24b2001-08-24 14:24:40 +00002653 return lBreak;
2654}
2655
hyattb4b20872004-10-20 21:34:01 +00002656void RenderBlock::checkLinesForOverflow()
2657{
hyattb4b20872004-10-20 21:34:01 +00002658 m_overflowWidth = m_width;
2659 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
darin7bd70952006-04-13 07:07:34 +00002660 m_overflowLeft = min(curr->leftOverflow(), m_overflowLeft);
2661 m_overflowTop = min(curr->topOverflow(), m_overflowTop);
2662 m_overflowWidth = max(curr->rightOverflow(), m_overflowWidth);
2663 m_overflowHeight = max(curr->bottomOverflow(), m_overflowHeight);
hyattb4b20872004-10-20 21:34:01 +00002664 }
2665}
2666
hyatted77ad82004-06-15 07:21:23 +00002667void RenderBlock::deleteEllipsisLineBoxes()
2668{
hyatted77ad82004-06-15 07:21:23 +00002669 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox())
hyattda77c4b2004-06-17 18:09:49 +00002670 curr->clearTruncation();
hyatted77ad82004-06-15 07:21:23 +00002671}
2672
2673void RenderBlock::checkLinesForTextOverflow()
2674{
2675 // Determine the width of the ellipsis using the current font.
darindbba2bb2007-01-11 12:23:49 +00002676 // FIXME: CSS3 says this is configurable, also need to use 0x002E (FULL STOP) if horizontal ellipsis is "not renderable"
2677 TextRun ellipsisRun(&horizontalEllipsis, 1);
2678 static AtomicString ellipsisStr(&horizontalEllipsis, 1);
hyatt3e99d1c2006-02-24 21:13:08 +00002679 const Font& firstLineFont = firstLineStyle()->font();
2680 const Font& font = style()->font();
hyatt43d6c792006-05-11 10:19:34 +00002681 int firstLineEllipsisWidth = firstLineFont.width(ellipsisRun);
2682 int ellipsisWidth = (font == firstLineFont) ? firstLineEllipsisWidth : font.width(ellipsisRun);
hyatted77ad82004-06-15 07:21:23 +00002683
2684 // For LTR text truncation, we want to get the right edge of our padding box, and then we want to see
2685 // if the right edge of a line box exceeds that. For RTL, we use the left edge of the padding box and
2686 // check the left edge of the line box to see if it is less
2687 // Include the scrollbar for overflow blocks, which means we want to use "contentWidth()"
2688 bool ltr = style()->direction() == LTR;
hyatted77ad82004-06-15 07:21:23 +00002689 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
hyattda77c4b2004-06-17 18:09:49 +00002690 int blockEdge = ltr ? rightOffset(curr->yPos()) : leftOffset(curr->yPos());
hyatt1a8d2512004-06-17 01:38:30 +00002691 int lineBoxEdge = ltr ? curr->xPos() + curr->width() : curr->xPos();
hyatted77ad82004-06-15 07:21:23 +00002692 if ((ltr && lineBoxEdge > blockEdge) || (!ltr && lineBoxEdge < blockEdge)) {
hyattf918d2d2004-06-15 07:24:11 +00002693 // 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 +00002694 // can be truncated. In order for truncation to be possible, the line must have sufficient space to
2695 // accommodate our truncation string, and no replaced elements (images, tables) can overlap the ellipsis
2696 // space.
2697 int width = curr == firstRootBox() ? firstLineEllipsisWidth : ellipsisWidth;
hyatt1a8d2512004-06-17 01:38:30 +00002698 if (curr->canAccommodateEllipsis(ltr, blockEdge, lineBoxEdge, width))
2699 curr->placeEllipsis(ellipsisStr, ltr, blockEdge, width);
hyatted77ad82004-06-15 07:21:23 +00002700 }
2701 }
2702}
2703
hyattffe78712003-02-11 01:59:29 +00002704}