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