📄 bidiresolver.h
字号:
/* * Copyright (C) 2000 Lars Knoll (knoll@kde.org) * Copyright (C) 2003, 2004, 2006, 2007, 2008 Apple Inc. All right reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */#ifndef BidiResolver_h#define BidiResolver_h#include "BidiContext.h"#include <wtf/Noncopyable.h>#include <wtf/PassRefPtr.h>#include <wtf/Vector.h>namespace WebCore {// The BidiStatus at a given position (typically the end of a line) can// be cached and then used to restart bidi resolution at that position.struct BidiStatus { BidiStatus() : eor(WTF::Unicode::OtherNeutral) , lastStrong(WTF::Unicode::OtherNeutral) , last(WTF::Unicode::OtherNeutral) { } BidiStatus(WTF::Unicode::Direction eorDir, WTF::Unicode::Direction lastStrongDir, WTF::Unicode::Direction lastDir, PassRefPtr<BidiContext> bidiContext) : eor(eorDir) , lastStrong(lastStrongDir) , last(lastDir) , context(bidiContext) { } WTF::Unicode::Direction eor; WTF::Unicode::Direction lastStrong; WTF::Unicode::Direction last; RefPtr<BidiContext> context;};inline bool operator==(const BidiStatus& status1, const BidiStatus& status2){ return status1.eor == status2.eor && status1.last == status2.last && status1.lastStrong == status2.lastStrong && *(status1.context) == *(status2.context);}inline bool operator!=(const BidiStatus& status1, const BidiStatus& status2){ return !(status1 == status2);}struct BidiCharacterRun { BidiCharacterRun(int start, int stop, BidiContext* context, WTF::Unicode::Direction dir) : m_start(start) , m_stop(stop) , m_override(context->override()) , m_next(0) { if (dir == WTF::Unicode::OtherNeutral) dir = context->dir(); m_level = context->level(); // add level of run (cases I1 & I2) if (m_level % 2) { if (dir == WTF::Unicode::LeftToRight || dir == WTF::Unicode::ArabicNumber || dir == WTF::Unicode::EuropeanNumber) m_level++; } else { if (dir == WTF::Unicode::RightToLeft) m_level++; else if (dir == WTF::Unicode::ArabicNumber || dir == WTF::Unicode::EuropeanNumber) m_level += 2; } } void destroy() { delete this; } int start() const { return m_start; } int stop() const { return m_stop; } unsigned char level() const { return m_level; } bool reversed(bool visuallyOrdered) { return m_level % 2 && !visuallyOrdered; } bool dirOverride(bool visuallyOrdered) { return m_override || visuallyOrdered; } BidiCharacterRun* next() const { return m_next; } unsigned char m_level; int m_start; int m_stop; bool m_override; BidiCharacterRun* m_next;};template <class Iterator, class Run> class BidiResolver : public Noncopyable {public : BidiResolver() : m_direction(WTF::Unicode::OtherNeutral) , reachedEndOfLine(false) , emptyRun(true) , m_firstRun(0) , m_lastRun(0) , m_logicallyLastRun(0) , m_runCount(0) { } const Iterator& position() const { return current; } void setPosition(const Iterator& position) { current = position; } void increment() { current.increment(); } BidiContext* context() const { return m_status.context.get(); } void setContext(PassRefPtr<BidiContext> c) { m_status.context = c; } void setLastDir(WTF::Unicode::Direction lastDir) { m_status.last = lastDir; } void setLastStrongDir(WTF::Unicode::Direction lastStrongDir) { m_status.lastStrong = lastStrongDir; } void setEorDir(WTF::Unicode::Direction eorDir) { m_status.eor = eorDir; } WTF::Unicode::Direction dir() const { return m_direction; } void setDir(WTF::Unicode::Direction d) { m_direction = d; } const BidiStatus& status() const { return m_status; } void setStatus(const BidiStatus s) { m_status = s; } void embed(WTF::Unicode::Direction); void commitExplicitEmbedding(); void createBidiRunsForLine(const Iterator& end, bool visualOrder = false, bool hardLineBreak = false); Run* firstRun() const { return m_firstRun; } Run* lastRun() const { return m_lastRun; } Run* logicallyLastRun() const { return m_logicallyLastRun; } unsigned runCount() const { return m_runCount; } void addRun(Run*); void prependRun(Run*); void moveRunToEnd(Run*); void moveRunToBeginning(Run*); void deleteRuns();protected: void appendRun(); void reverseRuns(unsigned start, unsigned end); Iterator current; Iterator sor; Iterator eor; Iterator last; BidiStatus m_status; WTF::Unicode::Direction m_direction; Iterator endOfLine; bool reachedEndOfLine; Iterator lastBeforeET; bool emptyRun; Run* m_firstRun; Run* m_lastRun; Run* m_logicallyLastRun; unsigned m_runCount;private: void raiseExplicitEmbeddingLevel(WTF::Unicode::Direction from, WTF::Unicode::Direction to); void lowerExplicitEmbeddingLevel(WTF::Unicode::Direction from); Vector<WTF::Unicode::Direction, 8> m_currentExplicitEmbeddingSequence;};template <class Iterator, class Run>inline void BidiResolver<Iterator, Run>::addRun(Run* run){ if (!m_firstRun) m_firstRun = run; else m_lastRun->m_next = run; m_lastRun = run; m_runCount++;}template <class Iterator, class Run>inline void BidiResolver<Iterator, Run>::prependRun(Run* run){ ASSERT(!run->m_next); if (!m_lastRun) m_lastRun = run; else run->m_next = m_firstRun; m_firstRun = run; m_runCount++;}template <class Iterator, class Run>inline void BidiResolver<Iterator, Run>::moveRunToEnd(Run* run){ ASSERT(m_firstRun); ASSERT(m_lastRun); ASSERT(run->m_next); Run* current = 0; Run* next = m_firstRun; while (next != run) { current = next; next = current->next(); } if (!current) m_firstRun = run->next(); else current->m_next = run->m_next; run->m_next = 0; m_lastRun->m_next = run; m_lastRun = run;}template <class Iterator, class Run>inline void BidiResolver<Iterator, Run>::moveRunToBeginning(Run* run){ ASSERT(m_firstRun); ASSERT(m_lastRun); ASSERT(run != m_firstRun); Run* current = m_firstRun; Run* next = current->next(); while (next != run) { current = next; next = current->next(); } current->m_next = run->m_next; if (run == m_lastRun) m_lastRun = current; run->m_next = m_firstRun; m_firstRun = run;}template <class Iterator, class Run>void BidiResolver<Iterator, Run>::appendRun(){ if (!emptyRun && !eor.atEnd()) { addRun(new Run(sor.offset(), eor.offset() + 1, context(), m_direction)); eor.increment(); sor = eor; } m_direction = WTF::Unicode::OtherNeutral; m_status.eor = WTF::Unicode::OtherNeutral;}template <class Iterator, class Run>void BidiResolver<Iterator, Run>::embed(WTF::Unicode::Direction d){ using namespace WTF::Unicode; ASSERT(d == PopDirectionalFormat || d == LeftToRightEmbedding || d == LeftToRightOverride || d == RightToLeftEmbedding || d == RightToLeftOverride); m_currentExplicitEmbeddingSequence.append(d);}template <class Iterator, class Run>void BidiResolver<Iterator, Run>::lowerExplicitEmbeddingLevel(WTF::Unicode::Direction from){ using namespace WTF::Unicode; if (!emptyRun && eor != last) { ASSERT(m_status.eor != OtherNeutral || eor.atEnd()); // bidi.sor ... bidi.eor ... bidi.last eor; need to append the bidi.sor-bidi.eor run or extend it through bidi.last ASSERT(m_status.last == EuropeanNumberSeparator || m_status.last == EuropeanNumberTerminator || m_status.last == CommonNumberSeparator || m_status.last == BoundaryNeutral || m_status.last == BlockSeparator || m_status.last == SegmentSeparator || m_status.last == WhiteSpaceNeutral || m_status.last == OtherNeutral); if (m_direction == OtherNeutral) m_direction = m_status.lastStrong == LeftToRight ? LeftToRight : RightToLeft; if (from == LeftToRight) { // bidi.sor ... bidi.eor ... bidi.last L if (m_status.eor == EuropeanNumber) { if (m_status.lastStrong != LeftToRight) { m_direction = EuropeanNumber; appendRun(); } } else if (m_status.eor == ArabicNumber) { m_direction = ArabicNumber; appendRun(); } else if (m_status.lastStrong != LeftToRight) { appendRun(); m_direction = LeftToRight; } } else if (m_status.eor == EuropeanNumber || m_status.eor == ArabicNumber || m_status.lastStrong == LeftToRight) { appendRun(); m_direction = RightToLeft; } eor = last; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -