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