]> git.saurik.com Git - iphone-api.git/blob - WebCore/BidiResolver.h
Add support for new WinterBoard Settings features.
[iphone-api.git] / WebCore / BidiResolver.h
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 {
35 BidiStatus()
36 : eor(WTF::Unicode::OtherNeutral)
37 , lastStrong(WTF::Unicode::OtherNeutral)
38 , last(WTF::Unicode::OtherNeutral)
39 {
40 }
41
42 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 {
67 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
90 void destroy() { delete this; }
91
92 int start() const { return m_start; }
93 int stop() const { return m_stop; }
94 unsigned char level() const { return m_level; }
95 bool reversed(bool visuallyOrdered) { return m_level % 2 && !visuallyOrdered; }
96 bool dirOverride(bool visuallyOrdered) { return m_override || visuallyOrdered; }
97
98 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 :
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
120 const Iterator& position() const { return current; }
121 void setPosition(const Iterator& position) { current = position; }
122
123 void increment() { current.increment(); }
124
125 BidiContext* context() const { return m_status.context.get(); }
126 void setContext(PassRefPtr<BidiContext> c) { m_status.context = c; }
127
128 void setLastDir(WTF::Unicode::Direction lastDir) { m_status.last = lastDir; }
129 void setLastStrongDir(WTF::Unicode::Direction lastStrongDir) { m_status.lastStrong = lastStrongDir; }
130 void setEorDir(WTF::Unicode::Direction eorDir) { m_status.eor = eorDir; }
131
132 WTF::Unicode::Direction dir() const { return m_direction; }
133 void setDir(WTF::Unicode::Direction d) { m_direction = d; }
134
135 const BidiStatus& status() const { return m_status; }
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
143 Run* firstRun() const { return m_firstRun; }
144 Run* lastRun() const { return m_lastRun; }
145 Run* logicallyLastRun() const { return m_logicallyLastRun; }
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>
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>
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>
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>
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>
254 void BidiResolver<Iterator, Run>::appendRun()
255 {
256 if (!emptyRun && !eor.atEnd()) {
257 unsigned startOffset = sor.offset();
258 unsigned endOffset = eor.offset();
259
260 if (!endOfLine.atEnd() && endOffset >= endOfLine.offset()) {
261 reachedEndOfLine = true;
262 endOffset = endOfLine.offset();
263 }
264
265 if (endOffset >= startOffset)
266 addRun(new Run(startOffset, endOffset + 1, context(), m_direction));
267
268 eor.increment();
269 sor = eor;
270 }
271
272 m_direction = WTF::Unicode::OtherNeutral;
273 m_status.eor = WTF::Unicode::OtherNeutral;
274 }
275
276 template <class Iterator, class Run>
277 void BidiResolver<Iterator, Run>::embed(WTF::Unicode::Direction d)
278 {
279 using namespace WTF::Unicode;
280
281 ASSERT(d == PopDirectionalFormat || d == LeftToRightEmbedding || d == LeftToRightOverride || d == RightToLeftEmbedding || d == RightToLeftOverride);
282 m_currentExplicitEmbeddingSequence.append(d);
283 }
284
285 template <class Iterator, class Run>
286 void BidiResolver<Iterator, Run>::lowerExplicitEmbeddingLevel(WTF::Unicode::Direction from)
287 {
288 using namespace WTF::Unicode;
289
290 if (!emptyRun && eor != last) {
291 ASSERT(m_status.eor != OtherNeutral || eor.atEnd());
292 // bidi.sor ... bidi.eor ... bidi.last eor; need to append the bidi.sor-bidi.eor run or extend it through bidi.last
293 ASSERT(m_status.last == EuropeanNumberSeparator
294 || m_status.last == EuropeanNumberTerminator
295 || m_status.last == CommonNumberSeparator
296 || m_status.last == BoundaryNeutral
297 || m_status.last == BlockSeparator
298 || m_status.last == SegmentSeparator
299 || m_status.last == WhiteSpaceNeutral
300 || m_status.last == OtherNeutral);
301 if (m_direction == OtherNeutral)
302 m_direction = m_status.lastStrong == LeftToRight ? LeftToRight : RightToLeft;
303 if (from == LeftToRight) {
304 // bidi.sor ... bidi.eor ... bidi.last L
305 if (m_status.eor == EuropeanNumber) {
306 if (m_status.lastStrong != LeftToRight) {
307 m_direction = EuropeanNumber;
308 appendRun();
309 }
310 } else if (m_status.eor == ArabicNumber) {
311 m_direction = ArabicNumber;
312 appendRun();
313 } else if (m_status.lastStrong != LeftToRight) {
314 appendRun();
315 m_direction = LeftToRight;
316 }
317 } else if (m_status.eor == EuropeanNumber || m_status.eor == ArabicNumber || m_status.lastStrong == LeftToRight) {
318 appendRun();
319 m_direction = RightToLeft;
320 }
321 eor = last;
322 }
323 appendRun();
324 emptyRun = true;
325 // sor for the new run is determined by the higher level (rule X10)
326 setLastDir(from);
327 setLastStrongDir(from);
328 eor = Iterator();
329 }
330
331 template <class Iterator, class Run>
332 void BidiResolver<Iterator, Run>::raiseExplicitEmbeddingLevel(WTF::Unicode::Direction from, WTF::Unicode::Direction to)
333 {
334 using namespace WTF::Unicode;
335
336 if (!emptyRun && eor != last) {
337 ASSERT(m_status.eor != OtherNeutral || eor.atEnd());
338 // bidi.sor ... bidi.eor ... bidi.last eor; need to append the bidi.sor-bidi.eor run or extend it through bidi.last
339 ASSERT(m_status.last == EuropeanNumberSeparator
340 || m_status.last == EuropeanNumberTerminator
341 || m_status.last == CommonNumberSeparator
342 || m_status.last == BoundaryNeutral
343 || m_status.last == BlockSeparator
344 || m_status.last == SegmentSeparator
345 || m_status.last == WhiteSpaceNeutral
346 || m_status.last == OtherNeutral);
347 if (m_direction == OtherNeutral)
348 m_direction = m_status.lastStrong == LeftToRight ? LeftToRight : RightToLeft;
349 if (to == LeftToRight) {
350 // bidi.sor ... bidi.eor ... bidi.last L
351 if (m_status.eor == EuropeanNumber) {
352 if (m_status.lastStrong != LeftToRight) {
353 m_direction = EuropeanNumber;
354 appendRun();
355 }
356 } else if (m_status.eor == ArabicNumber) {
357 m_direction = ArabicNumber;
358 appendRun();
359 } else if (m_status.lastStrong != LeftToRight && from == LeftToRight) {
360 appendRun();
361 m_direction = LeftToRight;
362 }
363 } else if (m_status.eor == ArabicNumber
364 || m_status.eor == EuropeanNumber && (m_status.lastStrong != LeftToRight || from == RightToLeft)
365 || m_status.eor != EuropeanNumber && m_status.lastStrong == LeftToRight && from == RightToLeft) {
366 appendRun();
367 m_direction = RightToLeft;
368 }
369 eor = last;
370 }
371 appendRun();
372 emptyRun = true;
373 setLastDir(to);
374 setLastStrongDir(to);
375 eor = Iterator();
376 }
377
378 template <class Iterator, class Run>
379 void BidiResolver<Iterator, Run>::commitExplicitEmbedding()
380 {
381 using namespace WTF::Unicode;
382
383 unsigned char fromLevel = context()->level();
384 RefPtr<BidiContext> toContext = context();
385
386 for (size_t i = 0; i < m_currentExplicitEmbeddingSequence.size(); ++i) {
387 Direction embedding = m_currentExplicitEmbeddingSequence[i];
388 if (embedding == PopDirectionalFormat) {
389 if (BidiContext* parentContext = toContext->parent())
390 toContext = parentContext;
391 } else {
392 Direction direction = (embedding == RightToLeftEmbedding || embedding == RightToLeftOverride) ? RightToLeft : LeftToRight;
393 bool override = embedding == LeftToRightOverride || embedding == RightToLeftOverride;
394 unsigned char level = toContext->level();
395 if (direction == RightToLeft) {
396 // Go to the least greater odd integer
397 level += 1;
398 level |= 1;
399 } else {
400 // Go to the least greater even integer
401 level += 2;
402 level &= ~1;
403 }
404 if (level < 61)
405 toContext = new BidiContext(level, direction, override, toContext.get());
406 }
407 }
408
409 unsigned char toLevel = toContext->level();
410
411 if (toLevel > fromLevel)
412 raiseExplicitEmbeddingLevel(fromLevel % 2 ? RightToLeft : LeftToRight, toLevel % 2 ? RightToLeft : LeftToRight);
413 else if (toLevel < fromLevel)
414 lowerExplicitEmbeddingLevel(fromLevel % 2 ? RightToLeft : LeftToRight);
415
416 setContext(toContext);
417
418 m_currentExplicitEmbeddingSequence.clear();
419 }
420
421 template <class Iterator, class Run>
422 void BidiResolver<Iterator, Run>::deleteRuns()
423 {
424 emptyRun = true;
425 if (!m_firstRun)
426 return;
427
428 Run* curr = m_firstRun;
429 while (curr) {
430 Run* s = curr->next();
431 curr->destroy();
432 curr = s;
433 }
434
435 m_firstRun = 0;
436 m_lastRun = 0;
437 m_runCount = 0;
438 }
439
440 template <class Iterator, class Run>
441 void BidiResolver<Iterator, Run>::reverseRuns(unsigned start, unsigned end)
442 {
443 if (start >= end)
444 return;
445
446 ASSERT(end < m_runCount);
447
448 // Get the item before the start of the runs to reverse and put it in
449 // |beforeStart|. |curr| should point to the first run to reverse.
450 Run* curr = m_firstRun;
451 Run* beforeStart = 0;
452 unsigned i = 0;
453 while (i < start) {
454 i++;
455 beforeStart = curr;
456 curr = curr->next();
457 }
458
459 Run* startRun = curr;
460 while (i < end) {
461 i++;
462 curr = curr->next();
463 }
464 Run* endRun = curr;
465 Run* afterEnd = curr->next();
466
467 i = start;
468 curr = startRun;
469 Run* newNext = afterEnd;
470 while (i <= end) {
471 // Do the reversal.
472 Run* next = curr->next();
473 curr->m_next = newNext;
474 newNext = curr;
475 curr = next;
476 i++;
477 }
478
479 // Now hook up beforeStart and afterEnd to the startRun and endRun.
480 if (beforeStart)
481 beforeStart->m_next = endRun;
482 else
483 m_firstRun = endRun;
484
485 startRun->m_next = afterEnd;
486 if (!afterEnd)
487 m_lastRun = startRun;
488 }
489
490 template <class Iterator, class Run>
491 void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, bool visualOrder, bool hardLineBreak)
492 {
493 using namespace WTF::Unicode;
494
495 ASSERT(m_direction == OtherNeutral);
496
497 emptyRun = true;
498
499 eor = Iterator();
500
501 last = current;
502 bool pastEnd = false;
503 BidiResolver<Iterator, Run> stateAtEnd;
504
505 while (true) {
506 Direction dirCurrent;
507 if (pastEnd && (hardLineBreak || current.atEnd())) {
508 BidiContext* c = context();
509 while (c->parent())
510 c = c->parent();
511 dirCurrent = c->dir();
512 if (hardLineBreak) {
513 // A deviation from the Unicode Bidi Algorithm in order to match
514 // Mac OS X text and WinIE: a hard line break resets bidi state.
515 stateAtEnd.setContext(c);
516 stateAtEnd.setEorDir(dirCurrent);
517 stateAtEnd.setLastDir(dirCurrent);
518 stateAtEnd.setLastStrongDir(dirCurrent);
519 }
520 } else {
521 dirCurrent = current.direction();
522 if (context()->override()
523 && dirCurrent != RightToLeftEmbedding
524 && dirCurrent != LeftToRightEmbedding
525 && dirCurrent != RightToLeftOverride
526 && dirCurrent != LeftToRightOverride
527 && dirCurrent != PopDirectionalFormat)
528 dirCurrent = context()->dir();
529 else if (dirCurrent == NonSpacingMark)
530 dirCurrent = m_status.last;
531 }
532
533 ASSERT(m_status.eor != OtherNeutral || eor.atEnd());
534 switch (dirCurrent) {
535
536 // embedding and overrides (X1-X9 in the Bidi specs)
537 case RightToLeftEmbedding:
538 case LeftToRightEmbedding:
539 case RightToLeftOverride:
540 case LeftToRightOverride:
541 case PopDirectionalFormat:
542 embed(dirCurrent);
543 commitExplicitEmbedding();
544 break;
545
546 // strong types
547 case LeftToRight:
548 switch(m_status.last) {
549 case RightToLeft:
550 case RightToLeftArabic:
551 case EuropeanNumber:
552 case ArabicNumber:
553 if (m_status.last != EuropeanNumber || m_status.lastStrong != LeftToRight)
554 appendRun();
555 break;
556 case LeftToRight:
557 break;
558 case EuropeanNumberSeparator:
559 case EuropeanNumberTerminator:
560 case CommonNumberSeparator:
561 case BoundaryNeutral:
562 case BlockSeparator:
563 case SegmentSeparator:
564 case WhiteSpaceNeutral:
565 case OtherNeutral:
566 if (m_status.eor == EuropeanNumber) {
567 if (m_status.lastStrong != LeftToRight) {
568 // the numbers need to be on a higher embedding level, so let's close that run
569 m_direction = EuropeanNumber;
570 appendRun();
571 if (context()->dir() != LeftToRight) {
572 // the neutrals take the embedding direction, which is R
573 eor = last;
574 m_direction = RightToLeft;
575 appendRun();
576 }
577 }
578 } else if (m_status.eor == ArabicNumber) {
579 // Arabic numbers are always on a higher embedding level, so let's close that run
580 m_direction = ArabicNumber;
581 appendRun();
582 if (context()->dir() != LeftToRight) {
583 // the neutrals take the embedding direction, which is R
584 eor = last;
585 m_direction = RightToLeft;
586 appendRun();
587 }
588 } else if (m_status.lastStrong != LeftToRight) {
589 //last stuff takes embedding dir
590 if (context()->dir() == RightToLeft) {
591 eor = last;
592 m_direction = RightToLeft;
593 }
594 appendRun();
595 }
596 default:
597 break;
598 }
599 eor = current;
600 m_status.eor = LeftToRight;
601 m_status.lastStrong = LeftToRight;
602 m_direction = LeftToRight;
603 break;
604 case RightToLeftArabic:
605 case RightToLeft:
606 switch (m_status.last) {
607 case LeftToRight:
608 case EuropeanNumber:
609 case ArabicNumber:
610 appendRun();
611 case RightToLeft:
612 case RightToLeftArabic:
613 break;
614 case EuropeanNumberSeparator:
615 case EuropeanNumberTerminator:
616 case CommonNumberSeparator:
617 case BoundaryNeutral:
618 case BlockSeparator:
619 case SegmentSeparator:
620 case WhiteSpaceNeutral:
621 case OtherNeutral:
622 if (m_status.eor == EuropeanNumber) {
623 if (m_status.lastStrong == LeftToRight && context()->dir() == LeftToRight)
624 eor = last;
625 appendRun();
626 } else if (m_status.eor == ArabicNumber)
627 appendRun();
628 else if (m_status.lastStrong == LeftToRight) {
629 if (context()->dir() == LeftToRight)
630 eor = last;
631 appendRun();
632 }
633 default:
634 break;
635 }
636 eor = current;
637 m_status.eor = RightToLeft;
638 m_status.lastStrong = dirCurrent;
639 m_direction = RightToLeft;
640 break;
641
642 // weak types:
643
644 case EuropeanNumber:
645 if (m_status.lastStrong != RightToLeftArabic) {
646 // if last strong was AL change EN to AN
647 switch (m_status.last) {
648 case EuropeanNumber:
649 case LeftToRight:
650 break;
651 case RightToLeft:
652 case RightToLeftArabic:
653 case ArabicNumber:
654 eor = last;
655 appendRun();
656 m_direction = EuropeanNumber;
657 break;
658 case EuropeanNumberSeparator:
659 case CommonNumberSeparator:
660 if (m_status.eor == EuropeanNumber)
661 break;
662 case EuropeanNumberTerminator:
663 case BoundaryNeutral:
664 case BlockSeparator:
665 case SegmentSeparator:
666 case WhiteSpaceNeutral:
667 case OtherNeutral:
668 if (m_status.eor == EuropeanNumber) {
669 if (m_status.lastStrong == RightToLeft) {
670 // ENs on both sides behave like Rs, so the neutrals should be R.
671 // Terminate the EN run.
672 appendRun();
673 // Make an R run.
674 eor = m_status.last == EuropeanNumberTerminator ? lastBeforeET : last;
675 m_direction = RightToLeft;
676 appendRun();
677 // Begin a new EN run.
678 m_direction = EuropeanNumber;
679 }
680 } else if (m_status.eor == ArabicNumber) {
681 // Terminate the AN run.
682 appendRun();
683 if (m_status.lastStrong == RightToLeft || context()->dir() == RightToLeft) {
684 // Make an R run.
685 eor = m_status.last == EuropeanNumberTerminator ? lastBeforeET : last;
686 m_direction = RightToLeft;
687 appendRun();
688 // Begin a new EN run.
689 m_direction = EuropeanNumber;
690 }
691 } else if (m_status.lastStrong == RightToLeft) {
692 // Extend the R run to include the neutrals.
693 eor = m_status.last == EuropeanNumberTerminator ? lastBeforeET : last;
694 m_direction = RightToLeft;
695 appendRun();
696 // Begin a new EN run.
697 m_direction = EuropeanNumber;
698 }
699 default:
700 break;
701 }
702 eor = current;
703 m_status.eor = EuropeanNumber;
704 if (m_direction == OtherNeutral)
705 m_direction = LeftToRight;
706 break;
707 }
708 case ArabicNumber:
709 dirCurrent = ArabicNumber;
710 switch (m_status.last) {
711 case LeftToRight:
712 if (context()->dir() == LeftToRight)
713 appendRun();
714 break;
715 case ArabicNumber:
716 break;
717 case RightToLeft:
718 case RightToLeftArabic:
719 case EuropeanNumber:
720 eor = last;
721 appendRun();
722 break;
723 case CommonNumberSeparator:
724 if (m_status.eor == ArabicNumber)
725 break;
726 case EuropeanNumberSeparator:
727 case EuropeanNumberTerminator:
728 case BoundaryNeutral:
729 case BlockSeparator:
730 case SegmentSeparator:
731 case WhiteSpaceNeutral:
732 case OtherNeutral:
733 if (m_status.eor == ArabicNumber
734 || m_status.eor == EuropeanNumber && (m_status.lastStrong == RightToLeft || context()->dir() == RightToLeft)
735 || m_status.eor != EuropeanNumber && m_status.lastStrong == LeftToRight && context()->dir() == RightToLeft) {
736 // Terminate the run before the neutrals.
737 appendRun();
738 // Begin an R run for the neutrals.
739 m_direction = RightToLeft;
740 } else if (m_direction == OtherNeutral)
741 m_direction = m_status.lastStrong == LeftToRight ? LeftToRight : RightToLeft;
742 eor = last;
743 appendRun();
744 default:
745 break;
746 }
747 eor = current;
748 m_status.eor = ArabicNumber;
749 if (m_direction == OtherNeutral)
750 m_direction = ArabicNumber;
751 break;
752 case EuropeanNumberSeparator:
753 case CommonNumberSeparator:
754 break;
755 case EuropeanNumberTerminator:
756 if (m_status.last == EuropeanNumber) {
757 dirCurrent = EuropeanNumber;
758 eor = current;
759 m_status.eor = dirCurrent;
760 } else if (m_status.last != EuropeanNumberTerminator)
761 lastBeforeET = emptyRun ? eor : last;
762 break;
763
764 // boundary neutrals should be ignored
765 case BoundaryNeutral:
766 if (eor == last)
767 eor = current;
768 break;
769 // neutrals
770 case BlockSeparator:
771 // ### what do we do with newline and paragraph seperators that come to here?
772 break;
773 case SegmentSeparator:
774 // ### implement rule L1
775 break;
776 case WhiteSpaceNeutral:
777 break;
778 case OtherNeutral:
779 break;
780 default:
781 break;
782 }
783
784 if (pastEnd) {
785 if (eor == current) {
786 if (!reachedEndOfLine) {
787 eor = endOfLine;
788 switch (m_status.eor) {
789 case LeftToRight:
790 case RightToLeft:
791 case ArabicNumber:
792 m_direction = m_status.eor;
793 break;
794 case EuropeanNumber:
795 m_direction = m_status.lastStrong == LeftToRight ? LeftToRight : EuropeanNumber;
796 break;
797 default:
798 ASSERT(false);
799 }
800 appendRun();
801 }
802 current = end;
803 m_status = stateAtEnd.m_status;
804 sor = stateAtEnd.sor;
805 eor = stateAtEnd.eor;
806 last = stateAtEnd.last;
807 reachedEndOfLine = stateAtEnd.reachedEndOfLine;
808 lastBeforeET = stateAtEnd.lastBeforeET;
809 emptyRun = stateAtEnd.emptyRun;
810 m_direction = OtherNeutral;
811 break;
812 }
813 }
814
815 // set m_status.last as needed.
816 switch (dirCurrent) {
817 case EuropeanNumberTerminator:
818 if (m_status.last != EuropeanNumber)
819 m_status.last = EuropeanNumberTerminator;
820 break;
821 case EuropeanNumberSeparator:
822 case CommonNumberSeparator:
823 case SegmentSeparator:
824 case WhiteSpaceNeutral:
825 case OtherNeutral:
826 switch(m_status.last) {
827 case LeftToRight:
828 case RightToLeft:
829 case RightToLeftArabic:
830 case EuropeanNumber:
831 case ArabicNumber:
832 m_status.last = dirCurrent;
833 break;
834 default:
835 m_status.last = OtherNeutral;
836 }
837 break;
838 case NonSpacingMark:
839 case BoundaryNeutral:
840 case RightToLeftEmbedding:
841 case LeftToRightEmbedding:
842 case RightToLeftOverride:
843 case LeftToRightOverride:
844 case PopDirectionalFormat:
845 // ignore these
846 break;
847 case EuropeanNumber:
848 // fall through
849 default:
850 m_status.last = dirCurrent;
851 }
852
853 last = current;
854
855 if (emptyRun && !(dirCurrent == RightToLeftEmbedding
856 || dirCurrent == LeftToRightEmbedding
857 || dirCurrent == RightToLeftOverride
858 || dirCurrent == LeftToRightOverride
859 || dirCurrent == PopDirectionalFormat)) {
860 sor = current;
861 emptyRun = false;
862 }
863
864 increment();
865 if (!m_currentExplicitEmbeddingSequence.isEmpty())
866 commitExplicitEmbedding();
867
868 if (emptyRun && (dirCurrent == RightToLeftEmbedding
869 || dirCurrent == LeftToRightEmbedding
870 || dirCurrent == RightToLeftOverride
871 || dirCurrent == LeftToRightOverride
872 || dirCurrent == PopDirectionalFormat)) {
873 // exclude the embedding char itself from the new run so that ATSUI will never see it
874 eor = Iterator();
875 last = current;
876 sor = current;
877 }
878
879 if (!pastEnd && (current == end || current.atEnd())) {
880 if (emptyRun)
881 break;
882 stateAtEnd.m_status = m_status;
883 stateAtEnd.sor = sor;
884 stateAtEnd.eor = eor;
885 stateAtEnd.last = last;
886 stateAtEnd.reachedEndOfLine = reachedEndOfLine;
887 stateAtEnd.lastBeforeET = lastBeforeET;
888 stateAtEnd.emptyRun = emptyRun;
889 endOfLine = last;
890 pastEnd = true;
891 }
892 }
893
894 m_logicallyLastRun = m_lastRun;
895
896 // reorder line according to run structure...
897 // do not reverse for visually ordered web sites
898 if (!visualOrder) {
899
900 // first find highest and lowest levels
901 unsigned char levelLow = 128;
902 unsigned char levelHigh = 0;
903 Run* r = firstRun();
904 while (r) {
905 if (r->m_level > levelHigh)
906 levelHigh = r->m_level;
907 if (r->m_level < levelLow)
908 levelLow = r->m_level;
909 r = r->next();
910 }
911
912 // implements reordering of the line (L2 according to Bidi spec):
913 // L2. From the highest level found in the text to the lowest odd level on each line,
914 // reverse any contiguous sequence of characters that are at that level or higher.
915
916 // reversing is only done up to the lowest odd level
917 if (!(levelLow % 2))
918 levelLow++;
919
920 unsigned count = runCount() - 1;
921
922 while (levelHigh >= levelLow) {
923 unsigned i = 0;
924 Run* currRun = firstRun();
925 while (i < count) {
926 while (i < count && currRun && currRun->m_level < levelHigh) {
927 i++;
928 currRun = currRun->next();
929 }
930 unsigned start = i;
931 while (i <= count && currRun && currRun->m_level >= levelHigh) {
932 i++;
933 currRun = currRun->next();
934 }
935 unsigned end = i - 1;
936 reverseRuns(start, end);
937 }
938 levelHigh--;
939 }
940 }
941 endOfLine = Iterator();
942 }
943
944 } // namespace WebCore
945
946 #endif // BidiResolver_h