From 0cf411b09cf5d8970b873a338a69eae98d5ce5d8 Mon Sep 17 00:00:00 2001 From: Michele Calgaro Date: Sat, 8 Jun 2024 12:56:43 +0900 Subject: Rename text nt* related files to equivalent tq* Signed-off-by: Michele Calgaro --- src/kernel/ntqnamespace.h | 2 +- src/kernel/ntqt.h | 18 +- src/kernel/qapplication.cpp | 2 +- src/kernel/qapplication_x11.cpp | 2 +- src/kernel/qclipboard_x11.cpp | 2 +- src/kernel/qdragobject.cpp | 2 +- src/kernel/qfont.cpp | 2 +- src/kernel/qfont_x11.cpp | 4 +- src/kernel/qfontengine_p.h | 4 +- src/kernel/qfontengine_x11.cpp | 4 +- src/kernel/qpainter.cpp | 2 +- src/kernel/qpainter_x11.cpp | 8 +- src/kernel/qpsprinter.cpp | 6 +- src/kernel/qpsprinter_p.h | 2 +- src/kernel/qrichtext.cpp | 4 +- src/kernel/qrichtext_p.h | 2 +- src/kernel/qscriptengine.cpp | 2 +- src/kernel/qscriptengine_p.h | 2 +- src/kernel/qscriptengine_x11.cpp | 2 +- src/kernel/qt_kernel.pri | 8 +- src/kernel/qtextengine.cpp | 1180 -------------------------------------- src/kernel/qtextengine_p.h | 377 ------------ src/kernel/qtextengine_unix.cpp | 127 ---- src/kernel/qtextlayout.cpp | 643 --------------------- src/kernel/qtextlayout_p.h | 184 ------ src/kernel/tqimage.cpp | 2 +- src/kernel/tqtextengine.cpp | 1180 ++++++++++++++++++++++++++++++++++++++ src/kernel/tqtextengine_p.h | 377 ++++++++++++ src/kernel/tqtextengine_unix.cpp | 127 ++++ src/kernel/tqtextlayout.cpp | 643 +++++++++++++++++++++ src/kernel/tqtextlayout_p.h | 184 ++++++ src/kernel/tqwidget_x11.cpp | 4 +- 32 files changed, 2554 insertions(+), 2554 deletions(-) delete mode 100644 src/kernel/qtextengine.cpp delete mode 100644 src/kernel/qtextengine_p.h delete mode 100644 src/kernel/qtextengine_unix.cpp delete mode 100644 src/kernel/qtextlayout.cpp delete mode 100644 src/kernel/qtextlayout_p.h create mode 100644 src/kernel/tqtextengine.cpp create mode 100644 src/kernel/tqtextengine_p.h create mode 100644 src/kernel/tqtextengine_unix.cpp create mode 100644 src/kernel/tqtextlayout.cpp create mode 100644 src/kernel/tqtextlayout_p.h (limited to 'src/kernel') diff --git a/src/kernel/ntqnamespace.h b/src/kernel/ntqnamespace.h index 8bdc0a374..03c58309c 100644 --- a/src/kernel/ntqnamespace.h +++ b/src/kernel/ntqnamespace.h @@ -920,7 +920,7 @@ public: LogText }; - // Documented in qtextedit.cpp + // Documented in tqtextedit.cpp enum AnchorAttribute { AnchorName, AnchorHref diff --git a/src/kernel/ntqt.h b/src/kernel/ntqt.h index 876d07c1f..3e62736f3 100644 --- a/src/kernel/ntqt.h +++ b/src/kernel/ntqt.h @@ -36,7 +36,7 @@ #include "tqpair.h" #include "ntqpoint.h" #include -#include "ntqtextstream.h" +#include "tqtextstream.h" #include "ntqfontinfo.h" #include "ntqsizepolicy.h" #include "ntqtl.h" @@ -65,7 +65,7 @@ #include "ntqpalette.h" #include "tqwidget.h" #include "ntqjpunicode.h" -#include "ntqtextcodec.h" +#include "tqtextcodec.h" #include "ntqpixmap.h" #include #include "ntqiconset.h" @@ -224,18 +224,18 @@ #include #include #include -#include "ntqtextedit.h" +#include "tqtextedit.h" #include #include #include "tqsqleditorfactory.h" #include -#include +#include #include -#include -#include +#include +#include #include #include "ntqtoolbar.h" -#include +#include #include "ntqwaitcondition.h" #include #include @@ -295,7 +295,7 @@ #include "private/qrichtext_p.h" #include "private/qsvgdevice_p.h" #include "private/qfontcodecs_p.h" -#include "private/qtextcodecinterface_p.h" +#include "private/tqtextcodecinterface_p.h" #include "private/qpsprinter_p.h" #include "private/qtitlebar_p.h" #include "private/qucom_p.h" @@ -325,7 +325,7 @@ #endif #ifdef TQ_WS_QWS -#include +#include #include "qfontmanager_qws.h" #include #include diff --git a/src/kernel/qapplication.cpp b/src/kernel/qapplication.cpp index e5b28642b..baf5ba495 100644 --- a/src/kernel/qapplication.cpp +++ b/src/kernel/qapplication.cpp @@ -49,7 +49,7 @@ #include "ntqcleanuphandler.h" #include "ntqtranslator.h" -#include "ntqtextcodec.h" +#include "tqtextcodec.h" #include "ntqsessionmanager.h" #include "ntqdragobject.h" #include "ntqclipboard.h" diff --git a/src/kernel/qapplication_x11.cpp b/src/kernel/qapplication_x11.cpp index 57c55feba..0cfd812c2 100644 --- a/src/kernel/qapplication_x11.cpp +++ b/src/kernel/qapplication_x11.cpp @@ -74,7 +74,7 @@ #include "ntqpainter.h" #include "ntqpixmapcache.h" #include "ntqdatetime.h" -#include "ntqtextcodec.h" +#include "tqtextcodec.h" #include "ntqdatastream.h" #include "ntqbuffer.h" #include "ntqsocketnotifier.h" diff --git a/src/kernel/qclipboard_x11.cpp b/src/kernel/qclipboard_x11.cpp index 51fbc63ab..7776cf606 100644 --- a/src/kernel/qclipboard_x11.cpp +++ b/src/kernel/qclipboard_x11.cpp @@ -70,7 +70,7 @@ #include "ntqdatetime.h" #include "ntqdragobject.h" #include "ntqbuffer.h" -#include "ntqtextcodec.h" +#include "tqtextcodec.h" #include "tqvaluelist.h" #include "tqmap.h" #include "qt_x11_p.h" diff --git a/src/kernel/qdragobject.cpp b/src/kernel/qdragobject.cpp index 5e6a0dab9..9854c33a3 100644 --- a/src/kernel/qdragobject.cpp +++ b/src/kernel/qdragobject.cpp @@ -46,7 +46,7 @@ #ifndef TQT_NO_MIME #include "ntqdragobject.h" -#include "ntqtextcodec.h" +#include "tqtextcodec.h" #include "ntqapplication.h" #include "ntqpoint.h" #include "tqwidget.h" diff --git a/src/kernel/qfont.cpp b/src/kernel/qfont.cpp index b442a3253..387f75dfe 100644 --- a/src/kernel/qfont.cpp +++ b/src/kernel/qfont.cpp @@ -59,7 +59,7 @@ #include "qfontdata_p.h" #include "qfontengine_p.h" #include "qpainter_p.h" -#include "qtextengine_p.h" +#include "tqtextengine_p.h" // #define TQFONTCACHE_DEBUG #ifdef TQFONTCACHE_DEBUG diff --git a/src/kernel/qfont_x11.cpp b/src/kernel/qfont_x11.cpp index 3cd207c65..07c3fe2c6 100644 --- a/src/kernel/qfont_x11.cpp +++ b/src/kernel/qfont_x11.cpp @@ -52,13 +52,13 @@ #include "ntqfontmetrics.h" #include "ntqpaintdevice.h" #include "ntqpaintdevicemetrics.h" -#include "ntqtextcodec.h" +#include "tqtextcodec.h" #include #include #include "qfontdata_p.h" #include "qfontengine_p.h" -#include "qtextengine_p.h" +#include "tqtextengine_p.h" #include "qt_x11_p.h" diff --git a/src/kernel/qfontengine_p.h b/src/kernel/qfontengine_p.h index 17aa618b6..9e3c31261 100644 --- a/src/kernel/qfontengine_p.h +++ b/src/kernel/qfontengine_p.h @@ -46,7 +46,7 @@ #include "tqptrdict.h" #endif -#include "qtextengine_p.h" +#include "tqtextengine_p.h" class TQPaintDevice; @@ -475,7 +475,7 @@ class TQTextEngine; #ifndef TQT_NO_XFTFREETYPE #include "qscriptengine_p.h" -#include "qtextengine_p.h" +#include "tqtextengine_p.h" #include #include FT_FREETYPE_H #include "ftxopen.h" diff --git a/src/kernel/qfontengine_x11.cpp b/src/kernel/qfontengine_x11.cpp index 5cf756265..54bedb33e 100644 --- a/src/kernel/qfontengine_x11.cpp +++ b/src/kernel/qfontengine_x11.cpp @@ -42,7 +42,7 @@ #include #include -#include +#include #include "ntqbitmap.h" #include "ntqfontdatabase.h" @@ -54,7 +54,7 @@ #include "qt_x11_p.h" #include "ntqfont.h" -#include "qtextengine_p.h" +#include "tqtextengine_p.h" #include diff --git a/src/kernel/qpainter.cpp b/src/kernel/qpainter.cpp index 3f91a8023..82840cc27 100644 --- a/src/kernel/qpainter.cpp +++ b/src/kernel/qpainter.cpp @@ -56,7 +56,7 @@ #endif #include -#include "qtextlayout_p.h" +#include "tqtextlayout_p.h" #include "qfontengine_p.h" #ifndef TQT_NO_TRANSFORMATIONS diff --git a/src/kernel/qpainter_x11.cpp b/src/kernel/qpainter_x11.cpp index a4f71fc00..0e72d64da 100644 --- a/src/kernel/qpainter_x11.cpp +++ b/src/kernel/qpainter_x11.cpp @@ -45,15 +45,15 @@ #include "tqwidget.h" #include "ntqbitmap.h" #include "ntqpixmapcache.h" -#include "ntqtextcodec.h" +#include "tqtextcodec.h" #include "ntqpaintdevicemetrics.h" #include "qt_x11_p.h" -#include "qtextlayout_p.h" +#include "tqtextlayout_p.h" #include "qfontdata_p.h" #include "qfontengine_p.h" -#include "qtextengine_p.h" +#include "tqtextengine_p.h" #include @@ -435,7 +435,7 @@ static void init_gc_cache() // #define GC_CACHE_STAT #if defined(GC_CACHE_STAT) -#include "ntqtextstream.h" +#include "tqtextstream.h" #include "ntqbuffer.h" static int g_numhits = 0; diff --git a/src/kernel/qpsprinter.cpp b/src/kernel/qpsprinter.cpp index 6974fdf6c..22acd9832 100644 --- a/src/kernel/qpsprinter.cpp +++ b/src/kernel/qpsprinter.cpp @@ -67,7 +67,7 @@ #include "ntqfile.h" #include "ntqbuffer.h" #include "ntqintdict.h" -#include "ntqtextcodec.h" +#include "tqtextcodec.h" #include "ntqsettings.h" #include "tqmap.h" #include "ntqfontdatabase.h" @@ -98,8 +98,8 @@ #if defined( TQ_WS_X11 ) || defined (TQ_WS_QWS) #include "qfontdata_p.h" #include "qfontengine_p.h" -#include "qtextlayout_p.h" -#include "qtextengine_p.h" +#include "tqtextlayout_p.h" +#include "tqtextengine_p.h" extern bool tqt_has_xft; #endif diff --git a/src/kernel/qpsprinter_p.h b/src/kernel/qpsprinter_p.h index 6b96a965d..47939b1db 100644 --- a/src/kernel/qpsprinter_p.h +++ b/src/kernel/qpsprinter_p.h @@ -59,7 +59,7 @@ #ifndef QT_H #include "ntqprinter.h" -#include "ntqtextstream.h" +#include "tqtextstream.h" #endif // QT_H #ifndef TQT_NO_PRINTER diff --git a/src/kernel/qrichtext.cpp b/src/kernel/qrichtext.cpp index 484553d3e..cd4c31055 100644 --- a/src/kernel/qrichtext.cpp +++ b/src/kernel/qrichtext.cpp @@ -45,7 +45,7 @@ #include "tqstringlist.h" #include "ntqfont.h" -#include "ntqtextstream.h" +#include "tqtextstream.h" #include "ntqfile.h" #include "ntqapplication.h" #include "tqmap.h" @@ -62,7 +62,7 @@ #include "tqptrdict.h" #include "ntqstyle.h" #include "ntqcleanuphandler.h" -#include "qtextengine_p.h" +#include "tqtextengine_p.h" #include #include diff --git a/src/kernel/qrichtext_p.h b/src/kernel/qrichtext_p.h index 52762c6b4..58fed9826 100644 --- a/src/kernel/qrichtext_p.h +++ b/src/kernel/qrichtext_p.h @@ -118,7 +118,7 @@ public: enum Type { Regular=0, Custom=1, Anchor=2, CustomAnchor=3 }; TQChar c; - // this is the same struct as in qtextengine_p.h. Don't change! + // this is the same struct as in tqtextengine_p.h. Don't change! uchar softBreak :1; // Potential linebreak point uchar whiteSpace :1; // A unicode whitespace character, except NBSP, ZWNBSP uchar charStop :1; // Valid cursor position (for left/right arrow) diff --git a/src/kernel/qscriptengine.cpp b/src/kernel/qscriptengine.cpp index 08cac102f..5e18dad56 100644 --- a/src/kernel/qscriptengine.cpp +++ b/src/kernel/qscriptengine.cpp @@ -40,7 +40,7 @@ #include "ntqrect.h" #include "ntqfont.h" #include -#include "qtextengine_p.h" +#include "tqtextengine_p.h" #include "qfontengine_p.h" #include diff --git a/src/kernel/qscriptengine_p.h b/src/kernel/qscriptengine_p.h index 1c5d55370..77dd87b96 100644 --- a/src/kernel/qscriptengine_p.h +++ b/src/kernel/qscriptengine_p.h @@ -48,7 +48,7 @@ // We mean it. // -#include "qtextengine_p.h" +#include "tqtextengine_p.h" class TQString; struct TQCharAttributes; diff --git a/src/kernel/qscriptengine_x11.cpp b/src/kernel/qscriptengine_x11.cpp index 97ae6828b..6c1190fb3 100644 --- a/src/kernel/qscriptengine_x11.cpp +++ b/src/kernel/qscriptengine_x11.cpp @@ -1899,7 +1899,7 @@ static void indic_attributes(int script, const TQString &text, int from, int len // // -------------------------------------------------------------------------------------------------------------------------------------------- -#include +#include #include diff --git a/src/kernel/qt_kernel.pri b/src/kernel/qt_kernel.pri index cf370058b..5f20c7111 100644 --- a/src/kernel/qt_kernel.pri +++ b/src/kernel/qt_kernel.pri @@ -94,9 +94,9 @@ kernel { $$KERNEL_H/ntqgplugin.h \ $$KERNEL_H/ntqsimplerichtext.h \ $$KERNEL_CPP/qscriptengine_p.h \ - $$KERNEL_CPP/qtextengine_p.h \ + $$KERNEL_CPP/tqtextengine_p.h \ $$KERNEL_CPP/qfontengine_p.h \ - $$KERNEL_CPP/qtextlayout_p.h + $$KERNEL_CPP/tqtextlayout_p.h inputmethod { unix:x11 { @@ -264,8 +264,8 @@ kernel { $$KERNEL_CPP/qgplugin.cpp \ $$KERNEL_CPP/qsimplerichtext.cpp \ $$KERNEL_CPP/qscriptengine.cpp \ - $$KERNEL_CPP/qtextlayout.cpp \ - $$KERNEL_CPP/qtextengine.cpp + $$KERNEL_CPP/tqtextlayout.cpp \ + $$KERNEL_CPP/tqtextengine.cpp unix:HEADERS += $$KERNEL_P/qpsprinter_p.h \ $$KERNEL_H/ntqfontdatabase.h diff --git a/src/kernel/qtextengine.cpp b/src/kernel/qtextengine.cpp deleted file mode 100644 index e1a806f52..000000000 --- a/src/kernel/qtextengine.cpp +++ /dev/null @@ -1,1180 +0,0 @@ -/**************************************************************************** -** -** Text engine classes -** -** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. -** -** This file is part of the kernel module of the TQt GUI Toolkit. -** -** This file may be used under the terms of the GNU General -** Public License versions 2.0 or 3.0 as published by the Free -** Software Foundation and appearing in the files LICENSE.GPL2 -** and LICENSE.GPL3 included in the packaging of this file. -** Alternatively you may (at your option) use any later version -** of the GNU General Public License if such license has been -** publicly approved by Trolltech ASA (or its successors, if any) -** and the KDE Free TQt Foundation. -** -** Please review the following information to ensure GNU General -** Public Licensing requirements will be met: -** http://trolltech.com/products/qt/licenses/licensing/opensource/. -** If you are unsure which license is appropriate for your use, please -** review the following information: -** http://trolltech.com/products/qt/licenses/licensing/licensingoverview -** or contact the sales department at sales@trolltech.com. -** -** This file may be used under the terms of the Q Public License as -** defined by Trolltech ASA and appearing in the file LICENSE.TQPL -** included in the packaging of this file. Licensees holding valid TQt -** Commercial licenses may use this file in accordance with the TQt -** Commercial License Agreement provided with the Software. -** -** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, -** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted -** herein. -** -**********************************************************************/ - -#include "qtextengine_p.h" - -#include "qscriptengine_p.h" -#include -#include "qfontdata_p.h" -#include "qfontengine_p.h" -#include -#include -#include - -// ----------------------------------------------------------------------------------------------------- -// -// The BiDi algorithm -// -// ----------------------------------------------------------------------------------------------------- - - -#define BIDI_DEBUG 0//2 -#if (BIDI_DEBUG >= 1) -#include -using namespace std; - -static const char *directions[] = { - "DirL", "DirR", "DirEN", "DirES", "DirET", "DirAN", "DirCS", "DirB", "DirS", "DirWS", "DirON", - "DirLRE", "DirLRO", "DirAL", "DirRLE", "DirRLO", "DirPDF", "DirNSM", "DirBN" -}; - -#endif - -struct BidiStatus { - BidiStatus() { - eor = TQChar::DirON; - lastStrong = TQChar::DirON; - last = TQChar:: DirON; - dir = TQChar::DirON; - } - TQChar::Direction eor; - TQChar::Direction lastStrong; - TQChar::Direction last; - TQChar::Direction dir; -}; - -struct BidiControl { - struct Context { - unsigned char level : 6; - unsigned char override : 1; - unsigned char unused : 1; - }; - - inline BidiControl( bool rtl ) - : cCtx( 0 ), singleLine( FALSE ) { - ctx[0].level = (rtl ? 1 : 0); - ctx[0].override = FALSE; - } - - inline void embed( int level, bool override = FALSE ) { - if ( ctx[cCtx].level < 61 && cCtx < 61 ) { - (void) ++cCtx; - ctx[cCtx].level = level; - ctx[cCtx].override = override; - } - } - inline void pdf() { - if ( cCtx ) (void) --cCtx; - } - - inline uchar level() const { - return ctx[cCtx].level; - } - inline bool override() const { - return ctx[cCtx].override; - } - inline TQChar::Direction basicDirection() { - return (ctx[0].level ? TQChar::DirR : TQChar:: DirL ); - } - inline uchar baseLevel() { - return ctx[0].level; - } - inline TQChar::Direction direction() { - return ((ctx[cCtx].level%2) ? TQChar::DirR : TQChar:: DirL ); - } - - Context ctx[63]; - unsigned int cCtx : 8; - bool singleLine : 8; -}; - -static TQChar::Direction basicDirection( const TQString &str ) -{ - int len = str.length(); - int pos = 0; - const TQChar *uc = str.unicode() + pos; - while( pos < len ) { - switch( direction( *uc ) ) - { - case TQChar::DirL: - case TQChar::DirLRO: - case TQChar::DirLRE: - return TQChar::DirL; - case TQChar::DirR: - case TQChar::DirAL: - case TQChar::DirRLO: - case TQChar::DirRLE: - return TQChar::DirR; - default: - break; - } - ++pos; - ++uc; - } - return TQChar::DirL; -} - - -static void tqAppendItems(TQTextEngine *engine, int &start, int &stop, BidiControl &control, TQChar::Direction dir ) -{ - TQScriptItemArray &items = engine->items; - const TQChar *text = engine->string.unicode(); - - if ( start > stop ) { - // #### the algorithm is currently not really safe against this. Still needs fixing. -// tqWarning( "Bidi: appendItems() internal error" ); - return; - } - - int level = control.level(); - - if(dir != TQChar::DirON && !control.override()) { - // add level of run (cases I1 & I2) - if( level % 2 ) { - if(dir == TQChar::DirL || dir == TQChar::DirAN || dir == TQChar::DirEN ) - level++; - } else { - if( dir == TQChar::DirR ) - level++; - else if( dir == TQChar::DirAN || dir == TQChar::DirEN ) - level += 2; - } - } - -#if (BIDI_DEBUG >= 1) - tqDebug("new run: dir=%s from %d, to %d level = %d\n", directions[dir], start, stop, level); -#endif - TQFont::Script script = TQFont::NoScript; - TQScriptItem item; - item.position = start; - item.analysis.script = script; - item.analysis.bidiLevel = level; - item.analysis.override = control.override(); - item.analysis.reserved = 0; - - if ( control.singleLine ) { - for ( int i = start; i <= stop; i++ ) { - - unsigned short uc = text[i].unicode(); - TQFont::Script s = (TQFont::Script)scriptForChar( uc ); - if (s == TQFont::UnknownScript || s == TQFont::CombiningMarks) - s = script; - - if (s != script) { - item.analysis.script = s; - item.analysis.bidiLevel = level; - item.position = i; - items.append( item ); - script = s; - } - } - } else { - for ( int i = start; i <= stop; i++ ) { - - unsigned short uc = text[i].unicode(); - TQFont::Script s = (TQFont::Script)scriptForChar( uc ); - if (s == TQFont::UnknownScript || s == TQFont::CombiningMarks) - s = script; - - TQChar::Category category = ::category( uc ); - if ( uc == 0xfffcU || uc == 0x2028U ) { - item.analysis.bidiLevel = level % 2 ? level-1 : level; - item.analysis.script = TQFont::Latin; - item.isObject = TRUE; - s = TQFont::NoScript; - } else if ((uc >= 9 && uc <=13) || - (category >= TQChar::Separator_Space && category <= TQChar::Separator_Paragraph)) { - item.analysis.script = TQFont::Latin; - item.isSpace = TRUE; - item.isTab = ( uc == '\t' ); - item.analysis.bidiLevel = item.isTab ? control.baseLevel() : level; - s = TQFont::NoScript; - } else if ( s != script && (category != TQChar::Mark_NonSpacing || script == TQFont::NoScript)) { - item.analysis.script = s; - item.analysis.bidiLevel = level; - } else { - if (i - start < 32000) - continue; - start = i; - } - - item.position = i; - items.append( item ); - script = s; - item.isSpace = item.isTab = item.isObject = FALSE; - } - } - ++stop; - start = stop; -} - -typedef void (* fAppendItems)(TQTextEngine *, int &start, int &stop, BidiControl &control, TQChar::Direction dir); -static fAppendItems appendItems = tqAppendItems; - -// creates the next TQScript items. -static void bidiItemize( TQTextEngine *engine, bool rightToLeft, int mode ) -{ - BidiControl control( rightToLeft ); - if ( mode & TQTextEngine::SingleLine ) - control.singleLine = TRUE; - - int sor = 0; - int eor = -1; - - // ### should get rid of this! - bool first = TRUE; - - int length = engine->string.length(); - - if ( !length ) - return; - - const TQChar *unicode = engine->string.unicode(); - int current = 0; - - TQChar::Direction dir = rightToLeft ? TQChar::DirR : TQChar::DirL; - BidiStatus status; - TQChar::Direction sdir = direction( *unicode ); - if ( sdir != TQChar::DirL && sdir != TQChar::DirR && sdir != TQChar::DirAL && sdir != TQChar::DirEN && sdir != TQChar::DirAN ) - sdir = TQChar::DirON; - else - dir = TQChar::DirON; - status.eor = sdir; - status.lastStrong = rightToLeft ? TQChar::DirR : TQChar::DirL; - status.last = status.lastStrong; - status.dir = sdir; -#if (BIDI_DEBUG >= 2) - tqDebug("---- bidiReorder --- '%s'", engine->string.utf8().data()); - tqDebug("rightToLeft = %d", rightToLeft); -#endif - - - while ( current <= length ) { - - TQChar::Direction dirCurrent; - if ( current == (int)length ) - dirCurrent = control.basicDirection(); - else - dirCurrent = direction( unicode[current] ); - -#if (BIDI_DEBUG >= 2) - cout << "pos=" << current << " dir=" << directions[dir] - << " current=" << directions[dirCurrent] << " last=" << directions[status.last] - << " eor=" << eor << "/" << directions[status.eor] - << " sor=" << sor << " lastStrong=" - << directions[status.lastStrong] - << " level=" << (int)control.level() << endl; -#endif - - switch(dirCurrent) { - - // embedding and overrides (X1-X9 in the BiDi specs) - case TQChar::DirRLE: - case TQChar::DirRLO: - case TQChar::DirLRE: - case TQChar::DirLRO: - { - bool rtl = (dirCurrent == TQChar::DirRLE || dirCurrent == TQChar::DirRLO ); - bool override = (dirCurrent == TQChar::DirLRO || dirCurrent == TQChar::DirRLO ); - - uchar level = control.level(); - if( (level%2 != 0) == rtl ) - level += 2; - else - level++; - if(level < 61) { - eor = current-1; - appendItems(engine, sor, eor, control, dir); - eor = current; - control.embed( level, override ); - TQChar::Direction edir = (rtl ? TQChar::DirR : TQChar::DirL ); - dir = status.eor = edir; - status.lastStrong = edir; - } - break; - } - case TQChar::DirPDF: - { - if (dir != control.direction()) { - eor = current-1; - appendItems(engine, sor, eor, control, dir); - dir = control.direction(); - } - eor = current; - appendItems(engine, sor, eor, control, dir); - dir = TQChar::DirON; status.eor = TQChar::DirON; - status.last = control.direction(); - control.pdf(); - if ( control.override() ) - dir = control.direction(); - else - dir = TQChar::DirON; - status.lastStrong = control.direction(); - break; - } - - // strong types - case TQChar::DirL: - if(dir == TQChar::DirON) - dir = TQChar::DirL; - switch(status.last) - { - case TQChar::DirL: - eor = current; status.eor = TQChar::DirL; break; - case TQChar::DirR: - case TQChar::DirAL: - case TQChar::DirEN: - case TQChar::DirAN: - if ( !first ) { - appendItems(engine, sor, eor, control, dir); - dir = eor < length ? direction( unicode[eor] ) : control.basicDirection(); - status.eor = dir; - } else { - eor = current; status.eor = dir; - } - break; - case TQChar::DirES: - case TQChar::DirET: - case TQChar::DirCS: - case TQChar::DirBN: - case TQChar::DirB: - case TQChar::DirS: - case TQChar::DirWS: - case TQChar::DirON: - if(dir != TQChar::DirL) { - //last stuff takes embedding dir - if( control.direction() == TQChar::DirR ) { - if(status.eor != TQChar::DirR) { - // AN or EN - appendItems(engine, sor, eor, control, dir); - status.eor = TQChar::DirON; - dir = TQChar::DirR; - } - eor = current - 1; - appendItems(engine, sor, eor, control, dir); - dir = eor < length ? direction( unicode[eor] ) : control.basicDirection(); - status.eor = dir; - } else { - if(status.eor != TQChar::DirL) { - appendItems(engine, sor, eor, control, dir); - status.eor = TQChar::DirON; - dir = TQChar::DirL; - } else { - eor = current; status.eor = TQChar::DirL; break; - } - } - } else { - eor = current; status.eor = TQChar::DirL; - } - default: - break; - } - status.lastStrong = TQChar::DirL; - break; - case TQChar::DirAL: - case TQChar::DirR: - if(dir == TQChar::DirON) dir = TQChar::DirR; - switch(status.last) - { - case TQChar::DirL: - case TQChar::DirEN: - case TQChar::DirAN: - if ( !first ) { - appendItems(engine, sor, eor, control, dir); - dir = TQChar::DirON; status.eor = TQChar::DirON; - break; - } - case TQChar::DirR: - case TQChar::DirAL: - eor = current; status.eor = TQChar::DirR; break; - case TQChar::DirES: - case TQChar::DirET: - case TQChar::DirCS: - case TQChar::DirBN: - case TQChar::DirB: - case TQChar::DirS: - case TQChar::DirWS: - case TQChar::DirON: - if( status.eor != TQChar::DirR && status.eor != TQChar::DirAL ) { - //last stuff takes embedding dir - if(control.direction() == TQChar::DirR - || status.lastStrong == TQChar::DirR || status.lastStrong == TQChar::DirAL) { - appendItems(engine, sor, eor, control, dir); - dir = TQChar::DirON; status.eor = TQChar::DirON; - dir = TQChar::DirR; - eor = current; - } else { - eor = current - 1; - appendItems(engine, sor, eor, control, dir); - dir = TQChar::DirON; status.eor = TQChar::DirON; - dir = TQChar::DirR; - } - } else { - eor = current; status.eor = TQChar::DirR; - } - default: - break; - } - status.lastStrong = dirCurrent; - break; - - // weak types: - - case TQChar::DirNSM: - if (eor == current-1) - eor = current; - break; - case TQChar::DirEN: - // if last strong was AL change EN to AN - if(status.lastStrong != TQChar::DirAL) { - if(dir == TQChar::DirON) { - if(status.lastStrong == TQChar::DirL) - dir = TQChar::DirL; - else - dir = TQChar::DirEN; - } - switch(status.last) - { - case TQChar::DirET: - if ( status.lastStrong == TQChar::DirR || status.lastStrong == TQChar::DirAL ) { - appendItems(engine, sor, eor, control, dir); - status.eor = TQChar::DirON; - dir = TQChar::DirAN; - } - // fall through - case TQChar::DirEN: - case TQChar::DirL: - eor = current; - status.eor = dirCurrent; - break; - case TQChar::DirR: - case TQChar::DirAL: - case TQChar::DirAN: - if ( !first ) - appendItems(engine, sor, eor, control, dir); - status.eor = TQChar::DirEN; - dir = TQChar::DirAN; break; - case TQChar::DirES: - case TQChar::DirCS: - if(status.eor == TQChar::DirEN || dir == TQChar::DirAN) { - eor = current; break; - } - case TQChar::DirBN: - case TQChar::DirB: - case TQChar::DirS: - case TQChar::DirWS: - case TQChar::DirON: - if(status.eor == TQChar::DirR) { - // neutrals go to R - eor = current - 1; - appendItems(engine, sor, eor, control, dir); - dir = TQChar::DirON; status.eor = TQChar::DirEN; - dir = TQChar::DirAN; - } - else if( status.eor == TQChar::DirL || - (status.eor == TQChar::DirEN && status.lastStrong == TQChar::DirL)) { - eor = current; status.eor = dirCurrent; - } else { - // numbers on both sides, neutrals get right to left direction - if(dir != TQChar::DirL) { - appendItems(engine, sor, eor, control, dir); - dir = TQChar::DirON; status.eor = TQChar::DirON; - eor = current - 1; - dir = TQChar::DirR; - appendItems(engine, sor, eor, control, dir); - dir = TQChar::DirON; status.eor = TQChar::DirON; - dir = TQChar::DirAN; - } else { - eor = current; status.eor = dirCurrent; - } - } - default: - break; - } - break; - } - case TQChar::DirAN: - dirCurrent = TQChar::DirAN; - if(dir == TQChar::DirON) dir = TQChar::DirAN; - switch(status.last) - { - case TQChar::DirL: - case TQChar::DirAN: - eor = current; status.eor = TQChar::DirAN; break; - case TQChar::DirR: - case TQChar::DirAL: - case TQChar::DirEN: - if ( !first ) - appendItems(engine, sor, eor, control, dir); - dir = TQChar::DirON; status.eor = TQChar::DirAN; - break; - case TQChar::DirCS: - if(status.eor == TQChar::DirAN) { - eor = current; break; - } - case TQChar::DirES: - case TQChar::DirET: - case TQChar::DirBN: - case TQChar::DirB: - case TQChar::DirS: - case TQChar::DirWS: - case TQChar::DirON: - if(status.eor == TQChar::DirR) { - // neutrals go to R - eor = current - 1; - appendItems(engine, sor, eor, control, dir); - status.eor = TQChar::DirAN; - dir = TQChar::DirAN; - } else if( status.eor == TQChar::DirL || - (status.eor == TQChar::DirEN && status.lastStrong == TQChar::DirL)) { - eor = current; status.eor = dirCurrent; - } else { - // numbers on both sides, neutrals get right to left direction - if(dir != TQChar::DirL) { - appendItems(engine, sor, eor, control, dir); - status.eor = TQChar::DirON; - eor = current - 1; - dir = TQChar::DirR; - appendItems(engine, sor, eor, control, dir); - status.eor = TQChar::DirAN; - dir = TQChar::DirAN; - } else { - eor = current; status.eor = dirCurrent; - } - } - default: - break; - } - break; - case TQChar::DirES: - case TQChar::DirCS: - break; - case TQChar::DirET: - if(status.last == TQChar::DirEN) { - dirCurrent = TQChar::DirEN; - eor = current; status.eor = dirCurrent; - } - break; - - // boundary neutrals should be ignored - case TQChar::DirBN: - break; - // neutrals - case TQChar::DirB: - // ### what do we do with newline and paragraph separators that come to here? - break; - case TQChar::DirS: - // ### implement rule L1 - break; - case TQChar::DirWS: - case TQChar::DirON: - break; - default: - break; - } - - //cout << " after: dir=" << // dir << " current=" << dirCurrent << " last=" << status.last << " eor=" << status.eor << " lastStrong=" << status.lastStrong << " embedding=" << control.direction() << endl; - - if(current >= (int)length) break; - - // set status.last as needed. - switch(dirCurrent) { - case TQChar::DirET: - case TQChar::DirES: - case TQChar::DirCS: - case TQChar::DirS: - case TQChar::DirWS: - case TQChar::DirON: - switch(status.last) - { - case TQChar::DirL: - case TQChar::DirR: - case TQChar::DirAL: - case TQChar::DirEN: - case TQChar::DirAN: - status.last = dirCurrent; - break; - default: - status.last = TQChar::DirON; - } - break; - case TQChar::DirNSM: - case TQChar::DirBN: - // ignore these - break; - case TQChar::DirLRO: - case TQChar::DirLRE: - status.last = TQChar::DirL; - break; - case TQChar::DirRLO: - case TQChar::DirRLE: - status.last = TQChar::DirR; - break; - case TQChar::DirEN: - if ( status.last == TQChar::DirL ) { - status.last = TQChar::DirL; - break; - } - // fall through - default: - status.last = dirCurrent; - } - - first = FALSE; - ++current; - } - -#if (BIDI_DEBUG >= 1) - cout << "reached end of line current=" << current << ", eor=" << eor << endl; -#endif - eor = current - 1; // remove dummy char - - if ( sor <= eor ) - appendItems(engine, sor, eor, control, dir); - - -} - -void TQTextEngine::bidiReorder( int numItems, const TQ_UINT8 *levels, int *visualOrder ) -{ - - // first find highest and lowest levels - uchar levelLow = 128; - uchar levelHigh = 0; - int i = 0; - while ( i < numItems ) { - //printf("level = %d\n", r->level); - if ( levels[i] > levelHigh ) - levelHigh = levels[i]; - if ( levels[i] < levelLow ) - levelLow = levels[i]; - i++; - } - - // implements reordering of the line (L2 according to BiDi spec): - // L2. From the highest level found in the text to the lowest odd level on each line, - // reverse any contiguous sequence of characters that are at that level or higher. - - // reversing is only done up to the lowest odd level - if(!(levelLow%2)) levelLow++; - -#if (BIDI_DEBUG >= 1) - cout << "reorderLine: lineLow = " << (uint)levelLow << ", lineHigh = " << (uint)levelHigh << endl; -#endif - - int count = numItems - 1; - for ( i = 0; i < numItems; i++ ) - visualOrder[i] = i; - - while(levelHigh >= levelLow) { - int i = 0; - while ( i < count ) { - while(i < count && levels[i] < levelHigh) i++; - int start = i; - while(i <= count && levels[i] >= levelHigh) i++; - int end = i-1; - - if(start != end) { - //cout << "reversing from " << start << " to " << end << endl; - for(int j = 0; j < (end-start+1)/2; j++) { - int tmp = visualOrder[start+j]; - visualOrder[start+j] = visualOrder[end-j]; - visualOrder[end-j] = tmp; - } - } - i++; - } - levelHigh--; - } - -#if (BIDI_DEBUG >= 1) - cout << "visual order is:" << endl; - for ( i = 0; i < numItems; i++ ) - cout << visualOrder[i] << endl; -#endif -} - - -// ----------------------------------------------------------------------------------------------------- -// -// The line break algorithm. See http://www.unicode.org/reports/tr14/tr14-13.html -// -// ----------------------------------------------------------------------------------------------------- - -/* The Unicode algorithm does in our opinion allow line breaks at some - places they shouldn't be allowed. The following changes were thus - made in comparison to the Unicode reference: - - CL->AL from Dbk to Ibk - CL->PR from Dbk to Ibk - EX->AL from Dbk to Ibk - IS->AL from Dbk to Ibk - PO->AL from Dbk to Ibk - SY->AL from Dbk to Ibk - SY->PO from Dbk to Ibk - SY->PR from Dbk to Ibk - SY->OP from Dbk to Ibk - Al->OP from Dbk to Ibk - AL->HY from Dbk to Ibk - AL->PR from Dbk to Ibk - AL->PO from Dbk to Ibk - PR->PR from Dbk to Ibk - PO->PO from Dbk to Ibk - PR->PO from Dbk to Ibk - PO->PR from Dbk to Ibk - HY->PO from Dbk to Ibk - HY->PR from Dbk to Ibk - HY->OP from Dbk to Ibk - PO->OP from Dbk to Ibk - NU->EX from Dbk to Ibk - NU->PR from Dbk to Ibk - PO->NU from Dbk to Ibk - EX->PO from Dbk to Ibk -*/ - -enum break_action { - Dbk, // Direct break - Ibk, // Indirect break; only allowed if space between the two chars - Pbk // Prohibited break; no break allowed even if space between chars -}; - -// The following line break classes are not treated by the table: -// SA, BK, CR, LF, SG, CB, SP -static const TQ_UINT8 breakTable[TQUnicodeTables::LineBreak_CM+1][TQUnicodeTables::LineBreak_CM+1] = -{ - // OP, CL, QU, GL, NS, EX, SY, IS, PR, PO, NU, AL, ID, IN, HY, BA, BB, B2, ZW, CM - { Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk }, // OP - { Dbk, Pbk, Ibk, Pbk, Pbk, Pbk, Pbk, Pbk, Ibk, Ibk, Dbk, Ibk, Dbk, Dbk, Ibk, Ibk, Pbk, Pbk, Pbk, Pbk }, // CL - { Pbk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Pbk, Pbk }, // QU - { Ibk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Pbk, Pbk }, // GL - { Dbk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Ibk, Ibk, Dbk, Dbk, Pbk, Ibk }, // NS - { Dbk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Dbk, Ibk, Ibk, Ibk, Dbk, Dbk, Ibk, Ibk, Dbk, Dbk, Pbk, Ibk }, // EX - { Ibk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Ibk, Ibk, Ibk, Ibk, Dbk, Dbk, Ibk, Ibk, Dbk, Dbk, Pbk, Ibk }, // SY - { Dbk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Dbk, Dbk, Ibk, Ibk, Dbk, Dbk, Ibk, Ibk, Dbk, Dbk, Pbk, Ibk }, // IS - { Ibk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Ibk, Ibk, Ibk, Ibk, Ibk, Dbk, Ibk, Ibk, Dbk, Dbk, Pbk, Pbk }, // PR - { Ibk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Ibk, Ibk, Ibk, Ibk, Dbk, Dbk, Ibk, Ibk, Dbk, Dbk, Pbk, Ibk }, // PO - { Dbk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Ibk, Ibk, Ibk, Ibk, Dbk, Ibk, Ibk, Ibk, Dbk, Dbk, Pbk, Pbk }, // NU - { Ibk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Ibk, Ibk, Ibk, Ibk, Dbk, Ibk, Ibk, Ibk, Dbk, Dbk, Pbk, Pbk }, // AL - { Dbk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Dbk, Ibk, Dbk, Dbk, Dbk, Ibk, Ibk, Ibk, Dbk, Dbk, Pbk, Ibk }, // ID - { Dbk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Dbk, Dbk, Dbk, Dbk, Dbk, Ibk, Ibk, Ibk, Dbk, Dbk, Pbk, Ibk }, // IN - { Ibk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Ibk, Ibk, Ibk, Ibk, Dbk, Dbk, Ibk, Ibk, Dbk, Dbk, Pbk, Ibk }, // HY - { Dbk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Ibk, Ibk, Dbk, Dbk, Pbk, Ibk }, // BA - { Ibk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Pbk, Ibk }, // BB - { Dbk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Ibk, Ibk, Dbk, Pbk, Pbk, Ibk }, // B2 - { Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Pbk, Ibk }, // ZW - { Dbk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Dbk, Ibk, Dbk, Dbk, Dbk, Ibk, Ibk, Ibk, Dbk, Dbk, Pbk, Pbk } // CM -}; - -// set the soft break flag at every possible line breaking point. This needs correct clustering information. -static void calcLineBreaks(const TQString &str, TQCharAttributes *charAttributes) -{ - int len = str.length(); - if (!len) - return; - - const TQChar *uc = str.unicode(); - int cls = lineBreakClass(*uc); - if (cls >= TQUnicodeTables::LineBreak_CM) - cls = TQUnicodeTables::LineBreak_ID; - - charAttributes[0].softBreak = FALSE; - charAttributes[0].whiteSpace = (cls == TQUnicodeTables::LineBreak_SP); - charAttributes[0].charStop = TRUE; - - for (int i = 1; i < len; ++i) { - int ncls = ::lineBreakClass(uc[i]); - int category = ::category(uc[i]); - if (category == TQChar::Mark_NonSpacing) - goto nsm; - - if (category == TQChar::Other_Surrogate) { - // char stop only on first pair - if (uc[i].unicode() >= 0xd800 && uc[i].unicode() < 0xdc00 && i < len-1 - && uc[i+1].unicode() >= 0xdc00 && uc[i+1].unicode() < 0xe000) - goto nsm; - // ### correctly handle second surrogate - } - - if (ncls == TQUnicodeTables::LineBreak_SP) { - charAttributes[i].softBreak = FALSE; - charAttributes[i].whiteSpace = TRUE; - charAttributes[i].charStop = TRUE; - cls = ncls; - continue; - } - - - if (cls == TQUnicodeTables::LineBreak_SA && ncls == TQUnicodeTables::LineBreak_SA) { - // two complex chars (thai or lao), thai_attributes might override, but here - // we do a best guess - charAttributes[i].softBreak = TRUE; - charAttributes[i].whiteSpace = FALSE; - charAttributes[i].charStop = TRUE; - cls = ncls; - continue; - } - { - int tcls = ncls; - if (tcls >= TQUnicodeTables::LineBreak_SA) - tcls = TQUnicodeTables::LineBreak_ID; - if (cls >= TQUnicodeTables::LineBreak_SA) - cls = TQUnicodeTables::LineBreak_ID; - - bool softBreak; - int brk = breakTable[cls][tcls]; - if (brk == Ibk) - softBreak = (cls == TQUnicodeTables::LineBreak_SP); - else - softBreak = (brk == Dbk); -// tqDebug("char = %c %04x, cls=%d, ncls=%d, brk=%d soft=%d", uc[i].cell(), uc[i].unicode(), cls, ncls, brk, charAttributes[i].softBreak); - charAttributes[i].softBreak = softBreak; - charAttributes[i].whiteSpace = FALSE; - charAttributes[i].charStop = TRUE; - cls = ncls; - } - continue; - nsm: - charAttributes[i].softBreak = FALSE; - charAttributes[i].whiteSpace = FALSE; - charAttributes[i].charStop = FALSE; - } -} - -#if defined( TQ_WS_X11 ) || defined ( TQ_WS_QWS ) -# include "qtextengine_unix.cpp" -#elif defined( TQ_WS_WIN ) -# include "qtextengine_win.cpp" -#elif defined( TQ_WS_MAC ) -# include "qtextengine_mac.cpp" -#endif - - - -TQTextEngine::TQTextEngine( const TQString &str, TQFontPrivate *f ) - : string( str ), fnt( f ), direction( TQChar::DirON ), haveCharAttributes( FALSE ), widthOnly( FALSE ) -{ -#ifdef TQ_WS_WIN - if ( !resolvedUsp10 ) - resolveUsp10(); -#endif - if ( fnt ) fnt->ref(); - - num_glyphs = TQMAX( 16, str.length()*3/2 ); - int space_charAttributes = (sizeof(TQCharAttributes)*str.length()+sizeof(void*)-1)/sizeof(void*); - int space_logClusters = (sizeof(unsigned short)*str.length()+sizeof(void*)-1)/sizeof(void*); - int space_glyphs = (sizeof(glyph_t)*num_glyphs+sizeof(void*)-1)/sizeof(void*); - int space_advances = (sizeof(advance_t)*num_glyphs+sizeof(void*)-1)/sizeof(void*); - int space_offsets = (sizeof(qoffset_t)*num_glyphs+sizeof(void*)-1)/sizeof(void*); - int space_glyphAttributes = (sizeof(GlyphAttributes)*num_glyphs+sizeof(void*)-1)/sizeof(void*); - - allocated = space_charAttributes + space_glyphs + space_advances + - space_offsets + space_logClusters + space_glyphAttributes; - memory = (void **)::malloc( allocated*sizeof( void * ) ); - memset( memory, 0, allocated*sizeof( void * ) ); - - void **m = memory; - m += space_charAttributes; - logClustersPtr = (unsigned short *) m; - m += space_logClusters; - glyphPtr = (glyph_t *) m; - m += space_glyphs; - advancePtr = (advance_t *) m; - m += space_advances; - offsetsPtr = (qoffset_t *) m; - m += space_offsets; - glyphAttributesPtr = (GlyphAttributes *) m; - - used = 0; -} - -TQTextEngine::~TQTextEngine() -{ - if ( fnt && fnt->deref()) - delete fnt; - free( memory ); - allocated = 0; -} - -void TQTextEngine::reallocate( int totalGlyphs ) -{ - int new_num_glyphs = totalGlyphs; - int space_charAttributes = (sizeof(TQCharAttributes)*string.length()+sizeof(void*)-1)/sizeof(void*); - int space_logClusters = (sizeof(unsigned short)*string.length()+sizeof(void*)-1)/sizeof(void*); - int space_glyphs = (sizeof(glyph_t)*new_num_glyphs+sizeof(void*)-1)/sizeof(void*); - int space_advances = (sizeof(advance_t)*new_num_glyphs+sizeof(void*)-1)/sizeof(void*); - int space_offsets = (sizeof(qoffset_t)*new_num_glyphs+sizeof(void*)-1)/sizeof(void*); - int space_glyphAttributes = (sizeof(GlyphAttributes)*new_num_glyphs+sizeof(void*)-1)/sizeof(void*); - - int newAllocated = space_charAttributes + space_glyphs + space_advances + - space_offsets + space_logClusters + space_glyphAttributes; - void ** newMemory = (void **)::malloc( newAllocated*sizeof( void * ) ); - - void **nm = newMemory; - memcpy( nm, memory, string.length()*sizeof(TQCharAttributes) ); - nm += space_charAttributes; - memcpy( nm, logClustersPtr, num_glyphs*sizeof(unsigned short) ); - logClustersPtr = (unsigned short *) nm; - nm += space_logClusters; - memcpy( nm, glyphPtr, num_glyphs*sizeof(glyph_t) ); - glyphPtr = (glyph_t *) nm; - nm += space_glyphs; - memcpy( nm, advancePtr, num_glyphs*sizeof(advance_t) ); - advancePtr = (advance_t *) nm; - nm += space_advances; - memcpy( nm, offsetsPtr, num_glyphs*sizeof(qoffset_t) ); - offsetsPtr = (qoffset_t *) nm; - nm += space_offsets; - memcpy( nm, glyphAttributesPtr, num_glyphs*sizeof(GlyphAttributes) ); - glyphAttributesPtr = (GlyphAttributes *) nm; - - free( memory ); - memory = newMemory; - allocated = newAllocated; - num_glyphs = new_num_glyphs; -} - -const TQCharAttributes *TQTextEngine::attributes() -{ - TQCharAttributes *charAttributes = (TQCharAttributes *) memory; - if ( haveCharAttributes ) - return charAttributes; - - if ( !items.d ) - itemize(); - - ensureSpace(string.length()); - charAttributes = (TQCharAttributes *) memory; - calcLineBreaks(string, charAttributes); - - for ( int i = 0; i < items.size(); i++ ) { - TQScriptItem &si = items[i]; -#ifdef TQ_WS_WIN - int script = uspScriptForItem(this, i); -#else - int script = si.analysis.script; -#endif - Q_ASSERT( script < TQFont::NScripts ); - AttributeFunction attributes = scriptEngines[script].charAttributes; - if (!attributes) - continue; - int from = si.position; - int len = length( i ); - attributes( script, string, from, len, charAttributes ); - } - - haveCharAttributes = TRUE; - return charAttributes; -} - -void TQTextEngine::splitItem( int item, int pos ) -{ - if ( pos <= 0 ) - return; - - // we have to ensure we get correct shaping for arabic and other - // complex languages so we have to call shape _before_ we split the item. - shape(item); - - if ( items.d->size == items.d->alloc ) - items.resize( items.d->size + 1 ); - - int numMove = items.d->size - item-1; - if ( numMove > 0 ) - memmove( items.d->items + item+2, items.d->items +item+1, numMove*sizeof( TQScriptItem ) ); - items.d->size++; - TQScriptItem &newItem = items.d->items[item+1]; - TQScriptItem &oldItem = items.d->items[item]; - newItem = oldItem; - items.d->items[item+1].position += pos; - if ( newItem.fontEngine ) - newItem.fontEngine->ref(); - - if (oldItem.num_glyphs) { - // already shaped, break glyphs aswell - int breakGlyph = logClusters(&oldItem)[pos]; - - newItem.num_glyphs = oldItem.num_glyphs - breakGlyph; - oldItem.num_glyphs = breakGlyph; - newItem.glyph_data_offset = oldItem.glyph_data_offset + breakGlyph; - - for (int i = 0; i < newItem.num_glyphs; i++) - logClusters(&newItem)[i] -= breakGlyph; - - int w = 0; - const advance_t *a = advances(&oldItem); - for(int j = 0; j < breakGlyph; ++j) - w += *(a++); - - newItem.width = oldItem.width - w; - oldItem.width = w; - } - -// tqDebug("split at position %d itempos=%d", pos, item ); -} - - -int TQTextEngine::width( int from, int len ) const -{ - int w = 0; - -// tqDebug("TQTextEngine::width( from = %d, len = %d ), numItems=%d, strleng=%d", from, len, items.size(), string.length() ); - for ( int i = 0; i < items.size(); i++ ) { - TQScriptItem *si = &items[i]; - int pos = si->position; - int ilen = length( i ); -// tqDebug("item %d: from %d len %d", i, pos, ilen ); - if ( pos >= from + len ) - break; - if ( pos + ilen > from ) { - if ( !si->num_glyphs ) - shape( i ); - - advance_t *advances = this->advances( si ); - unsigned short *logClusters = this->logClusters( si ); - -// fprintf( stderr, " logclusters:" ); -// for ( int k = 0; k < ilen; k++ ) -// fprintf( stderr, " %d", logClusters[k] ); -// fprintf( stderr, "\n" ); - // do the simple thing for now and give the first glyph in a cluster the full width, all other ones 0. - int charFrom = from - pos; - if ( charFrom < 0 ) - charFrom = 0; - int glyphStart = logClusters[charFrom]; - if ( charFrom > 0 && logClusters[charFrom-1] == glyphStart ) - while ( charFrom < ilen && logClusters[charFrom] == glyphStart ) - charFrom++; - if ( charFrom < ilen ) { - glyphStart = logClusters[charFrom]; - int charEnd = from + len - 1 - pos; - if ( charEnd >= ilen ) - charEnd = ilen-1; - int glyphEnd = logClusters[charEnd]; - while ( charEnd < ilen && logClusters[charEnd] == glyphEnd ) - charEnd++; - glyphEnd = (charEnd == ilen) ? si->num_glyphs : logClusters[charEnd]; - -// tqDebug("char: start=%d end=%d / glyph: start = %d, end = %d", charFrom, charEnd, glyphStart, glyphEnd ); - for ( int i = glyphStart; i < glyphEnd; i++ ) - w += advances[i]; - } - } - } -// tqDebug(" --> w= %d ", w ); - return w; -} - -void TQTextEngine::itemize( int mode ) -{ - if ( !items.d ) { - int size = 8; - items.d = (TQScriptItemArrayPrivate *)malloc( sizeof( TQScriptItemArrayPrivate ) + - sizeof( TQScriptItem ) * size ); - items.d->alloc = size; - } - items.d->size = 0; - if ( string.length() == 0 ) - return; - - if ( !(mode & NoBidi) ) { - if ( direction == TQChar::DirON ) - direction = basicDirection( string ); - bidiItemize( this, direction == TQChar::DirR, mode ); - } else { - BidiControl control( FALSE ); - if ( mode & TQTextEngine::SingleLine ) - control.singleLine = TRUE; - int start = 0; - int stop = string.length() - 1; - appendItems(this, start, stop, control, TQChar::DirL); - } - if ( (mode & WidthOnly) == WidthOnly ) - widthOnly = TRUE; -} - -glyph_metrics_t TQTextEngine::boundingBox( int from, int len ) const -{ - glyph_metrics_t gm; - - for ( int i = 0; i < items.size(); i++ ) { - TQScriptItem *si = &items[i]; - int pos = si->position; - int ilen = length( i ); - if ( pos > from + len ) - break; - if ( pos + len > from ) { - if ( !si->num_glyphs ) - shape( i ); - advance_t *advances = this->advances( si ); - unsigned short *logClusters = this->logClusters( si ); - glyph_t *glyphs = this->glyphs( si ); - qoffset_t *offsets = this->offsets( si ); - - // do the simple thing for now and give the first glyph in a cluster the full width, all other ones 0. - int charFrom = from - pos; - if ( charFrom < 0 ) - charFrom = 0; - int glyphStart = logClusters[charFrom]; - if ( charFrom > 0 && logClusters[charFrom-1] == glyphStart ) - while ( charFrom < ilen && logClusters[charFrom] == glyphStart ) - charFrom++; - if ( charFrom < ilen ) { - glyphStart = logClusters[charFrom]; - int charEnd = from + len - 1 - pos; - if ( charEnd >= ilen ) - charEnd = ilen-1; - int glyphEnd = logClusters[charEnd]; - while ( charEnd < ilen && logClusters[charEnd] == glyphEnd ) - charEnd++; - glyphEnd = (charEnd == ilen) ? si->num_glyphs : logClusters[charEnd]; - if ( glyphStart <= glyphEnd ) { - TQFontEngine *fe = si->fontEngine; - glyph_metrics_t m = fe->boundingBox( glyphs+glyphStart, advances+glyphStart, - offsets+glyphStart, glyphEnd-glyphStart ); - gm.x = TQMIN( gm.x, m.x + gm.xoff ); - gm.y = TQMIN( gm.y, m.y + gm.yoff ); - gm.width = TQMAX( gm.width, m.width+gm.xoff ); - gm.height = TQMAX( gm.height, m.height+gm.yoff ); - gm.xoff += m.xoff; - gm.yoff += m.yoff; - } - } - } - } - return gm; -} diff --git a/src/kernel/qtextengine_p.h b/src/kernel/qtextengine_p.h deleted file mode 100644 index 774302a07..000000000 --- a/src/kernel/qtextengine_p.h +++ /dev/null @@ -1,377 +0,0 @@ -/**************************************************************************** -** -** ??? -** -** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. -** -** This file is part of the kernel module of the TQt GUI Toolkit. -** -** This file may be used under the terms of the GNU General -** Public License versions 2.0 or 3.0 as published by the Free -** Software Foundation and appearing in the files LICENSE.GPL2 -** and LICENSE.GPL3 included in the packaging of this file. -** Alternatively you may (at your option) use any later version -** of the GNU General Public License if such license has been -** publicly approved by Trolltech ASA (or its successors, if any) -** and the KDE Free TQt Foundation. -** -** Please review the following information to ensure GNU General -** Public Licensing requirements will be met: -** http://trolltech.com/products/qt/licenses/licensing/opensource/. -** If you are unsure which license is appropriate for your use, please -** review the following information: -** http://trolltech.com/products/qt/licenses/licensing/licensingoverview -** or contact the sales department at sales@trolltech.com. -** -** Licensees holding valid TQt Commercial licenses may use this file in -** accordance with the TQt Commercial License Agreement provided with -** the Software. -** -** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, -** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted -** herein. -** -**********************************************************************/ - -#ifndef TQTEXTENGINE_P_H -#define TQTEXTENGINE_P_H - -#ifndef QT_H -#include "ntqglobal.h" -#include "tqstring.h" -#include "ntqnamespace.h" -#include -#endif // QT_H - -#include -#ifndef Q_OS_TEMP -#include -#endif // Q_OS_TEMP - -class TQFontPrivate; -class TQString; - -class TQOpenType; -class TQPainter; - -// this uses the same coordinate system as TQt, but a different one to freetype and Xft. -// * y is usually negative, and is equal to the ascent. -// * negative yoff means the following stuff is drawn higher up. -// the characters bounding rect is given by TQRect( x,y,width,height), it's advance by -// xoo and yoff -struct glyph_metrics_t -{ - inline glyph_metrics_t() { - x = 100000; - y = 100000; - width = 0; - height = 0; - xoff = 0; - yoff = 0; - } - inline glyph_metrics_t( int _x, int _y, int _width, int _height, int _xoff, int _yoff ) { - x = _x; - y = _y; - width = _width; - height = _height; - xoff = _xoff; - yoff = _yoff; - } - int x; - int y; - int width; - int height; - int xoff; - int yoff; -}; - -#if defined( TQ_WS_X11 ) || defined ( TQ_WS_QWS ) -typedef unsigned short glyph_t; - -struct qoffset_t { - short x; - short y; -}; - -typedef int advance_t; - -struct TQScriptAnalysis -{ - unsigned short script : 7; - unsigned short bidiLevel : 6; // Unicode Bidi algorithm embedding level (0-61) - unsigned short override : 1; // Set when in LRO/RLO embedding - unsigned short reserved : 2; - bool operator == ( const TQScriptAnalysis &other ) { - return - script == other.script && - bidiLevel == other.bidiLevel; - // ### -// && override == other.override; - } - -}; - -#elif defined( TQ_WS_MAC ) - -typedef unsigned short glyph_t; - -struct qoffset_t { - short x; - short y; -}; - -typedef int advance_t; - -struct TQScriptAnalysis -{ - unsigned short script : 7; - unsigned short bidiLevel : 6; // Unicode Bidi algorithm embedding level (0-61) - unsigned short override : 1; // Set when in LRO/RLO embedding - unsigned short reserved : 2; - bool operator == ( const TQScriptAnalysis &other ) { - return - script == other.script && - bidiLevel == other.bidiLevel; - // ### -// && override == other.override; - } - -}; - -#elif defined( TQ_WS_WIN ) - -// do not change the definitions below unless you know what you are doing! -// it is designed to be compatible with the types found in uniscribe. - -typedef unsigned short glyph_t; - -struct qoffset_t { - int x; - int y; -}; - -typedef int advance_t; - -struct TQScriptAnalysis { - unsigned short script :10; - unsigned short rtl :1; - unsigned short layoutRTL :1; - unsigned short linkBefore :1; - unsigned short linkAfter :1; - unsigned short logicalOrder :1; - unsigned short noGlyphIndex :1; - unsigned short bidiLevel :5; - unsigned short override :1; - unsigned short inhibitSymSwap :1; - unsigned short charShape :1; - unsigned short digitSubstitute :1; - unsigned short inhibitLigate :1; - unsigned short fDisplayZWG :1; - unsigned short arabicNumContext :1; - unsigned short gcpClusters :1; - unsigned short reserved :1; - unsigned short engineReserved :2; -}; - -inline bool operator == ( const TQScriptAnalysis &sa1, const TQScriptAnalysis &sa2 ) -{ - return - sa1.script == sa2.script && - sa1.bidiLevel == sa2.bidiLevel; - // ### -// && override == other.override; -} - -#endif - -// enum and struct are made to be compatible with Uniscribe, dont change unless you know what you're doing. -struct GlyphAttributes { - // highest value means highest priority for justification. Justification is done by first inserting kashidas - // starting with the highest priority positions, then stretching spaces, afterwards extending inter char - // spacing, and last spacing between arabic words. - // NoJustification is for example set for arabic where no Kashida can be inserted or for diacritics. - enum Justification { - NoJustification= 0, // Justification can't be applied after this glyph - Arabic_Space = 1, // This glyph represents a space inside arabic text - Character = 2, // Inter-character justification point follows this glyph - Space = 4, // This glyph represents a blank outside an Arabic run - Arabic_Normal = 7, // Normal Middle-Of-Word glyph that connects to the right (begin) - Arabic_Waw = 8, // Next character is final form of Waw/Ain/Qaf/Fa - Arabic_BaRa = 9, // Next two chars are Ba + Ra/Ya/AlefMaksura - Arabic_Alef = 10, // Next character is final form of Alef/Tah/Lam/Kaf/Gaf - Arabic_HaaDal = 11, // Next character is final form of Haa/Dal/Taa Marbutah - Arabic_Seen = 12, // Initial or Medial form Of Seen/Sad - Arabic_Kashida = 13 // Kashida(U+640) in middle of word - }; - unsigned short justification :4; // Justification class - unsigned short clusterStart :1; // First glyph of representation of cluster - unsigned short mark :1; // needs to be positioned around base char - unsigned short zeroWidth :1; // ZWJ, ZWNJ etc, with no width, currently used as "Don't print" for ZWSP - unsigned short reserved :1; - unsigned short combiningClass :8; -}; - -// also this is compatible to uniscribe. Do not change. -struct TQCharAttributes { - uchar softBreak :1; // Potential linebreak point _before_ this character - uchar whiteSpace :1; // A unicode whitespace character, except NBSP, ZWNBSP - uchar charStop :1; // Valid cursor position (for left/right arrow) - uchar wordStop :1; // Valid cursor position (for ctrl + left/right arrow) - uchar invalid :1; - uchar reserved :3; -}; - -inline bool qIsZeroWidthChar(ushort uc) -{ - return (uc >= 0x200b && uc <= 0x200f /* ZW Space, ZWNJ, ZWJ, LRM and RLM */) - || (uc >= 0x2028 && uc <= 0x202f /* LS, PS, LRE, RLE, PDF, LRO, RLO, NNBSP */) - || (uc >= 0x206a && uc <= 0x206f /* ISS, ASS, IAFS, AFS, NADS, NODS */); -} - -class TQFontEngine; - -struct TQScriptItem -{ - inline TQScriptItem() : position( 0 ), isSpace( FALSE ), isTab( FALSE ), - isObject( FALSE ), hasPositioning( FALSE ), - descent( -1 ), ascent( -1 ), width( -1 ), - x( 0 ), y( 0 ), num_glyphs( 0 ), glyph_data_offset( 0 ), - fontEngine( 0 ) { } - int position; - TQScriptAnalysis analysis; - unsigned short isSpace : 1; - unsigned short isTab : 1; - unsigned short isObject : 1; - unsigned short hasPositioning : 1; - unsigned short complex : 1; // Windows only - unsigned short private_use : 1; // Windows only - unsigned short reserved : 10; - short descent; - int ascent; - int width; - int x; - int y; - int num_glyphs; - int glyph_data_offset; - TQFontEngine *fontEngine; -}; - -struct TQScriptItemArrayPrivate -{ - unsigned int alloc; - unsigned int size; - TQScriptItem items[1]; -}; - -class TQScriptItemArray -{ -public: - TQScriptItemArray() : d( 0 ) {} - ~TQScriptItemArray(); - - inline TQScriptItem &operator[] (int i) const {return d->items[i]; } - inline void append( const TQScriptItem &item ) { - if ( d->size == d->alloc ) - resize( d->size + 1 ); - d->items[d->size] = item; - d->size++; - } - inline int size() const { return d ? d->size : 0; } - - void resize( int s ); - void clear(); - - TQScriptItemArrayPrivate *d; -private: -#ifdef TQ_DISABLE_COPY - TQScriptItemArray( const TQScriptItemArray & ); - TQScriptItemArray &operator = ( const TQScriptItemArray & ); -#endif -}; - -class TQFontPrivate; - -class TQ_EXPORT TQTextEngine { -public: - TQTextEngine( const TQString &str, TQFontPrivate *f ); - ~TQTextEngine(); - - enum Mode { - Full = 0x00, - NoBidi = 0x01, - SingleLine = 0x02, - WidthOnly = 0x07 - }; - - void itemize( int mode = Full ); - - static void bidiReorder( int numRuns, const TQ_UINT8 *levels, int *visualOrder ); - - const TQCharAttributes *attributes(); - void shape( int item ) const; - - // ### we need something for justification - - enum Edge { - Leading, - Trailing - }; - enum ShaperFlag { - RightToLeft = 0x0001, - Mirrored = 0x0001 - }; - - int width( int charFrom, int numChars ) const; - glyph_metrics_t boundingBox( int from, int len ) const; - - TQScriptItemArray items; - TQString string; - TQFontPrivate *fnt; - int lineWidth; - int widthUsed; - int firstItemInLine; - int currentItem; - TQChar::Direction direction : 5; - unsigned int haveCharAttributes : 1; - unsigned int widthOnly : 1; - unsigned int reserved : 25; - - int length( int item ) const { - const TQScriptItem &si = items[item]; - int from = si.position; - item++; - return ( item < items.size() ? items[item].position : string.length() ) - from; - } - void splitItem( int item, int pos ); - - unsigned short *logClustersPtr; - glyph_t *glyphPtr; - advance_t *advancePtr; - qoffset_t *offsetsPtr; - GlyphAttributes *glyphAttributesPtr; - - inline unsigned short *logClusters( const TQScriptItem *si ) const - { return logClustersPtr+si->position; } - inline glyph_t *glyphs( const TQScriptItem *si ) const - { return glyphPtr+si->glyph_data_offset; } - inline advance_t *advances( const TQScriptItem *si ) const - { return advancePtr+si->glyph_data_offset; } - inline qoffset_t *offsets( const TQScriptItem *si ) const - { return offsetsPtr+si->glyph_data_offset; } - inline GlyphAttributes *glyphAttributes( const TQScriptItem *si ) const - { return glyphAttributesPtr+si->glyph_data_offset; } - - void reallocate( int totalGlyphs ); - inline void ensureSpace( int nGlyphs ) const { - if ( num_glyphs - used < nGlyphs ) - ((TQTextEngine *)this)->reallocate( ( (used + nGlyphs + 16) >> 4 ) << 4 ); - } - - int allocated; - void **memory; - int num_glyphs; - int used; -}; - -#endif diff --git a/src/kernel/qtextengine_unix.cpp b/src/kernel/qtextengine_unix.cpp deleted file mode 100644 index 0d5e3b920..000000000 --- a/src/kernel/qtextengine_unix.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/**************************************************************************** -** -** Text engine classes -** -** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. -** -** This file is part of the kernel module of the TQt GUI Toolkit. -** -** This file may be used under the terms of the GNU General -** Public License versions 2.0 or 3.0 as published by the Free -** Software Foundation and appearing in the files LICENSE.GPL2 -** and LICENSE.GPL3 included in the packaging of this file. -** Alternatively you may (at your option) use any later version -** of the GNU General Public License if such license has been -** publicly approved by Trolltech ASA (or its successors, if any) -** and the KDE Free TQt Foundation. -** -** Please review the following information to ensure GNU General -** Public Licensing requirements will be met: -** http://trolltech.com/products/qt/licenses/licensing/opensource/. -** If you are unsure which license is appropriate for your use, please -** review the following information: -** http://trolltech.com/products/qt/licenses/licensing/licensingoverview -** or contact the sales department at sales@trolltech.com. -** -** This file may be used under the terms of the Q Public License as -** defined by Trolltech ASA and appearing in the file LICENSE.TQPL -** included in the packaging of this file. Licensees holding valid TQt -** Commercial licenses may use this file in accordance with the TQt -** Commercial License Agreement provided with the Software. -** -** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, -** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted -** herein. -** -**********************************************************************/ - -#include - - -TQScriptItemArray::~TQScriptItemArray() -{ - clear(); - free( d ); -} - -void TQScriptItemArray::clear() -{ - if ( d ) { - for ( unsigned int i = 0; i < d->size; i++ ) { - TQScriptItem &si = d->items[i]; - if ( si.fontEngine ) - si.fontEngine->deref(); - } - d->size = 0; - } -} - -void TQScriptItemArray::resize( int s ) -{ - int alloc = (s + 8) >> 3 << 3; - d = (TQScriptItemArrayPrivate *)realloc( d, sizeof( TQScriptItemArrayPrivate ) + - sizeof( TQScriptItem ) * alloc ); - d->alloc = alloc; -} - -void TQTextEngine::shape( int item ) const -{ - assert( item < items.size() ); - TQScriptItem &si = items[item]; - - if ( si.num_glyphs ) - return; - - TQFont::Script script = (TQFont::Script)si.analysis.script; - si.glyph_data_offset = used; - - if ( !si.fontEngine ) - si.fontEngine = fnt->engineForScript( script ); - si.fontEngine->ref(); - - si.ascent = si.fontEngine->ascent(); - si.descent = si.fontEngine->descent(); - si.num_glyphs = 0; - - if ( si.fontEngine && si.fontEngine != (TQFontEngine*)-1 ) { - TQShaperItem shaper_item; - shaper_item.script = si.analysis.script; - shaper_item.string = &string; - shaper_item.from = si.position; - shaper_item.length = length(item); - shaper_item.font = si.fontEngine; - shaper_item.num_glyphs = TQMAX(int(num_glyphs - used), shaper_item.length); - shaper_item.flags = si.analysis.bidiLevel % 2 ? RightToLeft : 0; - shaper_item.has_positioning = FALSE; - - while (1) { -// tqDebug(" . num_glyphs=%d, used=%d, item.num_glyphs=%d", num_glyphs, used, shaper_item.num_glyphs); - ensureSpace(shaper_item.num_glyphs); - shaper_item.num_glyphs = num_glyphs - used; -// tqDebug(" .. num_glyphs=%d, used=%d, item.num_glyphs=%d", num_glyphs, used, shaper_item.num_glyphs); - shaper_item.glyphs = glyphs(&si); - shaper_item.advances = advances(&si); - shaper_item.offsets = offsets(&si); - shaper_item.attributes = glyphAttributes(&si); - shaper_item.log_clusters = logClusters(&si); - if (scriptEngines[shaper_item.script].shape(&shaper_item)) - break; - } - - si.num_glyphs = shaper_item.num_glyphs; - si.hasPositioning = shaper_item.has_positioning; - } - ((TQTextEngine *)this)->used += si.num_glyphs; - - si.width = 0; - advance_t *advances = this->advances( &si ); - advance_t *end = advances + si.num_glyphs; - while ( advances < end ) { -// tqDebug("advances[%d] = %d", advances - this->advances(&si), *advances); - si.width += *(advances++); - } - - return; -} - diff --git a/src/kernel/qtextlayout.cpp b/src/kernel/qtextlayout.cpp deleted file mode 100644 index 777e61ad7..000000000 --- a/src/kernel/qtextlayout.cpp +++ /dev/null @@ -1,643 +0,0 @@ -/**************************************************************************** -** -** ??? -** -** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. -** -** This file is part of the kernel module of the TQt GUI Toolkit. -** -** This file may be used under the terms of the GNU General -** Public License versions 2.0 or 3.0 as published by the Free -** Software Foundation and appearing in the files LICENSE.GPL2 -** and LICENSE.GPL3 included in the packaging of this file. -** Alternatively you may (at your option) use any later version -** of the GNU General Public License if such license has been -** publicly approved by Trolltech ASA (or its successors, if any) -** and the KDE Free TQt Foundation. -** -** Please review the following information to ensure GNU General -** Public Licensing requirements will be met: -** http://trolltech.com/products/qt/licenses/licensing/opensource/. -** If you are unsure which license is appropriate for your use, please -** review the following information: -** http://trolltech.com/products/qt/licenses/licensing/licensingoverview -** or contact the sales department at sales@trolltech.com. -** -** This file may be used under the terms of the Q Public License as -** defined by Trolltech ASA and appearing in the file LICENSE.TQPL -** included in the packaging of this file. Licensees holding valid TQt -** Commercial licenses may use this file in accordance with the TQt -** Commercial License Agreement provided with the Software. -** -** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, -** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted -** herein. -** -**********************************************************************/ - -#include "qtextlayout_p.h" -#include "qtextengine_p.h" - -#include -#include -#include - - -TQRect TQTextItem::rect() const -{ - TQScriptItem& si = engine->items[item]; - return TQRect( si.x, si.y, si.width, si.ascent+si.descent ); -} - -int TQTextItem::x() const -{ - return engine->items[item].x; -} - -int TQTextItem::y() const -{ - return engine->items[item].y; -} - -int TQTextItem::width() const -{ - return engine->items[item].width; -} - -int TQTextItem::ascent() const -{ - return engine->items[item].ascent; -} - -int TQTextItem::descent() const -{ - return engine->items[item].descent; -} - -void TQTextItem::setWidth( int w ) -{ - engine->items[item].width = w; -} - -void TQTextItem::setAscent( int a ) -{ - engine->items[item].ascent = a; -} - -void TQTextItem::setDescent( int d ) -{ - engine->items[item].descent = d; -} - -int TQTextItem::from() const -{ - return engine->items[item].position; -} - -int TQTextItem::length() const -{ - return engine->length(item); -} - - -int TQTextItem::cursorToX( int *cPos, Edge edge ) const -{ - int pos = *cPos; - TQScriptItem *si = &engine->items[item]; - - engine->shape( item ); - advance_t *advances = engine->advances( si ); - GlyphAttributes *glyphAttributes = engine->glyphAttributes( si ); - unsigned short *logClusters = engine->logClusters( si ); - - int l = engine->length( item ); - if ( pos > l ) - pos = l; - if ( pos < 0 ) - pos = 0; - - int glyph_pos = pos == l ? si->num_glyphs : logClusters[pos]; - if ( edge == Trailing ) { - // trailing edge is leading edge of next cluster - while ( glyph_pos < si->num_glyphs && !glyphAttributes[glyph_pos].clusterStart ) - glyph_pos++; - } - - int x = 0; - bool reverse = engine->items[item].analysis.bidiLevel % 2; - - if ( reverse ) { - for ( int i = si->num_glyphs-1; i >= glyph_pos; i-- ) - x += advances[i]; - } else { - for ( int i = 0; i < glyph_pos; i++ ) - x += advances[i]; - } -// tqDebug("cursorToX: pos=%d, gpos=%d x=%d", pos, glyph_pos, x ); - *cPos = pos; - return x; -} - -int TQTextItem::xToCursor( int x, CursorPosition cpos ) const -{ - TQScriptItem *si = &engine->items[item]; - engine->shape( item ); - advance_t *advances = engine->advances( si ); - unsigned short *logClusters = engine->logClusters( si ); - - int l = engine->length( item ); - bool reverse = si->analysis.bidiLevel % 2; - if ( x < 0 ) - return reverse ? l : 0; - - - if ( reverse ) { - int width = 0; - for ( int i = 0; i < si->num_glyphs; i++ ) { - width += advances[i]; - } - x = -x + width; - } - int cp_before = 0; - int cp_after = 0; - int x_before = 0; - int x_after = 0; - - int lastCluster = 0; - for ( int i = 1; i <= l; i++ ) { - int newCluster = i < l ? logClusters[i] : si->num_glyphs; - if ( newCluster != lastCluster ) { - // calculate cluster width - cp_before = cp_after; - x_before = x_after; - cp_after = i; - for ( int j = lastCluster; j < newCluster; j++ ) - x_after += advances[j]; - // tqDebug("cluster boundary: lastCluster=%d, newCluster=%d, x_before=%d, x_after=%d", - // lastCluster, newCluster, x_before, x_after ); - if ( x_after > x ) - break; - lastCluster = newCluster; - } - } - - bool before = ( cpos == OnCharacters || (x - x_before) < (x_after - x) ); - -// tqDebug("got cursor position for %d: %d/%d, x_ba=%d/%d using %d", -// x, cp_before,cp_after, x_before, x_after, before ? cp_before : cp_after ); - - return before ? cp_before : cp_after; - -} - - -bool TQTextItem::isRightToLeft() const -{ - return (engine->items[item].analysis.bidiLevel % 2); -} - -bool TQTextItem::isObject() const -{ - return engine->items[item].isObject; -} - -bool TQTextItem::isSpace() const -{ - return engine->items[item].isSpace; -} - -bool TQTextItem::isTab() const -{ - return engine->items[item].isTab; -} - - -TQTextLayout::TQTextLayout() - :d(0) {} - -TQTextLayout::TQTextLayout( const TQString& string, TQPainter *p ) -{ - TQFontPrivate *f = p ? ( p->pfont ? p->pfont->d : p->cfont.d ) : TQApplication::font().d; - d = new TQTextEngine( (string.isNull() ? (const TQString&)TQString::fromLatin1("") : string), f ); -} - -TQTextLayout::TQTextLayout( const TQString& string, const TQFont& fnt ) -{ - d = new TQTextEngine( (string.isNull() ? (const TQString&)TQString::fromLatin1("") : string), fnt.d ); -} - -TQTextLayout::~TQTextLayout() -{ - delete d; -} - -void TQTextLayout::setText( const TQString& string, const TQFont& fnt ) -{ - delete d; - d = new TQTextEngine( (string.isNull() ? (const TQString&)TQString::fromLatin1("") : string), fnt.d ); -} - -/* add an additional item boundary eg. for style change */ -void TQTextLayout::setBoundary( int strPos ) -{ - if ( strPos <= 0 || strPos >= (int)d->string.length() ) - return; - - int itemToSplit = 0; - while ( itemToSplit < d->items.size() && d->items[itemToSplit].position <= strPos ) - itemToSplit++; - itemToSplit--; - if ( d->items[itemToSplit].position == strPos ) { - // already a split at the requested position - return; - } - d->splitItem( itemToSplit, strPos - d->items[itemToSplit].position ); -} - - -int TQTextLayout::numItems() const -{ - return d->items.size(); -} - -TQTextItem TQTextLayout::itemAt( int i ) const -{ - return TQTextItem( i, d ); -} - - -TQTextItem TQTextLayout::findItem( int strPos ) const -{ - if ( strPos == 0 && d->items.size() ) - return TQTextItem( 0, d ); - // ## TODO use bsearch - for ( int i = d->items.size()-1; i >= 0; --i ) { - if ( d->items[i].position < strPos ) - return TQTextItem( i, d ); - } - return TQTextItem(); -} - - -void TQTextLayout::beginLayout( TQTextLayout::LayoutMode m ) -{ - d->items.clear(); - TQTextEngine::Mode mode = TQTextEngine::Full; - if (m == NoBidi) - mode = TQTextEngine::NoBidi; - else if (m == SingleLine) - mode = TQTextEngine::SingleLine; - d->itemize( mode ); - d->currentItem = 0; - d->firstItemInLine = -1; -} - -void TQTextLayout::beginLine( int width ) -{ - d->lineWidth = width; - d->widthUsed = 0; - d->firstItemInLine = -1; -} - -bool TQTextLayout::atEnd() const -{ - return d->currentItem >= d->items.size(); -} - -TQTextItem TQTextLayout::nextItem() -{ - d->currentItem++; - - if ( d->currentItem >= d->items.size() ) - return TQTextItem(); - - d->shape( d->currentItem ); - return TQTextItem( d->currentItem, d ); -} - -TQTextItem TQTextLayout::currentItem() -{ - if ( d->currentItem >= d->items.size() ) - return TQTextItem(); - - d->shape( d->currentItem ); - return TQTextItem( d->currentItem, d ); -} - -/* ## maybe also currentItem() */ -void TQTextLayout::setLineWidth( int newWidth ) -{ - d->lineWidth = newWidth; -} - -int TQTextLayout::lineWidth() const -{ - return d->lineWidth; -} - -int TQTextLayout::widthUsed() const -{ - return d->widthUsed; -} - -int TQTextLayout::availableWidth() const -{ - return d->lineWidth - d->widthUsed; -} - - -/* returns true if completely added */ -TQTextLayout::Result TQTextLayout::addCurrentItem() -{ - if ( d->firstItemInLine == -1 ) - d->firstItemInLine = d->currentItem; - TQScriptItem ¤t = d->items[d->currentItem]; - d->shape( d->currentItem ); - d->widthUsed += current.width; -// tqDebug("trying to add item %d with width %d, remaining %d", d->currentItem, current.width, d->lineWidth-d->widthUsed ); - - d->currentItem++; - - return (d->widthUsed <= d->lineWidth - || (d->currentItem < d->items.size() && d->items[d->currentItem].isSpace)) ? Ok : LineFull; -} - -TQTextLayout::Result TQTextLayout::endLine( int x, int y, int alignment, - int *ascent, int *descent, int *lineLeft, int *lineRight ) -{ - int available = d->lineWidth; - int numRuns = 0; - int numSpaceItems = 0; - TQ_UINT8 _levels[128]; - int _visual[128]; - TQ_UINT8 *levels = _levels; - int *visual = _visual; - int i; - TQTextLayout::Result result = LineEmpty; - -// tqDebug("endLine x=%d, y=%d, first=%d, current=%d lw=%d wu=%d", x, y, d->firstItemInLine, d->currentItem, d->lineWidth, d->widthUsed ); - int width_nobreak_found = d->widthUsed; - if ( d->firstItemInLine == -1 ) - goto end; - - if ( !(alignment & (TQt::SingleLine|TQt::IncludeTrailingSpaces)) - && d->currentItem > d->firstItemInLine && d->items[d->currentItem-1].isSpace ) { - int i = d->currentItem-1; - while ( i > d->firstItemInLine && d->items[i].isSpace ) { - numSpaceItems++; - d->widthUsed -= d->items[i--].width; - } - } - - if ( (alignment & (TQt::WordBreak|TQt::BreakAnywhere)) && - d->widthUsed > d->lineWidth ) { - // find linebreak - - // even though we removed trailing spaces the line was too wide. We'll have to break at an earlier - // position. To not confuse the layouting below, reset the number of space items - numSpaceItems = 0; - - - bool breakany = alignment & TQt::BreakAnywhere; - - const TQCharAttributes *attrs = d->attributes(); - int w = 0; - int itemWidth = 0; - int breakItem = d->firstItemInLine; - int breakPosition = -1; -#if 0 - // we iterate backwards or forward depending on what we guess is closer - if ( d->widthUsed - d->lineWidth < d->lineWidth ) { - // backwards search should be faster - - } else -#endif - { - int tmpWidth = 0; - int swidth = 0; - // forward search is probably faster - for ( int i = d->firstItemInLine; i < d->currentItem; i++ ) { - const TQScriptItem *si = &d->items[i]; - int length = d->length( i ); - const TQCharAttributes *itemAttrs = attrs + si->position; - - advance_t *advances = d->advances( si ); - unsigned short *logClusters = d->logClusters( si ); - - int lastGlyph = 0; - int tmpItemWidth = 0; - -// tqDebug("looking for break in item %d, isSpace=%d", i, si->isSpace ); - if(si->isSpace && !(alignment & (TQt::SingleLine|TQt::IncludeTrailingSpaces))) { - swidth += si->width; - } else { - tmpWidth += swidth; - swidth = 0; - for ( int pos = 0; pos < length; pos++ ) { -// tqDebug("advance=%d, w=%d, tmpWidth=%d, softbreak=%d, whitespace=%d", -// *advances, w, tmpWidth, itemAttrs->softBreak, itemAttrs->whiteSpace ); - int glyph = logClusters[pos]; - if ( lastGlyph != glyph ) { - while ( lastGlyph < glyph ) - tmpItemWidth += advances[lastGlyph++]; - if ( breakPosition != -1 && w + tmpWidth + tmpItemWidth > d->lineWidth ) { -// tqDebug("found break at w=%d, tmpWidth=%d, tmpItemWidth=%d", w, tmpWidth, tmpItemWidth); - d->widthUsed = w; - goto found; - } - } - if ( (itemAttrs->softBreak || - ( breakany && itemAttrs->charStop ) ) && - (i != d->firstItemInLine || pos != 0) ) { - if ( breakItem != i ) - itemWidth = 0; - if (itemAttrs->softBreak) - breakany = FALSE; - breakItem = i; - breakPosition = pos; -// tqDebug("found possible break at item %d, position %d (absolute=%d), w=%d, tmpWidth=%d, tmpItemWidth=%d", breakItem, breakPosition, d->items[breakItem].position+breakPosition, w, tmpWidth, tmpItemWidth); - w += tmpWidth + tmpItemWidth; - itemWidth += tmpItemWidth; - tmpWidth = 0; - tmpItemWidth = 0; - } - itemAttrs++; - } - while ( lastGlyph < si->num_glyphs ) - tmpItemWidth += advances[lastGlyph++]; - tmpWidth += tmpItemWidth; - if ( w + tmpWidth > d->lineWidth ) { - d->widthUsed = w; - goto found; - } - } - } - } - - found: - // no valid break point found - if ( breakPosition == -1 ) { - d->widthUsed = width_nobreak_found; - goto nobreak; - } - -// tqDebug("linebreak at item %d, position %d, wu=%d", breakItem, breakPosition, d->widthUsed ); - // split the line - if ( breakPosition > 0 ) { -// int length = d->length( breakItem ); - -// tqDebug("splitting item, itemWidth=%d", itemWidth); - // not a full item, need to break - d->splitItem( breakItem, breakPosition ); - d->currentItem = breakItem+1; - } else { - d->currentItem = breakItem; - } - } - - result = Ok; - - nobreak: - // position the objects in the line - available -= d->widthUsed; - - numRuns = d->currentItem - d->firstItemInLine - numSpaceItems; - if ( numRuns > 127 ) { - levels = new TQ_UINT8[numRuns]; - visual = new int[numRuns]; - } - -// tqDebug("reordering %d runs, numSpaceItems=%d", numRuns, numSpaceItems ); - for ( i = 0; i < numRuns; i++ ) { - levels[i] = d->items[i+d->firstItemInLine].analysis.bidiLevel; -// tqDebug(" level = %d", d->items[i+d->firstItemInLine].analysis.bidiLevel ); - } - d->bidiReorder( numRuns, levels, visual ); - - end: - // ### FIXME - if ( alignment & TQt::AlignJustify ) { - // #### justify items - alignment = TQt::AlignAuto; - } - if ( (alignment & TQt::AlignHorizontal_Mask) == TQt::AlignAuto ) - alignment = TQt::AlignLeft; - if ( alignment & TQt::AlignRight ) - x += available; - else if ( alignment & TQt::AlignHCenter ) - x += available/2; - - - int asc = ascent ? *ascent : 0; - int desc = descent ? *descent : 0; - - for ( i = 0; i < numRuns; i++ ) { - TQScriptItem &si = d->items[d->firstItemInLine+visual[i]]; - asc = TQMAX( asc, si.ascent ); - desc = TQMAX( desc, si.descent ); - } - - int left = x; - for ( i = 0; i < numRuns; i++ ) { - TQScriptItem &si = d->items[d->firstItemInLine+visual[i]]; -// tqDebug("positioning item %d with width %d (from=%d/length=%d) at %d", d->firstItemInLine+visual[i], si.width, si.position, -// d->length(d->firstItemInLine+visual[i]), x ); - si.x = x; - si.y = y + asc; - x += si.width; - } - int right = x; - - if ( numSpaceItems ) { - if ( d->items[d->firstItemInLine+numRuns].analysis.bidiLevel % 2 ) { - x = left; - for ( i = 0; i < numSpaceItems; i++ ) { - TQScriptItem &si = d->items[d->firstItemInLine + numRuns + i]; - x -= si.width; - si.x = x; - si.y = y + asc; - } - } else { - for ( i = 0; i < numSpaceItems; i++ ) { - TQScriptItem &si = d->items[d->firstItemInLine + numRuns + i]; - si.x = x; - si.y = y + asc; - x += si.width; - } - } - } - - if ( lineLeft ) - *lineLeft = left; - if ( lineRight ) - *lineRight = right; - if ( ascent ) - *ascent = asc; - if ( descent ) - *descent = desc; - - if (levels != _levels) - delete []levels; - if (visual != _visual) - delete []visual; - - return result; -} - -void TQTextLayout::endLayout() -{ - // nothing to do currently -} - - -int TQTextLayout::nextCursorPosition( int oldPos, CursorMode mode ) const -{ -// tqDebug("looking for next cursor pos for %d", oldPos ); - const TQCharAttributes *attributes = d->attributes(); - int len = d->string.length(); - if ( oldPos >= len ) - return oldPos; - oldPos++; - if ( mode == SkipCharacters ) { - while ( oldPos < len && !attributes[oldPos].charStop ) - oldPos++; - } else { - while ( oldPos < len && !attributes[oldPos].wordStop && !attributes[oldPos-1].whiteSpace ) - oldPos++; - } -// tqDebug(" -> %d", oldPos ); - return oldPos; -} - -int TQTextLayout::previousCursorPosition( int oldPos, CursorMode mode ) const -{ -// tqDebug("looking for previous cursor pos for %d", oldPos ); - const TQCharAttributes *attributes = d->attributes(); - if ( oldPos <= 0 ) - return 0; - oldPos--; - if ( mode == SkipCharacters ) { - while ( oldPos && !attributes[oldPos].charStop ) - oldPos--; - } else { - while ( oldPos && !attributes[oldPos].wordStop && !attributes[oldPos-1].whiteSpace ) - oldPos--; - } -// tqDebug(" -> %d", oldPos ); - return oldPos; -} - - -bool TQTextLayout::validCursorPosition( int pos ) const -{ - const TQCharAttributes *attributes = d->attributes(); - if ( pos < 0 || pos > (int)d->string.length() ) - return FALSE; - return attributes[pos].charStop; -} - -void TQTextLayout::setDirection(TQChar::Direction dir) -{ - d->direction = dir; -} diff --git a/src/kernel/qtextlayout_p.h b/src/kernel/qtextlayout_p.h deleted file mode 100644 index 64c7f64db..000000000 --- a/src/kernel/qtextlayout_p.h +++ /dev/null @@ -1,184 +0,0 @@ -/**************************************************************************** -** -** ??? -** -** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. -** -** This file is part of the kernel module of the TQt GUI Toolkit. -** -** This file may be used under the terms of the GNU General -** Public License versions 2.0 or 3.0 as published by the Free -** Software Foundation and appearing in the files LICENSE.GPL2 -** and LICENSE.GPL3 included in the packaging of this file. -** Alternatively you may (at your option) use any later version -** of the GNU General Public License if such license has been -** publicly approved by Trolltech ASA (or its successors, if any) -** and the KDE Free TQt Foundation. -** -** Please review the following information to ensure GNU General -** Public Licensing requirements will be met: -** http://trolltech.com/products/qt/licenses/licensing/opensource/. -** If you are unsure which license is appropriate for your use, please -** review the following information: -** http://trolltech.com/products/qt/licenses/licensing/licensingoverview -** or contact the sales department at sales@trolltech.com. -** -** Licensees holding valid TQt Commercial licenses may use this file in -** accordance with the TQt Commercial License Agreement provided with -** the Software. -** -** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, -** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted -** herein. -** -**********************************************************************/ - -#ifndef TQTEXTLAYOUT_P_H -#define TQTEXTLAYOUT_P_H - -#ifndef QT_H -#include "tqstring.h" -#include "ntqnamespace.h" -#include "ntqrect.h" -#endif // QT_H - -class TQTextEngine; -class TQFont; - -class TQ_EXPORT TQTextItem -{ -public: - inline TQTextItem() : item(0), engine(0) {} - inline bool isValid() const { return (bool)engine; } - - TQRect rect() const; - int x() const; - int y() const; - int width() const; - int ascent() const; - int descent() const; - - enum Edge { - Leading, - Trailing - }; - enum CursorPosition { - BetweenCharacters, - OnCharacters - }; - - /* cPos gets set to the valid position */ - int cursorToX( int *cPos, Edge edge = Leading ) const; - inline int cursorToX( int cPos, Edge edge = Leading ) const { return cursorToX( &cPos, edge ); } - int xToCursor( int x, CursorPosition = BetweenCharacters ) const; - - bool isRightToLeft() const; - bool isObject() const; - bool isSpace() const; - bool isTab() const; - - void setWidth( int w ); - void setAscent( int a ); - void setDescent( int d ); - - int from() const; - int length() const; - -private: - friend class TQTextLayout; - friend class TQPainter; - friend class TQPSPrinter; - TQTextItem( int i, TQTextEngine *e ) : item( i ), engine( e ) {} - int item; - TQTextEngine *engine; -}; - - -class TQPainter; - -class TQ_EXPORT TQTextLayout -{ -public: - // does itemization - TQTextLayout(); - TQTextLayout( const TQString& string, TQPainter * = 0 ); - TQTextLayout( const TQString& string, const TQFont& fnt ); - ~TQTextLayout(); - - void setText( const TQString& string, const TQFont& fnt ); - - enum LineBreakStrategy { - AtWordBoundaries, - AtCharBoundaries - }; - - /* add an additional item boundary eg. for style change */ - void setBoundary( int strPos ); - - int numItems() const; - TQTextItem itemAt( int i ) const; - TQTextItem findItem( int strPos ) const; - - enum LayoutMode { - NoBidi, - SingleLine, - MultiLine - }; - void beginLayout( LayoutMode m = MultiLine ); - void beginLine( int width ); - - bool atEnd() const; - TQTextItem nextItem(); - TQTextItem currentItem(); - /* ## maybe also currentItem() */ - void setLineWidth( int newWidth ); - int lineWidth() const; - int widthUsed() const; - int availableWidth() const; - - enum Result { - Ok, - LineFull, - LineEmpty, - Error - }; - /* returns true if completely added */ - Result addCurrentItem(); - - /* Note: if ascent and descent are used they must be initialized to the minimum ascent/descent - acceptable for the line. TQFontMetrics::ascent/descent() is usually the right choice */ - Result endLine( int x = 0, int y = 0, int alignment = TQt::AlignLeft, - int *ascent = 0, int *descent = 0, int *left = 0, int *right = 0 ); - void endLayout(); - - enum CursorMode { - SkipCharacters, - SkipWords - }; - bool validCursorPosition( int pos ) const; - int nextCursorPosition( int oldPos, CursorMode mode = SkipCharacters ) const; - int previousCursorPosition( int oldPos, CursorMode mode = SkipCharacters ) const; - - void setDirection(TQChar::Direction); -private: - TQTextLayout( TQTextEngine *e ) : d( e ) {} - /* disable copy and assignment */ - TQTextLayout( const TQTextLayout & ) {} - void operator = ( const TQTextLayout & ) {} - - friend class TQTextItem; - friend class TQPainter; - friend class TQPSPrinter; - TQTextEngine *d; -}; - - -/* - class TQPainter { - ..... - void drawTextItem( int x, int y, TQTextItem *item ); - }; -*/ - -#endif diff --git a/src/kernel/tqimage.cpp b/src/kernel/tqimage.cpp index 7a454818e..d31168c70 100644 --- a/src/kernel/tqimage.cpp +++ b/src/kernel/tqimage.cpp @@ -42,7 +42,7 @@ #include "ntqregexp.h" #include "ntqfile.h" #include "ntqdatastream.h" -#include "ntqtextstream.h" +#include "tqtextstream.h" #include "ntqbuffer.h" #include "tqptrlist.h" #include "ntqasyncimageio.h" diff --git a/src/kernel/tqtextengine.cpp b/src/kernel/tqtextengine.cpp new file mode 100644 index 000000000..b66fb7d95 --- /dev/null +++ b/src/kernel/tqtextengine.cpp @@ -0,0 +1,1180 @@ +/**************************************************************************** +** +** Text engine classes +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the kernel module of the TQt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.TQPL +** included in the packaging of this file. Licensees holding valid TQt +** Commercial licenses may use this file in accordance with the TQt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "tqtextengine_p.h" + +#include "qscriptengine_p.h" +#include +#include "qfontdata_p.h" +#include "qfontengine_p.h" +#include +#include +#include + +// ----------------------------------------------------------------------------------------------------- +// +// The BiDi algorithm +// +// ----------------------------------------------------------------------------------------------------- + + +#define BIDI_DEBUG 0//2 +#if (BIDI_DEBUG >= 1) +#include +using namespace std; + +static const char *directions[] = { + "DirL", "DirR", "DirEN", "DirES", "DirET", "DirAN", "DirCS", "DirB", "DirS", "DirWS", "DirON", + "DirLRE", "DirLRO", "DirAL", "DirRLE", "DirRLO", "DirPDF", "DirNSM", "DirBN" +}; + +#endif + +struct BidiStatus { + BidiStatus() { + eor = TQChar::DirON; + lastStrong = TQChar::DirON; + last = TQChar:: DirON; + dir = TQChar::DirON; + } + TQChar::Direction eor; + TQChar::Direction lastStrong; + TQChar::Direction last; + TQChar::Direction dir; +}; + +struct BidiControl { + struct Context { + unsigned char level : 6; + unsigned char override : 1; + unsigned char unused : 1; + }; + + inline BidiControl( bool rtl ) + : cCtx( 0 ), singleLine( FALSE ) { + ctx[0].level = (rtl ? 1 : 0); + ctx[0].override = FALSE; + } + + inline void embed( int level, bool override = FALSE ) { + if ( ctx[cCtx].level < 61 && cCtx < 61 ) { + (void) ++cCtx; + ctx[cCtx].level = level; + ctx[cCtx].override = override; + } + } + inline void pdf() { + if ( cCtx ) (void) --cCtx; + } + + inline uchar level() const { + return ctx[cCtx].level; + } + inline bool override() const { + return ctx[cCtx].override; + } + inline TQChar::Direction basicDirection() { + return (ctx[0].level ? TQChar::DirR : TQChar:: DirL ); + } + inline uchar baseLevel() { + return ctx[0].level; + } + inline TQChar::Direction direction() { + return ((ctx[cCtx].level%2) ? TQChar::DirR : TQChar:: DirL ); + } + + Context ctx[63]; + unsigned int cCtx : 8; + bool singleLine : 8; +}; + +static TQChar::Direction basicDirection( const TQString &str ) +{ + int len = str.length(); + int pos = 0; + const TQChar *uc = str.unicode() + pos; + while( pos < len ) { + switch( direction( *uc ) ) + { + case TQChar::DirL: + case TQChar::DirLRO: + case TQChar::DirLRE: + return TQChar::DirL; + case TQChar::DirR: + case TQChar::DirAL: + case TQChar::DirRLO: + case TQChar::DirRLE: + return TQChar::DirR; + default: + break; + } + ++pos; + ++uc; + } + return TQChar::DirL; +} + + +static void tqAppendItems(TQTextEngine *engine, int &start, int &stop, BidiControl &control, TQChar::Direction dir ) +{ + TQScriptItemArray &items = engine->items; + const TQChar *text = engine->string.unicode(); + + if ( start > stop ) { + // #### the algorithm is currently not really safe against this. Still needs fixing. +// tqWarning( "Bidi: appendItems() internal error" ); + return; + } + + int level = control.level(); + + if(dir != TQChar::DirON && !control.override()) { + // add level of run (cases I1 & I2) + if( level % 2 ) { + if(dir == TQChar::DirL || dir == TQChar::DirAN || dir == TQChar::DirEN ) + level++; + } else { + if( dir == TQChar::DirR ) + level++; + else if( dir == TQChar::DirAN || dir == TQChar::DirEN ) + level += 2; + } + } + +#if (BIDI_DEBUG >= 1) + tqDebug("new run: dir=%s from %d, to %d level = %d\n", directions[dir], start, stop, level); +#endif + TQFont::Script script = TQFont::NoScript; + TQScriptItem item; + item.position = start; + item.analysis.script = script; + item.analysis.bidiLevel = level; + item.analysis.override = control.override(); + item.analysis.reserved = 0; + + if ( control.singleLine ) { + for ( int i = start; i <= stop; i++ ) { + + unsigned short uc = text[i].unicode(); + TQFont::Script s = (TQFont::Script)scriptForChar( uc ); + if (s == TQFont::UnknownScript || s == TQFont::CombiningMarks) + s = script; + + if (s != script) { + item.analysis.script = s; + item.analysis.bidiLevel = level; + item.position = i; + items.append( item ); + script = s; + } + } + } else { + for ( int i = start; i <= stop; i++ ) { + + unsigned short uc = text[i].unicode(); + TQFont::Script s = (TQFont::Script)scriptForChar( uc ); + if (s == TQFont::UnknownScript || s == TQFont::CombiningMarks) + s = script; + + TQChar::Category category = ::category( uc ); + if ( uc == 0xfffcU || uc == 0x2028U ) { + item.analysis.bidiLevel = level % 2 ? level-1 : level; + item.analysis.script = TQFont::Latin; + item.isObject = TRUE; + s = TQFont::NoScript; + } else if ((uc >= 9 && uc <=13) || + (category >= TQChar::Separator_Space && category <= TQChar::Separator_Paragraph)) { + item.analysis.script = TQFont::Latin; + item.isSpace = TRUE; + item.isTab = ( uc == '\t' ); + item.analysis.bidiLevel = item.isTab ? control.baseLevel() : level; + s = TQFont::NoScript; + } else if ( s != script && (category != TQChar::Mark_NonSpacing || script == TQFont::NoScript)) { + item.analysis.script = s; + item.analysis.bidiLevel = level; + } else { + if (i - start < 32000) + continue; + start = i; + } + + item.position = i; + items.append( item ); + script = s; + item.isSpace = item.isTab = item.isObject = FALSE; + } + } + ++stop; + start = stop; +} + +typedef void (* fAppendItems)(TQTextEngine *, int &start, int &stop, BidiControl &control, TQChar::Direction dir); +static fAppendItems appendItems = tqAppendItems; + +// creates the next TQScript items. +static void bidiItemize( TQTextEngine *engine, bool rightToLeft, int mode ) +{ + BidiControl control( rightToLeft ); + if ( mode & TQTextEngine::SingleLine ) + control.singleLine = TRUE; + + int sor = 0; + int eor = -1; + + // ### should get rid of this! + bool first = TRUE; + + int length = engine->string.length(); + + if ( !length ) + return; + + const TQChar *unicode = engine->string.unicode(); + int current = 0; + + TQChar::Direction dir = rightToLeft ? TQChar::DirR : TQChar::DirL; + BidiStatus status; + TQChar::Direction sdir = direction( *unicode ); + if ( sdir != TQChar::DirL && sdir != TQChar::DirR && sdir != TQChar::DirAL && sdir != TQChar::DirEN && sdir != TQChar::DirAN ) + sdir = TQChar::DirON; + else + dir = TQChar::DirON; + status.eor = sdir; + status.lastStrong = rightToLeft ? TQChar::DirR : TQChar::DirL; + status.last = status.lastStrong; + status.dir = sdir; +#if (BIDI_DEBUG >= 2) + tqDebug("---- bidiReorder --- '%s'", engine->string.utf8().data()); + tqDebug("rightToLeft = %d", rightToLeft); +#endif + + + while ( current <= length ) { + + TQChar::Direction dirCurrent; + if ( current == (int)length ) + dirCurrent = control.basicDirection(); + else + dirCurrent = direction( unicode[current] ); + +#if (BIDI_DEBUG >= 2) + cout << "pos=" << current << " dir=" << directions[dir] + << " current=" << directions[dirCurrent] << " last=" << directions[status.last] + << " eor=" << eor << "/" << directions[status.eor] + << " sor=" << sor << " lastStrong=" + << directions[status.lastStrong] + << " level=" << (int)control.level() << endl; +#endif + + switch(dirCurrent) { + + // embedding and overrides (X1-X9 in the BiDi specs) + case TQChar::DirRLE: + case TQChar::DirRLO: + case TQChar::DirLRE: + case TQChar::DirLRO: + { + bool rtl = (dirCurrent == TQChar::DirRLE || dirCurrent == TQChar::DirRLO ); + bool override = (dirCurrent == TQChar::DirLRO || dirCurrent == TQChar::DirRLO ); + + uchar level = control.level(); + if( (level%2 != 0) == rtl ) + level += 2; + else + level++; + if(level < 61) { + eor = current-1; + appendItems(engine, sor, eor, control, dir); + eor = current; + control.embed( level, override ); + TQChar::Direction edir = (rtl ? TQChar::DirR : TQChar::DirL ); + dir = status.eor = edir; + status.lastStrong = edir; + } + break; + } + case TQChar::DirPDF: + { + if (dir != control.direction()) { + eor = current-1; + appendItems(engine, sor, eor, control, dir); + dir = control.direction(); + } + eor = current; + appendItems(engine, sor, eor, control, dir); + dir = TQChar::DirON; status.eor = TQChar::DirON; + status.last = control.direction(); + control.pdf(); + if ( control.override() ) + dir = control.direction(); + else + dir = TQChar::DirON; + status.lastStrong = control.direction(); + break; + } + + // strong types + case TQChar::DirL: + if(dir == TQChar::DirON) + dir = TQChar::DirL; + switch(status.last) + { + case TQChar::DirL: + eor = current; status.eor = TQChar::DirL; break; + case TQChar::DirR: + case TQChar::DirAL: + case TQChar::DirEN: + case TQChar::DirAN: + if ( !first ) { + appendItems(engine, sor, eor, control, dir); + dir = eor < length ? direction( unicode[eor] ) : control.basicDirection(); + status.eor = dir; + } else { + eor = current; status.eor = dir; + } + break; + case TQChar::DirES: + case TQChar::DirET: + case TQChar::DirCS: + case TQChar::DirBN: + case TQChar::DirB: + case TQChar::DirS: + case TQChar::DirWS: + case TQChar::DirON: + if(dir != TQChar::DirL) { + //last stuff takes embedding dir + if( control.direction() == TQChar::DirR ) { + if(status.eor != TQChar::DirR) { + // AN or EN + appendItems(engine, sor, eor, control, dir); + status.eor = TQChar::DirON; + dir = TQChar::DirR; + } + eor = current - 1; + appendItems(engine, sor, eor, control, dir); + dir = eor < length ? direction( unicode[eor] ) : control.basicDirection(); + status.eor = dir; + } else { + if(status.eor != TQChar::DirL) { + appendItems(engine, sor, eor, control, dir); + status.eor = TQChar::DirON; + dir = TQChar::DirL; + } else { + eor = current; status.eor = TQChar::DirL; break; + } + } + } else { + eor = current; status.eor = TQChar::DirL; + } + default: + break; + } + status.lastStrong = TQChar::DirL; + break; + case TQChar::DirAL: + case TQChar::DirR: + if(dir == TQChar::DirON) dir = TQChar::DirR; + switch(status.last) + { + case TQChar::DirL: + case TQChar::DirEN: + case TQChar::DirAN: + if ( !first ) { + appendItems(engine, sor, eor, control, dir); + dir = TQChar::DirON; status.eor = TQChar::DirON; + break; + } + case TQChar::DirR: + case TQChar::DirAL: + eor = current; status.eor = TQChar::DirR; break; + case TQChar::DirES: + case TQChar::DirET: + case TQChar::DirCS: + case TQChar::DirBN: + case TQChar::DirB: + case TQChar::DirS: + case TQChar::DirWS: + case TQChar::DirON: + if( status.eor != TQChar::DirR && status.eor != TQChar::DirAL ) { + //last stuff takes embedding dir + if(control.direction() == TQChar::DirR + || status.lastStrong == TQChar::DirR || status.lastStrong == TQChar::DirAL) { + appendItems(engine, sor, eor, control, dir); + dir = TQChar::DirON; status.eor = TQChar::DirON; + dir = TQChar::DirR; + eor = current; + } else { + eor = current - 1; + appendItems(engine, sor, eor, control, dir); + dir = TQChar::DirON; status.eor = TQChar::DirON; + dir = TQChar::DirR; + } + } else { + eor = current; status.eor = TQChar::DirR; + } + default: + break; + } + status.lastStrong = dirCurrent; + break; + + // weak types: + + case TQChar::DirNSM: + if (eor == current-1) + eor = current; + break; + case TQChar::DirEN: + // if last strong was AL change EN to AN + if(status.lastStrong != TQChar::DirAL) { + if(dir == TQChar::DirON) { + if(status.lastStrong == TQChar::DirL) + dir = TQChar::DirL; + else + dir = TQChar::DirEN; + } + switch(status.last) + { + case TQChar::DirET: + if ( status.lastStrong == TQChar::DirR || status.lastStrong == TQChar::DirAL ) { + appendItems(engine, sor, eor, control, dir); + status.eor = TQChar::DirON; + dir = TQChar::DirAN; + } + // fall through + case TQChar::DirEN: + case TQChar::DirL: + eor = current; + status.eor = dirCurrent; + break; + case TQChar::DirR: + case TQChar::DirAL: + case TQChar::DirAN: + if ( !first ) + appendItems(engine, sor, eor, control, dir); + status.eor = TQChar::DirEN; + dir = TQChar::DirAN; break; + case TQChar::DirES: + case TQChar::DirCS: + if(status.eor == TQChar::DirEN || dir == TQChar::DirAN) { + eor = current; break; + } + case TQChar::DirBN: + case TQChar::DirB: + case TQChar::DirS: + case TQChar::DirWS: + case TQChar::DirON: + if(status.eor == TQChar::DirR) { + // neutrals go to R + eor = current - 1; + appendItems(engine, sor, eor, control, dir); + dir = TQChar::DirON; status.eor = TQChar::DirEN; + dir = TQChar::DirAN; + } + else if( status.eor == TQChar::DirL || + (status.eor == TQChar::DirEN && status.lastStrong == TQChar::DirL)) { + eor = current; status.eor = dirCurrent; + } else { + // numbers on both sides, neutrals get right to left direction + if(dir != TQChar::DirL) { + appendItems(engine, sor, eor, control, dir); + dir = TQChar::DirON; status.eor = TQChar::DirON; + eor = current - 1; + dir = TQChar::DirR; + appendItems(engine, sor, eor, control, dir); + dir = TQChar::DirON; status.eor = TQChar::DirON; + dir = TQChar::DirAN; + } else { + eor = current; status.eor = dirCurrent; + } + } + default: + break; + } + break; + } + case TQChar::DirAN: + dirCurrent = TQChar::DirAN; + if(dir == TQChar::DirON) dir = TQChar::DirAN; + switch(status.last) + { + case TQChar::DirL: + case TQChar::DirAN: + eor = current; status.eor = TQChar::DirAN; break; + case TQChar::DirR: + case TQChar::DirAL: + case TQChar::DirEN: + if ( !first ) + appendItems(engine, sor, eor, control, dir); + dir = TQChar::DirON; status.eor = TQChar::DirAN; + break; + case TQChar::DirCS: + if(status.eor == TQChar::DirAN) { + eor = current; break; + } + case TQChar::DirES: + case TQChar::DirET: + case TQChar::DirBN: + case TQChar::DirB: + case TQChar::DirS: + case TQChar::DirWS: + case TQChar::DirON: + if(status.eor == TQChar::DirR) { + // neutrals go to R + eor = current - 1; + appendItems(engine, sor, eor, control, dir); + status.eor = TQChar::DirAN; + dir = TQChar::DirAN; + } else if( status.eor == TQChar::DirL || + (status.eor == TQChar::DirEN && status.lastStrong == TQChar::DirL)) { + eor = current; status.eor = dirCurrent; + } else { + // numbers on both sides, neutrals get right to left direction + if(dir != TQChar::DirL) { + appendItems(engine, sor, eor, control, dir); + status.eor = TQChar::DirON; + eor = current - 1; + dir = TQChar::DirR; + appendItems(engine, sor, eor, control, dir); + status.eor = TQChar::DirAN; + dir = TQChar::DirAN; + } else { + eor = current; status.eor = dirCurrent; + } + } + default: + break; + } + break; + case TQChar::DirES: + case TQChar::DirCS: + break; + case TQChar::DirET: + if(status.last == TQChar::DirEN) { + dirCurrent = TQChar::DirEN; + eor = current; status.eor = dirCurrent; + } + break; + + // boundary neutrals should be ignored + case TQChar::DirBN: + break; + // neutrals + case TQChar::DirB: + // ### what do we do with newline and paragraph separators that come to here? + break; + case TQChar::DirS: + // ### implement rule L1 + break; + case TQChar::DirWS: + case TQChar::DirON: + break; + default: + break; + } + + //cout << " after: dir=" << // dir << " current=" << dirCurrent << " last=" << status.last << " eor=" << status.eor << " lastStrong=" << status.lastStrong << " embedding=" << control.direction() << endl; + + if(current >= (int)length) break; + + // set status.last as needed. + switch(dirCurrent) { + case TQChar::DirET: + case TQChar::DirES: + case TQChar::DirCS: + case TQChar::DirS: + case TQChar::DirWS: + case TQChar::DirON: + switch(status.last) + { + case TQChar::DirL: + case TQChar::DirR: + case TQChar::DirAL: + case TQChar::DirEN: + case TQChar::DirAN: + status.last = dirCurrent; + break; + default: + status.last = TQChar::DirON; + } + break; + case TQChar::DirNSM: + case TQChar::DirBN: + // ignore these + break; + case TQChar::DirLRO: + case TQChar::DirLRE: + status.last = TQChar::DirL; + break; + case TQChar::DirRLO: + case TQChar::DirRLE: + status.last = TQChar::DirR; + break; + case TQChar::DirEN: + if ( status.last == TQChar::DirL ) { + status.last = TQChar::DirL; + break; + } + // fall through + default: + status.last = dirCurrent; + } + + first = FALSE; + ++current; + } + +#if (BIDI_DEBUG >= 1) + cout << "reached end of line current=" << current << ", eor=" << eor << endl; +#endif + eor = current - 1; // remove dummy char + + if ( sor <= eor ) + appendItems(engine, sor, eor, control, dir); + + +} + +void TQTextEngine::bidiReorder( int numItems, const TQ_UINT8 *levels, int *visualOrder ) +{ + + // first find highest and lowest levels + uchar levelLow = 128; + uchar levelHigh = 0; + int i = 0; + while ( i < numItems ) { + //printf("level = %d\n", r->level); + if ( levels[i] > levelHigh ) + levelHigh = levels[i]; + if ( levels[i] < levelLow ) + levelLow = levels[i]; + i++; + } + + // implements reordering of the line (L2 according to BiDi spec): + // L2. From the highest level found in the text to the lowest odd level on each line, + // reverse any contiguous sequence of characters that are at that level or higher. + + // reversing is only done up to the lowest odd level + if(!(levelLow%2)) levelLow++; + +#if (BIDI_DEBUG >= 1) + cout << "reorderLine: lineLow = " << (uint)levelLow << ", lineHigh = " << (uint)levelHigh << endl; +#endif + + int count = numItems - 1; + for ( i = 0; i < numItems; i++ ) + visualOrder[i] = i; + + while(levelHigh >= levelLow) { + int i = 0; + while ( i < count ) { + while(i < count && levels[i] < levelHigh) i++; + int start = i; + while(i <= count && levels[i] >= levelHigh) i++; + int end = i-1; + + if(start != end) { + //cout << "reversing from " << start << " to " << end << endl; + for(int j = 0; j < (end-start+1)/2; j++) { + int tmp = visualOrder[start+j]; + visualOrder[start+j] = visualOrder[end-j]; + visualOrder[end-j] = tmp; + } + } + i++; + } + levelHigh--; + } + +#if (BIDI_DEBUG >= 1) + cout << "visual order is:" << endl; + for ( i = 0; i < numItems; i++ ) + cout << visualOrder[i] << endl; +#endif +} + + +// ----------------------------------------------------------------------------------------------------- +// +// The line break algorithm. See http://www.unicode.org/reports/tr14/tr14-13.html +// +// ----------------------------------------------------------------------------------------------------- + +/* The Unicode algorithm does in our opinion allow line breaks at some + places they shouldn't be allowed. The following changes were thus + made in comparison to the Unicode reference: + + CL->AL from Dbk to Ibk + CL->PR from Dbk to Ibk + EX->AL from Dbk to Ibk + IS->AL from Dbk to Ibk + PO->AL from Dbk to Ibk + SY->AL from Dbk to Ibk + SY->PO from Dbk to Ibk + SY->PR from Dbk to Ibk + SY->OP from Dbk to Ibk + Al->OP from Dbk to Ibk + AL->HY from Dbk to Ibk + AL->PR from Dbk to Ibk + AL->PO from Dbk to Ibk + PR->PR from Dbk to Ibk + PO->PO from Dbk to Ibk + PR->PO from Dbk to Ibk + PO->PR from Dbk to Ibk + HY->PO from Dbk to Ibk + HY->PR from Dbk to Ibk + HY->OP from Dbk to Ibk + PO->OP from Dbk to Ibk + NU->EX from Dbk to Ibk + NU->PR from Dbk to Ibk + PO->NU from Dbk to Ibk + EX->PO from Dbk to Ibk +*/ + +enum break_action { + Dbk, // Direct break + Ibk, // Indirect break; only allowed if space between the two chars + Pbk // Prohibited break; no break allowed even if space between chars +}; + +// The following line break classes are not treated by the table: +// SA, BK, CR, LF, SG, CB, SP +static const TQ_UINT8 breakTable[TQUnicodeTables::LineBreak_CM+1][TQUnicodeTables::LineBreak_CM+1] = +{ + // OP, CL, QU, GL, NS, EX, SY, IS, PR, PO, NU, AL, ID, IN, HY, BA, BB, B2, ZW, CM + { Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk, Pbk }, // OP + { Dbk, Pbk, Ibk, Pbk, Pbk, Pbk, Pbk, Pbk, Ibk, Ibk, Dbk, Ibk, Dbk, Dbk, Ibk, Ibk, Pbk, Pbk, Pbk, Pbk }, // CL + { Pbk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Pbk, Pbk }, // QU + { Ibk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Pbk, Pbk }, // GL + { Dbk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Ibk, Ibk, Dbk, Dbk, Pbk, Ibk }, // NS + { Dbk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Dbk, Ibk, Ibk, Ibk, Dbk, Dbk, Ibk, Ibk, Dbk, Dbk, Pbk, Ibk }, // EX + { Ibk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Ibk, Ibk, Ibk, Ibk, Dbk, Dbk, Ibk, Ibk, Dbk, Dbk, Pbk, Ibk }, // SY + { Dbk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Dbk, Dbk, Ibk, Ibk, Dbk, Dbk, Ibk, Ibk, Dbk, Dbk, Pbk, Ibk }, // IS + { Ibk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Ibk, Ibk, Ibk, Ibk, Ibk, Dbk, Ibk, Ibk, Dbk, Dbk, Pbk, Pbk }, // PR + { Ibk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Ibk, Ibk, Ibk, Ibk, Dbk, Dbk, Ibk, Ibk, Dbk, Dbk, Pbk, Ibk }, // PO + { Dbk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Ibk, Ibk, Ibk, Ibk, Dbk, Ibk, Ibk, Ibk, Dbk, Dbk, Pbk, Pbk }, // NU + { Ibk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Ibk, Ibk, Ibk, Ibk, Dbk, Ibk, Ibk, Ibk, Dbk, Dbk, Pbk, Pbk }, // AL + { Dbk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Dbk, Ibk, Dbk, Dbk, Dbk, Ibk, Ibk, Ibk, Dbk, Dbk, Pbk, Ibk }, // ID + { Dbk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Dbk, Dbk, Dbk, Dbk, Dbk, Ibk, Ibk, Ibk, Dbk, Dbk, Pbk, Ibk }, // IN + { Ibk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Ibk, Ibk, Ibk, Ibk, Dbk, Dbk, Ibk, Ibk, Dbk, Dbk, Pbk, Ibk }, // HY + { Dbk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Ibk, Ibk, Dbk, Dbk, Pbk, Ibk }, // BA + { Ibk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Ibk, Pbk, Ibk }, // BB + { Dbk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Ibk, Ibk, Dbk, Pbk, Pbk, Ibk }, // B2 + { Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Dbk, Pbk, Ibk }, // ZW + { Dbk, Pbk, Ibk, Pbk, Ibk, Pbk, Pbk, Pbk, Dbk, Ibk, Dbk, Dbk, Dbk, Ibk, Ibk, Ibk, Dbk, Dbk, Pbk, Pbk } // CM +}; + +// set the soft break flag at every possible line breaking point. This needs correct clustering information. +static void calcLineBreaks(const TQString &str, TQCharAttributes *charAttributes) +{ + int len = str.length(); + if (!len) + return; + + const TQChar *uc = str.unicode(); + int cls = lineBreakClass(*uc); + if (cls >= TQUnicodeTables::LineBreak_CM) + cls = TQUnicodeTables::LineBreak_ID; + + charAttributes[0].softBreak = FALSE; + charAttributes[0].whiteSpace = (cls == TQUnicodeTables::LineBreak_SP); + charAttributes[0].charStop = TRUE; + + for (int i = 1; i < len; ++i) { + int ncls = ::lineBreakClass(uc[i]); + int category = ::category(uc[i]); + if (category == TQChar::Mark_NonSpacing) + goto nsm; + + if (category == TQChar::Other_Surrogate) { + // char stop only on first pair + if (uc[i].unicode() >= 0xd800 && uc[i].unicode() < 0xdc00 && i < len-1 + && uc[i+1].unicode() >= 0xdc00 && uc[i+1].unicode() < 0xe000) + goto nsm; + // ### correctly handle second surrogate + } + + if (ncls == TQUnicodeTables::LineBreak_SP) { + charAttributes[i].softBreak = FALSE; + charAttributes[i].whiteSpace = TRUE; + charAttributes[i].charStop = TRUE; + cls = ncls; + continue; + } + + + if (cls == TQUnicodeTables::LineBreak_SA && ncls == TQUnicodeTables::LineBreak_SA) { + // two complex chars (thai or lao), thai_attributes might override, but here + // we do a best guess + charAttributes[i].softBreak = TRUE; + charAttributes[i].whiteSpace = FALSE; + charAttributes[i].charStop = TRUE; + cls = ncls; + continue; + } + { + int tcls = ncls; + if (tcls >= TQUnicodeTables::LineBreak_SA) + tcls = TQUnicodeTables::LineBreak_ID; + if (cls >= TQUnicodeTables::LineBreak_SA) + cls = TQUnicodeTables::LineBreak_ID; + + bool softBreak; + int brk = breakTable[cls][tcls]; + if (brk == Ibk) + softBreak = (cls == TQUnicodeTables::LineBreak_SP); + else + softBreak = (brk == Dbk); +// tqDebug("char = %c %04x, cls=%d, ncls=%d, brk=%d soft=%d", uc[i].cell(), uc[i].unicode(), cls, ncls, brk, charAttributes[i].softBreak); + charAttributes[i].softBreak = softBreak; + charAttributes[i].whiteSpace = FALSE; + charAttributes[i].charStop = TRUE; + cls = ncls; + } + continue; + nsm: + charAttributes[i].softBreak = FALSE; + charAttributes[i].whiteSpace = FALSE; + charAttributes[i].charStop = FALSE; + } +} + +#if defined( TQ_WS_X11 ) || defined ( TQ_WS_QWS ) +# include "tqtextengine_unix.cpp" +#elif defined( TQ_WS_WIN ) +# include "tqtextengine_win.cpp" +#elif defined( TQ_WS_MAC ) +# include "tqtextengine_mac.cpp" +#endif + + + +TQTextEngine::TQTextEngine( const TQString &str, TQFontPrivate *f ) + : string( str ), fnt( f ), direction( TQChar::DirON ), haveCharAttributes( FALSE ), widthOnly( FALSE ) +{ +#ifdef TQ_WS_WIN + if ( !resolvedUsp10 ) + resolveUsp10(); +#endif + if ( fnt ) fnt->ref(); + + num_glyphs = TQMAX( 16, str.length()*3/2 ); + int space_charAttributes = (sizeof(TQCharAttributes)*str.length()+sizeof(void*)-1)/sizeof(void*); + int space_logClusters = (sizeof(unsigned short)*str.length()+sizeof(void*)-1)/sizeof(void*); + int space_glyphs = (sizeof(glyph_t)*num_glyphs+sizeof(void*)-1)/sizeof(void*); + int space_advances = (sizeof(advance_t)*num_glyphs+sizeof(void*)-1)/sizeof(void*); + int space_offsets = (sizeof(qoffset_t)*num_glyphs+sizeof(void*)-1)/sizeof(void*); + int space_glyphAttributes = (sizeof(GlyphAttributes)*num_glyphs+sizeof(void*)-1)/sizeof(void*); + + allocated = space_charAttributes + space_glyphs + space_advances + + space_offsets + space_logClusters + space_glyphAttributes; + memory = (void **)::malloc( allocated*sizeof( void * ) ); + memset( memory, 0, allocated*sizeof( void * ) ); + + void **m = memory; + m += space_charAttributes; + logClustersPtr = (unsigned short *) m; + m += space_logClusters; + glyphPtr = (glyph_t *) m; + m += space_glyphs; + advancePtr = (advance_t *) m; + m += space_advances; + offsetsPtr = (qoffset_t *) m; + m += space_offsets; + glyphAttributesPtr = (GlyphAttributes *) m; + + used = 0; +} + +TQTextEngine::~TQTextEngine() +{ + if ( fnt && fnt->deref()) + delete fnt; + free( memory ); + allocated = 0; +} + +void TQTextEngine::reallocate( int totalGlyphs ) +{ + int new_num_glyphs = totalGlyphs; + int space_charAttributes = (sizeof(TQCharAttributes)*string.length()+sizeof(void*)-1)/sizeof(void*); + int space_logClusters = (sizeof(unsigned short)*string.length()+sizeof(void*)-1)/sizeof(void*); + int space_glyphs = (sizeof(glyph_t)*new_num_glyphs+sizeof(void*)-1)/sizeof(void*); + int space_advances = (sizeof(advance_t)*new_num_glyphs+sizeof(void*)-1)/sizeof(void*); + int space_offsets = (sizeof(qoffset_t)*new_num_glyphs+sizeof(void*)-1)/sizeof(void*); + int space_glyphAttributes = (sizeof(GlyphAttributes)*new_num_glyphs+sizeof(void*)-1)/sizeof(void*); + + int newAllocated = space_charAttributes + space_glyphs + space_advances + + space_offsets + space_logClusters + space_glyphAttributes; + void ** newMemory = (void **)::malloc( newAllocated*sizeof( void * ) ); + + void **nm = newMemory; + memcpy( nm, memory, string.length()*sizeof(TQCharAttributes) ); + nm += space_charAttributes; + memcpy( nm, logClustersPtr, num_glyphs*sizeof(unsigned short) ); + logClustersPtr = (unsigned short *) nm; + nm += space_logClusters; + memcpy( nm, glyphPtr, num_glyphs*sizeof(glyph_t) ); + glyphPtr = (glyph_t *) nm; + nm += space_glyphs; + memcpy( nm, advancePtr, num_glyphs*sizeof(advance_t) ); + advancePtr = (advance_t *) nm; + nm += space_advances; + memcpy( nm, offsetsPtr, num_glyphs*sizeof(qoffset_t) ); + offsetsPtr = (qoffset_t *) nm; + nm += space_offsets; + memcpy( nm, glyphAttributesPtr, num_glyphs*sizeof(GlyphAttributes) ); + glyphAttributesPtr = (GlyphAttributes *) nm; + + free( memory ); + memory = newMemory; + allocated = newAllocated; + num_glyphs = new_num_glyphs; +} + +const TQCharAttributes *TQTextEngine::attributes() +{ + TQCharAttributes *charAttributes = (TQCharAttributes *) memory; + if ( haveCharAttributes ) + return charAttributes; + + if ( !items.d ) + itemize(); + + ensureSpace(string.length()); + charAttributes = (TQCharAttributes *) memory; + calcLineBreaks(string, charAttributes); + + for ( int i = 0; i < items.size(); i++ ) { + TQScriptItem &si = items[i]; +#ifdef TQ_WS_WIN + int script = uspScriptForItem(this, i); +#else + int script = si.analysis.script; +#endif + Q_ASSERT( script < TQFont::NScripts ); + AttributeFunction attributes = scriptEngines[script].charAttributes; + if (!attributes) + continue; + int from = si.position; + int len = length( i ); + attributes( script, string, from, len, charAttributes ); + } + + haveCharAttributes = TRUE; + return charAttributes; +} + +void TQTextEngine::splitItem( int item, int pos ) +{ + if ( pos <= 0 ) + return; + + // we have to ensure we get correct shaping for arabic and other + // complex languages so we have to call shape _before_ we split the item. + shape(item); + + if ( items.d->size == items.d->alloc ) + items.resize( items.d->size + 1 ); + + int numMove = items.d->size - item-1; + if ( numMove > 0 ) + memmove( items.d->items + item+2, items.d->items +item+1, numMove*sizeof( TQScriptItem ) ); + items.d->size++; + TQScriptItem &newItem = items.d->items[item+1]; + TQScriptItem &oldItem = items.d->items[item]; + newItem = oldItem; + items.d->items[item+1].position += pos; + if ( newItem.fontEngine ) + newItem.fontEngine->ref(); + + if (oldItem.num_glyphs) { + // already shaped, break glyphs aswell + int breakGlyph = logClusters(&oldItem)[pos]; + + newItem.num_glyphs = oldItem.num_glyphs - breakGlyph; + oldItem.num_glyphs = breakGlyph; + newItem.glyph_data_offset = oldItem.glyph_data_offset + breakGlyph; + + for (int i = 0; i < newItem.num_glyphs; i++) + logClusters(&newItem)[i] -= breakGlyph; + + int w = 0; + const advance_t *a = advances(&oldItem); + for(int j = 0; j < breakGlyph; ++j) + w += *(a++); + + newItem.width = oldItem.width - w; + oldItem.width = w; + } + +// tqDebug("split at position %d itempos=%d", pos, item ); +} + + +int TQTextEngine::width( int from, int len ) const +{ + int w = 0; + +// tqDebug("TQTextEngine::width( from = %d, len = %d ), numItems=%d, strleng=%d", from, len, items.size(), string.length() ); + for ( int i = 0; i < items.size(); i++ ) { + TQScriptItem *si = &items[i]; + int pos = si->position; + int ilen = length( i ); +// tqDebug("item %d: from %d len %d", i, pos, ilen ); + if ( pos >= from + len ) + break; + if ( pos + ilen > from ) { + if ( !si->num_glyphs ) + shape( i ); + + advance_t *advances = this->advances( si ); + unsigned short *logClusters = this->logClusters( si ); + +// fprintf( stderr, " logclusters:" ); +// for ( int k = 0; k < ilen; k++ ) +// fprintf( stderr, " %d", logClusters[k] ); +// fprintf( stderr, "\n" ); + // do the simple thing for now and give the first glyph in a cluster the full width, all other ones 0. + int charFrom = from - pos; + if ( charFrom < 0 ) + charFrom = 0; + int glyphStart = logClusters[charFrom]; + if ( charFrom > 0 && logClusters[charFrom-1] == glyphStart ) + while ( charFrom < ilen && logClusters[charFrom] == glyphStart ) + charFrom++; + if ( charFrom < ilen ) { + glyphStart = logClusters[charFrom]; + int charEnd = from + len - 1 - pos; + if ( charEnd >= ilen ) + charEnd = ilen-1; + int glyphEnd = logClusters[charEnd]; + while ( charEnd < ilen && logClusters[charEnd] == glyphEnd ) + charEnd++; + glyphEnd = (charEnd == ilen) ? si->num_glyphs : logClusters[charEnd]; + +// tqDebug("char: start=%d end=%d / glyph: start = %d, end = %d", charFrom, charEnd, glyphStart, glyphEnd ); + for ( int i = glyphStart; i < glyphEnd; i++ ) + w += advances[i]; + } + } + } +// tqDebug(" --> w= %d ", w ); + return w; +} + +void TQTextEngine::itemize( int mode ) +{ + if ( !items.d ) { + int size = 8; + items.d = (TQScriptItemArrayPrivate *)malloc( sizeof( TQScriptItemArrayPrivate ) + + sizeof( TQScriptItem ) * size ); + items.d->alloc = size; + } + items.d->size = 0; + if ( string.length() == 0 ) + return; + + if ( !(mode & NoBidi) ) { + if ( direction == TQChar::DirON ) + direction = basicDirection( string ); + bidiItemize( this, direction == TQChar::DirR, mode ); + } else { + BidiControl control( FALSE ); + if ( mode & TQTextEngine::SingleLine ) + control.singleLine = TRUE; + int start = 0; + int stop = string.length() - 1; + appendItems(this, start, stop, control, TQChar::DirL); + } + if ( (mode & WidthOnly) == WidthOnly ) + widthOnly = TRUE; +} + +glyph_metrics_t TQTextEngine::boundingBox( int from, int len ) const +{ + glyph_metrics_t gm; + + for ( int i = 0; i < items.size(); i++ ) { + TQScriptItem *si = &items[i]; + int pos = si->position; + int ilen = length( i ); + if ( pos > from + len ) + break; + if ( pos + len > from ) { + if ( !si->num_glyphs ) + shape( i ); + advance_t *advances = this->advances( si ); + unsigned short *logClusters = this->logClusters( si ); + glyph_t *glyphs = this->glyphs( si ); + qoffset_t *offsets = this->offsets( si ); + + // do the simple thing for now and give the first glyph in a cluster the full width, all other ones 0. + int charFrom = from - pos; + if ( charFrom < 0 ) + charFrom = 0; + int glyphStart = logClusters[charFrom]; + if ( charFrom > 0 && logClusters[charFrom-1] == glyphStart ) + while ( charFrom < ilen && logClusters[charFrom] == glyphStart ) + charFrom++; + if ( charFrom < ilen ) { + glyphStart = logClusters[charFrom]; + int charEnd = from + len - 1 - pos; + if ( charEnd >= ilen ) + charEnd = ilen-1; + int glyphEnd = logClusters[charEnd]; + while ( charEnd < ilen && logClusters[charEnd] == glyphEnd ) + charEnd++; + glyphEnd = (charEnd == ilen) ? si->num_glyphs : logClusters[charEnd]; + if ( glyphStart <= glyphEnd ) { + TQFontEngine *fe = si->fontEngine; + glyph_metrics_t m = fe->boundingBox( glyphs+glyphStart, advances+glyphStart, + offsets+glyphStart, glyphEnd-glyphStart ); + gm.x = TQMIN( gm.x, m.x + gm.xoff ); + gm.y = TQMIN( gm.y, m.y + gm.yoff ); + gm.width = TQMAX( gm.width, m.width+gm.xoff ); + gm.height = TQMAX( gm.height, m.height+gm.yoff ); + gm.xoff += m.xoff; + gm.yoff += m.yoff; + } + } + } + } + return gm; +} diff --git a/src/kernel/tqtextengine_p.h b/src/kernel/tqtextengine_p.h new file mode 100644 index 000000000..774302a07 --- /dev/null +++ b/src/kernel/tqtextengine_p.h @@ -0,0 +1,377 @@ +/**************************************************************************** +** +** ??? +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the kernel module of the TQt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** Licensees holding valid TQt Commercial licenses may use this file in +** accordance with the TQt Commercial License Agreement provided with +** the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef TQTEXTENGINE_P_H +#define TQTEXTENGINE_P_H + +#ifndef QT_H +#include "ntqglobal.h" +#include "tqstring.h" +#include "ntqnamespace.h" +#include +#endif // QT_H + +#include +#ifndef Q_OS_TEMP +#include +#endif // Q_OS_TEMP + +class TQFontPrivate; +class TQString; + +class TQOpenType; +class TQPainter; + +// this uses the same coordinate system as TQt, but a different one to freetype and Xft. +// * y is usually negative, and is equal to the ascent. +// * negative yoff means the following stuff is drawn higher up. +// the characters bounding rect is given by TQRect( x,y,width,height), it's advance by +// xoo and yoff +struct glyph_metrics_t +{ + inline glyph_metrics_t() { + x = 100000; + y = 100000; + width = 0; + height = 0; + xoff = 0; + yoff = 0; + } + inline glyph_metrics_t( int _x, int _y, int _width, int _height, int _xoff, int _yoff ) { + x = _x; + y = _y; + width = _width; + height = _height; + xoff = _xoff; + yoff = _yoff; + } + int x; + int y; + int width; + int height; + int xoff; + int yoff; +}; + +#if defined( TQ_WS_X11 ) || defined ( TQ_WS_QWS ) +typedef unsigned short glyph_t; + +struct qoffset_t { + short x; + short y; +}; + +typedef int advance_t; + +struct TQScriptAnalysis +{ + unsigned short script : 7; + unsigned short bidiLevel : 6; // Unicode Bidi algorithm embedding level (0-61) + unsigned short override : 1; // Set when in LRO/RLO embedding + unsigned short reserved : 2; + bool operator == ( const TQScriptAnalysis &other ) { + return + script == other.script && + bidiLevel == other.bidiLevel; + // ### +// && override == other.override; + } + +}; + +#elif defined( TQ_WS_MAC ) + +typedef unsigned short glyph_t; + +struct qoffset_t { + short x; + short y; +}; + +typedef int advance_t; + +struct TQScriptAnalysis +{ + unsigned short script : 7; + unsigned short bidiLevel : 6; // Unicode Bidi algorithm embedding level (0-61) + unsigned short override : 1; // Set when in LRO/RLO embedding + unsigned short reserved : 2; + bool operator == ( const TQScriptAnalysis &other ) { + return + script == other.script && + bidiLevel == other.bidiLevel; + // ### +// && override == other.override; + } + +}; + +#elif defined( TQ_WS_WIN ) + +// do not change the definitions below unless you know what you are doing! +// it is designed to be compatible with the types found in uniscribe. + +typedef unsigned short glyph_t; + +struct qoffset_t { + int x; + int y; +}; + +typedef int advance_t; + +struct TQScriptAnalysis { + unsigned short script :10; + unsigned short rtl :1; + unsigned short layoutRTL :1; + unsigned short linkBefore :1; + unsigned short linkAfter :1; + unsigned short logicalOrder :1; + unsigned short noGlyphIndex :1; + unsigned short bidiLevel :5; + unsigned short override :1; + unsigned short inhibitSymSwap :1; + unsigned short charShape :1; + unsigned short digitSubstitute :1; + unsigned short inhibitLigate :1; + unsigned short fDisplayZWG :1; + unsigned short arabicNumContext :1; + unsigned short gcpClusters :1; + unsigned short reserved :1; + unsigned short engineReserved :2; +}; + +inline bool operator == ( const TQScriptAnalysis &sa1, const TQScriptAnalysis &sa2 ) +{ + return + sa1.script == sa2.script && + sa1.bidiLevel == sa2.bidiLevel; + // ### +// && override == other.override; +} + +#endif + +// enum and struct are made to be compatible with Uniscribe, dont change unless you know what you're doing. +struct GlyphAttributes { + // highest value means highest priority for justification. Justification is done by first inserting kashidas + // starting with the highest priority positions, then stretching spaces, afterwards extending inter char + // spacing, and last spacing between arabic words. + // NoJustification is for example set for arabic where no Kashida can be inserted or for diacritics. + enum Justification { + NoJustification= 0, // Justification can't be applied after this glyph + Arabic_Space = 1, // This glyph represents a space inside arabic text + Character = 2, // Inter-character justification point follows this glyph + Space = 4, // This glyph represents a blank outside an Arabic run + Arabic_Normal = 7, // Normal Middle-Of-Word glyph that connects to the right (begin) + Arabic_Waw = 8, // Next character is final form of Waw/Ain/Qaf/Fa + Arabic_BaRa = 9, // Next two chars are Ba + Ra/Ya/AlefMaksura + Arabic_Alef = 10, // Next character is final form of Alef/Tah/Lam/Kaf/Gaf + Arabic_HaaDal = 11, // Next character is final form of Haa/Dal/Taa Marbutah + Arabic_Seen = 12, // Initial or Medial form Of Seen/Sad + Arabic_Kashida = 13 // Kashida(U+640) in middle of word + }; + unsigned short justification :4; // Justification class + unsigned short clusterStart :1; // First glyph of representation of cluster + unsigned short mark :1; // needs to be positioned around base char + unsigned short zeroWidth :1; // ZWJ, ZWNJ etc, with no width, currently used as "Don't print" for ZWSP + unsigned short reserved :1; + unsigned short combiningClass :8; +}; + +// also this is compatible to uniscribe. Do not change. +struct TQCharAttributes { + uchar softBreak :1; // Potential linebreak point _before_ this character + uchar whiteSpace :1; // A unicode whitespace character, except NBSP, ZWNBSP + uchar charStop :1; // Valid cursor position (for left/right arrow) + uchar wordStop :1; // Valid cursor position (for ctrl + left/right arrow) + uchar invalid :1; + uchar reserved :3; +}; + +inline bool qIsZeroWidthChar(ushort uc) +{ + return (uc >= 0x200b && uc <= 0x200f /* ZW Space, ZWNJ, ZWJ, LRM and RLM */) + || (uc >= 0x2028 && uc <= 0x202f /* LS, PS, LRE, RLE, PDF, LRO, RLO, NNBSP */) + || (uc >= 0x206a && uc <= 0x206f /* ISS, ASS, IAFS, AFS, NADS, NODS */); +} + +class TQFontEngine; + +struct TQScriptItem +{ + inline TQScriptItem() : position( 0 ), isSpace( FALSE ), isTab( FALSE ), + isObject( FALSE ), hasPositioning( FALSE ), + descent( -1 ), ascent( -1 ), width( -1 ), + x( 0 ), y( 0 ), num_glyphs( 0 ), glyph_data_offset( 0 ), + fontEngine( 0 ) { } + int position; + TQScriptAnalysis analysis; + unsigned short isSpace : 1; + unsigned short isTab : 1; + unsigned short isObject : 1; + unsigned short hasPositioning : 1; + unsigned short complex : 1; // Windows only + unsigned short private_use : 1; // Windows only + unsigned short reserved : 10; + short descent; + int ascent; + int width; + int x; + int y; + int num_glyphs; + int glyph_data_offset; + TQFontEngine *fontEngine; +}; + +struct TQScriptItemArrayPrivate +{ + unsigned int alloc; + unsigned int size; + TQScriptItem items[1]; +}; + +class TQScriptItemArray +{ +public: + TQScriptItemArray() : d( 0 ) {} + ~TQScriptItemArray(); + + inline TQScriptItem &operator[] (int i) const {return d->items[i]; } + inline void append( const TQScriptItem &item ) { + if ( d->size == d->alloc ) + resize( d->size + 1 ); + d->items[d->size] = item; + d->size++; + } + inline int size() const { return d ? d->size : 0; } + + void resize( int s ); + void clear(); + + TQScriptItemArrayPrivate *d; +private: +#ifdef TQ_DISABLE_COPY + TQScriptItemArray( const TQScriptItemArray & ); + TQScriptItemArray &operator = ( const TQScriptItemArray & ); +#endif +}; + +class TQFontPrivate; + +class TQ_EXPORT TQTextEngine { +public: + TQTextEngine( const TQString &str, TQFontPrivate *f ); + ~TQTextEngine(); + + enum Mode { + Full = 0x00, + NoBidi = 0x01, + SingleLine = 0x02, + WidthOnly = 0x07 + }; + + void itemize( int mode = Full ); + + static void bidiReorder( int numRuns, const TQ_UINT8 *levels, int *visualOrder ); + + const TQCharAttributes *attributes(); + void shape( int item ) const; + + // ### we need something for justification + + enum Edge { + Leading, + Trailing + }; + enum ShaperFlag { + RightToLeft = 0x0001, + Mirrored = 0x0001 + }; + + int width( int charFrom, int numChars ) const; + glyph_metrics_t boundingBox( int from, int len ) const; + + TQScriptItemArray items; + TQString string; + TQFontPrivate *fnt; + int lineWidth; + int widthUsed; + int firstItemInLine; + int currentItem; + TQChar::Direction direction : 5; + unsigned int haveCharAttributes : 1; + unsigned int widthOnly : 1; + unsigned int reserved : 25; + + int length( int item ) const { + const TQScriptItem &si = items[item]; + int from = si.position; + item++; + return ( item < items.size() ? items[item].position : string.length() ) - from; + } + void splitItem( int item, int pos ); + + unsigned short *logClustersPtr; + glyph_t *glyphPtr; + advance_t *advancePtr; + qoffset_t *offsetsPtr; + GlyphAttributes *glyphAttributesPtr; + + inline unsigned short *logClusters( const TQScriptItem *si ) const + { return logClustersPtr+si->position; } + inline glyph_t *glyphs( const TQScriptItem *si ) const + { return glyphPtr+si->glyph_data_offset; } + inline advance_t *advances( const TQScriptItem *si ) const + { return advancePtr+si->glyph_data_offset; } + inline qoffset_t *offsets( const TQScriptItem *si ) const + { return offsetsPtr+si->glyph_data_offset; } + inline GlyphAttributes *glyphAttributes( const TQScriptItem *si ) const + { return glyphAttributesPtr+si->glyph_data_offset; } + + void reallocate( int totalGlyphs ); + inline void ensureSpace( int nGlyphs ) const { + if ( num_glyphs - used < nGlyphs ) + ((TQTextEngine *)this)->reallocate( ( (used + nGlyphs + 16) >> 4 ) << 4 ); + } + + int allocated; + void **memory; + int num_glyphs; + int used; +}; + +#endif diff --git a/src/kernel/tqtextengine_unix.cpp b/src/kernel/tqtextengine_unix.cpp new file mode 100644 index 000000000..0d5e3b920 --- /dev/null +++ b/src/kernel/tqtextengine_unix.cpp @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Text engine classes +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the kernel module of the TQt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.TQPL +** included in the packaging of this file. Licensees holding valid TQt +** Commercial licenses may use this file in accordance with the TQt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include + + +TQScriptItemArray::~TQScriptItemArray() +{ + clear(); + free( d ); +} + +void TQScriptItemArray::clear() +{ + if ( d ) { + for ( unsigned int i = 0; i < d->size; i++ ) { + TQScriptItem &si = d->items[i]; + if ( si.fontEngine ) + si.fontEngine->deref(); + } + d->size = 0; + } +} + +void TQScriptItemArray::resize( int s ) +{ + int alloc = (s + 8) >> 3 << 3; + d = (TQScriptItemArrayPrivate *)realloc( d, sizeof( TQScriptItemArrayPrivate ) + + sizeof( TQScriptItem ) * alloc ); + d->alloc = alloc; +} + +void TQTextEngine::shape( int item ) const +{ + assert( item < items.size() ); + TQScriptItem &si = items[item]; + + if ( si.num_glyphs ) + return; + + TQFont::Script script = (TQFont::Script)si.analysis.script; + si.glyph_data_offset = used; + + if ( !si.fontEngine ) + si.fontEngine = fnt->engineForScript( script ); + si.fontEngine->ref(); + + si.ascent = si.fontEngine->ascent(); + si.descent = si.fontEngine->descent(); + si.num_glyphs = 0; + + if ( si.fontEngine && si.fontEngine != (TQFontEngine*)-1 ) { + TQShaperItem shaper_item; + shaper_item.script = si.analysis.script; + shaper_item.string = &string; + shaper_item.from = si.position; + shaper_item.length = length(item); + shaper_item.font = si.fontEngine; + shaper_item.num_glyphs = TQMAX(int(num_glyphs - used), shaper_item.length); + shaper_item.flags = si.analysis.bidiLevel % 2 ? RightToLeft : 0; + shaper_item.has_positioning = FALSE; + + while (1) { +// tqDebug(" . num_glyphs=%d, used=%d, item.num_glyphs=%d", num_glyphs, used, shaper_item.num_glyphs); + ensureSpace(shaper_item.num_glyphs); + shaper_item.num_glyphs = num_glyphs - used; +// tqDebug(" .. num_glyphs=%d, used=%d, item.num_glyphs=%d", num_glyphs, used, shaper_item.num_glyphs); + shaper_item.glyphs = glyphs(&si); + shaper_item.advances = advances(&si); + shaper_item.offsets = offsets(&si); + shaper_item.attributes = glyphAttributes(&si); + shaper_item.log_clusters = logClusters(&si); + if (scriptEngines[shaper_item.script].shape(&shaper_item)) + break; + } + + si.num_glyphs = shaper_item.num_glyphs; + si.hasPositioning = shaper_item.has_positioning; + } + ((TQTextEngine *)this)->used += si.num_glyphs; + + si.width = 0; + advance_t *advances = this->advances( &si ); + advance_t *end = advances + si.num_glyphs; + while ( advances < end ) { +// tqDebug("advances[%d] = %d", advances - this->advances(&si), *advances); + si.width += *(advances++); + } + + return; +} + diff --git a/src/kernel/tqtextlayout.cpp b/src/kernel/tqtextlayout.cpp new file mode 100644 index 000000000..41be6076a --- /dev/null +++ b/src/kernel/tqtextlayout.cpp @@ -0,0 +1,643 @@ +/**************************************************************************** +** +** ??? +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the kernel module of the TQt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.TQPL +** included in the packaging of this file. Licensees holding valid TQt +** Commercial licenses may use this file in accordance with the TQt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "tqtextlayout_p.h" +#include "tqtextengine_p.h" + +#include +#include +#include + + +TQRect TQTextItem::rect() const +{ + TQScriptItem& si = engine->items[item]; + return TQRect( si.x, si.y, si.width, si.ascent+si.descent ); +} + +int TQTextItem::x() const +{ + return engine->items[item].x; +} + +int TQTextItem::y() const +{ + return engine->items[item].y; +} + +int TQTextItem::width() const +{ + return engine->items[item].width; +} + +int TQTextItem::ascent() const +{ + return engine->items[item].ascent; +} + +int TQTextItem::descent() const +{ + return engine->items[item].descent; +} + +void TQTextItem::setWidth( int w ) +{ + engine->items[item].width = w; +} + +void TQTextItem::setAscent( int a ) +{ + engine->items[item].ascent = a; +} + +void TQTextItem::setDescent( int d ) +{ + engine->items[item].descent = d; +} + +int TQTextItem::from() const +{ + return engine->items[item].position; +} + +int TQTextItem::length() const +{ + return engine->length(item); +} + + +int TQTextItem::cursorToX( int *cPos, Edge edge ) const +{ + int pos = *cPos; + TQScriptItem *si = &engine->items[item]; + + engine->shape( item ); + advance_t *advances = engine->advances( si ); + GlyphAttributes *glyphAttributes = engine->glyphAttributes( si ); + unsigned short *logClusters = engine->logClusters( si ); + + int l = engine->length( item ); + if ( pos > l ) + pos = l; + if ( pos < 0 ) + pos = 0; + + int glyph_pos = pos == l ? si->num_glyphs : logClusters[pos]; + if ( edge == Trailing ) { + // trailing edge is leading edge of next cluster + while ( glyph_pos < si->num_glyphs && !glyphAttributes[glyph_pos].clusterStart ) + glyph_pos++; + } + + int x = 0; + bool reverse = engine->items[item].analysis.bidiLevel % 2; + + if ( reverse ) { + for ( int i = si->num_glyphs-1; i >= glyph_pos; i-- ) + x += advances[i]; + } else { + for ( int i = 0; i < glyph_pos; i++ ) + x += advances[i]; + } +// tqDebug("cursorToX: pos=%d, gpos=%d x=%d", pos, glyph_pos, x ); + *cPos = pos; + return x; +} + +int TQTextItem::xToCursor( int x, CursorPosition cpos ) const +{ + TQScriptItem *si = &engine->items[item]; + engine->shape( item ); + advance_t *advances = engine->advances( si ); + unsigned short *logClusters = engine->logClusters( si ); + + int l = engine->length( item ); + bool reverse = si->analysis.bidiLevel % 2; + if ( x < 0 ) + return reverse ? l : 0; + + + if ( reverse ) { + int width = 0; + for ( int i = 0; i < si->num_glyphs; i++ ) { + width += advances[i]; + } + x = -x + width; + } + int cp_before = 0; + int cp_after = 0; + int x_before = 0; + int x_after = 0; + + int lastCluster = 0; + for ( int i = 1; i <= l; i++ ) { + int newCluster = i < l ? logClusters[i] : si->num_glyphs; + if ( newCluster != lastCluster ) { + // calculate cluster width + cp_before = cp_after; + x_before = x_after; + cp_after = i; + for ( int j = lastCluster; j < newCluster; j++ ) + x_after += advances[j]; + // tqDebug("cluster boundary: lastCluster=%d, newCluster=%d, x_before=%d, x_after=%d", + // lastCluster, newCluster, x_before, x_after ); + if ( x_after > x ) + break; + lastCluster = newCluster; + } + } + + bool before = ( cpos == OnCharacters || (x - x_before) < (x_after - x) ); + +// tqDebug("got cursor position for %d: %d/%d, x_ba=%d/%d using %d", +// x, cp_before,cp_after, x_before, x_after, before ? cp_before : cp_after ); + + return before ? cp_before : cp_after; + +} + + +bool TQTextItem::isRightToLeft() const +{ + return (engine->items[item].analysis.bidiLevel % 2); +} + +bool TQTextItem::isObject() const +{ + return engine->items[item].isObject; +} + +bool TQTextItem::isSpace() const +{ + return engine->items[item].isSpace; +} + +bool TQTextItem::isTab() const +{ + return engine->items[item].isTab; +} + + +TQTextLayout::TQTextLayout() + :d(0) {} + +TQTextLayout::TQTextLayout( const TQString& string, TQPainter *p ) +{ + TQFontPrivate *f = p ? ( p->pfont ? p->pfont->d : p->cfont.d ) : TQApplication::font().d; + d = new TQTextEngine( (string.isNull() ? (const TQString&)TQString::fromLatin1("") : string), f ); +} + +TQTextLayout::TQTextLayout( const TQString& string, const TQFont& fnt ) +{ + d = new TQTextEngine( (string.isNull() ? (const TQString&)TQString::fromLatin1("") : string), fnt.d ); +} + +TQTextLayout::~TQTextLayout() +{ + delete d; +} + +void TQTextLayout::setText( const TQString& string, const TQFont& fnt ) +{ + delete d; + d = new TQTextEngine( (string.isNull() ? (const TQString&)TQString::fromLatin1("") : string), fnt.d ); +} + +/* add an additional item boundary eg. for style change */ +void TQTextLayout::setBoundary( int strPos ) +{ + if ( strPos <= 0 || strPos >= (int)d->string.length() ) + return; + + int itemToSplit = 0; + while ( itemToSplit < d->items.size() && d->items[itemToSplit].position <= strPos ) + itemToSplit++; + itemToSplit--; + if ( d->items[itemToSplit].position == strPos ) { + // already a split at the requested position + return; + } + d->splitItem( itemToSplit, strPos - d->items[itemToSplit].position ); +} + + +int TQTextLayout::numItems() const +{ + return d->items.size(); +} + +TQTextItem TQTextLayout::itemAt( int i ) const +{ + return TQTextItem( i, d ); +} + + +TQTextItem TQTextLayout::findItem( int strPos ) const +{ + if ( strPos == 0 && d->items.size() ) + return TQTextItem( 0, d ); + // ## TODO use bsearch + for ( int i = d->items.size()-1; i >= 0; --i ) { + if ( d->items[i].position < strPos ) + return TQTextItem( i, d ); + } + return TQTextItem(); +} + + +void TQTextLayout::beginLayout( TQTextLayout::LayoutMode m ) +{ + d->items.clear(); + TQTextEngine::Mode mode = TQTextEngine::Full; + if (m == NoBidi) + mode = TQTextEngine::NoBidi; + else if (m == SingleLine) + mode = TQTextEngine::SingleLine; + d->itemize( mode ); + d->currentItem = 0; + d->firstItemInLine = -1; +} + +void TQTextLayout::beginLine( int width ) +{ + d->lineWidth = width; + d->widthUsed = 0; + d->firstItemInLine = -1; +} + +bool TQTextLayout::atEnd() const +{ + return d->currentItem >= d->items.size(); +} + +TQTextItem TQTextLayout::nextItem() +{ + d->currentItem++; + + if ( d->currentItem >= d->items.size() ) + return TQTextItem(); + + d->shape( d->currentItem ); + return TQTextItem( d->currentItem, d ); +} + +TQTextItem TQTextLayout::currentItem() +{ + if ( d->currentItem >= d->items.size() ) + return TQTextItem(); + + d->shape( d->currentItem ); + return TQTextItem( d->currentItem, d ); +} + +/* ## maybe also currentItem() */ +void TQTextLayout::setLineWidth( int newWidth ) +{ + d->lineWidth = newWidth; +} + +int TQTextLayout::lineWidth() const +{ + return d->lineWidth; +} + +int TQTextLayout::widthUsed() const +{ + return d->widthUsed; +} + +int TQTextLayout::availableWidth() const +{ + return d->lineWidth - d->widthUsed; +} + + +/* returns true if completely added */ +TQTextLayout::Result TQTextLayout::addCurrentItem() +{ + if ( d->firstItemInLine == -1 ) + d->firstItemInLine = d->currentItem; + TQScriptItem ¤t = d->items[d->currentItem]; + d->shape( d->currentItem ); + d->widthUsed += current.width; +// tqDebug("trying to add item %d with width %d, remaining %d", d->currentItem, current.width, d->lineWidth-d->widthUsed ); + + d->currentItem++; + + return (d->widthUsed <= d->lineWidth + || (d->currentItem < d->items.size() && d->items[d->currentItem].isSpace)) ? Ok : LineFull; +} + +TQTextLayout::Result TQTextLayout::endLine( int x, int y, int alignment, + int *ascent, int *descent, int *lineLeft, int *lineRight ) +{ + int available = d->lineWidth; + int numRuns = 0; + int numSpaceItems = 0; + TQ_UINT8 _levels[128]; + int _visual[128]; + TQ_UINT8 *levels = _levels; + int *visual = _visual; + int i; + TQTextLayout::Result result = LineEmpty; + +// tqDebug("endLine x=%d, y=%d, first=%d, current=%d lw=%d wu=%d", x, y, d->firstItemInLine, d->currentItem, d->lineWidth, d->widthUsed ); + int width_nobreak_found = d->widthUsed; + if ( d->firstItemInLine == -1 ) + goto end; + + if ( !(alignment & (TQt::SingleLine|TQt::IncludeTrailingSpaces)) + && d->currentItem > d->firstItemInLine && d->items[d->currentItem-1].isSpace ) { + int i = d->currentItem-1; + while ( i > d->firstItemInLine && d->items[i].isSpace ) { + numSpaceItems++; + d->widthUsed -= d->items[i--].width; + } + } + + if ( (alignment & (TQt::WordBreak|TQt::BreakAnywhere)) && + d->widthUsed > d->lineWidth ) { + // find linebreak + + // even though we removed trailing spaces the line was too wide. We'll have to break at an earlier + // position. To not confuse the layouting below, reset the number of space items + numSpaceItems = 0; + + + bool breakany = alignment & TQt::BreakAnywhere; + + const TQCharAttributes *attrs = d->attributes(); + int w = 0; + int itemWidth = 0; + int breakItem = d->firstItemInLine; + int breakPosition = -1; +#if 0 + // we iterate backwards or forward depending on what we guess is closer + if ( d->widthUsed - d->lineWidth < d->lineWidth ) { + // backwards search should be faster + + } else +#endif + { + int tmpWidth = 0; + int swidth = 0; + // forward search is probably faster + for ( int i = d->firstItemInLine; i < d->currentItem; i++ ) { + const TQScriptItem *si = &d->items[i]; + int length = d->length( i ); + const TQCharAttributes *itemAttrs = attrs + si->position; + + advance_t *advances = d->advances( si ); + unsigned short *logClusters = d->logClusters( si ); + + int lastGlyph = 0; + int tmpItemWidth = 0; + +// tqDebug("looking for break in item %d, isSpace=%d", i, si->isSpace ); + if(si->isSpace && !(alignment & (TQt::SingleLine|TQt::IncludeTrailingSpaces))) { + swidth += si->width; + } else { + tmpWidth += swidth; + swidth = 0; + for ( int pos = 0; pos < length; pos++ ) { +// tqDebug("advance=%d, w=%d, tmpWidth=%d, softbreak=%d, whitespace=%d", +// *advances, w, tmpWidth, itemAttrs->softBreak, itemAttrs->whiteSpace ); + int glyph = logClusters[pos]; + if ( lastGlyph != glyph ) { + while ( lastGlyph < glyph ) + tmpItemWidth += advances[lastGlyph++]; + if ( breakPosition != -1 && w + tmpWidth + tmpItemWidth > d->lineWidth ) { +// tqDebug("found break at w=%d, tmpWidth=%d, tmpItemWidth=%d", w, tmpWidth, tmpItemWidth); + d->widthUsed = w; + goto found; + } + } + if ( (itemAttrs->softBreak || + ( breakany && itemAttrs->charStop ) ) && + (i != d->firstItemInLine || pos != 0) ) { + if ( breakItem != i ) + itemWidth = 0; + if (itemAttrs->softBreak) + breakany = FALSE; + breakItem = i; + breakPosition = pos; +// tqDebug("found possible break at item %d, position %d (absolute=%d), w=%d, tmpWidth=%d, tmpItemWidth=%d", breakItem, breakPosition, d->items[breakItem].position+breakPosition, w, tmpWidth, tmpItemWidth); + w += tmpWidth + tmpItemWidth; + itemWidth += tmpItemWidth; + tmpWidth = 0; + tmpItemWidth = 0; + } + itemAttrs++; + } + while ( lastGlyph < si->num_glyphs ) + tmpItemWidth += advances[lastGlyph++]; + tmpWidth += tmpItemWidth; + if ( w + tmpWidth > d->lineWidth ) { + d->widthUsed = w; + goto found; + } + } + } + } + + found: + // no valid break point found + if ( breakPosition == -1 ) { + d->widthUsed = width_nobreak_found; + goto nobreak; + } + +// tqDebug("linebreak at item %d, position %d, wu=%d", breakItem, breakPosition, d->widthUsed ); + // split the line + if ( breakPosition > 0 ) { +// int length = d->length( breakItem ); + +// tqDebug("splitting item, itemWidth=%d", itemWidth); + // not a full item, need to break + d->splitItem( breakItem, breakPosition ); + d->currentItem = breakItem+1; + } else { + d->currentItem = breakItem; + } + } + + result = Ok; + + nobreak: + // position the objects in the line + available -= d->widthUsed; + + numRuns = d->currentItem - d->firstItemInLine - numSpaceItems; + if ( numRuns > 127 ) { + levels = new TQ_UINT8[numRuns]; + visual = new int[numRuns]; + } + +// tqDebug("reordering %d runs, numSpaceItems=%d", numRuns, numSpaceItems ); + for ( i = 0; i < numRuns; i++ ) { + levels[i] = d->items[i+d->firstItemInLine].analysis.bidiLevel; +// tqDebug(" level = %d", d->items[i+d->firstItemInLine].analysis.bidiLevel ); + } + d->bidiReorder( numRuns, levels, visual ); + + end: + // ### FIXME + if ( alignment & TQt::AlignJustify ) { + // #### justify items + alignment = TQt::AlignAuto; + } + if ( (alignment & TQt::AlignHorizontal_Mask) == TQt::AlignAuto ) + alignment = TQt::AlignLeft; + if ( alignment & TQt::AlignRight ) + x += available; + else if ( alignment & TQt::AlignHCenter ) + x += available/2; + + + int asc = ascent ? *ascent : 0; + int desc = descent ? *descent : 0; + + for ( i = 0; i < numRuns; i++ ) { + TQScriptItem &si = d->items[d->firstItemInLine+visual[i]]; + asc = TQMAX( asc, si.ascent ); + desc = TQMAX( desc, si.descent ); + } + + int left = x; + for ( i = 0; i < numRuns; i++ ) { + TQScriptItem &si = d->items[d->firstItemInLine+visual[i]]; +// tqDebug("positioning item %d with width %d (from=%d/length=%d) at %d", d->firstItemInLine+visual[i], si.width, si.position, +// d->length(d->firstItemInLine+visual[i]), x ); + si.x = x; + si.y = y + asc; + x += si.width; + } + int right = x; + + if ( numSpaceItems ) { + if ( d->items[d->firstItemInLine+numRuns].analysis.bidiLevel % 2 ) { + x = left; + for ( i = 0; i < numSpaceItems; i++ ) { + TQScriptItem &si = d->items[d->firstItemInLine + numRuns + i]; + x -= si.width; + si.x = x; + si.y = y + asc; + } + } else { + for ( i = 0; i < numSpaceItems; i++ ) { + TQScriptItem &si = d->items[d->firstItemInLine + numRuns + i]; + si.x = x; + si.y = y + asc; + x += si.width; + } + } + } + + if ( lineLeft ) + *lineLeft = left; + if ( lineRight ) + *lineRight = right; + if ( ascent ) + *ascent = asc; + if ( descent ) + *descent = desc; + + if (levels != _levels) + delete []levels; + if (visual != _visual) + delete []visual; + + return result; +} + +void TQTextLayout::endLayout() +{ + // nothing to do currently +} + + +int TQTextLayout::nextCursorPosition( int oldPos, CursorMode mode ) const +{ +// tqDebug("looking for next cursor pos for %d", oldPos ); + const TQCharAttributes *attributes = d->attributes(); + int len = d->string.length(); + if ( oldPos >= len ) + return oldPos; + oldPos++; + if ( mode == SkipCharacters ) { + while ( oldPos < len && !attributes[oldPos].charStop ) + oldPos++; + } else { + while ( oldPos < len && !attributes[oldPos].wordStop && !attributes[oldPos-1].whiteSpace ) + oldPos++; + } +// tqDebug(" -> %d", oldPos ); + return oldPos; +} + +int TQTextLayout::previousCursorPosition( int oldPos, CursorMode mode ) const +{ +// tqDebug("looking for previous cursor pos for %d", oldPos ); + const TQCharAttributes *attributes = d->attributes(); + if ( oldPos <= 0 ) + return 0; + oldPos--; + if ( mode == SkipCharacters ) { + while ( oldPos && !attributes[oldPos].charStop ) + oldPos--; + } else { + while ( oldPos && !attributes[oldPos].wordStop && !attributes[oldPos-1].whiteSpace ) + oldPos--; + } +// tqDebug(" -> %d", oldPos ); + return oldPos; +} + + +bool TQTextLayout::validCursorPosition( int pos ) const +{ + const TQCharAttributes *attributes = d->attributes(); + if ( pos < 0 || pos > (int)d->string.length() ) + return FALSE; + return attributes[pos].charStop; +} + +void TQTextLayout::setDirection(TQChar::Direction dir) +{ + d->direction = dir; +} diff --git a/src/kernel/tqtextlayout_p.h b/src/kernel/tqtextlayout_p.h new file mode 100644 index 000000000..64c7f64db --- /dev/null +++ b/src/kernel/tqtextlayout_p.h @@ -0,0 +1,184 @@ +/**************************************************************************** +** +** ??? +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the kernel module of the TQt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** Licensees holding valid TQt Commercial licenses may use this file in +** accordance with the TQt Commercial License Agreement provided with +** the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef TQTEXTLAYOUT_P_H +#define TQTEXTLAYOUT_P_H + +#ifndef QT_H +#include "tqstring.h" +#include "ntqnamespace.h" +#include "ntqrect.h" +#endif // QT_H + +class TQTextEngine; +class TQFont; + +class TQ_EXPORT TQTextItem +{ +public: + inline TQTextItem() : item(0), engine(0) {} + inline bool isValid() const { return (bool)engine; } + + TQRect rect() const; + int x() const; + int y() const; + int width() const; + int ascent() const; + int descent() const; + + enum Edge { + Leading, + Trailing + }; + enum CursorPosition { + BetweenCharacters, + OnCharacters + }; + + /* cPos gets set to the valid position */ + int cursorToX( int *cPos, Edge edge = Leading ) const; + inline int cursorToX( int cPos, Edge edge = Leading ) const { return cursorToX( &cPos, edge ); } + int xToCursor( int x, CursorPosition = BetweenCharacters ) const; + + bool isRightToLeft() const; + bool isObject() const; + bool isSpace() const; + bool isTab() const; + + void setWidth( int w ); + void setAscent( int a ); + void setDescent( int d ); + + int from() const; + int length() const; + +private: + friend class TQTextLayout; + friend class TQPainter; + friend class TQPSPrinter; + TQTextItem( int i, TQTextEngine *e ) : item( i ), engine( e ) {} + int item; + TQTextEngine *engine; +}; + + +class TQPainter; + +class TQ_EXPORT TQTextLayout +{ +public: + // does itemization + TQTextLayout(); + TQTextLayout( const TQString& string, TQPainter * = 0 ); + TQTextLayout( const TQString& string, const TQFont& fnt ); + ~TQTextLayout(); + + void setText( const TQString& string, const TQFont& fnt ); + + enum LineBreakStrategy { + AtWordBoundaries, + AtCharBoundaries + }; + + /* add an additional item boundary eg. for style change */ + void setBoundary( int strPos ); + + int numItems() const; + TQTextItem itemAt( int i ) const; + TQTextItem findItem( int strPos ) const; + + enum LayoutMode { + NoBidi, + SingleLine, + MultiLine + }; + void beginLayout( LayoutMode m = MultiLine ); + void beginLine( int width ); + + bool atEnd() const; + TQTextItem nextItem(); + TQTextItem currentItem(); + /* ## maybe also currentItem() */ + void setLineWidth( int newWidth ); + int lineWidth() const; + int widthUsed() const; + int availableWidth() const; + + enum Result { + Ok, + LineFull, + LineEmpty, + Error + }; + /* returns true if completely added */ + Result addCurrentItem(); + + /* Note: if ascent and descent are used they must be initialized to the minimum ascent/descent + acceptable for the line. TQFontMetrics::ascent/descent() is usually the right choice */ + Result endLine( int x = 0, int y = 0, int alignment = TQt::AlignLeft, + int *ascent = 0, int *descent = 0, int *left = 0, int *right = 0 ); + void endLayout(); + + enum CursorMode { + SkipCharacters, + SkipWords + }; + bool validCursorPosition( int pos ) const; + int nextCursorPosition( int oldPos, CursorMode mode = SkipCharacters ) const; + int previousCursorPosition( int oldPos, CursorMode mode = SkipCharacters ) const; + + void setDirection(TQChar::Direction); +private: + TQTextLayout( TQTextEngine *e ) : d( e ) {} + /* disable copy and assignment */ + TQTextLayout( const TQTextLayout & ) {} + void operator = ( const TQTextLayout & ) {} + + friend class TQTextItem; + friend class TQPainter; + friend class TQPSPrinter; + TQTextEngine *d; +}; + + +/* + class TQPainter { + ..... + void drawTextItem( int x, int y, TQTextItem *item ); + }; +*/ + +#endif diff --git a/src/kernel/tqwidget_x11.cpp b/src/kernel/tqwidget_x11.cpp index ff33dddbf..78d1e850e 100644 --- a/src/kernel/tqwidget_x11.cpp +++ b/src/kernel/tqwidget_x11.cpp @@ -47,7 +47,7 @@ #include "tqimage.h" #include "tqobjectlist.h" #include "ntqlayout.h" -#include "ntqtextcodec.h" +#include "tqtextcodec.h" #include "ntqdatetime.h" #include "ntqcursor.h" #include "qt_x11_p.h" @@ -3055,7 +3055,7 @@ void TQWidget::destroyInputContext() /*! This function is called when text widgets need to be neutral state to - execute text operations properly. See qlineedit.cpp and qtextedit.cpp as + execute text operations properly. See qlineedit.cpp and tqtextedit.cpp as example. Ordinary reset that along with changing focus to another widget, -- cgit v1.2.3