summaryrefslogtreecommitdiffstats
path: root/tqtinterface/qt4/src/kernel/tqfontengine_x11.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tqtinterface/qt4/src/kernel/tqfontengine_x11.cpp')
-rw-r--r--tqtinterface/qt4/src/kernel/tqfontengine_x11.cpp2752
1 files changed, 2752 insertions, 0 deletions
diff --git a/tqtinterface/qt4/src/kernel/tqfontengine_x11.cpp b/tqtinterface/qt4/src/kernel/tqfontengine_x11.cpp
new file mode 100644
index 0000000..0b45ec9
--- /dev/null
+++ b/tqtinterface/qt4/src/kernel/tqfontengine_x11.cpp
@@ -0,0 +1,2752 @@
+/****************************************************************************
+**
+** ???
+**
+** Copyright (C) 2003-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 "tqtglobaldefines.h"
+
+#ifdef USE_QT4
+
+#include <Qt/qdatastream.h>
+
+#endif // USE_QT4
+
+#ifdef USE_QT4
+#else // USE_QT4
+#include "tqfontengine_p.h"
+#endif // USE_QT4
+
+// #define FONTENGINE_DEBUG
+
+#include <tqwidget.h>
+#include <tqcstring.h>
+#include <tqtextcodec.h>
+
+#include "tqbitmap.h"
+#include "tqfontdatabase.h"
+#include "tqpaintdevice.h"
+#include "tqpaintdevicemetrics.h"
+#include "tqpainter.h"
+#include "tqimage.h"
+
+#include "tqt_x11_p.h"
+
+#include "tqfont.h"
+#include "tqtextengine_p.h"
+
+#include <private/tqunicodetables_p.h>
+
+#ifdef USE_QT4
+#include "tqfontengine_p.h"
+#endif // USE_QT4
+
+#include <limits.h>
+
+#ifdef USE_QT4
+
+#else // USE_QT4
+
+// defined in qfontdatbase_x11.cpp
+extern int qt_mib_for_xlfd_encoding( const char *encoding );
+extern int qt_xlfd_encoding_id( const char *encoding );
+
+extern void qt_draw_transformed_rect( TQPainter *p, int x, int y, int w, int h, bool fill );
+
+static void drawLines( TQPainter *p, TQFontEngine *fe, int baseline, int x1, int w, int textFlags )
+{
+ int lw = fe->lineThickness();
+ if ( textFlags & TQt::Underline ) {
+ int pos = fe->underlinePosition();
+ qt_draw_transformed_rect( p, x1, baseline+pos, w, lw, TRUE );
+ }
+ if ( textFlags & TQt::Overline ) {
+ int pos = fe->ascent()+1;
+ if ( !pos ) pos = 1;
+ qt_draw_transformed_rect( p, x1, baseline-pos, w, lw, TRUE );
+ }
+ if ( textFlags & TQt::StrikeOut ) {
+ int pos = fe->ascent()/3;
+ if ( !pos ) pos = 1;
+ qt_draw_transformed_rect( p, x1, baseline-pos, w, lw, TRUE );
+ }
+}
+
+
+inline static void qSafeXDestroyImage( XImage *x )
+{
+ if ( x->data ) {
+ free( x->data );
+ x->data = 0;
+ }
+ XDestroyImage( x );
+}
+
+extern bool qt_xForm_helper( const TQWMatrix &trueMat, int xoffset,
+ int type, int depth,
+ uchar *dptr, int dbpl, int p_inc, int dHeight,
+ uchar *sptr, int sbpl, int sWidth, int sHeight
+ );
+
+static TQBitmap transform(Display *dpy, const TQBitmap &source, int xoff, int yoff, int w, int h, const TQWMatrix &matrix)
+{
+ int ws = source.width();
+ int hs = source.height();
+
+ bool invertible;
+ TQWMatrix mat = matrix.invert( &invertible ); // invert matrix
+
+ if (!invertible )
+ return TQBitmap();
+ mat.translate(xoff, yoff);
+
+ XImage *xi = XGetImage(dpy, source.handle(), 0, 0, ws, hs, AllPlanes, XYPixmap);
+
+ if ( !xi )
+ return TQBitmap();
+
+ int sbpl = xi->bytes_per_line;
+ uchar *sptr = (uchar *)xi->data;
+
+ int dbpl = (w+7)/8;
+ int dbytes = dbpl*h;
+
+ uchar *dptr = (uchar *)malloc( dbytes ); // create buffer for bits
+ memset( dptr, 0, dbytes );
+
+ int type = xi->bitmap_bit_order == MSBFirst ? TQT_XFORM_TYPE_MSBFIRST : TQT_XFORM_TYPE_LSBFIRST;
+ int xbpl, p_inc;
+ xbpl = (w+7)/8;
+ p_inc = dbpl - xbpl;
+
+ bool ok = qt_xForm_helper( mat, xi->xoffset, type, 1, dptr, xbpl, p_inc, h, sptr, sbpl, ws, hs );
+ qSafeXDestroyImage(xi);
+ TQBitmap bm;
+ if (ok) {
+ bm = TQBitmap( w, h, dptr, TQImage::systemBitOrder() != TQImage::BigEndian );
+ } else {
+#if defined(TQT_CHECK_RANGE)
+ qWarning( "TQFontEngineXft::tranform: xform failed");
+#endif
+ }
+
+ free( dptr );
+ return bm;
+}
+
+
+static void drawScaled(int x, int y, const TQTextEngine *engine, const TQScriptItem *si, int textFlags,
+ Display *dpy, GC gc, TQPaintDevice *pdev, TQFontEngine *fe,
+ const TQWMatrix &xmat, float scale)
+{
+ // font doesn't support transformations, need to do it by hand
+ int w = tqRound(si->width/scale);
+ int h = tqRound((si->ascent + si->descent + 1)/scale);
+ if (w == 0 || h == 0)
+ return;
+ TQWMatrix mat1 = xmat;
+ mat1.scale(scale, scale);
+
+ w += h; // add some pixels to width because of italic correction
+ TQBitmap bm( w, h, TRUE ); // create bitmap
+ TQPainter paint;
+ paint.begin( &bm ); // draw text in bitmap
+ fe->draw( &paint, 0, si->ascent/scale, engine, si, textFlags );
+ paint.end();
+
+ TQRect pdevRect;
+ if (pdev->devType() == TQInternal::Widget)
+ pdevRect = ((TQWidget *)pdev)->rect();
+ else if (pdev->devType() == TQInternal::Pixmap)
+ pdevRect = ((TQPixmap *)pdev)->rect();
+ else
+ return;
+
+
+ TQRect br = mat1.mapRect(TQRect(x, y - si->ascent, w, h));
+ TQRect br2 = br & pdevRect;
+ if (br2.width() <= 0 || br2.height() <= 0
+ || br2.width() >= 32768 || br2.height() >= 32768)
+ return;
+ TQWMatrix mat = TQT_TQWMATRIX_OBJECT(TQPixmap::trueMatrix( mat1, w, h ));
+ TQBitmap wx_bm = ::transform(dpy, bm, br2.x() - br.x(), br2.y() - br.y(), br2.width(), br2.height(), mat);
+ if ( wx_bm.isNull() )
+ return;
+
+ x = br2.x();
+ y = br2.y();
+
+ TQt::HANDLE hd = pdev->handle();
+ XSetFillStyle( dpy, gc, FillStippled );
+ XSetStipple( dpy, gc, wx_bm.handle() );
+ XSetTSOrigin( dpy, gc, x, y );
+ XFillRectangle( dpy, hd, gc, x, y, wx_bm.width(), wx_bm.height() );
+ XSetTSOrigin( dpy, gc, 0, 0 );
+ XSetFillStyle( dpy, gc, FillSolid );
+}
+
+
+TQFontEngine::~TQFontEngine()
+{
+}
+
+int TQFontEngine::lineThickness() const
+{
+ // ad hoc algorithm
+ int score = fontDef.weight * fontDef.pixelSize;
+ int lw = score / 700;
+
+ // looks better with thicker line for small pointsizes
+ if ( lw < 2 && score >= 1050 ) lw = 2;
+ if ( lw == 0 ) lw = 1;
+
+ return lw;
+}
+
+int TQFontEngine::underlinePosition() const
+{
+ int pos = ( ( lineThickness() * 2 ) + 3 ) / 6;
+ return pos ? pos : 1;
+}
+
+// ------------------------------------------------------------------
+// The box font engine
+// ------------------------------------------------------------------
+
+
+TQFontEngineBox::TQFontEngineBox( int size )
+ : _size( size )
+{
+ cache_cost = sizeof( TQFontEngineBox );
+}
+
+TQFontEngineBox::~TQFontEngineBox()
+{
+}
+
+TQFontEngine::Error TQFontEngineBox::stringToCMap( const TQChar *, int len, glyph_t *glyphs, advance_t *advances, int *nglyphs, bool ) const
+{
+ if ( *nglyphs < len ) {
+ *nglyphs = len;
+ return OutOfMemory;
+ }
+
+ memset( glyphs, 0, len * sizeof( glyph_t ) );
+ *nglyphs = len;
+
+ if ( advances ) {
+ for ( int i = 0; i < len; i++ )
+ *(advances++) = _size;
+ }
+ return NoError;
+}
+
+void TQFontEngineBox::draw( TQPainter *p, int x, int y, const TQTextEngine *engine, const TQScriptItem *si, int textFlags )
+{
+ Display *dpy = TQPaintDevice::x11AppDisplay();
+ TQt::HANDLE hd = p->tqdevice()->handle();
+ GC gc = p->gc;
+
+#ifdef FONTENGINE_DEBUG
+ p->save();
+ p->setBrush( TQt::white );
+ glyph_metrics_t ci = boundingBox( glyphs, offsets, numGlyphs );
+ p->drawRect( x + ci.x, y + ci.y, ci.width, ci.height );
+ p->drawRect( x + ci.x, y + 50 + ci.y, ci.width, ci.height );
+ qDebug("bounding rect=%d %d (%d/%d)", ci.x, ci.y, ci.width, ci.height );
+ p->restore();
+ int xp = x;
+ int yp = y;
+#endif
+
+ GlyphAttributes *glyphAttributes = engine->glyphAttributes( si );
+
+ if ( p->txop > TQPainter::TxTranslate ) {
+ int xp = x;
+ int yp = _size + 2;
+ int s = _size - 3;
+ for (int k = 0; k < si->num_glyphs; k++) {
+ if (!glyphAttributes[k].zeroWidth)
+ qt_draw_transformed_rect( p, xp, yp, s, s, FALSE );
+ xp += _size;
+ }
+ } else {
+ if ( p->txop == TQPainter::TxTranslate )
+ p->map( x, y, &x, &y );
+
+ XRectangle rects[64];
+
+ int gl = 0;
+ while (gl < si->num_glyphs) {
+ int toDraw = TQMIN(64, si->num_glyphs-gl);
+ int adv = toDraw*_size;
+ if (x + adv < SHRT_MAX && x > SHRT_MIN) {
+ int ng = 0;
+ for (int k = 0; k < toDraw; k++) {
+ if (!glyphAttributes[gl + k].zeroWidth) {
+ rects[ng].x = x + (k * _size);
+ rects[ng].y = y - _size + 2;
+ rects[ng].width = rects[k].height = _size - 3;
+ ++ng;
+ }
+ }
+ XDrawRectangles(dpy, hd, gc, rects, ng);
+ }
+ gl += toDraw;
+ x += adv;
+ }
+ }
+
+ if ( textFlags != 0 )
+ drawLines( p, this, y, x, si->num_glyphs*_size, textFlags );
+
+#ifdef FONTENGINE_DEBUG
+ x = xp;
+ y = yp;
+ p->save();
+ p->setPen( TQt::red );
+ for ( int i = 0; i < numGlyphs; i++ ) {
+ glyph_metrics_t ci = boundingBox( glyphs[i] );
+ x += offsets[i].x;
+ y += offsets[i].y;
+ p->drawRect( x + ci.x, y + 50 + ci.y, ci.width, ci.height );
+ qDebug("bounding ci[%d]=%d %d (%d/%d) / %d %d offset=(%d/%d)", i, ci.x, ci.y, ci.width, ci.height,
+ ci.xoff, ci.yoff, offsets[i].x, offsets[i].y );
+ x += ci.xoff;
+ y += ci.yoff;
+ }
+ p->restore();
+#endif
+}
+
+glyph_metrics_t TQFontEngineBox::boundingBox( const glyph_t *, const advance_t *, const qoffset_t *, int numGlyphs )
+{
+ glyph_metrics_t overall;
+ overall.x = overall.y = 0;
+ overall.width = _size*numGlyphs;
+ overall.height = _size;
+ overall.xoff = overall.width;
+ overall.yoff = 0;
+ return overall;
+}
+
+glyph_metrics_t TQFontEngineBox::boundingBox( glyph_t )
+{
+ return glyph_metrics_t( 0, _size, _size, _size, _size, 0 );
+}
+
+
+
+int TQFontEngineBox::ascent() const
+{
+ return _size;
+}
+
+int TQFontEngineBox::descent() const
+{
+ return 0;
+}
+
+int TQFontEngineBox::leading() const
+{
+ int l = tqRound( _size * 0.15 );
+ return (l > 0) ? l : 1;
+}
+
+int TQFontEngineBox::maxCharWidth() const
+{
+ return _size;
+}
+
+int TQFontEngineBox::cmap() const
+{
+ return -1;
+}
+
+const char *TQFontEngineBox::name() const
+{
+ return "null";
+}
+
+bool TQFontEngineBox::canRender( const TQChar *, int )
+{
+ return TRUE;
+}
+
+TQFontEngine::Type TQFontEngineBox::type() const
+{
+ return Box;
+}
+
+
+
+
+// ------------------------------------------------------------------
+// Xlfd cont engine
+// ------------------------------------------------------------------
+
+static inline XCharStruct *charStruct( XFontStruct *xfs, uint ch )
+{
+ XCharStruct *xcs = 0;
+ unsigned char r = ch>>8;
+ unsigned char c = ch&0xff;
+ if ( r >= xfs->min_byte1 &&
+ r <= xfs->max_byte1 &&
+ c >= xfs->min_char_or_byte2 &&
+ c <= xfs->max_char_or_byte2) {
+ if ( !xfs->per_char )
+ xcs = &(xfs->min_bounds);
+ else {
+ xcs = xfs->per_char + ((r - xfs->min_byte1) *
+ (xfs->max_char_or_byte2 -
+ xfs->min_char_or_byte2 + 1)) +
+ (c - xfs->min_char_or_byte2);
+ if (xcs->width == 0 && xcs->ascent == 0 && xcs->descent == 0)
+ xcs = 0;
+ }
+ }
+ return xcs;
+}
+
+TQFontEngineXLFD::TQFontEngineXLFD( XFontStruct *fs, const char *name, int mib )
+ : _fs( fs ), _name( name ), _codec( 0 ), _scale( 1. ), _cmap( mib )
+{
+ if ( _cmap ) _codec = TQTextCodec::codecForMib( _cmap );
+
+ cache_cost = (((fs->max_byte1 - fs->min_byte1) *
+ (fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1)) +
+ fs->max_char_or_byte2 - fs->min_char_or_byte2);
+ cache_cost = ((fs->max_bounds.ascent + fs->max_bounds.descent) *
+ (fs->max_bounds.width * cache_cost / 8));
+ lbearing = SHRT_MIN;
+ rbearing = SHRT_MIN;
+
+#if 1
+ // Server side transformations do not seem to work correctly for
+ // all types of fonts (for example, it works for bdf/pcf fonts,
+ // but not for ttf). It also seems to be extermely server
+ // dependent. The best thing is to just disable server side
+ // transformations until either server support matures or we
+ // figure out a better way to do it.
+ xlfd_transformations = XlfdTrUnsupported;
+#else
+ xlfd_transformations = XlfdTrUnknown;
+
+ // Hummingbird's Exceed X server will substitute 'fixed' for any
+ // known fonts, and it doesn't seem to support transformations, so
+ // we should never try to use xlfd transformations with it
+ if (strstr(ServerVendor(TQPaintDevice::x11AppDisplay()), "Hummingbird"))
+ xlfd_transformations = XlfdTrUnsupported;
+#endif
+}
+
+TQFontEngineXLFD::~TQFontEngineXLFD()
+{
+ XFreeFont( TQPaintDevice::x11AppDisplay(), _fs );
+ _fs = 0;
+ TransformedFont *trf = transformed_fonts;
+ while ( trf ) {
+ XUnloadFont( TQPaintDevice::x11AppDisplay(), trf->xlfd_font );
+ TransformedFont *tmp = trf;
+ trf = trf->next;
+ delete tmp;
+ }
+}
+
+TQFontEngine::Error TQFontEngineXLFD::stringToCMap( const TQChar *str, int len, glyph_t *glyphs, advance_t *advances, int *nglyphs, bool mirrored ) const
+{
+ if ( *nglyphs < len ) {
+ *nglyphs = len;
+ return OutOfMemory;
+ }
+
+ if ( _codec ) {
+ bool haveNbsp = FALSE;
+ for ( int i = 0; i < len; i++ )
+ if ( str[i].tqunicode() == 0xa0 ) {
+ haveNbsp = TRUE;
+ break;
+ }
+
+ TQChar *chars = (TQChar *)str;
+ if ( haveNbsp || mirrored ) {
+ chars = (TQChar *)malloc( len*sizeof(TQChar) );
+ for ( int i = 0; i < len; i++ )
+ chars[i] = (str[i].tqunicode() == 0xa0 ? 0x20 :
+ (mirrored ? ::mirroredChar(str[i]).tqunicode() : str[i].tqunicode()));
+ }
+ _codec->fromUnicodeInternal( chars, glyphs, len );
+ if (chars != str)
+ free( chars );
+ } else {
+ glyph_t *g = glyphs + len;
+ const TQChar *c = str + len;
+ if ( mirrored ) {
+ while ( c != str )
+ *(--g) = (--c)->tqunicode() == 0xa0 ? 0x20 : ::mirroredChar(*c).tqunicode();
+ } else {
+ while ( c != str )
+ *(--g) = (--c)->tqunicode() == 0xa0 ? 0x20 : c->tqunicode();
+ }
+ }
+ *nglyphs = len;
+
+ if ( advances ) {
+ glyph_t *g = glyphs + len;
+ advance_t *a = advances + len;
+ XCharStruct *xcs;
+ // inlined for better perfomance
+ if ( !_fs->per_char ) {
+ xcs = &_fs->min_bounds;
+ while ( a != advances )
+ *(--a) = xcs->width;
+ }
+ else if ( !_fs->max_byte1 ) {
+ XCharStruct *base = _fs->per_char - _fs->min_char_or_byte2;
+ while ( g-- != glyphs ) {
+ unsigned int gl = *g;
+ xcs = (gl >= _fs->min_char_or_byte2 && gl <= _fs->max_char_or_byte2) ?
+ base + gl : 0;
+ *(--a) = (!xcs || (!xcs->width && !xcs->ascent && !xcs->descent)) ? _fs->ascent : xcs->width;
+ }
+ }
+ else {
+ while ( g != glyphs ) {
+ xcs = charStruct( _fs, *(--g) );
+ *(--a) = (xcs ? xcs->width : _fs->ascent);
+ }
+ }
+ if ( _scale != 1. ) {
+ for ( int i = 0; i < len; i++ )
+ advances[i] = tqRound(advances[i]*_scale);
+ }
+ }
+ return NoError;
+}
+
+#if defined(TQ_C_CALLBACKS)
+extern "C" {
+#endif
+
+static bool x_font_load_error = FALSE;
+static int x_font_errorhandler(Display *, XErrorEvent *)
+{
+ x_font_load_error = TRUE;
+ return 0;
+}
+
+#if defined(TQ_C_CALLBACKS)
+}
+#endif
+
+
+void TQFontEngineXLFD::draw( TQPainter *p, int x, int y, const TQTextEngine *engine, const TQScriptItem *si, int textFlags )
+{
+ if ( !si->num_glyphs )
+ return;
+
+// qDebug("TQFontEngineXLFD::draw( %d, %d, numglyphs=%d", x, y, si->num_glyphs );
+
+ Display *dpy = TQPaintDevice::x11AppDisplay();
+ TQt::HANDLE hd = p->tqdevice()->handle();
+ GC gc = p->gc;
+
+ bool transform = FALSE;
+ int xorig = x;
+ int yorig = y;
+
+ TQt::HANDLE font_id = _fs->fid;
+ if ( p->txop > TQPainter::TxTranslate || _scale < 0.9999 || _scale > 1.0001 ) {
+ bool degenerate = TQABS( p->m11()*p->m22() - p->m12()*p->m21() ) < 0.01;
+ if ( !degenerate && xlfd_transformations != XlfdTrUnsupported ) {
+ // need a transformed font from the server
+ TQCString xlfd_transformed = _name;
+ int field = 0;
+ char *data = xlfd_transformed.data();
+ int pos = 0;
+ while ( field < 7 ) {
+ if ( data[pos] == '-' )
+ field++;
+ pos++;
+ }
+ int endPos = pos;
+ while ( data[endPos] != '-' )
+ endPos++;
+ float size = xlfd_transformed.mid( pos, endPos-pos ).toInt();
+ float mat[4];
+ mat[0] = p->m11()*size*_scale;
+ mat[1] = -p->m12()*size*_scale;
+ mat[2] = -p->m21()*size*_scale;
+ mat[3] = p->m22()*size*_scale;
+
+ // check if we have it cached
+ TransformedFont *trf = transformed_fonts;
+ TransformedFont *prev = 0;
+ int i = 0;
+ while ( trf ) {
+ if ( trf->xx == mat[0] &&
+ trf->xy == mat[1] &&
+ trf->yx == mat[2] &&
+ trf->yy == mat[3] )
+ break;
+ TransformedFont *tmp = trf;
+ trf = trf->next;
+ if (i > 10) {
+ XUnloadFont( TQPaintDevice::x11AppDisplay(), tmp->xlfd_font );
+ delete tmp;
+ prev->next = trf;
+ } else {
+ prev = tmp;
+ }
+ ++i;
+ }
+ if ( trf ) {
+ if ( prev ) {
+ // move to beginning of list
+ prev->next = trf->next;
+ trf->next = transformed_fonts;
+ transformed_fonts = trf;
+ }
+ font_id = trf->xlfd_font;
+ } else {
+ TQCString matrix="[";
+ for ( int i = 0; i < 4; i++ ) {
+ float f = mat[i];
+ if ( f < 0 ) {
+ matrix += '~';
+ f = -f;
+ }
+ matrix += TQString::number( f, 'f', 5 ).latin1();
+ matrix += ' ';
+ }
+ matrix += ']';
+ //qDebug("m: %2.2f %2.2f %2.2f %2.2f, matrix=%s", p->m11(), p->m12(), p->m21(), p->m22(), matrix.data());
+ xlfd_transformed.tqreplace( pos, endPos-pos, matrix );
+
+ x_font_load_error = FALSE;
+ XErrorHandler old_handler = XSetErrorHandler( x_font_errorhandler );
+ font_id = XLoadFont( dpy, xlfd_transformed.data() );
+ XSync( dpy, FALSE );
+ XSetErrorHandler( old_handler );
+ if ( x_font_load_error ) {
+ //qDebug( "couldn't load transformed font" );
+ font_id = _fs->fid;
+ xlfd_transformations = XlfdTrUnsupported;
+ } else {
+ TransformedFont *trf = new TransformedFont;
+ trf->xx = mat[0];
+ trf->xy = mat[1];
+ trf->yx = mat[2];
+ trf->yy = mat[3];
+ trf->xlfd_font = font_id;
+ trf->next = transformed_fonts;
+ transformed_fonts = trf;
+ }
+ }
+ }
+ if ( degenerate || xlfd_transformations == XlfdTrUnsupported ) {
+ // XServer or font don't support server side transformations, need to do it by hand
+ float tmp = _scale;
+ _scale = 1.;
+ drawScaled(x, y, engine, si, textFlags, dpy, p->gc, p->tqdevice(), this, p->xmat, tmp);
+ _scale = tmp;
+ return;
+ }
+ transform = TRUE;
+ } else if ( p->txop == TQPainter::TxTranslate ) {
+ p->map( x, y, &x, &y );
+ }
+
+ XSetFont(dpy, gc, font_id);
+
+#ifdef FONTENGINE_DEBUG
+ p->save();
+ p->setBrush( TQt::white );
+ glyph_metrics_t ci = boundingBox( glyphs, advances, offsets, si->num_glyphs );
+ p->drawRect( x + ci.x, y + ci.y, ci.width, ci.height );
+ p->drawRect( x + ci.x, y + 100 + ci.y, ci.width, ci.height );
+ qDebug("bounding rect=%d %d (%d/%d)", ci.x, ci.y, ci.width, ci.height );
+ p->restore();
+ int xp = x;
+ int yp = y;
+#endif
+
+ glyph_t *glyphs = engine->glyphs( si );
+ advance_t *advances = engine->advances( si );
+ qoffset_t *offsets = engine->offsets( si );
+
+ XChar2b ch[256];
+ XChar2b *chars = ch;
+ if ( si->num_glyphs > 255 )
+ chars = (XChar2b *)malloc( si->num_glyphs*sizeof(XChar2b) );
+
+ for (int i = 0; i < si->num_glyphs; i++) {
+ chars[i].byte1 = glyphs[i] >> 8;
+ chars[i].byte2 = glyphs[i] & 0xff;
+ }
+
+ int xpos = x;
+ GlyphAttributes *glyphAttributes = engine->glyphAttributes( si );
+
+ if ( si->analysis.bidiLevel % 2 ) {
+ int i = si->num_glyphs;
+ while( i-- ) {
+ advance_t adv = advances[i];
+ // qDebug("advance = %d/%d", adv.x, adv.y );
+ x += adv;
+ glyph_metrics_t gi = boundingBox( glyphs[i] );
+ int xp = x-offsets[i].x-gi.xoff;
+ int yp = y+offsets[i].y-gi.yoff;
+ if ( transform )
+ p->map( xp, yp, &xp, &yp );
+ if (!glyphAttributes[i].zeroWidth && xp < SHRT_MAX && xp > SHRT_MIN)
+ XDrawString16(dpy, hd, gc, xp, yp, chars+i, 1 );
+ }
+ } else {
+ if ( transform || si->hasPositioning ) {
+ int i = 0;
+ while( i < si->num_glyphs ) {
+ int xp = x+offsets[i].x;
+ int yp = y+offsets[i].y;
+ if ( transform )
+ p->map( xp, yp, &xp, &yp );
+ if (!glyphAttributes[i].zeroWidth && xp < SHRT_MAX && xp > SHRT_MIN)
+ XDrawString16(dpy, hd, gc, xp, yp, chars+i, 1 );
+ advance_t adv = advances[i];
+ // qDebug("advance = %d/%d", adv.x, adv.y );
+ x += adv;
+ i++;
+ }
+ } else {
+ // we can take a shortcut
+ int gl = 0;
+ while (gl < si->num_glyphs) {
+ int toDraw = TQMIN(64, si->num_glyphs-gl);
+ int adv = 0;
+ for (int i = gl; i < gl+toDraw; ++i)
+ adv += advances[i];
+ if (x + adv < SHRT_MAX && x > SHRT_MIN)
+ XDrawString16(dpy, hd, gc, x, y, chars+gl, toDraw);
+ gl += toDraw;
+ x += adv;
+ }
+ }
+ }
+
+ if ( chars != ch )
+ free( chars );
+
+ if ( textFlags != 0 )
+ drawLines( p, this, yorig, xorig, x-xpos, textFlags );
+
+#ifdef FONTENGINE_DEBUG
+ x = xp;
+ y = yp;
+ p->save();
+ p->setPen( TQt::red );
+ for ( int i = 0; i < si->num_glyphs; i++ ) {
+ glyph_metrics_t ci = boundingBox( glyphs[i] );
+ p->drawRect( x + ci.x + offsets[i].x, y + 100 + ci.y + offsets[i].y, ci.width, ci.height );
+ qDebug("bounding ci[%d]=%d %d (%d/%d) / %d %d offs=(%d/%d) advance=(%d/%d)", i, ci.x, ci.y, ci.width, ci.height,
+ ci.xoff, ci.yoff, offsets[i].x, offsets[i].y,
+ advances[i].x, advances[i].y);
+ x += advances[i].x;
+ y += advances[i].y;
+ }
+ p->restore();
+#endif
+}
+
+glyph_metrics_t TQFontEngineXLFD::boundingBox( const glyph_t *glyphs, const advance_t *advances, const qoffset_t *offsets, int numGlyphs )
+{
+ int i;
+
+ glyph_metrics_t overall;
+ int ymax = 0;
+ int xmax = 0;
+ for (i = 0; i < numGlyphs; i++) {
+ XCharStruct *xcs = charStruct( _fs, glyphs[i] );
+ if (xcs) {
+ int x = overall.xoff + offsets[i].x - xcs->lbearing;
+ int y = overall.yoff + offsets[i].y - xcs->ascent;
+ overall.x = TQMIN( overall.x, x );
+ overall.y = TQMIN( overall.y, y );
+ xmax = TQMAX( xmax, overall.xoff + offsets[i].x + xcs->rbearing );
+ ymax = TQMAX( ymax, y + xcs->ascent + xcs->descent );
+ overall.xoff += tqRound(advances[i]/_scale);
+ } else {
+ int size = _fs->ascent;
+ overall.x = TQMIN(overall.x, overall.xoff );
+ overall.y = TQMIN(overall.y, overall.yoff - size );
+ ymax = TQMAX( ymax, overall.yoff );
+ overall.xoff += size;
+ xmax = TQMAX( xmax, overall.xoff );
+ }
+ }
+ overall.height = ymax - overall.y;
+ overall.width = xmax - overall.x;
+
+ if ( _scale != 1. ) {
+ overall.x = tqRound(overall.x * _scale);
+ overall.y = tqRound(overall.y * _scale);
+ overall.height = tqRound(overall.height * _scale);
+ overall.width = tqRound(overall.width * _scale);
+ overall.xoff = tqRound(overall.xoff * _scale);
+ overall.yoff = tqRound(overall.yoff * _scale);
+ }
+ return overall;
+}
+
+glyph_metrics_t TQFontEngineXLFD::boundingBox( glyph_t glyph )
+{
+ glyph_metrics_t gm;
+ // ### scale missing!
+ XCharStruct *xcs = charStruct( _fs, glyph );
+ if (xcs) {
+ gm = glyph_metrics_t( xcs->lbearing, -xcs->ascent, xcs->rbearing- xcs->lbearing, xcs->ascent + xcs->descent, xcs->width, 0 );
+ } else {
+ int size = _fs->ascent;
+ gm = glyph_metrics_t( 0, size, size, size, size, 0 );
+ }
+ if ( _scale != 1. ) {
+ gm.x = tqRound(gm.x * _scale);
+ gm.y = tqRound(gm.y * _scale);
+ gm.height = tqRound(gm.height * _scale);
+ gm.width = tqRound(gm.width * _scale);
+ gm.xoff = tqRound(gm.xoff * _scale);
+ gm.yoff = tqRound(gm.yoff * _scale);
+ }
+ return gm;
+}
+
+
+int TQFontEngineXLFD::ascent() const
+{
+ return tqRound(_fs->ascent*_scale);
+}
+
+int TQFontEngineXLFD::descent() const
+{
+ return tqRound((_fs->descent-1)*_scale);
+}
+
+int TQFontEngineXLFD::leading() const
+{
+ int l = tqRound((TQMIN(_fs->ascent, _fs->max_bounds.ascent)
+ + TQMIN(_fs->descent, _fs->max_bounds.descent)) * _scale * 0.15 );
+ return (l > 0) ? l : 1;
+}
+
+int TQFontEngineXLFD::maxCharWidth() const
+{
+ return tqRound(_fs->max_bounds.width*_scale);
+}
+
+
+// Loads the font for the specified script
+static inline int maxIndex(XFontStruct *f) {
+ return (((f->max_byte1 - f->min_byte1) *
+ (f->max_char_or_byte2 - f->min_char_or_byte2 + 1)) +
+ f->max_char_or_byte2 - f->min_char_or_byte2);
+}
+
+int TQFontEngineXLFD::minLeftBearing() const
+{
+ if ( lbearing == SHRT_MIN ) {
+ if ( _fs->per_char ) {
+ XCharStruct *cs = _fs->per_char;
+ int nc = maxIndex(_fs) + 1;
+ int mx = cs->lbearing;
+
+ for (int c = 1; c < nc; c++) {
+ // ignore the bearings for characters whose ink is
+ // completely outside the normal bounding box
+ if ((cs[c].lbearing <= 0 && cs[c].rbearing <= 0) ||
+ (cs[c].lbearing >= cs[c].width && cs[c].rbearing >= cs[c].width))
+ continue;
+
+ int nmx = cs[c].lbearing;
+
+ if (nmx < mx)
+ mx = nmx;
+ }
+
+ ((TQFontEngineXLFD *)this)->lbearing = mx;
+ } else
+ ((TQFontEngineXLFD *)this)->lbearing = _fs->min_bounds.lbearing;
+ }
+ return tqRound (lbearing*_scale);
+}
+
+int TQFontEngineXLFD::minRightBearing() const
+{
+ if ( rbearing == SHRT_MIN ) {
+ if ( _fs->per_char ) {
+ XCharStruct *cs = _fs->per_char;
+ int nc = maxIndex(_fs) + 1;
+ int mx = cs->rbearing;
+
+ for (int c = 1; c < nc; c++) {
+ // ignore the bearings for characters whose ink is
+ // completely outside the normal bounding box
+ if ((cs[c].lbearing <= 0 && cs[c].rbearing <= 0) ||
+ (cs[c].lbearing >= cs[c].width && cs[c].rbearing >= cs[c].width))
+ continue;
+
+ int nmx = cs[c].rbearing;
+
+ if (nmx < mx)
+ mx = nmx;
+ }
+
+ ((TQFontEngineXLFD *)this)->rbearing = mx;
+ } else
+ ((TQFontEngineXLFD *)this)->rbearing = _fs->min_bounds.rbearing;
+ }
+ return tqRound (rbearing*_scale);
+}
+
+int TQFontEngineXLFD::cmap() const
+{
+ return _cmap;
+}
+
+const char *TQFontEngineXLFD::name() const
+{
+ return _name;
+}
+
+bool TQFontEngineXLFD::canRender( const TQChar *string, int len )
+{
+ glyph_t glyphs[256];
+ int nglyphs = 255;
+ glyph_t *g = glyphs;
+ if ( stringToCMap( string, len, g, 0, &nglyphs, FALSE ) == OutOfMemory ) {
+ g = (glyph_t *)malloc( nglyphs*sizeof(glyph_t) );
+ stringToCMap( string, len, g, 0, &nglyphs, FALSE );
+ }
+
+ bool allExist = TRUE;
+ for ( int i = 0; i < nglyphs; i++ ) {
+ if ( !g[i] || !charStruct( _fs, g[i] ) ) {
+ allExist = FALSE;
+ break;
+ }
+ }
+
+ if ( g != glyphs )
+ free( g );
+
+ return allExist;
+}
+
+
+void TQFontEngineXLFD::setScale( double scale )
+{
+ _scale = scale;
+}
+
+
+TQFontEngine::Type TQFontEngineXLFD::type() const
+{
+ return XLFD;
+}
+
+
+// ------------------------------------------------------------------
+// LatinXLFD engine
+// ------------------------------------------------------------------
+
+static const int engine_array_inc = 4;
+
+TQFontEngineLatinXLFD::TQFontEngineLatinXLFD( XFontStruct *xfs, const char *name,
+ int mib )
+{
+ _engines = new TQFontEngine*[ engine_array_inc ];
+ _engines[0] = new TQFontEngineXLFD( xfs, name, mib );
+ _count = 1;
+
+ cache_cost = _engines[0]->cache_cost;
+
+ memset( glyphIndices, 0, sizeof( glyphIndices ) );
+ memset( glyphAdvances, 0, sizeof( glyphAdvances ) );
+ euroIndex = 0;
+ euroAdvance = 0;
+}
+
+TQFontEngineLatinXLFD::~TQFontEngineLatinXLFD()
+{
+ for ( int i = 0; i < _count; ++i ) {
+ delete _engines[i];
+ _engines[i] = 0;
+ }
+ delete [] _engines;
+ _engines = 0;
+}
+
+void TQFontEngineLatinXLFD::tqfindEngine( const TQChar &ch )
+{
+ if ( ch.tqunicode() == 0 ) return;
+
+ static const char *alternate_encodings[] = {
+ "iso8859-1",
+ "iso8859-2",
+ "iso8859-3",
+ "iso8859-4",
+ "iso8859-9",
+ "iso8859-10",
+ "iso8859-13",
+ "iso8859-14",
+ "iso8859-15",
+ "hp-roman8"
+ };
+ static const int mib_count = sizeof( alternate_encodings ) / sizeof( const char * );
+
+ // see if one of the above mibs can map the char we want
+ TQTextCodec *codec = 0;
+ int which = -1;
+ int i;
+ for ( i = 0; i < mib_count; ++i ) {
+ const int mib = qt_mib_for_xlfd_encoding( alternate_encodings[i] );
+ bool skip = FALSE;
+ for ( int e = 0; e < _count; ++e ) {
+ if ( _engines[e]->cmap() == mib ) {
+ skip = TRUE;
+ break;
+ }
+ }
+ if ( skip ) continue;
+
+ codec = TQTextCodec::codecForMib( mib );
+ if ( codec && codec->canEncode( ch ) ) {
+ which = i;
+ break;
+ }
+ }
+
+ if ( ! codec || which == -1 )
+ return;
+
+ const int enc_id = qt_xlfd_encoding_id( alternate_encodings[which] );
+ TQFontDef req = fontDef;
+ TQFontEngine *engine = TQFontDatabase::tqfindFont( TQFont::Latin, 0, req, enc_id );
+ if ( ! engine ) {
+ req.family = TQString::null;
+ engine = TQFontDatabase::tqfindFont( TQFont::Latin, 0, req, enc_id );
+ if ( ! engine ) return;
+ }
+ engine->setScale( scale() );
+
+ if ( ! ( _count % engine_array_inc ) ) {
+ // grow the engines array
+ TQFontEngine **old = _engines;
+ int new_size =
+ ( ( ( _count+engine_array_inc ) / engine_array_inc ) * engine_array_inc );
+ _engines = new TQFontEngine*[new_size];
+ for ( i = 0; i < _count; ++i )
+ _engines[i] = old[i];
+ delete [] old;
+ }
+
+ _engines[_count] = engine;
+ const int hi = _count << 8;
+ ++_count;
+
+ unsigned short chars[0x201];
+ glyph_t glyphs[0x201];
+ advance_t advances[0x201];
+ for ( i = 0; i < 0x200; ++i )
+ chars[i] = i;
+ chars[0x200] = 0x20ac;
+ int glyphCount = 0x201;
+ engine->stringToCMap( (const TQChar *) chars, 0x201, glyphs, advances, &glyphCount, FALSE );
+
+ // merge member data with the above
+ for ( i = 0; i < 0x200; ++i ) {
+ if ( glyphIndices[i] != 0 || glyphs[i] == 0 ) continue;
+ glyphIndices[i] = glyphs[i] >= 0x2100 ? glyphs[i] : hi | glyphs[i];
+ glyphAdvances[i] = advances[i];
+ }
+ if (!euroIndex && glyphs[0x200]) {
+ euroIndex = hi | glyphs[0x200];
+ euroAdvance = advances[0x200];
+ }
+}
+
+TQFontEngine::Error
+TQFontEngineLatinXLFD::stringToCMap( const TQChar *str, int len, glyph_t *glyphs,
+ advance_t *advances, int *nglyphs, bool mirrored ) const
+{
+ if ( *nglyphs < len ) {
+ *nglyphs = len;
+ return OutOfMemory;
+ }
+
+ int i;
+ bool missing = FALSE;
+ const TQChar *c = str+len;
+ glyph_t *g = glyphs+len;
+ if ( advances ) {
+ int asc = ascent();
+ advance_t *a = advances+len;
+ if ( mirrored ) {
+ while ( c != str ) {
+ --c;
+ --g;
+ --a;
+ if ( c->tqunicode() < 0x200 ) {
+ unsigned short ch = ::mirroredChar(*c).tqunicode();
+ *g = glyphIndices[ch];
+ *a = glyphAdvances[ch];
+ } else {
+ if ( c->tqunicode() == 0x20ac ) {
+ *g = euroIndex;
+ *a = euroAdvance;
+ } else {
+ *g = 0;
+ *a = asc;
+ }
+ }
+ missing = ( missing || ( *g == 0 ) );
+ }
+ } else {
+ while ( c != str ) {
+ --c;
+ --g;
+ --a;
+ if ( c->tqunicode() < 0x200 ) {
+ *g = glyphIndices[c->tqunicode()];
+ *a = glyphAdvances[c->tqunicode()];
+ } else {
+ if ( c->tqunicode() == 0x20ac ) {
+ *g = euroIndex;
+ *a = euroAdvance;
+ } else {
+ *g = 0;
+ *a = asc;
+ }
+ }
+ missing = ( missing || ( *g == 0 ) );
+ }
+ }
+ } else {
+ if ( mirrored ) {
+ while ( c != str ) {
+ --c;
+ --g;
+ *g = ( ( c->tqunicode() < 0x200 ) ? glyphIndices[::mirroredChar(*c).tqunicode()]
+ : (c->tqunicode() == 0x20ac) ? euroIndex : 0 );
+ missing = ( missing || ( *g == 0 ) );
+ }
+ } else {
+ while ( c != str ) {
+ --c;
+ --g;
+ *g = ( ( c->tqunicode() < 0x200 ) ? glyphIndices[c->tqunicode()]
+ : (c->tqunicode() == 0x20ac) ? euroIndex : 0 );
+ missing = ( missing || ( *g == 0 ) );
+ }
+ }
+ }
+
+ if ( missing ) {
+ for ( i = 0; i < len; ++i ) {
+ unsigned short uc = str[i].tqunicode();
+ if ( glyphs[i] != 0 || (uc >= 0x200 && uc != 0x20ac) )
+ continue;
+
+ TQFontEngineLatinXLFD *that = (TQFontEngineLatinXLFD *) this;
+ that->tqfindEngine( str[i] );
+ glyphs[i] = (uc == 0x20ac ? euroIndex : that->glyphIndices[uc]);
+ if ( advances )
+ advances[i] = (uc == 0x20ac ? euroAdvance : glyphAdvances[uc]);
+ }
+ }
+
+ *nglyphs = len;
+ return NoError;
+}
+
+void TQFontEngineLatinXLFD::draw( TQPainter *p, int x, int y, const TQTextEngine *engine,
+ const TQScriptItem *si, int textFlags )
+{
+ if ( !si->num_glyphs ) return;
+
+ glyph_t *glyphs = engine->glyphs( si );
+ advance_t *advances = engine->advances( si );
+ int which = glyphs[0] >> 8;
+ if (which > 0x20)
+ which = 0;
+
+ int start = 0;
+ int end, i;
+ for ( end = 0; end < si->num_glyphs; ++end ) {
+ int e = glyphs[end] >> 8;
+ if (e > 0x20)
+ e = 0;
+ if ( e == which ) continue;
+
+ // set the high byte to zero
+ if (which != 0) {
+ for ( i = start; i < end; ++i )
+ glyphs[i] = glyphs[i] & 0xff;
+ }
+
+ // draw the text
+ TQScriptItem si2 = *si;
+ si2.glyph_data_offset = si->glyph_data_offset + start;
+ si2.num_glyphs = end - start;
+ _engines[which]->draw( p, x, y, engine, &si2, textFlags );
+
+ // reset the high byte for all glyphs and advance to the next sub-string
+ const int hi = which << 8;
+ for ( i = start; i < end; ++i ) {
+ glyphs[i] = hi | glyphs[i];
+ x += advances[i];
+ }
+
+ // change engine
+ start = end;
+ which = e;
+ }
+
+ // set the high byte to zero
+ if (which != 0) {
+ for ( i = start; i < end; ++i )
+ glyphs[i] = glyphs[i] & 0xff;
+ }
+ // draw the text
+ TQScriptItem si2 = *si;
+ si2.glyph_data_offset = si->glyph_data_offset + start;
+ si2.num_glyphs = end - start;
+ _engines[which]->draw( p, x, y, engine, &si2, textFlags );
+
+ // reset the high byte for all glyphs
+ if (which != 0) {
+ const int hi = which << 8;
+ for ( i = start; i < end; ++i )
+ glyphs[i] = hi | glyphs[i];
+ }
+}
+
+glyph_metrics_t TQFontEngineLatinXLFD::boundingBox( const glyph_t *glyphs_const,
+ const advance_t *advances,
+ const qoffset_t *offsets,
+ int numGlyphs )
+{
+ if ( numGlyphs <= 0 ) return glyph_metrics_t();
+
+ glyph_metrics_t overall;
+
+ glyph_t *glyphs = (glyph_t *) glyphs_const;
+ int which = glyphs[0] >> 8;
+ if (which > 0x20)
+ which = 0;
+
+ int start = 0;
+ int end, i;
+ for ( end = 0; end < numGlyphs; ++end ) {
+ int e = glyphs[end] >> 8;
+ if (e > 0x20)
+ e = 0;
+ if ( e == which ) continue;
+
+ // set the high byte to zero
+ if (which != 0) {
+ for ( i = start; i < end; ++i )
+ glyphs[i] = glyphs[i] & 0xff;
+ }
+
+ // merge the bounding box for this run
+ const glyph_metrics_t gm =
+ _engines[which]->boundingBox( glyphs + start,
+ advances + start,
+ offsets + start,
+ end - start );
+
+ overall.x = TQMIN( overall.x, gm.x );
+ overall.y = TQMIN( overall.y, gm.y );
+ overall.width = overall.xoff + gm.width;
+ overall.height = TQMAX( overall.height + overall.y, gm.height + gm.y ) -
+ TQMIN( overall.y, gm.y );
+ overall.xoff += gm.xoff;
+ overall.yoff += gm.yoff;
+
+ // reset the high byte for all glyphs
+ if (which != 0) {
+ const int hi = which << 8;
+ for ( i = start; i < end; ++i )
+ glyphs[i] = hi | glyphs[i];
+ }
+
+ // change engine
+ start = end;
+ which = e;
+ }
+
+ // set the high byte to zero
+ if (which != 0) {
+ for ( i = start; i < end; ++i )
+ glyphs[i] = glyphs[i] & 0xff;
+ }
+
+ // merge the bounding box for this run
+ const glyph_metrics_t gm =
+ _engines[which]->boundingBox( glyphs + start,
+ advances + start,
+ offsets + start,
+ end - start );
+
+ overall.x = TQMIN( overall.x, gm.x );
+ overall.y = TQMIN( overall.y, gm.y );
+ overall.width = overall.xoff + gm.width;
+ overall.height = TQMAX( overall.height + overall.y, gm.height + gm.y ) -
+ TQMIN( overall.y, gm.y );
+ overall.xoff += gm.xoff;
+ overall.yoff += gm.yoff;
+
+ // reset the high byte for all glyphs
+ if (which != 0) {
+ const int hi = which << 8;
+ for ( i = start; i < end; ++i )
+ glyphs[i] = hi | glyphs[i];
+ }
+
+ return overall;
+}
+
+glyph_metrics_t TQFontEngineLatinXLFD::boundingBox( glyph_t glyph )
+{
+ int engine = glyph >> 8;
+ if (engine > 0x20)
+ engine = 0;
+ TQ_ASSERT( engine < _count );
+ return _engines[engine]->boundingBox( engine > 0 ? glyph & 0xff : glyph );
+}
+
+int TQFontEngineLatinXLFD::ascent() const
+{
+ return _engines[0]->ascent();
+}
+
+int TQFontEngineLatinXLFD::descent() const
+{
+ return _engines[0]->descent();
+}
+
+int TQFontEngineLatinXLFD::leading() const
+{
+ return _engines[0]->leading();
+}
+
+int TQFontEngineLatinXLFD::maxCharWidth() const
+{
+ return _engines[0]->maxCharWidth();
+}
+
+int TQFontEngineLatinXLFD::minLeftBearing() const
+{
+ return _engines[0]->minLeftBearing();
+}
+
+int TQFontEngineLatinXLFD::minRightBearing() const
+{
+ return _engines[0]->minRightBearing();
+}
+
+const char *TQFontEngineLatinXLFD::name() const
+{
+ return _engines[0]->name();
+}
+
+bool TQFontEngineLatinXLFD::canRender( const TQChar *string, int len )
+{
+ bool all = TRUE;
+ int i;
+ for ( i = 0; i < len; ++i ) {
+ if ( string[i].tqunicode() >= 0x200 ||
+ glyphIndices[string[i].tqunicode()] == 0 ) {
+ if (string[i].tqunicode() != 0x20ac || euroIndex == 0)
+ all = FALSE;
+ break;
+ }
+ }
+
+ if ( all )
+ return TRUE;
+
+ all = TRUE;
+ for ( i = 0; i < len; ++i ) {
+ if ( string[i].tqunicode() >= 0x200 ) {
+ if (string[i].tqunicode() == 0x20ac) {
+ if (euroIndex)
+ continue;
+
+ tqfindEngine(string[i]);
+ if (euroIndex)
+ continue;
+ }
+ all = FALSE;
+ break;
+ }
+ if ( glyphIndices[string[i].tqunicode()] != 0 ) continue;
+
+ tqfindEngine( string[i] );
+ if ( glyphIndices[string[i].tqunicode()] == 0 ) {
+ all = FALSE;
+ break;
+ }
+ }
+
+ return all;
+}
+
+void TQFontEngineLatinXLFD::setScale( double scale )
+{
+ int i;
+ for ( i = 0; i < _count; ++i )
+ _engines[i]->setScale( scale );
+ unsigned short chars[0x200];
+ for ( i = 0; i < 0x200; ++i )
+ chars[i] = i;
+ int glyphCount = 0x200;
+ _engines[0]->stringToCMap( (const TQChar *)chars, 0x200,
+ glyphIndices, glyphAdvances, &glyphCount, FALSE );
+}
+
+
+// ------------------------------------------------------------------
+// Xft cont engine
+// ------------------------------------------------------------------
+// #define FONTENGINE_DEBUG
+
+#ifndef TQT_NO_XFTFREETYPE
+class TQ_HackPaintDevice : public TQPaintDevice
+{
+public:
+ inline TQ_HackPaintDevice() : TQPaintDevice( 0 ) {}
+ inline XftDraw *xftDrawHandle() const {
+ return (XftDraw *)rendhd;
+ }
+
+};
+
+#ifdef TQT_XFT2
+static inline void getGlyphInfo( XGlyphInfo *xgi, XftFont *font, int glyph )
+{
+ FT_UInt x = glyph;
+ XftGlyphExtents( TQPaintDevice::x11AppDisplay(), font, &x, 1, xgi );
+}
+#else
+static inline XftFontStruct *getFontStruct( XftFont *font )
+{
+ if (font->core)
+ return 0;
+ return font->u.ft.font;
+}
+
+static inline void getGlyphInfo(XGlyphInfo *xgi, XftFont *font, int glyph)
+{
+
+ XftTextExtents32(TQPaintDevice::x11AppDisplay(), font, (XftChar32 *) &glyph, 1, xgi);
+}
+#endif // TQT_XFT2
+
+static inline FT_Face lockFTFace( XftFont *font )
+{
+#ifdef TQT_XFT2
+ return XftLockFace( font );
+#else
+ if (font->core) return 0;
+ return font->u.ft.font->face;
+#endif // TQT_XFT2
+}
+
+static inline void unlockFTFace( XftFont *font )
+{
+#ifdef TQT_XFT2
+ XftUnlockFace( font );
+#else
+ TQ_UNUSED( font );
+#endif // TQT_XFT2
+}
+
+
+
+TQFontEngineXft::TQFontEngineXft( XftFont *font, XftPattern *pattern, int cmap )
+ : _font( font ), _pattern( pattern ), _openType( 0 ), _cmap( cmap )
+{
+ _face = lockFTFace( _font );
+
+#ifndef TQT_XFT2
+ XftFontStruct *xftfs = getFontStruct( _font );
+ if ( xftfs ) {
+ // dirty hack: we set the charmap in the Xftfreetype to -1, so
+ // XftFreetype assumes no encoding and really draws glyph
+ // indices. The FT_Face still has the Unicode encoding to we
+ // can convert from Unicode to glyph index
+ xftfs->charmap = -1;
+ }
+#else
+ _cmap = -1;
+ // Xft maps Unicode and adobe roman for us.
+ for (int i = 0; i < _face->num_charmaps; ++i) {
+ FT_CharMap cm = _face->charmaps[i];
+// qDebug("font has charmap %x", cm->encoding);
+ if (cm->encoding == ft_encoding_adobe_custom
+ || cm->encoding == ft_encoding_symbol) {
+// qDebug("font has adobe custom or ms symbol charmap");
+ _cmap = i;
+ break;
+ }
+ }
+#endif // TQT_XFT2
+
+
+ cache_cost = _font->height * _font->max_advance_width *
+ ( _face ? _face->num_glyphs : 1024 );
+
+ // if the Xft font is not antialiased, it uses bitmaps instead of
+ // 8-bit alpha maps... adjust the cache_cost to reflect this
+ Bool antialiased = TRUE;
+ if ( XftPatternGetBool( pattern, XFT_ANTIALIAS,
+ 0, &antialiased ) == XftResultMatch &&
+ ! antialiased ) {
+ cache_cost /= 8;
+ }
+ lbearing = SHRT_MIN;
+ rbearing = SHRT_MIN;
+
+ memset( widthCache, 0, sizeof(widthCache) );
+ memset( cmapCache, 0, sizeof(cmapCache) );
+}
+
+TQFontEngineXft::~TQFontEngineXft()
+{
+ delete _openType;
+ unlockFTFace( _font );
+
+ XftFontClose( TQPaintDevice::x11AppDisplay(),_font );
+ XftPatternDestroy( _pattern );
+ _font = 0;
+ _pattern = 0;
+ TransformedFont *trf = transformed_fonts;
+ while ( trf ) {
+ XftFontClose( TQPaintDevice::x11AppDisplay(), trf->xft_font );
+ TransformedFont *tmp = trf;
+ trf = trf->next;
+ delete tmp;
+ }
+}
+
+#ifdef TQT_XFT2
+static glyph_t getAdobeCharIndex(XftFont *font, int cmap, uint ucs4)
+{
+ FT_Face _face = XftLockFace( font );
+ FT_Set_Charmap(_face, _face->charmaps[cmap]);
+ glyph_t g = FT_Get_Char_Index(_face, ucs4);
+ XftUnlockFace(font);
+ return g;
+}
+#endif
+
+TQFontEngine::Error TQFontEngineXft::stringToCMap( const TQChar *str, int len, glyph_t *glyphs, advance_t *advances, int *nglyphs, bool mirrored ) const
+{
+ if ( *nglyphs < len ) {
+ *nglyphs = len;
+ return OutOfMemory;
+ }
+
+#ifdef TQT_XFT2
+ if (_cmap != -1) {
+ for ( int i = 0; i < len; ++i ) {
+ unsigned short uc = str[i].tqunicode();
+ if (mirrored)
+ uc = ::mirroredChar(str[i]).tqunicode();
+ glyphs[i] = uc < cmapCacheSize ? cmapCache[uc] : 0;
+ if ( !glyphs[i] ) {
+ glyph_t glyph = XftCharIndex(0, _font, uc);
+ if (!glyph)
+ glyph = getAdobeCharIndex(_font, _cmap, uc);
+ glyphs[i] = glyph;
+ if ( uc < cmapCacheSize )
+ ((TQFontEngineXft *)this)->cmapCache[uc] = glyph;
+ }
+ }
+ } else if ( mirrored ) {
+ for ( int i = 0; i < len; ++i ) {
+ unsigned short uc = ::mirroredChar(str[i]).tqunicode();
+ glyphs[i] = uc < cmapCacheSize ? cmapCache[uc] : 0;
+ if ( !glyphs[i] ) {
+ if (uc == 0xa0)
+ uc = 0x20;
+ glyph_t glyph = XftCharIndex(0, _font, uc);
+ glyphs[i] = glyph;
+ if ( uc < cmapCacheSize )
+ ((TQFontEngineXft *)this)->cmapCache[uc] = glyph;
+ }
+ }
+ } else {
+ for ( int i = 0; i < len; ++i ) {
+ unsigned short uc = str[i].tqunicode();
+ glyphs[i] = uc < cmapCacheSize ? cmapCache[uc] : 0;
+ if ( !glyphs[i] ) {
+ if (uc == 0xa0)
+ uc = 0x20;
+ glyph_t glyph = XftCharIndex(0, _font, uc);
+ glyphs[i] = glyph;
+ if ( uc < cmapCacheSize )
+ ((TQFontEngineXft *)this)->cmapCache[uc] = glyph;
+ }
+ }
+ }
+
+ if ( advances ) {
+ for ( int i = 0; i < len; i++ ) {
+ FT_UInt glyph = *(glyphs + i);
+ advances[i] = (glyph < widthCacheSize) ? widthCache[glyph] : 0;
+ if ( !advances[i] ) {
+ XGlyphInfo gi;
+ XftGlyphExtents( TQPaintDevice::x11AppDisplay(), _font, &glyph, 1, &gi );
+ advances[i] = gi.xOff;
+ if ( glyph < widthCacheSize && gi.xOff > 0 && gi.xOff < 0x100 )
+ ((TQFontEngineXft *)this)->widthCache[glyph] = gi.xOff;
+ }
+ }
+ if ( _scale != 1. ) {
+ for ( int i = 0; i < len; i++ )
+ advances[i] = tqRound(advances[i]*_scale);
+ }
+ }
+#else
+ if ( !_face ) {
+ if ( mirrored ) {
+ for ( int i = 0; i < len; i++ )
+ glyphs[i] = ::mirroredChar(str[i]).tqunicode();
+ } else {
+ for ( int i = 0; i < len; i++ )
+ glyphs[i] = str[i].tqunicode();
+ }
+ } else {
+ if ( _cmap == 1 ) {
+ // symbol font
+ for ( int i = 0; i < len; i++ ) {
+ unsigned short uc = str[i].tqunicode();
+ glyphs[i] = uc < cmapCacheSize ? cmapCache[uc] : 0;
+ if ( !glyphs[i] ) {
+ glyph_t glyph = FT_Get_Char_Index( _face, uc );
+ if(!glyph && uc < 0x100)
+ glyph = FT_Get_Char_Index( _face, uc+0xf000 );
+ glyphs[i] = glyph;
+ if ( uc < cmapCacheSize )
+ ((TQFontEngineXft *)this)->cmapCache[uc] = glyph;
+ }
+ }
+ } else if ( mirrored ) {
+ for ( int i = 0; i < len; i++ ) {
+ unsigned short uc = ::mirroredChar(str[i]).tqunicode();
+ glyphs[i] = uc < cmapCacheSize ? cmapCache[uc] : 0;
+ if ( !glyphs[i] ) {
+ glyph_t glyph = FT_Get_Char_Index( _face, uc );
+ glyphs[i] = glyph;
+ if ( uc < cmapCacheSize )
+ ((TQFontEngineXft *)this)->cmapCache[uc] = glyph;
+ }
+ }
+ } else {
+ for ( int i = 0; i < len; i++ ) {
+ unsigned short uc = str[i].tqunicode();
+ glyphs[i] = uc < cmapCacheSize ? cmapCache[uc] : 0;
+ if ( !glyphs[i] ) {
+ glyph_t glyph = FT_Get_Char_Index( _face, uc );
+ glyphs[i] = glyph;
+ if ( uc < cmapCacheSize )
+ ((TQFontEngineXft *)this)->cmapCache[uc] = glyph;
+ }
+ }
+ }
+ }
+
+ if ( advances ) {
+ for ( int i = 0; i < len; i++ ) {
+ XftChar16 glyph = *(glyphs + i);
+ advances[i] = (glyph < widthCacheSize) ? widthCache[glyph] : 0;
+ if ( !advances[i] ) {
+ XGlyphInfo gi;
+ XftTextExtents16(TQPaintDevice::x11AppDisplay(), _font, &glyph, 1, &gi);
+ advances[i] = gi.xOff;
+ if ( glyph < widthCacheSize && gi.xOff > 0 && gi.xOff < 0x100 )
+ ((TQFontEngineXft *)this)->widthCache[glyph] = gi.xOff;
+ }
+ }
+ if ( _scale != 1. ) {
+ for ( int i = 0; i < len; i++ )
+ advances[i] = tqRound(advances[i]*_scale);
+ }
+ }
+#endif // TQT_XFT2
+
+ *nglyphs = len;
+ return NoError;
+}
+
+
+void TQFontEngineXft::recalcAdvances( int len, glyph_t *glyphs, advance_t *advances )
+{
+
+#ifdef TQT_XFT2
+ for ( int i = 0; i < len; i++ ) {
+ FT_UInt glyph = *(glyphs + i);
+ advances[i] = (glyph < widthCacheSize) ? widthCache[glyph] : 0;
+ if ( !advances[i] ) {
+ XGlyphInfo gi;
+ XftGlyphExtents( TQPaintDevice::x11AppDisplay(), _font, &glyph, 1, &gi );
+ advances[i] = gi.xOff;
+ if ( glyph < widthCacheSize && gi.xOff > 0 && gi.xOff < 0x100 )
+ ((TQFontEngineXft *)this)->widthCache[glyph] = gi.xOff;
+ }
+ if ( _scale != 1. ) {
+ for ( int i = 0; i < len; i++ )
+ advances[i] = tqRound(advances[i]*_scale);
+ }
+ }
+#else
+ for ( int i = 0; i < len; i++ ) {
+ XftChar16 glyph = *(glyphs + i);
+ advances[i] = (glyph < widthCacheSize) ? widthCache[glyph] : 0;
+ if ( !advances[i] ) {
+ XGlyphInfo gi;
+ XftTextExtents16(TQPaintDevice::x11AppDisplay(), _font, &glyph, 1, &gi);
+ advances[i] = gi.xOff;
+ if ( glyph < widthCacheSize && gi.xOff > 0 && gi.xOff < 0x100 )
+ ((TQFontEngineXft *)this)->widthCache[glyph] = gi.xOff;
+ }
+ }
+ if ( _scale != 1. ) {
+ for ( int i = 0; i < len; i++ )
+ advances[i] = tqRound(advances[i]*_scale);
+ }
+#endif // TQT_XFT2
+}
+
+//#define FONTENGINE_DEBUG
+void TQFontEngineXft::draw( TQPainter *p, int x, int y, const TQTextEngine *engine, const TQScriptItem *si, int textFlags )
+{
+ if ( !si->num_glyphs )
+ return;
+
+ Display *dpy = TQPaintDevice::x11AppDisplay();
+
+ int xorig = x;
+ int yorig = y;
+
+ GlyphAttributes *glyphAttributes = engine->glyphAttributes( si );
+
+ XftFont *fnt = _font;
+ bool transform = FALSE;
+ if ( p->txop >= TQPainter::TxScale || p->rop != TQt::CopyROP || _scale < 0.9999 || _scale > 1.001) {
+ bool can_scale = (_face->face_flags & FT_FACE_FLAG_SCALABLE) && p->rop == TQt::CopyROP;
+ double size = (p->m11()*p->m22() - p->m12()*p->m21())*_scale*_scale*fontDef.pixelSize*fontDef.pixelSize;
+ if (size > 256*256 || _scale < .9999 || _scale > 1.001)
+ can_scale = FALSE;
+ if (!can_scale) {
+ // font doesn't support transformations, need to do it by hand
+ float tmp = _scale;
+ _scale = 1.;
+ drawScaled(x, y, engine, si, textFlags, dpy, p->gc, p->tqdevice(), this, p->xmat, tmp);
+ _scale = tmp;
+ return;
+ }
+
+ XftMatrix *mat = 0;
+ XftPatternGetMatrix( _pattern, XFT_MATRIX, 0, &mat );
+ XftMatrix m2;
+ m2.xx = p->m11()*_scale;
+ m2.xy = -p->m21()*_scale;
+ m2.yx = -p->m12()*_scale;
+ m2.yy = p->m22()*_scale;
+
+ // check if we have it cached
+ TransformedFont *trf = transformed_fonts;
+ TransformedFont *prev = 0;
+ int i = 0;
+ while ( trf ) {
+ if ( trf->xx == (float)m2.xx &&
+ trf->xy == (float)m2.xy &&
+ trf->yx == (float)m2.yx &&
+ trf->yy == (float)m2.yy )
+ break;
+ TransformedFont *tmp = trf;
+ trf = trf->next;
+ if (i > 10) {
+ XftFontClose( TQPaintDevice::x11AppDisplay(), tmp->xft_font );
+ delete tmp;
+ prev->next = trf;
+ } else {
+ prev = tmp;
+ }
+ ++i;
+ }
+ if ( trf ) {
+ if ( prev ) {
+ // move to beginning of list
+ prev->next = trf->next;
+ trf->next = transformed_fonts;
+ transformed_fonts = trf;
+ }
+ fnt = trf->xft_font;
+ } else {
+ if ( mat )
+ XftMatrixMultiply( &m2, &m2, mat );
+
+ XftPattern *pattern = XftPatternDuplicate( _pattern );
+ XftPatternDel( pattern, XFT_MATRIX );
+ XftPatternAddMatrix( pattern, XFT_MATRIX, &m2 );
+
+ fnt = XftFontOpenPattern( dpy, pattern );
+#ifndef TQT_XFT2
+ XftFontStruct *xftfs = getFontStruct( fnt );
+ if ( xftfs ) {
+ // dirty hack: we set the charmap in the Xftfreetype to -1, so
+ // XftFreetype assumes no encoding and really draws glyph
+ // indices. The FT_Face still has the Unicode encoding to we
+ // can convert from Unicode to glyph index
+ xftfs->charmap = -1;
+ }
+#endif // TQT_XFT2
+ TransformedFont *trf = new TransformedFont;
+ trf->xx = (float)m2.xx;
+ trf->xy = (float)m2.xy;
+ trf->yx = (float)m2.yx;
+ trf->yy = (float)m2.yy;
+ trf->xft_font = fnt;
+ trf->next = transformed_fonts;
+ transformed_fonts = trf;
+ }
+ transform = TRUE;
+ } else if ( p->txop == TQPainter::TxTranslate ) {
+ p->map( x, y, &x, &y );
+ }
+
+ glyph_t *glyphs = engine->glyphs( si );
+ advance_t *advances = engine->advances( si );
+ qoffset_t *offsets = engine->offsets( si );
+
+ const TQColor &pen = p->cpen.color();
+ XftDraw *draw = ((TQ_HackPaintDevice *)p->pdev)->xftDrawHandle();
+
+ XftColor col;
+ col.color.red = pen.red () | pen.red() << 8;
+ col.color.green = pen.green () | pen.green() << 8;
+ col.color.blue = pen.blue () | pen.blue() << 8;
+ col.color.alpha = 0xffff;
+ col.pixel = pen.pixel();
+#ifdef FONTENGINE_DEBUG
+ qDebug("===== drawing %d glyphs reverse=%s ======", si->num_glyphs, si->analysis.bidiLevel % 2?"TRUE":"FALSE" );
+ p->save();
+ p->setBrush( TQt::white );
+ glyph_metrics_t ci = boundingBox( glyphs, advances, offsets, si->num_glyphs );
+ p->drawRect( x + ci.x, y + ci.y, ci.width, ci.height );
+ p->drawRect( x + ci.x, y + 100 + ci.y, ci.width, ci.height );
+ qDebug("bounding rect=%d %d (%d/%d)", ci.x, ci.y, ci.width, ci.height );
+ p->restore();
+ int yp = y;
+ int xp = x;
+#endif
+
+ if ( textFlags != 0 )
+ drawLines( p, this, yorig, xorig, si->width, textFlags );
+
+
+ if ( si->isSpace )
+ return;
+
+ if ( transform || si->hasPositioning ) {
+ if ( si->analysis.bidiLevel % 2 ) {
+ int i = si->num_glyphs;
+ while( i-- ) {
+ int xp = x + offsets[i].x;
+ int yp = y + offsets[i].y;
+ if ( transform )
+ p->map( xp, yp, &xp, &yp );
+#ifdef TQT_XFT2
+ FT_UInt glyph = *(glyphs + i);
+ if (!glyphAttributes[i].zeroWidth && xp < SHRT_MAX && xp > SHRT_MIN)
+ XftDrawGlyphs( draw, &col, fnt, xp, yp, &glyph, 1 );
+#else
+ if (!glyphAttributes[i].zeroWidth && xp < SHRT_MAX && xp > SHRT_MIN)
+ XftDrawString16( draw, &col, fnt, xp, yp, (XftChar16 *) (glyphs+i), 1);
+#endif // TQT_XFT2
+#ifdef FONTENGINE_DEBUG
+ glyph_metrics_t gi = boundingBox( glyphs[i] );
+ p->drawRect( x+offsets[i].x+gi.x, y+offsets[i].y+100+gi.y, gi.width, gi.height );
+ p->drawLine( x+offsets[i].x, y + 150 + 5*i , x+offsets[i].x+advances[i], y + 150 + 5*i );
+ p->drawLine( x+offsets[i].x, y + 152 + 5*i , x+offsets[i].x+gi.xoff, y + 152 + 5*i );
+ qDebug("bounding ci[%d]=%d %d (%d/%d) / %d %d offs=(%d/%d) advance=%d", i, gi.x, gi.y, gi.width, gi.height,
+ gi.xoff, gi.yoff, offsets[i].x, offsets[i].y, advances[i]);
+#endif
+ x += advances[i];
+ }
+ } else {
+ int i = 0;
+ while ( i < si->num_glyphs ) {
+ int xp = x + offsets[i].x;
+ int yp = y + offsets[i].y;
+ if ( transform )
+ p->map( xp, yp, &xp, &yp );
+#ifdef TQT_XFT2
+ FT_UInt glyph = *(glyphs + i);
+ if (!glyphAttributes[i].zeroWidth && xp < SHRT_MAX && xp > SHRT_MIN)
+ XftDrawGlyphs( draw, &col, fnt, xp, yp, &glyph, 1 );
+#else
+ if (!glyphAttributes[i].zeroWidth && xp < SHRT_MAX && xp > SHRT_MIN)
+ XftDrawString16( draw, &col, fnt, xp, yp, (XftChar16 *) (glyphs+i), 1 );
+#endif // TQT_XFT2
+ // qDebug("advance = %d/%d", adv.x, adv.y );
+ x += advances[i];
+ i++;
+ }
+ }
+ } else {
+ // Xft has real trouble drawing the glyphs on their own.
+ // Drawing them as one string increases performance significantly.
+#ifdef TQT_XFT2
+ // #### we should use a different method anyways on Xft2
+ FT_UInt g[64];
+ int gl = 0;
+ while (gl < si->num_glyphs) {
+ int toDraw = TQMIN(64, si->num_glyphs-gl);
+ int adv = 0;
+ if ( si->analysis.bidiLevel % 2 ) {
+ for ( int i = 0; i < toDraw; i++ ) {
+ g[i] = glyphs[si->num_glyphs-1-(gl+i)];
+ adv += advances[si->num_glyphs-1-(gl+i)];
+ }
+ } else {
+ for ( int i = 0; i < toDraw; i++ ) {
+ g[i] = glyphs[gl+i];
+ adv += advances[gl+i];
+ }
+ }
+ if (x + adv < SHRT_MAX && x > SHRT_MIN)
+ XftDrawGlyphs( draw, &col, fnt, x, y, g, toDraw );
+ gl += toDraw;
+ x += adv;
+ }
+#else
+ XftChar16 g[64];
+ int gl = 0;
+ while (gl < si->num_glyphs) {
+ int toDraw = TQMIN(64, si->num_glyphs-gl);
+ int adv = 0;
+ if ( si->analysis.bidiLevel % 2 ) {
+ for ( int i = 0; i < toDraw; i++ ) {
+ g[i] = glyphs[si->num_glyphs-1-(gl+i)];
+ adv += advances[si->num_glyphs-1-(gl+i)];
+ }
+ } else {
+ for ( int i = 0; i < toDraw; i++ ) {
+ g[i] = glyphs[gl+i];
+ adv += advances[gl+i];
+ }
+ }
+ if (x + adv < SHRT_MAX && x > SHRT_MIN)
+ XftDrawString16( draw, &col, fnt, x, y, g, toDraw );
+ gl += toDraw;
+ x += adv;
+ }
+#endif // TQT_XFT2
+ }
+
+#ifdef FONTENGINE_DEBUG
+ if ( !si->analysis.bidiLevel % 2 ) {
+ x = xp;
+ y = yp;
+ p->save();
+ p->setPen( TQt::red );
+ for ( int i = 0; i < si->num_glyphs; i++ ) {
+ glyph_metrics_t ci = boundingBox( glyphs[i] );
+ p->drawRect( x + ci.x + offsets[i].x, y + 100 + ci.y + offsets[i].y, ci.width, ci.height );
+ qDebug("bounding ci[%d]=%d %d (%d/%d) / %d %d offs=(%d/%d) advance=%d", i, ci.x, ci.y, ci.width, ci.height,
+ ci.xoff, ci.yoff, offsets[i].x, offsets[i].y, advances[i]);
+ x += advances[i];
+ }
+ p->restore();
+ }
+#endif
+}
+
+glyph_metrics_t TQFontEngineXft::boundingBox( const glyph_t *glyphs, const advance_t *advances, const qoffset_t *offsets, int numGlyphs )
+{
+ XGlyphInfo xgi;
+
+ glyph_metrics_t overall;
+ int ymax = 0;
+ int xmax = 0;
+ if (_scale != 1) {
+ for (int i = 0; i < numGlyphs; i++) {
+ getGlyphInfo( &xgi, _font, glyphs[i] );
+ int x = overall.xoff + offsets[i].x - xgi.x;
+ int y = overall.yoff + offsets[i].y - xgi.y;
+ overall.x = TQMIN( overall.x, x );
+ overall.y = TQMIN( overall.y, y );
+ xmax = TQMAX( xmax, x + xgi.width );
+ ymax = TQMAX( ymax, y + xgi.height );
+ overall.xoff += tqRound(advances[i]/_scale);
+ }
+ overall.x = tqRound(overall.x * _scale);
+ overall.y = tqRound(overall.y * _scale);
+ overall.xoff = tqRound(overall.xoff * _scale);
+ overall.yoff = tqRound(overall.yoff * _scale);
+ xmax = tqRound(xmax * _scale);
+ ymax = tqRound(ymax * _scale);
+ } else {
+ for (int i = 0; i < numGlyphs; i++) {
+ getGlyphInfo( &xgi, _font, glyphs[i] );
+ int x = overall.xoff + offsets[i].x - xgi.x;
+ int y = overall.yoff + offsets[i].y - xgi.y;
+ overall.x = TQMIN( overall.x, x );
+ overall.y = TQMIN( overall.y, y );
+ xmax = TQMAX( xmax, x + xgi.width );
+ ymax = TQMAX( ymax, y + xgi.height );
+ overall.xoff += advances[i];
+ }
+ }
+ overall.height = ymax - overall.y;
+ overall.width = xmax - overall.x;
+ return overall;
+}
+
+glyph_metrics_t TQFontEngineXft::boundingBox( glyph_t glyph )
+{
+ XGlyphInfo xgi;
+ getGlyphInfo( &xgi, _font, glyph );
+ glyph_metrics_t gm = glyph_metrics_t( -xgi.x, -xgi.y, xgi.width, xgi.height, xgi.xOff, -xgi.yOff );
+ if ( _scale != 1. ) {
+ gm.x = tqRound(gm.x * _scale);
+ gm.y = tqRound(gm.y * _scale);
+ gm.height = tqRound(gm.height * _scale);
+ gm.width = tqRound(gm.width * _scale);
+ gm.xoff = tqRound(gm.xoff * _scale);
+ gm.yoff = tqRound(gm.yoff * _scale);
+ }
+ return gm;
+}
+
+
+
+int TQFontEngineXft::ascent() const
+{
+ return tqRound(_font->ascent*_scale);
+}
+
+int TQFontEngineXft::descent() const
+{
+ return tqRound((_font->descent-1)*_scale);
+}
+
+// #### use Freetype to determine this
+int TQFontEngineXft::leading() const
+{
+ int l = tqRound(TQMIN( _font->height - (_font->ascent + _font->descent),
+ ((_font->ascent + _font->descent) >> 4)*_scale ));
+ return (l > 0) ? l : 1;
+}
+
+// #### use Freetype to determine this
+int TQFontEngineXft::lineThickness() const
+{
+ // ad hoc algorithm
+ int score = fontDef.weight * fontDef.pixelSize;
+ int lw = score / 700;
+
+ // looks better with thicker line for small pointsizes
+ if ( lw < 2 && score >= 1050 ) lw = 2;
+ if ( lw == 0 ) lw = 1;
+
+ return lw;
+}
+
+// #### use Freetype to determine this
+int TQFontEngineXft::underlinePosition() const
+{
+ int pos = ( ( lineThickness() * 2 ) + 3 ) / 6;
+ return pos ? pos : 1;
+}
+
+int TQFontEngineXft::maxCharWidth() const
+{
+ return tqRound(_font->max_advance_width*_scale);
+}
+
+static const ushort char_table[] = {
+ 40,
+ 67,
+ 70,
+ 75,
+ 86,
+ 88,
+ 89,
+ 91,
+ 102,
+ 114,
+ 124,
+ 127,
+ 205,
+ 645,
+ 884,
+ 922,
+ 1070,
+ 12386
+};
+
+static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
+
+
+int TQFontEngineXft::minLeftBearing() const
+{
+ if ( lbearing == SHRT_MIN )
+ minRightBearing(); // calculates both
+
+ return lbearing;
+}
+
+int TQFontEngineXft::minRightBearing() const
+{
+ if ( rbearing == SHRT_MIN ) {
+ TQFontEngineXft *that = (TQFontEngineXft *)this;
+ that->lbearing = that->rbearing = 0;
+ TQChar *ch = (TQChar *)char_table;
+ glyph_t glyphs[char_table_entries];
+ int ng = char_table_entries;
+ stringToCMap(ch, char_table_entries, glyphs, 0, &ng, FALSE);
+ while (--ng) {
+ if (glyphs[ng]) {
+ glyph_metrics_t gi = that->boundingBox( glyphs[ng] );
+ if (gi.xoff) {
+ that->lbearing = TQMIN(lbearing, gi.x);
+ that->rbearing = TQMIN(rbearing, gi.xoff - gi.x - gi.width);
+ }
+ }
+ }
+ }
+
+ return rbearing;
+}
+
+int TQFontEngineXft::cmap() const
+{
+ return _cmap;
+}
+
+const char *TQFontEngineXft::name() const
+{
+ return "xft";
+}
+
+void TQFontEngineXft::setScale( double scale )
+{
+ _scale = scale;
+}
+
+bool TQFontEngineXft::canRender( const TQChar *string, int len )
+{
+ bool allExist = TRUE;
+
+#ifdef TQT_XFT2
+ if (_cmap != -1) {
+ for ( int i = 0; i < len; i++ ) {
+ if (!XftCharExists(0, _font, string[i].tqunicode())
+ && getAdobeCharIndex(_font, _cmap, string[i].tqunicode()) == 0) {
+ allExist = FALSE;
+ break;
+ }
+ }
+ } else {
+ for ( int i = 0; i < len; i++ ) {
+ if (!XftCharExists(0, _font, string[i].tqunicode())) {
+ allExist = FALSE;
+ break;
+ }
+ }
+ }
+#else
+ glyph_t glyphs[256];
+ int nglyphs = 255;
+ glyph_t *g = glyphs;
+ if ( stringToCMap( string, len, g, 0, &nglyphs, FALSE ) == OutOfMemory ) {
+ g = (glyph_t *)malloc( nglyphs*sizeof(glyph_t) );
+ stringToCMap( string, len, g, 0, &nglyphs, FALSE );
+ }
+
+ for ( int i = 0; i < nglyphs; i++ ) {
+ if ( !XftGlyphExists(TQPaintDevice::x11AppDisplay(), _font, g[i]) ) {
+ allExist = FALSE;
+ break;
+ }
+ }
+
+ if ( g != glyphs )
+ free( g );
+#endif // TQT_XFT2
+
+ return allExist;
+}
+
+TQOpenType *TQFontEngineXft::openType() const
+{
+// qDebug("openTypeIface requested!");
+ if ( _openType )
+ return _openType;
+
+ if ( !_face || ! FT_IS_SFNT( _face ) )
+ return 0;
+
+ TQFontEngineXft *that = (TQFontEngineXft *)this;
+ that->_openType = new TQOpenType(that);
+ return _openType;
+}
+
+
+TQFontEngine::Type TQFontEngineXft::type() const
+{
+ return Xft;
+}
+#endif
+
+
+// --------------------------------------------------------------------------------------------------------------------
+// Open type support
+// --------------------------------------------------------------------------------------------------------------------
+
+#ifndef TQT_NO_XFTFREETYPE
+
+#include "tqscriptengine_p.h"
+
+//#define OT_DEBUG
+
+#ifdef OT_DEBUG
+static inline char *tag_to_string(FT_ULong tag)
+{
+ static char string[5];
+ string[0] = (tag >> 24)&0xff;
+ string[1] = (tag >> 16)&0xff;
+ string[2] = (tag >> 8)&0xff;
+ string[3] = tag&0xff;
+ string[4] = 0;
+ return string;
+}
+#endif
+
+#define DefaultLangSys 0xffff
+#define DefaultScript FT_MAKE_TAG('D', 'F', 'L', 'T')
+
+enum {
+ RequiresGsub = 1,
+ RequiresGpos = 2
+};
+
+struct OTScripts {
+ unsigned int tag;
+ int flags;
+};
+
+static const OTScripts ot_scripts [] = {
+// // European Alphabetic Scripts
+// Latin,
+ { FT_MAKE_TAG( 'l', 'a', 't', 'n' ), 0 },
+// Greek,
+ { FT_MAKE_TAG( 'g', 'r', 'e', 'k' ), 0 },
+// Cyrillic,
+ { FT_MAKE_TAG( 'c', 'y', 'r', 'l' ), 0 },
+// Armenian,
+ { FT_MAKE_TAG( 'a', 'r', 'm', 'n' ), 0 },
+// Georgian,
+ { FT_MAKE_TAG( 'g', 'e', 'o', 'r' ), 0 },
+// Runic,
+ { FT_MAKE_TAG( 'r', 'u', 'n', 'r' ), 0 },
+// Ogham,
+ { FT_MAKE_TAG( 'o', 'g', 'a', 'm' ), 0 },
+// SpacingModifiers,
+ { FT_MAKE_TAG( 'D', 'F', 'L', 'T' ), 0 },
+// CombiningMarks,
+ { FT_MAKE_TAG( 'D', 'F', 'L', 'T' ), 0 },
+
+// // Middle Eastern Scripts
+// Hebrew,
+ { FT_MAKE_TAG( 'h', 'e', 'b', 'r' ), 1 },
+// Arabic,
+ { FT_MAKE_TAG( 'a', 'r', 'a', 'b' ), 1 },
+// Syriac,
+ { FT_MAKE_TAG( 's', 'y', 'r', 'c' ), 1 },
+// Thaana,
+ { FT_MAKE_TAG( 't', 'h', 'a', 'a' ), 1 },
+
+// // South and Southeast Asian Scripts
+// Devanagari,
+ { FT_MAKE_TAG( 'd', 'e', 'v', 'a' ), 1 },
+// Bengali,
+ { FT_MAKE_TAG( 'b', 'e', 'n', 'g' ), 1 },
+// Gurmukhi,
+ { FT_MAKE_TAG( 'g', 'u', 'r', 'u' ), 1 },
+// Gujarati,
+ { FT_MAKE_TAG( 'g', 'u', 'j', 'r' ), 1 },
+// Oriya,
+ { FT_MAKE_TAG( 'o', 'r', 'y', 'a' ), 1 },
+// Tamil,
+ { FT_MAKE_TAG( 't', 'a', 'm', 'l' ), 1 },
+// Telugu,
+ { FT_MAKE_TAG( 't', 'e', 'l', 'u' ), 1 },
+// Kannada,
+ { FT_MAKE_TAG( 'k', 'n', 'd', 'a' ), 1 },
+// Malayalam,
+ { FT_MAKE_TAG( 'm', 'l', 'y', 'm' ), 1 },
+// Sinhala,
+ // ### could not tqfind any OT specs on this
+ { FT_MAKE_TAG( 's', 'i', 'n', 'h' ), 1 },
+// Thai,
+ { FT_MAKE_TAG( 't', 'h', 'a', 'i' ), 1 },
+// Lao,
+ { FT_MAKE_TAG( 'l', 'a', 'o', ' ' ), 1 },
+// Tibetan,
+ { FT_MAKE_TAG( 't', 'i', 'b', 't' ), 1 },
+// Myanmar,
+ { FT_MAKE_TAG( 'm', 'y', 'm', 'r' ), 1 },
+// Khmer,
+ { FT_MAKE_TAG( 'k', 'h', 'm', 'r' ), 1 },
+
+// // East Asian Scripts
+// Han,
+ { FT_MAKE_TAG( 'h', 'a', 'n', 'i' ), 0 },
+// Hiragana,
+ { FT_MAKE_TAG( 'k', 'a', 'n', 'a' ), 0 },
+// Katakana,
+ { FT_MAKE_TAG( 'k', 'a', 'n', 'a' ), 0 },
+// Hangul,
+ { FT_MAKE_TAG( 'h', 'a', 'n', 'g' ), 1 },
+// Bopomofo,
+ { FT_MAKE_TAG( 'b', 'o', 'p', 'o' ), 0 },
+// Yi,
+ { FT_MAKE_TAG( 'y', 'i', ' ', ' ' ), 0 },
+
+// // Additional Scripts
+// Ethiopic,
+ { FT_MAKE_TAG( 'e', 't', 'h', 'i' ), 0 },
+// Cherokee,
+ { FT_MAKE_TAG( 'c', 'h', 'e', 'r' ), 0 },
+// CanadianAboriginal,
+ { FT_MAKE_TAG( 'c', 'a', 'n', 's' ), 0 },
+// Mongolian,
+ { FT_MAKE_TAG( 'm', 'o', 'n', 'g' ), 0 },
+// // Symbols
+// CurrencySymbols,
+ { FT_MAKE_TAG( 'D', 'F', 'L', 'T' ), 0 },
+// LetterlikeSymbols,
+ { FT_MAKE_TAG( 'D', 'F', 'L', 'T' ), 0 },
+// NumberForms,
+ { FT_MAKE_TAG( 'D', 'F', 'L', 'T' ), 0 },
+// MathematicalOperators,
+ { FT_MAKE_TAG( 'D', 'F', 'L', 'T' ), 0 },
+// TechnicalSymbols,
+ { FT_MAKE_TAG( 'D', 'F', 'L', 'T' ), 0 },
+// GeometricSymbols,
+ { FT_MAKE_TAG( 'D', 'F', 'L', 'T' ), 0 },
+// MiscellaneousSymbols,
+ { FT_MAKE_TAG( 'D', 'F', 'L', 'T' ), 0 },
+// EnclosedAndSquare,
+ { FT_MAKE_TAG( 'D', 'F', 'L', 'T' ), 0 },
+// Braille,
+ { FT_MAKE_TAG( 'b', 'r', 'a', 'i' ), 0 },
+// Unicode, should be used
+ { FT_MAKE_TAG( 'D', 'F', 'L', 'T' ), 0 }
+ // ### where are these?
+// { FT_MAKE_TAG( 'b', 'y', 'z', 'm' ), 0 },
+// { FT_MAKE_TAG( 'D', 'F', 'L', 'T' ), 0 },
+ // ### Hangul Jamo
+// { FT_MAKE_TAG( 'j', 'a', 'm', 'o' ), 0 },
+};
+
+TQOpenType::TQOpenType(TQFontEngineXft *fe)
+ : fontEngine(fe), gdef(0), gsub(0), gpos(0), current_script(0)
+{
+ face = fe->face();
+ otl_buffer_new(face->memory, &otl_buffer);
+ tmpAttributes = 0;
+ tmpLogClusters = 0;
+
+ FT_Error error;
+ if ((error = TT_Load_GDEF_Table(face, &gdef))) {
+#ifdef OT_DEBUG
+ qDebug("error loading gdef table: %d", error);
+#endif
+ gdef = 0;
+ }
+
+ if ((error = TT_Load_GSUB_Table(face, &gsub, gdef))) {
+ gsub = 0;
+#ifdef OT_DEBUG
+ if (error != FT_Err_Table_Missing) {
+ qDebug("error loading gsub table: %d", error);
+ } else {
+ qDebug("face doesn't have a gsub table");
+ }
+#endif
+ }
+
+ if ((error = TT_Load_GPOS_Table(face, &gpos, gdef))) {
+ gpos = 0;
+#ifdef OT_DEBUG
+ qDebug("error loading gpos table: %d", error);
+#endif
+ }
+
+ for (uint i = 0; i < TQFont::NScripts; ++i)
+ supported_scripts[i] = checkScript(i);
+}
+
+TQOpenType::~TQOpenType()
+{
+ if (gpos)
+ TT_Done_GPOS_Table(gpos);
+ if (gsub)
+ TT_Done_GSUB_Table(gsub);
+ if (gdef)
+ TT_Done_GDEF_Table(gdef);
+ if (otl_buffer)
+ otl_buffer_free(otl_buffer);
+ if (tmpAttributes)
+ free(tmpAttributes);
+ if (tmpLogClusters)
+ free(tmpLogClusters);
+}
+
+bool TQOpenType::checkScript(unsigned int script)
+{
+ assert(script < TQFont::NScripts);
+
+ uint tag = ot_scripts[script].tag;
+ int requirements = ot_scripts[script].flags;
+
+ if (requirements & RequiresGsub) {
+ if (!gsub)
+ return FALSE;
+
+ FT_UShort script_index;
+ FT_Error error = TT_GSUB_Select_Script(gsub, tag, &script_index);
+ if (error) {
+#ifdef OT_DEBUG
+ qDebug("could not select script %d in GSub table: %d", (int)script, error);
+#endif
+ return FALSE;
+ }
+ }
+
+ if (requirements & RequiresGpos) {
+ if (!gpos)
+ return FALSE;
+
+ FT_UShort script_index;
+ FT_Error error = TT_GPOS_Select_Script(gpos, script, &script_index);
+ if (error) {
+#ifdef OT_DEBUG
+ qDebug("could not select script in gpos table: %d", error);
+#endif
+ return FALSE;
+ }
+
+ }
+ return TRUE;
+}
+
+
+void TQOpenType::selectScript(unsigned int script, const Features *features)
+{
+ if (current_script == script)
+ return;
+
+ assert(script < TQFont::NScripts);
+ // tqfind script in our list of supported scripts.
+ uint tag = ot_scripts[script].tag;
+
+ if (gsub && features) {
+#ifdef OT_DEBUG
+ {
+ TTO_FeatureList featurelist = gsub->FeatureList;
+ int numfeatures = featurelist.FeatureCount;
+ qDebug("gsub table has %d features", numfeatures);
+ for(int i = 0; i < numfeatures; i++) {
+ TTO_FeatureRecord *r = featurelist.FeatureRecord + i;
+ qDebug(" feature '%s'", tag_to_string(r->FeatureTag));
+ }
+ }
+#endif
+ TT_GSUB_Clear_Features(gsub);
+ FT_UShort script_index;
+ FT_Error error = TT_GSUB_Select_Script(gsub, tag, &script_index);
+ if (!error) {
+#ifdef OT_DEBUG
+ qDebug("script %s has script index %d", tag_to_string(script), script_index);
+#endif
+ while (features->tag) {
+ FT_UShort feature_index;
+ error = TT_GSUB_Select_Feature(gsub, features->tag, script_index, 0xffff, &feature_index);
+ if (!error) {
+#ifdef OT_DEBUG
+ qDebug(" adding feature %s", tag_to_string(features->tag));
+#endif
+ TT_GSUB_Add_Feature(gsub, feature_index, features->property);
+ }
+ ++features;
+ }
+ }
+ }
+
+ if (gpos) {
+ TT_GPOS_Clear_Features(gpos);
+ FT_UShort script_index;
+ FT_Error error = TT_GPOS_Select_Script(gpos, tag, &script_index);
+ if (!error) {
+#ifdef OT_DEBUG
+ {
+ TTO_FeatureList featurelist = gpos->FeatureList;
+ int numfeatures = featurelist.FeatureCount;
+ qDebug("gpos table has %d features", numfeatures);
+ for(int i = 0; i < numfeatures; i++) {
+ TTO_FeatureRecord *r = featurelist.FeatureRecord + i;
+ FT_UShort feature_index;
+ TT_GPOS_Select_Feature(gpos, r->FeatureTag, script_index, 0xffff, &feature_index);
+ qDebug(" feature '%s'", tag_to_string(r->FeatureTag));
+ }
+ }
+#endif
+ FT_ULong *feature_tag_list;
+ error = TT_GPOS_Query_Features(gpos, script_index, 0xffff, &feature_tag_list);
+ if (!error) {
+ while (*feature_tag_list) {
+ FT_UShort feature_index;
+ error = TT_GPOS_Select_Feature(gpos, *feature_tag_list, script_index, 0xffff, &feature_index);
+ if (!error)
+ TT_GPOS_Add_Feature(gpos, feature_index, PositioningProperties);
+ ++feature_tag_list;
+ }
+ }
+ }
+ }
+
+ current_script = script;
+}
+
+#ifdef OT_DEBUG
+static void dump_string(OTL_Buffer buffer)
+{
+ for (uint i = 0; i < buffer->in_length; ++i) {
+ qDebug(" %x: cluster=%d", buffer->in_string[i].gindex, buffer->in_string[i].cluster);
+ }
+}
+#endif
+
+extern void qt_heuristicPosition(TQShaperItem *item);
+
+bool TQOpenType::tqshape(TQShaperItem *item, const unsigned int *properties)
+{
+ length = item->num_glyphs;
+
+ otl_buffer_clear(otl_buffer);
+
+ tmpAttributes = (GlyphAttributes *) realloc(tmpAttributes, length*sizeof(GlyphAttributes));
+ tmpLogClusters = (unsigned int *) realloc(tmpLogClusters, length*sizeof(unsigned int));
+ for (int i = 0; i < length; ++i) {
+ otl_buffer_add_glyph(otl_buffer, item->glyphs[i], properties ? properties[i] : 0, i);
+ tmpAttributes[i] = item->attributes[i];
+ tmpLogClusters[i] = item->log_clusters[i];
+ }
+
+#ifdef OT_DEBUG
+ qDebug("-----------------------------------------");
+// qDebug("log clusters before shaping:");
+// for (int j = 0; j < length; j++)
+// qDebug(" log[%d] = %d", j, item->log_clusters[j]);
+ qDebug("original glyphs: %p", item->glyphs);
+ for (int i = 0; i < length; ++i)
+ qDebug(" glyph=%4x", otl_buffer->in_string[i].gindex);
+// dump_string(otl_buffer);
+#endif
+
+ loadFlags = FT_LOAD_DEFAULT;
+
+ if (gsub) {
+ uint error = TT_GSUB_Apply_String(gsub, otl_buffer);
+ if (error && error != TTO_Err_Not_Covered)
+ return false;
+ }
+
+#ifdef OT_DEBUG
+// qDebug("log clusters before shaping:");
+// for (int j = 0; j < length; j++)
+// qDebug(" log[%d] = %d", j, item->log_clusters[j]);
+ qDebug("tqshaped glyphs:");
+ for (int i = 0; i < length; ++i)
+ qDebug(" glyph=%4x", otl_buffer->in_string[i].gindex);
+ qDebug("-----------------------------------------");
+// dump_string(otl_buffer);
+#endif
+
+ return true;
+}
+
+bool TQOpenType::positionAndAdd(TQShaperItem *item, bool doLogClusters)
+{
+ if (gpos) {
+#ifdef TQ_WS_X11
+ TQ_ASSERT(fontEngine->type() == TQFontEngine::Xft);
+ face = lockFTFace(static_cast<TQFontEngineXft *>(fontEngine)->font());
+#endif
+ memset(otl_buffer->positions, 0, otl_buffer->in_length*sizeof(OTL_PositionRec));
+ // #### check that passing "FALSE,FALSE" is correct
+ TT_GPOS_Apply_String(face, gpos, loadFlags, otl_buffer, FALSE, FALSE);
+#ifdef TQ_WS_X11
+ unlockFTFace(static_cast<TQFontEngineXft *>(fontEngine)->font());
+#endif
+ }
+
+ // make sure we have enough space to write everything back
+ if (item->num_glyphs < (int)otl_buffer->in_length) {
+ item->num_glyphs = otl_buffer->in_length;
+ return FALSE;
+ }
+
+ for (unsigned int i = 0; i < otl_buffer->in_length; ++i) {
+ item->glyphs[i] = otl_buffer->in_string[i].gindex;
+ item->attributes[i] = tmpAttributes[otl_buffer->in_string[i].cluster];
+ if (i && otl_buffer->in_string[i].cluster == otl_buffer->in_string[i-1].cluster)
+ item->attributes[i].clusterStart = FALSE;
+ }
+ item->num_glyphs = otl_buffer->in_length;
+
+ if (doLogClusters) {
+ // we can't do this for indic, as we pass the stuf in syllables and it's easier to do it in the tqshaper.
+ unsigned short *logClusters = item->log_clusters;
+ int clusterStart = 0;
+ int oldCi = 0;
+ for (unsigned int i = 0; i < otl_buffer->in_length; ++i) {
+ int ci = otl_buffer->in_string[i].cluster;
+ // qDebug(" ci[%d] = %d mark=%d, cmb=%d, cs=%d",
+ // i, ci, glyphAttributes[i].mark, glyphAttributes[i].combiningClass, glyphAttributes[i].clusterStart);
+ if (!item->attributes[i].mark && item->attributes[i].clusterStart && ci != oldCi) {
+ for (int j = oldCi; j < ci; j++)
+ logClusters[j] = clusterStart;
+ clusterStart = i;
+ oldCi = ci;
+ }
+ }
+ for (int j = oldCi; j < length; j++)
+ logClusters[j] = clusterStart;
+ }
+
+ // calulate the advances for the tqshaped glyphs
+// qDebug("unpositioned: ");
+ static_cast<TQFontEngineXft *>(item->font)->recalcAdvances(item->num_glyphs, item->glyphs, item->advances);
+
+ // positioning code:
+ if (gpos) {
+ float scale = item->font->scale();
+ OTL_Position positions = otl_buffer->positions;
+
+// qDebug("positioned glyphs:");
+ for (unsigned int i = 0; i < otl_buffer->in_length; i++) {
+// qDebug(" %d:\t orig advance: (%d/%d)\tadv=(%d/%d)\tpos=(%d/%d)\tback=%d\tnew_advance=%d", i,
+// glyphs[i].advance.x.toInt(), glyphs[i].advance.y.toInt(),
+// (int)(positions[i].x_advance >> 6), (int)(positions[i].y_advance >> 6),
+// (int)(positions[i].x_pos >> 6), (int)(positions[i].y_pos >> 6),
+// positions[i].back, positions[i].new_advance);
+ // ###### fix the case where we have y advances. How do we handle this in Uniscribe?????
+ if (positions[i].new_advance) {
+ item->advances[i] = item->flags & TQTextEngine::RightToLeft
+ ? -tqRound((positions[i].x_advance >> 6)*scale)
+ : tqRound((positions[i].x_advance >> 6)*scale);
+ } else {
+ item->advances[i] += item->flags & TQTextEngine::RightToLeft
+ ? -tqRound((positions[i].x_advance >> 6)*scale)
+ : tqRound((positions[i].x_advance >> 6)*scale);
+ }
+ int back = 0;
+ item->offsets[i].x = tqRound((positions[i].x_pos >> 6)*scale);
+ item->offsets[i].y = tqRound((positions[i].y_pos >> 6)*scale);
+ while (positions[i-back].back) {
+ back += positions[i - back].back;
+ item->offsets[i].x += tqRound((positions[i - back].x_pos >> 6)*scale);
+ item->offsets[i].y += tqRound((positions[i - back].y_pos >> 6)*scale);
+ }
+ item->offsets[i].y = -item->offsets[i].y;
+ back = positions[i].back;
+ if (item->flags & TQTextEngine::RightToLeft) {
+ while (back--) {
+ item->offsets[i].x -= item->advances[i-back];
+ }
+ } else {
+ while (back) {
+ item->offsets[i].x -= item->advances[i-back];
+ --back;
+ }
+ }
+// qDebug(" ->\tadv=%d\tpos=(%d/%d)",
+// glyphs[i].advance.x.toInt(), glyphs[i].offset.x.toInt(), glyphs[i].offset.y.toInt());
+ }
+ item->has_positioning = TRUE;
+ } else {
+ qt_heuristicPosition(item);
+ }
+
+#ifdef OT_DEBUG
+// if (doLogClusters) {
+// qDebug("log clusters after shaping:");
+// for (int j = 0; j < length; j++)
+// qDebug(" log[%d] = %d", j, item->log_clusters[j]);
+// }
+ qDebug("final glyphs:");
+ for (int i = 0; i < (int)otl_buffer->in_length; ++i)
+ qDebug(" glyph=%4x char_index=%d mark: %d cmp: %d, clusterStart: %d advance=%d offset=%d/%d",
+ item->glyphs[i], otl_buffer->in_string[i].cluster, item->attributes[i].mark,
+ item->attributes[i].combiningClass, item->attributes[i].clusterStart,
+ item->advances[i],
+ item->offsets[i].x, item->offsets[i].y);
+ qDebug("-----------------------------------------");
+#endif
+ return TRUE;
+}
+
+#endif
+
+#endif // USE_QT4 \ No newline at end of file