1 /*
2 * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2003, 2004, 2006, 2007, 2008 Apple Inc. All right reserved.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 *
20 */
21
22 #ifndef BidiResolver_h
23 #define BidiResolver_h
24
25 #include "BidiContext.h"
26 #include <wtf/Noncopyable.h>
27 #include <wtf/PassRefPtr.h>
28 #include <wtf/Vector.h>
29
30 namespace WebCore {
31
32 // The BidiStatus at a given position (typically the end of a line) can
33 // be cached and then used to restart bidi resolution at that position.
34 struct BidiStatus {
BidiStatusBidiStatus35 BidiStatus()
36 : eor(WTF::Unicode::OtherNeutral)
37 , lastStrong(WTF::Unicode::OtherNeutral)
38 , last(WTF::Unicode::OtherNeutral)
39 {
40 }
41
BidiStatusBidiStatus42 BidiStatus(WTF::Unicode::Direction eorDir, WTF::Unicode::Direction lastStrongDir, WTF::Unicode::Direction lastDir, PassRefPtr<BidiContext> bidiContext)
43 : eor(eorDir)
44 , lastStrong(lastStrongDir)
45 , last(lastDir)
46 , context(bidiContext)
47 {
48 }
49
50 WTF::Unicode::Direction eor;
51 WTF::Unicode::Direction lastStrong;
52 WTF::Unicode::Direction last;
53 RefPtr<BidiContext> context;
54 };
55
56 inline bool operator==(const BidiStatus& status1, const BidiStatus& status2)
57 {
58 return status1.eor == status2.eor && status1.last == status2.last && status1.lastStrong == status2.lastStrong && *(status1.context) == *(status2.context);
59 }
60
61 inline bool operator!=(const BidiStatus& status1, const BidiStatus& status2)
62 {
63 return !(status1 == status2);
64 }
65
66 struct BidiCharacterRun {
BidiCharacterRunBidiCharacterRun67 BidiCharacterRun(int start, int stop, BidiContext* context, WTF::Unicode::Direction dir)
68 : m_start(start)
69 , m_stop(stop)
70 , m_override(context->override())
71 , m_next(0)
72 {
73 if (dir == WTF::Unicode::OtherNeutral)
74 dir = context->dir();
75
76 m_level = context->level();
77
78 // add level of run (cases I1 & I2)
79 if (m_level % 2) {
80 if (dir == WTF::Unicode::LeftToRight || dir == WTF::Unicode::ArabicNumber || dir == WTF::Unicode::EuropeanNumber)
81 m_level++;
82 } else {
83 if (dir == WTF::Unicode::RightToLeft)
84 m_level++;
85 else if (dir == WTF::Unicode::ArabicNumber || dir == WTF::Unicode::EuropeanNumber)
86 m_level += 2;
87 }
88 }
89
destroyBidiCharacterRun90 void destroy() { delete this; }
91
startBidiCharacterRun92 int start() const { return m_start; }
stopBidiCharacterRun93 int stop() const { return m_stop; }
levelBidiCharacterRun94 unsigned char level() const { return m_level; }
reversedBidiCharacterRun95 bool reversed(bool visuallyOrdered) { return m_level % 2 && !visuallyOrdered; }
dirOverrideBidiCharacterRun96 bool dirOverride(bool visuallyOrdered) { return m_override || visuallyOrdered; }
97
nextBidiCharacterRun98 BidiCharacterRun* next() const { return m_next; }
99
100 unsigned char m_level;
101 int m_start;
102 int m_stop;
103 bool m_override;
104 BidiCharacterRun* m_next;
105 };
106
107 template <class Iterator, class Run> class BidiResolver : public Noncopyable {
108 public :
BidiResolver()109 BidiResolver()
110 : m_direction(WTF::Unicode::OtherNeutral)
111 , reachedEndOfLine(false)
112 , emptyRun(true)
113 , m_firstRun(0)
114 , m_lastRun(0)
115 , m_logicallyLastRun(0)
116 , m_runCount(0)
117 {
118 }
119
position()120 const Iterator& position() const { return current; }
setPosition(const Iterator & position)121 void setPosition(const Iterator& position) { current = position; }
122
increment()123 void increment() { current.increment(); }
124
context()125 BidiContext* context() const { return m_status.context.get(); }
setContext(PassRefPtr<BidiContext> c)126 void setContext(PassRefPtr<BidiContext> c) { m_status.context = c; }
127
setLastDir(WTF::Unicode::Direction lastDir)128 void setLastDir(WTF::Unicode::Direction lastDir) { m_status.last = lastDir; }
setLastStrongDir(WTF::Unicode::Direction lastStrongDir)129 void setLastStrongDir(WTF::Unicode::Direction lastStrongDir) { m_status.lastStrong = lastStrongDir; }
setEorDir(WTF::Unicode::Direction eorDir)130 void setEorDir(WTF::Unicode::Direction eorDir) { m_status.eor = eorDir; }
131
dir()132 WTF::Unicode::Direction dir() const { return m_direction; }
setDir(WTF::Unicode::Direction d)133 void setDir(WTF::Unicode::Direction d) { m_direction = d; }
134
status()135 const BidiStatus& status() const { return m_status; }
setStatus(const BidiStatus s)136 void setStatus(const BidiStatus s) { m_status = s; }
137
138 void embed(WTF::Unicode::Direction);
139 void commitExplicitEmbedding();
140
141 void createBidiRunsForLine(const Iterator& end, bool visualOrder = false, bool hardLineBreak = false);
142
firstRun()143 Run* firstRun() const { return m_firstRun; }
lastRun()144 Run* lastRun() const { return m_lastRun; }
logicallyLastRun()145 Run* logicallyLastRun() const { return m_logicallyLastRun; }
runCount()146 unsigned runCount() const { return m_runCount; }
147
148 void addRun(Run*);
149 void prependRun(Run*);
150
151 void moveRunToEnd(Run*);
152 void moveRunToBeginning(Run*);
153
154 void deleteRuns();
155
156 protected:
157 void appendRun();
158 void reverseRuns(unsigned start, unsigned end);
159
160 Iterator current;
161 Iterator sor;
162 Iterator eor;
163 Iterator last;
164 BidiStatus m_status;
165 WTF::Unicode::Direction m_direction;
166 Iterator endOfLine;
167 bool reachedEndOfLine;
168 Iterator lastBeforeET;
169 bool emptyRun;
170
171 Run* m_firstRun;
172 Run* m_lastRun;
173 Run* m_logicallyLastRun;
174 unsigned m_runCount;
175
176 private:
177 void raiseExplicitEmbeddingLevel(WTF::Unicode::Direction from, WTF::Unicode::Direction to);
178 void lowerExplicitEmbeddingLevel(WTF::Unicode::Direction from);
179
180 Vector<WTF::Unicode::Direction, 8> m_currentExplicitEmbeddingSequence;
181 };
182
183 template <class Iterator, class Run>
addRun(Run * run)184 inline void BidiResolver<Iterator, Run>::addRun(Run* run)
185 {
186 if (!m_firstRun)
187 m_firstRun = run;
188 else
189 m_lastRun->m_next = run;
190 m_lastRun = run;
191 m_runCount++;
192 }
193
194 template <class Iterator, class Run>
prependRun(Run * run)195 inline void BidiResolver<Iterator, Run>::prependRun(Run* run)
196 {
197 ASSERT(!run->m_next);
198
199 if (!m_lastRun)
200 m_lastRun = run;
201 else
202 run->m_next = m_firstRun;
203 m_firstRun = run;
204 m_runCount++;
205 }
206
207 template <class Iterator, class Run>
moveRunToEnd(Run * run)208 inline void BidiResolver<Iterator, Run>::moveRunToEnd(Run* run)
209 {
210 ASSERT(m_firstRun);
211 ASSERT(m_lastRun);
212 ASSERT(run->m_next);
213
214 Run* current = 0;
215 Run* next = m_firstRun;
216 while (next != run) {
217 current = next;
218 next = current->next();
219 }
220
221 if (!current)
222 m_firstRun = run->next();
223 else
224 current->m_next = run->m_next;
225
226 run->m_next = 0;
227 m_lastRun->m_next = run;
228 m_lastRun = run;
229 }
230
231 template <class Iterator, class Run>
moveRunToBeginning(Run * run)232 inline void BidiResolver<Iterator, Run>::moveRunToBeginning(Run* run)
233 {
234 ASSERT(m_firstRun);
235 ASSERT(m_lastRun);
236 ASSERT(run != m_firstRun);
237
238 Run* current = m_firstRun;
239 Run* next = current->next();
240 while (next != run) {
241 current = next;
242 next = current->next();
243 }
244
245 current->m_next = run->m_next;
246 if (run == m_lastRun)
247 m_lastRun = current;
248
249 run->m_next = m_firstRun;
250 m_firstRun = run;
251 }
252
253 template <class Iterator, class Run>
appendRun()254 void BidiResolver<Iterator, Run>::appendRun()
255 {
256 if (!emptyRun && !eor.atEnd()) {
257 addRun(new Run(sor.offset(), eor.offset() + 1, context(), m_direction));
258
259 eor.increment();
260 sor = eor;
261 }
262
263 m_direction = WTF::Unicode::OtherNeutral;
264 m_status.eor = WTF::Unicode::OtherNeutral;
265 }
266
267 template <class Iterator, class Run>
embed(WTF::Unicode::Direction d)268 void BidiResolver<Iterator, Run>::embed(WTF::Unicode::Direction d)
269 {
270 using namespace WTF::Unicode;
271
272 ASSERT(d == PopDirectionalFormat || d == LeftToRightEmbedding || d == LeftToRightOverride || d == RightToLeftEmbedding || d == RightToLeftOverride);
273 m_currentExplicitEmbeddingSequence.append(d);
274 }
275
276 template <class Iterator, class Run>
lowerExplicitEmbeddingLevel(WTF::Unicode::Direction from)277 void BidiResolver<Iterator, Run>::lowerExplicitEmbeddingLevel(WTF::Unicode::Direction from)
278 {
279 using namespace WTF::Unicode;
280
281 if (!emptyRun && eor != last) {
282 ASSERT(m_status.eor != OtherNeutral || eor.atEnd());
283 // bidi.sor ... bidi.eor ... bidi.last eor; need to append the bidi.sor-bidi.eor run or extend it through bidi.last
284 ASSERT(m_status.last == EuropeanNumberSeparator
285 || m_status.last == EuropeanNumberTerminator
286 || m_status.last == CommonNumberSeparator
287 || m_status.last == BoundaryNeutral
288 || m_status.last == BlockSeparator
289 || m_status.last == SegmentSeparator
290 || m_status.last == WhiteSpaceNeutral
291 || m_status.last == OtherNeutral);
292 if (m_direction == OtherNeutral)
293 m_direction = m_status.lastStrong == LeftToRight ? LeftToRight : RightToLeft;
294 if (from == LeftToRight) {
295 // bidi.sor ... bidi.eor ... bidi.last L
296 if (m_status.eor == EuropeanNumber) {
297 if (m_status.lastStrong != LeftToRight) {
298 m_direction = EuropeanNumber;
299 appendRun();
300 }
301 } else if (m_status.eor == ArabicNumber) {
302 m_direction = ArabicNumber;
303 appendRun();
304 } else if (m_status.lastStrong != LeftToRight) {
305 appendRun();
306 m_direction = LeftToRight;
307 }
308 } else if (m_status.eor == EuropeanNumber || m_status.eor == ArabicNumber || m_status.lastStrong == LeftToRight) {
309 appendRun();
310 m_direction = RightToLeft;
311 }
312 eor = last;
313 }
314 appendRun();
315 emptyRun = true;
316 // sor for the new run is determined by the higher level (rule X10)
317 setLastDir(from);
318 setLastStrongDir(from);
319 eor = Iterator();
320 }
321
322 template <class Iterator, class Run>
raiseExplicitEmbeddingLevel(WTF::Unicode::Direction from,WTF::Unicode::Direction to)323 void BidiResolver<Iterator, Run>::raiseExplicitEmbeddingLevel(WTF::Unicode::Direction from, WTF::Unicode::Direction to)
324 {
325 using namespace WTF::Unicode;
326
327 if (!emptyRun && eor != last) {
328 ASSERT(m_status.eor != OtherNeutral || eor.atEnd());
329 // bidi.sor ... bidi.eor ... bidi.last eor; need to append the bidi.sor-bidi.eor run or extend it through bidi.last
330 ASSERT(m_status.last == EuropeanNumberSeparator
331 || m_status.last == EuropeanNumberTerminator
332 || m_status.last == CommonNumberSeparator
333 || m_status.last == BoundaryNeutral
334 || m_status.last == BlockSeparator
335 || m_status.last == SegmentSeparator
336 || m_status.last == WhiteSpaceNeutral
337 || m_status.last == OtherNeutral);
338 if (m_direction == OtherNeutral)
339 m_direction = m_status.lastStrong == LeftToRight ? LeftToRight : RightToLeft;
340 if (to == LeftToRight) {
341 // bidi.sor ... bidi.eor ... bidi.last L
342 if (m_status.eor == EuropeanNumber) {
343 if (m_status.lastStrong != LeftToRight) {
344 m_direction = EuropeanNumber;
345 appendRun();
346 }
347 } else if (m_status.eor == ArabicNumber) {
348 m_direction = ArabicNumber;
349 appendRun();
350 } else if (m_status.lastStrong != LeftToRight && from == LeftToRight) {
351 appendRun();
352 m_direction = LeftToRight;
353 }
354 } else if (m_status.eor == ArabicNumber
355 || m_status.eor == EuropeanNumber && (m_status.lastStrong != LeftToRight || from == RightToLeft)
356 || m_status.eor != EuropeanNumber && m_status.lastStrong == LeftToRight && from == RightToLeft) {
357 appendRun();
358 m_direction = RightToLeft;
359 }
360 eor = last;
361 }
362 appendRun();
363 emptyRun = true;
364 setLastDir(to);
365 setLastStrongDir(to);
366 eor = Iterator();
367 }
368
369 template <class Iterator, class Run>
commitExplicitEmbedding()370 void BidiResolver<Iterator, Run>::commitExplicitEmbedding()
371 {
372 using namespace WTF::Unicode;
373
374 unsigned char fromLevel = context()->level();
375 RefPtr<BidiContext> toContext = context();
376
377 for (size_t i = 0; i < m_currentExplicitEmbeddingSequence.size(); ++i) {
378 Direction embedding = m_currentExplicitEmbeddingSequence[i];
379 if (embedding == PopDirectionalFormat) {
380 if (BidiContext* parentContext = toContext->parent())
381 toContext = parentContext;
382 } else {
383 Direction direction = (embedding == RightToLeftEmbedding || embedding == RightToLeftOverride) ? RightToLeft : LeftToRight;
384 bool override = embedding == LeftToRightOverride || embedding == RightToLeftOverride;
385 unsigned char level = toContext->level();
386 if (direction == RightToLeft) {
387 // Go to the least greater odd integer
388 level += 1;
389 level |= 1;
390 } else {
391 // Go to the least greater even integer
392 level += 2;
393 level &= ~1;
394 }
395 if (level < 61)
396 toContext = new BidiContext(level, direction, override, toContext.get());
397 }
398 }
399
400 unsigned char toLevel = toContext->level();
401
402 if (toLevel > fromLevel)
403 raiseExplicitEmbeddingLevel(fromLevel % 2 ? RightToLeft : LeftToRight, toLevel % 2 ? RightToLeft : LeftToRight);
404 else if (toLevel < fromLevel)
405 lowerExplicitEmbeddingLevel(fromLevel % 2 ? RightToLeft : LeftToRight);
406
407 setContext(toContext);
408
409 m_currentExplicitEmbeddingSequence.clear();
410 }
411
412 template <class Iterator, class Run>
deleteRuns()413 void BidiResolver<Iterator, Run>::deleteRuns()
414 {
415 emptyRun = true;
416 if (!m_firstRun)
417 return;
418
419 Run* curr = m_firstRun;
420 while (curr) {
421 Run* s = curr->next();
422 curr->destroy();
423 curr = s;
424 }
425
426 m_firstRun = 0;
427 m_lastRun = 0;
428 m_runCount = 0;
429 }
430
431 template <class Iterator, class Run>
reverseRuns(unsigned start,unsigned end)432 void BidiResolver<Iterator, Run>::reverseRuns(unsigned start, unsigned end)
433 {
434 if (start >= end)
435 return;
436
437 ASSERT(end < m_runCount);
438
439 // Get the item before the start of the runs to reverse and put it in
440 // |beforeStart|. |curr| should point to the first run to reverse.
441 Run* curr = m_firstRun;
442 Run* beforeStart = 0;
443 unsigned i = 0;
444 while (i < start) {
445 i++;
446 beforeStart = curr;
447 curr = curr->next();
448 }
449
450 Run* startRun = curr;
451 while (i < end) {
452 i++;
453 curr = curr->next();
454 }
455 Run* endRun = curr;
456 Run* afterEnd = curr->next();
457
458 i = start;
459 curr = startRun;
460 Run* newNext = afterEnd;
461 while (i <= end) {
462 // Do the reversal.
463 Run* next = curr->next();
464 curr->m_next = newNext;
465 newNext = curr;
466 curr = next;
467 i++;
468 }
469
470 // Now hook up beforeStart and afterEnd to the startRun and endRun.
471 if (beforeStart)
472 beforeStart->m_next = endRun;
473 else
474 m_firstRun = endRun;
475
476 startRun->m_next = afterEnd;
477 if (!afterEnd)
478 m_lastRun = startRun;
479 }
480
481 template <class Iterator, class Run>
createBidiRunsForLine(const Iterator & end,bool visualOrder,bool hardLineBreak)482 void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, bool visualOrder, bool hardLineBreak)
483 {
484 using namespace WTF::Unicode;
485
486 ASSERT(m_direction == OtherNeutral);
487
488 emptyRun = true;
489
490 eor = Iterator();
491
492 last = current;
493 bool pastEnd = false;
494 BidiResolver<Iterator, Run> stateAtEnd;
495
496 while (true) {
497 Direction dirCurrent;
498 if (pastEnd && (hardLineBreak || current.atEnd())) {
499 BidiContext* c = context();
500 while (c->parent())
501 c = c->parent();
502 dirCurrent = c->dir();
503 if (hardLineBreak) {
504 // A deviation from the Unicode Bidi Algorithm in order to match
505 // Mac OS X text and WinIE: a hard line break resets bidi state.
506 stateAtEnd.setContext(c);
507 stateAtEnd.setEorDir(dirCurrent);
508 stateAtEnd.setLastDir(dirCurrent);
509 stateAtEnd.setLastStrongDir(dirCurrent);
510 }
511 } else {
512 dirCurrent = current.direction();
513 if (context()->override()
514 && dirCurrent != RightToLeftEmbedding
515 && dirCurrent != LeftToRightEmbedding
516 && dirCurrent != RightToLeftOverride
517 && dirCurrent != LeftToRightOverride
518 && dirCurrent != PopDirectionalFormat)
519 dirCurrent = context()->dir();
520 else if (dirCurrent == NonSpacingMark)
521 dirCurrent = m_status.last;
522 }
523
524 ASSERT(m_status.eor != OtherNeutral || eor.atEnd());
525 switch (dirCurrent) {
526
527 // embedding and overrides (X1-X9 in the Bidi specs)
528 case RightToLeftEmbedding:
529 case LeftToRightEmbedding:
530 case RightToLeftOverride:
531 case LeftToRightOverride:
532 case PopDirectionalFormat:
533 embed(dirCurrent);
534 commitExplicitEmbedding();
535 break;
536
537 // strong types
538 case LeftToRight:
539 switch(m_status.last) {
540 case RightToLeft:
541 case RightToLeftArabic:
542 case EuropeanNumber:
543 case ArabicNumber:
544 if (m_status.last != EuropeanNumber || m_status.lastStrong != LeftToRight)
545 appendRun();
546 break;
547 case LeftToRight:
548 break;
549 case EuropeanNumberSeparator:
550 case EuropeanNumberTerminator:
551 case CommonNumberSeparator:
552 case BoundaryNeutral:
553 case BlockSeparator:
554 case SegmentSeparator:
555 case WhiteSpaceNeutral:
556 case OtherNeutral:
557 if (m_status.eor == EuropeanNumber) {
558 if (m_status.lastStrong != LeftToRight) {
559 // the numbers need to be on a higher embedding level, so let's close that run
560 m_direction = EuropeanNumber;
561 appendRun();
562 if (context()->dir() != LeftToRight) {
563 // the neutrals take the embedding direction, which is R
564 eor = last;
565 m_direction = RightToLeft;
566 appendRun();
567 }
568 }
569 } else if (m_status.eor == ArabicNumber) {
570 // Arabic numbers are always on a higher embedding level, so let's close that run
571 m_direction = ArabicNumber;
572 appendRun();
573 if (context()->dir() != LeftToRight) {
574 // the neutrals take the embedding direction, which is R
575 eor = last;
576 m_direction = RightToLeft;
577 appendRun();
578 }
579 } else if (m_status.lastStrong != LeftToRight) {
580 //last stuff takes embedding dir
581 if (context()->dir() == RightToLeft) {
582 eor = last;
583 m_direction = RightToLeft;
584 }
585 appendRun();
586 }
587 default:
588 break;
589 }
590 eor = current;
591 m_status.eor = LeftToRight;
592 m_status.lastStrong = LeftToRight;
593 m_direction = LeftToRight;
594 break;
595 case RightToLeftArabic:
596 case RightToLeft:
597 switch (m_status.last) {
598 case LeftToRight:
599 case EuropeanNumber:
600 case ArabicNumber:
601 appendRun();
602 case RightToLeft:
603 case RightToLeftArabic:
604 break;
605 case EuropeanNumberSeparator:
606 case EuropeanNumberTerminator:
607 case CommonNumberSeparator:
608 case BoundaryNeutral:
609 case BlockSeparator:
610 case SegmentSeparator:
611 case WhiteSpaceNeutral:
612 case OtherNeutral:
613 if (m_status.eor == EuropeanNumber) {
614 if (m_status.lastStrong == LeftToRight && context()->dir() == LeftToRight)
615 eor = last;
616 appendRun();
617 } else if (m_status.eor == ArabicNumber)
618 appendRun();
619 else if (m_status.lastStrong == LeftToRight) {
620 if (context()->dir() == LeftToRight)
621 eor = last;
622 appendRun();
623 }
624 default:
625 break;
626 }
627 eor = current;
628 m_status.eor = RightToLeft;
629 m_status.lastStrong = dirCurrent;
630 m_direction = RightToLeft;
631 break;
632
633 // weak types:
634
635 case EuropeanNumber:
636 if (m_status.lastStrong != RightToLeftArabic) {
637 // if last strong was AL change EN to AN
638 switch (m_status.last) {
639 case EuropeanNumber:
640 case LeftToRight:
641 break;
642 case RightToLeft:
643 case RightToLeftArabic:
644 case ArabicNumber:
645 eor = last;
646 appendRun();
647 m_direction = EuropeanNumber;
648 break;
649 case EuropeanNumberSeparator:
650 case CommonNumberSeparator:
651 if (m_status.eor == EuropeanNumber)
652 break;
653 case EuropeanNumberTerminator:
654 case BoundaryNeutral:
655 case BlockSeparator:
656 case SegmentSeparator:
657 case WhiteSpaceNeutral:
658 case OtherNeutral:
659 if (m_status.eor == EuropeanNumber) {
660 if (m_status.lastStrong == RightToLeft) {
661 // ENs on both sides behave like Rs, so the neutrals should be R.
662 // Terminate the EN run.
663 appendRun();
664 // Make an R run.
665 eor = m_status.last == EuropeanNumberTerminator ? lastBeforeET : last;
666 m_direction = RightToLeft;
667 appendRun();
668 // Begin a new EN run.
669 m_direction = EuropeanNumber;
670 }
671 } else if (m_status.eor == ArabicNumber) {
672 // Terminate the AN run.
673 appendRun();
674 if (m_status.lastStrong == RightToLeft || context()->dir() == RightToLeft) {
675 // Make an R run.
676 eor = m_status.last == EuropeanNumberTerminator ? lastBeforeET : last;
677 m_direction = RightToLeft;
678 appendRun();
679 // Begin a new EN run.
680 m_direction = EuropeanNumber;
681 }
682 } else if (m_status.lastStrong == RightToLeft) {
683 // Extend the R run to include the neutrals.
684 eor = m_status.last == EuropeanNumberTerminator ? lastBeforeET : last;
685 m_direction = RightToLeft;
686 appendRun();
687 // Begin a new EN run.
688 m_direction = EuropeanNumber;
689 }
690 default:
691 break;
692 }
693 eor = current;
694 m_status.eor = EuropeanNumber;
695 if (m_direction == OtherNeutral)
696 m_direction = LeftToRight;
697 break;
698 }
699 case ArabicNumber:
700 dirCurrent = ArabicNumber;
701 switch (m_status.last) {
702 case LeftToRight:
703 if (context()->dir() == LeftToRight)
704 appendRun();
705 break;
706 case ArabicNumber:
707 break;
708 case RightToLeft:
709 case RightToLeftArabic:
710 case EuropeanNumber:
711 eor = last;
712 appendRun();
713 break;
714 case CommonNumberSeparator:
715 if (m_status.eor == ArabicNumber)
716 break;
717 case EuropeanNumberSeparator:
718 case EuropeanNumberTerminator:
719 case BoundaryNeutral:
720 case BlockSeparator:
721 case SegmentSeparator:
722 case WhiteSpaceNeutral:
723 case OtherNeutral:
724 if (m_status.eor == ArabicNumber
725 || m_status.eor == EuropeanNumber && (m_status.lastStrong == RightToLeft || context()->dir() == RightToLeft)
726 || m_status.eor != EuropeanNumber && m_status.lastStrong == LeftToRight && context()->dir() == RightToLeft) {
727 // Terminate the run before the neutrals.
728 appendRun();
729 // Begin an R run for the neutrals.
730 m_direction = RightToLeft;
731 } else if (m_direction == OtherNeutral)
732 m_direction = m_status.lastStrong == LeftToRight ? LeftToRight : RightToLeft;
733 eor = last;
734 appendRun();
735 default:
736 break;
737 }
738 eor = current;
739 m_status.eor = ArabicNumber;
740 if (m_direction == OtherNeutral)
741 m_direction = ArabicNumber;
742 break;
743 case EuropeanNumberSeparator:
744 case CommonNumberSeparator:
745 break;
746 case EuropeanNumberTerminator:
747 if (m_status.last == EuropeanNumber) {
748 dirCurrent = EuropeanNumber;
749 eor = current;
750 m_status.eor = dirCurrent;
751 } else if (m_status.last != EuropeanNumberTerminator)
752 lastBeforeET = emptyRun ? eor : last;
753 break;
754
755 // boundary neutrals should be ignored
756 case BoundaryNeutral:
757 if (eor == last)
758 eor = current;
759 break;
760 // neutrals
761 case BlockSeparator:
762 // ### what do we do with newline and paragraph seperators that come to here?
763 break;
764 case SegmentSeparator:
765 // ### implement rule L1
766 break;
767 case WhiteSpaceNeutral:
768 break;
769 case OtherNeutral:
770 break;
771 default:
772 break;
773 }
774
775 if (pastEnd) {
776 if (eor == current) {
777 if (!reachedEndOfLine) {
778 eor = endOfLine;
779 switch (m_status.eor) {
780 case LeftToRight:
781 case RightToLeft:
782 case ArabicNumber:
783 m_direction = m_status.eor;
784 break;
785 case EuropeanNumber:
786 m_direction = m_status.lastStrong == LeftToRight ? LeftToRight : EuropeanNumber;
787 break;
788 default:
789 ASSERT(false);
790 }
791 appendRun();
792 }
793 current = end;
794 m_status = stateAtEnd.m_status;
795 sor = stateAtEnd.sor;
796 eor = stateAtEnd.eor;
797 last = stateAtEnd.last;
798 reachedEndOfLine = stateAtEnd.reachedEndOfLine;
799 lastBeforeET = stateAtEnd.lastBeforeET;
800 emptyRun = stateAtEnd.emptyRun;
801 m_direction = OtherNeutral;
802 break;
803 }
804 }
805
806 // set m_status.last as needed.
807 switch (dirCurrent) {
808 case EuropeanNumberTerminator:
809 if (m_status.last != EuropeanNumber)
810 m_status.last = EuropeanNumberTerminator;
811 break;
812 case EuropeanNumberSeparator:
813 case CommonNumberSeparator:
814 case SegmentSeparator:
815 case WhiteSpaceNeutral:
816 case OtherNeutral:
817 switch(m_status.last) {
818 case LeftToRight:
819 case RightToLeft:
820 case RightToLeftArabic:
821 case EuropeanNumber:
822 case ArabicNumber:
823 m_status.last = dirCurrent;
824 break;
825 default:
826 m_status.last = OtherNeutral;
827 }
828 break;
829 case NonSpacingMark:
830 case BoundaryNeutral:
831 case RightToLeftEmbedding:
832 case LeftToRightEmbedding:
833 case RightToLeftOverride:
834 case LeftToRightOverride:
835 case PopDirectionalFormat:
836 // ignore these
837 break;
838 case EuropeanNumber:
839 // fall through
840 default:
841 m_status.last = dirCurrent;
842 }
843
844 last = current;
845
846 if (emptyRun && !(dirCurrent == RightToLeftEmbedding
847 || dirCurrent == LeftToRightEmbedding
848 || dirCurrent == RightToLeftOverride
849 || dirCurrent == LeftToRightOverride
850 || dirCurrent == PopDirectionalFormat)) {
851 sor = current;
852 emptyRun = false;
853 }
854
855 increment();
856 if (!m_currentExplicitEmbeddingSequence.isEmpty())
857 commitExplicitEmbedding();
858
859 if (emptyRun && (dirCurrent == RightToLeftEmbedding
860 || dirCurrent == LeftToRightEmbedding
861 || dirCurrent == RightToLeftOverride
862 || dirCurrent == LeftToRightOverride
863 || dirCurrent == PopDirectionalFormat)) {
864 // exclude the embedding char itself from the new run so that ATSUI will never see it
865 eor = Iterator();
866 last = current;
867 sor = current;
868 }
869
870 if (!pastEnd && (current == end || current.atEnd())) {
871 if (emptyRun)
872 break;
873 stateAtEnd.m_status = m_status;
874 stateAtEnd.sor = sor;
875 stateAtEnd.eor = eor;
876 stateAtEnd.last = last;
877 stateAtEnd.reachedEndOfLine = reachedEndOfLine;
878 stateAtEnd.lastBeforeET = lastBeforeET;
879 stateAtEnd.emptyRun = emptyRun;
880 endOfLine = last;
881 pastEnd = true;
882 }
883 }
884
885 m_logicallyLastRun = m_lastRun;
886
887 // reorder line according to run structure...
888 // do not reverse for visually ordered web sites
889 if (!visualOrder) {
890
891 // first find highest and lowest levels
892 unsigned char levelLow = 128;
893 unsigned char levelHigh = 0;
894 Run* r = firstRun();
895 while (r) {
896 if (r->m_level > levelHigh)
897 levelHigh = r->m_level;
898 if (r->m_level < levelLow)
899 levelLow = r->m_level;
900 r = r->next();
901 }
902
903 // implements reordering of the line (L2 according to Bidi spec):
904 // L2. From the highest level found in the text to the lowest odd level on each line,
905 // reverse any contiguous sequence of characters that are at that level or higher.
906
907 // reversing is only done up to the lowest odd level
908 if (!(levelLow % 2))
909 levelLow++;
910
911 unsigned count = runCount() - 1;
912
913 while (levelHigh >= levelLow) {
914 unsigned i = 0;
915 Run* currRun = firstRun();
916 while (i < count) {
917 while (i < count && currRun && currRun->m_level < levelHigh) {
918 i++;
919 currRun = currRun->next();
920 }
921 unsigned start = i;
922 while (i <= count && currRun && currRun->m_level >= levelHigh) {
923 i++;
924 currRun = currRun->next();
925 }
926 unsigned end = i - 1;
927 reverseRuns(start, end);
928 }
929 levelHigh--;
930 }
931 }
932 endOfLine = Iterator();
933 }
934
935 } // namespace WebCore
936
937 #endif // BidiResolver_h
938