src/gui/text/qfontengine_x11.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.
00004 **
00005 ** This file is part of the QtGui module of the Qt Toolkit.
00006 **
00007 ** This file may be used under the terms of the GNU General Public
00008 ** License version 2.0 as published by the Free Software Foundation
00009 ** and appearing in the file LICENSE.GPL included in the packaging of
00010 ** this file.  Please review the following information to ensure GNU
00011 ** General Public Licensing requirements will be met:
00012 ** http://www.trolltech.com/products/qt/opensource.html
00013 **
00014 ** If you are unsure which license is appropriate for your use, please
00015 ** review the following information:
00016 ** http://www.trolltech.com/products/qt/licensing.html or contact the
00017 ** sales department at sales@trolltech.com.
00018 **
00019 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021 **
00022 ****************************************************************************/
00023 
00024 #include "qbitmap.h"
00025 
00026 // #define FONTENGINE_DEBUG
00027 
00028 #include <qbytearray.h>
00029 #include <qdebug.h>
00030 #include <qtextcodec.h>
00031 
00032 #include "qfontdatabase.h"
00033 #include "qpaintdevice.h"
00034 #include "qpainter.h"
00035 #include "qvarlengtharray.h"
00036 #include "qwidget.h"
00037 #include "qsettings.h"
00038 #include "qfile.h"
00039 #include "qabstractfileengine.h"
00040 
00041 #include <private/qpaintengine_x11_p.h>
00042 #include "qfont.h"
00043 #include "qfont_p.h"
00044 #include "qfontengine_p.h"
00045 #include "qopentype_p.h"
00046 #include <qhash.h>
00047 
00048 #include <private/qpainter_p.h>
00049 #include <private/qunicodetables_p.h>
00050 #include <private/qpdf_p.h>
00051 
00052 #include <private/qt_x11_p.h>
00053 #include "qx11info_x11.h"
00054 
00055 #include <math.h>
00056 #include <limits.h>
00057 
00058 #ifndef QT_NO_FREETYPE
00059 
00060 #include <ft2build.h>
00061 #include FT_FREETYPE_H
00062 #include FT_OUTLINE_H
00063 #include FT_TRUETYPE_TABLES_H
00064 #include FT_TYPE1_TABLES_H
00065 #include FT_GLYPH_H
00066 
00067 /*
00068  * Freetype 2.1.7 and earlier used width/height
00069  * for matching sizes in the BDF and PCF loaders.
00070  * This has been fixed for 2.1.8.
00071  */
00072 #if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20105
00073 #define X_SIZE(face,i) ((face)->available_sizes[i].x_ppem)
00074 #define Y_SIZE(face,i) ((face)->available_sizes[i].y_ppem)
00075 #else
00076 #define X_SIZE(face,i) ((face)->available_sizes[i].width << 6)
00077 #define Y_SIZE(face,i) ((face)->available_sizes[i].height << 6)
00078 #endif
00079 
00080 #define FLOOR(x)    ((x) & -64)
00081 #define CEIL(x)     (((x)+63) & -64)
00082 #define TRUNC(x)    ((x) >> 6)
00083 #define ROUND(x)    (((x)+32) & -64)
00084 
00085 
00086 // -------------------------- Freetype support ------------------------------
00087 
00088 struct QFreetypeFace
00089 {
00090     void computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing);
00091     QFontEngine::Properties properties() const;
00092     QByteArray getSfntTable(uint tag) const;
00093 
00094     static QFreetypeFace *getFace(const QFontEngine::FaceId &face_id);
00095     void release(const QFontEngine::FaceId &face_id);
00096 
00097     void lock() {
00098         Q_ASSERT(_lock == 0);
00099         while (!_lock.testAndSet(0, 1))
00100             usleep(100);
00101     }
00102     void unlock() {
00103         if (!_lock.testAndSet(1, 0))
00104             Q_ASSERT(false);
00105     }
00106 
00107     FT_Face face;
00108 #ifndef QT_NO_FONTCONFIG
00109     FcCharSet *charset;
00110 #endif
00111     int xsize; // 26.6
00112     int ysize; // 26.6
00113     FT_Matrix matrix;
00114     FT_CharMap unicode_map;
00115     FT_CharMap symbol_map;
00116 
00117     enum { cmapCacheSize = 0x200 };
00118     glyph_t cmapCache[cmapCacheSize];
00119 
00120     int fsType() const;
00121 
00122 private:
00123     QFreetypeFace() {}
00124     ~QFreetypeFace() {}
00125     QAtomic ref;
00126     QAtomic _lock;
00127     QByteArray fontData;
00128 };
00129 
00130 static FT_Library library = 0;
00131 FT_Library qt_getFreetype()
00132 {
00133     if (!library)
00134         FT_Init_FreeType(&library);
00135     return library;
00136 }
00137 static QHash<QFontEngine::FaceId, QFreetypeFace *> *freetypeFaces = 0;
00138 
00139 int QFreetypeFace::fsType() const
00140 {
00141     int fsType = 0;
00142     TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
00143     if (os2)
00144         fsType = os2->fsType;
00145     return fsType;
00146 }
00147 
00148 QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id)
00149 {
00150     if (face_id.filename.isEmpty())
00151         return 0;
00152 
00153     if (!library)
00154         FT_Init_FreeType(&library);
00155     if (!freetypeFaces)
00156         freetypeFaces = new QHash<QFontEngine::FaceId, QFreetypeFace *>();
00157 
00158     QFreetypeFace *freetype = freetypeFaces->value(face_id, 0);
00159     if (!freetype) {
00160         freetype = new QFreetypeFace;
00161         FT_Face face;
00162         QFile file(QString::fromUtf8(face_id.filename));
00163         if (face_id.filename.startsWith(":qmemoryfonts/")) {
00164             // from qfontdatabase_x11.cpp
00165             extern QByteArray qt_fontdata_from_index(int);
00166             QByteArray idx = face_id.filename;
00167             idx.remove(0, 14); // remove ':qmemoryfonts/'
00168             bool ok = false;
00169             freetype->fontData = qt_fontdata_from_index(idx.toInt(&ok));
00170             if (!ok)
00171                 freetype->fontData = QByteArray();
00172         } else if (!(file.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) {
00173             if (!file.open(QIODevice::ReadOnly)) {
00174                 delete freetype;
00175                 return 0;
00176             }
00177             freetype->fontData = file.readAll();
00178         }
00179         if (!freetype->fontData.isEmpty()) {
00180             if (FT_New_Memory_Face(library, (const FT_Byte *)freetype->fontData.constData(), freetype->fontData.size(), face_id.index, &face)) {
00181                 delete freetype;
00182                 return 0;
00183             }
00184         } else if (FT_New_Face(library, face_id.filename, face_id.index, &face)) {
00185             delete freetype;
00186             return 0;
00187         }
00188         freetype->face = face;
00189         freetype->ref = 0;
00190         freetype->_lock = 0;
00191         freetype->xsize = 0;
00192         freetype->ysize = 0;
00193         freetype->matrix.xx = 0x10000;
00194         freetype->matrix.yy = 0x10000;
00195         freetype->matrix.xy = 0;
00196         freetype->matrix.yx = 0;
00197         freetype->unicode_map = 0;
00198         freetype->symbol_map = 0;
00199 #ifndef QT_NO_FONTCONFIG
00200         freetype->charset = 0;
00201 #endif
00202 
00203         memset(freetype->cmapCache, 0, sizeof(freetype->cmapCache));
00204 
00205         for (int i = 0; i < freetype->face->num_charmaps; ++i) {
00206             FT_CharMap cm = freetype->face->charmaps[i];
00207             switch(cm->encoding) {
00208             case ft_encoding_unicode:
00209                 freetype->unicode_map = cm;
00210                 break;
00211             case ft_encoding_apple_roman:
00212             case ft_encoding_latin_1:
00213                 if (!freetype->unicode_map || freetype->unicode_map->encoding != ft_encoding_unicode)
00214                     freetype->unicode_map = cm;
00215                 break;
00216             case ft_encoding_adobe_custom:
00217             case ft_encoding_symbol:
00218                 if (!freetype->symbol_map)
00219                     freetype->symbol_map = cm;
00220                 break;
00221             default:
00222                 break;
00223             }
00224         }
00225 
00226         if (!FT_IS_SCALABLE(freetype->face) && freetype->face->num_fixed_sizes == 1)
00227             FT_Set_Char_Size (face, X_SIZE(freetype->face, 0), Y_SIZE(freetype->face, 0), 0, 0);
00228 # if 0
00229         FcChar8 *name;
00230         FcPatternGetString(pattern, FC_FAMILY, 0, &name);
00231         qDebug("%s: using maps: default: %x unicode: %x, symbol: %x", name,
00232                freetype->face->charmap ? freetype->face->charmap->encoding : 0,
00233                freetype->unicode_map ? freetype->unicode_map->encoding : 0,
00234                freetype->symbol_map ? freetype->symbol_map->encoding : 0);
00235 
00236         for (int i = 0; i < 256; i += 8)
00237             qDebug("    %x: %d %d %d %d %d %d %d %d", i,
00238                    FcCharSetHasChar(freetype->charset, i), FcCharSetHasChar(freetype->charset, i),
00239                    FcCharSetHasChar(freetype->charset, i), FcCharSetHasChar(freetype->charset, i),
00240                    FcCharSetHasChar(freetype->charset, i), FcCharSetHasChar(freetype->charset, i),
00241                    FcCharSetHasChar(freetype->charset, i), FcCharSetHasChar(freetype->charset, i));
00242 #endif
00243 
00244         FT_Set_Charmap(freetype->face, freetype->unicode_map);
00245         freetypeFaces->insert(face_id, freetype);
00246     }
00247     freetype->ref.ref();
00248     return freetype;
00249 }
00250 
00251 void QFreetypeFace::release(const QFontEngine::FaceId &face_id)
00252 {
00253     if (!ref.deref()) {
00254         FT_Done_Face(face);
00255 #ifndef QT_NO_FONTCONFIG
00256         if (charset)
00257             FcCharSetDestroy(charset);
00258 #endif
00259         freetypeFaces->take(face_id);
00260         delete this;
00261     }
00262     if (!freetypeFaces->size()) {
00263         delete freetypeFaces;
00264         freetypeFaces = 0;
00265         FT_Done_FreeType(library);
00266         library = 0;
00267     }
00268 }
00269 
00270 
00271 void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing)
00272 {
00273     *ysize = fontDef.pixelSize << 6;
00274     *xsize = *ysize * fontDef.stretch / 100;
00275     *outline_drawing = false;
00276 
00277     /*
00278      * Bitmap only faces must match exactly, so find the closest
00279      * one (height dominant search)
00280      */
00281     if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) {
00282         int best = 0;
00283         for (int i = 1; i < face->num_fixed_sizes; i++) {
00284             if (qAbs(*ysize -  Y_SIZE(face,i)) <
00285                 qAbs (*ysize - Y_SIZE(face, best)) ||
00286                 (qAbs (*ysize - Y_SIZE(face, i)) ==
00287                  qAbs (*ysize - Y_SIZE(face, best)) &&
00288                  qAbs (*xsize - X_SIZE(face, i)) <
00289                  qAbs (*xsize - X_SIZE(face, best)))) {
00290                 best = i;
00291             }
00292         }
00293         if (FT_Set_Char_Size (face, X_SIZE(face, best), Y_SIZE(face, best), 0, 0) == 0) {
00294             *xsize = X_SIZE(face, best);
00295             *ysize = Y_SIZE(face, best);
00296         } else
00297             *xsize = *ysize = 0;
00298     } else {
00299         *outline_drawing = (*xsize > (64<<6) || *ysize > (64<<6));
00300     }
00301 }
00302 
00303 QFontEngine::Properties QFreetypeFace::properties() const
00304 {
00305     QFontEngine::Properties p;
00306     p.postscriptName = FT_Get_Postscript_Name(face);
00307     PS_FontInfoRec font_info;
00308     if (FT_Get_PS_Font_Info(face, &font_info) == 0)
00309         p.copyright = font_info.notice;
00310     if (FT_IS_SCALABLE(face)) {
00311         p.ascent = face->ascender;
00312         p.descent = -face->descender;
00313         p.leading = face->height - face->ascender + face->descender;
00314         p.emSquare = face->units_per_EM;
00315         p.boundingBox = QRectF(face->bbox.xMin, -face->bbox.yMax,
00316                                face->bbox.xMax - face->bbox.xMin,
00317                                face->bbox.yMax - face->bbox.yMin);
00318     } else {
00319         p.ascent = QFixed::fromFixed(face->size->metrics.ascender);
00320         p.descent = QFixed::fromFixed(-face->size->metrics.descender);
00321         p.leading = QFixed::fromFixed(face->size->metrics.height - face->size->metrics.ascender + face->size->metrics.descender);
00322         p.emSquare = face->size->metrics.y_ppem;
00323         p.boundingBox = QRectF(-p.ascent.toReal(), 0, (p.ascent + p.descent).toReal(), face->size->metrics.max_advance/64.);
00324     }
00325     p.italicAngle = 0;
00326     p.capHeight = p.ascent;
00327     p.lineWidth = face->underline_thickness;
00328     return p;
00329 }
00330 
00331 QByteArray QFreetypeFace::getSfntTable(uint tag) const
00332 {
00333     QByteArray table;
00334 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
00335     if (FT_IS_SFNT(face)) {
00336         FT_ULong length = 0;
00337         FT_Load_Sfnt_Table(face, tag, 0, 0, &length);
00338         if (length != 0) {
00339             table.resize(length);
00340             FT_Load_Sfnt_Table(face, tag, 0, (FT_Byte *)table.data(), &length);
00341         }
00342     }
00343 #endif
00344     return table;
00345 }
00346 
00347 static void addGlyphToPath(FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, bool no_scale = false)
00348 {
00349     qreal factor = no_scale ? 1. : 1./64.;
00350 
00351     QPointF cp = point.toPointF();
00352 
00353     // convert the outline to a painter path
00354     int i = 0;
00355     for (int j = 0; j < g->outline.n_contours; ++j) {
00356         int last_point = g->outline.contours[j];
00357         QPointF start = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
00358         if(!(g->outline.tags[i] & 1)) {
00359             start += cp + QPointF(g->outline.points[last_point].x*factor, -g->outline.points[last_point].y*factor);
00360             start /= 2;
00361         }
00362 //                 qDebug("contour: %d -- %d", i, g->outline.contours[c]);
00363 //                 qDebug("first point at %f %f", start.x(), start.y());
00364         path->moveTo(start);
00365 
00366         QPointF c[4];
00367         c[0] = start;
00368         int n = 1;
00369         while (i < last_point) {
00370             ++i;
00371             c[n] = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
00372 //                     qDebug() << "    i=" << i << " flag=" << (int)g->outline.tags[i] << "point=" << c[n];
00373             ++n;
00374             switch (g->outline.tags[i] & 3) {
00375             case 2:
00376                 // cubic bezier element
00377                 if (n < 4)
00378                     continue;
00379                 c[3] = (c[3] + c[2])/2;
00380                 --i;
00381                 break;
00382             case 0:
00383                 // quadratic bezier element
00384                 if (n < 3)
00385                     continue;
00386                 c[3] = (c[1] + c[2])/2;
00387                 c[2] = (2*c[1] + c[3])/3;
00388                 c[1] = (2*c[1] + c[0])/3;
00389                 --i;
00390                 break;
00391             case 1:
00392             case 3:
00393                 if (n == 2) {
00394 //                             qDebug() << "lineTo" << c[1];
00395                     path->lineTo(c[1]);
00396                     c[0] = c[1];
00397                     n = 1;
00398                     continue;
00399                 } else if (n == 3) {
00400                     c[3] = c[2];
00401                     c[2] = (2*c[1] + c[3])/3;
00402                     c[1] = (2*c[1] + c[0])/3;
00403                 }
00404                 break;
00405             }
00406 //                     qDebug() << "cubicTo" << c[1] << c[2] << c[3];
00407             path->cubicTo(c[1], c[2], c[3]);
00408             c[0] = c[3];
00409             n = 1;
00410         }
00411         if (n == 1) {
00412 //                     qDebug() << "closeSubpath";
00413             path->closeSubpath();
00414         } else {
00415             c[3] = start;
00416             if (n == 2) {
00417                 c[2] = (2*c[1] + c[3])/3;
00418                 c[1] = (2*c[1] + c[0])/3;
00419             }
00420 //                     qDebug() << "cubicTo" << c[1] << c[2] << c[3];
00421             path->cubicTo(c[1], c[2], c[3]);
00422         }
00423         ++i;
00424     }
00425 }
00426 
00427 extern void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path);
00428 
00429 static void addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path, bool = false)
00430 {
00431     if (slot->format != FT_GLYPH_FORMAT_BITMAP
00432         || slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO)
00433         return;
00434 
00435     QPointF cp = point.toPointF();
00436     qt_addBitmapToPath(cp.x() + TRUNC(slot->metrics.horiBearingX), cp.y() - TRUNC(slot->metrics.horiBearingY),
00437                        slot->bitmap.buffer, slot->bitmap.pitch, slot->bitmap.width, slot->bitmap.rows, path);
00438 }
00439 
00440 #endif // QT_NO_FREETYPE
00441 
00442 
00443 // ------------------------------------------------------------------
00444 // Multi XLFD engine
00445 // ------------------------------------------------------------------
00446 
00447 QFontEngineMultiXLFD::QFontEngineMultiXLFD(const QFontDef &r, const QList<int> &l, int s)
00448     : QFontEngineMulti(l.size()), encodings(l), screen(s), request(r)
00449 {
00450     loadEngine(0);
00451     fontDef = engines[0]->fontDef;
00452 }
00453 
00454 QFontEngineMultiXLFD::~QFontEngineMultiXLFD()
00455 { }
00456 
00457 void QFontEngineMultiXLFD::loadEngine(int at)
00458 {
00459     Q_ASSERT(at < engines.size());
00460     Q_ASSERT(engines.at(at) == 0);
00461     const int encoding = encodings.at(at);
00462     QFontEngine *fontEngine = QFontDatabase::loadXlfd(0, QUnicodeTables::Common, request, encoding);
00463     Q_ASSERT(fontEngine != 0);
00464     fontEngine->ref.ref();
00465     engines[at] = fontEngine;
00466 }
00467 
00468 // ------------------------------------------------------------------
00469 // Xlfd font engine
00470 // ------------------------------------------------------------------
00471 
00472 #ifndef QT_NO_FREETYPE
00473 
00474 static QStringList *qt_fontpath = 0;
00475 
00476 static QStringList fontPath()
00477 {
00478     if (qt_fontpath)
00479         return *qt_fontpath;
00480 
00481     // append qsettings fontpath
00482     QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
00483     settings.beginGroup(QLatin1String("Qt"));
00484 
00485     QStringList fontpath;
00486 
00487     int npaths;
00488     char** font_path;
00489     font_path = XGetFontPath(X11->display, &npaths);
00490     bool xfsconfig_read = false;
00491     for (int i=0; i<npaths; i++) {
00492         // If we're using xfs, append font paths from /etc/X11/fs/config
00493         // can't hurt, and chances are we'll get all fonts that way.
00494         if (((font_path[i])[0] != '/') && !xfsconfig_read) {
00495             // We're using xfs -> read its config
00496             bool finished = false;
00497             QFile f(QLatin1String("/etc/X11/fs/config"));
00498             if (!f.exists())
00499                 f.setFileName(QLatin1String("/usr/X11R6/lib/X11/fs/config"));
00500             if (!f.exists())
00501                 f.setFileName(QLatin1String("/usr/X11/lib/X11/fs/config"));
00502             if (f.exists()) {
00503                 f.open(QIODevice::ReadOnly);
00504                 while (f.error()==QFile::NoError && !finished) {
00505                     QString fs = QString::fromLocal8Bit(f.readLine(1024));
00506                     fs=fs.trimmed();
00507                     if (fs.left(9)==QLatin1String("catalogue") && fs.contains(QLatin1Char('='))) {
00508                         fs = fs.mid(fs.indexOf(QLatin1Char('=')) + 1).trimmed();
00509                         bool end = false;
00510                         while (f.error()==QFile::NoError && !end) {
00511                             if (fs[int(fs.length())-1] == QLatin1Char(','))
00512                                 fs = fs.left(fs.length()-1);
00513                             else
00514                                 end = true;
00515 
00516                             fs = fs.left(fs.indexOf(QLatin1String(":unscaled")));
00517                             if (fs[0] != QLatin1Char('#'))
00518                                 fontpath += fs;
00519                             fs = QLatin1String(f.readLine(1024));
00520                             fs = fs.trimmed();
00521                             if (fs.isEmpty())
00522                                 end = true;
00523                         }
00524                         finished = true;
00525                     }
00526                 }
00527                 f.close();
00528             }
00529             xfsconfig_read = true;
00530         } else {
00531             QString fs = QString::fromLocal8Bit(font_path[i]);
00532             fontpath += fs.left(fs.indexOf(QLatin1String(":unscaled")));
00533         }
00534     }
00535     XFreeFontPath(font_path);
00536 
00537     // append qsettings fontpath
00538     QStringList fp = settings.value(QLatin1String("fontPath")).toStringList();
00539     if (!fp.isEmpty())
00540         fontpath += fp;
00541 
00542     qt_fontpath = new QStringList(fontpath);
00543     return fontpath;
00544 }
00545 
00546 static QFontEngine::FaceId fontFile(const QByteArray &_xname, QFreetypeFace **freetype, int *synth)
00547 {
00548     *freetype = 0;
00549     *synth = 0;
00550 
00551     QByteArray xname = _xname.toLower();
00552 
00553     int pos = 0;
00554     int minus = 0;
00555     while (minus < 5 && (pos = xname.indexOf('-', pos + 1)))
00556         ++minus;
00557     QByteArray searchname = xname.left(pos);
00558     while (minus < 12 && (pos = xname.indexOf('-', pos + 1)))
00559         ++minus;
00560     QByteArray encoding = xname.mid(pos + 1);
00561     //qDebug("xname='%s', searchname='%s', encoding='%s'", xname.data(), searchname.data(), encoding.data());
00562     QStringList fontpath = ::fontPath();
00563     QFontEngine::FaceId face_id;
00564     face_id.index = 0;
00565 
00566     QByteArray best_mapping;
00567 
00568     for (QStringList::ConstIterator it = fontpath.constBegin(); it != fontpath.constEnd(); ++it) {
00569         if ((*it).left(1) != QLatin1String("/"))
00570             continue; // not a path name, a font server
00571         QString fontmapname;
00572         int num = 0;
00573         // search font.dir and font.scale for the right file
00574         while (num < 2) {
00575             if (num == 0)
00576                 fontmapname = (*it) + QLatin1String("/fonts.scale");
00577             else
00578                 fontmapname = (*it) + QLatin1String("/fonts.dir");
00579             ++num;
00580             //qWarning(fontmapname);
00581             QFile fontmap(fontmapname);
00582             if (!fontmap.open(QIODevice::ReadOnly))
00583                 continue;
00584             while (!fontmap.atEnd()) {
00585                 QByteArray mapping = fontmap.readLine();
00586                 QByteArray lmapping = mapping.toLower();
00587 
00588                 //qWarning(xfontname);
00589                 //qWarning(mapping);
00590                 if (!lmapping.contains(searchname))
00591                     continue;
00592                 int index = mapping.indexOf(' ');
00593                 QByteArray ffn = mapping.mid(0,index);
00594                 // remove bitmap formats freetype can't handle
00595                 if (ffn.contains(".spd") || ffn.contains(".phont"))
00596                     continue;
00597                 bool best_match = false;
00598                 if (!best_mapping.isEmpty()) {
00599                     if (lmapping.contains("-0-0-0-0-")) { // scalable font
00600                         best_match = true;
00601                         goto found;
00602                     }
00603                     if (lmapping.contains(encoding) && !best_mapping.toLower().contains(encoding))
00604                         goto found;
00605                     continue;
00606                 }
00607 
00608             found:
00609                 int colon = ffn.lastIndexOf(':');
00610                 if (colon != -1) {
00611                     QByteArray s = ffn.left(colon);
00612                     ffn = ffn.mid(colon + 1);
00613                     if (s.contains("ds="))
00614                         *synth |= QFontEngine::SynthesizedBold;
00615                     if (s.contains("ai="))
00616                         *synth |= QFontEngine::SynthesizedItalic;
00617                 }
00618                 face_id.filename = (*it).toLocal8Bit() + '/' + ffn;
00619                 best_mapping = mapping;
00620                 if (best_match)
00621                     goto end;
00622             }
00623         }
00624     }
00625 end:
00626 //     qDebug("fontfile for %s is from '%s'\n    got %s synth=%d", xname.data(),
00627 //            best_mapping.data(), face_id.filename.data(), *synth);
00628     *freetype = QFreetypeFace::getFace(face_id);
00629     if (!*freetype) {
00630         face_id.index = 0;
00631         face_id.filename = QByteArray();
00632     }
00633     return face_id;
00634 }
00635 
00636 #endif // QT_NO_FREETYPE
00637 
00638 // defined in qfontdatabase_x11.cpp
00639 extern int qt_mib_for_xlfd_encoding(const char *encoding);
00640 extern int qt_xlfd_encoding_id(const char *encoding);
00641 
00642 static inline XCharStruct *charStruct(XFontStruct *xfs, uint ch)
00643 {
00644     XCharStruct *xcs = 0;
00645     unsigned char r = ch>>8;
00646     unsigned char c = ch&0xff;
00647     if (xfs->per_char &&
00648          r >= xfs->min_byte1 &&
00649          r <= xfs->max_byte1 &&
00650          c >= xfs->min_char_or_byte2 &&
00651          c <= xfs->max_char_or_byte2) {
00652         xcs = xfs->per_char + ((r - xfs->min_byte1) *
00653                                (xfs->max_char_or_byte2 -
00654                                 xfs->min_char_or_byte2 + 1)) +
00655               (c - xfs->min_char_or_byte2);
00656         if (xcs->width == 0 && xcs->ascent == 0 &&  xcs->descent == 0)
00657             xcs = 0;
00658     }
00659     return xcs;
00660 }
00661 
00662 QFontEngineXLFD::QFontEngineXLFD(XFontStruct *fs, const QByteArray &name, int mib)
00663     : _fs(fs), _name(name), _codec(0), _cmap(mib)
00664 {
00665     if (_cmap) _codec = QTextCodec::codecForMib(_cmap);
00666 
00667     cache_cost = (((fs->max_byte1 - fs->min_byte1) *
00668                    (fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1)) +
00669                   fs->max_char_or_byte2 - fs->min_char_or_byte2);
00670     cache_cost = ((fs->max_bounds.ascent + fs->max_bounds.descent) *
00671                   (fs->max_bounds.width * cache_cost / 8));
00672     lbearing = SHRT_MIN;
00673     rbearing = SHRT_MIN;
00674     face_id.index = -1;
00675     freetype = 0;
00676     synth = 0;
00677 }
00678 
00679 QFontEngineXLFD::~QFontEngineXLFD()
00680 {
00681     XFreeFont(QX11Info::display(), _fs);
00682     _fs = 0;
00683 #ifndef QT_NO_FREETYPE
00684     if (freetype)
00685         freetype->release(face_id);
00686 #endif
00687 }
00688 
00689 bool QFontEngineXLFD::stringToCMap(const QChar *s, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
00690 {
00691     if (*nglyphs < len) {
00692         *nglyphs = len;
00693         return false;
00694     }
00695 
00696     // filter out surrogates, we can't handle them anyway with XLFD fonts
00697     QVarLengthArray<ushort> _s(len);
00698     QChar *str = (QChar *)_s.data();
00699     for (int i = 0; i < len; ++i) {
00700         if (i < len - 1
00701             && s[i].unicode() >= 0xd800 && s[i].unicode() < 0xdc00
00702             && s[i+1].unicode() >= 0xdc00 && s[i].unicode() < 0xe000) {
00703             *str = QChar();
00704             ++i;
00705         } else {
00706             *str = s[i];
00707         }
00708         ++str;
00709     }
00710 
00711     len = str - (QChar *)_s.data();
00712     str = (QChar *)_s.data();
00713 
00714     bool mirrored = flags & QTextEngine::RightToLeft;
00715     if (_codec) {
00716         bool haveNbsp = false;
00717         for (int i = 0; i < len; i++)
00718             if (str[i].unicode() == 0xa0) {
00719                 haveNbsp = true;
00720                 break;
00721             }
00722 
00723         QVarLengthArray<unsigned short> ch(len);
00724         QChar *chars = (QChar *)ch.data();
00725         if (haveNbsp || mirrored) {
00726             for (int i = 0; i < len; i++)
00727                 chars[i] = (str[i].unicode() == 0xa0 ? 0x20 :
00728                             (mirrored ? QUnicodeTables::mirroredChar(str[i]).unicode() : str[i].unicode()));
00729         } else {
00730             for (int i = 0; i < len; i++)
00731                 chars[i] = str[i].unicode();
00732         }
00733         QTextCodec::ConverterState state;
00734         state.flags = QTextCodec::ConvertInvalidToNull;
00735         QByteArray ba = _codec->fromUnicode(chars, len, &state);
00736         if (ba.length() == 2*len) {
00737             // double byte encoding
00738             const uchar *data = (const uchar *)ba.constData();
00739             for (int i = 0; i < len; i++) {
00740                 glyphs[i].glyph = ((ushort)data[0] << 8) + data[1];
00741                 data += 2;
00742             }
00743         } else {
00744             const uchar *data = (const uchar *)ba.constData();
00745             for (int i = 0; i < len; i++)
00746                 glyphs[i].glyph = (ushort)data[i];
00747         }
00748     } else {
00749         QGlyphLayout *g = glyphs + len;
00750         const QChar *c = str + len;
00751         if (mirrored) {
00752             while (c != str)
00753                 (--g)->glyph = (--c)->unicode() == 0xa0 ? 0x20 : QUnicodeTables::mirroredChar(*c).unicode();
00754         } else {
00755             while (c != str)
00756                 (--g)->glyph = (--c)->unicode() == 0xa0 ? 0x20 : c->unicode();
00757         }
00758     }
00759     *nglyphs = len;
00760 
00761     QGlyphLayout *g = glyphs + len;
00762     XCharStruct *xcs;
00763     // inlined for better perfomance
00764     if (!_fs->per_char) {
00765         xcs = &_fs->min_bounds;
00766         while (g != glyphs) {
00767             --g;
00768             const unsigned char r = g->glyph >> 8;
00769             const unsigned char c = g->glyph & 0xff;
00770             if (r >= _fs->min_byte1 &&
00771                 r <= _fs->max_byte1 &&
00772                 c >= _fs->min_char_or_byte2 &&
00773                 c <= _fs->max_char_or_byte2) {
00774                 g->advance.x = xcs->width;
00775             } else {
00776                 g->glyph = 0;
00777             }
00778         }
00779     }
00780     else if (!_fs->max_byte1) {
00781         XCharStruct *base = _fs->per_char - _fs->min_char_or_byte2;
00782         while (g != glyphs) {
00783             unsigned int gl = (--g)->glyph;
00784             xcs = (gl >= _fs->min_char_or_byte2 && gl <= _fs->max_char_or_byte2) ?
00785                   base + gl : 0;
00786             if (!xcs || (!xcs->width && !xcs->ascent && !xcs->descent)) {
00787                 g->glyph = 0;
00788             } else {
00789                 g->advance.x = xcs->width;
00790             }
00791         }
00792     }
00793     else {
00794         while (g != glyphs) {
00795             xcs = charStruct(_fs, (--g)->glyph);
00796             if (!xcs) {
00797                 g->glyph = 0;
00798             } else {
00799                 g->advance.x = xcs->width;
00800             }
00801         }
00802     }
00803     return true;
00804 }
00805 
00806 glyph_metrics_t QFontEngineXLFD::boundingBox(const QGlyphLayout *glyphs, int numGlyphs)
00807 {
00808     int i;
00809 
00810     glyph_metrics_t overall;
00811     // initialize with line height, we get the same behaviour on all platforms
00812     overall.y = -ascent();
00813     overall.height = ascent() + descent() + 1;
00814     QFixed ymax;
00815     QFixed xmax;
00816     for (i = 0; i < numGlyphs; i++) {
00817         XCharStruct *xcs = charStruct(_fs, glyphs[i].glyph);
00818         if (xcs) {
00819             QFixed x = overall.xoff + glyphs[i].offset.x + xcs->lbearing;
00820             QFixed y = overall.yoff + glyphs[i].offset.y - xcs->ascent;
00821             overall.x = qMin(overall.x, x);
00822             overall.y = qMin(overall.y, y);
00823             xmax = qMax(xmax, overall.xoff + glyphs[i].offset.x + xcs->rbearing);
00824             ymax = qMax(ymax, y + xcs->ascent + xcs->descent);
00825             overall.xoff += glyphs[i].advance.x;
00826         } else {
00827             QFixed size = _fs->ascent;
00828             overall.x = qMin(overall.x, overall.xoff);
00829             overall.y = qMin(overall.y, overall.yoff - size);
00830             ymax = qMax(ymax, overall.yoff);
00831             overall.xoff += size;
00832             xmax = qMax(xmax, overall.xoff);
00833         }
00834     }
00835     overall.height = qMax(overall.height, ymax - overall.y);
00836     overall.width = xmax - overall.x;
00837 
00838     return overall;
00839 }
00840 
00841 glyph_metrics_t QFontEngineXLFD::boundingBox(glyph_t glyph)
00842 {
00843     glyph_metrics_t gm;
00844     XCharStruct *xcs = charStruct(_fs, glyph);
00845     if (xcs) {
00846         gm = glyph_metrics_t(xcs->lbearing, -xcs->ascent, xcs->rbearing- xcs->lbearing, xcs->ascent + xcs->descent,
00847                               xcs->width, 0);
00848     } else {
00849         QFixed size = ascent();
00850         gm = glyph_metrics_t(0, size, size, size, size, 0);
00851     }
00852     return gm;
00853 }
00854 
00855 QFixed QFontEngineXLFD::ascent() const
00856 {
00857     return _fs->ascent;
00858 }
00859 
00860 QFixed QFontEngineXLFD::descent() const
00861 {
00862     return (_fs->descent-1);
00863 }
00864 
00865 QFixed QFontEngineXLFD::leading() const
00866 {
00867     QFixed l = QFixed(qMin<int>(_fs->ascent, _fs->max_bounds.ascent)
00868                       + qMin<int>(_fs->descent, _fs->max_bounds.descent)) * QFixed::fromReal(0.15);
00869     return l.ceil();
00870 }
00871 
00872 qreal QFontEngineXLFD::maxCharWidth() const
00873 {
00874     return _fs->max_bounds.width;
00875 }
00876 
00877 
00878 // Loads the font for the specified script
00879 static inline int maxIndex(XFontStruct *f) {
00880     return (((f->max_byte1 - f->min_byte1) *
00881              (f->max_char_or_byte2 - f->min_char_or_byte2 + 1)) +
00882             f->max_char_or_byte2 - f->min_char_or_byte2);
00883 }
00884 
00885 qreal QFontEngineXLFD::minLeftBearing() const
00886 {
00887     if (lbearing == SHRT_MIN) {
00888         if (_fs->per_char) {
00889             XCharStruct *cs = _fs->per_char;
00890             int nc = maxIndex(_fs) + 1;
00891             int mx = cs->lbearing;
00892 
00893             for (int c = 1; c < nc; c++) {
00894                 // ignore the bearings for characters whose ink is
00895                 // completely outside the normal bounding box
00896                 if ((cs[c].lbearing <= 0 && cs[c].rbearing <= 0) ||
00897                     (cs[c].lbearing >= cs[c].width && cs[c].rbearing >= cs[c].width))
00898                     continue;
00899 
00900                 int nmx = cs[c].lbearing;
00901 
00902                 if (nmx < mx)
00903                     mx = nmx;
00904             }
00905 
00906             ((QFontEngineXLFD *)this)->lbearing = mx;
00907         } else
00908             ((QFontEngineXLFD *)this)->lbearing = _fs->min_bounds.lbearing;
00909     }
00910     return lbearing;
00911 }
00912 
00913 qreal QFontEngineXLFD::minRightBearing() const
00914 {
00915     if (rbearing == SHRT_MIN) {
00916         if (_fs->per_char) {
00917             XCharStruct *cs = _fs->per_char;
00918             int nc = maxIndex(_fs) + 1;
00919             int mx = cs->rbearing;
00920 
00921             for (int c = 1; c < nc; c++) {
00922                 // ignore the bearings for characters whose ink is
00923                 // completely outside the normal bounding box
00924                 if ((cs[c].lbearing <= 0 && cs[c].rbearing <= 0) ||
00925                     (cs[c].lbearing >= cs[c].width && cs[c].rbearing >= cs[c].width))
00926                     continue;
00927 
00928                 int nmx = cs[c].rbearing;
00929 
00930                 if (nmx < mx)
00931                     mx = nmx;
00932             }
00933 
00934             ((QFontEngineXLFD *)this)->rbearing = mx;
00935         } else
00936             ((QFontEngineXLFD *)this)->rbearing = _fs->min_bounds.rbearing;
00937     }
00938     return rbearing;
00939 }
00940 
00941 const char *QFontEngineXLFD::name() const
00942 {
00943     return _name;
00944 }
00945 
00946 bool QFontEngineXLFD::canRender(const QChar *string, int len)
00947 {
00948     QVarLengthArray<QGlyphLayout, 256> glyphs(len);
00949     int nglyphs = len;
00950     if (stringToCMap(string, len, glyphs.data(), &nglyphs, 0) == false) {
00951         glyphs.resize(nglyphs);
00952         stringToCMap(string, len, glyphs.data(), &nglyphs, 0);
00953     }
00954 
00955     bool allExist = true;
00956     for (int i = 0; i < nglyphs; i++) {
00957         if (!glyphs[i].glyph || !charStruct(_fs, glyphs[i].glyph)) {
00958             allExist = false;
00959             break;
00960         }
00961     }
00962 
00963     return allExist;
00964 }
00965 
00966 void QFontEngineXLFD::addOutlineToPath(qreal x, qreal y, const QGlyphLayout *glyphs, int numGlyphs, QPainterPath *path, QTextItem::RenderFlags flags)
00967 {
00968     addBitmapFontToPath(x, y, glyphs, numGlyphs, path, flags);
00969 }
00970 
00971 QFontEngine::FaceId QFontEngineXLFD::faceId() const
00972 {
00973 #ifndef QT_NO_FREETYPE
00974     if (face_id.index == -1) {
00975         face_id = ::fontFile(_name, &freetype, &synth);
00976         if (_codec)
00977             face_id.encoding = _codec->mibEnum();
00978         if (freetype) {
00979             const_cast<QFontEngineXLFD *>(this)->fsType = freetype->fsType();
00980         } else {
00981             QFontEngine::Properties properties = QFontEngine::properties();
00982             face_id.index = 0;
00983             face_id.filename = "-" + properties.postscriptName;
00984         }
00985     }
00986 #endif
00987 
00988     return face_id;
00989 }
00990 
00991 QFontEngine::Properties QFontEngineXLFD::properties() const
00992 {
00993     if (face_id.index == -1)
00994         (void)faceId();
00995 
00996 #ifndef QT_NO_FREETYPE
00997     if (freetype)
00998         return freetype->properties();
00999 #endif
01000     return QFontEngine::properties();
01001 }
01002 
01003 void QFontEngineXLFD::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
01004 {
01005     if (face_id.index == -1)
01006         (void)faceId();
01007 #ifndef QT_NO_FREETYPE
01008     if (!freetype)
01009 #endif
01010     {
01011         QFontEngine::getUnscaledGlyph(glyph, path, metrics);
01012         return;
01013     }
01014 
01015 #ifndef QT_NO_FREETYPE
01016     freetype->lock();
01017 
01018     FT_Face face = freetype->face;
01019     FT_Set_Transform(face, 0, 0);
01020     glyph = glyphIndexToFreetypeGlyphIndex(glyph);
01021     FT_Load_Glyph(face, glyph, FT_LOAD_NO_HINTING|FT_LOAD_NO_BITMAP|FT_LOAD_NO_SCALE);
01022 
01023     int left  = face->glyph->metrics.horiBearingX;
01024     int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
01025     int top    = face->glyph->metrics.horiBearingY;
01026     int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
01027 
01028     QFixedPoint p;
01029     p.x = 0;
01030     p.y = 0;
01031     if (!FT_IS_SCALABLE(freetype->face)) {
01032         metrics->width = QFixed::fromFixed(right-left);
01033         metrics->height = QFixed::fromFixed(top-bottom);
01034         metrics->x = QFixed::fromFixed(left);
01035         metrics->y = QFixed::fromFixed(-top);
01036         metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
01037 
01038         ::addBitmapToPath(face->glyph, p, path);
01039     } else {
01040         metrics->width = right-left;
01041         metrics->height = top-bottom;
01042         metrics->x = left;
01043         metrics->y = -top;
01044         metrics->xoff = face->glyph->advance.x;
01045 
01046         ::addGlyphToPath(face->glyph, p, path, true /* no_scale */);
01047     }
01048     FT_Set_Transform(face, &freetype->matrix, 0);
01049     freetype->unlock();
01050 #endif // QT_NO_FREETYPE
01051 }
01052 
01053 
01054 QByteArray QFontEngineXLFD::getSfntTable(uint tag) const
01055 {
01056 #ifndef QT_NO_FREETYPE
01057     if (face_id.index == -1)
01058         (void)faceId();
01059     if (!freetype)
01060         return QByteArray();
01061     return freetype->getSfntTable(tag);
01062 #else
01063     Q_UNUSED(tag);
01064     return QByteArray();
01065 #endif
01066 }
01067 
01068 int QFontEngineXLFD::synthesized() const
01069 {
01070     return synth;
01071 }
01072 
01073 #ifndef QT_NO_FREETYPE
01074 
01075 FT_Face QFontEngineXLFD::non_locked_face() const
01076 {
01077     return freetype ? freetype->face : 0;
01078 }
01079 
01080 uint QFontEngineXLFD::toUnicode(glyph_t g) const
01081 {
01082     if (_codec) {
01083         QTextCodec::ConverterState state;
01084         state.flags = QTextCodec::ConvertInvalidToNull;
01085         uchar data[2];
01086         int l = 1;
01087         if (g > 255) {
01088             data[0] = (g >> 8);
01089             data[1] = (g & 255);
01090             l = 2;
01091         } else {
01092             data[0] = g;
01093         }
01094         QString s = _codec->toUnicode((char *)data, l, &state);
01095         Q_ASSERT(s.length() == 1);
01096         g = s.at(0).unicode();
01097     }
01098     return g;
01099 }
01100 
01101 glyph_t QFontEngineXLFD::glyphIndexToFreetypeGlyphIndex(glyph_t g) const
01102 {
01103     return FT_Get_Char_Index(freetype->face, toUnicode(g));
01104 }
01105 #endif
01106 
01107 #ifndef QT_NO_FONTCONFIG
01108 
01109 // ------------------------------------------------------------------
01110 // Multi FT engine
01111 // ------------------------------------------------------------------
01112 
01113 static QFontEngine *engineForPattern(FcPattern *pattern, const QFontDef &request,
01114                                      int screen)
01115 {
01116     FcResult res;
01117     FcPattern *match = FcFontMatch(0, pattern, &res);
01118     QFontEngineFT *engine = new QFontEngineFT(match, request, screen);
01119     if (!engine->invalid())
01120         return engine;
01121 
01122     delete engine;
01123     QFontEngine *fe = new QFontEngineBox(request.pixelSize);
01124     fe->fontDef = request;
01125     return fe;
01126 }
01127 
01128 QFontEngineMultiFT::QFontEngineMultiFT(QFontEngine *fe, FcPattern *p, int s, const QFontDef &req)
01129     : QFontEngineMulti(2), request(req), pattern(p), fontSet(0), screen(s)
01130 {
01131 
01132     engines[0] = fe;
01133     engines.at(0)->ref.ref();
01134     fontDef = engines[0]->fontDef;
01135     cache_cost = 100;
01136 }
01137 
01138 QFontEngineMultiFT::~QFontEngineMultiFT()
01139 {
01140     FcPatternDestroy(pattern);
01141     if (fontSet)
01142         FcFontSetDestroy(fontSet);
01143 }
01144 
01145 
01146 void QFontEngineMultiFT::loadEngine(int at)
01147 {
01148     extern void qt_addPatternProps(FcPattern *pattern, int screen, int script,
01149                                    const QFontDef &request);
01150     extern QFontDef qt_FcPatternToQFontDef(FcPattern *pattern, const QFontDef &);
01151     extern FcFontSet *qt_fontSetForPattern(FcPattern *pattern, const QFontDef &request);
01152 
01153     Q_ASSERT(at > 0);
01154     if (!fontSet) {
01155         fontSet = qt_fontSetForPattern(pattern, request);
01156         engines.resize(fontSet->nfont);
01157     }
01158     Q_ASSERT(at < engines.size());
01159     Q_ASSERT(engines.at(at) == 0);
01160 
01161     FcPattern *pattern = FcPatternDuplicate(fontSet->fonts[at]);
01162     qt_addPatternProps(pattern, screen, QUnicodeTables::Common, request);
01163 
01164     QFontDef fontDef = qt_FcPatternToQFontDef(pattern, this->request);
01165 
01166     // note: we use -1 for the script to make sure that we keep real
01167     // FT engines separate from Multi engines in the font cache
01168     QFontCache::Key key(fontDef, -1, screen);
01169     QFontEngine *fontEngine = QFontCache::instance->findEngine(key);
01170     if (!fontEngine) {
01171         FcConfigSubstitute(0, pattern, FcMatchPattern);
01172         FcDefaultSubstitute(pattern);
01173         fontEngine = engineForPattern(pattern, request, screen);
01174         FcPatternDestroy(pattern);
01175         QFontCache::instance->insertEngine(key, fontEngine);
01176     }
01177     fontEngine->ref.ref();
01178     engines[at] = fontEngine;
01179 }
01180 
01181 // ------------------------------------------------------------------
01182 // FT font engine
01183 // ------------------------------------------------------------------
01184 
01185 
01186 QFontEngineFT::Glyph::~Glyph()
01187 {
01188     delete [] data;
01189 }
01190 
01191 static QFontEngine::FaceId face_id(FcPattern *pattern)
01192 {
01193     char *file_name;
01194     FcPatternGetString(pattern, FC_FILE, 0, (FcChar8 **)&file_name);
01195     int face_index;
01196     if (!FcPatternGetInteger(pattern, FC_INDEX, 0, &face_index))
01197         face_index = 0;
01198     QFontEngine::FaceId face_id;
01199     face_id.filename = file_name;
01200     face_id.index = face_index;
01201     return face_id;
01202 }
01203 
01204 QFontEngineFT::QFontEngineFT(FcPattern *pattern, const QFontDef &fd, int screen)
01205 {
01206     _openType = 0;
01207     cache_cost = 100;
01208     fontDef = fd;
01209     _pattern = pattern;
01210     transform = false;
01211     matrix.xx = 0x10000;
01212     matrix.yy = 0x10000;
01213     matrix.xy = 0;
01214     matrix.yx = 0;
01215 //     FcPatternPrint(pattern);
01216 
01217     antialias = X11->fc_antialias;
01218     FcBool b;
01219     if (FcPatternGetBool(pattern, FC_ANTIALIAS, 0, &b) == FcResultMatch)
01220         antialias = b;
01221     if (FcPatternGetInteger(pattern, FC_RGBA, 0, &subpixel) == FcResultNoMatch)
01222         subpixel = X11->screens[screen].subpixel;
01223     if (!antialias || subpixel == FC_RGBA_UNKNOWN)
01224         subpixel = FC_RGBA_NONE;
01225 
01226 #ifdef FC_HINT_STYLE
01227     if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hint_style) == FcResultNoMatch)
01228   hint_style = X11->fc_hint_style;
01229 #endif
01230 
01231     autohint = false;
01232 #ifdef FC_AUTOHINT
01233     if (FcPatternGetBool(pattern, FC_AUTOHINT, 0, &b) == FcResultMatch)
01234         autohint = b;
01235 #endif
01236 
01237     face_id = ::face_id(pattern);
01238 
01239     freetype = QFreetypeFace::getFace(face_id);
01240     if (!freetype) {
01241         xsize = 0;
01242         ysize = 0;
01243         return;
01244     }
01245 
01246     if (!freetype->charset) {
01247         FcCharSet *cs;
01248         FcPatternGetCharSet (pattern, FC_CHARSET, 0, &cs);
01249         freetype->charset = FcCharSetCopy(cs);
01250     }
01251     symbol = freetype->symbol_map != 0;
01252 
01253     lbearing = rbearing = SHRT_MIN;
01254     freetype->computeSize(fontDef, &xsize, &ysize, &outline_drawing);
01255 
01256     FT_Face face = lockFace();
01257 
01258     //underline metrics
01259     if (FT_IS_SCALABLE(face)) {
01260         line_thickness =  QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale));
01261         underline_position = QFixed::fromFixed(-FT_MulFix(face->underline_position, face->size->metrics.y_scale));
01262         bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC);
01263         if (fake_oblique)
01264             matrix.xy = 0x10000*3/10;
01265         FT_Set_Transform(face, &matrix, 0);
01266         if (fake_oblique)
01267             transform = true;
01268     } else {
01269         // copied from QFontEngineQPF
01270         // ad hoc algorithm
01271         int score = fontDef.weight * fontDef.pixelSize;
01272         line_thickness = score / 700;
01273         // looks better with thicker line for small pointsizes
01274         if (line_thickness < 2 && score >= 1050)
01275             line_thickness = 2;
01276         underline_position =  ((line_thickness * 2) + 3) / 6;
01277     }
01278     if (line_thickness < 1)
01279         line_thickness = 1;
01280 
01281     metrics = face->size->metrics;
01282 
01283     unlockFace();
01284 
01285     fsType = freetype->fsType();
01286 
01287 #ifndef QT_NO_XRENDER
01288     if (X11->use_xrender) {
01289         int format = PictStandardA8;
01290         if (!antialias)
01291             format = PictStandardA1;
01292         else if (subpixel == FC_RGBA_RGB
01293                  || subpixel == FC_RGBA_BGR
01294                  || subpixel == FC_RGBA_VRGB
01295                  || subpixel == FC_RGBA_VBGR)
01296             format = PictStandardARGB32;
01297         fnt.glyphSet = XRenderCreateGlyphSet(X11->display,
01298                                              XRenderFindStandardFormat(X11->display, format));
01299         xglyph_format = format;
01300     } else {
01301         fnt.glyphSet = 0;
01302     }
01303 #endif
01304 }
01305 
01306 QFontEngineFT::~QFontEngineFT()
01307 {
01308     delete _openType;
01309     _openType = 0;
01310 
01311     if (freetype)
01312     freetype->release(face_id);
01313 
01314     FcPatternDestroy(_pattern);
01315     _pattern = 0;
01316 }
01317 
01318 FT_Face QFontEngineFT::lockFace() const
01319 {
01320     freetype->lock();
01321     FT_Face face = freetype->face;
01322     if (freetype->xsize != xsize || freetype->ysize != ysize) {
01323         FT_Set_Char_Size(face, xsize, ysize, 0, 0);
01324         freetype->xsize = xsize;
01325         freetype->ysize = ysize;
01326     }
01327     if (freetype->matrix.xx != matrix.xx ||
01328         freetype->matrix.yy != matrix.yy ||
01329         freetype->matrix.xy != matrix.xy ||
01330         freetype->matrix.yx != matrix.yx) {
01331         freetype->matrix = matrix;
01332         FT_Set_Transform(face, &freetype->matrix, 0);
01333     }
01334 
01335     return face;
01336 }
01337 
01338 void QFontEngineFT::unlockFace() const
01339 {
01340     freetype->unlock();
01341 }
01342 
01343 FT_Face QFontEngineFT::non_locked_face() const
01344 {
01345     return freetype->face;
01346 }
01347 
01348 static const uint subpixel_filter[3][3] = {
01349     { 180, 60, 16 },
01350     { 38, 180, 38 },
01351     { 16, 60, 180 }
01352 };
01353 
01354 QFontEngineFT::Font::Font()
01355 #ifndef QT_NO_XRENDER
01356     : glyphSet(0)
01357 #endif
01358 {
01359     transformationMatrix.xx = 0x10000;
01360     transformationMatrix.yy = 0x10000;
01361     transformationMatrix.xy = 0;
01362     transformationMatrix.yx = 0;
01363 }
01364 
01365 QFontEngineFT::Font::~Font()
01366 {
01367     qDeleteAll(glyph_data);
01368 #ifndef QT_NO_XRENDER
01369     if (glyphSet != 0)
01370         XRenderFreeGlyphSet(X11->display, glyphSet);
01371 #endif
01372 }
01373 
01374 QFontEngineFT::Glyph *QFontEngineFT::Font::loadGlyph(const QFontEngineFT *fe, uint glyph, GlyphFormat format) const
01375 {
01376 //     Q_ASSERT(freetype->lock == 1);
01377 
01378     bool add_to_glyphset = false;
01379     if (format == Format_None) {
01380         format = Format_Mono;
01381         if (X11->use_xrender) {
01382             add_to_glyphset = true;
01383             if (fe->subpixel != FC_RGBA_NONE)
01384                 format = Format_A32;
01385             else if (fe->antialias)
01386                 format = Format_A8;
01387         }
01388     }
01389     Q_ASSERT(format != Format_None);
01390     bool hsubpixel = false;
01391     int vfactor = 1;
01392     int load_flags = FT_LOAD_DEFAULT;
01393     if (fe->outline_drawing) {
01394         load_flags = FT_LOAD_NO_BITMAP|FT_LOAD_NO_HINTING;
01395     } else if (format == Format_Mono) {
01396         load_flags |= FT_LOAD_TARGET_MONO;
01397     } else if (format == Format_A32) {
01398         if (fe->subpixel == FC_RGBA_RGB || fe->subpixel == FC_RGBA_BGR) {
01399             load_flags |= FT_LOAD_TARGET_LCD;
01400             hsubpixel = true;
01401         } else if (fe->subpixel == FC_RGBA_VRGB || fe->subpixel == FC_RGBA_VBGR) {
01402             load_flags |= FT_LOAD_TARGET_LCD_V;
01403             vfactor = 3;
01404         }
01405 
01406     }
01407     if (format != Format_Mono)
01408         load_flags |= FT_LOAD_NO_BITMAP;
01409 
01410 #ifdef FC_HINT_STYLE
01411     if (fe->hint_style == FC_HINT_NONE)
01412         load_flags |= FT_LOAD_NO_HINTING;
01413     else if (fe->hint_style < FC_HINT_FULL)
01414         load_flags |= FT_LOAD_TARGET_LIGHT;
01415 #endif
01416 
01417 #ifdef FT_LOAD_FORCE_AUTOHINT
01418     if (fe->autohint)
01419         load_flags |= FT_LOAD_FORCE_AUTOHINT;
01420 #endif
01421 
01422     bool transform = fe->transform
01423                      || transformationMatrix.xx != 0x10000
01424                      || transformationMatrix.yy != 0x10000
01425                      || transformationMatrix.xy != 0
01426                      || transformationMatrix.yx != 0;
01427 
01428     if (transform)
01429         load_flags |= FT_LOAD_NO_BITMAP;
01430 
01431     {
01432         Glyph *g = glyph_data.value(glyph);
01433         if (g && g->format == format)
01434             return g;
01435     }
01436 
01437     const QFreetypeFace * const freetype = fe->freetype;
01438     FT_Face face = freetype->face;
01439     FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
01440     if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
01441         load_flags &= ~FT_LOAD_NO_BITMAP;
01442         err = FT_Load_Glyph(face, glyph, load_flags);
01443     }
01444     if (err == FT_Err_Too_Few_Arguments) {
01445         // this is an error in the bytecode interpreter, just try to run without it
01446         load_flags |= FT_LOAD_FORCE_AUTOHINT;
01447         err = FT_Load_Glyph(face, glyph, load_flags);
01448     }
01449     if (err != FT_Err_Ok)
01450         qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
01451 
01452     if (fe->outline_drawing)
01453         return 0;
01454 
01455     FT_GlyphSlot slot = face->glyph;
01456 
01457     FT_Matrix matrix = freetype->matrix;
01458 
01459     int left  = slot->metrics.horiBearingX;
01460     int right = slot->metrics.horiBearingX + slot->metrics.width;
01461     int top    = slot->metrics.horiBearingY;
01462     int bottom = slot->metrics.horiBearingY - slot->metrics.height;
01463     if(transform && slot->format != FT_GLYPH_FORMAT_BITMAP) {
01464         int l, r, t, b;
01465         FT_Vector vector;
01466         vector.x = left;
01467         vector.y = top;
01468         FT_Vector_Transform(&vector, &matrix);
01469         l = r = vector.x;
01470         t = b = vector.y;
01471         vector.x = right;
01472         vector.y = top;
01473         FT_Vector_Transform(&vector, &matrix);
01474         if (l > vector.x) l = vector.x;
01475         if (r < vector.x) r = vector.x;
01476         if (t < vector.y) t = vector.y;
01477         if (b > vector.y) b = vector.y;
01478         vector.x = right;
01479         vector.y = bottom;
01480         FT_Vector_Transform(&vector, &matrix);
01481         if (l > vector.x) l = vector.x;
01482         if (r < vector.x) r = vector.x;
01483         if (t < vector.y) t = vector.y;
01484         if (b > vector.y) b = vector.y;
01485         vector.x = left;
01486         vector.y = bottom;
01487         FT_Vector_Transform(&vector, &matrix);
01488         if (l > vector.x) l = vector.x;
01489         if (r < vector.x) r = vector.x;
01490         if (t < vector.y) t = vector.y;
01491         if (b > vector.y) b = vector.y;
01492         left = l;
01493         right = r;
01494         top = t;
01495         bottom = b;
01496     }
01497     left = FLOOR(left);
01498     right = CEIL(right);
01499     bottom = FLOOR(bottom);
01500     top = CEIL(top);
01501 
01502     int hpixels = TRUNC(right - left);
01503     if (hsubpixel)
01504         hpixels = hpixels*3 + 8;
01505 #ifndef QT_NO_XRENDER
01506     XGlyphInfo info;
01507 #else
01508     typedef struct _XGlyphInfoDummy {
01509         unsigned short  width;
01510         unsigned short  height;
01511         short           x;
01512         short           y;
01513         short           xOff;
01514         short           yOff;
01515     } XGlyphInfoDummy;
01516     XGlyphInfoDummy info;
01517 #endif
01518     info.width = hpixels;
01519     info.height = TRUNC(top - bottom);
01520     info.x = -TRUNC(left);
01521     info.y = TRUNC(top);
01522     info.xOff = TRUNC(ROUND(slot->advance.x));
01523     info.yOff = 0;
01524     if (hsubpixel) {
01525         info.width /= 3;
01526         info.x += 1;
01527     }
01528 
01529     int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
01530                  (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
01531     int size = pitch * info.height;
01532     uchar *glyph_buffer = new uchar[size];
01533 
01534     if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
01535         FT_Bitmap bitmap;
01536         bitmap.rows = info.height*vfactor;
01537         bitmap.width = hpixels;
01538         bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3);
01539         if (!hsubpixel && vfactor == 1)
01540             bitmap.buffer = glyph_buffer;
01541         else
01542             bitmap.buffer = new uchar[bitmap.rows*bitmap.pitch];
01543         memset(bitmap.buffer, 0, bitmap.rows*bitmap.pitch);
01544         bitmap.pixel_mode = format == Format_Mono ? ft_pixel_mode_mono : ft_pixel_mode_grays;
01545         FT_Matrix matrix;
01546         matrix.xx = (hsubpixel ? 3 : 1) << 16;
01547         matrix.yy = vfactor << 16;
01548         matrix.yx = matrix.xy = 0;
01549 
01550         FT_Outline_Transform(&slot->outline, &matrix);
01551         FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor);
01552         FT_Outline_Get_Bitmap(library, &slot->outline, &bitmap);
01553         if (hsubpixel) {
01554             Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
01555             Q_ASSERT(fe->antialias);
01556             const uchar *src = bitmap.buffer;
01557             uchar *convoluted = new uchar[bitmap.rows*bitmap.pitch];
01558             uchar *c = convoluted;
01559             // convolute the bitmap with a triangle filter to get rid of color fringes
01560             // If we take account for a gamma value of 2, we end up with
01561             // weights of 1, 4, 9, 4, 1. We use an approximation of 1, 3, 8, 3, 1 here,
01562             // as this nicely sums up to 16 :)
01563             int h = info.height;
01564             while (h--) {
01565                 c[0] = c[1] = 0;
01566                 //
01567                 for (int x = 2; x < bitmap.width - 2; ++x) {
01568                     uint sum = src[x-2] + 3*src[x-1] + 8*src[x] + 3*src[x+1] + src[x+2];
01569                     c[x] = (uchar) (sum >> 4);
01570                 }
01571                 c[bitmap.width - 2] = c[bitmap.width -1] = 0;
01572                 src += bitmap.pitch;
01573                 c += bitmap.pitch;
01574             }
01575 
01576             uint *dst = (uint *)glyph_buffer;
01577             src = convoluted;
01578             h = info.height;
01579             if (fe->subpixel == FC_RGBA_RGB) {
01580                 while (h--) {
01581                     uint *dd = dst;
01582                     for (int x = 1; x < bitmap.width - 1; x += 3) {
01583                         uint red = src[x];
01584                         uint green = src[x+1];
01585                         uint blue = src[x+2];
01586                         uint res = (red << 16) + (green << 8) + blue;
01587                         *dd = res;
01588                         ++dd;
01589                     }
01590                     dst += info.width;
01591                     src += bitmap.pitch;
01592                 }
01593             } else {
01594                 while (h--) {
01595                     uint *dd = dst;
01596                     for (int x = 1; x < bitmap.width - 1; x += 3) {
01597                         uint blue = src[x];
01598                         uint green = src[x+1];
01599                         uint red = src[x+2];
01600                         uint res = (red << 16) + (green << 8) + blue;
01601                         *dd = res;
01602                         ++dd;
01603                     }
01604                     dst += info.width;
01605                     src += bitmap.pitch;
01606                 }
01607             }
01608             delete [] convoluted;
01609             delete [] bitmap.buffer;
01610         } else if (vfactor != 1) {
01611             uchar *src = bitmap.buffer;
01612             size = info.width * 4 * info.height;
01613             uint *dst = (uint *)glyph_buffer;
01614             int h = info.height;
01615             if (fe->subpixel == FC_RGBA_VRGB) {
01616                 while (h--) {
01617                     for (int x = 0; x < info.width; x++) {
01618                         uint red = src[x];
01619                         uint green = src[x+bitmap.pitch];
01620                         uint blue = src[x+2*bitmap.pitch];
01621                         uint high = (red*subpixel_filter[0][0] + green*subpixel_filter[0][1] + blue*subpixel_filter[0][2]) >> 8;
01622                         uint mid = (red*subpixel_filter[1][0] + green*subpixel_filter[1][1] + blue*subpixel_filter[1][2]) >> 8;
01623                         uint low = (red*subpixel_filter[2][0] + green*subpixel_filter[2][1] + blue*subpixel_filter[2][2]) >> 8;
01624                         uint res = (high << 16) + (mid << 8) + low;
01625                         dst[x] = res;
01626                     }
01627                     dst += info.width;
01628                     src += 3*bitmap.pitch;
01629                 }
01630             } else {
01631                 while (h--) {
01632                     for (int x = 0; x < info.width; x++) {
01633                         uint blue = src[x];
01634                         uint green = src[x+bitmap.pitch];
01635                         uint red = src[x+2*bitmap.pitch];
01636                         uint high = (red*subpixel_filter[0][0] + green*subpixel_filter[0][1] + blue*subpixel_filter[0][2]) >> 8;
01637                         uint mid = (red*subpixel_filter[1][0] + green*subpixel_filter[1][1] + blue*subpixel_filter[1][2]) >> 8;
01638                         uint low = (red*subpixel_filter[2][0] + green*subpixel_filter[2][1] + blue*subpixel_filter[2][2]) >> 8;
01639                         uint res = (high << 16) + (mid << 8) + low;
01640                         dst[x] = res;
01641                     }
01642                     dst += info.width;
01643                     src += 3*bitmap.pitch;
01644                 }
01645             }
01646             delete [] bitmap.buffer;
01647         }
01648     } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
01649         Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO);
01650         uchar *src = slot->bitmap.buffer;
01651         uchar *dst = glyph_buffer;
01652         int h = slot->bitmap.rows;
01653         if (format == Format_Mono) {
01654             int bytes = ((info.width + 7) & ~7) >> 3;
01655             while (h--) {
01656                 memcpy (dst, src, bytes);
01657                 dst += pitch;
01658                 src += slot->bitmap.pitch;
01659             }
01660         } else {
01661             if (hsubpixel) {
01662                 while (h--) {
01663                     uint *dd = (uint *)dst;
01664                     *dd++ = 0;
01665                     for (int x = 0; x < slot->bitmap.width; x++) {
01666                         uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
01667                         *dd++ = a;
01668                     }
01669                     *dd++ = 0;
01670                     dst += pitch;
01671                     src += slot->bitmap.pitch;
01672                 }
01673             } else if (vfactor != 1) {
01674                 while (h--) {
01675                     uint *dd = (uint *)dst;
01676                     for (int x = 0; x < slot->bitmap.width; x++) {
01677                         uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
01678                         *dd++ = a;
01679                     }
01680                     dst += pitch;
01681                     src += slot->bitmap.pitch;
01682                 }
01683             } else {
01684                 while (h--) {
01685                     for (int x = 0; x < slot->bitmap.width; x++) {
01686                         unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
01687                         dst[x] = a;
01688                     }
01689                     dst += pitch;
01690                     src += slot->bitmap.pitch;
01691                 }
01692             }
01693         }
01694     } else {
01695         qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format);
01696         delete [] glyph_buffer;
01697         return 0;
01698     }
01699 
01700 #ifndef QT_NO_XRENDER
01701     if (add_to_glyphset) {
01702         if (format == Format_Mono) {
01703             /*
01704              * swap bit order around; FreeType is always MSBFirst
01705              */
01706             if (BitmapBitOrder(X11->display) != MSBFirst) {
01707                 unsigned char *line = (unsigned char *) glyph_buffer;
01708                 int i = size;
01709                 i = size;
01710                 while (i--) {
01711                     unsigned char c;
01712                     c = *line;
01713                     c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
01714                     c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
01715                     c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
01716                     *line++ = c;
01717                 }
01718             }
01719         }
01720 
01721         ::Glyph xglyph = glyph;
01722         XRenderAddGlyphs (X11->display, glyphSet, &xglyph, &info, 1, (const char *)glyph_buffer, size);
01723         delete [] glyph_buffer;
01724         glyph_buffer = 0;
01725     }
01726 #endif
01727 
01728 
01729     bool large_glyph = (((signed char)(slot->linearHoriAdvance>>16) != slot->linearHoriAdvance>>16)
01730                         || ((uchar)(info.width) != info.width)
01731                         || ((uchar)(info.height) != info.height)
01732                         || ((signed char)(info.x) != info.x)
01733                         || ((signed char)(info.y) != info.y)
01734                         || ((signed char)(info.xOff) != info.xOff));
01735 
01736     if (large_glyph) {
01737 //         qDebug("got a large glyph!");
01738         return 0;
01739     }
01740 
01741     Glyph *g = new Glyph;
01742 
01743     g->linearAdvance = slot->linearHoriAdvance >> 10;
01744     g->width = info.width;
01745     g->height = TRUNC(top - bottom);
01746     g->x = -info.x;
01747     g->y = TRUNC(top);
01748     g->advance = TRUNC(ROUND(slot->advance.x));
01749     g->format = add_to_glyphset ? Format_None : format;
01750     g->data = glyph_buffer;
01751 
01752     // make sure we delete the old cached glyph
01753     delete glyph_data.value(glyph);
01754     glyph_data[glyph] = g;
01755 
01756     return g;
01757 }
01758 #ifndef QT_NO_XRENDER
01759 bool QFontEngineFT::loadTransformedGlyphSet(glyph_t *glyphs, int num_glyphs, const QMatrix &matrix, GlyphSet *gs)
01760 {
01761     // don't try to load huge fonts
01762     if (fontDef.pixelSize * sqrt(matrix.det()) >= 64) {
01763         *gs = 0;
01764         return false;
01765     }
01766 
01767     FT_Matrix m;
01768     m.xx = FT_Fixed(matrix.m11() * 65536);
01769     m.xy = FT_Fixed(-matrix.m21() * 65536);
01770     m.yx = FT_Fixed(-matrix.m12() * 65536);
01771     m.yy = FT_Fixed(matrix.m22() * 65536);
01772 
01773     Font *font = 0;
01774 
01775     for (int i = 0; i < transformedFonts.count(); ++i) {
01776         const Font &f = transformedFonts.at(i);
01777         if (f.transformationMatrix.xx == m.xx
01778             && f.transformationMatrix.xy == m.xy
01779             && f.transformationMatrix.yx == m.yx
01780             && f.transformationMatrix.yy == m.yy) {
01781 
01782             // found a match, move it to the front
01783             transformedFonts.move(i, 0);
01784             font = &transformedFonts[0];
01785             break;
01786         }
01787     }
01788 
01789     if (!font) {
01790         // don't cache more than 10 transformations
01791         if (transformedFonts.count() >= 10) {
01792             transformedFonts.move(transformedFonts.size() - 1, 0);
01793             XRenderFreeGlyphSet(X11->display, transformedFonts.at(0).glyphSet);
01794         } else {
01795             transformedFonts.prepend(Font());
01796         }
01797         font = &transformedFonts[0];
01798 
01799         qDeleteAll(font->glyph_data);
01800         font->glyph_data.clear();
01801 
01802         font->glyphSet = XRenderCreateGlyphSet(X11->display,
01803                          XRenderFindStandardFormat(X11->display, xglyph_format));
01804 
01805         font->transformationMatrix = m;
01806     }
01807 
01808     FT_Face face = 0;
01809     bool lockedFace = false;
01810 
01811     for (int i = 0; i < num_glyphs; ++i) {
01812         if (!font->glyph_data.contains(glyphs[i])) {
01813             if (!lockedFace) {
01814                 face = lockFace();
01815                 m = this->matrix;
01816                 FT_Matrix_Multiply(&font->transformationMatrix, &m);
01817                 FT_Set_Transform(face, &m, 0);
01818                 freetype->matrix = m;
01819                 lockedFace = true;
01820             }
01821             if (!font->loadGlyph(this, glyphs[i])) {
01822                 FT_Set_Transform(face, &freetype->matrix, 0);
01823                 unlockFace();
01824                 return false;
01825             }
01826         }
01827     }
01828     *gs = font->glyphSet;
01829 
01830     if (lockedFace) {
01831         FT_Set_Transform(face, &freetype->matrix, 0);
01832         unlockFace();
01833     }
01834 
01835     return true;
01836 }
01837 #endif
01838 
01839 inline unsigned int getChar(const QChar *str, int &i, const int len)
01840 {
01841     unsigned int uc = str[i].unicode();
01842     if (uc >= 0xd800 && uc < 0xdc00 && i < len-1) {
01843         uint low = str[i+1].unicode();
01844        if (low >= 0xdc00 && low < 0xe000) {
01845             uc = (uc - 0xd800)*0x400 + (low - 0xdc00) + 0x10000;
01846             ++i;
01847         }
01848     }
01849     return uc;
01850 }
01851 
01852 bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
01853                                  QTextEngine::ShaperFlags flags) const
01854 {
01855     if (*nglyphs < len) {
01856         *nglyphs = len;
01857         return false;
01858     }
01859 
01860     bool mirrored = flags & QTextEngine::RightToLeft;
01861     int glyph_pos = 0;
01862     if (freetype->symbol_map) {
01863         FT_Face face = freetype->face;
01864         for ( int i = 0; i < len; ++i ) {
01865             unsigned int uc = getChar(str, i, len);
01866             if (mirrored)
01867                 uc = QUnicodeTables::mirroredChar(uc);
01868             glyphs[glyph_pos].glyph = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
01869             if ( !glyphs[glyph_pos].glyph ) {
01870                 glyph_t glyph;
01871                 if (FcCharSetHasChar(freetype->charset, uc)) {
01872                 redo0:
01873                     glyph = FT_Get_Char_Index(face, uc);
01874                     if (!glyph && (uc == 0xa0 || uc == 0x9)) {
01875                         uc = 0x20;
01876                         goto redo0;
01877                     }
01878                 } else {
01879                     FT_Set_Charmap(face, freetype->symbol_map);
01880                     glyph = FT_Get_Char_Index(face, uc);
01881                     FT_Set_Charmap(face, freetype->unicode_map);
01882                 }
01883                 glyphs[glyph_pos].glyph = glyph;
01884                 if (uc < QFreetypeFace::cmapCacheSize)
01885                     freetype->cmapCache[uc] = glyph;
01886             }
01887             ++glyph_pos;
01888         }
01889     } else {
01890         FT_Face face = freetype->face;
01891         for (int i = 0; i < len; ++i) {
01892             unsigned int uc = getChar(str, i, len);
01893             if (mirrored)
01894                 uc = QUnicodeTables::mirroredChar(uc);
01895             glyphs[glyph_pos].glyph = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
01896             if (!glyphs[glyph_pos].glyph && FcCharSetHasChar(freetype->charset, uc)) {
01897             redo:
01898                 glyph_t glyph = FT_Get_Char_Index(face, uc);
01899                 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
01900                     uc = 0x20;
01901                     goto redo;
01902                 }
01903                 glyphs[glyph_pos].glyph = glyph;
01904                 if (uc < QFreetypeFace::cmapCacheSize)
01905                     freetype->cmapCache[uc] = glyph;
01906             }
01907             ++glyph_pos;
01908         }
01909     }
01910 
01911     *nglyphs = glyph_pos;
01912     recalcAdvances(*nglyphs, glyphs, flags);
01913 
01914     return true;
01915 }
01916 
01917 void QFontEngineFT::recalcAdvances(int len, QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
01918 {
01919     FT_Face face = 0;
01920     if (flags & QTextEngine::DesignMetrics) {
01921         for (int i = 0; i < len; i++) {
01922             Glyph *g = fnt.glyph_data.value(glyphs[i].glyph);
01923             if (!g) {
01924                 if (!face)
01925                     face = lockFace();
01926                 g = loadGlyph(glyphs[i].glyph);
01927             }
01928             // for uncachable glyph, get advance from glyphslot
01929             glyphs[i].advance.x = QFixed::fromFixed(g ? g->linearAdvance : (face->glyph->linearHoriAdvance >> 10));
01930             glyphs[i].advance.y = 0;
01931         }
01932     } else {
01933         for (int i = 0; i < len; i++) {
01934             Glyph *g = fnt.glyph_data.value(glyphs[i].glyph);
01935             if (!g) {
01936                 if (!face)
01937                     face = lockFace();
01938                 g = loadGlyph(glyphs[i].glyph);
01939             }
01940             // for uncachable glyph, get advance from glyphslot
01941             glyphs[i].advance.x = g ? QFixed(g->advance) : QFixed::fromFixed(face->glyph->metrics.horiAdvance);
01942             glyphs[i].advance.y = 0;
01943         }
01944     }
01945     if (face)
01946         unlockFace();
01947 }
01948 
01949 glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout *glyphs, int numGlyphs)
01950 {
01951 
01952     FT_Face face = 0;
01953 
01954     glyph_metrics_t overall;
01955     // initialize with line height, we get the same behaviour on all platforms
01956     overall.y = -ascent();
01957     overall.height = ascent() + descent() + 1;
01958 
01959     QFixed ymax = 0;
01960     QFixed xmax = 0;
01961     for (int i = 0; i < numGlyphs; i++) {
01962         Glyph *g = fnt.glyph_data.value(glyphs[i].glyph);
01963         if (!g) {
01964             if (!face)
01965                 face = lockFace();
01966             g = loadGlyph(glyphs[i].glyph);
01967         }
01968         if (g) {
01969             QFixed x = overall.xoff + glyphs[i].offset.x + g->x;
01970             QFixed y = overall.yoff + glyphs[i].offset.y - g->y;
01971             overall.x = qMin(overall.x, x);
01972             overall.y = qMin(overall.y, y);
01973             xmax = qMax(xmax, x + g->width);
01974             ymax = qMax(ymax, y + g->height);
01975             overall.xoff += qRound(g->advance);
01976         } else {
01977             int left  = FLOOR(face->glyph->metrics.horiBearingX);
01978             int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
01979             int top    = CEIL(face->glyph->metrics.horiBearingY);
01980             int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
01981 
01982             QFixed x = overall.xoff + glyphs[i].offset.x - (-TRUNC(left));
01983             QFixed y = overall.yoff + glyphs[i].offset.y - TRUNC(top);
01984             overall.x = qMin(overall.x, x);
01985             overall.y = qMin(overall.y, y);
01986             xmax = qMax(xmax, x + TRUNC(right - left));
01987             ymax = qMax(ymax, y + TRUNC(top - bottom));
01988             overall.xoff += qRound(TRUNC(ROUND(face->glyph->advance.x)));
01989         }
01990     }
01991     overall.height = qMax(overall.height, ymax - overall.y);
01992     overall.width = xmax - overall.x;
01993 
01994     if (face)
01995         unlockFace();
01996 
01997     return overall;
01998 }
01999 
02000 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
02001 {
02002     FT_Face face = 0;
02003     glyph_metrics_t overall;
02004     Glyph *g = fnt.glyph_data.value(glyph);
02005     if (!g) {
02006         face = lockFace();
02007         g = loadGlyph(glyph);
02008     }
02009     if (g) {
02010         overall.x = g->x;
02011         overall.y = -g->y;
02012         overall.width = g->width;
02013         overall.height = g->height;
02014         overall.xoff = g->advance;
02015     } else {
02016         int left  = FLOOR(face->glyph->metrics.horiBearingX);
02017         int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
02018         int top    = CEIL(face->glyph->metrics.horiBearingY);
02019         int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
02020 
02021         overall.width = TRUNC(right-left);
02022         overall.height = TRUNC(top-bottom);
02023         overall.x = TRUNC(left);
02024         overall.y = -TRUNC(top);
02025         overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
02026     }
02027     if (face)
02028         unlockFace();
02029     return overall;
02030 }
02031 
02032 bool QFontEngineFT::canRender(const QChar *string, int len)
02033 {
02034     FT_Face face = freetype->face;
02035 #if 0
02036     if (_cmap != -1) {
02037         lockFace();
02038         for ( int i = 0; i < len; i++ ) {
02039             unsigned int uc = getChar(string, i, len);
02040             if (!FcCharSetHasChar (_font->charset, uc) && getAdobeCharIndex(face, _cmap, uc) == 0) {
02041                 allExist = false;
02042                 break;
02043             }
02044         }
02045         unlockFace();
02046     } else
02047 #endif
02048     {
02049         for ( int i = 0; i < len; i++ ) {
02050             unsigned int uc = getChar(string, i, len);
02051             if (!FT_Get_Char_Index(face, uc))
02052                     return false;
02053         }
02054     }
02055     return true;
02056 }
02057 
02058 void QFontEngineFT::doKerning(int num_glyphs, QGlyphLayout *g, QTextEngine::ShaperFlags flags) const
02059 {
02060     if (!FT_HAS_KERNING(freetype->face))
02061         return;
02062     FT_Face face = lockFace();
02063     uint f = (flags == QTextEngine::DesignMetrics ? FT_KERNING_UNFITTED : FT_KERNING_DEFAULT);
02064     for (int i = 0; i < num_glyphs-1; ++i) {
02065         FT_Vector kerning;
02066         FT_Get_Kerning(face, g[i].glyph, g[i+1].glyph, f, &kerning);
02067         g[i].advance.x += QFixed::fromFixed(kerning.x);
02068         g[i].advance.y += QFixed::fromFixed(kerning.y);
02069     }
02070     unlockFace();
02071 }
02072 
02073 
02074 void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs,
02075                                     QPainterPath *path, QTextItem::RenderFlags)
02076 {
02077     FT_Face face = lockFace();
02078 
02079     for (int gl = 0; gl < numGlyphs; gl++) {
02080         FT_UInt glyph = glyphs[gl];
02081 
02082         FT_Load_Glyph(face, glyph, FT_LOAD_NO_HINTING|FT_LOAD_NO_BITMAP);
02083 
02084         FT_GlyphSlot g = face->glyph;
02085         if (g->format != FT_GLYPH_FORMAT_OUTLINE)
02086             continue;
02087         addGlyphToPath(g, positions[gl], path);
02088     }
02089     unlockFace();
02090 }
02091 
02092 void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout *glyphs, int numGlyphs, QPainterPath *path, QTextItem::RenderFlags flags)
02093 {
02094     if (FT_IS_SCALABLE(freetype->face)) {
02095         QFontEngine::addOutlineToPath(x, y, glyphs, numGlyphs, path, flags);
02096     } else {
02097         addBitmapFontToPath(x, y, glyphs, numGlyphs, path, flags);
02098     }
02099 }
02100 
02101 QImage QFontEngineFT::alphaMapForGlyph(glyph_t g)
02102 {
02103     lockFace();
02104 
02105     Glyph *glyph = loadGlyph(g, Format_A8);
02106     if (!glyph) {
02107         unlockFace();
02108         return QFontEngine::alphaMapForGlyph(g);
02109     }
02110 
02111     Q_ASSERT(glyph->format == QFontEngineFT::Format_A8);
02112 
02113     const int pitch = (glyph->width + 3) & ~3;
02114 
02115     QImage img(glyph->width, glyph->height, QImage::Format_Indexed8);
02116     QVector<QRgb> colors(256);
02117     for (int i=0; i<256; ++i)
02118         colors[i] = qRgba(0, 0, 0, i);
02119     img.setColorTable(colors);
02120 
02121     for (int y = 0; y < glyph->height; ++y)
02122         memcpy(img.scanLine(y), &glyph->data[y * pitch], glyph->width);
02123     unlockFace();
02124 
02125     return img;
02126 }
02127 
02128 QFixed QFontEngineFT::ascent() const
02129 {
02130     return QFixed::fromFixed(metrics.ascender);
02131 }
02132 
02133 QFixed QFontEngineFT::descent() const
02134 {
02135     return QFixed::fromFixed(-metrics.descender + (1<<6));
02136 }
02137 
02138 QFixed QFontEngineFT::leading() const
02139 {
02140     return QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender);
02141 }
02142 
02143 QFixed QFontEngineFT::xHeight() const
02144 {
02145     TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
02146     if (os2 && os2->sxHeight)
02147         return QFixed(os2->sxHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
02148     return QFontEngine::xHeight();
02149 }
02150 
02151 QFixed QFontEngineFT::averageCharWidth() const
02152 {
02153     TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
02154     if (os2 && os2->xAvgCharWidth)
02155         return QFixed(os2->xAvgCharWidth*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
02156     return QFontEngine::averageCharWidth();
02157 }
02158 
02159 
02160 qreal QFontEngineFT::maxCharWidth() const
02161 {
02162     return metrics.max_advance >> 6;
02163 }
02164 
02165 static const ushort char_table[] = {
02166         40,
02167         67,
02168         70,
02169         75,
02170         86,
02171         88,
02172         89,
02173         91,
02174         102,
02175         114,
02176         124,
02177         127,
02178         205,
02179         645,
02180         884,
02181         922,
02182         1070,
02183         12386
02184 };
02185 
02186 static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
02187 
02188 
02189 qreal QFontEngineFT::minLeftBearing() const
02190 {
02191     if (lbearing == SHRT_MIN)
02192         (void) minRightBearing(); // calculates both
02193     return lbearing.toReal();
02194 }
02195 
02196 qreal QFontEngineFT::minRightBearing() const
02197 {
02198     if (rbearing == SHRT_MIN) {
02199         lbearing = rbearing = 0;
02200         const QChar *ch = (const QChar *)char_table;
02201         QGlyphLayout glyphs[char_table_entries];
02202         int ng = char_table_entries;
02203         stringToCMap(ch, char_table_entries, glyphs, &ng, 0);
02204         while (--ng) {
02205             if (glyphs[ng].glyph) {
02206                 glyph_metrics_t gi = ((QFontEngineFT *)this)->boundingBox(glyphs[ng].glyph);
02207                 lbearing = qMin(lbearing, gi.x);
02208                 rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
02209             }
02210         }
02211     }
02212     return rbearing.toReal();
02213 }
02214 
02215 QFixed QFontEngineFT::lineThickness() const
02216 {
02217     return line_thickness;
02218 }
02219 
02220 QFixed QFontEngineFT::underlinePosition() const
02221 {
02222     return underline_position;
02223 }
02224 
02225 QFontEngine::FaceId QFontEngineFT::faceId() const
02226 {
02227     return face_id;
02228 }
02229 
02230 QFontEngine::Properties QFontEngineFT::properties() const
02231 {
02232     Properties p = freetype->properties();
02233     if (p.postscriptName.isEmpty()) {
02234         p.postscriptName = fontDef.family.toUtf8();
02235         p.postscriptName = QPdf::stripSpecialCharacters(p.postscriptName);
02236     }
02237 
02238     return freetype->properties();
02239 }
02240 
02241 
02242 void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
02243 {
02244     FT_Face face = lockFace();
02245     FT_Set_Transform(face, 0, 0);
02246     FT_Load_Glyph(face, glyph, FT_LOAD_NO_HINTING|FT_LOAD_NO_BITMAP|FT_LOAD_NO_SCALE);
02247 
02248     int left  = face->glyph->metrics.horiBearingX;
02249     int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
02250     int top    = face->glyph->metrics.horiBearingY;
02251     int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
02252 
02253     QFixedPoint p;
02254     p.x = 0;
02255     p.y = 0;
02256 
02257     if (!FT_IS_SCALABLE(freetype->face)) {
02258         metrics->width = QFixed::fromFixed(right-left);
02259         metrics->height = QFixed::fromFixed(top-bottom);
02260         metrics->x = QFixed::fromFixed(left);
02261         metrics->y = QFixed::fromFixed(-top);
02262         metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
02263 
02264         ::addBitmapToPath(face->glyph, p, path);
02265     } else {
02266         metrics->width = right-left;
02267         metrics->height = top-bottom;
02268         metrics->x = left;
02269         metrics->y = -top;
02270         metrics->xoff = face->glyph->advance.x;
02271 
02272         ::addGlyphToPath(face->glyph, p, path, true /* no_scale */);
02273     }
02274 
02275     FT_Set_Transform(face, &freetype->matrix, 0);
02276     unlockFace();
02277 }
02278 
02279 QByteArray QFontEngineFT::getSfntTable(uint tag) const
02280 {
02281     return freetype->getSfntTable(tag);
02282 }
02283 
02284 int QFontEngineFT::synthesized() const
02285 {
02286     int s = 0;
02287     if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC))
02288         s = SynthesizedItalic;
02289     if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face))
02290         s |= SynthesizedStretch;
02291     return s;
02292 }
02293 
02294 QOpenType *QFontEngineFT::openType() const
02295 {
02296     if (_openType)
02297          return _openType;
02298 
02299     FT_Face face = lockFace();
02300     if (!face || !FT_IS_SFNT(face)) {
02301         unlockFace();
02302         return 0;
02303     }
02304 
02305     _openType = new QOpenType(const_cast<QFontEngineFT *>(this), face);
02306     unlockFace();
02307     return _openType;
02308 }
02309 
02310 #endif // QT_NO_FONTCONFIG

Generated on Thu Mar 15 11:55:56 2007 for Qt 4.2 User's Guide by  doxygen 1.5.1