| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2000 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 2000 Lars Knoll (knoll@kde.org) |
| 3 * Copyright (C) 2003, 2004, 2006, 2007, 2008 Apple Inc. All right reserved. | 3 * Copyright (C) 2003, 2004, 2006, 2007, 2008 Apple Inc. All right reserved. |
| 4 * | 4 * |
| 5 * This library is free software; you can redistribute it and/or | 5 * This library is free software; you can redistribute it and/or |
| 6 * modify it under the terms of the GNU Library General Public | 6 * modify it under the terms of the GNU Library General Public |
| 7 * License as published by the Free Software Foundation; either | 7 * License as published by the Free Software Foundation; either |
| 8 * version 2 of the License, or (at your option) any later version. | 8 * version 2 of the License, or (at your option) any later version. |
| 9 * | 9 * |
| 10 * This library is distributed in the hope that it will be useful, | 10 * This library is distributed in the hope that it will be useful, |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 165 // BidiResolver is WebKit's implementation of the Unicode Bidi Algorithm | 165 // BidiResolver is WebKit's implementation of the Unicode Bidi Algorithm |
| 166 // http://unicode.org/reports/tr9 | 166 // http://unicode.org/reports/tr9 |
| 167 template <class Iterator, class Run> class BidiResolver { | 167 template <class Iterator, class Run> class BidiResolver { |
| 168 WTF_MAKE_NONCOPYABLE(BidiResolver); | 168 WTF_MAKE_NONCOPYABLE(BidiResolver); |
| 169 public: | 169 public: |
| 170 BidiResolver() | 170 BidiResolver() |
| 171 : m_direction(WTF::Unicode::OtherNeutral) | 171 : m_direction(WTF::Unicode::OtherNeutral) |
| 172 , m_reachedEndOfLine(false) | 172 , m_reachedEndOfLine(false) |
| 173 , m_emptyRun(true) | 173 , m_emptyRun(true) |
| 174 , m_nestedIsolateCount(0) | 174 , m_nestedIsolateCount(0) |
| 175 , m_trailingSpaceRun(0) |
| 175 { | 176 { |
| 176 } | 177 } |
| 177 | 178 |
| 178 #ifndef NDEBUG | 179 #ifndef NDEBUG |
| 179 ~BidiResolver(); | 180 ~BidiResolver(); |
| 180 #endif | 181 #endif |
| 181 | 182 |
| 182 const Iterator& position() const { return m_current; } | 183 const Iterator& position() const { return m_current; } |
| 183 Iterator& position() { return m_current; } | 184 Iterator& position() { return m_current; } |
| 184 void setPositionIgnoringNestedIsolates(const Iterator& position) { m_current
= position; } | 185 void setPositionIgnoringNestedIsolates(const Iterator& position) { m_current
= position; } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 196 void setEorDir(WTF::Unicode::Direction eorDir) { m_status.eor = eorDir; } | 197 void setEorDir(WTF::Unicode::Direction eorDir) { m_status.eor = eorDir; } |
| 197 | 198 |
| 198 WTF::Unicode::Direction dir() const { return m_direction; } | 199 WTF::Unicode::Direction dir() const { return m_direction; } |
| 199 void setDir(WTF::Unicode::Direction d) { m_direction = d; } | 200 void setDir(WTF::Unicode::Direction d) { m_direction = d; } |
| 200 | 201 |
| 201 const BidiStatus& status() const { return m_status; } | 202 const BidiStatus& status() const { return m_status; } |
| 202 void setStatus(const BidiStatus s) | 203 void setStatus(const BidiStatus s) |
| 203 { | 204 { |
| 204 ASSERT(s.context); | 205 ASSERT(s.context); |
| 205 m_status = s; | 206 m_status = s; |
| 207 m_paragraphDirectionality = s.context->dir() == WTF::Unicode::LeftToRigh
t ? LTR : RTL; |
| 206 } | 208 } |
| 207 | 209 |
| 208 MidpointState<Iterator>& midpointState() { return m_midpointState; } | 210 MidpointState<Iterator>& midpointState() { return m_midpointState; } |
| 209 | 211 |
| 210 // The current algorithm handles nested isolates one layer of nesting at a t
ime. | 212 // The current algorithm handles nested isolates one layer of nesting at a t
ime. |
| 211 // But when we layout each isolated span, we will walk into (and ignore) all | 213 // But when we layout each isolated span, we will walk into (and ignore) all |
| 212 // child isolated spans. | 214 // child isolated spans. |
| 213 void enterIsolate() { m_nestedIsolateCount++; } | 215 void enterIsolate() { m_nestedIsolateCount++; } |
| 214 void exitIsolate() { ASSERT(m_nestedIsolateCount >= 1); m_nestedIsolateCount
--; } | 216 void exitIsolate() { ASSERT(m_nestedIsolateCount >= 1); m_nestedIsolateCount
--; } |
| 215 bool inIsolate() const { return m_nestedIsolateCount; } | 217 bool inIsolate() const { return m_nestedIsolateCount; } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 229 | 231 |
| 230 bool isEndOfLine(const Iterator& end) { return m_current == end || m_current
.atEnd(); } | 232 bool isEndOfLine(const Iterator& end) { return m_current == end || m_current
.atEnd(); } |
| 231 | 233 |
| 232 TextDirection determineParagraphDirectionality(bool* hasStrongDirectionality
= 0); | 234 TextDirection determineParagraphDirectionality(bool* hasStrongDirectionality
= 0); |
| 233 | 235 |
| 234 void setMidpointStateForIsolatedRun(Run*, const MidpointState<Iterator>&); | 236 void setMidpointStateForIsolatedRun(Run*, const MidpointState<Iterator>&); |
| 235 MidpointState<Iterator> midpointStateForIsolatedRun(Run*); | 237 MidpointState<Iterator> midpointStateForIsolatedRun(Run*); |
| 236 | 238 |
| 237 Iterator endOfLine() const { return m_endOfLine; } | 239 Iterator endOfLine() const { return m_endOfLine; } |
| 238 | 240 |
| 241 Run* trailingSpaceRun() const { return m_trailingSpaceRun; } |
| 242 |
| 239 protected: | 243 protected: |
| 240 void increment() { m_current.increment(); } | 244 void increment() { m_current.increment(); } |
| 241 // FIXME: Instead of InlineBidiResolvers subclassing this method, we should | 245 // FIXME: Instead of InlineBidiResolvers subclassing this method, we should |
| 242 // pass in some sort of Traits object which knows how to create runs for app
ending. | 246 // pass in some sort of Traits object which knows how to create runs for app
ending. |
| 243 void appendRun(); | 247 void appendRun(); |
| 244 | 248 |
| 249 Run* addTrailingRun(int, int, Run*, BidiContext*, TextDirection) { return 0;
} |
| 245 Iterator m_current; | 250 Iterator m_current; |
| 246 // sor and eor are "start of run" and "end of run" respectively and correpon
d | 251 // sor and eor are "start of run" and "end of run" respectively and correpon
d |
| 247 // to abreviations used in UBA spec: http://unicode.org/reports/tr9/#BD7 | 252 // to abreviations used in UBA spec: http://unicode.org/reports/tr9/#BD7 |
| 248 Iterator m_sor; // Points to the first character in the current run. | 253 Iterator m_sor; // Points to the first character in the current run. |
| 249 Iterator m_eor; // Points to the last character in the current run. | 254 Iterator m_eor; // Points to the last character in the current run. |
| 250 Iterator m_last; | 255 Iterator m_last; |
| 251 BidiStatus m_status; | 256 BidiStatus m_status; |
| 252 WTF::Unicode::Direction m_direction; | 257 WTF::Unicode::Direction m_direction; |
| 253 // m_endOfRunAtEndOfLine is "the position last eor in the end of line" | 258 // m_endOfRunAtEndOfLine is "the position last eor in the end of line" |
| 254 Iterator m_endOfRunAtEndOfLine; | 259 Iterator m_endOfRunAtEndOfLine; |
| 255 Iterator m_endOfLine; | 260 Iterator m_endOfLine; |
| 256 bool m_reachedEndOfLine; | 261 bool m_reachedEndOfLine; |
| 257 Iterator m_lastBeforeET; // Before a EuropeanNumberTerminator | 262 Iterator m_lastBeforeET; // Before a EuropeanNumberTerminator |
| 258 bool m_emptyRun; | 263 bool m_emptyRun; |
| 259 | 264 |
| 260 // FIXME: This should not belong to the resolver, but rather be passed | 265 // FIXME: This should not belong to the resolver, but rather be passed |
| 261 // into createBidiRunsForLine by the caller. | 266 // into createBidiRunsForLine by the caller. |
| 262 BidiRunList<Run> m_runs; | 267 BidiRunList<Run> m_runs; |
| 263 | 268 |
| 264 MidpointState<Iterator> m_midpointState; | 269 MidpointState<Iterator> m_midpointState; |
| 265 | 270 |
| 266 unsigned m_nestedIsolateCount; | 271 unsigned m_nestedIsolateCount; |
| 267 Vector<Run*> m_isolatedRuns; | 272 Vector<Run*> m_isolatedRuns; |
| 273 Run* m_trailingSpaceRun; |
| 274 TextDirection m_paragraphDirectionality; |
| 268 | 275 |
| 269 private: | 276 private: |
| 270 void raiseExplicitEmbeddingLevel(WTF::Unicode::Direction from, WTF::Unicode:
:Direction to); | 277 void raiseExplicitEmbeddingLevel(WTF::Unicode::Direction from, WTF::Unicode:
:Direction to); |
| 271 void lowerExplicitEmbeddingLevel(WTF::Unicode::Direction from); | 278 void lowerExplicitEmbeddingLevel(WTF::Unicode::Direction from); |
| 272 void checkDirectionInLowerRaiseEmbeddingLevel(); | 279 void checkDirectionInLowerRaiseEmbeddingLevel(); |
| 273 | 280 |
| 274 void updateStatusLastFromCurrentDirection(WTF::Unicode::Direction); | 281 void updateStatusLastFromCurrentDirection(WTF::Unicode::Direction); |
| 275 void reorderRunsFromLevels(); | 282 void reorderRunsFromLevels(); |
| 276 | 283 |
| 284 bool needsToApplyL1Rule() { return false; } |
| 285 int findFirstTrailingSpaceAtRun(Run*) { return 0; } |
| 286 // http://www.unicode.org/reports/tr9/#L1 |
| 287 void applyL1Rule(); |
| 288 |
| 277 Vector<BidiEmbedding, 8> m_currentExplicitEmbeddingSequence; | 289 Vector<BidiEmbedding, 8> m_currentExplicitEmbeddingSequence; |
| 278 HashMap<Run *, MidpointState<Iterator> > m_midpointStateForIsolatedRun; | 290 HashMap<Run *, MidpointState<Iterator> > m_midpointStateForIsolatedRun; |
| 279 }; | 291 }; |
| 280 | 292 |
| 281 #ifndef NDEBUG | 293 #ifndef NDEBUG |
| 282 template <class Iterator, class Run> | 294 template <class Iterator, class Run> |
| 283 BidiResolver<Iterator, Run>::~BidiResolver() | 295 BidiResolver<Iterator, Run>::~BidiResolver() |
| 284 { | 296 { |
| 285 // The owner of this resolver should have handled the isolated runs. | 297 // The owner of this resolver should have handled the isolated runs. |
| 286 ASSERT(m_isolatedRuns.isEmpty()); | 298 ASSERT(m_isolatedRuns.isEmpty()); |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 410 | 422 |
| 411 appendRun(); | 423 appendRun(); |
| 412 m_emptyRun = true; | 424 m_emptyRun = true; |
| 413 | 425 |
| 414 setLastDir(to); | 426 setLastDir(to); |
| 415 setLastStrongDir(to); | 427 setLastStrongDir(to); |
| 416 m_eor = Iterator(); | 428 m_eor = Iterator(); |
| 417 } | 429 } |
| 418 | 430 |
| 419 template <class Iterator, class Run> | 431 template <class Iterator, class Run> |
| 432 void BidiResolver<Iterator, Run>::applyL1Rule() |
| 433 { |
| 434 ASSERT(m_runs.runCount()); |
| 435 if (!needsToApplyL1Rule()) |
| 436 return; |
| 437 |
| 438 Run* trailingSpaceRun = m_runs.logicallyLastRun(); |
| 439 |
| 440 int firstSpace = findFirstTrailingSpaceAtRun(trailingSpaceRun); |
| 441 if (firstSpace == trailingSpaceRun->stop()) |
| 442 return; |
| 443 |
| 444 bool shouldReorder = trailingSpaceRun != (m_paragraphDirectionality == LTR ?
m_runs.lastRun() : m_runs.firstRun()); |
| 445 if (firstSpace != trailingSpaceRun->start()) { |
| 446 BidiContext* baseContext = context(); |
| 447 while (BidiContext* parent = baseContext->parent()) |
| 448 baseContext = parent; |
| 449 |
| 450 m_trailingSpaceRun = addTrailingRun(firstSpace, trailingSpaceRun->m_stop
, trailingSpaceRun, baseContext, m_paragraphDirectionality); |
| 451 ASSERT(m_trailingSpaceRun); |
| 452 trailingSpaceRun->m_stop = firstSpace; |
| 453 return; |
| 454 } |
| 455 if (!shouldReorder) { |
| 456 m_trailingSpaceRun = trailingSpaceRun; |
| 457 return; |
| 458 } |
| 459 |
| 460 if (m_paragraphDirectionality == LTR) { |
| 461 m_runs.moveRunToEnd(trailingSpaceRun); |
| 462 trailingSpaceRun->m_level = 0; |
| 463 } else { |
| 464 m_runs.moveRunToBeginning(trailingSpaceRun); |
| 465 trailingSpaceRun->m_level = 1; |
| 466 } |
| 467 m_trailingSpaceRun = trailingSpaceRun; |
| 468 } |
| 469 |
| 470 template <class Iterator, class Run> |
| 420 bool BidiResolver<Iterator, Run>::commitExplicitEmbedding() | 471 bool BidiResolver<Iterator, Run>::commitExplicitEmbedding() |
| 421 { | 472 { |
| 422 // When we're "inIsolate()" we're resolving the parent context which | 473 // When we're "inIsolate()" we're resolving the parent context which |
| 423 // ignores (skips over) the isolated content, including embedding levels. | 474 // ignores (skips over) the isolated content, including embedding levels. |
| 424 // We should never accrue embedding levels while skipping over isolated cont
ent. | 475 // We should never accrue embedding levels while skipping over isolated cont
ent. |
| 425 ASSERT(!inIsolate() || m_currentExplicitEmbeddingSequence.isEmpty()); | 476 ASSERT(!inIsolate() || m_currentExplicitEmbeddingSequence.isEmpty()); |
| 426 | 477 |
| 427 using namespace WTF::Unicode; | 478 using namespace WTF::Unicode; |
| 428 | 479 |
| 429 unsigned char fromLevel = context()->level(); | 480 unsigned char fromLevel = context()->level(); |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 582 *hasStrongDirectionality = false; | 633 *hasStrongDirectionality = false; |
| 583 return LTR; | 634 return LTR; |
| 584 } | 635 } |
| 585 | 636 |
| 586 template <class Iterator, class Run> | 637 template <class Iterator, class Run> |
| 587 void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis
ualDirectionOverride override, bool hardLineBreak) | 638 void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& end, Vis
ualDirectionOverride override, bool hardLineBreak) |
| 588 { | 639 { |
| 589 using namespace WTF::Unicode; | 640 using namespace WTF::Unicode; |
| 590 | 641 |
| 591 ASSERT(m_direction == OtherNeutral); | 642 ASSERT(m_direction == OtherNeutral); |
| 643 m_trailingSpaceRun = 0; |
| 592 | 644 |
| 593 m_endOfLine = end; | 645 m_endOfLine = end; |
| 594 | 646 |
| 595 if (override != NoVisualOverride) { | 647 if (override != NoVisualOverride) { |
| 596 m_emptyRun = false; | 648 m_emptyRun = false; |
| 597 m_sor = m_current; | 649 m_sor = m_current; |
| 598 m_eor = Iterator(); | 650 m_eor = Iterator(); |
| 599 while (m_current != end && !m_current.atEnd()) { | 651 while (m_current != end && !m_current.atEnd()) { |
| 600 m_eor = m_current; | 652 m_eor = m_current; |
| 601 increment(); | 653 increment(); |
| (...skipping 376 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 978 m_direction = OtherNeutral; | 1030 m_direction = OtherNeutral; |
| 979 break; | 1031 break; |
| 980 } | 1032 } |
| 981 } | 1033 } |
| 982 } | 1034 } |
| 983 | 1035 |
| 984 m_runs.setLogicallyLastRun(m_runs.lastRun()); | 1036 m_runs.setLogicallyLastRun(m_runs.lastRun()); |
| 985 reorderRunsFromLevels(); | 1037 reorderRunsFromLevels(); |
| 986 m_endOfRunAtEndOfLine = Iterator(); | 1038 m_endOfRunAtEndOfLine = Iterator(); |
| 987 m_endOfLine = Iterator(); | 1039 m_endOfLine = Iterator(); |
| 1040 |
| 1041 if (!hardLineBreak && m_runs.runCount()) |
| 1042 applyL1Rule(); |
| 988 } | 1043 } |
| 989 | 1044 |
| 990 template <class Iterator, class Run> | 1045 template <class Iterator, class Run> |
| 991 void BidiResolver<Iterator, Run>::setMidpointStateForIsolatedRun(Run* run, const
MidpointState<Iterator>& midpoint) | 1046 void BidiResolver<Iterator, Run>::setMidpointStateForIsolatedRun(Run* run, const
MidpointState<Iterator>& midpoint) |
| 992 { | 1047 { |
| 993 ASSERT(!m_midpointStateForIsolatedRun.contains(run)); | 1048 ASSERT(!m_midpointStateForIsolatedRun.contains(run)); |
| 994 m_midpointStateForIsolatedRun.add(run, midpoint); | 1049 m_midpointStateForIsolatedRun.add(run, midpoint); |
| 995 } | 1050 } |
| 996 | 1051 |
| 997 template<class Iterator, class Run> | 1052 template<class Iterator, class Run> |
| 998 MidpointState<Iterator> BidiResolver<Iterator, Run>::midpointStateForIsolatedRun
(Run* run) | 1053 MidpointState<Iterator> BidiResolver<Iterator, Run>::midpointStateForIsolatedRun
(Run* run) |
| 999 { | 1054 { |
| 1000 return m_midpointStateForIsolatedRun.take(run); | 1055 return m_midpointStateForIsolatedRun.take(run); |
| 1001 } | 1056 } |
| 1002 | 1057 |
| 1003 | 1058 |
| 1004 } // namespace WebCore | 1059 } // namespace WebCore |
| 1005 | 1060 |
| 1006 #endif // BidiResolver_h | 1061 #endif // BidiResolver_h |
| OLD | NEW |