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