blob: 529d7f066b52d4aca51e1f1818cb747c4132af99 [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"
darin36d11362006-04-11 16:30:21 +000032#include "RenderArena.h"
darinec375482007-01-06 01:36:24 +000033#include "RenderLayer.h"
hyattd8048342006-05-31 01:48:18 +000034#include "RenderView.h"
darin36d11362006-04-11 16:30:21 +000035#include "break_lines.h"
mjsbb863512006-05-09 09:27:55 +000036#include <wtf/AlwaysInline.h>
darin91298e52006-06-12 01:10:17 +000037#include <wtf/Vector.h>
hyatt8c371e52004-06-16 01:19:26 +000038
darin7bd70952006-04-13 07:07:34 +000039using namespace std;
darinf9e5d6c2007-01-09 14:54:26 +000040using namespace WTF;
41using namespace Unicode;
darin7bd70952006-04-13 07:07:34 +000042
darinb9481ed2006-03-20 02:57:59 +000043namespace WebCore {
mjsfe301d72003-10-02 18:46:18 +000044
hyatt275d0702005-11-03 23:53:57 +000045// an iterator which traverses all the objects within a block
darin7ab31092006-05-10 04:59:57 +000046struct BidiIterator {
hyatt275d0702005-11-03 23:53:57 +000047 BidiIterator() : block(0), obj(0), pos(0) {}
48 BidiIterator(RenderBlock* b, RenderObject* o, unsigned int p)
darin7ab31092006-05-10 04:59:57 +000049 : block(b), obj(o), pos(p) {}
hyattffe78712003-02-11 01:59:29 +000050
hyatt275d0702005-11-03 23:53:57 +000051 void increment(BidiState& state);
mjsfe301d72003-10-02 18:46:18 +000052 bool atEnd() const;
53
darin7ab31092006-05-10 04:59:57 +000054 UChar current() const;
darinf9e5d6c2007-01-09 14:54:26 +000055 Direction direction() const;
hyatt275d0702005-11-03 23:53:57 +000056
57 RenderBlock* block;
58 RenderObject* obj;
mjsfe301d72003-10-02 18:46:18 +000059 unsigned int pos;
60};
61
mjsfe301d72003-10-02 18:46:18 +000062struct BidiState {
darinf9e5d6c2007-01-09 14:54:26 +000063 BidiState() : context(0), dir(OtherNeutral), adjustEmbedding(false), reachedEndOfLine(false) {}
mjsfe301d72003-10-02 18:46:18 +000064
65 BidiIterator sor;
66 BidiIterator eor;
67 BidiIterator last;
68 BidiIterator current;
mjsbb3d15c2005-12-01 10:32:32 +000069 RefPtr<BidiContext> context;
mjsfe301d72003-10-02 18:46:18 +000070 BidiStatus status;
darinf9e5d6c2007-01-09 14:54:26 +000071 Direction dir;
hyatt275d0702005-11-03 23:53:57 +000072 bool adjustEmbedding;
eseidel789896f2005-11-27 22:52:09 +000073 BidiIterator endOfLine;
74 bool reachedEndOfLine;
darine4fa9e22005-12-16 18:18:50 +000075 BidiIterator lastBeforeET;
mjsfe301d72003-10-02 18:46:18 +000076};
hyatt2f1e7102003-02-20 01:27:03 +000077
eseidel789896f2005-11-27 22:52:09 +000078inline bool operator==(const BidiStatus& status1, const BidiStatus& status2)
79{
80 return status1.eor == status2.eor && status1.last == status2.last && status1.lastStrong == status2.lastStrong;
81}
82
83inline bool operator!=(const BidiStatus& status1, const BidiStatus& status2)
84{
85 return !(status1 == status2);
86}
87
hyatt2f1e7102003-02-20 01:27:03 +000088// Used to track a list of chained bidi runs.
mjsfe301d72003-10-02 18:46:18 +000089static BidiRun* sFirstBidiRun;
90static BidiRun* sLastBidiRun;
ddkilzerfe115062006-07-14 04:42:01 +000091static BidiRun* sLogicallyLastBidiRun;
mjsfe301d72003-10-02 18:46:18 +000092static int sBidiRunCount;
93static BidiRun* sCompactFirstBidiRun;
94static BidiRun* sCompactLastBidiRun;
95static int sCompactBidiRunCount;
96static bool sBuildingCompactRuns;
hyatt85586af2003-02-19 23:22:42 +000097
98// Midpoint globals. The goal is not to do any allocation when dealing with
99// these midpoints, so we just keep an array around and never clear it. We track
100// the number of items and position using the two other variables.
darin91298e52006-06-12 01:10:17 +0000101static Vector<BidiIterator>* smidpoints;
darinb9481ed2006-03-20 02:57:59 +0000102static unsigned sNumMidpoints;
103static unsigned sCurrMidpoint;
mjsfe301d72003-10-02 18:46:18 +0000104static bool betweenMidpoints;
hyatt85586af2003-02-19 23:22:42 +0000105
hyatt33f8d492002-11-12 21:44:52 +0000106static bool isLineEmpty = true;
hyatt0c3a9862004-02-23 21:26:26 +0000107static bool previousLineBrokeCleanly = true;
mjs6f821c82002-03-22 00:31:57 +0000108static bool emptyRun = true;
darinb70665a2002-04-15 23:43:21 +0000109static int numSpaces;
mjs6f821c82002-03-22 00:31:57 +0000110
darinf9e5d6c2007-01-09 14:54:26 +0000111static void embed(Direction, BidiState&);
darin7ab31092006-05-10 04:59:57 +0000112static void appendRun(BidiState&);
mjs6f821c82002-03-22 00:31:57 +0000113
adele68afa0b2007-02-05 23:25:44 +0000114void RenderBlock::bidiReorderCharacters(Document* document, RenderStyle* style, CharacterBuffer& characterBuffer)
115{
116 unsigned bufferLength = characterBuffer.size();
117 // Create a local copy of the buffer.
118 String string(characterBuffer.data(), bufferLength);
119
120 // Create anonymous RenderBlock
121 RenderStyle* blockStyle = new (document->renderArena()) RenderStyle();
122 blockStyle->inheritFrom(style);
123 blockStyle->setDisplay(BLOCK);
124 blockStyle->setWhiteSpace(PRE);
125 RenderBlock* block = new (document->renderArena()) RenderBlock(document);
126 block->setStyle(blockStyle);
127
128 // Create RenderText
129 RenderText* text = new (document->renderArena()) RenderText(document, string.impl());
130 text->setStyle(blockStyle);
131 block->addChild(text);
132
133 // Call bidiReorderLine
134 BidiState bidi;
adelefcfff3d2007-02-06 02:12:26 +0000135 PassRefPtr<BidiContext> startEmbed;
adele68afa0b2007-02-05 23:25:44 +0000136 if (style->direction() == LTR) {
137 startEmbed = new BidiContext(0, LeftToRight, NULL, style->unicodeBidi() == Override);
138 bidi.status.eor = LeftToRight;
139 } else {
140 startEmbed = new BidiContext(1, RightToLeft, NULL, style->unicodeBidi() == Override);
141 bidi.status.eor = RightToLeft;
142 }
143 bidi.status.lastStrong = startEmbed->dir();
144 bidi.status.last = startEmbed->dir();
145 bidi.status.eor = startEmbed->dir();
146 bidi.context = startEmbed;
147 bidi.dir = OtherNeutral;
148 betweenMidpoints = false;
149
150 block->bidiReorderLine(BidiIterator(block, text, 0), BidiIterator(block, text, bufferLength), bidi);
151
152 // Fill the characterBuffer.
153 int index = 0;
154 BidiRun* r = sFirstBidiRun;
155 while (r) {
156 bool reversed = r->reversed(style->visuallyOrdered());
157 // If there's only one run, and it doesn't need to be reversed, return early
158 if (sBidiRunCount == 1 && !reversed)
159 break;
160 for (int i = r->start; i < r->stop; ++i) {
161 if (reversed)
162 characterBuffer[index] = string[r->stop + r->start - i - 1];
163 else
164 characterBuffer[index] = string[i];
165 ++index;
166 }
167 r = r->nextRun;
168 }
169
170 // Tear down temporary RenderBlock and RenderText
171 block->removeChild(text);
172 text->destroy();
173 block->destroy();
174}
175
hyattffe78712003-02-11 01:59:29 +0000176static int getBPMWidth(int childValue, Length cssUnit)
177{
hyatt275d0702005-11-03 23:53:57 +0000178 if (!cssUnit.isIntrinsicOrAuto())
darin947a31b2006-02-24 03:08:41 +0000179 return (cssUnit.isFixed() ? cssUnit.value() : childValue);
hyattffe78712003-02-11 01:59:29 +0000180 return 0;
181}
182
183static int getBorderPaddingMargin(RenderObject* child, bool endOfInline)
184{
185 RenderStyle* cstyle = child->style();
186 int result = 0;
187 bool leftSide = (cstyle->direction() == LTR) ? !endOfInline : endOfInline;
188 result += getBPMWidth((leftSide ? child->marginLeft() : child->marginRight()),
189 (leftSide ? cstyle->marginLeft() :
190 cstyle->marginRight()));
191 result += getBPMWidth((leftSide ? child->paddingLeft() : child->paddingRight()),
192 (leftSide ? cstyle->paddingLeft() :
193 cstyle->paddingRight()));
194 result += leftSide ? child->borderLeft() : child->borderRight();
195 return result;
196}
197
198static int inlineWidth(RenderObject* child, bool start = true, bool end = true)
199{
200 int extraWidth = 0;
201 RenderObject* parent = child->parent();
hyatt450813d2003-07-25 20:22:34 +0000202 while (parent->isInline() && !parent->isInlineBlockOrInlineTable()) {
hyattffe78712003-02-11 01:59:29 +0000203 if (start && parent->firstChild() == child)
204 extraWidth += getBorderPaddingMargin(parent, false);
205 if (end && parent->lastChild() == child)
206 extraWidth += getBorderPaddingMargin(parent, true);
207 child = parent;
208 parent = child->parent();
209 }
210 return extraWidth;
211}
212
darin35355e52002-12-20 09:19:00 +0000213#ifndef NDEBUG
harrison0012ced2005-10-06 18:37:42 +0000214static bool inBidiRunDestroy;
hyattffe78712003-02-11 01:59:29 +0000215#endif
216
harrisone8363b42005-10-06 00:54:06 +0000217void BidiRun::destroy(RenderArena* renderArena)
hyattffe78712003-02-11 01:59:29 +0000218{
219#ifndef NDEBUG
harrison0012ced2005-10-06 18:37:42 +0000220 inBidiRunDestroy = true;
hyattffe78712003-02-11 01:59:29 +0000221#endif
222 delete this;
223#ifndef NDEBUG
harrison0012ced2005-10-06 18:37:42 +0000224 inBidiRunDestroy = false;
hyattffe78712003-02-11 01:59:29 +0000225#endif
226
227 // Recover the size left there for us by operator delete and free the memory.
228 renderArena->free(*(size_t *)this, this);
229}
230
231void* BidiRun::operator new(size_t sz, RenderArena* renderArena) throw()
232{
233 return renderArena->allocate(sz);
234}
235
236void BidiRun::operator delete(void* ptr, size_t sz)
237{
harrison0012ced2005-10-06 18:37:42 +0000238 assert(inBidiRunDestroy);
hyattffe78712003-02-11 01:59:29 +0000239
harrisone8363b42005-10-06 00:54:06 +0000240 // Stash size where destroy() can find it.
hyattffe78712003-02-11 01:59:29 +0000241 *(size_t*)ptr = sz;
242}
243
244static void deleteBidiRuns(RenderArena* arena)
245{
darinef0c09f2005-10-09 01:46:17 +0000246 emptyRun = true;
hyatt2f1e7102003-02-20 01:27:03 +0000247 if (!sFirstBidiRun)
hyattffe78712003-02-11 01:59:29 +0000248 return;
249
hyatt2f1e7102003-02-20 01:27:03 +0000250 BidiRun* curr = sFirstBidiRun;
251 while (curr) {
252 BidiRun* s = curr->nextRun;
harrisone8363b42005-10-06 00:54:06 +0000253 curr->destroy(arena);
hyatt2f1e7102003-02-20 01:27:03 +0000254 curr = s;
hyattffe78712003-02-11 01:59:29 +0000255 }
hyatt2f1e7102003-02-20 01:27:03 +0000256
257 sFirstBidiRun = 0;
258 sLastBidiRun = 0;
259 sBidiRunCount = 0;
hyattffe78712003-02-11 01:59:29 +0000260}
261
kociendabb0c24b2001-08-24 14:24:40 +0000262// ---------------------------------------------------------------------
263
264/* a small helper class used internally to resolve Bidi embedding levels.
265 Each line of text caches the embedding level at the start of the line for faster
266 relayouting
267*/
darinf9e5d6c2007-01-09 14:54:26 +0000268BidiContext::BidiContext(unsigned char l, Direction e, BidiContext *p, bool o)
mjs08191d52006-03-06 02:53:41 +0000269 : level(l), override(o), m_dir(e)
kociendabb0c24b2001-08-24 14:24:40 +0000270{
271 parent = p;
weinigda22cda2006-12-27 21:19:02 +0000272 if (p)
kociendabb0c24b2001-08-24 14:24:40 +0000273 p->ref();
kociendabb0c24b2001-08-24 14:24:40 +0000274 count = 0;
275}
276
277BidiContext::~BidiContext()
278{
hyatt275d0702005-11-03 23:53:57 +0000279 if (parent)
280 parent->deref();
kociendabb0c24b2001-08-24 14:24:40 +0000281}
282
283void BidiContext::ref() const
284{
285 count++;
286}
287
288void BidiContext::deref() const
289{
290 count--;
hyatt275d0702005-11-03 23:53:57 +0000291 if (count <= 0)
292 delete this;
kociendabb0c24b2001-08-24 14:24:40 +0000293}
294
eseidel789896f2005-11-27 22:52:09 +0000295bool operator==(const BidiContext& c1, const BidiContext& c2)
296{
297 if (&c1 == &c2)
298 return true;
weinigda22cda2006-12-27 21:19:02 +0000299 if (c1.level != c2.level || c1.override != c2.override || c1.dir() != c2.dir())
eseidel789896f2005-11-27 22:52:09 +0000300 return false;
eseidel6465a0f2006-01-10 13:35:45 +0000301 if (!c1.parent)
302 return !c2.parent;
303 return c2.parent && *c1.parent == *c2.parent;
eseidel789896f2005-11-27 22:52:09 +0000304}
305
306inline bool operator!=(const BidiContext& c1, const BidiContext& c2)
307{
308 return !(c1 == c2);
309}
310
kociendabb0c24b2001-08-24 14:24:40 +0000311// ---------------------------------------------------------------------
312
hyatt275d0702005-11-03 23:53:57 +0000313inline bool operator==(const BidiIterator& it1, const BidiIterator& it2)
darinb70665a2002-04-15 23:43:21 +0000314{
hyatt275d0702005-11-03 23:53:57 +0000315 if (it1.pos != it2.pos)
316 return false;
317 if (it1.obj != it2.obj)
318 return false;
darinb70665a2002-04-15 23:43:21 +0000319 return true;
320}
321
hyatt275d0702005-11-03 23:53:57 +0000322inline bool operator!=(const BidiIterator& it1, const BidiIterator& it2)
darinb70665a2002-04-15 23:43:21 +0000323{
hyatt275d0702005-11-03 23:53:57 +0000324 if (it1.pos != it2.pos)
325 return true;
326 if (it1.obj != it2.obj)
327 return true;
darinb70665a2002-04-15 23:43:21 +0000328 return false;
329}
330
hyatt275d0702005-11-03 23:53:57 +0000331static inline RenderObject* bidiNext(RenderBlock* block, RenderObject* current, BidiState& bidi,
hyattffe78712003-02-11 01:59:29 +0000332 bool skipInlines = true, bool* endOfInline = 0)
mjs6f821c82002-03-22 00:31:57 +0000333{
hyatt275d0702005-11-03 23:53:57 +0000334 RenderObject* next = 0;
hyattffe78712003-02-11 01:59:29 +0000335 bool oldEndOfInline = endOfInline ? *endOfInline : false;
336 if (endOfInline)
337 *endOfInline = false;
338
hyatt275d0702005-11-03 23:53:57 +0000339 while (current) {
sullivanabd4d032007-02-09 22:51:41 +0000340 next = 0;
hyattffe78712003-02-11 01:59:29 +0000341 if (!oldEndOfInline && !current->isFloating() && !current->isReplaced() && !current->isPositioned()) {
342 next = current->firstChild();
darindde01502005-12-18 22:55:35 +0000343 if (next && bidi.adjustEmbedding && next->isInlineFlow()) {
hyattffe78712003-02-11 01:59:29 +0000344 EUnicodeBidi ub = next->style()->unicodeBidi();
hyatt275d0702005-11-03 23:53:57 +0000345 if (ub != UBNormal) {
darin9d0a6282006-03-01 07:49:33 +0000346 TextDirection dir = next->style()->direction();
darinf9e5d6c2007-01-09 14:54:26 +0000347 Direction d = (ub == Embed
348 ? (dir == RTL ? RightToLeftEmbedding : LeftToRightEmbedding)
349 : (dir == RTL ? RightToLeftOverride : LeftToRightOverride));
hyatt275d0702005-11-03 23:53:57 +0000350 embed(d, bidi);
hyattffe78712003-02-11 01:59:29 +0000351 }
352 }
353 }
hyatt275d0702005-11-03 23:53:57 +0000354
hyattffe78712003-02-11 01:59:29 +0000355 if (!next) {
hyatt275d0702005-11-03 23:53:57 +0000356 if (!skipInlines && !oldEndOfInline && current->isInlineFlow()) {
hyattffe78712003-02-11 01:59:29 +0000357 next = current;
358 if (endOfInline)
359 *endOfInline = true;
360 break;
361 }
mjs6f821c82002-03-22 00:31:57 +0000362
hyatt275d0702005-11-03 23:53:57 +0000363 while (current && current != block) {
darindde01502005-12-18 22:55:35 +0000364 if (bidi.adjustEmbedding && current->isInlineFlow() && current->style()->unicodeBidi() != UBNormal)
darinf9e5d6c2007-01-09 14:54:26 +0000365 embed(PopDirectionalFormat, bidi);
hyatt275d0702005-11-03 23:53:57 +0000366
darindde01502005-12-18 22:55:35 +0000367 next = current->nextSibling();
368 if (next) {
369 if (bidi.adjustEmbedding && next->isInlineFlow()) {
370 EUnicodeBidi ub = next->style()->unicodeBidi();
371 if (ub != UBNormal) {
darin9d0a6282006-03-01 07:49:33 +0000372 TextDirection dir = next->style()->direction();
darinf9e5d6c2007-01-09 14:54:26 +0000373 Direction d = (ub == Embed
374 ? (dir == RTL ? RightToLeftEmbedding: LeftToRightEmbedding)
375 : (dir == RTL ? RightToLeftOverride : LeftToRightOverride));
darindde01502005-12-18 22:55:35 +0000376 embed(d, bidi);
377 }
378 }
379 break;
380 }
381
hyattffe78712003-02-11 01:59:29 +0000382 current = current->parent();
hyatt275d0702005-11-03 23:53:57 +0000383 if (!skipInlines && current && current != block && current->isInlineFlow()) {
hyattffe78712003-02-11 01:59:29 +0000384 next = current;
385 if (endOfInline)
386 *endOfInline = true;
387 break;
388 }
389 }
390 }
mjs6f821c82002-03-22 00:31:57 +0000391
hyatt275d0702005-11-03 23:53:57 +0000392 if (!next)
393 break;
hyattffe78712003-02-11 01:59:29 +0000394
395 if (next->isText() || next->isBR() || next->isFloating() || next->isReplaced() || next->isPositioned()
396 || ((!skipInlines || !next->firstChild()) // Always return EMPTY inlines.
397 && next->isInlineFlow()))
mjs6f821c82002-03-22 00:31:57 +0000398 break;
399 current = next;
400 }
401 return next;
402}
403
hyatt275d0702005-11-03 23:53:57 +0000404static RenderObject* bidiFirst(RenderBlock* block, BidiState& bidi, bool skipInlines = true )
mjs6f821c82002-03-22 00:31:57 +0000405{
hyatt275d0702005-11-03 23:53:57 +0000406 if (!block->firstChild())
407 return 0;
408
409 RenderObject* o = block->firstChild();
hyattffe78712003-02-11 01:59:29 +0000410 if (o->isInlineFlow()) {
darindde01502005-12-18 22:55:35 +0000411 if (bidi.adjustEmbedding) {
412 EUnicodeBidi ub = o->style()->unicodeBidi();
413 if (ub != UBNormal) {
darin9d0a6282006-03-01 07:49:33 +0000414 TextDirection dir = o->style()->direction();
darinf9e5d6c2007-01-09 14:54:26 +0000415 Direction d = (ub == Embed
416 ? (dir == RTL ? RightToLeftEmbedding : LeftToRightEmbedding)
417 : (dir == RTL ? RightToLeftOverride : LeftToRightOverride));
darindde01502005-12-18 22:55:35 +0000418 embed(d, bidi);
419 }
420 }
hyattffe78712003-02-11 01:59:29 +0000421 if (skipInlines && o->firstChild())
hyatt275d0702005-11-03 23:53:57 +0000422 o = bidiNext(block, o, bidi, skipInlines);
hyattffe78712003-02-11 01:59:29 +0000423 else
424 return o; // Never skip empty inlines.
425 }
hyattc5334f12003-08-08 22:26:08 +0000426
427 if (o && !o->isText() && !o->isBR() && !o->isReplaced() && !o->isFloating() && !o->isPositioned())
hyatt275d0702005-11-03 23:53:57 +0000428 o = bidiNext(block, o, bidi, skipInlines);
mjs6f821c82002-03-22 00:31:57 +0000429 return o;
430}
431
hyatt275d0702005-11-03 23:53:57 +0000432inline void BidiIterator::increment(BidiState& bidi)
kociendabb0c24b2001-08-24 14:24:40 +0000433{
hyatt275d0702005-11-03 23:53:57 +0000434 if (!obj)
435 return;
436 if (obj->isText()) {
kociendabb0c24b2001-08-24 14:24:40 +0000437 pos++;
darin42563ac52007-01-22 17:28:57 +0000438 if (pos >= static_cast<RenderText *>(obj)->textLength()) {
hyatt275d0702005-11-03 23:53:57 +0000439 obj = bidiNext(block, obj, bidi);
kociendabb0c24b2001-08-24 14:24:40 +0000440 pos = 0;
441 }
442 } else {
hyatt275d0702005-11-03 23:53:57 +0000443 obj = bidiNext(block, obj, bidi);
kociendabb0c24b2001-08-24 14:24:40 +0000444 pos = 0;
445 }
446}
447
mjs6f821c82002-03-22 00:31:57 +0000448inline bool BidiIterator::atEnd() const
kociendabb0c24b2001-08-24 14:24:40 +0000449{
hyatt275d0702005-11-03 23:53:57 +0000450 return !obj;
kociendabb0c24b2001-08-24 14:24:40 +0000451}
452
darin7ab31092006-05-10 04:59:57 +0000453UChar BidiIterator::current() const
kociendabb0c24b2001-08-24 14:24:40 +0000454{
hyatt30586b42003-12-02 23:19:11 +0000455 if (!obj || !obj->isText())
darin7ab31092006-05-10 04:59:57 +0000456 return 0;
hyatt30586b42003-12-02 23:19:11 +0000457
458 RenderText* text = static_cast<RenderText*>(obj);
darin42563ac52007-01-22 17:28:57 +0000459 if (!text->characters())
darin7ab31092006-05-10 04:59:57 +0000460 return 0;
hyatt30586b42003-12-02 23:19:11 +0000461
darin42563ac52007-01-22 17:28:57 +0000462 return text->characters()[pos];
kociendabb0c24b2001-08-24 14:24:40 +0000463}
464
darinf9e5d6c2007-01-09 14:54:26 +0000465ALWAYS_INLINE Direction BidiIterator::direction() const
kociendabb0c24b2001-08-24 14:24:40 +0000466{
hyatt5c18e1a2004-09-28 18:32:47 +0000467 if (!obj)
darinf9e5d6c2007-01-09 14:54:26 +0000468 return OtherNeutral;
hyatt5c18e1a2004-09-28 18:32:47 +0000469 if (obj->isListMarker())
darinf9e5d6c2007-01-09 14:54:26 +0000470 return obj->style()->direction() == LTR ? LeftToRight : RightToLeft;
hyatt5c18e1a2004-09-28 18:32:47 +0000471 if (!obj->isText())
darinf9e5d6c2007-01-09 14:54:26 +0000472 return OtherNeutral;
darin7ab31092006-05-10 04:59:57 +0000473 RenderText* renderTxt = static_cast<RenderText*>(obj);
darin42563ac52007-01-22 17:28:57 +0000474 if (pos >= renderTxt->textLength())
darinf9e5d6c2007-01-09 14:54:26 +0000475 return OtherNeutral;
darin42563ac52007-01-22 17:28:57 +0000476 return Unicode::direction(renderTxt->characters()[pos]);
kociendabb0c24b2001-08-24 14:24:40 +0000477}
478
kociendabb0c24b2001-08-24 14:24:40 +0000479// -------------------------------------------------------------------------------------------------
480
hyatt2f1e7102003-02-20 01:27:03 +0000481static void addRun(BidiRun* bidiRun)
482{
483 if (!sFirstBidiRun)
484 sFirstBidiRun = sLastBidiRun = bidiRun;
485 else {
486 sLastBidiRun->nextRun = bidiRun;
487 sLastBidiRun = bidiRun;
488 }
489 sBidiRunCount++;
hyatt4b381692003-03-10 21:11:59 +0000490 bidiRun->compact = sBuildingCompactRuns;
hyattfe99c872003-07-31 22:25:29 +0000491
492 // Compute the number of spaces in this run,
493 if (bidiRun->obj && bidiRun->obj->isText()) {
494 RenderText* text = static_cast<RenderText*>(bidiRun->obj);
darin42563ac52007-01-22 17:28:57 +0000495 if (text->characters()) {
hyattefebbdd2003-12-02 22:25:31 +0000496 for (int i = bidiRun->start; i < bidiRun->stop; i++) {
darin42563ac52007-01-22 17:28:57 +0000497 UChar c = text->characters()[i];
harrison208ea792005-07-29 23:42:59 +0000498 if (c == ' ' || c == '\n' || c == '\t')
hyattefebbdd2003-12-02 22:25:31 +0000499 numSpaces++;
500 }
darina3c48282003-10-07 15:49:30 +0000501 }
hyattfe99c872003-07-31 22:25:29 +0000502 }
hyatt2f1e7102003-02-20 01:27:03 +0000503}
504
505static void reverseRuns(int start, int end)
506{
507 if (start >= end)
508 return;
509
510 assert(start >= 0 && end < sBidiRunCount);
511
512 // Get the item before the start of the runs to reverse and put it in
513 // |beforeStart|. |curr| should point to the first run to reverse.
514 BidiRun* curr = sFirstBidiRun;
515 BidiRun* beforeStart = 0;
516 int i = 0;
517 while (i < start) {
518 i++;
519 beforeStart = curr;
520 curr = curr->nextRun;
521 }
522
hyatt793fbbc2003-02-26 02:38:01 +0000523 BidiRun* startRun = curr;
hyatt2f1e7102003-02-20 01:27:03 +0000524 while (i < end) {
hyatt793fbbc2003-02-26 02:38:01 +0000525 i++;
526 curr = curr->nextRun;
527 }
528 BidiRun* endRun = curr;
529 BidiRun* afterEnd = curr->nextRun;
530
531 i = start;
532 curr = startRun;
533 BidiRun* newNext = afterEnd;
534 while (i <= end) {
hyatt2f1e7102003-02-20 01:27:03 +0000535 // Do the reversal.
536 BidiRun* next = curr->nextRun;
hyatt793fbbc2003-02-26 02:38:01 +0000537 curr->nextRun = newNext;
538 newNext = curr;
hyatt2f1e7102003-02-20 01:27:03 +0000539 curr = next;
540 i++;
541 }
542
hyatt2f1e7102003-02-20 01:27:03 +0000543 // Now hook up beforeStart and afterEnd to the newStart and newEnd.
544 if (beforeStart)
hyatt793fbbc2003-02-26 02:38:01 +0000545 beforeStart->nextRun = endRun;
hyatt2f1e7102003-02-20 01:27:03 +0000546 else
hyatt793fbbc2003-02-26 02:38:01 +0000547 sFirstBidiRun = endRun;
hyatt2f1e7102003-02-20 01:27:03 +0000548
hyatt793fbbc2003-02-26 02:38:01 +0000549 startRun->nextRun = afterEnd;
hyatt2f1e7102003-02-20 01:27:03 +0000550 if (!afterEnd)
hyatt793fbbc2003-02-26 02:38:01 +0000551 sLastBidiRun = startRun;
hyatt2f1e7102003-02-20 01:27:03 +0000552}
553
darinb9481ed2006-03-20 02:57:59 +0000554static void chopMidpointsAt(RenderObject* obj, unsigned pos)
hyatt78b85132004-03-29 20:07:45 +0000555{
hyatt275d0702005-11-03 23:53:57 +0000556 if (!sNumMidpoints)
557 return;
hyatt78b85132004-03-29 20:07:45 +0000558 BidiIterator* midpoints = smidpoints->data();
darinb9481ed2006-03-20 02:57:59 +0000559 for (unsigned i = 0; i < sNumMidpoints; i++) {
hyatt78b85132004-03-29 20:07:45 +0000560 const BidiIterator& point = midpoints[i];
561 if (point.obj == obj && point.pos == pos) {
562 sNumMidpoints = i;
563 break;
564 }
565 }
566}
567
hyatt275d0702005-11-03 23:53:57 +0000568static void checkMidpoints(BidiIterator& lBreak, BidiState& bidi)
hyattfe99c872003-07-31 22:25:29 +0000569{
570 // Check to see if our last midpoint is a start point beyond the line break. If so,
hyattdca76e92005-11-02 08:52:50 +0000571 // shave it off the list, and shave off a trailing space if the previous end point doesn't
572 // preserve whitespace.
hyattfe99c872003-07-31 22:25:29 +0000573 if (lBreak.obj && sNumMidpoints && sNumMidpoints%2 == 0) {
574 BidiIterator* midpoints = smidpoints->data();
575 BidiIterator& endpoint = midpoints[sNumMidpoints-2];
576 const BidiIterator& startpoint = midpoints[sNumMidpoints-1];
577 BidiIterator currpoint = endpoint;
578 while (!currpoint.atEnd() && currpoint != startpoint && currpoint != lBreak)
hyatt275d0702005-11-03 23:53:57 +0000579 currpoint.increment(bidi);
hyattfe99c872003-07-31 22:25:29 +0000580 if (currpoint == lBreak) {
581 // We hit the line break before the start point. Shave off the start point.
582 sNumMidpoints--;
hyattdca76e92005-11-02 08:52:50 +0000583 if (endpoint.obj->style()->collapseWhiteSpace()) {
hyattee1bcae2004-03-29 21:36:04 +0000584 if (endpoint.obj->isText()) {
harrisona4d6cdc2006-10-02 15:32:17 +0000585 // Don't shave a character off the endpoint if it was from a soft hyphen.
hyattee1bcae2004-03-29 21:36:04 +0000586 RenderText* textObj = static_cast<RenderText*>(endpoint.obj);
darin42563ac52007-01-22 17:28:57 +0000587 if (endpoint.pos + 1 < textObj->textLength()) {
588 if (textObj->characters()[endpoint.pos+1] == softHyphen)
bdakin9151ba52005-10-24 22:51:06 +0000589 return;
590 } else if (startpoint.obj->isText()) {
591 RenderText *startText = static_cast<RenderText*>(startpoint.obj);
darin42563ac52007-01-22 17:28:57 +0000592 if (startText->textLength() && startText->characters()[0] == softHyphen)
bdakin9151ba52005-10-24 22:51:06 +0000593 return;
594 }
hyattee1bcae2004-03-29 21:36:04 +0000595 }
hyattfe99c872003-07-31 22:25:29 +0000596 endpoint.pos--;
hyattee1bcae2004-03-29 21:36:04 +0000597 }
hyattfe99c872003-07-31 22:25:29 +0000598 }
599 }
600}
601
hyatt85586af2003-02-19 23:22:42 +0000602static void addMidpoint(const BidiIterator& midpoint)
603{
604 if (!smidpoints)
605 return;
606
607 if (smidpoints->size() <= sNumMidpoints)
darin91298e52006-06-12 01:10:17 +0000608 smidpoints->resize(sNumMidpoints + 10);
hyatt85586af2003-02-19 23:22:42 +0000609
610 BidiIterator* midpoints = smidpoints->data();
611 midpoints[sNumMidpoints++] = midpoint;
612}
613
mjsfe301d72003-10-02 18:46:18 +0000614static void appendRunsForObject(int start, int end, RenderObject* obj, BidiState &bidi)
hyatt33f8d492002-11-12 21:44:52 +0000615{
hyatt98ee7e42003-05-14 01:39:15 +0000616 if (start > end || obj->isFloating() ||
hyatt853cd7d2004-11-05 02:59:48 +0000617 (obj->isPositioned() && !obj->hasStaticX() && !obj->hasStaticY() && !obj->container()->isInlineFlow()))
hyatteb003b82002-11-15 22:35:10 +0000618 return;
hyatt85586af2003-02-19 23:22:42 +0000619
620 bool haveNextMidpoint = (smidpoints && sCurrMidpoint < sNumMidpoints);
mjsfe301d72003-10-02 18:46:18 +0000621 BidiIterator nextMidpoint;
hyatt85586af2003-02-19 23:22:42 +0000622 if (haveNextMidpoint)
623 nextMidpoint = smidpoints->at(sCurrMidpoint);
hyatt33f8d492002-11-12 21:44:52 +0000624 if (betweenMidpoints) {
hyatt85586af2003-02-19 23:22:42 +0000625 if (!(haveNextMidpoint && nextMidpoint.obj == obj))
hyatt33f8d492002-11-12 21:44:52 +0000626 return;
627 // This is a new start point. Stop ignoring objects and
628 // adjust our start.
629 betweenMidpoints = false;
hyatt85586af2003-02-19 23:22:42 +0000630 start = nextMidpoint.pos;
631 sCurrMidpoint++;
hyatt33f8d492002-11-12 21:44:52 +0000632 if (start < end)
mjsfe301d72003-10-02 18:46:18 +0000633 return appendRunsForObject(start, end, obj, bidi);
hyatt33f8d492002-11-12 21:44:52 +0000634 }
635 else {
hyatt85586af2003-02-19 23:22:42 +0000636 if (!smidpoints || !haveNextMidpoint || (obj != nextMidpoint.obj)) {
eseidel789896f2005-11-27 22:52:09 +0000637 addRun(new (obj->renderArena()) BidiRun(start, end, obj, bidi.context.get(), bidi.dir));
hyatt33f8d492002-11-12 21:44:52 +0000638 return;
639 }
640
hyatt78b85132004-03-29 20:07:45 +0000641 // An end midpoint has been encountered within our object. We
hyatt33f8d492002-11-12 21:44:52 +0000642 // need to go ahead and append a run with our endpoint.
hyatt85586af2003-02-19 23:22:42 +0000643 if (int(nextMidpoint.pos+1) <= end) {
hyatt26179432002-11-17 01:57:27 +0000644 betweenMidpoints = true;
hyatt85586af2003-02-19 23:22:42 +0000645 sCurrMidpoint++;
hyattc64f9fc2003-03-14 01:25:59 +0000646 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 +0000647 if (int(nextMidpoint.pos+1) > start)
648 addRun(new (obj->renderArena())
eseidel789896f2005-11-27 22:52:09 +0000649 BidiRun(start, nextMidpoint.pos+1, obj, bidi.context.get(), bidi.dir));
mjsfe301d72003-10-02 18:46:18 +0000650 return appendRunsForObject(nextMidpoint.pos+1, end, obj, bidi);
hyattc64f9fc2003-03-14 01:25:59 +0000651 }
hyatt26179432002-11-17 01:57:27 +0000652 }
653 else
eseidel789896f2005-11-27 22:52:09 +0000654 addRun(new (obj->renderArena()) BidiRun(start, end, obj, bidi.context.get(), bidi.dir));
hyatt33f8d492002-11-12 21:44:52 +0000655 }
656}
657
hyatt275d0702005-11-03 23:53:57 +0000658static void appendRun(BidiState &bidi)
kociendabb0c24b2001-08-24 14:24:40 +0000659{
ggarenef026b22005-07-06 00:21:53 +0000660 if (emptyRun || !bidi.eor.obj)
661 return;
weinigf18aae32006-08-03 21:55:57 +0000662#if defined(BIDI_DEBUG) && BIDI_DEBUG > 1
kociendabb0c24b2001-08-24 14:24:40 +0000663 kdDebug(6041) << "appendRun: dir="<<(int)dir<<endl;
664#endif
darinf028f812002-06-10 20:08:04 +0000665
hyatt275d0702005-11-03 23:53:57 +0000666 bool b = bidi.adjustEmbedding;
667 bidi.adjustEmbedding = false;
kociendabb0c24b2001-08-24 14:24:40 +0000668
mjsfe301d72003-10-02 18:46:18 +0000669 int start = bidi.sor.pos;
670 RenderObject *obj = bidi.sor.obj;
eseidel789896f2005-11-27 22:52:09 +0000671 while (obj && obj != bidi.eor.obj && obj != bidi.endOfLine.obj) {
mjsfe301d72003-10-02 18:46:18 +0000672 appendRunsForObject(start, obj->length(), obj, bidi);
kociendabb0c24b2001-08-24 14:24:40 +0000673 start = 0;
hyatt275d0702005-11-03 23:53:57 +0000674 obj = bidiNext(bidi.sor.block, obj, bidi);
kociendabb0c24b2001-08-24 14:24:40 +0000675 }
justing5b0e0422005-08-01 03:20:49 +0000676 if (obj) {
eseidel789896f2005-11-27 22:52:09 +0000677 unsigned pos = obj == bidi.eor.obj ? bidi.eor.pos : UINT_MAX;
678 if (obj == bidi.endOfLine.obj && bidi.endOfLine.pos <= pos) {
679 bidi.reachedEndOfLine = true;
680 pos = bidi.endOfLine.pos;
681 }
justing5b0e0422005-08-01 03:20:49 +0000682 // 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 +0000683 int end = obj->length() ? pos+1 : 0;
justing5b0e0422005-08-01 03:20:49 +0000684 appendRunsForObject(start, end, obj, bidi);
685 }
hyatt33f8d492002-11-12 21:44:52 +0000686
hyatt275d0702005-11-03 23:53:57 +0000687 bidi.eor.increment(bidi);
mjsfe301d72003-10-02 18:46:18 +0000688 bidi.sor = bidi.eor;
darinf9e5d6c2007-01-09 14:54:26 +0000689 bidi.dir = OtherNeutral;
690 bidi.status.eor = OtherNeutral;
hyatt275d0702005-11-03 23:53:57 +0000691 bidi.adjustEmbedding = b;
mjs6f821c82002-03-22 00:31:57 +0000692}
693
darinf9e5d6c2007-01-09 14:54:26 +0000694static void embed(Direction d, BidiState& bidi)
mjs6f821c82002-03-22 00:31:57 +0000695{
hyatt275d0702005-11-03 23:53:57 +0000696 bool b = bidi.adjustEmbedding;
697 bidi.adjustEmbedding = false;
darinf9e5d6c2007-01-09 14:54:26 +0000698 if (d == PopDirectionalFormat) {
darin54008922006-01-13 16:39:05 +0000699 BidiContext *c = bidi.context->parent;
700 if (c) {
701 if (!emptyRun && bidi.eor != bidi.last) {
darinf9e5d6c2007-01-09 14:54:26 +0000702 assert(bidi.status.eor != OtherNeutral);
hyatt275d0702005-11-03 23:53:57 +0000703 // 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 +0000704 assert(bidi.status.last == EuropeanNumberSeparator
705 || bidi.status.last == EuropeanNumberTerminator
706 || bidi.status.last == CommonNumberSeparator
707 || bidi.status.last == BoundaryNeutral
708 || bidi.status.last == BlockSeparator
709 || bidi.status.last == SegmentSeparator
710 || bidi.status.last == WhiteSpaceNeutral
711 || bidi.status.last == OtherNeutral);
712 if (bidi.dir == OtherNeutral)
mjs08191d52006-03-06 02:53:41 +0000713 bidi.dir = bidi.context->dir();
darinf9e5d6c2007-01-09 14:54:26 +0000714 if (bidi.context->dir() == LeftToRight) {
hyatt275d0702005-11-03 23:53:57 +0000715 // bidi.sor ... bidi.eor ... bidi.last L
darinf9e5d6c2007-01-09 14:54:26 +0000716 if (bidi.status.eor == EuropeanNumber) {
717 if (bidi.status.lastStrong != LeftToRight) {
718 bidi.dir = EuropeanNumber;
hyatt275d0702005-11-03 23:53:57 +0000719 appendRun(bidi);
720 }
darinf9e5d6c2007-01-09 14:54:26 +0000721 } else if (bidi.status.eor == ArabicNumber) {
722 bidi.dir = ArabicNumber;
darinef0c09f2005-10-09 01:46:17 +0000723 appendRun(bidi);
darinf9e5d6c2007-01-09 14:54:26 +0000724 } else if (bidi.status.eor != LeftToRight)
hyatt275d0702005-11-03 23:53:57 +0000725 appendRun(bidi);
darinf9e5d6c2007-01-09 14:54:26 +0000726 } else if (bidi.status.eor != RightToLeft && bidi.status.eor != RightToLeftArabic)
darinef0c09f2005-10-09 01:46:17 +0000727 appendRun(bidi);
hyatt275d0702005-11-03 23:53:57 +0000728 bidi.eor = bidi.last;
729 }
darin54008922006-01-13 16:39:05 +0000730 appendRun(bidi);
731 emptyRun = true;
hyatt275d0702005-11-03 23:53:57 +0000732 // sor for the new run is determined by the higher level (rule X10)
mjs08191d52006-03-06 02:53:41 +0000733 bidi.status.last = bidi.context->dir();
734 bidi.status.lastStrong = bidi.context->dir();
darin54008922006-01-13 16:39:05 +0000735 bidi.context = c;
mjs08191d52006-03-06 02:53:41 +0000736 bidi.status.eor = bidi.context->dir();
hyatt275d0702005-11-03 23:53:57 +0000737 bidi.eor.obj = 0;
738 }
mjs6f821c82002-03-22 00:31:57 +0000739 } else {
darinf9e5d6c2007-01-09 14:54:26 +0000740 Direction runDir;
741 if (d == RightToLeftEmbedding || d == RightToLeftOverride)
742 runDir = RightToLeft;
darin54008922006-01-13 16:39:05 +0000743 else
darinf9e5d6c2007-01-09 14:54:26 +0000744 runDir = LeftToRight;
745 bool override = d == LeftToRightOverride || d == RightToLeftOverride;
mjs6f821c82002-03-22 00:31:57 +0000746
darin54008922006-01-13 16:39:05 +0000747 unsigned char level = bidi.context->level;
darinf9e5d6c2007-01-09 14:54:26 +0000748 if (runDir == RightToLeft) {
darin54008922006-01-13 16:39:05 +0000749 if (level%2) // we have an odd level
750 level += 2;
751 else
752 level++;
753 } else {
754 if (level%2) // we have an odd level
755 level++;
756 else
757 level += 2;
758 }
mjs6f821c82002-03-22 00:31:57 +0000759
darin54008922006-01-13 16:39:05 +0000760 if (level < 61) {
761 if (!emptyRun && bidi.eor != bidi.last) {
darinf9e5d6c2007-01-09 14:54:26 +0000762 assert(bidi.status.eor != OtherNeutral);
hyatt275d0702005-11-03 23:53:57 +0000763 // 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 +0000764 assert(bidi.status.last == EuropeanNumberSeparator
765 || bidi.status.last == EuropeanNumberTerminator
766 || bidi.status.last == CommonNumberSeparator
767 || bidi.status.last == BoundaryNeutral
768 || bidi.status.last == BlockSeparator
769 || bidi.status.last == SegmentSeparator
770 || bidi.status.last == WhiteSpaceNeutral
771 || bidi.status.last == OtherNeutral);
772 if (bidi.dir == OtherNeutral)
hyatt275d0702005-11-03 23:53:57 +0000773 bidi.dir = runDir;
darinf9e5d6c2007-01-09 14:54:26 +0000774 if (runDir == LeftToRight) {
hyatt275d0702005-11-03 23:53:57 +0000775 // bidi.sor ... bidi.eor ... bidi.last L
darinf9e5d6c2007-01-09 14:54:26 +0000776 if (bidi.status.eor == EuropeanNumber) {
777 if (bidi.status.lastStrong != LeftToRight) {
778 bidi.dir = EuropeanNumber;
hyatt275d0702005-11-03 23:53:57 +0000779 appendRun(bidi);
darinf9e5d6c2007-01-09 14:54:26 +0000780 if (bidi.context->dir() != LeftToRight)
781 bidi.dir = RightToLeft;
hyatt275d0702005-11-03 23:53:57 +0000782 }
darinf9e5d6c2007-01-09 14:54:26 +0000783 } else if (bidi.status.eor == ArabicNumber) {
784 bidi.dir = ArabicNumber;
darinef0c09f2005-10-09 01:46:17 +0000785 appendRun(bidi);
darinf9e5d6c2007-01-09 14:54:26 +0000786 if (bidi.context->dir() != LeftToRight) {
hyatt275d0702005-11-03 23:53:57 +0000787 bidi.eor = bidi.last;
darinf9e5d6c2007-01-09 14:54:26 +0000788 bidi.dir = RightToLeft;
hyatt275d0702005-11-03 23:53:57 +0000789 appendRun(bidi);
790 }
darinf9e5d6c2007-01-09 14:54:26 +0000791 } else if (bidi.status.eor != LeftToRight) {
792 if (bidi.context->dir() == LeftToRight || bidi.status.lastStrong == LeftToRight)
hyatt275d0702005-11-03 23:53:57 +0000793 appendRun(bidi);
794 else
darinf9e5d6c2007-01-09 14:54:26 +0000795 bidi.dir = RightToLeft;
darinef0c09f2005-10-09 01:46:17 +0000796 }
darinf9e5d6c2007-01-09 14:54:26 +0000797 } else if (bidi.status.eor != RightToLeft && bidi.status.eor != RightToLeftArabic) {
hyatt275d0702005-11-03 23:53:57 +0000798 // 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 +0000799 if (bidi.context->dir() == RightToLeft || bidi.status.lastStrong == RightToLeft || bidi.status.lastStrong == RightToLeftArabic)
darinef0c09f2005-10-09 01:46:17 +0000800 appendRun(bidi);
801 else
darinf9e5d6c2007-01-09 14:54:26 +0000802 bidi.dir = LeftToRight;
darinef0c09f2005-10-09 01:46:17 +0000803 }
hyatt275d0702005-11-03 23:53:57 +0000804 bidi.eor = bidi.last;
hyatt2f1e7102003-02-20 01:27:03 +0000805 }
hyatt275d0702005-11-03 23:53:57 +0000806 appendRun(bidi);
807 emptyRun = true;
eseidel789896f2005-11-27 22:52:09 +0000808 bidi.context = new BidiContext(level, runDir, bidi.context.get(), override);
hyatt275d0702005-11-03 23:53:57 +0000809 bidi.status.last = runDir;
810 bidi.status.lastStrong = runDir;
811 bidi.status.eor = runDir;
812 bidi.eor.obj = 0;
darinef0c09f2005-10-09 01:46:17 +0000813 }
mjs6f821c82002-03-22 00:31:57 +0000814 }
hyatt275d0702005-11-03 23:53:57 +0000815 bidi.adjustEmbedding = b;
kociendabb0c24b2001-08-24 14:24:40 +0000816}
817
hyattffe78712003-02-11 01:59:29 +0000818InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj)
819{
820 // See if we have an unconstructed line box for this object that is also
821 // the last item on the line.
darinb53ebdc2006-07-09 15:10:21 +0000822 ASSERT(obj->isInlineFlow() || obj == this);
hyattffe78712003-02-11 01:59:29 +0000823 RenderFlow* flow = static_cast<RenderFlow*>(obj);
824
825 // Get the last box we made for this render object.
826 InlineFlowBox* box = flow->lastLineBox();
827
828 // If this box is constructed then it is from a previous line, and we need
829 // to make a new box for our line. If this box is unconstructed but it has
830 // something following it on the line, then we know we have to make a new box
831 // as well. In this situation our inline has actually been split in two on
832 // the same line (this can happen with very fancy language mixtures).
833 if (!box || box->isConstructed() || box->nextOnLine()) {
834 // We need to make a new box for this render object. Once
835 // made, we need to place it at the end of the current line.
hyatt450813d2003-07-25 20:22:34 +0000836 InlineBox* newBox = obj->createInlineBox(false, obj == this);
darinb53ebdc2006-07-09 15:10:21 +0000837 ASSERT(newBox->isInlineFlowBox());
hyattffe78712003-02-11 01:59:29 +0000838 box = static_cast<InlineFlowBox*>(newBox);
839 box->setFirstLineStyleBit(m_firstLine);
840
841 // We have a new box. Append it to the inline box we get by constructing our
842 // parent. If we have hit the block itself, then |box| represents the root
843 // inline box for the line, and it doesn't have to be appended to any parent
844 // inline.
845 if (obj != this) {
846 InlineFlowBox* parentBox = createLineBoxes(obj->parent());
847 parentBox->addToLine(box);
848 }
849 }
850
851 return box;
852}
853
hyatt275d0702005-11-03 23:53:57 +0000854RootInlineBox* RenderBlock::constructLine(const BidiIterator& start, const BidiIterator& end)
hyattffe78712003-02-11 01:59:29 +0000855{
hyatt2f1e7102003-02-20 01:27:03 +0000856 if (!sFirstBidiRun)
hyattffe78712003-02-11 01:59:29 +0000857 return 0; // We had no runs. Don't make a root inline box at all. The line is empty.
858
859 InlineFlowBox* parentBox = 0;
hyatt2f1e7102003-02-20 01:27:03 +0000860 for (BidiRun* r = sFirstBidiRun; r; r = r->nextRun) {
hyattffe78712003-02-11 01:59:29 +0000861 // Create a box for our object.
harrison8d773e72006-01-29 15:06:17 +0000862 bool isOnlyRun = (sBidiRunCount == 1);
863 if (sBidiRunCount == 2 && !r->obj->isListMarker())
864 isOnlyRun = ((style()->direction() == RTL) ? sLastBidiRun : sFirstBidiRun)->obj->isListMarker();
865 r->box = r->obj->createInlineBox(r->obj->isPositioned(), false, isOnlyRun);
hyatt0c3a9862004-02-23 21:26:26 +0000866 if (r->box) {
867 // If we have no parent box yet, or if the run is not simply a sibling,
868 // then we need to construct inline boxes as necessary to properly enclose the
869 // run's inline box.
hyatt275d0702005-11-03 23:53:57 +0000870 if (!parentBox || parentBox->object() != r->obj->parent())
hyatt0c3a9862004-02-23 21:26:26 +0000871 // Create new inline boxes all the way back to the appropriate insertion point.
872 parentBox = createLineBoxes(r->obj->parent());
hyattffe78712003-02-11 01:59:29 +0000873
hyatt0c3a9862004-02-23 21:26:26 +0000874 // Append the inline box to this line.
875 parentBox->addToLine(r->box);
darin06dcb9c2005-08-15 04:31:09 +0000876
877 if (r->box->isInlineTextBox()) {
878 InlineTextBox *text = static_cast<InlineTextBox*>(r->box);
879 text->setStart(r->start);
adele80407612006-07-28 05:13:24 +0000880 text->setLen(r->stop - r->start);
881 bool visuallyOrdered = r->obj->style()->visuallyOrdered();
adele68afa0b2007-02-05 23:25:44 +0000882 text->m_reversed = r->reversed(visuallyOrdered);
883 text->m_dirOverride = r->dirOverride(visuallyOrdered);
darin06dcb9c2005-08-15 04:31:09 +0000884 }
hyatt0c3a9862004-02-23 21:26:26 +0000885 }
hyattffe78712003-02-11 01:59:29 +0000886 }
887
888 // We should have a root inline box. It should be unconstructed and
889 // be the last continuation of our line list.
hyatt275d0702005-11-03 23:53:57 +0000890 assert(lastLineBox() && !lastLineBox()->isConstructed());
hyattffe78712003-02-11 01:59:29 +0000891
892 // Set bits on our inline flow boxes that indicate which sides should
893 // paint borders/margins/padding. This knowledge will ultimately be used when
894 // we determine the horizontal positions and widths of all the inline boxes on
895 // the line.
896 RenderObject* endObject = 0;
897 bool lastLine = !end.obj;
898 if (end.obj && end.pos == 0)
899 endObject = end.obj;
900 lastLineBox()->determineSpacingForFlowBoxes(lastLine, endObject);
901
902 // Now mark the line boxes as being constructed.
903 lastLineBox()->setConstructed();
904
905 // Return the last line.
hyatt0c3a9862004-02-23 21:26:26 +0000906 return lastRootBox();
hyattffe78712003-02-11 01:59:29 +0000907}
908
harrison208ea792005-07-29 23:42:59 +0000909// usage: tw - (xpos % tw);
910int RenderBlock::tabWidth(bool isWhitespacePre)
911{
912 if (!isWhitespacePre)
913 return 0;
914
adele1a307da2006-06-01 06:30:08 +0000915 if (m_tabWidth == -1) {
darin7ab31092006-05-10 04:59:57 +0000916 const UChar spaceChar = ' ';
hyatt3e99d1c2006-02-24 21:13:08 +0000917 const Font& font = style()->font();
hyatt43d6c792006-05-11 10:19:34 +0000918 int spaceWidth = font.width(TextRun(&spaceChar, 1));
harrison208ea792005-07-29 23:42:59 +0000919 m_tabWidth = spaceWidth * 8;
harrison208ea792005-07-29 23:42:59 +0000920 }
921
922 return m_tabWidth;
923}
924
hyatt275d0702005-11-03 23:53:57 +0000925void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, BidiState& bidi)
hyattffe78712003-02-11 01:59:29 +0000926{
927 // First determine our total width.
kociendae40cb942004-10-05 20:05:38 +0000928 int availableWidth = lineWidth(m_height);
hyattffe78712003-02-11 01:59:29 +0000929 int totWidth = lineBox->getFlowSpacingWidth();
hyatt2f1e7102003-02-20 01:27:03 +0000930 BidiRun* r = 0;
darin06dcb9c2005-08-15 04:31:09 +0000931 bool needsWordSpacing = false;
hyatt2f1e7102003-02-20 01:27:03 +0000932 for (r = sFirstBidiRun; r; r = r->nextRun) {
hyatt0c05e102006-04-14 08:15:00 +0000933 if (!r->box || r->obj->isPositioned() || r->box->isLineBreak())
hyatt98ee7e42003-05-14 01:39:15 +0000934 continue; // Positioned objects are only participating to figure out their
935 // correct static x position. They have no effect on the width.
hyatt0c05e102006-04-14 08:15:00 +0000936 // Similarly, line break boxes have no effect on the width.
kociendae40cb942004-10-05 20:05:38 +0000937 if (r->obj->isText()) {
ddkilzerfe115062006-07-14 04:42:01 +0000938 RenderText* rt = static_cast<RenderText*>(r->obj);
darin06dcb9c2005-08-15 04:31:09 +0000939 int textWidth = rt->width(r->start, r->stop-r->start, totWidth, m_firstLine);
940 int effectiveWidth = textWidth;
darin42563ac52007-01-22 17:28:57 +0000941 int rtLength = rt->textLength();
darin06dcb9c2005-08-15 04:31:09 +0000942 if (rtLength != 0) {
darin42563ac52007-01-22 17:28:57 +0000943 if (r->start == 0 && needsWordSpacing && DeprecatedChar(rt->characters()[r->start]).isSpace())
944 effectiveWidth += rt->style(m_firstLine)->font().wordSpacing();
945 needsWordSpacing = !DeprecatedChar(rt->characters()[r->stop-1]).isSpace() && r->stop == rtLength;
darin06dcb9c2005-08-15 04:31:09 +0000946 }
kociendaee701982004-10-05 23:06:58 +0000947 r->box->setWidth(textWidth);
darin06dcb9c2005-08-15 04:31:09 +0000948 } else if (!r->obj->isInlineFlow()) {
hyattffe78712003-02-11 01:59:29 +0000949 r->obj->calcWidth();
950 r->box->setWidth(r->obj->width());
hyatt4b381692003-03-10 21:11:59 +0000951 if (!r->compact)
darin06dcb9c2005-08-15 04:31:09 +0000952 totWidth += r->obj->marginLeft() + r->obj->marginRight();
hyattffe78712003-02-11 01:59:29 +0000953 }
hyatt4b381692003-03-10 21:11:59 +0000954
955 // Compacts don't contribute to the width of the line, since they are placed in the margin.
956 if (!r->compact)
957 totWidth += r->box->width();
hyattffe78712003-02-11 01:59:29 +0000958 }
959
ddkilzerfe115062006-07-14 04:42:01 +0000960 if (totWidth > availableWidth && sLogicallyLastBidiRun->obj->style(m_firstLine)->autoWrap() &&
961 sLogicallyLastBidiRun->obj->style(m_firstLine)->breakOnlyAfterWhiteSpace() &&
962 !sLogicallyLastBidiRun->compact) {
963 sLogicallyLastBidiRun->box->setWidth(sLogicallyLastBidiRun->box->width() - totWidth + availableWidth);
964 totWidth = availableWidth;
965 }
966
hyattffe78712003-02-11 01:59:29 +0000967 // Armed with the total width of the line (without justification),
968 // we now examine our text-align property in order to determine where to position the
969 // objects horizontally. The total width of the line can be increased if we end up
970 // justifying text.
971 int x = leftOffset(m_height);
hyattffe78712003-02-11 01:59:29 +0000972 switch(style()->textAlign()) {
973 case LEFT:
hyatt47c1d4d2003-07-24 22:07:45 +0000974 case KHTML_LEFT:
hyatt959a54e2004-09-27 17:52:18 +0000975 // The direction of the block should determine what happens with wide lines. In
976 // particular with RTL blocks, wide lines should still spill out to the left.
977 if (style()->direction() == RTL && totWidth > availableWidth)
978 x -= (totWidth - availableWidth);
hyattffe78712003-02-11 01:59:29 +0000979 numSpaces = 0;
980 break;
981 case JUSTIFY:
hyatt0c3a9862004-02-23 21:26:26 +0000982 if (numSpaces != 0 && !bidi.current.atEnd() && !lineBox->endsWithBreak())
hyattffe78712003-02-11 01:59:29 +0000983 break;
984 // fall through
985 case TAAUTO:
986 numSpaces = 0;
987 // for right to left fall through to right aligned
weinigda22cda2006-12-27 21:19:02 +0000988 if (style()->direction() == LTR)
hyattffe78712003-02-11 01:59:29 +0000989 break;
990 case RIGHT:
hyatt47c1d4d2003-07-24 22:07:45 +0000991 case KHTML_RIGHT:
hyatt959a54e2004-09-27 17:52:18 +0000992 // Wide lines spill out of the block based off direction.
993 // So even if text-align is right, if direction is LTR, wide lines should overflow out of the right
994 // side of the block.
995 if (style()->direction() == RTL || totWidth < availableWidth)
996 x += availableWidth - totWidth;
hyattffe78712003-02-11 01:59:29 +0000997 numSpaces = 0;
998 break;
999 case CENTER:
hyatt47c1d4d2003-07-24 22:07:45 +00001000 case KHTML_CENTER:
hyattffe78712003-02-11 01:59:29 +00001001 int xd = (availableWidth - totWidth)/2;
eseidel789896f2005-11-27 22:52:09 +00001002 x += xd > 0 ? xd : 0;
hyattffe78712003-02-11 01:59:29 +00001003 numSpaces = 0;
1004 break;
1005 }
1006
hyattacbb0d42003-04-25 01:32:49 +00001007 if (numSpaces > 0) {
1008 for (r = sFirstBidiRun; r; r = r->nextRun) {
hyatt0c3a9862004-02-23 21:26:26 +00001009 if (!r->box) continue;
1010
hyattacbb0d42003-04-25 01:32:49 +00001011 int spaceAdd = 0;
1012 if (numSpaces > 0 && r->obj->isText() && !r->compact) {
1013 // get the number of spaces in the run
1014 int spaces = 0;
darina3c48282003-10-07 15:49:30 +00001015 for ( int i = r->start; i < r->stop; i++ ) {
darin42563ac52007-01-22 17:28:57 +00001016 UChar c = static_cast<RenderText*>(r->obj)->characters()[i];
harrison208ea792005-07-29 23:42:59 +00001017 if (c == ' ' || c == '\n' || c == '\t')
hyattacbb0d42003-04-25 01:32:49 +00001018 spaces++;
darina3c48282003-10-07 15:49:30 +00001019 }
hyatt870bdda2003-05-21 23:37:33 +00001020
darinb53ebdc2006-07-09 15:10:21 +00001021 ASSERT(spaces <= numSpaces);
hyatt870bdda2003-05-21 23:37:33 +00001022
hyattdca76e92005-11-02 08:52:50 +00001023 // Only justify text if whitespace is collapsed.
1024 if (r->obj->style()->collapseWhiteSpace()) {
hyatt870bdda2003-05-21 23:37:33 +00001025 spaceAdd = (availableWidth - totWidth)*spaces/numSpaces;
kocienda01bcc352003-09-25 16:51:11 +00001026 static_cast<InlineTextBox*>(r->box)->setSpaceAdd(spaceAdd);
hyatt870bdda2003-05-21 23:37:33 +00001027 totWidth += spaceAdd;
1028 }
hyattacbb0d42003-04-25 01:32:49 +00001029 numSpaces -= spaces;
hyattacbb0d42003-04-25 01:32:49 +00001030 }
hyattffe78712003-02-11 01:59:29 +00001031 }
hyattffe78712003-02-11 01:59:29 +00001032 }
hyattacbb0d42003-04-25 01:32:49 +00001033
hyattffe78712003-02-11 01:59:29 +00001034 // The widths of all runs are now known. We can now place every inline box (and
1035 // compute accurate widths for the inline flow boxes).
hyatt1f14a612004-12-07 00:34:02 +00001036 int leftPosition = x;
1037 int rightPosition = x;
darin06dcb9c2005-08-15 04:31:09 +00001038 needsWordSpacing = false;
1039 lineBox->placeBoxesHorizontally(x, leftPosition, rightPosition, needsWordSpacing);
hyatt1f14a612004-12-07 00:34:02 +00001040 lineBox->setHorizontalOverflowPositions(leftPosition, rightPosition);
hyattffe78712003-02-11 01:59:29 +00001041}
1042
hyatt0c3a9862004-02-23 21:26:26 +00001043void RenderBlock::computeVerticalPositionsForLine(RootInlineBox* lineBox)
hyattffe78712003-02-11 01:59:29 +00001044{
1045 lineBox->verticallyAlignBoxes(m_height);
hyatt0c3a9862004-02-23 21:26:26 +00001046 lineBox->setBlockHeight(m_height);
hyattffe78712003-02-11 01:59:29 +00001047
hyatt35a85e52003-02-14 19:43:07 +00001048 // See if the line spilled out. If so set overflow height accordingly.
1049 int bottomOfLine = lineBox->bottomOverflow();
1050 if (bottomOfLine > m_height && bottomOfLine > m_overflowHeight)
1051 m_overflowHeight = bottomOfLine;
1052
hyattffe78712003-02-11 01:59:29 +00001053 // Now make sure we place replaced render objects correctly.
hyatt98ee7e42003-05-14 01:39:15 +00001054 for (BidiRun* r = sFirstBidiRun; r; r = r->nextRun) {
eseidel789896f2005-11-27 22:52:09 +00001055 if (!r->box)
1056 continue; // Skip runs with no line boxes.
hyatt0c3a9862004-02-23 21:26:26 +00001057
hyatt98ee7e42003-05-14 01:39:15 +00001058 // Align positioned boxes with the top of the line box. This is
1059 // a reasonable approximation of an appropriate y position.
1060 if (r->obj->isPositioned())
1061 r->box->setYPos(m_height);
1062
1063 // Position is used to properly position both replaced elements and
1064 // to update the static normal flow x/y of positioned elements.
adele80407612006-07-28 05:13:24 +00001065 r->obj->position(r->box);
hyatt98ee7e42003-05-14 01:39:15 +00001066 }
hyattffe78712003-02-11 01:59:29 +00001067}
kociendabb0c24b2001-08-24 14:24:40 +00001068
1069// collects one line of the paragraph and transforms it to visual order
hyatt275d0702005-11-03 23:53:57 +00001070void RenderBlock::bidiReorderLine(const BidiIterator& start, const BidiIterator& end, BidiState& bidi)
kociendabb0c24b2001-08-24 14:24:40 +00001071{
hyatt275d0702005-11-03 23:53:57 +00001072 if (start == end) {
1073 if (start.current() == '\n')
1074 m_height += lineHeight(m_firstLine, true);
hyatt33f8d492002-11-12 21:44:52 +00001075 return;
darinb70665a2002-04-15 23:43:21 +00001076 }
hyattffe78712003-02-11 01:59:29 +00001077
hyatt2f1e7102003-02-20 01:27:03 +00001078 sFirstBidiRun = 0;
1079 sLastBidiRun = 0;
1080 sBidiRunCount = 0;
rjw834c8062005-02-25 23:41:39 +00001081
darinf9e5d6c2007-01-09 14:54:26 +00001082 assert(bidi.dir == OtherNeutral);
eseidel789896f2005-11-27 22:52:09 +00001083
mjs6f821c82002-03-22 00:31:57 +00001084 emptyRun = true;
eseidel789896f2005-11-27 22:52:09 +00001085
ggarenef026b22005-07-06 00:21:53 +00001086 bidi.eor.obj = 0;
darinf028f812002-06-10 20:08:04 +00001087
darinb70665a2002-04-15 23:43:21 +00001088 numSpaces = 0;
kociendabb0c24b2001-08-24 14:24:40 +00001089
mjsfe301d72003-10-02 18:46:18 +00001090 bidi.current = start;
1091 bidi.last = bidi.current;
eseidel789896f2005-11-27 22:52:09 +00001092 bool pastEnd = false;
eseidel789896f2005-11-27 22:52:09 +00001093 BidiState stateAtEnd;
rjw834c8062005-02-25 23:41:39 +00001094
hyatt275d0702005-11-03 23:53:57 +00001095 while (true) {
darinf9e5d6c2007-01-09 14:54:26 +00001096 Direction dirCurrent;
adele7fc3e832006-02-17 09:31:35 +00001097 if (pastEnd && (previousLineBrokeCleanly || bidi.current.atEnd())) {
eseidel789896f2005-11-27 22:52:09 +00001098 BidiContext *c = bidi.context.get();
1099 while (c->parent)
1100 c = c->parent;
mjs08191d52006-03-06 02:53:41 +00001101 dirCurrent = c->dir();
adele7fc3e832006-02-17 09:31:35 +00001102 if (previousLineBrokeCleanly) {
eseidel789896f2005-11-27 22:52:09 +00001103 // A deviation from the Unicode Bidi Algorithm in order to match
1104 // Mac OS X text and WinIE: a hard line break resets bidi state.
1105 stateAtEnd.context = c;
1106 stateAtEnd.status.eor = dirCurrent;
1107 stateAtEnd.status.last = dirCurrent;
1108 stateAtEnd.status.lastStrong = dirCurrent;
1109 }
darinb70665a2002-04-15 23:43:21 +00001110 } else {
mjsfe301d72003-10-02 18:46:18 +00001111 dirCurrent = bidi.current.direction();
darin7ab31092006-05-10 04:59:57 +00001112 if (bidi.context->override
darinf9e5d6c2007-01-09 14:54:26 +00001113 && dirCurrent != RightToLeftEmbedding
1114 && dirCurrent != LeftToRightEmbedding
1115 && dirCurrent != RightToLeftOverride
1116 && dirCurrent != LeftToRightOverride
1117 && dirCurrent != PopDirectionalFormat)
mjs08191d52006-03-06 02:53:41 +00001118 dirCurrent = bidi.context->dir();
darinf9e5d6c2007-01-09 14:54:26 +00001119 else if (dirCurrent == NonSpacingMark)
darinef0c09f2005-10-09 01:46:17 +00001120 dirCurrent = bidi.status.last;
hyatt33f8d492002-11-12 21:44:52 +00001121 }
darinf028f812002-06-10 20:08:04 +00001122
darinf9e5d6c2007-01-09 14:54:26 +00001123 assert(bidi.status.eor != OtherNeutral);
hyatt275d0702005-11-03 23:53:57 +00001124 switch (dirCurrent) {
kociendabb0c24b2001-08-24 14:24:40 +00001125
hyatt275d0702005-11-03 23:53:57 +00001126 // embedding and overrides (X1-X9 in the Bidi specs)
darinf9e5d6c2007-01-09 14:54:26 +00001127 case RightToLeftEmbedding:
1128 case LeftToRightEmbedding:
1129 case RightToLeftOverride:
1130 case LeftToRightOverride:
1131 case PopDirectionalFormat:
hyatt275d0702005-11-03 23:53:57 +00001132 embed(dirCurrent, bidi);
hyatt33f8d492002-11-12 21:44:52 +00001133 break;
kociendabb0c24b2001-08-24 14:24:40 +00001134
1135 // strong types
darinf9e5d6c2007-01-09 14:54:26 +00001136 case LeftToRight:
hyatt275d0702005-11-03 23:53:57 +00001137 switch(bidi.status.last) {
darinf9e5d6c2007-01-09 14:54:26 +00001138 case RightToLeft:
1139 case RightToLeftArabic:
1140 case EuropeanNumber:
1141 case ArabicNumber:
1142 if (bidi.status.last != EuropeanNumber || bidi.status.lastStrong != LeftToRight)
hyatt275d0702005-11-03 23:53:57 +00001143 appendRun(bidi);
eseidel789896f2005-11-27 22:52:09 +00001144 break;
darinf9e5d6c2007-01-09 14:54:26 +00001145 case LeftToRight:
kociendabb0c24b2001-08-24 14:24:40 +00001146 break;
darinf9e5d6c2007-01-09 14:54:26 +00001147 case EuropeanNumberSeparator:
1148 case EuropeanNumberTerminator:
1149 case CommonNumberSeparator:
1150 case BoundaryNeutral:
1151 case BlockSeparator:
1152 case SegmentSeparator:
1153 case WhiteSpaceNeutral:
1154 case OtherNeutral:
1155 if (bidi.status.eor == EuropeanNumber) {
1156 if (bidi.status.lastStrong != LeftToRight) {
ggarenef026b22005-07-06 00:21:53 +00001157 // the numbers need to be on a higher embedding level, so let's close that run
darinf9e5d6c2007-01-09 14:54:26 +00001158 bidi.dir = EuropeanNumber;
ggarenef026b22005-07-06 00:21:53 +00001159 appendRun(bidi);
darinf9e5d6c2007-01-09 14:54:26 +00001160 if (bidi.context->dir() != LeftToRight) {
ggarenef026b22005-07-06 00:21:53 +00001161 // the neutrals take the embedding direction, which is R
1162 bidi.eor = bidi.last;
darinf9e5d6c2007-01-09 14:54:26 +00001163 bidi.dir = RightToLeft;
ggarenef026b22005-07-06 00:21:53 +00001164 appendRun(bidi);
1165 }
1166 }
darinf9e5d6c2007-01-09 14:54:26 +00001167 } else if (bidi.status.eor == ArabicNumber) {
ggarenef026b22005-07-06 00:21:53 +00001168 // Arabic numbers are always on a higher embedding level, so let's close that run
darinf9e5d6c2007-01-09 14:54:26 +00001169 bidi.dir = ArabicNumber;
ggarenef026b22005-07-06 00:21:53 +00001170 appendRun(bidi);
darinf9e5d6c2007-01-09 14:54:26 +00001171 if (bidi.context->dir() != LeftToRight) {
ggarenef026b22005-07-06 00:21:53 +00001172 // the neutrals take the embedding direction, which is R
1173 bidi.eor = bidi.last;
darinf9e5d6c2007-01-09 14:54:26 +00001174 bidi.dir = RightToLeft;
ggarenef026b22005-07-06 00:21:53 +00001175 appendRun(bidi);
1176 }
darinf9e5d6c2007-01-09 14:54:26 +00001177 } else if(bidi.status.eor != LeftToRight) {
eseidel789896f2005-11-27 22:52:09 +00001178 //last stuff takes embedding dir
darinf9e5d6c2007-01-09 14:54:26 +00001179 if (bidi.context->dir() != LeftToRight && bidi.status.lastStrong != LeftToRight) {
darin6f05b4c2005-05-27 01:17:32 +00001180 bidi.eor = bidi.last;
darinf9e5d6c2007-01-09 14:54:26 +00001181 bidi.dir = RightToLeft;
kociendabb0c24b2001-08-24 14:24:40 +00001182 }
eseidel789896f2005-11-27 22:52:09 +00001183 appendRun(bidi);
kociendabb0c24b2001-08-24 14:24:40 +00001184 }
1185 default:
1186 break;
eseidel789896f2005-11-27 22:52:09 +00001187 }
1188 bidi.eor = bidi.current;
darinf9e5d6c2007-01-09 14:54:26 +00001189 bidi.status.eor = LeftToRight;
1190 bidi.status.lastStrong = LeftToRight;
1191 bidi.dir = LeftToRight;
kociendabb0c24b2001-08-24 14:24:40 +00001192 break;
darinf9e5d6c2007-01-09 14:54:26 +00001193 case RightToLeftArabic:
1194 case RightToLeft:
eseidel789896f2005-11-27 22:52:09 +00001195 switch (bidi.status.last) {
darinf9e5d6c2007-01-09 14:54:26 +00001196 case LeftToRight:
1197 case EuropeanNumber:
1198 case ArabicNumber:
darinef0c09f2005-10-09 01:46:17 +00001199 appendRun(bidi);
darinf9e5d6c2007-01-09 14:54:26 +00001200 case RightToLeft:
1201 case RightToLeftArabic:
kociendabb0c24b2001-08-24 14:24:40 +00001202 break;
darinf9e5d6c2007-01-09 14:54:26 +00001203 case EuropeanNumberSeparator:
1204 case EuropeanNumberTerminator:
1205 case CommonNumberSeparator:
1206 case BoundaryNeutral:
1207 case BlockSeparator:
1208 case SegmentSeparator:
1209 case WhiteSpaceNeutral:
1210 case OtherNeutral:
1211 if (bidi.status.eor != RightToLeft && bidi.status.eor != RightToLeftArabic) {
kociendabb0c24b2001-08-24 14:24:40 +00001212 //last stuff takes embedding dir
darinf9e5d6c2007-01-09 14:54:26 +00001213 if (bidi.context->dir() != RightToLeft && bidi.status.lastStrong != RightToLeft
1214 && bidi.status.lastStrong != RightToLeftArabic) {
mjsfe301d72003-10-02 18:46:18 +00001215 bidi.eor = bidi.last;
darinf9e5d6c2007-01-09 14:54:26 +00001216 bidi.dir = LeftToRight;
kociendabb0c24b2001-08-24 14:24:40 +00001217 }
eseidel789896f2005-11-27 22:52:09 +00001218 appendRun(bidi);
1219 }
kociendabb0c24b2001-08-24 14:24:40 +00001220 default:
1221 break;
eseidel789896f2005-11-27 22:52:09 +00001222 }
1223 bidi.eor = bidi.current;
darinf9e5d6c2007-01-09 14:54:26 +00001224 bidi.status.eor = RightToLeft;
mjsfe301d72003-10-02 18:46:18 +00001225 bidi.status.lastStrong = dirCurrent;
darinf9e5d6c2007-01-09 14:54:26 +00001226 bidi.dir = RightToLeft;
kociendabb0c24b2001-08-24 14:24:40 +00001227 break;
1228
1229 // weak types:
1230
darinf9e5d6c2007-01-09 14:54:26 +00001231 case EuropeanNumber:
1232 if (bidi.status.lastStrong != RightToLeftArabic) {
kociendabb0c24b2001-08-24 14:24:40 +00001233 // if last strong was AL change EN to AN
hyatt275d0702005-11-03 23:53:57 +00001234 switch (bidi.status.last) {
darinf9e5d6c2007-01-09 14:54:26 +00001235 case EuropeanNumber:
1236 case LeftToRight:
kociendabb0c24b2001-08-24 14:24:40 +00001237 break;
darinf9e5d6c2007-01-09 14:54:26 +00001238 case RightToLeft:
1239 case RightToLeftArabic:
1240 case ArabicNumber:
darinef0c09f2005-10-09 01:46:17 +00001241 bidi.eor = bidi.last;
hyatt275d0702005-11-03 23:53:57 +00001242 appendRun(bidi);
darinf9e5d6c2007-01-09 14:54:26 +00001243 bidi.dir = EuropeanNumber;
darinef0c09f2005-10-09 01:46:17 +00001244 break;
darinf9e5d6c2007-01-09 14:54:26 +00001245 case EuropeanNumberSeparator:
1246 case CommonNumberSeparator:
1247 if (bidi.status.eor == EuropeanNumber)
eseidel789896f2005-11-27 22:52:09 +00001248 break;
darinf9e5d6c2007-01-09 14:54:26 +00001249 case EuropeanNumberTerminator:
1250 case BoundaryNeutral:
1251 case BlockSeparator:
1252 case SegmentSeparator:
1253 case WhiteSpaceNeutral:
1254 case OtherNeutral:
1255 if (bidi.status.eor == RightToLeft) {
kociendabb0c24b2001-08-24 14:24:40 +00001256 // neutrals go to R
darinf9e5d6c2007-01-09 14:54:26 +00001257 bidi.eor = bidi.status.last == EuropeanNumberTerminator ? bidi.lastBeforeET : bidi.last;
hyatt275d0702005-11-03 23:53:57 +00001258 appendRun(bidi);
darinf9e5d6c2007-01-09 14:54:26 +00001259 bidi.dir = EuropeanNumber;
1260 } else if (bidi.status.eor != LeftToRight &&
1261 (bidi.status.eor != EuropeanNumber || bidi.status.lastStrong != LeftToRight) &&
1262 bidi.dir != LeftToRight) {
kociendabb0c24b2001-08-24 14:24:40 +00001263 // numbers on both sides, neutrals get right to left direction
eseidel789896f2005-11-27 22:52:09 +00001264 appendRun(bidi);
darinf9e5d6c2007-01-09 14:54:26 +00001265 bidi.eor = bidi.status.last == EuropeanNumberTerminator ? bidi.lastBeforeET : bidi.last;
1266 bidi.dir = RightToLeft;
eseidel789896f2005-11-27 22:52:09 +00001267 appendRun(bidi);
darinf9e5d6c2007-01-09 14:54:26 +00001268 bidi.dir = EuropeanNumber;
kociendabb0c24b2001-08-24 14:24:40 +00001269 }
1270 default:
1271 break;
eseidel789896f2005-11-27 22:52:09 +00001272 }
1273 bidi.eor = bidi.current;
darinf9e5d6c2007-01-09 14:54:26 +00001274 bidi.status.eor = EuropeanNumber;
1275 if (bidi.dir == OtherNeutral)
1276 bidi.dir = LeftToRight;
kociendabb0c24b2001-08-24 14:24:40 +00001277 break;
1278 }
darinf9e5d6c2007-01-09 14:54:26 +00001279 case ArabicNumber:
1280 dirCurrent = ArabicNumber;
eseidel789896f2005-11-27 22:52:09 +00001281 switch (bidi.status.last) {
darinf9e5d6c2007-01-09 14:54:26 +00001282 case LeftToRight:
1283 if (bidi.context->dir() == LeftToRight)
mjs89ab8912005-11-28 04:37:33 +00001284 appendRun(bidi);
1285 break;
darinf9e5d6c2007-01-09 14:54:26 +00001286 case ArabicNumber:
eseidel789896f2005-11-27 22:52:09 +00001287 break;
darinf9e5d6c2007-01-09 14:54:26 +00001288 case RightToLeft:
1289 case RightToLeftArabic:
1290 case EuropeanNumber:
darinef0c09f2005-10-09 01:46:17 +00001291 bidi.eor = bidi.last;
hyatt275d0702005-11-03 23:53:57 +00001292 appendRun(bidi);
kociendabb0c24b2001-08-24 14:24:40 +00001293 break;
darinf9e5d6c2007-01-09 14:54:26 +00001294 case CommonNumberSeparator:
1295 if (bidi.status.eor == ArabicNumber)
eseidel789896f2005-11-27 22:52:09 +00001296 break;
darinf9e5d6c2007-01-09 14:54:26 +00001297 case EuropeanNumberSeparator:
1298 case EuropeanNumberTerminator:
1299 case BoundaryNeutral:
1300 case BlockSeparator:
1301 case SegmentSeparator:
1302 case WhiteSpaceNeutral:
1303 case OtherNeutral:
1304 if (bidi.status.eor != RightToLeft && bidi.status.eor != RightToLeftArabic) {
ggarenef026b22005-07-06 00:21:53 +00001305 // run of L before neutrals, neutrals take embedding dir (N2)
darinf9e5d6c2007-01-09 14:54:26 +00001306 if (bidi.context->dir() == RightToLeft || bidi.status.lastStrong == RightToLeft
1307 || bidi.status.lastStrong == RightToLeftArabic) {
ggarenef026b22005-07-06 00:21:53 +00001308 // the embedding direction is R
1309 // close the L run
hyatt275d0702005-11-03 23:53:57 +00001310 appendRun(bidi);
ggarenef026b22005-07-06 00:21:53 +00001311 // neutrals become an R run
darinf9e5d6c2007-01-09 14:54:26 +00001312 bidi.dir = RightToLeft;
kociendabb0c24b2001-08-24 14:24:40 +00001313 } else {
ggarenef026b22005-07-06 00:21:53 +00001314 // the embedding direction is L
1315 // append neutrals to the L run and close it
darinf9e5d6c2007-01-09 14:54:26 +00001316 bidi.dir = LeftToRight;
kociendabb0c24b2001-08-24 14:24:40 +00001317 }
1318 }
eseidel789896f2005-11-27 22:52:09 +00001319 bidi.eor = bidi.last;
1320 appendRun(bidi);
kociendabb0c24b2001-08-24 14:24:40 +00001321 default:
1322 break;
hyatt275d0702005-11-03 23:53:57 +00001323 }
eseidel789896f2005-11-27 22:52:09 +00001324 bidi.eor = bidi.current;
darinf9e5d6c2007-01-09 14:54:26 +00001325 bidi.status.eor = ArabicNumber;
1326 if (bidi.dir == OtherNeutral)
1327 bidi.dir = ArabicNumber;
kociendabb0c24b2001-08-24 14:24:40 +00001328 break;
darinf9e5d6c2007-01-09 14:54:26 +00001329 case EuropeanNumberSeparator:
1330 case CommonNumberSeparator:
kociendabb0c24b2001-08-24 14:24:40 +00001331 break;
darinf9e5d6c2007-01-09 14:54:26 +00001332 case EuropeanNumberTerminator:
1333 if (bidi.status.last == EuropeanNumber) {
1334 dirCurrent = EuropeanNumber;
hyatt275d0702005-11-03 23:53:57 +00001335 bidi.eor = bidi.current;
1336 bidi.status.eor = dirCurrent;
darinf9e5d6c2007-01-09 14:54:26 +00001337 } else if (bidi.status.last != EuropeanNumberTerminator)
darine4fa9e22005-12-16 18:18:50 +00001338 bidi.lastBeforeET = emptyRun ? bidi.eor : bidi.last;
kociendabb0c24b2001-08-24 14:24:40 +00001339 break;
1340
1341 // boundary neutrals should be ignored
darinf9e5d6c2007-01-09 14:54:26 +00001342 case BoundaryNeutral:
darinef0c09f2005-10-09 01:46:17 +00001343 if (bidi.eor == bidi.last)
1344 bidi.eor = bidi.current;
kociendabb0c24b2001-08-24 14:24:40 +00001345 break;
1346 // neutrals
darinf9e5d6c2007-01-09 14:54:26 +00001347 case BlockSeparator:
kociendabb0c24b2001-08-24 14:24:40 +00001348 // ### what do we do with newline and paragraph seperators that come to here?
1349 break;
darinf9e5d6c2007-01-09 14:54:26 +00001350 case SegmentSeparator:
kociendabb0c24b2001-08-24 14:24:40 +00001351 // ### implement rule L1
1352 break;
darinf9e5d6c2007-01-09 14:54:26 +00001353 case WhiteSpaceNeutral:
hyattfe99c872003-07-31 22:25:29 +00001354 break;
darinf9e5d6c2007-01-09 14:54:26 +00001355 case OtherNeutral:
kociendabb0c24b2001-08-24 14:24:40 +00001356 break;
1357 default:
1358 break;
1359 }
1360
eseidel789896f2005-11-27 22:52:09 +00001361 if (pastEnd) {
1362 if (bidi.eor == bidi.current) {
1363 if (!bidi.reachedEndOfLine) {
1364 bidi.eor = bidi.endOfLine;
1365 switch (bidi.status.eor) {
darinf9e5d6c2007-01-09 14:54:26 +00001366 case LeftToRight:
1367 case RightToLeft:
1368 case ArabicNumber:
eseidel789896f2005-11-27 22:52:09 +00001369 bidi.dir = bidi.status.eor;
1370 break;
darinf9e5d6c2007-01-09 14:54:26 +00001371 case EuropeanNumber:
1372 bidi.dir = bidi.status.lastStrong == LeftToRight ? LeftToRight : EuropeanNumber;
eseidel789896f2005-11-27 22:52:09 +00001373 break;
1374 default:
1375 assert(false);
1376 }
1377 appendRun(bidi);
1378 }
1379 bidi = stateAtEnd;
darinf9e5d6c2007-01-09 14:54:26 +00001380 bidi.dir = OtherNeutral;
eseidel789896f2005-11-27 22:52:09 +00001381 break;
1382 }
1383 }
kociendabb0c24b2001-08-24 14:24:40 +00001384
1385 // set status.last as needed.
hyatt275d0702005-11-03 23:53:57 +00001386 switch (dirCurrent) {
darinf9e5d6c2007-01-09 14:54:26 +00001387 case EuropeanNumberTerminator:
1388 if (bidi.status.last != EuropeanNumber)
1389 bidi.status.last = EuropeanNumberTerminator;
ggarenef026b22005-07-06 00:21:53 +00001390 break;
darinf9e5d6c2007-01-09 14:54:26 +00001391 case EuropeanNumberSeparator:
1392 case CommonNumberSeparator:
1393 case SegmentSeparator:
1394 case WhiteSpaceNeutral:
1395 case OtherNeutral:
hyatt275d0702005-11-03 23:53:57 +00001396 switch(bidi.status.last) {
darinf9e5d6c2007-01-09 14:54:26 +00001397 case LeftToRight:
1398 case RightToLeft:
1399 case RightToLeftArabic:
1400 case EuropeanNumber:
1401 case ArabicNumber:
mjsfe301d72003-10-02 18:46:18 +00001402 bidi.status.last = dirCurrent;
kociendabb0c24b2001-08-24 14:24:40 +00001403 break;
1404 default:
darinf9e5d6c2007-01-09 14:54:26 +00001405 bidi.status.last = OtherNeutral;
kociendabb0c24b2001-08-24 14:24:40 +00001406 }
1407 break;
darinf9e5d6c2007-01-09 14:54:26 +00001408 case NonSpacingMark:
1409 case BoundaryNeutral:
1410 case RightToLeftEmbedding:
1411 case LeftToRightEmbedding:
1412 case RightToLeftOverride:
1413 case LeftToRightOverride:
1414 case PopDirectionalFormat:
kociendabb0c24b2001-08-24 14:24:40 +00001415 // ignore these
1416 break;
darinf9e5d6c2007-01-09 14:54:26 +00001417 case EuropeanNumber:
rjw2028aa42003-01-14 21:14:16 +00001418 // fall through
kociendabb0c24b2001-08-24 14:24:40 +00001419 default:
mjsfe301d72003-10-02 18:46:18 +00001420 bidi.status.last = dirCurrent;
hyatt275d0702005-11-03 23:53:57 +00001421 }
kociendabb0c24b2001-08-24 14:24:40 +00001422
mjsfe301d72003-10-02 18:46:18 +00001423 bidi.last = bidi.current;
mjs6f821c82002-03-22 00:31:57 +00001424
darinf9e5d6c2007-01-09 14:54:26 +00001425 if (emptyRun && !(dirCurrent == RightToLeftEmbedding
1426 || dirCurrent == LeftToRightEmbedding
1427 || dirCurrent == RightToLeftOverride
1428 || dirCurrent == LeftToRightOverride
1429 || dirCurrent == PopDirectionalFormat)) {
darin54008922006-01-13 16:39:05 +00001430 bidi.sor = bidi.current;
1431 emptyRun = false;
1432 }
darinb70665a2002-04-15 23:43:21 +00001433
darin54008922006-01-13 16:39:05 +00001434 // this causes the operator ++ to open and close embedding levels as needed
1435 // for the CSS unicode-bidi property
1436 bidi.adjustEmbedding = true;
hyatt275d0702005-11-03 23:53:57 +00001437 bidi.current.increment(bidi);
darin54008922006-01-13 16:39:05 +00001438 bidi.adjustEmbedding = false;
darinf9e5d6c2007-01-09 14:54:26 +00001439 if (emptyRun && (dirCurrent == RightToLeftEmbedding
1440 || dirCurrent == LeftToRightEmbedding
1441 || dirCurrent == RightToLeftOverride
1442 || dirCurrent == LeftToRightOverride
1443 || dirCurrent == PopDirectionalFormat)) {
darinef0c09f2005-10-09 01:46:17 +00001444 // exclude the embedding char itself from the new run so that ATSUI will never see it
1445 bidi.eor.obj = 0;
1446 bidi.last = bidi.current;
1447 bidi.sor = bidi.current;
1448 }
darinb70665a2002-04-15 23:43:21 +00001449
eseidel789896f2005-11-27 22:52:09 +00001450 if (!pastEnd && (bidi.current == end || bidi.current.atEnd())) {
1451 if (emptyRun)
1452 break;
1453 stateAtEnd = bidi;
1454 bidi.endOfLine = bidi.last;
1455 pastEnd = true;
eseidel789896f2005-11-27 22:52:09 +00001456 }
mjs6f821c82002-03-22 00:31:57 +00001457 }
kociendabb0c24b2001-08-24 14:24:40 +00001458
ddkilzerfe115062006-07-14 04:42:01 +00001459 sLogicallyLastBidiRun = sLastBidiRun;
1460
kociendabb0c24b2001-08-24 14:24:40 +00001461 // reorder line according to run structure...
kociendabb0c24b2001-08-24 14:24:40 +00001462 // do not reverse for visually ordered web sites
hyatt275d0702005-11-03 23:53:57 +00001463 if (!style()->visuallyOrdered()) {
eseidel789896f2005-11-27 22:52:09 +00001464
1465 // first find highest and lowest levels
darin479ef852006-01-30 06:06:32 +00001466 unsigned char levelLow = 128;
1467 unsigned char levelHigh = 0;
eseidel789896f2005-11-27 22:52:09 +00001468 BidiRun* r = sFirstBidiRun;
1469 while (r) {
1470 if (r->level > levelHigh)
1471 levelHigh = r->level;
1472 if (r->level < levelLow)
1473 levelLow = r->level;
1474 r = r->nextRun;
1475 }
1476
1477 // implements reordering of the line (L2 according to Bidi spec):
1478 // L2. From the highest level found in the text to the lowest odd level on each line,
1479 // reverse any contiguous sequence of characters that are at that level or higher.
1480
1481 // reversing is only done up to the lowest odd level
1482 if (!(levelLow%2))
1483 levelLow++;
1484
1485 int count = sBidiRunCount - 1;
1486
hyatt275d0702005-11-03 23:53:57 +00001487 while (levelHigh >= levelLow) {
kociendabb0c24b2001-08-24 14:24:40 +00001488 int i = 0;
hyatt2f1e7102003-02-20 01:27:03 +00001489 BidiRun* currRun = sFirstBidiRun;
hyatt275d0702005-11-03 23:53:57 +00001490 while (i < count) {
1491 while (i < count && currRun && currRun->level < levelHigh) {
kociendabb0c24b2001-08-24 14:24:40 +00001492 i++;
hyatt2f1e7102003-02-20 01:27:03 +00001493 currRun = currRun->nextRun;
kociendabb0c24b2001-08-24 14:24:40 +00001494 }
hyatt2f1e7102003-02-20 01:27:03 +00001495 int start = i;
hyatt275d0702005-11-03 23:53:57 +00001496 while (i <= count && currRun && currRun->level >= levelHigh) {
hyatt2f1e7102003-02-20 01:27:03 +00001497 i++;
1498 currRun = currRun->nextRun;
1499 }
1500 int end = i-1;
1501 reverseRuns(start, end);
kociendabb0c24b2001-08-24 14:24:40 +00001502 }
1503 levelHigh--;
1504 }
1505 }
eseidel789896f2005-11-27 22:52:09 +00001506 bidi.endOfLine.obj = 0;
hyatt4b381692003-03-10 21:11:59 +00001507}
kociendabb0c24b2001-08-24 14:24:40 +00001508
hyatt275d0702005-11-03 23:53:57 +00001509static void buildCompactRuns(RenderObject* compactObj, BidiState& bidi)
hyatt4b381692003-03-10 21:11:59 +00001510{
1511 sBuildingCompactRuns = true;
1512 if (!compactObj->isRenderBlock()) {
1513 // Just append a run for our object.
1514 isLineEmpty = false;
eseidel789896f2005-11-27 22:52:09 +00001515 addRun(new (compactObj->renderArena()) BidiRun(0, compactObj->length(), compactObj, bidi.context.get(), bidi.dir));
hyatt4b381692003-03-10 21:11:59 +00001516 }
1517 else {
1518 // Format the compact like it is its own single line. We build up all the runs for
1519 // the little compact and then reorder them for bidi.
1520 RenderBlock* compactBlock = static_cast<RenderBlock*>(compactObj);
hyatt275d0702005-11-03 23:53:57 +00001521 bidi.adjustEmbedding = true;
1522 BidiIterator start(compactBlock, bidiFirst(compactBlock, bidi), 0);
1523 bidi.adjustEmbedding = false;
darin8341f372003-04-29 18:30:31 +00001524 BidiIterator end = start;
hyattffe78712003-02-11 01:59:29 +00001525
hyatt4b381692003-03-10 21:11:59 +00001526 betweenMidpoints = false;
1527 isLineEmpty = true;
hyatt0c3a9862004-02-23 21:26:26 +00001528 previousLineBrokeCleanly = true;
hyatt01eff982003-03-14 20:13:23 +00001529
mjsfe301d72003-10-02 18:46:18 +00001530 end = compactBlock->findNextLineBreak(start, bidi);
hyatt4b381692003-03-10 21:11:59 +00001531 if (!isLineEmpty)
mjsfe301d72003-10-02 18:46:18 +00001532 compactBlock->bidiReorderLine(start, end, bidi);
hyatt4b381692003-03-10 21:11:59 +00001533 }
hyatt275d0702005-11-03 23:53:57 +00001534
hyatt4b381692003-03-10 21:11:59 +00001535 sCompactFirstBidiRun = sFirstBidiRun;
1536 sCompactLastBidiRun = sLastBidiRun;
1537 sCompactBidiRunCount = sBidiRunCount;
1538
1539 sNumMidpoints = 0;
1540 sCurrMidpoint = 0;
1541 betweenMidpoints = false;
1542 sBuildingCompactRuns = false;
kociendabb0c24b2001-08-24 14:24:40 +00001543}
1544
hyatt673184e2006-01-14 22:07:08 +00001545IntRect RenderBlock::layoutInlineChildren(bool relayoutChildren)
kociendabb0c24b2001-08-24 14:24:40 +00001546{
mjsfe301d72003-10-02 18:46:18 +00001547 BidiState bidi;
1548
hyatt0c3a9862004-02-23 21:26:26 +00001549 bool useRepaintRect = false;
ap9059f6f2006-07-24 16:55:02 +00001550 int repaintTop = 0;
1551 int repaintBottom = 0;
hyatt0c3a9862004-02-23 21:26:26 +00001552
hyatta70560a2002-11-20 01:53:20 +00001553 m_overflowHeight = 0;
1554
kociendabb0c24b2001-08-24 14:24:40 +00001555 invalidateVerticalPositions();
hyattdd7dfe92003-11-16 20:48:12 +00001556
1557 m_height = borderTop() + paddingTop();
hyattf9f247b2007-01-12 22:53:40 +00001558 int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
hyattdd7dfe92003-11-16 20:48:12 +00001559
hyatt0c3a9862004-02-23 21:26:26 +00001560 // Figure out if we should clear out our line boxes.
1561 // FIXME: Handle resize eventually!
1562 // FIXME: Do something better when floats are present.
hyatt452d3112006-07-11 01:22:07 +00001563 bool fullLayout = !firstLineBox() || !firstChild() || selfNeedsLayout() || relayoutChildren || containsFloats();
hyatt0c3a9862004-02-23 21:26:26 +00001564 if (fullLayout)
1565 deleteLineBoxes();
hyatted77ad82004-06-15 07:21:23 +00001566
1567 // Text truncation only kicks in if your overflow isn't visible and your text-overflow-mode isn't
1568 // clip.
1569 // FIXME: CSS3 says that descendants that are clipped must also know how to truncate. This is insanely
1570 // difficult to figure out (especially in the middle of doing layout), and is really an esoteric pile of nonsense
1571 // anyway, so we won't worry about following the draft here.
1572 bool hasTextOverflow = style()->textOverflow() && hasOverflowClip();
hyatt33f8d492002-11-12 21:44:52 +00001573
hyatted77ad82004-06-15 07:21:23 +00001574 // Walk all the lines and delete our ellipsis line boxes if they exist.
1575 if (hasTextOverflow)
1576 deleteEllipsisLineBoxes();
1577
hyattffe78712003-02-11 01:59:29 +00001578 if (firstChild()) {
kociendabb0c24b2001-08-24 14:24:40 +00001579 // layout replaced elements
hyattffe78712003-02-11 01:59:29 +00001580 bool endOfInline = false;
hyatt275d0702005-11-03 23:53:57 +00001581 RenderObject *o = bidiFirst(this, bidi, false);
hyatt0c3a9862004-02-23 21:26:26 +00001582 bool hasFloat = false;
1583 while (o) {
1584 if (o->isReplaced() || o->isFloating() || o->isPositioned()) {
hyatt89377f12002-12-13 21:24:40 +00001585 if (relayoutChildren || o->style()->width().isPercent() || o->style()->height().isPercent())
hyattadbb2ef2003-11-18 09:21:44 +00001586 o->setChildNeedsLayout(true, false);
hyatt3ac01352003-03-22 01:37:33 +00001587 if (o->isPositioned())
1588 o->containingBlock()->insertPositionedObject(o);
hyatt0c3a9862004-02-23 21:26:26 +00001589 else {
1590 if (o->isFloating())
1591 hasFloat = true;
1592 else if (fullLayout || o->needsLayout()) // Replaced elements
1593 o->dirtyLineBoxes(fullLayout);
hyatt390427a2003-05-03 18:33:42 +00001594 o->layoutIfNeeded();
hyatt0c3a9862004-02-23 21:26:26 +00001595 }
kociendabb0c24b2001-08-24 14:24:40 +00001596 }
hyatt0c3a9862004-02-23 21:26:26 +00001597 else if (o->isText() || (o->isInlineFlow() && !endOfInline)) {
1598 if (fullLayout || o->selfNeedsLayout())
1599 o->dirtyLineBoxes(fullLayout);
hyattf4fe67f2003-10-07 04:43:23 +00001600 o->setNeedsLayout(false);
hyattf4fe67f2003-10-07 04:43:23 +00001601 }
hyatt275d0702005-11-03 23:53:57 +00001602 o = bidiNext(this, o, bidi, false, &endOfInline);
kociendabb0c24b2001-08-24 14:24:40 +00001603 }
1604
hyatt0c3a9862004-02-23 21:26:26 +00001605 if (hasFloat)
1606 fullLayout = true; // FIXME: Will need to find a way to optimize floats some day.
1607
hyatt837eb362004-05-21 22:17:10 +00001608 if (fullLayout && !selfNeedsLayout()) {
hyatt0c3a9862004-02-23 21:26:26 +00001609 setNeedsLayout(true, false); // Mark ourselves as needing a full layout. This way we'll repaint like
1610 // we're supposed to.
hyatt837eb362004-05-21 22:17:10 +00001611 if (!document()->view()->needsFullRepaint() && m_layer) {
1612 // Because we waited until we were already inside layout to discover
1613 // that the block really needed a full layout, we missed our chance to repaint the layer
1614 // before layout started. Luckily the layer has cached the repaint rect for its original
1615 // position and size, and so we can use that to make a repaint happen now.
hyattd8048342006-05-31 01:48:18 +00001616 RenderView* c = view();
sfalken6f98c4d2007-01-11 01:39:58 +00001617 if (c && !c->printing())
hyatt837eb362004-05-21 22:17:10 +00001618 c->repaintViewRectangle(m_layer->repaintRect());
1619 }
1620 }
hyatt0c3a9862004-02-23 21:26:26 +00001621
kociendabb0c24b2001-08-24 14:24:40 +00001622 BidiContext *startEmbed;
hyatt275d0702005-11-03 23:53:57 +00001623 if (style()->direction() == LTR) {
darinf9e5d6c2007-01-09 14:54:26 +00001624 startEmbed = new BidiContext(0, LeftToRight, NULL, style()->unicodeBidi() == Override);
1625 bidi.status.eor = LeftToRight;
kociendabb0c24b2001-08-24 14:24:40 +00001626 } else {
darinf9e5d6c2007-01-09 14:54:26 +00001627 startEmbed = new BidiContext(1, RightToLeft, NULL, style()->unicodeBidi() == Override);
1628 bidi.status.eor = RightToLeft;
kociendabb0c24b2001-08-24 14:24:40 +00001629 }
kociendabb0c24b2001-08-24 14:24:40 +00001630
mjs08191d52006-03-06 02:53:41 +00001631 bidi.status.lastStrong = startEmbed->dir();
1632 bidi.status.last = startEmbed->dir();
1633 bidi.status.eor = startEmbed->dir();
mjsfe301d72003-10-02 18:46:18 +00001634 bidi.context = startEmbed;
darinf9e5d6c2007-01-09 14:54:26 +00001635 bidi.dir = OtherNeutral;
hyatt33f8d492002-11-12 21:44:52 +00001636
hyatt85586af2003-02-19 23:22:42 +00001637 if (!smidpoints)
darin91298e52006-06-12 01:10:17 +00001638 smidpoints = new Vector<BidiIterator>();
hyatt0c3a9862004-02-23 21:26:26 +00001639
hyatt85586af2003-02-19 23:22:42 +00001640 sNumMidpoints = 0;
1641 sCurrMidpoint = 0;
hyatt4b381692003-03-10 21:11:59 +00001642 sCompactFirstBidiRun = sCompactLastBidiRun = 0;
1643 sCompactBidiRunCount = 0;
hyatt01eff982003-03-14 20:13:23 +00001644
hyatt0c3a9862004-02-23 21:26:26 +00001645 // We want to skip ahead to the first dirty line
1646 BidiIterator start;
1647 RootInlineBox* startLine = determineStartPosition(fullLayout, start, bidi);
1648
1649 // We also find the first clean line and extract these lines. We will add them back
1650 // if we determine that we're able to synchronize after handling all our dirty lines.
1651 BidiIterator cleanLineStart;
eseidel789896f2005-11-27 22:52:09 +00001652 BidiStatus cleanLineBidiStatus;
1653 BidiContext* cleanLineBidiContext;
hyatt0c3a9862004-02-23 21:26:26 +00001654 int endLineYPos;
1655 RootInlineBox* endLine = (fullLayout || !startLine) ?
eseidel789896f2005-11-27 22:52:09 +00001656 0 : determineEndPosition(startLine, cleanLineStart, cleanLineBidiStatus, cleanLineBidiContext, endLineYPos);
1657 if (endLine && cleanLineBidiContext)
1658 cleanLineBidiContext->ref();
hyatt0c3a9862004-02-23 21:26:26 +00001659 if (startLine) {
1660 useRepaintRect = true;
ap9059f6f2006-07-24 16:55:02 +00001661 repaintTop = m_height;
1662 repaintBottom = m_height;
hyatt0c3a9862004-02-23 21:26:26 +00001663 RenderArena* arena = renderArena();
1664 RootInlineBox* box = startLine;
1665 while (box) {
ap9059f6f2006-07-24 16:55:02 +00001666 repaintTop = min(repaintTop, box->topOverflow());
1667 repaintBottom = max(repaintBottom, box->bottomOverflow());
hyatt0c3a9862004-02-23 21:26:26 +00001668 RootInlineBox* next = box->nextRootBox();
1669 box->deleteLine(arena);
1670 box = next;
1671 }
1672 startLine = 0;
1673 }
1674
1675 BidiIterator end = start;
1676
1677 bool endLineMatched = false;
1678 while (!end.atEnd()) {
kociendabb0c24b2001-08-24 14:24:40 +00001679 start = end;
ap9059f6f2006-07-24 16:55:02 +00001680 if (endLine && (endLineMatched = matchedEndLine(start, bidi.status, bidi.context.get(), cleanLineStart, cleanLineBidiStatus, cleanLineBidiContext, endLine, endLineYPos, repaintBottom, repaintTop)))
hyatt0c3a9862004-02-23 21:26:26 +00001681 break;
1682
hyatt33f8d492002-11-12 21:44:52 +00001683 betweenMidpoints = false;
1684 isLineEmpty = true;
hyatt75c30b62004-07-16 20:15:34 +00001685 if (m_firstLine && firstChild() && firstChild()->isCompact() && firstChild()->isRenderBlock()) {
mjsfe301d72003-10-02 18:46:18 +00001686 buildCompactRuns(firstChild(), bidi);
hyatt4b381692003-03-10 21:11:59 +00001687 start.obj = firstChild()->nextSibling();
1688 end = start;
1689 }
mjsfe301d72003-10-02 18:46:18 +00001690 end = findNextLineBreak(start, bidi);
eseidel789896f2005-11-27 22:52:09 +00001691 if (start.atEnd())
1692 break;
hyatt33f8d492002-11-12 21:44:52 +00001693 if (!isLineEmpty) {
mjsfe301d72003-10-02 18:46:18 +00001694 bidiReorderLine(start, end, bidi);
hyatt4b381692003-03-10 21:11:59 +00001695
1696 // Now that the runs have been ordered, we create the line boxes.
1697 // At the same time we figure out where border/padding/margin should be applied for
1698 // inline flow boxes.
1699 if (sCompactFirstBidiRun) {
1700 // We have a compact line sharing this line. Link the compact runs
1701 // to our runs to create a single line of runs.
1702 sCompactLastBidiRun->nextRun = sFirstBidiRun;
1703 sFirstBidiRun = sCompactFirstBidiRun;
1704 sBidiRunCount += sCompactBidiRunCount;
1705 }
hyatt4b381692003-03-10 21:11:59 +00001706
hyatt0c3a9862004-02-23 21:26:26 +00001707 RootInlineBox* lineBox = 0;
hyattdfb09052003-03-11 02:58:59 +00001708 if (sBidiRunCount) {
hyatt0c3a9862004-02-23 21:26:26 +00001709 lineBox = constructLine(start, end);
hyattdfb09052003-03-11 02:58:59 +00001710 if (lineBox) {
hyatt0c3a9862004-02-23 21:26:26 +00001711 lineBox->setEndsWithBreak(previousLineBrokeCleanly);
1712
hyattdfb09052003-03-11 02:58:59 +00001713 // Now we position all of our text runs horizontally.
mjsfe301d72003-10-02 18:46:18 +00001714 computeHorizontalPositionsForLine(lineBox, bidi);
hyattdfb09052003-03-11 02:58:59 +00001715
1716 // Now position our text runs vertically.
1717 computeVerticalPositionsForLine(lineBox);
hyattbddcc612006-07-24 23:16:15 +00001718
1719#if PLATFORM(MAC)
1720 // Highlight acts as an overflow inflation.
1721 if (style()->highlight() != nullAtom)
1722 lineBox->addHighlightOverflow();
1723#endif
1724
hyattdfb09052003-03-11 02:58:59 +00001725 deleteBidiRuns(renderArena());
1726 }
1727 }
hyatt4b381692003-03-10 21:11:59 +00001728
hyatt0c05e102006-04-14 08:15:00 +00001729 if (end == start) {
hyatt275d0702005-11-03 23:53:57 +00001730 bidi.adjustEmbedding = true;
mjsfe301d72003-10-02 18:46:18 +00001731 end.increment(bidi);
hyatt275d0702005-11-03 23:53:57 +00001732 bidi.adjustEmbedding = false;
hyatt33f8d492002-11-12 21:44:52 +00001733 }
hyatt35a85e52003-02-14 19:43:07 +00001734
ap9059f6f2006-07-24 16:55:02 +00001735 if (lineBox) {
eseidel789896f2005-11-27 22:52:09 +00001736 lineBox->setLineBreakInfo(end.obj, end.pos, &bidi.status, bidi.context.get());
ap9059f6f2006-07-24 16:55:02 +00001737 if (useRepaintRect) {
1738 repaintTop = min(repaintTop, lineBox->topOverflow());
1739 repaintBottom = max(repaintBottom, lineBox->bottomOverflow());
1740 }
1741 }
hyatt0c3a9862004-02-23 21:26:26 +00001742
hyatt35a85e52003-02-14 19:43:07 +00001743 m_firstLine = false;
hyatt33f8d492002-11-12 21:44:52 +00001744 newLine();
darinb70665a2002-04-15 23:43:21 +00001745 }
hyatt74eec4d2003-03-23 08:02:47 +00001746
hyatt85586af2003-02-19 23:22:42 +00001747 sNumMidpoints = 0;
1748 sCurrMidpoint = 0;
hyatt4b381692003-03-10 21:11:59 +00001749 sCompactFirstBidiRun = sCompactLastBidiRun = 0;
1750 sCompactBidiRunCount = 0;
kociendabb0c24b2001-08-24 14:24:40 +00001751 }
hyatt0c3a9862004-02-23 21:26:26 +00001752
1753 if (endLine) {
1754 if (endLineMatched) {
1755 // Attach all the remaining lines, and then adjust their y-positions as needed.
1756 for (RootInlineBox* line = endLine; line; line = line->nextRootBox())
1757 line->attachLine();
1758
1759 // Now apply the offset to each line if needed.
1760 int delta = m_height - endLineYPos;
harrison208ea792005-07-29 23:42:59 +00001761 if (delta) {
ap9059f6f2006-07-24 16:55:02 +00001762 for (RootInlineBox* line = endLine; line; line = line->nextRootBox()) {
1763 repaintTop = min(repaintTop, line->topOverflow() + (delta < 0 ? delta : 0));
1764 repaintBottom = max(repaintBottom, line->bottomOverflow() + (delta > 0 ? delta : 0));
hyattda77c4b2004-06-17 18:09:49 +00001765 line->adjustPosition(0, delta);
ap9059f6f2006-07-24 16:55:02 +00001766 }
harrison208ea792005-07-29 23:42:59 +00001767 }
hyatt0c3a9862004-02-23 21:26:26 +00001768 m_height = lastRootBox()->blockHeight();
ap9059f6f2006-07-24 16:55:02 +00001769 } else {
hyatt0c3a9862004-02-23 21:26:26 +00001770 // Delete all the remaining lines.
hyatt0c3a9862004-02-23 21:26:26 +00001771 InlineRunBox* line = endLine;
1772 RenderArena* arena = renderArena();
1773 while (line) {
ap9059f6f2006-07-24 16:55:02 +00001774 repaintTop = min(repaintTop, line->topOverflow());
1775 repaintBottom = max(repaintBottom, line->bottomOverflow());
hyatt0c3a9862004-02-23 21:26:26 +00001776 InlineRunBox* next = line->nextLineBox();
hyatt0c3a9862004-02-23 21:26:26 +00001777 line->deleteLine(arena);
1778 line = next;
1779 }
1780 }
eseidel789896f2005-11-27 22:52:09 +00001781 if (cleanLineBidiContext)
1782 cleanLineBidiContext->deref();
hyatt0c3a9862004-02-23 21:26:26 +00001783 }
kociendabb0c24b2001-08-24 14:24:40 +00001784 }
hyatt85586af2003-02-19 23:22:42 +00001785
1786 sNumMidpoints = 0;
1787 sCurrMidpoint = 0;
hyatta70560a2002-11-20 01:53:20 +00001788
hyattefa00882003-03-22 23:27:03 +00001789 // in case we have a float on the last line, it might not be positioned up to now.
1790 // This has to be done before adding in the bottom border/padding, or the float will
1791 // include the padding incorrectly. -dwh
1792 positionNewFloats();
1793
hyatta70560a2002-11-20 01:53:20 +00001794 // Now add in the bottom border/padding.
kociendabb0c24b2001-08-24 14:24:40 +00001795 m_height += toAdd;
1796
hyatta70560a2002-11-20 01:53:20 +00001797 // Always make sure this is at least our height.
darin7bd70952006-04-13 07:07:34 +00001798 m_overflowHeight = max(m_height, m_overflowHeight);
hyatta70560a2002-11-20 01:53:20 +00001799
hyattb4b20872004-10-20 21:34:01 +00001800 // See if any lines spill out of the block. If so, we need to update our overflow width.
1801 checkLinesForOverflow();
1802
ap9059f6f2006-07-24 16:55:02 +00001803 IntRect repaintRect(0, 0, 0, 0);
hyatt0c3a9862004-02-23 21:26:26 +00001804 if (useRepaintRect) {
eseidelcf075d02006-03-26 22:58:26 +00001805 repaintRect.setX(m_overflowLeft);
ap9059f6f2006-07-24 16:55:02 +00001806 repaintRect.setWidth(m_overflowWidth - m_overflowLeft);
1807 repaintRect.setY(repaintTop);
1808 repaintRect.setHeight(repaintBottom - repaintTop);
hyatt0c3a9862004-02-23 21:26:26 +00001809 }
hyatta6960b12004-12-07 02:09:10 +00001810
adele7a470a72006-04-20 22:22:14 +00001811 if (!firstLineBox() && hasLineIfEmpty())
adele05abee32006-08-25 23:44:05 +00001812 m_height += lineHeight(true, true);
hyatted77ad82004-06-15 07:21:23 +00001813
1814 // See if we have any lines that spill out of our block. If we do, then we will possibly need to
1815 // truncate text.
1816 if (hasTextOverflow)
1817 checkLinesForTextOverflow();
1818
hyatt0c3a9862004-02-23 21:26:26 +00001819 return repaintRect;
1820
weinigf18aae32006-08-03 21:55:57 +00001821#if defined(BIDI_DEBUG) && BIDI_DEBUG > 1
darinb70665a2002-04-15 23:43:21 +00001822 kdDebug(6041) << " ------- bidi end " << this << " -------" << endl;
darinf028f812002-06-10 20:08:04 +00001823#endif
kociendabb0c24b2001-08-24 14:24:40 +00001824}
1825
hyatt0c3a9862004-02-23 21:26:26 +00001826RootInlineBox* RenderBlock::determineStartPosition(bool fullLayout, BidiIterator& start, BidiState& bidi)
1827{
1828 RootInlineBox* curr = 0;
1829 RootInlineBox* last = 0;
1830 RenderObject* startObj = 0;
1831 int pos = 0;
1832
1833 if (fullLayout) {
1834 // Nuke all our lines.
1835 if (firstRootBox()) {
1836 RenderArena* arena = renderArena();
1837 curr = firstRootBox();
1838 while (curr) {
1839 RootInlineBox* next = curr->nextRootBox();
1840 curr->deleteLine(arena);
1841 curr = next;
1842 }
darinec375482007-01-06 01:36:24 +00001843 ASSERT(!firstLineBox() && !lastLineBox());
hyatt0c3a9862004-02-23 21:26:26 +00001844 }
eseidel789896f2005-11-27 22:52:09 +00001845 } else {
hyatt0c3a9862004-02-23 21:26:26 +00001846 for (curr = firstRootBox(); curr && !curr->isDirty(); curr = curr->nextRootBox());
1847 if (curr) {
1848 // We have a dirty line.
mjs9f78dd92007-02-12 04:06:07 +00001849 if (RootInlineBox* prevRootBox = curr->prevRootBox()) {
hyatt0c3a9862004-02-23 21:26:26 +00001850 // We have a previous line.
mjs9f78dd92007-02-12 04:06:07 +00001851 if (!prevRootBox->endsWithBreak() || prevRootBox->lineBreakObj()->isText() && prevRootBox->lineBreakPos() >= static_cast<RenderText*>(prevRootBox->lineBreakObj())->textLength())
1852 // The previous line didn't break cleanly or broke at a newline
1853 // that has been deleted, so treat it as dirty too.
1854 curr = prevRootBox;
hyatt0c3a9862004-02-23 21:26:26 +00001855 }
eseidel789896f2005-11-27 22:52:09 +00001856 } else {
hyatt0c3a9862004-02-23 21:26:26 +00001857 // No dirty lines were found.
1858 // If the last line didn't break cleanly, treat it as dirty.
1859 if (lastRootBox() && !lastRootBox()->endsWithBreak())
1860 curr = lastRootBox();
1861 }
1862
1863 // If we have no dirty lines, then last is just the last root box.
1864 last = curr ? curr->prevRootBox() : lastRootBox();
1865 }
1866
1867 m_firstLine = !last;
1868 previousLineBrokeCleanly = !last || last->endsWithBreak();
1869 if (last) {
1870 m_height = last->blockHeight();
hyatt0c3a9862004-02-23 21:26:26 +00001871 startObj = last->lineBreakObj();
1872 pos = last->lineBreakPos();
eseidel789896f2005-11-27 22:52:09 +00001873 bidi.status = last->lineBreakBidiStatus();
1874 bidi.context = last->lineBreakBidiContext();
darindde01502005-12-18 22:55:35 +00001875 } else {
1876 bidi.adjustEmbedding = true;
hyatt275d0702005-11-03 23:53:57 +00001877 startObj = bidiFirst(this, bidi, 0);
darindde01502005-12-18 22:55:35 +00001878 bidi.adjustEmbedding = false;
1879 }
hyatt0c3a9862004-02-23 21:26:26 +00001880
hyatt0c3a9862004-02-23 21:26:26 +00001881 start = BidiIterator(this, startObj, pos);
hyatt0c3a9862004-02-23 21:26:26 +00001882
1883 return curr;
1884}
1885
1886RootInlineBox* RenderBlock::determineEndPosition(RootInlineBox* startLine, BidiIterator& cleanLineStart,
eseidel789896f2005-11-27 22:52:09 +00001887 BidiStatus& cleanLineBidiStatus, BidiContext*& cleanLineBidiContext,
hyatt0c3a9862004-02-23 21:26:26 +00001888 int& yPos)
1889{
1890 RootInlineBox* last = 0;
hyatta6960b12004-12-07 02:09:10 +00001891 if (!startLine)
hyatt0c3a9862004-02-23 21:26:26 +00001892 last = 0;
1893 else {
hyatt04420ca2004-07-16 00:05:42 +00001894 for (RootInlineBox* curr = startLine->nextRootBox(); curr; curr = curr->nextRootBox()) {
1895 if (curr->isDirty())
1896 last = 0;
1897 else if (!last)
1898 last = curr;
1899 }
hyatt0c3a9862004-02-23 21:26:26 +00001900 }
1901
1902 if (!last)
1903 return 0;
1904
eseidel789896f2005-11-27 22:52:09 +00001905 RootInlineBox* prev = last->prevRootBox();
1906 cleanLineStart = BidiIterator(this, prev->lineBreakObj(), prev->lineBreakPos());
1907 cleanLineBidiStatus = prev->lineBreakBidiStatus();
1908 cleanLineBidiContext = prev->lineBreakBidiContext();
ap9059f6f2006-07-24 16:55:02 +00001909 yPos = prev->blockHeight();
hyatt0c3a9862004-02-23 21:26:26 +00001910
1911 for (RootInlineBox* line = last; line; line = line->nextRootBox())
1912 line->extractLine(); // Disconnect all line boxes from their render objects while preserving
1913 // their connections to one another.
1914
1915 return last;
1916}
1917
eseidel789896f2005-11-27 22:52:09 +00001918bool RenderBlock::matchedEndLine(const BidiIterator& start, const BidiStatus& status, BidiContext* context,
ap9059f6f2006-07-24 16:55:02 +00001919 const BidiIterator& endLineStart, const BidiStatus& endLineStatus, BidiContext* endLineContext,
1920 RootInlineBox*& endLine, int& endYPos, int& repaintBottom, int& repaintTop)
hyatt0c3a9862004-02-23 21:26:26 +00001921{
hyatt40731602005-04-18 18:12:42 +00001922 if (start == endLineStart)
eseidel789896f2005-11-27 22:52:09 +00001923 return status == endLineStatus && *context == *endLineContext;
hyatt40731602005-04-18 18:12:42 +00001924 else {
hyatt0c3a9862004-02-23 21:26:26 +00001925 // The first clean line doesn't match, but we can check a handful of following lines to try
1926 // to match back up.
1927 static int numLines = 8; // The # of lines we're willing to match against.
1928 RootInlineBox* line = endLine;
1929 for (int i = 0; i < numLines && line; i++, line = line->nextRootBox()) {
1930 if (line->lineBreakObj() == start.obj && line->lineBreakPos() == start.pos) {
1931 // We have a match.
eseidel789896f2005-11-27 22:52:09 +00001932 if (line->lineBreakBidiStatus() != status || *line->lineBreakBidiContext() != *context)
1933 return false; // ...but the bidi state doesn't match.
hyatt0c3a9862004-02-23 21:26:26 +00001934 RootInlineBox* result = line->nextRootBox();
1935
1936 // Set our yPos to be the block height of endLine.
1937 if (result)
1938 endYPos = line->blockHeight();
1939
1940 // Now delete the lines that we failed to sync.
1941 RootInlineBox* boxToDelete = endLine;
1942 RenderArena* arena = renderArena();
1943 while (boxToDelete && boxToDelete != result) {
ap9059f6f2006-07-24 16:55:02 +00001944 repaintTop = min(repaintTop, boxToDelete->topOverflow());
1945 repaintBottom = max(repaintBottom, boxToDelete->bottomOverflow());
hyatt0c3a9862004-02-23 21:26:26 +00001946 RootInlineBox* next = boxToDelete->nextRootBox();
1947 boxToDelete->deleteLine(arena);
1948 boxToDelete = next;
1949 }
1950
1951 endLine = result;
1952 return result;
1953 }
1954 }
1955 }
1956 return false;
1957}
1958
hyattd9953212005-11-03 21:05:59 +00001959static inline bool skipNonBreakingSpace(BidiIterator &it)
kocienda98440082004-10-14 23:51:47 +00001960{
darinf9e5d6c2007-01-09 14:54:26 +00001961 if (it.obj->style()->nbspMode() != SPACE || it.current() != noBreakSpace)
kocienda98440082004-10-14 23:51:47 +00001962 return false;
1963
hyattdca76e92005-11-02 08:52:50 +00001964 // FIXME: This is bad. It makes nbsp inconsistent with space and won't work correctly
1965 // with m_minWidth/m_maxWidth.
kocienda498d1982004-10-15 21:07:24 +00001966 // Do not skip a non-breaking space if it is the first character
hyattdca76e92005-11-02 08:52:50 +00001967 // on a line after a clean line break (or on the first line, since previousLineBrokeCleanly starts off
1968 // |true|).
1969 if (isLineEmpty && previousLineBrokeCleanly)
kocienda498d1982004-10-15 21:07:24 +00001970 return false;
1971
1972 return true;
kocienda98440082004-10-14 23:51:47 +00001973}
1974
hyattd9953212005-11-03 21:05:59 +00001975static inline bool shouldCollapseWhiteSpace(const RenderStyle* style)
1976{
1977 return style->collapseWhiteSpace() || (style->whiteSpace() == PRE_WRAP && (!isLineEmpty || !previousLineBrokeCleanly));
1978}
1979
zimmermannac3781f2007-02-04 01:25:03 +00001980static inline bool shouldPreserveNewline(RenderObject* object)
1981{
1982#ifdef SVG_SUPPORT
1983 if (object->isSVGText())
1984 return false;
1985#endif
1986
1987 return object->style()->preserveNewline();
1988}
1989
kociendae40cb942004-10-05 20:05:38 +00001990int RenderBlock::skipWhitespace(BidiIterator &it, BidiState &bidi)
kociendabb0c24b2001-08-24 14:24:40 +00001991{
hyatt853cd7d2004-11-05 02:59:48 +00001992 // FIXME: The entire concept of the skipWhitespace function is flawed, since we really need to be building
1993 // line boxes even for containers that may ultimately collapse away. Otherwise we'll never get positioned
1994 // elements quite right. In other words, we need to build this function's work into the normal line
1995 // object iteration process.
1996 int w = lineWidth(m_height);
hyattd9953212005-11-03 21:05:59 +00001997 while (!it.atEnd() && (it.obj->isInlineFlow() || (shouldCollapseWhiteSpace(it.obj->style()) && !it.obj->isBR() &&
zimmermannac3781f2007-02-04 01:25:03 +00001998 (it.current() == ' ' || it.current() == '\t' || (!shouldPreserveNewline(it.obj) && it.current() == '\n') ||
darin42563ac52007-01-22 17:28:57 +00001999 it.current() == softHyphen || skipNonBreakingSpace(it) || it.obj->isFloatingOrPositioned())))) {
kociendae40cb942004-10-05 20:05:38 +00002000 if (it.obj->isFloatingOrPositioned()) {
2001 RenderObject *o = it.obj;
hyatt3b5905b2003-02-01 01:13:30 +00002002 // add to special objects...
hyatt98ee7e42003-05-14 01:39:15 +00002003 if (o->isFloating()) {
hyatt3ac01352003-03-22 01:37:33 +00002004 insertFloatingObject(o);
hyatt38e32632003-07-31 00:46:03 +00002005 positionNewFloats();
hyatt853cd7d2004-11-05 02:59:48 +00002006 w = lineWidth(m_height);
hyatt33f8d492002-11-12 21:44:52 +00002007 }
hyatt98ee7e42003-05-14 01:39:15 +00002008 else if (o->isPositioned()) {
hyatt853cd7d2004-11-05 02:59:48 +00002009 // FIXME: The math here is actually not really right. It's a best-guess approximation that
2010 // will work for the common cases
2011 RenderObject* c = o->container();
2012 if (c->isInlineFlow()) {
2013 // A relative positioned inline encloses us. In this case, we also have to determine our
2014 // position as though we were an inline. Set |staticX| and |staticY| on the relative positioned
2015 // inline so that we can obtain the value later.
2016 c->setStaticX(style()->direction() == LTR ?
2017 leftOffset(m_height) : rightOffset(m_height));
2018 c->setStaticY(m_height);
2019 }
2020
2021 if (o->hasStaticX()) {
2022 bool wasInline = o->style()->isOriginalDisplayInlineType();
2023 if (wasInline)
2024 o->setStaticX(style()->direction() == LTR ?
2025 leftOffset(m_height) :
2026 width() - rightOffset(m_height));
2027 else
2028 o->setStaticX(style()->direction() == LTR ?
2029 borderLeft() + paddingLeft() :
2030 borderRight() + paddingRight());
2031 }
hyatt98ee7e42003-05-14 01:39:15 +00002032 if (o->hasStaticY())
2033 o->setStaticY(m_height);
2034 }
hyatt33f8d492002-11-12 21:44:52 +00002035 }
hyatt4b381692003-03-10 21:11:59 +00002036
hyatt275d0702005-11-03 23:53:57 +00002037 bidi.adjustEmbedding = true;
kociendae40cb942004-10-05 20:05:38 +00002038 it.increment(bidi);
hyatt275d0702005-11-03 23:53:57 +00002039 bidi.adjustEmbedding = false;
mjs6f821c82002-03-22 00:31:57 +00002040 }
hyatt853cd7d2004-11-05 02:59:48 +00002041 return w;
kociendae40cb942004-10-05 20:05:38 +00002042}
2043
2044BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi)
2045{
thatcher459b94a2005-10-13 22:07:51 +00002046 // eliminate spaces at beginning of line
2047 int width = skipWhitespace(start, bidi);
kociendae40cb942004-10-05 20:05:38 +00002048 int w = 0;
2049 int tmpW = 0;
kociendae40cb942004-10-05 20:05:38 +00002050
hyatt853cd7d2004-11-05 02:59:48 +00002051 if (start.atEnd())
darinb70665a2002-04-15 23:43:21 +00002052 return start;
mjs6f821c82002-03-22 00:31:57 +00002053
hyatt33f8d492002-11-12 21:44:52 +00002054 // This variable is used only if whitespace isn't set to PRE, and it tells us whether
2055 // or not we are currently ignoring whitespace.
2056 bool ignoringSpaces = false;
hyatt98b16282004-03-31 18:43:12 +00002057 BidiIterator ignoreStart;
hyatt33f8d492002-11-12 21:44:52 +00002058
2059 // This variable tracks whether the very last character we saw was a space. We use
2060 // this to detect when we encounter a second space so we know we have to terminate
2061 // a run.
rjwc9c257d2003-01-24 03:46:17 +00002062 bool currentCharacterIsSpace = false;
harrisone343c412005-01-18 01:07:26 +00002063 bool currentCharacterIsWS = false;
hyatt33f8d492002-11-12 21:44:52 +00002064 RenderObject* trailingSpaceObject = 0;
hyatt98b16282004-03-31 18:43:12 +00002065
mjs6f821c82002-03-22 00:31:57 +00002066 BidiIterator lBreak = start;
2067
kociendabb0c24b2001-08-24 14:24:40 +00002068 RenderObject *o = start.obj;
2069 RenderObject *last = o;
bdakin9151ba52005-10-24 22:51:06 +00002070 RenderObject *previous = o;
kociendabb0c24b2001-08-24 14:24:40 +00002071 int pos = start.pos;
2072
hyatt0c3a9862004-02-23 21:26:26 +00002073 bool prevLineBrokeCleanly = previousLineBrokeCleanly;
2074 previousLineBrokeCleanly = false;
ddkilzer5d01fa22007-01-29 03:10:37 +00002075
2076 bool autoWrapWasEverTrueOnLine = false;
hyatt01eff982003-03-14 20:13:23 +00002077
hyattb0d9f602007-01-15 01:28:23 +00002078 EWhiteSpace currWS = style()->whiteSpace();
2079 EWhiteSpace lastWS = currWS;
hyatt275d0702005-11-03 23:53:57 +00002080 while (o) {
hyattb0d9f602007-01-15 01:28:23 +00002081 currWS = o->isReplaced() ? o->parent()->style()->whiteSpace() : o->style()->whiteSpace();
2082 lastWS = last->isReplaced() ? last->parent()->style()->whiteSpace() : last->style()->whiteSpace();
2083
2084 bool autoWrap = RenderStyle::autoWrap(currWS);
ddkilzer5d01fa22007-01-29 03:10:37 +00002085 autoWrapWasEverTrueOnLine = autoWrapWasEverTrueOnLine || autoWrap;
zimmermannac3781f2007-02-04 01:25:03 +00002086
2087#ifdef SVG_SUPPORT
2088 bool preserveNewline = o->isSVGText() ? false : RenderStyle::preserveNewline(currWS);
2089#else
hyattb0d9f602007-01-15 01:28:23 +00002090 bool preserveNewline = RenderStyle::preserveNewline(currWS);
zimmermannac3781f2007-02-04 01:25:03 +00002091#endif
2092
hyattb0d9f602007-01-15 01:28:23 +00002093 bool collapseWhiteSpace = RenderStyle::collapseWhiteSpace(currWS);
2094
hyatt275d0702005-11-03 23:53:57 +00002095 if (o->isBR()) {
hyatt0c3a9862004-02-23 21:26:26 +00002096 if (w + tmpW <= width) {
kociendabb0c24b2001-08-24 14:24:40 +00002097 lBreak.obj = o;
2098 lBreak.pos = 0;
hyatt0c3a9862004-02-23 21:26:26 +00002099 lBreak.increment(bidi);
2100
hyatt33f8d492002-11-12 21:44:52 +00002101 // A <br> always breaks a line, so don't let the line be collapsed
2102 // away. Also, the space at the end of a line with a <br> does not
hyatt01eff982003-03-14 20:13:23 +00002103 // get collapsed away. It only does this if the previous line broke
2104 // cleanly. Otherwise the <br> has no effect on whether the line is
2105 // empty or not.
2106 if (prevLineBrokeCleanly)
2107 isLineEmpty = false;
hyatt33f8d492002-11-12 21:44:52 +00002108 trailingSpaceObject = 0;
hyatt0c3a9862004-02-23 21:26:26 +00002109 previousLineBrokeCleanly = true;
hyatt74eec4d2003-03-23 08:02:47 +00002110
2111 if (!isLineEmpty) {
2112 // only check the clear status for non-empty lines.
2113 EClear clear = o->style()->clear();
eseidel789896f2005-11-27 22:52:09 +00002114 if (clear != CNONE)
hyatt74eec4d2003-03-23 08:02:47 +00002115 m_clearStatus = (EClear) (m_clearStatus | clear);
kociendabb0c24b2001-08-24 14:24:40 +00002116 }
2117 }
2118 goto end;
2119 }
hyattb0d9f602007-01-15 01:28:23 +00002120
hyatt275d0702005-11-03 23:53:57 +00002121 if (o->isFloatingOrPositioned()) {
kociendabb0c24b2001-08-24 14:24:40 +00002122 // add to special objects...
hyatt275d0702005-11-03 23:53:57 +00002123 if (o->isFloating()) {
hyatt3ac01352003-03-22 01:37:33 +00002124 insertFloatingObject(o);
hyatt33f8d492002-11-12 21:44:52 +00002125 // check if it fits in the current line.
2126 // If it does, position it now, otherwise, position
2127 // it after moving to next line (in newLine() func)
hyattb0d9f602007-01-15 01:28:23 +00002128 if (o->width() + o->marginLeft() + o->marginRight() + w + tmpW <= width) {
hyatt33f8d492002-11-12 21:44:52 +00002129 positionNewFloats();
2130 width = lineWidth(m_height);
2131 }
hyatt275d0702005-11-03 23:53:57 +00002132 } else if (o->isPositioned()) {
hyatt851816b2003-07-08 07:54:17 +00002133 // If our original display wasn't an inline type, then we can
hyatt98ee7e42003-05-14 01:39:15 +00002134 // go ahead and determine our static x position now.
hyatt851816b2003-07-08 07:54:17 +00002135 bool isInlineType = o->style()->isOriginalDisplayInlineType();
hyatt98ee7e42003-05-14 01:39:15 +00002136 bool needToSetStaticX = o->hasStaticX();
2137 if (o->hasStaticX() && !isInlineType) {
2138 o->setStaticX(o->parent()->style()->direction() == LTR ?
hyattb0d9f602007-01-15 01:28:23 +00002139 borderLeft() + paddingLeft() :
2140 borderRight() + paddingRight());
hyatt98ee7e42003-05-14 01:39:15 +00002141 needToSetStaticX = false;
2142 }
2143
2144 // If our original display was an INLINE type, then we can go ahead
2145 // and determine our static y position now.
2146 bool needToSetStaticY = o->hasStaticY();
2147 if (o->hasStaticY() && isInlineType) {
2148 o->setStaticY(m_height);
2149 needToSetStaticY = false;
2150 }
2151
hyatt853cd7d2004-11-05 02:59:48 +00002152 bool needToCreateLineBox = needToSetStaticX || needToSetStaticY;
2153 RenderObject* c = o->container();
2154 if (c->isInlineFlow() && (!needToSetStaticX || !needToSetStaticY))
2155 needToCreateLineBox = true;
2156
hyatt98ee7e42003-05-14 01:39:15 +00002157 // If we're ignoring spaces, we have to stop and include this object and
2158 // then start ignoring spaces again.
hyatt853cd7d2004-11-05 02:59:48 +00002159 if (needToCreateLineBox) {
hyattbc7f07f2003-05-27 20:04:26 +00002160 trailingSpaceObject = 0;
hyatt98b16282004-03-31 18:43:12 +00002161 ignoreStart.obj = o;
2162 ignoreStart.pos = 0;
hyattbc7f07f2003-05-27 20:04:26 +00002163 if (ignoringSpaces) {
hyatt98b16282004-03-31 18:43:12 +00002164 addMidpoint(ignoreStart); // Stop ignoring spaces.
2165 addMidpoint(ignoreStart); // Start ignoring again.
hyattbc7f07f2003-05-27 20:04:26 +00002166 }
hyatt98b16282004-03-31 18:43:12 +00002167
hyatt851816b2003-07-08 07:54:17 +00002168 }
hyatt98ee7e42003-05-14 01:39:15 +00002169 }
hyattffe78712003-02-11 01:59:29 +00002170 } else if (o->isInlineFlow()) {
2171 // Only empty inlines matter. We treat those similarly to replaced elements.
hyatt275d0702005-11-03 23:53:57 +00002172 assert(!o->firstChild());
hyattb0d9f602007-01-15 01:28:23 +00002173 tmpW += o->marginLeft() + o->borderLeft() + o->paddingLeft() +
2174 o->marginRight() + o->borderRight() + o->paddingRight();
hyatt275d0702005-11-03 23:53:57 +00002175 } else if (o->isReplaced()) {
hyattde396342003-10-29 08:57:20 +00002176 // Break on replaced elements if either has normal white-space.
hyattb0d9f602007-01-15 01:28:23 +00002177 if (autoWrap || RenderStyle::autoWrap(lastWS)) {
hyatt711fe232002-11-20 21:25:14 +00002178 w += tmpW;
2179 tmpW = 0;
hyattf14a4a32002-11-21 22:06:32 +00002180 lBreak.obj = o;
2181 lBreak.pos = 0;
hyatt711fe232002-11-20 21:25:14 +00002182 }
2183
hyatt33f8d492002-11-12 21:44:52 +00002184 if (ignoringSpaces) {
mjsfe301d72003-10-02 18:46:18 +00002185 BidiIterator startMid( 0, o, 0 );
hyatt85586af2003-02-19 23:22:42 +00002186 addMidpoint(startMid);
hyatt33f8d492002-11-12 21:44:52 +00002187 }
2188 isLineEmpty = false;
2189 ignoringSpaces = false;
rjwc9c257d2003-01-24 03:46:17 +00002190 currentCharacterIsSpace = false;
harrisone343c412005-01-18 01:07:26 +00002191 currentCharacterIsWS = false;
hyatt33f8d492002-11-12 21:44:52 +00002192 trailingSpaceObject = 0;
hyatte85e4a72002-12-08 02:06:16 +00002193
2194 if (o->isListMarker() && o->style()->listStylePosition() == OUTSIDE) {
2195 // The marker must not have an effect on whitespace at the start
2196 // of the line. We start ignoring spaces to make sure that any additional
2197 // spaces we see will be discarded.
2198 //
2199 // Optimize for a common case. If we can't find whitespace after the list
2200 // item, then this is all moot. -dwh
hyatt275d0702005-11-03 23:53:57 +00002201 RenderObject* next = bidiNext(start.block, o, bidi);
darin42563ac52007-01-22 17:28:57 +00002202 if (style()->collapseWhiteSpace() && next && !next->isBR() && next->isText() && static_cast<RenderText*>(next)->textLength() > 0) {
harrison208ea792005-07-29 23:42:59 +00002203 RenderText *nextText = static_cast<RenderText*>(next);
darin42563ac52007-01-22 17:28:57 +00002204 UChar nextChar = nextText->characters()[0];
hyattdca76e92005-11-02 08:52:50 +00002205 if (nextText->style()->isCollapsibleWhiteSpace(nextChar)) {
harrisone343c412005-01-18 01:07:26 +00002206 currentCharacterIsSpace = true;
2207 currentCharacterIsWS = true;
2208 ignoringSpaces = true;
2209 BidiIterator endMid( 0, o, 0 );
2210 addMidpoint(endMid);
2211 }
hyatte85e4a72002-12-08 02:06:16 +00002212 }
justing244d3a32006-04-13 01:31:24 +00002213 } else
hyattb0d9f602007-01-15 01:28:23 +00002214 tmpW += o->width() + o->marginLeft() + o->marginRight() + inlineWidth(o);
eseidel789896f2005-11-27 22:52:09 +00002215 } else if (o->isText()) {
hyatt33f8d492002-11-12 21:44:52 +00002216 RenderText *t = static_cast<RenderText *>(o);
darin42563ac52007-01-22 17:28:57 +00002217 int strlen = t->textLength();
hyatt33f8d492002-11-12 21:44:52 +00002218 int len = strlen - pos;
darin42563ac52007-01-22 17:28:57 +00002219 const UChar* str = t->characters();
kociendabb0c24b2001-08-24 14:24:40 +00002220
darin42563ac52007-01-22 17:28:57 +00002221 const Font& f = t->style(m_firstLine)->font();
hyatt33f8d492002-11-12 21:44:52 +00002222 // proportional font, needs a bit more work.
2223 int lastSpace = pos;
hyatt3aff2332003-01-23 01:15:28 +00002224 int wordSpacing = o->style()->wordSpacing();
eseideld13fe532005-11-30 02:40:29 +00002225 int lastSpaceWordSpacing = 0;
hyattffe78712003-02-11 01:59:29 +00002226
2227 bool appliedStartWidth = pos > 0; // If the span originated on a previous line,
2228 // then assume the start width has been applied.
darin54008922006-01-13 16:39:05 +00002229 int wrapW = tmpW + inlineWidth(o, !appliedStartWidth, true);
darin47ece0d2005-09-04 07:42:31 +00002230 int nextBreakable = -1;
hyattb0d9f602007-01-15 01:28:23 +00002231
hyatt275d0702005-11-03 23:53:57 +00002232 while (len) {
rjwc9c257d2003-01-24 03:46:17 +00002233 bool previousCharacterIsSpace = currentCharacterIsSpace;
harrisone343c412005-01-18 01:07:26 +00002234 bool previousCharacterIsWS = currentCharacterIsWS;
darin7ab31092006-05-10 04:59:57 +00002235 UChar c = str[pos];
hyattb0d9f602007-01-15 01:28:23 +00002236 currentCharacterIsSpace = c == ' ' || c == '\t' || (!preserveNewline && (c == '\n'));
darin47ece0d2005-09-04 07:42:31 +00002237
hyattb0d9f602007-01-15 01:28:23 +00002238 if (!collapseWhiteSpace || !currentCharacterIsSpace)
hyatt33f8d492002-11-12 21:44:52 +00002239 isLineEmpty = false;
hyatt3aff2332003-01-23 01:15:28 +00002240
hyatt78b85132004-03-29 20:07:45 +00002241 // Check for soft hyphens. Go ahead and ignore them.
darin42563ac52007-01-22 17:28:57 +00002242 if (c == softHyphen) {
hyatt78b85132004-03-29 20:07:45 +00002243 if (!ignoringSpaces) {
2244 // Ignore soft hyphens
bdakin9151ba52005-10-24 22:51:06 +00002245 BidiIterator endMid;
2246 if (pos > 0)
2247 endMid = BidiIterator(0, o, pos-1);
2248 else
darin42563ac52007-01-22 17:28:57 +00002249 endMid = BidiIterator(0, previous, previous->isText() ? static_cast<RenderText *>(previous)->textLength() - 1 : 0);
bdakin9151ba52005-10-24 22:51:06 +00002250 // Two consecutive soft hyphens. Avoid overlapping midpoints.
2251 if (sNumMidpoints && smidpoints->at(sNumMidpoints - 1).obj == endMid.obj && smidpoints->at(sNumMidpoints - 1).pos > endMid.pos)
2252 sNumMidpoints--;
2253 else
2254 addMidpoint(endMid);
hyatt78b85132004-03-29 20:07:45 +00002255
2256 // Add the width up to but not including the hyphen.
eseideld13fe532005-11-30 02:40:29 +00002257 tmpW += t->width(lastSpace, pos - lastSpace, f, w+tmpW) + lastSpaceWordSpacing;
hyatt78b85132004-03-29 20:07:45 +00002258
hyattdca76e92005-11-02 08:52:50 +00002259 // For wrapping text only, include the hyphen. We need to ensure it will fit
hyatt78b85132004-03-29 20:07:45 +00002260 // on the line if it shows when we break.
hyattb0d9f602007-01-15 01:28:23 +00002261 if (autoWrap)
harrison208ea792005-07-29 23:42:59 +00002262 tmpW += t->width(pos, 1, f, w+tmpW);
hyatt78b85132004-03-29 20:07:45 +00002263
2264 BidiIterator startMid(0, o, pos+1);
2265 addMidpoint(startMid);
2266 }
2267
2268 pos++;
2269 len--;
eseideld13fe532005-11-30 02:40:29 +00002270 lastSpaceWordSpacing = 0;
hyatt78b85132004-03-29 20:07:45 +00002271 lastSpace = pos; // Cheesy hack to prevent adding in widths of the run twice.
2272 continue;
2273 }
2274
hyatt3aff2332003-01-23 01:15:28 +00002275 bool applyWordSpacing = false;
hyattb0d9f602007-01-15 01:28:23 +00002276 bool breakNBSP = autoWrap && o->style()->nbspMode() == SPACE;
hyattdca76e92005-11-02 08:52:50 +00002277
2278 // FIXME: This check looks suspicious. Why does w have to be 0?
hyattb0d9f602007-01-15 01:28:23 +00002279 bool breakWords = o->style()->wordWrap() == BREAK_WORD && ((autoWrap && w == 0) || currWS == PRE);
harrisone343c412005-01-18 01:07:26 +00002280
darinf9e5d6c2007-01-09 14:54:26 +00002281 currentCharacterIsWS = currentCharacterIsSpace || (breakNBSP && c == noBreakSpace);
harrisone343c412005-01-18 01:07:26 +00002282
kociendae4ebdd92004-09-29 21:55:48 +00002283 if (breakWords)
harrison208ea792005-07-29 23:42:59 +00002284 wrapW += t->width(pos, 1, f, w+wrapW);
darin54008922006-01-13 16:39:05 +00002285 bool midWordBreak = breakWords && (w + wrapW > width);
darin47ece0d2005-09-04 07:42:31 +00002286
hyattb0d9f602007-01-15 01:28:23 +00002287 if (c == '\n' || (currWS != PRE && isBreakable(str, pos, strlen, nextBreakable, breakNBSP)) || midWordBreak) {
hyatt0c05e102006-04-14 08:15:00 +00002288 bool stoppedIgnoringSpaces = false;
hyatt33f8d492002-11-12 21:44:52 +00002289 if (ignoringSpaces) {
rjwc9c257d2003-01-24 03:46:17 +00002290 if (!currentCharacterIsSpace) {
hyatt33f8d492002-11-12 21:44:52 +00002291 // Stop ignoring spaces and begin at this
2292 // new point.
hyatt48710d62003-08-21 09:17:13 +00002293 ignoringSpaces = false;
eseideld13fe532005-11-30 02:40:29 +00002294 lastSpaceWordSpacing = 0;
hyatt48710d62003-08-21 09:17:13 +00002295 lastSpace = pos; // e.g., "Foo goo", don't add in any of the ignored spaces.
mjsfe301d72003-10-02 18:46:18 +00002296 BidiIterator startMid ( 0, o, pos );
hyatt85586af2003-02-19 23:22:42 +00002297 addMidpoint(startMid);
hyatt0c05e102006-04-14 08:15:00 +00002298 stoppedIgnoringSpaces = true;
harrisone343c412005-01-18 01:07:26 +00002299 } else {
hyatt33f8d492002-11-12 21:44:52 +00002300 // Just keep ignoring these spaces.
2301 pos++;
2302 len--;
2303 continue;
2304 }
2305 }
rjwc9c257d2003-01-24 03:46:17 +00002306
darin54008922006-01-13 16:39:05 +00002307 int additionalTmpW = t->width(lastSpace, pos - lastSpace, f, w+tmpW) + lastSpaceWordSpacing;
2308 tmpW += additionalTmpW;
hyattffe78712003-02-11 01:59:29 +00002309 if (!appliedStartWidth) {
2310 tmpW += inlineWidth(o, true, false);
2311 appliedStartWidth = true;
2312 }
2313
eseideld13fe532005-11-30 02:40:29 +00002314 applyWordSpacing = wordSpacing && currentCharacterIsSpace && !previousCharacterIsSpace;
hyatt3aff2332003-01-23 01:15:28 +00002315
hyattb0d9f602007-01-15 01:28:23 +00002316 if (autoWrap && w + tmpW > width && w == 0) {
hyatte2b14092003-01-23 23:33:39 +00002317 int fb = nearestFloatBottom(m_height);
hyatt33f8d492002-11-12 21:44:52 +00002318 int newLineWidth = lineWidth(fb);
hyatt2df52192003-03-28 22:05:02 +00002319 // See if |tmpW| will fit on the new line. As long as it does not,
2320 // keep adjusting our float bottom until we find some room.
2321 int lastFloatBottom = m_height;
2322 while (lastFloatBottom < fb && tmpW > newLineWidth) {
2323 lastFloatBottom = fb;
2324 fb = nearestFloatBottom(fb);
2325 newLineWidth = lineWidth(fb);
2326 }
2327
hyatt275d0702005-11-03 23:53:57 +00002328 if (!w && m_height < fb && width < newLineWidth) {
hyatt33f8d492002-11-12 21:44:52 +00002329 m_height = fb;
2330 width = newLineWidth;
hyatt33f8d492002-11-12 21:44:52 +00002331 }
2332 }
2333
hyattb0d9f602007-01-15 01:28:23 +00002334 if (autoWrap || breakWords) {
hyattdca76e92005-11-02 08:52:50 +00002335 // If we break only after white-space, consider the current character
kociendae4134242004-10-25 18:48:44 +00002336 // as candidate width for this line.
ap932806a2006-10-01 09:06:09 +00002337 bool lineWasTooWide = false;
2338 if (w + tmpW <= width && currentCharacterIsWS && o->style()->breakOnlyAfterWhiteSpace() && !midWordBreak) {
2339 int charWidth = t->width(pos, 1, f, w + tmpW) + (applyWordSpacing ? wordSpacing : 0);
2340 // Check if line is too big even without the extra space
2341 // at the end of the line. If it is not, do nothing.
2342 // If the line needs the extra whitespace to be too long,
2343 // then move the line break to the space and skip all
2344 // additional whitespace.
2345 if (w + tmpW + charWidth > width) {
2346 lineWasTooWide = true;
2347 lBreak.obj = o;
2348 lBreak.pos = pos;
2349 if (pos > 0) {
2350 // Separate the trailing space into its own box, which we will
2351 // resize to fit on the line in computeHorizontalPositionsForLine().
2352 BidiIterator midpoint(0, o, pos);
2353 addMidpoint(BidiIterator(0, o, pos-1)); // Stop
2354 addMidpoint(BidiIterator(0, o, pos)); // Start
kociendae4134242004-10-25 18:48:44 +00002355 }
ap932806a2006-10-01 09:06:09 +00002356 skipWhitespace(lBreak, bidi);
kocienda9dbe9b12004-10-22 20:07:05 +00002357 }
ap932806a2006-10-01 09:06:09 +00002358 }
2359 if (lineWasTooWide || w + tmpW > width) {
zimmermannac3781f2007-02-04 01:25:03 +00002360 if (lBreak.obj && shouldPreserveNewline(lBreak.obj) && lBreak.obj->isText() && static_cast<RenderText*>(lBreak.obj)->characters()[lBreak.pos] == '\n') {
hyatt0c05e102006-04-14 08:15:00 +00002361 if (!stoppedIgnoringSpaces && pos > 0) {
2362 // We need to stop right before the newline and then start up again.
2363 BidiIterator midpoint(0, o, pos);
2364 addMidpoint(BidiIterator(0, o, pos-1)); // Stop
2365 addMidpoint(BidiIterator(0, o, pos)); // Start
2366 }
2367 lBreak.increment(bidi);
adele7fc3e832006-02-17 09:31:35 +00002368 previousLineBrokeCleanly = true;
adele7fc3e832006-02-17 09:31:35 +00002369 }
hyatt78b85132004-03-29 20:07:45 +00002370 goto end; // Didn't fit. Jump to the end.
darin54008922006-01-13 16:39:05 +00002371 } else {
2372 if (midWordBreak)
2373 tmpW -= additionalTmpW;
darin42563ac52007-01-22 17:28:57 +00002374 if (pos > 0 && str[pos-1] == softHyphen)
darin54008922006-01-13 16:39:05 +00002375 // Subtract the width of the soft hyphen out since we fit on a line.
2376 tmpW -= t->width(pos-1, 1, f, w+tmpW);
2377 }
rjwc9c257d2003-01-24 03:46:17 +00002378 }
hyatt33f8d492002-11-12 21:44:52 +00002379
hyattb0d9f602007-01-15 01:28:23 +00002380 if (c == '\n' && preserveNewline) {
hyatt0c05e102006-04-14 08:15:00 +00002381 if (!stoppedIgnoringSpaces && pos > 0) {
2382 // We need to stop right before the newline and then start up again.
2383 BidiIterator midpoint(0, o, pos);
2384 addMidpoint(BidiIterator(0, o, pos-1)); // Stop
2385 addMidpoint(BidiIterator(0, o, pos)); // Start
2386 }
hyatta9f48e32003-02-03 22:48:01 +00002387 lBreak.obj = o;
2388 lBreak.pos = pos;
hyatt0c05e102006-04-14 08:15:00 +00002389 lBreak.increment(bidi);
adele7fc3e832006-02-17 09:31:35 +00002390 previousLineBrokeCleanly = true;
hyatt33f8d492002-11-12 21:44:52 +00002391 return lBreak;
2392 }
hyatta9f48e32003-02-03 22:48:01 +00002393
hyattb0d9f602007-01-15 01:28:23 +00002394 if (autoWrap) {
hyatta9f48e32003-02-03 22:48:01 +00002395 w += tmpW;
2396 tmpW = 0;
2397 lBreak.obj = o;
2398 lBreak.pos = pos;
2399 }
hyatt33f8d492002-11-12 21:44:52 +00002400
darin54008922006-01-13 16:39:05 +00002401 if (midWordBreak) {
2402 // Remember this as a breakable position in case
2403 // adding the end width forces a break.
2404 lBreak.obj = o;
2405 lBreak.pos = pos;
2406 } else {
2407 lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
2408 lastSpace = pos;
2409 }
hyatt33f8d492002-11-12 21:44:52 +00002410
hyattdca76e92005-11-02 08:52:50 +00002411 if (!ignoringSpaces && o->style()->collapseWhiteSpace()) {
hyatt33f8d492002-11-12 21:44:52 +00002412 // If we encounter a newline, or if we encounter a
2413 // second space, we need to go ahead and break up this
2414 // run and enter a mode where we start collapsing spaces.
hyatt98b16282004-03-31 18:43:12 +00002415 if (currentCharacterIsSpace && previousCharacterIsSpace) {
hyatt33f8d492002-11-12 21:44:52 +00002416 ignoringSpaces = true;
hyatt98b16282004-03-31 18:43:12 +00002417
hyatt33f8d492002-11-12 21:44:52 +00002418 // We just entered a mode where we are ignoring
2419 // spaces. Create a midpoint to terminate the run
2420 // before the second space.
hyatt98b16282004-03-31 18:43:12 +00002421 addMidpoint(ignoreStart);
hyatt33f8d492002-11-12 21:44:52 +00002422 }
2423 }
eseidel789896f2005-11-27 22:52:09 +00002424 } else if (ignoringSpaces) {
hyatt33f8d492002-11-12 21:44:52 +00002425 // Stop ignoring spaces and begin at this
2426 // new point.
2427 ignoringSpaces = false;
eseideld13fe532005-11-30 02:40:29 +00002428 lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
hyatt33f8d492002-11-12 21:44:52 +00002429 lastSpace = pos; // e.g., "Foo goo", don't add in any of the ignored spaces.
eseidel789896f2005-11-27 22:52:09 +00002430 BidiIterator startMid(0, o, pos);
hyatt85586af2003-02-19 23:22:42 +00002431 addMidpoint(startMid);
hyatt33f8d492002-11-12 21:44:52 +00002432 }
hyatt98b16282004-03-31 18:43:12 +00002433
2434 if (currentCharacterIsSpace && !previousCharacterIsSpace) {
2435 ignoreStart.obj = o;
2436 ignoreStart.pos = pos;
2437 }
harrisone343c412005-01-18 01:07:26 +00002438
2439 if (!currentCharacterIsWS && previousCharacterIsWS) {
hyattb0d9f602007-01-15 01:28:23 +00002440 if (autoWrap && o->style()->breakOnlyAfterWhiteSpace()) {
harrisone343c412005-01-18 01:07:26 +00002441 lBreak.obj = o;
2442 lBreak.pos = pos;
2443 }
2444 }
hyatt33f8d492002-11-12 21:44:52 +00002445
hyattb0d9f602007-01-15 01:28:23 +00002446 if (collapseWhiteSpace && currentCharacterIsSpace && !ignoringSpaces)
hyatt33f8d492002-11-12 21:44:52 +00002447 trailingSpaceObject = o;
hyattdca76e92005-11-02 08:52:50 +00002448 else if (!o->style()->collapseWhiteSpace() || !currentCharacterIsSpace)
hyatt33f8d492002-11-12 21:44:52 +00002449 trailingSpaceObject = 0;
2450
2451 pos++;
2452 len--;
2453 }
2454
kociendabb0c24b2001-08-24 14:24:40 +00002455 // IMPORTANT: pos is > length here!
hyatt33f8d492002-11-12 21:44:52 +00002456 if (!ignoringSpaces)
eseideld13fe532005-11-30 02:40:29 +00002457 tmpW += t->width(lastSpace, pos - lastSpace, f, w+tmpW) + lastSpaceWordSpacing;
hyattffe78712003-02-11 01:59:29 +00002458 if (!appliedStartWidth)
2459 tmpW += inlineWidth(o, true, false);
darin54008922006-01-13 16:39:05 +00002460 tmpW += inlineWidth(o, false, true);
kociendabb0c24b2001-08-24 14:24:40 +00002461 } else
darinb53ebdc2006-07-09 15:10:21 +00002462 ASSERT( false );
kociendabb0c24b2001-08-24 14:24:40 +00002463
hyatt275d0702005-11-03 23:53:57 +00002464 RenderObject* next = bidiNext(start.block, o, bidi);
hyattdca76e92005-11-02 08:52:50 +00002465 bool checkForBreak = autoWrap;
hyattb0d9f602007-01-15 01:28:23 +00002466 if (w && w + tmpW > width && lBreak.obj && currWS == NOWRAP)
hyatt74eec4d2003-03-23 08:02:47 +00002467 checkForBreak = true;
2468 else if (next && o->isText() && next->isText() && !next->isBR()) {
hyattdca76e92005-11-02 08:52:50 +00002469 if (autoWrap || (next->style()->autoWrap())) {
hyatta9f48e32003-02-03 22:48:01 +00002470 if (currentCharacterIsSpace)
2471 checkForBreak = true;
2472 else {
harrison07b5e582005-08-15 23:31:16 +00002473 checkForBreak = false;
hyatta9f48e32003-02-03 22:48:01 +00002474 RenderText* nextText = static_cast<RenderText*>(next);
darin42563ac52007-01-22 17:28:57 +00002475 if (nextText->textLength() != 0) {
2476 UChar c = nextText->characters()[0];
zimmermannac3781f2007-02-04 01:25:03 +00002477 if (c == ' ' || c == '\t' || (c == '\n' && !shouldPreserveNewline(next)))
eseideld13fe532005-11-30 02:40:29 +00002478 // If the next item on the line is text, and if we did not end with
2479 // a space, then the next text run continues our word (and so it needs to
2480 // keep adding to |tmpW|. Just update and continue.
2481 checkForBreak = true;
harrison07b5e582005-08-15 23:31:16 +00002482 }
ddkilzer5d01fa22007-01-29 03:10:37 +00002483 bool willFitOnLine = (w + tmpW <= width);
ddkilzere7605022007-01-31 12:51:30 +00002484 bool canPlaceOnLine = willFitOnLine || !willFitOnLine && !autoWrapWasEverTrueOnLine;
hyatta9f48e32003-02-03 22:48:01 +00002485 if (canPlaceOnLine && checkForBreak) {
2486 w += tmpW;
2487 tmpW = 0;
2488 lBreak.obj = next;
2489 lBreak.pos = 0;
2490 }
2491 }
2492 }
2493 }
2494
darin54008922006-01-13 16:39:05 +00002495 if (checkForBreak && (w + tmpW > width)) {
kociendabb0c24b2001-08-24 14:24:40 +00002496 // if we have floats, try to get below them.
hyattdca76e92005-11-02 08:52:50 +00002497 if (currentCharacterIsSpace && !ignoringSpaces && o->style()->collapseWhiteSpace())
hyatt33f8d492002-11-12 21:44:52 +00002498 trailingSpaceObject = 0;
hyatta14d1742003-01-02 20:25:46 +00002499
hyatte2b14092003-01-23 23:33:39 +00002500 int fb = nearestFloatBottom(m_height);
hyatt33f8d492002-11-12 21:44:52 +00002501 int newLineWidth = lineWidth(fb);
hyatt2df52192003-03-28 22:05:02 +00002502 // See if |tmpW| will fit on the new line. As long as it does not,
2503 // keep adjusting our float bottom until we find some room.
2504 int lastFloatBottom = m_height;
2505 while (lastFloatBottom < fb && tmpW > newLineWidth) {
2506 lastFloatBottom = fb;
2507 fb = nearestFloatBottom(fb);
2508 newLineWidth = lineWidth(fb);
2509 }
hyatt275d0702005-11-03 23:53:57 +00002510 if (!w && m_height < fb && width < newLineWidth) {
kociendabb0c24b2001-08-24 14:24:40 +00002511 m_height = fb;
darinb70665a2002-04-15 23:43:21 +00002512 width = newLineWidth;
kociendabb0c24b2001-08-24 14:24:40 +00002513 }
hyattf14a4a32002-11-21 22:06:32 +00002514
hyatta14d1742003-01-02 20:25:46 +00002515 // |width| may have been adjusted because we got shoved down past a float (thus
2516 // giving us more room), so we need to retest, and only jump to
2517 // the end label if we still don't fit on the line. -dwh
darin54008922006-01-13 16:39:05 +00002518 if (w + tmpW > width)
hyatta14d1742003-01-02 20:25:46 +00002519 goto end;
kociendabb0c24b2001-08-24 14:24:40 +00002520 }
hyatt1d9e29b2003-04-10 01:48:53 +00002521
hyattf14a4a32002-11-21 22:06:32 +00002522 last = o;
bdakin9151ba52005-10-24 22:51:06 +00002523 if (!o->isFloating() && (!o->isPositioned() || o->hasStaticX() || o->hasStaticY() || !o->container()->isInlineFlow()))
2524 previous = o;
hyatta9f48e32003-02-03 22:48:01 +00002525 o = next;
hyattf14a4a32002-11-21 22:06:32 +00002526
hyattb0d9f602007-01-15 01:28:23 +00002527 if (!last->isFloatingOrPositioned() && last->isReplaced() && autoWrap &&
bdakina964eb32005-10-24 17:47:26 +00002528 (!last->isListMarker() || last->style()->listStylePosition()==INSIDE)) {
hyatt711fe232002-11-20 21:25:14 +00002529 // Go ahead and add in tmpW.
2530 w += tmpW;
2531 tmpW = 0;
2532 lBreak.obj = o;
2533 lBreak.pos = 0;
2534 }
2535
hyatta9f48e32003-02-03 22:48:01 +00002536 // Clear out our character space bool, since inline <pre>s don't collapse whitespace
2537 // with adjacent inline normal/nowrap spans.
hyattb0d9f602007-01-15 01:28:23 +00002538 if (!collapseWhiteSpace)
hyatta9f48e32003-02-03 22:48:01 +00002539 currentCharacterIsSpace = false;
2540
kociendabb0c24b2001-08-24 14:24:40 +00002541 pos = 0;
2542 }
2543
hyattb0d9f602007-01-15 01:28:23 +00002544
2545 if (w + tmpW <= width || lastWS == NOWRAP) {
kociendabb0c24b2001-08-24 14:24:40 +00002546 lBreak.obj = 0;
2547 lBreak.pos = 0;
2548 }
2549
2550 end:
rjwc9c257d2003-01-24 03:46:17 +00002551
hyatt275d0702005-11-03 23:53:57 +00002552 if (lBreak == start && !lBreak.obj->isBR()) {
kociendabb0c24b2001-08-24 14:24:40 +00002553 // we just add as much as possible
zimmermannac3781f2007-02-04 01:25:03 +00002554 if (shouldPreserveNewline(this)) {
hyattdca76e92005-11-02 08:52:50 +00002555 // FIXME: Don't really understand this case.
hyatt275d0702005-11-03 23:53:57 +00002556 if (pos != 0) {
kociendabb0c24b2001-08-24 14:24:40 +00002557 lBreak.obj = o;
2558 lBreak.pos = pos - 1;
2559 } else {
2560 lBreak.obj = last;
hyattc3731d42002-12-12 06:20:22 +00002561 lBreak.pos = last->isText() ? last->length() : 0;
kociendabb0c24b2001-08-24 14:24:40 +00002562 }
hyatt275d0702005-11-03 23:53:57 +00002563 } else if (lBreak.obj) {
2564 if (last != o && !last->isListMarker()) {
bdakina964eb32005-10-24 17:47:26 +00002565 // better to break between object boundaries than in the middle of a word (except for list markers)
hyatt33f8d492002-11-12 21:44:52 +00002566 lBreak.obj = o;
2567 lBreak.pos = 0;
2568 } else {
hyattdda1d1b2002-12-13 09:44:17 +00002569 // Don't ever break in the middle of a word if we can help it.
2570 // There's no room at all. We just have to be on this line,
2571 // even though we'll spill out.
2572 lBreak.obj = o;
2573 lBreak.pos = pos;
hyatt33f8d492002-11-12 21:44:52 +00002574 }
kociendabb0c24b2001-08-24 14:24:40 +00002575 }
2576 }
2577
2578 // make sure we consume at least one char/object.
hyatt275d0702005-11-03 23:53:57 +00002579 if (lBreak == start)
mjsfe301d72003-10-02 18:46:18 +00002580 lBreak.increment(bidi);
hyatt33f8d492002-11-12 21:44:52 +00002581
hyattfe99c872003-07-31 22:25:29 +00002582 // Sanity check our midpoints.
mjsfe301d72003-10-02 18:46:18 +00002583 checkMidpoints(lBreak, bidi);
hyattfe99c872003-07-31 22:25:29 +00002584
hyatt33f8d492002-11-12 21:44:52 +00002585 if (trailingSpaceObject) {
2586 // This object is either going to be part of the last midpoint, or it is going
2587 // to be the actual endpoint. In both cases we just decrease our pos by 1 level to
2588 // exclude the space, allowing it to - in effect - collapse into the newline.
hyatt85586af2003-02-19 23:22:42 +00002589 if (sNumMidpoints%2==1) {
2590 BidiIterator* midpoints = smidpoints->data();
2591 midpoints[sNumMidpoints-1].pos--;
hyatt33f8d492002-11-12 21:44:52 +00002592 }
2593 //else if (lBreak.pos > 0)
2594 // lBreak.pos--;
2595 else if (lBreak.obj == 0 && trailingSpaceObject->isText()) {
hyattd20075d2002-11-16 02:23:32 +00002596 // Add a new end midpoint that stops right at the very end.
hyattd20075d2002-11-16 02:23:32 +00002597 RenderText* text = static_cast<RenderText *>(trailingSpaceObject);
darin42563ac52007-01-22 17:28:57 +00002598 unsigned length = text->textLength();
2599 unsigned pos = length >= 2 ? length - 2 : UINT_MAX;
eseidel789896f2005-11-27 22:52:09 +00002600 BidiIterator endMid(0, trailingSpaceObject, pos);
hyatt85586af2003-02-19 23:22:42 +00002601 addMidpoint(endMid);
hyatt33f8d492002-11-12 21:44:52 +00002602 }
2603 }
rjwc9c257d2003-01-24 03:46:17 +00002604
mjs54b64002003-04-02 02:59:02 +00002605 // We might have made lBreak an iterator that points past the end
2606 // of the object. Do this adjustment to make it point to the start
2607 // of the next object instead to avoid confusing the rest of the
2608 // code.
2609 if (lBreak.pos > 0) {
darin54008922006-01-13 16:39:05 +00002610 lBreak.pos--;
2611 lBreak.increment(bidi);
mjs54b64002003-04-02 02:59:02 +00002612 }
2613
hyatt78b85132004-03-29 20:07:45 +00002614 if (lBreak.obj && lBreak.pos >= 2 && lBreak.obj->isText()) {
2615 // For soft hyphens on line breaks, we have to chop out the midpoints that made us
2616 // ignore the hyphen so that it will render at the end of the line.
darin42563ac52007-01-22 17:28:57 +00002617 UChar c = static_cast<RenderText*>(lBreak.obj)->characters()[lBreak.pos-1];
2618 if (c == softHyphen)
hyatt78b85132004-03-29 20:07:45 +00002619 chopMidpointsAt(lBreak.obj, lBreak.pos-2);
2620 }
2621
kociendabb0c24b2001-08-24 14:24:40 +00002622 return lBreak;
2623}
2624
hyattb4b20872004-10-20 21:34:01 +00002625void RenderBlock::checkLinesForOverflow()
2626{
hyattb4b20872004-10-20 21:34:01 +00002627 m_overflowWidth = m_width;
2628 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
darin7bd70952006-04-13 07:07:34 +00002629 m_overflowLeft = min(curr->leftOverflow(), m_overflowLeft);
2630 m_overflowTop = min(curr->topOverflow(), m_overflowTop);
2631 m_overflowWidth = max(curr->rightOverflow(), m_overflowWidth);
2632 m_overflowHeight = max(curr->bottomOverflow(), m_overflowHeight);
hyattb4b20872004-10-20 21:34:01 +00002633 }
2634}
2635
hyatted77ad82004-06-15 07:21:23 +00002636void RenderBlock::deleteEllipsisLineBoxes()
2637{
hyatted77ad82004-06-15 07:21:23 +00002638 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox())
hyattda77c4b2004-06-17 18:09:49 +00002639 curr->clearTruncation();
hyatted77ad82004-06-15 07:21:23 +00002640}
2641
2642void RenderBlock::checkLinesForTextOverflow()
2643{
2644 // Determine the width of the ellipsis using the current font.
darindbba2bb2007-01-11 12:23:49 +00002645 // FIXME: CSS3 says this is configurable, also need to use 0x002E (FULL STOP) if horizontal ellipsis is "not renderable"
2646 TextRun ellipsisRun(&horizontalEllipsis, 1);
2647 static AtomicString ellipsisStr(&horizontalEllipsis, 1);
hyatt3e99d1c2006-02-24 21:13:08 +00002648 const Font& firstLineFont = firstLineStyle()->font();
2649 const Font& font = style()->font();
hyatt43d6c792006-05-11 10:19:34 +00002650 int firstLineEllipsisWidth = firstLineFont.width(ellipsisRun);
2651 int ellipsisWidth = (font == firstLineFont) ? firstLineEllipsisWidth : font.width(ellipsisRun);
hyatted77ad82004-06-15 07:21:23 +00002652
2653 // For LTR text truncation, we want to get the right edge of our padding box, and then we want to see
2654 // if the right edge of a line box exceeds that. For RTL, we use the left edge of the padding box and
2655 // check the left edge of the line box to see if it is less
2656 // Include the scrollbar for overflow blocks, which means we want to use "contentWidth()"
2657 bool ltr = style()->direction() == LTR;
hyatted77ad82004-06-15 07:21:23 +00002658 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
hyattda77c4b2004-06-17 18:09:49 +00002659 int blockEdge = ltr ? rightOffset(curr->yPos()) : leftOffset(curr->yPos());
hyatt1a8d2512004-06-17 01:38:30 +00002660 int lineBoxEdge = ltr ? curr->xPos() + curr->width() : curr->xPos();
hyatted77ad82004-06-15 07:21:23 +00002661 if ((ltr && lineBoxEdge > blockEdge) || (!ltr && lineBoxEdge < blockEdge)) {
hyattf918d2d2004-06-15 07:24:11 +00002662 // 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 +00002663 // can be truncated. In order for truncation to be possible, the line must have sufficient space to
2664 // accommodate our truncation string, and no replaced elements (images, tables) can overlap the ellipsis
2665 // space.
2666 int width = curr == firstRootBox() ? firstLineEllipsisWidth : ellipsisWidth;
hyatt1a8d2512004-06-17 01:38:30 +00002667 if (curr->canAccommodateEllipsis(ltr, blockEdge, lineBoxEdge, width))
2668 curr->placeEllipsis(ellipsisStr, ltr, blockEdge, width);
hyatted77ad82004-06-15 07:21:23 +00002669 }
2670 }
2671}
2672
hyattffe78712003-02-11 01:59:29 +00002673}