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