📄 bidi.cpp
字号:
/** * This file is part of the html renderer for KDE. * * Copyright (C) 2000 Lars Knoll (knoll@kde.org) * * 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., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * $Id: bidi.cpp,v 1.105.2.1 2001/11/01 18:57:06 mueller Exp $ */#include "bidi.h"#include "break_lines.h"#include "render_flow.h"#include "render_text.h"using namespace khtml;#include "kdebug.h"#include "qdatetime.h"#include "qfontmetrics.h"#define BIDI_DEBUG 0//#define DEBUG_LINEBREAKS// ---------------------------------------------------------------------/* a small helper class used internally to resolve Bidi embedding levels. Each line of text caches the embedding level at the start of the line for faster relayouting*/BidiContext::BidiContext(unsigned char l, QChar::Direction e, BidiContext *p, bool o) : level(l) , override(o), dir(e){ parent = p; if(p) { p->ref(); basicDir = p->basicDir; } else basicDir = e; count = 0;}BidiContext::~BidiContext(){ if(parent) parent->deref();}void BidiContext::ref() const{ count++;}void BidiContext::deref() const{ count--; if(count <= 0) delete this;}// ---------------------------------------------------------------------BidiIterator::BidiIterator(){ par = 0; obj = 0; pos = 0;}BidiIterator::BidiIterator(RenderFlow *_par){ par = _par; obj = par->first(); pos = 0;}BidiIterator::BidiIterator(const BidiIterator &it){ par = it.par; obj = it.obj; pos = it.pos;}BidiIterator::BidiIterator(RenderFlow *_par, RenderObject *_obj, int _pos){ par = _par; obj = _obj; pos = _pos;}BidiIterator &BidiIterator::operator = (const BidiIterator &it){ obj = it.obj; pos = it.pos; par = it.par; return *this;}inline void BidiIterator::operator ++ (){ if(!obj) return; if(obj->isText()) { pos++; if(pos >= obj->length()) { obj = par->next(obj); pos = 0; } } else { obj = par->next(obj); pos = 0; }}inline bool BidiIterator::atEnd(){ if(!obj) return true; return false;}const QChar &BidiIterator::current(){ static const QChar nbsp = QChar(0xA0); if( !obj || !obj->isText()) return nbsp; // non breaking space return static_cast<RenderText *>(obj)->text()[pos];}QChar::Direction BidiIterator::direction(){ if(!obj || !obj->isText() || obj->length() <= 0) return QChar::DirON; RenderText *renderTxt = static_cast<RenderText *>( obj ); if ( pos >= renderTxt->length() ) return QChar::DirON; return renderTxt->text()[pos].direction();}inline bool operator==( const BidiIterator &it1, const BidiIterator &it2 ){ if(it1.pos != it2.pos) return false; if(it1.obj != it2.obj) return false; return true;}inline bool operator!=( const BidiIterator &it1, const BidiIterator &it2 ){ if(it1.pos != it2.pos) return true; if(it1.obj != it2.obj) return true; return false;}// -------------------------------------------------------------------------------------------------void RenderFlow::appendRun(QList<BidiRun> &runs, BidiIterator &sor, BidiIterator &eor, BidiContext *context, QChar::Direction dir){#if BIDI_DEBUG > 1 kdDebug(6041) << "appendRun: dir="<<(int)dir<<endl;#endif int start = sor.pos; RenderObject *obj = sor.obj; while( obj && obj != eor.obj ) { if(!obj->isHidden()) { //kdDebug(6041) << "appendRun: "<< start << "/" << obj->length() <<endl; runs.append( new BidiRun(start, obj->length(), obj, context, dir) ); } start = 0; obj = next(obj); } if( obj && !obj->isHidden()) { //kdDebug(6041) << "appendRun: "<< start << "/" << eor.pos <<endl; runs.append( new BidiRun(start, eor.pos + 1, obj, context, dir) ); }}// collects one line of the paragraph and transforms it to visual orderBidiContext *RenderFlow::bidiReorderLine(BidiStatus &status, const BidiIterator &start, const BidiIterator &end, BidiContext *startEmbed){ //kdDebug(6041) << "reordering Line from " << start.obj << "/" << start.pos << " to " << end.obj << "/" << end.pos << endl; QList<BidiRun> runs; runs.setAutoDelete(true); BidiContext *context = startEmbed; // context->ref(); QChar::Direction dir = QChar::DirON; BidiIterator sor = start; BidiIterator eor = start;#ifndef QT_NO_UNICODETABLES BidiIterator current = start; BidiIterator last = current; while(current != end) { QChar::Direction dirCurrent; if(current.atEnd()) { //kdDebug(6041) << "atEnd" << endl; BidiContext *c = context; while ( c->parent ) c = c->parent; dirCurrent = c->dir; } else dirCurrent = current.direction();#if BIDI_DEBUG > 1 kdDebug(6041) << "directions: dir=" << (int)dir << " current=" << (int)dirCurrent << " last=" << status.last << " eor=" << status.eor << " lastStrong=" << status.lastStrong << " embedding=" << (int)context->dir << " level =" << (int)context->level << endl;#endif switch(dirCurrent) { // embedding and overrides (X1-X9 in the Bidi specs) case QChar::DirRLE: { unsigned char level = context->level; if(level%2) // we have an odd level level += 2; else level++; if(level < 61) { appendRun(runs, sor, eor, context, dir); ++eor; sor = eor; dir = QChar::DirON; status.eor = QChar::DirON; context = new BidiContext(level, QChar::DirR, context); context->ref(); status.last = QChar::DirR; status.lastStrong = QChar::DirR; } break; } case QChar::DirLRE: { unsigned char level = context->level; if(level%2) // we have an odd level level++; else level += 2; if(level < 61) { appendRun(runs, sor, eor, context, dir); ++eor; sor = eor; dir = QChar::DirON; status.eor = QChar::DirON; context = new BidiContext(level, QChar::DirL, context); context->ref(); status.last = QChar::DirL; status.lastStrong = QChar::DirL; } break; } case QChar::DirRLO: { unsigned char level = context->level; if(level%2) // we have an odd level level += 2; else level++; if(level < 61) { appendRun(runs, sor, eor, context, dir); ++eor; sor = eor; dir = QChar::DirON; status.eor = QChar::DirON; context = new BidiContext(level, QChar::DirR, context, true); context->ref(); dir = QChar::DirR; status.last = QChar::DirR; status.lastStrong = QChar::DirR; } break; } case QChar::DirLRO: { unsigned char level = context->level; if(level%2) // we have an odd level level++; else level += 2; if(level < 61) { appendRun(runs, sor, eor, context, dir); ++eor; sor = eor; dir = QChar::DirON; status.eor = QChar::DirON; context = new BidiContext(level, QChar::DirL, context, true); context->ref(); dir = QChar::DirL; status.last = QChar::DirL; status.lastStrong = QChar::DirL; } break; } case QChar::DirPDF: { BidiContext *c = context->parent; if(c) { appendRun(runs, sor, eor, context, dir); ++eor; sor = eor; dir = QChar::DirON; status.eor = QChar::DirON; status.last = context->dir; context->deref(); context = c; if(context->override) dir = context->dir; else dir = QChar::DirON; status.lastStrong = context->dir; } break; } // strong types case QChar::DirL: if(dir == QChar::DirON) dir = QChar::DirL; switch(status.last) { case QChar::DirL: eor = current; status.eor = QChar::DirL; break; case QChar::DirR: case QChar::DirAL: case QChar::DirEN: case QChar::DirAN: appendRun(runs, sor, eor, context, dir); ++eor; sor = eor; dir = QChar::DirON; status.eor = QChar::DirON; break; case QChar::DirES: case QChar::DirET: case QChar::DirCS: case QChar::DirBN: case QChar::DirB: case QChar::DirS: case QChar::DirWS: case QChar::DirON: if(dir != QChar::DirL) { //last stuff takes embedding dir if( context->dir == QChar::DirR ) { if(status.eor != QChar::DirR) { // AN or EN appendRun(runs, sor, eor, context, dir); ++eor; sor = eor; dir = QChar::DirON; status.eor = QChar::DirON; dir = QChar::DirR; } else eor = last; appendRun(runs, sor, eor, context, dir); ++eor; sor = eor; dir = QChar::DirON; status.eor = QChar::DirON; } else { if(status.eor == QChar::DirR) { appendRun(runs, sor, eor, context, dir); ++eor; sor = eor; dir = QChar::DirON; status.eor = QChar::DirON; dir = QChar::DirL; } else { eor = current; status.eor = QChar::DirL; break; } } } else { eor = current; status.eor = QChar::DirL; } default: break; } status.lastStrong = QChar::DirL; break; case QChar::DirAL: case QChar::DirR: if(dir == QChar::DirON) dir = QChar::DirR; switch(status.last) { case QChar::DirR: case QChar::DirAL: eor = current; status.eor = QChar::DirR; break; case QChar::DirL: case QChar::DirEN: case QChar::DirAN: appendRun(runs, sor, eor, context, dir); ++eor; sor = eor; dir = QChar::DirON; status.eor = QChar::DirON; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -