OSDN Git Service

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