~ubuntu-branches/ubuntu/maverick/webkit/maverick

« back to all changes in this revision

Viewing changes to WebCore/platform/BidiResolver.h

  • Committer: Bazaar Package Importer
  • Author(s): Mike Hommey
  • Date: 2007-08-19 15:54:12 UTC
  • Revision ID: james.westby@ubuntu.com-20070819155412-uxxg1h9plpghmtbi
Tags: upstream-0~svn25144
ImportĀ upstreamĀ versionĀ 0~svn25144

Show diffs side-by-side

added added

removed removed

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