• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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