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 |