📄 bidi.cpp
字号:
/** * This file is part of the html renderer for KDE. * * Copyright (C) 2000-2003 Lars Knoll (knoll@kde.org) * (C) 2003-2004 Apple Computer, Inc. * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) * * 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. * */#include "rendering/bidi.h"#include "rendering/break_lines.h"#include "rendering/render_block.h"#include "rendering/render_text.h"#include "rendering/render_arena.h"#include "rendering/render_layer.h"#include "rendering/render_canvas.h"#include "xml/dom_docimpl.h"#include "kdebug.h"#include "qdatetime.h"#include "qfontmetrics.h"#define BIDI_DEBUG 0//#define DEBUG_LINEBREAKS//#define PAGE_DEBUGnamespace khtml {// an iterator which goes through a BidiParagraphstruct BidiIterator{ BidiIterator() : par(0), obj(0), pos(0) {} BidiIterator(RenderBlock *_par, RenderObject *_obj, unsigned int _pos) : par(_par), obj(_obj), pos(_pos) {} void increment( BidiState &bidi ); bool atEnd() const; const QChar ¤t() const; QChar::Direction direction() const; RenderBlock *par; RenderObject *obj; unsigned int pos;};struct BidiStatus { BidiStatus() : eor(QChar::DirON), lastStrong(QChar::DirON), last(QChar::DirON) {} QChar::Direction eor; QChar::Direction lastStrong; QChar::Direction last;};struct BidiState { BidiState() : context(0) {} BidiIterator sor; BidiIterator eor; BidiIterator last; BidiIterator current; BidiContext *context; BidiStatus status;};// Used to track a list of chained bidi runs.static BidiRun* sFirstBidiRun;static BidiRun* sLastBidiRun;static int sBidiRunCount;static BidiRun* sCompactFirstBidiRun;static BidiRun* sCompactLastBidiRun;static int sCompactBidiRunCount;static bool sBuildingCompactRuns;// Midpoint globals. The goal is not to do any allocation when dealing with// these midpoints, so we just keep an array around and never clear it. We track// the number of items and position using the two other variables.static QMemArray<BidiIterator> *smidpoints;static uint sNumMidpoints;static uint sCurrMidpoint;static bool betweenMidpoints;static bool isLineEmpty = true;static bool previousLineBrokeAtBR = true;static QChar::Direction dir;static bool adjustEmbedding;static bool emptyRun = true;static int numSpaces;static void embed( QChar::Direction d, BidiState &bidi );static void appendRun( BidiState &bidi );static int getBPMWidth(int childValue, Length cssUnit){ if (!cssUnit.isVariable()) return (cssUnit.isFixed() ? cssUnit.value() : childValue); return 0;}static int getBorderPaddingMargin(RenderObject* child, bool endOfInline){ RenderStyle* cstyle = child->style(); int result = 0; bool leftSide = (cstyle->direction() == LTR) ? !endOfInline : endOfInline; result += getBPMWidth((leftSide ? child->marginLeft() : child->marginRight()), (leftSide ? cstyle->marginLeft() : cstyle->marginRight())); result += getBPMWidth((leftSide ? child->paddingLeft() : child->paddingRight()), (leftSide ? cstyle->paddingLeft() : cstyle->paddingRight())); result += leftSide ? child->borderLeft() : child->borderRight(); return result;}static int inlineWidth(RenderObject* child, bool start = true, bool end = true){ int extraWidth = 0; RenderObject* parent = child->parent(); while (parent->isInline() && !parent->isInlineBlockOrInlineTable()) { if (start && parent->firstChild() == child) extraWidth += getBorderPaddingMargin(parent, false); if (end && parent->lastChild() == child) extraWidth += getBorderPaddingMargin(parent, true); child = parent; parent = child->parent(); } return extraWidth;}#ifndef NDEBUGstatic bool inBidiRunDetach;#endifvoid BidiRun::detach(RenderArena* renderArena){#ifndef NDEBUG inBidiRunDetach = true;#endif delete this;#ifndef NDEBUG inBidiRunDetach = false;#endif // Recover the size left there for us by operator delete and free the memory. renderArena->free(*(size_t *)this, this);}void* BidiRun::operator new(size_t sz, RenderArena* renderArena) throw(){ return renderArena->allocate(sz);}void BidiRun::operator delete(void* ptr, size_t sz){ assert(inBidiRunDetach); // Stash size where detach can find it. *(size_t*)ptr = sz;}static void deleteBidiRuns(RenderArena* arena){ if (!sFirstBidiRun) return; BidiRun* curr = sFirstBidiRun; while (curr) { BidiRun* s = curr->nextRun; curr->detach(arena); curr = s; } sFirstBidiRun = 0; sLastBidiRun = 0; sBidiRunCount = 0;}// ---------------------------------------------------------------------/* 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;}// ---------------------------------------------------------------------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;}static inline RenderObject *Bidinext(RenderObject *par, RenderObject *current, BidiState &bidi, bool skipInlines = true){ RenderObject *next = 0; while(current != 0) { //kdDebug( 6040 ) << "current = " << current << endl; if (!current->isFloating() && !current->isReplaced() && !current->isPositioned()) { next = current->firstChild(); if ( next && adjustEmbedding ) { EUnicodeBidi ub = next->style()->unicodeBidi(); if ( ub != UBNormal && !emptyRun ) { EDirection dir = next->style()->direction(); QChar::Direction d = ( ub == Embed ? ( dir == RTL ? QChar::DirRLE : QChar::DirLRE ) : ( dir == RTL ? QChar::DirRLO : QChar::DirLRO ) ); embed( d, bidi ); } } } if (!next) { while (current && current != par) { next = current->nextSibling(); if (next) break; if ( adjustEmbedding && current->style()->unicodeBidi() != UBNormal && !emptyRun ) { embed( QChar::DirPDF, bidi ); } current = current->parent(); } } if (!next) break; if (next->isText() || next->isBR() || next->isFloating() || next->isReplaced() || next->isPositioned() || ((!skipInlines || !next->firstChild()) // Always return EMPTY inlines. && next->isInlineFlow())) break; current = next; } return next;}static RenderObject *first( RenderObject *par, BidiState &bidi, bool skipInlines = true ){ if(!par->firstChild()) return 0; RenderObject *o = par->firstChild(); if (o->isInlineFlow()) { if (skipInlines && o->firstChild()) o = Bidinext( par, o, bidi, skipInlines ); else return o; // Never skip empty inlines. } if (o && !o->isText() && !o->isBR() && !o->isReplaced() && !o->isFloating() && !o->isPositioned()) o = Bidinext( par, o, bidi, skipInlines ); return o;}inline void BidiIterator::increment (BidiState &bidi){ if(!obj) return; if(obj->isText()) { pos++; if(pos >= static_cast<RenderText *>(obj)->stringLength()) { obj = Bidinext( par, obj, bidi ); pos = 0; } } else { obj = Bidinext( par, obj, bidi ); pos = 0; }}inline bool BidiIterator::atEnd() const{ if(!obj) return true; return false;}const QChar &BidiIterator::current() const{ static QChar nonBreakingSpace(0xA0); if (!obj || !obj->isText()) return nonBreakingSpace; RenderText* text = static_cast<RenderText*>(obj); if (!text->text()) return nonBreakingSpace; return text->text()[pos];}inline QChar::Direction BidiIterator::direction() const{ if(!obj || !obj->isText() ) return QChar::DirON; RenderText *renderTxt = static_cast<RenderText *>( obj ); if ( pos >= renderTxt->stringLength() ) return QChar::DirON; return renderTxt->text()[pos].direction();}// -------------------------------------------------------------------------------------------------static void addRun(BidiRun* bidiRun){ if (!sFirstBidiRun) sFirstBidiRun = sLastBidiRun = bidiRun; else { sLastBidiRun->nextRun = bidiRun; sLastBidiRun = bidiRun; } sBidiRunCount++; bidiRun->compact = sBuildingCompactRuns; // Compute the number of spaces in this run, if (bidiRun->obj && bidiRun->obj->isText()) { RenderText* text = static_cast<RenderText*>(bidiRun->obj); if (text->text()) { for (int i = bidiRun->start; i < bidiRun->stop; i++) { const QChar c = text->text()[i]; if (c.category() == QChar::Separator_Space || c == '\n') numSpaces++; } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -